From 9a8e197d7e03298fce9cec030ae961ca7814419e Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Mon, 18 Jul 2016 15:01:32 +0300 Subject: [PATCH 001/151] Initial version based on XML generator --- Makefile.in | 2 +- include/jid.hrl | 17 + include/mod_privacy.hrl | 11 +- include/xmpp.hrl | 29 + {tools => include}/xmpp_codec.hrl | 387 +- src/cyrsasl.erl | 16 +- src/cyrsasl_digest.erl | 12 +- src/cyrsasl_oauth.erl | 4 +- src/cyrsasl_plain.erl | 4 +- src/cyrsasl_scram.erl | 32 +- src/ejabberd_c2s.erl | 2304 +++--- src/ejabberd_frontend_socket.erl | 17 + src/ejabberd_local.erl | 137 +- src/ejabberd_router.erl | 105 +- src/ejabberd_sm.erl | 182 +- src/ejabberd_socket.erl | 15 + src/ejabberd_system_monitor.erl | 32 +- src/gen_iq_handler.erl | 55 +- src/jid.erl | 15 +- src/mod_caps.erl | 292 +- src/mod_carboncopy.erl | 168 +- src/mod_client_state.erl | 134 +- src/mod_disco.erl | 401 +- src/mod_echo.erl | 50 +- src/mod_last.erl | 129 +- src/mod_ping.erl | 33 +- src/mod_privacy.erl | 563 +- src/mod_privacy_mnesia.erl | 24 +- src/mod_privacy_riak.erl | 25 +- src/mod_privacy_sql.erl | 27 +- src/mod_private.erl | 120 +- src/mod_roster.erl | 579 +- src/mod_time.erl | 51 +- src/mod_vcard.erl | 580 +- src/mod_vcard_xupdate.erl | 43 +- src/mod_version.erl | 51 +- src/translate.erl | 4 +- src/xmpp.erl | 712 ++ {tools => src}/xmpp_codec.erl | 10831 ++++++++++++++++++---------- src/xmpp_util.erl | 81 + tools/xmpp_codec.spec | 264 +- 41 files changed, 10861 insertions(+), 7677 deletions(-) create mode 100644 include/jid.hrl create mode 100644 include/xmpp.hrl rename {tools => include}/xmpp_codec.hrl (55%) create mode 100644 src/xmpp.erl rename {tools => src}/xmpp_codec.erl (68%) create mode 100644 src/xmpp_util.erl diff --git a/Makefile.in b/Makefile.in index eb1474926..07502f06e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -110,7 +110,7 @@ edoc: spec: $(ERL) -noinput +B -pa ebin -pa deps/*/ebin -eval \ - 'case fxml_gen:compile("tools/xmpp_codec.spec") of ok -> halt(0); _ -> halt(1) end.' + 'case fxml_gen:compile("tools/xmpp_codec.spec", [{add_type_specs, xmpp_element}, {erl_dir, "src"}, {hrl_dir, "include"}]) of ok -> halt(0); _ -> halt(1) end.' JOIN_PATHS=$(if $(wordlist 2,1000,$(1)),$(firstword $(1))/$(call JOIN_PATHS,$(wordlist 2,1000,$(1))),$(1)) diff --git a/include/jid.hrl b/include/jid.hrl new file mode 100644 index 000000000..965985c31 --- /dev/null +++ b/include/jid.hrl @@ -0,0 +1,17 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 10 Jul 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-record(jid, {user = <<"">> :: binary(), + server = <<"">> :: binary(), + resource = <<"">> :: binary(), + luser = <<"">> :: binary(), + lserver = <<"">> :: binary(), + lresource = <<"">> :: binary()}). + +-type(jid() :: #jid{}). +-type(ljid() :: {binary(), binary(), binary()}). diff --git a/include/mod_privacy.hrl b/include/mod_privacy.hrl index 8fe5abcca..0d263d659 100644 --- a/include/mod_privacy.hrl +++ b/include/mod_privacy.hrl @@ -22,9 +22,11 @@ default = none :: none | binary(), lists = [] :: [{binary(), [listitem()]}]}). --record(listitem, {type = none :: none | jid | group | subscription, - value = none :: none | both | from | to | ljid() | binary(), - action = allow :: allow | deny, +-type privacy() :: #privacy{}. + +-record(listitem, {type = none :: listitem_type(), + value = none :: listitem_value(), + action = allow :: listitem_action(), order = 0 :: integer(), match_all = false :: boolean(), match_iq = false :: boolean(), @@ -33,6 +35,9 @@ match_presence_out = false :: boolean()}). -type listitem() :: #listitem{}. +-type listitem_type() :: none | jid | group | subscription. +-type listitem_value() :: none | both | from | to | ljid() | binary(). +-type listitem_action() :: allow | deny. -record(userlist, {name = none :: none | binary(), list = [] :: [listitem()], diff --git a/include/xmpp.hrl b/include/xmpp.hrl new file mode 100644 index 000000000..e1bdaeed0 --- /dev/null +++ b/include/xmpp.hrl @@ -0,0 +1,29 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2015, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 10 Dec 2015 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-include("ns.hrl"). +-include("jid.hrl"). +-include("xmpp_codec.hrl"). +-ifdef(NO_EXT_LIB). +-include("fxml.hrl"). +-else. +-include_lib("fast_xml/include/fxml.hrl"). +-endif. + +-type iq_type() :: get | set | result | error. +-type message_type() :: chat | error | groupchat | headline | normal. +-type presence_type() :: available | error | probe | subscribe | + subscribed | unavailable | unsubscribe | + unsubscribed. + +-type stanza() :: iq() | presence() | message(). + +-define(is_stanza(Pkt), + (is_record(Pkt, iq) or + is_record(Pkt, message) or + is_record(Pkt, presence))). diff --git a/tools/xmpp_codec.hrl b/include/xmpp_codec.hrl similarity index 55% rename from tools/xmpp_codec.hrl rename to include/xmpp_codec.hrl index 6d4b750b6..64a185a30 100644 --- a/tools/xmpp_codec.hrl +++ b/include/xmpp_codec.hrl @@ -1,179 +1,249 @@ %% Created automatically by XML generator (fxml_gen.erl) %% Source: xmpp_codec.spec +-record(vcard_xupdate, {us :: {binary(), binary()}, + hash :: binary()}). +-type vcard_xupdate() :: #vcard_xupdate{}. + -record(chatstate, {type :: active | composing | gone | inactive | paused}). +-type chatstate() :: #chatstate{}. -record(csi, {type :: active | inactive}). +-type csi() :: #csi{}. + +-record(hint, {type :: 'no-copy' | 'no-store' | 'store' | 'no-permanent-store'}). +-type hint() :: #hint{}. -record(feature_register, {}). +-type feature_register() :: #feature_register{}. -record(sasl_success, {text :: any()}). +-type sasl_success() :: #sasl_success{}. -record(mam_result, {xmlns :: binary(), queryid :: binary(), id :: binary(), sub_els = [] :: [any()]}). +-type mam_result() :: #mam_result{}. -record(rsm_first, {index :: non_neg_integer(), data :: binary()}). +-type rsm_first() :: #rsm_first{}. -record(text, {lang :: binary(), data :: binary()}). +-type text() :: #text{}. -record(streamhost, {jid :: any(), host :: binary(), port = 1080 :: non_neg_integer()}). +-type streamhost() :: #streamhost{}. -record(sm_resume, {h :: non_neg_integer(), previd :: binary(), xmlns :: binary()}). +-type sm_resume() :: #sm_resume{}. -record(carbons_enable, {}). +-type carbons_enable() :: #carbons_enable{}. -record(carbons_private, {}). +-type carbons_private() :: #carbons_private{}. -record(pubsub_unsubscribe, {node :: binary(), jid :: any(), subid :: binary()}). +-type pubsub_unsubscribe() :: #pubsub_unsubscribe{}. -record(mix_leave, {}). +-type mix_leave() :: #mix_leave{}. -record(ping, {}). +-type ping() :: #ping{}. -record(delay, {stamp :: any(), - from :: any()}). + from :: any(), + desc = <<>> :: binary()}). +-type delay() :: #delay{}. -record(muc_history, {maxchars :: non_neg_integer(), maxstanzas :: non_neg_integer(), seconds :: non_neg_integer(), since :: any()}). +-type muc_history() :: #muc_history{}. -record(pubsub_affiliation, {node :: binary(), type :: 'member' | 'none' | 'outcast' | 'owner' | 'publish-only' | 'publisher'}). +-type pubsub_affiliation() :: #pubsub_affiliation{}. -record(muc_decline, {reason :: binary(), from :: any(), to :: any()}). +-type muc_decline() :: #muc_decline{}. -record(sm_a, {h :: non_neg_integer(), xmlns :: binary()}). +-type sm_a() :: #sm_a{}. -record(starttls_proceed, {}). +-type starttls_proceed() :: #starttls_proceed{}. -record(sm_resumed, {h :: non_neg_integer(), previd :: binary(), xmlns :: binary()}). +-type sm_resumed() :: #sm_resumed{}. -record(forwarded, {delay :: #delay{}, sub_els = [] :: [any()]}). +-type forwarded() :: #forwarded{}. -record(sm_enable, {max :: non_neg_integer(), resume = false :: any(), xmlns :: binary()}). +-type sm_enable() :: #sm_enable{}. -record(starttls_failure, {}). +-type starttls_failure() :: #starttls_failure{}. -record(sasl_challenge, {text :: any()}). +-type sasl_challenge() :: #sasl_challenge{}. -record(gone, {uri :: binary()}). +-type gone() :: #gone{}. -record(private, {xml_els = [] :: [any()]}). +-type private() :: #private{}. -record(p1_ack, {}). +-type p1_ack() :: #p1_ack{}. -record(feature_sm, {xmlns :: binary()}). +-type feature_sm() :: #feature_sm{}. -record(pubsub_item, {id :: binary(), xml_els = [] :: [any()]}). +-type pubsub_item() :: #pubsub_item{}. -record(pubsub_publish, {node :: binary(), items = [] :: [#pubsub_item{}]}). +-type pubsub_publish() :: #pubsub_publish{}. -record(roster_item, {jid :: any(), - name :: binary(), + name = <<>> :: binary(), groups = [] :: [binary()], subscription = none :: 'both' | 'from' | 'none' | 'remove' | 'to', ask :: 'subscribe'}). +-type roster_item() :: #roster_item{}. --record(roster, {items = [] :: [#roster_item{}], - ver :: binary()}). +-record(roster_query, {items = [] :: [#roster_item{}], + ver :: binary()}). +-type roster_query() :: #roster_query{}. -record(pubsub_event_item, {id :: binary(), node :: binary(), publisher :: binary(), xml_els = [] :: [any()]}). +-type pubsub_event_item() :: #pubsub_event_item{}. -record(sm_r, {xmlns :: binary()}). +-type sm_r() :: #sm_r{}. -record(muc_actor, {jid :: any(), nick :: binary()}). +-type muc_actor() :: #muc_actor{}. -record(stat, {name :: binary(), units :: binary(), value :: binary(), error = [] :: [{integer(),'undefined' | binary()}]}). +-type stat() :: #stat{}. -record('see-other-host', {host :: binary()}). +-type 'see-other-host'() :: #'see-other-host'{}. -record(compress, {methods = [] :: [binary()]}). +-type compress() :: #compress{}. -record(starttls, {required = false :: boolean()}). +-type starttls() :: #starttls{}. -record(last, {seconds :: non_neg_integer(), - text :: binary()}). + status = <<>> :: binary()}). +-type last() :: #last{}. -record(redirect, {uri :: binary()}). +-type redirect() :: #redirect{}. -record(sm_enabled, {id :: binary(), location :: binary(), max :: non_neg_integer(), resume = false :: any(), xmlns :: binary()}). +-type sm_enabled() :: #sm_enabled{}. -record(pubsub_event_items, {node :: binary(), retract = [] :: [binary()], items = [] :: [#pubsub_event_item{}]}). +-type pubsub_event_items() :: #pubsub_event_items{}. -record(pubsub_event, {items = [] :: [#pubsub_event_items{}]}). +-type pubsub_event() :: #pubsub_event{}. -record(sasl_response, {text :: any()}). +-type sasl_response() :: #sasl_response{}. + +-record(legacy_auth, {username :: 'none' | binary(), + password :: 'none' | binary(), + digest :: 'none' | binary(), + resource :: 'none' | binary()}). +-type legacy_auth() :: #legacy_auth{}. -record(pubsub_subscribe, {node :: binary(), jid :: any()}). +-type pubsub_subscribe() :: #pubsub_subscribe{}. -record(sasl_auth, {mechanism :: binary(), text :: any()}). +-type sasl_auth() :: #sasl_auth{}. -record(p1_push, {}). +-type p1_push() :: #p1_push{}. -record(feature_csi, {xmlns :: binary()}). +-type feature_csi() :: #feature_csi{}. -record(muc_user_destroy, {reason :: binary(), jid :: any()}). +-type muc_user_destroy() :: #muc_user_destroy{}. -record(disco_item, {jid :: any(), name :: binary(), node :: binary()}). +-type disco_item() :: #disco_item{}. -record(disco_items, {node :: binary(), items = [] :: [#disco_item{}]}). +-type disco_items() :: #disco_items{}. -record(unblock, {items = [] :: [any()]}). +-type unblock() :: #unblock{}. -record(block, {items = [] :: [any()]}). - --record(session, {}). +-type block() :: #block{}. -record(compression, {methods = [] :: [binary()]}). +-type compression() :: #compression{}. -record(muc_owner_destroy, {jid :: any(), reason :: binary(), password :: binary()}). +-type muc_owner_destroy() :: #muc_owner_destroy{}. -record(pubsub_subscription, {jid :: any(), node :: binary(), subid :: binary(), type :: 'none' | 'pending' | 'subscribed' | 'unconfigured'}). +-type pubsub_subscription() :: #pubsub_subscription{}. -record(muc_item, {actor :: #muc_actor{}, continue :: binary(), @@ -182,42 +252,57 @@ role :: 'moderator' | 'none' | 'participant' | 'visitor', jid :: any(), nick :: binary()}). +-type muc_item() :: #muc_item{}. -record(muc_admin, {items = [] :: [#muc_item{}]}). +-type muc_admin() :: #muc_admin{}. -record(shim, {headers = [] :: [{binary(),'undefined' | binary()}]}). +-type shim() :: #shim{}. -record(mam_prefs, {xmlns :: binary(), default :: 'always' | 'never' | 'roster', always = [] :: [any()], never = [] :: [any()]}). +-type mam_prefs() :: #mam_prefs{}. --record(caps, {hash :: binary(), - node :: binary(), - ver :: any()}). +-record(caps, {node :: binary(), + version :: binary(), + hash :: binary(), + exts = [] :: any()}). +-type caps() :: #caps{}. -record(muc, {history :: #muc_history{}, password :: binary()}). +-type muc() :: #muc{}. -record(stream_features, {sub_els = [] :: [any()]}). +-type stream_features() :: #stream_features{}. -record(stats, {stat = [] :: [#stat{}]}). +-type stats() :: #stats{}. -record(pubsub_items, {node :: binary(), max_items :: non_neg_integer(), subid :: binary(), items = [] :: [#pubsub_item{}]}). +-type pubsub_items() :: #pubsub_items{}. -record(carbons_sent, {forwarded :: #forwarded{}}). +-type carbons_sent() :: #carbons_sent{}. -record(mam_archived, {by :: any(), id :: binary()}). +-type mam_archived() :: #mam_archived{}. -record(p1_rebind, {}). +-type p1_rebind() :: #p1_rebind{}. -record(compress_failure, {reason :: 'processing-failed' | 'setup-failed' | 'unsupported-method'}). +-type compress_failure() :: #compress_failure{}. -record(sasl_abort, {}). +-type sasl_abort() :: #sasl_abort{}. -record(vcard_email, {home = false :: boolean(), work = false :: boolean(), @@ -225,25 +310,33 @@ pref = false :: boolean(), x400 = false :: boolean(), userid :: binary()}). +-type vcard_email() :: #vcard_email{}. -record(carbons_received, {forwarded :: #forwarded{}}). +-type carbons_received() :: #carbons_received{}. -record(pubsub_retract, {node :: binary(), notify = false :: any(), items = [] :: [#pubsub_item{}]}). +-type pubsub_retract() :: #pubsub_retract{}. -record(mix_participant, {jid :: any(), nick :: binary()}). +-type mix_participant() :: #mix_participant{}. -record(vcard_geo, {lat :: binary(), lon :: binary()}). +-type vcard_geo() :: #vcard_geo{}. -record(compressed, {}). +-type compressed() :: #compressed{}. --record(sasl_failure, {reason :: 'aborted' | 'account-disabled' | 'credentials-expired' | 'encryption-required' | 'incorrect-encoding' | 'invalid-authzid' | 'invalid-mechanism' | 'malformed-request' | 'mechanism-too-weak' | 'not-authorized' | 'temporary-auth-failure', +-record(sasl_failure, {reason :: 'aborted' | 'account-disabled' | 'bad-protocol' | 'credentials-expired' | 'encryption-required' | 'incorrect-encoding' | 'invalid-authzid' | 'invalid-mechanism' | 'malformed-request' | 'mechanism-too-weak' | 'not-authorized' | 'temporary-auth-failure', text = [] :: [#text{}]}). +-type sasl_failure() :: #sasl_failure{}. -record(block_list, {}). +-type block_list() :: #block_list{}. -record(xdata_field, {label :: binary(), type :: 'boolean' | 'fixed' | 'hidden' | 'jid-multi' | 'jid-single' | 'list-multi' | 'list-single' | 'text-multi' | 'text-private' | 'text-single', @@ -252,17 +345,24 @@ desc :: binary(), values = [] :: [binary()], options = [] :: [binary()]}). +-type xdata_field() :: #xdata_field{}. -record(version, {name :: binary(), ver :: binary(), os :: binary()}). +-type version() :: #version{}. -record(muc_invite, {reason :: binary(), from :: any(), to :: any()}). +-type muc_invite() :: #muc_invite{}. -record(bind, {jid :: any(), resource :: any()}). +-type bind() :: #bind{}. + +-record(rosterver_feature, {}). +-type rosterver_feature() :: #rosterver_feature{}. -record(muc_user, {decline :: #muc_decline{}, destroy :: #muc_user_destroy{}, @@ -270,10 +370,10 @@ items = [] :: [#muc_item{}], status_codes = [] :: [pos_integer()], password :: binary()}). - --record(vcard_xupdate, {photo :: binary()}). +-type muc_user() :: #muc_user{}. -record(carbons_disable, {}). +-type carbons_disable() :: #carbons_disable{}. -record(bytestreams, {hosts = [] :: [#streamhost{}], used :: any(), @@ -281,9 +381,11 @@ dstaddr :: binary(), mode = tcp :: 'tcp' | 'udp', sid :: binary()}). +-type bytestreams() :: #bytestreams{}. -record(vcard_org, {name :: binary(), units = [] :: [binary()]}). +-type vcard_org() :: #vcard_org{}. -record(rsm_set, {'after' :: binary(), before :: 'none' | binary(), @@ -292,11 +394,13 @@ index :: non_neg_integer(), last :: binary(), max :: non_neg_integer()}). +-type rsm_set() :: #rsm_set{}. -record(mam_fin, {id :: binary(), rsm :: #rsm_set{}, stable :: any(), complete :: any()}). +-type mam_fin() :: #mam_fin{}. -record(vcard_tel, {home = false :: boolean(), work = false :: boolean(), @@ -312,40 +416,52 @@ pcs = false :: boolean(), pref = false :: boolean(), number :: binary()}). +-type vcard_tel() :: #vcard_tel{}. -record(vcard_key, {type :: binary(), cred :: binary()}). +-type vcard_key() :: #vcard_key{}. -record(vcard_name, {family :: binary(), given :: binary(), middle :: binary(), prefix :: binary(), suffix :: binary()}). +-type vcard_name() :: #vcard_name{}. -record(identity, {category :: binary(), type :: binary(), lang :: binary(), name :: binary()}). +-type identity() :: #identity{}. -record(bookmark_conference, {name :: binary(), jid :: any(), autojoin = false :: any(), nick :: binary(), password :: binary()}). +-type bookmark_conference() :: #bookmark_conference{}. + +-record(xmpp_session, {optional = false :: boolean()}). +-type xmpp_session() :: #xmpp_session{}. -record(bookmark_url, {name :: binary(), url :: binary()}). +-type bookmark_url() :: #bookmark_url{}. -record(bookmark_storage, {conference = [] :: [#bookmark_conference{}], url = [] :: [#bookmark_url{}]}). +-type bookmark_storage() :: #bookmark_storage{}. -record(vcard_sound, {phonetic :: binary(), binval :: any(), extval :: binary()}). +-type vcard_sound() :: #vcard_sound{}. -record(vcard_photo, {type :: binary(), binval :: any(), extval :: binary()}). +-type vcard_photo() :: #vcard_photo{}. -record(vcard_label, {home = false :: boolean(), work = false :: boolean(), @@ -355,6 +471,7 @@ intl = false :: boolean(), pref = false :: boolean(), line = [] :: [binary()]}). +-type vcard_label() :: #vcard_label{}. -record(vcard_adr, {home = false :: boolean(), work = false :: boolean(), @@ -370,6 +487,14 @@ region :: binary(), pcode :: binary(), ctry :: binary()}). +-type vcard_adr() :: #vcard_adr{}. + +-record(search_item, {jid :: any(), + first :: binary(), + last :: binary(), + nick :: binary(), + email :: binary()}). +-type search_item() :: #search_item{}. -record(xdata, {type :: 'cancel' | 'form' | 'result' | 'submit', instructions = [] :: [binary()], @@ -377,6 +502,16 @@ reported :: [#xdata_field{}], items = [] :: [[#xdata_field{}]], fields = [] :: [#xdata_field{}]}). +-type xdata() :: #xdata{}. + +-record(search, {instructions :: binary(), + first :: binary(), + last :: binary(), + nick :: binary(), + email :: binary(), + items = [] :: [#search_item{}], + xdata :: #xdata{}}). +-type search() :: #search{}. -record(mam_query, {xmlns :: binary(), id :: binary(), @@ -385,14 +520,17 @@ with :: any(), rsm :: #rsm_set{}, xdata :: #xdata{}}). +-type mam_query() :: #mam_query{}. -record(muc_owner, {destroy :: #muc_owner_destroy{}, config :: #xdata{}}). +-type muc_owner() :: #muc_owner{}. -record(pubsub_options, {node :: binary(), jid :: any(), subid :: binary(), xdata :: #xdata{}}). +-type pubsub_options() :: #pubsub_options{}. -record(pubsub, {subscriptions :: {'none' | binary(),[#pubsub_subscription{}]}, affiliations :: [#pubsub_affiliation{}], @@ -402,6 +540,7 @@ options :: #pubsub_options{}, items :: #pubsub_items{}, retract :: #pubsub_retract{}}). +-type pubsub() :: #pubsub{}. -record(register, {registered = false :: boolean(), remove = false :: boolean(), @@ -424,32 +563,40 @@ text :: 'none' | binary(), key :: 'none' | binary(), xdata :: #xdata{}}). +-type register() :: #register{}. -record(disco_info, {node :: binary(), identities = [] :: [#identity{}], features = [] :: [binary()], xdata = [] :: [#xdata{}]}). +-type disco_info() :: #disco_info{}. -record(offline_item, {node :: binary(), action :: 'remove' | 'view'}). +-type offline_item() :: #offline_item{}. -record(offline, {items = [] :: [#offline_item{}], purge = false :: boolean(), fetch = false :: boolean()}). +-type offline() :: #offline{}. -record(sasl_mechanisms, {list = [] :: [binary()]}). +-type sasl_mechanisms() :: #sasl_mechanisms{}. -record(sm_failed, {reason :: atom() | #gone{} | #redirect{}, h :: non_neg_integer(), xmlns :: binary()}). +-type sm_failed() :: #sm_failed{}. -record(error, {type :: 'auth' | 'cancel' | 'continue' | 'modify' | 'wait', + code :: non_neg_integer(), by :: binary(), reason :: atom() | #gone{} | #redirect{}, text :: #text{}}). +-type error() :: #error{}. -record(presence, {id :: binary(), - type :: 'error' | 'probe' | 'subscribe' | 'subscribed' | 'unavailable' | 'unsubscribe' | 'unsubscribed', + type = available :: 'available' | 'error' | 'probe' | 'subscribe' | 'subscribed' | 'unavailable' | 'unsubscribe' | 'unsubscribed', lang :: binary(), from :: any(), to :: any(), @@ -458,6 +605,7 @@ priority :: integer(), error :: #error{}, sub_els = [] :: [any()]}). +-type presence() :: #presence{}. -record(message, {id :: binary(), type = normal :: 'chat' | 'error' | 'groupchat' | 'headline' | 'normal', @@ -469,6 +617,7 @@ thread :: binary(), error :: #error{}, sub_els = [] :: [any()]}). +-type message() :: #message{}. -record(iq, {id :: binary(), type :: 'error' | 'get' | 'result' | 'set', @@ -477,61 +626,203 @@ to :: any(), error :: #error{}, sub_els = [] :: [any()]}). +-type iq() :: #iq{}. -record(mix_join, {jid :: any(), subscribe = [] :: [binary()]}). +-type mix_join() :: #mix_join{}. -record(privacy_item, {order :: non_neg_integer(), action :: 'allow' | 'deny', type :: 'group' | 'jid' | 'subscription', value :: binary(), - kinds = [] :: ['iq' | 'message' | 'presence-in' | 'presence-out']}). + message = false :: boolean(), + iq = false :: boolean(), + presence_in = false :: boolean(), + presence_out = false :: boolean()}). +-type privacy_item() :: #privacy_item{}. -record(privacy_list, {name :: binary(), items = [] :: [#privacy_item{}]}). +-type privacy_list() :: #privacy_list{}. --record(privacy, {lists = [] :: [#privacy_list{}], - default :: 'none' | binary(), - active :: 'none' | binary()}). +-record(privacy_query, {lists = [] :: [#privacy_list{}], + default :: 'none' | binary(), + active :: 'none' | binary()}). +-type privacy_query() :: #privacy_query{}. -record(stream_error, {reason :: atom() | #'see-other-host'{}, text :: #text{}}). +-type stream_error() :: #stream_error{}. -record(vcard_logo, {type :: binary(), binval :: any(), extval :: binary()}). +-type vcard_logo() :: #vcard_logo{}. --record(vcard, {version :: binary(), - fn :: binary(), - n :: #vcard_name{}, - nickname :: binary(), - photo :: #vcard_photo{}, - bday :: binary(), - adr = [] :: [#vcard_adr{}], - label = [] :: [#vcard_label{}], - tel = [] :: [#vcard_tel{}], - email = [] :: [#vcard_email{}], - jabberid :: binary(), - mailer :: binary(), - tz :: binary(), - geo :: #vcard_geo{}, - title :: binary(), - role :: binary(), - logo :: #vcard_logo{}, - org :: #vcard_org{}, - categories = [] :: [binary()], - note :: binary(), - prodid :: binary(), - rev :: binary(), - sort_string :: binary(), - sound :: #vcard_sound{}, - uid :: binary(), - url :: binary(), - class :: 'confidential' | 'private' | 'public', - key :: #vcard_key{}, - desc :: binary()}). +-record(vcard_temp, {version :: binary(), + fn :: binary(), + n :: #vcard_name{}, + nickname :: binary(), + photo :: #vcard_photo{}, + bday :: binary(), + adr = [] :: [#vcard_adr{}], + label = [] :: [#vcard_label{}], + tel = [] :: [#vcard_tel{}], + email = [] :: [#vcard_email{}], + jabberid :: binary(), + mailer :: binary(), + tz :: binary(), + geo :: #vcard_geo{}, + title :: binary(), + role :: binary(), + logo :: #vcard_logo{}, + org :: #vcard_org{}, + categories = [] :: [binary()], + note :: binary(), + prodid :: binary(), + rev :: binary(), + sort_string :: binary(), + sound :: #vcard_sound{}, + uid :: binary(), + url :: binary(), + class :: 'confidential' | 'private' | 'public', + key :: #vcard_key{}, + desc :: binary()}). +-type vcard_temp() :: #vcard_temp{}. -record(time, {tzo :: any(), utc :: any()}). +-type time() :: #time{}. - +-type xmpp_element() :: compression() | + pubsub_subscription() | + version() | + pubsub_affiliation() | + muc_admin() | + mam_fin() | + sm_a() | + carbons_sent() | + mam_archived() | + p1_rebind() | + sasl_abort() | + carbons_received() | + pubsub_retract() | + mix_participant() | + compressed() | + block_list() | + rsm_set() | + 'see-other-host'() | + hint() | + starttls_proceed() | + sm_resumed() | + forwarded() | + privacy_list() | + text() | + vcard_org() | + shim() | + search_item() | + offline_item() | + feature_sm() | + pubsub_item() | + roster_item() | + pubsub_event_item() | + muc_item() | + vcard_temp() | + sasl_success() | + pubsub_event_items() | + disco_items() | + pubsub_options() | + compress() | + bytestreams() | + identity() | + feature_csi() | + muc_user_destroy() | + privacy_query() | + delay() | + muc_history() | + vcard_tel() | + vcard_logo() | + disco_info() | + vcard_geo() | + vcard_photo() | + feature_register() | + register() | + muc_owner() | + pubsub() | + sm_r() | + muc_actor() | + error() | + stream_error() | + muc_user() | + vcard_adr() | + carbons_private() | + mix_leave() | + muc_invite() | + rosterver_feature() | + vcard_xupdate() | + carbons_disable() | + bookmark_conference() | + offline() | + time() | + sasl_response() | + pubsub_subscribe() | + presence() | + message() | + sm_enable() | + starttls_failure() | + sasl_challenge() | + gone() | + private() | + compress_failure() | + sasl_failure() | + bookmark_storage() | + vcard_name() | + sm_resume() | + carbons_enable() | + pubsub_unsubscribe() | + muc_decline() | + chatstate() | + sasl_auth() | + p1_push() | + legacy_auth() | + search() | + pubsub_publish() | + unblock() | + p1_ack() | + block() | + mix_join() | + xmpp_session() | + xdata() | + iq() | + streamhost() | + bind() | + last() | + redirect() | + sm_enabled() | + pubsub_event() | + vcard_sound() | + mam_result() | + rsm_first() | + stat() | + xdata_field() | + sm_failed() | + ping() | + disco_item() | + privacy_item() | + caps() | + muc() | + stream_features() | + stats() | + pubsub_items() | + starttls() | + mam_prefs() | + sasl_mechanisms() | + vcard_key() | + csi() | + roster_query() | + muc_owner_destroy() | + mam_query() | + bookmark_url() | + vcard_email() | + vcard_label(). diff --git a/src/cyrsasl.erl b/src/cyrsasl.erl index a101e1380..46b23384e 100644 --- a/src/cyrsasl.erl +++ b/src/cyrsasl.erl @@ -73,8 +73,8 @@ -callback mech_step(any(), binary()) -> {ok, props()} | {ok, props(), binary()} | {continue, binary(), any()} | - {error, binary()} | - {error, binary(), binary()}. + {error, atom()} | + {error, atom(), binary()}. start() -> ets:new(sasl_mechanism, @@ -129,8 +129,8 @@ register_mechanism(Mechanism, Module, PasswordType) -> check_credentials(_State, Props) -> User = proplists:get_value(authzid, Props, <<>>), case jid:nodeprep(User) of - error -> {error, <<"not-authorized">>}; - <<"">> -> {error, <<"not-authorized">>}; + error -> {error, 'not-authorized'}; + <<"">> -> {error, 'not-authorized'}; _LUser -> ok end. @@ -159,6 +159,8 @@ server_new(Service, ServerFQDN, UserRealm, _SecFlags, check_password = CheckPassword, check_password_digest = CheckPasswordDigest}. +server_start(State, Mech, undefined) -> + server_start(State, Mech, <<"">>); server_start(State, Mech, ClientIn) -> case lists:member(Mech, listmech(State#sasl_state.myname)) @@ -174,11 +176,13 @@ server_start(State, Mech, ClientIn) -> server_step(State#sasl_state{mech_mod = Module, mech_state = MechState}, ClientIn); - _ -> {error, <<"no-mechanism">>} + _ -> {error, 'no-mechanism'} end; - false -> {error, <<"no-mechanism">>} + false -> {error, 'no-mechanism'} end. +server_step(State, undefined) -> + server_step(State, <<"">>); server_step(State, ClientIn) -> Module = State#sasl_state.mech_mod, MechState = State#sasl_state.mech_state, diff --git a/src/cyrsasl_digest.erl b/src/cyrsasl_digest.erl index 0d408fc48..150aa854c 100644 --- a/src/cyrsasl_digest.erl +++ b/src/cyrsasl_digest.erl @@ -80,7 +80,7 @@ mech_step(#state{step = 1, nonce = Nonce} = State, _) -> mech_step(#state{step = 3, nonce = Nonce} = State, ClientIn) -> case parse(ClientIn) of - bad -> {error, <<"bad-protocol">>}; + bad -> {error, 'bad-protocol'}; KeyVals -> DigestURI = proplists:get_value(<<"digest-uri">>, KeyVals, <<>>), UserName = proplists:get_value(<<"username">>, KeyVals, <<>>), @@ -92,11 +92,11 @@ mech_step(#state{step = 3, nonce = Nonce} = State, "seems invalid: ~p (checking for Host " "~p, FQDN ~p)", [DigestURI, State#state.host, State#state.hostfqdn]), - {error, <<"not-authorized">>, UserName}; + {error, 'not-authorized', UserName}; true -> AuthzId = proplists:get_value(<<"authzid">>, KeyVals, <<>>), case (State#state.get_password)(UserName) of - {false, _} -> {error, <<"not-authorized">>, UserName}; + {false, _} -> {error, 'not-authorized', UserName}; {Passwd, AuthModule} -> case (State#state.check_password)(UserName, UserName, <<"">>, proplists:get_value(<<"response">>, KeyVals, <<>>), @@ -116,8 +116,8 @@ mech_step(#state{step = 3, nonce = Nonce} = State, State#state{step = 5, auth_module = AuthModule, username = UserName, authzid = AuthzId}}; - false -> {error, <<"not-authorized">>, UserName}; - {false, _} -> {error, <<"not-authorized">>, UserName} + false -> {error, 'not-authorized', UserName}; + {false, _} -> {error, 'not-authorized', UserName} end end end @@ -134,7 +134,7 @@ mech_step(#state{step = 5, auth_module = AuthModule, {auth_module, AuthModule}]}; mech_step(A, B) -> ?DEBUG("SASL DIGEST: A ~p B ~p", [A, B]), - {error, <<"bad-protocol">>}. + {error, 'bad-protocol'}. parse(S) -> parse1(binary_to_list(S), "", []). diff --git a/src/cyrsasl_oauth.erl b/src/cyrsasl_oauth.erl index 16f1e3dfb..09d143ef5 100644 --- a/src/cyrsasl_oauth.erl +++ b/src/cyrsasl_oauth.erl @@ -52,9 +52,9 @@ mech_step(State, ClientIn) -> [{username, User}, {authzid, AuthzId}, {auth_module, ejabberd_oauth}]}; false -> - {error, <<"not-authorized">>, User} + {error, 'not-authorized', User} end; - _ -> {error, <<"bad-protocol">>} + _ -> {error, 'bad-protocol'} end. prepare(ClientIn) -> diff --git a/src/cyrsasl_plain.erl b/src/cyrsasl_plain.erl index 82d68f87f..8e9b32b99 100644 --- a/src/cyrsasl_plain.erl +++ b/src/cyrsasl_plain.erl @@ -50,9 +50,9 @@ mech_step(State, ClientIn) -> {ok, [{username, User}, {authzid, AuthzId}, {auth_module, AuthModule}]}; - _ -> {error, <<"not-authorized">>, User} + _ -> {error, 'not-authorized', User} end; - _ -> {error, <<"bad-protocol">>} + _ -> {error, 'bad-protocol'} end. prepare(ClientIn) -> diff --git a/src/cyrsasl_scram.erl b/src/cyrsasl_scram.erl index 18f52b48f..8643a8924 100644 --- a/src/cyrsasl_scram.erl +++ b/src/cyrsasl_scram.erl @@ -67,21 +67,21 @@ mech_step(#state{step = 2} = State, ClientIn) -> case re:split(ClientIn, <<",">>, [{return, binary}]) of [_CBind, _AuthorizationIdentity, _UserNameAttribute, _ClientNonceAttribute, ExtensionAttribute | _] when ExtensionAttribute /= [] -> - {error, <<"protocol-error-extension-not-supported">>}; + {error, 'protocol-error-extension-not-supported'}; [CBind, _AuthorizationIdentity, UserNameAttribute, ClientNonceAttribute | _] when (CBind == <<"y">>) or (CBind == <<"n">>) -> case parse_attribute(UserNameAttribute) of {error, Reason} -> {error, Reason}; {_, EscapedUserName} -> case unescape_username(EscapedUserName) of - error -> {error, <<"protocol-error-bad-username">>}; + error -> {error, 'protocol-error-bad-username'}; UserName -> case parse_attribute(ClientNonceAttribute) of {$r, ClientNonce} -> {Ret, _AuthModule} = (State#state.get_password)(UserName), case {Ret, jid:resourceprep(Ret)} of - {false, _} -> {error, <<"not-authorized">>, UserName}; - {_, error} when is_binary(Ret) -> ?WARNING_MSG("invalid plain password", []), {error, <<"not-authorized">>, UserName}; + {false, _} -> {error, 'not-authorized', UserName}; + {_, error} when is_binary(Ret) -> ?WARNING_MSG("invalid plain password", []), {error, 'not-authorized', UserName}; {Ret, _} -> {StoredKey, ServerKey, Salt, IterationCount} = if is_tuple(Ret) -> Ret; @@ -121,11 +121,11 @@ mech_step(#state{step = 2} = State, ClientIn) -> server_nonce = ServerNonce, username = UserName}} end; - _Else -> {error, <<"not-supported">>} + _Else -> {error, 'not-supported'} end end end; - _Else -> {error, <<"bad-protocol">>} + _Else -> {error, 'bad-protocol'} end; mech_step(#state{step = 4} = State, ClientIn) -> case str:tokens(ClientIn, <<",">>) of @@ -163,18 +163,18 @@ mech_step(#state{step = 4} = State, ClientIn) -> {authzid, State#state.username}], <<"v=", (jlib:encode_base64(ServerSignature))/binary>>}; - true -> {error, <<"bad-auth">>, State#state.username} + true -> {error, 'bad-auth', State#state.username} end; - _Else -> {error, <<"bad-protocol">>} + _Else -> {error, 'bad-protocol'} end; - {$r, _} -> {error, <<"bad-nonce">>}; - _Else -> {error, <<"bad-protocol">>} + {$r, _} -> {error, 'bad-nonce'}; + _Else -> {error, 'bad-protocol'} end; - true -> {error, <<"bad-channel-binding">>} + true -> {error, 'bad-channel-binding'} end; - _Else -> {error, <<"bad-protocol">>} + _Else -> {error, 'bad-protocol'} end; - _Else -> {error, <<"bad-protocol">>} + _Else -> {error, 'bad-protocol'} end. parse_attribute(Attribute) -> @@ -187,11 +187,11 @@ parse_attribute(Attribute) -> if SecondChar == $= -> String = str:substr(Attribute, 3), {lists:nth(1, AttributeS), String}; - true -> {error, <<"bad-format second char not equal sign">>} + true -> {error, 'bad-format-second-char-not-equal-sign'} end; - _Else -> {error, <<"bad-format first char not a letter">>} + _Else -> {error, 'bad-format-first-char-not-a-letter'} end; - true -> {error, <<"bad-format attribute too short">>} + true -> {error, 'bad-format-attribute-too-short'} end. unescape_username(<<"">>) -> <<"">>; diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 9ddb8511d..8d217a354 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -67,7 +67,8 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). +%%-include("legacy.hrl"). -include("mod_privacy.hrl"). @@ -117,6 +118,16 @@ ask_offline = true, lang = <<"">>}). +-type state_name() :: wait_for_stream | wait_for_auth | + wait_for_feature_request | wait_for_bind | + wait_for_sasl_response | wait_for_resume | + session_established. +-type state() :: #state{}. +-type fsm_stop() :: {stop, normal, state()}. +-type fsm_next() :: {next_state, state_name(), state(), non_neg_integer()}. +-type fsm_transition() :: fsm_stop() | fsm_next(). +-export_type([state/0]). + %-define(DBGFSM, true). -ifdef(DBGFSM). @@ -143,55 +154,13 @@ -define(STREAM_TRAILER, <<"">>). --define(INVALID_NS_ERR, ?SERR_INVALID_NAMESPACE). - --define(INVALID_XML_ERR, ?SERR_XML_NOT_WELL_FORMED). - --define(HOST_UNKNOWN_ERR, ?SERR_HOST_UNKNOWN). - --define(POLICY_VIOLATION_ERR(Lang, Text), - ?SERRT_POLICY_VIOLATION(Lang, Text)). - --define(INVALID_FROM, ?SERR_INVALID_FROM). - %% XEP-0198: --define(IS_STREAM_MGMT_TAG(Name), - (Name == <<"enable">>) or - (Name == <<"resume">>) or - (Name == <<"a">>) or - (Name == <<"r">>)). - --define(IS_SUPPORTED_MGMT_XMLNS(Xmlns), - (Xmlns == ?NS_STREAM_MGMT_2) or - (Xmlns == ?NS_STREAM_MGMT_3)). - --define(MGMT_FAILED(Condition, Attrs), - #xmlel{name = <<"failed">>, - attrs = Attrs, - children = [#xmlel{name = Condition, - attrs = [{<<"xmlns">>, ?NS_STANZAS}], - children = []}]}). - --define(MGMT_BAD_REQUEST(Xmlns), - ?MGMT_FAILED(<<"bad-request">>, [{<<"xmlns">>, Xmlns}])). - --define(MGMT_SERVICE_UNAVAILABLE(Xmlns), - ?MGMT_FAILED(<<"service-unavailable">>, [{<<"xmlns">>, Xmlns}])). - --define(MGMT_UNEXPECTED_REQUEST(Xmlns), - ?MGMT_FAILED(<<"unexpected-request">>, [{<<"xmlns">>, Xmlns}])). - --define(MGMT_UNSUPPORTED_VERSION(Xmlns), - ?MGMT_FAILED(<<"unsupported-version">>, [{<<"xmlns">>, Xmlns}])). - --define(MGMT_ITEM_NOT_FOUND(Xmlns), - ?MGMT_FAILED(<<"item-not-found">>, [{<<"xmlns">>, Xmlns}])). - --define(MGMT_ITEM_NOT_FOUND_H(Xmlns, NumStanzasIn), - ?MGMT_FAILED(<<"item-not-found">>, - [{<<"xmlns">>, Xmlns}, - {<<"h">>, jlib:integer_to_binary(NumStanzasIn)}])). +-define(IS_STREAM_MGMT_PACKET(Pkt), + is_record(Pkt, sm_enable) or + is_record(Pkt, sm_resume) or + is_record(Pkt, sm_a) or + is_record(Pkt, sm_r)). %%%---------------------------------------------------------------------- %%% API @@ -213,21 +182,25 @@ get_presence(FsmRef) -> (?GEN_FSM):sync_send_all_state_event(FsmRef, {get_presence}, 1000). +-spec get_aux_field(any(), state()) -> {ok, any()} | error. get_aux_field(Key, #state{aux_fields = Opts}) -> case lists:keysearch(Key, 1, Opts) of {value, {_, Val}} -> {ok, Val}; _ -> error end. +-spec set_aux_field(any(), any(), state()) -> state(). set_aux_field(Key, Val, #state{aux_fields = Opts} = State) -> Opts1 = lists:keydelete(Key, 1, Opts), State#state{aux_fields = [{Key, Val} | Opts1]}. +-spec del_aux_field(any(), state()) -> state(). del_aux_field(Key, #state{aux_fields = Opts} = State) -> Opts1 = lists:keydelete(Key, 1, Opts), State#state{aux_fields = Opts1}. +-spec get_subscription(jid() | ljid(), state()) -> both | from | to | none. get_subscription(From = #jid{}, StateData) -> get_subscription(jid:tolower(From), StateData); get_subscription(LFrom, StateData) -> @@ -244,14 +217,19 @@ get_subscription(LFrom, StateData) -> true -> none end. +-spec send_filtered(pid(), binary(), jid(), jid(), stanza()) -> any(). send_filtered(FsmRef, Feature, From, To, Packet) -> FsmRef ! {send_filtered, Feature, From, To, Packet}. +-spec broadcast(pid(), any(), jid(), stanza()) -> any(). broadcast(FsmRef, Type, From, Packet) -> FsmRef ! {broadcast, Type, From, Packet}. +-spec stop(pid()) -> any(). stop(FsmRef) -> (?GEN_FSM):send_event(FsmRef, stop). +-spec close(pid()) -> any(). +%% What is the difference between stop and close??? close(FsmRef) -> (?GEN_FSM):send_event(FsmRef, closed). %%%---------------------------------------------------------------------- @@ -336,6 +314,7 @@ init([{SockMod, Socket}, Opts]) -> mgmt_resend = ResendOnTimeout}, {ok, wait_for_stream, StateData, ?C2S_OPEN_TIMEOUT}. +-spec get_subscribed(pid()) -> [ljid()]. %% Return list of all available resources of contacts, get_subscribed(FsmRef) -> (?GEN_FSM):sync_send_all_state_event(FsmRef, @@ -399,15 +378,7 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> Mechs = case TLSEnabled or not TLSRequired of true -> - Ms = lists:map(fun (S) -> - #xmlel{name = <<"mechanism">>, - attrs = [], - children = [{xmlcdata, S}]} - end, - cyrsasl:listmech(Server)), - [#xmlel{name = <<"mechanisms">>, - attrs = [{<<"xmlns">>, ?NS_SASL}], - children = Ms}]; + [#sasl_mechanisms{list = cyrsasl:listmech(Server)}]; false -> [] end, @@ -417,11 +388,7 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> CompressFeature = case Zlib andalso ((SockMod == gen_tcp) orelse (SockMod == fast_tls)) of true -> - [#xmlel{name = <<"compression">>, - attrs = [{<<"xmlns">>, ?NS_FEATURE_COMPRESS}], - children = [#xmlel{name = <<"method">>, - attrs = [], - children = [{xmlcdata, <<"zlib">>}]}]}]; + [#compression{methods = [<<"zlib">>]}]; _ -> [] end, @@ -430,18 +397,7 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> (TLSEnabled == false) andalso (SockMod == gen_tcp) of true -> - case TLSRequired of - true -> - [#xmlel{name = <<"starttls">>, - attrs = [{<<"xmlns">>, ?NS_TLS}], - children = [#xmlel{name = <<"required">>, - attrs = [], - children = []}]}]; - _ -> - [#xmlel{name = <<"starttls">>, - attrs = [{<<"xmlns">>, ?NS_TLS}], - children = []}] - end; + [#starttls{required = TLSRequired}]; false -> [] end, @@ -449,9 +405,7 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> StreamFeatures = ejabberd_hooks:run_fold(c2s_stream_features, Server, StreamFeatures1, [Server]), send_element(StateData, - #xmlel{name = <<"stream:features">>, - attrs = [], - children = StreamFeatures}), + #stream_features{sub_els = StreamFeatures}), fsm_next_state(wait_for_feature_request, StateData#state{server = Server, sasl_state = SASLState, @@ -466,12 +420,8 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> StreamManagementFeature = case stream_mgmt_enabled(StateData) of true -> - [#xmlel{name = <<"sm">>, - attrs = [{<<"xmlns">>, ?NS_STREAM_MGMT_2}], - children = []}, - #xmlel{name = <<"sm">>, - attrs = [{<<"xmlns">>, ?NS_STREAM_MGMT_3}], - children = []}]; + [#feature_sm{xmlns = ?NS_STREAM_MGMT_2}, + #feature_sm{xmlns = ?NS_STREAM_MGMT_3}]; false -> [] end, @@ -483,21 +433,12 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> case Zlib andalso ((SockMod == gen_tcp) orelse (SockMod == fast_tls)) of true -> - [#xmlel{name = <<"compression">>, - attrs = [{<<"xmlns">>, ?NS_FEATURE_COMPRESS}], - children = [#xmlel{name = <<"method">>, - attrs = [], - children = [{xmlcdata, <<"zlib">>}]}]}]; + [#compression{methods = [<<"zlib">>]}]; _ -> [] end, - StreamFeatures1 = [#xmlel{name = <<"bind">>, - attrs = [{<<"xmlns">>, ?NS_BIND}], - children = []}, - #xmlel{name = <<"session">>, - attrs = [{<<"xmlns">>, ?NS_SESSION}], - children = - [#xmlel{name = <<"optional">>}]}] + StreamFeatures1 = + [#bind{}, #xmpp_session{optional = true}] ++ RosterVersioningFeature ++ StreamManagementFeature ++ @@ -507,16 +448,11 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> StreamFeatures = ejabberd_hooks:run_fold(c2s_stream_features, Server, StreamFeatures1, [Server]), send_element(StateData, - #xmlel{name = <<"stream:features">>, - attrs = [], - children = StreamFeatures}), + #stream_features{sub_els = StreamFeatures}), fsm_next_state(wait_for_bind, StateData#state{server = Server, lang = Lang}); _ -> - send_element(StateData, - #xmlel{name = <<"stream:features">>, - attrs = [], - children = []}), + send_element(StateData, #stream_features{}), fsm_next_state(session_established, StateData#state{server = Server, lang = Lang}) end @@ -525,9 +461,10 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> send_header(StateData, Server, <<"">>, DefaultLang), if not StateData#state.tls_enabled and StateData#state.tls_required -> - send_element(StateData, - ?POLICY_VIOLATION_ERR(Lang, - <<"Use of STARTTLS required">>)), + send_element( + StateData, + xmpp:serr_policy_violation( + <<"Use of STARTTLS required">>, Lang)), {stop, normal, StateData}; true -> fsm_next_state(wait_for_auth, @@ -541,183 +478,151 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> ?INFO_MSG("Connection attempt from blacklisted IP ~s: ~s", [jlib:ip_to_list(IP), LogReason]), send_header(StateData, Server, StreamVersion, DefaultLang), - send_element(StateData, ?POLICY_VIOLATION_ERR(Lang, ReasonT)), + send_element(StateData, xmpp:serr_policy_violation(ReasonT, Lang)), {stop, normal, StateData}; _ -> send_header(StateData, ?MYNAME, StreamVersion, DefaultLang), - send_element(StateData, ?HOST_UNKNOWN_ERR), + send_element(StateData, xmpp:serr_host_unknown()), {stop, normal, StateData} end; _ -> send_header(StateData, ?MYNAME, <<"">>, DefaultLang), - send_element(StateData, ?INVALID_NS_ERR), + send_element(StateData, xmpp:serr_invalid_namespace()), {stop, normal, StateData} end; wait_for_stream(timeout, StateData) -> {stop, normal, StateData}; wait_for_stream({xmlstreamelement, _}, StateData) -> - send_element(StateData, ?INVALID_XML_ERR), + send_element(StateData, xmpp:serr_not_well_formed()), {stop, normal, StateData}; wait_for_stream({xmlstreamend, _}, StateData) -> - send_element(StateData, ?INVALID_XML_ERR), + send_element(StateData, xmpp:serr_not_well_formed()), {stop, normal, StateData}; wait_for_stream({xmlstreamerror, _}, StateData) -> send_header(StateData, ?MYNAME, <<"1.0">>, <<"">>), - send_element(StateData, ?INVALID_XML_ERR), + send_element(StateData, xmpp:serr_not_well_formed()), {stop, normal, StateData}; wait_for_stream(closed, StateData) -> {stop, normal, StateData}; wait_for_stream(stop, StateData) -> {stop, normal, StateData}. -wait_for_auth({xmlstreamelement, #xmlel{name = Name} = El}, StateData) - when ?IS_STREAM_MGMT_TAG(Name) -> - fsm_next_state(wait_for_auth, dispatch_stream_mgmt(El, StateData)); -wait_for_auth({xmlstreamelement, El}, StateData) -> - case is_auth_packet(El) of - {auth, _ID, get, {U, _, _, _}} -> - #xmlel{name = Name, attrs = Attrs} = jlib:make_result_iq_reply(El), - case U of - <<"">> -> UCdata = []; - _ -> UCdata = [{xmlcdata, U}] - end, - Res = case - ejabberd_auth:plain_password_required(StateData#state.server) - of - false -> - #xmlel{name = Name, attrs = Attrs, - children = - [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_AUTH}], - children = - [#xmlel{name = <<"username">>, - attrs = [], - children = UCdata}, - #xmlel{name = <<"password">>, - attrs = [], children = []}, - #xmlel{name = <<"digest">>, - attrs = [], children = []}, - #xmlel{name = <<"resource">>, - attrs = [], - children = []}]}]}; - true -> - #xmlel{name = Name, attrs = Attrs, - children = - [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_AUTH}], - children = - [#xmlel{name = <<"username">>, - attrs = [], - children = UCdata}, - #xmlel{name = <<"password">>, - attrs = [], children = []}, - #xmlel{name = <<"resource">>, - attrs = [], - children = []}]}]} - end, - send_element(StateData, Res), - fsm_next_state(wait_for_auth, StateData); - {auth, _ID, set, {_U, _P, _D, <<"">>}} -> - Lang = StateData#state.lang, - Txt = <<"No resource provided">>, - Err = jlib:make_error_reply(El, ?ERRT_NOT_ACCEPTABLE(Lang, Txt)), +wait_for_auth({xmlstreamelement, #xmlel{} = El}, StateData) -> + decode_element(El, wait_for_auth, StateData); +wait_for_auth(Pkt, StateData) when ?IS_STREAM_MGMT_PACKET(Pkt) -> + fsm_next_state(wait_for_auth, dispatch_stream_mgmt(Pkt, StateData)); +wait_for_auth(#iq{type = get, + sub_els = [#legacy_auth{username = U}]} = IQ, StateData) -> + Username = case U of + undefined -> none; + _ -> U + end, + Auth = #legacy_auth{username = Username, password = none, resource = none}, + Res = case ejabberd_auth:plain_password_required(StateData#state.server) of + false -> + xmpp:make_iq_result(IQ, Auth#legacy_auth{digest = none}); + true -> + xmpp:make_iq_result(IQ, Auth) + end, + send_element(StateData, Res), + fsm_next_state(wait_for_auth, StateData); +wait_for_auth(#iq{type = set, sub_els = [#legacy_auth{resource = <<"">>}]} = IQ, + StateData) -> + Lang = StateData#state.lang, + Txt = <<"No resource provided">>, + Err = xmpp:make_error(IQ, xmpp:err_not_acceptable(Txt, Lang)), + send_element(StateData, Err), + fsm_next_state(wait_for_auth, StateData); +wait_for_auth(#iq{type = set, sub_els = [#legacy_auth{username = U, + password = P0, + digest = D0, + resource = R}]} = IQ, + StateData) when is_binary(U), is_binary(R) -> + JID = jid:make(U, StateData#state.server, R), + case (JID /= error) andalso + acl:access_matches(StateData#state.access, + #{usr => jid:split(JID), ip => StateData#state.ip}, + StateData#state.server) == allow of + true -> + DGen = fun (PW) -> + p1_sha:sha(<<(StateData#state.streamid)/binary, PW/binary>>) + end, + P = if is_binary(P0) -> P0; true -> <<>> end, + D = if is_binary(D0) -> D0; true -> <<>> end, + case ejabberd_auth:check_password_with_authmodule( + U, U, StateData#state.server, P, D, DGen) of + {true, AuthModule} -> + ?INFO_MSG("(~w) Accepted legacy authentication for ~s by ~p from ~s", + [StateData#state.socket, + jid:to_string(JID), AuthModule, + ejabberd_config:may_hide_data(jlib:ip_to_list(StateData#state.ip))]), + ejabberd_hooks:run(c2s_auth_result, StateData#state.server, + [true, U, StateData#state.server, + StateData#state.ip]), + Conn = get_conn_type(StateData), + Info = [{ip, StateData#state.ip}, {conn, Conn}, + {auth_module, AuthModule}], + Res = xmpp:make_iq_result(IQ), + send_element(StateData, Res), + ejabberd_sm:open_session(StateData#state.sid, U, + StateData#state.server, R, + Info), + change_shaper(StateData, JID), + {Fs, Ts} = ejabberd_hooks:run_fold( + roster_get_subscription_lists, + StateData#state.server, + {[], []}, + [U, StateData#state.server]), + LJID = jid:tolower(jid:remove_resource(JID)), + Fs1 = [LJID | Fs], + Ts1 = [LJID | Ts], + PrivList = ejabberd_hooks:run_fold(privacy_get_user_list, + StateData#state.server, + #userlist{}, + [U, StateData#state.server]), + NewStateData = StateData#state{ + user = U, + resource = R, + jid = JID, + conn = Conn, + auth_module = AuthModule, + pres_f = (?SETS):from_list(Fs1), + pres_t = (?SETS):from_list(Ts1), + privacy_list = PrivList}, + fsm_next_state(session_established, NewStateData); + _ -> + ?INFO_MSG("(~w) Failed legacy authentication for ~s from ~s", + [StateData#state.socket, + jid:to_string(JID), + ejabberd_config:may_hide_data(jlib:ip_to_list(StateData#state.ip))]), + ejabberd_hooks:run(c2s_auth_result, StateData#state.server, + [false, U, StateData#state.server, + StateData#state.ip]), + Lang = StateData#state.lang, + Txt = <<"Legacy authentication failed">>, + Err = xmpp:make_error(IQ, xmpp:err_not_authorized(Txt, Lang)), + send_element(StateData, Err), + fsm_next_state(wait_for_auth, StateData) + end; + false when JID == error -> + ?INFO_MSG("(~w) Forbidden legacy authentication " + "for username '~s' with resource '~s'", + [StateData#state.socket, U, R]), + Err = xmpp:make_error(IQ, xmpp:err_jid_malformed()), send_element(StateData, Err), fsm_next_state(wait_for_auth, StateData); - {auth, _ID, set, {U, P, D, R}} -> - JID = jid:make(U, StateData#state.server, R), - case JID /= error andalso - acl:access_matches(StateData#state.access, - #{usr => jid:split(JID), ip => StateData#state.ip}, - StateData#state.server) == allow - of - true -> - DGen = fun (PW) -> - p1_sha:sha(<<(StateData#state.streamid)/binary, PW/binary>>) - end, - case ejabberd_auth:check_password_with_authmodule(U, U, - StateData#state.server, - P, D, DGen) - of - {true, AuthModule} -> - ?INFO_MSG("(~w) Accepted legacy authentication for ~s by ~p from ~s", - [StateData#state.socket, - jid:to_string(JID), AuthModule, - ejabberd_config:may_hide_data(jlib:ip_to_list(StateData#state.ip))]), - ejabberd_hooks:run(c2s_auth_result, StateData#state.server, - [true, U, StateData#state.server, - StateData#state.ip]), - Conn = get_conn_type(StateData), - Info = [{ip, StateData#state.ip}, {conn, Conn}, - {auth_module, AuthModule}], - Res = jlib:make_result_iq_reply( - El#xmlel{children = []}), - send_element(StateData, Res), - ejabberd_sm:open_session(StateData#state.sid, U, - StateData#state.server, R, - Info), - change_shaper(StateData, JID), - {Fs, Ts} = - ejabberd_hooks:run_fold(roster_get_subscription_lists, - StateData#state.server, - {[], []}, - [U, StateData#state.server]), - LJID = jid:tolower(jid:remove_resource(JID)), - Fs1 = [LJID | Fs], - Ts1 = [LJID | Ts], - PrivList = ejabberd_hooks:run_fold(privacy_get_user_list, - StateData#state.server, - #userlist{}, - [U, StateData#state.server]), - NewStateData = StateData#state{user = U, - resource = R, - jid = JID, - conn = Conn, - auth_module = AuthModule, - pres_f = (?SETS):from_list(Fs1), - pres_t = (?SETS):from_list(Ts1), - privacy_list = PrivList}, - fsm_next_state(session_established, NewStateData); - _ -> - ?INFO_MSG("(~w) Failed legacy authentication for ~s from ~s", - [StateData#state.socket, - jid:to_string(JID), - ejabberd_config:may_hide_data(jlib:ip_to_list(StateData#state.ip))]), - ejabberd_hooks:run(c2s_auth_result, StateData#state.server, - [false, U, StateData#state.server, - StateData#state.ip]), - Lang = StateData#state.lang, - Txt = <<"Legacy authentication failed">>, - Err = jlib:make_error_reply( - El, ?ERRT_NOT_AUTHORIZED(Lang, Txt)), - send_element(StateData, Err), - fsm_next_state(wait_for_auth, StateData) - end; - _ -> - if JID == error -> - ?INFO_MSG("(~w) Forbidden legacy authentication " - "for username '~s' with resource '~s'", - [StateData#state.socket, U, R]), - Err = jlib:make_error_reply(El, ?ERR_JID_MALFORMED), - send_element(StateData, Err), - fsm_next_state(wait_for_auth, StateData); - true -> - ?INFO_MSG("(~w) Forbidden legacy authentication " - "for ~s from ~s", - [StateData#state.socket, - jid:to_string(JID), - ejabberd_config:may_hide_data(jlib:ip_to_list(StateData#state.ip))]), - ejabberd_hooks:run(c2s_auth_result, StateData#state.server, - [false, U, StateData#state.server, - StateData#state.ip]), - Lang = StateData#state.lang, - Txt = <<"Legacy authentication forbidden">>, - Err = jlib:make_error_reply(El, ?ERRT_NOT_ALLOWED(Lang, Txt)), - send_element(StateData, Err), - fsm_next_state(wait_for_auth, StateData) - end - end; - _ -> - process_unauthenticated_stanza(StateData, El), + false -> + ?INFO_MSG("(~w) Forbidden legacy authentication for ~s from ~s", + [StateData#state.socket, + jid:to_string(JID), + ejabberd_config:may_hide_data(jlib:ip_to_list(StateData#state.ip))]), + ejabberd_hooks:run(c2s_auth_result, StateData#state.server, + [false, U, StateData#state.server, + StateData#state.ip]), + Lang = StateData#state.lang, + Txt = <<"Legacy authentication forbidden">>, + Err = xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)), + send_element(StateData, Err), fsm_next_state(wait_for_auth, StateData) end; wait_for_auth(timeout, StateData) -> @@ -725,127 +630,97 @@ wait_for_auth(timeout, StateData) -> wait_for_auth({xmlstreamend, _Name}, StateData) -> {stop, normal, StateData}; wait_for_auth({xmlstreamerror, _}, StateData) -> - send_element(StateData, ?INVALID_XML_ERR), + send_element(StateData, xmpp:serr_not_well_formed()), {stop, normal, StateData}; wait_for_auth(closed, StateData) -> {stop, normal, StateData}; wait_for_auth(stop, StateData) -> - {stop, normal, StateData}. + {stop, normal, StateData}; +wait_for_auth(Pkt, StateData) -> + process_unauthenticated_stanza(StateData, Pkt), + fsm_next_state(wait_for_auth, StateData). -wait_for_feature_request({xmlstreamelement, #xmlel{name = Name} = El}, - StateData) - when ?IS_STREAM_MGMT_TAG(Name) -> +wait_for_feature_request({xmlstreamelement, El}, StateData) -> + decode_element(El, wait_for_feature_request, StateData); +wait_for_feature_request(Pkt, StateData) when ?IS_STREAM_MGMT_PACKET(Pkt) -> fsm_next_state(wait_for_feature_request, - dispatch_stream_mgmt(El, StateData)); -wait_for_feature_request({xmlstreamelement, El}, - StateData) -> - #xmlel{name = Name, attrs = Attrs, children = Els} = El, + dispatch_stream_mgmt(Pkt, StateData)); +wait_for_feature_request(#sasl_auth{mechanism = Mech, + text = ClientIn}, + #state{tls_enabled = TLSEnabled, + tls_required = TLSRequired} = StateData) + when TLSEnabled or not TLSRequired -> + case cyrsasl:server_start(StateData#state.sasl_state, Mech, ClientIn) of + {ok, Props} -> + (StateData#state.sockmod):reset_stream(StateData#state.socket), + U = identity(Props), + AuthModule = proplists:get_value(auth_module, Props, undefined), + ?INFO_MSG("(~w) Accepted authentication for ~s by ~p from ~s", + [StateData#state.socket, U, AuthModule, + ejabberd_config:may_hide_data(jlib:ip_to_list(StateData#state.ip))]), + ejabberd_hooks:run(c2s_auth_result, StateData#state.server, + [true, U, StateData#state.server, + StateData#state.ip]), + send_element(StateData, #sasl_success{}), + fsm_next_state(wait_for_stream, + StateData#state{streamid = new_id(), + authenticated = true, + auth_module = AuthModule, + sasl_state = undefined, + user = U}); + {continue, ServerOut, NewSASLState} -> + send_element(StateData, #sasl_challenge{text = ServerOut}), + fsm_next_state(wait_for_sasl_response, + StateData#state{sasl_state = NewSASLState}); + {error, Error, Username} -> + ?INFO_MSG("(~w) Failed authentication for ~s@~s from ~s", + [StateData#state.socket, + Username, StateData#state.server, + ejabberd_config:may_hide_data(jlib:ip_to_list(StateData#state.ip))]), + ejabberd_hooks:run(c2s_auth_result, StateData#state.server, + [false, Username, StateData#state.server, + StateData#state.ip]), + send_element(StateData, #sasl_failure{reason = Error}), + fsm_next_state(wait_for_feature_request, StateData); + {error, Error} -> + send_element(StateData, #sasl_failure{reason = Error}), + fsm_next_state(wait_for_feature_request, StateData) + end; +wait_for_feature_request(#starttls{}, + #state{tls = true, tls_enabled = false} = StateData) -> + case (StateData#state.sockmod):get_sockmod(StateData#state.socket) of + gen_tcp -> + TLSOpts = case ejabberd_config:get_option( + {domain_certfile, StateData#state.server}, + fun iolist_to_binary/1) of + undefined -> + StateData#state.tls_options; + CertFile -> + lists:keystore(certfile, 1, + StateData#state.tls_options, + {certfile, CertFile}) + end, + Socket = StateData#state.socket, + BProceed = fxml:element_to_binary(xmpp:encode(#starttls_proceed{})), + TLSSocket = (StateData#state.sockmod):starttls(Socket, TLSOpts, BProceed), + fsm_next_state(wait_for_stream, + StateData#state{socket = TLSSocket, + streamid = new_id(), + tls_enabled = true}); + _ -> + Lang = StateData#state.lang, + Txt = <<"Unsupported TLS transport">>, + send_element(StateData, xmpp:serr_policy_violation(Txt, Lang)), + {stop, normal, StateData} + end; +wait_for_feature_request(#compress{} = Comp, StateData) -> Zlib = StateData#state.zlib, - TLS = StateData#state.tls, - TLSEnabled = StateData#state.tls_enabled, - TLSRequired = StateData#state.tls_required, - SockMod = - (StateData#state.sockmod):get_sockmod(StateData#state.socket), - case {fxml:get_attr_s(<<"xmlns">>, Attrs), Name} of - {?NS_SASL, <<"auth">>} - when TLSEnabled or not TLSRequired -> - Mech = fxml:get_attr_s(<<"mechanism">>, Attrs), - ClientIn = jlib:decode_base64(fxml:get_cdata(Els)), - case cyrsasl:server_start(StateData#state.sasl_state, - Mech, ClientIn) - of - {ok, Props} -> - (StateData#state.sockmod):reset_stream(StateData#state.socket), - U = identity(Props), - AuthModule = proplists:get_value(auth_module, Props, undefined), - ?INFO_MSG("(~w) Accepted authentication for ~s " - "by ~p from ~s", - [StateData#state.socket, U, AuthModule, - ejabberd_config:may_hide_data(jlib:ip_to_list(StateData#state.ip))]), - ejabberd_hooks:run(c2s_auth_result, StateData#state.server, - [true, U, StateData#state.server, - StateData#state.ip]), - send_element(StateData, - #xmlel{name = <<"success">>, - attrs = [{<<"xmlns">>, ?NS_SASL}], - children = []}), - fsm_next_state(wait_for_stream, - StateData#state{streamid = new_id(), - authenticated = true, - auth_module = AuthModule, - sasl_state = undefined, - user = U}); - {continue, ServerOut, NewSASLState} -> - send_element(StateData, - #xmlel{name = <<"challenge">>, - attrs = [{<<"xmlns">>, ?NS_SASL}], - children = - [{xmlcdata, - jlib:encode_base64(ServerOut)}]}), - fsm_next_state(wait_for_sasl_response, - StateData#state{sasl_state = NewSASLState}); - {error, Error, Username} -> - ?INFO_MSG("(~w) Failed authentication for ~s@~s from ~s", - [StateData#state.socket, - Username, StateData#state.server, - ejabberd_config:may_hide_data(jlib:ip_to_list(StateData#state.ip))]), - ejabberd_hooks:run(c2s_auth_result, StateData#state.server, - [false, Username, StateData#state.server, - StateData#state.ip]), - send_element(StateData, - #xmlel{name = <<"failure">>, - attrs = [{<<"xmlns">>, ?NS_SASL}], - children = - [#xmlel{name = Error, attrs = [], - children = []}]}), - fsm_next_state(wait_for_feature_request, StateData); - {error, Error} -> - send_element(StateData, - #xmlel{name = <<"failure">>, - attrs = [{<<"xmlns">>, ?NS_SASL}], - children = - [#xmlel{name = Error, attrs = [], - children = []}]}), - fsm_next_state(wait_for_feature_request, StateData) - end; - {?NS_TLS, <<"starttls">>} - when TLS == true, TLSEnabled == false, - SockMod == gen_tcp -> - TLSOpts = case - ejabberd_config:get_option( - {domain_certfile, StateData#state.server}, - fun iolist_to_binary/1) - of - undefined -> StateData#state.tls_options; - CertFile -> - [{certfile, CertFile} | lists:keydelete(certfile, 1, - StateData#state.tls_options)] - end, - Socket = StateData#state.socket, - BProceed = fxml:element_to_binary(#xmlel{name = <<"proceed">>, - attrs = [{<<"xmlns">>, ?NS_TLS}]}), - TLSSocket = (StateData#state.sockmod):starttls(Socket, - TLSOpts, - BProceed), - fsm_next_state(wait_for_stream, - StateData#state{socket = TLSSocket, - streamid = new_id(), - tls_enabled = true}); - {?NS_COMPRESS, <<"compress">>} - when Zlib == true, - (SockMod == gen_tcp) or (SockMod == fast_tls) -> - process_compression_request(El, wait_for_feature_request, StateData); - _ -> - if TLSRequired and not TLSEnabled -> - Lang = StateData#state.lang, - send_element(StateData, - ?POLICY_VIOLATION_ERR(Lang, - <<"Use of STARTTLS required">>)), - {stop, normal, StateData}; - true -> - process_unauthenticated_stanza(StateData, El), - fsm_next_state(wait_for_feature_request, StateData) - end + SockMod = (StateData#state.sockmod):get_sockmod(StateData#state.socket), + if Zlib == true, (SockMod == gen_tcp) or (SockMod == fast_tls) -> + process_compression_request(Comp, wait_for_feature_request, StateData); + true -> + send_element(StateData, #compress_failure{reason = 'setup-failed'}), + fsm_next_state(wait_for_feature_request, StateData) end; wait_for_feature_request(timeout, StateData) -> {stop, normal, StateData}; @@ -854,106 +729,82 @@ wait_for_feature_request({xmlstreamend, _Name}, {stop, normal, StateData}; wait_for_feature_request({xmlstreamerror, _}, StateData) -> - send_element(StateData, ?INVALID_XML_ERR), + send_element(StateData, xmpp:serr_not_well_formed()), {stop, normal, StateData}; wait_for_feature_request(closed, StateData) -> {stop, normal, StateData}; wait_for_feature_request(stop, StateData) -> - {stop, normal, StateData}. + {stop, normal, StateData}; +wait_for_feature_request(_Pkt, + #state{tls_required = TLSRequired, + tls_enabled = TLSEnabled} = StateData) + when TLSRequired and not TLSEnabled -> + Lang = StateData#state.lang, + Txt = <<"Use of STARTTLS required">>, + send_element(StateData, xmpp:serr_policy_violation(Txt, Lang)), + {stop, normal, StateData}; +wait_for_feature_request(Pkt, StateData) -> + process_unauthenticated_stanza(StateData, Pkt), + fsm_next_state(wait_for_feature_request, StateData). -wait_for_sasl_response({xmlstreamelement, #xmlel{name = Name} = El}, StateData) - when ?IS_STREAM_MGMT_TAG(Name) -> - fsm_next_state(wait_for_sasl_response, dispatch_stream_mgmt(El, StateData)); -wait_for_sasl_response({xmlstreamelement, El}, - StateData) -> - #xmlel{name = Name, attrs = Attrs, children = Els} = El, - case {fxml:get_attr_s(<<"xmlns">>, Attrs), Name} of - {?NS_SASL, <<"response">>} -> - ClientIn = jlib:decode_base64(fxml:get_cdata(Els)), - case cyrsasl:server_step(StateData#state.sasl_state, - ClientIn) - of - {ok, Props} -> - catch - (StateData#state.sockmod):reset_stream(StateData#state.socket), - U = identity(Props), - AuthModule = proplists:get_value(auth_module, Props, <<>>), - ?INFO_MSG("(~w) Accepted authentication for ~s " - "by ~p from ~s", - [StateData#state.socket, U, AuthModule, - ejabberd_config:may_hide_data(jlib:ip_to_list(StateData#state.ip))]), - ejabberd_hooks:run(c2s_auth_result, StateData#state.server, - [true, U, StateData#state.server, - StateData#state.ip]), - send_element(StateData, - #xmlel{name = <<"success">>, - attrs = [{<<"xmlns">>, ?NS_SASL}], - children = []}), - fsm_next_state(wait_for_stream, - StateData#state{streamid = new_id(), - authenticated = true, - auth_module = AuthModule, - sasl_state = undefined, - user = U}); - {ok, Props, ServerOut} -> - (StateData#state.sockmod):reset_stream(StateData#state.socket), - U = identity(Props), - AuthModule = proplists:get_value(auth_module, Props, undefined), - ?INFO_MSG("(~w) Accepted authentication for ~s " - "by ~p from ~s", - [StateData#state.socket, U, AuthModule, - ejabberd_config:may_hide_data(jlib:ip_to_list(StateData#state.ip))]), - ejabberd_hooks:run(c2s_auth_result, StateData#state.server, - [true, U, StateData#state.server, - StateData#state.ip]), - send_element(StateData, - #xmlel{name = <<"success">>, - attrs = [{<<"xmlns">>, ?NS_SASL}], - children = - [{xmlcdata, - jlib:encode_base64(ServerOut)}]}), - fsm_next_state(wait_for_stream, - StateData#state{streamid = new_id(), - authenticated = true, - auth_module = AuthModule, - sasl_state = undefined, - user = U}); - {continue, ServerOut, NewSASLState} -> - send_element(StateData, - #xmlel{name = <<"challenge">>, - attrs = [{<<"xmlns">>, ?NS_SASL}], - children = - [{xmlcdata, - jlib:encode_base64(ServerOut)}]}), - fsm_next_state(wait_for_sasl_response, - StateData#state{sasl_state = NewSASLState}); - {error, Error, Username} -> - ?INFO_MSG("(~w) Failed authentication for ~s@~s from ~s", - [StateData#state.socket, - Username, StateData#state.server, - ejabberd_config:may_hide_data(jlib:ip_to_list(StateData#state.ip))]), - ejabberd_hooks:run(c2s_auth_result, StateData#state.server, - [false, Username, StateData#state.server, - StateData#state.ip]), - send_element(StateData, - #xmlel{name = <<"failure">>, - attrs = [{<<"xmlns">>, ?NS_SASL}], - children = - [#xmlel{name = Error, attrs = [], - children = []}]}), - fsm_next_state(wait_for_feature_request, StateData); - {error, Error} -> - send_element(StateData, - #xmlel{name = <<"failure">>, - attrs = [{<<"xmlns">>, ?NS_SASL}], - children = - [#xmlel{name = Error, attrs = [], - children = []}]}), - fsm_next_state(wait_for_feature_request, StateData) - end; - _ -> - process_unauthenticated_stanza(StateData, El), - fsm_next_state(wait_for_feature_request, StateData) +wait_for_sasl_response({xmlstreamelement, El}, StateData) -> + decode_element(El, wait_for_sasl_response, StateData); +wait_for_sasl_response(Pkt, StateData) when ?IS_STREAM_MGMT_PACKET(Pkt) -> + fsm_next_state(wait_for_sasl_response, + dispatch_stream_mgmt(Pkt, StateData)); +wait_for_sasl_response(#sasl_response{text = ClientIn}, StateData) -> + case cyrsasl:server_step(StateData#state.sasl_state, ClientIn) of + {ok, Props} -> + catch (StateData#state.sockmod):reset_stream(StateData#state.socket), + U = identity(Props), + AuthModule = proplists:get_value(auth_module, Props, <<>>), + ?INFO_MSG("(~w) Accepted authentication for ~s by ~p from ~s", + [StateData#state.socket, U, AuthModule, + ejabberd_config:may_hide_data(jlib:ip_to_list(StateData#state.ip))]), + ejabberd_hooks:run(c2s_auth_result, StateData#state.server, + [true, U, StateData#state.server, + StateData#state.ip]), + send_element(StateData, #sasl_success{}), + fsm_next_state(wait_for_stream, + StateData#state{streamid = new_id(), + authenticated = true, + auth_module = AuthModule, + sasl_state = undefined, + user = U}); + {ok, Props, ServerOut} -> + (StateData#state.sockmod):reset_stream(StateData#state.socket), + U = identity(Props), + AuthModule = proplists:get_value(auth_module, Props, undefined), + ?INFO_MSG("(~w) Accepted authentication for ~s by ~p from ~s", + [StateData#state.socket, U, AuthModule, + ejabberd_config:may_hide_data(jlib:ip_to_list(StateData#state.ip))]), + ejabberd_hooks:run(c2s_auth_result, StateData#state.server, + [true, U, StateData#state.server, + StateData#state.ip]), + send_element(StateData, #sasl_success{text = ServerOut}), + fsm_next_state(wait_for_stream, + StateData#state{streamid = new_id(), + authenticated = true, + auth_module = AuthModule, + sasl_state = undefined, + user = U}); + {continue, ServerOut, NewSASLState} -> + send_element(StateData, #sasl_challenge{text = ServerOut}), + fsm_next_state(wait_for_sasl_response, + StateData#state{sasl_state = NewSASLState}); + {error, Error, Username} -> + ?INFO_MSG("(~w) Failed authentication for ~s@~s from ~s", + [StateData#state.socket, + Username, StateData#state.server, + ejabberd_config:may_hide_data(jlib:ip_to_list(StateData#state.ip))]), + ejabberd_hooks:run(c2s_auth_result, StateData#state.server, + [false, Username, StateData#state.server, + StateData#state.ip]), + send_element(StateData, #sasl_failure{reason = Error}), + fsm_next_state(wait_for_feature_request, StateData); + {error, Error} -> + send_element(StateData, #sasl_failure{reason = Error}), + fsm_next_state(wait_for_feature_request, StateData) end; wait_for_sasl_response(timeout, StateData) -> {stop, normal, StateData}; @@ -962,13 +813,18 @@ wait_for_sasl_response({xmlstreamend, _Name}, {stop, normal, StateData}; wait_for_sasl_response({xmlstreamerror, _}, StateData) -> - send_element(StateData, ?INVALID_XML_ERR), + send_element(StateData, xmpp:serr_not_well_formed()), {stop, normal, StateData}; wait_for_sasl_response(closed, StateData) -> {stop, normal, StateData}; wait_for_sasl_response(stop, StateData) -> - {stop, normal, StateData}. + {stop, normal, StateData}; +wait_for_sasl_response(Pkt, StateData) -> + process_unauthenticated_stanza(StateData, Pkt), + fsm_next_state(wait_for_feature_request, StateData). +-spec resource_conflict_action(binary(), binary(), binary()) -> + {accept_resource, binary()} | closenew. resource_conflict_action(U, S, R) -> OptionRaw = case ejabberd_sm:is_existing_resource(U, S, R) of true -> @@ -998,108 +854,116 @@ resource_conflict_action(U, S, R) -> {accept_resource, Rnew} end. -wait_for_bind({xmlstreamelement, #xmlel{name = Name, attrs = Attrs} = El}, - StateData) - when ?IS_STREAM_MGMT_TAG(Name) -> - case Name of - <<"resume">> -> - case handle_resume(StateData, Attrs) of - {ok, ResumedState} -> - fsm_next_state(session_established, ResumedState); - error -> - fsm_next_state(wait_for_bind, StateData) - end; - _ -> - fsm_next_state(wait_for_bind, dispatch_stream_mgmt(El, StateData)) - end; -wait_for_bind({xmlstreamelement, El}, StateData) -> - case jlib:iq_query_info(El) of - #iq{type = set, lang = Lang, xmlns = ?NS_BIND, sub_el = SubEl} = - IQ -> - U = StateData#state.user, - R1 = fxml:get_path_s(SubEl, - [{elem, <<"resource">>}, cdata]), - R = case jid:resourceprep(R1) of - error -> error; - <<"">> -> new_uniq_id(); - Resource -> Resource - end, - case R of - error -> - Txt = <<"Malformed resource">>, - Err = jlib:make_error_reply(El, ?ERRT_BAD_REQUEST(Lang, Txt)), - send_element(StateData, Err), - fsm_next_state(wait_for_bind, StateData); - _ -> - case resource_conflict_action(U, StateData#state.server, - R) - of - closenew -> - Err = jlib:make_error_reply(El, - ?STANZA_ERROR(<<"409">>, - <<"modify">>, - <<"conflict">>)), - send_element(StateData, Err), - fsm_next_state(wait_for_bind, StateData); - {accept_resource, R2} -> - JID = jid:make(U, StateData#state.server, R2), - StateData2 = - StateData#state{resource = R2, jid = JID}, - case open_session(StateData2) of - {ok, StateData3} -> - Res = - IQ#iq{ - type = result, - sub_el = - [#xmlel{name = <<"bind">>, - attrs = [{<<"xmlns">>, ?NS_BIND}], - children = - [#xmlel{name = <<"jid">>, - attrs = [], - children = - [{xmlcdata, - jid:to_string(JID)}]}]}]}, - try - send_element(StateData3, jlib:iq_to_xml(Res)) - catch exit:normal -> - close(self()) - end, - fsm_next_state_pack( - session_established, - StateData3); - {error, Error} -> - Err = jlib:make_error_reply(El, Error), - send_element(StateData, Err), - fsm_next_state(wait_for_bind, StateData) - end - end - end; - _ -> - #xmlel{name = Name, attrs = Attrs, children = _Els} = El, - Zlib = StateData#state.zlib, - SockMod = - (StateData#state.sockmod):get_sockmod(StateData#state.socket), - case {fxml:get_attr_s(<<"xmlns">>, Attrs), Name} of - {?NS_COMPRESS, <<"compress">>} - when Zlib == true, - (SockMod == gen_tcp) or (SockMod == fast_tls) -> - process_compression_request(El, wait_for_bind, StateData); +-spec decode_subels(stanza()) -> stanza(). +decode_subels(#iq{sub_els = [El], type = T} = IQ) when T == set; T == get -> + NewEl = case xmpp:get_ns(El) of + ?NS_BIND when T == set -> xmpp:decode(El); + ?NS_AUTH -> xmpp:decode(El); + ?NS_PRIVACY -> xmpp:decode(El); + ?NS_BLOCKING -> xmpp:decode(El); + _ -> El + end, + IQ#iq{sub_els = [NewEl]}; +decode_subels(Pkt) -> + Pkt. + +-spec decode_element(xmlel(), state_name(), state()) -> fsm_next(). +decode_element(#xmlel{} = El, StateName, StateData) -> + try + Pkt0 = xmpp:decode(El, [ignore_els]), + Pkt = decode_subels(Pkt0), + ?MODULE:StateName(Pkt, StateData) + catch error:{xmpp_codec, Why} -> + Type = xmpp:get_type(El), + NS = xmpp:get_ns(El), + case xmpp:is_stanza(El) of + true when Type /= <<"result">>, Type /= <<"error">> -> + Lang = xmpp:get_lang(El), + Txt = xmpp:format_error(Why), + Err = xmpp:make_error(El, xmpp:err_bad_request(Txt, Lang)), + send_element(StateData, Err); + _ when NS == ?NS_STREAM_MGMT_2; NS == ?NS_STREAM_MGMT_3 -> + Err = #sm_failed{reason = 'bad-request', xmlns = NS}, + send_element(StateData, Err); _ -> + ok + end, + fsm_next_state(StateName, StateData) + end. + +wait_for_bind({xmlstreamelement, El}, StateData) -> + decode_element(El, wait_for_bind, StateData); +wait_for_bind(#sm_resume{} = Pkt, StateData) -> + case handle_resume(StateData, Pkt) of + {ok, ResumedState} -> + fsm_next_state(session_established, ResumedState); + error -> + fsm_next_state(wait_for_bind, StateData) + end; +wait_for_bind(Pkt, StateData) when ?IS_STREAM_MGMT_PACKET(Pkt) -> + fsm_next_state(wait_for_bind, dispatch_stream_mgmt(Pkt, StateData)); +wait_for_bind(#iq{type = set, + sub_els = [#bind{resource = R}]} = IQ, StateData) -> + U = StateData#state.user, + case resource_conflict_action(U, StateData#state.server, R) of + closenew -> + Err = xmpp:make_error(IQ, xmpp:err_conflict()), + send_element(StateData, Err), + fsm_next_state(wait_for_bind, StateData); + {accept_resource, R2} -> + JID = jid:make(U, StateData#state.server, R2), + StateData2 = StateData#state{resource = R2, jid = JID}, + case open_session(StateData2) of + {ok, StateData3} -> + Res = xmpp:make_iq_result(IQ, #bind{jid = JID}), + try + send_element(StateData3, Res) + catch + exit:normal -> close(self()) + end, + fsm_next_state_pack(session_established,StateData3); + {error, Error} -> + Err = xmpp:make_error(IQ, Error), + send_element(StateData, Err), fsm_next_state(wait_for_bind, StateData) end end; +wait_for_bind(#compress{} = Comp, StateData) -> + Zlib = StateData#state.zlib, + SockMod = (StateData#state.sockmod):get_sockmod(StateData#state.socket), + if Zlib == true, (SockMod == gen_tcp) or (SockMod == fast_tls) -> + process_compression_request(Comp, wait_for_bind, StateData); + true -> + send_element(StateData, #compress_failure{reason = 'setup-failed'}), + fsm_next_state(wait_for_bind, StateData) + end; wait_for_bind(timeout, StateData) -> {stop, normal, StateData}; wait_for_bind({xmlstreamend, _Name}, StateData) -> {stop, normal, StateData}; wait_for_bind({xmlstreamerror, _}, StateData) -> - send_element(StateData, ?INVALID_XML_ERR), + send_element(StateData, xmpp:serr_not_well_formed()), {stop, normal, StateData}; wait_for_bind(closed, StateData) -> {stop, normal, StateData}; wait_for_bind(stop, StateData) -> - {stop, normal, StateData}. + {stop, normal, StateData}; +wait_for_bind(Pkt, StateData) -> + case xmpp:is_stanza(Pkt) of + true -> + Type = xmpp:get_type(Pkt), + if Type /= error, Type /= result -> + Err = xmpp:make_error(Pkt, xmpp:err_not_acceptable()), + send_element(StateData, Err); + true -> + ok + end; + false -> + ok + end, + fsm_next_state(wait_for_bind, StateData). +-spec open_session(state()) -> {ok, state()} | {error, error()}. open_session(StateData) -> U = StateData#state.user, R = StateData#state.resource, @@ -1145,33 +1009,18 @@ open_session(StateData) -> ?INFO_MSG("(~w) Forbidden session for ~s", [StateData#state.socket, jid:to_string(JID)]), Txt = <<"Denied by ACL">>, - {error, ?ERRT_NOT_ALLOWED(Lang, Txt)} + {error, xmpp:err_not_allowed(Txt, Lang)} end. -session_established({xmlstreamelement, #xmlel{name = Name} = El}, StateData) - when ?IS_STREAM_MGMT_TAG(Name) -> - fsm_next_state(session_established, dispatch_stream_mgmt(El, StateData)); -session_established({xmlstreamelement, - #xmlel{name = <<"active">>, - attrs = [{<<"xmlns">>, ?NS_CLIENT_STATE}]}}, - StateData) -> +session_established({xmlstreamelement, El}, StateData) -> + decode_element(El, session_established, StateData); +session_established(Pkt, StateData) when ?IS_STREAM_MGMT_PACKET(Pkt) -> + fsm_next_state(session_established, dispatch_stream_mgmt(Pkt, StateData)); +session_established(#csi{type = active}, StateData) -> NewStateData = csi_flush_queue(StateData), fsm_next_state(session_established, NewStateData#state{csi_state = active}); -session_established({xmlstreamelement, - #xmlel{name = <<"inactive">>, - attrs = [{<<"xmlns">>, ?NS_CLIENT_STATE}]}}, - StateData) -> +session_established(#csi{type = inactive}, StateData) -> fsm_next_state(session_established, StateData#state{csi_state = inactive}); -session_established({xmlstreamelement, El}, - StateData) -> - FromJID = StateData#state.jid, - case check_from(El, FromJID) of - 'invalid-from' -> - send_element(StateData, ?INVALID_FROM), - {stop, normal, StateData}; - _NewEl -> - session_established2(El, StateData) - end; %% We hibernate the process to reduce memory consumption after a %% configurable activity timeout session_established(timeout, StateData) -> @@ -1185,10 +1034,10 @@ session_established({xmlstreamerror, <<"XML stanza is too big">> = E}, StateData) -> send_element(StateData, - ?POLICY_VIOLATION_ERR((StateData#state.lang), E)), + xmpp:serr_policy_violation(E, StateData#state.lang)), {stop, normal, StateData}; session_established({xmlstreamerror, _}, StateData) -> - send_element(StateData, ?INVALID_XML_ERR), + send_element(StateData, xmpp:serr_not_well_formed()), {stop, normal, StateData}; session_established(closed, #state{mgmt_state = active} = StateData) -> catch (StateData#state.sockmod):close(StateData#state.socket), @@ -1196,92 +1045,82 @@ session_established(closed, #state{mgmt_state = active} = StateData) -> session_established(closed, StateData) -> {stop, normal, StateData}; session_established(stop, StateData) -> - {stop, normal, StateData}. + {stop, normal, StateData}; +session_established(Pkt, StateData) -> + FromJID = StateData#state.jid, + case check_from(Pkt, FromJID) of + 'invalid-from' -> + send_element(StateData, xmpp:serr_invalid_from()), + {stop, normal, StateData}; + _ -> + NewStateData = update_num_stanzas_in(StateData, Pkt), + session_established2(Pkt, NewStateData) + end. +-spec session_established2(xmpp_element(), state()) -> fsm_next(). %% Process packets sent by user (coming from user on c2s XMPP connection) -session_established2(El, StateData) -> - #xmlel{name = Name, attrs = Attrs} = El, - NewStateData = update_num_stanzas_in(StateData, El), - User = NewStateData#state.user, - Server = NewStateData#state.server, - FromJID = NewStateData#state.jid, - To = fxml:get_attr_s(<<"to">>, Attrs), - ToJID = case To of - <<"">> -> jid:make(User, Server, <<"">>); - _ -> jid:from_string(To) +session_established2(Pkt, StateData) when ?is_stanza(Pkt) -> + User = StateData#state.user, + Server = StateData#state.server, + FromJID = StateData#state.jid, + ToJID = case xmpp:get_to(Pkt) of + undefined -> jid:make(User, Server, <<"">>); + J -> J end, - NewEl1 = jlib:remove_attr(<<"xmlns">>, El), - NewEl = case fxml:get_attr_s(<<"xml:lang">>, Attrs) of - <<"">> -> - case NewStateData#state.lang of - <<"">> -> NewEl1; - Lang -> - fxml:replace_tag_attr(<<"xml:lang">>, Lang, NewEl1) - end; - _ -> NewEl1 - end, - NewState = case ToJID of - error -> - case fxml:get_attr_s(<<"type">>, Attrs) of - <<"error">> -> NewStateData; - <<"result">> -> NewStateData; - _ -> - Err = jlib:make_error_reply(NewEl, - ?ERR_JID_MALFORMED), - send_packet(NewStateData, Err) - end; - _ -> - case Name of - <<"presence">> -> - PresenceEl0 = - ejabberd_hooks:run_fold(c2s_update_presence, - Server, NewEl, - [User, Server]), - PresenceEl = - ejabberd_hooks:run_fold( - user_send_packet, Server, PresenceEl0, - [NewStateData, FromJID, ToJID]), - case ToJID of - #jid{user = User, server = Server, - resource = <<"">>} -> - ?DEBUG("presence_update(~p,~n\t~p,~n\t~p)", - [FromJID, PresenceEl, NewStateData]), - presence_update(FromJID, PresenceEl, - NewStateData); - _ -> - presence_track(FromJID, ToJID, PresenceEl, - NewStateData) - end; - <<"iq">> -> - case jlib:iq_query_info(NewEl) of - #iq{xmlns = Xmlns} = IQ - when Xmlns == (?NS_PRIVACY); - Xmlns == (?NS_BLOCKING) -> - process_privacy_iq(FromJID, ToJID, IQ, - NewStateData); - #iq{xmlns = ?NS_SESSION} -> - Res = jlib:make_result_iq_reply( - NewEl#xmlel{children = []}), - send_stanza(NewStateData, Res); - _ -> - NewEl0 = ejabberd_hooks:run_fold( - user_send_packet, Server, NewEl, - [NewStateData, FromJID, ToJID]), - check_privacy_route(FromJID, NewStateData, - FromJID, ToJID, NewEl0) - end; - <<"message">> -> - NewEl0 = ejabberd_hooks:run_fold( - user_send_packet, Server, NewEl, - [NewStateData, FromJID, ToJID]), - check_privacy_route(FromJID, NewStateData, FromJID, - ToJID, NewEl0); - _ -> NewStateData - end - end, + Lang = case xmpp:get_lang(Pkt) of + undefined -> StateData#state.lang; + <<"">> -> StateData#state.lang; + L -> L + end, + NewPkt = xmpp:set_lang(Pkt, Lang), + NewState = + case NewPkt of + #presence{} -> + Presence0 = ejabberd_hooks:run_fold( + c2s_update_presence, Server, NewPkt, + [User, Server]), + Presence = ejabberd_hooks:run_fold( + user_send_packet, Server, Presence0, + [StateData, FromJID, ToJID]), + case ToJID of + #jid{user = User, server = Server, resource = <<"">>} -> + ?DEBUG("presence_update(~p,~n\t~p,~n\t~p)", + [FromJID, Presence, StateData]), + presence_update(FromJID, Presence, + StateData); + _ -> + presence_track(FromJID, ToJID, Presence, + StateData) + end; + #iq{type = T, sub_els = [El]} when T == set; T == get -> + NS = xmpp:get_ns(El), + if NS == ?NS_BLOCKING; NS == ?NS_PRIVACY -> + IQ = xmpp:set_from_to(Pkt, FromJID, ToJID), + process_privacy_iq(IQ, StateData); + NS == ?NS_SESSION -> + Res = xmpp:make_iq_result(Pkt), + send_stanza(StateData, Res); + true -> + NewPkt0 = ejabberd_hooks:run_fold( + user_send_packet, Server, NewPkt, + [StateData, FromJID, ToJID]), + check_privacy_route(FromJID, StateData, FromJID, + ToJID, NewPkt0) + end; + _ -> + NewPkt0 = ejabberd_hooks:run_fold( + user_send_packet, Server, NewPkt, + [StateData, FromJID, ToJID]), + check_privacy_route(FromJID, StateData, FromJID, + ToJID, NewPkt0) + end, ejabberd_hooks:run(c2s_loop_debug, - [{xmlstreamelement, El}]), - fsm_next_state(session_established, NewState). + [{xmlstreamelement, Pkt}]), + fsm_next_state(session_established, NewState); +session_established2(Pkt, StateData) -> + ejabberd_hooks:run(c2s_loop_debug, + [{xmlstreamelement, Pkt}]), + fsm_next_state(session_established, StateData). wait_for_resume({xmlstreamelement, _El} = Event, StateData) -> Result = session_established(Event, StateData), @@ -1335,14 +1174,14 @@ handle_info({send_text, Text}, StateName, StateData) -> fsm_next_state(StateName, StateData); handle_info(replaced, StateName, StateData) -> Lang = StateData#state.lang, - Xmlelement = ?SERRT_CONFLICT(Lang, <<"Replaced by new connection">>), - handle_info({kick, replaced, Xmlelement}, StateName, StateData); + Pkt = xmpp:serr_conflict(<<"Replaced by new connection">>, Lang), + handle_info({kick, replaced, Pkt}, StateName, StateData); handle_info(kick, StateName, StateData) -> Lang = StateData#state.lang, - Xmlelement = ?SERRT_POLICY_VIOLATION(Lang, <<"has been kicked">>), - handle_info({kick, kicked_by_admin, Xmlelement}, StateName, StateData); -handle_info({kick, Reason, Xmlelement}, _StateName, StateData) -> - send_element(StateData, Xmlelement), + Pkt = xmpp:serr_policy_violation(<<"has been kicked">>, Lang), + handle_info({kick, kicked_by_admin, Pkt}, StateName, StateData); +handle_info({kick, Reason, Pkt}, _StateName, StateData) -> + send_element(StateData, Pkt), {stop, normal, StateData#state{authenticated = Reason}}; handle_info({route, _From, _To, {broadcast, Data}}, @@ -1354,7 +1193,7 @@ handle_info({route, _From, _To, {broadcast, Data}}, roster_change(IJID, ISubscription, StateData)); {exit, Reason} -> Lang = StateData#state.lang, - send_element(StateData, ?SERRT_CONFLICT(Lang, Reason)), + send_element(StateData, xmpp:serr_conflict(Reason, Lang)), {stop, normal, StateData}; {privacy_list, PrivList, PrivListName} -> case ejabberd_hooks:run_fold(privacy_updated_list, @@ -1365,24 +1204,15 @@ handle_info({route, _From, _To, {broadcast, Data}}, false -> fsm_next_state(StateName, StateData); NewPL -> - PrivPushIQ = #iq{type = set, - id = <<"push", - (randoms:get_string())/binary>>, - sub_el = - [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, - ?NS_PRIVACY}], - children = - [#xmlel{name = <<"list">>, - attrs = [{<<"name">>, - PrivListName}], - children = []}]}]}, - PrivPushEl = jlib:replace_from_to( - jid:remove_resource(StateData#state.jid), - StateData#state.jid, - jlib:iq_to_xml(PrivPushIQ)), - NewState = send_stanza( - StateData, PrivPushEl), + PrivPushIQ = + #iq{type = set, + from = jid:remove_resource(StateData#state.jid), + to = StateData#state.jid, + id = <<"push", (randoms:get_string())/binary>>, + sub_els = [#privacy_query{ + lists = [#privacy_list{ + name = PrivListName}]}]}, + NewState = send_stanza(StateData, PrivPushIQ), fsm_next_state(StateName, NewState#state{privacy_list = NewPL}) end; @@ -1393,265 +1223,147 @@ handle_info({route, _From, _To, {broadcast, Data}}, fsm_next_state(StateName, StateData) end; %% Process Packets that are to be send to the user -handle_info({route, From, To, - #xmlel{name = Name, attrs = Attrs, children = Els} = Packet}, - StateName, StateData) -> - {Pass, NewAttrs, NewState} = case Name of - <<"presence">> -> - State = - ejabberd_hooks:run_fold(c2s_presence_in, - StateData#state.server, - StateData, - [{From, To, - Packet}]), - case fxml:get_attr_s(<<"type">>, Attrs) of - <<"probe">> -> - LFrom = jid:tolower(From), - LBFrom = - jid:remove_resource(LFrom), - NewStateData = case - (?SETS):is_element(LFrom, - State#state.pres_a) - orelse - (?SETS):is_element(LBFrom, - State#state.pres_a) - of - true -> State; - false -> - case - (?SETS):is_element(LFrom, - State#state.pres_f) - of - true -> - A = - (?SETS):add_element(LFrom, - State#state.pres_a), - State#state{pres_a - = - A}; - false -> - case - (?SETS):is_element(LBFrom, - State#state.pres_f) - of - true -> - A = - (?SETS):add_element(LBFrom, - State#state.pres_a), - State#state{pres_a - = - A}; - false -> - State - end - end - end, - process_presence_probe(From, To, - NewStateData), - {false, Attrs, NewStateData}; - <<"error">> -> - NewA = - remove_element(jid:tolower(From), - State#state.pres_a), - {true, Attrs, - State#state{pres_a = NewA}}; - <<"subscribe">> -> - SRes = is_privacy_allow(State, - From, To, - Packet, - in), - {SRes, Attrs, State}; - <<"subscribed">> -> - SRes = is_privacy_allow(State, - From, To, - Packet, - in), - {SRes, Attrs, State}; - <<"unsubscribe">> -> - SRes = is_privacy_allow(State, - From, To, - Packet, - in), - {SRes, Attrs, State}; - <<"unsubscribed">> -> - SRes = is_privacy_allow(State, - From, To, - Packet, - in), - {SRes, Attrs, State}; - _ -> - case privacy_check_packet(State, - From, To, - Packet, - in) - of - allow -> - LFrom = - jid:tolower(From), - LBFrom = - jid:remove_resource(LFrom), - case - (?SETS):is_element(LFrom, - State#state.pres_a) - orelse - (?SETS):is_element(LBFrom, - State#state.pres_a) - of - true -> - {true, Attrs, State}; - false -> - case - (?SETS):is_element(LFrom, - State#state.pres_f) - of - true -> - A = - (?SETS):add_element(LFrom, - State#state.pres_a), - {true, Attrs, - State#state{pres_a - = - A}}; - false -> - case - (?SETS):is_element(LBFrom, - State#state.pres_f) - of - true -> - A = - (?SETS):add_element(LBFrom, - State#state.pres_a), - {true, - Attrs, - State#state{pres_a - = - A}}; - false -> - {true, - Attrs, - State} - end - end - end; - deny -> {false, Attrs, State} - end - end; - <<"iq">> -> - IQ = jlib:iq_query_info(Packet), - case IQ of - #iq{xmlns = ?NS_LAST} -> - LFrom = jid:tolower(From), - LBFrom = - jid:remove_resource(LFrom), - HasFromSub = - ((?SETS):is_element(LFrom, - StateData#state.pres_f) - orelse - (?SETS):is_element(LBFrom, - StateData#state.pres_f)) - andalso - is_privacy_allow(StateData, - To, From, - #xmlel{name - = - <<"presence">>, - attrs - = - [], - children - = - []}, - out), - case HasFromSub of - true -> - case - privacy_check_packet(StateData, - From, - To, - Packet, - in) - of - allow -> - {true, Attrs, - StateData}; - deny -> - Err = - jlib:make_error_reply(Packet, - ?ERR_SERVICE_UNAVAILABLE), - ejabberd_router:route(To, - From, - Err), - {false, Attrs, - StateData} - end; - _ -> - Err = - jlib:make_error_reply(Packet, - ?ERR_FORBIDDEN), - ejabberd_router:route(To, - From, - Err), - {false, Attrs, StateData} - end; - IQ - when is_record(IQ, iq) or - (IQ == reply) -> - case - privacy_check_packet(StateData, - From, To, - Packet, in) - of - allow -> - {true, Attrs, StateData}; - deny when is_record(IQ, iq) -> - Err = - jlib:make_error_reply(Packet, - ?ERR_SERVICE_UNAVAILABLE), - ejabberd_router:route(To, - From, - Err), - {false, Attrs, StateData}; - deny when IQ == reply -> - {false, Attrs, StateData} - end; - IQ - when (IQ == invalid) or - (IQ == not_iq) -> - {false, Attrs, StateData} - end; - <<"message">> -> - case privacy_check_packet(StateData, - From, To, - Packet, in) - of - allow -> - {true, Attrs, StateData}; - deny -> - case fxml:get_attr_s(<<"type">>, Attrs) of - <<"error">> -> ok; - <<"groupchat">> -> ok; - <<"headline">> -> ok; - _ -> - Err = - jlib:make_error_reply(Packet, - ?ERR_SERVICE_UNAVAILABLE), - ejabberd_router:route(To, From, - Err) - end, - {false, Attrs, StateData} - end; - _ -> {true, Attrs, StateData} - end, +handle_info({route, From, To, Packet}, StateName, StateData) when ?is_stanza(Packet) -> + {Pass, NewState} = + case Packet of + #presence{type = T} -> + State = ejabberd_hooks:run_fold(c2s_presence_in, + StateData#state.server, + StateData, + [{From, To, Packet}]), + case T of + probe -> + LFrom = jid:tolower(From), + LBFrom = jid:remove_resource(LFrom), + NewStateData = + case (?SETS):is_element(LFrom, State#state.pres_a) + orelse (?SETS):is_element(LBFrom, State#state.pres_a) of + true -> State; + false -> + case (?SETS):is_element(LFrom, State#state.pres_f) of + true -> + A = (?SETS):add_element(LFrom, State#state.pres_a), + State#state{pres_a = A}; + false -> + case (?SETS):is_element(LBFrom, State#state.pres_f) of + true -> + A = (?SETS):add_element(LBFrom, State#state.pres_a), + State#state{pres_a = A}; + false -> + State + end + end + end, + process_presence_probe(From, To, NewStateData), + {false, NewStateData}; + error -> + NewA = remove_element(jid:tolower(From), State#state.pres_a), + {true, State#state{pres_a = NewA}}; + subscribe -> + SRes = is_privacy_allow(State, From, To, Packet, in), + {SRes, State}; + subscribed -> + SRes = is_privacy_allow(State, From, To, Packet, in), + {SRes, State}; + unsubscribe -> + SRes = is_privacy_allow(State, From, To, Packet, in), + {SRes, State}; + unsubscribed -> + SRes = is_privacy_allow(State, From, To, Packet, in), + {SRes, State}; + _ -> + case privacy_check_packet(State, From, To, Packet, in) of + allow -> + LFrom = jid:tolower(From), + LBFrom = jid:remove_resource(LFrom), + case (?SETS):is_element(LFrom, State#state.pres_a) + orelse (?SETS):is_element(LBFrom, State#state.pres_a) of + true -> + {true, State}; + false -> + case (?SETS):is_element(LFrom, State#state.pres_f) of + true -> + A = (?SETS):add_element(LFrom, State#state.pres_a), + {true, State#state{pres_a = A}}; + false -> + case (?SETS):is_element(LBFrom, + State#state.pres_f) of + true -> + A = (?SETS):add_element( + LBFrom, + State#state.pres_a), + {true, State#state{pres_a = A}}; + false -> + {true, State} + end + end + end; + deny -> {false, State} + end + end; + #iq{type = T} -> + case xmpp:has_subtag(Packet, #last{}) of + true when T == get; T == set -> + LFrom = jid:tolower(From), + LBFrom = jid:remove_resource(LFrom), + HasFromSub = ((?SETS):is_element(LFrom, StateData#state.pres_f) + orelse (?SETS):is_element(LBFrom, StateData#state.pres_f)) + andalso is_privacy_allow(StateData, To, From, #presence{}, out), + case HasFromSub of + true -> + case privacy_check_packet( + StateData, From, To, Packet, in) of + allow -> + {true, StateData}; + deny -> + Err = xmpp:make_error( + Packet, + xmpp:err_service_unavailable()), + ejabberd_router:route(To, From, Err), + {false, StateData} + end; + _ -> + Err = xmpp:make_error(Packet, xmpp:err_forbidden()), + ejabberd_router:route(To, From, Err), + {false, StateData} + end; + _ -> + case privacy_check_packet(StateData, From, To, Packet, in) of + allow -> + {true, StateData}; + deny when T == get; T == set -> + Err = xmpp:make_error( + Packet, xmpp:err_service_unavailable()), + ejabberd_router:route(To, From, Err), + {false, StateData}; + deny -> + {false, StateData} + end + end; + #message{type = T} -> + case privacy_check_packet(StateData, From, To, Packet, in) of + allow -> + {true, StateData}; + deny -> + case T of + error -> ok; + groupchat -> ok; + headline -> ok; + _ -> + Err = xmpp:make_error( + Packet, xmpp:err_service_unavailable()), + ejabberd_router:route(To, From, Err) + end, + {false, StateData} + end + end, if Pass -> - Attrs2 = - jlib:replace_from_to_attrs(jid:to_string(From), - jid:to_string(To), NewAttrs), - FixedPacket0 = #xmlel{name = Name, attrs = Attrs2, children = Els}, + FixedPacket0 = xmpp:set_from_to(Packet, From, To), FixedPacket = ejabberd_hooks:run_fold( - user_receive_packet, - NewState#state.server, - FixedPacket0, - [NewState, NewState#state.jid, From, To]), + user_receive_packet, + NewState#state.server, + FixedPacket0, + [NewState, NewState#state.jid, From, To]), SentStateData = send_packet(NewState, FixedPacket), ejabberd_hooks:run(c2s_loop_debug, [{route, From, To, Packet}]), fsm_next_state(StateName, SentStateData); @@ -1672,10 +1384,10 @@ handle_info(system_shutdown, StateName, StateData) -> case StateName of wait_for_stream -> send_header(StateData, ?MYNAME, <<"1.0">>, <<"en">>), - send_element(StateData, ?SERR_SYSTEM_SHUTDOWN), + send_element(StateData, xmpp:serr_system_shutdown()), ok; _ -> - send_element(StateData, ?SERR_SYSTEM_SHUTDOWN), + send_element(StateData, xmpp:serr_system_shutdown()), ok end, {stop, normal, StateData}; @@ -1686,17 +1398,17 @@ handle_info({route_xmlstreamelement, El}, _StateName, StateData) -> handle_info({force_update_presence, LUser, LServer}, StateName, #state{jid = #jid{luser = LUser, lserver = LServer}} = StateData) -> NewStateData = case StateData#state.pres_last of - #xmlel{name = <<"presence">>} -> - PresenceEl = - ejabberd_hooks:run_fold(c2s_update_presence, - LServer, - StateData#state.pres_last, - [LUser, LServer]), - StateData2 = StateData#state{pres_last = PresenceEl}, - presence_update(StateData2#state.jid, PresenceEl, - StateData2), - StateData2; - _ -> StateData + #presence{} -> + Presence = + ejabberd_hooks:run_fold(c2s_update_presence, + LServer, + StateData#state.pres_last, + [LUser, LServer]), + StateData2 = StateData#state{pres_last = Presence}, + presence_update(StateData2#state.jid, Presence, + StateData2), + StateData2; + undefined -> StateData end, fsm_next_state(StateName, NewStateData); handle_info({send_filtered, Feature, From, To, Packet}, StateName, StateData) -> @@ -1709,7 +1421,7 @@ handle_info({send_filtered, Feature, From, To, Packet}, StateName, StateData) -> jid:to_string(To)]), StateData; true -> - FinalPacket = jlib:replace_from_to(From, To, Packet), + FinalPacket = xmpp:set_from_to(Packet, From, To), case StateData#state.jid of To -> case privacy_check_packet(StateData, From, To, @@ -1742,6 +1454,7 @@ handle_info(Info, StateName, StateData) -> ?ERROR_MSG("Unexpected info: ~p", [Info]), fsm_next_state(StateName, StateData). +-spec print_state(state()) -> state(). print_state(State = #state{pres_t = T, pres_f = F, pres_a = A}) -> State#state{pres_t = {pres_t, (?SETS):size(T)}, pres_f = {pres_f, (?SETS):size(F)}, @@ -1761,18 +1474,16 @@ terminate(_Reason, StateName, StateData) -> [StateData#state.socket, jid:to_string(StateData#state.jid)]), From = StateData#state.jid, - Packet = #xmlel{name = <<"presence">>, - attrs = [{<<"type">>, <<"unavailable">>}], - children = - [#xmlel{name = <<"status">>, attrs = [], - children = - [{xmlcdata, - <<"Replaced by new connection">>}]}]}, + Lang = StateData#state.lang, + Status = <<"Replaced by new connection">>, + Packet = #presence{ + type = unavailable, + status = xmpp:mk_text(Status, Lang)}, ejabberd_sm:close_session_unset_presence(StateData#state.sid, StateData#state.user, StateData#state.server, StateData#state.resource, - <<"Replaced by new connection">>), + Status), presence_broadcast(StateData, From, StateData#state.pres_a, Packet); _ -> @@ -1788,9 +1499,7 @@ terminate(_Reason, StateName, StateData) -> StateData#state.resource); _ -> From = StateData#state.jid, - Packet = #xmlel{name = <<"presence">>, - attrs = [{<<"type">>, <<"unavailable">>}], - children = []}, + Packet = #presence{type = unavailable}, ejabberd_sm:close_session_unset_presence(StateData#state.sid, StateData#state.user, StateData#state.server, @@ -1825,7 +1534,7 @@ terminate(_Reason, StateName, StateData) -> %%%---------------------------------------------------------------------- %%% Internal functions %%%---------------------------------------------------------------------- - +-spec change_shaper(state(), jid()) -> ok. change_shaper(StateData, JID) -> Shaper = acl:access_matches(StateData#state.shaper, #{usr => jid:split(JID), ip => StateData#state.ip}, @@ -1833,6 +1542,7 @@ change_shaper(StateData, JID) -> (StateData#state.sockmod):change_shaper(StateData#state.socket, Shaper). +-spec send_text(state(), iodata()) -> ok | {error, any()}. send_text(StateData, Text) when StateData#state.mgmt_state == pending -> ?DEBUG("Cannot send text while waiting for resumption: ~p", [Text]); send_text(StateData, Text) when StateData#state.xml_socket -> @@ -1852,14 +1562,18 @@ send_text(StateData, Text) -> ?DEBUG("Send XML on stream = ~p", [Text]), (StateData#state.sockmod):send(StateData#state.socket, Text). +-spec send_element(state(), xmlel() | xmpp_element()) -> ok | {error, any()}. send_element(StateData, El) when StateData#state.mgmt_state == pending -> ?DEBUG("Cannot send element while waiting for resumption: ~p", [El]); -send_element(StateData, El) when StateData#state.xml_socket -> +send_element(StateData, #xmlel{} = El) when StateData#state.xml_socket -> (StateData#state.sockmod):send_xml(StateData#state.socket, {xmlstreamelement, El}); -send_element(StateData, El) -> - send_text(StateData, fxml:element_to_binary(El)). +send_element(StateData, #xmlel{} = El) -> + send_text(StateData, fxml:element_to_binary(El)); +send_element(StateData, Pkt) -> + send_element(StateData, xmpp:encode(Pkt)). +-spec send_stanza(state(), xmpp_element()) -> state(). send_stanza(StateData, Stanza) when StateData#state.csi_state == inactive -> csi_filter_stanza(StateData, Stanza); send_stanza(StateData, Stanza) when StateData#state.mgmt_state == pending -> @@ -1871,8 +1585,9 @@ send_stanza(StateData, Stanza) -> send_element(StateData, Stanza), StateData. +-spec send_packet(state(), xmpp_element()) -> state(). send_packet(StateData, Packet) -> - case is_stanza(Packet) of + case xmpp:is_stanza(Packet) of true -> send_stanza(StateData, Packet); false -> @@ -1880,6 +1595,7 @@ send_packet(StateData, Packet) -> StateData end. +-spec send_header(state(), binary(), binary(), binary()) -> ok | {error, any()}. send_header(StateData, Server, Version, Lang) when StateData#state.xml_socket -> VersionAttr = case Version of @@ -1914,6 +1630,7 @@ send_header(StateData, Server, Version, Lang) -> LangStr]), send_text(StateData, iolist_to_binary(Header)). +-spec send_trailer(state()) -> ok | {error, any()}. send_trailer(StateData) when StateData#state.mgmt_state == pending -> ?DEBUG("Cannot send stream trailer while waiting for resumption", []); @@ -1924,64 +1641,24 @@ send_trailer(StateData) send_trailer(StateData) -> send_text(StateData, ?STREAM_TRAILER). +-spec new_id() -> binary(). new_id() -> randoms:get_string(). +-spec new_uniq_id() -> binary(). new_uniq_id() -> iolist_to_binary([randoms:get_string(), jlib:integer_to_binary(p1_time_compat:unique_integer([positive]))]). -is_auth_packet(El) -> - case jlib:iq_query_info(El) of - #iq{id = ID, type = Type, xmlns = ?NS_AUTH, sub_el = SubEl} -> - #xmlel{children = Els} = SubEl, - {auth, ID, Type, - get_auth_tags(Els, <<"">>, <<"">>, <<"">>, <<"">>)}; - _ -> false - end. - -is_stanza(#xmlel{name = Name, attrs = Attrs}) when Name == <<"message">>; - Name == <<"presence">>; - Name == <<"iq">> -> - case fxml:get_attr(<<"xmlns">>, Attrs) of - {value, NS} when NS /= <<"jabber:client">>, - NS /= <<"jabber:server">> -> - false; - _ -> - true - end; -is_stanza(_El) -> - false. - -get_auth_tags([#xmlel{name = Name, children = Els} | L], - U, P, D, R) -> - CData = fxml:get_cdata(Els), - case Name of - <<"username">> -> get_auth_tags(L, CData, P, D, R); - <<"password">> -> get_auth_tags(L, U, CData, D, R); - <<"digest">> -> get_auth_tags(L, U, P, CData, R); - <<"resource">> -> get_auth_tags(L, U, P, D, CData); - _ -> get_auth_tags(L, U, P, D, R) - end; -get_auth_tags([_ | L], U, P, D, R) -> - get_auth_tags(L, U, P, D, R); -get_auth_tags([], U, P, D, R) -> - {U, P, D, R}. - -%% Copied from ejabberd_socket.erl --record(socket_state, {sockmod, socket, receiver}). - +-spec get_conn_type(state()) -> c2s | c2s_tls | c2s_compressed | websocket | + c2s_compressed_tls | http_bind. get_conn_type(StateData) -> - case (StateData#state.sockmod):get_sockmod(StateData#state.socket) of - gen_tcp -> c2s; - fast_tls -> c2s_tls; - ezlib -> - case ezlib:get_sockmod((StateData#state.socket)#socket_state.socket) of - gen_tcp -> c2s_compressed; - fast_tls -> c2s_compressed_tls - end; - ejabberd_http_bind -> http_bind; - ejabberd_http_ws -> websocket; - _ -> unknown + case (StateData#state.sockmod):get_transport(StateData#state.socket) of + tcp -> c2s; + tls -> c2s_tls; + tcp_zlib -> c2s_compressed; + tls_zlib -> c2s_compressed_tls; + http_bind -> http_bind; + websocket -> websocket end. process_presence_probe(From, To, StateData) -> @@ -1997,8 +1674,9 @@ process_presence_probe(From, To, StateData) -> (?SETS):is_element(LBFrom, StateData#state.pres_f))), if Cond -> %% To is the one sending the presence (the probe target) - Packet = jlib:add_delay_info(StateData#state.pres_last, To, - StateData#state.pres_timestamp), + Packet = xmpp_util:add_delay_info( + StateData#state.pres_last, To, + StateData#state.pres_timestamp), case privacy_check_packet(StateData, To, From, Packet, out) of deny -> ok; @@ -2020,13 +1698,10 @@ process_presence_probe(From, To, StateData) -> %% User updates his presence (non-directed presence packet) presence_update(From, Packet, StateData) -> - #xmlel{attrs = Attrs} = Packet, - case fxml:get_attr_s(<<"type">>, Attrs) of - <<"unavailable">> -> - Status = case fxml:get_subtag(Packet, <<"status">>) of - false -> <<"">>; - StatusTag -> fxml:get_tag_cdata(StatusTag) - end, + #presence{type = Type} = Packet, + case Type of + unavailable -> + Status = xmpp:get_text(Packet#presence.status), Info = [{ip, StateData#state.ip}, {conn, StateData#state.conn}, {auth_module, StateData#state.auth_module}], @@ -2038,12 +1713,12 @@ presence_update(From, Packet, StateData) -> StateData#state.pres_a, Packet), StateData#state{pres_last = undefined, pres_timestamp = undefined, pres_a = (?SETS):new()}; - <<"error">> -> StateData; - <<"probe">> -> StateData; - <<"subscribe">> -> StateData; - <<"subscribed">> -> StateData; - <<"unsubscribe">> -> StateData; - <<"unsubscribed">> -> StateData; + error -> StateData; + probe -> StateData; + subscribe -> StateData; + subscribed -> StateData; + unsubscribe -> StateData; + unsubscribed -> StateData; _ -> OldPriority = case StateData#state.pres_last of undefined -> 0; @@ -2082,31 +1757,31 @@ presence_update(From, Packet, StateData) -> %% User sends a directed presence packet presence_track(From, To, Packet, StateData) -> - #xmlel{attrs = Attrs} = Packet, + #presence{type = Type} = Packet, LTo = jid:tolower(To), User = StateData#state.user, Server = StateData#state.server, - case fxml:get_attr_s(<<"type">>, Attrs) of - <<"unavailable">> -> + case Type of + unavailable -> A = remove_element(LTo, StateData#state.pres_a), check_privacy_route(From, StateData#state{pres_a = A}, From, To, Packet); - <<"subscribe">> -> + subscribe -> try_roster_subscribe(subscribe, User, Server, From, To, Packet, StateData); - <<"subscribed">> -> + subscribed -> ejabberd_hooks:run(roster_out_subscription, Server, [User, Server, To, subscribed]), check_privacy_route(From, StateData, jid:remove_resource(From), To, Packet); - <<"unsubscribe">> -> + unsubscribe -> try_roster_subscribe(unsubscribe, User, Server, From, To, Packet, StateData); - <<"unsubscribed">> -> + unsubscribed -> ejabberd_hooks:run(roster_out_subscription, Server, [User, Server, To, unsubscribed]), check_privacy_route(From, StateData, jid:remove_resource(From), To, Packet); - <<"error">> -> + error -> check_privacy_route(From, StateData, From, To, Packet); - <<"probe">> -> + probe -> check_privacy_route(From, StateData, From, To, Packet); _ -> A = (?SETS):add_element(LTo, StateData#state.pres_a), @@ -2122,12 +1797,12 @@ check_privacy_route(From, StateData, FromRoute, To, Lang = StateData#state.lang, ErrText = <<"Your active privacy list has denied " "the routing of this stanza.">>, - Err = jlib:make_error_reply(Packet, - ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)), - Err2 = jlib:replace_from_to(To, From, Err), - send_stanza(StateData, Err2); + Err = xmpp:make_error( + xmpp:set_from_to(Packet, From, To), + xmpp:err_not_acceptable(ErrText, Lang)), + send_stanza(StateData, Err); allow -> - ejabberd_router:route(FromRoute, To, Packet), + ejabberd_router:route(FromRoute, To, Packet), StateData end. @@ -2182,7 +1857,7 @@ presence_broadcast_first(From, StateData, Packet) -> fun(JID, L) -> [JID | L] end, [], StateData#state.pres_t), - PacketProbe = #xmlel{name = <<"presence">>, attrs = [{<<"type">>,<<"probe">>}], children = []}, + PacketProbe = #presence{type = probe}, JIDs2Probe = format_and_check_privacy(From, StateData, PacketProbe, JIDsProbe, out), Server = StateData#state.server, send_multiple(From, Server, JIDs2Probe, PacketProbe), @@ -2260,9 +1935,7 @@ roster_change(IJID, ISubscription, StateData) -> pres_t = TSet}; Cond2 -> ?DEBUG("C2: ~p~n", [LIJID]), - PU = #xmlel{name = <<"presence">>, - attrs = [{<<"type">>, <<"unavailable">>}], - children = []}, + PU = #presence{type = unavailable}, case privacy_check_packet(StateData, From, To, PU, out) of deny -> ok; @@ -2282,20 +1955,14 @@ update_priority(Priority, Packet, StateData) -> StateData#state.user, StateData#state.server, StateData#state.resource, Priority, Packet, Info). -get_priority_from_presence(PresencePacket) -> - case fxml:get_subtag(PresencePacket, <<"priority">>) of - false -> 0; - SubEl -> - case catch - jlib:binary_to_integer(fxml:get_tag_cdata(SubEl)) - of - P when is_integer(P) -> P; - _ -> 0 - end +get_priority_from_presence(#presence{priority = Prio}) -> + case Prio of + undefined -> 0; + _ -> Prio end. -process_privacy_iq(From, To, - #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ, StateData) -> +process_privacy_iq(#iq{from = From, to = To, + type = Type, lang = Lang} = IQ, StateData) -> Txt = <<"No module is handling this query">>, {Res, NewStateData} = case Type of @@ -2303,16 +1970,15 @@ process_privacy_iq(From, To, R = ejabberd_hooks:run_fold( privacy_iq_get, StateData#state.server, - {error, ?ERRT_FEATURE_NOT_IMPLEMENTED(Lang, Txt)}, - [From, To, IQ, - StateData#state.privacy_list]), + {error, xmpp:err_feature_not_implemented(Txt, Lang)}, + [IQ, StateData#state.privacy_list]), {R, StateData}; set -> case ejabberd_hooks:run_fold( privacy_iq_set, StateData#state.server, - {error, ?ERRT_FEATURE_NOT_IMPLEMENTED(Lang, Txt)}, - [From, To, IQ]) + {error, xmpp:err_feature_not_implemented(Txt, Lang)}, + [IQ]) of {result, R, NewPrivList} -> {{result, R}, @@ -2323,11 +1989,11 @@ process_privacy_iq(From, To, end, IQRes = case Res of {result, Result} -> - IQ#iq{type = result, sub_el = Result}; + xmpp:make_iq_result(IQ, Result); {error, Error} -> - IQ#iq{type = error, sub_el = [SubEl, Error]} + xmpp:make_error(IQ, Error) end, - ejabberd_router:route(To, From, jlib:iq_to_xml(IQRes)), + ejabberd_router:route(To, From, IQRes), NewStateData. resend_offline_messages(#state{ask_offline = true} = StateData) -> @@ -2336,8 +2002,7 @@ resend_offline_messages(#state{ask_offline = true} = StateData) -> [StateData#state.user, StateData#state.server]) of Rs -> %%when is_list(Rs) -> - lists:foreach(fun ({route, From, To, - #xmlel{} = Packet}) -> + lists:foreach(fun ({route, From, To, Packet}) -> Pass = case privacy_check_packet(StateData, From, To, Packet, in) @@ -2367,50 +2032,35 @@ resend_subscription_requests(#state{user = User, PendingSubscriptions). get_showtag(undefined) -> <<"unavailable">>; -get_showtag(Presence) -> - case fxml:get_path_s(Presence, [{elem, <<"show">>}, cdata]) of - <<"">> -> <<"available">>; - ShowTag -> ShowTag - end. +get_showtag(#presence{show = undefined}) -> <<"available">>; +get_showtag(#presence{show = Show}) -> atom_to_binary(Show, utf8). -get_statustag(undefined) -> <<"">>; -get_statustag(Presence) -> - fxml:get_path_s(Presence, [{elem, <<"status">>}, cdata]). +get_statustag(#presence{status = [#text{data = Status}|_]}) -> Status; +get_statustag(_) -> <<"">>. -process_unauthenticated_stanza(StateData, El) -> - NewEl = case fxml:get_tag_attr_s(<<"xml:lang">>, El) of - <<"">> -> - case StateData#state.lang of - <<"">> -> El; - Lang -> fxml:replace_tag_attr(<<"xml:lang">>, Lang, El) - end; - _ -> El - end, - case jlib:iq_query_info(NewEl) of - #iq{lang = L} = IQ -> - Res = ejabberd_hooks:run_fold(c2s_unauthenticated_iq, - StateData#state.server, empty, - [StateData#state.server, IQ, - StateData#state.ip]), - case Res of - empty -> - Txt = <<"Authentication required">>, - ResIQ = IQ#iq{type = error, - sub_el = [?ERRT_SERVICE_UNAVAILABLE(L, Txt)]}, - Res1 = jlib:replace_from_to(jid:make(<<"">>, - StateData#state.server, - <<"">>), - jid:make(<<"">>, <<"">>, - <<"">>), - jlib:iq_to_xml(ResIQ)), - send_element(StateData, - jlib:remove_attr(<<"to">>, Res1)); - _ -> send_element(StateData, Res) - end; - _ -> - % Drop any stanza, which isn't IQ stanza - ok - end. +process_unauthenticated_stanza(StateData, #iq{type = T, lang = L} = IQ) + when T == set; T == get -> + Lang = if L == undefined; L == <<"">> -> StateData#state.lang; + true -> L + end, + NewIQ = IQ#iq{lang = Lang}, + Res = ejabberd_hooks:run_fold(c2s_unauthenticated_iq, + StateData#state.server, empty, + [StateData#state.server, NewIQ, + StateData#state.ip]), + case Res of + empty -> + Txt = <<"Authentication required">>, + Err0 = xmpp:make_error(IQ, xmpp:err_service_unavailable(Txt, Lang)), + Err1 = Err0#iq{from = jid:make(<<>>, StateData#state.server, <<>>), + to = undefined}, + send_element(StateData, Err1); + _ -> + send_element(StateData, Res) + end; +process_unauthenticated_stanza(_StateData, _) -> + %% Drop any stanza, which isn't IQ stanza + ok. peerip(SockMod, Socket) -> IP = case SockMod of @@ -2424,9 +2074,11 @@ peerip(SockMod, Socket) -> %% fsm_next_state_pack: Pack the StateData structure to improve %% sharing. +-spec fsm_next_state_pack(state_name(), state()) -> fsm_transition(). fsm_next_state_pack(StateName, StateData) -> fsm_next_state_gc(StateName, pack(StateData)). +-spec fsm_next_state_gc(state_name(), state()) -> fsm_transition(). %% fsm_next_state_gc: Garbage collect the process heap to make use of %% the newly packed StateData structure. fsm_next_state_gc(StateName, PackedStateData) -> @@ -2435,12 +2087,13 @@ fsm_next_state_gc(StateName, PackedStateData) -> %% fsm_next_state: Generate the next_state FSM tuple with different %% timeout, depending on the future state +-spec fsm_next_state(state_name(), state()) -> fsm_transition(). fsm_next_state(session_established, #state{mgmt_max_queue = exceeded} = StateData) -> ?WARNING_MSG("ACK queue too long, terminating session for ~s", [jid:to_string(StateData#state.jid)]), - Err = ?SERRT_POLICY_VIOLATION(StateData#state.lang, - <<"Too many unacked stanzas">>), + Err = xmpp:serr_policy_violation(<<"Too many unacked stanzas">>, + StateData#state.lang), send_element(StateData, Err), {stop, normal, StateData#state{mgmt_resend = false}}; fsm_next_state(session_established, #state{mgmt_state = pending} = StateData) -> @@ -2483,25 +2136,25 @@ is_ip_blacklisted({IP, _Port}, Lang) -> %% Check from attributes %% returns invalid-from|NewElement -check_from(El, FromJID) -> - case fxml:get_tag_attr(<<"from">>, El) of +check_from(Pkt, FromJID) -> + case xmpp:is_stanza(Pkt) of false -> - El; - {value, SJID} -> - JID = jid:from_string(SJID), + Pkt; + true -> + JID = xmpp:get_from(Pkt), case JID of - error -> - 'invalid-from'; + undefined -> + Pkt; #jid{} -> if (JID#jid.luser == FromJID#jid.luser) and - (JID#jid.lserver == FromJID#jid.lserver) and - (JID#jid.lresource == FromJID#jid.lresource) -> - El; + (JID#jid.lserver == FromJID#jid.lserver) and + (JID#jid.lresource == FromJID#jid.lresource) -> + Pkt; (JID#jid.luser == FromJID#jid.luser) and - (JID#jid.lserver == FromJID#jid.lserver) and - (JID#jid.lresource == <<"">>) -> - El; + (JID#jid.lserver == FromJID#jid.lserver) and + (JID#jid.lresource == <<"">>) -> + Pkt; true -> 'invalid-from' end @@ -2527,39 +2180,22 @@ bounce_messages() -> after 0 -> ok end. -process_compression_request(El, StateName, StateData) -> - case fxml:get_subtag(El, <<"method">>) of +process_compression_request(#compress{methods = []}, StateName, StateData) -> + send_element(StateData, #compress_failure{reason = 'setup-failed'}), + fsm_next_state(StateName, StateData); +process_compression_request(#compress{methods = Ms}, StateName, StateData) -> + case lists:member(<<"zlib">>, Ms) of + true -> + Socket = StateData#state.socket, + BCompressed = fxml:element_to_binary(xmpp:encode(#compressed{})), + ZlibSocket = (StateData#state.sockmod):compress(Socket, BCompressed), + fsm_next_state(wait_for_stream, + StateData#state{socket = ZlibSocket, + streamid = new_id()}); false -> send_element(StateData, - #xmlel{name = <<"failure">>, - attrs = [{<<"xmlns">>, ?NS_COMPRESS}], - children = - [#xmlel{name = <<"setup-failed">>, - attrs = [], children = []}]}), - fsm_next_state(StateName, StateData); - Method -> - case fxml:get_tag_cdata(Method) of - <<"zlib">> -> - Socket = StateData#state.socket, - BCompressed = fxml:element_to_binary( - #xmlel{name = <<"compressed">>, - attrs = [{<<"xmlns">>, - ?NS_COMPRESS}]}), - ZlibSocket = (StateData#state.sockmod):compress( - Socket, BCompressed), - fsm_next_state(wait_for_stream, - StateData#state{socket = ZlibSocket, - streamid = new_id()}); - _ -> - send_element(StateData, - #xmlel{name = <<"failure">>, - attrs = [{<<"xmlns">>, ?NS_COMPRESS}], - children = - [#xmlel{name = <<"unsupported-method">>, - attrs = [], - children = []}]}), - fsm_next_state(StateName, StateData) - end + #compress_failure{reason = 'unsupported-method'}), + fsm_next_state(StateName, StateData) end. %%%---------------------------------------------------------------------- @@ -2568,42 +2204,20 @@ process_compression_request(El, StateName, StateData) -> route_blocking(What, StateData) -> SubEl = case What of - {block, JIDs} -> - #xmlel{name = <<"block">>, - attrs = [{<<"xmlns">>, ?NS_BLOCKING}], - children = - lists:map(fun (JID) -> - #xmlel{name = <<"item">>, - attrs = - [{<<"jid">>, - jid:to_string(JID)}], - children = []} - end, - JIDs)}; - {unblock, JIDs} -> - #xmlel{name = <<"unblock">>, - attrs = [{<<"xmlns">>, ?NS_BLOCKING}], - children = - lists:map(fun (JID) -> - #xmlel{name = <<"item">>, - attrs = - [{<<"jid">>, - jid:to_string(JID)}], - children = []} - end, - JIDs)}; - unblock_all -> - #xmlel{name = <<"unblock">>, - attrs = [{<<"xmlns">>, ?NS_BLOCKING}], children = []} + {block, JIDs} -> + #block{items = JIDs}; + {unblock, JIDs} -> + #unblock{items = JIDs}; + unblock_all -> + #unblock{} end, - PrivPushIQ = #iq{type = set, id = <<"push">>, sub_el = [SubEl]}, - PrivPushEl = - jlib:replace_from_to(jid:remove_resource(StateData#state.jid), - StateData#state.jid, jlib:iq_to_xml(PrivPushIQ)), + PrivPushIQ = #iq{type = set, id = <<"push">>, sub_els = [SubEl], + from = jid:remove_resource(StateData#state.jid), + to = StateData#state.jid}, %% No need to replace active privacy list here, %% blocking pushes are always accompanied by %% Privacy List pushes - send_stanza(StateData, PrivPushEl). + send_stanza(StateData, PrivPushIQ). %%%---------------------------------------------------------------------- %%% XEP-0198 @@ -2627,164 +2241,131 @@ negotiate_stream_mgmt(_El, #state{resource = <<"">>} = StateData) -> %% Binding unless it is resuming a previous session". However, it also %% says: "Stream management errors SHOULD be considered recoverable", so we %% won't bail out. - send_element(StateData, ?MGMT_UNEXPECTED_REQUEST(?NS_STREAM_MGMT_3)), + send_element(StateData, #sm_failed{reason = 'unexpected-request', + xmlns = ?NS_STREAM_MGMT_3}), StateData; -negotiate_stream_mgmt(#xmlel{name = Name, attrs = Attrs}, StateData) -> - case fxml:get_attr_s(<<"xmlns">>, Attrs) of - Xmlns when ?IS_SUPPORTED_MGMT_XMLNS(Xmlns) -> - case stream_mgmt_enabled(StateData) of - true -> - case Name of - <<"enable">> -> - handle_enable(StateData#state{mgmt_xmlns = Xmlns}, Attrs); - _ -> - Res = if Name == <<"a">>; - Name == <<"r">>; - Name == <<"resume">> -> - ?MGMT_UNEXPECTED_REQUEST(Xmlns); - true -> - ?MGMT_BAD_REQUEST(Xmlns) - end, - send_element(StateData, Res), - StateData - end; - false -> - send_element(StateData, ?MGMT_SERVICE_UNAVAILABLE(Xmlns)), - StateData - end; - _ -> - send_element(StateData, ?MGMT_UNSUPPORTED_VERSION(?NS_STREAM_MGMT_3)), - StateData +negotiate_stream_mgmt(Pkt, StateData) -> + Xmlns = xmpp:get_ns(Pkt), + case stream_mgmt_enabled(StateData) of + true -> + case Pkt of + #sm_enable{} -> + handle_enable(StateData#state{mgmt_xmlns = Xmlns}, Pkt); + _ -> + Res = if is_record(Pkt, sm_a); + is_record(Pkt, sm_r); + is_record(Pkt, sm_resume) -> + #sm_failed{reason = 'unexpected-request', + xmlns = Xmlns}; + true -> + #sm_failed{reason = 'bad-request', + xmlns = Xmlns} + end, + send_element(StateData, Res), + StateData + end; + false -> + send_element(StateData, + #sm_failed{reason = 'service-unavailable', + xmlns = Xmlns}), + StateData end. -perform_stream_mgmt(#xmlel{name = Name, attrs = Attrs}, StateData) -> - case fxml:get_attr_s(<<"xmlns">>, Attrs) of - Xmlns when Xmlns == StateData#state.mgmt_xmlns -> - case Name of - <<"r">> -> - handle_r(StateData); - <<"a">> -> - handle_a(StateData, Attrs); - _ -> - Res = if Name == <<"enable">>; - Name == <<"resume">> -> - ?MGMT_UNEXPECTED_REQUEST(Xmlns); - true -> - ?MGMT_BAD_REQUEST(Xmlns) - end, - send_element(StateData, Res), - StateData - end; - _ -> - send_element(StateData, - ?MGMT_UNSUPPORTED_VERSION(StateData#state.mgmt_xmlns)), - StateData +perform_stream_mgmt(Pkt, StateData) -> + case xmpp:get_ns(Pkt) of + Xmlns when Xmlns == StateData#state.mgmt_xmlns -> + case Pkt of + #sm_r{} -> + handle_r(StateData); + #sm_a{} -> + handle_a(StateData, Pkt); + _ -> + Res = if is_record(Pkt, sm_enable); + is_record(Pkt, sm_resume) -> + #sm_failed{reason = 'unexpected-request', + xmlns = Xmlns}; + true -> + #sm_failed{reason = 'bad-request', + xmlns = Xmlns} + end, + send_element(StateData, Res), + StateData + end; + _ -> + send_element(StateData, + #sm_failed{reason = 'unsupported-version', + xmlns = StateData#state.mgmt_xmlns}) end. handle_enable(#state{mgmt_timeout = DefaultTimeout, - mgmt_max_timeout = MaxTimeout} = StateData, Attrs) -> - Timeout = case fxml:get_attr_s(<<"resume">>, Attrs) of - ResumeAttr when ResumeAttr == <<"true">>; - ResumeAttr == <<"1">> -> - MaxAttr = fxml:get_attr_s(<<"max">>, Attrs), - case catch jlib:binary_to_integer(MaxAttr) of - Max when is_integer(Max), Max > 0, Max =< MaxTimeout -> - Max; - _ -> - DefaultTimeout - end; - _ -> - 0 + mgmt_max_timeout = MaxTimeout} = StateData, + #sm_enable{resume = Resume, max = Max}) -> + Timeout = if Resume == false -> + 0; + Max /= undefined, Max > 0, Max =< MaxTimeout -> + Max; + true -> + DefaultTimeout end, - ResAttrs = [{<<"xmlns">>, StateData#state.mgmt_xmlns}] ++ - if Timeout > 0 -> - ?INFO_MSG("Stream management with resumption enabled for ~s", - [jid:to_string(StateData#state.jid)]), - [{<<"id">>, make_resume_id(StateData)}, - {<<"resume">>, <<"true">>}, - {<<"max">>, jlib:integer_to_binary(Timeout)}]; - true -> - ?INFO_MSG("Stream management without resumption enabled for ~s", - [jid:to_string(StateData#state.jid)]), - [] - end, - Res = #xmlel{name = <<"enabled">>, - attrs = ResAttrs, - children = []}, + Res = if Timeout > 0 -> + ?INFO_MSG("Stream management with resumption enabled for ~s", + [jid:to_string(StateData#state.jid)]), + #sm_enabled{xmlns = StateData#state.mgmt_xmlns, + id = make_resume_id(StateData), + resume = true, + max = Timeout}; + true -> + ?INFO_MSG("Stream management without resumption enabled for ~s", + [jid:to_string(StateData#state.jid)]), + #sm_enabled{xmlns = StateData#state.mgmt_xmlns} + end, send_element(StateData, Res), StateData#state{mgmt_state = active, mgmt_queue = queue:new(), mgmt_timeout = Timeout * 1000}. handle_r(StateData) -> - H = jlib:integer_to_binary(StateData#state.mgmt_stanzas_in), - Res = #xmlel{name = <<"a">>, - attrs = [{<<"xmlns">>, StateData#state.mgmt_xmlns}, - {<<"h">>, H}], - children = []}, + Res = #sm_a{xmlns = StateData#state.mgmt_xmlns, + h = StateData#state.mgmt_stanzas_in}, send_element(StateData, Res), StateData. -handle_a(StateData, Attrs) -> - case catch jlib:binary_to_integer(fxml:get_attr_s(<<"h">>, Attrs)) of - H when is_integer(H), H >= 0 -> - check_h_attribute(StateData, H); - _ -> - ?DEBUG("Ignoring invalid ACK element from ~s", - [jid:to_string(StateData#state.jid)]), - StateData - end. +handle_a(StateData, #sm_a{h = H}) -> + check_h_attribute(StateData, H). -handle_resume(StateData, Attrs) -> - R = case fxml:get_attr_s(<<"xmlns">>, Attrs) of - Xmlns when ?IS_SUPPORTED_MGMT_XMLNS(Xmlns) -> - case stream_mgmt_enabled(StateData) of - true -> - case {fxml:get_attr(<<"previd">>, Attrs), - catch jlib:binary_to_integer(fxml:get_attr_s(<<"h">>, Attrs))} - of - {{value, PrevID}, H} when is_integer(H), H >= 0 -> - case inherit_session_state(StateData, PrevID) of - {ok, InheritedState} -> - {ok, InheritedState, H}; - {error, Err, InH} -> - {error, ?MGMT_ITEM_NOT_FOUND_H(Xmlns, InH), Err}; - {error, Err} -> - {error, ?MGMT_ITEM_NOT_FOUND(Xmlns), Err} - end; - _ -> - {error, ?MGMT_BAD_REQUEST(Xmlns), - <<"Invalid request">>} - end; - false -> - {error, ?MGMT_SERVICE_UNAVAILABLE(Xmlns), - <<"XEP-0198 disabled">>} - end; - _ -> - {error, ?MGMT_UNSUPPORTED_VERSION(?NS_STREAM_MGMT_3), - <<"Invalid XMLNS">>} +handle_resume(StateData, #sm_resume{h = H, previd = PrevID, xmlns = Xmlns}) -> + R = case stream_mgmt_enabled(StateData) of + true -> + case inherit_session_state(StateData, PrevID) of + {ok, InheritedState} -> + {ok, InheritedState, H}; + {error, Err, InH} -> + {error, #sm_failed{reason = 'item-not-found', + h = InH, xmlns = Xmlns}, Err}; + {error, Err} -> + {error, #sm_failed{reason = 'item-not-found', + xmlns = Xmlns}, Err} + end; + false -> + {error, #sm_failed{reason = 'service-unavailable', + xmlns = Xmlns}, + <<"XEP-0198 disabled">>} end, case R of {ok, ResumedState, NumHandled} -> NewState = check_h_attribute(ResumedState, NumHandled), AttrXmlns = NewState#state.mgmt_xmlns, AttrId = make_resume_id(NewState), - AttrH = jlib:integer_to_binary(NewState#state.mgmt_stanzas_in), - send_element(NewState, - #xmlel{name = <<"resumed">>, - attrs = [{<<"xmlns">>, AttrXmlns}, - {<<"h">>, AttrH}, - {<<"previd">>, AttrId}], - children = []}), + AttrH = NewState#state.mgmt_stanzas_in, + send_element(NewState, #sm_resumed{xmlns = AttrXmlns, + h = AttrH, + previd = AttrId}), SendFun = fun(_F, _T, El, Time) -> NewEl = add_resent_delay_info(NewState, El, Time), send_element(NewState, NewEl) end, handle_unacked_stanzas(NewState, SendFun), - send_element(NewState, - #xmlel{name = <<"r">>, - attrs = [{<<"xmlns">>, AttrXmlns}], - children = []}), + send_element(NewState, #sm_r{xmlns = AttrXmlns}), FlushedState = csi_flush_queue(NewState), NewStateData = FlushedState#state{csi_state = active}, ?INFO_MSG("Resumed session for ~s", @@ -2810,7 +2391,7 @@ check_h_attribute(#state{mgmt_stanzas_out = NumStanzasOut} = StateData, H) -> update_num_stanzas_in(#state{mgmt_state = MgmtState} = StateData, El) when MgmtState == active; MgmtState == pending -> - NewNum = case {is_stanza(El), StateData#state.mgmt_stanzas_in} of + NewNum = case {xmpp:is_stanza(El), StateData#state.mgmt_stanzas_in} of {true, 4294967295} -> 0; {true, Num} -> @@ -2823,9 +2404,7 @@ update_num_stanzas_in(StateData, _El) -> StateData. send_stanza_and_ack_req(StateData, Stanza) -> - AckReq = #xmlel{name = <<"r">>, - attrs = [{<<"xmlns">>, StateData#state.mgmt_xmlns}], - children = []}, + AckReq = #sm_r{xmlns = StateData#state.mgmt_xmlns}, case send_element(StateData, Stanza) == ok andalso send_element(StateData, AckReq) == ok of true -> @@ -2876,12 +2455,10 @@ handle_unacked_stanzas(#state{mgmt_state = MgmtState} = StateData, F) ?DEBUG("~B stanza(s) were not acknowledged by ~s", [N, jid:to_string(StateData#state.jid)]), lists:foreach( - fun({_, Time, #xmlel{attrs = Attrs} = El}) -> - From_s = fxml:get_attr_s(<<"from">>, Attrs), - From = jid:from_string(From_s), - To_s = fxml:get_attr_s(<<"to">>, Attrs), - To = jid:from_string(To_s), - F(From, To, El, Time) + fun({_, Time, Pkt}) -> + From = xmpp:get_from(Pkt), + To = xmpp:get_to(Pkt), + F(From, To, Pkt, Time) end, queue:to_list(Queue)) end; handle_unacked_stanzas(_StateData, _F) -> @@ -2917,20 +2494,18 @@ handle_unacked_stanzas(#state{mgmt_state = MgmtState} = StateData) false -> fun(From, To, El, _Time) -> Txt = <<"User session terminated">>, - Err = - jlib:make_error_reply( - El, - ?ERRT_SERVICE_UNAVAILABLE(Lang, Txt)), + Err = xmpp:make_error( + El, xmpp:err_service_unavailable(Txt, Lang)), ejabberd_router:route(To, From, Err) end end, - F = fun(From, _To, #xmlel{name = <<"presence">>}, _Time) -> + F = fun(From, _To, #presence{}, _Time) -> ?DEBUG("Dropping presence stanza from ~s", [jid:to_string(From)]); - (From, To, #xmlel{name = <<"iq">>} = El, _Time) -> + (From, To, #iq{} = El, _Time) -> Txt = <<"User session terminated">>, - Err = jlib:make_error_reply( - El, ?ERRT_SERVICE_UNAVAILABLE(Lang, Txt)), + Err = xmpp:make_error( + El, xmpp:err_service_unavailable(Txt, Lang)), ejabberd_router:route(To, From, Err); (From, To, El, Time) -> %% We'll drop the stanza if it was by some @@ -2943,7 +2518,7 @@ handle_unacked_stanzas(#state{mgmt_state = MgmtState} = StateData) case is_encapsulated_forward(El) of true -> ?DEBUG("Dropping forwarded message stanza from ~s", - [fxml:get_attr_s(<<"from">>, El#xmlel.attrs)]); + [jid:to_string(From)]); false -> case ejabberd_hooks:run_fold(message_is_archived, StateData#state.server, @@ -2961,29 +2536,10 @@ handle_unacked_stanzas(#state{mgmt_state = MgmtState} = StateData) handle_unacked_stanzas(_StateData) -> ok. -is_encapsulated_forward(#xmlel{name = <<"message">>} = El) -> - SubTag = case {fxml:get_subtag(El, <<"sent">>), - fxml:get_subtag(El, <<"received">>), - fxml:get_subtag(El, <<"result">>)} of - {false, false, false} -> - false; - {Tag, false, false} -> - Tag; - {false, Tag, false} -> - Tag; - {_, _, Tag} -> - Tag - end, - if SubTag == false -> - false; - true -> - case fxml:get_subtag(SubTag, <<"forwarded">>) of - false -> - false; - _ -> - true - end - end; +is_encapsulated_forward(#message{} = Msg) -> + xmpp:has_subtag(Msg, #forwarded{}) orelse + xmpp:has_subtag(Msg, #carbons_sent{}) orelse + xmpp:has_subtag(Msg, #carbons_received{}); is_encapsulated_forward(_El) -> false. @@ -3054,10 +2610,10 @@ make_resume_id(StateData) -> {Time, _} = StateData#state.sid, jlib:term_to_base64({StateData#state.resource, Time}). -add_resent_delay_info(_State, #xmlel{name = <<"iq">>} = El, _Time) -> +add_resent_delay_info(_State, #iq{} = El, _Time) -> El; add_resent_delay_info(#state{server = From}, El, Time) -> - jlib:add_delay_info(El, From, Time, <<"Resent">>). + xmpp_util:add_delay_info(El, From, Time, <<"Resent">>). %%%---------------------------------------------------------------------- %%% XEP-0352 diff --git a/src/ejabberd_frontend_socket.erl b/src/ejabberd_frontend_socket.erl index b8e706f23..ab5b6a701 100644 --- a/src/ejabberd_frontend_socket.erl +++ b/src/ejabberd_frontend_socket.erl @@ -42,6 +42,7 @@ change_shaper/2, monitor/1, get_sockmod/1, + get_transport/1, get_peer_certificate/1, get_verify_result/1, close/1, @@ -118,6 +119,9 @@ monitor(FsmRef) -> erlang:monitor(process, FsmRef). get_sockmod(FsmRef) -> gen_server:call(FsmRef, get_sockmod). +get_transport(FsmRef) -> + gen_server:call(FsmRef, get_transport). + get_peer_certificate(FsmRef) -> gen_server:call(FsmRef, get_peer_certificate). @@ -186,6 +190,19 @@ handle_call({change_shaper, Shaper}, _From, State) -> handle_call(get_sockmod, _From, State) -> Reply = State#state.sockmod, {reply, Reply, State, ?HIBERNATE_TIMEOUT}; +handle_call(get_transport, _From, State) -> + Reply = case State#state.sockmod of + gen_tcp -> tcp; + fast_tls -> tls; + ezlib -> + case ezlib:get_sockmod(State#state.socket) of + tcp -> tcp_zlib; + tls -> tls_zlib + end; + ejabberd_http_bind -> http_bind; + ejabberd_http_ws -> websocket + end, + {reply, Reply, State, ?HIBERNATE_TIMEOUT}; handle_call(get_peer_certificate, _From, State) -> Reply = fast_tls:get_peer_certificate(State#state.socket), {reply, Reply, State, ?HIBERNATE_TIMEOUT}; diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index 2ba943693..dca456427 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -46,7 +46,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -record(state, {}). @@ -60,6 +60,8 @@ %% This value is used in SIP and Megaco for a transaction lifetime. -define(IQ_TIMEOUT, 32000). +-type ping_timeout() :: non_neg_integer() | undefined. + %%==================================================================== %% API %%==================================================================== @@ -71,37 +73,38 @@ start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). -process_iq(From, To, Packet) -> - IQ = jlib:iq_query_info(Packet), - case IQ of - #iq{xmlns = XMLNS, lang = Lang} -> - Host = To#jid.lserver, - case ets:lookup(?IQTABLE, {XMLNS, Host}) of - [{_, Module, Function}] -> - ResIQ = Module:Function(From, To, IQ), - if ResIQ /= ignore -> - ejabberd_router:route(To, From, jlib:iq_to_xml(ResIQ)); - true -> ok - end; - [{_, Module, Function, Opts}] -> - gen_iq_handler:handle(Host, Module, Function, Opts, - From, To, IQ); - [] -> - Txt = <<"No module is handling this query">>, - Err = jlib:make_error_reply( - Packet, - ?ERRT_FEATURE_NOT_IMPLEMENTED(Lang, Txt)), - ejabberd_router:route(To, From, Err) - end; - reply -> - IQReply = jlib:iq_query_or_response_info(Packet), - process_iq_reply(From, To, IQReply); - _ -> - Err = jlib:make_error_reply(Packet, ?ERR_BAD_REQUEST), - ejabberd_router:route(To, From, Err), - ok +-spec process_iq(jid(), jid(), iq()) -> any(). +process_iq(From, To, #iq{type = T, lang = Lang, sub_els = [El]} = Packet) + when T == get; T == set -> + XMLNS = xmpp:get_ns(El), + Host = To#jid.lserver, + case ets:lookup(?IQTABLE, {XMLNS, Host}) of + [{_, Module, Function}] -> + gen_iq_handler:handle(Host, Module, Function, no_queue, + From, To, Packet); + [{_, Module, Function, Opts}] -> + gen_iq_handler:handle(Host, Module, Function, Opts, + From, To, Packet); + [] -> + Txt = <<"No module is handling this query">>, + Err = xmpp:make_error( + Packet, + xmpp:err_service_unavailable(Txt, Lang)), + ejabberd_router:route(To, From, Err) + end; +process_iq(From, To, #iq{type = T} = Packet) when T == get; T == set -> + Err = xmpp:make_error(Packet, xmpp:err_bad_request()), + ejabberd_router:route(To, From, Err); +process_iq(From, To, #iq{type = T} = Packet) when T == result; T == error -> + try + NewPacket = xmpp:decode_els(Packet), + process_iq_reply(From, To, NewPacket) + catch _:{xmpp_codec, Why} -> + ?DEBUG("failed to decode iq-result ~p: ~s", + [Packet, xmpp:format_error(Why)]) end. +-spec process_iq_reply(jid(), jid(), iq()) -> any(). process_iq_reply(From, To, #iq{id = ID} = IQ) -> case get_iq_callback(ID) of {ok, undefined, Function} -> Function(IQ), ok; @@ -110,6 +113,7 @@ process_iq_reply(From, To, #iq{id = ID} = IQ) -> _ -> nothing end. +-spec route(jid(), jid(), stanza()) -> any(). route(From, To, Packet) -> case catch do_route(From, To, Packet) of {'EXIT', Reason} -> @@ -118,26 +122,32 @@ route(From, To, Packet) -> _ -> ok end. +-spec route_iq(jid(), jid(), iq(), function()) -> any(). route_iq(From, To, IQ, F) -> route_iq(From, To, IQ, F, undefined). +-spec route_iq(jid(), jid(), iq(), function(), ping_timeout()) -> any(). route_iq(From, To, #iq{type = Type} = IQ, F, Timeout) when is_function(F) -> Packet = if Type == set; Type == get -> ID = randoms:get_string(), Host = From#jid.lserver, register_iq_response_handler(Host, ID, undefined, F, Timeout), - jlib:iq_to_xml(IQ#iq{id = ID}); + IQ#iq{id = ID}; true -> - jlib:iq_to_xml(IQ) + IQ end, ejabberd_router:route(From, To, Packet). +-spec register_iq_response_handler(binary(), binary(), module(), + atom() | function()) -> any(). register_iq_response_handler(Host, ID, Module, Function) -> register_iq_response_handler(Host, ID, Module, Function, undefined). +-spec register_iq_response_handler(binary(), binary(), module(), + atom() | function(), ping_timeout()) -> any(). register_iq_response_handler(_Host, ID, Module, Function, Timeout0) -> Timeout = case Timeout0 of @@ -150,28 +160,35 @@ register_iq_response_handler(_Host, ID, Module, function = Function, timer = TRef}). +-spec register_iq_handler(binary(), binary(), module(), function()) -> any(). register_iq_handler(Host, XMLNS, Module, Fun) -> ejabberd_local ! {register_iq_handler, Host, XMLNS, Module, Fun}. +-spec register_iq_handler(binary(), binary(), module(), function(), + gen_iq_handler:opts()) -> any(). register_iq_handler(Host, XMLNS, Module, Fun, Opts) -> ejabberd_local ! {register_iq_handler, Host, XMLNS, Module, Fun, Opts}. +-spec unregister_iq_response_handler(binary(), binary()) -> ok. unregister_iq_response_handler(_Host, ID) -> catch get_iq_callback(ID), ok. +-spec unregister_iq_handler(binary(), binary()) -> any(). unregister_iq_handler(Host, XMLNS) -> ejabberd_local ! {unregister_iq_handler, Host, XMLNS}. +-spec refresh_iq_handlers() -> any(). refresh_iq_handlers() -> ejabberd_local ! refresh_iq_handlers. +-spec bounce_resource_packet(jid(), jid(), stanza()) -> stop. bounce_resource_packet(From, To, Packet) -> - Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), + Lang = xmpp:get_lang(Packet), Txt = <<"No available resource found">>, - Err = jlib:make_error_reply(Packet, - ?ERRT_ITEM_NOT_FOUND(Lang, Txt)), + Err = xmpp:make_error(Packet, + xmpp:err_item_not_found(Txt, Lang)), ejabberd_router:route(To, From, Err), stop. @@ -261,50 +278,45 @@ code_change(_OldVsn, State, _Extra) -> %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- +-spec do_route(jid(), jid(), stanza()) -> any(). do_route(From, To, Packet) -> ?DEBUG("local route~n\tfrom ~p~n\tto ~p~n\tpacket " "~P~n", [From, To, Packet, 8]), if To#jid.luser /= <<"">> -> - ejabberd_sm:route(From, To, Packet); + ejabberd_sm:route(From, To, Packet); To#jid.lresource == <<"">> -> - #xmlel{name = Name} = Packet, - case Name of - <<"iq">> -> process_iq(From, To, Packet); - <<"message">> -> - #xmlel{attrs = Attrs} = Packet, - case fxml:get_attr_s(<<"type">>, Attrs) of - <<"headline">> -> ok; - <<"error">> -> ok; - _ -> - Err = jlib:make_error_reply(Packet, - ?ERR_SERVICE_UNAVAILABLE), - ejabberd_router:route(To, From, Err) - end; - <<"presence">> -> ok; - _ -> ok - end; + case Packet of + #iq{} -> + process_iq(From, To, Packet); + #message{type = T} when T /= headline, T /= error -> + Err = xmpp:make_error(Packet, xmpp:err_service_unavailable()), + ejabberd_router:route(To, From, Err); + _ -> ok + end; true -> - #xmlel{attrs = Attrs} = Packet, - case fxml:get_attr_s(<<"type">>, Attrs) of - <<"error">> -> ok; - <<"result">> -> ok; - _ -> - ejabberd_hooks:run(local_send_to_resource_hook, - To#jid.lserver, [From, To, Packet]) - end + case xmpp:get_type(Packet) of + error -> ok; + result -> ok; + _ -> + ejabberd_hooks:run(local_send_to_resource_hook, + To#jid.lserver, [From, To, Packet]) + end end. +-spec update_table() -> ok. update_table() -> case catch mnesia:table_info(iq_response, attributes) of [id, module, function] -> - mnesia:delete_table(iq_response); + mnesia:delete_table(iq_response), + ok; [id, module, function, timer] -> ok; {'EXIT', _} -> ok end. +-spec get_iq_callback(binary()) -> {ok, module(), atom() | function()} | error. get_iq_callback(ID) -> case mnesia:dirty_read(iq_response, ID) of [#iq_response{module = Module, timer = TRef, @@ -316,9 +328,11 @@ get_iq_callback(ID) -> error end. +-spec process_iq_timeout(binary()) -> any(). process_iq_timeout(ID) -> spawn(fun process_iq_timeout/0) ! ID. +-spec process_iq_timeout() -> any(). process_iq_timeout() -> receive ID -> @@ -332,6 +346,7 @@ process_iq_timeout() -> ok end. +-spec cancel_timer(reference()) -> ok. cancel_timer(TRef) -> case erlang:cancel_timer(TRef) of false -> diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl index e29d6acfb..5924d92c0 100644 --- a/src/ejabberd_router.erl +++ b/src/ejabberd_router.erl @@ -39,6 +39,7 @@ register_route/3, register_routes/1, host_of_route/1, + process_iq/3, unregister_route/1, unregister_routes/1, dirty_get_all_routes/0, @@ -53,7 +54,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -type local_hint() :: undefined | integer() | {apply, atom(), atom()}. @@ -71,7 +72,7 @@ start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). --spec route(jid(), jid(), xmlel()) -> ok. +-spec route(jid(), jid(), xmlel() | xmpp_element()) -> ok. route(From, To, Packet) -> case catch do_route(From, To, Packet) of @@ -236,6 +237,28 @@ host_of_route(Domain) -> end end. +-spec process_iq(jid(), jid(), iq() | xmlel()) -> any(). +process_iq(From, To, #iq{} = IQ) -> + if To#jid.luser == <<"">> -> + ejabberd_local:process_iq(From, To, IQ); + true -> + ejabberd_sm:process_iq(From, To, IQ) + end; +process_iq(From, To, El) -> + try xmpp:decode(El, [ignore_els]) of + IQ -> process_iq(From, To, IQ) + catch _:{xmpp_codec, Why} -> + Type = xmpp:get_type(El), + if Type == <<"get">>; Type == <<"set">> -> + Txt = xmpp:format_error(Why), + Lang = xmpp:get_lang(El), + Err = xmpp:make_error(El, xmpp:err_bad_request(Txt, Lang)), + ejabberd_router:route(To, From, Err); + true -> + ok + end + end. + %%==================================================================== %% gen_server callbacks %%==================================================================== @@ -347,6 +370,7 @@ code_change(_OldVsn, State, _Extra) -> %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- +-spec do_route(jid(), jid(), xmlel() | xmpp_element()) -> any(). do_route(OrigFrom, OrigTo, OrigPacket) -> ?DEBUG("route~n\tfrom ~p~n\tto ~p~n\tpacket " "~p~n", @@ -359,67 +383,66 @@ do_route(OrigFrom, OrigTo, OrigPacket) -> case mnesia:dirty_read(route, LDstDomain) of [] -> ejabberd_s2s:route(From, To, Packet); [R] -> - Pid = R#route.pid, - if node(Pid) == node() -> - case R#route.local_hint of - {apply, Module, Function} -> - Module:Function(From, To, Packet); - _ -> Pid ! {route, From, To, Packet} - end; - is_pid(Pid) -> Pid ! {route, From, To, Packet}; - true -> drop - end; + do_route(From, To, Packet, R); Rs -> - Value = case - ejabberd_config:get_option({domain_balancing, - LDstDomain}, fun(D) when is_atom(D) -> D end) - of - undefined -> p1_time_compat:monotonic_time(); - random -> p1_time_compat:monotonic_time(); - source -> jid:tolower(From); - destination -> jid:tolower(To); - bare_source -> - jid:remove_resource(jid:tolower(From)); - bare_destination -> - jid:remove_resource(jid:tolower(To)) - end, + Value = get_domain_balancing(From, To, LDstDomain), case get_component_number(LDstDomain) of undefined -> case [R || R <- Rs, node(R#route.pid) == node()] of [] -> R = lists:nth(erlang:phash(Value, length(Rs)), Rs), - Pid = R#route.pid, - if is_pid(Pid) -> Pid ! {route, From, To, Packet}; - true -> drop - end; + do_route(From, To, Packet, R); LRs -> - R = lists:nth(erlang:phash(Value, length(LRs)), - LRs), - Pid = R#route.pid, - case R#route.local_hint of - {apply, Module, Function} -> - Module:Function(From, To, Packet); - _ -> Pid ! {route, From, To, Packet} - end + R = lists:nth(erlang:phash(Value, length(LRs)), LRs), + do_route(From, To, Packet, R) end; _ -> SRs = lists:ukeysort(#route.local_hint, Rs), R = lists:nth(erlang:phash(Value, length(SRs)), SRs), - Pid = R#route.pid, - if is_pid(Pid) -> Pid ! {route, From, To, Packet}; - true -> drop - end + do_route(From, To, Packet, R) end end; drop -> ok end. +-spec do_route(jid(), jid(), xmlel() | xmpp_element(), #route{}) -> any(). +do_route(From, To, Packet, + #route{local_hint = {apply, Module, Function}, pid = Pid}) + when is_pid(Pid) andalso node(Pid) == node() -> + try + Module:Function(From, To, xmpp:decode(Packet, [ignore_els])) + catch error:{xmpp_codec, Why} -> + ?ERROR_MSG("failed to decode xml element ~p when " + "routing from ~s to ~s: ~s", + [Packet, jid:to_string(From), jid:to_string(To), + xmpp:format_error(Why)]), + drop + end; +do_route(From, To, Packet, #route{pid = Pid}) when is_pid(Pid) -> + Pid ! {route, From, To, xmpp:encode(Packet)}; +do_route(_From, _To, _Packet, _Route) -> + drop. + +-spec get_component_number(binary()) -> pos_integer() | undefined. get_component_number(LDomain) -> ejabberd_config:get_option( {domain_balancing_component_number, LDomain}, fun(N) when is_integer(N), N > 1 -> N end, undefined). +-spec get_domain_balancing(jid(), jid(), binary()) -> any(). +get_domain_balancing(From, To, LDomain) -> + case ejabberd_config:get_option( + {domain_balancing, LDomain}, fun(D) when is_atom(D) -> D end) of + undefined -> p1_time_compat:monotonic_time(); + random -> p1_time_compat:monotonic_time(); + source -> jid:tolower(From); + destination -> jid:tolower(To); + bare_source -> jid:remove_resource(jid:tolower(From)); + bare_destination -> jid:remove_resource(jid:tolower(To)) + end. + +-spec update_tables() -> ok. update_tables() -> try mnesia:transform_table(route, ignore, record_info(fields, route)) diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 8d94bc6aa..ec9ef43c6 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -78,7 +78,8 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +%%-include("jlib.hrl"). +-include("xmpp.hrl"). -include("ejabberd_commands.hrl"). -include("mod_privacy.hrl"). @@ -98,6 +99,15 @@ %% default value for the maximum number of user connections -define(MAX_USER_SESSIONS, infinity). +-type broadcast() :: {broadcast, broadcast_data()}. + +-type broadcast_data() :: + {rebind, pid(), binary()} | %% ejabberd_c2s + {item, ljid(), mod_roster:subscription()} | %% mod_roster/mod_shared_roster + {exit, binary()} | %% mod_roster/mod_shared_roster + {privacy_list, mod_privacy:userlist(), binary()} | %% mod_privacy + {blocking, unblock_all | {block | unblock, [ljid()]}}. %% mod_blocking + %%==================================================================== %% API %%==================================================================== @@ -111,7 +121,7 @@ start() -> start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). --spec route(jid(), jid(), xmlel() | broadcast()) -> ok. +-spec route(jid(), jid(), stanza() | broadcast()) -> ok. route(From, To, Packet) -> case catch do_route(From, To, Packet) of @@ -162,10 +172,10 @@ check_in_subscription(Acc, User, Server, _JID, _Type, _Reason) -> -spec bounce_offline_message(jid(), jid(), xmlel()) -> stop. bounce_offline_message(From, To, Packet) -> - Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), + Lang = xmpp:get_lang(Packet), Txt = <<"User session not found">>, - Err = jlib:make_error_reply( - Packet, ?ERRT_SERVICE_UNAVAILABLE(Lang, Txt)), + Err = xmpp:make_error( + Packet, xmpp:err_service_unavailable(Txt, Lang)), ejabberd_router:route(To, From, Err), stop. @@ -432,7 +442,7 @@ online(Sessions) -> end, Sessions). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - +-spec do_route(jid(), jid(), stanza() | broadcast()) -> any(). do_route(From, To, {broadcast, _} = Packet) -> case To#jid.lresource of <<"">> -> @@ -455,25 +465,20 @@ do_route(From, To, {broadcast, _} = Packet) -> Pid ! {route, From, To, Packet} end end; -do_route(From, To, #xmlel{} = Packet) -> +do_route(From, To, Packet) -> ?DEBUG("session manager~n\tfrom ~p~n\tto ~p~n\tpacket " "~P~n", [From, To, Packet, 8]), #jid{user = User, server = Server, luser = LUser, lserver = LServer, lresource = LResource} = To, - #xmlel{name = Name, attrs = Attrs} = Packet, - Lang = fxml:get_attr_s(<<"xml:lang">>, Attrs), + Lang = xmpp:get_lang(Packet), case LResource of <<"">> -> - case Name of - <<"presence">> -> - {Pass, _Subsc} = case fxml:get_attr_s(<<"type">>, Attrs) - of - <<"subscribe">> -> - Reason = fxml:get_path_s(Packet, - [{elem, - <<"status">>}, - cdata]), + case Packet of + #presence{type = T, status = Status} -> + {Pass, _Subsc} = case T of + subscribe -> + Reason = xmpp:get_text(Status), {is_privacy_allow(From, To, Packet) andalso ejabberd_hooks:run_fold(roster_in_subscription, @@ -484,7 +489,7 @@ do_route(From, To, #xmlel{} = Packet) -> subscribe, Reason]), true}; - <<"subscribed">> -> + subscribed -> {is_privacy_allow(From, To, Packet) andalso ejabberd_hooks:run_fold(roster_in_subscription, @@ -495,7 +500,7 @@ do_route(From, To, #xmlel{} = Packet) -> subscribed, <<"">>]), true}; - <<"unsubscribe">> -> + unsubscribe -> {is_privacy_allow(From, To, Packet) andalso ejabberd_hooks:run_fold(roster_in_subscription, @@ -506,7 +511,7 @@ do_route(From, To, #xmlel{} = Packet) -> unsubscribe, <<"">>]), true}; - <<"unsubscribed">> -> + unsubscribed -> {is_privacy_allow(From, To, Packet) andalso ejabberd_hooks:run_fold(roster_in_subscription, @@ -530,53 +535,36 @@ do_route(From, To, #xmlel{} = Packet) -> PResources); true -> ok end; - <<"message">> -> - case fxml:get_attr_s(<<"type">>, Attrs) of - <<"chat">> -> route_message(From, To, Packet, chat); - <<"headline">> -> route_message(From, To, Packet, headline); - <<"error">> -> ok; - <<"groupchat">> -> - ErrTxt = <<"User session not found">>, - Err = jlib:make_error_reply( - Packet, ?ERRT_SERVICE_UNAVAILABLE(Lang, ErrTxt)), - ejabberd_router:route(To, From, Err); - _ -> - route_message(From, To, Packet, normal) - end; - <<"iq">> -> process_iq(From, To, Packet); - _ -> ok + #message{type = T} when T == chat; T == headline; T == normal -> + route_message(From, To, Packet, T); + #message{type = groupchat} -> + ErrTxt = <<"User session not found">>, + Err = xmpp:make_error( + Packet, xmpp:err_service_unavailable(ErrTxt, Lang)), + ejabberd_router:route(To, From, Err); + #iq{} -> process_iq(From, To, Packet); + _ -> ok end; _ -> Mod = get_sm_backend(LServer), case online(Mod:get_sessions(LUser, LServer, LResource)) of [] -> - case Name of - <<"message">> -> - case fxml:get_attr_s(<<"type">>, Attrs) of - <<"chat">> -> route_message(From, To, Packet, chat); - <<"headline">> -> ok; - <<"error">> -> ok; - <<"groupchat">> -> - ErrTxt = <<"User session not found">>, - Err = jlib:make_error_reply( - Packet, - ?ERRT_SERVICE_UNAVAILABLE(Lang, ErrTxt)), - ejabberd_router:route(To, From, Err); - _ -> - route_message(From, To, Packet, normal) - end; - <<"iq">> -> - case fxml:get_attr_s(<<"type">>, Attrs) of - <<"error">> -> ok; - <<"result">> -> ok; - _ -> - ErrTxt = <<"User session not found">>, - Err = jlib:make_error_reply( - Packet, - ?ERRT_SERVICE_UNAVAILABLE(Lang, ErrTxt)), - ejabberd_router:route(To, From, Err) - end; - _ -> ?DEBUG("packet dropped~n", []) + case Packet of + #message{type = T} when T == chat; T == normal -> + route_message(From, To, Packet, T); + #message{type = groupchat} -> + ErrTxt = <<"User session not found">>, + Err = xmpp:make_error( + Packet, + xmpp:err_service_unavailable(ErrTxt, Lang)), + ejabberd_router:route(To, From, Err); + #iq{type = T} when T == get; T == set -> + ErrTxt = <<"User session not found">>, + Err = xmpp:make_error( + Packet, + xmpp:err_service_unavailable(ErrTxt, Lang)), + ejabberd_router:route(To, From, Err); + _ -> ?DEBUG("packet dropped~n", []) end; Ss -> Session = lists:max(Ss), @@ -590,6 +578,7 @@ do_route(From, To, #xmlel{} = Packet) -> %% and is processed if there is no active list set %% for the target session/resource to which a stanza is addressed, %% or if there are no current sessions for the user. +-spec is_privacy_allow(jid(), jid(), stanza()) -> boolean(). is_privacy_allow(From, To, Packet) -> User = To#jid.user, Server = To#jid.server, @@ -600,6 +589,7 @@ is_privacy_allow(From, To, Packet) -> %% Check if privacy rules allow this delivery %% Function copied from ejabberd_c2s.erl +-spec is_privacy_allow(jid(), jid(), stanza(), #userlist{}) -> boolean(). is_privacy_allow(From, To, Packet, PrivacyList) -> User = To#jid.user, Server = To#jid.server, @@ -609,6 +599,7 @@ is_privacy_allow(From, To, Packet, PrivacyList) -> [User, Server, PrivacyList, {From, To, Packet}, in]). +-spec route_message(jid(), jid(), message(), message_type()) -> any(). route_message(From, To, Packet, Type) -> LUser = To#jid.luser, LServer = To#jid.lserver, @@ -644,18 +635,19 @@ route_message(From, To, Packet, Type) -> ejabberd_hooks:run(offline_message_hook, LServer, [From, To, Packet]); false -> - Err = jlib:make_error_reply(Packet, - ?ERR_SERVICE_UNAVAILABLE), + Err = xmpp:make_error(Packet, + xmpp:err_service_unavailable()), ejabberd_router:route(To, From, Err) end end end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - +-spec clean_session_list([#session{}]) -> [#session{}]. clean_session_list(Ss) -> clean_session_list(lists:keysort(#session.usr, Ss), []). +-spec clean_session_list([#session{}], [#session{}]) -> [#session{}]. clean_session_list([], Res) -> Res; clean_session_list([S], Res) -> [S | Res]; clean_session_list([S1, S2 | Rest], Res) -> @@ -670,6 +662,7 @@ clean_session_list([S1, S2 | Rest], Res) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% On new session, check if some existing connections need to be replace +-spec check_for_sessions_to_replace(binary(), binary(), binary()) -> ok | replaced. check_for_sessions_to_replace(User, Server, Resource) -> LUser = jid:nodeprep(User), LServer = jid:nameprep(Server), @@ -677,6 +670,7 @@ check_for_sessions_to_replace(User, Server, Resource) -> check_existing_resources(LUser, LServer, LResource), check_max_sessions(LUser, LServer). +-spec check_existing_resources(binary(), binary(), binary()) -> ok. check_existing_resources(LUser, LServer, LResource) -> SIDs = get_resource_sessions(LUser, LServer, LResource), if SIDs == [] -> ok; @@ -698,6 +692,7 @@ check_existing_resources(LUser, LServer, LResource) -> is_existing_resource(LUser, LServer, LResource) -> [] /= get_resource_sessions(LUser, LServer, LResource). +-spec get_resource_sessions(binary(), binary(), binary()) -> [sid()]. get_resource_sessions(User, Server, Resource) -> LUser = jid:nodeprep(User), LServer = jid:nameprep(Server), @@ -705,6 +700,7 @@ get_resource_sessions(User, Server, Resource) -> Mod = get_sm_backend(LServer), [S#session.sid || S <- online(Mod:get_sessions(LUser, LServer, LResource))]. +-spec check_max_sessions(binary(), binary()) -> ok | replaced. check_max_sessions(LUser, LServer) -> Mod = get_sm_backend(LServer), SIDs = [S#session.sid || S <- online(Mod:get_sessions(LUser, LServer))], @@ -717,6 +713,7 @@ check_max_sessions(LUser, LServer) -> %% This option defines the max number of time a given users are allowed to %% log in %% Defaults to infinity +-spec get_max_user_sessions(binary(), binary()) -> infinity | non_neg_integer(). get_max_user_sessions(LUser, Host) -> case acl:match_rule(Host, max_user_sessions, jid:make(LUser, Host, <<"">>)) @@ -728,34 +725,31 @@ get_max_user_sessions(LUser, Host) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -process_iq(From, To, Packet) -> - IQ = jlib:iq_query_info(Packet), - case IQ of - #iq{xmlns = XMLNS, lang = Lang} -> - Host = To#jid.lserver, - case ets:lookup(sm_iqtable, {XMLNS, Host}) of - [{_, Module, Function}] -> - ResIQ = Module:Function(From, To, IQ), - if ResIQ /= ignore -> - ejabberd_router:route(To, From, jlib:iq_to_xml(ResIQ)); - true -> ok - end; - [{_, Module, Function, Opts}] -> - gen_iq_handler:handle(Host, Module, Function, Opts, - From, To, IQ); - [] -> - Txt = <<"No module is handling this query">>, - Err = jlib:make_error_reply( - Packet, - ?ERRT_SERVICE_UNAVAILABLE(Lang, Txt)), - ejabberd_router:route(To, From, Err) - end; - reply -> ok; - _ -> - Err = jlib:make_error_reply(Packet, ?ERR_BAD_REQUEST), - ejabberd_router:route(To, From, Err), - ok - end. +-spec process_iq(jid(), jid(), iq()) -> any(). +process_iq(From, To, #iq{type = T, lang = Lang, sub_els = [El]} = Packet) + when T == get; T == set -> + XMLNS = xmpp:get_ns(El), + Host = To#jid.lserver, + case ets:lookup(sm_iqtable, {XMLNS, Host}) of + [{_, Module, Function}] -> + gen_iq_handler:handle(Host, Module, Function, no_queue, + From, To, Packet); + [{_, Module, Function, Opts}] -> + gen_iq_handler:handle(Host, Module, Function, Opts, + From, To, Packet); + [] -> + Txt = <<"No module is handling this query">>, + Err = xmpp:make_error( + Packet, + xmpp:err_service_unavailable(Txt, Lang)), + ejabberd_router:route(To, From, Err) + end; +process_iq(From, To, #iq{type = T} = Packet) when T == get; T == set -> + Err = xmpp:make_error(Packet, xmpp:err_bad_request()), + ejabberd_router:route(To, From, Err), + ok; +process_iq(_From, _To, #iq{}) -> + ok. -spec force_update_presence({binary(), binary()}) -> any(). diff --git a/src/ejabberd_socket.erl b/src/ejabberd_socket.erl index 887b4a0f3..aa916867a 100644 --- a/src/ejabberd_socket.erl +++ b/src/ejabberd_socket.erl @@ -41,6 +41,7 @@ change_shaper/2, monitor/1, get_sockmod/1, + get_transport/1, get_peer_certificate/1, get_verify_result/1, close/1, @@ -215,6 +216,20 @@ monitor(SocketData) get_sockmod(SocketData) -> SocketData#socket_state.sockmod. +get_transport(#socket_state{sockmod = SockMod, + socket = Socket}) -> + case SockMod of + gen_tcp -> tcp; + fast_tls -> tls; + ezlib -> + case ezlib:get_sockmod(Socket) of + tcp -> tcp_zlib; + tls -> tls_zlib + end; + ejabberd_http_bind -> http_bind; + ejabberd_http_ws -> websocket + end. + get_peer_certificate(SocketData) -> fast_tls:get_peer_certificate(SocketData#socket_state.socket). diff --git a/src/ejabberd_system_monitor.erl b/src/ejabberd_system_monitor.erl index 3f6c05667..ae7cb2d88 100644 --- a/src/ejabberd_system_monitor.erl +++ b/src/ejabberd_system_monitor.erl @@ -41,7 +41,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -record(state, {}). @@ -64,18 +64,16 @@ start_link() -> process_command(From, To, Packet) -> case To of #jid{luser = <<"">>, lresource = <<"watchdog">>} -> - #xmlel{name = Name} = Packet, - case Name of - <<"message">> -> + case Packet of + #message{body = Body} -> LFrom = jid:tolower(jid:remove_resource(From)), case lists:member(LFrom, get_admin_jids()) of true -> - Body = fxml:get_path_s(Packet, - [{elem, <<"body">>}, cdata]), + BodyText = xmpp:get_text(Body), spawn(fun () -> process_flag(priority, high), - process_command1(From, To, Body) + process_command1(From, To, BodyText) end), stop; false -> ok @@ -186,24 +184,20 @@ process_large_heap(Pid, Info) -> "much memory:~n~p~n~s", [node(), Pid, Info, DetailedInfo])), From = jid:make(<<"">>, Host, <<"watchdog">>), - Hint = [#xmlel{name = <<"no-permanent-store">>, - attrs = [{<<"xmlns">>, ?NS_HINTS}]}], - lists:foreach(fun (JID) -> - send_message(From, jid:make(JID), Body, Hint) - end, JIDs). + Hint = [#hint{type = 'no-permanent-store'}], + lists:foreach( + fun(JID) -> + send_message(From, jid:make(JID), Body, Hint) + end, JIDs). send_message(From, To, Body) -> send_message(From, To, Body, []). send_message(From, To, Body, ExtraEls) -> ejabberd_router:route(From, To, - #xmlel{name = <<"message">>, - attrs = [{<<"type">>, <<"chat">>}], - children = - [#xmlel{name = <<"body">>, attrs = [], - children = - [{xmlcdata, Body}]} - | ExtraEls]}). + #message{type = chat, + body = xmpp:mk_text(Body), + sub_els = ExtraEls}). get_admin_jids() -> ejabberd_config:get_option( diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl index c2b4252c9..f78ba7e40 100644 --- a/src/gen_iq_handler.erl +++ b/src/gen_iq_handler.erl @@ -40,7 +40,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -record(state, {host, module, function}). @@ -59,6 +59,8 @@ start_link(Host, Module, Function) -> gen_server:start_link(?MODULE, [Host, Module, Function], []). +-spec add_iq_handler(module(), binary(), binary(), module(), atom(), type()) -> any(). + add_iq_handler(Component, Host, NS, Module, Function, Type) -> case Type of @@ -124,14 +126,49 @@ handle(Host, Module, Function, Opts, From, To, IQ) -> -spec process_iq(binary(), atom(), atom(), jid(), jid(), iq()) -> any(). -process_iq(_Host, Module, Function, From, To, IQ) -> - case catch Module:Function(From, To, IQ) of - {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]); - ResIQ -> - if ResIQ /= ignore -> - ejabberd_router:route(To, From, jlib:iq_to_xml(ResIQ)); - true -> ok - end +process_iq(_Host, Module, Function, From, To, IQ0) -> + IQ = xmpp:set_from_to(IQ0, From, To), + try + ResIQ = case erlang:function_exported(Module, Function, 1) of + true -> + process_iq(Module, Function, IQ); + false -> + process_iq(Module, Function, From, To, + jlib:iq_query_info(xmpp:encode(IQ))) + end, + if ResIQ /= ignore -> + ejabberd_router:route(To, From, ResIQ); + true -> + ok + end + catch E:R -> + ?ERROR_MSG("failed to process iq:~n~s~nReason = ~p", + [xmpp_codec:pp(IQ), {E, {R, erlang:get_stacktrace()}}]), + Txt = <<"Module failed to handle the query">>, + Err = xmpp:err_internal_server_error(Txt, IQ#iq.lang), + ejabberd_router:route(To, From, xmpp:make_error(IQ, Err)) + end. + +-spec process_iq(module(), atom(), iq()) -> ignore | iq(). +process_iq(Module, Function, #iq{lang = Lang, sub_els = [El]} = IQ) -> + try + %% TODO: move this 'conditional' decoding somewhere + %% IQ handler should know *nothing* about vCards. + Pkt = case xmpp:get_ns(El) of + ?NS_VCARD -> El; + _ -> xmpp:decode(El) + end, + Module:Function(IQ#iq{sub_els = [Pkt]}) + catch error:{xmpp_codec, Why} -> + Txt = xmpp:format_error(Why), + xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)) + end. + +-spec process_iq(module(), atom(), jid(), jid(), term()) -> iq(). +process_iq(Module, Function, From, To, IQ) -> + case Module:Function(From, To, IQ) of + ignore -> ignore; + ResIQ -> xmpp:decode(jlib:iq_to_xml(ResIQ), [ignore_els]) end. -spec check_type(type()) -> type(). diff --git a/src/jid.erl b/src/jid.erl index 0c3ac77c0..d81cbcefd 100644 --- a/src/jid.erl +++ b/src/jid.erl @@ -28,6 +28,7 @@ %% API -export([start/0, make/1, + make/2, make/3, split/1, from_string/1, @@ -40,7 +41,7 @@ remove_resource/1, replace_resource/2]). --include("jlib.hrl"). +-include("jid.hrl"). -export_type([jid/0]). @@ -74,10 +75,16 @@ make(User, Server, Resource) -> end end. --spec make({binary(), binary(), binary()}) -> jid() | error. +-spec make(binary(), binary()) -> jid() | error. +make(User, Server) -> + make(User, Server, <<"">>). + +-spec make({binary(), binary(), binary()} | binary()) -> jid() | error. make({User, Server, Resource}) -> - make(User, Server, Resource). + make(User, Server, Resource); +make(Server) -> + make(<<"">>, Server, <<"">>). %% This is the reverse of make_jid/1 -spec split(jid()) -> {binary(), binary(), binary()} | error. @@ -93,6 +100,8 @@ from_string(S) when is_list(S) -> %% using binaries for string. However, we do not let it crash to avoid %% losing associated ets table. {error, need_jid_as_binary}; +from_string(<<>>) -> + error; from_string(S) when is_binary(S) -> SplitPattern = ets:lookup_element(jlib, string_to_jid_pattern, 2), Size = size(S), diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 3ed3149bb..7c7ebf7b3 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -35,6 +35,8 @@ -behaviour(gen_mod). +-compile(export_all). + -export([read_caps/1, caps_stream_features/2, disco_features/5, disco_identity/5, disco_info/5, get_features/2, export/1, import_info/0, import/5, @@ -54,24 +56,12 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -define(PROCNAME, ejabberd_mod_caps). -define(BAD_HASH_LIFETIME, 600). --record(caps, -{ - node = <<"">> :: binary(), - version = <<"">> :: binary(), - hash = <<"">> :: binary(), - exts = [] :: [binary()] -}). - --type caps() :: #caps{}. - --export_type([caps/0]). - -record(caps_features, { node_pair = {<<"">>, <<"">>} :: {binary(), binary()}, @@ -103,6 +93,7 @@ stop(Host) -> supervisor:terminate_child(ejabberd_sup, Proc), supervisor:delete_child(ejabberd_sup, Proc). +-spec get_features(binary(), nothing | caps()) -> [binary()]. get_features(_Host, nothing) -> []; get_features(Host, #caps{node = Node, version = Version, exts = Exts}) -> @@ -119,65 +110,37 @@ get_features(Host, #caps{node = Node, version = Version, end, [], SubNodes). --spec read_caps([xmlel()]) -> nothing | caps(). +-spec read_caps(#presence{}) -> nothing | caps(). +read_caps(Presence) -> + case xmpp:get_subtag(Presence, #caps{}) of + false -> nothing; + Caps -> Caps + end. -read_caps(Els) -> read_caps(Els, nothing). - -read_caps([#xmlel{name = <<"c">>, attrs = Attrs} - | Tail], - Result) -> - case fxml:get_attr_s(<<"xmlns">>, Attrs) of - ?NS_CAPS -> - Node = fxml:get_attr_s(<<"node">>, Attrs), - Version = fxml:get_attr_s(<<"ver">>, Attrs), - Hash = fxml:get_attr_s(<<"hash">>, Attrs), - Exts = str:tokens(fxml:get_attr_s(<<"ext">>, Attrs), - <<" ">>), - read_caps(Tail, - #caps{node = Node, hash = Hash, version = Version, - exts = Exts}); - _ -> read_caps(Tail, Result) - end; -read_caps([#xmlel{name = <<"x">>, attrs = Attrs} - | Tail], - Result) -> - case fxml:get_attr_s(<<"xmlns">>, Attrs) of - ?NS_MUC_USER -> nothing; - _ -> read_caps(Tail, Result) - end; -read_caps([_ | Tail], Result) -> - read_caps(Tail, Result); -read_caps([], Result) -> Result. - -user_send_packet(#xmlel{name = <<"presence">>, attrs = Attrs, - children = Els} = Pkt, +-spec user_send_packet(stanza(), ejabberd_c2s:state(), jid(), jid()) -> stanza(). +user_send_packet(#presence{type = available} = Pkt, _C2SState, #jid{luser = User, lserver = Server} = From, #jid{luser = User, lserver = Server, lresource = <<"">>}) -> - Type = fxml:get_attr_s(<<"type">>, Attrs), - if Type == <<"">>; Type == <<"available">> -> - case read_caps(Els) of - nothing -> ok; - #caps{version = Version, exts = Exts} = Caps -> - feature_request(Server, From, Caps, [Version | Exts]) - end; - true -> ok + case read_caps(Pkt) of + nothing -> ok; + #caps{version = Version, exts = Exts} = Caps -> + feature_request(Server, From, Caps, [Version | Exts]) end, Pkt; user_send_packet(Pkt, _C2SState, _From, _To) -> Pkt. -user_receive_packet(#xmlel{name = <<"presence">>, attrs = Attrs, - children = Els} = Pkt, +-spec user_receive_packet(stanza(), ejabberd_c2s:state(), + jid(), jid(), jid()) -> stanza(). +user_receive_packet(#presence{type = available} = Pkt, _C2SState, #jid{lserver = Server}, From, _To) -> - Type = fxml:get_attr_s(<<"type">>, Attrs), IsRemote = not lists:member(From#jid.lserver, ?MYHOSTS), - if IsRemote and - ((Type == <<"">>) or (Type == <<"available">>)) -> - case read_caps(Els) of + if IsRemote -> + case read_caps(Pkt) of nothing -> ok; #caps{version = Version, exts = Exts} = Caps -> feature_request(Server, From, Caps, [Version | Exts]) @@ -188,58 +151,62 @@ user_receive_packet(#xmlel{name = <<"presence">>, attrs = Attrs, user_receive_packet(Pkt, _C2SState, _JID, _From, _To) -> Pkt. --spec caps_stream_features([xmlel()], binary()) -> [xmlel()]. +-spec caps_stream_features([xmpp_element()], binary()) -> [xmpp_element()]. caps_stream_features(Acc, MyHost) -> case make_my_disco_hash(MyHost) of <<"">> -> Acc; Hash -> - [#xmlel{name = <<"c">>, - attrs = - [{<<"xmlns">>, ?NS_CAPS}, {<<"hash">>, <<"sha-1">>}, - {<<"node">>, ?EJABBERD_URI}, {<<"ver">>, Hash}], - children = []} - | Acc] + [#caps{hash = <<"sha-1">>, node = ?EJABBERD_URI, version = Hash}|Acc] end. +-spec disco_features({error, error()} | {result, [binary()]} | empty, + jid(), jid(), + undefined | binary(), undefined | binary()) -> + {error, error()} | {result, [binary()]}. disco_features(Acc, From, To, Node, Lang) -> case is_valid_node(Node) of true -> ejabberd_hooks:run_fold(disco_local_features, To#jid.lserver, empty, - [From, To, <<"">>, Lang]); + [From, To, undefined, Lang]); false -> Acc end. +-spec disco_identity([identity()], jid(), jid(), + undefined | binary(), undefined | binary()) -> + [identity()]. disco_identity(Acc, From, To, Node, Lang) -> case is_valid_node(Node) of true -> ejabberd_hooks:run_fold(disco_local_identity, To#jid.lserver, [], - [From, To, <<"">>, Lang]); + [From, To, undefined, Lang]); false -> Acc end. +-spec disco_info([xdata()], binary(), module(), + undefined | binary(), undefined | binary()) -> [xdata()]. disco_info(Acc, Host, Module, Node, Lang) -> case is_valid_node(Node) of true -> ejabberd_hooks:run_fold(disco_info, Host, [], - [Host, Module, <<"">>, Lang]); + [Host, Module, undefined, Lang]); false -> Acc end. +-spec c2s_presence_in(ejabberd_c2s:state(), {jid(), jid(), presence()}) -> + ejabberd_c2s:state(). c2s_presence_in(C2SState, - {From, To, {_, _, Attrs, Els}}) -> - Type = fxml:get_attr_s(<<"type">>, Attrs), + {From, To, #presence{type = Type} = Presence}) -> Subscription = ejabberd_c2s:get_subscription(From, C2SState), - Insert = ((Type == <<"">>) or (Type == <<"available">>)) + Insert = (Type == available) and ((Subscription == both) or (Subscription == to)), - Delete = (Type == <<"unavailable">>) or - (Type == <<"error">>), + Delete = (Type == unavailable) or (Type == error), if Insert or Delete -> LFrom = jid:tolower(From), Rs = case ejabberd_c2s:get_aux_field(caps_resources, @@ -248,7 +215,7 @@ c2s_presence_in(C2SState, {ok, Rs1} -> Rs1; error -> gb_trees:empty() end, - Caps = read_caps(Els), + Caps = read_caps(Presence), NewRs = case Caps of nothing when Insert == true -> Rs; _ when Insert == true -> @@ -272,6 +239,9 @@ c2s_presence_in(C2SState, true -> C2SState end. +-spec c2s_filter_packet(boolean(), binary(), ejabberd_c2s:state(), + {pep_message, binary()}, jid(), stanza()) -> + boolean(). c2s_filter_packet(InAcc, Host, C2SState, {pep_message, Feature}, To, _Packet) -> case ejabberd_c2s:get_aux_field(caps_resources, C2SState) of {ok, Rs} -> @@ -287,6 +257,9 @@ c2s_filter_packet(InAcc, Host, C2SState, {pep_message, Feature}, To, _Packet) -> end; c2s_filter_packet(Acc, _, _, _, _, _) -> Acc. +-spec c2s_broadcast_recipients([ljid()], binary(), ejabberd_c2s:state(), + {pep_message, binary()}, jid(), stanza()) -> + [ljid()]. c2s_broadcast_recipients(InAcc, Host, C2SState, {pep_message, Feature}, _From, _Packet) -> case ejabberd_c2s:get_aux_field(caps_resources, @@ -377,6 +350,7 @@ terminate(_Reason, State) -> code_change(_OldVsn, State, _Extra) -> {ok, State}. +-spec feature_request(binary(), jid(), caps(), [binary()]) -> any(). feature_request(Host, From, Caps, [SubNode | Tail] = SubNodes) -> Node = Caps#caps.node, @@ -392,15 +366,9 @@ feature_request(Host, From, Caps, _ -> true end, if NeedRequest -> - IQ = #iq{type = get, xmlns = ?NS_DISCO_INFO, - sub_el = - [#xmlel{name = <<"query">>, - attrs = - [{<<"xmlns">>, ?NS_DISCO_INFO}, - {<<"node">>, - <>}], - children = []}]}, + IQ = #iq{type = get, + sub_els = [#disco_info{node = <>}]}, cache_tab:insert(caps_features, NodePair, now_ts(), caps_write_fun(Host, NodePair, now_ts())), F = fun (IQReply) -> @@ -415,39 +383,41 @@ feature_request(Host, From, Caps, end; feature_request(_Host, _From, _Caps, []) -> ok. -feature_response(#iq{type = result, - sub_el = [#xmlel{children = Els}]}, +-spec feature_response(iq(), binary(), jid(), caps(), [binary()]) -> any(). +feature_response(#iq{type = result, sub_els = [El]}, Host, From, Caps, [SubNode | SubNodes]) -> NodePair = {Caps#caps.node, SubNode}, - case check_hash(Caps, Els) of - true -> - Features = lists:flatmap(fun (#xmlel{name = - <<"feature">>, - attrs = FAttrs}) -> - [fxml:get_attr_s(<<"var">>, FAttrs)]; - (_) -> [] - end, - Els), - cache_tab:insert(caps_features, NodePair, - Features, - caps_write_fun(Host, NodePair, Features)); - false -> ok + try + DiscoInfo = xmpp:decode(El), + case check_hash(Caps, DiscoInfo) of + true -> + Features = DiscoInfo#disco_info.features, + cache_tab:insert(caps_features, NodePair, + Features, + caps_write_fun(Host, NodePair, Features)); + false -> ok + end + catch _:{xmpp_codec, _Why} -> + ok end, feature_request(Host, From, Caps, SubNodes); feature_response(_IQResult, Host, From, Caps, [_SubNode | SubNodes]) -> feature_request(Host, From, Caps, SubNodes). +-spec caps_read_fun(binary(), binary()) -> function(). caps_read_fun(Host, Node) -> LServer = jid:nameprep(Host), Mod = gen_mod:db_mod(LServer, ?MODULE), fun() -> Mod:caps_read(LServer, Node) end. +-spec caps_write_fun(binary(), binary(), [binary()]) -> function(). caps_write_fun(Host, Node, Features) -> LServer = jid:nameprep(Host), Mod = gen_mod:db_mod(LServer, ?MODULE), fun() -> Mod:caps_write(LServer, Node, Features) end. +-spec make_my_disco_hash(binary()) -> binary(). make_my_disco_hash(Host) -> JID = jid:make(<<"">>, Host, <<"">>), case {ejabberd_hooks:run_fold(disco_local_features, @@ -458,119 +428,70 @@ make_my_disco_hash(Host) -> [Host, undefined, <<"">>, <<"">>])} of {{result, Features}, Identities, Info} -> - Feats = lists:map(fun ({{Feat, _Host}}) -> - #xmlel{name = <<"feature">>, - attrs = [{<<"var">>, Feat}], - children = []}; - (Feat) -> - #xmlel{name = <<"feature">>, - attrs = [{<<"var">>, Feat}], - children = []} + Feats = lists:map(fun ({{Feat, _Host}}) -> Feat; + (Feat) -> Feat end, Features), - make_disco_hash(Identities ++ Info ++ Feats, sha1); + DiscoInfo = #disco_info{identities = Identities, + features = Feats, + xdata = Info}, + make_disco_hash(DiscoInfo, sha); _Err -> <<"">> end. -make_disco_hash(DiscoEls, Algo) -> - Concat = list_to_binary([concat_identities(DiscoEls), - concat_features(DiscoEls), concat_info(DiscoEls)]), +-spec make_disco_hash(disco_info(), crypto:digest_type()) -> binary(). + +make_disco_hash(DiscoInfo, Algo) -> + Concat = list_to_binary([concat_identities(DiscoInfo), + concat_features(DiscoInfo), concat_info(DiscoInfo)]), jlib:encode_base64(case Algo of md5 -> erlang:md5(Concat); - sha1 -> p1_sha:sha1(Concat); + sha -> p1_sha:sha1(Concat); sha224 -> p1_sha:sha224(Concat); sha256 -> p1_sha:sha256(Concat); sha384 -> p1_sha:sha384(Concat); sha512 -> p1_sha:sha512(Concat) end). -check_hash(Caps, Els) -> +-spec check_hash(caps(), disco_info()) -> boolean(). +check_hash(Caps, DiscoInfo) -> case Caps#caps.hash of <<"md5">> -> - Caps#caps.version == make_disco_hash(Els, md5); + Caps#caps.version == make_disco_hash(DiscoInfo, md5); <<"sha-1">> -> - Caps#caps.version == make_disco_hash(Els, sha1); + Caps#caps.version == make_disco_hash(DiscoInfo, sha); <<"sha-224">> -> - Caps#caps.version == make_disco_hash(Els, sha224); + Caps#caps.version == make_disco_hash(DiscoInfo, sha224); <<"sha-256">> -> - Caps#caps.version == make_disco_hash(Els, sha256); + Caps#caps.version == make_disco_hash(DiscoInfo, sha256); <<"sha-384">> -> - Caps#caps.version == make_disco_hash(Els, sha384); + Caps#caps.version == make_disco_hash(DiscoInfo, sha384); <<"sha-512">> -> - Caps#caps.version == make_disco_hash(Els, sha512); + Caps#caps.version == make_disco_hash(DiscoInfo, sha512); _ -> true end. -concat_features(Els) -> - lists:usort(lists:flatmap(fun (#xmlel{name = - <<"feature">>, - attrs = Attrs}) -> - [[fxml:get_attr_s(<<"var">>, Attrs), $<]]; - (_) -> [] - end, - Els)). +concat_features(#disco_info{features = Features}) -> + lists:usort([[Feat, $<] || Feat <- Features]). -concat_identities(Els) -> - lists:sort(lists:flatmap(fun (#xmlel{name = - <<"identity">>, - attrs = Attrs}) -> - [[fxml:get_attr_s(<<"category">>, Attrs), - $/, fxml:get_attr_s(<<"type">>, Attrs), - $/, - fxml:get_attr_s(<<"xml:lang">>, Attrs), - $/, fxml:get_attr_s(<<"name">>, Attrs), - $<]]; - (_) -> [] - end, - Els)). +concat_identities(#disco_info{identities = Identities}) -> + lists:sort( + [[Cat, $/, T, $/, Lang, $/, Name, $<] || + #identity{category = Cat, type = T, + lang = Lang, name = Name} <- Identities]). -concat_info(Els) -> - lists:sort(lists:flatmap(fun (#xmlel{name = <<"x">>, - attrs = Attrs, children = Fields}) -> - case {fxml:get_attr_s(<<"xmlns">>, Attrs), - fxml:get_attr_s(<<"type">>, Attrs)} - of - {?NS_XDATA, <<"result">>} -> - [concat_xdata_fields(Fields)]; - _ -> [] - end; - (_) -> [] - end, - Els)). +concat_info(#disco_info{xdata = Xs}) -> + lists:sort( + [concat_xdata_fields(Fs) || #xdata{type = result, fields = Fs} <- Xs]). concat_xdata_fields(Fields) -> - [Form, Res] = lists:foldl(fun (#xmlel{name = - <<"field">>, - attrs = Attrs, children = Els} = - El, - [FormType, VarFields] = Acc) -> - case fxml:get_attr_s(<<"var">>, Attrs) of - <<"">> -> Acc; - <<"FORM_TYPE">> -> - [fxml:get_subtag_cdata(El, - <<"value">>), - VarFields]; - Var -> - [FormType, - [[[Var, $<], - lists:sort(lists:flatmap(fun - (#xmlel{name - = - <<"value">>, - children - = - VEls}) -> - [[fxml:get_cdata(VEls), - $<]]; - (_) -> - [] - end, - Els))] - | VarFields]] - end; - (_, Acc) -> Acc - end, - [<<"">>, []], Fields), + Form = case lists:keysearch(<<"FORM_TYPE">>, #xdata_field.var, Fields) of + #xdata_field{values = Values} -> Values; + false -> [] + end, + Res = [[Var, $<, lists:sort([[Val, $<] || Val <- Values])] + || #xdata_field{var = Var, values = Values} <- Fields, + is_binary(Var), Var /= <<"FORM_TYPE">>], [Form, $<, lists:sort(Res)]. gb_trees_fold(F, Acc, Tree) -> @@ -588,6 +509,9 @@ gb_trees_fold_iter(F, Acc, Iter) -> now_ts() -> p1_time_compat:system_time(seconds). +-spec is_valid_node(undefined | binary()) -> boolean(). +is_valid_node(undefined) -> + false; is_valid_node(Node) -> case str:tokens(Node, <<"#">>) of [?EJABBERD_URI|_] -> diff --git a/src/mod_carboncopy.erl b/src/mod_carboncopy.erl index de8d8e1a7..b70ccbc2a 100644 --- a/src/mod_carboncopy.erl +++ b/src/mod_carboncopy.erl @@ -36,37 +36,28 @@ stop/1]). -export([user_send_packet/4, user_receive_packet/5, - iq_handler2/3, iq_handler1/3, remove_connection/4, + iq_handler/1, remove_connection/4, is_carbon_copy/1, mod_opt_type/1, depends/2]). -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -define(PROCNAME, ?MODULE). +-type direction() :: sent | received. + -callback init(binary(), gen_mod:opts()) -> any(). -callback enable(binary(), binary(), binary(), binary()) -> ok | {error, any()}. -callback disable(binary(), binary(), binary()) -> ok | {error, any()}. -callback list(binary(), binary()) -> [{binary(), binary()}]. +-spec is_carbon_copy(stanza()) -> boolean(). is_carbon_copy(Packet) -> - is_carbon_copy(Packet, <<"sent">>) orelse - is_carbon_copy(Packet, <<"received">>). - -is_carbon_copy(Packet, Direction) -> - case fxml:get_subtag(Packet, Direction) of - #xmlel{name = Direction, attrs = Attrs} -> - case fxml:get_attr_s(<<"xmlns">>, Attrs) of - ?NS_CARBONS_2 -> true; - ?NS_CARBONS_1 -> true; - _ -> false - end; - _ -> false - end. + xmpp:has_subtag(Packet, #carbons_sent{}) orelse + xmpp:has_subtag(Packet, #carbons_received{}). start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts,fun gen_iq_handler:check_type/1, one_queue), - mod_disco:register_feature(Host, ?NS_CARBONS_1), mod_disco:register_feature(Host, ?NS_CARBONS_2), Mod = gen_mod:db_mod(Host, ?MODULE), Mod:init(Host, Opts), @@ -74,54 +65,53 @@ start(Host, Opts) -> %% why priority 89: to define clearly that we must run BEFORE mod_logdb hook (90) ejabberd_hooks:add(user_send_packet,Host, ?MODULE, user_send_packet, 89), ejabberd_hooks:add(user_receive_packet,Host, ?MODULE, user_receive_packet, 89), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_CARBONS_2, ?MODULE, iq_handler2, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_CARBONS_1, ?MODULE, iq_handler1, IQDisc). + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_CARBONS_2, ?MODULE, iq_handler, IQDisc). stop(Host) -> - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_CARBONS_1), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_CARBONS_2), mod_disco:unregister_feature(Host, ?NS_CARBONS_2), - mod_disco:unregister_feature(Host, ?NS_CARBONS_1), %% why priority 89: to define clearly that we must run BEFORE mod_logdb hook (90) ejabberd_hooks:delete(user_send_packet,Host, ?MODULE, user_send_packet, 89), ejabberd_hooks:delete(user_receive_packet,Host, ?MODULE, user_receive_packet, 89), ejabberd_hooks:delete(unset_presence_hook,Host, ?MODULE, remove_connection, 10). -iq_handler2(From, To, IQ) -> - iq_handler(From, To, IQ, ?NS_CARBONS_2). -iq_handler1(From, To, IQ) -> - iq_handler(From, To, IQ, ?NS_CARBONS_1). - -iq_handler(From, _To, - #iq{type=set, lang = Lang, - sub_el = #xmlel{name = Operation} = SubEl} = IQ, CC)-> - ?DEBUG("carbons IQ received: ~p", [IQ]), +-spec iq_handler(iq()) -> iq(). +iq_handler(#iq{type = set, lang = Lang, from = From, + sub_els = [El]} = IQ) when is_record(El, carbons_enable); + is_record(El, carbons_disable) -> {U, S, R} = jid:tolower(From), - Result = case Operation of - <<"enable">>-> - ?INFO_MSG("carbons enabled for user ~s@~s/~s", [U,S,R]), - enable(S,U,R,CC); - <<"disable">>-> - ?INFO_MSG("carbons disabled for user ~s@~s/~s", [U,S,R]), - disable(S, U, R) - end, + Result = case El of + #carbons_enable{} -> + ?INFO_MSG("carbons enabled for user ~s@~s/~s", [U,S,R]), + enable(S, U, R, ?NS_CARBONS_2); + #carbons_disable{} -> + ?INFO_MSG("carbons disabled for user ~s@~s/~s", [U,S,R]), + disable(S, U, R) + end, case Result of - ok -> + ok -> ?DEBUG("carbons IQ result: ok", []), - IQ#iq{type=result, sub_el=[]}; + xmpp:make_iq_result(IQ); {error,_Error} -> ?ERROR_MSG("Error enabling / disabling carbons: ~p", [Result]), Txt = <<"Database failure">>, - IQ#iq{type=error,sub_el = [SubEl, ?ERRT_INTERNAL_SERVER_ERROR(Lang, Txt)]} + xmpp:make_error(IQ, xmpp:err_internal_server_error(Txt, Lang)) end; - -iq_handler(_From, _To, #iq{lang = Lang, sub_el = SubEl} = IQ, _CC)-> +iq_handler(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Only or tags are allowed">>, + xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)); +iq_handler(#iq{type = get, lang = Lang} = IQ)-> Txt = <<"Value 'get' of 'type' attribute is not allowed">>, - IQ#iq{type=error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]}. + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)). +-spec user_send_packet(stanza(), ejabberd_c2s:state(), jid(), jid()) -> + stanza() | {stop, stanza()}. user_send_packet(Packet, _C2SState, From, To) -> check_and_forward(From, To, Packet, sent). +-spec user_receive_packet(stanza(), ejabberd_c2s:state(), + jid(), jid(), jid()) -> + stanza() | {stop, stanza()}. user_receive_packet(Packet, _C2SState, JID, _From, To) -> check_and_forward(JID, To, Packet, received). @@ -129,10 +119,12 @@ user_receive_packet(Packet, _C2SState, JID, _From, To) -> % - registered to the user_send_packet hook, to be called only once even for multicast % - do not support "private" message mode, and do not modify the original packet in any way % - we also replicate "read" notifications +-spec check_and_forward(jid(), jid(), stanza(), direction()) -> + stanza() | {stop, stanza()}. check_and_forward(JID, To, Packet, Direction)-> case is_chat_message(Packet) andalso - fxml:get_subtag(Packet, <<"private">>) == false andalso - fxml:get_subtag(Packet, <<"no-copy">>) == false of + xmpp:has_subtag(Packet, #carbons_private{}) == false andalso + xmpp:has_subtag(Packet, #hint{type = 'no-copy'}) == false of true -> case is_carbon_copy(Packet) of false -> @@ -147,6 +139,7 @@ check_and_forward(JID, To, Packet, Direction)-> Packet end. +-spec remove_connection(binary(), binary(), binary(), binary()) -> ok. remove_connection(User, Server, Resource, _Status)-> disable(Server, User, Resource), ok. @@ -154,6 +147,7 @@ remove_connection(User, Server, Resource, _Status)-> %%% Internal %% Direction = received | sent +-spec send_copies(jid(), jid(), message(), direction()) -> ok. send_copies(JID, To, Packet, Direction)-> {U, S, R} = jid:tolower(JID), PrioRes = ejabberd_sm:get_user_present_resources(U, S), @@ -191,88 +185,54 @@ send_copies(JID, To, Packet, Direction)-> %TargetJIDs = lists:delete(JID, [ jid:make({U, S, CCRes}) || CCRes <- list(U, S) ]), end, - lists:map(fun({Dest,Version}) -> + lists:map(fun({Dest, _Version}) -> {_, _, Resource} = jid:tolower(Dest), ?DEBUG("Sending: ~p =/= ~p", [R, Resource]), Sender = jid:make({U, S, <<>>}), %{xmlelement, N, A, C} = Packet, - New = build_forward_packet(JID, Packet, Sender, Dest, Direction, Version), + New = build_forward_packet(JID, Packet, Sender, Dest, Direction), ejabberd_router:route(Sender, Dest, New) end, TargetJIDs), ok. -build_forward_packet(JID, Packet, Sender, Dest, Direction, ?NS_CARBONS_2) -> - #xmlel{name = <<"message">>, - attrs = [{<<"xmlns">>, <<"jabber:client">>}, - {<<"type">>, message_type(Packet)}, - {<<"from">>, jid:to_string(Sender)}, - {<<"to">>, jid:to_string(Dest)}], - children = [ - #xmlel{name = list_to_binary(atom_to_list(Direction)), - attrs = [{<<"xmlns">>, ?NS_CARBONS_2}], - children = [ - #xmlel{name = <<"forwarded">>, - attrs = [{<<"xmlns">>, ?NS_FORWARD}], - children = [ - complete_packet(JID, Packet, Direction)]} - ]} - ]}; -build_forward_packet(JID, Packet, Sender, Dest, Direction, ?NS_CARBONS_1) -> - #xmlel{name = <<"message">>, - attrs = [{<<"xmlns">>, <<"jabber:client">>}, - {<<"type">>, message_type(Packet)}, - {<<"from">>, jid:to_string(Sender)}, - {<<"to">>, jid:to_string(Dest)}], - children = [ - #xmlel{name = list_to_binary(atom_to_list(Direction)), - attrs = [{<<"xmlns">>, ?NS_CARBONS_1}]}, - #xmlel{name = <<"forwarded">>, - attrs = [{<<"xmlns">>, ?NS_FORWARD}], - children = [complete_packet(JID, Packet, Direction)]} - ]}. - +-spec build_forward_packet(jid(), message(), jid(), jid(), direction()) -> message(). +build_forward_packet(JID, #message{type = T} = Msg, Sender, Dest, Direction) -> + Forwarded = #forwarded{sub_els = complete_packet(JID, Msg, Direction)}, + Carbon = case Direction of + sent -> #carbons_sent{forwarded = Forwarded}; + received -> #carbons_received{forwarded = Forwarded} + end, + #message{from = Sender, to = Dest, type = T, sub_els = [Carbon]}. +-spec enable(binary(), binary(), binary(), binary()) -> ok | {error, any()}. enable(Host, U, R, CC)-> ?DEBUG("enabling for ~p", [U]), Mod = gen_mod:db_mod(Host, ?MODULE), Mod:enable(U, Host, R, CC). +-spec disable(binary(), binary(), binary()) -> ok | {error, any()}. disable(Host, U, R)-> ?DEBUG("disabling for ~p", [U]), Mod = gen_mod:db_mod(Host, ?MODULE), Mod:disable(U, Host, R). -complete_packet(From, #xmlel{name = <<"message">>, attrs = OrigAttrs} = Packet, sent) -> +-spec complete_packet(jid(), message(), direction()) -> message(). +complete_packet(From, #message{from = undefined} = Msg, sent) -> %% if this is a packet sent by user on this host, then Packet doesn't %% include the 'from' attribute. We must add it. - Attrs = lists:keystore(<<"xmlns">>, 1, OrigAttrs, {<<"xmlns">>, <<"jabber:client">>}), - case proplists:get_value(<<"from">>, Attrs) of - undefined -> - Packet#xmlel{attrs = [{<<"from">>, jid:to_string(From)}|Attrs]}; - _ -> - Packet#xmlel{attrs = Attrs} - end; -complete_packet(_From, #xmlel{name = <<"message">>, attrs=OrigAttrs} = Packet, received) -> - Attrs = lists:keystore(<<"xmlns">>, 1, OrigAttrs, {<<"xmlns">>, <<"jabber:client">>}), - Packet#xmlel{attrs = Attrs}. + Msg#message{from = From}; +complete_packet(_From, Msg, _Direction) -> + Msg. -message_type(#xmlel{attrs = Attrs}) -> - case fxml:get_attr(<<"type">>, Attrs) of - {value, Type} -> Type; - false -> <<"normal">> - end. - -is_chat_message(#xmlel{name = <<"message">>} = Packet) -> - case message_type(Packet) of - <<"chat">> -> true; - <<"normal">> -> has_non_empty_body(Packet); - _ -> false - end; -is_chat_message(_Packet) -> false. - -has_non_empty_body(Packet) -> - fxml:get_subtag_cdata(Packet, <<"body">>) =/= <<"">>. +-spec is_chat_message(stanza()) -> boolean(). +is_chat_message(#message{type = chat}) -> + true; +is_chat_message(#message{type = normal, body = Body}) -> + xmpp:get_text(Body) /= <<"">>; +is_chat_message(_) -> + false. +-spec list(binary(), binary()) -> [{binary(), binary()}]. %% list {resource, cc_version} with carbons enabled for given user and host list(User, Server) -> Mod = gen_mod:db_mod(Server, ?MODULE), diff --git a/src/mod_client_state.erl b/src/mod_client_state.erl index 036175cce..a6a6ddc20 100644 --- a/src/mod_client_state.erl +++ b/src/mod_client_state.erl @@ -39,7 +39,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -define(CSI_QUEUE_MAX, 100). @@ -151,66 +151,62 @@ depends(_Host, _Opts) -> %% ejabberd_hooks callbacks. %%-------------------------------------------------------------------- --spec filter_presence({term(), [xmlel()]}, binary(), xmlel()) - -> {term(), [xmlel()]} | {stop, {term(), [xmlel()]}}. +-spec filter_presence({term(), [stanza()]}, binary(), stanza()) + -> {term(), [stanza()]} | {stop, {term(), [stanza()]}}. filter_presence({C2SState, _OutStanzas} = Acc, Host, - #xmlel{name = <<"presence">>, attrs = Attrs} = Stanza) -> - case fxml:get_attr(<<"type">>, Attrs) of - {value, Type} when Type /= <<"unavailable">> -> - Acc; - _ -> - ?DEBUG("Got availability presence stanza", []), - queue_add(presence, Stanza, Host, C2SState) + #presence{type = Type} = Stanza) -> + if Type == available, Type == unavailable -> + ?DEBUG("Got availability presence stanza", []), + queue_add(presence, Stanza, Host, C2SState); + true -> + Acc end; filter_presence(Acc, _Host, _Stanza) -> Acc. --spec filter_chat_states({term(), [xmlel()]}, binary(), xmlel()) - -> {term(), [xmlel()]} | {stop, {term(), [xmlel()]}}. +-spec filter_chat_states({term(), [stanza()]}, binary(), stanza()) + -> {term(), [stanza()]} | {stop, {term(), [stanza()]}}. filter_chat_states({C2SState, _OutStanzas} = Acc, Host, - #xmlel{name = <<"message">>} = Stanza) -> - case jlib:is_standalone_chat_state(Stanza) of - true -> - From = fxml:get_tag_attr_s(<<"from">>, Stanza), - To = fxml:get_tag_attr_s(<<"to">>, Stanza), - case {jid:from_string(From), jid:from_string(To)} of - {#jid{luser = U, lserver = S}, #jid{luser = U, lserver = S}} -> - %% Don't queue (carbon copies of) chat states from other - %% resources, as they might be used to sync the state of - %% conversations across clients. - Acc; - _ -> - ?DEBUG("Got standalone chat state notification", []), - queue_add(chatstate, Stanza, Host, C2SState) - end; - false -> - Acc + #message{from = From, to = To} = Stanza) -> + case xmpp_util:is_standalone_chat_state(Stanza) of + true -> + case {From, To} of + {#jid{luser = U, lserver = S}, #jid{luser = U, lserver = S}} -> + %% Don't queue (carbon copies of) chat states from other + %% resources, as they might be used to sync the state of + %% conversations across clients. + Acc; + _ -> + ?DEBUG("Got standalone chat state notification", []), + queue_add(chatstate, Stanza, Host, C2SState) + end; + false -> + Acc end; filter_chat_states(Acc, _Host, _Stanza) -> Acc. --spec filter_pep({term(), [xmlel()]}, binary(), xmlel()) - -> {term(), [xmlel()]} | {stop, {term(), [xmlel()]}}. +-spec filter_pep({term(), [stanza()]}, binary(), stanza()) + -> {term(), [stanza()]} | {stop, {term(), [stanza()]}}. -filter_pep({C2SState, _OutStanzas} = Acc, Host, - #xmlel{name = <<"message">>} = Stanza) -> +filter_pep({C2SState, _OutStanzas} = Acc, Host, #message{} = Stanza) -> case get_pep_node(Stanza) of - {value, Node} -> - ?DEBUG("Got PEP notification", []), - queue_add({pep, Node}, Stanza, Host, C2SState); - false -> - Acc + undefined -> + Acc; + Node -> + ?DEBUG("Got PEP notification", []), + queue_add({pep, Node}, Stanza, Host, C2SState) end; filter_pep(Acc, _Host, _Stanza) -> Acc. --spec filter_other({term(), [xmlel()]}, binary(), xmlel()) - -> {stop, {term(), [xmlel()]}}. +-spec filter_other({term(), [stanza()]}, binary(), stanza()) + -> {stop, {term(), [stanza()]}}. filter_other({C2SState, _OutStanzas}, Host, Stanza) -> ?DEBUG("Won't add stanza to CSI queue", []), queue_take(Stanza, Host, C2SState). --spec flush_queue({term(), [xmlel()]}, binary()) -> {term(), [xmlel()]}. +-spec flush_queue({term(), [stanza()]}, binary()) -> {term(), [stanza()]}. flush_queue({C2SState, _OutStanzas}, Host) -> ?DEBUG("Going to flush CSI queue", []), @@ -218,20 +214,17 @@ flush_queue({C2SState, _OutStanzas}, Host) -> NewState = set_queue([], C2SState), {NewState, get_stanzas(Queue, Host)}. --spec add_stream_feature([xmlel()], binary) -> [xmlel()]. +-spec add_stream_feature([stanza()], binary) -> [stanza()]. add_stream_feature(Features, _Host) -> - Feature = #xmlel{name = <<"csi">>, - attrs = [{<<"xmlns">>, ?NS_CLIENT_STATE}], - children = []}, - [Feature | Features]. + [#feature_csi{xmlns = <<"urn:xmpp:csi:0">>} | Features]. %%-------------------------------------------------------------------- %% Internal functions. %%-------------------------------------------------------------------- --spec queue_add(csi_type(), xmlel(), binary(), term()) - -> {stop, {term(), [xmlel()]}}. +-spec queue_add(csi_type(), stanza(), binary(), term()) + -> {stop, {term(), [stanza()]}}. queue_add(Type, Stanza, Host, C2SState) -> case get_queue(C2SState) of @@ -241,19 +234,19 @@ queue_add(Type, Stanza, Host, C2SState) -> {stop, {NewState, get_stanzas(Queue, Host) ++ [Stanza]}}; Queue -> ?DEBUG("Adding stanza to CSI queue", []), - From = fxml:get_tag_attr_s(<<"from">>, Stanza), - Key = {jid:tolower(jid:from_string(From)), Type}, + From = xmpp:get_from(Stanza), + Key = {jid:tolower(From), Type}, Entry = {Key, p1_time_compat:timestamp(), Stanza}, NewQueue = lists:keystore(Key, 1, Queue, Entry), NewState = set_queue(NewQueue, C2SState), {stop, {NewState, []}} end. --spec queue_take(xmlel(), binary(), term()) -> {stop, {term(), [xmlel()]}}. +-spec queue_take(stanza(), binary(), term()) -> {stop, {term(), [stanza()]}}. queue_take(Stanza, Host, C2SState) -> - From = fxml:get_tag_attr_s(<<"from">>, Stanza), - {LUser, LServer, _LResource} = jid:tolower(jid:from_string(From)), + From = xmpp:get_from(Stanza), + {LUser, LServer, _LResource} = jid:tolower(From), {Selected, Rest} = lists:partition( fun({{{U, S, _R}, _Type}, _Time, _Stanza}) -> U == LUser andalso S == LServer @@ -276,32 +269,23 @@ get_queue(C2SState) -> [] end. --spec get_stanzas(csi_queue(), binary()) -> [xmlel()]. +-spec get_stanzas(csi_queue(), binary()) -> [stanza()]. get_stanzas(Queue, Host) -> lists:map(fun({_Key, Time, Stanza}) -> - jlib:add_delay_info(Stanza, Host, Time, - <<"Client Inactive">>) + xmpp_util:add_delay_info(Stanza, Host, Time, + <<"Client Inactive">>) end, Queue). --spec get_pep_node(xmlel()) -> {value, binary()} | false. +-spec get_pep_node(message()) -> binary() | undefined. -get_pep_node(#xmlel{name = <<"message">>} = Stanza) -> - From = fxml:get_tag_attr_s(<<"from">>, Stanza), - case jid:from_string(From) of - #jid{luser = <<>>} -> % It's not PEP. - false; - _ -> - case fxml:get_subtag_with_xmlns(Stanza, <<"event">>, - ?NS_PUBSUB_EVENT) of - #xmlel{children = Els} -> - case fxml:remove_cdata(Els) of - [#xmlel{name = <<"items">>, attrs = ItemsAttrs}] -> - fxml:get_attr(<<"node">>, ItemsAttrs); - _ -> - false - end; - false -> - false - end +get_pep_node(#message{from = #jid{luser = <<>>}}) -> + %% It's not PEP. + undefined; +get_pep_node(#message{} = Msg) -> + case xmpp:get_subtag(Msg, #pubsub_event{}) of + #pubsub_event{items = [#pubsub_event_item{node = Node}]} -> + Node; + _ -> + undefined end. diff --git a/src/mod_disco.erl b/src/mod_disco.erl index 2e7b80c18..03fdab209 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -32,10 +32,10 @@ -behaviour(gen_mod). --export([start/2, stop/1, process_local_iq_items/3, - process_local_iq_info/3, get_local_identity/5, +-export([start/2, stop/1, process_local_iq_items/1, + process_local_iq_info/1, get_local_identity/5, get_local_features/5, get_local_services/5, - process_sm_iq_items/3, process_sm_iq_info/3, + process_sm_iq_items/1, process_sm_iq_info/1, get_sm_identity/5, get_sm_features/5, get_sm_items/5, get_info/5, register_feature/2, unregister_feature/2, register_extra_domain/2, unregister_extra_domain/2, @@ -44,8 +44,8 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). - +-include("xmpp.hrl"). +-include_lib("stdlib/include/ms_transform.hrl"). -include("mod_roster.hrl"). start(Host, Opts) -> @@ -126,158 +126,133 @@ stop(Host) -> {{'_', Host}}), ok. +-spec register_feature(binary(), binary()) -> true. register_feature(Host, Feature) -> catch ets:new(disco_features, [named_table, ordered_set, public]), ets:insert(disco_features, {{Feature, Host}}). +-spec unregister_feature(binary(), binary()) -> true. unregister_feature(Host, Feature) -> catch ets:new(disco_features, [named_table, ordered_set, public]), ets:delete(disco_features, {Feature, Host}). +-spec register_extra_domain(binary(), binary()) -> true. register_extra_domain(Host, Domain) -> catch ets:new(disco_extra_domains, [named_table, ordered_set, public]), ets:insert(disco_extra_domains, {{Domain, Host}}). +-spec unregister_extra_domain(binary(), binary()) -> true. unregister_extra_domain(Host, Domain) -> catch ets:new(disco_extra_domains, [named_table, ordered_set, public]), ets:delete(disco_extra_domains, {Domain, Host}). -process_local_iq_items(From, To, - #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> - case Type of - set -> - Txt = <<"Value 'set' of 'type' attribute is not allowed">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]}; - get -> - Node = fxml:get_tag_attr_s(<<"node">>, SubEl), - Host = To#jid.lserver, - case ejabberd_hooks:run_fold(disco_local_items, Host, - empty, [From, To, Node, Lang]) - of - {result, Items} -> - ANode = case Node of - <<"">> -> []; - _ -> [{<<"node">>, Node}] - end, - IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = - [{<<"xmlns">>, ?NS_DISCO_ITEMS} | ANode], - children = Items}]}; - {error, Error} -> - IQ#iq{type = error, sub_el = [SubEl, Error]} - end +-spec process_local_iq_items(iq()) -> iq(). +process_local_iq_items(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_local_iq_items(#iq{type = get, lang = Lang, + from = From, to = To, + sub_els = [#disco_items{node = Node}]} = IQ) -> + Host = To#jid.lserver, + case ejabberd_hooks:run_fold(disco_local_items, Host, + empty, [From, To, Node, Lang]) of + {result, Items} -> + xmpp:make_iq_result(IQ, #disco_items{node = Node, items = Items}); + {error, Error} -> + xmpp:make_error(IQ, Error) end. -process_local_iq_info(From, To, - #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> - case Type of - set -> - Txt = <<"Value 'set' of 'type' attribute is not allowed">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]}; - get -> - Host = To#jid.lserver, - Node = fxml:get_tag_attr_s(<<"node">>, SubEl), - Identity = ejabberd_hooks:run_fold(disco_local_identity, - Host, [], [From, To, Node, Lang]), - Info = ejabberd_hooks:run_fold(disco_info, Host, [], - [Host, ?MODULE, Node, Lang]), - case ejabberd_hooks:run_fold(disco_local_features, Host, - empty, [From, To, Node, Lang]) - of - {result, Features} -> - ANode = case Node of - <<"">> -> []; - _ -> [{<<"node">>, Node}] - end, - IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = - [{<<"xmlns">>, ?NS_DISCO_INFO} | ANode], - children = - Identity ++ - Info ++ features_to_xml(Features)}]}; - {error, Error} -> - IQ#iq{type = error, sub_el = [SubEl, Error]} - end +-spec process_local_iq_info(iq()) -> iq(). +process_local_iq_info(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_local_iq_info(#iq{type = get, lang = Lang, + from = From, to = To, + sub_els = [#disco_info{node = Node}]} = IQ) -> + Host = To#jid.lserver, + Identity = ejabberd_hooks:run_fold(disco_local_identity, + Host, [], [From, To, Node, Lang]), + Info = ejabberd_hooks:run_fold(disco_info, Host, [], + [Host, ?MODULE, Node, Lang]), + case ejabberd_hooks:run_fold(disco_local_features, Host, + empty, [From, To, Node, Lang]) of + {result, Features} -> + xmpp:make_iq_result(IQ, #disco_info{node = Node, + identities = Identity, + xdata = Info, + features = Features}); + {error, Error} -> + xmpp:make_error(IQ, Error) end. -get_local_identity(Acc, _From, _To, <<>>, _Lang) -> - Acc ++ - [#xmlel{name = <<"identity">>, - attrs = - [{<<"category">>, <<"server">>}, {<<"type">>, <<"im">>}, - {<<"name">>, <<"ejabberd">>}], - children = []}]; +-spec get_local_identity([identity()], jid(), jid(), + undefined | binary(), undefined | binary()) -> + [identity()]. +get_local_identity(Acc, _From, _To, undefined, _Lang) -> + Acc ++ [#identity{category = <<"server">>, + type = <<"im">>, + name = <<"ejabberd">>}]; get_local_identity(Acc, _From, _To, _Node, _Lang) -> Acc. +-spec get_local_features({error, error()} | {result, [binary()]} | empty, + jid(), jid(), + undefined | binary(), undefined | binary()) -> + {error, error()} | {result, [binary()]}. get_local_features({error, _Error} = Acc, _From, _To, _Node, _Lang) -> Acc; -get_local_features(Acc, _From, To, <<>>, _Lang) -> +get_local_features(Acc, _From, To, undefined, _Lang) -> Feats = case Acc of - {result, Features} -> Features; - empty -> [] + {result, Features} -> Features; + empty -> [] end, Host = To#jid.lserver, {result, ets:select(disco_features, - [{{{'_', Host}}, [], ['$_']}]) - ++ Feats}; + ets:fun2ms(fun({{F, H}}) when H == Host -> F end)) + ++ Feats}; get_local_features(Acc, _From, _To, _Node, Lang) -> case Acc of {result, _Features} -> Acc; empty -> Txt = <<"No features available">>, - {error, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)} + {error, xmpp:err_item_not_found(Txt, Lang)} end. -features_to_xml(FeatureList) -> - [#xmlel{name = <<"feature">>, - attrs = [{<<"var">>, Feat}], children = []} - || Feat - <- lists:usort(lists:map(fun ({{Feature, _Host}}) -> - Feature; - (Feature) when is_binary(Feature) -> - Feature - end, - FeatureList))]. - -domain_to_xml({Domain}) -> - #xmlel{name = <<"item">>, attrs = [{<<"jid">>, Domain}], - children = []}; -domain_to_xml(Domain) -> - #xmlel{name = <<"item">>, attrs = [{<<"jid">>, Domain}], - children = []}. - +-spec get_local_services({error, error()} | {result, [disco_item()]} | empty, + jid(), jid(), + undefined | binary(), undefined | binary()) -> + {error, error()} | {result, [disco_item()]}. get_local_services({error, _Error} = Acc, _From, _To, _Node, _Lang) -> Acc; -get_local_services(Acc, _From, To, <<>>, _Lang) -> +get_local_services(Acc, _From, To, undefined, _Lang) -> Items = case Acc of {result, Its} -> Its; empty -> [] end, Host = To#jid.lserver, {result, - lists:usort(lists:map(fun domain_to_xml/1, - get_vh_services(Host) ++ - ets:select(disco_extra_domains, - [{{{'$1', Host}}, [], ['$1']}]))) - ++ Items}; + lists:usort( + lists:map( + fun(Domain) -> #disco_item{jid = jid:make(Domain)} end, + get_vh_services(Host) ++ + ets:select(disco_extra_domains, + ets:fun2ms( + fun({{D, H}}) when H == Host -> D end)))) + ++ Items}; get_local_services({result, _} = Acc, _From, _To, _Node, _Lang) -> Acc; get_local_services(empty, _From, _To, _Node, Lang) -> - {error, ?ERRT_ITEM_NOT_FOUND(Lang, <<"No services available">>)}. + {error, xmpp:err_item_not_found(<<"No services available">>, Lang)}. +-spec get_vh_services(binary()) -> [binary()]. get_vh_services(Host) -> Hosts = lists:sort(fun (H1, H2) -> byte_size(H1) >= byte_size(H2) @@ -300,47 +275,38 @@ get_vh_services(Host) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -process_sm_iq_items(From, To, - #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> - case Type of - set -> - Txt = <<"Value 'set' of 'type' attribute is not allowed">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]}; - get -> - case is_presence_subscribed(From, To) of - true -> - Host = To#jid.lserver, - Node = fxml:get_tag_attr_s(<<"node">>, SubEl), - case ejabberd_hooks:run_fold(disco_sm_items, Host, - empty, [From, To, Node, Lang]) - of - {result, Items} -> - ANode = case Node of - <<"">> -> []; - _ -> [{<<"node">>, Node}] - end, - IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = - [{<<"xmlns">>, ?NS_DISCO_ITEMS} - | ANode], - children = Items}]}; - {error, Error} -> - IQ#iq{type = error, sub_el = [SubEl, Error]} - end; - false -> - Txt = <<"Not subscribed">>, - IQ#iq{type = error, - sub_el = [SubEl, ?ERRT_SERVICE_UNAVAILABLE(Lang, Txt)]} - end +-spec process_sm_iq_items(iq()) -> iq(). +process_sm_iq_items(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_sm_iq_items(#iq{type = get, lang = Lang, + from = From, to = To, + sub_els = [#disco_items{node = Node}]} = IQ) -> + case is_presence_subscribed(From, To) of + true -> + Host = To#jid.lserver, + case ejabberd_hooks:run_fold(disco_sm_items, Host, + empty, [From, To, Node, Lang]) of + {result, Items} -> + xmpp:make_iq_result( + IQ, #disco_items{node = Node, items = Items}); + {error, Error} -> + xmpp:make_error(IQ, Error) + end; + false -> + Txt = <<"Not subscribed">>, + xmpp:make_error(IQ, xmpp:err_service_unavailable(Txt, Lang)) end. +-spec get_sm_items({error, error()} | {result, [disco_item()]} | empty, + jid(), jid(), + undefined | binary(), undefined | binary()) -> + {error, error()} | {result, [disco_item()]}. get_sm_items({error, _Error} = Acc, _From, _To, _Node, _Lang) -> Acc; get_sm_items(Acc, From, - #jid{user = User, server = Server} = To, <<>>, _Lang) -> + #jid{user = User, server = Server} = To, undefined, _Lang) -> Items = case Acc of {result, Its} -> Its; empty -> [] @@ -357,12 +323,13 @@ get_sm_items(empty, From, To, _Node, Lang) -> #jid{luser = LFrom, lserver = LSFrom} = From, #jid{luser = LTo, lserver = LSTo} = To, case {LFrom, LSFrom} of - {LTo, LSTo} -> {error, ?ERR_ITEM_NOT_FOUND}; + {LTo, LSTo} -> {error, xmpp:err_item_not_found()}; _ -> Txt = <<"Query to another users is forbidden">>, - {error, ?ERRT_NOT_ALLOWED(Lang, Txt)} + {error, xmpp:err_not_allowed(Txt, Lang)} end. +-spec is_presence_subscribed(jid(), jid()) -> boolean(). is_presence_subscribed(#jid{luser = User, lserver = Server}, #jid{luser = User, lserver = Server}) -> true; is_presence_subscribed(#jid{luser = FromUser, lserver = FromServer}, @@ -377,86 +344,70 @@ is_presence_subscribed(#jid{luser = FromUser, lserver = FromServer}, ejabberd_hooks:run_fold(roster_get, ToServer, [], [{ToUser, ToServer}])). -process_sm_iq_info(From, To, - #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> - case Type of - set -> - Txt = <<"Value 'set' of 'type' attribute is not allowed">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]}; - get -> - case is_presence_subscribed(From, To) of - true -> - Host = To#jid.lserver, - Node = fxml:get_tag_attr_s(<<"node">>, SubEl), - Identity = ejabberd_hooks:run_fold(disco_sm_identity, - Host, [], - [From, To, Node, Lang]), - Info = ejabberd_hooks:run_fold(disco_info, Host, [], +-spec process_sm_iq_info(iq()) -> iq(). +process_sm_iq_info(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_sm_iq_info(#iq{type = get, lang = Lang, + from = From, to = To, + sub_els = [#disco_info{node = Node}]} = IQ) -> + case is_presence_subscribed(From, To) of + true -> + Host = To#jid.lserver, + Identity = ejabberd_hooks:run_fold(disco_sm_identity, + Host, [], [From, To, Node, Lang]), - case ejabberd_hooks:run_fold(disco_sm_features, Host, - empty, [From, To, Node, Lang]) - of - {result, Features} -> - ANode = case Node of - <<"">> -> []; - _ -> [{<<"node">>, Node}] - end, - IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = - [{<<"xmlns">>, ?NS_DISCO_INFO} - | ANode], - children = - Identity ++ Info ++ - features_to_xml(Features)}]}; - {error, Error} -> - IQ#iq{type = error, sub_el = [SubEl, Error]} - end; - false -> - Txt = <<"Not subscribed">>, - IQ#iq{type = error, - sub_el = [SubEl, ?ERRT_SERVICE_UNAVAILABLE(Lang, Txt)]} - end + Info = ejabberd_hooks:run_fold(disco_info, Host, [], + [From, To, Node, Lang]), + case ejabberd_hooks:run_fold(disco_sm_features, Host, + empty, [From, To, Node, Lang]) of + {result, Features} -> + xmpp:make_iq_result(IQ, #disco_info{node = Node, + identities = Identity, + xdata = Info, + features = Features}); + {error, Error} -> + xmpp:make_error(IQ, Error) + end; + false -> + Txt = <<"Not subscribed">>, + xmpp:make_error(IQ, xmpp:err_service_unavailable(Txt, Lang)) end. +-spec get_sm_identity([identity()], jid(), jid(), + undefined | binary(), undefined | binary()) -> + [identity()]. get_sm_identity(Acc, _From, #jid{luser = LUser, lserver = LServer}, _Node, _Lang) -> Acc ++ case ejabberd_auth:is_user_exists(LUser, LServer) of true -> - [#xmlel{name = <<"identity">>, - attrs = - [{<<"category">>, <<"account">>}, - {<<"type">>, <<"registered">>}], - children = []}]; + [#identity{category = <<"account">>, type = <<"registered">>}]; _ -> [] end. +-spec get_sm_features({error, error()} | {result, [binary()]} | empty, + jid(), jid(), + undefined | binary(), undefined | binary()) -> + {error, error()} | {result, [binary()]}. get_sm_features(empty, From, To, _Node, Lang) -> #jid{luser = LFrom, lserver = LSFrom} = From, #jid{luser = LTo, lserver = LSTo} = To, case {LFrom, LSFrom} of - {LTo, LSTo} -> {error, ?ERR_ITEM_NOT_FOUND}; + {LTo, LSTo} -> {error, xmpp:err_item_not_found()}; _ -> Txt = <<"Query to another users is forbidden">>, - {error, ?ERRT_NOT_ALLOWED(Lang, Txt)} + {error, xmpp:err_not_allowed(Txt, Lang)} end; get_sm_features(Acc, _From, _To, _Node, _Lang) -> Acc. +-spec get_user_resources(binary(), binary()) -> [disco_item()]. get_user_resources(User, Server) -> Rs = ejabberd_sm:get_user_resources(User, Server), - lists:map(fun (R) -> - #xmlel{name = <<"item">>, - attrs = - [{<<"jid">>, - <>}, - {<<"name">>, User}], - children = []} - end, - lists:sort(Rs)). + [#disco_item{jid = jid:make(User, Server, Resource), name = User} + || Resource <- lists:sort(Rs)]. +-spec transform_module_options(gen_mod:opts()) -> gen_mod:opts(). transform_module_options(Opts) -> lists:map( fun({server_info, Infos}) -> @@ -477,27 +428,23 @@ transform_module_options(Opts) -> %%% Support for: XEP-0157 Contact Addresses for XMPP Services -get_info(_A, Host, Mod, Node, _Lang) when Node == <<>> -> +-spec get_info([xdata()], binary(), module(), + undefined | binary(), undefined | binary()) -> + [xdata()]. +get_info(_A, Host, Mod, Node, _Lang) when Node == undefined -> Module = case Mod of undefined -> ?MODULE; _ -> Mod end, - Serverinfo_fields = get_fields_xml(Host, Module), - [#xmlel{name = <<"x">>, - attrs = - [{<<"xmlns">>, ?NS_XDATA}, {<<"type">>, <<"result">>}], - children = - [#xmlel{name = <<"field">>, - attrs = - [{<<"var">>, <<"FORM_TYPE">>}, - {<<"type">>, <<"hidden">>}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = [{xmlcdata, ?NS_SERVERINFO}]}]}] - ++ Serverinfo_fields}]; + [#xdata{type = result, + fields = [#xdata_field{type = hidden, + var = <<"FORM_TYPE">>, + values = [?NS_SERVERINFO]} + | get_fields(Host, Module)]}]; get_info(Acc, _, _, _Node, _) -> Acc. -get_fields_xml(Host, Module) -> +-spec get_fields(binary(), module()) -> [xdata_field()]. +get_fields(Host, Module) -> Fields = gen_mod:get_module_opt( Host, ?MODULE, server_info, fun(L) -> @@ -509,31 +456,17 @@ get_fields_xml(Host, Module) -> {Mods, Name, URLs} end, L) end, []), - Fields_good = lists:filter(fun ({Modules, _, _}) -> - case Modules of - all -> true; - Modules -> - lists:member(Module, Modules) - end - end, - Fields), - fields_to_xml(Fields_good). - -fields_to_xml(Fields) -> - [field_to_xml(Field) || Field <- Fields]. - -field_to_xml({_, Var, Values}) -> - Values_xml = values_to_xml(Values), - #xmlel{name = <<"field">>, attrs = [{<<"var">>, Var}], - children = Values_xml}. - -values_to_xml(Values) -> - lists:map(fun (Value) -> - #xmlel{name = <<"value">>, attrs = [], - children = [{xmlcdata, Value}]} - end, - Values). + Fields1 = lists:filter(fun ({Modules, _, _}) -> + case Modules of + all -> true; + Modules -> + lists:member(Module, Modules) + end + end, + Fields), + [#xdata_field{var = Var, values = Values} || {_, Var, Values} <- Fields1]. +-spec depends(binary(), gen_mod:opts()) -> []. depends(_Host, _Opts) -> []. diff --git a/src/mod_echo.erl b/src/mod_echo.erl index ee904d798..fe4b8d90d 100644 --- a/src/mod_echo.erl +++ b/src/mod_echo.erl @@ -42,7 +42,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -record(state, {host = <<"">> :: binary()}). @@ -118,10 +118,10 @@ handle_cast(_Msg, State) -> {noreply, State}. handle_info({route, From, To, Packet}, State) -> Packet2 = case From#jid.user of <<"">> -> - Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), + Lang = xmpp:get_lang(Packet), Txt = <<"User part of JID in 'from' is empty">>, - jlib:make_error_reply( - Packet, ?ERRT_BAD_REQUEST(Lang, Txt)); + xmpp:make_error( + Packet, xmpp:err_bad_request(Txt, Lang)); _ -> Packet end, do_client_version(disabled, To, From), @@ -168,37 +168,27 @@ code_change(_OldVsn, State, _Extra) -> {ok, State}. %% using exactly the same JID. We add a (mostly) random resource to %% try to guarantee that the received response matches the request sent. %% Finally, the received response is printed in the ejabberd log file. + +%% THIS IS **NOT** HOW TO WRITE ejabberd CODE. THIS CODE IS RETARDED. + do_client_version(disabled, _From, _To) -> ok; do_client_version(enabled, From, To) -> - ToS = jid:to_string(To), - Random_resource = - iolist_to_binary(integer_to_list(random:uniform(100000))), + Random_resource = randoms:get_string(), From2 = From#jid{resource = Random_resource, lresource = Random_resource}, - Packet = #xmlel{name = <<"iq">>, - attrs = [{<<"to">>, ToS}, {<<"type">>, <<"get">>}], - children = - [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_VERSION}], - children = []}]}, + ID = randoms:get_string(), + Packet = #iq{from = From, to = To, type = get, + id = randoms:get_string(), + sub_els = [#version{}]}, ejabberd_router:route(From2, To, Packet), - Els = receive - {route, To, From2, IQ} -> - #xmlel{name = <<"query">>, children = List} = - fxml:get_subtag(IQ, <<"query">>), - List - after 5000 -> % Timeout in miliseconds: 5 seconds - [] - end, - Values = [{Name, Value} - || #xmlel{name = Name, attrs = [], - children = [{xmlcdata, Value}]} - <- Els], - Values_string1 = [io_lib:format("~n~s: ~p", [N, V]) - || {N, V} <- Values], - Values_string2 = iolist_to_binary(Values_string1), - ?INFO_MSG("Information of the client: ~s~s", - [ToS, Values_string2]). + receive + {route, To, From2, + #iq{id = ID, type = result, sub_els = [#version{} = V]}} -> + ?INFO_MSG("Version of the client ~s:~n~s", + [jid:to_string(To), xmpp:pp(V)]) + after 5000 -> % Timeout in miliseconds: 5 seconds + [] + end. depends(_Host, _Opts) -> []. diff --git a/src/mod_last.erl b/src/mod_last.erl index ce9148841..b267aa89b 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -33,8 +33,8 @@ -behaviour(gen_mod). --export([start/2, stop/1, process_local_iq/3, export/1, - process_sm_iq/3, on_presence_update/4, import/1, +-export([start/2, stop/1, process_local_iq/1, export/1, + process_sm_iq/1, on_presence_update/4, import/1, import/3, store_last_info/4, get_last_info/2, remove_user/2, transform_options/1, mod_opt_type/1, opt_type/1, register_user/2, depends/2]). @@ -42,7 +42,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_privacy.hrl"). -include("mod_last.hrl"). @@ -87,25 +87,14 @@ stop(Host) -> %%% Uptime of ejabberd node %%% -process_local_iq(_From, _To, - #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> - case Type of - set -> - Txt = <<"Value 'set' of 'type' attribute is not allowed">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]}; - get -> - Sec = get_node_uptime(), - IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = - [{<<"xmlns">>, ?NS_LAST}, - {<<"seconds">>, - iolist_to_binary(integer_to_list(Sec))}], - children = []}]} - end. +-spec process_local_iq(iq()) -> iq(). +process_local_iq(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_local_iq(#iq{type = get} = IQ) -> + xmpp:make_iq_result(IQ, #last{seconds = get_node_uptime()}). -%% @spec () -> integer() +-spec get_node_uptime() -> non_neg_integer(). %% @doc Get the uptime of the ejabberd node, expressed in seconds. %% When ejabberd is starting, ejabberd_config:start/0 stores the datetime. get_node_uptime() -> @@ -118,6 +107,7 @@ get_node_uptime() -> p1_time_compat:system_time(seconds) - Now end. +-spec now_to_seconds(erlang:timestamp()) -> non_neg_integer(). now_to_seconds({MegaSecs, Secs, _MicroSecs}) -> MegaSecs * 1000000 + Secs. @@ -125,83 +115,63 @@ now_to_seconds({MegaSecs, Secs, _MicroSecs}) -> %%% Serve queries about user last online %%% -process_sm_iq(From, To, - #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> - case Type of - set -> - Txt = <<"Value 'set' of 'type' attribute is not allowed">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]}; - get -> - User = To#jid.luser, - Server = To#jid.lserver, - {Subscription, _Groups} = - ejabberd_hooks:run_fold(roster_get_jid_info, Server, - {none, []}, [User, Server, From]), - if (Subscription == both) or (Subscription == from) or - (From#jid.luser == To#jid.luser) and - (From#jid.lserver == To#jid.lserver) -> - UserListRecord = - ejabberd_hooks:run_fold(privacy_get_user_list, Server, - #userlist{}, [User, Server]), - case ejabberd_hooks:run_fold(privacy_check_packet, - Server, allow, - [User, Server, UserListRecord, - {To, From, - #xmlel{name = <<"presence">>, - attrs = [], - children = []}}, - out]) - of - allow -> get_last_iq(IQ, SubEl, User, Server); - deny -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_FORBIDDEN]} - end; - true -> - Txt = <<"Not subscribed">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_FORBIDDEN(Lang, Txt)]} - end +-spec process_sm_iq(iq()) -> iq(). +process_sm_iq(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_sm_iq(#iq{from = From, to = To, lang = Lang} = IQ) -> + User = To#jid.luser, + Server = To#jid.lserver, + {Subscription, _Groups} = + ejabberd_hooks:run_fold(roster_get_jid_info, Server, + {none, []}, [User, Server, From]), + if (Subscription == both) or (Subscription == from) or + (From#jid.luser == To#jid.luser) and + (From#jid.lserver == To#jid.lserver) -> + UserListRecord = + ejabberd_hooks:run_fold(privacy_get_user_list, Server, + #userlist{}, [User, Server]), + case ejabberd_hooks:run_fold(privacy_check_packet, + Server, allow, + [User, Server, UserListRecord, + {To, From, #presence{}}, out]) of + allow -> get_last_iq(IQ, User, Server); + deny -> xmpp:make_error(IQ, xmpp:err_forbidden()) + end; + true -> + Txt = <<"Not subscribed">>, + xmpp:make_error(IQ, xmpp:err_not_subscribed(Txt, Lang)) end. %% @spec (LUser::string(), LServer::string()) -> %% {ok, TimeStamp::integer(), Status::string()} | not_found | {error, Reason} +-spec get_last(binary(), binary()) -> {ok, non_neg_integer(), binary()} | + not_found | {error, any()}. get_last(LUser, LServer) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:get_last(LUser, LServer). -get_last_iq(#iq{lang = Lang} = IQ, SubEl, LUser, LServer) -> +-spec get_last_iq(iq(), binary(), binary()) -> iq(). +get_last_iq(#iq{lang = Lang} = IQ, LUser, LServer) -> case ejabberd_sm:get_user_resources(LUser, LServer) of [] -> case get_last(LUser, LServer) of {error, _Reason} -> Txt = <<"Database failure">>, - IQ#iq{type = error, - sub_el = [SubEl, ?ERRT_INTERNAL_SERVER_ERROR(Lang, Txt)]}; + xmpp:make_error(IQ, xmpp:err_internal_server_error(Txt, Lang)); not_found -> Txt = <<"No info about last activity found">>, - IQ#iq{type = error, - sub_el = [SubEl, ?ERRT_SERVICE_UNAVAILABLE(Lang, Txt)]}; + xmpp:make_error(IQ, xmpp:err_service_unavailable(Txt, Lang)); {ok, TimeStamp, Status} -> TimeStamp2 = p1_time_compat:system_time(seconds), Sec = TimeStamp2 - TimeStamp, - IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = - [{<<"xmlns">>, ?NS_LAST}, - {<<"seconds">>, - iolist_to_binary(integer_to_list(Sec))}], - children = [{xmlcdata, Status}]}]} + xmpp:make_iq_result(IQ, #last{seconds = Sec, status = Status}) end; _ -> - IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = - [{<<"xmlns">>, ?NS_LAST}, - {<<"seconds">>, <<"0">>}], - children = []}]} + xmpp:make_iq_result(IQ, #last{seconds = 0}) end. +-spec register_user(binary(), binary()) -> {atomic, any()}. register_user(User, Server) -> on_presence_update( User, @@ -209,18 +179,21 @@ register_user(User, Server) -> <<"RegisterResource">>, <<"Registered but didn't login">>). +-spec on_presence_update(binary(), binary(), binary(), binary()) -> {atomic, any()}. on_presence_update(User, Server, _Resource, Status) -> TimeStamp = p1_time_compat:system_time(seconds), store_last_info(User, Server, TimeStamp, Status). +-spec store_last_info(binary(), binary(), non_neg_integer(), binary()) -> + {atomic, any()}. store_last_info(User, Server, TimeStamp, Status) -> LUser = jid:nodeprep(User), LServer = jid:nameprep(Server), Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:store_last_info(LUser, LServer, TimeStamp, Status). -%% @spec (LUser::string(), LServer::string()) -> -%% {ok, TimeStamp::integer(), Status::string()} | not_found +-spec get_last_info(binary(), binary()) -> {ok, non_neg_integer(), binary()} | + not_found. get_last_info(LUser, LServer) -> case get_last(LUser, LServer) of {error, _Reason} -> not_found; diff --git a/src/mod_ping.erl b/src/mod_ping.erl index d1b3f9322..b09ca9ab2 100644 --- a/src/mod_ping.erl +++ b/src/mod_ping.erl @@ -36,7 +36,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -define(SUPERVISOR, ejabberd_sup). @@ -54,7 +54,7 @@ -export([init/1, terminate/2, handle_call/3, handle_cast/2, handle_info/2, code_change/3]). --export([iq_ping/3, user_online/3, user_offline/3, +-export([iq_ping/1, user_online/3, user_offline/3, user_send/4, mod_opt_type/1, depends/2]). -record(state, @@ -73,10 +73,12 @@ start_link(Host, Opts) -> gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []). +-spec start_ping(binary(), jid()) -> ok. start_ping(Host, JID) -> Proc = gen_mod:get_module_proc(Host, ?MODULE), gen_server:cast(Proc, {start_ping, JID}). +-spec stop_ping(binary(), jid()) -> ok. stop_ping(Host, JID) -> Proc = gen_mod:get_module_proc(Host, ?MODULE), gen_server:cast(Proc, {stop_ping, JID}). @@ -181,10 +183,7 @@ handle_cast({iq_pong, JID, timeout}, State) -> handle_cast(_Msg, State) -> {noreply, State}. handle_info({timeout, _TRef, {ping, JID}}, State) -> - IQ = #iq{type = get, - sub_el = - [#xmlel{name = <<"ping">>, - attrs = [{<<"xmlns">>, ?NS_PING}], children = []}]}, + IQ = #iq{type = get, sub_els = [#ping{}]}, Pid = self(), F = fun (Response) -> gen_server:cast(Pid, {iq_pong, JID, Response}) @@ -201,23 +200,22 @@ code_change(_OldVsn, State, _Extra) -> {ok, State}. %%==================================================================== %% Hook callbacks %%==================================================================== -iq_ping(_From, _To, - #iq{type = Type, sub_el = SubEl, lang = Lang} = IQ) -> - case {Type, SubEl} of - {get, #xmlel{name = <<"ping">>}} -> - IQ#iq{type = result, sub_el = []}; - _ -> - Txt = <<"Ping query is incorrect">>, - IQ#iq{type = error, - sub_el = [SubEl, ?ERRT_BAD_REQUEST(Lang, Txt)]} - end. +-spec iq_ping(iq()) -> iq(). +iq_ping(#iq{type = get, sub_els = [#ping{}]} = IQ) -> + xmpp:make_iq_result(IQ); +iq_ping(#iq{lang = Lang} = IQ) -> + Txt = <<"Ping query is incorrect">>, + xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)). +-spec user_online(ejabberd_sm:sid(), jid(), any()) -> ok. user_online(_SID, JID, _Info) -> start_ping(JID#jid.lserver, JID). +-spec user_offline(ejabberd_sm:sid(), jid(), any()) -> ok. user_offline(_SID, JID, _Info) -> stop_ping(JID#jid.lserver, JID). +-spec user_send(stanza(), ejabberd_c2s:state(), jid(), jid()) -> stanza(). user_send(Packet, _C2SState, JID, _From) -> start_ping(JID#jid.lserver, JID), Packet. @@ -225,6 +223,7 @@ user_send(Packet, _C2SState, JID, _From) -> %%==================================================================== %% Internal functions %%==================================================================== +-spec add_timer(jid(), non_neg_integer(), map()) -> map(). add_timer(JID, Interval, Timers) -> LJID = jid:tolower(JID), NewTimers = case maps:find(LJID, Timers) of @@ -237,6 +236,7 @@ add_timer(JID, Interval, Timers) -> {ping, JID}), maps:put(LJID, TRef, NewTimers). +-spec del_timer(jid(), map()) -> map(). del_timer(JID, Timers) -> LJID = jid:tolower(JID), case maps:find(LJID, Timers) of @@ -246,6 +246,7 @@ del_timer(JID, Timers) -> _ -> Timers end. +-spec cancel_timer(reference()) -> ok. cancel_timer(TRef) -> case erlang:cancel_timer(TRef) of false -> diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index 18ff78371..e88c1fb5b 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -31,8 +31,8 @@ -behaviour(gen_mod). --export([start/2, stop/1, process_iq/3, export/1, import/1, - process_iq_set/4, process_iq_get/5, get_user_list/3, +-export([start/2, stop/1, process_iq/1, export/1, import/1, + process_iq_set/2, process_iq_get/3, get_user_list/3, check_packet/6, remove_user/2, is_list_needdb/1, updated_list/3, item_to_xml/1, get_user_lists/2, import/3, @@ -41,15 +41,15 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_privacy.hrl"). -callback init(binary(), gen_mod:opts()) -> any(). -callback import(binary(), #privacy{}) -> ok | pass. --callback process_lists_get(binary(), binary()) -> {none | binary(), [xmlel()]} | error. +-callback process_lists_get(binary(), binary()) -> {none | binary(), [binary()]} | error. -callback process_list_get(binary(), binary(), binary()) -> [listitem()] | error | not_found. --callback process_default_set(binary(), binary(), {value, binary()} | false) -> {atomic, any()}. +-callback process_default_set(binary(), binary(), binary() | none) -> {atomic, any()}. -callback process_active_set(binary(), binary(), binary()) -> [listitem()] | error. -callback remove_privacy_list(binary(), binary(), binary()) -> {atomic, any()}. -callback set_privacy_list(#privacy{}) -> any(). @@ -96,335 +96,276 @@ stop(Host) -> gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PRIVACY). -process_iq(_From, _To, IQ) -> - SubEl = IQ#iq.sub_el, - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}. +-spec process_iq(iq()) -> iq(). +process_iq(IQ) -> + xmpp:make_error(IQ, xmpp:err_not_allowed()). -process_iq_get(_, From, _To, #iq{lang = Lang, sub_el = SubEl}, +-spec process_iq_get({error, error()} | iq(), + iq(), userlist()) -> {error, error()} | {result, privacy_query()}. +process_iq_get(_, #iq{from = From, lang = Lang, + sub_els = [#privacy_query{lists = Lists}]}, #userlist{name = Active}) -> #jid{luser = LUser, lserver = LServer} = From, - #xmlel{children = Els} = SubEl, - case fxml:remove_cdata(Els) of - [] -> process_lists_get(LUser, LServer, Active, Lang); - [#xmlel{name = Name, attrs = Attrs}] -> - case Name of - <<"list">> -> - ListName = fxml:get_attr(<<"name">>, Attrs), - process_list_get(LUser, LServer, ListName, Lang); - _ -> - Txt = <<"Unsupported tag name">>, - {error, ?ERRT_BAD_REQUEST(Lang, Txt)} - end; - _ -> {error, ?ERRT_BAD_REQUEST(Lang, <<"Too many elements">>)} + case Lists of + [] -> + process_lists_get(LUser, LServer, Active, Lang); + [#privacy_list{name = ListName}] -> + process_list_get(LUser, LServer, ListName, Lang); + _ -> + Txt = <<"Too many elements">>, + {error, xmpp:err_bad_request(Txt, Lang)} end. +-spec process_lists_get(binary(), binary(), binary(), undefined | binary()) -> + {error, error()} | {result, privacy_query()}. process_lists_get(LUser, LServer, Active, Lang) -> Mod = gen_mod:db_mod(LServer, ?MODULE), case Mod:process_lists_get(LUser, LServer) of - error -> {error, ?ERRT_INTERNAL_SERVER_ERROR(Lang, <<"Database failure">>)}; - {_Default, []} -> - {result, - [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_PRIVACY}], children = []}]}; - {Default, LItems} -> - DItems = case Default of - none -> LItems; - _ -> - [#xmlel{name = <<"default">>, - attrs = [{<<"name">>, Default}], children = []} - | LItems] - end, - ADItems = case Active of - none -> DItems; - _ -> - [#xmlel{name = <<"active">>, - attrs = [{<<"name">>, Active}], children = []} - | DItems] - end, - {result, - [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_PRIVACY}], - children = ADItems}]} + error -> + Txt = <<"Database failure">>, + {error, xmpp:err_internal_server_error(Txt, Lang)}; + {_Default, []} -> + {result, #privacy_query{}}; + {Default, ListNames} -> + {result, + #privacy_query{active = Active, + default = Default, + lists = [#privacy_list{name = ListName} + || ListName <- ListNames]}} end. -process_list_get(LUser, LServer, {value, Name}, Lang) -> +-spec process_list_get(binary(), binary(), binary(), undefined | binary()) -> + {error, error()} | {result, privacy_query()}. +process_list_get(LUser, LServer, Name, Lang) -> Mod = gen_mod:db_mod(LServer, ?MODULE), case Mod:process_list_get(LUser, LServer, Name) of - error -> {error, ?ERRT_INTERNAL_SERVER_ERROR(Lang, <<"Database failure">>)}; - not_found -> {error, ?ERR_ITEM_NOT_FOUND}; - Items -> - LItems = lists:map(fun item_to_xml/1, Items), - {result, - [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_PRIVACY}], - children = - [#xmlel{name = <<"list">>, attrs = [{<<"name">>, Name}], - children = LItems}]}]} - end; -process_list_get(_LUser, _LServer, false, _Lang) -> - {error, ?ERR_BAD_REQUEST}. - -item_to_xml(Item) -> - Attrs1 = [{<<"action">>, - action_to_list(Item#listitem.action)}, - {<<"order">>, order_to_list(Item#listitem.order)}], - Attrs2 = case Item#listitem.type of - none -> Attrs1; - Type -> - [{<<"type">>, type_to_list(Item#listitem.type)}, - {<<"value">>, value_to_list(Type, Item#listitem.value)} - | Attrs1] - end, - SubEls = case Item#listitem.match_all of - true -> []; - false -> - SE1 = case Item#listitem.match_iq of - true -> - [#xmlel{name = <<"iq">>, attrs = [], - children = []}]; - false -> [] - end, - SE2 = case Item#listitem.match_message of - true -> - [#xmlel{name = <<"message">>, attrs = [], - children = []} - | SE1]; - false -> SE1 - end, - SE3 = case Item#listitem.match_presence_in of - true -> - [#xmlel{name = <<"presence-in">>, attrs = [], - children = []} - | SE2]; - false -> SE2 - end, - SE4 = case Item#listitem.match_presence_out of - true -> - [#xmlel{name = <<"presence-out">>, attrs = [], - children = []} - | SE3]; - false -> SE3 - end, - SE4 - end, - #xmlel{name = <<"item">>, attrs = Attrs2, - children = SubEls}. - -action_to_list(Action) -> - case Action of - allow -> <<"allow">>; - deny -> <<"deny">> + error -> + Txt = <<"Database failure">>, + {error, xmpp:err_internal_server_error(Txt, Lang)}; + not_found -> + Txt = <<"No privacy list with this name found">>, + {error, xmpp:err_item_not_found(Txt, Lang)}; + Items -> + LItems = lists:map(fun encode_list_item/1, Items), + {result, + #privacy_query{ + lists = [#privacy_list{name = Name, items = LItems}]}} end. -order_to_list(Order) -> - iolist_to_binary(integer_to_list(Order)). +-spec item_to_xml(listitem()) -> xmlel(). +item_to_xml(ListItem) -> + xmpp:encode(encode_list_item(ListItem)). -type_to_list(Type) -> +-spec encode_list_item(listitem()) -> privacy_item(). +encode_list_item(#listitem{action = Action, + order = Order, + type = Type, + match_all = MatchAll, + match_iq = MatchIQ, + match_message = MatchMessage, + match_presence_in = MatchPresenceIn, + match_presence_out = MatchPresenceOut, + value = Value}) -> + Item = #privacy_item{action = Action, + order = Order, + type = case Type of + none -> undefined; + Type -> Type + end, + value = encode_value(Type, Value)}, + case MatchAll of + true -> + Item; + false -> + Item#privacy_item{message = MatchMessage, + iq = MatchIQ, + presence_in = MatchPresenceIn, + presence_out = MatchPresenceOut} + end. + +-spec encode_value(listitem_type(), listitem_value()) -> undefined | binary(). +encode_value(Type, Val) -> case Type of - jid -> <<"jid">>; - group -> <<"group">>; - subscription -> <<"subscription">> + jid -> jid:to_string(Val); + group -> Val; + subscription -> + case Val of + both -> <<"both">>; + to -> <<"to">>; + from -> <<"from">>; + none -> <<"none">> + end; + none -> undefined end. -value_to_list(Type, Val) -> +-spec decode_value(jid | subscription | group | undefined, binary()) -> + listitem_value(). +decode_value(Type, Value) -> case Type of - jid -> jid:to_string(Val); - group -> Val; - subscription -> - case Val of - both -> <<"both">>; - to -> <<"to">>; - from -> <<"from">>; - none -> <<"none">> - end + jid -> jid:from_string(Value); + subscription -> + case Value of + <<"from">> -> from; + <<"to">> -> to; + <<"both">> -> both; + <<"none">> -> none + end; + group -> Value; + undefined -> none end. -list_to_action(S) -> - case S of - <<"allow">> -> allow; - <<"deny">> -> deny - end. - -process_iq_set(_, From, _To, #iq{lang = Lang, sub_el = SubEl}) -> +-spec process_iq_set({error, error()} | + {result, privacy_query() | undefined, userlist()}, + iq()) -> {error, error()} | + {result, undefined, userlist()}. +process_iq_set(_, #iq{from = From, lang = Lang, + sub_els = [#privacy_query{default = Default, + active = Active, + lists = Lists}]}) -> #jid{luser = LUser, lserver = LServer} = From, - #xmlel{children = Els} = SubEl, - case fxml:remove_cdata(Els) of - [#xmlel{name = Name, attrs = Attrs, - children = SubEls}] -> - ListName = fxml:get_attr(<<"name">>, Attrs), - case Name of - <<"list">> -> - process_list_set(LUser, LServer, ListName, - fxml:remove_cdata(SubEls), Lang); - <<"active">> -> - process_active_set(LUser, LServer, ListName); - <<"default">> -> - process_default_set(LUser, LServer, ListName, Lang); - _ -> - Txt = <<"Unsupported tag name">>, - {error, ?ERRT_BAD_REQUEST(Lang, Txt)} - end; - _ -> {error, ?ERR_BAD_REQUEST} + case Lists of + [#privacy_list{items = Items, name = ListName}] + when Default == undefined, Active == undefined -> + process_lists_set(LUser, LServer, ListName, Items, Lang); + [] when Default == undefined, Active /= undefined -> + process_active_set(LUser, LServer, Active, Lang); + [] when Active == undefined, Default /= undefined -> + process_default_set(LUser, LServer, Default, Lang); + _ -> + Txt = <<"There should be exactly one element in this query: " + ", or ">>, + {error, xmpp:err_bad_request(Txt, Lang)} end. +-spec process_default_set(binary(), binary(), none | binary(), + undefined | binary()) -> {error, error()} | + {result, undefined}. process_default_set(LUser, LServer, Value, Lang) -> Mod = gen_mod:db_mod(LServer, ?MODULE), case Mod:process_default_set(LUser, LServer, Value) of - {atomic, error} -> - {error, ?ERRT_INTERNAL_SERVER_ERROR(Lang, <<"Database failure">>)}; - {atomic, not_found} -> {error, ?ERR_ITEM_NOT_FOUND}; - {atomic, ok} -> {result, []}; - _ -> {error, ?ERR_INTERNAL_SERVER_ERROR} + {atomic, error} -> + Txt = <<"Database failure">>, + {error, xmpp:err_internal_server_error(Txt, Lang)}; + {atomic, not_found} -> + Txt = <<"No privacy list with this name found">>, + {error, xmpp:err_item_not_found(Txt, Lang)}; + {atomic, ok} -> + {result, undefined}; + Err -> + ?ERROR_MSG("failed to set default list '~s' for user ~s@~s: ~p", + [Value, LUser, LServer, Err]), + {error, xmpp:err_internal_server_error()} end. -process_active_set(LUser, LServer, {value, Name}) -> +-spec process_active_set(binary(), binary(), none | binary(), + undefined | binary()) -> + {error, error()} | + {result, undefined, userlist()}. +process_active_set(_LUser, _LServer, none, _Lang) -> + {result, undefined, #userlist{}}; +process_active_set(LUser, LServer, Name, Lang) -> Mod = gen_mod:db_mod(LServer, ?MODULE), case Mod:process_active_set(LUser, LServer, Name) of - error -> {error, ?ERR_ITEM_NOT_FOUND}; - Items -> - NeedDb = is_list_needdb(Items), - {result, [], - #userlist{name = Name, list = Items, needdb = NeedDb}} - end; -process_active_set(_LUser, _LServer, false) -> - {result, [], #userlist{}}. + error -> + Txt = <<"No privacy list with this name found">>, + {error, xmpp:err_item_not_found(Txt, Lang)}; + Items -> + NeedDb = is_list_needdb(Items), + {result, undefined, + #userlist{name = Name, list = Items, needdb = NeedDb}} + end. +-spec set_privacy_list(privacy()) -> any(). set_privacy_list(#privacy{us = {_, LServer}} = Privacy) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:set_privacy_list(Privacy). -process_list_set(LUser, LServer, {value, Name}, Els, Lang) -> - case parse_items(Els) of - false -> {error, ?ERR_BAD_REQUEST}; - remove -> - Mod = gen_mod:db_mod(LServer, ?MODULE), - case Mod:remove_privacy_list(LUser, LServer, Name) of - {atomic, conflict} -> - Txt = <<"Cannot remove default list">>, - {error, ?ERRT_CONFLICT(Lang, Txt)}; - {atomic, ok} -> - ejabberd_sm:route(jid:make(LUser, LServer, - <<"">>), - jid:make(LUser, LServer, <<"">>), - {broadcast, {privacy_list, - #userlist{name = Name, - list = []}, - Name}}), - {result, []}; - _ -> {error, ?ERRT_INTERNAL_SERVER_ERROR(Lang, <<"Database failure">>)} - end; - List -> - Mod = gen_mod:db_mod(LServer, ?MODULE), - case Mod:set_privacy_list(LUser, LServer, Name, List) of - {atomic, ok} -> - NeedDb = is_list_needdb(List), - ejabberd_sm:route(jid:make(LUser, LServer, - <<"">>), - jid:make(LUser, LServer, <<"">>), - {broadcast, {privacy_list, - #userlist{name = Name, - list = List, - needdb = NeedDb}, - Name}}), - {result, []}; - _ -> {error, ?ERRT_INTERNAL_SERVER_ERROR(Lang, <<"Database failure">>)} - end +-spec process_lists_set(binary(), binary(), binary(), [privacy_item()], + undefined | binary()) -> {error, error()} | + {result, undefined}. +process_lists_set(LUser, LServer, Name, [], Lang) -> + Mod = gen_mod:db_mod(LServer, ?MODULE), + case Mod:remove_privacy_list(LUser, LServer, Name) of + {atomic, conflict} -> + Txt = <<"Cannot remove default list">>, + {error, xmpp:err_conflict(Txt, Lang)}; + {atomic, ok} -> + ejabberd_sm:route(jid:make(LUser, LServer, + <<"">>), + jid:make(LUser, LServer, <<"">>), + {broadcast, {privacy_list, + #userlist{name = Name, + list = []}, + Name}}), + {result, undefined}; + Err -> + ?ERROR_MSG("failed to remove privacy list '~s' for user ~s@~s: ~p", + [Name, LUser, LServer, Err]), + Txt = <<"Database failure">>, + {error, xmpp:err_internal_server_error(Txt, Lang)} end; -process_list_set(_LUser, _LServer, false, _Els, _Lang) -> - {error, ?ERR_BAD_REQUEST}. +process_lists_set(LUser, LServer, Name, Items, Lang) -> + case catch lists:map(fun decode_item/1, Items) of + {error, Why} -> + Txt = xmpp:format_error(Why), + {error, xmpp:err_bad_request(Txt, Lang)}; + List -> + Mod = gen_mod:db_mod(LServer, ?MODULE), + case Mod:set_privacy_list(LUser, LServer, Name, List) of + {atomic, ok} -> + NeedDb = is_list_needdb(List), + ejabberd_sm:route(jid:make(LUser, LServer, + <<"">>), + jid:make(LUser, LServer, <<"">>), + {broadcast, {privacy_list, + #userlist{name = Name, + list = List, + needdb = NeedDb}, + Name}}), + {result, undefined}; + Err -> + ?ERROR_MSG("failed to set privacy list '~s' " + "for user ~s@~s: ~p", + [Name, LUser, LServer, Err]), + Txt = <<"Database failure">>, + {error, xmpp:err_internal_server_error(Txt, Lang)} + end + end. -parse_items([]) -> remove; -parse_items(Els) -> parse_items(Els, []). - -parse_items([], Res) -> - lists:keysort(#listitem.order, Res); -parse_items([#xmlel{name = <<"item">>, attrs = Attrs, - children = SubEls} - | Els], - Res) -> - Type = fxml:get_attr(<<"type">>, Attrs), - Value = fxml:get_attr(<<"value">>, Attrs), - SAction = fxml:get_attr(<<"action">>, Attrs), - SOrder = fxml:get_attr(<<"order">>, Attrs), - Action = case catch list_to_action(element(2, SAction)) - of - {'EXIT', _} -> false; - Val -> Val - end, - Order = case catch jlib:binary_to_integer(element(2, - SOrder)) - of - {'EXIT', _} -> false; - IntVal -> - if IntVal >= 0 -> IntVal; - true -> false - end +-spec decode_item(privacy_item()) -> listitem(). +decode_item(#privacy_item{order = Order, + action = Action, + type = T, + value = V, + message = MatchMessage, + iq = MatchIQ, + presence_in = MatchPresenceIn, + presence_out = MatchPresenceOut}) -> + Value = try decode_value(T, V) + catch _:_ -> + throw({error, {bad_attr_value, <<"value">>, + <<"item">>, ?NS_PRIVACY}}) end, - if (Action /= false) and (Order /= false) -> - I1 = #listitem{action = Action, order = Order}, - I2 = case {Type, Value} of - {{value, T}, {value, V}} -> - case T of - <<"jid">> -> - case jid:from_string(V) of - error -> false; - JID -> - I1#listitem{type = jid, - value = jid:tolower(JID)} - end; - <<"group">> -> I1#listitem{type = group, value = V}; - <<"subscription">> -> - case V of - <<"none">> -> - I1#listitem{type = subscription, - value = none}; - <<"both">> -> - I1#listitem{type = subscription, - value = both}; - <<"from">> -> - I1#listitem{type = subscription, - value = from}; - <<"to">> -> - I1#listitem{type = subscription, value = to}; - _ -> false - end - end; - {{value, _}, false} -> false; - _ -> I1 - end, - case I2 of - false -> false; - _ -> - case parse_matches(I2, fxml:remove_cdata(SubEls)) of - false -> false; - I3 -> parse_items(Els, [I3 | Res]) - end - end; - true -> false - end; -parse_items(_, _Res) -> false. - -parse_matches(Item, []) -> - Item#listitem{match_all = true}; -parse_matches(Item, Els) -> parse_matches1(Item, Els). - -parse_matches1(Item, []) -> Item; -parse_matches1(Item, - [#xmlel{name = <<"message">>} | Els]) -> - parse_matches1(Item#listitem{match_message = true}, - Els); -parse_matches1(Item, [#xmlel{name = <<"iq">>} | Els]) -> - parse_matches1(Item#listitem{match_iq = true}, Els); -parse_matches1(Item, - [#xmlel{name = <<"presence-in">>} | Els]) -> - parse_matches1(Item#listitem{match_presence_in = true}, - Els); -parse_matches1(Item, - [#xmlel{name = <<"presence-out">>} | Els]) -> - parse_matches1(Item#listitem{match_presence_out = true}, - Els); -parse_matches1(_Item, [#xmlel{} | _Els]) -> false. + Type = case T of + undefined -> none; + _ -> T + end, + ListItem = #listitem{order = Order, + action = Action, + type = Type, + value = Value}, + if MatchMessage and MatchIQ and MatchPresenceIn and MatchPresenceOut -> + ListItem#listitem{match_all = true}; + not (MatchMessage or MatchIQ or MatchPresenceIn or MatchPresenceOut) -> + ListItem#listitem{match_all = true}; + true -> + ListItem#listitem{match_iq = MatchIQ, + match_message = MatchMessage, + match_presence_in = MatchPresenceIn, + match_presence_out = MatchPresenceOut} + end. +-spec is_list_needdb([listitem()]) -> boolean(). is_list_needdb(Items) -> lists:any(fun (X) -> case X#listitem.type of @@ -435,6 +376,7 @@ is_list_needdb(Items) -> end, Items). +-spec get_user_list(userlist(), binary(), binary()) -> userlist(). get_user_list(_Acc, User, Server) -> LUser = jid:nodeprep(User), LServer = jid:nameprep(Server), @@ -444,6 +386,7 @@ get_user_list(_Acc, User, Server) -> #userlist{name = Default, list = Items, needdb = NeedDb}. +-spec get_user_lists(binary(), binary()) -> {ok, privacy()} | error. get_user_lists(User, Server) -> LUser = jid:nodeprep(User), LServer = jid:nameprep(Server), @@ -453,6 +396,8 @@ get_user_lists(User, Server) -> %% From is the sender, To is the destination. %% If Dir = out, User@Server is the sender account (From). %% If Dir = in, User@Server is the destination account (To). +-spec check_packet(allow | deny, binary(), binary(), userlist(), + {jid(), jid(), stanza()}, in | out) -> allow | deny. check_packet(_, _User, _Server, _UserList, {#jid{luser = <<"">>, lserver = Server} = _From, #jid{lserver = Server} = _To, _}, @@ -470,22 +415,16 @@ check_packet(_, _User, _Server, _UserList, allow; check_packet(_, User, Server, #userlist{list = List, needdb = NeedDb}, - {From, To, #xmlel{name = PName, attrs = Attrs}}, Dir) -> + {From, To, Packet}, Dir) -> case List of [] -> allow; _ -> - PType = case PName of - <<"message">> -> message; - <<"iq">> -> iq; - <<"presence">> -> - case fxml:get_attr_s(<<"type">>, Attrs) of - %% notification - <<"">> -> presence; - <<"unavailable">> -> presence; - %% subscribe, subscribed, unsubscribe, - %% unsubscribed, error, probe, or other - _ -> other - end + PType = case Packet of + #message{} -> message; + #iq{} -> iq; + #presence{type = available} -> presence; + #presence{type = unavailable} -> presence; + _ -> other end, PType2 = case {PType, Dir} of {message, in} -> message; @@ -511,6 +450,10 @@ check_packet(_, User, Server, Groups) end. +-spec check_packet_aux([listitem()], + message | iq | presence_in | presence_out | other, + ljid(), none | both | from | to, [binary()]) -> + allow | deny. %% Ptype = mesage | iq | presence_in | presence_out | other check_packet_aux([], _PType, _JID, _Subscription, _Groups) -> @@ -536,6 +479,9 @@ check_packet_aux([Item | List], PType, JID, check_packet_aux(List, PType, JID, Subscription, Groups) end. +-spec is_ptype_match(listitem(), + message | iq | presence_in | presence_out | other) -> + boolean(). is_ptype_match(Item, PType) -> case Item#listitem.match_all of true -> true; @@ -549,6 +495,8 @@ is_ptype_match(Item, PType) -> end end. +-spec is_type_match(jid | subscription | group, listitem_value(), + ljid(), none | both | from | to, [binary()]) -> boolean(). is_type_match(Type, Value, JID, Subscription, Groups) -> case Type of jid -> @@ -575,6 +523,7 @@ remove_user(User, Server) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:remove_user(LUser, LServer). +-spec updated_list(userlist(), userlist(), userlist()) -> userlist(). updated_list(_, #userlist{name = OldName} = Old, #userlist{name = NewName} = New) -> if OldName == NewName -> New; diff --git a/src/mod_privacy_mnesia.erl b/src/mod_privacy_mnesia.erl index 4026b7f64..1a9172b5a 100644 --- a/src/mod_privacy_mnesia.erl +++ b/src/mod_privacy_mnesia.erl @@ -35,11 +35,7 @@ process_lists_get(LUser, LServer) -> {'EXIT', _Reason} -> error; [] -> {none, []}; [#privacy{default = Default, lists = Lists}] -> - LItems = lists:map(fun ({N, _}) -> - #xmlel{name = <<"list">>, - attrs = [{<<"name">>, N}], - children = []} - end, Lists), + LItems = lists:map(fun ({N, _}) -> N end, Lists), {Default, LItems} end. @@ -54,7 +50,15 @@ process_list_get(LUser, LServer, Name) -> end end. -process_default_set(LUser, LServer, {value, Name}) -> +process_default_set(LUser, LServer, none) -> + F = fun () -> + case mnesia:read({privacy, {LUser, LServer}}) of + [] -> ok; + [R] -> mnesia:write(R#privacy{default = none}) + end + end, + mnesia:transaction(F); +process_default_set(LUser, LServer, Name) -> F = fun () -> case mnesia:read({privacy, {LUser, LServer}}) of [] -> not_found; @@ -68,14 +72,6 @@ process_default_set(LUser, LServer, {value, Name}) -> end end end, - mnesia:transaction(F); -process_default_set(LUser, LServer, false) -> - F = fun () -> - case mnesia:read({privacy, {LUser, LServer}}) of - [] -> ok; - [R] -> mnesia:write(R#privacy{default = none}) - end - end, mnesia:transaction(F). process_active_set(LUser, LServer, Name) -> diff --git a/src/mod_privacy_riak.erl b/src/mod_privacy_riak.erl index 0c43e74f9..40e92005c 100644 --- a/src/mod_privacy_riak.erl +++ b/src/mod_privacy_riak.erl @@ -31,12 +31,7 @@ init(_Host, _Opts) -> process_lists_get(LUser, LServer) -> case ejabberd_riak:get(privacy, privacy_schema(), {LUser, LServer}) of {ok, #privacy{default = Default, lists = Lists}} -> - LItems = lists:map(fun ({N, _}) -> - #xmlel{name = <<"list">>, - attrs = [{<<"name">>, N}], - children = []} - end, - Lists), + LItems = lists:map(fun ({N, _}) -> N end, Lists), {Default, LItems}; {error, notfound} -> {none, []}; @@ -57,7 +52,15 @@ process_list_get(LUser, LServer, Name) -> error end. -process_default_set(LUser, LServer, {value, Name}) -> +process_default_set(LUser, LServer, none) -> + {atomic, + case ejabberd_riak:get(privacy, privacy_schema(), {LUser, LServer}) of + {ok, R} -> + ejabberd_riak:put(R#privacy{default = none}, privacy_schema()); + {error, _} -> + ok + end}; +process_default_set(LUser, LServer, Name) -> {atomic, case ejabberd_riak:get(privacy, privacy_schema(), {LUser, LServer}) of {ok, #privacy{lists = Lists} = P} -> @@ -71,14 +74,6 @@ process_default_set(LUser, LServer, {value, Name}) -> end; {error, _} -> not_found - end}; -process_default_set(LUser, LServer, false) -> - {atomic, - case ejabberd_riak:get(privacy, privacy_schema(), {LUser, LServer}) of - {ok, R} -> - ejabberd_riak:put(R#privacy{default = none}, privacy_schema()); - {error, _} -> - ok end}. process_active_set(LUser, LServer, Name) -> diff --git a/src/mod_privacy_sql.erl b/src/mod_privacy_sql.erl index 6da917e9d..66926f236 100644 --- a/src/mod_privacy_sql.erl +++ b/src/mod_privacy_sql.erl @@ -47,12 +47,7 @@ process_lists_get(LUser, LServer) -> end, case catch sql_get_privacy_list_names(LUser, LServer) of {selected, Names} -> - LItems = lists:map(fun ({N}) -> - #xmlel{name = <<"list">>, - attrs = [{<<"name">>, N}], - children = []} - end, - Names), + LItems = lists:map(fun ({N}) -> N end, Names), {Default, LItems}; _ -> error end. @@ -69,7 +64,15 @@ process_list_get(LUser, LServer, Name) -> _ -> error end. -process_default_set(LUser, LServer, {value, Name}) -> +process_default_set(LUser, LServer, none) -> + case catch sql_unset_default_privacy_list(LUser, + LServer) + of + {'EXIT', _Reason} -> {atomic, error}; + {error, _Reason} -> {atomic, error}; + _ -> {atomic, ok} + end; +process_default_set(LUser, LServer, Name) -> F = fun () -> case sql_get_privacy_list_names_t(LUser) of {selected, []} -> not_found; @@ -80,15 +83,7 @@ process_default_set(LUser, LServer, {value, Name}) -> end end end, - sql_queries:sql_transaction(LServer, F); -process_default_set(LUser, LServer, false) -> - case catch sql_unset_default_privacy_list(LUser, - LServer) - of - {'EXIT', _Reason} -> {atomic, error}; - {error, _Reason} -> {atomic, error}; - _ -> {atomic, ok} - end. + sql_queries:sql_transaction(LServer, F). process_active_set(LUser, LServer, Name) -> case catch sql_get_privacy_list_id(LUser, LServer, Name) of diff --git a/src/mod_private.erl b/src/mod_private.erl index f0e4632f6..28d49bb3f 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -31,14 +31,14 @@ -behaviour(gen_mod). --export([start/2, stop/1, process_sm_iq/3, import/3, +-export([start/2, stop/1, process_sm_iq/1, import/3, remove_user/2, get_data/2, export/1, import/1, mod_opt_type/1, set_data/3, depends/2]). -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_private.hrl"). -callback init(binary(), gen_mod:opts()) -> any(). @@ -46,10 +46,7 @@ -callback set_data(binary(), binary(), [{binary(), xmlel()}]) -> {atomic, any()}. -callback get_data(binary(), binary(), binary()) -> {ok, xmlel()} | error. -callback get_all_data(binary(), binary()) -> [xmlel()]. - --define(Xmlel_Query(Attrs, Children), - #xmlel{name = <<"query">>, attrs = Attrs, - children = Children}). +-callback remove_user(binary(), binary()) -> {atomic, any()}. start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, fun gen_iq_handler:check_type/1, @@ -67,90 +64,55 @@ stop(Host) -> gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PRIVATE). -process_sm_iq(#jid{luser = LUser, lserver = LServer}, - #jid{luser = LUser, lserver = LServer}, #iq{lang = Lang} = IQ) - when IQ#iq.type == set -> - case IQ#iq.sub_el of - #xmlel{name = <<"query">>, children = Xmlels} -> - case filter_xmlels(Xmlels) of - [] -> - Txt = <<"No private data found in this query">>, - IQ#iq{type = error, - sub_el = [IQ#iq.sub_el, ?ERRT_NOT_ACCEPTABLE(Lang, Txt)]}; - Data -> - set_data(LUser, LServer, Data), - IQ#iq{type = result, sub_el = []} - end; - _ -> - Txt = <<"No query found">>, - IQ#iq{type = error, - sub_el = [IQ#iq.sub_el, ?ERRT_NOT_ACCEPTABLE(Lang, Txt)]} +-spec process_sm_iq(iq()) -> iq(). +process_sm_iq(#iq{type = Type, lang = Lang, + from = #jid{luser = LUser, lserver = LServer}, + to = #jid{luser = LUser, lserver = LServer}, + sub_els = [#private{xml_els = Els0}]} = IQ) -> + case filter_xmlels(Els0) of + [] -> + Txt = <<"No private data found in this query">>, + xmpp:make_error(IQ, xmpp:err_bad_format(Txt, Lang)); + Data when Type == set -> + set_data(LUser, LServer, Data), + xmpp:make_iq_result(IQ); + Data when Type == get -> + StorageEls = get_data(LUser, LServer, Data), + xmpp:make_iq_result(IQ, #private{xml_els = StorageEls}) end; -%% -process_sm_iq(#jid{luser = LUser, lserver = LServer}, - #jid{luser = LUser, lserver = LServer}, #iq{lang = Lang} = IQ) - when IQ#iq.type == get -> - case IQ#iq.sub_el of - #xmlel{name = <<"query">>, attrs = Attrs, - children = Xmlels} -> - case filter_xmlels(Xmlels) of - [] -> - Txt = <<"No private data found in this query">>, - IQ#iq{type = error, - sub_el = [IQ#iq.sub_el, ?ERRT_BAD_FORMAT(Lang, Txt)]}; - Data -> - case catch get_data(LUser, LServer, Data) of - {'EXIT', _Reason} -> - Txt = <<"Database failure">>, - IQ#iq{type = error, - sub_el = - [IQ#iq.sub_el, ?ERRT_INTERNAL_SERVER_ERROR(Lang, Txt)]}; - Storage_Xmlels -> - IQ#iq{type = result, - sub_el = [?Xmlel_Query(Attrs, Storage_Xmlels)]} - end - end; - _ -> - Txt = <<"No query found">>, - IQ#iq{type = error, - sub_el = [IQ#iq.sub_el, ?ERRT_BAD_FORMAT(Lang, Txt)]} - end; -%% -process_sm_iq(_From, _To, #iq{lang = Lang} = IQ) -> +process_sm_iq(#iq{lang = Lang} = IQ) -> Txt = <<"Query to another users is forbidden">>, - IQ#iq{type = error, - sub_el = [IQ#iq.sub_el, ?ERRT_FORBIDDEN(Lang, Txt)]}. + xmpp:make_error(IQ, xmpp:err_forbidden(Txt, Lang)). -filter_xmlels(Xmlels) -> filter_xmlels(Xmlels, []). - -filter_xmlels([], Data) -> lists:reverse(Data); -filter_xmlels([#xmlel{attrs = Attrs} = Xmlel | Xmlels], - Data) -> - case fxml:get_attr_s(<<"xmlns">>, Attrs) of - <<"">> -> []; - XmlNS -> filter_xmlels(Xmlels, [{XmlNS, Xmlel} | Data]) - end; -filter_xmlels([_ | Xmlels], Data) -> - filter_xmlels(Xmlels, Data). +-spec filter_xmlels([xmlel()]) -> [{binary(), xmlel()}]. +filter_xmlels(Els) -> + lists:flatmap( + fun(#xmlel{} = El) -> + case fxml:get_tag_attr_s(<<"xmlns">>, El) of + <<"">> -> []; + NS -> [{NS, El}] + end + end, Els). +-spec set_data(binary(), binary(), [{binary(), xmlel()}]) -> {atomic, any()}. set_data(LUser, LServer, Data) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:set_data(LUser, LServer, Data). +-spec get_data(binary(), binary(), [{binary(), xmlel()}]) -> [xmlel()]. get_data(LUser, LServer, Data) -> Mod = gen_mod:db_mod(LServer, ?MODULE), - get_data(LUser, LServer, Data, Mod, []). - -get_data(_LUser, _LServer, [], _Mod, Storage_Xmlels) -> - lists:reverse(Storage_Xmlels); -get_data(LUser, LServer, [{XmlNS, Xmlel} | Data], Mod, Storage_Xmlels) -> - case Mod:get_data(LUser, LServer, XmlNS) of - {ok, Storage_Xmlel} -> - get_data(LUser, LServer, Data, Mod, [Storage_Xmlel | Storage_Xmlels]); - error -> - get_data(LUser, LServer, Data, Mod, [Xmlel | Storage_Xmlels]) - end. + lists:map( + fun({NS, El}) -> + case Mod:get_data(LUser, LServer, NS) of + {ok, StorageEl} -> + StorageEl; + error -> + El + end + end, Data). +-spec get_data(binary(), binary()) -> [xmlel()]. get_data(LUser, LServer) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:get_all_data(LUser, LServer). diff --git a/src/mod_roster.erl b/src/mod_roster.erl index a75041bc7..58dc51983 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -41,12 +41,12 @@ -behaviour(gen_mod). --export([start/2, stop/1, process_iq/3, export/1, - import/1, process_local_iq/3, get_user_roster/2, +-export([start/2, stop/1, process_iq/1, export/1, + import/1, process_local_iq/1, get_user_roster/2, import/3, get_subscription_lists/3, get_roster/2, get_in_pending_subscriptions/3, in_subscription/6, out_subscription/4, set_items/3, remove_user/2, - get_jid_info/4, item_to_xml/1, webadmin_page/3, + get_jid_info/4, encode_item/1, webadmin_page/3, webadmin_user/4, get_versioning_feature/2, roster_versioning_enabled/1, roster_version/2, mod_opt_type/1, set_roster/1, depends/2]). @@ -54,7 +54,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_roster.hrl"). @@ -139,24 +139,23 @@ stop(Host) -> depends(_Host, _Opts) -> []. -process_iq(From, To, IQ) when ((From#jid.luser == <<"">>) andalso (From#jid.resource == <<"">>)) -> - process_iq_manager(From, To, IQ); +process_iq(#iq{from = #jid{luser = <<"">>}, + to = #jid{resource = <<"">>}} = IQ) -> + process_iq_manager(IQ); -process_iq(From, To, IQ) -> - #iq{sub_el = SubEl, lang = Lang} = IQ, +process_iq(#iq{from = From, lang = Lang} = IQ) -> #jid{lserver = LServer} = From, case lists:member(LServer, ?MYHOSTS) of - true -> process_local_iq(From, To, IQ); + true -> process_local_iq(IQ); _ -> Txt = <<"The query is only allowed from local users">>, - IQ#iq{type = error, - sub_el = [SubEl, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)]} + xmpp:make_error(IQ, xmpp:err_item_not_found(Txt, Lang)) end. -process_local_iq(From, To, #iq{type = Type} = IQ) -> +process_local_iq(#iq{type = Type} = IQ) -> case Type of - set -> try_process_iq_set(From, To, IQ); - get -> process_iq_get(From, To, IQ) + set -> try_process_iq_set(IQ); + get -> process_iq_get(IQ) end. roster_hash(Items) -> @@ -179,10 +178,7 @@ roster_version_on_db(Host) -> get_versioning_feature(Acc, Host) -> case roster_versioning_enabled(Host) of true -> - Feature = #xmlel{name = <<"ver">>, - attrs = [{<<"xmlns">>, ?NS_ROSTER_VER}], - children = []}, - [Feature | Acc]; + [#rosterver_feature{}|Acc]; false -> [] end. @@ -221,82 +217,61 @@ write_roster_version(LUser, LServer, InTransaction) -> %% - roster versioning is not used by the client OR %% - roster versioning is used by server and client, BUT the server isn't storing versions on db OR %% - the roster version from client don't match current version. -process_iq_get(From, To, #iq{sub_el = SubEl} = IQ) -> +process_iq_get(#iq{from = From, to = To, lang = Lang, + sub_els = [#roster_query{ver = RequestedVersion}]} = IQ) -> LUser = From#jid.luser, LServer = From#jid.lserver, US = {LUser, LServer}, - try {ItemsToSend, VersionToSend} = case - {fxml:get_tag_attr(<<"ver">>, SubEl), - roster_versioning_enabled(LServer), - roster_version_on_db(LServer)} - of - {{value, RequestedVersion}, true, - true} -> - case read_roster_version(LUser, - LServer) - of - error -> - RosterVersion = - write_roster_version(LUser, - LServer), - {lists:map(fun item_to_xml/1, - ejabberd_hooks:run_fold(roster_get, - To#jid.lserver, - [], - [US])), - RosterVersion}; - RequestedVersion -> - {false, false}; - NewVersion -> - {lists:map(fun item_to_xml/1, - ejabberd_hooks:run_fold(roster_get, - To#jid.lserver, - [], - [US])), - NewVersion} - end; - {{value, RequestedVersion}, true, - false} -> - RosterItems = - ejabberd_hooks:run_fold(roster_get, - To#jid.lserver, - [], - [US]), - case roster_hash(RosterItems) of - RequestedVersion -> - {false, false}; - New -> - {lists:map(fun item_to_xml/1, - RosterItems), - New} - end; - _ -> - {lists:map(fun item_to_xml/1, - ejabberd_hooks:run_fold(roster_get, - To#jid.lserver, - [], - [US])), - false} - end, - IQ#iq{type = result, - sub_el = - case {ItemsToSend, VersionToSend} of - {false, false} -> []; - {Items, false} -> - [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_ROSTER}], - children = Items}]; - {Items, Version} -> - [#xmlel{name = <<"query">>, - attrs = - [{<<"xmlns">>, ?NS_ROSTER}, - {<<"ver">>, Version}], - children = Items}] - end} - catch - _:_ -> - IQ#iq{type = error, - sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]} + try {ItemsToSend, VersionToSend} = + case {roster_versioning_enabled(LServer), + roster_version_on_db(LServer)} of + {true, true} when RequestedVersion /= undefined -> + case read_roster_version(LUser, LServer) of + error -> + RosterVersion = write_roster_version(LUser, LServer), + {lists:map(fun encode_item/1, + ejabberd_hooks:run_fold( + roster_get, To#jid.lserver, [], [US])), + RosterVersion}; + RequestedVersion -> + {false, false}; + NewVersion -> + {lists:map(fun encode_item/1, + ejabberd_hooks:run_fold( + roster_get, To#jid.lserver, [], [US])), + NewVersion} + end; + {true, false} when RequestedVersion /= undefined -> + RosterItems = ejabberd_hooks:run_fold( + roster_get, To#jid.lserver, [], [US]), + case roster_hash(RosterItems) of + RequestedVersion -> + {false, false}; + New -> + {lists:map(fun encode_item/1, RosterItems), New} + end; + _ -> + {lists:map(fun encode_item/1, + ejabberd_hooks:run_fold( + roster_get, To#jid.lserver, [], [US])), + false} + end, + xmpp:make_iq_result( + IQ, + case {ItemsToSend, VersionToSend} of + {false, false} -> + undefined; + {Items, false} -> + #roster_query{items = Items}; + {Items, Version} -> + #roster_query{items = Items, + ver = Version} + end) + catch E:R -> + ?ERROR_MSG("failed to process roster get for ~s: ~p", + [jid:to_string(From), {E, {R, erlang:get_stacktrace()}}]), + Txt = <<"Roster module has failed">>, + xmpp:make_error(IQ, xmpp:err_internal_server_error(Txt, Lang)) end. get_user_roster(Acc, {LUser, LServer}) -> @@ -320,144 +295,83 @@ set_roster(#roster{us = {LUser, LServer}, jid = LJID} = Item) -> roster_subscribe_t(LUser, LServer, LJID, Item) end). -item_to_xml(Item) -> - Attrs1 = [{<<"jid">>, - jid:to_string(Item#roster.jid)}], - Attrs2 = case Item#roster.name of - <<"">> -> Attrs1; - Name -> [{<<"name">>, Name} | Attrs1] - end, - Attrs3 = case Item#roster.subscription of - none -> [{<<"subscription">>, <<"none">>} | Attrs2]; - from -> [{<<"subscription">>, <<"from">>} | Attrs2]; - to -> [{<<"subscription">>, <<"to">>} | Attrs2]; - both -> [{<<"subscription">>, <<"both">>} | Attrs2]; - remove -> [{<<"subscription">>, <<"remove">>} | Attrs2] - end, - Attrs4 = case ask_to_pending(Item#roster.ask) of - out -> [{<<"ask">>, <<"subscribe">>} | Attrs3]; - both -> [{<<"ask">>, <<"subscribe">>} | Attrs3]; - _ -> Attrs3 - end, - SubEls1 = lists:map(fun (G) -> - #xmlel{name = <<"group">>, attrs = [], - children = [{xmlcdata, G}]} - end, - Item#roster.groups), - SubEls = SubEls1 ++ Item#roster.xs, - #xmlel{name = <<"item">>, attrs = Attrs4, - children = SubEls}. +encode_item(Item) -> + #roster_item{jid = jid:make(Item#roster.jid), + name = Item#roster.name, + subscription = Item#roster.subscription, + ask = case ask_to_pending(Item#roster.ask) of + out -> subscribe; + both -> subscribe; + _ -> undefined + end, + groups = Item#roster.groups}. + +decode_item(#roster_item{} = Item, R, Managed) -> + R#roster{jid = jid:tolower(Item#roster_item.jid), + name = Item#roster_item.name, + subscription = case Item#roster_item.subscription of + remove -> remove; + Sub when Managed -> Sub; + _ -> undefined + end, + groups = Item#roster_item.groups}. get_roster_by_jid_t(LUser, LServer, LJID) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:get_roster_by_jid(LUser, LServer, LJID). -try_process_iq_set(From, To, #iq{sub_el = SubEl, lang = Lang} = IQ) -> +try_process_iq_set(#iq{from = From, lang = Lang} = IQ) -> #jid{server = Server} = From, Access = gen_mod:get_module_opt(Server, ?MODULE, access, fun(A) -> A end, all), case acl:match_rule(Server, Access, From) of deny -> Txt = <<"Denied by ACL">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]}; + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); allow -> - process_iq_set(From, To, IQ) + process_iq_set(IQ) end. -process_iq_set(From, To, #iq{sub_el = SubEl, id = Id} = IQ) -> - #xmlel{children = Els} = SubEl, +process_iq_set(#iq{from = From, to = To, id = Id, + sub_els = [#roster_query{items = Items}]} = IQ) -> Managed = is_managed_from_id(Id), - lists:foreach(fun (El) -> process_item_set(From, To, El, Managed) + lists:foreach(fun (Item) -> process_item_set(From, To, Item, Managed) end, - Els), - IQ#iq{type = result, sub_el = []}. + Items), + xmpp:make_iq_result(IQ). -process_item_set(From, To, - #xmlel{attrs = Attrs, children = Els}, Managed) -> - JID1 = jid:from_string(fxml:get_attr_s(<<"jid">>, - Attrs)), - #jid{user = User, luser = LUser, lserver = LServer} = - From, - case JID1 of - error -> ok; - _ -> - LJID = jid:tolower(JID1), - F = fun () -> - Item = get_roster_by_jid_t(LUser, LServer, LJID), - Item1 = process_item_attrs_managed(Item, Attrs, Managed), - Item2 = process_item_els(Item1, Els), - Item3 = ejabberd_hooks:run_fold(roster_process_item, - LServer, Item2, - [LServer]), - case Item3#roster.subscription of - remove -> del_roster_t(LUser, LServer, LJID); - _ -> update_roster_t(LUser, LServer, LJID, Item3) - end, - send_itemset_to_managers(From, Item3, Managed), - case roster_version_on_db(LServer) of - true -> write_roster_version_t(LUser, LServer); - false -> ok - end, - {Item, Item3} - end, - case transaction(LServer, F) of - {atomic, {OldItem, Item}} -> - push_item(User, LServer, To, Item), - case Item#roster.subscription of - remove -> - send_unsubscribing_presence(From, OldItem), ok; - _ -> ok - end; - E -> - ?DEBUG("ROSTER: roster item set error: ~p~n", [E]), ok - end +process_item_set(From, To, #roster_item{jid = JID1} = QueryItem, Managed) -> + #jid{user = User, luser = LUser, lserver = LServer} = From, + LJID = jid:tolower(JID1), + F = fun () -> + Item = get_roster_by_jid_t(LUser, LServer, LJID), + Item2 = decode_item(QueryItem, Item, Managed), + Item3 = ejabberd_hooks:run_fold(roster_process_item, + LServer, Item2, + [LServer]), + case Item3#roster.subscription of + remove -> del_roster_t(LUser, LServer, LJID); + _ -> update_roster_t(LUser, LServer, LJID, Item3) + end, + send_itemset_to_managers(From, Item3, Managed), + case roster_version_on_db(LServer) of + true -> write_roster_version_t(LUser, LServer); + false -> ok + end, + {Item, Item3} + end, + case transaction(LServer, F) of + {atomic, {OldItem, Item}} -> + push_item(User, LServer, To, Item), + case Item#roster.subscription of + remove -> + send_unsubscribing_presence(From, OldItem), ok; + _ -> ok + end; + E -> + ?DEBUG("ROSTER: roster item set error: ~p~n", [E]), ok end; process_item_set(_From, _To, _, _Managed) -> ok. -process_item_attrs(Item, [{Attr, Val} | Attrs]) -> - case Attr of - <<"jid">> -> - case jid:from_string(Val) of - error -> process_item_attrs(Item, Attrs); - JID1 -> - JID = {JID1#jid.luser, JID1#jid.lserver, - JID1#jid.lresource}, - process_item_attrs(Item#roster{jid = JID}, Attrs) - end; - <<"name">> -> - process_item_attrs(Item#roster{name = Val}, Attrs); - <<"subscription">> -> - case Val of - <<"remove">> -> - process_item_attrs(Item#roster{subscription = remove}, - Attrs); - _ -> process_item_attrs(Item, Attrs) - end; - <<"ask">> -> process_item_attrs(Item, Attrs); - _ -> process_item_attrs(Item, Attrs) - end; -process_item_attrs(Item, []) -> Item. - -process_item_els(Item, - [#xmlel{name = Name, attrs = Attrs, children = SEls} - | Els]) -> - case Name of - <<"group">> -> - Groups = [fxml:get_cdata(SEls) | Item#roster.groups], - process_item_els(Item#roster{groups = Groups}, Els); - _ -> - case fxml:get_attr_s(<<"xmlns">>, Attrs) of - <<"">> -> process_item_els(Item, Els); - _ -> - XEls = [#xmlel{name = Name, attrs = Attrs, - children = SEls} - | Item#roster.xs], - process_item_els(Item#roster{xs = XEls}, Els) - end - end; -process_item_els(Item, [{xmlcdata, _} | Els]) -> - process_item_els(Item, Els); -process_item_els(Item, []) -> Item. - push_item(User, Server, From, Item) -> ejabberd_sm:route(jid:make(<<"">>, <<"">>, <<"">>), jid:make(User, Server, <<"">>), @@ -480,21 +394,19 @@ push_item(User, Server, Resource, From, Item) -> push_item(User, Server, Resource, From, Item, RosterVersion) -> - ExtraAttrs = case RosterVersion of - not_found -> []; - _ -> [{<<"ver">>, RosterVersion}] - end, - ResIQ = #iq{type = set, xmlns = ?NS_ROSTER, + Ver = case RosterVersion of + not_found -> undefined; + _ -> RosterVersion + end, + ResIQ = #iq{type = set, %% @doc Roster push, calculate and include the version attribute. %% TODO: don't push to those who didn't load roster id = <<"push", (randoms:get_string())/binary>>, - sub_el = - [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_ROSTER} | ExtraAttrs], - children = [item_to_xml(Item)]}]}, + sub_els = [#roster_query{ver = Ver, + items = [encode_item(Item)]}]}, ejabberd_router:route(From, jid:make(User, Server, Resource), - jlib:iq_to_xml(ResIQ)). + ResIQ). push_item_version(Server, User, From, Item, RosterVersion) -> @@ -598,16 +510,8 @@ process_subscription(Direction, User, Server, JID1, case AutoReply of none -> ok; _ -> - T = case AutoReply of - subscribed -> <<"subscribed">>; - unsubscribed -> <<"unsubscribed">> - end, - ejabberd_router:route(jid:make(User, Server, - <<"">>), - JID1, - #xmlel{name = <<"presence">>, - attrs = [{<<"type">>, T}], - children = []}) + ejabberd_router:route(jid:make(User, Server, <<"">>), + JID1, #presence{type = AutoReply}) end, case Push of {push, Item} -> @@ -769,24 +673,19 @@ send_unsubscribing_presence(From, Item) -> _ -> false end, if IsTo -> - send_presence_type(jid:remove_resource(From), - jid:make(Item#roster.jid), - <<"unsubscribe">>); + ejabberd_router:route(jid:remove_resource(From), + jid:make(Item#roster.jid), + #presence{type = unsubscribe}); true -> ok end, if IsFrom -> - send_presence_type(jid:remove_resource(From), - jid:make(Item#roster.jid), - <<"unsubscribed">>); + ejabberd_router:route(jid:remove_resource(From), + jid:make(Item#roster.jid), + #presence{type = unsubscribed}); true -> ok end, ok. -send_presence_type(From, To, Type) -> - ejabberd_router:route(From, To, - #xmlel{name = <<"presence">>, - attrs = [{<<"type">>, Type}], children = []}). - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% set_items(User, Server, SubEl) -> @@ -809,65 +708,20 @@ del_roster_t(LUser, LServer, LJID) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:del_roster(LUser, LServer, LJID). -process_item_set_t(LUser, LServer, - #xmlel{attrs = Attrs, children = Els}) -> - JID1 = jid:from_string(fxml:get_attr_s(<<"jid">>, - Attrs)), - case JID1 of - error -> ok; - _ -> - JID = {JID1#jid.user, JID1#jid.server, - JID1#jid.resource}, - LJID = {JID1#jid.luser, JID1#jid.lserver, - JID1#jid.lresource}, - Item = #roster{usj = {LUser, LServer, LJID}, - us = {LUser, LServer}, jid = JID}, - Item1 = process_item_attrs_ws(Item, Attrs), - Item2 = process_item_els(Item1, Els), - case Item2#roster.subscription of - remove -> del_roster_t(LUser, LServer, LJID); - _ -> update_roster_t(LUser, LServer, LJID, Item2) - end +process_item_set_t(LUser, LServer, #roster_item{jid = JID1} = QueryItem) -> + JID = {JID1#jid.user, JID1#jid.server, + JID1#jid.resource}, + LJID = {JID1#jid.luser, JID1#jid.lserver, + JID1#jid.lresource}, + Item = #roster{usj = {LUser, LServer, LJID}, + us = {LUser, LServer}, jid = JID}, + Item2 = decode_item(QueryItem, Item, _Managed = true), + case Item2#roster.subscription of + remove -> del_roster_t(LUser, LServer, LJID); + _ -> update_roster_t(LUser, LServer, LJID, Item2) end; process_item_set_t(_LUser, _LServer, _) -> ok. -process_item_attrs_ws(Item, [{Attr, Val} | Attrs]) -> - case Attr of - <<"jid">> -> - case jid:from_string(Val) of - error -> process_item_attrs_ws(Item, Attrs); - JID1 -> - JID = {JID1#jid.luser, JID1#jid.lserver, - JID1#jid.lresource}, - process_item_attrs_ws(Item#roster{jid = JID}, Attrs) - end; - <<"name">> -> - process_item_attrs_ws(Item#roster{name = Val}, Attrs); - <<"subscription">> -> - case Val of - <<"remove">> -> - process_item_attrs_ws(Item#roster{subscription = - remove}, - Attrs); - <<"none">> -> - process_item_attrs_ws(Item#roster{subscription = none}, - Attrs); - <<"both">> -> - process_item_attrs_ws(Item#roster{subscription = both}, - Attrs); - <<"from">> -> - process_item_attrs_ws(Item#roster{subscription = from}, - Attrs); - <<"to">> -> - process_item_attrs_ws(Item#roster{subscription = to}, - Attrs); - _ -> process_item_attrs_ws(Item, Attrs) - end; - <<"ask">> -> process_item_attrs_ws(Item, Attrs); - _ -> process_item_attrs_ws(Item, Attrs) - end; -process_item_attrs_ws(Item, []) -> Item. - get_in_pending_subscriptions(Ls, User, Server) -> LServer = jid:nameprep(Server), Mod = gen_mod:db_mod(LServer, ?MODULE), @@ -876,31 +730,18 @@ get_in_pending_subscriptions(Ls, User, Server) -> get_in_pending_subscriptions(Ls, User, Server, Mod) -> JID = jid:make(User, Server, <<"">>), Result = Mod:get_only_items(JID#jid.luser, JID#jid.lserver), - Ls ++ lists:map(fun (R) -> - Message = R#roster.askmessage, - Status = if is_binary(Message) -> (Message); - true -> <<"">> - end, - #xmlel{name = <<"presence">>, - attrs = - [{<<"from">>, - jid:to_string(R#roster.jid)}, - {<<"to">>, jid:to_string(JID)}, - {<<"type">>, <<"subscribe">>}], - children = - [#xmlel{name = <<"status">>, - attrs = [], - children = - [{xmlcdata, Status}]}]} - end, - lists:filter(fun (R) -> - case R#roster.ask of - in -> true; - both -> true; - _ -> false - end - end, - Result)). + Ls ++ lists:flatmap( + fun(#roster{ask = Ask} = R) when Ask == in; Ask == both -> + Message = R#roster.askmessage, + Status = if is_binary(Message) -> (Message); + true -> <<"">> + end, + [#presence{from = R#roster.jid, to = JID, + type = subscribe, + status = xmpp:mk_text(Status)}]; + (_) -> + [] + end, Result). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1070,10 +911,7 @@ user_roster_parse_query(User, Server, Items, Query) -> user_roster_subscribe_jid(User, Server, JID) -> out_subscription(User, Server, JID, subscribe), UJID = jid:make(User, Server, <<"">>), - ejabberd_router:route(UJID, JID, - #xmlel{name = <<"presence">>, - attrs = [{<<"type">>, <<"subscribe">>}], - children = []}). + ejabberd_router:route(UJID, JID, #presence{type = subscribe}). user_roster_item_parse_query(User, Server, Items, Query) -> @@ -1089,12 +927,7 @@ user_roster_item_parse_query(User, Server, Items, subscribed), UJID = jid:make(User, Server, <<"">>), ejabberd_router:route(UJID, JID1, - #xmlel{name = - <<"presence">>, - attrs = - [{<<"type">>, - <<"subscribed">>}], - children = []}), + #presence{type = subscribed}), throw(submitted); false -> case lists:keysearch(<<"remove", @@ -1102,29 +935,17 @@ user_roster_item_parse_query(User, Server, Items, 1, Query) of {value, _} -> - UJID = jid:make(User, Server, - <<"">>), - process_iq_set(UJID, UJID, - #iq{type = set, - sub_el = - #xmlel{name = - <<"query">>, - attrs = - [{<<"xmlns">>, - ?NS_ROSTER}], - children = - [#xmlel{name - = - <<"item">>, - attrs - = - [{<<"jid">>, - jid:to_string(JID)}, - {<<"subscription">>, - <<"remove">>}], - children - = - []}]}}), + UJID = jid:make(User, Server), + RosterItem = #roster_item{ + jid = jid:make(JID), + subscription = remove}, + process_iq_set( + #iq{type = set, + from = UJID, + to = UJID, + id = randoms:get_string(), + sub_els = [#roster_query{ + items = [RosterItem]}]}), throw(submitted); false -> ok end @@ -1144,24 +965,24 @@ webadmin_user(Acc, _User, _Server, Lang) -> %% Implement XEP-0321 Remote Roster Management -process_iq_manager(From, To, IQ) -> +process_iq_manager(#iq{from = From, to = To, lang = Lang} = IQ) -> %% Check what access is allowed for From to To MatchDomain = From#jid.lserver, case is_domain_managed(MatchDomain, To#jid.lserver) of true -> - process_iq_manager2(MatchDomain, To, IQ); + process_iq_manager2(MatchDomain, IQ); false -> - #iq{sub_el = SubEl, lang = Lang} = IQ, Txt = <<"Roster management is not allowed from this domain">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_BAD_REQUEST(Lang, Txt)]} + xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)) end. -process_iq_manager2(MatchDomain, To, IQ) -> +process_iq_manager2(MatchDomain, #iq{to = To} = IQ) -> %% If IQ is SET, filter the input IQ IQFiltered = maybe_filter_request(MatchDomain, IQ), %% Call the standard function with reversed JIDs IdInitial = IQFiltered#iq.id, - ResIQ = process_iq(To, To, IQFiltered#iq{id = <<"roster-remotely-managed">>}), + ResIQ = process_iq(IQFiltered#iq{from = To, to = To, + id = <<"roster-remotely-managed">>}), %% Filter the output IQ filter_stanza(MatchDomain, ResIQ#iq{id = IdInitial}). @@ -1176,37 +997,13 @@ maybe_filter_request(MatchDomain, IQ) when IQ#iq.type == set -> maybe_filter_request(_MatchDomain, IQ) -> IQ. -filter_stanza(_MatchDomain, #iq{sub_el = []} = IQ) -> - IQ; -filter_stanza(MatchDomain, #iq{sub_el = [SubEl | _]} = IQ) -> - #iq{sub_el = SubElFiltered} = IQRes = - filter_stanza(MatchDomain, IQ#iq{sub_el = SubEl}), - IQRes#iq{sub_el = [SubElFiltered]}; -filter_stanza(MatchDomain, #iq{sub_el = SubEl} = IQ) -> - #xmlel{name = Type, attrs = Attrs, children = Items} = SubEl, +filter_stanza(MatchDomain, + #iq{sub_els = [#roster_query{items = Items} = R]} = IQ) -> ItemsFiltered = lists:filter( - fun(Item) -> - is_item_of_domain(MatchDomain, Item) end, Items), - SubElFiltered = #xmlel{name=Type, attrs = Attrs, children = ItemsFiltered}, - IQ#iq{sub_el = SubElFiltered}. - -is_item_of_domain(MatchDomain, #xmlel{} = El) -> - lists:any(fun(Attr) -> is_jid_of_domain(MatchDomain, Attr) end, El#xmlel.attrs); -is_item_of_domain(_MatchDomain, {xmlcdata, _}) -> - false. - -is_jid_of_domain(MatchDomain, {<<"jid">>, JIDString}) -> - case jid:from_string(JIDString) of - JID when JID#jid.lserver == MatchDomain -> true; - _ -> false - end; -is_jid_of_domain(_, _) -> - false. - -process_item_attrs_managed(Item, Attrs, true) -> - process_item_attrs_ws(Item, Attrs); -process_item_attrs_managed(Item, _Attrs, false) -> - process_item_attrs(Item, _Attrs). + fun(#roster_item{jid = #jid{lserver = S}}) -> + S == MatchDomain + end, Items), + IQ#iq{sub_els = [R#roster_query{items = ItemsFiltered}]}. send_itemset_to_managers(_From, _Item, true) -> ok; diff --git a/src/mod_time.erl b/src/mod_time.erl index 90296f3d8..0aeb6831c 100644 --- a/src/mod_time.erl +++ b/src/mod_time.erl @@ -32,13 +32,13 @@ -behaviour(gen_mod). --export([start/2, stop/1, process_local_iq/3, +-export([start/2, stop/1, process_local_iq/1, mod_opt_type/1, depends/2]). -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, fun gen_iq_handler:check_type/1, @@ -50,41 +50,18 @@ stop(Host) -> gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_TIME). -process_local_iq(_From, _To, - #iq{type = Type, sub_el = SubEl, lang = Lang} = IQ) -> - case Type of - set -> - Txt = <<"Value 'set' of 'type' attribute is not allowed">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]}; - get -> - Now_universal = calendar:universal_time(), - Now_local = calendar:universal_time_to_local_time(Now_universal), - {UTC, UTC_diff} = jlib:timestamp_to_iso(Now_universal, - utc), - Seconds_diff = - calendar:datetime_to_gregorian_seconds(Now_local) - - calendar:datetime_to_gregorian_seconds(Now_universal), - {Hd, Md, _} = - calendar:seconds_to_time(abs(Seconds_diff)), - {_, TZO_diff} = jlib:timestamp_to_iso({{0, 1, 1}, - {0, 0, 0}}, - {sign(Seconds_diff), {Hd, Md}}), - IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"time">>, - attrs = [{<<"xmlns">>, ?NS_TIME}], - children = - [#xmlel{name = <<"tzo">>, attrs = [], - children = [{xmlcdata, TZO_diff}]}, - #xmlel{name = <<"utc">>, attrs = [], - children = - [{xmlcdata, - <>}]}]}]} - end. - -sign(N) when N < 0 -> <<"-">>; -sign(_) -> <<"+">>. +process_local_iq(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_local_iq(#iq{type = get} = IQ) -> + Now = p1_time_compat:timestamp(), + Now_universal = calendar:now_to_universal_time(Now), + Now_local = calendar:universal_time_to_local_time(Now_universal), + Seconds_diff = + calendar:datetime_to_gregorian_seconds(Now_local) - + calendar:datetime_to_gregorian_seconds(Now_universal), + {Hd, Md, _} = calendar:seconds_to_time(abs(Seconds_diff)), + xmpp:make_iq_result(IQ, #time{tzo = {Hd, Md}, utc = Now}). depends(_Host, _Opts) -> []. diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index aca9d7462..de9fce00d 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -33,13 +33,15 @@ -behaviour(gen_mod). -export([start/2, init/3, stop/1, get_sm_features/5, - process_local_iq/3, process_sm_iq/3, string2lower/1, + process_local_iq/1, process_sm_iq/1, string2lower/1, remove_user/2, export/1, import/1, import/3, depends/2, + process_search/1, process_vcard/1, + disco_items/5, disco_features/5, disco_identity/5, mod_opt_type/1, set_vcard/3, make_vcard_search/4]). -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_vcard.hrl"). -define(JUD_MATCHES, 30). @@ -68,11 +70,30 @@ start(Host, Opts) -> ?NS_VCARD, ?MODULE, process_sm_iq, IQDisc), ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, get_sm_features, 50), - MyHost = gen_mod:get_opt_host(Host, Opts, - <<"vjud.@HOST@">>), + MyHost = gen_mod:get_opt_host(Host, Opts, <<"vjud.@HOST@">>), Search = gen_mod:get_opt(search, Opts, fun(B) when is_boolean(B) -> B end, false), + if Search -> + ejabberd_hooks:add( + disco_local_items, MyHost, ?MODULE, disco_items, 100), + ejabberd_hooks:add( + disco_local_features, MyHost, ?MODULE, disco_features, 100), + ejabberd_hooks:add( + disco_local_identity, MyHost, ?MODULE, disco_identity, 100), + gen_iq_handler:add_iq_handler( + ejabberd_local, MyHost, ?NS_SEARCH, ?MODULE, process_search, IQDisc), + gen_iq_handler:add_iq_handler( + ejabberd_local, MyHost, ?NS_VCARD, ?MODULE, process_vcard, IQDisc), + gen_iq_handler:add_iq_handler( + ejabberd_local, MyHost, ?NS_DISCO_ITEMS, mod_disco, + process_local_iq_items, IQDisc), + gen_iq_handler:add_iq_handler( + ejabberd_local, MyHost, ?NS_DISCO_INFO, mod_disco, + process_local_iq_info, IQDisc); + true -> + ok + end, register(gen_mod:get_module_proc(Host, ?PROCNAME), spawn(?MODULE, init, [MyHost, Host, Search])). @@ -87,12 +108,20 @@ init(Host, ServerHost, Search) -> loop(Host, ServerHost) -> receive {route, From, To, Packet} -> - case catch do_route(ServerHost, From, To, Packet) of + case catch do_route(From, To, Packet) of {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]); _ -> ok end, loop(Host, ServerHost); - stop -> ejabberd_router:unregister_route(Host), ok; + stop -> + ejabberd_router:unregister_route(Host), + ejabberd_hooks:delete(disco_local_items, Host, ?MODULE, disco_items, 50), + ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, disco_features, 50), + ejabberd_hooks:delete(disco_local_identity, Host, ?MODULE, disco_identity, 50), + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_SEARCH), + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VCARD), + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS), + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO); _ -> loop(Host, ServerHost) end. @@ -109,12 +138,23 @@ stop(Host) -> Proc ! stop, {wait, Proc}. +do_route(From, To, #xmlel{name = <<"iq">>} = El) -> + ejabberd_router:process_iq(From, To, El); +do_route(From, To, #iq{} = IQ) -> + ejabberd_router:process_iq(From, To, IQ); +do_route(_, _, _) -> + ok. + +-spec get_sm_features({error, error()} | empty | {result, [binary()]}, + jid(), jid(), + undefined | binary(), undefined | binary()) -> + {error, error()} | empty | {result, [binary()]}. get_sm_features({error, _Error} = Acc, _From, _To, _Node, _Lang) -> Acc; get_sm_features(Acc, _From, _To, Node, _Lang) -> case Node of - <<"">> -> + undefined -> case Acc of {result, Features} -> {result, [?NS_DISCO_INFO, ?NS_VCARD | Features]}; @@ -123,67 +163,113 @@ get_sm_features(Acc, _From, _To, Node, _Lang) -> _ -> Acc end. -process_local_iq(_From, _To, - #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> - case Type of - set -> - Txt = <<"Value 'set' of 'type' attribute is not allowed">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]}; - get -> - IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"vCard">>, - attrs = [{<<"xmlns">>, ?NS_VCARD}], - children = - [#xmlel{name = <<"FN">>, attrs = [], - children = - [{xmlcdata, <<"ejabberd">>}]}, - #xmlel{name = <<"URL">>, attrs = [], - children = [{xmlcdata, ?EJABBERD_URI}]}, - #xmlel{name = <<"DESC">>, attrs = [], - children = - [{xmlcdata, - <<(translate:translate(Lang, - <<"Erlang Jabber Server">>))/binary, - "\nCopyright (c) 2002-2016 ProcessOne">>}]}, - #xmlel{name = <<"BDAY">>, attrs = [], - children = - [{xmlcdata, <<"2002-11-16">>}]}]}]} +-spec process_local_iq(iq()) -> iq(). +process_local_iq(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_local_iq(#iq{type = get, lang = Lang} = IQ) -> + Desc = translate:translate(Lang, <<"Erlang Jabber Server">>), + Copyright = <<"Copyright (c) 2002-2016 ProcessOne">>, + xmpp:make_iq_result( + IQ, #vcard_temp{fn = <<"ejabberd">>, + url = ?EJABBERD_URI, + desc = <>, + bday = <<"2002-11-16">>}). + +-spec process_sm_iq(iq()) -> iq(). +process_sm_iq(#iq{type = set, lang = Lang, from = From, + sub_els = [SubEl]} = IQ) -> + #jid{user = User, lserver = LServer} = From, + case lists:member(LServer, ?MYHOSTS) of + true -> + set_vcard(User, LServer, SubEl), + xmpp:make_iq_result(IQ); + false -> + Txt = <<"The query is only allowed from local users">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)) + end; +process_sm_iq(#iq{type = get, from = From, to = To, lang = Lang} = IQ) -> + #jid{luser = LUser, lserver = LServer} = To, + case get_vcard(LUser, LServer) of + error -> + Txt = <<"Database failure">>, + xmpp:make_error(IQ, xmpp:err_internal_server_error(Txt, Lang)); + [] -> + xmpp:make_iq_result(IQ, #vcard_temp{}); + Els -> + IQ#iq{type = result, to = From, from = To, sub_els = Els} end. -process_sm_iq(From, To, - #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> - case Type of - set -> - #jid{user = User, lserver = LServer} = From, - case lists:member(LServer, ?MYHOSTS) of - true -> - set_vcard(User, LServer, SubEl), - IQ#iq{type = result, sub_el = []}; - false -> - Txt = <<"The query is only allowed from local users">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]} - end; - get -> - #jid{luser = LUser, lserver = LServer} = To, - case get_vcard(LUser, LServer) of - error -> - Txt = <<"Database failure">>, - IQ#iq{type = error, - sub_el = [SubEl, ?ERRT_INTERNAL_SERVER_ERROR(Lang, Txt)]}; - [] -> - IQ#iq{type = result, - sub_el = [#xmlel{name = <<"vCard">>, - attrs = [{<<"xmlns">>, ?NS_VCARD}], - children = []}]}; - Els -> IQ#iq{type = result, sub_el = Els} - end - end. +-spec process_vcard(iq()) -> iq(). +process_vcard(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_vcard(#iq{type = get, lang = Lang} = IQ) -> + Desc = translate:translate(Lang, <<"ejabberd vCard module">>), + Copyright = <<"Copyright (c) 2003-2016 ProcessOne">>, + xmpp:make_iq_result( + IQ, #vcard_temp{fn = <<"ejabberd/mod_vcard">>, + url = ?EJABBERD_URI, + desc = <>}). +-spec process_search(iq()) -> iq(). +process_search(#iq{type = get, to = To, lang = Lang} = IQ) -> + xmpp:make_iq_result(IQ, mk_search_form(To, Lang)); +process_search(#iq{type = set, to = To, lang = Lang, + sub_els = [#search{xdata = #xdata{type = submit, + fields = Fs}}]} = IQ) -> + ServerHost = ejabberd_router:host_of_route(To#jid.lserver), + ResultXData = search_result(Lang, To, ServerHost, Fs), + xmpp:make_iq_result(IQ, #search{xdata = ResultXData}); +process_search(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Incorrect data form">>, + xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)). + +-spec disco_items({error, error()} | {result, [disco_item()]} | empty, + jid(), jid(), + undefined | binary(), undefined | binary()) -> + {error, error()} | {result, [disco_item()]}. +disco_items(empty, _From, _To, undefined, _Lang) -> + {result, []}; +disco_items(empty, _From, _To, _Node, Lang) -> + {error, xmpp:err_item_not_found(<<"No services available">>, Lang)}; +disco_items(Acc, _From, _To, _Node, _Lang) -> + Acc. + +-spec disco_features({error, error()} | {result, [binary()]} | empty, + jid(), jid(), + undefined | binary(), undefined | binary()) -> + {error, error()} | {result, [binary()]}. +disco_features({error, _Error} = Acc, _From, _To, _Node, _Lang) -> + Acc; +disco_features(Acc, _From, _To, undefined, _Lang) -> + Features = case Acc of + {result, Fs} -> Fs; + empty -> [] + end, + {result, [?NS_DISCO_INFO, ?NS_DISCO_ITEMS, + ?NS_VCARD, ?NS_SEARCH | Features]}; +disco_features(empty, _From, _To, _Node, Lang) -> + Txt = <<"No features available">>, + {error, xmpp:err_item_not_found(Txt, Lang)}; +disco_features(Acc, _From, _To, _Node, _Lang) -> + Acc. + +-spec disco_identity([identity()], jid(), jid(), undefined | binary(), + undefined | binary()) -> [identity()]. +disco_identity(Acc, _From, _To, undefined, Lang) -> + [#identity{category = <<"directory">>, + type = <<"user">>, + name = translate:translate(Lang, <<"vCard User Search">>)}|Acc]; +disco_identity(Acc, _From, _To, _Node, _Lang) -> + Acc. + +-spec get_vcard(binary(), binary()) -> [xmlel()] | error. get_vcard(LUser, LServer) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:get_vcard(LUser, LServer). +-spec make_vcard_search(binary(), binary(), binary(), xmlel()) -> #vcard_search{}. make_vcard_search(User, LUser, LServer, VCARD) -> FN = fxml:get_path_s(VCARD, [{elem, <<"FN">>}, cdata]), Family = fxml:get_path_s(VCARD, @@ -250,6 +336,7 @@ make_vcard_search(User, LUser, LServer, VCARD) -> orgunit = OrgUnit, lorgunit = LOrgUnit}. +-spec set_vcard(binary(), binary(), xmlel()) -> any(). set_vcard(User, LServer, VCARD) -> case jid:nodeprep(User) of error -> @@ -262,307 +349,108 @@ set_vcard(User, LServer, VCARD) -> [LUser, LServer, VCARD]) end. +-spec string2lower(binary()) -> binary(). string2lower(String) -> case stringprep:tolower(String) of Lower when is_binary(Lower) -> Lower; error -> str:to_lower(String) end. --define(TLFIELD(Type, Label, Var), - #xmlel{name = <<"field">>, - attrs = - [{<<"type">>, Type}, - {<<"label">>, translate:translate(Lang, Label)}, - {<<"var">>, Var}], - children = []}). +-spec mk_tfield(binary(), binary(), undefined | binary()) -> xdata_field(). +mk_tfield(Label, Var, Lang) -> + #xdata_field{type = 'text-single', + label = translate:translate(Lang, Label), + var = Var}. --define(FORM(JID), - [#xmlel{name = <<"instructions">>, attrs = [], - children = - [{xmlcdata, - translate:translate(Lang, - <<"You need an x:data capable client to " - "search">>)}]}, - #xmlel{name = <<"x">>, - attrs = - [{<<"xmlns">>, ?NS_XDATA}, {<<"type">>, <<"form">>}], - children = - [#xmlel{name = <<"title">>, attrs = [], - children = - [{xmlcdata, - <<(translate:translate(Lang, - <<"Search users in ">>))/binary, - (jid:to_string(JID))/binary>>}]}, - #xmlel{name = <<"instructions">>, attrs = [], - children = - [{xmlcdata, - translate:translate(Lang, - <<"Fill in the form to search for any matching " - "Jabber User (Add * to the end of field " - "to match substring)">>)}]}, - ?TLFIELD(<<"text-single">>, <<"User">>, <<"user">>), - ?TLFIELD(<<"text-single">>, <<"Full Name">>, <<"fn">>), - ?TLFIELD(<<"text-single">>, <<"Name">>, <<"first">>), - ?TLFIELD(<<"text-single">>, <<"Middle Name">>, - <<"middle">>), - ?TLFIELD(<<"text-single">>, <<"Family Name">>, - <<"last">>), - ?TLFIELD(<<"text-single">>, <<"Nickname">>, <<"nick">>), - ?TLFIELD(<<"text-single">>, <<"Birthday">>, <<"bday">>), - ?TLFIELD(<<"text-single">>, <<"Country">>, <<"ctry">>), - ?TLFIELD(<<"text-single">>, <<"City">>, <<"locality">>), - ?TLFIELD(<<"text-single">>, <<"Email">>, <<"email">>), - ?TLFIELD(<<"text-single">>, <<"Organization Name">>, - <<"orgname">>), - ?TLFIELD(<<"text-single">>, <<"Organization Unit">>, - <<"orgunit">>)]}]). +-spec mk_field(binary(), binary()) -> xdata_field(). +mk_field(Var, Val) -> + #xdata_field{var = Var, values = [Val]}. -do_route(ServerHost, From, To, Packet) -> - #jid{user = User, resource = Resource} = To, - if (User /= <<"">>) or (Resource /= <<"">>) -> - Err = jlib:make_error_reply(Packet, - ?ERR_SERVICE_UNAVAILABLE), - ejabberd_router:route(To, From, Err); - true -> - IQ = jlib:iq_query_info(Packet), - case IQ of - #iq{type = Type, xmlns = ?NS_SEARCH, lang = Lang, - sub_el = SubEl} -> - case Type of - set -> - XDataEl = find_xdata_el(SubEl), - case XDataEl of - false -> - Txt = <<"Data form not found">>, - Err = jlib:make_error_reply( - Packet, ?ERRT_BAD_REQUEST(Lang, Txt)), - ejabberd_router:route(To, From, Err); - _ -> - XData = jlib:parse_xdata_submit(XDataEl), - case XData of - invalid -> - Txt = <<"Incorrect data form">>, - Err = jlib:make_error_reply( - Packet, ?ERRT_BAD_REQUEST(Lang, Txt)), - ejabberd_router:route(To, From, Err); - _ -> - ResIQ = IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = - [{<<"xmlns">>, - ?NS_SEARCH}], - children = - [#xmlel{name = - <<"x">>, - attrs = - [{<<"xmlns">>, - ?NS_XDATA}, - {<<"type">>, - <<"result">>}], - children - = - search_result(Lang, - To, - ServerHost, - XData)}]}]}, - ejabberd_router:route(To, From, - jlib:iq_to_xml(ResIQ)) - end - end; - get -> - ResIQ = IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = - [{<<"xmlns">>, - ?NS_SEARCH}], - children = ?FORM(To)}]}, - ejabberd_router:route(To, From, jlib:iq_to_xml(ResIQ)) - end; - #iq{type = Type, xmlns = ?NS_DISCO_INFO, lang = Lang} -> - case Type of - set -> - Txt = <<"Value 'set' of 'type' attribute is not allowed">>, - Err = jlib:make_error_reply(Packet, ?ERRT_NOT_ALLOWED(Lang, Txt)), - ejabberd_router:route(To, From, Err); - get -> - Info = ejabberd_hooks:run_fold(disco_info, ServerHost, - [], - [ServerHost, ?MODULE, - <<"">>, <<"">>]), - ResIQ = IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = - [{<<"xmlns">>, - ?NS_DISCO_INFO}], - children = - [#xmlel{name = - <<"identity">>, - attrs = - [{<<"category">>, - <<"directory">>}, - {<<"type">>, - <<"user">>}, - {<<"name">>, - translate:translate(Lang, - <<"vCard User Search">>)}], - children = []}, - #xmlel{name = - <<"feature">>, - attrs = - [{<<"var">>, - ?NS_DISCO_INFO}], - children = []}, - #xmlel{name = - <<"feature">>, - attrs = - [{<<"var">>, - ?NS_SEARCH}], - children = []}, - #xmlel{name = - <<"feature">>, - attrs = - [{<<"var">>, - ?NS_VCARD}], - children = []}] - ++ Info}]}, - ejabberd_router:route(To, From, jlib:iq_to_xml(ResIQ)) - end; - #iq{type = Type, lang = Lang, xmlns = ?NS_DISCO_ITEMS} -> - case Type of - set -> - Txt = <<"Value 'set' of 'type' attribute is not allowed">>, - Err = jlib:make_error_reply(Packet, ?ERRT_NOT_ALLOWED(Lang, Txt)), - ejabberd_router:route(To, From, Err); - get -> - ResIQ = IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = - [{<<"xmlns">>, - ?NS_DISCO_ITEMS}], - children = []}]}, - ejabberd_router:route(To, From, jlib:iq_to_xml(ResIQ)) - end; - #iq{type = get, xmlns = ?NS_VCARD, lang = Lang} -> - ResIQ = IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"vCard">>, - attrs = [{<<"xmlns">>, ?NS_VCARD}], - children = iq_get_vcard(Lang)}]}, - ejabberd_router:route(To, From, jlib:iq_to_xml(ResIQ)); - _ -> - Err = jlib:make_error_reply(Packet, - ?ERR_SERVICE_UNAVAILABLE), - ejabberd_router:route(To, From, Err) - end - end. +-spec mk_search_form(jid(), undefined | binary()) -> search(). +mk_search_form(JID, Lang) -> + Title = <<(translate:translate(Lang, <<"Search users in ">>))/binary, + (jid:to_string(JID))/binary>>, + Fs = [mk_tfield(<<"User">>, <<"user">>, Lang), + mk_tfield(<<"Full Name">>, <<"fn">>, Lang), + mk_tfield(<<"Name">>, <<"first">>, Lang), + mk_tfield(<<"Middle Name">>, <<"middle">>, Lang), + mk_tfield(<<"Family Name">>, <<"last">>, Lang), + mk_tfield(<<"Nickname">>, <<"nick">>, Lang), + mk_tfield(<<"Birthday">>, <<"bday">>, Lang), + mk_tfield(<<"Country">>, <<"ctry">>, Lang), + mk_tfield(<<"City">>, <<"locality">>, Lang), + mk_tfield(<<"Email">>, <<"email">>, Lang), + mk_tfield(<<"Organization Name">>, <<"orgname">>, Lang), + mk_tfield(<<"Organization Unit">>, <<"orgunit">>, Lang)], + X = #xdata{type = form, + title = Title, + instructions = + [translate:translate( + Lang, + <<"Fill in the form to search for any matching " + "Jabber User (Add * to the end of field " + "to match substring)">>)], + fields = Fs}, + #search{instructions = + translate:translate( + Lang, <<"You need an x:data capable client to search">>), + xdata = X}. -iq_get_vcard(Lang) -> - [#xmlel{name = <<"FN">>, attrs = [], - children = [{xmlcdata, <<"ejabberd/mod_vcard">>}]}, - #xmlel{name = <<"URL">>, attrs = [], - children = [{xmlcdata, ?EJABBERD_URI}]}, - #xmlel{name = <<"DESC">>, attrs = [], - children = - [{xmlcdata, - <<(translate:translate(Lang, - <<"ejabberd vCard module">>))/binary, - "\nCopyright (c) 2003-2016 ProcessOne">>}]}]. - -find_xdata_el(#xmlel{children = SubEls}) -> - find_xdata_el1(SubEls). - -find_xdata_el1([]) -> false; -find_xdata_el1([#xmlel{name = Name, attrs = Attrs, - children = SubEls} - | Els]) -> - case fxml:get_attr_s(<<"xmlns">>, Attrs) of - ?NS_XDATA -> - #xmlel{name = Name, attrs = Attrs, children = SubEls}; - _ -> find_xdata_el1(Els) - end; -find_xdata_el1([_ | Els]) -> find_xdata_el1(Els). - --define(LFIELD(Label, Var), - #xmlel{name = <<"field">>, - attrs = - [{<<"label">>, translate:translate(Lang, Label)}, - {<<"var">>, Var}], - children = []}). - -search_result(Lang, JID, ServerHost, Data) -> - [#xmlel{name = <<"title">>, attrs = [], - children = - [{xmlcdata, - <<(translate:translate(Lang, - <<"Search Results for ">>))/binary, - (jid:to_string(JID))/binary>>}]}, - #xmlel{name = <<"reported">>, attrs = [], - children = - [?TLFIELD(<<"text-single">>, <<"Jabber ID">>, - <<"jid">>), - ?TLFIELD(<<"text-single">>, <<"Full Name">>, <<"fn">>), - ?TLFIELD(<<"text-single">>, <<"Name">>, <<"first">>), - ?TLFIELD(<<"text-single">>, <<"Middle Name">>, - <<"middle">>), - ?TLFIELD(<<"text-single">>, <<"Family Name">>, - <<"last">>), - ?TLFIELD(<<"text-single">>, <<"Nickname">>, <<"nick">>), - ?TLFIELD(<<"text-single">>, <<"Birthday">>, <<"bday">>), - ?TLFIELD(<<"text-single">>, <<"Country">>, <<"ctry">>), - ?TLFIELD(<<"text-single">>, <<"City">>, <<"locality">>), - ?TLFIELD(<<"text-single">>, <<"Email">>, <<"email">>), - ?TLFIELD(<<"text-single">>, <<"Organization Name">>, - <<"orgname">>), - ?TLFIELD(<<"text-single">>, <<"Organization Unit">>, - <<"orgunit">>)]}] - ++ - lists:map(fun (R) -> record_to_item(ServerHost, R) end, - search(ServerHost, Data)). - --define(FIELD(Var, Val), - #xmlel{name = <<"field">>, attrs = [{<<"var">>, Var}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = [{xmlcdata, Val}]}]}). +-spec search_result(undefined | binary(), jid(), binary(), [xdata_field()]) -> xdata(). +search_result(Lang, JID, ServerHost, XFields) -> + #xdata{type = result, + title = <<(translate:translate(Lang, + <<"Search Results for ">>))/binary, + (jid:to_string(JID))/binary>>, + reported = [mk_tfield(<<"Jabber ID">>, <<"jid">>, Lang), + mk_tfield(<<"Full Name">>, <<"fn">>, Lang), + mk_tfield(<<"Name">>, <<"first">>, Lang), + mk_tfield(<<"Middle Name">>, <<"middle">>, Lang), + mk_tfield(<<"Family Name">>, <<"last">>, Lang), + mk_tfield(<<"Nickname">>, <<"nick">>, Lang), + mk_tfield(<<"Birthday">>, <<"bday">>, Lang), + mk_tfield(<<"Country">>, <<"ctry">>, Lang), + mk_tfield(<<"City">>, <<"locality">>, Lang), + mk_tfield(<<"Email">>, <<"email">>, Lang), + mk_tfield(<<"Organization Name">>, <<"orgname">>, Lang), + mk_tfield(<<"Organization Unit">>, <<"orgunit">>, Lang)], + items = lists:map(fun (R) -> record_to_item(ServerHost, R) end, + search(ServerHost, XFields))}. +-spec record_to_item(binary(), [binary()] | #vcard_search{}) -> [xdata_field()]. record_to_item(LServer, [Username, FN, Family, Given, Middle, Nickname, BDay, CTRY, Locality, EMail, OrgName, OrgUnit]) -> - #xmlel{name = <<"item">>, attrs = [], - children = - [?FIELD(<<"jid">>, - <>), - ?FIELD(<<"fn">>, FN), ?FIELD(<<"last">>, Family), - ?FIELD(<<"first">>, Given), - ?FIELD(<<"middle">>, Middle), - ?FIELD(<<"nick">>, Nickname), ?FIELD(<<"bday">>, BDay), - ?FIELD(<<"ctry">>, CTRY), - ?FIELD(<<"locality">>, Locality), - ?FIELD(<<"email">>, EMail), - ?FIELD(<<"orgname">>, OrgName), - ?FIELD(<<"orgunit">>, OrgUnit)]}; + [mk_field(<<"jid">>, <>), + mk_field(<<"fn">>, FN), + mk_field(<<"last">>, Family), + mk_field(<<"first">>, Given), + mk_field(<<"middle">>, Middle), + mk_field(<<"nick">>, Nickname), + mk_field(<<"bday">>, BDay), + mk_field(<<"ctry">>, CTRY), + mk_field(<<"locality">>, Locality), + mk_field(<<"email">>, EMail), + mk_field(<<"orgname">>, OrgName), + mk_field(<<"orgunit">>, OrgUnit)]; record_to_item(_LServer, #vcard_search{} = R) -> {User, Server} = R#vcard_search.user, - #xmlel{name = <<"item">>, attrs = [], - children = - [?FIELD(<<"jid">>, <>), - ?FIELD(<<"fn">>, (R#vcard_search.fn)), - ?FIELD(<<"last">>, (R#vcard_search.family)), - ?FIELD(<<"first">>, (R#vcard_search.given)), - ?FIELD(<<"middle">>, (R#vcard_search.middle)), - ?FIELD(<<"nick">>, (R#vcard_search.nickname)), - ?FIELD(<<"bday">>, (R#vcard_search.bday)), - ?FIELD(<<"ctry">>, (R#vcard_search.ctry)), - ?FIELD(<<"locality">>, (R#vcard_search.locality)), - ?FIELD(<<"email">>, (R#vcard_search.email)), - ?FIELD(<<"orgname">>, (R#vcard_search.orgname)), - ?FIELD(<<"orgunit">>, (R#vcard_search.orgunit))]}. + [mk_field(<<"jid">>, <>), + mk_field(<<"fn">>, (R#vcard_search.fn)), + mk_field(<<"last">>, (R#vcard_search.family)), + mk_field(<<"first">>, (R#vcard_search.given)), + mk_field(<<"middle">>, (R#vcard_search.middle)), + mk_field(<<"nick">>, (R#vcard_search.nickname)), + mk_field(<<"bday">>, (R#vcard_search.bday)), + mk_field(<<"ctry">>, (R#vcard_search.ctry)), + mk_field(<<"locality">>, (R#vcard_search.locality)), + mk_field(<<"email">>, (R#vcard_search.email)), + mk_field(<<"orgname">>, (R#vcard_search.orgname)), + mk_field(<<"orgunit">>, (R#vcard_search.orgunit))]. -search(LServer, Data) -> +-spec search(binary(), [xdata_field()]) -> [binary()]. +search(LServer, XFields) -> + Data = [{Var, Vals} || #xdata_field{var = Var, values = Vals} <- XFields], Mod = gen_mod:db_mod(LServer, ?MODULE), AllowReturnAll = gen_mod:get_module_opt(LServer, ?MODULE, allow_return_all, fun(B) when is_boolean(B) -> B end, diff --git a/src/mod_vcard_xupdate.erl b/src/mod_vcard_xupdate.erl index f2101df91..27ea8461a 100644 --- a/src/mod_vcard_xupdate.erl +++ b/src/mod_vcard_xupdate.erl @@ -17,8 +17,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("mod_vcard_xupdate.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -callback init(binary(), gen_mod:opts()) -> any(). -callback import(binary(), #vcard_xupdate{}) -> ok | pass. @@ -53,12 +52,8 @@ depends(_Host, _Opts) -> %% Hooks %%==================================================================== -update_presence(#xmlel{name = <<"presence">>, attrs = Attrs} = Packet, - User, Host) -> - case fxml:get_attr_s(<<"type">>, Attrs) of - <<>> -> presence_with_xupdate(Packet, User, Host); - _ -> Packet - end; +update_presence(#presence{type = undefined} = Packet, User, Host) -> + presence_with_xupdate(Packet, User, Host); update_presence(Packet, _User, _Host) -> Packet. vcard_set(LUser, LServer, VCARD) -> @@ -93,36 +88,10 @@ remove_xupdate(LUser, LServer) -> %%% Presence stanza rebuilding %%%---------------------------------------------------------------------- -presence_with_xupdate(#xmlel{name = <<"presence">>, - attrs = Attrs, children = Els}, - User, Host) -> - XPhotoEl = build_xphotoel(User, Host), - Els2 = presence_with_xupdate2(Els, [], XPhotoEl), - #xmlel{name = <<"presence">>, attrs = Attrs, - children = Els2}. - -presence_with_xupdate2([], Els2, XPhotoEl) -> - lists:reverse([XPhotoEl | Els2]); -%% This clause assumes that the x element contains only the XMLNS attribute: -presence_with_xupdate2([#xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_VCARD_UPDATE}]} - | Els], - Els2, XPhotoEl) -> - presence_with_xupdate2(Els, Els2, XPhotoEl); -presence_with_xupdate2([El | Els], Els2, XPhotoEl) -> - presence_with_xupdate2(Els, [El | Els2], XPhotoEl). - -build_xphotoel(User, Host) -> +presence_with_xupdate(Presence, User, Host) -> Hash = get_xupdate(User, Host), - PhotoSubEls = case Hash of - Hash when is_binary(Hash) -> [{xmlcdata, Hash}]; - _ -> [] - end, - PhotoEl = [#xmlel{name = <<"photo">>, attrs = [], - children = PhotoSubEls}], - #xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_VCARD_UPDATE}], - children = PhotoEl}. + Presence1 = xmpp:remove_subtag(Presence, #vcard_xupdate{}), + xmpp:set_subtag(Presence1, #vcard_xupdate{hash = Hash}). export(LServer) -> Mod = gen_mod:db_mod(LServer, ?MODULE), diff --git a/src/mod_version.erl b/src/mod_version.erl index 8a035763f..80b22554d 100644 --- a/src/mod_version.erl +++ b/src/mod_version.erl @@ -31,13 +31,13 @@ -behaviour(gen_mod). --export([start/2, stop/1, process_local_iq/3, +-export([start/2, stop/1, process_local_iq/1, mod_opt_type/1, depends/2]). -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, fun gen_iq_handler:check_type/1, @@ -50,35 +50,20 @@ stop(Host) -> gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VERSION). -process_local_iq(_From, To, - #iq{id = _ID, type = Type, xmlns = _XMLNS, - sub_el = SubEl, lang = Lang} = - IQ) -> - case Type of - set -> - Txt = <<"Value 'set' of 'type' attribute is not allowed">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]}; - get -> - Host = To#jid.lserver, - OS = case gen_mod:get_module_opt(Host, ?MODULE, show_os, - fun(B) when is_boolean(B) -> B end, - true) - of - true -> [get_os()]; - false -> [] - end, - IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_VERSION}], - children = - [#xmlel{name = <<"name">>, attrs = [], - children = - [{xmlcdata, <<"ejabberd">>}]}, - #xmlel{name = <<"version">>, attrs = [], - children = [{xmlcdata, ?VERSION}]}] - ++ OS}]} - end. +process_local_iq(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_local_iq(#iq{type = get, to = To} = IQ) -> + Host = To#jid.lserver, + OS = case gen_mod:get_module_opt(Host, ?MODULE, show_os, + fun(B) when is_boolean(B) -> B end, + true) of + true -> get_os(); + false -> undefined + end, + xmpp:make_iq_result(IQ, #version{name = <<"ejabberd">>, + ver = ?VERSION, + os = OS}). get_os() -> {Osfamily, Osname} = os:type(), @@ -89,9 +74,7 @@ get_os() -> [Major, Minor, Release])); VersionString -> VersionString end, - OS = <>, - #xmlel{name = <<"os">>, attrs = [], - children = [{xmlcdata, OS}]}. + <>. depends(_Host, _Opts) -> []. diff --git a/src/translate.erl b/src/translate.erl index e9f61ab8c..c8a924585 100644 --- a/src/translate.erl +++ b/src/translate.erl @@ -126,8 +126,10 @@ load_file_loop(Fd, Line, File, Lang) -> ok end. --spec translate(binary(), binary()) -> binary(). +-spec translate(binary() | undefined, binary()) -> binary(). +translate(undefined, Msg) -> + translate(?MYLANG, Msg); translate(Lang, Msg) -> LLang = ascii_tolower(Lang), case ets:lookup(translations, {LLang, Msg}) of diff --git a/src/xmpp.erl b/src/xmpp.erl new file mode 100644 index 000000000..ca6ed5e4c --- /dev/null +++ b/src/xmpp.erl @@ -0,0 +1,712 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2015, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 9 Dec 2015 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(xmpp). + +%% API +-export([make_iq_result/1, make_iq_result/2, make_error/2, + decode/1, decode/2, decode_tags_by_ns/2, encode/1, + get_type/1, get_to/1, get_from/1, get_id/1, + get_lang/1, get_error/1, get_els/1, get_ns/1, + set_type/2, set_to/2, set_from/2, set_id/2, + set_lang/2, set_error/2, set_els/2, set_from_to/3, + format_error/1, is_stanza/1, set_subtag/2, get_subtag/2, + remove_subtag/2, has_subtag/2, decode_els/1, pp/1, + get_name/1, get_text/1, mk_text/1, mk_text/2]). + +%% XMPP errors +-export([err_bad_request/0, err_bad_request/2, + err_bad_format/0, err_bad_format/2, + err_not_allowed/0, err_not_allowed/2, + err_conflict/0, err_conflict/2, + err_forbidden/0, err_forbidden/2, + err_not_acceptable/0, err_not_acceptable/2, + err_internal_server_error/0, err_internal_server_error/2, + err_service_unavailable/0, err_service_unavailable/2, + err_item_not_found/0, err_item_not_found/2, + err_jid_malformed/0, err_jid_malformed/2, + err_not_authorized/0, err_not_authorized/2, + err_feature_not_implemented/0, err_feature_not_implemented/2]). + +%% XMPP stream errors +-export([serr_bad_format/0, serr_bad_format/2, + serr_bad_namespace_prefix/0, serr_bad_namespace_prefix/2, + serr_conflict/0, serr_conflict/2, + serr_connection_timeout/0, serr_connection_timeout/2, + serr_host_gone/0, serr_host_gone/2, + serr_host_unknown/0, serr_host_unknown/2, + serr_improper_addressing/0, serr_improper_addressing/2, + serr_internal_server_error/0, serr_internal_server_error/2, + serr_invalid_from/0, serr_invalid_from/2, + serr_invalid_id/0, serr_invalid_id/2, + serr_invalid_namespace/0, serr_invalid_namespace/2, + serr_invalid_xml/0, serr_invalid_xml/2, + serr_not_authorized/0, serr_not_authorized/2, + serr_not_well_formed/0, serr_not_well_formed/2, + serr_policy_violation/0, serr_policy_violation/2, + serr_remote_connection_failed/0, serr_remote_connection_failed/2, + serr_reset/0, serr_reset/2, + serr_resource_constraint/0, serr_resource_constraint/2, + serr_restricted_xml/0, serr_restricted_xml/2, + serr_see_other_host/0, serr_see_other_host/2, + serr_system_shutdown/0, serr_system_shutdown/2, + serr_undefined_condition/0, serr_undefined_condition/2, + serr_unsupported_encoding/0, serr_unsupported_encoding/2, + serr_unsupported_stanza_type/0, serr_unsupported_stanza_type/2, + serr_unsupported_version/0, serr_unsupported_version/2]). + +-ifndef(NS_CLIENT). +-define(NS_CLIENT, <<"jabber:client">>). +-endif. + +-include("xmpp.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +-spec make_iq_result(iq()) -> iq(). +make_iq_result(IQ) -> + make_iq_result(IQ, undefined). + +-spec make_iq_result(iq(), xmpp_element() | xmlel() | undefined) -> iq(). +make_iq_result(#iq{type = Type, from = From, to = To} = IQ, El) + when Type == get; Type == set -> + SubEls = if El == undefined -> []; + true -> [El] + end, + IQ#iq{type = result, to = From, from = To, sub_els = SubEls}. + +-spec make_error(message(), error()) -> message(); + (presence(), error()) -> presence(); + (iq(), error()) -> iq(); + (xmlel(), error()) -> xmlel(). +make_error(#message{type = Type, from = From, to = To, sub_els = Els} = Msg, + Err) when Type /= error -> + Msg#message{type = error, from = To, to = From, sub_els = Els ++ [Err]}; +make_error(#presence{type = Type, from = From, to = To, sub_els = Els} = Pres, + Err) when Type /= error -> + Pres#presence{type = error, from = To, to = From, sub_els = Els ++ [Err]}; +make_error(#iq{type = Type, from = From, to = To, sub_els = Els} = IQ, + Err) when Type /= result, Type /= error -> + IQ#iq{type = error, from = To, to = From, sub_els = Els ++ [Err]}; +make_error(#xmlel{attrs = Attrs, children = Els} = El, Err) -> + To = fxml:get_attr(<<"to">>, Attrs), + From = fxml:get_attr(<<"from">>, Attrs), + Attrs1 = case To of + {value, T} -> + lists:keystore(<<"from">>, 1, Attrs, {<<"from">>, T}); + _ -> + Attrs + end, + Attrs2 = case From of + {value, F} -> + lists:keystore(<<"to">>, 1, Attrs1, {<<"to">>, F}); + _ -> + Attrs + end, + Attrs3 = lists:keystore(<<"type">>, 1, Attrs2, {<<"type">>, <<"error">>}), + El#xmlel{attrs = Attrs3, children = Els ++ [encode(Err)]}. + +-spec get_id(iq() | message() | presence() | xmlel()) -> undefined | binary(). +get_id(#iq{id = ID}) -> ID; +get_id(#message{id = ID}) -> ID; +get_id(#presence{id = ID}) -> ID; +get_id(#xmlel{attrs = Attrs}) -> + case fxml:get_attr(<<"id">>, Attrs) of + {value, ID} -> ID; + false -> undefined + end. + +-spec get_type(iq()) -> iq_type(); + (message()) -> message_type(); + (presence()) -> presence_type(); + (xmlel()) -> binary(). +get_type(#iq{type = T}) -> T; +get_type(#message{type = T}) -> T; +get_type(#presence{type = T}) -> T; +get_type(#xmlel{attrs = Attrs}) -> fxml:get_attr_s(<<"type">>, Attrs). + +-spec get_lang(iq() | message() | presence()) -> undefined | binary(). +get_lang(#iq{lang = L}) -> L; +get_lang(#message{lang = L}) -> L; +get_lang(#presence{lang = L}) -> L; +get_lang(#xmlel{attrs = Attrs}) -> + case fxml:get_attr(<<"xml:lang">>, Attrs) of + {value, L} -> L; + false -> undefined + end. + +-spec get_from(iq() | message() | presence()) -> undefined | jid:jid(). +get_from(#iq{from = J}) -> J; +get_from(#message{from = J}) -> J; +get_from(#presence{from = J}) -> J. + +-spec get_to(iq() | message() | presence()) -> undefined | jid:jid(). +get_to(#iq{to = J}) -> J; +get_to(#message{to = J}) -> J; +get_to(#presence{to = J}) -> J. + +-spec get_error(iq() | message() | presence()) -> undefined | error(). +get_error(#iq{error = E}) -> E; +get_error(#message{error = E}) -> E; +get_error(#presence{error = E}) -> E. + +-spec get_els(iq() | message() | presence()) -> [xmpp_element() | xmlel()]. +get_els(#iq{sub_els = Els}) -> Els; +get_els(#message{sub_els = Els}) -> Els; +get_els(#presence{sub_els = Els}) -> Els. + +-spec set_id(iq(), binary()) -> iq(); + (message(), binary()) -> message(); + (presence(), binary()) -> presence(). +set_id(#iq{} = IQ, I) -> IQ#iq{id = I}; +set_id(#message{} = Msg, I) -> Msg#message{id = I}; +set_id(#presence{} = Pres, I) -> Pres#presence{id = I}. + +-spec set_type(iq(), iq_type()) -> iq(); + (message(), message_type()) -> message(); + (presence(), presence_type()) -> presence(). +set_type(#iq{} = IQ, T) -> IQ#iq{type = T}; +set_type(#message{} = Msg, T) -> Msg#message{type = T}; +set_type(#presence{} = Pres, T) -> Pres#presence{type = T}. + +-spec set_lang(iq(), binary()) -> iq(); + (message(), binary()) -> message(); + (presence(), binary()) -> presence(). +set_lang(#iq{} = IQ, L) -> IQ#iq{lang = L}; +set_lang(#message{} = Msg, L) -> Msg#message{lang = L}; +set_lang(#presence{} = Pres, L) -> Pres#presence{lang = L}. + +-spec set_from(iq(), jid:jid()) -> iq(); + (message(), jid:jid()) -> message(); + (presence(), jid:jid()) -> presence(). +set_from(#iq{} = IQ, J) -> IQ#iq{from = J}; +set_from(#message{} = Msg, J) -> Msg#message{from = J}; +set_from(#presence{} = Pres, J) -> Pres#presence{from = J}. + +-spec set_to(iq(), jid:jid()) -> iq(); + (message(), jid:jid()) -> message(); + (presence(), jid:jid()) -> presence(). +set_to(#iq{} = IQ, J) -> IQ#iq{to = J}; +set_to(#message{} = Msg, J) -> Msg#message{to = J}; +set_to(#presence{} = Pres, J) -> Pres#presence{to = J}. + +-spec set_from_to(iq(), jid:jid(), jid:jid()) -> iq(); + (message(), jid:jid(), jid:jid()) -> message(); + (presence(), jid:jid(), jid:jid()) -> presence(). +set_from_to(#iq{} = IQ, F, T) -> IQ#iq{from = F, to = T}; +set_from_to(#message{} = Msg, F, T) -> Msg#message{from = F, to = T}; +set_from_to(#presence{} = Pres, F, T) -> Pres#presence{from = F, to = T}. + +-spec set_error(iq(), error()) -> iq(); + (message(), error()) -> message(); + (presence(), error()) -> presence(). +set_error(#iq{} = IQ, E) -> IQ#iq{error = E}; +set_error(#message{} = Msg, E) -> Msg#message{error = E}; +set_error(#presence{} = Pres, E) -> Pres#presence{error = E}. + +-spec set_els(iq(), [xmpp_element() | xmlel()]) -> iq(); + (message(), [xmpp_element() | xmlel()]) -> message(); + (presence(), [xmpp_element() | xmlel()]) -> presence(). +set_els(#iq{} = IQ, Els) -> IQ#iq{sub_els = Els}; +set_els(#message{} = Msg, Els) -> Msg#message{sub_els = Els}; +set_els(#presence{} = Pres, Els) -> Pres#presence{sub_els = Els}. + +-spec get_ns(xmpp_element() | xmlel()) -> binary(). +get_ns(#xmlel{attrs = Attrs}) -> + fxml:get_attr_s(<<"xmlns">>, Attrs); +get_ns(Pkt) -> + xmpp_codec:get_ns(Pkt). + +-spec get_name(xmpp_element() | xmlel()) -> binary(). +get_name(#xmlel{name = Name}) -> + Name; +get_name(Pkt) -> + xmpp_codec:get_name(Pkt). + +-spec decode(xmlel() | xmpp_element()) -> {ok, xmpp_element()} | {error, any()}. +decode(El) -> + decode(El, []). + +-spec decode(xmlel() | xmpp_element(), [proplists:property()]) -> + {ok, xmpp_element()} | {error, any()}. +decode(#xmlel{} = El, Opts) -> + xmpp_codec:decode(add_ns(El), Opts); +decode(Pkt, _Opts) -> + Pkt. + +-spec decode_els(iq()) -> iq(); + (message()) -> message(); + (presence()) -> presence(). +decode_els(Stanza) -> + Els = lists:map( + fun(#xmlel{} = El) -> + case xmpp_codec:is_known_tag(El) of + true -> decode(El); + false -> El + end; + (Pkt) -> + Pkt + end, get_els(Stanza)), + set_els(Stanza, Els). + +-spec encode(xmpp_element() | xmlel()) -> xmlel(). +encode(Pkt) -> + xmpp_codec:encode(Pkt). + +-spec decode_tags_by_ns([xmpp_element() | xmlel()], [binary()]) -> [xmpp_element()]. +decode_tags_by_ns(Els, NSList) -> + [xmpp_codec:decode(El) || El <- Els, lists:member(get_ns(El), NSList)]. + +format_error(Reason) -> + xmpp_codec:format_error(Reason). + +-spec is_stanza(any()) -> boolean(). +is_stanza(#message{}) -> true; +is_stanza(#iq{}) -> true; +is_stanza(#presence{}) -> true; +is_stanza(#xmlel{name = Name}) -> + (Name == <<"iq">>) or (Name == <<"message">>) or (Name == <<"presence">>); +is_stanza(_) -> false. + +-spec set_subtag(iq(), xmpp_element()) -> iq(); + (message(), xmpp_element()) -> message(); + (presence(), xmpp_element()) -> presence(). +set_subtag(Stanza, Tag) -> + TagName = xmpp_codec:get_name(Tag), + XMLNS = xmpp_codec:get_ns(Tag), + Els = get_els(Stanza), + NewEls = set_subtag(Els, Tag, TagName, XMLNS), + set_els(Stanza, NewEls). + +set_subtag([El|Els], Tag, TagName, XMLNS) -> + case {get_name(El), get_ns(El)} of + {TagName, XMLNS} -> + [Tag|Els]; + _ -> + [El|set_subtag(Els, Tag, TagName, XMLNS)] + end; +set_subtag([], Tag, _, _) -> + [Tag]. + +-spec get_subtag(stanza(), xmpp_element()) -> xmpp_element() | false. +get_subtag(Stanza, Tag) -> + Els = get_els(Stanza), + TagName = xmpp_codec:get_name(Tag), + XMLNS = xmpp_codec:get_ns(Tag), + get_subtag(Els, TagName, XMLNS). + +get_subtag([El|Els], TagName, XMLNS) -> + case {get_name(El), get_ns(El)} of + {TagName, XMLNS} -> + try + decode(El) + catch _:{xmpp_codec, _Why} -> + get_subtag(Els, TagName, XMLNS) + end; + _ -> + get_subtag(Els, TagName, XMLNS) + end; +get_subtag([], _, _) -> + false. + +-spec remove_subtag(iq(), xmpp_element()) -> iq(); + (message(), xmpp_element()) -> message(); + (presence(), xmpp_element()) -> presence(). +remove_subtag(Stanza, Tag) -> + Els = get_els(Stanza), + TagName = xmpp_codec:get_name(Tag), + XMLNS = xmpp_codec:get_ns(Tag), + NewEls = remove_subtag(Els, TagName, XMLNS), + set_els(Stanza, NewEls). + +remove_subtag([El|Els], TagName, XMLNS) -> + case {get_name(El), get_ns(El)} of + {TagName, XMLNS} -> + remove_subtag(Els, TagName, XMLNS); + _ -> + [El|remove_subtag(Els, TagName, XMLNS)] + end; +remove_subtag([], _, _) -> + []. + +-spec has_subtag(stanza(), xmpp_element()) -> boolean(). +has_subtag(Stanza, Tag) -> + Els = get_els(Stanza), + TagName = xmpp_codec:get_name(Tag), + XMLNS = xmpp_codec:get_ns(Tag), + has_subtag(Els, TagName, XMLNS). + +has_subtag([El|Els], TagName, XMLNS) -> + case {get_name(El), get_ns(El)} of + {TagName, XMLNS} -> + true; + _ -> + has_subtag(Els, TagName, XMLNS) + end; +has_subtag([], _, _) -> + false. + +-spec get_text([text()]) -> binary(). +get_text([]) -> <<"">>; +get_text([#text{data = undefined}|_]) -> <<"">>; +get_text([#text{data = Data}|_]) -> Data. + +-spec mk_text(binary()) -> [text()]. +mk_text(Text) -> + mk_text(Text, undefined). + +-spec mk_text(binary(), binary() | undefined) -> [text()]. +mk_text(<<"">>, _) -> + []; +mk_text(Text, Lang) -> + [#text{lang = Lang, + data = translate:translate(Lang, Text)}]. + +-spec pp(any()) -> iodata(). +pp(Term) -> + xmpp_codec:pp(Term). + +%%%=================================================================== +%%% Functions to construct general XMPP errors +%%%=================================================================== +-spec err_bad_request() -> error(). +err_bad_request() -> + err(modify, 'bad-request', 400). + +-spec err_bad_request(binary(), binary() | undefined) -> error(). +err_bad_request(Text, Lang) -> + err(modify, 'bad-request', 400, Text, Lang). + +-spec err_bad_format() -> error(). +err_bad_format() -> + err(modify, 'bad-format', 406). + +-spec err_bad_format(binary(), binary() | undefined) -> error(). +err_bad_format(Text, Lang) -> + err(modify, 'bad-format', 406, Text, Lang). + +-spec err_conflict() -> error(). +err_conflict() -> + err(cancel, 'conflict', 409). + +-spec err_conflict(binary(), binary() | undefined) -> error(). +err_conflict(Text, Lang) -> + err(cancel, 'conflict', 409, Text, Lang). + +-spec err_not_allowed() -> error(). +err_not_allowed() -> + err(cancel, 'not-allowed', 405). + +-spec err_not_allowed(binary(), binary() | undefined) -> error(). +err_not_allowed(Text, Lang) -> + err(cancel, 'not-allowed', 405, Text, Lang). + +-spec err_feature_not_implemented() -> error(). +err_feature_not_implemented() -> + err(cancel, 'feature-not-implemented', 501). + +-spec err_feature_not_implemented(binary(), binary() | undefined) -> error(). +err_feature_not_implemented(Text, Lang) -> + err(cancel, 'feature-not-implemented', 501, Text, Lang). + +-spec err_item_not_found() -> error(). +err_item_not_found() -> + err(cancel, 'item-not-found', 404). + +-spec err_item_not_found(binary(), binary() | undefined) -> error(). +err_item_not_found(Text, Lang) -> + err(cancel, 'item-not-found', 404, Text, Lang). + +-spec err_forbidden() -> error(). +err_forbidden() -> + err(auth, 'forbidden', 403). + +-spec err_forbidden(binary(), binary() | undefined) -> error(). +err_forbidden(Text, Lang) -> + err(auth, 'forbidden', 403, Text, Lang). + +-spec err_not_acceptable() -> error(). +err_not_acceptable() -> + err(modify, 'not-acceptable', 406). + +-spec err_not_acceptable(binary(), binary() | undefined) -> error(). +err_not_acceptable(Text, Lang) -> + err(modify, 'not-acceptable', 406, Text, Lang). + +-spec err_internal_server_error() -> error(). +err_internal_server_error() -> + err(wait, 'internal-server-error', 500). + +-spec err_internal_server_error(binary(), binary() | undefined) -> error(). +err_internal_server_error(Text, Lang) -> + err(wait, 'internal-server-error', 500, Text, Lang). + +-spec err_service_unavailable() -> error(). +err_service_unavailable() -> + err(cancel, 'service-unavailable', 503). + +-spec err_service_unavailable(binary(), binary() | undefined) -> error(). +err_service_unavailable(Text, Lang) -> + err(cancel, 'service-unavailable', 503, Text, Lang). + +-spec err_jid_malformed() -> error(). +err_jid_malformed() -> + err(modify, 'jid-malformed', 400). + +-spec err_jid_malformed(binary(), binary() | undefined) -> error(). +err_jid_malformed(Text, Lang) -> + err(modify, 'jid-malformed', 400, Text, Lang). + +-spec err_not_authorized() -> error(). +err_not_authorized() -> + err(auth, 'not-authorized', 401). + +-spec err_not_authorized(binary(), binary() | undefined) -> error(). +err_not_authorized(Text, Lang) -> + err(auth, 'not-authorized', 401, Text, Lang). + +%%%=================================================================== +%%% Functions to construct stream errors +%%%=================================================================== +-spec serr_bad_format() -> stream_error(). +serr_bad_format() -> + serr('bad-format'). + +-spec serr_bad_format(binary(), binary() | undefined) -> stream_error(). +serr_bad_format(Text, Lang) -> + serr('bad-format', Text, Lang). + +-spec serr_bad_namespace_prefix() -> stream_error(). +serr_bad_namespace_prefix() -> + serr('bad-namespace-prefix'). + +-spec serr_bad_namespace_prefix(binary(), binary() | undefined) -> stream_error(). +serr_bad_namespace_prefix(Text, Lang) -> + serr('bad-namespace-prefix', Text, Lang). + +-spec serr_conflict() -> stream_error(). +serr_conflict() -> + serr('conflict'). + +-spec serr_conflict(binary(), binary() | undefined) -> stream_error(). +serr_conflict(Text, Lang) -> + serr('conflict', Text, Lang). + +-spec serr_connection_timeout() -> stream_error(). +serr_connection_timeout() -> + serr('connection-timeout'). + +-spec serr_connection_timeout(binary(), binary() | undefined) -> stream_error(). +serr_connection_timeout(Text, Lang) -> + serr('connection-timeout', Text, Lang). + +-spec serr_host_gone() -> stream_error(). +serr_host_gone() -> + serr('host-gone'). + +-spec serr_host_gone(binary(), binary() | undefined) -> stream_error(). +serr_host_gone(Text, Lang) -> + serr('host-gone', Text, Lang). + +-spec serr_host_unknown() -> stream_error(). +serr_host_unknown() -> + serr('host-unknown'). + +-spec serr_host_unknown(binary(), binary() | undefined) -> stream_error(). +serr_host_unknown(Text, Lang) -> + serr('host-unknown', Text, Lang). + +-spec serr_improper_addressing() -> stream_error(). +serr_improper_addressing() -> + serr('improper-addressing'). + +-spec serr_improper_addressing(binary(), binary() | undefined) -> stream_error(). +serr_improper_addressing(Text, Lang) -> + serr('improper-addressing', Text, Lang). + +-spec serr_internal_server_error() -> stream_error(). +serr_internal_server_error() -> + serr('internal-server-error'). + +-spec serr_internal_server_error(binary(), binary() | undefined) -> stream_error(). +serr_internal_server_error(Text, Lang) -> + serr('internal-server-error', Text, Lang). + +-spec serr_invalid_from() -> stream_error(). +serr_invalid_from() -> + serr('invalid-from'). + +-spec serr_invalid_from(binary(), binary() | undefined) -> stream_error(). +serr_invalid_from(Text, Lang) -> + serr('invalid-from', Text, Lang). + +-spec serr_invalid_id() -> stream_error(). +serr_invalid_id() -> + serr('invalid-id'). + +-spec serr_invalid_id(binary(), binary() | undefined) -> stream_error(). +serr_invalid_id(Text, Lang) -> + serr('invalid-id', Text, Lang). + +-spec serr_invalid_namespace() -> stream_error(). +serr_invalid_namespace() -> + serr('invalid-namespace'). + +-spec serr_invalid_namespace(binary(), binary() | undefined) -> stream_error(). +serr_invalid_namespace(Text, Lang) -> + serr('invalid-namespace', Text, Lang). + +-spec serr_invalid_xml() -> stream_error(). +serr_invalid_xml() -> + serr('invalid-xml'). + +-spec serr_invalid_xml(binary(), binary() | undefined) -> stream_error(). +serr_invalid_xml(Text, Lang) -> + serr('invalid-xml', Text, Lang). + +-spec serr_not_authorized() -> stream_error(). +serr_not_authorized() -> + serr('not-authorized'). + +-spec serr_not_authorized(binary(), binary() | undefined) -> stream_error(). +serr_not_authorized(Text, Lang) -> + serr('not-authorized', Text, Lang). + +-spec serr_not_well_formed() -> stream_error(). +serr_not_well_formed() -> + serr('not-well-formed'). + +-spec serr_not_well_formed(binary(), binary() | undefined) -> stream_error(). +serr_not_well_formed(Text, Lang) -> + serr('not-well-formed', Text, Lang). + +-spec serr_policy_violation() -> stream_error(). +serr_policy_violation() -> + serr('policy-violation'). + +-spec serr_policy_violation(binary(), binary() | undefined) -> stream_error(). +serr_policy_violation(Text, Lang) -> + serr('policy-violation', Text, Lang). + +-spec serr_remote_connection_failed() -> stream_error(). +serr_remote_connection_failed() -> + serr('remote-connection-failed'). + +-spec serr_remote_connection_failed(binary(), binary() | undefined) -> stream_error(). +serr_remote_connection_failed(Text, Lang) -> + serr('remote-connection-failed', Text, Lang). + +-spec serr_reset() -> stream_error(). +serr_reset() -> + serr('reset'). + +-spec serr_reset(binary(), binary() | undefined) -> stream_error(). +serr_reset(Text, Lang) -> + serr('reset', Text, Lang). + +-spec serr_resource_constraint() -> stream_error(). +serr_resource_constraint() -> + serr('resource-constraint'). + +-spec serr_resource_constraint(binary(), binary() | undefined) -> stream_error(). +serr_resource_constraint(Text, Lang) -> + serr('resource-constraint', Text, Lang). + +-spec serr_restricted_xml() -> stream_error(). +serr_restricted_xml() -> + serr('restricted-xml'). + +-spec serr_restricted_xml(binary(), binary() | undefined) -> stream_error(). +serr_restricted_xml(Text, Lang) -> + serr('restricted-xml', Text, Lang). + +-spec serr_see_other_host() -> stream_error(). +serr_see_other_host() -> + serr('see-other-host'). + +-spec serr_see_other_host(binary(), binary() | undefined) -> stream_error(). +serr_see_other_host(Text, Lang) -> + serr('see-other-host', Text, Lang). + +-spec serr_system_shutdown() -> stream_error(). +serr_system_shutdown() -> + serr('system-shutdown'). + +-spec serr_system_shutdown(binary(), binary() | undefined) -> stream_error(). +serr_system_shutdown(Text, Lang) -> + serr('system-shutdown', Text, Lang). + +-spec serr_undefined_condition() -> stream_error(). +serr_undefined_condition() -> + serr('undefined-condition'). + +-spec serr_undefined_condition(binary(), binary() | undefined) -> stream_error(). +serr_undefined_condition(Text, Lang) -> + serr('undefined-condition', Text, Lang). + +-spec serr_unsupported_encoding() -> stream_error(). +serr_unsupported_encoding() -> + serr('unsupported-encoding'). + +-spec serr_unsupported_encoding(binary(), binary() | undefined) -> stream_error(). +serr_unsupported_encoding(Text, Lang) -> + serr('unsupported-encoding', Text, Lang). + +-spec serr_unsupported_stanza_type() -> stream_error(). +serr_unsupported_stanza_type() -> + serr('unsupported-stanza-type'). + +-spec serr_unsupported_stanza_type(binary(), binary() | undefined) -> stream_error(). +serr_unsupported_stanza_type(Text, Lang) -> + serr('unsupported-stanza-type', Text, Lang). + +-spec serr_unsupported_version() -> stream_error(). +serr_unsupported_version() -> + serr('unsupported-version'). + +-spec serr_unsupported_version(binary(), binary() | undefined) -> stream_error(). +serr_unsupported_version(Text, Lang) -> + serr('unsupported-version', Text, Lang). + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +-spec err('auth' | 'cancel' | 'continue' | 'modify' | 'wait', + atom() | gone() | redirect(), non_neg_integer()) -> error(). +err(Type, Reason, Code) -> + #error{type = Type, reason = Reason, code = Code}. + +-spec err('auth' | 'cancel' | 'continue' | 'modify' | 'wait', + atom() | gone() | redirect(), non_neg_integer(), + binary(), binary() | undefined) -> error(). +err(Type, Reason, Code, Text, Lang) -> + #error{type = Type, reason = Reason, code = Code, + text = #text{lang = Lang, + data = translate:translate(Lang, Text)}}. + +-spec serr(atom() | 'see-other-host'()) -> stream_error(). +serr(Reason) -> + #stream_error{reason = Reason}. + +-spec serr(atom() | 'see-other-host'(), binary(), + binary() | undefined) -> stream_error(). +serr(Reason, Text, Lang) -> + #stream_error{reason = Reason, + text = #text{lang = Lang, + data = translate:translate(Lang, Text)}}. + +-spec add_ns(xmlel()) -> xmlel(). +add_ns(#xmlel{name = Name} = El) when Name == <<"message">>; + Name == <<"presence">>; + Name == <<"iq">> -> + Attrs = lists:keystore(<<"xmlns">>, 1, El#xmlel.attrs, + {<<"xmlns">>, ?NS_CLIENT}), + El#xmlel{attrs = Attrs}; +add_ns(El) -> + El. diff --git a/tools/xmpp_codec.erl b/src/xmpp_codec.erl similarity index 68% rename from tools/xmpp_codec.erl rename to src/xmpp_codec.erl index ef1421962..568c5fbc7 100644 --- a/tools/xmpp_codec.erl +++ b/src/xmpp_codec.erl @@ -8,13 +8,44 @@ {enc_int, 1}, {get_attr, 2}, {enc_enum, 1}]}). -export([pp/1, format_error/1, decode/1, decode/2, - is_known_tag/1, encode/1, get_ns/1]). + is_known_tag/1, encode/1, get_name/1, get_ns/1]). decode(_el) -> decode(_el, []). decode({xmlel, _name, _attrs, _} = _el, Opts) -> IgnoreEls = proplists:get_bool(ignore_els, Opts), case {_name, get_attr(<<"xmlns">>, _attrs)} of + {<<"query">>, <<"jabber:iq:search">>} -> + decode_search(<<"jabber:iq:search">>, IgnoreEls, _el); + {<<"item">>, <<"jabber:iq:search">>} -> + decode_search_item(<<"jabber:iq:search">>, IgnoreEls, + _el); + {<<"email">>, <<"jabber:iq:search">>} -> + decode_search_email(<<"jabber:iq:search">>, IgnoreEls, + _el); + {<<"nick">>, <<"jabber:iq:search">>} -> + decode_search_nick(<<"jabber:iq:search">>, IgnoreEls, + _el); + {<<"last">>, <<"jabber:iq:search">>} -> + decode_search_last(<<"jabber:iq:search">>, IgnoreEls, + _el); + {<<"first">>, <<"jabber:iq:search">>} -> + decode_search_first(<<"jabber:iq:search">>, IgnoreEls, + _el); + {<<"instructions">>, <<"jabber:iq:search">>} -> + decode_search_instructions(<<"jabber:iq:search">>, + IgnoreEls, _el); + {<<"no-permanent-store">>, <<"urn:xmpp:hints">>} -> + decode_hint_no_permanent_store(<<"urn:xmpp:hints">>, + IgnoreEls, _el); + {<<"store">>, <<"urn:xmpp:hints">>} -> + decode_hint_store(<<"urn:xmpp:hints">>, IgnoreEls, _el); + {<<"no-store">>, <<"urn:xmpp:hints">>} -> + decode_hint_no_store(<<"urn:xmpp:hints">>, IgnoreEls, + _el); + {<<"no-copy">>, <<"urn:xmpp:hints">>} -> + decode_hint_no_copy(<<"urn:xmpp:hints">>, IgnoreEls, + _el); {<<"participant">>, <<"urn:xmpp:mix:0">>} -> decode_mix_participant(<<"urn:xmpp:mix:0">>, IgnoreEls, _el); @@ -382,7 +413,7 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> decode_vcard_xupdate_photo(<<"vcard-temp:x:update">>, IgnoreEls, _el); {<<"vCard">>, <<"vcard-temp">>} -> - decode_vcard(<<"vcard-temp">>, IgnoreEls, _el); + decode_vcard_temp(<<"vcard-temp">>, IgnoreEls, _el); {<<"CLASS">>, <<"vcard-temp">>} -> decode_vcard_CLASS(<<"vcard-temp">>, IgnoreEls, _el); {<<"CATEGORIES">>, <<"vcard-temp">>} -> @@ -658,6 +689,10 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> <<"urn:ietf:params:xml:ns:xmpp-session">>} -> decode_session(<<"urn:ietf:params:xml:ns:xmpp-session">>, IgnoreEls, _el); + {<<"optional">>, + <<"urn:ietf:params:xml:ns:xmpp-session">>} -> + decode_session_optional(<<"urn:ietf:params:xml:ns:xmpp-session">>, + IgnoreEls, _el); {<<"query">>, <<"jabber:iq:register">>} -> decode_register(<<"jabber:iq:register">>, IgnoreEls, _el); @@ -806,6 +841,10 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> decode_sasl_failure_temporary_auth_failure(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, IgnoreEls, _el); + {<<"bad-protocol">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> + decode_sasl_failure_bad_protocol(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + IgnoreEls, _el); {<<"not-authorized">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> decode_sasl_failure_not_authorized(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, @@ -867,6 +906,21 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> {<<"auth">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> decode_sasl_auth(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, IgnoreEls, _el); + {<<"query">>, <<"jabber:iq:auth">>} -> + decode_legacy_auth(<<"jabber:iq:auth">>, IgnoreEls, + _el); + {<<"resource">>, <<"jabber:iq:auth">>} -> + decode_legacy_auth_resource(<<"jabber:iq:auth">>, + IgnoreEls, _el); + {<<"digest">>, <<"jabber:iq:auth">>} -> + decode_legacy_auth_digest(<<"jabber:iq:auth">>, + IgnoreEls, _el); + {<<"password">>, <<"jabber:iq:auth">>} -> + decode_legacy_auth_password(<<"jabber:iq:auth">>, + IgnoreEls, _el); + {<<"username">>, <<"jabber:iq:auth">>} -> + decode_legacy_auth_username(<<"jabber:iq:auth">>, + IgnoreEls, _el); {<<"bind">>, <<"urn:ietf:params:xml:ns:xmpp-bind">>} -> decode_bind(<<"urn:ietf:params:xml:ns:xmpp-bind">>, IgnoreEls, _el); @@ -1077,8 +1131,12 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> {<<"message">>, <<"jabber:iq:privacy">>} -> decode_privacy_message(<<"jabber:iq:privacy">>, IgnoreEls, _el); + {<<"ver">>, <<"urn:xmpp:features:rosterver">>} -> + decode_rosterver_feature(<<"urn:xmpp:features:rosterver">>, + IgnoreEls, _el); {<<"query">>, <<"jabber:iq:roster">>} -> - decode_roster(<<"jabber:iq:roster">>, IgnoreEls, _el); + decode_roster_query(<<"jabber:iq:roster">>, IgnoreEls, + _el); {<<"item">>, <<"jabber:iq:roster">>} -> decode_roster_item(<<"jabber:iq:roster">>, IgnoreEls, _el); @@ -1104,6 +1162,18 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> is_known_tag({xmlel, _name, _attrs, _} = _el) -> case {_name, get_attr(<<"xmlns">>, _attrs)} of + {<<"query">>, <<"jabber:iq:search">>} -> true; + {<<"item">>, <<"jabber:iq:search">>} -> true; + {<<"email">>, <<"jabber:iq:search">>} -> true; + {<<"nick">>, <<"jabber:iq:search">>} -> true; + {<<"last">>, <<"jabber:iq:search">>} -> true; + {<<"first">>, <<"jabber:iq:search">>} -> true; + {<<"instructions">>, <<"jabber:iq:search">>} -> true; + {<<"no-permanent-store">>, <<"urn:xmpp:hints">>} -> + true; + {<<"store">>, <<"urn:xmpp:hints">>} -> true; + {<<"no-store">>, <<"urn:xmpp:hints">>} -> true; + {<<"no-copy">>, <<"urn:xmpp:hints">>} -> true; {<<"participant">>, <<"urn:xmpp:mix:0">>} -> true; {<<"leave">>, <<"urn:xmpp:mix:0">>} -> true; {<<"join">>, <<"urn:xmpp:mix:0">>} -> true; @@ -1491,6 +1561,9 @@ is_known_tag({xmlel, _name, _attrs, _} = _el) -> {<<"session">>, <<"urn:ietf:params:xml:ns:xmpp-session">>} -> true; + {<<"optional">>, + <<"urn:ietf:params:xml:ns:xmpp-session">>} -> + true; {<<"query">>, <<"jabber:iq:register">>} -> true; {<<"key">>, <<"jabber:iq:register">>} -> true; {<<"text">>, <<"jabber:iq:register">>} -> true; @@ -1574,6 +1647,9 @@ is_known_tag({xmlel, _name, _attrs, _} = _el) -> {<<"temporary-auth-failure">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> true; + {<<"bad-protocol">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> + true; {<<"not-authorized">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> true; @@ -1619,6 +1695,11 @@ is_known_tag({xmlel, _name, _attrs, _} = _el) -> true; {<<"auth">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> true; + {<<"query">>, <<"jabber:iq:auth">>} -> true; + {<<"resource">>, <<"jabber:iq:auth">>} -> true; + {<<"digest">>, <<"jabber:iq:auth">>} -> true; + {<<"password">>, <<"jabber:iq:auth">>} -> true; + {<<"username">>, <<"jabber:iq:auth">>} -> true; {<<"bind">>, <<"urn:ietf:params:xml:ns:xmpp-bind">>} -> true; {<<"resource">>, @@ -1745,6 +1826,7 @@ is_known_tag({xmlel, _name, _attrs, _} = _el) -> {<<"presence-in">>, <<"jabber:iq:privacy">>} -> true; {<<"iq">>, <<"jabber:iq:privacy">>} -> true; {<<"message">>, <<"jabber:iq:privacy">>} -> true; + {<<"ver">>, <<"urn:xmpp:features:rosterver">>} -> true; {<<"query">>, <<"jabber:iq:roster">>} -> true; {<<"item">>, <<"jabber:iq:roster">>} -> true; {<<"group">>, <<"jabber:iq:roster">>} -> true; @@ -1766,16 +1848,20 @@ encode({version, _, _, _} = Query) -> encode({roster_item, _, _, _, _, _} = Item) -> encode_roster_item(Item, [{<<"xmlns">>, <<"jabber:iq:roster">>}]); -encode({roster, _, _} = Query) -> - encode_roster(Query, - [{<<"xmlns">>, <<"jabber:iq:roster">>}]); -encode({privacy_item, _, _, _, _, _} = Item) -> +encode({roster_query, _, _} = Query) -> + encode_roster_query(Query, + [{<<"xmlns">>, <<"jabber:iq:roster">>}]); +encode({rosterver_feature} = Ver) -> + encode_rosterver_feature(Ver, + [{<<"xmlns">>, + <<"urn:xmpp:features:rosterver">>}]); +encode({privacy_item, _, _, _, _, _, _, _, _} = Item) -> encode_privacy_item(Item, [{<<"xmlns">>, <<"jabber:iq:privacy">>}]); encode({privacy_list, _, _} = List) -> encode_privacy_list(List, [{<<"xmlns">>, <<"jabber:iq:privacy">>}]); -encode({privacy, _, _, _} = Query) -> +encode({privacy_query, _, _, _} = Query) -> encode_privacy(Query, [{<<"xmlns">>, <<"jabber:iq:privacy">>}]); encode({block, _} = Block) -> @@ -1842,13 +1928,16 @@ encode({redirect, _} = Redirect) -> encode_error_redirect(Redirect, [{<<"xmlns">>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]); -encode({error, _, _, _, _} = Error) -> +encode({error, _, _, _, _, _} = Error) -> encode_error(Error, [{<<"xmlns">>, <<"jabber:client">>}]); encode({bind, _, _} = Bind) -> encode_bind(Bind, [{<<"xmlns">>, <<"urn:ietf:params:xml:ns:xmpp-bind">>}]); +encode({legacy_auth, _, _, _, _} = Query) -> + encode_legacy_auth(Query, + [{<<"xmlns">>, <<"jabber:iq:auth">>}]); encode({sasl_auth, _, _} = Auth) -> encode_sasl_auth(Auth, [{<<"xmlns">>, @@ -1915,7 +2004,7 @@ encode({p1_rebind} = Rebind) -> [{<<"xmlns">>, <<"p1:rebind">>}]); encode({p1_ack} = Ack) -> encode_p1_ack(Ack, [{<<"xmlns">>, <<"p1:ack">>}]); -encode({caps, _, _, _} = C) -> +encode({caps, _, _, _, _} = C) -> encode_caps(C, [{<<"xmlns">>, <<"http://jabber.org/protocol/caps">>}]); encode({feature_register} = Register) -> @@ -1927,7 +2016,7 @@ encode({register, _, _, _, _, _, _, _, _, _, _, _, _, _, Query) -> encode_register(Query, [{<<"xmlns">>, <<"jabber:iq:register">>}]); -encode({session} = Session) -> +encode({xmpp_session, _} = Session) -> encode_session(Session, [{<<"xmlns">>, <<"urn:ietf:params:xml:ns:xmpp-session">>}]); @@ -1981,11 +2070,12 @@ encode({vcard_sound, _, _, _} = Sound) -> encode({vcard_key, _, _} = Key) -> encode_vcard_KEY(Key, [{<<"xmlns">>, <<"vcard-temp">>}]); -encode({vcard, _, _, _, _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _} = +encode({vcard_temp, _, _, _, _, _, _, _, _, _, _, _, _, + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _} = Vcard) -> - encode_vcard(Vcard, [{<<"xmlns">>, <<"vcard-temp">>}]); -encode({vcard_xupdate, _} = X) -> + encode_vcard_temp(Vcard, + [{<<"xmlns">>, <<"vcard-temp">>}]); +encode({vcard_xupdate, undefined, _} = X) -> encode_vcard_xupdate(X, [{<<"xmlns">>, <<"vcard-temp:x:update">>}]); encode({xdata_field, _, _, _, _, _, _, _} = Field) -> @@ -2069,7 +2159,7 @@ encode({chatstate, paused} = Paused) -> encode_chatstate_paused(Paused, [{<<"xmlns">>, <<"http://jabber.org/protocol/chatstates">>}]); -encode({delay, _, _} = Delay) -> +encode({delay, _, _, _} = Delay) -> encode_delay(Delay, [{<<"xmlns">>, <<"urn:xmpp:delay">>}]); encode({streamhost, _, _, _} = Streamhost) -> @@ -2192,17 +2282,202 @@ encode({mix_leave} = Leave) -> [{<<"xmlns">>, <<"urn:xmpp:mix:0">>}]); encode({mix_participant, _, _} = Participant) -> encode_mix_participant(Participant, - [{<<"xmlns">>, <<"urn:xmpp:mix:0">>}]). + [{<<"xmlns">>, <<"urn:xmpp:mix:0">>}]); +encode({hint, 'no-copy'} = No_copy) -> + encode_hint_no_copy(No_copy, + [{<<"xmlns">>, <<"urn:xmpp:hints">>}]); +encode({hint, 'no-store'} = No_store) -> + encode_hint_no_store(No_store, + [{<<"xmlns">>, <<"urn:xmpp:hints">>}]); +encode({hint, store} = Store) -> + encode_hint_store(Store, + [{<<"xmlns">>, <<"urn:xmpp:hints">>}]); +encode({hint, 'no-permanent-store'} = + No_permanent_store) -> + encode_hint_no_permanent_store(No_permanent_store, + [{<<"xmlns">>, <<"urn:xmpp:hints">>}]); +encode({search_item, _, _, _, _, _} = Item) -> + encode_search_item(Item, + [{<<"xmlns">>, <<"jabber:iq:search">>}]); +encode({search, _, _, _, _, _, _, _} = Query) -> + encode_search(Query, + [{<<"xmlns">>, <<"jabber:iq:search">>}]). + +get_name({last, _, _}) -> <<"query">>; +get_name({version, _, _, _}) -> <<"query">>; +get_name({roster_item, _, _, _, _, _}) -> <<"item">>; +get_name({roster_query, _, _}) -> <<"query">>; +get_name({rosterver_feature}) -> <<"ver">>; +get_name({privacy_item, _, _, _, _, _, _, _, _}) -> + <<"item">>; +get_name({privacy_list, _, _}) -> <<"list">>; +get_name({privacy_query, _, _, _}) -> <<"query">>; +get_name({block, _}) -> <<"block">>; +get_name({unblock, _}) -> <<"unblock">>; +get_name({block_list}) -> <<"blocklist">>; +get_name({identity, _, _, _, _}) -> <<"identity">>; +get_name({disco_info, _, _, _, _}) -> <<"query">>; +get_name({disco_item, _, _, _}) -> <<"item">>; +get_name({disco_items, _, _}) -> <<"query">>; +get_name({private, _}) -> <<"query">>; +get_name({bookmark_conference, _, _, _, _, _}) -> + <<"conference">>; +get_name({bookmark_url, _, _}) -> <<"url">>; +get_name({bookmark_storage, _, _}) -> <<"storage">>; +get_name({stat, _, _, _, _}) -> <<"stat">>; +get_name({stats, _}) -> <<"query">>; +get_name({iq, _, _, _, _, _, _, _}) -> <<"iq">>; +get_name({message, _, _, _, _, _, _, _, _, _, _}) -> + <<"message">>; +get_name({presence, _, _, _, _, _, _, _, _, _, _}) -> + <<"presence">>; +get_name({gone, _}) -> <<"gone">>; +get_name({redirect, _}) -> <<"redirect">>; +get_name({error, _, _, _, _, _}) -> <<"error">>; +get_name({bind, _, _}) -> <<"bind">>; +get_name({legacy_auth, _, _, _, _}) -> <<"query">>; +get_name({sasl_auth, _, _}) -> <<"auth">>; +get_name({sasl_abort}) -> <<"abort">>; +get_name({sasl_challenge, _}) -> <<"challenge">>; +get_name({sasl_response, _}) -> <<"response">>; +get_name({sasl_success, _}) -> <<"success">>; +get_name({sasl_failure, _, _}) -> <<"failure">>; +get_name({sasl_mechanisms, _}) -> <<"mechanisms">>; +get_name({starttls, _}) -> <<"starttls">>; +get_name({starttls_proceed}) -> <<"proceed">>; +get_name({starttls_failure}) -> <<"failure">>; +get_name({compress_failure, _}) -> <<"failure">>; +get_name({compress, _}) -> <<"compress">>; +get_name({compressed}) -> <<"compressed">>; +get_name({compression, _}) -> <<"compression">>; +get_name({stream_features, _}) -> <<"stream:features">>; +get_name({p1_push}) -> <<"push">>; +get_name({p1_rebind}) -> <<"rebind">>; +get_name({p1_ack}) -> <<"ack">>; +get_name({caps, _, _, _, _}) -> <<"c">>; +get_name({feature_register}) -> <<"register">>; +get_name({register, _, _, _, _, _, _, _, _, _, _, _, _, + _, _, _, _, _, _, _, _, _}) -> + <<"query">>; +get_name({xmpp_session, _}) -> <<"session">>; +get_name({ping}) -> <<"ping">>; +get_name({time, _, _}) -> <<"time">>; +get_name({text, _, _}) -> <<"text">>; +get_name({'see-other-host', _}) -> <<"see-other-host">>; +get_name({stream_error, _, _}) -> <<"stream:error">>; +get_name({vcard_name, _, _, _, _, _}) -> <<"N">>; +get_name({vcard_adr, _, _, _, _, _, _, _, _, _, _, _, _, + _, _}) -> + <<"ADR">>; +get_name({vcard_label, _, _, _, _, _, _, _, _}) -> + <<"LABEL">>; +get_name({vcard_tel, _, _, _, _, _, _, _, _, _, _, _, _, + _, _}) -> + <<"TEL">>; +get_name({vcard_email, _, _, _, _, _, _}) -> + <<"EMAIL">>; +get_name({vcard_geo, _, _}) -> <<"GEO">>; +get_name({vcard_logo, _, _, _}) -> <<"LOGO">>; +get_name({vcard_photo, _, _, _}) -> <<"PHOTO">>; +get_name({vcard_org, _, _}) -> <<"ORG">>; +get_name({vcard_sound, _, _, _}) -> <<"SOUND">>; +get_name({vcard_key, _, _}) -> <<"KEY">>; +get_name({vcard_temp, _, _, _, _, _, _, _, _, _, _, _, + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, + _}) -> + <<"vCard">>; +get_name({vcard_xupdate, undefined, _}) -> <<"x">>; +get_name({xdata_field, _, _, _, _, _, _, _}) -> + <<"field">>; +get_name({xdata, _, _, _, _, _, _}) -> <<"x">>; +get_name({pubsub_subscription, _, _, _, _}) -> + <<"subscription">>; +get_name({pubsub_affiliation, _, _}) -> + <<"affiliation">>; +get_name({pubsub_item, _, _}) -> <<"item">>; +get_name({pubsub_items, _, _, _, _}) -> <<"items">>; +get_name({pubsub_event_item, _, _, _, _}) -> <<"item">>; +get_name({pubsub_event_items, _, _, _}) -> <<"items">>; +get_name({pubsub_event, _}) -> <<"event">>; +get_name({pubsub_subscribe, _, _}) -> <<"subscribe">>; +get_name({pubsub_unsubscribe, _, _, _}) -> + <<"unsubscribe">>; +get_name({pubsub_publish, _, _}) -> <<"publish">>; +get_name({pubsub_options, _, _, _, _}) -> <<"options">>; +get_name({pubsub_retract, _, _, _}) -> <<"retract">>; +get_name({pubsub, _, _, _, _, _, _, _, _}) -> + <<"pubsub">>; +get_name({shim, _}) -> <<"headers">>; +get_name({chatstate, active}) -> <<"active">>; +get_name({chatstate, composing}) -> <<"composing">>; +get_name({chatstate, gone}) -> <<"gone">>; +get_name({chatstate, inactive}) -> <<"inactive">>; +get_name({chatstate, paused}) -> <<"paused">>; +get_name({delay, _, _, _}) -> <<"delay">>; +get_name({streamhost, _, _, _}) -> <<"streamhost">>; +get_name({bytestreams, _, _, _, _, _, _}) -> + <<"query">>; +get_name({muc_history, _, _, _, _}) -> <<"history">>; +get_name({muc_decline, _, _, _}) -> <<"decline">>; +get_name({muc_user_destroy, _, _}) -> <<"destroy">>; +get_name({muc_invite, _, _, _}) -> <<"invite">>; +get_name({muc_user, _, _, _, _, _, _}) -> <<"x">>; +get_name({muc_owner_destroy, _, _, _}) -> <<"destroy">>; +get_name({muc_owner, _, _}) -> <<"query">>; +get_name({muc_item, _, _, _, _, _, _, _}) -> <<"item">>; +get_name({muc_actor, _, _}) -> <<"actor">>; +get_name({muc_admin, _}) -> <<"query">>; +get_name({muc, _, _}) -> <<"x">>; +get_name({rsm_first, _, _}) -> <<"first">>; +get_name({rsm_set, _, _, _, _, _, _, _}) -> <<"set">>; +get_name({mam_query, _, _, _, _, _, _, _}) -> + <<"query">>; +get_name({mam_archived, _, _}) -> <<"archived">>; +get_name({mam_result, _, _, _, _}) -> <<"result">>; +get_name({mam_prefs, _, _, _, _}) -> <<"prefs">>; +get_name({mam_fin, _, _, _, _}) -> <<"fin">>; +get_name({forwarded, _, _}) -> <<"forwarded">>; +get_name({carbons_disable}) -> <<"disable">>; +get_name({carbons_enable}) -> <<"enable">>; +get_name({carbons_private}) -> <<"private">>; +get_name({carbons_received, _}) -> <<"received">>; +get_name({carbons_sent, _}) -> <<"sent">>; +get_name({feature_csi, _}) -> <<"csi">>; +get_name({csi, active}) -> <<"active">>; +get_name({csi, inactive}) -> <<"inactive">>; +get_name({feature_sm, _}) -> <<"sm">>; +get_name({sm_enable, _, _, _}) -> <<"enable">>; +get_name({sm_enabled, _, _, _, _, _}) -> <<"enabled">>; +get_name({sm_resume, _, _, _}) -> <<"resume">>; +get_name({sm_resumed, _, _, _}) -> <<"resumed">>; +get_name({sm_r, _}) -> <<"r">>; +get_name({sm_a, _, _}) -> <<"a">>; +get_name({sm_failed, _, _, _}) -> <<"failed">>; +get_name({offline_item, _, _}) -> <<"item">>; +get_name({offline, _, _, _}) -> <<"offline">>; +get_name({mix_join, _, _}) -> <<"join">>; +get_name({mix_leave}) -> <<"leave">>; +get_name({mix_participant, _, _}) -> <<"participant">>; +get_name({hint, 'no-copy'}) -> <<"no-copy">>; +get_name({hint, 'no-store'}) -> <<"no-store">>; +get_name({hint, store}) -> <<"store">>; +get_name({hint, 'no-permanent-store'}) -> + <<"no-permanent-store">>; +get_name({search_item, _, _, _, _, _}) -> <<"item">>; +get_name({search, _, _, _, _, _, _, _}) -> <<"query">>. get_ns({last, _, _}) -> <<"jabber:iq:last">>; get_ns({version, _, _, _}) -> <<"jabber:iq:version">>; get_ns({roster_item, _, _, _, _, _}) -> <<"jabber:iq:roster">>; -get_ns({roster, _, _}) -> <<"jabber:iq:roster">>; -get_ns({privacy_item, _, _, _, _, _}) -> +get_ns({roster_query, _, _}) -> <<"jabber:iq:roster">>; +get_ns({rosterver_feature}) -> + <<"urn:xmpp:features:rosterver">>; +get_ns({privacy_item, _, _, _, _, _, _, _, _}) -> <<"jabber:iq:privacy">>; get_ns({privacy_list, _, _}) -> <<"jabber:iq:privacy">>; -get_ns({privacy, _, _, _}) -> <<"jabber:iq:privacy">>; +get_ns({privacy_query, _, _, _}) -> + <<"jabber:iq:privacy">>; get_ns({block, _}) -> <<"urn:xmpp:blocking">>; get_ns({unblock, _}) -> <<"urn:xmpp:blocking">>; get_ns({block_list}) -> <<"urn:xmpp:blocking">>; @@ -2234,9 +2509,11 @@ get_ns({gone, _}) -> <<"urn:ietf:params:xml:ns:xmpp-stanzas">>; get_ns({redirect, _}) -> <<"urn:ietf:params:xml:ns:xmpp-stanzas">>; -get_ns({error, _, _, _, _}) -> <<"jabber:client">>; +get_ns({error, _, _, _, _, _}) -> <<"jabber:client">>; get_ns({bind, _, _}) -> <<"urn:ietf:params:xml:ns:xmpp-bind">>; +get_ns({legacy_auth, _, _, _, _}) -> + <<"jabber:iq:auth">>; get_ns({sasl_auth, _, _}) -> <<"urn:ietf:params:xml:ns:xmpp-sasl">>; get_ns({sasl_abort}) -> @@ -2270,14 +2547,14 @@ get_ns({stream_features, _}) -> get_ns({p1_push}) -> <<"p1:push">>; get_ns({p1_rebind}) -> <<"p1:rebind">>; get_ns({p1_ack}) -> <<"p1:ack">>; -get_ns({caps, _, _, _}) -> +get_ns({caps, _, _, _, _}) -> <<"http://jabber.org/protocol/caps">>; get_ns({feature_register}) -> <<"http://jabber.org/features/iq-register">>; get_ns({register, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _}) -> <<"jabber:iq:register">>; -get_ns({session}) -> +get_ns({xmpp_session, _}) -> <<"urn:ietf:params:xml:ns:xmpp-session">>; get_ns({ping}) -> <<"urn:xmpp:ping">>; get_ns({time, _, _}) -> <<"urn:xmpp:time">>; @@ -2302,10 +2579,11 @@ get_ns({vcard_photo, _, _, _}) -> <<"vcard-temp">>; get_ns({vcard_org, _, _}) -> <<"vcard-temp">>; get_ns({vcard_sound, _, _, _}) -> <<"vcard-temp">>; get_ns({vcard_key, _, _}) -> <<"vcard-temp">>; -get_ns({vcard, _, _, _, _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _}) -> +get_ns({vcard_temp, _, _, _, _, _, _, _, _, _, _, _, _, + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _}) -> <<"vcard-temp">>; -get_ns({vcard_xupdate, _}) -> <<"vcard-temp:x:update">>; +get_ns({vcard_xupdate, undefined, _}) -> + <<"vcard-temp:x:update">>; get_ns({xdata_field, _, _, _, _, _, _, _}) -> <<"jabber:x:data">>; get_ns({xdata, _, _, _, _, _, _}) -> @@ -2348,7 +2626,7 @@ get_ns({chatstate, inactive}) -> <<"http://jabber.org/protocol/chatstates">>; get_ns({chatstate, paused}) -> <<"http://jabber.org/protocol/chatstates">>; -get_ns({delay, _, _}) -> <<"urn:xmpp:delay">>; +get_ns({delay, _, _, _}) -> <<"urn:xmpp:delay">>; get_ns({streamhost, _, _, _}) -> <<"http://jabber.org/protocol/bytestreams">>; get_ns({bytestreams, _, _, _, _, _, _}) -> @@ -2375,7 +2653,10 @@ get_ns({rsm_first, _, _}) -> <<"http://jabber.org/protocol/rsm">>; get_ns({rsm_set, _, _, _, _, _, _, _}) -> <<"http://jabber.org/protocol/rsm">>; +get_ns({mam_query, Xmlns, _, _, _, _, _, _}) -> Xmlns; get_ns({mam_archived, _, _}) -> <<"urn:xmpp:mam:tmp">>; +get_ns({mam_result, Xmlns, _, _, _}) -> Xmlns; +get_ns({mam_prefs, Xmlns, _, _, _}) -> Xmlns; get_ns({mam_fin, _, _, _, _}) -> <<"urn:xmpp:mam:0">>; get_ns({forwarded, _, _}) -> <<"urn:xmpp:forward:0">>; get_ns({carbons_disable}) -> <<"urn:xmpp:carbons:2">>; @@ -2384,9 +2665,17 @@ get_ns({carbons_private}) -> <<"urn:xmpp:carbons:2">>; get_ns({carbons_received, _}) -> <<"urn:xmpp:carbons:2">>; get_ns({carbons_sent, _}) -> <<"urn:xmpp:carbons:2">>; -get_ns({feature_csi, _}) -> <<"urn:xmpp:csi:0">>; +get_ns({feature_csi, Xmlns}) -> Xmlns; get_ns({csi, active}) -> <<"urn:xmpp:csi:0">>; get_ns({csi, inactive}) -> <<"urn:xmpp:csi:0">>; +get_ns({feature_sm, Xmlns}) -> Xmlns; +get_ns({sm_enable, _, _, Xmlns}) -> Xmlns; +get_ns({sm_enabled, _, _, _, _, Xmlns}) -> Xmlns; +get_ns({sm_resume, _, _, Xmlns}) -> Xmlns; +get_ns({sm_resumed, _, _, Xmlns}) -> Xmlns; +get_ns({sm_r, Xmlns}) -> Xmlns; +get_ns({sm_a, _, Xmlns}) -> Xmlns; +get_ns({sm_failed, _, _, Xmlns}) -> Xmlns; get_ns({offline_item, _, _}) -> <<"http://jabber.org/protocol/offline">>; get_ns({offline, _, _, _}) -> @@ -2394,7 +2683,15 @@ get_ns({offline, _, _, _}) -> get_ns({mix_join, _, _}) -> <<"urn:xmpp:mix:0">>; get_ns({mix_leave}) -> <<"urn:xmpp:mix:0">>; get_ns({mix_participant, _, _}) -> <<"urn:xmpp:mix:0">>; -get_ns(_) -> <<>>. +get_ns({hint, 'no-copy'}) -> <<"urn:xmpp:hints">>; +get_ns({hint, 'no-store'}) -> <<"urn:xmpp:hints">>; +get_ns({hint, store}) -> <<"urn:xmpp:hints">>; +get_ns({hint, 'no-permanent-store'}) -> + <<"urn:xmpp:hints">>; +get_ns({search_item, _, _, _, _, _}) -> + <<"jabber:iq:search">>; +get_ns({search, _, _, _, _, _, _, _}) -> + <<"jabber:iq:search">>. dec_int(Val) -> dec_int(Val, infinity, infinity). @@ -2443,15 +2740,17 @@ get_attr(Attr, Attrs) -> pp(Term) -> io_lib_pretty:print(Term, fun pp/2). -pp(last, 2) -> [seconds, text]; +pp(last, 2) -> [seconds, status]; pp(version, 3) -> [name, ver, os]; pp(roster_item, 5) -> [jid, name, groups, subscription, ask]; -pp(roster, 2) -> [items, ver]; -pp(privacy_item, 5) -> - [order, action, type, value, kinds]; +pp(roster_query, 2) -> [items, ver]; +pp(rosterver_feature, 0) -> []; +pp(privacy_item, 8) -> + [order, action, type, value, message, iq, presence_in, + presence_out]; pp(privacy_list, 2) -> [name, items]; -pp(privacy, 3) -> [lists, default, active]; +pp(privacy_query, 3) -> [lists, default, active]; pp(block, 1) -> [items]; pp(unblock, 1) -> [items]; pp(block_list, 0) -> []; @@ -2476,8 +2775,10 @@ pp(presence, 10) -> error, sub_els]; pp(gone, 1) -> [uri]; pp(redirect, 1) -> [uri]; -pp(error, 4) -> [type, by, reason, text]; +pp(error, 5) -> [type, code, by, reason, text]; pp(bind, 2) -> [jid, resource]; +pp(legacy_auth, 4) -> + [username, password, digest, resource]; pp(sasl_auth, 2) -> [mechanism, text]; pp(sasl_abort, 0) -> []; pp(sasl_challenge, 1) -> [text]; @@ -2496,13 +2797,13 @@ pp(stream_features, 1) -> [sub_els]; pp(p1_push, 0) -> []; pp(p1_rebind, 0) -> []; pp(p1_ack, 0) -> []; -pp(caps, 3) -> [hash, node, ver]; +pp(caps, 4) -> [node, version, hash, exts]; pp(feature_register, 0) -> []; pp(register, 21) -> [registered, remove, instructions, username, nick, password, name, first, last, email, address, city, state, zip, phone, url, date, misc, text, key, xdata]; -pp(session, 0) -> []; +pp(xmpp_session, 1) -> [optional]; pp(ping, 0) -> []; pp(time, 2) -> [tzo, utc]; pp(text, 2) -> [lang, data]; @@ -2526,12 +2827,12 @@ pp(vcard_photo, 3) -> [type, binval, extval]; pp(vcard_org, 2) -> [name, units]; pp(vcard_sound, 3) -> [phonetic, binval, extval]; pp(vcard_key, 2) -> [type, cred]; -pp(vcard, 29) -> +pp(vcard_temp, 29) -> [version, fn, n, nickname, photo, bday, adr, label, tel, email, jabberid, mailer, tz, geo, title, role, logo, org, categories, note, prodid, rev, sort_string, sound, uid, url, class, key, desc]; -pp(vcard_xupdate, 1) -> [photo]; +pp(vcard_xupdate, 2) -> [us, hash]; pp(xdata_field, 7) -> [label, type, var, required, desc, values, options]; pp(xdata, 6) -> @@ -2554,7 +2855,7 @@ pp(pubsub, 8) -> unsubscribe, options, items, retract]; pp(shim, 1) -> [headers]; pp(chatstate, 1) -> [type]; -pp(delay, 2) -> [stamp, from]; +pp(delay, 3) -> [stamp, from, desc]; pp(streamhost, 3) -> [jid, host, port]; pp(bytestreams, 6) -> [hosts, used, activate, dstaddr, mode, sid]; @@ -2603,8 +2904,16 @@ pp(offline, 3) -> [items, purge, fetch]; pp(mix_join, 2) -> [jid, subscribe]; pp(mix_leave, 0) -> []; pp(mix_participant, 2) -> [jid, nick]; +pp(hint, 1) -> [type]; +pp(search_item, 5) -> [jid, first, last, nick, email]; +pp(search, 7) -> + [instructions, first, last, nick, email, items, xdata]; pp(_, _) -> no. +join([], _Sep) -> <<>>; +join([H | T], Sep) -> + <> || X <- T >>/binary>>. + enc_bool(false) -> <<"false">>; enc_bool(true) -> <<"true">>. @@ -2645,6 +2954,530 @@ dec_tzo(Val) -> M = jlib:binary_to_integer(M1), if H >= -12, H =< 12, M >= 0, M < 60 -> {H, M} end. +decode_search(__TopXMLNS, __IgnoreEls, + {xmlel, <<"query">>, _attrs, _els}) -> + {Xdata, Items, Instructions, Last, First, Nick, Email} = + decode_search_els(__TopXMLNS, __IgnoreEls, _els, + undefined, [], undefined, undefined, undefined, + undefined, undefined), + {search, Instructions, First, Last, Nick, Email, Items, + Xdata}. + +decode_search_els(__TopXMLNS, __IgnoreEls, [], Xdata, + Items, Instructions, Last, First, Nick, Email) -> + {Xdata, lists:reverse(Items), Instructions, Last, First, + Nick, Email}; +decode_search_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"instructions">>, _attrs, _} = _el | _els], + Xdata, Items, Instructions, Last, First, Nick, Email) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:search">> -> + decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, + Items, + decode_search_instructions(__TopXMLNS, __IgnoreEls, + _el), + Last, First, Nick, Email); + <<"jabber:iq:search">> -> + decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, + Items, + decode_search_instructions(<<"jabber:iq:search">>, + __IgnoreEls, _el), + Last, First, Nick, Email); + _ -> + decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, + Items, Instructions, Last, First, Nick, Email) + end; +decode_search_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"first">>, _attrs, _} = _el | _els], Xdata, + Items, Instructions, Last, First, Nick, Email) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:search">> -> + decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, + Items, Instructions, Last, + decode_search_first(__TopXMLNS, __IgnoreEls, _el), + Nick, Email); + <<"jabber:iq:search">> -> + decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, + Items, Instructions, Last, + decode_search_first(<<"jabber:iq:search">>, + __IgnoreEls, _el), + Nick, Email); + _ -> + decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, + Items, Instructions, Last, First, Nick, Email) + end; +decode_search_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"last">>, _attrs, _} = _el | _els], Xdata, + Items, Instructions, Last, First, Nick, Email) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:search">> -> + decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, + Items, Instructions, + decode_search_last(__TopXMLNS, __IgnoreEls, _el), + First, Nick, Email); + <<"jabber:iq:search">> -> + decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, + Items, Instructions, + decode_search_last(<<"jabber:iq:search">>, + __IgnoreEls, _el), + First, Nick, Email); + _ -> + decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, + Items, Instructions, Last, First, Nick, Email) + end; +decode_search_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"nick">>, _attrs, _} = _el | _els], Xdata, + Items, Instructions, Last, First, Nick, Email) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:search">> -> + decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, + Items, Instructions, Last, First, + decode_search_nick(__TopXMLNS, __IgnoreEls, _el), + Email); + <<"jabber:iq:search">> -> + decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, + Items, Instructions, Last, First, + decode_search_nick(<<"jabber:iq:search">>, + __IgnoreEls, _el), + Email); + _ -> + decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, + Items, Instructions, Last, First, Nick, Email) + end; +decode_search_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"email">>, _attrs, _} = _el | _els], Xdata, + Items, Instructions, Last, First, Nick, Email) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:search">> -> + decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, + Items, Instructions, Last, First, Nick, + decode_search_email(__TopXMLNS, __IgnoreEls, _el)); + <<"jabber:iq:search">> -> + decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, + Items, Instructions, Last, First, Nick, + decode_search_email(<<"jabber:iq:search">>, + __IgnoreEls, _el)); + _ -> + decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, + Items, Instructions, Last, First, Nick, Email) + end; +decode_search_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"item">>, _attrs, _} = _el | _els], Xdata, + Items, Instructions, Last, First, Nick, Email) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:search">> -> + decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, + [decode_search_item(__TopXMLNS, __IgnoreEls, _el) + | Items], + Instructions, Last, First, Nick, Email); + <<"jabber:iq:search">> -> + decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, + [decode_search_item(<<"jabber:iq:search">>, + __IgnoreEls, _el) + | Items], + Instructions, Last, First, Nick, Email); + _ -> + decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, + Items, Instructions, Last, First, Nick, Email) + end; +decode_search_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"x">>, _attrs, _} = _el | _els], Xdata, + Items, Instructions, Last, First, Nick, Email) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"jabber:x:data">> -> + decode_search_els(__TopXMLNS, __IgnoreEls, _els, + decode_xdata(<<"jabber:x:data">>, __IgnoreEls, _el), + Items, Instructions, Last, First, Nick, Email); + _ -> + decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, + Items, Instructions, Last, First, Nick, Email) + end; +decode_search_els(__TopXMLNS, __IgnoreEls, [_ | _els], + Xdata, Items, Instructions, Last, First, Nick, Email) -> + decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, + Items, Instructions, Last, First, Nick, Email). + +encode_search({search, Instructions, First, Last, Nick, + Email, Items, Xdata}, + _xmlns_attrs) -> + _els = lists:reverse('encode_search_$xdata'(Xdata, + 'encode_search_$items'(Items, + 'encode_search_$instructions'(Instructions, + 'encode_search_$last'(Last, + 'encode_search_$first'(First, + 'encode_search_$nick'(Nick, + 'encode_search_$email'(Email, + [])))))))), + _attrs = _xmlns_attrs, + {xmlel, <<"query">>, _attrs, _els}. + +'encode_search_$xdata'(undefined, _acc) -> _acc; +'encode_search_$xdata'(Xdata, _acc) -> + [encode_xdata(Xdata, + [{<<"xmlns">>, <<"jabber:x:data">>}]) + | _acc]. + +'encode_search_$items'([], _acc) -> _acc; +'encode_search_$items'([Items | _els], _acc) -> + 'encode_search_$items'(_els, + [encode_search_item(Items, []) | _acc]). + +'encode_search_$instructions'(undefined, _acc) -> _acc; +'encode_search_$instructions'(Instructions, _acc) -> + [encode_search_instructions(Instructions, []) | _acc]. + +'encode_search_$last'(undefined, _acc) -> _acc; +'encode_search_$last'(Last, _acc) -> + [encode_search_last(Last, []) | _acc]. + +'encode_search_$first'(undefined, _acc) -> _acc; +'encode_search_$first'(First, _acc) -> + [encode_search_first(First, []) | _acc]. + +'encode_search_$nick'(undefined, _acc) -> _acc; +'encode_search_$nick'(Nick, _acc) -> + [encode_search_nick(Nick, []) | _acc]. + +'encode_search_$email'(undefined, _acc) -> _acc; +'encode_search_$email'(Email, _acc) -> + [encode_search_email(Email, []) | _acc]. + +decode_search_item(__TopXMLNS, __IgnoreEls, + {xmlel, <<"item">>, _attrs, _els}) -> + {Last, First, Nick, Email} = + decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, + undefined, undefined, undefined, undefined), + Jid = decode_search_item_attrs(__TopXMLNS, _attrs, + undefined), + {search_item, Jid, First, Last, Nick, Email}. + +decode_search_item_els(__TopXMLNS, __IgnoreEls, [], + Last, First, Nick, Email) -> + {Last, First, Nick, Email}; +decode_search_item_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"first">>, _attrs, _} = _el | _els], Last, + First, Nick, Email) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:search">> -> + decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, + Last, + decode_search_first(__TopXMLNS, __IgnoreEls, + _el), + Nick, Email); + <<"jabber:iq:search">> -> + decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, + Last, + decode_search_first(<<"jabber:iq:search">>, + __IgnoreEls, _el), + Nick, Email); + _ -> + decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, + Last, First, Nick, Email) + end; +decode_search_item_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"last">>, _attrs, _} = _el | _els], Last, + First, Nick, Email) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:search">> -> + decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, + decode_search_last(__TopXMLNS, __IgnoreEls, + _el), + First, Nick, Email); + <<"jabber:iq:search">> -> + decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, + decode_search_last(<<"jabber:iq:search">>, + __IgnoreEls, _el), + First, Nick, Email); + _ -> + decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, + Last, First, Nick, Email) + end; +decode_search_item_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"nick">>, _attrs, _} = _el | _els], Last, + First, Nick, Email) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:search">> -> + decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, + Last, First, + decode_search_nick(__TopXMLNS, __IgnoreEls, + _el), + Email); + <<"jabber:iq:search">> -> + decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, + Last, First, + decode_search_nick(<<"jabber:iq:search">>, + __IgnoreEls, _el), + Email); + _ -> + decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, + Last, First, Nick, Email) + end; +decode_search_item_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"email">>, _attrs, _} = _el | _els], Last, + First, Nick, Email) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:search">> -> + decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, + Last, First, Nick, + decode_search_email(__TopXMLNS, __IgnoreEls, + _el)); + <<"jabber:iq:search">> -> + decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, + Last, First, Nick, + decode_search_email(<<"jabber:iq:search">>, + __IgnoreEls, _el)); + _ -> + decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, + Last, First, Nick, Email) + end; +decode_search_item_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Last, First, Nick, Email) -> + decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, + Last, First, Nick, Email). + +decode_search_item_attrs(__TopXMLNS, + [{<<"jid">>, _val} | _attrs], _Jid) -> + decode_search_item_attrs(__TopXMLNS, _attrs, _val); +decode_search_item_attrs(__TopXMLNS, [_ | _attrs], + Jid) -> + decode_search_item_attrs(__TopXMLNS, _attrs, Jid); +decode_search_item_attrs(__TopXMLNS, [], Jid) -> + decode_search_item_attr_jid(__TopXMLNS, Jid). + +encode_search_item({search_item, Jid, First, Last, Nick, + Email}, + _xmlns_attrs) -> + _els = lists:reverse('encode_search_item_$last'(Last, + 'encode_search_item_$first'(First, + 'encode_search_item_$nick'(Nick, + 'encode_search_item_$email'(Email, + []))))), + _attrs = encode_search_item_attr_jid(Jid, _xmlns_attrs), + {xmlel, <<"item">>, _attrs, _els}. + +'encode_search_item_$last'(undefined, _acc) -> _acc; +'encode_search_item_$last'(Last, _acc) -> + [encode_search_last(Last, []) | _acc]. + +'encode_search_item_$first'(undefined, _acc) -> _acc; +'encode_search_item_$first'(First, _acc) -> + [encode_search_first(First, []) | _acc]. + +'encode_search_item_$nick'(undefined, _acc) -> _acc; +'encode_search_item_$nick'(Nick, _acc) -> + [encode_search_nick(Nick, []) | _acc]. + +'encode_search_item_$email'(undefined, _acc) -> _acc; +'encode_search_item_$email'(Email, _acc) -> + [encode_search_email(Email, []) | _acc]. + +decode_search_item_attr_jid(__TopXMLNS, undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"jid">>, <<"item">>, __TopXMLNS}}); +decode_search_item_attr_jid(__TopXMLNS, _val) -> + case catch dec_jid(_val) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"jid">>, <<"item">>, __TopXMLNS}}); + _res -> _res + end. + +encode_search_item_attr_jid(_val, _acc) -> + [{<<"jid">>, enc_jid(_val)} | _acc]. + +decode_search_email(__TopXMLNS, __IgnoreEls, + {xmlel, <<"email">>, _attrs, _els}) -> + Cdata = decode_search_email_els(__TopXMLNS, __IgnoreEls, + _els, <<>>), + Cdata. + +decode_search_email_els(__TopXMLNS, __IgnoreEls, [], + Cdata) -> + decode_search_email_cdata(__TopXMLNS, Cdata); +decode_search_email_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Cdata) -> + decode_search_email_els(__TopXMLNS, __IgnoreEls, _els, + <>); +decode_search_email_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Cdata) -> + decode_search_email_els(__TopXMLNS, __IgnoreEls, _els, + Cdata). + +encode_search_email(Cdata, _xmlns_attrs) -> + _els = encode_search_email_cdata(Cdata, []), + _attrs = _xmlns_attrs, + {xmlel, <<"email">>, _attrs, _els}. + +decode_search_email_cdata(__TopXMLNS, <<>>) -> <<>>; +decode_search_email_cdata(__TopXMLNS, _val) -> _val. + +encode_search_email_cdata(<<>>, _acc) -> _acc; +encode_search_email_cdata(_val, _acc) -> + [{xmlcdata, _val} | _acc]. + +decode_search_nick(__TopXMLNS, __IgnoreEls, + {xmlel, <<"nick">>, _attrs, _els}) -> + Cdata = decode_search_nick_els(__TopXMLNS, __IgnoreEls, + _els, <<>>), + Cdata. + +decode_search_nick_els(__TopXMLNS, __IgnoreEls, [], + Cdata) -> + decode_search_nick_cdata(__TopXMLNS, Cdata); +decode_search_nick_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Cdata) -> + decode_search_nick_els(__TopXMLNS, __IgnoreEls, _els, + <>); +decode_search_nick_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Cdata) -> + decode_search_nick_els(__TopXMLNS, __IgnoreEls, _els, + Cdata). + +encode_search_nick(Cdata, _xmlns_attrs) -> + _els = encode_search_nick_cdata(Cdata, []), + _attrs = _xmlns_attrs, + {xmlel, <<"nick">>, _attrs, _els}. + +decode_search_nick_cdata(__TopXMLNS, <<>>) -> <<>>; +decode_search_nick_cdata(__TopXMLNS, _val) -> _val. + +encode_search_nick_cdata(<<>>, _acc) -> _acc; +encode_search_nick_cdata(_val, _acc) -> + [{xmlcdata, _val} | _acc]. + +decode_search_last(__TopXMLNS, __IgnoreEls, + {xmlel, <<"last">>, _attrs, _els}) -> + Cdata = decode_search_last_els(__TopXMLNS, __IgnoreEls, + _els, <<>>), + Cdata. + +decode_search_last_els(__TopXMLNS, __IgnoreEls, [], + Cdata) -> + decode_search_last_cdata(__TopXMLNS, Cdata); +decode_search_last_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Cdata) -> + decode_search_last_els(__TopXMLNS, __IgnoreEls, _els, + <>); +decode_search_last_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Cdata) -> + decode_search_last_els(__TopXMLNS, __IgnoreEls, _els, + Cdata). + +encode_search_last(Cdata, _xmlns_attrs) -> + _els = encode_search_last_cdata(Cdata, []), + _attrs = _xmlns_attrs, + {xmlel, <<"last">>, _attrs, _els}. + +decode_search_last_cdata(__TopXMLNS, <<>>) -> <<>>; +decode_search_last_cdata(__TopXMLNS, _val) -> _val. + +encode_search_last_cdata(<<>>, _acc) -> _acc; +encode_search_last_cdata(_val, _acc) -> + [{xmlcdata, _val} | _acc]. + +decode_search_first(__TopXMLNS, __IgnoreEls, + {xmlel, <<"first">>, _attrs, _els}) -> + Cdata = decode_search_first_els(__TopXMLNS, __IgnoreEls, + _els, <<>>), + Cdata. + +decode_search_first_els(__TopXMLNS, __IgnoreEls, [], + Cdata) -> + decode_search_first_cdata(__TopXMLNS, Cdata); +decode_search_first_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Cdata) -> + decode_search_first_els(__TopXMLNS, __IgnoreEls, _els, + <>); +decode_search_first_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Cdata) -> + decode_search_first_els(__TopXMLNS, __IgnoreEls, _els, + Cdata). + +encode_search_first(Cdata, _xmlns_attrs) -> + _els = encode_search_first_cdata(Cdata, []), + _attrs = _xmlns_attrs, + {xmlel, <<"first">>, _attrs, _els}. + +decode_search_first_cdata(__TopXMLNS, <<>>) -> <<>>; +decode_search_first_cdata(__TopXMLNS, _val) -> _val. + +encode_search_first_cdata(<<>>, _acc) -> _acc; +encode_search_first_cdata(_val, _acc) -> + [{xmlcdata, _val} | _acc]. + +decode_search_instructions(__TopXMLNS, __IgnoreEls, + {xmlel, <<"instructions">>, _attrs, _els}) -> + Cdata = decode_search_instructions_els(__TopXMLNS, + __IgnoreEls, _els, <<>>), + Cdata. + +decode_search_instructions_els(__TopXMLNS, __IgnoreEls, + [], Cdata) -> + decode_search_instructions_cdata(__TopXMLNS, Cdata); +decode_search_instructions_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Cdata) -> + decode_search_instructions_els(__TopXMLNS, __IgnoreEls, + _els, <>); +decode_search_instructions_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Cdata) -> + decode_search_instructions_els(__TopXMLNS, __IgnoreEls, + _els, Cdata). + +encode_search_instructions(Cdata, _xmlns_attrs) -> + _els = encode_search_instructions_cdata(Cdata, []), + _attrs = _xmlns_attrs, + {xmlel, <<"instructions">>, _attrs, _els}. + +decode_search_instructions_cdata(__TopXMLNS, <<>>) -> + undefined; +decode_search_instructions_cdata(__TopXMLNS, _val) -> + _val. + +encode_search_instructions_cdata(undefined, _acc) -> + _acc; +encode_search_instructions_cdata(_val, _acc) -> + [{xmlcdata, _val} | _acc]. + +decode_hint_no_permanent_store(__TopXMLNS, __IgnoreEls, + {xmlel, <<"no-permanent-store">>, _attrs, + _els}) -> + {hint, 'no-permanent-store'}. + +encode_hint_no_permanent_store({hint, + 'no-permanent-store'}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"no-permanent-store">>, _attrs, _els}. + +decode_hint_store(__TopXMLNS, __IgnoreEls, + {xmlel, <<"store">>, _attrs, _els}) -> + {hint, store}. + +encode_hint_store({hint, store}, _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"store">>, _attrs, _els}. + +decode_hint_no_store(__TopXMLNS, __IgnoreEls, + {xmlel, <<"no-store">>, _attrs, _els}) -> + {hint, 'no-store'}. + +encode_hint_no_store({hint, 'no-store'}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"no-store">>, _attrs, _els}. + +decode_hint_no_copy(__TopXMLNS, __IgnoreEls, + {xmlel, <<"no-copy">>, _attrs, _els}) -> + {hint, 'no-copy'}. + +encode_hint_no_copy({hint, 'no-copy'}, _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"no-copy">>, _attrs, _els}. + decode_mix_participant(__TopXMLNS, __IgnoreEls, {xmlel, <<"participant">>, _attrs, _els}) -> {Jid, Nick} = decode_mix_participant_attrs(__TopXMLNS, @@ -2727,15 +3560,20 @@ decode_mix_join_els(__TopXMLNS, __IgnoreEls, [], decode_mix_join_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"subscribe">>, _attrs, _} = _el | _els], Subscribe) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_mix_join_els(__TopXMLNS, __IgnoreEls, _els, - [decode_mix_subscribe(__TopXMLNS, __IgnoreEls, - _el) - | Subscribe]); - true -> - decode_mix_join_els(__TopXMLNS, __IgnoreEls, _els, - Subscribe) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"urn:xmpp:mix:0">> -> + decode_mix_join_els(__TopXMLNS, __IgnoreEls, _els, + [decode_mix_subscribe(__TopXMLNS, __IgnoreEls, + _el) + | Subscribe]); + <<"urn:xmpp:mix:0">> -> + decode_mix_join_els(__TopXMLNS, __IgnoreEls, _els, + [decode_mix_subscribe(<<"urn:xmpp:mix:0">>, + __IgnoreEls, _el) + | Subscribe]); + _ -> + decode_mix_join_els(__TopXMLNS, __IgnoreEls, _els, + Subscribe) end; decode_mix_join_els(__TopXMLNS, __IgnoreEls, [_ | _els], Subscribe) -> @@ -2822,41 +3660,62 @@ decode_offline_els(__TopXMLNS, __IgnoreEls, [], Items, decode_offline_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"purge">>, _attrs, _} = _el | _els], Items, Purge, Fetch) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items, - decode_offline_purge(__TopXMLNS, __IgnoreEls, - _el), - Fetch); - true -> - decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items, - Purge, Fetch) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/offline">> -> + decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items, + decode_offline_purge(__TopXMLNS, __IgnoreEls, _el), + Fetch); + <<"http://jabber.org/protocol/offline">> -> + decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items, + decode_offline_purge(<<"http://jabber.org/protocol/offline">>, + __IgnoreEls, _el), + Fetch); + _ -> + decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items, + Purge, Fetch) end; decode_offline_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"fetch">>, _attrs, _} = _el | _els], Items, Purge, Fetch) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items, - Purge, - decode_offline_fetch(__TopXMLNS, __IgnoreEls, - _el)); - true -> - decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items, - Purge, Fetch) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/offline">> -> + decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items, + Purge, + decode_offline_fetch(__TopXMLNS, __IgnoreEls, + _el)); + <<"http://jabber.org/protocol/offline">> -> + decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items, + Purge, + decode_offline_fetch(<<"http://jabber.org/protocol/offline">>, + __IgnoreEls, _el)); + _ -> + decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items, + Purge, Fetch) end; decode_offline_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items, Purge, Fetch) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_offline_els(__TopXMLNS, __IgnoreEls, _els, - [decode_offline_item(__TopXMLNS, __IgnoreEls, _el) - | Items], - Purge, Fetch); - true -> - decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items, - Purge, Fetch) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/offline">> -> + decode_offline_els(__TopXMLNS, __IgnoreEls, _els, + [decode_offline_item(__TopXMLNS, __IgnoreEls, _el) + | Items], + Purge, Fetch); + <<"http://jabber.org/protocol/offline">> -> + decode_offline_els(__TopXMLNS, __IgnoreEls, _els, + [decode_offline_item(<<"http://jabber.org/protocol/offline">>, + __IgnoreEls, _el) + | Items], + Purge, Fetch); + _ -> + decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items, + Purge, Fetch) end; decode_offline_els(__TopXMLNS, __IgnoreEls, [_ | _els], Items, Purge, Fetch) -> @@ -2973,311 +3832,289 @@ decode_sm_failed_els(__TopXMLNS, __IgnoreEls, [], decode_sm_failed_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"bad-request">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_bad_request(_xmlns, __IgnoreEls, - _el)); - true -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + decode_error_bad_request(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + Reason) end; decode_sm_failed_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"conflict">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_conflict(_xmlns, __IgnoreEls, - _el)); - true -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + decode_error_conflict(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + Reason) end; decode_sm_failed_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"feature-not-implemented">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_feature_not_implemented(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + decode_error_feature_not_implemented(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, + _el)); + _ -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + Reason) end; decode_sm_failed_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"forbidden">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_forbidden(_xmlns, __IgnoreEls, - _el)); - true -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + decode_error_forbidden(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + Reason) end; decode_sm_failed_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"gone">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_gone(_xmlns, __IgnoreEls, _el)); - true -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + decode_error_gone(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + Reason) end; decode_sm_failed_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"internal-server-error">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_internal_server_error(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + decode_error_internal_server_error(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, + _el)); + _ -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + Reason) end; decode_sm_failed_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"item-not-found">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_item_not_found(_xmlns, __IgnoreEls, - _el)); - true -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + decode_error_item_not_found(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + Reason) end; decode_sm_failed_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"jid-malformed">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_jid_malformed(_xmlns, __IgnoreEls, - _el)); - true -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + decode_error_jid_malformed(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + Reason) end; decode_sm_failed_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"not-acceptable">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_not_acceptable(_xmlns, __IgnoreEls, - _el)); - true -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + decode_error_not_acceptable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + Reason) end; decode_sm_failed_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"not-allowed">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_not_allowed(_xmlns, __IgnoreEls, - _el)); - true -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + decode_error_not_allowed(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + Reason) end; decode_sm_failed_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"not-authorized">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_not_authorized(_xmlns, __IgnoreEls, - _el)); - true -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + decode_error_not_authorized(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + Reason) end; decode_sm_failed_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"policy-violation">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_policy_violation(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + decode_error_policy_violation(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + Reason) end; decode_sm_failed_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"recipient-unavailable">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_recipient_unavailable(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + decode_error_recipient_unavailable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, + _el)); + _ -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + Reason) end; decode_sm_failed_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"redirect">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_redirect(_xmlns, __IgnoreEls, - _el)); - true -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + decode_error_redirect(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + Reason) end; decode_sm_failed_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"registration-required">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_registration_required(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + decode_error_registration_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, + _el)); + _ -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + Reason) end; decode_sm_failed_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"remote-server-not-found">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_remote_server_not_found(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + decode_error_remote_server_not_found(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, + _el)); + _ -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + Reason) end; decode_sm_failed_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"remote-server-timeout">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_remote_server_timeout(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + decode_error_remote_server_timeout(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, + _el)); + _ -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + Reason) end; decode_sm_failed_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"resource-constraint">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_resource_constraint(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + decode_error_resource_constraint(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, + _el)); + _ -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + Reason) end; decode_sm_failed_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"service-unavailable">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_service_unavailable(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + decode_error_service_unavailable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, + _el)); + _ -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + Reason) end; decode_sm_failed_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"subscription-required">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_subscription_required(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + decode_error_subscription_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, + _el)); + _ -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + Reason) end; decode_sm_failed_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"undefined-condition">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_undefined_condition(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + decode_error_undefined_condition(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, + _el)); + _ -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + Reason) end; decode_sm_failed_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"unexpected-request">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_unexpected_request(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + decode_error_unexpected_request(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, + _el)); + _ -> + decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, + Reason) end; decode_sm_failed_els(__TopXMLNS, __IgnoreEls, [_ | _els], Reason) -> @@ -3963,15 +4800,15 @@ decode_carbons_sent_els(__TopXMLNS, __IgnoreEls, [], decode_carbons_sent_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"forwarded">>, _attrs, _} = _el | _els], Forwarded) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<"urn:xmpp:forward:0">> -> - decode_carbons_sent_els(__TopXMLNS, __IgnoreEls, _els, - {value, - decode_forwarded(_xmlns, __IgnoreEls, - _el)}); - true -> - decode_carbons_sent_els(__TopXMLNS, __IgnoreEls, _els, - Forwarded) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:xmpp:forward:0">> -> + decode_carbons_sent_els(__TopXMLNS, __IgnoreEls, _els, + {value, + decode_forwarded(<<"urn:xmpp:forward:0">>, + __IgnoreEls, _el)}); + _ -> + decode_carbons_sent_els(__TopXMLNS, __IgnoreEls, _els, + Forwarded) end; decode_carbons_sent_els(__TopXMLNS, __IgnoreEls, [_ | _els], Forwarded) -> @@ -4008,16 +4845,16 @@ decode_carbons_received_els(__TopXMLNS, __IgnoreEls, [], decode_carbons_received_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"forwarded">>, _attrs, _} = _el | _els], Forwarded) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<"urn:xmpp:forward:0">> -> - decode_carbons_received_els(__TopXMLNS, __IgnoreEls, - _els, - {value, - decode_forwarded(_xmlns, __IgnoreEls, - _el)}); - true -> - decode_carbons_received_els(__TopXMLNS, __IgnoreEls, - _els, Forwarded) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:xmpp:forward:0">> -> + decode_carbons_received_els(__TopXMLNS, __IgnoreEls, + _els, + {value, + decode_forwarded(<<"urn:xmpp:forward:0">>, + __IgnoreEls, _el)}); + _ -> + decode_carbons_received_els(__TopXMLNS, __IgnoreEls, + _els, Forwarded) end; decode_carbons_received_els(__TopXMLNS, __IgnoreEls, [_ | _els], Forwarded) -> @@ -4078,13 +4915,15 @@ decode_forwarded_els(__TopXMLNS, __IgnoreEls, [], Delay, decode_forwarded_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"delay">>, _attrs, _} = _el | _els], Delay, __Els) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<"urn:xmpp:delay">> -> - decode_forwarded_els(__TopXMLNS, __IgnoreEls, _els, - decode_delay(_xmlns, __IgnoreEls, _el), __Els); - true -> - decode_forwarded_els(__TopXMLNS, __IgnoreEls, _els, - Delay, __Els) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:xmpp:delay">> -> + decode_forwarded_els(__TopXMLNS, __IgnoreEls, _els, + decode_delay(<<"urn:xmpp:delay">>, __IgnoreEls, + _el), + __Els); + _ -> + decode_forwarded_els(__TopXMLNS, __IgnoreEls, _els, + Delay, __Els) end; decode_forwarded_els(__TopXMLNS, __IgnoreEls, [{xmlel, _, _, _} = _el | _els], Delay, __Els) -> @@ -4132,12 +4971,13 @@ decode_mam_fin_els(__TopXMLNS, __IgnoreEls, [], Rsm) -> Rsm; decode_mam_fin_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"set">>, _attrs, _} = _el | _els], Rsm) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<"http://jabber.org/protocol/rsm">> -> - decode_mam_fin_els(__TopXMLNS, __IgnoreEls, _els, - decode_rsm_set(_xmlns, __IgnoreEls, _el)); - true -> - decode_mam_fin_els(__TopXMLNS, __IgnoreEls, _els, Rsm) + case get_attr(<<"xmlns">>, _attrs) of + <<"http://jabber.org/protocol/rsm">> -> + decode_mam_fin_els(__TopXMLNS, __IgnoreEls, _els, + decode_rsm_set(<<"http://jabber.org/protocol/rsm">>, + __IgnoreEls, _el)); + _ -> + decode_mam_fin_els(__TopXMLNS, __IgnoreEls, _els, Rsm) end; decode_mam_fin_els(__TopXMLNS, __IgnoreEls, [_ | _els], Rsm) -> @@ -4234,27 +5074,36 @@ decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, [], Never, decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"always">>, _attrs, _} = _el | _els], Never, Always) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, - Never, - decode_mam_always(__TopXMLNS, __IgnoreEls, - _el)); - true -> - decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, - Never, Always) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> + decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, + Never, + decode_mam_always(__TopXMLNS, __IgnoreEls, _el)); + <<"urn:xmpp:mam:tmp">> -> + decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, + Never, + decode_mam_always(<<"urn:xmpp:mam:tmp">>, + __IgnoreEls, _el)); + _ -> + decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, + Never, Always) end; decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"never">>, _attrs, _} = _el | _els], Never, Always) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, - decode_mam_never(__TopXMLNS, __IgnoreEls, _el), - Always); - true -> - decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, - Never, Always) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> + decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, + decode_mam_never(__TopXMLNS, __IgnoreEls, _el), + Always); + <<"urn:xmpp:mam:tmp">> -> + decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, + decode_mam_never(<<"urn:xmpp:mam:tmp">>, + __IgnoreEls, _el), + Always); + _ -> + decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, + Never, Always) end; decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, [_ | _els], Never, Always) -> @@ -4290,15 +5139,11 @@ encode_mam_prefs({mam_prefs, Xmlns, Default, Always, 'encode_mam_prefs_$never'([], _acc) -> _acc; 'encode_mam_prefs_$never'(Never, _acc) -> - [encode_mam_never(Never, - [{<<"xmlns">>, <<"urn:xmpp:mam:tmp">>}]) - | _acc]. + [encode_mam_never(Never, []) | _acc]. 'encode_mam_prefs_$always'([], _acc) -> _acc; 'encode_mam_prefs_$always'(Always, _acc) -> - [encode_mam_always(Always, - [{<<"xmlns">>, <<"urn:xmpp:mam:tmp">>}]) - | _acc]. + [encode_mam_always(Always, []) | _acc]. decode_mam_prefs_attr_default(__TopXMLNS, undefined) -> undefined; @@ -4334,18 +5179,26 @@ decode_mam_always_els(__TopXMLNS, __IgnoreEls, [], lists:reverse(Jids); decode_mam_always_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"jid">>, _attrs, _} = _el | _els], Jids) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_mam_always_els(__TopXMLNS, __IgnoreEls, _els, - case decode_mam_jid(__TopXMLNS, __IgnoreEls, - _el) - of - [] -> Jids; - _new_el -> [_new_el | Jids] - end); - true -> - decode_mam_always_els(__TopXMLNS, __IgnoreEls, _els, - Jids) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> + decode_mam_always_els(__TopXMLNS, __IgnoreEls, _els, + case decode_mam_jid(__TopXMLNS, __IgnoreEls, + _el) + of + [] -> Jids; + _new_el -> [_new_el | Jids] + end); + <<"urn:xmpp:mam:tmp">> -> + decode_mam_always_els(__TopXMLNS, __IgnoreEls, _els, + case decode_mam_jid(<<"urn:xmpp:mam:tmp">>, + __IgnoreEls, _el) + of + [] -> Jids; + _new_el -> [_new_el | Jids] + end); + _ -> + decode_mam_always_els(__TopXMLNS, __IgnoreEls, _els, + Jids) end; decode_mam_always_els(__TopXMLNS, __IgnoreEls, [_ | _els], Jids) -> @@ -4374,18 +5227,25 @@ decode_mam_never_els(__TopXMLNS, __IgnoreEls, [], lists:reverse(Jids); decode_mam_never_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"jid">>, _attrs, _} = _el | _els], Jids) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_mam_never_els(__TopXMLNS, __IgnoreEls, _els, - case decode_mam_jid(__TopXMLNS, __IgnoreEls, - _el) - of - [] -> Jids; - _new_el -> [_new_el | Jids] - end); - true -> - decode_mam_never_els(__TopXMLNS, __IgnoreEls, _els, - Jids) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> + decode_mam_never_els(__TopXMLNS, __IgnoreEls, _els, + case decode_mam_jid(__TopXMLNS, __IgnoreEls, _el) + of + [] -> Jids; + _new_el -> [_new_el | Jids] + end); + <<"urn:xmpp:mam:tmp">> -> + decode_mam_never_els(__TopXMLNS, __IgnoreEls, _els, + case decode_mam_jid(<<"urn:xmpp:mam:tmp">>, + __IgnoreEls, _el) + of + [] -> Jids; + _new_el -> [_new_el | Jids] + end); + _ -> + decode_mam_never_els(__TopXMLNS, __IgnoreEls, _els, + Jids) end; decode_mam_never_els(__TopXMLNS, __IgnoreEls, [_ | _els], Jids) -> @@ -4596,65 +5456,85 @@ decode_mam_query_els(__TopXMLNS, __IgnoreEls, [], Xdata, decode_mam_query_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"start">>, _attrs, _} = _el | _els], Xdata, End, Start, With, Rsm) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, End, - decode_mam_start(__TopXMLNS, __IgnoreEls, _el), - With, Rsm); - true -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, End, Start, With, Rsm) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> + decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, End, + decode_mam_start(__TopXMLNS, __IgnoreEls, _el), + With, Rsm); + <<"urn:xmpp:mam:tmp">> -> + decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, End, + decode_mam_start(<<"urn:xmpp:mam:tmp">>, + __IgnoreEls, _el), + With, Rsm); + _ -> + decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, End, Start, With, Rsm) end; decode_mam_query_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"end">>, _attrs, _} = _el | _els], Xdata, End, Start, With, Rsm) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, - decode_mam_end(__TopXMLNS, __IgnoreEls, _el), - Start, With, Rsm); - true -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, End, Start, With, Rsm) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> + decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, + decode_mam_end(__TopXMLNS, __IgnoreEls, _el), + Start, With, Rsm); + <<"urn:xmpp:mam:tmp">> -> + decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, + decode_mam_end(<<"urn:xmpp:mam:tmp">>, + __IgnoreEls, _el), + Start, With, Rsm); + _ -> + decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, End, Start, With, Rsm) end; decode_mam_query_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"with">>, _attrs, _} = _el | _els], Xdata, End, Start, With, Rsm) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, End, Start, - decode_mam_with(__TopXMLNS, __IgnoreEls, _el), - Rsm); - true -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, End, Start, With, Rsm) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> + decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, End, Start, + decode_mam_with(__TopXMLNS, __IgnoreEls, _el), + Rsm); + <<"urn:xmpp:mam:tmp">> -> + decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, End, Start, + decode_mam_with(<<"urn:xmpp:mam:tmp">>, + __IgnoreEls, _el), + Rsm); + _ -> + decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, End, Start, With, Rsm) end; decode_mam_query_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"set">>, _attrs, _} = _el | _els], Xdata, End, Start, With, Rsm) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<"http://jabber.org/protocol/rsm">> -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, End, Start, With, - decode_rsm_set(_xmlns, __IgnoreEls, _el)); - true -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, End, Start, With, Rsm) + case get_attr(<<"xmlns">>, _attrs) of + <<"http://jabber.org/protocol/rsm">> -> + decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, End, Start, With, + decode_rsm_set(<<"http://jabber.org/protocol/rsm">>, + __IgnoreEls, _el)); + _ -> + decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, End, Start, With, Rsm) end; decode_mam_query_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"x">>, _attrs, _} = _el | _els], Xdata, End, Start, With, Rsm) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<"jabber:x:data">> -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - decode_xdata(_xmlns, __IgnoreEls, _el), End, - Start, With, Rsm); - true -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, End, Start, With, Rsm) + case get_attr(<<"xmlns">>, _attrs) of + <<"jabber:x:data">> -> + decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, + decode_xdata(<<"jabber:x:data">>, __IgnoreEls, + _el), + End, Start, With, Rsm); + _ -> + decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, End, Start, With, Rsm) end; decode_mam_query_els(__TopXMLNS, __IgnoreEls, [_ | _els], Xdata, End, Start, With, Rsm) -> @@ -4696,21 +5576,15 @@ encode_mam_query({mam_query, Xmlns, Id, Start, End, 'encode_mam_query_$end'(undefined, _acc) -> _acc; 'encode_mam_query_$end'(End, _acc) -> - [encode_mam_end(End, - [{<<"xmlns">>, <<"urn:xmpp:mam:tmp">>}]) - | _acc]. + [encode_mam_end(End, []) | _acc]. 'encode_mam_query_$start'(undefined, _acc) -> _acc; 'encode_mam_query_$start'(Start, _acc) -> - [encode_mam_start(Start, - [{<<"xmlns">>, <<"urn:xmpp:mam:tmp">>}]) - | _acc]. + [encode_mam_start(Start, []) | _acc]. 'encode_mam_query_$with'(undefined, _acc) -> _acc; 'encode_mam_query_$with'(With, _acc) -> - [encode_mam_with(With, - [{<<"xmlns">>, <<"urn:xmpp:mam:tmp">>}]) - | _acc]. + [encode_mam_with(With, []) | _acc]. 'encode_mam_query_$rsm'(undefined, _acc) -> _acc; 'encode_mam_query_$rsm'(Rsm, _acc) -> @@ -4860,90 +5734,143 @@ decode_rsm_set_els(__TopXMLNS, __IgnoreEls, [], After, decode_rsm_set_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"after">>, _attrs, _} = _el | _els], After, Last, First, Count, Before, Max, Index) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, - decode_rsm_after(__TopXMLNS, __IgnoreEls, _el), - Last, First, Count, Before, Max, Index); - true -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, Count, Before, Max, Index) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/rsm">> -> + decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, + decode_rsm_after(__TopXMLNS, __IgnoreEls, _el), + Last, First, Count, Before, Max, Index); + <<"http://jabber.org/protocol/rsm">> -> + decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, + decode_rsm_after(<<"http://jabber.org/protocol/rsm">>, + __IgnoreEls, _el), + Last, First, Count, Before, Max, Index); + _ -> + decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, + Last, First, Count, Before, Max, Index) end; decode_rsm_set_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"before">>, _attrs, _} = _el | _els], After, Last, First, Count, Before, Max, Index) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, Count, - decode_rsm_before(__TopXMLNS, __IgnoreEls, _el), - Max, Index); - true -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, Count, Before, Max, Index) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/rsm">> -> + decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, + Last, First, Count, + decode_rsm_before(__TopXMLNS, __IgnoreEls, _el), + Max, Index); + <<"http://jabber.org/protocol/rsm">> -> + decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, + Last, First, Count, + decode_rsm_before(<<"http://jabber.org/protocol/rsm">>, + __IgnoreEls, _el), + Max, Index); + _ -> + decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, + Last, First, Count, Before, Max, Index) end; decode_rsm_set_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"count">>, _attrs, _} = _el | _els], After, Last, First, Count, Before, Max, Index) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, - decode_rsm_count(__TopXMLNS, __IgnoreEls, _el), - Before, Max, Index); - true -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, Count, Before, Max, Index) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/rsm">> -> + decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, + Last, First, + decode_rsm_count(__TopXMLNS, __IgnoreEls, _el), + Before, Max, Index); + <<"http://jabber.org/protocol/rsm">> -> + decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, + Last, First, + decode_rsm_count(<<"http://jabber.org/protocol/rsm">>, + __IgnoreEls, _el), + Before, Max, Index); + _ -> + decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, + Last, First, Count, Before, Max, Index) end; decode_rsm_set_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"first">>, _attrs, _} = _el | _els], After, Last, First, Count, Before, Max, Index) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, - decode_rsm_first(__TopXMLNS, __IgnoreEls, _el), - Count, Before, Max, Index); - true -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, Count, Before, Max, Index) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/rsm">> -> + decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, + Last, + decode_rsm_first(__TopXMLNS, __IgnoreEls, _el), + Count, Before, Max, Index); + <<"http://jabber.org/protocol/rsm">> -> + decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, + Last, + decode_rsm_first(<<"http://jabber.org/protocol/rsm">>, + __IgnoreEls, _el), + Count, Before, Max, Index); + _ -> + decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, + Last, First, Count, Before, Max, Index) end; decode_rsm_set_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"index">>, _attrs, _} = _el | _els], After, Last, First, Count, Before, Max, Index) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, Count, Before, Max, - decode_rsm_index(__TopXMLNS, __IgnoreEls, _el)); - true -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, Count, Before, Max, Index) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/rsm">> -> + decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, + Last, First, Count, Before, Max, + decode_rsm_index(__TopXMLNS, __IgnoreEls, _el)); + <<"http://jabber.org/protocol/rsm">> -> + decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, + Last, First, Count, Before, Max, + decode_rsm_index(<<"http://jabber.org/protocol/rsm">>, + __IgnoreEls, _el)); + _ -> + decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, + Last, First, Count, Before, Max, Index) end; decode_rsm_set_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"last">>, _attrs, _} = _el | _els], After, Last, First, Count, Before, Max, Index) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - decode_rsm_last(__TopXMLNS, __IgnoreEls, _el), - First, Count, Before, Max, Index); - true -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, Count, Before, Max, Index) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/rsm">> -> + decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, + decode_rsm_last(__TopXMLNS, __IgnoreEls, _el), + First, Count, Before, Max, Index); + <<"http://jabber.org/protocol/rsm">> -> + decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, + decode_rsm_last(<<"http://jabber.org/protocol/rsm">>, + __IgnoreEls, _el), + First, Count, Before, Max, Index); + _ -> + decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, + Last, First, Count, Before, Max, Index) end; decode_rsm_set_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"max">>, _attrs, _} = _el | _els], After, Last, First, Count, Before, Max, Index) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, Count, Before, - decode_rsm_max(__TopXMLNS, __IgnoreEls, _el), - Index); - true -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, Count, Before, Max, Index) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/rsm">> -> + decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, + Last, First, Count, Before, + decode_rsm_max(__TopXMLNS, __IgnoreEls, _el), + Index); + <<"http://jabber.org/protocol/rsm">> -> + decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, + Last, First, Count, Before, + decode_rsm_max(<<"http://jabber.org/protocol/rsm">>, + __IgnoreEls, _el), + Index); + _ -> + decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, + Last, First, Count, Before, Max, Index) end; decode_rsm_set_els(__TopXMLNS, __IgnoreEls, [_ | _els], After, Last, First, Count, Before, Max, Index) -> @@ -5261,12 +6188,18 @@ decode_muc_els(__TopXMLNS, __IgnoreEls, [], History) -> decode_muc_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"history">>, _attrs, _} = _el | _els], History) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_muc_els(__TopXMLNS, __IgnoreEls, _els, - decode_muc_history(__TopXMLNS, __IgnoreEls, _el)); - true -> - decode_muc_els(__TopXMLNS, __IgnoreEls, _els, History) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/muc">> -> + decode_muc_els(__TopXMLNS, __IgnoreEls, _els, + decode_muc_history(__TopXMLNS, __IgnoreEls, _el)); + <<"http://jabber.org/protocol/muc">> -> + decode_muc_els(__TopXMLNS, __IgnoreEls, _els, + decode_muc_history(<<"http://jabber.org/protocol/muc">>, + __IgnoreEls, _el)); + _ -> + decode_muc_els(__TopXMLNS, __IgnoreEls, _els, History) end; decode_muc_els(__TopXMLNS, __IgnoreEls, [_ | _els], History) -> @@ -5310,15 +6243,22 @@ decode_muc_admin_els(__TopXMLNS, __IgnoreEls, [], lists:reverse(Items); decode_muc_admin_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_muc_admin_els(__TopXMLNS, __IgnoreEls, _els, - [decode_muc_admin_item(__TopXMLNS, __IgnoreEls, - _el) - | Items]); - true -> - decode_muc_admin_els(__TopXMLNS, __IgnoreEls, _els, - Items) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/muc#admin">> -> + decode_muc_admin_els(__TopXMLNS, __IgnoreEls, _els, + [decode_muc_admin_item(__TopXMLNS, __IgnoreEls, + _el) + | Items]); + <<"http://jabber.org/protocol/muc#admin">> -> + decode_muc_admin_els(__TopXMLNS, __IgnoreEls, _els, + [decode_muc_admin_item(<<"http://jabber.org/protocol/muc#admin">>, + __IgnoreEls, _el) + | Items]); + _ -> + decode_muc_admin_els(__TopXMLNS, __IgnoreEls, _els, + Items) end; decode_muc_admin_els(__TopXMLNS, __IgnoreEls, [_ | _els], Items) -> @@ -5480,43 +6420,64 @@ decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, [], decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"actor">>, _attrs, _} = _el | _els], Actor, Continue, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, - decode_muc_admin_actor(__TopXMLNS, - __IgnoreEls, _el), - Continue, Reason); - true -> - decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/muc#admin">> -> + decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, + decode_muc_admin_actor(__TopXMLNS, + __IgnoreEls, _el), + Continue, Reason); + <<"http://jabber.org/protocol/muc#admin">> -> + decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, + decode_muc_admin_actor(<<"http://jabber.org/protocol/muc#admin">>, + __IgnoreEls, _el), + Continue, Reason); + _ -> + decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, Continue, Reason) end; decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"continue">>, _attrs, _} = _el | _els], Actor, Continue, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, - decode_muc_admin_continue(__TopXMLNS, - __IgnoreEls, - _el), - Reason); - true -> - decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/muc#admin">> -> + decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, + decode_muc_admin_continue(__TopXMLNS, + __IgnoreEls, _el), + Reason); + <<"http://jabber.org/protocol/muc#admin">> -> + decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, + decode_muc_admin_continue(<<"http://jabber.org/protocol/muc#admin">>, + __IgnoreEls, _el), + Reason); + _ -> + decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, Continue, Reason) end; decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"reason">>, _attrs, _} = _el | _els], Actor, Continue, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, - decode_muc_admin_reason(__TopXMLNS, - __IgnoreEls, _el)); - true -> - decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/muc#admin">> -> + decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, Continue, + decode_muc_admin_reason(__TopXMLNS, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/muc#admin">> -> + decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, Continue, + decode_muc_admin_reason(<<"http://jabber.org/protocol/muc#admin">>, + __IgnoreEls, _el)); + _ -> + decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, Continue, Reason) end; decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, [_ | _els], Actor, Continue, Reason) -> @@ -5661,27 +6622,35 @@ decode_muc_owner_els(__TopXMLNS, __IgnoreEls, [], decode_muc_owner_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"destroy">>, _attrs, _} = _el | _els], Config, Destroy) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, - Config, - decode_muc_owner_destroy(__TopXMLNS, - __IgnoreEls, _el)); - true -> - decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, - Config, Destroy) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/muc#owner">> -> + decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, + Config, + decode_muc_owner_destroy(__TopXMLNS, __IgnoreEls, + _el)); + <<"http://jabber.org/protocol/muc#owner">> -> + decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, + Config, + decode_muc_owner_destroy(<<"http://jabber.org/protocol/muc#owner">>, + __IgnoreEls, _el)); + _ -> + decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, + Config, Destroy) end; decode_muc_owner_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"x">>, _attrs, _} = _el | _els], Config, Destroy) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<"jabber:x:data">> -> - decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, - decode_xdata(_xmlns, __IgnoreEls, _el), - Destroy); - true -> - decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, - Config, Destroy) + case get_attr(<<"xmlns">>, _attrs) of + <<"jabber:x:data">> -> + decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, + decode_xdata(<<"jabber:x:data">>, __IgnoreEls, + _el), + Destroy); + _ -> + decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, + Config, Destroy) end; decode_muc_owner_els(__TopXMLNS, __IgnoreEls, [_ | _els], Config, Destroy) -> @@ -5721,31 +6690,48 @@ decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"password">>, _attrs, _} = _el | _els], Password, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, - _els, - decode_muc_owner_password(__TopXMLNS, - __IgnoreEls, - _el), - Reason); - true -> - decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, - _els, Password, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/muc#owner">> -> + decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, + _els, + decode_muc_owner_password(__TopXMLNS, + __IgnoreEls, + _el), + Reason); + <<"http://jabber.org/protocol/muc#owner">> -> + decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, + _els, + decode_muc_owner_password(<<"http://jabber.org/protocol/muc#owner">>, + __IgnoreEls, + _el), + Reason); + _ -> + decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, + _els, Password, Reason) end; decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"reason">>, _attrs, _} = _el | _els], Password, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, - _els, Password, - decode_muc_owner_reason(__TopXMLNS, - __IgnoreEls, - _el)); - true -> - decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, - _els, Password, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/muc#owner">> -> + decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, + _els, Password, + decode_muc_owner_reason(__TopXMLNS, + __IgnoreEls, + _el)); + <<"http://jabber.org/protocol/muc#owner">> -> + decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, + _els, Password, + decode_muc_owner_reason(<<"http://jabber.org/protocol/muc#owner">>, + __IgnoreEls, + _el)); + _ -> + decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, + _els, Password, Reason) end; decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, [_ | _els], Password, Reason) -> @@ -5881,76 +6867,121 @@ decode_muc_user_els(__TopXMLNS, __IgnoreEls, [], decode_muc_user_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"decline">>, _attrs, _} = _el | _els], Status_codes, Items, Invites, Decline, Destroy) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, - decode_muc_user_decline(__TopXMLNS, __IgnoreEls, - _el), - Destroy); - true -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Decline, Destroy) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, + Status_codes, Items, Invites, + decode_muc_user_decline(__TopXMLNS, __IgnoreEls, + _el), + Destroy); + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, + Status_codes, Items, Invites, + decode_muc_user_decline(<<"http://jabber.org/protocol/muc#user">>, + __IgnoreEls, _el), + Destroy); + _ -> + decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, + Status_codes, Items, Invites, Decline, Destroy) end; decode_muc_user_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"destroy">>, _attrs, _} = _el | _els], Status_codes, Items, Invites, Decline, Destroy) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Decline, - decode_muc_user_destroy(__TopXMLNS, __IgnoreEls, - _el)); - true -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Decline, Destroy) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, + Status_codes, Items, Invites, Decline, + decode_muc_user_destroy(__TopXMLNS, __IgnoreEls, + _el)); + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, + Status_codes, Items, Invites, Decline, + decode_muc_user_destroy(<<"http://jabber.org/protocol/muc#user">>, + __IgnoreEls, _el)); + _ -> + decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, + Status_codes, Items, Invites, Decline, Destroy) end; decode_muc_user_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"invite">>, _attrs, _} = _el | _els], Status_codes, Items, Invites, Decline, Destroy) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, - [decode_muc_user_invite(__TopXMLNS, __IgnoreEls, - _el) - | Invites], - Decline, Destroy); - true -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Decline, Destroy) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, + Status_codes, Items, + [decode_muc_user_invite(__TopXMLNS, __IgnoreEls, + _el) + | Invites], + Decline, Destroy); + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, + Status_codes, Items, + [decode_muc_user_invite(<<"http://jabber.org/protocol/muc#user">>, + __IgnoreEls, _el) + | Invites], + Decline, Destroy); + _ -> + decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, + Status_codes, Items, Invites, Decline, Destroy) end; decode_muc_user_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"item">>, _attrs, _} = _el | _els], Status_codes, Items, Invites, Decline, Destroy) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, - [decode_muc_user_item(__TopXMLNS, __IgnoreEls, - _el) - | Items], - Invites, Decline, Destroy); - true -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Decline, Destroy) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, + Status_codes, + [decode_muc_user_item(__TopXMLNS, __IgnoreEls, + _el) + | Items], + Invites, Decline, Destroy); + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, + Status_codes, + [decode_muc_user_item(<<"http://jabber.org/protocol/muc#user">>, + __IgnoreEls, _el) + | Items], + Invites, Decline, Destroy); + _ -> + decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, + Status_codes, Items, Invites, Decline, Destroy) end; decode_muc_user_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"status">>, _attrs, _} = _el | _els], Status_codes, Items, Invites, Decline, Destroy) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - case decode_muc_user_status(__TopXMLNS, - __IgnoreEls, _el) - of - undefined -> Status_codes; - _new_el -> [_new_el | Status_codes] - end, - Items, Invites, Decline, Destroy); - true -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Decline, Destroy) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, + case decode_muc_user_status(__TopXMLNS, + __IgnoreEls, _el) + of + undefined -> Status_codes; + _new_el -> [_new_el | Status_codes] + end, + Items, Invites, Decline, Destroy); + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, + case + decode_muc_user_status(<<"http://jabber.org/protocol/muc#user">>, + __IgnoreEls, _el) + of + undefined -> Status_codes; + _new_el -> [_new_el | Status_codes] + end, + Items, Invites, Decline, Destroy); + _ -> + decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, + Status_codes, Items, Invites, Decline, Destroy) end; decode_muc_user_els(__TopXMLNS, __IgnoreEls, [_ | _els], Status_codes, Items, Invites, Decline, Destroy) -> @@ -6030,42 +7061,64 @@ decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, [], decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"actor">>, _attrs, _} = _el | _els], Actor, Continue, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, - decode_muc_user_actor(__TopXMLNS, - __IgnoreEls, _el), - Continue, Reason); - true -> - decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, + decode_muc_user_actor(__TopXMLNS, + __IgnoreEls, _el), + Continue, Reason); + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, + decode_muc_user_actor(<<"http://jabber.org/protocol/muc#user">>, + __IgnoreEls, _el), + Continue, Reason); + _ -> + decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, Continue, Reason) end; decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"continue">>, _attrs, _} = _el | _els], Actor, Continue, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, - decode_muc_user_continue(__TopXMLNS, - __IgnoreEls, _el), - Reason); - true -> - decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, + decode_muc_user_continue(__TopXMLNS, + __IgnoreEls, _el), + Reason); + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, + decode_muc_user_continue(<<"http://jabber.org/protocol/muc#user">>, + __IgnoreEls, _el), + Reason); + _ -> + decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, Continue, Reason) end; decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"reason">>, _attrs, _} = _el | _els], Actor, Continue, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, - decode_muc_user_reason(__TopXMLNS, - __IgnoreEls, _el)); - true -> - decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, Continue, + decode_muc_user_reason(__TopXMLNS, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, Continue, + decode_muc_user_reason(<<"http://jabber.org/protocol/muc#user">>, + __IgnoreEls, _el)); + _ -> + decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, Continue, Reason) end; decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, [_ | _els], Actor, Continue, Reason) -> @@ -6337,15 +7390,22 @@ decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, [], decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"reason">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, - _els, - decode_muc_user_reason(__TopXMLNS, - __IgnoreEls, _el)); - true -> - decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, - _els, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, + _els, + decode_muc_user_reason(__TopXMLNS, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, + _els, + decode_muc_user_reason(<<"http://jabber.org/protocol/muc#user">>, + __IgnoreEls, _el)); + _ -> + decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, + _els, Reason) end; decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, [_ | _els], Reason) -> @@ -6429,16 +7489,22 @@ decode_muc_user_destroy_els(__TopXMLNS, __IgnoreEls, [], decode_muc_user_destroy_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"reason">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_muc_user_destroy_els(__TopXMLNS, __IgnoreEls, - _els, - decode_muc_user_reason(__TopXMLNS, - __IgnoreEls, - _el)); - true -> - decode_muc_user_destroy_els(__TopXMLNS, __IgnoreEls, - _els, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_destroy_els(__TopXMLNS, __IgnoreEls, + _els, + decode_muc_user_reason(__TopXMLNS, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_destroy_els(__TopXMLNS, __IgnoreEls, + _els, + decode_muc_user_reason(<<"http://jabber.org/protocol/muc#user">>, + __IgnoreEls, _el)); + _ -> + decode_muc_user_destroy_els(__TopXMLNS, __IgnoreEls, + _els, Reason) end; decode_muc_user_destroy_els(__TopXMLNS, __IgnoreEls, [_ | _els], Reason) -> @@ -6499,16 +7565,22 @@ decode_muc_user_decline_els(__TopXMLNS, __IgnoreEls, [], decode_muc_user_decline_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"reason">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_muc_user_decline_els(__TopXMLNS, __IgnoreEls, - _els, - decode_muc_user_reason(__TopXMLNS, - __IgnoreEls, - _el)); - true -> - decode_muc_user_decline_els(__TopXMLNS, __IgnoreEls, - _els, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_decline_els(__TopXMLNS, __IgnoreEls, + _els, + decode_muc_user_reason(__TopXMLNS, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_decline_els(__TopXMLNS, __IgnoreEls, + _els, + decode_muc_user_reason(<<"http://jabber.org/protocol/muc#user">>, + __IgnoreEls, _el)); + _ -> + decode_muc_user_decline_els(__TopXMLNS, __IgnoreEls, + _els, Reason) end; decode_muc_user_decline_els(__TopXMLNS, __IgnoreEls, [_ | _els], Reason) -> @@ -6744,47 +7816,71 @@ decode_bytestreams_els(__TopXMLNS, __IgnoreEls, [], decode_bytestreams_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"streamhost">>, _attrs, _} = _el | _els], Hosts, Used, Activate) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, - [decode_bytestreams_streamhost(__TopXMLNS, - __IgnoreEls, - _el) - | Hosts], - Used, Activate); - true -> - decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, - Hosts, Used, Activate) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/bytestreams">> -> + decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, + [decode_bytestreams_streamhost(__TopXMLNS, + __IgnoreEls, + _el) + | Hosts], + Used, Activate); + <<"http://jabber.org/protocol/bytestreams">> -> + decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, + [decode_bytestreams_streamhost(<<"http://jabber.org/protocol/bytestreams">>, + __IgnoreEls, + _el) + | Hosts], + Used, Activate); + _ -> + decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, + Hosts, Used, Activate) end; decode_bytestreams_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"streamhost-used">>, _attrs, _} = _el | _els], Hosts, Used, Activate) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, - Hosts, - decode_bytestreams_streamhost_used(__TopXMLNS, - __IgnoreEls, - _el), - Activate); - true -> - decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, - Hosts, Used, Activate) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/bytestreams">> -> + decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, + Hosts, + decode_bytestreams_streamhost_used(__TopXMLNS, + __IgnoreEls, + _el), + Activate); + <<"http://jabber.org/protocol/bytestreams">> -> + decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, + Hosts, + decode_bytestreams_streamhost_used(<<"http://jabber.org/protocol/bytestreams">>, + __IgnoreEls, + _el), + Activate); + _ -> + decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, + Hosts, Used, Activate) end; decode_bytestreams_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"activate">>, _attrs, _} = _el | _els], Hosts, Used, Activate) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, - Hosts, Used, - decode_bytestreams_activate(__TopXMLNS, - __IgnoreEls, - _el)); - true -> - decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, - Hosts, Used, Activate) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/bytestreams">> -> + decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, + Hosts, Used, + decode_bytestreams_activate(__TopXMLNS, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/bytestreams">> -> + decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, + Hosts, Used, + decode_bytestreams_activate(<<"http://jabber.org/protocol/bytestreams">>, + __IgnoreEls, _el)); + _ -> + decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, + Hosts, Used, Activate) end; decode_bytestreams_els(__TopXMLNS, __IgnoreEls, [_ | _els], Hosts, Used, Activate) -> @@ -7055,9 +8151,21 @@ encode_bytestreams_streamhost_attr_port(_val, _acc) -> decode_delay(__TopXMLNS, __IgnoreEls, {xmlel, <<"delay">>, _attrs, _els}) -> + Desc = decode_delay_els(__TopXMLNS, __IgnoreEls, _els, + <<>>), {Stamp, From} = decode_delay_attrs(__TopXMLNS, _attrs, undefined, undefined), - {delay, Stamp, From}. + {delay, Stamp, From, Desc}. + +decode_delay_els(__TopXMLNS, __IgnoreEls, [], Desc) -> + decode_delay_cdata(__TopXMLNS, Desc); +decode_delay_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Desc) -> + decode_delay_els(__TopXMLNS, __IgnoreEls, _els, + <>); +decode_delay_els(__TopXMLNS, __IgnoreEls, [_ | _els], + Desc) -> + decode_delay_els(__TopXMLNS, __IgnoreEls, _els, Desc). decode_delay_attrs(__TopXMLNS, [{<<"stamp">>, _val} | _attrs], _Stamp, From) -> @@ -7072,8 +8180,9 @@ decode_delay_attrs(__TopXMLNS, [], Stamp, From) -> {decode_delay_attr_stamp(__TopXMLNS, Stamp), decode_delay_attr_from(__TopXMLNS, From)}. -encode_delay({delay, Stamp, From}, _xmlns_attrs) -> - _els = [], +encode_delay({delay, Stamp, From, Desc}, + _xmlns_attrs) -> + _els = encode_delay_cdata(Desc, []), _attrs = encode_delay_attr_from(From, encode_delay_attr_stamp(Stamp, _xmlns_attrs)), @@ -7108,6 +8217,13 @@ encode_delay_attr_from(undefined, _acc) -> _acc; encode_delay_attr_from(_val, _acc) -> [{<<"from">>, enc_jid(_val)} | _acc]. +decode_delay_cdata(__TopXMLNS, <<>>) -> <<>>; +decode_delay_cdata(__TopXMLNS, _val) -> _val. + +encode_delay_cdata(<<>>, _acc) -> _acc; +encode_delay_cdata(_val, _acc) -> + [{xmlcdata, _val} | _acc]. + decode_chatstate_paused(__TopXMLNS, __IgnoreEls, {xmlel, <<"paused">>, _attrs, _els}) -> {chatstate, paused}. @@ -7170,15 +8286,22 @@ decode_shim_headers_els(__TopXMLNS, __IgnoreEls, [], decode_shim_headers_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"header">>, _attrs, _} = _el | _els], Headers) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_shim_headers_els(__TopXMLNS, __IgnoreEls, _els, - [decode_shim_header(__TopXMLNS, __IgnoreEls, - _el) - | Headers]); - true -> - decode_shim_headers_els(__TopXMLNS, __IgnoreEls, _els, - Headers) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/shim">> -> + decode_shim_headers_els(__TopXMLNS, __IgnoreEls, _els, + [decode_shim_header(__TopXMLNS, __IgnoreEls, + _el) + | Headers]); + <<"http://jabber.org/protocol/shim">> -> + decode_shim_headers_els(__TopXMLNS, __IgnoreEls, _els, + [decode_shim_header(<<"http://jabber.org/protocol/shim">>, + __IgnoreEls, _el) + | Headers]); + _ -> + decode_shim_headers_els(__TopXMLNS, __IgnoreEls, _els, + Headers) end; decode_shim_headers_els(__TopXMLNS, __IgnoreEls, [_ | _els], Headers) -> @@ -7267,130 +8390,194 @@ decode_pubsub_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"subscriptions">>, _attrs, _} = _el | _els], Items, Options, Affiliations, Subscriptions, Retract, Unsubscribe, Subscribe, Publish) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, - decode_pubsub_subscriptions(__TopXMLNS, - __IgnoreEls, _el), - Retract, Unsubscribe, Subscribe, Publish); - true -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, + Options, Affiliations, + decode_pubsub_subscriptions(__TopXMLNS, __IgnoreEls, + _el), + Retract, Unsubscribe, Subscribe, Publish); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, + Options, Affiliations, + decode_pubsub_subscriptions(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el), + Retract, Unsubscribe, Subscribe, Publish); + _ -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, + Options, Affiliations, Subscriptions, Retract, + Unsubscribe, Subscribe, Publish) end; decode_pubsub_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"affiliations">>, _attrs, _} = _el | _els], Items, Options, Affiliations, Subscriptions, Retract, Unsubscribe, Subscribe, Publish) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, - decode_pubsub_affiliations(__TopXMLNS, __IgnoreEls, - _el), - Subscriptions, Retract, Unsubscribe, Subscribe, - Publish); - true -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, + Options, + decode_pubsub_affiliations(__TopXMLNS, __IgnoreEls, + _el), + Subscriptions, Retract, Unsubscribe, Subscribe, + Publish); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, + Options, + decode_pubsub_affiliations(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el), + Subscriptions, Retract, Unsubscribe, Subscribe, + Publish); + _ -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, + Options, Affiliations, Subscriptions, Retract, + Unsubscribe, Subscribe, Publish) end; decode_pubsub_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"subscribe">>, _attrs, _} = _el | _els], Items, Options, Affiliations, Subscriptions, Retract, Unsubscribe, Subscribe, Publish) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, - decode_pubsub_subscribe(__TopXMLNS, __IgnoreEls, - _el), - Publish); - true -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, + Options, Affiliations, Subscriptions, Retract, + Unsubscribe, + decode_pubsub_subscribe(__TopXMLNS, __IgnoreEls, + _el), + Publish); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, + Options, Affiliations, Subscriptions, Retract, + Unsubscribe, + decode_pubsub_subscribe(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el), + Publish); + _ -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, + Options, Affiliations, Subscriptions, Retract, + Unsubscribe, Subscribe, Publish) end; decode_pubsub_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"unsubscribe">>, _attrs, _} = _el | _els], Items, Options, Affiliations, Subscriptions, Retract, Unsubscribe, Subscribe, Publish) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, - decode_pubsub_unsubscribe(__TopXMLNS, __IgnoreEls, - _el), - Subscribe, Publish); - true -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, + Options, Affiliations, Subscriptions, Retract, + decode_pubsub_unsubscribe(__TopXMLNS, __IgnoreEls, + _el), + Subscribe, Publish); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, + Options, Affiliations, Subscriptions, Retract, + decode_pubsub_unsubscribe(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el), + Subscribe, Publish); + _ -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, + Options, Affiliations, Subscriptions, Retract, + Unsubscribe, Subscribe, Publish) end; decode_pubsub_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"options">>, _attrs, _} = _el | _els], Items, Options, Affiliations, Subscriptions, Retract, Unsubscribe, Subscribe, Publish) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - decode_pubsub_options(__TopXMLNS, __IgnoreEls, - _el), - Affiliations, Subscriptions, Retract, Unsubscribe, - Subscribe, Publish); - true -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, + decode_pubsub_options(__TopXMLNS, __IgnoreEls, _el), + Affiliations, Subscriptions, Retract, Unsubscribe, + Subscribe, Publish); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, + decode_pubsub_options(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el), + Affiliations, Subscriptions, Retract, Unsubscribe, + Subscribe, Publish); + _ -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, + Options, Affiliations, Subscriptions, Retract, + Unsubscribe, Subscribe, Publish) end; decode_pubsub_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"items">>, _attrs, _} = _el | _els], Items, Options, Affiliations, Subscriptions, Retract, Unsubscribe, Subscribe, Publish) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - decode_pubsub_items(__TopXMLNS, __IgnoreEls, _el), - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish); - true -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + decode_pubsub_items(__TopXMLNS, __IgnoreEls, _el), + Options, Affiliations, Subscriptions, Retract, + Unsubscribe, Subscribe, Publish); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + decode_pubsub_items(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el), + Options, Affiliations, Subscriptions, Retract, + Unsubscribe, Subscribe, Publish); + _ -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, + Options, Affiliations, Subscriptions, Retract, + Unsubscribe, Subscribe, Publish) end; decode_pubsub_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"retract">>, _attrs, _} = _el | _els], Items, Options, Affiliations, Subscriptions, Retract, Unsubscribe, Subscribe, Publish) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, - decode_pubsub_retract(__TopXMLNS, __IgnoreEls, - _el), - Unsubscribe, Subscribe, Publish); - true -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, + Options, Affiliations, Subscriptions, + decode_pubsub_retract(__TopXMLNS, __IgnoreEls, _el), + Unsubscribe, Subscribe, Publish); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, + Options, Affiliations, Subscriptions, + decode_pubsub_retract(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el), + Unsubscribe, Subscribe, Publish); + _ -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, + Options, Affiliations, Subscriptions, Retract, + Unsubscribe, Subscribe, Publish) end; decode_pubsub_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"publish">>, _attrs, _} = _el | _els], Items, Options, Affiliations, Subscriptions, Retract, Unsubscribe, Subscribe, Publish) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, - decode_pubsub_publish(__TopXMLNS, __IgnoreEls, - _el)); - true -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, + Options, Affiliations, Subscriptions, Retract, + Unsubscribe, Subscribe, + decode_pubsub_publish(__TopXMLNS, __IgnoreEls, + _el)); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, + Options, Affiliations, Subscriptions, Retract, + Unsubscribe, Subscribe, + decode_pubsub_publish(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el)); + _ -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, + Options, Affiliations, Subscriptions, Retract, + Unsubscribe, Subscribe, Publish) end; decode_pubsub_els(__TopXMLNS, __IgnoreEls, [_ | _els], Items, Options, Affiliations, Subscriptions, Retract, @@ -7461,15 +8648,22 @@ decode_pubsub_retract_els(__TopXMLNS, __IgnoreEls, [], decode_pubsub_retract_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_pubsub_retract_els(__TopXMLNS, __IgnoreEls, _els, - [decode_pubsub_item(__TopXMLNS, - __IgnoreEls, _el) - | Items]); - true -> - decode_pubsub_retract_els(__TopXMLNS, __IgnoreEls, _els, - Items) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_retract_els(__TopXMLNS, __IgnoreEls, _els, + [decode_pubsub_item(__TopXMLNS, __IgnoreEls, + _el) + | Items]); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_retract_els(__TopXMLNS, __IgnoreEls, _els, + [decode_pubsub_item(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el) + | Items]); + _ -> + decode_pubsub_retract_els(__TopXMLNS, __IgnoreEls, _els, + Items) end; decode_pubsub_retract_els(__TopXMLNS, __IgnoreEls, [_ | _els], Items) -> @@ -7549,13 +8743,14 @@ decode_pubsub_options_els(__TopXMLNS, __IgnoreEls, [], Xdata; decode_pubsub_options_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"x">>, _attrs, _} = _el | _els], Xdata) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<"jabber:x:data">> -> - decode_pubsub_options_els(__TopXMLNS, __IgnoreEls, _els, - decode_xdata(_xmlns, __IgnoreEls, _el)); - true -> - decode_pubsub_options_els(__TopXMLNS, __IgnoreEls, _els, - Xdata) + case get_attr(<<"xmlns">>, _attrs) of + <<"jabber:x:data">> -> + decode_pubsub_options_els(__TopXMLNS, __IgnoreEls, _els, + decode_xdata(<<"jabber:x:data">>, + __IgnoreEls, _el)); + _ -> + decode_pubsub_options_els(__TopXMLNS, __IgnoreEls, _els, + Xdata) end; decode_pubsub_options_els(__TopXMLNS, __IgnoreEls, [_ | _els], Xdata) -> @@ -7654,15 +8849,22 @@ decode_pubsub_publish_els(__TopXMLNS, __IgnoreEls, [], decode_pubsub_publish_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_pubsub_publish_els(__TopXMLNS, __IgnoreEls, _els, - [decode_pubsub_item(__TopXMLNS, - __IgnoreEls, _el) - | Items]); - true -> - decode_pubsub_publish_els(__TopXMLNS, __IgnoreEls, _els, - Items) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_publish_els(__TopXMLNS, __IgnoreEls, _els, + [decode_pubsub_item(__TopXMLNS, __IgnoreEls, + _el) + | Items]); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_publish_els(__TopXMLNS, __IgnoreEls, _els, + [decode_pubsub_item(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el) + | Items]); + _ -> + decode_pubsub_publish_els(__TopXMLNS, __IgnoreEls, _els, + Items) end; decode_pubsub_publish_els(__TopXMLNS, __IgnoreEls, [_ | _els], Items) -> @@ -7857,17 +9059,26 @@ decode_pubsub_affiliations_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"affiliation">>, _attrs, _} = _el | _els], Affiliations) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_pubsub_affiliations_els(__TopXMLNS, __IgnoreEls, - _els, - [decode_pubsub_affiliation(__TopXMLNS, - __IgnoreEls, - _el) - | Affiliations]); - true -> - decode_pubsub_affiliations_els(__TopXMLNS, __IgnoreEls, - _els, Affiliations) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_affiliations_els(__TopXMLNS, __IgnoreEls, + _els, + [decode_pubsub_affiliation(__TopXMLNS, + __IgnoreEls, + _el) + | Affiliations]); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_affiliations_els(__TopXMLNS, __IgnoreEls, + _els, + [decode_pubsub_affiliation(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, + _el) + | Affiliations]); + _ -> + decode_pubsub_affiliations_els(__TopXMLNS, __IgnoreEls, + _els, Affiliations) end; decode_pubsub_affiliations_els(__TopXMLNS, __IgnoreEls, [_ | _els], Affiliations) -> @@ -7908,17 +9119,26 @@ decode_pubsub_subscriptions_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"subscription">>, _attrs, _} = _el | _els], Subscriptions) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_pubsub_subscriptions_els(__TopXMLNS, __IgnoreEls, - _els, - [decode_pubsub_subscription(__TopXMLNS, - __IgnoreEls, - _el) - | Subscriptions]); - true -> - decode_pubsub_subscriptions_els(__TopXMLNS, __IgnoreEls, - _els, Subscriptions) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_subscriptions_els(__TopXMLNS, __IgnoreEls, + _els, + [decode_pubsub_subscription(__TopXMLNS, + __IgnoreEls, + _el) + | Subscriptions]); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_subscriptions_els(__TopXMLNS, __IgnoreEls, + _els, + [decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, + _el) + | Subscriptions]); + _ -> + decode_pubsub_subscriptions_els(__TopXMLNS, __IgnoreEls, + _els, Subscriptions) end; decode_pubsub_subscriptions_els(__TopXMLNS, __IgnoreEls, [_ | _els], Subscriptions) -> @@ -7981,15 +9201,22 @@ decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, [], decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"items">>, _attrs, _} = _el | _els], Items) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - [decode_pubsub_event_items(__TopXMLNS, - __IgnoreEls, _el) - | Items]); - true -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + [decode_pubsub_event_items(__TopXMLNS, + __IgnoreEls, _el) + | Items]); + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + [decode_pubsub_event_items(<<"http://jabber.org/protocol/pubsub#event">>, + __IgnoreEls, _el) + | Items]); + _ -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + Items) end; decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, [_ | _els], Items) -> @@ -8023,33 +9250,52 @@ decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"retract">>, _attrs, _} = _el | _els], Items, Retract) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, - _els, Items, - [decode_pubsub_event_retract(__TopXMLNS, - __IgnoreEls, - _el) - | Retract]); - true -> - decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, - _els, Items, Retract) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, + _els, Items, + [decode_pubsub_event_retract(__TopXMLNS, + __IgnoreEls, + _el) + | Retract]); + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, + _els, Items, + [decode_pubsub_event_retract(<<"http://jabber.org/protocol/pubsub#event">>, + __IgnoreEls, + _el) + | Retract]); + _ -> + decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, + _els, Items, Retract) end; decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items, Retract) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, - _els, - [decode_pubsub_event_item(__TopXMLNS, - __IgnoreEls, - _el) - | Items], - Retract); - true -> - decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, - _els, Items, Retract) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, + _els, + [decode_pubsub_event_item(__TopXMLNS, + __IgnoreEls, + _el) + | Items], + Retract); + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, + _els, + [decode_pubsub_event_item(<<"http://jabber.org/protocol/pubsub#event">>, + __IgnoreEls, + _el) + | Items], + Retract); + _ -> + decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, + _els, Items, Retract) end; decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, [_ | _els], Items, Retract) -> @@ -8243,15 +9489,22 @@ decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, [], lists:reverse(Items); decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, _els, - [decode_pubsub_item(__TopXMLNS, __IgnoreEls, - _el) - | Items]); - true -> - decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, _els, - Items) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, _els, + [decode_pubsub_item(__TopXMLNS, __IgnoreEls, + _el) + | Items]); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, _els, + [decode_pubsub_item(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el) + | Items]); + _ -> + decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, _els, + Items) end; decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, [_ | _els], Items) -> @@ -8580,71 +9833,104 @@ decode_xdata_els(__TopXMLNS, __IgnoreEls, [], Fields, decode_xdata_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"instructions">>, _attrs, _} = _el | _els], Fields, Items, Instructions, Reported, Title) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, - Items, - case decode_xdata_instructions(__TopXMLNS, - __IgnoreEls, _el) - of - undefined -> Instructions; - _new_el -> [_new_el | Instructions] - end, - Reported, Title); - true -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, - Items, Instructions, Reported, Title) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:x:data">> -> + decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, + Items, + case decode_xdata_instructions(__TopXMLNS, + __IgnoreEls, _el) + of + undefined -> Instructions; + _new_el -> [_new_el | Instructions] + end, + Reported, Title); + <<"jabber:x:data">> -> + decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, + Items, + case decode_xdata_instructions(<<"jabber:x:data">>, + __IgnoreEls, _el) + of + undefined -> Instructions; + _new_el -> [_new_el | Instructions] + end, + Reported, Title); + _ -> + decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, + Items, Instructions, Reported, Title) end; decode_xdata_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"title">>, _attrs, _} = _el | _els], Fields, Items, Instructions, Reported, Title) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, - Items, Instructions, Reported, - decode_xdata_title(__TopXMLNS, __IgnoreEls, _el)); - true -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, - Items, Instructions, Reported, Title) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:x:data">> -> + decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, + Items, Instructions, Reported, + decode_xdata_title(__TopXMLNS, __IgnoreEls, _el)); + <<"jabber:x:data">> -> + decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, + Items, Instructions, Reported, + decode_xdata_title(<<"jabber:x:data">>, __IgnoreEls, + _el)); + _ -> + decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, + Items, Instructions, Reported, Title) end; decode_xdata_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"reported">>, _attrs, _} = _el | _els], Fields, Items, Instructions, Reported, Title) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, - Items, Instructions, - decode_xdata_reported(__TopXMLNS, __IgnoreEls, _el), - Title); - true -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, - Items, Instructions, Reported, Title) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:x:data">> -> + decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, + Items, Instructions, + decode_xdata_reported(__TopXMLNS, __IgnoreEls, _el), + Title); + <<"jabber:x:data">> -> + decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, + Items, Instructions, + decode_xdata_reported(<<"jabber:x:data">>, + __IgnoreEls, _el), + Title); + _ -> + decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, + Items, Instructions, Reported, Title) end; decode_xdata_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"item">>, _attrs, _} = _el | _els], Fields, Items, Instructions, Reported, Title) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, - [decode_xdata_item(__TopXMLNS, __IgnoreEls, _el) - | Items], - Instructions, Reported, Title); - true -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, - Items, Instructions, Reported, Title) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:x:data">> -> + decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, + [decode_xdata_item(__TopXMLNS, __IgnoreEls, _el) + | Items], + Instructions, Reported, Title); + <<"jabber:x:data">> -> + decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, + [decode_xdata_item(<<"jabber:x:data">>, __IgnoreEls, + _el) + | Items], + Instructions, Reported, Title); + _ -> + decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, + Items, Instructions, Reported, Title) end; decode_xdata_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"field">>, _attrs, _} = _el | _els], Fields, Items, Instructions, Reported, Title) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, - [decode_xdata_field(__TopXMLNS, __IgnoreEls, _el) - | Fields], - Items, Instructions, Reported, Title); - true -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, - Items, Instructions, Reported, Title) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:x:data">> -> + decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, + [decode_xdata_field(__TopXMLNS, __IgnoreEls, _el) + | Fields], + Items, Instructions, Reported, Title); + <<"jabber:x:data">> -> + decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, + [decode_xdata_field(<<"jabber:x:data">>, __IgnoreEls, + _el) + | Fields], + Items, Instructions, Reported, Title); + _ -> + decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, + Items, Instructions, Reported, Title) end; decode_xdata_els(__TopXMLNS, __IgnoreEls, [_ | _els], Fields, Items, Instructions, Reported, Title) -> @@ -8724,15 +10010,20 @@ decode_xdata_item_els(__TopXMLNS, __IgnoreEls, [], decode_xdata_item_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"field">>, _attrs, _} = _el | _els], Fields) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_xdata_item_els(__TopXMLNS, __IgnoreEls, _els, - [decode_xdata_field(__TopXMLNS, __IgnoreEls, - _el) - | Fields]); - true -> - decode_xdata_item_els(__TopXMLNS, __IgnoreEls, _els, - Fields) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:x:data">> -> + decode_xdata_item_els(__TopXMLNS, __IgnoreEls, _els, + [decode_xdata_field(__TopXMLNS, __IgnoreEls, + _el) + | Fields]); + <<"jabber:x:data">> -> + decode_xdata_item_els(__TopXMLNS, __IgnoreEls, _els, + [decode_xdata_field(<<"jabber:x:data">>, + __IgnoreEls, _el) + | Fields]); + _ -> + decode_xdata_item_els(__TopXMLNS, __IgnoreEls, _els, + Fields) end; decode_xdata_item_els(__TopXMLNS, __IgnoreEls, [_ | _els], Fields) -> @@ -8762,15 +10053,20 @@ decode_xdata_reported_els(__TopXMLNS, __IgnoreEls, [], decode_xdata_reported_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"field">>, _attrs, _} = _el | _els], Fields) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_xdata_reported_els(__TopXMLNS, __IgnoreEls, _els, - [decode_xdata_field(__TopXMLNS, - __IgnoreEls, _el) - | Fields]); - true -> - decode_xdata_reported_els(__TopXMLNS, __IgnoreEls, _els, - Fields) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:x:data">> -> + decode_xdata_reported_els(__TopXMLNS, __IgnoreEls, _els, + [decode_xdata_field(__TopXMLNS, __IgnoreEls, + _el) + | Fields]); + <<"jabber:x:data">> -> + decode_xdata_reported_els(__TopXMLNS, __IgnoreEls, _els, + [decode_xdata_field(<<"jabber:x:data">>, + __IgnoreEls, _el) + | Fields]); + _ -> + decode_xdata_reported_els(__TopXMLNS, __IgnoreEls, _els, + Fields) end; decode_xdata_reported_els(__TopXMLNS, __IgnoreEls, [_ | _els], Fields) -> @@ -8871,67 +10167,97 @@ decode_xdata_field_els(__TopXMLNS, __IgnoreEls, [], decode_xdata_field_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"required">>, _attrs, _} = _el | _els], Options, Values, Desc, Required) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, Values, Desc, - decode_xdata_field_required(__TopXMLNS, - __IgnoreEls, - _el)); - true -> - decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, Values, Desc, Required) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:x:data">> -> + decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, + Options, Values, Desc, + decode_xdata_field_required(__TopXMLNS, + __IgnoreEls, _el)); + <<"jabber:x:data">> -> + decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, + Options, Values, Desc, + decode_xdata_field_required(<<"jabber:x:data">>, + __IgnoreEls, _el)); + _ -> + decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, + Options, Values, Desc, Required) end; decode_xdata_field_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"desc">>, _attrs, _} = _el | _els], Options, Values, Desc, Required) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, Values, - decode_xdata_field_desc(__TopXMLNS, - __IgnoreEls, _el), - Required); - true -> - decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, Values, Desc, Required) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:x:data">> -> + decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, + Options, Values, + decode_xdata_field_desc(__TopXMLNS, + __IgnoreEls, _el), + Required); + <<"jabber:x:data">> -> + decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, + Options, Values, + decode_xdata_field_desc(<<"jabber:x:data">>, + __IgnoreEls, _el), + Required); + _ -> + decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, + Options, Values, Desc, Required) end; decode_xdata_field_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"value">>, _attrs, _} = _el | _els], Options, Values, Desc, Required) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, - case decode_xdata_field_value(__TopXMLNS, - __IgnoreEls, - _el) - of - undefined -> Values; - _new_el -> [_new_el | Values] - end, - Desc, Required); - true -> - decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, Values, Desc, Required) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:x:data">> -> + decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, + Options, + case decode_xdata_field_value(__TopXMLNS, + __IgnoreEls, _el) + of + undefined -> Values; + _new_el -> [_new_el | Values] + end, + Desc, Required); + <<"jabber:x:data">> -> + decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, + Options, + case + decode_xdata_field_value(<<"jabber:x:data">>, + __IgnoreEls, _el) + of + undefined -> Values; + _new_el -> [_new_el | Values] + end, + Desc, Required); + _ -> + decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, + Options, Values, Desc, Required) end; decode_xdata_field_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"option">>, _attrs, _} = _el | _els], Options, Values, Desc, Required) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - case decode_xdata_field_option(__TopXMLNS, - __IgnoreEls, - _el) - of - undefined -> Options; - _new_el -> [_new_el | Options] - end, - Values, Desc, Required); - true -> - decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, Values, Desc, Required) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:x:data">> -> + decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, + case decode_xdata_field_option(__TopXMLNS, + __IgnoreEls, + _el) + of + undefined -> Options; + _new_el -> [_new_el | Options] + end, + Values, Desc, Required); + <<"jabber:x:data">> -> + decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, + case + decode_xdata_field_option(<<"jabber:x:data">>, + __IgnoreEls, _el) + of + undefined -> Options; + _new_el -> [_new_el | Options] + end, + Values, Desc, Required); + _ -> + decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, + Options, Values, Desc, Required) end; decode_xdata_field_els(__TopXMLNS, __IgnoreEls, [_ | _els], Options, Values, Desc, Required) -> @@ -9045,17 +10371,24 @@ decode_xdata_field_option_els(__TopXMLNS, __IgnoreEls, decode_xdata_field_option_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"value">>, _attrs, _} = _el | _els], Value) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_xdata_field_option_els(__TopXMLNS, __IgnoreEls, - _els, - {value, - decode_xdata_field_value(__TopXMLNS, - __IgnoreEls, - _el)}); - true -> - decode_xdata_field_option_els(__TopXMLNS, __IgnoreEls, - _els, Value) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:x:data">> -> + decode_xdata_field_option_els(__TopXMLNS, __IgnoreEls, + _els, + {value, + decode_xdata_field_value(__TopXMLNS, + __IgnoreEls, + _el)}); + <<"jabber:x:data">> -> + decode_xdata_field_option_els(__TopXMLNS, __IgnoreEls, + _els, + {value, + decode_xdata_field_value(<<"jabber:x:data">>, + __IgnoreEls, + _el)}); + _ -> + decode_xdata_field_option_els(__TopXMLNS, __IgnoreEls, + _els, Value) end; decode_xdata_field_option_els(__TopXMLNS, __IgnoreEls, [_ | _els], Value) -> @@ -9146,41 +10479,46 @@ encode_xdata_field_required(true, _xmlns_attrs) -> decode_vcard_xupdate(__TopXMLNS, __IgnoreEls, {xmlel, <<"x">>, _attrs, _els}) -> - Photo = decode_vcard_xupdate_els(__TopXMLNS, - __IgnoreEls, _els, undefined), - {vcard_xupdate, Photo}. + Hash = decode_vcard_xupdate_els(__TopXMLNS, __IgnoreEls, + _els, undefined), + {vcard_xupdate, undefined, Hash}. decode_vcard_xupdate_els(__TopXMLNS, __IgnoreEls, [], - Photo) -> - Photo; + Hash) -> + Hash; decode_vcard_xupdate_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"photo">>, _attrs, _} = _el | _els], - Photo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_xupdate_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_xupdate_photo(__TopXMLNS, - __IgnoreEls, - _el)); - true -> - decode_vcard_xupdate_els(__TopXMLNS, __IgnoreEls, _els, - Photo) + Hash) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp:x:update">> -> + decode_vcard_xupdate_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_xupdate_photo(__TopXMLNS, + __IgnoreEls, + _el)); + <<"vcard-temp:x:update">> -> + decode_vcard_xupdate_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_xupdate_photo(<<"vcard-temp:x:update">>, + __IgnoreEls, + _el)); + _ -> + decode_vcard_xupdate_els(__TopXMLNS, __IgnoreEls, _els, + Hash) end; decode_vcard_xupdate_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Photo) -> + [_ | _els], Hash) -> decode_vcard_xupdate_els(__TopXMLNS, __IgnoreEls, _els, - Photo). + Hash). -encode_vcard_xupdate({vcard_xupdate, Photo}, +encode_vcard_xupdate({vcard_xupdate, undefined, Hash}, _xmlns_attrs) -> - _els = - lists:reverse('encode_vcard_xupdate_$photo'(Photo, [])), + _els = lists:reverse('encode_vcard_xupdate_$hash'(Hash, + [])), _attrs = _xmlns_attrs, {xmlel, <<"x">>, _attrs, _els}. -'encode_vcard_xupdate_$photo'(undefined, _acc) -> _acc; -'encode_vcard_xupdate_$photo'(Photo, _acc) -> - [encode_vcard_xupdate_photo(Photo, []) | _acc]. +'encode_vcard_xupdate_$hash'(undefined, _acc) -> _acc; +'encode_vcard_xupdate_$hash'(Hash, _acc) -> + [encode_vcard_xupdate_photo(Hash, []) | _acc]. decode_vcard_xupdate_photo(__TopXMLNS, __IgnoreEls, {xmlel, <<"photo">>, _attrs, _els}) -> @@ -9215,833 +10553,1153 @@ encode_vcard_xupdate_photo_cdata(undefined, _acc) -> encode_vcard_xupdate_photo_cdata(_val, _acc) -> [{xmlcdata, _val} | _acc]. -decode_vcard(__TopXMLNS, __IgnoreEls, - {xmlel, <<"vCard">>, _attrs, _els}) -> +decode_vcard_temp(__TopXMLNS, __IgnoreEls, + {xmlel, <<"vCard">>, _attrs, _els}) -> {Mailer, Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, Sound, Note, Role, Title, Nickname, Rev, Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, N, Photo, Logo, Geo} = - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, - undefined, [], undefined, [], undefined, undefined, - undefined, undefined, undefined, undefined, undefined, - undefined, undefined, undefined, undefined, undefined, - undefined, undefined, undefined, undefined, [], [], [], - undefined, undefined, undefined, undefined, undefined, - undefined), - {vcard, Version, Fn, N, Nickname, Photo, Bday, Adr, + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + undefined, [], undefined, [], undefined, + undefined, undefined, undefined, undefined, + undefined, undefined, undefined, undefined, + undefined, undefined, undefined, undefined, + undefined, undefined, undefined, [], [], [], + undefined, undefined, undefined, undefined, + undefined, undefined), + {vcard_temp, Version, Fn, N, Nickname, Photo, Bday, Adr, Label, Tel, Email, Jabberid, Mailer, Tz, Geo, Title, Role, Logo, Org, Categories, Note, Prodid, Rev, Sort_string, Sound, Uid, Url, Class, Key, Desc}. -decode_vcard_els(__TopXMLNS, __IgnoreEls, [], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, [], + Mailer, Adr, Class, Categories, Desc, Uid, Prodid, + Jabberid, Sound, Note, Role, Title, Nickname, Rev, + Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, Label, + Fn, Version, N, Photo, Logo, Geo) -> {Mailer, lists:reverse(Adr), Class, Categories, Desc, Uid, Prodid, Jabberid, Sound, Note, Role, Title, Nickname, Rev, Sort_string, Org, Bday, Key, Tz, Url, lists:reverse(Email), lists:reverse(Tel), lists:reverse(Label), Fn, Version, N, Photo, Logo, Geo}; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"N">>, _attrs, _} = _el | _els], Mailer, Adr, - Class, Categories, Desc, Uid, Prodid, Jabberid, Sound, - Note, Role, Title, Nickname, Rev, Sort_string, Org, - Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, N, - Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, - decode_vcard_N(__TopXMLNS, __IgnoreEls, _el), Photo, - Logo, Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"N">>, _attrs, _} = _el | _els], Mailer, Adr, + Class, Categories, Desc, Uid, Prodid, Jabberid, Sound, + Note, Role, Title, Nickname, Rev, Sort_string, Org, + Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, N, + Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, + decode_vcard_N(__TopXMLNS, __IgnoreEls, _el), + Photo, Logo, Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, + decode_vcard_N(<<"vcard-temp">>, __IgnoreEls, + _el), + Photo, Logo, Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"ADR">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - [decode_vcard_ADR(__TopXMLNS, __IgnoreEls, _el) - | Adr], - Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"ADR">>, _attrs, _} = _el | _els], Mailer, + Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, + Sound, Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, + N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, + [decode_vcard_ADR(__TopXMLNS, __IgnoreEls, _el) + | Adr], + Class, Categories, Desc, Uid, Prodid, Jabberid, + Sound, Note, Role, Title, Nickname, Rev, + Sort_string, Org, Bday, Key, Tz, Url, Email, + Tel, Label, Fn, Version, N, Photo, Logo, Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, + [decode_vcard_ADR(<<"vcard-temp">>, __IgnoreEls, + _el) + | Adr], + Class, Categories, Desc, Uid, Prodid, Jabberid, + Sound, Note, Role, Title, Nickname, Rev, + Sort_string, Org, Bday, Key, Tz, Url, Email, + Tel, Label, Fn, Version, N, Photo, Logo, Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"LABEL">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - [decode_vcard_LABEL(__TopXMLNS, __IgnoreEls, _el) - | Label], - Fn, Version, N, Photo, Logo, Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"LABEL">>, _attrs, _} = _el | _els], Mailer, + Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, + Sound, Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, + N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, + [decode_vcard_LABEL(__TopXMLNS, __IgnoreEls, + _el) + | Label], + Fn, Version, N, Photo, Logo, Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, + [decode_vcard_LABEL(<<"vcard-temp">>, + __IgnoreEls, _el) + | Label], + Fn, Version, N, Photo, Logo, Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"TEL">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, - [decode_vcard_TEL(__TopXMLNS, __IgnoreEls, _el) - | Tel], - Label, Fn, Version, N, Photo, Logo, Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"TEL">>, _attrs, _} = _el | _els], Mailer, + Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, + Sound, Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, + N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, + [decode_vcard_TEL(__TopXMLNS, __IgnoreEls, _el) + | Tel], + Label, Fn, Version, N, Photo, Logo, Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, + [decode_vcard_TEL(<<"vcard-temp">>, __IgnoreEls, + _el) + | Tel], + Label, Fn, Version, N, Photo, Logo, Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"EMAIL">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, - [decode_vcard_EMAIL(__TopXMLNS, __IgnoreEls, _el) - | Email], - Tel, Label, Fn, Version, N, Photo, Logo, Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"EMAIL">>, _attrs, _} = _el | _els], Mailer, + Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, + Sound, Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, + N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, + [decode_vcard_EMAIL(__TopXMLNS, __IgnoreEls, + _el) + | Email], + Tel, Label, Fn, Version, N, Photo, Logo, Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, + [decode_vcard_EMAIL(<<"vcard-temp">>, + __IgnoreEls, _el) + | Email], + Tel, Label, Fn, Version, N, Photo, Logo, Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"GEO">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, - decode_vcard_GEO(__TopXMLNS, __IgnoreEls, _el)); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"GEO">>, _attrs, _} = _el | _els], Mailer, + Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, + Sound, Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, + N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, + decode_vcard_GEO(__TopXMLNS, __IgnoreEls, _el)); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, + decode_vcard_GEO(<<"vcard-temp">>, __IgnoreEls, + _el)); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"LOGO">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, - decode_vcard_LOGO(__TopXMLNS, __IgnoreEls, _el), - Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"LOGO">>, _attrs, _} = _el | _els], Mailer, + Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, + Sound, Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, + N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + decode_vcard_LOGO(__TopXMLNS, __IgnoreEls, _el), + Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + decode_vcard_LOGO(<<"vcard-temp">>, __IgnoreEls, + _el), + Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"PHOTO">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, - decode_vcard_PHOTO(__TopXMLNS, __IgnoreEls, _el), - Logo, Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"PHOTO">>, _attrs, _} = _el | _els], Mailer, + Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, + Sound, Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, + N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, + decode_vcard_PHOTO(__TopXMLNS, __IgnoreEls, + _el), + Logo, Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, + decode_vcard_PHOTO(<<"vcard-temp">>, + __IgnoreEls, _el), + Logo, Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"ORG">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, - decode_vcard_ORG(__TopXMLNS, __IgnoreEls, _el), - Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"ORG">>, _attrs, _} = _el | _els], Mailer, + Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, + Sound, Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, + N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, + decode_vcard_ORG(__TopXMLNS, __IgnoreEls, _el), + Bday, Key, Tz, Url, Email, Tel, Label, Fn, + Version, N, Photo, Logo, Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, + decode_vcard_ORG(<<"vcard-temp">>, __IgnoreEls, + _el), + Bday, Key, Tz, Url, Email, Tel, Label, Fn, + Version, N, Photo, Logo, Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"SOUND">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - decode_vcard_SOUND(__TopXMLNS, __IgnoreEls, _el), - Note, Role, Title, Nickname, Rev, Sort_string, Org, - Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"SOUND">>, _attrs, _} = _el | _els], Mailer, + Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, + Sound, Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, + N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, + decode_vcard_SOUND(__TopXMLNS, __IgnoreEls, + _el), + Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, + Version, N, Photo, Logo, Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, + decode_vcard_SOUND(<<"vcard-temp">>, + __IgnoreEls, _el), + Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, + Version, N, Photo, Logo, Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"KEY">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, - decode_vcard_KEY(__TopXMLNS, __IgnoreEls, _el), Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, Logo, - Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"KEY">>, _attrs, _} = _el | _els], Mailer, + Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, + Sound, Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, + N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, + decode_vcard_KEY(__TopXMLNS, __IgnoreEls, _el), + Tz, Url, Email, Tel, Label, Fn, Version, N, + Photo, Logo, Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, + decode_vcard_KEY(<<"vcard-temp">>, __IgnoreEls, + _el), + Tz, Url, Email, Tel, Label, Fn, Version, N, + Photo, Logo, Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"VERSION">>, _attrs, _} = _el | _els], - Mailer, Adr, Class, Categories, Desc, Uid, Prodid, - Jabberid, Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, Label, - Fn, Version, N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, - decode_vcard_VERSION(__TopXMLNS, __IgnoreEls, _el), - N, Photo, Logo, Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) - end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"FN">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, - decode_vcard_FN(__TopXMLNS, __IgnoreEls, _el), - Version, N, Photo, Logo, Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) - end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"NICKNAME">>, _attrs, _} = _el | _els], - Mailer, Adr, Class, Categories, Desc, Uid, Prodid, - Jabberid, Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, Label, - Fn, Version, N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, - decode_vcard_NICKNAME(__TopXMLNS, __IgnoreEls, _el), - Rev, Sort_string, Org, Bday, Key, Tz, Url, Email, - Tel, Label, Fn, Version, N, Photo, Logo, Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) - end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"BDAY">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, - decode_vcard_BDAY(__TopXMLNS, __IgnoreEls, _el), - Key, Tz, Url, Email, Tel, Label, Fn, Version, N, - Photo, Logo, Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) - end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"JABBERID">>, _attrs, _} = _el | _els], - Mailer, Adr, Class, Categories, Desc, Uid, Prodid, - Jabberid, Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, Label, - Fn, Version, N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, - decode_vcard_JABBERID(__TopXMLNS, __IgnoreEls, _el), - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) - end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"MAILER">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_MAILER(__TopXMLNS, __IgnoreEls, _el), - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) - end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"TZ">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, - decode_vcard_TZ(__TopXMLNS, __IgnoreEls, _el), Url, - Email, Tel, Label, Fn, Version, N, Photo, Logo, - Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) - end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"TITLE">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, - decode_vcard_TITLE(__TopXMLNS, __IgnoreEls, _el), - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, Url, - Email, Tel, Label, Fn, Version, N, Photo, Logo, - Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) - end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"ROLE">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, - decode_vcard_ROLE(__TopXMLNS, __IgnoreEls, _el), - Title, Nickname, Rev, Sort_string, Org, Bday, Key, - Tz, Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) - end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"NOTE">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, - decode_vcard_NOTE(__TopXMLNS, __IgnoreEls, _el), - Role, Title, Nickname, Rev, Sort_string, Org, Bday, - Key, Tz, Url, Email, Tel, Label, Fn, Version, N, - Photo, Logo, Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) - end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"PRODID">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, - decode_vcard_PRODID(__TopXMLNS, __IgnoreEls, _el), - Jabberid, Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) - end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"REV">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, - decode_vcard_REV(__TopXMLNS, __IgnoreEls, _el), - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) - end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"SORT-STRING">>, _attrs, _} = _el | _els], - Mailer, Adr, Class, Categories, Desc, Uid, Prodid, - Jabberid, Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, Label, - Fn, Version, N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - decode_vcard_SORT_STRING(__TopXMLNS, __IgnoreEls, +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"VERSION">>, _attrs, _} = _el | _els], + Mailer, Adr, Class, Categories, Desc, Uid, Prodid, + Jabberid, Sound, Note, Role, Title, Nickname, Rev, + Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, Label, + Fn, Version, N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, + decode_vcard_VERSION(__TopXMLNS, __IgnoreEls, _el), - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, - Version, N, Photo, Logo, Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) + N, Photo, Logo, Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, + decode_vcard_VERSION(<<"vcard-temp">>, + __IgnoreEls, _el), + N, Photo, Logo, Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"UID">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, - decode_vcard_UID(__TopXMLNS, __IgnoreEls, _el), - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, Url, - Email, Tel, Label, Fn, Version, N, Photo, Logo, - Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"FN">>, _attrs, _} = _el | _els], Mailer, + Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, + Sound, Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, + N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, + decode_vcard_FN(__TopXMLNS, __IgnoreEls, _el), + Version, N, Photo, Logo, Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, + decode_vcard_FN(<<"vcard-temp">>, __IgnoreEls, + _el), + Version, N, Photo, Logo, Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"URL">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, - decode_vcard_URL(__TopXMLNS, __IgnoreEls, _el), - Email, Tel, Label, Fn, Version, N, Photo, Logo, - Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"NICKNAME">>, _attrs, _} = _el | _els], + Mailer, Adr, Class, Categories, Desc, Uid, Prodid, + Jabberid, Sound, Note, Role, Title, Nickname, Rev, + Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, Label, + Fn, Version, N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + decode_vcard_NICKNAME(__TopXMLNS, __IgnoreEls, + _el), + Rev, Sort_string, Org, Bday, Key, Tz, Url, + Email, Tel, Label, Fn, Version, N, Photo, Logo, + Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + decode_vcard_NICKNAME(<<"vcard-temp">>, + __IgnoreEls, _el), + Rev, Sort_string, Org, Bday, Key, Tz, Url, + Email, Tel, Label, Fn, Version, N, Photo, Logo, + Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"DESC">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, - decode_vcard_DESC(__TopXMLNS, __IgnoreEls, _el), - Uid, Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, Url, - Email, Tel, Label, Fn, Version, N, Photo, Logo, - Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"BDAY">>, _attrs, _} = _el | _els], Mailer, + Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, + Sound, Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, + N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, + decode_vcard_BDAY(__TopXMLNS, __IgnoreEls, _el), + Key, Tz, Url, Email, Tel, Label, Fn, Version, N, + Photo, Logo, Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, + decode_vcard_BDAY(<<"vcard-temp">>, __IgnoreEls, + _el), + Key, Tz, Url, Email, Tel, Label, Fn, Version, N, + Photo, Logo, Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"CATEGORIES">>, _attrs, _} = _el | _els], - Mailer, Adr, Class, Categories, Desc, Uid, Prodid, - Jabberid, Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, Label, - Fn, Version, N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, - decode_vcard_CATEGORIES(__TopXMLNS, __IgnoreEls, +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"JABBERID">>, _attrs, _} = _el | _els], + Mailer, Adr, Class, Categories, Desc, Uid, Prodid, + Jabberid, Sound, Note, Role, Title, Nickname, Rev, + Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, Label, + Fn, Version, N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, + decode_vcard_JABBERID(__TopXMLNS, __IgnoreEls, + _el), + Sound, Note, Role, Title, Nickname, Rev, + Sort_string, Org, Bday, Key, Tz, Url, Email, + Tel, Label, Fn, Version, N, Photo, Logo, Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, + decode_vcard_JABBERID(<<"vcard-temp">>, + __IgnoreEls, _el), + Sound, Note, Role, Title, Nickname, Rev, + Sort_string, Org, Bday, Key, Tz, Url, Email, + Tel, Label, Fn, Version, N, Photo, Logo, Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) + end; +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"MAILER">>, _attrs, _} = _el | _els], Mailer, + Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, + Sound, Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, + N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_MAILER(__TopXMLNS, __IgnoreEls, _el), - Desc, Uid, Prodid, Jabberid, Sound, Note, Role, - Title, Nickname, Rev, Sort_string, Org, Bday, Key, - Tz, Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) + Adr, Class, Categories, Desc, Uid, Prodid, + Jabberid, Sound, Note, Role, Title, Nickname, + Rev, Sort_string, Org, Bday, Key, Tz, Url, + Email, Tel, Label, Fn, Version, N, Photo, Logo, + Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_MAILER(<<"vcard-temp">>, + __IgnoreEls, _el), + Adr, Class, Categories, Desc, Uid, Prodid, + Jabberid, Sound, Note, Role, Title, Nickname, + Rev, Sort_string, Org, Bday, Key, Tz, Url, + Email, Tel, Label, Fn, Version, N, Photo, Logo, + Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"CLASS">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, - decode_vcard_CLASS(__TopXMLNS, __IgnoreEls, _el), - Categories, Desc, Uid, Prodid, Jabberid, Sound, - Note, Role, Title, Nickname, Rev, Sort_string, Org, - Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo); - true -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"TZ">>, _attrs, _} = _el | _els], Mailer, + Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, + Sound, Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, + N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, + decode_vcard_TZ(__TopXMLNS, __IgnoreEls, _el), + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, + decode_vcard_TZ(<<"vcard-temp">>, __IgnoreEls, + _el), + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) end; -decode_vcard_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Mailer, Adr, Class, Categories, Desc, Uid, Prodid, - Jabberid, Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, Label, - Fn, Version, N, Photo, Logo, Geo) -> - decode_vcard_els(__TopXMLNS, __IgnoreEls, _els, Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo). +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"TITLE">>, _attrs, _} = _el | _els], Mailer, + Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, + Sound, Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, + N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, + decode_vcard_TITLE(__TopXMLNS, __IgnoreEls, + _el), + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, + decode_vcard_TITLE(<<"vcard-temp">>, + __IgnoreEls, _el), + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) + end; +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"ROLE">>, _attrs, _} = _el | _els], Mailer, + Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, + Sound, Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, + N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, + decode_vcard_ROLE(__TopXMLNS, __IgnoreEls, _el), + Title, Nickname, Rev, Sort_string, Org, Bday, + Key, Tz, Url, Email, Tel, Label, Fn, Version, N, + Photo, Logo, Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, + decode_vcard_ROLE(<<"vcard-temp">>, __IgnoreEls, + _el), + Title, Nickname, Rev, Sort_string, Org, Bday, + Key, Tz, Url, Email, Tel, Label, Fn, Version, N, + Photo, Logo, Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) + end; +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"NOTE">>, _attrs, _} = _el | _els], Mailer, + Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, + Sound, Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, + N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, + decode_vcard_NOTE(__TopXMLNS, __IgnoreEls, _el), + Role, Title, Nickname, Rev, Sort_string, Org, + Bday, Key, Tz, Url, Email, Tel, Label, Fn, + Version, N, Photo, Logo, Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, + decode_vcard_NOTE(<<"vcard-temp">>, __IgnoreEls, + _el), + Role, Title, Nickname, Rev, Sort_string, Org, + Bday, Key, Tz, Url, Email, Tel, Label, Fn, + Version, N, Photo, Logo, Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) + end; +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"PRODID">>, _attrs, _} = _el | _els], Mailer, + Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, + Sound, Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, + N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + decode_vcard_PRODID(__TopXMLNS, __IgnoreEls, + _el), + Jabberid, Sound, Note, Role, Title, Nickname, + Rev, Sort_string, Org, Bday, Key, Tz, Url, + Email, Tel, Label, Fn, Version, N, Photo, Logo, + Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + decode_vcard_PRODID(<<"vcard-temp">>, + __IgnoreEls, _el), + Jabberid, Sound, Note, Role, Title, Nickname, + Rev, Sort_string, Org, Bday, Key, Tz, Url, + Email, Tel, Label, Fn, Version, N, Photo, Logo, + Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) + end; +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"REV">>, _attrs, _} = _el | _els], Mailer, + Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, + Sound, Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, + N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, + decode_vcard_REV(__TopXMLNS, __IgnoreEls, _el), + Sort_string, Org, Bday, Key, Tz, Url, Email, + Tel, Label, Fn, Version, N, Photo, Logo, Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, + decode_vcard_REV(<<"vcard-temp">>, __IgnoreEls, + _el), + Sort_string, Org, Bday, Key, Tz, Url, Email, + Tel, Label, Fn, Version, N, Photo, Logo, Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) + end; +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"SORT-STRING">>, _attrs, _} = _el | _els], + Mailer, Adr, Class, Categories, Desc, Uid, Prodid, + Jabberid, Sound, Note, Role, Title, Nickname, Rev, + Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, Label, + Fn, Version, N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, + decode_vcard_SORT_STRING(__TopXMLNS, + __IgnoreEls, _el), + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, + Version, N, Photo, Logo, Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, + decode_vcard_SORT_STRING(<<"vcard-temp">>, + __IgnoreEls, _el), + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, + Version, N, Photo, Logo, Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) + end; +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"UID">>, _attrs, _} = _el | _els], Mailer, + Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, + Sound, Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, + N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, + decode_vcard_UID(__TopXMLNS, __IgnoreEls, _el), + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, + decode_vcard_UID(<<"vcard-temp">>, __IgnoreEls, + _el), + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) + end; +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"URL">>, _attrs, _} = _el | _els], Mailer, + Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, + Sound, Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, + N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + decode_vcard_URL(__TopXMLNS, __IgnoreEls, _el), + Email, Tel, Label, Fn, Version, N, Photo, Logo, + Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + decode_vcard_URL(<<"vcard-temp">>, __IgnoreEls, + _el), + Email, Tel, Label, Fn, Version, N, Photo, Logo, + Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) + end; +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"DESC">>, _attrs, _} = _el | _els], Mailer, + Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, + Sound, Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, + N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, + decode_vcard_DESC(__TopXMLNS, __IgnoreEls, _el), + Uid, Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, + decode_vcard_DESC(<<"vcard-temp">>, __IgnoreEls, + _el), + Uid, Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) + end; +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"CATEGORIES">>, _attrs, _} = _el | _els], + Mailer, Adr, Class, Categories, Desc, Uid, Prodid, + Jabberid, Sound, Note, Role, Title, Nickname, Rev, + Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, Label, + Fn, Version, N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, + decode_vcard_CATEGORIES(__TopXMLNS, __IgnoreEls, + _el), + Desc, Uid, Prodid, Jabberid, Sound, Note, Role, + Title, Nickname, Rev, Sort_string, Org, Bday, + Key, Tz, Url, Email, Tel, Label, Fn, Version, N, + Photo, Logo, Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, + decode_vcard_CATEGORIES(<<"vcard-temp">>, + __IgnoreEls, _el), + Desc, Uid, Prodid, Jabberid, Sound, Note, Role, + Title, Nickname, Rev, Sort_string, Org, Bday, + Key, Tz, Url, Email, Tel, Label, Fn, Version, N, + Photo, Logo, Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) + end; +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"CLASS">>, _attrs, _} = _el | _els], Mailer, + Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, + Sound, Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, + N, Photo, Logo, Geo) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, + decode_vcard_CLASS(__TopXMLNS, __IgnoreEls, + _el), + Categories, Desc, Uid, Prodid, Jabberid, Sound, + Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, + Version, N, Photo, Logo, Geo); + <<"vcard-temp">> -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, + decode_vcard_CLASS(<<"vcard-temp">>, + __IgnoreEls, _el), + Categories, Desc, Uid, Prodid, Jabberid, Sound, + Note, Role, Title, Nickname, Rev, Sort_string, + Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, + Version, N, Photo, Logo, Geo); + _ -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, + Nickname, Rev, Sort_string, Org, Bday, Key, Tz, + Url, Email, Tel, Label, Fn, Version, N, Photo, + Logo, Geo) + end; +decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Mailer, Adr, Class, Categories, Desc, Uid, + Prodid, Jabberid, Sound, Note, Role, Title, Nickname, + Rev, Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, + Label, Fn, Version, N, Photo, Logo, Geo) -> + decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, + Mailer, Adr, Class, Categories, Desc, Uid, Prodid, + Jabberid, Sound, Note, Role, Title, Nickname, Rev, + Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, + Label, Fn, Version, N, Photo, Logo, Geo). -encode_vcard({vcard, Version, Fn, N, Nickname, Photo, - Bday, Adr, Label, Tel, Email, Jabberid, Mailer, Tz, Geo, - Title, Role, Logo, Org, Categories, Note, Prodid, Rev, - Sort_string, Sound, Uid, Url, Class, Key, Desc}, - _xmlns_attrs) -> - _els = lists:reverse('encode_vcard_$mailer'(Mailer, - 'encode_vcard_$adr'(Adr, - 'encode_vcard_$class'(Class, - 'encode_vcard_$categories'(Categories, - 'encode_vcard_$desc'(Desc, - 'encode_vcard_$uid'(Uid, - 'encode_vcard_$prodid'(Prodid, - 'encode_vcard_$jabberid'(Jabberid, - 'encode_vcard_$sound'(Sound, - 'encode_vcard_$note'(Note, - 'encode_vcard_$role'(Role, - 'encode_vcard_$title'(Title, - 'encode_vcard_$nickname'(Nickname, - 'encode_vcard_$rev'(Rev, - 'encode_vcard_$sort_string'(Sort_string, - 'encode_vcard_$org'(Org, - 'encode_vcard_$bday'(Bday, - 'encode_vcard_$key'(Key, - 'encode_vcard_$tz'(Tz, - 'encode_vcard_$url'(Url, - 'encode_vcard_$email'(Email, - 'encode_vcard_$tel'(Tel, - 'encode_vcard_$label'(Label, - 'encode_vcard_$fn'(Fn, - 'encode_vcard_$version'(Version, - 'encode_vcard_$n'(N, - 'encode_vcard_$photo'(Photo, - 'encode_vcard_$logo'(Logo, - 'encode_vcard_$geo'(Geo, - [])))))))))))))))))))))))))))))), +encode_vcard_temp({vcard_temp, Version, Fn, N, Nickname, + Photo, Bday, Adr, Label, Tel, Email, Jabberid, Mailer, + Tz, Geo, Title, Role, Logo, Org, Categories, Note, + Prodid, Rev, Sort_string, Sound, Uid, Url, Class, Key, + Desc}, + _xmlns_attrs) -> + _els = lists:reverse('encode_vcard_temp_$mailer'(Mailer, + 'encode_vcard_temp_$adr'(Adr, + 'encode_vcard_temp_$class'(Class, + 'encode_vcard_temp_$categories'(Categories, + 'encode_vcard_temp_$desc'(Desc, + 'encode_vcard_temp_$uid'(Uid, + 'encode_vcard_temp_$prodid'(Prodid, + 'encode_vcard_temp_$jabberid'(Jabberid, + 'encode_vcard_temp_$sound'(Sound, + 'encode_vcard_temp_$note'(Note, + 'encode_vcard_temp_$role'(Role, + 'encode_vcard_temp_$title'(Title, + 'encode_vcard_temp_$nickname'(Nickname, + 'encode_vcard_temp_$rev'(Rev, + 'encode_vcard_temp_$sort_string'(Sort_string, + 'encode_vcard_temp_$org'(Org, + 'encode_vcard_temp_$bday'(Bday, + 'encode_vcard_temp_$key'(Key, + 'encode_vcard_temp_$tz'(Tz, + 'encode_vcard_temp_$url'(Url, + 'encode_vcard_temp_$email'(Email, + 'encode_vcard_temp_$tel'(Tel, + 'encode_vcard_temp_$label'(Label, + 'encode_vcard_temp_$fn'(Fn, + 'encode_vcard_temp_$version'(Version, + 'encode_vcard_temp_$n'(N, + 'encode_vcard_temp_$photo'(Photo, + 'encode_vcard_temp_$logo'(Logo, + 'encode_vcard_temp_$geo'(Geo, + [])))))))))))))))))))))))))))))), _attrs = _xmlns_attrs, {xmlel, <<"vCard">>, _attrs, _els}. -'encode_vcard_$mailer'(undefined, _acc) -> _acc; -'encode_vcard_$mailer'(Mailer, _acc) -> +'encode_vcard_temp_$mailer'(undefined, _acc) -> _acc; +'encode_vcard_temp_$mailer'(Mailer, _acc) -> [encode_vcard_MAILER(Mailer, []) | _acc]. -'encode_vcard_$adr'([], _acc) -> _acc; -'encode_vcard_$adr'([Adr | _els], _acc) -> - 'encode_vcard_$adr'(_els, - [encode_vcard_ADR(Adr, []) | _acc]). +'encode_vcard_temp_$adr'([], _acc) -> _acc; +'encode_vcard_temp_$adr'([Adr | _els], _acc) -> + 'encode_vcard_temp_$adr'(_els, + [encode_vcard_ADR(Adr, []) | _acc]). -'encode_vcard_$class'(undefined, _acc) -> _acc; -'encode_vcard_$class'(Class, _acc) -> +'encode_vcard_temp_$class'(undefined, _acc) -> _acc; +'encode_vcard_temp_$class'(Class, _acc) -> [encode_vcard_CLASS(Class, []) | _acc]. -'encode_vcard_$categories'([], _acc) -> _acc; -'encode_vcard_$categories'(Categories, _acc) -> +'encode_vcard_temp_$categories'([], _acc) -> _acc; +'encode_vcard_temp_$categories'(Categories, _acc) -> [encode_vcard_CATEGORIES(Categories, []) | _acc]. -'encode_vcard_$desc'(undefined, _acc) -> _acc; -'encode_vcard_$desc'(Desc, _acc) -> +'encode_vcard_temp_$desc'(undefined, _acc) -> _acc; +'encode_vcard_temp_$desc'(Desc, _acc) -> [encode_vcard_DESC(Desc, []) | _acc]. -'encode_vcard_$uid'(undefined, _acc) -> _acc; -'encode_vcard_$uid'(Uid, _acc) -> +'encode_vcard_temp_$uid'(undefined, _acc) -> _acc; +'encode_vcard_temp_$uid'(Uid, _acc) -> [encode_vcard_UID(Uid, []) | _acc]. -'encode_vcard_$prodid'(undefined, _acc) -> _acc; -'encode_vcard_$prodid'(Prodid, _acc) -> +'encode_vcard_temp_$prodid'(undefined, _acc) -> _acc; +'encode_vcard_temp_$prodid'(Prodid, _acc) -> [encode_vcard_PRODID(Prodid, []) | _acc]. -'encode_vcard_$jabberid'(undefined, _acc) -> _acc; -'encode_vcard_$jabberid'(Jabberid, _acc) -> +'encode_vcard_temp_$jabberid'(undefined, _acc) -> _acc; +'encode_vcard_temp_$jabberid'(Jabberid, _acc) -> [encode_vcard_JABBERID(Jabberid, []) | _acc]. -'encode_vcard_$sound'(undefined, _acc) -> _acc; -'encode_vcard_$sound'(Sound, _acc) -> +'encode_vcard_temp_$sound'(undefined, _acc) -> _acc; +'encode_vcard_temp_$sound'(Sound, _acc) -> [encode_vcard_SOUND(Sound, []) | _acc]. -'encode_vcard_$note'(undefined, _acc) -> _acc; -'encode_vcard_$note'(Note, _acc) -> +'encode_vcard_temp_$note'(undefined, _acc) -> _acc; +'encode_vcard_temp_$note'(Note, _acc) -> [encode_vcard_NOTE(Note, []) | _acc]. -'encode_vcard_$role'(undefined, _acc) -> _acc; -'encode_vcard_$role'(Role, _acc) -> +'encode_vcard_temp_$role'(undefined, _acc) -> _acc; +'encode_vcard_temp_$role'(Role, _acc) -> [encode_vcard_ROLE(Role, []) | _acc]. -'encode_vcard_$title'(undefined, _acc) -> _acc; -'encode_vcard_$title'(Title, _acc) -> +'encode_vcard_temp_$title'(undefined, _acc) -> _acc; +'encode_vcard_temp_$title'(Title, _acc) -> [encode_vcard_TITLE(Title, []) | _acc]. -'encode_vcard_$nickname'(undefined, _acc) -> _acc; -'encode_vcard_$nickname'(Nickname, _acc) -> +'encode_vcard_temp_$nickname'(undefined, _acc) -> _acc; +'encode_vcard_temp_$nickname'(Nickname, _acc) -> [encode_vcard_NICKNAME(Nickname, []) | _acc]. -'encode_vcard_$rev'(undefined, _acc) -> _acc; -'encode_vcard_$rev'(Rev, _acc) -> +'encode_vcard_temp_$rev'(undefined, _acc) -> _acc; +'encode_vcard_temp_$rev'(Rev, _acc) -> [encode_vcard_REV(Rev, []) | _acc]. -'encode_vcard_$sort_string'(undefined, _acc) -> _acc; -'encode_vcard_$sort_string'(Sort_string, _acc) -> +'encode_vcard_temp_$sort_string'(undefined, _acc) -> + _acc; +'encode_vcard_temp_$sort_string'(Sort_string, _acc) -> [encode_vcard_SORT_STRING(Sort_string, []) | _acc]. -'encode_vcard_$org'(undefined, _acc) -> _acc; -'encode_vcard_$org'(Org, _acc) -> +'encode_vcard_temp_$org'(undefined, _acc) -> _acc; +'encode_vcard_temp_$org'(Org, _acc) -> [encode_vcard_ORG(Org, []) | _acc]. -'encode_vcard_$bday'(undefined, _acc) -> _acc; -'encode_vcard_$bday'(Bday, _acc) -> +'encode_vcard_temp_$bday'(undefined, _acc) -> _acc; +'encode_vcard_temp_$bday'(Bday, _acc) -> [encode_vcard_BDAY(Bday, []) | _acc]. -'encode_vcard_$key'(undefined, _acc) -> _acc; -'encode_vcard_$key'(Key, _acc) -> +'encode_vcard_temp_$key'(undefined, _acc) -> _acc; +'encode_vcard_temp_$key'(Key, _acc) -> [encode_vcard_KEY(Key, []) | _acc]. -'encode_vcard_$tz'(undefined, _acc) -> _acc; -'encode_vcard_$tz'(Tz, _acc) -> +'encode_vcard_temp_$tz'(undefined, _acc) -> _acc; +'encode_vcard_temp_$tz'(Tz, _acc) -> [encode_vcard_TZ(Tz, []) | _acc]. -'encode_vcard_$url'(undefined, _acc) -> _acc; -'encode_vcard_$url'(Url, _acc) -> +'encode_vcard_temp_$url'(undefined, _acc) -> _acc; +'encode_vcard_temp_$url'(Url, _acc) -> [encode_vcard_URL(Url, []) | _acc]. -'encode_vcard_$email'([], _acc) -> _acc; -'encode_vcard_$email'([Email | _els], _acc) -> - 'encode_vcard_$email'(_els, - [encode_vcard_EMAIL(Email, []) | _acc]). +'encode_vcard_temp_$email'([], _acc) -> _acc; +'encode_vcard_temp_$email'([Email | _els], _acc) -> + 'encode_vcard_temp_$email'(_els, + [encode_vcard_EMAIL(Email, []) | _acc]). -'encode_vcard_$tel'([], _acc) -> _acc; -'encode_vcard_$tel'([Tel | _els], _acc) -> - 'encode_vcard_$tel'(_els, - [encode_vcard_TEL(Tel, []) | _acc]). +'encode_vcard_temp_$tel'([], _acc) -> _acc; +'encode_vcard_temp_$tel'([Tel | _els], _acc) -> + 'encode_vcard_temp_$tel'(_els, + [encode_vcard_TEL(Tel, []) | _acc]). -'encode_vcard_$label'([], _acc) -> _acc; -'encode_vcard_$label'([Label | _els], _acc) -> - 'encode_vcard_$label'(_els, - [encode_vcard_LABEL(Label, []) | _acc]). +'encode_vcard_temp_$label'([], _acc) -> _acc; +'encode_vcard_temp_$label'([Label | _els], _acc) -> + 'encode_vcard_temp_$label'(_els, + [encode_vcard_LABEL(Label, []) | _acc]). -'encode_vcard_$fn'(undefined, _acc) -> _acc; -'encode_vcard_$fn'(Fn, _acc) -> +'encode_vcard_temp_$fn'(undefined, _acc) -> _acc; +'encode_vcard_temp_$fn'(Fn, _acc) -> [encode_vcard_FN(Fn, []) | _acc]. -'encode_vcard_$version'(undefined, _acc) -> _acc; -'encode_vcard_$version'(Version, _acc) -> +'encode_vcard_temp_$version'(undefined, _acc) -> _acc; +'encode_vcard_temp_$version'(Version, _acc) -> [encode_vcard_VERSION(Version, []) | _acc]. -'encode_vcard_$n'(undefined, _acc) -> _acc; -'encode_vcard_$n'(N, _acc) -> +'encode_vcard_temp_$n'(undefined, _acc) -> _acc; +'encode_vcard_temp_$n'(N, _acc) -> [encode_vcard_N(N, []) | _acc]. -'encode_vcard_$photo'(undefined, _acc) -> _acc; -'encode_vcard_$photo'(Photo, _acc) -> +'encode_vcard_temp_$photo'(undefined, _acc) -> _acc; +'encode_vcard_temp_$photo'(Photo, _acc) -> [encode_vcard_PHOTO(Photo, []) | _acc]. -'encode_vcard_$logo'(undefined, _acc) -> _acc; -'encode_vcard_$logo'(Logo, _acc) -> +'encode_vcard_temp_$logo'(undefined, _acc) -> _acc; +'encode_vcard_temp_$logo'(Logo, _acc) -> [encode_vcard_LOGO(Logo, []) | _acc]. -'encode_vcard_$geo'(undefined, _acc) -> _acc; -'encode_vcard_$geo'(Geo, _acc) -> +'encode_vcard_temp_$geo'(undefined, _acc) -> _acc; +'encode_vcard_temp_$geo'(Geo, _acc) -> [encode_vcard_GEO(Geo, []) | _acc]. decode_vcard_CLASS(__TopXMLNS, __IgnoreEls, @@ -10056,38 +11714,50 @@ decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, [], decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"PUBLIC">>, _attrs, _} = _el | _els], Class) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_PUBLIC(__TopXMLNS, __IgnoreEls, - _el)); - true -> - decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, - Class) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_PUBLIC(__TopXMLNS, __IgnoreEls, + _el)); + <<"vcard-temp">> -> + decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_PUBLIC(<<"vcard-temp">>, + __IgnoreEls, _el)); + _ -> + decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, + Class) end; decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"PRIVATE">>, _attrs, _} = _el | _els], Class) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_PRIVATE(__TopXMLNS, __IgnoreEls, - _el)); - true -> - decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, - Class) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_PRIVATE(__TopXMLNS, __IgnoreEls, + _el)); + <<"vcard-temp">> -> + decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_PRIVATE(<<"vcard-temp">>, + __IgnoreEls, _el)); + _ -> + decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, + Class) end; decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"CONFIDENTIAL">>, _attrs, _} = _el | _els], Class) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_CONFIDENTIAL(__TopXMLNS, - __IgnoreEls, _el)); - true -> - decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, - Class) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_CONFIDENTIAL(__TopXMLNS, + __IgnoreEls, _el)); + <<"vcard-temp">> -> + decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_CONFIDENTIAL(<<"vcard-temp">>, + __IgnoreEls, _el)); + _ -> + decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, + Class) end; decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, [_ | _els], Class) -> @@ -10121,20 +11791,30 @@ decode_vcard_CATEGORIES_els(__TopXMLNS, __IgnoreEls, [], decode_vcard_CATEGORIES_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"KEYWORD">>, _attrs, _} = _el | _els], Keywords) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_CATEGORIES_els(__TopXMLNS, __IgnoreEls, - _els, - case decode_vcard_KEYWORD(__TopXMLNS, - __IgnoreEls, - _el) - of - undefined -> Keywords; - _new_el -> [_new_el | Keywords] - end); - true -> - decode_vcard_CATEGORIES_els(__TopXMLNS, __IgnoreEls, - _els, Keywords) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_CATEGORIES_els(__TopXMLNS, __IgnoreEls, + _els, + case decode_vcard_KEYWORD(__TopXMLNS, + __IgnoreEls, + _el) + of + undefined -> Keywords; + _new_el -> [_new_el | Keywords] + end); + <<"vcard-temp">> -> + decode_vcard_CATEGORIES_els(__TopXMLNS, __IgnoreEls, + _els, + case + decode_vcard_KEYWORD(<<"vcard-temp">>, + __IgnoreEls, _el) + of + undefined -> Keywords; + _new_el -> [_new_el | Keywords] + end); + _ -> + decode_vcard_CATEGORIES_els(__TopXMLNS, __IgnoreEls, + _els, Keywords) end; decode_vcard_CATEGORIES_els(__TopXMLNS, __IgnoreEls, [_ | _els], Keywords) -> @@ -10168,27 +11848,36 @@ decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, [], Cred, decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"TYPE">>, _attrs, _} = _el | _els], Cred, Type) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, _els, - Cred, - decode_vcard_TYPE(__TopXMLNS, __IgnoreEls, - _el)); - true -> - decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, _els, - Cred, Type) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, _els, + Cred, + decode_vcard_TYPE(__TopXMLNS, __IgnoreEls, _el)); + <<"vcard-temp">> -> + decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, _els, + Cred, + decode_vcard_TYPE(<<"vcard-temp">>, __IgnoreEls, + _el)); + _ -> + decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, _els, + Cred, Type) end; decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"CRED">>, _attrs, _} = _el | _els], Cred, Type) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_CRED(__TopXMLNS, __IgnoreEls, _el), - Type); - true -> - decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, _els, - Cred, Type) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_CRED(__TopXMLNS, __IgnoreEls, _el), + Type); + <<"vcard-temp">> -> + decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_CRED(<<"vcard-temp">>, __IgnoreEls, + _el), + Type); + _ -> + decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, _els, + Cred, Type) end; decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, [_ | _els], Cred, Type) -> @@ -10224,42 +11913,58 @@ decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, [], decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"BINVAL">>, _attrs, _} = _el | _els], Phonetic, Extval, Binval) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, - Phonetic, Extval, - decode_vcard_BINVAL(__TopXMLNS, __IgnoreEls, - _el)); - true -> - decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, - Phonetic, Extval, Binval) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, + Phonetic, Extval, + decode_vcard_BINVAL(__TopXMLNS, __IgnoreEls, + _el)); + <<"vcard-temp">> -> + decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, + Phonetic, Extval, + decode_vcard_BINVAL(<<"vcard-temp">>, + __IgnoreEls, _el)); + _ -> + decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, + Phonetic, Extval, Binval) end; decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"EXTVAL">>, _attrs, _} = _el | _els], Phonetic, Extval, Binval) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, - Phonetic, - decode_vcard_EXTVAL(__TopXMLNS, __IgnoreEls, - _el), - Binval); - true -> - decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, - Phonetic, Extval, Binval) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, + Phonetic, + decode_vcard_EXTVAL(__TopXMLNS, __IgnoreEls, + _el), + Binval); + <<"vcard-temp">> -> + decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, + Phonetic, + decode_vcard_EXTVAL(<<"vcard-temp">>, + __IgnoreEls, _el), + Binval); + _ -> + decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, + Phonetic, Extval, Binval) end; decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"PHONETIC">>, _attrs, _} = _el | _els], Phonetic, Extval, Binval) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_PHONETIC(__TopXMLNS, __IgnoreEls, - _el), - Extval, Binval); - true -> - decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, - Phonetic, Extval, Binval) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_PHONETIC(__TopXMLNS, __IgnoreEls, + _el), + Extval, Binval); + <<"vcard-temp">> -> + decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_PHONETIC(<<"vcard-temp">>, + __IgnoreEls, _el), + Extval, Binval); + _ -> + decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, + Phonetic, Extval, Binval) end; decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, [_ | _els], Phonetic, Extval, Binval) -> @@ -10301,32 +12006,46 @@ decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, [], Units, decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"ORGNAME">>, _attrs, _} = _el | _els], Units, Name) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, _els, - Units, - decode_vcard_ORGNAME(__TopXMLNS, __IgnoreEls, - _el)); - true -> - decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, _els, - Units, Name) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, _els, + Units, + decode_vcard_ORGNAME(__TopXMLNS, __IgnoreEls, + _el)); + <<"vcard-temp">> -> + decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, _els, + Units, + decode_vcard_ORGNAME(<<"vcard-temp">>, + __IgnoreEls, _el)); + _ -> + decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, _els, + Units, Name) end; decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"ORGUNIT">>, _attrs, _} = _el | _els], Units, Name) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, _els, - case decode_vcard_ORGUNIT(__TopXMLNS, - __IgnoreEls, _el) - of - undefined -> Units; - _new_el -> [_new_el | Units] - end, - Name); - true -> - decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, _els, - Units, Name) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, _els, + case decode_vcard_ORGUNIT(__TopXMLNS, + __IgnoreEls, _el) + of + undefined -> Units; + _new_el -> [_new_el | Units] + end, + Name); + <<"vcard-temp">> -> + decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, _els, + case decode_vcard_ORGUNIT(<<"vcard-temp">>, + __IgnoreEls, _el) + of + undefined -> Units; + _new_el -> [_new_el | Units] + end, + Name); + _ -> + decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, _els, + Units, Name) end; decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, [_ | _els], Units, Name) -> @@ -10363,42 +12082,58 @@ decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, [], decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"TYPE">>, _attrs, _} = _el | _els], Type, Extval, Binval) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_TYPE(__TopXMLNS, __IgnoreEls, - _el), - Extval, Binval); - true -> - decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, - Type, Extval, Binval) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_TYPE(__TopXMLNS, __IgnoreEls, + _el), + Extval, Binval); + <<"vcard-temp">> -> + decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_TYPE(<<"vcard-temp">>, + __IgnoreEls, _el), + Extval, Binval); + _ -> + decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, + Type, Extval, Binval) end; decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"BINVAL">>, _attrs, _} = _el | _els], Type, Extval, Binval) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, - Type, Extval, - decode_vcard_BINVAL(__TopXMLNS, __IgnoreEls, - _el)); - true -> - decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, - Type, Extval, Binval) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, + Type, Extval, + decode_vcard_BINVAL(__TopXMLNS, __IgnoreEls, + _el)); + <<"vcard-temp">> -> + decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, + Type, Extval, + decode_vcard_BINVAL(<<"vcard-temp">>, + __IgnoreEls, _el)); + _ -> + decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, + Type, Extval, Binval) end; decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"EXTVAL">>, _attrs, _} = _el | _els], Type, Extval, Binval) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, - Type, - decode_vcard_EXTVAL(__TopXMLNS, __IgnoreEls, - _el), - Binval); - true -> - decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, - Type, Extval, Binval) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, + Type, + decode_vcard_EXTVAL(__TopXMLNS, __IgnoreEls, + _el), + Binval); + <<"vcard-temp">> -> + decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, + Type, + decode_vcard_EXTVAL(<<"vcard-temp">>, + __IgnoreEls, _el), + Binval); + _ -> + decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, + Type, Extval, Binval) end; decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, [_ | _els], Type, Extval, Binval) -> @@ -10439,42 +12174,57 @@ decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, [], Type, decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"TYPE">>, _attrs, _} = _el | _els], Type, Extval, Binval) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_TYPE(__TopXMLNS, __IgnoreEls, - _el), - Extval, Binval); - true -> - decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, - Type, Extval, Binval) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_TYPE(__TopXMLNS, __IgnoreEls, _el), + Extval, Binval); + <<"vcard-temp">> -> + decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_TYPE(<<"vcard-temp">>, __IgnoreEls, + _el), + Extval, Binval); + _ -> + decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, + Type, Extval, Binval) end; decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"BINVAL">>, _attrs, _} = _el | _els], Type, Extval, Binval) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, - Type, Extval, - decode_vcard_BINVAL(__TopXMLNS, __IgnoreEls, - _el)); - true -> - decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, - Type, Extval, Binval) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, + Type, Extval, + decode_vcard_BINVAL(__TopXMLNS, __IgnoreEls, + _el)); + <<"vcard-temp">> -> + decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, + Type, Extval, + decode_vcard_BINVAL(<<"vcard-temp">>, + __IgnoreEls, _el)); + _ -> + decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, + Type, Extval, Binval) end; decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"EXTVAL">>, _attrs, _} = _el | _els], Type, Extval, Binval) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, - Type, - decode_vcard_EXTVAL(__TopXMLNS, __IgnoreEls, - _el), - Binval); - true -> - decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, - Type, Extval, Binval) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, + Type, + decode_vcard_EXTVAL(__TopXMLNS, __IgnoreEls, + _el), + Binval); + <<"vcard-temp">> -> + decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, + Type, + decode_vcard_EXTVAL(<<"vcard-temp">>, + __IgnoreEls, _el), + Binval); + _ -> + decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, + Type, Extval, Binval) end; decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, [_ | _els], Type, Extval, Binval) -> @@ -10551,25 +12301,34 @@ decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, [], Lat, decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"LAT">>, _attrs, _} = _el | _els], Lat, Lon) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_LAT(__TopXMLNS, __IgnoreEls, _el), - Lon); - true -> - decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, _els, Lat, - Lon) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_LAT(__TopXMLNS, __IgnoreEls, _el), + Lon); + <<"vcard-temp">> -> + decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_LAT(<<"vcard-temp">>, __IgnoreEls, + _el), + Lon); + _ -> + decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, _els, Lat, + Lon) end; decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"LON">>, _attrs, _} = _el | _els], Lat, Lon) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, _els, Lat, - decode_vcard_LON(__TopXMLNS, __IgnoreEls, _el)); - true -> - decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, _els, Lat, - Lon) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, _els, Lat, + decode_vcard_LON(__TopXMLNS, __IgnoreEls, _el)); + <<"vcard-temp">> -> + decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, _els, Lat, + decode_vcard_LON(<<"vcard-temp">>, __IgnoreEls, + _el)); + _ -> + decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, _els, Lat, + Lon) end; decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, [_ | _els], Lat, Lon) -> @@ -10604,84 +12363,118 @@ decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, [], decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"HOME">>, _attrs, _} = _el | _els], X400, Userid, Internet, Home, Pref, Work) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, Userid, Internet, - decode_vcard_HOME(__TopXMLNS, __IgnoreEls, - _el), - Pref, Work); - true -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, Userid, Internet, Home, Pref, Work) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, + X400, Userid, Internet, + decode_vcard_HOME(__TopXMLNS, __IgnoreEls, + _el), + Pref, Work); + <<"vcard-temp">> -> + decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, + X400, Userid, Internet, + decode_vcard_HOME(<<"vcard-temp">>, + __IgnoreEls, _el), + Pref, Work); + _ -> + decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, + X400, Userid, Internet, Home, Pref, Work) end; decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"WORK">>, _attrs, _} = _el | _els], X400, Userid, Internet, Home, Pref, Work) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, Userid, Internet, Home, Pref, - decode_vcard_WORK(__TopXMLNS, __IgnoreEls, - _el)); - true -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, Userid, Internet, Home, Pref, Work) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, + X400, Userid, Internet, Home, Pref, + decode_vcard_WORK(__TopXMLNS, __IgnoreEls, + _el)); + <<"vcard-temp">> -> + decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, + X400, Userid, Internet, Home, Pref, + decode_vcard_WORK(<<"vcard-temp">>, + __IgnoreEls, _el)); + _ -> + decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, + X400, Userid, Internet, Home, Pref, Work) end; decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"INTERNET">>, _attrs, _} = _el | _els], X400, Userid, Internet, Home, Pref, Work) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, Userid, - decode_vcard_INTERNET(__TopXMLNS, __IgnoreEls, - _el), - Home, Pref, Work); - true -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, Userid, Internet, Home, Pref, Work) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, + X400, Userid, + decode_vcard_INTERNET(__TopXMLNS, __IgnoreEls, + _el), + Home, Pref, Work); + <<"vcard-temp">> -> + decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, + X400, Userid, + decode_vcard_INTERNET(<<"vcard-temp">>, + __IgnoreEls, _el), + Home, Pref, Work); + _ -> + decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, + X400, Userid, Internet, Home, Pref, Work) end; decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"PREF">>, _attrs, _} = _el | _els], X400, Userid, Internet, Home, Pref, Work) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, Userid, Internet, Home, - decode_vcard_PREF(__TopXMLNS, __IgnoreEls, - _el), - Work); - true -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, Userid, Internet, Home, Pref, Work) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, + X400, Userid, Internet, Home, + decode_vcard_PREF(__TopXMLNS, __IgnoreEls, + _el), + Work); + <<"vcard-temp">> -> + decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, + X400, Userid, Internet, Home, + decode_vcard_PREF(<<"vcard-temp">>, + __IgnoreEls, _el), + Work); + _ -> + decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, + X400, Userid, Internet, Home, Pref, Work) end; decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"X400">>, _attrs, _} = _el | _els], X400, Userid, Internet, Home, Pref, Work) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_X400(__TopXMLNS, __IgnoreEls, - _el), - Userid, Internet, Home, Pref, Work); - true -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, Userid, Internet, Home, Pref, Work) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_X400(__TopXMLNS, __IgnoreEls, + _el), + Userid, Internet, Home, Pref, Work); + <<"vcard-temp">> -> + decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_X400(<<"vcard-temp">>, + __IgnoreEls, _el), + Userid, Internet, Home, Pref, Work); + _ -> + decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, + X400, Userid, Internet, Home, Pref, Work) end; decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"USERID">>, _attrs, _} = _el | _els], X400, Userid, Internet, Home, Pref, Work) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, - decode_vcard_USERID(__TopXMLNS, __IgnoreEls, - _el), - Internet, Home, Pref, Work); - true -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, Userid, Internet, Home, Pref, Work) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, + X400, + decode_vcard_USERID(__TopXMLNS, __IgnoreEls, + _el), + Internet, Home, Pref, Work); + <<"vcard-temp">> -> + decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, + X400, + decode_vcard_USERID(<<"vcard-temp">>, + __IgnoreEls, _el), + Internet, Home, Pref, Work); + _ -> + decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, + X400, Userid, Internet, Home, Pref, Work) end; decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, [_ | _els], X400, Userid, Internet, Home, Pref, Work) -> @@ -10745,224 +12538,313 @@ decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"HOME">>, _attrs, _} = _el | _els], Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, Cell, Modem, Isdn, Video) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, - decode_vcard_HOME(__TopXMLNS, __IgnoreEls, _el), - Pref, Msg, Fax, Work, Cell, Modem, Isdn, Video); - true -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, + decode_vcard_HOME(__TopXMLNS, __IgnoreEls, _el), + Pref, Msg, Fax, Work, Cell, Modem, Isdn, Video); + <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, + decode_vcard_HOME(<<"vcard-temp">>, __IgnoreEls, + _el), + Pref, Msg, Fax, Work, Cell, Modem, Isdn, Video); + _ -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + Fax, Work, Cell, Modem, Isdn, Video) end; decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"WORK">>, _attrs, _} = _el | _els], Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, Cell, Modem, Isdn, Video) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, - decode_vcard_WORK(__TopXMLNS, __IgnoreEls, _el), - Cell, Modem, Isdn, Video); - true -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + Fax, + decode_vcard_WORK(__TopXMLNS, __IgnoreEls, _el), + Cell, Modem, Isdn, Video); + <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + Fax, + decode_vcard_WORK(<<"vcard-temp">>, __IgnoreEls, + _el), + Cell, Modem, Isdn, Video); + _ -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + Fax, Work, Cell, Modem, Isdn, Video) end; decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"VOICE">>, _attrs, _} = _el | _els], Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, Cell, Modem, Isdn, Video) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, - decode_vcard_VOICE(__TopXMLNS, __IgnoreEls, - _el), - Home, Pref, Msg, Fax, Work, Cell, Modem, Isdn, - Video); - true -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, + decode_vcard_VOICE(__TopXMLNS, __IgnoreEls, _el), + Home, Pref, Msg, Fax, Work, Cell, Modem, Isdn, + Video); + <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, + decode_vcard_VOICE(<<"vcard-temp">>, __IgnoreEls, + _el), + Home, Pref, Msg, Fax, Work, Cell, Modem, Isdn, + Video); + _ -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + Fax, Work, Cell, Modem, Isdn, Video) end; decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"FAX">>, _attrs, _} = _el | _els], Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, Cell, Modem, Isdn, Video) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - decode_vcard_FAX(__TopXMLNS, __IgnoreEls, _el), - Work, Cell, Modem, Isdn, Video); - true -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + decode_vcard_FAX(__TopXMLNS, __IgnoreEls, _el), + Work, Cell, Modem, Isdn, Video); + <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + decode_vcard_FAX(<<"vcard-temp">>, __IgnoreEls, + _el), + Work, Cell, Modem, Isdn, Video); + _ -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + Fax, Work, Cell, Modem, Isdn, Video) end; decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"PAGER">>, _attrs, _} = _el | _els], Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, Cell, Modem, Isdn, Video) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, - decode_vcard_PAGER(__TopXMLNS, __IgnoreEls, - _el), - Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, - Cell, Modem, Isdn, Video); - true -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, + decode_vcard_PAGER(__TopXMLNS, __IgnoreEls, _el), + Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, + Cell, Modem, Isdn, Video); + <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, + decode_vcard_PAGER(<<"vcard-temp">>, __IgnoreEls, + _el), + Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, + Cell, Modem, Isdn, Video); + _ -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + Fax, Work, Cell, Modem, Isdn, Video) end; decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"MSG">>, _attrs, _} = _el | _els], Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, Cell, Modem, Isdn, Video) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, - decode_vcard_MSG(__TopXMLNS, __IgnoreEls, _el), - Fax, Work, Cell, Modem, Isdn, Video); - true -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, + decode_vcard_MSG(__TopXMLNS, __IgnoreEls, _el), + Fax, Work, Cell, Modem, Isdn, Video); + <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, + decode_vcard_MSG(<<"vcard-temp">>, __IgnoreEls, + _el), + Fax, Work, Cell, Modem, Isdn, Video); + _ -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + Fax, Work, Cell, Modem, Isdn, Video) end; decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"CELL">>, _attrs, _} = _el | _els], Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, Cell, Modem, Isdn, Video) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, - decode_vcard_CELL(__TopXMLNS, __IgnoreEls, _el), - Modem, Isdn, Video); - true -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + Fax, Work, + decode_vcard_CELL(__TopXMLNS, __IgnoreEls, _el), + Modem, Isdn, Video); + <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + Fax, Work, + decode_vcard_CELL(<<"vcard-temp">>, __IgnoreEls, + _el), + Modem, Isdn, Video); + _ -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + Fax, Work, Cell, Modem, Isdn, Video) end; decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"VIDEO">>, _attrs, _} = _el | _els], Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, Cell, Modem, Isdn, Video) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, - decode_vcard_VIDEO(__TopXMLNS, __IgnoreEls, - _el)); - true -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + Fax, Work, Cell, Modem, Isdn, + decode_vcard_VIDEO(__TopXMLNS, __IgnoreEls, + _el)); + <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + Fax, Work, Cell, Modem, Isdn, + decode_vcard_VIDEO(<<"vcard-temp">>, __IgnoreEls, + _el)); + _ -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + Fax, Work, Cell, Modem, Isdn, Video) end; decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"BBS">>, _attrs, _} = _el | _els], Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, Cell, Modem, Isdn, Video) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, - decode_vcard_BBS(__TopXMLNS, __IgnoreEls, _el), - Voice, Home, Pref, Msg, Fax, Work, Cell, Modem, - Isdn, Video); - true -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, + decode_vcard_BBS(__TopXMLNS, __IgnoreEls, _el), + Voice, Home, Pref, Msg, Fax, Work, Cell, Modem, + Isdn, Video); + <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, + decode_vcard_BBS(<<"vcard-temp">>, __IgnoreEls, + _el), + Voice, Home, Pref, Msg, Fax, Work, Cell, Modem, + Isdn, Video); + _ -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + Fax, Work, Cell, Modem, Isdn, Video) end; decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"MODEM">>, _attrs, _} = _el | _els], Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, Cell, Modem, Isdn, Video) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, - decode_vcard_MODEM(__TopXMLNS, __IgnoreEls, - _el), - Isdn, Video); - true -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + Fax, Work, Cell, + decode_vcard_MODEM(__TopXMLNS, __IgnoreEls, _el), + Isdn, Video); + <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + Fax, Work, Cell, + decode_vcard_MODEM(<<"vcard-temp">>, __IgnoreEls, + _el), + Isdn, Video); + _ -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + Fax, Work, Cell, Modem, Isdn, Video) end; decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"ISDN">>, _attrs, _} = _el | _els], Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, Cell, Modem, Isdn, Video) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, - decode_vcard_ISDN(__TopXMLNS, __IgnoreEls, _el), - Video); - true -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + Fax, Work, Cell, Modem, + decode_vcard_ISDN(__TopXMLNS, __IgnoreEls, _el), + Video); + <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + Fax, Work, Cell, Modem, + decode_vcard_ISDN(<<"vcard-temp">>, __IgnoreEls, + _el), + Video); + _ -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + Fax, Work, Cell, Modem, Isdn, Video) end; decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"PCS">>, _attrs, _} = _el | _els], Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, Cell, Modem, Isdn, Video) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, - decode_vcard_PCS(__TopXMLNS, __IgnoreEls, _el), - Bbs, Voice, Home, Pref, Msg, Fax, Work, Cell, - Modem, Isdn, Video); - true -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, + decode_vcard_PCS(__TopXMLNS, __IgnoreEls, _el), + Bbs, Voice, Home, Pref, Msg, Fax, Work, Cell, + Modem, Isdn, Video); + <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, + decode_vcard_PCS(<<"vcard-temp">>, __IgnoreEls, + _el), + Bbs, Voice, Home, Pref, Msg, Fax, Work, Cell, + Modem, Isdn, Video); + _ -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + Fax, Work, Cell, Modem, Isdn, Video) end; decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"PREF">>, _attrs, _} = _el | _els], Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, Cell, Modem, Isdn, Video) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, - decode_vcard_PREF(__TopXMLNS, __IgnoreEls, _el), - Msg, Fax, Work, Cell, Modem, Isdn, Video); - true -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, + decode_vcard_PREF(__TopXMLNS, __IgnoreEls, _el), + Msg, Fax, Work, Cell, Modem, Isdn, Video); + <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, + decode_vcard_PREF(<<"vcard-temp">>, __IgnoreEls, + _el), + Msg, Fax, Work, Cell, Modem, Isdn, Video); + _ -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + Fax, Work, Cell, Modem, Isdn, Video) end; decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"NUMBER">>, _attrs, _} = _el | _els], Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, Cell, Modem, Isdn, Video) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_NUMBER(__TopXMLNS, __IgnoreEls, - _el), - Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, - Work, Cell, Modem, Isdn, Video); - true -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_NUMBER(__TopXMLNS, __IgnoreEls, + _el), + Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, + Work, Cell, Modem, Isdn, Video); + <<"vcard-temp">> -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_NUMBER(<<"vcard-temp">>, + __IgnoreEls, _el), + Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, + Work, Cell, Modem, Isdn, Video); + _ -> + decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, + Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, + Fax, Work, Cell, Modem, Isdn, Video) end; decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, [_ | _els], Number, Pager, Pcs, Bbs, Voice, Home, Pref, @@ -11065,124 +12947,174 @@ decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, [], decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"HOME">>, _attrs, _} = _el | _els], Line, Home, Pref, Work, Intl, Parcel, Postal, Dom) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, - decode_vcard_HOME(__TopXMLNS, __IgnoreEls, - _el), - Pref, Work, Intl, Parcel, Postal, Dom); - true -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, Parcel, Postal, - Dom) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, + Line, + decode_vcard_HOME(__TopXMLNS, __IgnoreEls, + _el), + Pref, Work, Intl, Parcel, Postal, Dom); + <<"vcard-temp">> -> + decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, + Line, + decode_vcard_HOME(<<"vcard-temp">>, + __IgnoreEls, _el), + Pref, Work, Intl, Parcel, Postal, Dom); + _ -> + decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, + Line, Home, Pref, Work, Intl, Parcel, Postal, + Dom) end; decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"WORK">>, _attrs, _} = _el | _els], Line, Home, Pref, Work, Intl, Parcel, Postal, Dom) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, - decode_vcard_WORK(__TopXMLNS, __IgnoreEls, - _el), - Intl, Parcel, Postal, Dom); - true -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, Parcel, Postal, - Dom) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, + Line, Home, Pref, + decode_vcard_WORK(__TopXMLNS, __IgnoreEls, + _el), + Intl, Parcel, Postal, Dom); + <<"vcard-temp">> -> + decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, + Line, Home, Pref, + decode_vcard_WORK(<<"vcard-temp">>, + __IgnoreEls, _el), + Intl, Parcel, Postal, Dom); + _ -> + decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, + Line, Home, Pref, Work, Intl, Parcel, Postal, + Dom) end; decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"POSTAL">>, _attrs, _} = _el | _els], Line, Home, Pref, Work, Intl, Parcel, Postal, Dom) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, Parcel, - decode_vcard_POSTAL(__TopXMLNS, __IgnoreEls, - _el), - Dom); - true -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, Parcel, Postal, - Dom) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, + Line, Home, Pref, Work, Intl, Parcel, + decode_vcard_POSTAL(__TopXMLNS, __IgnoreEls, + _el), + Dom); + <<"vcard-temp">> -> + decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, + Line, Home, Pref, Work, Intl, Parcel, + decode_vcard_POSTAL(<<"vcard-temp">>, + __IgnoreEls, _el), + Dom); + _ -> + decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, + Line, Home, Pref, Work, Intl, Parcel, Postal, + Dom) end; decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"PARCEL">>, _attrs, _} = _el | _els], Line, Home, Pref, Work, Intl, Parcel, Postal, Dom) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, - decode_vcard_PARCEL(__TopXMLNS, __IgnoreEls, - _el), - Postal, Dom); - true -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, Parcel, Postal, - Dom) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, + Line, Home, Pref, Work, Intl, + decode_vcard_PARCEL(__TopXMLNS, __IgnoreEls, + _el), + Postal, Dom); + <<"vcard-temp">> -> + decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, + Line, Home, Pref, Work, Intl, + decode_vcard_PARCEL(<<"vcard-temp">>, + __IgnoreEls, _el), + Postal, Dom); + _ -> + decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, + Line, Home, Pref, Work, Intl, Parcel, Postal, + Dom) end; decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"DOM">>, _attrs, _} = _el | _els], Line, Home, Pref, Work, Intl, Parcel, Postal, Dom) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, Parcel, Postal, - decode_vcard_DOM(__TopXMLNS, __IgnoreEls, - _el)); - true -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, Parcel, Postal, - Dom) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, + Line, Home, Pref, Work, Intl, Parcel, Postal, + decode_vcard_DOM(__TopXMLNS, __IgnoreEls, + _el)); + <<"vcard-temp">> -> + decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, + Line, Home, Pref, Work, Intl, Parcel, Postal, + decode_vcard_DOM(<<"vcard-temp">>, __IgnoreEls, + _el)); + _ -> + decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, + Line, Home, Pref, Work, Intl, Parcel, Postal, + Dom) end; decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"INTL">>, _attrs, _} = _el | _els], Line, Home, Pref, Work, Intl, Parcel, Postal, Dom) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, - decode_vcard_INTL(__TopXMLNS, __IgnoreEls, - _el), - Parcel, Postal, Dom); - true -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, Parcel, Postal, - Dom) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, + Line, Home, Pref, Work, + decode_vcard_INTL(__TopXMLNS, __IgnoreEls, + _el), + Parcel, Postal, Dom); + <<"vcard-temp">> -> + decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, + Line, Home, Pref, Work, + decode_vcard_INTL(<<"vcard-temp">>, + __IgnoreEls, _el), + Parcel, Postal, Dom); + _ -> + decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, + Line, Home, Pref, Work, Intl, Parcel, Postal, + Dom) end; decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"PREF">>, _attrs, _} = _el | _els], Line, Home, Pref, Work, Intl, Parcel, Postal, Dom) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, - decode_vcard_PREF(__TopXMLNS, __IgnoreEls, - _el), - Work, Intl, Parcel, Postal, Dom); - true -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, Parcel, Postal, - Dom) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, + Line, Home, + decode_vcard_PREF(__TopXMLNS, __IgnoreEls, + _el), + Work, Intl, Parcel, Postal, Dom); + <<"vcard-temp">> -> + decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, + Line, Home, + decode_vcard_PREF(<<"vcard-temp">>, + __IgnoreEls, _el), + Work, Intl, Parcel, Postal, Dom); + _ -> + decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, + Line, Home, Pref, Work, Intl, Parcel, Postal, + Dom) end; decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"LINE">>, _attrs, _} = _el | _els], Line, Home, Pref, Work, Intl, Parcel, Postal, Dom) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - case decode_vcard_LINE(__TopXMLNS, - __IgnoreEls, _el) - of - undefined -> Line; - _new_el -> [_new_el | Line] - end, - Home, Pref, Work, Intl, Parcel, Postal, Dom); - true -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, Parcel, Postal, - Dom) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, + case decode_vcard_LINE(__TopXMLNS, __IgnoreEls, + _el) + of + undefined -> Line; + _new_el -> [_new_el | Line] + end, + Home, Pref, Work, Intl, Parcel, Postal, Dom); + <<"vcard-temp">> -> + decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, + case decode_vcard_LINE(<<"vcard-temp">>, + __IgnoreEls, _el) + of + undefined -> Line; + _new_el -> [_new_el | Line] + end, + Home, Pref, Work, Intl, Parcel, Postal, Dom); + _ -> + decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, + Line, Home, Pref, Work, Intl, Parcel, Postal, + Dom) end; decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, [_ | _els], Line, Home, Pref, Work, Intl, Parcel, @@ -11258,245 +13190,337 @@ decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"HOME">>, _attrs, _} = _el | _els], Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, Intl, Parcel, Postal, Dom, Region) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, - decode_vcard_HOME(__TopXMLNS, __IgnoreEls, _el), - Pref, Pobox, Ctry, Locality, Work, Intl, Parcel, - Postal, Dom, Region); - true -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, + decode_vcard_HOME(__TopXMLNS, __IgnoreEls, _el), + Pref, Pobox, Ctry, Locality, Work, Intl, Parcel, + Postal, Dom, Region); + <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, + decode_vcard_HOME(<<"vcard-temp">>, __IgnoreEls, + _el), + Pref, Pobox, Ctry, Locality, Work, Intl, Parcel, + Postal, Dom, Region); + _ -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, Work, Intl, Parcel, Postal, Dom, + Region) end; decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"WORK">>, _attrs, _} = _el | _els], Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, Intl, Parcel, Postal, Dom, Region) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, - decode_vcard_WORK(__TopXMLNS, __IgnoreEls, _el), - Intl, Parcel, Postal, Dom, Region); - true -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, + decode_vcard_WORK(__TopXMLNS, __IgnoreEls, _el), + Intl, Parcel, Postal, Dom, Region); + <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, + decode_vcard_WORK(<<"vcard-temp">>, __IgnoreEls, + _el), + Intl, Parcel, Postal, Dom, Region); + _ -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, Work, Intl, Parcel, Postal, Dom, + Region) end; decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"POSTAL">>, _attrs, _} = _el | _els], Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, Intl, Parcel, Postal, Dom, Region) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, - decode_vcard_POSTAL(__TopXMLNS, __IgnoreEls, - _el), - Dom, Region); - true -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, Work, Intl, Parcel, + decode_vcard_POSTAL(__TopXMLNS, __IgnoreEls, + _el), + Dom, Region); + <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, Work, Intl, Parcel, + decode_vcard_POSTAL(<<"vcard-temp">>, + __IgnoreEls, _el), + Dom, Region); + _ -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, Work, Intl, Parcel, Postal, Dom, + Region) end; decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"PARCEL">>, _attrs, _} = _el | _els], Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, Intl, Parcel, Postal, Dom, Region) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, - decode_vcard_PARCEL(__TopXMLNS, __IgnoreEls, - _el), - Postal, Dom, Region); - true -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, Work, Intl, + decode_vcard_PARCEL(__TopXMLNS, __IgnoreEls, + _el), + Postal, Dom, Region); + <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, Work, Intl, + decode_vcard_PARCEL(<<"vcard-temp">>, + __IgnoreEls, _el), + Postal, Dom, Region); + _ -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, Work, Intl, Parcel, Postal, Dom, + Region) end; decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"DOM">>, _attrs, _} = _el | _els], Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, Intl, Parcel, Postal, Dom, Region) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, - decode_vcard_DOM(__TopXMLNS, __IgnoreEls, _el), - Region); - true -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, Work, Intl, Parcel, Postal, + decode_vcard_DOM(__TopXMLNS, __IgnoreEls, _el), + Region); + <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, Work, Intl, Parcel, Postal, + decode_vcard_DOM(<<"vcard-temp">>, __IgnoreEls, + _el), + Region); + _ -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, Work, Intl, Parcel, Postal, Dom, + Region) end; decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"INTL">>, _attrs, _} = _el | _els], Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, Intl, Parcel, Postal, Dom, Region) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, - decode_vcard_INTL(__TopXMLNS, __IgnoreEls, _el), - Parcel, Postal, Dom, Region); - true -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, Work, + decode_vcard_INTL(__TopXMLNS, __IgnoreEls, _el), + Parcel, Postal, Dom, Region); + <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, Work, + decode_vcard_INTL(<<"vcard-temp">>, __IgnoreEls, + _el), + Parcel, Postal, Dom, Region); + _ -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, Work, Intl, Parcel, Postal, Dom, + Region) end; decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"PREF">>, _attrs, _} = _el | _els], Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, Intl, Parcel, Postal, Dom, Region) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, - decode_vcard_PREF(__TopXMLNS, __IgnoreEls, _el), - Pobox, Ctry, Locality, Work, Intl, Parcel, - Postal, Dom, Region); - true -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, + decode_vcard_PREF(__TopXMLNS, __IgnoreEls, _el), + Pobox, Ctry, Locality, Work, Intl, Parcel, + Postal, Dom, Region); + <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, + decode_vcard_PREF(<<"vcard-temp">>, __IgnoreEls, + _el), + Pobox, Ctry, Locality, Work, Intl, Parcel, + Postal, Dom, Region); + _ -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, Work, Intl, Parcel, Postal, Dom, + Region) end; decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"POBOX">>, _attrs, _} = _el | _els], Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, Intl, Parcel, Postal, Dom, Region) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, - decode_vcard_POBOX(__TopXMLNS, __IgnoreEls, - _el), - Ctry, Locality, Work, Intl, Parcel, Postal, Dom, - Region); - true -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, + decode_vcard_POBOX(__TopXMLNS, __IgnoreEls, _el), + Ctry, Locality, Work, Intl, Parcel, Postal, Dom, + Region); + <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, + decode_vcard_POBOX(<<"vcard-temp">>, __IgnoreEls, + _el), + Ctry, Locality, Work, Intl, Parcel, Postal, Dom, + Region); + _ -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, Work, Intl, Parcel, Postal, Dom, + Region) end; decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"EXTADD">>, _attrs, _} = _el | _els], Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, Intl, Parcel, Postal, Dom, Region) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, - decode_vcard_EXTADD(__TopXMLNS, __IgnoreEls, - _el), - Pcode, Home, Pref, Pobox, Ctry, Locality, Work, - Intl, Parcel, Postal, Dom, Region); - true -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, + decode_vcard_EXTADD(__TopXMLNS, __IgnoreEls, + _el), + Pcode, Home, Pref, Pobox, Ctry, Locality, Work, + Intl, Parcel, Postal, Dom, Region); + <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, + decode_vcard_EXTADD(<<"vcard-temp">>, + __IgnoreEls, _el), + Pcode, Home, Pref, Pobox, Ctry, Locality, Work, + Intl, Parcel, Postal, Dom, Region); + _ -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, Work, Intl, Parcel, Postal, Dom, + Region) end; decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"STREET">>, _attrs, _} = _el | _els], Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, Intl, Parcel, Postal, Dom, Region) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_STREET(__TopXMLNS, __IgnoreEls, - _el), - Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region); - true -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_STREET(__TopXMLNS, __IgnoreEls, + _el), + Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, + Work, Intl, Parcel, Postal, Dom, Region); + <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_STREET(<<"vcard-temp">>, + __IgnoreEls, _el), + Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, + Work, Intl, Parcel, Postal, Dom, Region); + _ -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, Work, Intl, Parcel, Postal, Dom, + Region) end; decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"LOCALITY">>, _attrs, _} = _el | _els], Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, Intl, Parcel, Postal, Dom, Region) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - decode_vcard_LOCALITY(__TopXMLNS, __IgnoreEls, - _el), - Work, Intl, Parcel, Postal, Dom, Region); - true -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + decode_vcard_LOCALITY(__TopXMLNS, __IgnoreEls, + _el), + Work, Intl, Parcel, Postal, Dom, Region); + <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + decode_vcard_LOCALITY(<<"vcard-temp">>, + __IgnoreEls, _el), + Work, Intl, Parcel, Postal, Dom, Region); + _ -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, Work, Intl, Parcel, Postal, Dom, + Region) end; decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"REGION">>, _attrs, _} = _el | _els], Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, Intl, Parcel, Postal, Dom, Region) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - decode_vcard_REGION(__TopXMLNS, __IgnoreEls, - _el)); - true -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, Work, Intl, Parcel, Postal, Dom, + decode_vcard_REGION(__TopXMLNS, __IgnoreEls, + _el)); + <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, Work, Intl, Parcel, Postal, Dom, + decode_vcard_REGION(<<"vcard-temp">>, + __IgnoreEls, _el)); + _ -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, Work, Intl, Parcel, Postal, Dom, + Region) end; decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"PCODE">>, _attrs, _} = _el | _els], Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, Intl, Parcel, Postal, Dom, Region) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, - decode_vcard_PCODE(__TopXMLNS, __IgnoreEls, - _el), - Home, Pref, Pobox, Ctry, Locality, Work, Intl, - Parcel, Postal, Dom, Region); - true -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, + decode_vcard_PCODE(__TopXMLNS, __IgnoreEls, _el), + Home, Pref, Pobox, Ctry, Locality, Work, Intl, + Parcel, Postal, Dom, Region); + <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, + decode_vcard_PCODE(<<"vcard-temp">>, __IgnoreEls, + _el), + Home, Pref, Pobox, Ctry, Locality, Work, Intl, + Parcel, Postal, Dom, Region); + _ -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, Work, Intl, Parcel, Postal, Dom, + Region) end; decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"CTRY">>, _attrs, _} = _el | _els], Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, Intl, Parcel, Postal, Dom, Region) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, - decode_vcard_CTRY(__TopXMLNS, __IgnoreEls, _el), - Locality, Work, Intl, Parcel, Postal, Dom, - Region); - true -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, + decode_vcard_CTRY(__TopXMLNS, __IgnoreEls, _el), + Locality, Work, Intl, Parcel, Postal, Dom, + Region); + <<"vcard-temp">> -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, + decode_vcard_CTRY(<<"vcard-temp">>, __IgnoreEls, + _el), + Locality, Work, Intl, Parcel, Postal, Dom, + Region); + _ -> + decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, + Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, + Locality, Work, Intl, Parcel, Postal, Dom, + Region) end; decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, [_ | _els], Street, Extadd, Pcode, Home, Pref, Pobox, @@ -11598,65 +13622,93 @@ decode_vcard_N_els(__TopXMLNS, __IgnoreEls, [], Middle, decode_vcard_N_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"FAMILY">>, _attrs, _} = _el | _els], Middle, Suffix, Prefix, Family, Given) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - Middle, Suffix, Prefix, - decode_vcard_FAMILY(__TopXMLNS, __IgnoreEls, _el), - Given); - true -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - Middle, Suffix, Prefix, Family, Given) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, + Middle, Suffix, Prefix, + decode_vcard_FAMILY(__TopXMLNS, __IgnoreEls, _el), + Given); + <<"vcard-temp">> -> + decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, + Middle, Suffix, Prefix, + decode_vcard_FAMILY(<<"vcard-temp">>, __IgnoreEls, + _el), + Given); + _ -> + decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, + Middle, Suffix, Prefix, Family, Given) end; decode_vcard_N_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"GIVEN">>, _attrs, _} = _el | _els], Middle, Suffix, Prefix, Family, Given) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - Middle, Suffix, Prefix, Family, - decode_vcard_GIVEN(__TopXMLNS, __IgnoreEls, _el)); - true -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - Middle, Suffix, Prefix, Family, Given) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, + Middle, Suffix, Prefix, Family, + decode_vcard_GIVEN(__TopXMLNS, __IgnoreEls, _el)); + <<"vcard-temp">> -> + decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, + Middle, Suffix, Prefix, Family, + decode_vcard_GIVEN(<<"vcard-temp">>, __IgnoreEls, + _el)); + _ -> + decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, + Middle, Suffix, Prefix, Family, Given) end; decode_vcard_N_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"MIDDLE">>, _attrs, _} = _el | _els], Middle, Suffix, Prefix, Family, Given) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_MIDDLE(__TopXMLNS, __IgnoreEls, _el), - Suffix, Prefix, Family, Given); - true -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - Middle, Suffix, Prefix, Family, Given) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_MIDDLE(__TopXMLNS, __IgnoreEls, _el), + Suffix, Prefix, Family, Given); + <<"vcard-temp">> -> + decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, + decode_vcard_MIDDLE(<<"vcard-temp">>, __IgnoreEls, + _el), + Suffix, Prefix, Family, Given); + _ -> + decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, + Middle, Suffix, Prefix, Family, Given) end; decode_vcard_N_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"PREFIX">>, _attrs, _} = _el | _els], Middle, Suffix, Prefix, Family, Given) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - Middle, Suffix, - decode_vcard_PREFIX(__TopXMLNS, __IgnoreEls, _el), - Family, Given); - true -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - Middle, Suffix, Prefix, Family, Given) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, + Middle, Suffix, + decode_vcard_PREFIX(__TopXMLNS, __IgnoreEls, _el), + Family, Given); + <<"vcard-temp">> -> + decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, + Middle, Suffix, + decode_vcard_PREFIX(<<"vcard-temp">>, __IgnoreEls, + _el), + Family, Given); + _ -> + decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, + Middle, Suffix, Prefix, Family, Given) end; decode_vcard_N_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"SUFFIX">>, _attrs, _} = _el | _els], Middle, Suffix, Prefix, Family, Given) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - Middle, - decode_vcard_SUFFIX(__TopXMLNS, __IgnoreEls, _el), - Prefix, Family, Given); - true -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - Middle, Suffix, Prefix, Family, Given) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"vcard-temp">> -> + decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, + Middle, + decode_vcard_SUFFIX(__TopXMLNS, __IgnoreEls, _el), + Prefix, Family, Given); + <<"vcard-temp">> -> + decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, + Middle, + decode_vcard_SUFFIX(<<"vcard-temp">>, __IgnoreEls, + _el), + Prefix, Family, Given); + _ -> + decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, + Middle, Suffix, Prefix, Family, Given) end; decode_vcard_N_els(__TopXMLNS, __IgnoreEls, [_ | _els], Middle, Suffix, Prefix, Family, Given) -> @@ -13128,405 +15180,379 @@ decode_stream_error_els(__TopXMLNS, __IgnoreEls, [], decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"text">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - decode_stream_error_text(_xmlns, __IgnoreEls, - _el), - Reason); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + decode_stream_error_text(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, _el), + Reason); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"bad-format">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_bad_format(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_stream_error_bad_format(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, + _el)); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"bad-namespace-prefix">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_bad_namespace_prefix(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_stream_error_bad_namespace_prefix(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, + _el)); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"conflict">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_conflict(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_stream_error_conflict(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, + _el)); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"connection-timeout">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_connection_timeout(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_stream_error_connection_timeout(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, + _el)); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"host-gone">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_host_gone(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_stream_error_host_gone(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, + _el)); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"host-unknown">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_host_unknown(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_stream_error_host_unknown(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, + _el)); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"improper-addressing">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_improper_addressing(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_stream_error_improper_addressing(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, + _el)); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"internal-server-error">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_internal_server_error(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_stream_error_internal_server_error(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, + _el)); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"invalid-from">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_invalid_from(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_stream_error_invalid_from(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, + _el)); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"invalid-id">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_invalid_id(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_stream_error_invalid_id(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, + _el)); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"invalid-namespace">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_invalid_namespace(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_stream_error_invalid_namespace(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, + _el)); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"invalid-xml">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_invalid_xml(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_stream_error_invalid_xml(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, + _el)); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"not-authorized">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_not_authorized(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_stream_error_not_authorized(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, + _el)); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"not-well-formed">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_not_well_formed(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_stream_error_not_well_formed(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, + _el)); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"policy-violation">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_policy_violation(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_stream_error_policy_violation(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, + _el)); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"remote-connection-failed">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_remote_connection_failed(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_stream_error_remote_connection_failed(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, + _el)); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"reset">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_reset(_xmlns, - __IgnoreEls, _el)); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_stream_error_reset(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, _el)); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"resource-constraint">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_resource_constraint(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_stream_error_resource_constraint(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, + _el)); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"restricted-xml">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_restricted_xml(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_stream_error_restricted_xml(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, + _el)); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"see-other-host">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_see_other_host(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_stream_error_see_other_host(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, + _el)); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"system-shutdown">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_system_shutdown(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_stream_error_system_shutdown(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, + _el)); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"undefined-condition">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_undefined_condition(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_stream_error_undefined_condition(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, + _el)); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"unsupported-encoding">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_unsupported_encoding(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_stream_error_unsupported_encoding(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, + _el)); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"unsupported-stanza-type">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_unsupported_stanza_type(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_stream_error_unsupported_stanza_type(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, + _el)); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"unsupported-version">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_unsupported_version(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-streams">> -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_stream_error_unsupported_version(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + __IgnoreEls, + _el)); + _ -> + decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_stream_error_els(__TopXMLNS, __IgnoreEls, [_ | _els], Text, Reason) -> @@ -14105,22 +16131,31 @@ decode_time_els(__TopXMLNS, __IgnoreEls, [], Utc, decode_time_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"tzo">>, _attrs, _} = _el | _els], Utc, Tzo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_time_els(__TopXMLNS, __IgnoreEls, _els, Utc, - decode_time_tzo(__TopXMLNS, __IgnoreEls, _el)); - true -> - decode_time_els(__TopXMLNS, __IgnoreEls, _els, Utc, Tzo) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"urn:xmpp:time">> -> + decode_time_els(__TopXMLNS, __IgnoreEls, _els, Utc, + decode_time_tzo(__TopXMLNS, __IgnoreEls, _el)); + <<"urn:xmpp:time">> -> + decode_time_els(__TopXMLNS, __IgnoreEls, _els, Utc, + decode_time_tzo(<<"urn:xmpp:time">>, __IgnoreEls, + _el)); + _ -> + decode_time_els(__TopXMLNS, __IgnoreEls, _els, Utc, Tzo) end; decode_time_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"utc">>, _attrs, _} = _el | _els], Utc, Tzo) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_time_els(__TopXMLNS, __IgnoreEls, _els, - decode_time_utc(__TopXMLNS, __IgnoreEls, _el), Tzo); - true -> - decode_time_els(__TopXMLNS, __IgnoreEls, _els, Utc, Tzo) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"urn:xmpp:time">> -> + decode_time_els(__TopXMLNS, __IgnoreEls, _els, + decode_time_utc(__TopXMLNS, __IgnoreEls, _el), Tzo); + <<"urn:xmpp:time">> -> + decode_time_els(__TopXMLNS, __IgnoreEls, _els, + decode_time_utc(<<"urn:xmpp:time">>, __IgnoreEls, + _el), + Tzo); + _ -> + decode_time_els(__TopXMLNS, __IgnoreEls, _els, Utc, Tzo) end; decode_time_els(__TopXMLNS, __IgnoreEls, [_ | _els], Utc, Tzo) -> @@ -14224,13 +16259,56 @@ encode_ping({ping}, _xmlns_attrs) -> decode_session(__TopXMLNS, __IgnoreEls, {xmlel, <<"session">>, _attrs, _els}) -> - {session}. + Optional = decode_session_els(__TopXMLNS, __IgnoreEls, + _els, false), + {xmpp_session, Optional}. -encode_session({session}, _xmlns_attrs) -> - _els = [], +decode_session_els(__TopXMLNS, __IgnoreEls, [], + Optional) -> + Optional; +decode_session_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"optional">>, _attrs, _} = _el | _els], + Optional) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"urn:ietf:params:xml:ns:xmpp-session">> -> + decode_session_els(__TopXMLNS, __IgnoreEls, _els, + decode_session_optional(__TopXMLNS, __IgnoreEls, + _el)); + <<"urn:ietf:params:xml:ns:xmpp-session">> -> + decode_session_els(__TopXMLNS, __IgnoreEls, _els, + decode_session_optional(<<"urn:ietf:params:xml:ns:xmpp-session">>, + __IgnoreEls, _el)); + _ -> + decode_session_els(__TopXMLNS, __IgnoreEls, _els, + Optional) + end; +decode_session_els(__TopXMLNS, __IgnoreEls, [_ | _els], + Optional) -> + decode_session_els(__TopXMLNS, __IgnoreEls, _els, + Optional). + +encode_session({xmpp_session, Optional}, + _xmlns_attrs) -> + _els = + lists:reverse('encode_session_$optional'(Optional, [])), _attrs = _xmlns_attrs, {xmlel, <<"session">>, _attrs, _els}. +'encode_session_$optional'(false, _acc) -> _acc; +'encode_session_$optional'(Optional, _acc) -> + [encode_session_optional(Optional, []) | _acc]. + +decode_session_optional(__TopXMLNS, __IgnoreEls, + {xmlel, <<"optional">>, _attrs, _els}) -> + true. + +encode_session_optional(true, _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"optional">>, _attrs, _els}. + decode_register(__TopXMLNS, __IgnoreEls, {xmlel, <<"query">>, _attrs, _els}) -> {Zip, Xdata, Misc, Address, Instructions, Text, Last, @@ -14258,436 +16336,591 @@ decode_register_els(__TopXMLNS, __IgnoreEls, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, Email) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<"jabber:x:data">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - decode_xdata(_xmlns, __IgnoreEls, _el), Misc, - Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email); - true -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email) + case get_attr(<<"xmlns">>, _attrs) of + <<"jabber:x:data">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + decode_xdata(<<"jabber:x:data">>, __IgnoreEls, + _el), + Misc, Address, Instructions, Text, Last, First, + Password, Registered, Date, Phone, State, Name, + Username, Remove, Key, City, Nick, Url, Email); + _ -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"registered">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, Email) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, - decode_register_registered(__TopXMLNS, - __IgnoreEls, _el), - Date, Phone, State, Name, Username, Remove, Key, - City, Nick, Url, Email); - true -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, + decode_register_registered(__TopXMLNS, + __IgnoreEls, _el), + Date, Phone, State, Name, Username, Remove, Key, + City, Nick, Url, Email); + <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, + decode_register_registered(<<"jabber:iq:register">>, + __IgnoreEls, _el), + Date, Phone, State, Name, Username, Remove, Key, + City, Nick, Url, Email); + _ -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"remove">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, Email) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, - decode_register_remove(__TopXMLNS, __IgnoreEls, - _el), - Key, City, Nick, Url, Email); - true -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, + decode_register_remove(__TopXMLNS, __IgnoreEls, + _el), + Key, City, Nick, Url, Email); + <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, + decode_register_remove(<<"jabber:iq:register">>, + __IgnoreEls, _el), + Key, City, Nick, Url, Email); + _ -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"instructions">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, Email) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, - decode_register_instructions(__TopXMLNS, - __IgnoreEls, _el), - Text, Last, First, Password, Registered, Date, - Phone, State, Name, Username, Remove, Key, City, - Nick, Url, Email); - true -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, + decode_register_instructions(__TopXMLNS, + __IgnoreEls, _el), + Text, Last, First, Password, Registered, Date, + Phone, State, Name, Username, Remove, Key, City, + Nick, Url, Email); + <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, + decode_register_instructions(<<"jabber:iq:register">>, + __IgnoreEls, _el), + Text, Last, First, Password, Registered, Date, + Phone, State, Name, Username, Remove, Key, City, + Nick, Url, Email); + _ -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"username">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, Email) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, - decode_register_username(__TopXMLNS, __IgnoreEls, - _el), - Remove, Key, City, Nick, Url, Email); - true -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, + decode_register_username(__TopXMLNS, __IgnoreEls, + _el), + Remove, Key, City, Nick, Url, Email); + <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, + decode_register_username(<<"jabber:iq:register">>, + __IgnoreEls, _el), + Remove, Key, City, Nick, Url, Email); + _ -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"nick">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, Email) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, - decode_register_nick(__TopXMLNS, __IgnoreEls, - _el), - Url, Email); - true -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, + decode_register_nick(__TopXMLNS, __IgnoreEls, + _el), + Url, Email); + <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, + decode_register_nick(<<"jabber:iq:register">>, + __IgnoreEls, _el), + Url, Email); + _ -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"password">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, Email) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, - decode_register_password(__TopXMLNS, __IgnoreEls, - _el), - Registered, Date, Phone, State, Name, Username, - Remove, Key, City, Nick, Url, Email); - true -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, + decode_register_password(__TopXMLNS, __IgnoreEls, + _el), + Registered, Date, Phone, State, Name, Username, + Remove, Key, City, Nick, Url, Email); + <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, + decode_register_password(<<"jabber:iq:register">>, + __IgnoreEls, _el), + Registered, Date, Phone, State, Name, Username, + Remove, Key, City, Nick, Url, Email); + _ -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"name">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, Email) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - decode_register_name(__TopXMLNS, __IgnoreEls, - _el), - Username, Remove, Key, City, Nick, Url, Email); - true -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + decode_register_name(__TopXMLNS, __IgnoreEls, + _el), + Username, Remove, Key, City, Nick, Url, Email); + <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + decode_register_name(<<"jabber:iq:register">>, + __IgnoreEls, _el), + Username, Remove, Key, City, Nick, Url, Email); + _ -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"first">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, Email) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - decode_register_first(__TopXMLNS, __IgnoreEls, - _el), - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email); - true -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + decode_register_first(__TopXMLNS, __IgnoreEls, + _el), + Password, Registered, Date, Phone, State, Name, + Username, Remove, Key, City, Nick, Url, Email); + <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + decode_register_first(<<"jabber:iq:register">>, + __IgnoreEls, _el), + Password, Registered, Date, Phone, State, Name, + Username, Remove, Key, City, Nick, Url, Email); + _ -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"last">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, Email) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, - decode_register_last(__TopXMLNS, __IgnoreEls, - _el), - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email); - true -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, + decode_register_last(__TopXMLNS, __IgnoreEls, + _el), + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email); + <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, + decode_register_last(<<"jabber:iq:register">>, + __IgnoreEls, _el), + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email); + _ -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"email">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, Email) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - decode_register_email(__TopXMLNS, __IgnoreEls, - _el)); - true -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + decode_register_email(__TopXMLNS, __IgnoreEls, + _el)); + <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + decode_register_email(<<"jabber:iq:register">>, + __IgnoreEls, _el)); + _ -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"address">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, Email) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, - decode_register_address(__TopXMLNS, __IgnoreEls, - _el), - Instructions, Text, Last, First, Password, - Registered, Date, Phone, State, Name, Username, - Remove, Key, City, Nick, Url, Email); - true -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, + decode_register_address(__TopXMLNS, __IgnoreEls, + _el), + Instructions, Text, Last, First, Password, + Registered, Date, Phone, State, Name, Username, + Remove, Key, City, Nick, Url, Email); + <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, + decode_register_address(<<"jabber:iq:register">>, + __IgnoreEls, _el), + Instructions, Text, Last, First, Password, + Registered, Date, Phone, State, Name, Username, + Remove, Key, City, Nick, Url, Email); + _ -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"city">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, Email) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, - decode_register_city(__TopXMLNS, __IgnoreEls, - _el), - Nick, Url, Email); - true -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, + decode_register_city(__TopXMLNS, __IgnoreEls, + _el), + Nick, Url, Email); + <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, + decode_register_city(<<"jabber:iq:register">>, + __IgnoreEls, _el), + Nick, Url, Email); + _ -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"state">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, Email) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, - decode_register_state(__TopXMLNS, __IgnoreEls, - _el), - Name, Username, Remove, Key, City, Nick, Url, - Email); - true -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, + decode_register_state(__TopXMLNS, __IgnoreEls, + _el), + Name, Username, Remove, Key, City, Nick, Url, + Email); + <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, + decode_register_state(<<"jabber:iq:register">>, + __IgnoreEls, _el), + Name, Username, Remove, Key, City, Nick, Url, + Email); + _ -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"zip">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, Email) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, - decode_register_zip(__TopXMLNS, __IgnoreEls, - _el), - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email); - true -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, + decode_register_zip(__TopXMLNS, __IgnoreEls, _el), + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email); + <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, + decode_register_zip(<<"jabber:iq:register">>, + __IgnoreEls, _el), + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email); + _ -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"phone">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, Email) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, - decode_register_phone(__TopXMLNS, __IgnoreEls, - _el), - State, Name, Username, Remove, Key, City, Nick, - Url, Email); - true -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, + decode_register_phone(__TopXMLNS, __IgnoreEls, + _el), + State, Name, Username, Remove, Key, City, Nick, + Url, Email); + <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, + decode_register_phone(<<"jabber:iq:register">>, + __IgnoreEls, _el), + State, Name, Username, Remove, Key, City, Nick, + Url, Email); + _ -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"url">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, Email) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, - decode_register_url(__TopXMLNS, __IgnoreEls, - _el), - Email); - true -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, + decode_register_url(__TopXMLNS, __IgnoreEls, _el), + Email); + <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, + decode_register_url(<<"jabber:iq:register">>, + __IgnoreEls, _el), + Email); + _ -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"date">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, Email) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, - decode_register_date(__TopXMLNS, __IgnoreEls, - _el), - Phone, State, Name, Username, Remove, Key, City, - Nick, Url, Email); - true -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, + decode_register_date(__TopXMLNS, __IgnoreEls, + _el), + Phone, State, Name, Username, Remove, Key, City, + Nick, Url, Email); + <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, + decode_register_date(<<"jabber:iq:register">>, + __IgnoreEls, _el), + Phone, State, Name, Username, Remove, Key, City, + Nick, Url, Email); + _ -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"misc">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, Email) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, - decode_register_misc(__TopXMLNS, __IgnoreEls, - _el), - Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email); - true -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, + decode_register_misc(__TopXMLNS, __IgnoreEls, + _el), + Address, Instructions, Text, Last, First, + Password, Registered, Date, Phone, State, Name, + Username, Remove, Key, City, Nick, Url, Email); + <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, + decode_register_misc(<<"jabber:iq:register">>, + __IgnoreEls, _el), + Address, Instructions, Text, Last, First, + Password, Registered, Date, Phone, State, Name, + Username, Remove, Key, City, Nick, Url, Email); + _ -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"text">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, Email) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, - decode_register_text(__TopXMLNS, __IgnoreEls, - _el), - Last, First, Password, Registered, Date, Phone, - State, Name, Username, Remove, Key, City, Nick, - Url, Email); - true -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, + decode_register_text(__TopXMLNS, __IgnoreEls, + _el), + Last, First, Password, Registered, Date, Phone, + State, Name, Username, Remove, Key, City, Nick, + Url, Email); + <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, + decode_register_text(<<"jabber:iq:register">>, + __IgnoreEls, _el), + Last, First, Password, Registered, Date, Phone, + State, Name, Username, Remove, Key, City, Nick, + Url, Email); + _ -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"key">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, Email) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, - decode_register_key(__TopXMLNS, __IgnoreEls, - _el), - City, Nick, Url, Email); - true -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, + decode_register_key(__TopXMLNS, __IgnoreEls, _el), + City, Nick, Url, Email); + <<"jabber:iq:register">> -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, + decode_register_key(<<"jabber:iq:register">>, + __IgnoreEls, _el), + City, Nick, Url, Email); + _ -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email) end; decode_register_els(__TopXMLNS, __IgnoreEls, [_ | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, @@ -15394,34 +17627,50 @@ encode_feature_register({feature_register}, decode_caps(__TopXMLNS, __IgnoreEls, {xmlel, <<"c">>, _attrs, _els}) -> - {Hash, Node, Ver} = decode_caps_attrs(__TopXMLNS, - _attrs, undefined, undefined, - undefined), - {caps, Hash, Node, Ver}. + {Hash, Node, Exts, Version} = + decode_caps_attrs(__TopXMLNS, _attrs, undefined, + undefined, undefined, undefined), + {caps, Node, Version, Hash, Exts}. decode_caps_attrs(__TopXMLNS, - [{<<"hash">>, _val} | _attrs], _Hash, Node, Ver) -> - decode_caps_attrs(__TopXMLNS, _attrs, _val, Node, Ver); + [{<<"hash">>, _val} | _attrs], _Hash, Node, Exts, + Version) -> + decode_caps_attrs(__TopXMLNS, _attrs, _val, Node, Exts, + Version); decode_caps_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], Hash, _Node, Ver) -> - decode_caps_attrs(__TopXMLNS, _attrs, Hash, _val, Ver); + [{<<"node">>, _val} | _attrs], Hash, _Node, Exts, + Version) -> + decode_caps_attrs(__TopXMLNS, _attrs, Hash, _val, Exts, + Version); decode_caps_attrs(__TopXMLNS, - [{<<"ver">>, _val} | _attrs], Hash, Node, _Ver) -> - decode_caps_attrs(__TopXMLNS, _attrs, Hash, Node, _val); + [{<<"ext">>, _val} | _attrs], Hash, Node, _Exts, + Version) -> + decode_caps_attrs(__TopXMLNS, _attrs, Hash, Node, _val, + Version); +decode_caps_attrs(__TopXMLNS, + [{<<"ver">>, _val} | _attrs], Hash, Node, Exts, + _Version) -> + decode_caps_attrs(__TopXMLNS, _attrs, Hash, Node, Exts, + _val); decode_caps_attrs(__TopXMLNS, [_ | _attrs], Hash, Node, - Ver) -> - decode_caps_attrs(__TopXMLNS, _attrs, Hash, Node, Ver); -decode_caps_attrs(__TopXMLNS, [], Hash, Node, Ver) -> + Exts, Version) -> + decode_caps_attrs(__TopXMLNS, _attrs, Hash, Node, Exts, + Version); +decode_caps_attrs(__TopXMLNS, [], Hash, Node, Exts, + Version) -> {decode_caps_attr_hash(__TopXMLNS, Hash), decode_caps_attr_node(__TopXMLNS, Node), - decode_caps_attr_ver(__TopXMLNS, Ver)}. + decode_caps_attr_ext(__TopXMLNS, Exts), + decode_caps_attr_ver(__TopXMLNS, Version)}. -encode_caps({caps, Hash, Node, Ver}, _xmlns_attrs) -> +encode_caps({caps, Node, Version, Hash, Exts}, + _xmlns_attrs) -> _els = [], - _attrs = encode_caps_attr_ver(Ver, - encode_caps_attr_node(Node, - encode_caps_attr_hash(Hash, - _xmlns_attrs))), + _attrs = encode_caps_attr_ver(Version, + encode_caps_attr_ext(Exts, + encode_caps_attr_node(Node, + encode_caps_attr_hash(Hash, + _xmlns_attrs)))), {xmlel, <<"c">>, _attrs, _els}. decode_caps_attr_hash(__TopXMLNS, undefined) -> @@ -15440,19 +17689,26 @@ encode_caps_attr_node(undefined, _acc) -> _acc; encode_caps_attr_node(_val, _acc) -> [{<<"node">>, _val} | _acc]. -decode_caps_attr_ver(__TopXMLNS, undefined) -> - undefined; -decode_caps_attr_ver(__TopXMLNS, _val) -> - case catch base64:decode(_val) of +decode_caps_attr_ext(__TopXMLNS, undefined) -> []; +decode_caps_attr_ext(__TopXMLNS, _val) -> + case catch re:split(_val, "\\h+") of {'EXIT', _} -> erlang:error({xmpp_codec, - {bad_attr_value, <<"ver">>, <<"c">>, __TopXMLNS}}); + {bad_attr_value, <<"ext">>, <<"c">>, __TopXMLNS}}); _res -> _res end. +encode_caps_attr_ext([], _acc) -> _acc; +encode_caps_attr_ext(_val, _acc) -> + [{<<"ext">>, join(_val, 32)} | _acc]. + +decode_caps_attr_ver(__TopXMLNS, undefined) -> + undefined; +decode_caps_attr_ver(__TopXMLNS, _val) -> _val. + encode_caps_attr_ver(undefined, _acc) -> _acc; encode_caps_attr_ver(_val, _acc) -> - [{<<"ver">>, base64:encode(_val)} | _acc]. + [{<<"ver">>, _val} | _acc]. decode_p1_ack(__TopXMLNS, __IgnoreEls, {xmlel, <<"ack">>, _attrs, _els}) -> @@ -15528,19 +17784,30 @@ decode_compression_els(__TopXMLNS, __IgnoreEls, [], decode_compression_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"method">>, _attrs, _} = _el | _els], Methods) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_compression_els(__TopXMLNS, __IgnoreEls, _els, - case decode_compression_method(__TopXMLNS, - __IgnoreEls, - _el) - of - undefined -> Methods; - _new_el -> [_new_el | Methods] - end); - true -> - decode_compression_els(__TopXMLNS, __IgnoreEls, _els, - Methods) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/features/compress">> -> + decode_compression_els(__TopXMLNS, __IgnoreEls, _els, + case decode_compression_method(__TopXMLNS, + __IgnoreEls, + _el) + of + undefined -> Methods; + _new_el -> [_new_el | Methods] + end); + <<"http://jabber.org/features/compress">> -> + decode_compression_els(__TopXMLNS, __IgnoreEls, _els, + case + decode_compression_method(<<"http://jabber.org/features/compress">>, + __IgnoreEls, _el) + of + undefined -> Methods; + _new_el -> [_new_el | Methods] + end); + _ -> + decode_compression_els(__TopXMLNS, __IgnoreEls, _els, + Methods) end; decode_compression_els(__TopXMLNS, __IgnoreEls, [_ | _els], Methods) -> @@ -15615,18 +17882,29 @@ decode_compress_els(__TopXMLNS, __IgnoreEls, [], decode_compress_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"method">>, _attrs, _} = _el | _els], Methods) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_compress_els(__TopXMLNS, __IgnoreEls, _els, - case decode_compress_method(__TopXMLNS, - __IgnoreEls, _el) - of - undefined -> Methods; - _new_el -> [_new_el | Methods] - end); - true -> - decode_compress_els(__TopXMLNS, __IgnoreEls, _els, - Methods) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/compress">> -> + decode_compress_els(__TopXMLNS, __IgnoreEls, _els, + case decode_compress_method(__TopXMLNS, + __IgnoreEls, _el) + of + undefined -> Methods; + _new_el -> [_new_el | Methods] + end); + <<"http://jabber.org/protocol/compress">> -> + decode_compress_els(__TopXMLNS, __IgnoreEls, _els, + case + decode_compress_method(<<"http://jabber.org/protocol/compress">>, + __IgnoreEls, _el) + of + undefined -> Methods; + _new_el -> [_new_el | Methods] + end); + _ -> + decode_compress_els(__TopXMLNS, __IgnoreEls, _els, + Methods) end; decode_compress_els(__TopXMLNS, __IgnoreEls, [_ | _els], Methods) -> @@ -15688,46 +17966,70 @@ decode_compress_failure_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"setup-failed">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_compress_failure_els(__TopXMLNS, __IgnoreEls, - _els, - decode_compress_failure_setup_failed(__TopXMLNS, - __IgnoreEls, - _el)); - true -> - decode_compress_failure_els(__TopXMLNS, __IgnoreEls, - _els, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/compress">> -> + decode_compress_failure_els(__TopXMLNS, __IgnoreEls, + _els, + decode_compress_failure_setup_failed(__TopXMLNS, + __IgnoreEls, + _el)); + <<"http://jabber.org/protocol/compress">> -> + decode_compress_failure_els(__TopXMLNS, __IgnoreEls, + _els, + decode_compress_failure_setup_failed(<<"http://jabber.org/protocol/compress">>, + __IgnoreEls, + _el)); + _ -> + decode_compress_failure_els(__TopXMLNS, __IgnoreEls, + _els, Reason) end; decode_compress_failure_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"processing-failed">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_compress_failure_els(__TopXMLNS, __IgnoreEls, - _els, - decode_compress_failure_processing_failed(__TopXMLNS, - __IgnoreEls, - _el)); - true -> - decode_compress_failure_els(__TopXMLNS, __IgnoreEls, - _els, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/compress">> -> + decode_compress_failure_els(__TopXMLNS, __IgnoreEls, + _els, + decode_compress_failure_processing_failed(__TopXMLNS, + __IgnoreEls, + _el)); + <<"http://jabber.org/protocol/compress">> -> + decode_compress_failure_els(__TopXMLNS, __IgnoreEls, + _els, + decode_compress_failure_processing_failed(<<"http://jabber.org/protocol/compress">>, + __IgnoreEls, + _el)); + _ -> + decode_compress_failure_els(__TopXMLNS, __IgnoreEls, + _els, Reason) end; decode_compress_failure_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"unsupported-method">>, _attrs, _} = _el | _els], Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_compress_failure_els(__TopXMLNS, __IgnoreEls, - _els, - decode_compress_failure_unsupported_method(__TopXMLNS, - __IgnoreEls, - _el)); - true -> - decode_compress_failure_els(__TopXMLNS, __IgnoreEls, - _els, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/compress">> -> + decode_compress_failure_els(__TopXMLNS, __IgnoreEls, + _els, + decode_compress_failure_unsupported_method(__TopXMLNS, + __IgnoreEls, + _el)); + <<"http://jabber.org/protocol/compress">> -> + decode_compress_failure_els(__TopXMLNS, __IgnoreEls, + _els, + decode_compress_failure_unsupported_method(<<"http://jabber.org/protocol/compress">>, + __IgnoreEls, + _el)); + _ -> + decode_compress_failure_els(__TopXMLNS, __IgnoreEls, + _els, Reason) end; decode_compress_failure_els(__TopXMLNS, __IgnoreEls, [_ | _els], Reason) -> @@ -15828,14 +18130,20 @@ decode_starttls_els(__TopXMLNS, __IgnoreEls, [], decode_starttls_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"required">>, _attrs, _} = _el | _els], Required) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_starttls_els(__TopXMLNS, __IgnoreEls, _els, - decode_starttls_required(__TopXMLNS, __IgnoreEls, - _el)); - true -> - decode_starttls_els(__TopXMLNS, __IgnoreEls, _els, - Required) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"urn:ietf:params:xml:ns:xmpp-tls">> -> + decode_starttls_els(__TopXMLNS, __IgnoreEls, _els, + decode_starttls_required(__TopXMLNS, __IgnoreEls, + _el)); + <<"urn:ietf:params:xml:ns:xmpp-tls">> -> + decode_starttls_els(__TopXMLNS, __IgnoreEls, _els, + decode_starttls_required(<<"urn:ietf:params:xml:ns:xmpp-tls">>, + __IgnoreEls, _el)); + _ -> + decode_starttls_els(__TopXMLNS, __IgnoreEls, _els, + Required) end; decode_starttls_els(__TopXMLNS, __IgnoreEls, [_ | _els], Required) -> @@ -15874,20 +18182,32 @@ decode_sasl_mechanisms_els(__TopXMLNS, __IgnoreEls, [], decode_sasl_mechanisms_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"mechanism">>, _attrs, _} = _el | _els], List) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_sasl_mechanisms_els(__TopXMLNS, __IgnoreEls, - _els, - case decode_sasl_mechanism(__TopXMLNS, - __IgnoreEls, - _el) - of - undefined -> List; - _new_el -> [_new_el | List] - end); - true -> - decode_sasl_mechanisms_els(__TopXMLNS, __IgnoreEls, - _els, List) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_mechanisms_els(__TopXMLNS, __IgnoreEls, + _els, + case decode_sasl_mechanism(__TopXMLNS, + __IgnoreEls, + _el) + of + undefined -> List; + _new_el -> [_new_el | List] + end); + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_mechanisms_els(__TopXMLNS, __IgnoreEls, + _els, + case + decode_sasl_mechanism(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + __IgnoreEls, _el) + of + undefined -> List; + _new_el -> [_new_el | List] + end); + _ -> + decode_sasl_mechanisms_els(__TopXMLNS, __IgnoreEls, + _els, List) end; decode_sasl_mechanisms_els(__TopXMLNS, __IgnoreEls, [_ | _els], List) -> @@ -15949,179 +18269,297 @@ decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, [], decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"text">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - [decode_sasl_failure_text(__TopXMLNS, - __IgnoreEls, _el) - | Text], - Reason); - true -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + [decode_sasl_failure_text(__TopXMLNS, + __IgnoreEls, _el) + | Text], + Reason); + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + [decode_sasl_failure_text(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + __IgnoreEls, _el) + | Text], + Reason); + _ -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"aborted">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_aborted(__TopXMLNS, - __IgnoreEls, - _el)); - true -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_sasl_failure_aborted(__TopXMLNS, + __IgnoreEls, + _el)); + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_sasl_failure_aborted(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + __IgnoreEls, + _el)); + _ -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"account-disabled">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_account_disabled(__TopXMLNS, - __IgnoreEls, - _el)); - true -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_sasl_failure_account_disabled(__TopXMLNS, + __IgnoreEls, + _el)); + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_sasl_failure_account_disabled(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + __IgnoreEls, + _el)); + _ -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"credentials-expired">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_credentials_expired(__TopXMLNS, - __IgnoreEls, - _el)); - true -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_sasl_failure_credentials_expired(__TopXMLNS, + __IgnoreEls, + _el)); + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_sasl_failure_credentials_expired(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + __IgnoreEls, + _el)); + _ -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"encryption-required">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_encryption_required(__TopXMLNS, - __IgnoreEls, - _el)); - true -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_sasl_failure_encryption_required(__TopXMLNS, + __IgnoreEls, + _el)); + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_sasl_failure_encryption_required(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + __IgnoreEls, + _el)); + _ -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"incorrect-encoding">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_incorrect_encoding(__TopXMLNS, - __IgnoreEls, - _el)); - true -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_sasl_failure_incorrect_encoding(__TopXMLNS, + __IgnoreEls, + _el)); + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_sasl_failure_incorrect_encoding(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + __IgnoreEls, + _el)); + _ -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"invalid-authzid">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_invalid_authzid(__TopXMLNS, - __IgnoreEls, - _el)); - true -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_sasl_failure_invalid_authzid(__TopXMLNS, + __IgnoreEls, + _el)); + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_sasl_failure_invalid_authzid(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + __IgnoreEls, + _el)); + _ -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"invalid-mechanism">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_invalid_mechanism(__TopXMLNS, - __IgnoreEls, - _el)); - true -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_sasl_failure_invalid_mechanism(__TopXMLNS, + __IgnoreEls, + _el)); + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_sasl_failure_invalid_mechanism(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + __IgnoreEls, + _el)); + _ -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"malformed-request">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_malformed_request(__TopXMLNS, - __IgnoreEls, - _el)); - true -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_sasl_failure_malformed_request(__TopXMLNS, + __IgnoreEls, + _el)); + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_sasl_failure_malformed_request(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + __IgnoreEls, + _el)); + _ -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"mechanism-too-weak">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_mechanism_too_weak(__TopXMLNS, - __IgnoreEls, - _el)); - true -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_sasl_failure_mechanism_too_weak(__TopXMLNS, + __IgnoreEls, + _el)); + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_sasl_failure_mechanism_too_weak(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + __IgnoreEls, + _el)); + _ -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"not-authorized">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_not_authorized(__TopXMLNS, - __IgnoreEls, - _el)); - true -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_sasl_failure_not_authorized(__TopXMLNS, + __IgnoreEls, + _el)); + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_sasl_failure_not_authorized(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + __IgnoreEls, + _el)); + _ -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) + end; +decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"bad-protocol">>, _attrs, _} = _el | _els], + Text, Reason) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_sasl_failure_bad_protocol(__TopXMLNS, + __IgnoreEls, + _el)); + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_sasl_failure_bad_protocol(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + __IgnoreEls, + _el)); + _ -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"temporary-auth-failure">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_temporary_auth_failure(__TopXMLNS, - __IgnoreEls, - _el)); - true -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_sasl_failure_temporary_auth_failure(__TopXMLNS, + __IgnoreEls, + _el)); + <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, + decode_sasl_failure_temporary_auth_failure(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + __IgnoreEls, + _el)); + _ -> + decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, + Text, Reason) end; decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, [_ | _els], Text, Reason) -> @@ -16187,6 +18625,9 @@ encode_sasl_failure({sasl_failure, Reason, Text}, 'encode_sasl_failure_$reason'('not-authorized' = Reason, _acc) -> [encode_sasl_failure_not_authorized(Reason, []) | _acc]; +'encode_sasl_failure_$reason'('bad-protocol' = Reason, + _acc) -> + [encode_sasl_failure_bad_protocol(Reason, []) | _acc]; 'encode_sasl_failure_$reason'('temporary-auth-failure' = Reason, _acc) -> @@ -16205,6 +18646,17 @@ encode_sasl_failure_temporary_auth_failure('temporary-auth-failure', _attrs = _xmlns_attrs, {xmlel, <<"temporary-auth-failure">>, _attrs, _els}. +decode_sasl_failure_bad_protocol(__TopXMLNS, + __IgnoreEls, + {xmlel, <<"bad-protocol">>, _attrs, _els}) -> + 'bad-protocol'. + +encode_sasl_failure_bad_protocol('bad-protocol', + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"bad-protocol">>, _attrs, _els}. + decode_sasl_failure_not_authorized(__TopXMLNS, __IgnoreEls, {xmlel, <<"not-authorized">>, _attrs, @@ -16566,6 +19018,253 @@ encode_sasl_auth_cdata(undefined, _acc) -> _acc; encode_sasl_auth_cdata(_val, _acc) -> [{xmlcdata, base64:encode(_val)} | _acc]. +decode_legacy_auth(__TopXMLNS, __IgnoreEls, + {xmlel, <<"query">>, _attrs, _els}) -> + {Digest, Password, Resource, Username} = + decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, + undefined, undefined, undefined, undefined), + {legacy_auth, Username, Password, Digest, Resource}. + +decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, [], + Digest, Password, Resource, Username) -> + {Digest, Password, Resource, Username}; +decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"username">>, _attrs, _} = _el | _els], + Digest, Password, Resource, Username) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:auth">> -> + decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, + Digest, Password, Resource, + decode_legacy_auth_username(__TopXMLNS, + __IgnoreEls, _el)); + <<"jabber:iq:auth">> -> + decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, + Digest, Password, Resource, + decode_legacy_auth_username(<<"jabber:iq:auth">>, + __IgnoreEls, _el)); + _ -> + decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, + Digest, Password, Resource, Username) + end; +decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"password">>, _attrs, _} = _el | _els], + Digest, Password, Resource, Username) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:auth">> -> + decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, + Digest, + decode_legacy_auth_password(__TopXMLNS, + __IgnoreEls, _el), + Resource, Username); + <<"jabber:iq:auth">> -> + decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, + Digest, + decode_legacy_auth_password(<<"jabber:iq:auth">>, + __IgnoreEls, _el), + Resource, Username); + _ -> + decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, + Digest, Password, Resource, Username) + end; +decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"digest">>, _attrs, _} = _el | _els], Digest, + Password, Resource, Username) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:auth">> -> + decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, + decode_legacy_auth_digest(__TopXMLNS, + __IgnoreEls, _el), + Password, Resource, Username); + <<"jabber:iq:auth">> -> + decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, + decode_legacy_auth_digest(<<"jabber:iq:auth">>, + __IgnoreEls, _el), + Password, Resource, Username); + _ -> + decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, + Digest, Password, Resource, Username) + end; +decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"resource">>, _attrs, _} = _el | _els], + Digest, Password, Resource, Username) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:auth">> -> + decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, + Digest, Password, + decode_legacy_auth_resource(__TopXMLNS, + __IgnoreEls, _el), + Username); + <<"jabber:iq:auth">> -> + decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, + Digest, Password, + decode_legacy_auth_resource(<<"jabber:iq:auth">>, + __IgnoreEls, _el), + Username); + _ -> + decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, + Digest, Password, Resource, Username) + end; +decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Digest, Password, Resource, Username) -> + decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, + Digest, Password, Resource, Username). + +encode_legacy_auth({legacy_auth, Username, Password, + Digest, Resource}, + _xmlns_attrs) -> + _els = + lists:reverse('encode_legacy_auth_$digest'(Digest, + 'encode_legacy_auth_$password'(Password, + 'encode_legacy_auth_$resource'(Resource, + 'encode_legacy_auth_$username'(Username, + []))))), + _attrs = _xmlns_attrs, + {xmlel, <<"query">>, _attrs, _els}. + +'encode_legacy_auth_$digest'(undefined, _acc) -> _acc; +'encode_legacy_auth_$digest'(Digest, _acc) -> + [encode_legacy_auth_digest(Digest, []) | _acc]. + +'encode_legacy_auth_$password'(undefined, _acc) -> _acc; +'encode_legacy_auth_$password'(Password, _acc) -> + [encode_legacy_auth_password(Password, []) | _acc]. + +'encode_legacy_auth_$resource'(undefined, _acc) -> _acc; +'encode_legacy_auth_$resource'(Resource, _acc) -> + [encode_legacy_auth_resource(Resource, []) | _acc]. + +'encode_legacy_auth_$username'(undefined, _acc) -> _acc; +'encode_legacy_auth_$username'(Username, _acc) -> + [encode_legacy_auth_username(Username, []) | _acc]. + +decode_legacy_auth_resource(__TopXMLNS, __IgnoreEls, + {xmlel, <<"resource">>, _attrs, _els}) -> + Cdata = decode_legacy_auth_resource_els(__TopXMLNS, + __IgnoreEls, _els, <<>>), + Cdata. + +decode_legacy_auth_resource_els(__TopXMLNS, __IgnoreEls, + [], Cdata) -> + decode_legacy_auth_resource_cdata(__TopXMLNS, Cdata); +decode_legacy_auth_resource_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Cdata) -> + decode_legacy_auth_resource_els(__TopXMLNS, __IgnoreEls, + _els, <>); +decode_legacy_auth_resource_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Cdata) -> + decode_legacy_auth_resource_els(__TopXMLNS, __IgnoreEls, + _els, Cdata). + +encode_legacy_auth_resource(Cdata, _xmlns_attrs) -> + _els = encode_legacy_auth_resource_cdata(Cdata, []), + _attrs = _xmlns_attrs, + {xmlel, <<"resource">>, _attrs, _els}. + +decode_legacy_auth_resource_cdata(__TopXMLNS, <<>>) -> + none; +decode_legacy_auth_resource_cdata(__TopXMLNS, _val) -> + _val. + +encode_legacy_auth_resource_cdata(none, _acc) -> _acc; +encode_legacy_auth_resource_cdata(_val, _acc) -> + [{xmlcdata, _val} | _acc]. + +decode_legacy_auth_digest(__TopXMLNS, __IgnoreEls, + {xmlel, <<"digest">>, _attrs, _els}) -> + Cdata = decode_legacy_auth_digest_els(__TopXMLNS, + __IgnoreEls, _els, <<>>), + Cdata. + +decode_legacy_auth_digest_els(__TopXMLNS, __IgnoreEls, + [], Cdata) -> + decode_legacy_auth_digest_cdata(__TopXMLNS, Cdata); +decode_legacy_auth_digest_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Cdata) -> + decode_legacy_auth_digest_els(__TopXMLNS, __IgnoreEls, + _els, <>); +decode_legacy_auth_digest_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Cdata) -> + decode_legacy_auth_digest_els(__TopXMLNS, __IgnoreEls, + _els, Cdata). + +encode_legacy_auth_digest(Cdata, _xmlns_attrs) -> + _els = encode_legacy_auth_digest_cdata(Cdata, []), + _attrs = _xmlns_attrs, + {xmlel, <<"digest">>, _attrs, _els}. + +decode_legacy_auth_digest_cdata(__TopXMLNS, <<>>) -> + none; +decode_legacy_auth_digest_cdata(__TopXMLNS, _val) -> + _val. + +encode_legacy_auth_digest_cdata(none, _acc) -> _acc; +encode_legacy_auth_digest_cdata(_val, _acc) -> + [{xmlcdata, _val} | _acc]. + +decode_legacy_auth_password(__TopXMLNS, __IgnoreEls, + {xmlel, <<"password">>, _attrs, _els}) -> + Cdata = decode_legacy_auth_password_els(__TopXMLNS, + __IgnoreEls, _els, <<>>), + Cdata. + +decode_legacy_auth_password_els(__TopXMLNS, __IgnoreEls, + [], Cdata) -> + decode_legacy_auth_password_cdata(__TopXMLNS, Cdata); +decode_legacy_auth_password_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Cdata) -> + decode_legacy_auth_password_els(__TopXMLNS, __IgnoreEls, + _els, <>); +decode_legacy_auth_password_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Cdata) -> + decode_legacy_auth_password_els(__TopXMLNS, __IgnoreEls, + _els, Cdata). + +encode_legacy_auth_password(Cdata, _xmlns_attrs) -> + _els = encode_legacy_auth_password_cdata(Cdata, []), + _attrs = _xmlns_attrs, + {xmlel, <<"password">>, _attrs, _els}. + +decode_legacy_auth_password_cdata(__TopXMLNS, <<>>) -> + none; +decode_legacy_auth_password_cdata(__TopXMLNS, _val) -> + _val. + +encode_legacy_auth_password_cdata(none, _acc) -> _acc; +encode_legacy_auth_password_cdata(_val, _acc) -> + [{xmlcdata, _val} | _acc]. + +decode_legacy_auth_username(__TopXMLNS, __IgnoreEls, + {xmlel, <<"username">>, _attrs, _els}) -> + Cdata = decode_legacy_auth_username_els(__TopXMLNS, + __IgnoreEls, _els, <<>>), + Cdata. + +decode_legacy_auth_username_els(__TopXMLNS, __IgnoreEls, + [], Cdata) -> + decode_legacy_auth_username_cdata(__TopXMLNS, Cdata); +decode_legacy_auth_username_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Cdata) -> + decode_legacy_auth_username_els(__TopXMLNS, __IgnoreEls, + _els, <>); +decode_legacy_auth_username_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Cdata) -> + decode_legacy_auth_username_els(__TopXMLNS, __IgnoreEls, + _els, Cdata). + +encode_legacy_auth_username(Cdata, _xmlns_attrs) -> + _els = encode_legacy_auth_username_cdata(Cdata, []), + _attrs = _xmlns_attrs, + {xmlel, <<"username">>, _attrs, _els}. + +decode_legacy_auth_username_cdata(__TopXMLNS, <<>>) -> + none; +decode_legacy_auth_username_cdata(__TopXMLNS, _val) -> + _val. + +encode_legacy_auth_username_cdata(none, _acc) -> _acc; +encode_legacy_auth_username_cdata(_val, _acc) -> + [{xmlcdata, _val} | _acc]. + decode_bind(__TopXMLNS, __IgnoreEls, {xmlel, <<"bind">>, _attrs, _els}) -> {Jid, Resource} = decode_bind_els(__TopXMLNS, @@ -16578,25 +19277,38 @@ decode_bind_els(__TopXMLNS, __IgnoreEls, [], Jid, decode_bind_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"jid">>, _attrs, _} = _el | _els], Jid, Resource) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_bind_els(__TopXMLNS, __IgnoreEls, _els, - decode_bind_jid(__TopXMLNS, __IgnoreEls, _el), - Resource); - true -> - decode_bind_els(__TopXMLNS, __IgnoreEls, _els, Jid, - Resource) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"urn:ietf:params:xml:ns:xmpp-bind">> -> + decode_bind_els(__TopXMLNS, __IgnoreEls, _els, + decode_bind_jid(__TopXMLNS, __IgnoreEls, _el), + Resource); + <<"urn:ietf:params:xml:ns:xmpp-bind">> -> + decode_bind_els(__TopXMLNS, __IgnoreEls, _els, + decode_bind_jid(<<"urn:ietf:params:xml:ns:xmpp-bind">>, + __IgnoreEls, _el), + Resource); + _ -> + decode_bind_els(__TopXMLNS, __IgnoreEls, _els, Jid, + Resource) end; decode_bind_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"resource">>, _attrs, _} = _el | _els], Jid, Resource) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_bind_els(__TopXMLNS, __IgnoreEls, _els, Jid, - decode_bind_resource(__TopXMLNS, __IgnoreEls, _el)); - true -> - decode_bind_els(__TopXMLNS, __IgnoreEls, _els, Jid, - Resource) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"urn:ietf:params:xml:ns:xmpp-bind">> -> + decode_bind_els(__TopXMLNS, __IgnoreEls, _els, Jid, + decode_bind_resource(__TopXMLNS, __IgnoreEls, _el)); + <<"urn:ietf:params:xml:ns:xmpp-bind">> -> + decode_bind_els(__TopXMLNS, __IgnoreEls, _els, Jid, + decode_bind_resource(<<"urn:ietf:params:xml:ns:xmpp-bind">>, + __IgnoreEls, _el)); + _ -> + decode_bind_els(__TopXMLNS, __IgnoreEls, _els, Jid, + Resource) end; decode_bind_els(__TopXMLNS, __IgnoreEls, [_ | _els], Jid, Resource) -> @@ -16695,9 +19407,10 @@ decode_error(__TopXMLNS, __IgnoreEls, {xmlel, <<"error">>, _attrs, _els}) -> {Text, Reason} = decode_error_els(__TopXMLNS, __IgnoreEls, _els, undefined, undefined), - {Type, By} = decode_error_attrs(__TopXMLNS, _attrs, - undefined, undefined), - {error, Type, By, Reason, Text}. + {Type, Code, By} = decode_error_attrs(__TopXMLNS, + _attrs, undefined, undefined, + undefined), + {error, Type, Code, By, Reason, Text}. decode_error_els(__TopXMLNS, __IgnoreEls, [], Text, Reason) -> @@ -16705,314 +19418,298 @@ decode_error_els(__TopXMLNS, __IgnoreEls, [], Text, decode_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"text">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_text(_xmlns, __IgnoreEls, _el), - Reason); - true -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, + decode_error_text(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el), + Reason); + _ -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + Reason) end; decode_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"bad-request">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_bad_request(_xmlns, __IgnoreEls, _el)); - true -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + decode_error_bad_request(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + Reason) end; decode_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"conflict">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_conflict(_xmlns, __IgnoreEls, _el)); - true -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + decode_error_conflict(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + Reason) end; decode_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"feature-not-implemented">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_feature_not_implemented(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + decode_error_feature_not_implemented(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, + _el)); + _ -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + Reason) end; decode_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"forbidden">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_forbidden(_xmlns, __IgnoreEls, _el)); - true -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + decode_error_forbidden(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + Reason) end; decode_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"gone">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_gone(_xmlns, __IgnoreEls, _el)); - true -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + decode_error_gone(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + Reason) end; decode_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"internal-server-error">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_internal_server_error(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + decode_error_internal_server_error(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, + _el)); + _ -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + Reason) end; decode_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"item-not-found">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_item_not_found(_xmlns, __IgnoreEls, - _el)); - true -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + decode_error_item_not_found(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + Reason) end; decode_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"jid-malformed">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_jid_malformed(_xmlns, __IgnoreEls, - _el)); - true -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + decode_error_jid_malformed(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + Reason) end; decode_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"not-acceptable">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_not_acceptable(_xmlns, __IgnoreEls, - _el)); - true -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + decode_error_not_acceptable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + Reason) end; decode_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"not-allowed">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_not_allowed(_xmlns, __IgnoreEls, _el)); - true -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + decode_error_not_allowed(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + Reason) end; decode_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"not-authorized">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_not_authorized(_xmlns, __IgnoreEls, - _el)); - true -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + decode_error_not_authorized(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + Reason) end; decode_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"policy-violation">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_policy_violation(_xmlns, __IgnoreEls, - _el)); - true -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + decode_error_policy_violation(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + Reason) end; decode_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"recipient-unavailable">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_recipient_unavailable(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + decode_error_recipient_unavailable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, + _el)); + _ -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + Reason) end; decode_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"redirect">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_redirect(_xmlns, __IgnoreEls, _el)); - true -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + decode_error_redirect(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + Reason) end; decode_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"registration-required">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_registration_required(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + decode_error_registration_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, + _el)); + _ -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + Reason) end; decode_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"remote-server-not-found">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_remote_server_not_found(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + decode_error_remote_server_not_found(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, + _el)); + _ -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + Reason) end; decode_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"remote-server-timeout">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_remote_server_timeout(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + decode_error_remote_server_timeout(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, + _el)); + _ -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + Reason) end; decode_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"resource-constraint">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_resource_constraint(_xmlns, - __IgnoreEls, _el)); - true -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + decode_error_resource_constraint(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + Reason) end; decode_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"service-unavailable">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_service_unavailable(_xmlns, - __IgnoreEls, _el)); - true -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + decode_error_service_unavailable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + Reason) end; decode_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"subscription-required">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_subscription_required(_xmlns, - __IgnoreEls, - _el)); - true -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + decode_error_subscription_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, + _el)); + _ -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + Reason) end; decode_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"undefined-condition">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_undefined_condition(_xmlns, - __IgnoreEls, _el)); - true -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + decode_error_undefined_condition(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + Reason) end; decode_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"unexpected-request">>, _attrs, _} = _el | _els], Text, Reason) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_unexpected_request(_xmlns, __IgnoreEls, - _el)); - true -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason) + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + decode_error_unexpected_request(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + Reason) end; decode_error_els(__TopXMLNS, __IgnoreEls, [_ | _els], Text, Reason) -> @@ -17020,25 +19717,32 @@ decode_error_els(__TopXMLNS, __IgnoreEls, [_ | _els], Reason). decode_error_attrs(__TopXMLNS, - [{<<"type">>, _val} | _attrs], _Type, By) -> - decode_error_attrs(__TopXMLNS, _attrs, _val, By); + [{<<"type">>, _val} | _attrs], _Type, Code, By) -> + decode_error_attrs(__TopXMLNS, _attrs, _val, Code, By); decode_error_attrs(__TopXMLNS, - [{<<"by">>, _val} | _attrs], Type, _By) -> - decode_error_attrs(__TopXMLNS, _attrs, Type, _val); -decode_error_attrs(__TopXMLNS, [_ | _attrs], Type, + [{<<"code">>, _val} | _attrs], Type, _Code, By) -> + decode_error_attrs(__TopXMLNS, _attrs, Type, _val, By); +decode_error_attrs(__TopXMLNS, + [{<<"by">>, _val} | _attrs], Type, Code, _By) -> + decode_error_attrs(__TopXMLNS, _attrs, Type, Code, + _val); +decode_error_attrs(__TopXMLNS, [_ | _attrs], Type, Code, By) -> - decode_error_attrs(__TopXMLNS, _attrs, Type, By); -decode_error_attrs(__TopXMLNS, [], Type, By) -> + decode_error_attrs(__TopXMLNS, _attrs, Type, Code, By); +decode_error_attrs(__TopXMLNS, [], Type, Code, By) -> {decode_error_attr_type(__TopXMLNS, Type), + decode_error_attr_code(__TopXMLNS, Code), decode_error_attr_by(__TopXMLNS, By)}. -encode_error({error, Type, By, Reason, Text}, +encode_error({error, Type, Code, By, Reason, Text}, _xmlns_attrs) -> _els = lists:reverse('encode_error_$text'(Text, 'encode_error_$reason'(Reason, []))), _attrs = encode_error_attr_by(By, - encode_error_attr_type(Type, _xmlns_attrs)), + encode_error_attr_code(Code, + encode_error_attr_type(Type, + _xmlns_attrs))), {xmlel, <<"error">>, _attrs, _els}. 'encode_error_$text'(undefined, _acc) -> _acc; @@ -17194,6 +19898,20 @@ decode_error_attr_type(__TopXMLNS, _val) -> encode_error_attr_type(_val, _acc) -> [{<<"type">>, enc_enum(_val)} | _acc]. +decode_error_attr_code(__TopXMLNS, undefined) -> + undefined; +decode_error_attr_code(__TopXMLNS, _val) -> + case catch dec_int(_val, 0, infinity) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"code">>, <<"error">>, __TopXMLNS}}); + _res -> _res + end. + +encode_error_attr_code(undefined, _acc) -> _acc; +encode_error_attr_code(_val, _acc) -> + [{<<"code">>, enc_int(_val)} | _acc]. + decode_error_attr_by(__TopXMLNS, undefined) -> undefined; decode_error_attr_by(__TopXMLNS, _val) -> _val. @@ -17551,57 +20269,81 @@ decode_presence_els(__TopXMLNS, __IgnoreEls, [], Error, decode_presence_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"error">>, _attrs, _} = _el | _els], Error, Status, Show, Priority, __Els) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - decode_error(__TopXMLNS, __IgnoreEls, _el), - Status, Show, Priority, __Els); - true -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - Error, Status, Show, Priority, __Els) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:client">> -> + decode_presence_els(__TopXMLNS, __IgnoreEls, _els, + decode_error(__TopXMLNS, __IgnoreEls, _el), + Status, Show, Priority, __Els); + <<"jabber:client">> -> + decode_presence_els(__TopXMLNS, __IgnoreEls, _els, + decode_error(<<"jabber:client">>, __IgnoreEls, + _el), + Status, Show, Priority, __Els); + _ -> + decode_presence_els(__TopXMLNS, __IgnoreEls, _els, + Error, Status, Show, Priority, __Els) end; decode_presence_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"show">>, _attrs, _} = _el | _els], Error, Status, Show, Priority, __Els) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - Error, Status, - decode_presence_show(__TopXMLNS, __IgnoreEls, - _el), - Priority, __Els); - true -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - Error, Status, Show, Priority, __Els) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:client">> -> + decode_presence_els(__TopXMLNS, __IgnoreEls, _els, + Error, Status, + decode_presence_show(__TopXMLNS, __IgnoreEls, + _el), + Priority, __Els); + <<"jabber:client">> -> + decode_presence_els(__TopXMLNS, __IgnoreEls, _els, + Error, Status, + decode_presence_show(<<"jabber:client">>, + __IgnoreEls, _el), + Priority, __Els); + _ -> + decode_presence_els(__TopXMLNS, __IgnoreEls, _els, + Error, Status, Show, Priority, __Els) end; decode_presence_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"status">>, _attrs, _} = _el | _els], Error, Status, Show, Priority, __Els) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - Error, - [decode_presence_status(__TopXMLNS, __IgnoreEls, - _el) - | Status], - Show, Priority, __Els); - true -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - Error, Status, Show, Priority, __Els) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:client">> -> + decode_presence_els(__TopXMLNS, __IgnoreEls, _els, + Error, + [decode_presence_status(__TopXMLNS, __IgnoreEls, + _el) + | Status], + Show, Priority, __Els); + <<"jabber:client">> -> + decode_presence_els(__TopXMLNS, __IgnoreEls, _els, + Error, + [decode_presence_status(<<"jabber:client">>, + __IgnoreEls, _el) + | Status], + Show, Priority, __Els); + _ -> + decode_presence_els(__TopXMLNS, __IgnoreEls, _els, + Error, Status, Show, Priority, __Els) end; decode_presence_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"priority">>, _attrs, _} = _el | _els], Error, Status, Show, Priority, __Els) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - Error, Status, Show, - decode_presence_priority(__TopXMLNS, __IgnoreEls, - _el), - __Els); - true -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - Error, Status, Show, Priority, __Els) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:client">> -> + decode_presence_els(__TopXMLNS, __IgnoreEls, _els, + Error, Status, Show, + decode_presence_priority(__TopXMLNS, __IgnoreEls, + _el), + __Els); + <<"jabber:client">> -> + decode_presence_els(__TopXMLNS, __IgnoreEls, _els, + Error, Status, Show, + decode_presence_priority(<<"jabber:client">>, + __IgnoreEls, _el), + __Els); + _ -> + decode_presence_els(__TopXMLNS, __IgnoreEls, _els, + Error, Status, Show, Priority, __Els) end; decode_presence_els(__TopXMLNS, __IgnoreEls, [{xmlel, _, _, _} = _el | _els], Error, Status, Show, @@ -17705,11 +20447,11 @@ encode_presence_attr_id(_val, _acc) -> [{<<"id">>, _val} | _acc]. decode_presence_attr_type(__TopXMLNS, undefined) -> - undefined; + available; decode_presence_attr_type(__TopXMLNS, _val) -> case catch dec_enum(_val, [unavailable, subscribe, subscribed, unsubscribe, - unsubscribed, probe, error]) + unsubscribed, available, probe, error]) of {'EXIT', _} -> erlang:error({xmpp_codec, @@ -17718,7 +20460,7 @@ decode_presence_attr_type(__TopXMLNS, _val) -> _res -> _res end. -encode_presence_attr_type(undefined, _acc) -> _acc; +encode_presence_attr_type(available, _acc) -> _acc; encode_presence_attr_type(_val, _acc) -> [{<<"type">>, enc_enum(_val)} | _acc]. @@ -17913,56 +20655,80 @@ decode_message_els(__TopXMLNS, __IgnoreEls, [], Error, decode_message_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"error">>, _attrs, _} = _el | _els], Error, Thread, Subject, Body, __Els) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, - decode_error(__TopXMLNS, __IgnoreEls, _el), - Thread, Subject, Body, __Els); - true -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error, - Thread, Subject, Body, __Els) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:client">> -> + decode_message_els(__TopXMLNS, __IgnoreEls, _els, + decode_error(__TopXMLNS, __IgnoreEls, _el), Thread, + Subject, Body, __Els); + <<"jabber:client">> -> + decode_message_els(__TopXMLNS, __IgnoreEls, _els, + decode_error(<<"jabber:client">>, __IgnoreEls, + _el), + Thread, Subject, Body, __Els); + _ -> + decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error, + Thread, Subject, Body, __Els) end; decode_message_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"subject">>, _attrs, _} = _el | _els], Error, Thread, Subject, Body, __Els) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error, - Thread, - [decode_message_subject(__TopXMLNS, __IgnoreEls, - _el) - | Subject], - Body, __Els); - true -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error, - Thread, Subject, Body, __Els) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:client">> -> + decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error, + Thread, + [decode_message_subject(__TopXMLNS, __IgnoreEls, + _el) + | Subject], + Body, __Els); + <<"jabber:client">> -> + decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error, + Thread, + [decode_message_subject(<<"jabber:client">>, + __IgnoreEls, _el) + | Subject], + Body, __Els); + _ -> + decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error, + Thread, Subject, Body, __Els) end; decode_message_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"thread">>, _attrs, _} = _el | _els], Error, Thread, Subject, Body, __Els) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error, - decode_message_thread(__TopXMLNS, __IgnoreEls, - _el), - Subject, Body, __Els); - true -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error, - Thread, Subject, Body, __Els) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:client">> -> + decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error, + decode_message_thread(__TopXMLNS, __IgnoreEls, + _el), + Subject, Body, __Els); + <<"jabber:client">> -> + decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error, + decode_message_thread(<<"jabber:client">>, + __IgnoreEls, _el), + Subject, Body, __Els); + _ -> + decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error, + Thread, Subject, Body, __Els) end; decode_message_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"body">>, _attrs, _} = _el | _els], Error, Thread, Subject, Body, __Els) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error, - Thread, Subject, - [decode_message_body(__TopXMLNS, __IgnoreEls, _el) - | Body], - __Els); - true -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error, - Thread, Subject, Body, __Els) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:client">> -> + decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error, + Thread, Subject, + [decode_message_body(__TopXMLNS, __IgnoreEls, _el) + | Body], + __Els); + <<"jabber:client">> -> + decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error, + Thread, Subject, + [decode_message_body(<<"jabber:client">>, + __IgnoreEls, _el) + | Body], + __Els); + _ -> + decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error, + Thread, Subject, Body, __Els) end; decode_message_els(__TopXMLNS, __IgnoreEls, [{xmlel, _, _, _} = _el | _els], Error, Thread, Subject, @@ -18280,13 +21046,17 @@ decode_iq_els(__TopXMLNS, __IgnoreEls, [], Error, decode_iq_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"error">>, _attrs, _} = _el | _els], Error, __Els) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_iq_els(__TopXMLNS, __IgnoreEls, _els, - decode_error(__TopXMLNS, __IgnoreEls, _el), __Els); - true -> - decode_iq_els(__TopXMLNS, __IgnoreEls, _els, Error, - __Els) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:client">> -> + decode_iq_els(__TopXMLNS, __IgnoreEls, _els, + decode_error(__TopXMLNS, __IgnoreEls, _el), __Els); + <<"jabber:client">> -> + decode_iq_els(__TopXMLNS, __IgnoreEls, _els, + decode_error(<<"jabber:client">>, __IgnoreEls, _el), + __Els); + _ -> + decode_iq_els(__TopXMLNS, __IgnoreEls, _els, Error, + __Els) end; decode_iq_els(__TopXMLNS, __IgnoreEls, [{xmlel, _, _, _} = _el | _els], Error, __Els) -> @@ -18425,12 +21195,19 @@ decode_stats_els(__TopXMLNS, __IgnoreEls, [], Stat) -> lists:reverse(Stat); decode_stats_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"stat">>, _attrs, _} = _el | _els], Stat) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_stats_els(__TopXMLNS, __IgnoreEls, _els, - [decode_stat(__TopXMLNS, __IgnoreEls, _el) | Stat]); - true -> - decode_stats_els(__TopXMLNS, __IgnoreEls, _els, Stat) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/stats">> -> + decode_stats_els(__TopXMLNS, __IgnoreEls, _els, + [decode_stat(__TopXMLNS, __IgnoreEls, _el) | Stat]); + <<"http://jabber.org/protocol/stats">> -> + decode_stats_els(__TopXMLNS, __IgnoreEls, _els, + [decode_stat(<<"http://jabber.org/protocol/stats">>, + __IgnoreEls, _el) + | Stat]); + _ -> + decode_stats_els(__TopXMLNS, __IgnoreEls, _els, Stat) end; decode_stats_els(__TopXMLNS, __IgnoreEls, [_ | _els], Stat) -> @@ -18460,13 +21237,20 @@ decode_stat_els(__TopXMLNS, __IgnoreEls, [], Error) -> decode_stat_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"error">>, _attrs, _} = _el | _els], Error) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_stat_els(__TopXMLNS, __IgnoreEls, _els, - [decode_stat_error(__TopXMLNS, __IgnoreEls, _el) - | Error]); - true -> - decode_stat_els(__TopXMLNS, __IgnoreEls, _els, Error) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/stats">> -> + decode_stat_els(__TopXMLNS, __IgnoreEls, _els, + [decode_stat_error(__TopXMLNS, __IgnoreEls, _el) + | Error]); + <<"http://jabber.org/protocol/stats">> -> + decode_stat_els(__TopXMLNS, __IgnoreEls, _els, + [decode_stat_error(<<"http://jabber.org/protocol/stats">>, + __IgnoreEls, _el) + | Error]); + _ -> + decode_stat_els(__TopXMLNS, __IgnoreEls, _els, Error) end; decode_stat_els(__TopXMLNS, __IgnoreEls, [_ | _els], Error) -> @@ -18601,32 +21385,46 @@ decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"conference">>, _attrs, _} = _el | _els], Conference, Url) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, - _els, - [decode_bookmark_conference(__TopXMLNS, - __IgnoreEls, - _el) - | Conference], - Url); - true -> - decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, - _els, Conference, Url) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"storage:bookmarks">> -> + decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, + _els, + [decode_bookmark_conference(__TopXMLNS, + __IgnoreEls, + _el) + | Conference], + Url); + <<"storage:bookmarks">> -> + decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, + _els, + [decode_bookmark_conference(<<"storage:bookmarks">>, + __IgnoreEls, + _el) + | Conference], + Url); + _ -> + decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, + _els, Conference, Url) end; decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"url">>, _attrs, _} = _el | _els], Conference, Url) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, - _els, Conference, - [decode_bookmark_url(__TopXMLNS, - __IgnoreEls, _el) - | Url]); - true -> - decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, - _els, Conference, Url) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"storage:bookmarks">> -> + decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, + _els, Conference, + [decode_bookmark_url(__TopXMLNS, + __IgnoreEls, _el) + | Url]); + <<"storage:bookmarks">> -> + decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, + _els, Conference, + [decode_bookmark_url(<<"storage:bookmarks">>, + __IgnoreEls, _el) + | Url]); + _ -> + decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, + _els, Conference, Url) end; decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, [_ | _els], Conference, Url) -> @@ -18721,32 +21519,45 @@ decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"nick">>, _attrs, _} = _el | _els], Password, Nick) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, - _els, Password, - decode_conference_nick(__TopXMLNS, - __IgnoreEls, - _el)); - true -> - decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, - _els, Password, Nick) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"storage:bookmarks">> -> + decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, + _els, Password, + decode_conference_nick(__TopXMLNS, + __IgnoreEls, + _el)); + <<"storage:bookmarks">> -> + decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, + _els, Password, + decode_conference_nick(<<"storage:bookmarks">>, + __IgnoreEls, + _el)); + _ -> + decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, + _els, Password, Nick) end; decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"password">>, _attrs, _} = _el | _els], Password, Nick) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, - _els, - decode_conference_password(__TopXMLNS, - __IgnoreEls, - _el), - Nick); - true -> - decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, - _els, Password, Nick) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"storage:bookmarks">> -> + decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, + _els, + decode_conference_password(__TopXMLNS, + __IgnoreEls, + _el), + Nick); + <<"storage:bookmarks">> -> + decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, + _els, + decode_conference_password(<<"storage:bookmarks">>, + __IgnoreEls, + _el), + Nick); + _ -> + decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, + _els, Password, Nick) end; decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, [_ | _els], Password, Nick) -> @@ -18952,15 +21763,22 @@ decode_disco_items_els(__TopXMLNS, __IgnoreEls, [], lists:reverse(Items); decode_disco_items_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_disco_items_els(__TopXMLNS, __IgnoreEls, _els, - [decode_disco_item(__TopXMLNS, __IgnoreEls, - _el) - | Items]); - true -> - decode_disco_items_els(__TopXMLNS, __IgnoreEls, _els, - Items) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/disco#items">> -> + decode_disco_items_els(__TopXMLNS, __IgnoreEls, _els, + [decode_disco_item(__TopXMLNS, __IgnoreEls, + _el) + | Items]); + <<"http://jabber.org/protocol/disco#items">> -> + decode_disco_items_els(__TopXMLNS, __IgnoreEls, _els, + [decode_disco_item(<<"http://jabber.org/protocol/disco#items">>, + __IgnoreEls, _el) + | Items]); + _ -> + decode_disco_items_els(__TopXMLNS, __IgnoreEls, _els, + Items) end; decode_disco_items_els(__TopXMLNS, __IgnoreEls, [_ | _els], Items) -> @@ -19081,44 +21899,62 @@ decode_disco_info_els(__TopXMLNS, __IgnoreEls, [], decode_disco_info_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"identity">>, _attrs, _} = _el | _els], Xdata, Features, Identities) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_disco_info_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Features, - [decode_disco_identity(__TopXMLNS, __IgnoreEls, - _el) - | Identities]); - true -> - decode_disco_info_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Features, Identities) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/disco#info">> -> + decode_disco_info_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, Features, + [decode_disco_identity(__TopXMLNS, __IgnoreEls, + _el) + | Identities]); + <<"http://jabber.org/protocol/disco#info">> -> + decode_disco_info_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, Features, + [decode_disco_identity(<<"http://jabber.org/protocol/disco#info">>, + __IgnoreEls, _el) + | Identities]); + _ -> + decode_disco_info_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, Features, Identities) end; decode_disco_info_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"feature">>, _attrs, _} = _el | _els], Xdata, Features, Identities) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_disco_info_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, - [decode_disco_feature(__TopXMLNS, __IgnoreEls, - _el) - | Features], - Identities); - true -> - decode_disco_info_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Features, Identities) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/disco#info">> -> + decode_disco_info_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, + [decode_disco_feature(__TopXMLNS, __IgnoreEls, + _el) + | Features], + Identities); + <<"http://jabber.org/protocol/disco#info">> -> + decode_disco_info_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, + [decode_disco_feature(<<"http://jabber.org/protocol/disco#info">>, + __IgnoreEls, _el) + | Features], + Identities); + _ -> + decode_disco_info_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, Features, Identities) end; decode_disco_info_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"x">>, _attrs, _} = _el | _els], Xdata, Features, Identities) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<"jabber:x:data">> -> - decode_disco_info_els(__TopXMLNS, __IgnoreEls, _els, - [decode_xdata(_xmlns, __IgnoreEls, _el) - | Xdata], - Features, Identities); - true -> - decode_disco_info_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Features, Identities) + case get_attr(<<"xmlns">>, _attrs) of + <<"jabber:x:data">> -> + decode_disco_info_els(__TopXMLNS, __IgnoreEls, _els, + [decode_xdata(<<"jabber:x:data">>, __IgnoreEls, + _el) + | Xdata], + Features, Identities); + _ -> + decode_disco_info_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, Features, Identities) end; decode_disco_info_els(__TopXMLNS, __IgnoreEls, [_ | _els], Xdata, Features, Identities) -> @@ -19319,17 +22155,25 @@ decode_unblock_els(__TopXMLNS, __IgnoreEls, [], lists:reverse(Items); decode_unblock_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_unblock_els(__TopXMLNS, __IgnoreEls, _els, - case decode_block_item(__TopXMLNS, __IgnoreEls, - _el) - of - undefined -> Items; - _new_el -> [_new_el | Items] - end); - true -> - decode_unblock_els(__TopXMLNS, __IgnoreEls, _els, Items) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"urn:xmpp:blocking">> -> + decode_unblock_els(__TopXMLNS, __IgnoreEls, _els, + case decode_block_item(__TopXMLNS, __IgnoreEls, + _el) + of + undefined -> Items; + _new_el -> [_new_el | Items] + end); + <<"urn:xmpp:blocking">> -> + decode_unblock_els(__TopXMLNS, __IgnoreEls, _els, + case decode_block_item(<<"urn:xmpp:blocking">>, + __IgnoreEls, _el) + of + undefined -> Items; + _new_el -> [_new_el | Items] + end); + _ -> + decode_unblock_els(__TopXMLNS, __IgnoreEls, _els, Items) end; decode_unblock_els(__TopXMLNS, __IgnoreEls, [_ | _els], Items) -> @@ -19357,16 +22201,24 @@ decode_block_els(__TopXMLNS, __IgnoreEls, [], Items) -> lists:reverse(Items); decode_block_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_block_els(__TopXMLNS, __IgnoreEls, _els, - case decode_block_item(__TopXMLNS, __IgnoreEls, _el) - of - undefined -> Items; - _new_el -> [_new_el | Items] - end); - true -> - decode_block_els(__TopXMLNS, __IgnoreEls, _els, Items) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"urn:xmpp:blocking">> -> + decode_block_els(__TopXMLNS, __IgnoreEls, _els, + case decode_block_item(__TopXMLNS, __IgnoreEls, _el) + of + undefined -> Items; + _new_el -> [_new_el | Items] + end); + <<"urn:xmpp:blocking">> -> + decode_block_els(__TopXMLNS, __IgnoreEls, _els, + case decode_block_item(<<"urn:xmpp:blocking">>, + __IgnoreEls, _el) + of + undefined -> Items; + _new_el -> [_new_el | Items] + end); + _ -> + decode_block_els(__TopXMLNS, __IgnoreEls, _els, Items) end; decode_block_els(__TopXMLNS, __IgnoreEls, [_ | _els], Items) -> @@ -19421,7 +22273,7 @@ decode_privacy(__TopXMLNS, __IgnoreEls, {Lists, Default, Active} = decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, [], undefined, undefined), - {privacy, Lists, Default, Active}. + {privacy_query, Lists, Default, Active}. decode_privacy_els(__TopXMLNS, __IgnoreEls, [], Lists, Default, Active) -> @@ -19429,48 +22281,64 @@ decode_privacy_els(__TopXMLNS, __IgnoreEls, [], Lists, decode_privacy_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"list">>, _attrs, _} = _el | _els], Lists, Default, Active) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, - [decode_privacy_list(__TopXMLNS, __IgnoreEls, _el) - | Lists], - Default, Active); - true -> - decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, Lists, - Default, Active) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:privacy">> -> + decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, + [decode_privacy_list(__TopXMLNS, __IgnoreEls, _el) + | Lists], + Default, Active); + <<"jabber:iq:privacy">> -> + decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, + [decode_privacy_list(<<"jabber:iq:privacy">>, + __IgnoreEls, _el) + | Lists], + Default, Active); + _ -> + decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, Lists, + Default, Active) end; decode_privacy_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"default">>, _attrs, _} = _el | _els], Lists, Default, Active) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, Lists, - decode_privacy_default_list(__TopXMLNS, - __IgnoreEls, _el), - Active); - true -> - decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, Lists, - Default, Active) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:privacy">> -> + decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, Lists, + decode_privacy_default_list(__TopXMLNS, + __IgnoreEls, _el), + Active); + <<"jabber:iq:privacy">> -> + decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, Lists, + decode_privacy_default_list(<<"jabber:iq:privacy">>, + __IgnoreEls, _el), + Active); + _ -> + decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, Lists, + Default, Active) end; decode_privacy_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"active">>, _attrs, _} = _el | _els], Lists, Default, Active) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, Lists, - Default, - decode_privacy_active_list(__TopXMLNS, - __IgnoreEls, _el)); - true -> - decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, Lists, - Default, Active) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:privacy">> -> + decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, Lists, + Default, + decode_privacy_active_list(__TopXMLNS, __IgnoreEls, + _el)); + <<"jabber:iq:privacy">> -> + decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, Lists, + Default, + decode_privacy_active_list(<<"jabber:iq:privacy">>, + __IgnoreEls, _el)); + _ -> + decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, Lists, + Default, Active) end; decode_privacy_els(__TopXMLNS, __IgnoreEls, [_ | _els], Lists, Default, Active) -> decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, Lists, Default, Active). -encode_privacy({privacy, Lists, Default, Active}, +encode_privacy({privacy_query, Lists, Default, Active}, _xmlns_attrs) -> _els = lists:reverse('encode_privacy_$lists'(Lists, 'encode_privacy_$default'(Default, @@ -19577,15 +22445,20 @@ decode_privacy_list_els(__TopXMLNS, __IgnoreEls, [], lists:reverse(Items); decode_privacy_list_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_privacy_list_els(__TopXMLNS, __IgnoreEls, _els, - [decode_privacy_item(__TopXMLNS, __IgnoreEls, - _el) - | Items]); - true -> - decode_privacy_list_els(__TopXMLNS, __IgnoreEls, _els, - Items) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:privacy">> -> + decode_privacy_list_els(__TopXMLNS, __IgnoreEls, _els, + [decode_privacy_item(__TopXMLNS, __IgnoreEls, + _el) + | Items]); + <<"jabber:iq:privacy">> -> + decode_privacy_list_els(__TopXMLNS, __IgnoreEls, _els, + [decode_privacy_item(<<"jabber:iq:privacy">>, + __IgnoreEls, _el) + | Items]); + _ -> + decode_privacy_list_els(__TopXMLNS, __IgnoreEls, _els, + Items) end; decode_privacy_list_els(__TopXMLNS, __IgnoreEls, [_ | _els], Items) -> @@ -19624,63 +22497,98 @@ encode_privacy_list_attr_name(_val, _acc) -> decode_privacy_item(__TopXMLNS, __IgnoreEls, {xmlel, <<"item">>, _attrs, _els}) -> - Kinds = decode_privacy_item_els(__TopXMLNS, __IgnoreEls, - _els, []), + {Iq, Presence_out, Message, Presence_in} = + decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, + false, false, false, false), {Action, Order, Type, Value} = decode_privacy_item_attrs(__TopXMLNS, _attrs, undefined, undefined, undefined, undefined), - {privacy_item, Order, Action, Type, Value, Kinds}. + {privacy_item, Order, Action, Type, Value, Message, Iq, + Presence_in, Presence_out}. -decode_privacy_item_els(__TopXMLNS, __IgnoreEls, [], - Kinds) -> - lists:reverse(Kinds); +decode_privacy_item_els(__TopXMLNS, __IgnoreEls, [], Iq, + Presence_out, Message, Presence_in) -> + {Iq, Presence_out, Message, Presence_in}; decode_privacy_item_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"message">>, _attrs, _} = _el | _els], - Kinds) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, - Kinds); - true -> - decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, - Kinds) + [{xmlel, <<"message">>, _attrs, _} = _el | _els], Iq, + Presence_out, Message, Presence_in) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:privacy">> -> + decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, + Iq, Presence_out, + decode_privacy_message(__TopXMLNS, + __IgnoreEls, _el), + Presence_in); + <<"jabber:iq:privacy">> -> + decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, + Iq, Presence_out, + decode_privacy_message(<<"jabber:iq:privacy">>, + __IgnoreEls, _el), + Presence_in); + _ -> + decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, + Iq, Presence_out, Message, Presence_in) end; decode_privacy_item_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"iq">>, _attrs, _} = _el | _els], Kinds) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, - Kinds); - true -> - decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, - Kinds) + [{xmlel, <<"iq">>, _attrs, _} = _el | _els], Iq, + Presence_out, Message, Presence_in) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:privacy">> -> + decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, + decode_privacy_iq(__TopXMLNS, __IgnoreEls, + _el), + Presence_out, Message, Presence_in); + <<"jabber:iq:privacy">> -> + decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, + decode_privacy_iq(<<"jabber:iq:privacy">>, + __IgnoreEls, _el), + Presence_out, Message, Presence_in); + _ -> + decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, + Iq, Presence_out, Message, Presence_in) end; decode_privacy_item_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"presence-in">>, _attrs, _} = _el | _els], - Kinds) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, - Kinds); - true -> - decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, - Kinds) + Iq, Presence_out, Message, Presence_in) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:privacy">> -> + decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, + Iq, Presence_out, Message, + decode_privacy_presence_in(__TopXMLNS, + __IgnoreEls, _el)); + <<"jabber:iq:privacy">> -> + decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, + Iq, Presence_out, Message, + decode_privacy_presence_in(<<"jabber:iq:privacy">>, + __IgnoreEls, _el)); + _ -> + decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, + Iq, Presence_out, Message, Presence_in) end; decode_privacy_item_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"presence-out">>, _attrs, _} = _el | _els], - Kinds) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, - Kinds); - true -> - decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, - Kinds) + Iq, Presence_out, Message, Presence_in) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:privacy">> -> + decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, + Iq, + decode_privacy_presence_out(__TopXMLNS, + __IgnoreEls, _el), + Message, Presence_in); + <<"jabber:iq:privacy">> -> + decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, + Iq, + decode_privacy_presence_out(<<"jabber:iq:privacy">>, + __IgnoreEls, _el), + Message, Presence_in); + _ -> + decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, + Iq, Presence_out, Message, Presence_in) end; decode_privacy_item_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Kinds) -> + [_ | _els], Iq, Presence_out, Message, Presence_in) -> decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, - Kinds). + Iq, Presence_out, Message, Presence_in). decode_privacy_item_attrs(__TopXMLNS, [{<<"action">>, _val} | _attrs], _Action, Order, Type, @@ -19714,10 +22622,13 @@ decode_privacy_item_attrs(__TopXMLNS, [], Action, Order, decode_privacy_item_attr_value(__TopXMLNS, Value)}. encode_privacy_item({privacy_item, Order, Action, Type, - Value, Kinds}, + Value, Message, Iq, Presence_in, Presence_out}, _xmlns_attrs) -> - _els = lists:reverse('encode_privacy_item_$kinds'(Kinds, - [])), + _els = lists:reverse('encode_privacy_item_$iq'(Iq, + 'encode_privacy_item_$presence_out'(Presence_out, + 'encode_privacy_item_$message'(Message, + 'encode_privacy_item_$presence_in'(Presence_in, + []))))), _attrs = encode_privacy_item_attr_value(Value, encode_privacy_item_attr_type(Type, encode_privacy_item_attr_order(Order, @@ -19725,27 +22636,23 @@ encode_privacy_item({privacy_item, Order, Action, Type, _xmlns_attrs)))), {xmlel, <<"item">>, _attrs, _els}. -'encode_privacy_item_$kinds'([], _acc) -> _acc; -'encode_privacy_item_$kinds'([message = Kinds | _els], - _acc) -> - 'encode_privacy_item_$kinds'(_els, - [encode_privacy_message(Kinds, []) | _acc]); -'encode_privacy_item_$kinds'([iq = Kinds | _els], - _acc) -> - 'encode_privacy_item_$kinds'(_els, - [encode_privacy_iq(Kinds, []) | _acc]); -'encode_privacy_item_$kinds'(['presence-in' = Kinds - | _els], - _acc) -> - 'encode_privacy_item_$kinds'(_els, - [encode_privacy_presence_in(Kinds, []) - | _acc]); -'encode_privacy_item_$kinds'(['presence-out' = Kinds - | _els], - _acc) -> - 'encode_privacy_item_$kinds'(_els, - [encode_privacy_presence_out(Kinds, []) - | _acc]). +'encode_privacy_item_$iq'(false, _acc) -> _acc; +'encode_privacy_item_$iq'(Iq, _acc) -> + [encode_privacy_iq(Iq, []) | _acc]. + +'encode_privacy_item_$presence_out'(false, _acc) -> + _acc; +'encode_privacy_item_$presence_out'(Presence_out, + _acc) -> + [encode_privacy_presence_out(Presence_out, []) | _acc]. + +'encode_privacy_item_$message'(false, _acc) -> _acc; +'encode_privacy_item_$message'(Message, _acc) -> + [encode_privacy_message(Message, []) | _acc]. + +'encode_privacy_item_$presence_in'(false, _acc) -> _acc; +'encode_privacy_item_$presence_in'(Presence_in, _acc) -> + [encode_privacy_presence_in(Presence_in, []) | _acc]. decode_privacy_item_attr_action(__TopXMLNS, undefined) -> @@ -19802,90 +22709,111 @@ encode_privacy_item_attr_value(_val, _acc) -> decode_privacy_presence_out(__TopXMLNS, __IgnoreEls, {xmlel, <<"presence-out">>, _attrs, _els}) -> - 'presence-out'. + true. -encode_privacy_presence_out('presence-out', - _xmlns_attrs) -> +encode_privacy_presence_out(true, _xmlns_attrs) -> _els = [], _attrs = _xmlns_attrs, {xmlel, <<"presence-out">>, _attrs, _els}. decode_privacy_presence_in(__TopXMLNS, __IgnoreEls, {xmlel, <<"presence-in">>, _attrs, _els}) -> - 'presence-in'. + true. -encode_privacy_presence_in('presence-in', - _xmlns_attrs) -> +encode_privacy_presence_in(true, _xmlns_attrs) -> _els = [], _attrs = _xmlns_attrs, {xmlel, <<"presence-in">>, _attrs, _els}. decode_privacy_iq(__TopXMLNS, __IgnoreEls, {xmlel, <<"iq">>, _attrs, _els}) -> - iq. + true. -encode_privacy_iq(iq, _xmlns_attrs) -> +encode_privacy_iq(true, _xmlns_attrs) -> _els = [], _attrs = _xmlns_attrs, {xmlel, <<"iq">>, _attrs, _els}. decode_privacy_message(__TopXMLNS, __IgnoreEls, {xmlel, <<"message">>, _attrs, _els}) -> - message. + true. -encode_privacy_message(message, _xmlns_attrs) -> +encode_privacy_message(true, _xmlns_attrs) -> _els = [], _attrs = _xmlns_attrs, {xmlel, <<"message">>, _attrs, _els}. -decode_roster(__TopXMLNS, __IgnoreEls, - {xmlel, <<"query">>, _attrs, _els}) -> - Items = decode_roster_els(__TopXMLNS, __IgnoreEls, _els, - []), - Ver = decode_roster_attrs(__TopXMLNS, _attrs, - undefined), - {roster, Items, Ver}. +decode_rosterver_feature(__TopXMLNS, __IgnoreEls, + {xmlel, <<"ver">>, _attrs, _els}) -> + {rosterver_feature}. -decode_roster_els(__TopXMLNS, __IgnoreEls, [], Items) -> +encode_rosterver_feature({rosterver_feature}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"ver">>, _attrs, _els}. + +decode_roster_query(__TopXMLNS, __IgnoreEls, + {xmlel, <<"query">>, _attrs, _els}) -> + Items = decode_roster_query_els(__TopXMLNS, __IgnoreEls, + _els, []), + Ver = decode_roster_query_attrs(__TopXMLNS, _attrs, + undefined), + {roster_query, Items, Ver}. + +decode_roster_query_els(__TopXMLNS, __IgnoreEls, [], + Items) -> lists:reverse(Items); -decode_roster_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_roster_els(__TopXMLNS, __IgnoreEls, _els, - [decode_roster_item(__TopXMLNS, __IgnoreEls, _el) - | Items]); - true -> - decode_roster_els(__TopXMLNS, __IgnoreEls, _els, Items) +decode_roster_query_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:roster">> -> + decode_roster_query_els(__TopXMLNS, __IgnoreEls, _els, + [decode_roster_item(__TopXMLNS, __IgnoreEls, + _el) + | Items]); + <<"jabber:iq:roster">> -> + decode_roster_query_els(__TopXMLNS, __IgnoreEls, _els, + [decode_roster_item(<<"jabber:iq:roster">>, + __IgnoreEls, _el) + | Items]); + _ -> + decode_roster_query_els(__TopXMLNS, __IgnoreEls, _els, + Items) end; -decode_roster_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Items) -> - decode_roster_els(__TopXMLNS, __IgnoreEls, _els, Items). +decode_roster_query_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Items) -> + decode_roster_query_els(__TopXMLNS, __IgnoreEls, _els, + Items). -decode_roster_attrs(__TopXMLNS, - [{<<"ver">>, _val} | _attrs], _Ver) -> - decode_roster_attrs(__TopXMLNS, _attrs, _val); -decode_roster_attrs(__TopXMLNS, [_ | _attrs], Ver) -> - decode_roster_attrs(__TopXMLNS, _attrs, Ver); -decode_roster_attrs(__TopXMLNS, [], Ver) -> - decode_roster_attr_ver(__TopXMLNS, Ver). +decode_roster_query_attrs(__TopXMLNS, + [{<<"ver">>, _val} | _attrs], _Ver) -> + decode_roster_query_attrs(__TopXMLNS, _attrs, _val); +decode_roster_query_attrs(__TopXMLNS, [_ | _attrs], + Ver) -> + decode_roster_query_attrs(__TopXMLNS, _attrs, Ver); +decode_roster_query_attrs(__TopXMLNS, [], Ver) -> + decode_roster_query_attr_ver(__TopXMLNS, Ver). -encode_roster({roster, Items, Ver}, _xmlns_attrs) -> - _els = lists:reverse('encode_roster_$items'(Items, [])), - _attrs = encode_roster_attr_ver(Ver, _xmlns_attrs), +encode_roster_query({roster_query, Items, Ver}, + _xmlns_attrs) -> + _els = lists:reverse('encode_roster_query_$items'(Items, + [])), + _attrs = encode_roster_query_attr_ver(Ver, + _xmlns_attrs), {xmlel, <<"query">>, _attrs, _els}. -'encode_roster_$items'([], _acc) -> _acc; -'encode_roster_$items'([Items | _els], _acc) -> - 'encode_roster_$items'(_els, - [encode_roster_item(Items, []) | _acc]). +'encode_roster_query_$items'([], _acc) -> _acc; +'encode_roster_query_$items'([Items | _els], _acc) -> + 'encode_roster_query_$items'(_els, + [encode_roster_item(Items, []) | _acc]). -decode_roster_attr_ver(__TopXMLNS, undefined) -> +decode_roster_query_attr_ver(__TopXMLNS, undefined) -> undefined; -decode_roster_attr_ver(__TopXMLNS, _val) -> _val. +decode_roster_query_attr_ver(__TopXMLNS, _val) -> _val. -encode_roster_attr_ver(undefined, _acc) -> _acc; -encode_roster_attr_ver(_val, _acc) -> +encode_roster_query_attr_ver(undefined, _acc) -> _acc; +encode_roster_query_attr_ver(_val, _acc) -> [{<<"ver">>, _val} | _acc]. decode_roster_item(__TopXMLNS, __IgnoreEls, @@ -19903,15 +22831,20 @@ decode_roster_item_els(__TopXMLNS, __IgnoreEls, [], decode_roster_item_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"group">>, _attrs, _} = _el | _els], Groups) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_roster_item_els(__TopXMLNS, __IgnoreEls, _els, - [decode_roster_group(__TopXMLNS, __IgnoreEls, - _el) - | Groups]); - true -> - decode_roster_item_els(__TopXMLNS, __IgnoreEls, _els, - Groups) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:roster">> -> + decode_roster_item_els(__TopXMLNS, __IgnoreEls, _els, + [decode_roster_group(__TopXMLNS, __IgnoreEls, + _el) + | Groups]); + <<"jabber:iq:roster">> -> + decode_roster_item_els(__TopXMLNS, __IgnoreEls, _els, + [decode_roster_group(<<"jabber:iq:roster">>, + __IgnoreEls, _el) + | Groups]); + _ -> + decode_roster_item_els(__TopXMLNS, __IgnoreEls, _els, + Groups) end; decode_roster_item_els(__TopXMLNS, __IgnoreEls, [_ | _els], Groups) -> @@ -19982,10 +22915,10 @@ encode_roster_item_attr_jid(_val, _acc) -> [{<<"jid">>, enc_jid(_val)} | _acc]. decode_roster_item_attr_name(__TopXMLNS, undefined) -> - undefined; + <<>>; decode_roster_item_attr_name(__TopXMLNS, _val) -> _val. -encode_roster_item_attr_name(undefined, _acc) -> _acc; +encode_roster_item_attr_name(<<>>, _acc) -> _acc; encode_roster_item_attr_name(_val, _acc) -> [{<<"name">>, _val} | _acc]. @@ -20067,39 +23000,53 @@ decode_version_els(__TopXMLNS, __IgnoreEls, [], Ver, Os, decode_version_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"name">>, _attrs, _} = _el | _els], Ver, Os, Name) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_version_els(__TopXMLNS, __IgnoreEls, _els, Ver, - Os, - decode_version_name(__TopXMLNS, __IgnoreEls, - _el)); - true -> - decode_version_els(__TopXMLNS, __IgnoreEls, _els, Ver, - Os, Name) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:version">> -> + decode_version_els(__TopXMLNS, __IgnoreEls, _els, Ver, + Os, + decode_version_name(__TopXMLNS, __IgnoreEls, _el)); + <<"jabber:iq:version">> -> + decode_version_els(__TopXMLNS, __IgnoreEls, _els, Ver, + Os, + decode_version_name(<<"jabber:iq:version">>, + __IgnoreEls, _el)); + _ -> + decode_version_els(__TopXMLNS, __IgnoreEls, _els, Ver, + Os, Name) end; decode_version_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"version">>, _attrs, _} = _el | _els], Ver, Os, Name) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_version_els(__TopXMLNS, __IgnoreEls, _els, - decode_version_ver(__TopXMLNS, __IgnoreEls, _el), - Os, Name); - true -> - decode_version_els(__TopXMLNS, __IgnoreEls, _els, Ver, - Os, Name) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:version">> -> + decode_version_els(__TopXMLNS, __IgnoreEls, _els, + decode_version_ver(__TopXMLNS, __IgnoreEls, _el), + Os, Name); + <<"jabber:iq:version">> -> + decode_version_els(__TopXMLNS, __IgnoreEls, _els, + decode_version_ver(<<"jabber:iq:version">>, + __IgnoreEls, _el), + Os, Name); + _ -> + decode_version_els(__TopXMLNS, __IgnoreEls, _els, Ver, + Os, Name) end; decode_version_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"os">>, _attrs, _} = _el | _els], Ver, Os, Name) -> - _xmlns = get_attr(<<"xmlns">>, _attrs), - if _xmlns == <<>>; _xmlns == __TopXMLNS -> - decode_version_els(__TopXMLNS, __IgnoreEls, _els, Ver, - decode_version_os(__TopXMLNS, __IgnoreEls, _el), - Name); - true -> - decode_version_els(__TopXMLNS, __IgnoreEls, _els, Ver, - Os, Name) + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:iq:version">> -> + decode_version_els(__TopXMLNS, __IgnoreEls, _els, Ver, + decode_version_os(__TopXMLNS, __IgnoreEls, _el), + Name); + <<"jabber:iq:version">> -> + decode_version_els(__TopXMLNS, __IgnoreEls, _els, Ver, + decode_version_os(<<"jabber:iq:version">>, + __IgnoreEls, _el), + Name); + _ -> + decode_version_els(__TopXMLNS, __IgnoreEls, _els, Ver, + Os, Name) end; decode_version_els(__TopXMLNS, __IgnoreEls, [_ | _els], Ver, Os, Name) -> @@ -20222,21 +23169,21 @@ encode_version_name_cdata(_val, _acc) -> decode_last(__TopXMLNS, __IgnoreEls, {xmlel, <<"query">>, _attrs, _els}) -> - Text = decode_last_els(__TopXMLNS, __IgnoreEls, _els, - <<>>), + Status = decode_last_els(__TopXMLNS, __IgnoreEls, _els, + <<>>), Seconds = decode_last_attrs(__TopXMLNS, _attrs, undefined), - {last, Seconds, Text}. + {last, Seconds, Status}. -decode_last_els(__TopXMLNS, __IgnoreEls, [], Text) -> - decode_last_cdata(__TopXMLNS, Text); +decode_last_els(__TopXMLNS, __IgnoreEls, [], Status) -> + decode_last_cdata(__TopXMLNS, Status); decode_last_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Text) -> + [{xmlcdata, _data} | _els], Status) -> decode_last_els(__TopXMLNS, __IgnoreEls, _els, - <>); + <>); decode_last_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Text) -> - decode_last_els(__TopXMLNS, __IgnoreEls, _els, Text). + Status) -> + decode_last_els(__TopXMLNS, __IgnoreEls, _els, Status). decode_last_attrs(__TopXMLNS, [{<<"seconds">>, _val} | _attrs], _Seconds) -> @@ -20246,8 +23193,8 @@ decode_last_attrs(__TopXMLNS, [_ | _attrs], Seconds) -> decode_last_attrs(__TopXMLNS, [], Seconds) -> decode_last_attr_seconds(__TopXMLNS, Seconds). -encode_last({last, Seconds, Text}, _xmlns_attrs) -> - _els = encode_last_cdata(Text, []), +encode_last({last, Seconds, Status}, _xmlns_attrs) -> + _els = encode_last_cdata(Status, []), _attrs = encode_last_attr_seconds(Seconds, _xmlns_attrs), {xmlel, <<"query">>, _attrs, _els}. @@ -20267,9 +23214,9 @@ encode_last_attr_seconds(undefined, _acc) -> _acc; encode_last_attr_seconds(_val, _acc) -> [{<<"seconds">>, enc_int(_val)} | _acc]. -decode_last_cdata(__TopXMLNS, <<>>) -> undefined; +decode_last_cdata(__TopXMLNS, <<>>) -> <<>>; decode_last_cdata(__TopXMLNS, _val) -> _val. -encode_last_cdata(undefined, _acc) -> _acc; +encode_last_cdata(<<>>, _acc) -> _acc; encode_last_cdata(_val, _acc) -> [{xmlcdata, _val} | _acc]. diff --git a/src/xmpp_util.erl b/src/xmpp_util.erl new file mode 100644 index 000000000..42b251fc1 --- /dev/null +++ b/src/xmpp_util.erl @@ -0,0 +1,81 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 12 Jul 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(xmpp_util). + +%% API +-export([add_delay_info/3, add_delay_info/4, unwrap_carbon/1, + is_standalone_chat_state/1]). + +-include("xmpp.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +-spec add_delay_info(stanza(), jid(), erlang:timestamp()) -> stanza(). +add_delay_info(Stz, From, Time) -> + add_delay_info(Stz, From, Time, <<"">>). + +-spec add_delay_info(stanza(), jid(), + erlang:timestamp(), binary()) -> stanza(). + +add_delay_info(Stz, From, Time, Desc) -> + case xmpp:get_subtag(Stz, #delay{}) of + #delay{from = OldFrom, desc = OldDesc} = Delay -> + case jid:tolower(From) == jid:tolower(OldFrom) of + true when Desc == <<"">> -> + Stz; + true when OldDesc == <<"">> -> + xmpp:set_subtag(Stz, Delay#delay{desc = Desc}); + true -> + case binary:match(OldDesc, Desc) of + nomatch -> + NewDesc = <>, + xmpp:set_subtag(Stz, Delay#delay{desc = NewDesc}); + _ -> + Stz + end; + false -> + NewDelay = #delay{stamp = Time, from = From, desc = Desc}, + xmpp:set_subtag(Stz, NewDelay) + end; + false -> + Delay = #delay{stamp = Time, from = From, desc = Desc}, + xmpp:set_subtag(Stz, Delay) + end. + +-spec unwrap_carbon(stanza()) -> xmpp_element(). +unwrap_carbon(#message{} = Msg) -> + case xmpp:get_subtag(Msg, #carbons_sent{}) of + #carbons_sent{forwarded = #forwarded{sub_els = [El]}} -> + El; + _ -> + case xmpp:get_subtag(Msg, #carbons_received{}) of + #carbons_received{forwarded = #forwarded{sub_els = [El]}} -> + El; + _ -> + Msg + end + end; +unwrap_carbon(Stanza) -> Stanza. + +-spec is_standalone_chat_state(stanza()) -> boolean(). +is_standalone_chat_state(Stanza) -> + case unwrap_carbon(Stanza) of + #message{sub_els = Els} -> + IgnoreNS = [?NS_CHATSTATES, ?NS_DELAY], + Stripped = [El || El <- Els, + not lists:member(xmpp:get_ns(El), IgnoreNS)], + Stripped == []; + _ -> + false + end. + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== diff --git a/tools/xmpp_codec.spec b/tools/xmpp_codec.spec index acf9c3bb7..07d3a3dfd 100644 --- a/tools/xmpp_codec.spec +++ b/tools/xmpp_codec.spec @@ -1,11 +1,11 @@ -xml(last, #elem{name = <<"query">>, xmlns = <<"jabber:iq:last">>, - result = {last, '$seconds', '$text'}, + result = {last, '$seconds', '$status'}, attrs = [#attr{name = <<"seconds">>, enc = {enc_int, []}, dec = {dec_int, [0, infinity]}}], - cdata = #cdata{label = '$text'}}). + cdata = #cdata{default = <<"">>, label = '$status'}}). -xml(version_name, #elem{name = <<"name">>, @@ -54,7 +54,8 @@ required = true, dec = {dec_jid, []}, enc = {enc_jid, []}}, - #attr{name = <<"name">>}, + #attr{name = <<"name">>, + default = <<"">>}, #attr{name = <<"subscription">>, default = none, enc = {enc_enum, []}, @@ -64,29 +65,34 @@ dec = {dec_enum, [[subscribe]]}}], refs = [#ref{name = roster_group, label = '$groups'}]}). --xml(roster, +-xml(roster_query, #elem{name = <<"query">>, xmlns = <<"jabber:iq:roster">>, - result = {roster, '$items', '$ver'}, + result = {roster_query, '$items', '$ver'}, attrs = [#attr{name = <<"ver">>}], refs = [#ref{name = roster_item, label = '$items'}]}). +-xml(rosterver_feature, + #elem{name = <<"ver">>, + xmlns = <<"urn:xmpp:features:rosterver">>, + result = {rosterver_feature}}). + -xml(privacy_message, #elem{name = <<"message">>, xmlns = <<"jabber:iq:privacy">>, - result = message}). + result = true}). -xml(privacy_iq, #elem{name = <<"iq">>, xmlns = <<"jabber:iq:privacy">>, - result = iq}). + result = true}). -xml(privacy_presence_in, #elem{name = <<"presence-in">>, xmlns = <<"jabber:iq:privacy">>, - result = 'presence-in'}). + result = true}). -xml(privacy_presence_out, #elem{name = <<"presence-out">>, xmlns = <<"jabber:iq:privacy">>, - result = 'presence-out'}). + result = true}). -xml(privacy_item, #elem{name = <<"item">>, xmlns = <<"jabber:iq:privacy">>, - result = {privacy_item, '$order', '$action', '$type', - '$value', '$kinds'}, + result = {privacy_item, '$order', '$action', '$type', '$value', + '$message', '$iq', '$presence_in', '$presence_out'}, attrs = [#attr{name = <<"action">>, required = true, dec = {dec_enum, [[allow, deny]]}, @@ -99,14 +105,14 @@ dec = {dec_enum, [[group, jid, subscription]]}, enc = {enc_enum, []}}, #attr{name = <<"value">>}], - refs = [#ref{name = privacy_message, - label = '$kinds'}, - #ref{name = privacy_iq, - label = '$kinds'}, - #ref{name = privacy_presence_in, - label = '$kinds'}, - #ref{name = privacy_presence_out, - label = '$kinds'}]}). + refs = [#ref{name = privacy_message, default = false, + min = 0, max = 1, label = '$message'}, + #ref{name = privacy_iq, default = false, + min = 0, max = 1, label = '$iq'}, + #ref{name = privacy_presence_in, default = false, + min = 0, max = 1, label = '$presence_in'}, + #ref{name = privacy_presence_out, default = false, + min = 0, max = 1, label = '$presence_out'}]}). -xml(privacy_list, #elem{name = <<"list">>, @@ -134,7 +140,7 @@ -xml(privacy, #elem{name = <<"query">>, xmlns = <<"jabber:iq:privacy">>, - result = {privacy, '$lists', '$default', '$active'}, + result = {privacy_query, '$lists', '$default', '$active'}, refs = [#ref{name = privacy_list, label = '$lists'}, #ref{name = privacy_default_list, @@ -396,10 +402,11 @@ '$show', '$status', '$priority', '$error', '$_els'}, attrs = [#attr{name = <<"id">>}, #attr{name = <<"type">>, + default = available, enc = {enc_enum, []}, dec = {dec_enum, [[unavailable, subscribe, subscribed, unsubscribe, unsubscribed, - probe, error]]}}, + available, probe, error]]}}, #attr{name = <<"from">>, dec = {dec_jid, []}, enc = {enc_jid, []}}, @@ -516,13 +523,17 @@ -xml(error, #elem{name = <<"error">>, xmlns = <<"jabber:client">>, - result = {error, '$type', '$by', '$reason', '$text'}, + result = {error, '$type', '$code', '$by', '$reason', '$text'}, attrs = [#attr{name = <<"type">>, label = '$type', required = true, dec = {dec_enum, [[auth, cancel, continue, modify, wait]]}, enc = {enc_enum, []}}, + #attr{name = <<"code">>, + label = '$code', + enc = {enc_int, []}, + dec = {dec_int, [0, infinity]}}, #attr{name = <<"by">>}], refs = [#ref{name = error_text, min = 0, max = 1, label = '$text'}, @@ -595,6 +606,41 @@ min = 0, max = 1, label = '$resource'}]}). +-xml(legacy_auth_username, + #elem{name = <<"username">>, + xmlns = <<"jabber:iq:auth">>, + cdata = #cdata{default = none}, + result = '$cdata'}). +-xml(legacy_auth_password, + #elem{name = <<"password">>, + xmlns = <<"jabber:iq:auth">>, + cdata = #cdata{default = none}, + result = '$cdata'}). +-xml(legacy_auth_digest, + #elem{name = <<"digest">>, + xmlns = <<"jabber:iq:auth">>, + cdata = #cdata{default = none}, + result = '$cdata'}). +-xml(legacy_auth_resource, + #elem{name = <<"resource">>, + xmlns = <<"jabber:iq:auth">>, + cdata = #cdata{default = none}, + result = '$cdata'}). + +-xml(legacy_auth, + #elem{name = <<"query">>, + xmlns = <<"jabber:iq:auth">>, + result = {legacy_auth, '$username', '$password', + '$digest', '$resource'}, + refs = [#ref{name = legacy_auth_username, min = 0, max = 1, + label = '$username'}, + #ref{name = legacy_auth_password, min = 0, max = 1, + label = '$password'}, + #ref{name = legacy_auth_digest, min = 0, max = 1, + label = '$digest'}, + #ref{name = legacy_auth_resource, min = 0, max = 1, + label = '$resource'}]}). + -xml(sasl_auth, #elem{name = <<"auth">>, xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>, @@ -682,6 +728,10 @@ #elem{name = <<"not-authorized">>, result = 'not-authorized', xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>}). +-xml(sasl_failure_bad_protocol, + #elem{name = <<"bad-protocol">>, + result = 'bad-protocol', + xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>}). -xml(sasl_failure_temporary_auth_failure, #elem{name = <<"temporary-auth-failure">>, result = 'temporary-auth-failure', @@ -713,6 +763,8 @@ min = 0, max = 1, label = '$reason'}, #ref{name = sasl_failure_not_authorized, min = 0, max = 1, label = '$reason'}, + #ref{name = sasl_failure_bad_protocol, + min = 0, max = 1, label = '$reason'}, #ref{name = sasl_failure_temporary_auth_failure, min = 0, max = 1, label = '$reason'}]}). @@ -827,12 +879,16 @@ -xml(caps, #elem{name = <<"c">>, xmlns = <<"http://jabber.org/protocol/caps">>, - result = {caps, '$hash', '$node', '$ver'}, + result = {caps, '$node', '$version', '$hash', '$exts'}, attrs = [#attr{name = <<"hash">>}, #attr{name = <<"node">>}, + #attr{name = <<"ext">>, + label = '$exts', + default = [], + dec = {re, split, ["\\h+"]}, + enc = {join, [$ ]}}, #attr{name = <<"ver">>, - enc = {base64, encode, []}, - dec = {base64, decode, []}}]}). + label = '$version'}]}). -xml(feature_register, #elem{name = <<"register">>, @@ -988,10 +1044,18 @@ #ref{name = register_key, min = 0, max = 1, label = '$key'}]}). +-xml(session_optional, + #elem{name = <<"optional">>, + xmlns = <<"urn:ietf:params:xml:ns:xmpp-session">>, + result = true}). + -xml(session, #elem{name = <<"session">>, xmlns = <<"urn:ietf:params:xml:ns:xmpp-session">>, - result = {session}}). + result = {xmpp_session, '$optional'}, + refs = [#ref{name = session_optional, + min = 0, max = 1, default = false, + label = '$optional'}]}). -xml(ping, #elem{name = <<"ping">>, @@ -1444,10 +1508,10 @@ %% refs = [#ref{name = vcard, min = 0, max = 1, label = '$vcard'}, %% #ref{name = vcard_EXTVAL, min = 0, max = 1, label = '$extval'}]}). --xml(vcard, +-xml(vcard_temp, #elem{name = <<"vCard">>, xmlns = <<"vcard-temp">>, - result = {vcard, '$version', '$fn', '$n', '$nickname', '$photo', + result = {vcard_temp, '$version', '$fn', '$n', '$nickname', '$photo', '$bday', '$adr', '$label', '$tel', '$email', '$jabberid', '$mailer', '$tz', '$geo', '$title', '$role', '$logo', '$org', '$categories', '$note', '$prodid', %% '$agent', @@ -1491,12 +1555,16 @@ xmlns = <<"vcard-temp:x:update">>, result = '$cdata'}). +-record(vcard_xupdate, {us :: {binary(), binary()}, + hash :: binary()}). +-type vcard_xupdate() :: #vcard_xupdate{}. + -xml(vcard_xupdate, #elem{name = <<"x">>, xmlns = <<"vcard-temp:x:update">>, - result = {vcard_xupdate, '$photo'}, + result = {vcard_xupdate, undefined, '$hash'}, refs = [#ref{name = vcard_xupdate_photo, min = 0, max = 1, - label = '$photo'}]}). + label = '$hash'}]}). -xml(xdata_field_required, #elem{name = <<"required">>, @@ -1770,6 +1838,7 @@ refs = [#ref{name = shim_header, label = '$headers'}]}). -record(chatstate, {type :: active | composing | gone | inactive | paused}). +-type chatstate() :: #chatstate{}. -xml(chatstate_active, #elem{name = <<"active">>, @@ -1799,7 +1868,8 @@ -xml(delay, #elem{name = <<"delay">>, xmlns = <<"urn:xmpp:delay">>, - result = {delay, '$stamp', '$from'}, + result = {delay, '$stamp', '$from', '$desc'}, + cdata = #cdata{label = '$desc', default = <<"">>}, attrs = [#attr{name = <<"stamp">>, required = true, dec = {dec_utc, []}, @@ -2263,6 +2333,7 @@ attrs = [#attr{name = <<"xmlns">>}]}). -record(csi, {type :: active | inactive}). +-type csi() :: #csi{}. -xml(csi_active, #elem{name = <<"active">>, @@ -2432,38 +2503,123 @@ -xml(mix_subscribe, #elem{name = <<"subscribe">>, - xmlns = <<"urn:xmpp:mix:0">>, - result = '$node', - attrs = [#attr{name = <<"node">>, - required = true, - label = '$node'}]}). + xmlns = <<"urn:xmpp:mix:0">>, + result = '$node', + attrs = [#attr{name = <<"node">>, + required = true, + label = '$node'}]}). -xml(mix_join, #elem{name = <<"join">>, - xmlns = <<"urn:xmpp:mix:0">>, - result = {mix_join, '$jid', '$subscribe'}, - attrs = [#attr{name = <<"jid">>, - label = '$jid', - dec = {dec_jid, []}, + xmlns = <<"urn:xmpp:mix:0">>, + result = {mix_join, '$jid', '$subscribe'}, + attrs = [#attr{name = <<"jid">>, + label = '$jid', + dec = {dec_jid, []}, enc = {enc_jid, []}}], - refs = [#ref{name = mix_subscribe, min = 0, label = '$subscribe'}]}). + refs = [#ref{name = mix_subscribe, min = 0, label = '$subscribe'}]}). -xml(mix_leave, #elem{name = <<"leave">>, - xmlns = <<"urn:xmpp:mix:0">>, - result = {mix_leave}}). + xmlns = <<"urn:xmpp:mix:0">>, + result = {mix_leave}}). -xml(mix_participant, #elem{name = <<"participant">>, - xmlns = <<"urn:xmpp:mix:0">>, - result = {mix_participant, '$jid', '$nick'}, - attrs = [#attr{name = <<"jid">>, - required = true, - label = '$jid', - dec = {dec_jid, []}, + xmlns = <<"urn:xmpp:mix:0">>, + result = {mix_participant, '$jid', '$nick'}, + attrs = [#attr{name = <<"jid">>, + required = true, + label = '$jid', + dec = {dec_jid, []}, enc = {enc_jid, []}}, - #attr{name = <<"nick">>, - label = '$nick'}]}). + #attr{name = <<"nick">>, + label = '$nick'}]}). + +-record(hint, {type :: 'no-copy' | 'no-store' | 'store' | 'no-permanent-store'}). +-type hint() :: #hint{}. + +-xml(hint_no_copy, + #elem{name = <<"no-copy">>, + xmlns = <<"urn:xmpp:hints">>, + result = {hint, 'no-copy'}}). + +-xml(hint_no_store, + #elem{name = <<"no-store">>, + xmlns = <<"urn:xmpp:hints">>, + result = {hint, 'no-store'}}). + +-xml(hint_store, + #elem{name = <<"store">>, + xmlns = <<"urn:xmpp:hints">>, + result = {hint, 'store'}}). + +-xml(hint_no_permanent_store, + #elem{name = <<"no-permanent-store">>, + xmlns = <<"urn:xmpp:hints">>, + result = {hint, 'no-permanent-store'}}). + +-xml(search_instructions, + #elem{name = <<"instructions">>, + xmlns = <<"jabber:iq:search">>, + result = '$cdata'}). + +-xml(search_first, + #elem{name = <<"first">>, + xmlns = <<"jabber:iq:search">>, + cdata = #cdata{default = <<"">>}, + result = '$cdata'}). +-xml(search_last, + #elem{name = <<"last">>, + xmlns = <<"jabber:iq:search">>, + cdata = #cdata{default = <<"">>}, + result = '$cdata'}). +-xml(search_nick, + #elem{name = <<"nick">>, + xmlns = <<"jabber:iq:search">>, + cdata = #cdata{default = <<"">>}, + result = '$cdata'}). +-xml(search_email, + #elem{name = <<"email">>, + xmlns = <<"jabber:iq:search">>, + cdata = #cdata{default = <<"">>}, + result = '$cdata'}). + +-xml(search_item, + #elem{name = <<"item">>, + xmlns = <<"jabber:iq:search">>, + result = {search_item, '$jid', '$first', '$last', '$nick', '$email'}, + attrs = [#attr{name = <<"jid">>, + required = true, + enc = {enc_jid, []}, + dec = {dec_jid, []}}], + refs = [#ref{name = search_first, min = 0, max = 1, + label = '$first'}, + #ref{name = search_last, min = 0, max = 1, + label = '$last'}, + #ref{name = search_nick, min = 0, max = 1, + label = '$nick'}, + #ref{name = search_email, min = 0, max = 1, + label = '$email'}]}). + +-xml(search, + #elem{name = <<"query">>, + xmlns = <<"jabber:iq:search">>, + result = {search, '$instructions', '$first', '$last', + '$nick', '$email', '$items', '$xdata'}, + refs = [#ref{name = search_instructions, min = 0, max = 1, + label = '$instructions'}, + #ref{name = search_first, min = 0, max = 1, + label = '$first'}, + #ref{name = search_last, min = 0, max = 1, + label = '$last'}, + #ref{name = search_nick, min = 0, max = 1, + label = '$nick'}, + #ref{name = search_email, min = 0, max = 1, + label = '$email'}, + #ref{name = search_item, label = '$items'}, + #ref{name = xdata, min = 0, max = 1, + label = '$xdata'}]}). dec_tzo(Val) -> [H1, M1] = str:tokens(Val, <<":">>), @@ -2514,6 +2670,10 @@ dec_bool(<<"1">>) -> true. enc_bool(false) -> <<"false">>; enc_bool(true) -> <<"true">>. +join([], _Sep) -> <<>>; +join([H | T], Sep) -> + <> || X <- T >>)/binary>>. + %% Local Variables: %% mode: erlang %% End: From a4a9dd7f0334bf061c84a9825f8d743ec29a68bf Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Tue, 19 Jul 2016 07:56:14 +0300 Subject: [PATCH 002/151] Rewrite mod_offline to use XML generator --- include/xmpp_codec.hrl | 18 ++- src/mod_offline.erl | 348 +++++++++++++++++------------------------ src/xmpp.erl | 6 +- src/xmpp_codec.erl | 323 +++++++++++++++++++++++++++++++++++++- tools/xmpp_codec.spec | 58 ++++++- 5 files changed, 538 insertions(+), 215 deletions(-) diff --git a/include/xmpp_codec.hrl b/include/xmpp_codec.hrl index 64a185a30..e348404b0 100644 --- a/include/xmpp_codec.hrl +++ b/include/xmpp_codec.hrl @@ -11,7 +11,8 @@ -record(csi, {type :: active | inactive}). -type csi() :: #csi{}. --record(hint, {type :: 'no-copy' | 'no-store' | 'store' | 'no-permanent-store'}). +-record(hint, {type :: 'no-copy' | 'no-store' | 'no-storage' | + 'store' | 'no-permanent-store'}). -type hint() :: #hint{}. -record(feature_register, {}). @@ -50,6 +51,10 @@ -record(carbons_private, {}). -type carbons_private() :: #carbons_private{}. +-record(expire, {seconds :: non_neg_integer(), + stored :: non_neg_integer()}). +-type expire() :: #expire{}. + -record(pubsub_unsubscribe, {node :: binary(), jid :: any(), subid :: binary()}). @@ -304,6 +309,13 @@ -record(sasl_abort, {}). -type sasl_abort() :: #sasl_abort{}. +-record(xevent, {offline = false :: boolean(), + delivered = false :: boolean(), + displayed = false :: boolean(), + composing = false :: boolean(), + id :: binary()}). +-type xevent() :: #xevent{}. + -record(vcard_email, {home = false :: boolean(), work = false :: boolean(), internet = false :: boolean(), @@ -717,6 +729,7 @@ starttls_proceed() | sm_resumed() | forwarded() | + xevent() | privacy_list() | text() | vcard_org() | @@ -735,12 +748,12 @@ pubsub_options() | compress() | bytestreams() | + muc_history() | identity() | feature_csi() | muc_user_destroy() | privacy_query() | delay() | - muc_history() | vcard_tel() | vcard_logo() | disco_info() | @@ -780,6 +793,7 @@ vcard_name() | sm_resume() | carbons_enable() | + expire() | pubsub_unsubscribe() | muc_decline() | chatstate() | diff --git a/src/mod_offline.erl b/src/mod_offline.erl index 799605c69..66edb6a7c 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -49,7 +49,7 @@ get_sm_identity/5, get_sm_items/5, get_info/5, - handle_offline_query/3, + handle_offline_query/1, remove_expired_messages/1, remove_old_messages/2, remove_user/2, @@ -73,7 +73,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("ejabberd_http.hrl"). @@ -250,7 +250,7 @@ receive_all(US, Msgs, DBType) -> end end. -get_sm_features(Acc, _From, _To, <<"">>, _Lang) -> +get_sm_features(Acc, _From, _To, undefined, _Lang) -> Feats = case Acc of {result, I} -> I; _ -> [] @@ -268,12 +268,10 @@ get_sm_features(_Acc, #jid{luser = U, lserver = S}, #jid{luser = U, lserver = S} get_sm_features(Acc, _From, _To, _Node, _Lang) -> Acc. -get_sm_identity(_Acc, #jid{luser = U, lserver = S}, #jid{luser = U, lserver = S}, +get_sm_identity(Acc, #jid{luser = U, lserver = S}, #jid{luser = U, lserver = S}, ?NS_FLEX_OFFLINE, _Lang) -> - Identity = #xmlel{name = <<"identity">>, - attrs = [{<<"category">>, <<"automation">>}, - {<<"type">>, <<"message-list">>}]}, - [Identity]; + [#identity{category = <<"automation">>, + type = <<"message-list">>}|Acc]; get_sm_identity(Acc, _From, _To, _Node, _Lang) -> Acc. @@ -282,15 +280,16 @@ get_sm_items(_Acc, #jid{luser = U, lserver = S, lresource = R} = JID, ?NS_FLEX_OFFLINE, _Lang) -> case ejabberd_sm:get_session_pid(U, S, R) of Pid when is_pid(Pid) -> - Hdrs = read_message_headers(U, S), - BareJID = jid:to_string(jid:remove_resource(JID)), + Mod = gen_mod:db_mod(S, ?MODULE), + Hdrs = Mod:read_message_headers(U, S), + BareJID = jid:remove_resource(JID), Pid ! dont_ask_offline, {result, lists:map( - fun({Node, From, _To, _El}) -> - #xmlel{name = <<"item">>, - attrs = [{<<"jid">>, BareJID}, - {<<"node">>, Node}, - {<<"name">>, jid:to_string(From)}]} + fun({Seq, From, _To, _El}) -> + Node = integer_to_binary(Seq), + #disco_item{jid = BareJID, + node = Node, + name = jid:to_string(From)} end, Hdrs)}; none -> {result, []} @@ -298,6 +297,8 @@ get_sm_items(_Acc, #jid{luser = U, lserver = S, lresource = R} = JID, get_sm_items(Acc, _From, _To, _Node, _Lang) -> Acc. +-spec get_info([xdata()], jid(), jid(), + undefined | binary(), undefined | binary()) -> [xdata()]. get_info(_Acc, #jid{luser = U, lserver = S, lresource = R}, #jid{luser = U, lserver = S}, ?NS_FLEX_OFFLINE, _Lang) -> N = jlib:integer_to_binary(count_offline_messages(U, S)), @@ -307,50 +308,42 @@ get_info(_Acc, #jid{luser = U, lserver = S, lresource = R}, none -> ok end, - [#xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_XDATA}, - {<<"type">>, <<"result">>}], - children = [#xmlel{name = <<"field">>, - attrs = [{<<"var">>, <<"FORM_TYPE">>}, - {<<"type">>, <<"hidden">>}], - children = [#xmlel{name = <<"value">>, - children = [{xmlcdata, - ?NS_FLEX_OFFLINE}]}]}, - #xmlel{name = <<"field">>, - attrs = [{<<"var">>, <<"number_of_messages">>}], - children = [#xmlel{name = <<"value">>, - children = [{xmlcdata, N}]}]}]}]; + [#xdata{type = result, + fields = [#xdata_field{var = <<"FORM_TYPE">>, + type = hidden, + values = [?NS_FLEX_OFFLINE]}, + #xdata_field{var = <<"number_of_messages">>, + values = [N]}]}]; get_info(Acc, _From, _To, _Node, _Lang) -> Acc. -handle_offline_query(#jid{luser = U, lserver = S} = From, - #jid{luser = U, lserver = S} = _To, - #iq{type = Type, sub_el = SubEl} = IQ) -> +-spec handle_offline_query(iq()) -> iq(). +handle_offline_query(#iq{from = #jid{luser = U, lserver = S} = From, + to = #jid{luser = U, lserver = S} = _To, + type = Type, + sub_els = [#offline{purge = Purge, + items = Items, + fetch = Fetch}]} = IQ) -> case Type of get -> - case fxml:get_subtag(SubEl, <<"fetch">>) of - #xmlel{} -> - handle_offline_fetch(From); - false -> - handle_offline_items_view(From, SubEl) + if Fetch -> handle_offline_fetch(From); + true -> handle_offline_items_view(From, Items) end; set -> - case fxml:get_subtag(SubEl, <<"purge">>) of - #xmlel{} -> - delete_all_msgs(U, S); - false -> - handle_offline_items_remove(From, SubEl) + if Purge -> delete_all_msgs(U, S); + true -> handle_offline_items_remove(From, Items) end end, - IQ#iq{type = result, sub_el = []}; -handle_offline_query(_From, _To, #iq{sub_el = SubEl, lang = Lang} = IQ) -> + xmpp:make_iq_result(IQ); +handle_offline_query(#iq{lang = Lang} = IQ) -> Txt = <<"Query to another users is forbidden">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_FORBIDDEN(Lang, Txt)]}. + xmpp:make_error(IQ, xmpp:err_forbidden(Txt, Lang)). -handle_offline_items_view(JID, #xmlel{children = Items}) -> +-spec handle_offline_items_view(jid(), [offline_item()]) -> ok. +handle_offline_items_view(JID, Items) -> {U, S, R} = jid:tolower(JID), lists:foreach( - fun(Node) -> + fun(#offline_item{node = Node, action = view}) -> case fetch_msg_by_node(JID, Node) of {ok, OfflineMsg} -> case offline_msg_to_route(S, OfflineMsg) of @@ -367,40 +360,25 @@ handle_offline_items_view(JID, #xmlel{children = Items}) -> end; error -> ok - end - end, get_nodes_from_items(Items, <<"view">>)). - -handle_offline_items_remove(JID, #xmlel{children = Items}) -> - lists:foreach( - fun(Node) -> - remove_msg_by_node(JID, Node) - end, get_nodes_from_items(Items, <<"remove">>)). - -get_nodes_from_items(Items, Action) -> - lists:flatmap( - fun(#xmlel{name = <<"item">>, attrs = Attrs}) -> - case fxml:get_attr_s(<<"action">>, Attrs) of - Action -> - case fxml:get_attr_s(<<"node">>, Attrs) of - <<"">> -> - []; - TS -> - [TS] - end; - _ -> - [] end; (_) -> - [] + ok end, Items). -set_offline_tag(#xmlel{children = Els} = El, Node) -> - OfflineEl = #xmlel{name = <<"offline">>, - attrs = [{<<"xmlns">>, ?NS_FLEX_OFFLINE}], - children = [#xmlel{name = <<"item">>, - attrs = [{<<"node">>, Node}]}]}, - El#xmlel{children = [OfflineEl|Els]}. +-spec handle_offline_items_remove(jid(), [offline_item()]) -> ok. +handle_offline_items_remove(JID, Items) -> + lists:foreach( + fun(#offline_item{node = Node, action = remove}) -> + remove_msg_by_node(JID, Node); + (_) -> + ok + end, Items). +-spec set_offline_tag(message(), binary()) -> message(). +set_offline_tag(Msg, Node) -> + xmpp:set_subtag(Msg, #offline{items = [#offline_item{node = Node}]}). + +-spec handle_offline_fetch(jid()) -> ok. handle_offline_fetch(#jid{luser = U, lserver = S, lresource = R}) -> case ejabberd_sm:get_session_pid(U, S, R) of none -> @@ -414,6 +392,7 @@ handle_offline_fetch(#jid{luser = U, lserver = S, lresource = R}) -> end, read_message_headers(U, S)) end. +-spec fetch_msg_by_node(jid(), binary()) -> error | {ok, #offline_msg{}}. fetch_msg_by_node(To, Seq) -> case catch binary_to_integer(Seq) of I when is_integer(I), I >= 0 -> @@ -425,6 +404,7 @@ fetch_msg_by_node(To, Seq) -> error end. +-spec remove_msg_by_node(jid(), binary()) -> ok. remove_msg_by_node(To, Seq) -> case catch binary_to_integer(Seq) of I when is_integer(I), I>= 0 -> @@ -436,39 +416,38 @@ remove_msg_by_node(To, Seq) -> ok end. +-spec need_to_store(binary(), message()) -> boolean(). +need_to_store(_LServer, #message{type = error}) -> false; +need_to_store(_LServer, #message{type = groupchat}) -> false; +need_to_store(_LServer, #message{type = headline}) -> false; need_to_store(LServer, Packet) -> - Type = fxml:get_tag_attr_s(<<"type">>, Packet), - if (Type /= <<"error">>) and (Type /= <<"groupchat">>) - and (Type /= <<"headline">>) -> - case has_offline_tag(Packet) of - false -> - case check_store_hint(Packet) of - store -> - true; - no_store -> - false; - none -> - case gen_mod:get_module_opt( - LServer, ?MODULE, store_empty_body, - fun(V) when is_boolean(V) -> V; - (unless_chat_state) -> unless_chat_state - end, - unless_chat_state) of - false -> - fxml:get_subtag(Packet, <<"body">>) /= false; - unless_chat_state -> - not jlib:is_standalone_chat_state(Packet); - true -> - true - end - end; - true -> - false + case xmpp:has_subtag(Packet, #offline{}) of + false -> + case check_store_hint(Packet) of + store -> + true; + no_store -> + false; + none -> + case gen_mod:get_module_opt( + LServer, ?MODULE, store_empty_body, + fun(V) when is_boolean(V) -> V; + (unless_chat_state) -> unless_chat_state + end, + unless_chat_state) of + false -> + Packet#message.body /= []; + unless_chat_state -> + not xmpp_util:is_standalone_chat_state(Packet); + true -> + true + end end; - true -> + true -> false end. +-spec store_packet(jid(), jid(), message()) -> ok | stop. store_packet(From, To, Packet) -> case need_to_store(To#jid.lserver, Packet) of true -> @@ -476,18 +455,19 @@ store_packet(From, To, Packet) -> true -> #jid{luser = LUser, lserver = LServer} = To, TimeStamp = p1_time_compat:timestamp(), - #xmlel{children = Els} = Packet, - Expire = find_x_expire(TimeStamp, Els), + Expire = find_x_expire(TimeStamp, Packet), + El = xmpp:encode(Packet), gen_mod:get_module_proc(To#jid.lserver, ?PROCNAME) ! #offline_msg{us = {LUser, LServer}, timestamp = TimeStamp, expire = Expire, - from = From, to = To, packet = Packet}, + from = From, to = To, packet = El}, stop; _ -> ok end; false -> ok end. +-spec check_store_hint(message()) -> store | no_store | none. check_store_hint(Packet) -> case has_store_hint(Packet) of true -> @@ -501,89 +481,43 @@ check_store_hint(Packet) -> end end. +-spec has_store_hint(message()) -> boolean(). has_store_hint(Packet) -> - fxml:get_subtag_with_xmlns(Packet, <<"store">>, ?NS_HINTS) =/= false. + xmpp:has_subtag(Packet, #hint{type = 'store'}). +-spec has_no_store_hint(message()) -> boolean(). has_no_store_hint(Packet) -> - fxml:get_subtag_with_xmlns(Packet, <<"no-store">>, ?NS_HINTS) =/= false - orelse - fxml:get_subtag_with_xmlns(Packet, <<"no-storage">>, ?NS_HINTS) =/= false. - -has_offline_tag(Packet) -> - fxml:get_subtag_with_xmlns(Packet, <<"offline">>, ?NS_FLEX_OFFLINE) =/= false. + xmpp:has_subtag(Packet, #hint{type = 'no-store'}) + orelse + xmpp:has_subtag(Packet, #hint{type = 'no-storage'}). %% Check if the packet has any content about XEP-0022 -check_event(From, To, Packet) -> - #xmlel{name = Name, attrs = Attrs, children = Els} = - Packet, - case find_x_event(Els) of - false -> true; - El -> - case fxml:get_subtag(El, <<"id">>) of - false -> - case fxml:get_subtag(El, <<"offline">>) of - false -> true; - _ -> - ID = case fxml:get_tag_attr_s(<<"id">>, Packet) of - <<"">> -> - #xmlel{name = <<"id">>, attrs = [], - children = []}; - S -> - #xmlel{name = <<"id">>, attrs = [], - children = [{xmlcdata, S}]} - end, - ejabberd_router:route(To, From, - #xmlel{name = Name, attrs = Attrs, - children = - [#xmlel{name = <<"x">>, - attrs = - [{<<"xmlns">>, - ?NS_EVENT}], - children = - [ID, - #xmlel{name - = - <<"offline">>, - attrs - = - [], - children - = - []}]}]}), - true - end; - _ -> false - end +-spec check_event(jid(), jid(), message()) -> boolean(). +check_event(From, To, #message{id = ID} = Msg) -> + case xmpp:get_subtag(Msg, #xevent{}) of + false -> + true; + #xevent{id = undefined, offline = false} -> + true; + #xevent{id = undefined, offline = true} -> + NewMsg = Msg#message{sub_els = [#xevent{id = ID, offline = true}]}, + ejabberd_router:route(To, From, xmpp:set_from_to(NewMsg, To, From)), + true; + _ -> + false end. -%% Check if the packet has subelements about XEP-0022 -find_x_event([]) -> false; -find_x_event([{xmlcdata, _} | Els]) -> - find_x_event(Els); -find_x_event([El | Els]) -> - case fxml:get_tag_attr_s(<<"xmlns">>, El) of - ?NS_EVENT -> El; - _ -> find_x_event(Els) - end. - -find_x_expire(_, []) -> never; -find_x_expire(TimeStamp, [{xmlcdata, _} | Els]) -> - find_x_expire(TimeStamp, Els); -find_x_expire(TimeStamp, [El | Els]) -> - case fxml:get_tag_attr_s(<<"xmlns">>, El) of - ?NS_EXPIRE -> - Val = fxml:get_tag_attr_s(<<"seconds">>, El), - case catch jlib:binary_to_integer(Val) of - {'EXIT', _} -> never; - Int when Int > 0 -> - {MegaSecs, Secs, MicroSecs} = TimeStamp, - S = MegaSecs * 1000000 + Secs + Int, - MegaSecs1 = S div 1000000, - Secs1 = S rem 1000000, - {MegaSecs1, Secs1, MicroSecs}; - _ -> never - end; - _ -> find_x_expire(TimeStamp, Els) +-spec find_x_expire(erlang:timestamp(), message()) -> erlang:timestamp() | never. +find_x_expire(TimeStamp, Msg) -> + case xmpp:get_subtag(Msg, #expire{}) of + #expire{seconds = Int} -> + {MegaSecs, Secs, MicroSecs} = TimeStamp, + S = MegaSecs * 1000000 + Secs + Int, + MegaSecs1 = S div 1000000, + Secs1 = S rem 1000000, + {MegaSecs1, Secs1, MicroSecs}; + false -> + never end. resend_offline_messages(User, Server) -> @@ -612,10 +546,9 @@ pop_offline_messages(Ls, User, Server) -> end, lists:filter( fun(#offline_msg{packet = Pkt} = R) -> - #xmlel{children = Els} = Pkt, Expire = case R#offline_msg.expire of undefined -> - find_x_expire(TS, Els); + find_x_expire(TS, Pkt); Exp -> Exp end, @@ -648,17 +581,15 @@ remove_user(User, Server) -> %% Warn senders that their messages have been discarded: discard_warn_sender(Msgs) -> - lists:foreach(fun (#offline_msg{from = From, to = To, - packet = Packet}) -> - ErrText = <<"Your contact offline message queue is " - "full. The message has been discarded.">>, - Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), - Err = jlib:make_error_reply(Packet, - ?ERRT_RESOURCE_CONSTRAINT(Lang, - ErrText)), - ejabberd_router:route(To, From, Err) - end, - Msgs). + lists:foreach( + fun(#offline_msg{from = From, to = To, packet = Packet}) -> + ErrText = <<"Your contact offline message queue is " + "full. The message has been discarded.">>, + Lang = xmpp:get_lang(Packet), + Err = xmpp:make_error( + Packet, xmpp:err_resource_constraint(ErrText, Lang)), + ejabberd_router:route(To, From, Err) + end, Msgs). webadmin_page(_, Host, #request{us = _US, path = [<<"user">>, U, <<"queue">>], @@ -668,29 +599,30 @@ webadmin_page(_, Host, webadmin_page(Acc, _, _) -> Acc. get_offline_els(LUser, LServer) -> - Mod = gen_mod:db_mod(LServer, ?MODULE), - Hdrs = Mod:read_message_headers(LUser, LServer), + Hdrs = read_message_headers(LUser, LServer), lists:map( fun({_Seq, From, To, Packet}) -> - jlib:replace_from_to(From, To, Packet) + xmpp:set_from_to(Packet, From, To) end, Hdrs). offline_msg_to_route(LServer, #offline_msg{} = R) -> - El = case R#offline_msg.timestamp of - undefined -> - R#offline_msg.packet; - TS -> - jlib:add_delay_info(R#offline_msg.packet, LServer, TS, - <<"Offline Storage">>) - end, - {route, R#offline_msg.from, R#offline_msg.to, El}. + Pkt = xmpp:decode(R#offline_msg.packet, [ignore_els]), + Pkt1 = case R#offline_msg.timestamp of + undefined -> + Pkt; + TS -> + xmpp_util:add_delay_info(Pkt, LServer, TS, + <<"Offline Storage">>) + end, + {route, R#offline_msg.from, R#offline_msg.to, Pkt1}. read_message_headers(LUser, LServer) -> Mod = gen_mod:db_mod(LServer, ?MODULE), lists:map( fun({Seq, From, To, El}) -> Node = integer_to_binary(Seq), - {Node, From, To, El} + Packet = xmpp:decode(El, [ignore_els]), + {Node, From, To, Packet} end, Mod:read_message_headers(LUser, LServer)). format_user_queue(Hdrs) -> @@ -826,6 +758,7 @@ webadmin_user(Acc, User, Server, Lang) -> ?INPUTT(<<"submit">>, <<"removealloffline">>, <<"Remove All Offline Messages">>)]. +-spec delete_all_msgs(binary(), binary()) -> {atomic, any()}. delete_all_msgs(User, Server) -> LUser = jid:nodeprep(User), LServer = jid:nameprep(Server), @@ -849,6 +782,7 @@ webadmin_user_parse_query(Acc, _Action, _User, _Server, Acc. %% Returns as integer the number of offline messages for a given user +-spec count_offline_messages(binary(), binary()) -> non_neg_integer(). count_offline_messages(User, Server) -> LUser = jid:nodeprep(User), LServer = jid:nameprep(Server), diff --git a/src/xmpp.erl b/src/xmpp.erl index ca6ed5e4c..f17eefa21 100644 --- a/src/xmpp.erl +++ b/src/xmpp.erl @@ -156,10 +156,12 @@ get_error(#iq{error = E}) -> E; get_error(#message{error = E}) -> E; get_error(#presence{error = E}) -> E. --spec get_els(iq() | message() | presence()) -> [xmpp_element() | xmlel()]. +-spec get_els(iq() | message() | presence()) -> [xmpp_element() | xmlel()]; + (xmlel()) -> [xmlel()]. get_els(#iq{sub_els = Els}) -> Els; get_els(#message{sub_els = Els}) -> Els; -get_els(#presence{sub_els = Els}) -> Els. +get_els(#presence{sub_els = Els}) -> Els; +get_els(#xmlel{children = Els}) -> [El || El = #xmlel{} <- Els]. -spec set_id(iq(), binary()) -> iq(); (message(), binary()) -> message(); diff --git a/src/xmpp_codec.erl b/src/xmpp_codec.erl index 568c5fbc7..976a7bfeb 100644 --- a/src/xmpp_codec.erl +++ b/src/xmpp_codec.erl @@ -15,6 +15,24 @@ decode(_el) -> decode(_el, []). decode({xmlel, _name, _attrs, _} = _el, Opts) -> IgnoreEls = proplists:get_bool(ignore_els, Opts), case {_name, get_attr(<<"xmlns">>, _attrs)} of + {<<"x">>, <<"jabber:x:expire">>} -> + decode_expire(<<"jabber:x:expire">>, IgnoreEls, _el); + {<<"x">>, <<"jabber:x:event">>} -> + decode_xevent(<<"jabber:x:event">>, IgnoreEls, _el); + {<<"id">>, <<"jabber:x:event">>} -> + decode_xevent_id(<<"jabber:x:event">>, IgnoreEls, _el); + {<<"composing">>, <<"jabber:x:event">>} -> + decode_xevent_composing(<<"jabber:x:event">>, IgnoreEls, + _el); + {<<"displayed">>, <<"jabber:x:event">>} -> + decode_xevent_displayed(<<"jabber:x:event">>, IgnoreEls, + _el); + {<<"delivered">>, <<"jabber:x:event">>} -> + decode_xevent_delivered(<<"jabber:x:event">>, IgnoreEls, + _el); + {<<"offline">>, <<"jabber:x:event">>} -> + decode_xevent_offline(<<"jabber:x:event">>, IgnoreEls, + _el); {<<"query">>, <<"jabber:iq:search">>} -> decode_search(<<"jabber:iq:search">>, IgnoreEls, _el); {<<"item">>, <<"jabber:iq:search">>} -> @@ -40,6 +58,9 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> IgnoreEls, _el); {<<"store">>, <<"urn:xmpp:hints">>} -> decode_hint_store(<<"urn:xmpp:hints">>, IgnoreEls, _el); + {<<"no-storage">>, <<"urn:xmpp:hints">>} -> + decode_hint_no_storage(<<"urn:xmpp:hints">>, IgnoreEls, + _el); {<<"no-store">>, <<"urn:xmpp:hints">>} -> decode_hint_no_store(<<"urn:xmpp:hints">>, IgnoreEls, _el); @@ -1162,6 +1183,13 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> is_known_tag({xmlel, _name, _attrs, _} = _el) -> case {_name, get_attr(<<"xmlns">>, _attrs)} of + {<<"x">>, <<"jabber:x:expire">>} -> true; + {<<"x">>, <<"jabber:x:event">>} -> true; + {<<"id">>, <<"jabber:x:event">>} -> true; + {<<"composing">>, <<"jabber:x:event">>} -> true; + {<<"displayed">>, <<"jabber:x:event">>} -> true; + {<<"delivered">>, <<"jabber:x:event">>} -> true; + {<<"offline">>, <<"jabber:x:event">>} -> true; {<<"query">>, <<"jabber:iq:search">>} -> true; {<<"item">>, <<"jabber:iq:search">>} -> true; {<<"email">>, <<"jabber:iq:search">>} -> true; @@ -1172,6 +1200,7 @@ is_known_tag({xmlel, _name, _attrs, _} = _el) -> {<<"no-permanent-store">>, <<"urn:xmpp:hints">>} -> true; {<<"store">>, <<"urn:xmpp:hints">>} -> true; + {<<"no-storage">>, <<"urn:xmpp:hints">>} -> true; {<<"no-store">>, <<"urn:xmpp:hints">>} -> true; {<<"no-copy">>, <<"urn:xmpp:hints">>} -> true; {<<"participant">>, <<"urn:xmpp:mix:0">>} -> true; @@ -2289,6 +2318,9 @@ encode({hint, 'no-copy'} = No_copy) -> encode({hint, 'no-store'} = No_store) -> encode_hint_no_store(No_store, [{<<"xmlns">>, <<"urn:xmpp:hints">>}]); +encode({hint, 'no-storage'} = No_storage) -> + encode_hint_no_storage(No_storage, + [{<<"xmlns">>, <<"urn:xmpp:hints">>}]); encode({hint, store} = Store) -> encode_hint_store(Store, [{<<"xmlns">>, <<"urn:xmpp:hints">>}]); @@ -2301,7 +2333,12 @@ encode({search_item, _, _, _, _, _} = Item) -> [{<<"xmlns">>, <<"jabber:iq:search">>}]); encode({search, _, _, _, _, _, _, _} = Query) -> encode_search(Query, - [{<<"xmlns">>, <<"jabber:iq:search">>}]). + [{<<"xmlns">>, <<"jabber:iq:search">>}]); +encode({xevent, _, _, _, _, _} = X) -> + encode_xevent(X, [{<<"xmlns">>, <<"jabber:x:event">>}]); +encode({expire, _, _} = X) -> + encode_expire(X, + [{<<"xmlns">>, <<"jabber:x:expire">>}]). get_name({last, _, _}) -> <<"query">>; get_name({version, _, _, _}) -> <<"query">>; @@ -2460,11 +2497,14 @@ get_name({mix_leave}) -> <<"leave">>; get_name({mix_participant, _, _}) -> <<"participant">>; get_name({hint, 'no-copy'}) -> <<"no-copy">>; get_name({hint, 'no-store'}) -> <<"no-store">>; +get_name({hint, 'no-storage'}) -> <<"no-storage">>; get_name({hint, store}) -> <<"store">>; get_name({hint, 'no-permanent-store'}) -> <<"no-permanent-store">>; get_name({search_item, _, _, _, _, _}) -> <<"item">>; -get_name({search, _, _, _, _, _, _, _}) -> <<"query">>. +get_name({search, _, _, _, _, _, _, _}) -> <<"query">>; +get_name({xevent, _, _, _, _, _}) -> <<"x">>; +get_name({expire, _, _}) -> <<"x">>. get_ns({last, _, _}) -> <<"jabber:iq:last">>; get_ns({version, _, _, _}) -> <<"jabber:iq:version">>; @@ -2685,13 +2725,16 @@ get_ns({mix_leave}) -> <<"urn:xmpp:mix:0">>; get_ns({mix_participant, _, _}) -> <<"urn:xmpp:mix:0">>; get_ns({hint, 'no-copy'}) -> <<"urn:xmpp:hints">>; get_ns({hint, 'no-store'}) -> <<"urn:xmpp:hints">>; +get_ns({hint, 'no-storage'}) -> <<"urn:xmpp:hints">>; get_ns({hint, store}) -> <<"urn:xmpp:hints">>; get_ns({hint, 'no-permanent-store'}) -> <<"urn:xmpp:hints">>; get_ns({search_item, _, _, _, _, _}) -> <<"jabber:iq:search">>; get_ns({search, _, _, _, _, _, _, _}) -> - <<"jabber:iq:search">>. + <<"jabber:iq:search">>; +get_ns({xevent, _, _, _, _, _}) -> <<"jabber:x:event">>; +get_ns({expire, _, _}) -> <<"jabber:x:expire">>. dec_int(Val) -> dec_int(Val, infinity, infinity). @@ -2908,6 +2951,9 @@ pp(hint, 1) -> [type]; pp(search_item, 5) -> [jid, first, last, nick, email]; pp(search, 7) -> [instructions, first, last, nick, email, items, xdata]; +pp(xevent, 5) -> + [offline, delivered, displayed, composing, id]; +pp(expire, 2) -> [seconds, stored]; pp(_, _) -> no. join([], _Sep) -> <<>>; @@ -2954,6 +3000,267 @@ dec_tzo(Val) -> M = jlib:binary_to_integer(M1), if H >= -12, H =< 12, M >= 0, M < 60 -> {H, M} end. +decode_expire(__TopXMLNS, __IgnoreEls, + {xmlel, <<"x">>, _attrs, _els}) -> + {Seconds, Stored} = decode_expire_attrs(__TopXMLNS, + _attrs, undefined, undefined), + {expire, Seconds, Stored}. + +decode_expire_attrs(__TopXMLNS, + [{<<"seconds">>, _val} | _attrs], _Seconds, Stored) -> + decode_expire_attrs(__TopXMLNS, _attrs, _val, Stored); +decode_expire_attrs(__TopXMLNS, + [{<<"stored">>, _val} | _attrs], Seconds, _Stored) -> + decode_expire_attrs(__TopXMLNS, _attrs, Seconds, _val); +decode_expire_attrs(__TopXMLNS, [_ | _attrs], Seconds, + Stored) -> + decode_expire_attrs(__TopXMLNS, _attrs, Seconds, + Stored); +decode_expire_attrs(__TopXMLNS, [], Seconds, Stored) -> + {decode_expire_attr_seconds(__TopXMLNS, Seconds), + decode_expire_attr_stored(__TopXMLNS, Stored)}. + +encode_expire({expire, Seconds, Stored}, + _xmlns_attrs) -> + _els = [], + _attrs = encode_expire_attr_stored(Stored, + encode_expire_attr_seconds(Seconds, + _xmlns_attrs)), + {xmlel, <<"x">>, _attrs, _els}. + +decode_expire_attr_seconds(__TopXMLNS, undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"seconds">>, <<"x">>, __TopXMLNS}}); +decode_expire_attr_seconds(__TopXMLNS, _val) -> + case catch dec_int(_val, 0, infinity) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"seconds">>, <<"x">>, __TopXMLNS}}); + _res -> _res + end. + +encode_expire_attr_seconds(_val, _acc) -> + [{<<"seconds">>, enc_int(_val)} | _acc]. + +decode_expire_attr_stored(__TopXMLNS, undefined) -> + undefined; +decode_expire_attr_stored(__TopXMLNS, _val) -> + case catch dec_int(_val, 0, infinity) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"stored">>, <<"x">>, __TopXMLNS}}); + _res -> _res + end. + +encode_expire_attr_stored(undefined, _acc) -> _acc; +encode_expire_attr_stored(_val, _acc) -> + [{<<"stored">>, enc_int(_val)} | _acc]. + +decode_xevent(__TopXMLNS, __IgnoreEls, + {xmlel, <<"x">>, _attrs, _els}) -> + {Id, Displayed, Delivered, Offline, Composing} = + decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, + undefined, false, false, false, false), + {xevent, Offline, Delivered, Displayed, Composing, Id}. + +decode_xevent_els(__TopXMLNS, __IgnoreEls, [], Id, + Displayed, Delivered, Offline, Composing) -> + {Id, Displayed, Delivered, Offline, Composing}; +decode_xevent_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"offline">>, _attrs, _} = _el | _els], Id, + Displayed, Delivered, Offline, Composing) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:x:event">> -> + decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, + Displayed, Delivered, + decode_xevent_offline(__TopXMLNS, __IgnoreEls, _el), + Composing); + <<"jabber:x:event">> -> + decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, + Displayed, Delivered, + decode_xevent_offline(<<"jabber:x:event">>, + __IgnoreEls, _el), + Composing); + _ -> + decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, + Displayed, Delivered, Offline, Composing) + end; +decode_xevent_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"delivered">>, _attrs, _} = _el | _els], Id, + Displayed, Delivered, Offline, Composing) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:x:event">> -> + decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, + Displayed, + decode_xevent_delivered(__TopXMLNS, __IgnoreEls, + _el), + Offline, Composing); + <<"jabber:x:event">> -> + decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, + Displayed, + decode_xevent_delivered(<<"jabber:x:event">>, + __IgnoreEls, _el), + Offline, Composing); + _ -> + decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, + Displayed, Delivered, Offline, Composing) + end; +decode_xevent_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"displayed">>, _attrs, _} = _el | _els], Id, + Displayed, Delivered, Offline, Composing) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:x:event">> -> + decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, + decode_xevent_displayed(__TopXMLNS, __IgnoreEls, + _el), + Delivered, Offline, Composing); + <<"jabber:x:event">> -> + decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, + decode_xevent_displayed(<<"jabber:x:event">>, + __IgnoreEls, _el), + Delivered, Offline, Composing); + _ -> + decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, + Displayed, Delivered, Offline, Composing) + end; +decode_xevent_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"composing">>, _attrs, _} = _el | _els], Id, + Displayed, Delivered, Offline, Composing) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:x:event">> -> + decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, + Displayed, Delivered, Offline, + decode_xevent_composing(__TopXMLNS, __IgnoreEls, + _el)); + <<"jabber:x:event">> -> + decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, + Displayed, Delivered, Offline, + decode_xevent_composing(<<"jabber:x:event">>, + __IgnoreEls, _el)); + _ -> + decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, + Displayed, Delivered, Offline, Composing) + end; +decode_xevent_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"id">>, _attrs, _} = _el | _els], Id, + Displayed, Delivered, Offline, Composing) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:x:event">> -> + decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, + decode_xevent_id(__TopXMLNS, __IgnoreEls, _el), + Displayed, Delivered, Offline, Composing); + <<"jabber:x:event">> -> + decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, + decode_xevent_id(<<"jabber:x:event">>, __IgnoreEls, + _el), + Displayed, Delivered, Offline, Composing); + _ -> + decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, + Displayed, Delivered, Offline, Composing) + end; +decode_xevent_els(__TopXMLNS, __IgnoreEls, [_ | _els], + Id, Displayed, Delivered, Offline, Composing) -> + decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, + Displayed, Delivered, Offline, Composing). + +encode_xevent({xevent, Offline, Delivered, Displayed, + Composing, Id}, + _xmlns_attrs) -> + _els = lists:reverse('encode_xevent_$id'(Id, + 'encode_xevent_$displayed'(Displayed, + 'encode_xevent_$delivered'(Delivered, + 'encode_xevent_$offline'(Offline, + 'encode_xevent_$composing'(Composing, + [])))))), + _attrs = _xmlns_attrs, + {xmlel, <<"x">>, _attrs, _els}. + +'encode_xevent_$id'(undefined, _acc) -> _acc; +'encode_xevent_$id'(Id, _acc) -> + [encode_xevent_id(Id, []) | _acc]. + +'encode_xevent_$displayed'(false, _acc) -> _acc; +'encode_xevent_$displayed'(Displayed, _acc) -> + [encode_xevent_displayed(Displayed, []) | _acc]. + +'encode_xevent_$delivered'(false, _acc) -> _acc; +'encode_xevent_$delivered'(Delivered, _acc) -> + [encode_xevent_delivered(Delivered, []) | _acc]. + +'encode_xevent_$offline'(false, _acc) -> _acc; +'encode_xevent_$offline'(Offline, _acc) -> + [encode_xevent_offline(Offline, []) | _acc]. + +'encode_xevent_$composing'(false, _acc) -> _acc; +'encode_xevent_$composing'(Composing, _acc) -> + [encode_xevent_composing(Composing, []) | _acc]. + +decode_xevent_id(__TopXMLNS, __IgnoreEls, + {xmlel, <<"id">>, _attrs, _els}) -> + Cdata = decode_xevent_id_els(__TopXMLNS, __IgnoreEls, + _els, <<>>), + Cdata. + +decode_xevent_id_els(__TopXMLNS, __IgnoreEls, [], + Cdata) -> + decode_xevent_id_cdata(__TopXMLNS, Cdata); +decode_xevent_id_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Cdata) -> + decode_xevent_id_els(__TopXMLNS, __IgnoreEls, _els, + <>); +decode_xevent_id_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Cdata) -> + decode_xevent_id_els(__TopXMLNS, __IgnoreEls, _els, + Cdata). + +encode_xevent_id(Cdata, _xmlns_attrs) -> + _els = encode_xevent_id_cdata(Cdata, []), + _attrs = _xmlns_attrs, + {xmlel, <<"id">>, _attrs, _els}. + +decode_xevent_id_cdata(__TopXMLNS, <<>>) -> undefined; +decode_xevent_id_cdata(__TopXMLNS, _val) -> _val. + +encode_xevent_id_cdata(undefined, _acc) -> _acc; +encode_xevent_id_cdata(_val, _acc) -> + [{xmlcdata, _val} | _acc]. + +decode_xevent_composing(__TopXMLNS, __IgnoreEls, + {xmlel, <<"composing">>, _attrs, _els}) -> + true. + +encode_xevent_composing(true, _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"composing">>, _attrs, _els}. + +decode_xevent_displayed(__TopXMLNS, __IgnoreEls, + {xmlel, <<"displayed">>, _attrs, _els}) -> + true. + +encode_xevent_displayed(true, _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"displayed">>, _attrs, _els}. + +decode_xevent_delivered(__TopXMLNS, __IgnoreEls, + {xmlel, <<"delivered">>, _attrs, _els}) -> + true. + +encode_xevent_delivered(true, _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"delivered">>, _attrs, _els}. + +decode_xevent_offline(__TopXMLNS, __IgnoreEls, + {xmlel, <<"offline">>, _attrs, _els}) -> + true. + +encode_xevent_offline(true, _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"offline">>, _attrs, _els}. + decode_search(__TopXMLNS, __IgnoreEls, {xmlel, <<"query">>, _attrs, _els}) -> {Xdata, Items, Instructions, Last, First, Nick, Email} = @@ -3459,6 +3766,16 @@ encode_hint_store({hint, store}, _xmlns_attrs) -> _attrs = _xmlns_attrs, {xmlel, <<"store">>, _attrs, _els}. +decode_hint_no_storage(__TopXMLNS, __IgnoreEls, + {xmlel, <<"no-storage">>, _attrs, _els}) -> + {hint, 'no-storage'}. + +encode_hint_no_storage({hint, 'no-storage'}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"no-storage">>, _attrs, _els}. + decode_hint_no_store(__TopXMLNS, __IgnoreEls, {xmlel, <<"no-store">>, _attrs, _els}) -> {hint, 'no-store'}. diff --git a/tools/xmpp_codec.spec b/tools/xmpp_codec.spec index 07d3a3dfd..a94b317de 100644 --- a/tools/xmpp_codec.spec +++ b/tools/xmpp_codec.spec @@ -2536,7 +2536,8 @@ #attr{name = <<"nick">>, label = '$nick'}]}). --record(hint, {type :: 'no-copy' | 'no-store' | 'store' | 'no-permanent-store'}). +-record(hint, {type :: 'no-copy' | 'no-store' | 'no-storage' | + 'store' | 'no-permanent-store'}). -type hint() :: #hint{}. -xml(hint_no_copy, @@ -2549,6 +2550,11 @@ xmlns = <<"urn:xmpp:hints">>, result = {hint, 'no-store'}}). +-xml(hint_no_storage, + #elem{name = <<"no-storage">>, + xmlns = <<"urn:xmpp:hints">>, + result = {hint, 'no-storage'}}). + -xml(hint_store, #elem{name = <<"store">>, xmlns = <<"urn:xmpp:hints">>, @@ -2621,6 +2627,56 @@ #ref{name = xdata, min = 0, max = 1, label = '$xdata'}]}). +-xml(xevent_offline, + #elem{name = <<"offline">>, + xmlns = <<"jabber:x:event">>, + result = true}). +-xml(xevent_delivered, + #elem{name = <<"delivered">>, + xmlns = <<"jabber:x:event">>, + result = true}). +-xml(xevent_displayed, + #elem{name = <<"displayed">>, + xmlns = <<"jabber:x:event">>, + result = true}). +-xml(xevent_composing, + #elem{name = <<"composing">>, + xmlns = <<"jabber:x:event">>, + result = true}). +-xml(xevent_id, + #elem{name = <<"id">>, + xmlns = <<"jabber:x:event">>, + cdata = #cdata{}, + result = '$cdata'}). + +-xml(xevent, + #elem{name = <<"x">>, + xmlns = <<"jabber:x:event">>, + result = {xevent, '$offline', '$delivered', '$displayed', + '$composing', '$id'}, + refs = [#ref{name = xevent_offline, min = 0, max = 1, + label = '$offline', default = false}, + #ref{name = xevent_delivered, min = 0, max = 1, + label = '$delivered', default = false}, + #ref{name = xevent_displayed, min = 0, max = 1, + label = '$displayed', default = false}, + #ref{name = xevent_composing, min = 0, max = 1, + label = '$composing', default = false}, + #ref{name = xevent_id, min = 0, max = 1, + label = '$id'}]}). + +-xml(expire, + #elem{name = <<"x">>, + xmlns = <<"jabber:x:expire">>, + result = {expire, '$seconds', '$stored'}, + attrs = [#attr{name = <<"seconds">>, + required = true, + dec = {dec_int, [0, infinity]}, + enc = {enc_int, []}}, + #attr{name = <<"stored">>, + dec = {dec_int, [0, infinity]}, + enc = {enc_int, []}}]}). + dec_tzo(Val) -> [H1, M1] = str:tokens(Val, <<":">>), H = jlib:binary_to_integer(H1), From bc802a4049c6a75f77323bf3c07a859dc1c4be47 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Tue, 19 Jul 2016 10:07:04 +0300 Subject: [PATCH 003/151] Rewrite mod_blocking to use XML generator --- include/xmpp_codec.hrl | 2 +- src/mod_blocking.erl | 166 +++++++++++++++++++++-------------------- src/mod_privacy.erl | 5 +- src/xmpp_codec.erl | 53 +++++++++++-- tools/xmpp_codec.spec | 4 +- 5 files changed, 140 insertions(+), 90 deletions(-) diff --git a/include/xmpp_codec.hrl b/include/xmpp_codec.hrl index e348404b0..7b8275ed5 100644 --- a/include/xmpp_codec.hrl +++ b/include/xmpp_codec.hrl @@ -347,7 +347,7 @@ text = [] :: [#text{}]}). -type sasl_failure() :: #sasl_failure{}. --record(block_list, {}). +-record(block_list, {items = [] :: [any()]}). -type block_list() :: #block_list{}. -record(xdata_field, {label :: binary(), diff --git a/src/mod_blocking.erl b/src/mod_blocking.erl index 818d53259..743b78efd 100644 --- a/src/mod_blocking.erl +++ b/src/mod_blocking.erl @@ -29,13 +29,13 @@ -protocol({xep, 191, '1.2'}). --export([start/2, stop/1, process_iq/3, - process_iq_set/4, process_iq_get/5, mod_opt_type/1, depends/2]). +-export([start/2, stop/1, process_iq/1, + process_iq_set/2, process_iq_get/3, mod_opt_type/1, depends/2]). -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_privacy.hrl"). @@ -43,6 +43,8 @@ -callback unblock_by_filter(binary(), binary(), function()) -> {atomic, any()}. -callback process_blocklist_get(binary(), binary()) -> [listitem()] | error. +-type block_event() :: {block, [jid()]} | {unblock, [jid()]} | unblock_all. + start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, fun gen_iq_handler:check_type/1, one_queue), @@ -66,55 +68,65 @@ stop(Host) -> depends(_Host, _Opts) -> [{mod_privacy, hard}]. -process_iq(_From, _To, IQ) -> - SubEl = IQ#iq.sub_el, - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}. +-spec process_iq(iq()) -> iq(). +process_iq(IQ) -> + xmpp:make_error(IQ, xmpp:err_not_allowed()). -process_iq_get(_, From, _To, - #iq{xmlns = ?NS_BLOCKING, lang = Lang, - sub_el = #xmlel{name = <<"blocklist">>}}, - _) -> +-spec process_iq_get({error, error()} | {result, xmpp_element() | undefined}, + iq(), userlist()) -> + {error, error()} | {result, block_list()}. +process_iq_get(_, #iq{lang = Lang, from = From, + sub_els = [#block_list{}]}, _) -> #jid{luser = LUser, lserver = LServer} = From, {stop, process_blocklist_get(LUser, LServer, Lang)}; -process_iq_get(Acc, _, _, _, _) -> Acc. +process_iq_get(Acc, _, _) -> Acc. -process_iq_set(_, From, _To, - #iq{xmlns = ?NS_BLOCKING, lang = Lang, - sub_el = - #xmlel{name = SubElName, children = SubEls}}) -> +-spec process_iq_set({error, error()} | + {result, xmpp_element() | undefined} | + {result, xmpp_element() | undefined, userlist()}, + iq()) -> {error, error()} | + {result, undefined} | + {result, undefined, userlist()}. +process_iq_set(_, #iq{from = From, lang = Lang, sub_els = [SubEl]}) -> #jid{luser = LUser, lserver = LServer} = From, - Res = case {SubElName, fxml:remove_cdata(SubEls)} of - {<<"block">>, []} -> - Txt = <<"No items found in this query">>, - {error, ?ERRT_BAD_REQUEST(Lang, Txt)}; - {<<"block">>, Els} -> - JIDs = parse_blocklist_items(Els, []), - process_blocklist_block(LUser, LServer, JIDs, Lang); - {<<"unblock">>, []} -> - process_blocklist_unblock_all(LUser, LServer, Lang); - {<<"unblock">>, Els} -> - JIDs = parse_blocklist_items(Els, []), - process_blocklist_unblock(LUser, LServer, JIDs, Lang); - _ -> - Txt = <<"Unknown blocking command">>, - {error, ?ERRT_BAD_REQUEST(Lang, Txt)} + Res = case SubEl of + #block{items = []} -> + Txt = <<"No items found in this query">>, + {error, xmpp:err_bad_request(Txt, Lang)}; + #block{items = Items} -> + JIDs = [jid:tolower(Item) || Item <- Items], + process_blocklist_block(LUser, LServer, JIDs, Lang); + #unblock{items = []} -> + process_blocklist_unblock_all(LUser, LServer, Lang); + #unblock{items = Items} -> + JIDs = [jid:tolower(Item) || Item <- Items], + process_blocklist_unblock(LUser, LServer, JIDs, Lang); + _ -> + Txt = <<"Only and are allowed " + "in this request">>, + {error, xmpp:err_bad_request(Txt, Lang)} end, {stop, Res}; -process_iq_set(Acc, _, _, _) -> Acc. +process_iq_set(Acc, _) -> Acc. +-spec list_to_blocklist_jids([listitem()], [ljid()]) -> [ljid()]. list_to_blocklist_jids([], JIDs) -> JIDs; list_to_blocklist_jids([#listitem{type = jid, action = deny, value = JID} = Item | Items], JIDs) -> - case Item of - #listitem{match_all = true} -> Match = true; - #listitem{match_iq = true, match_message = true, - match_presence_in = true, match_presence_out = true} -> - Match = true; - _ -> Match = false - end, + Match = case Item of + #listitem{match_all = true} -> + true; + #listitem{match_iq = true, + match_message = true, + match_presence_in = true, + match_presence_out = true} -> + true; + _ -> + false + end, if Match -> list_to_blocklist_jids(Items, [JID | JIDs]); true -> list_to_blocklist_jids(Items, JIDs) end; @@ -122,20 +134,10 @@ list_to_blocklist_jids([#listitem{type = jid, list_to_blocklist_jids([_ | Items], JIDs) -> list_to_blocklist_jids(Items, JIDs). -parse_blocklist_items([], JIDs) -> JIDs; -parse_blocklist_items([#xmlel{name = <<"item">>, - attrs = Attrs} - | Els], - JIDs) -> - case fxml:get_attr(<<"jid">>, Attrs) of - {value, JID1} -> - JID = jid:tolower(jid:from_string(JID1)), - parse_blocklist_items(Els, [JID | JIDs]); - false -> parse_blocklist_items(Els, JIDs) - end; -parse_blocklist_items([_ | Els], JIDs) -> - parse_blocklist_items(Els, JIDs). - +-spec process_blocklist_block(binary(), binary(), [ljid()], + undefined | binary()) -> + {error, error()} | + {result, undefined, userlist()}. process_blocklist_block(LUser, LServer, JIDs, Lang) -> Filter = fun (List) -> AlreadyBlocked = list_to_blocklist_jids(List, []), @@ -161,13 +163,17 @@ process_blocklist_block(LUser, LServer, JIDs, Lang) -> broadcast_list_update(LUser, LServer, Default, UserList), broadcast_blocklist_event(LUser, LServer, - {block, JIDs}), - {result, [], UserList}; + {block, [jid:make(J) || J <- JIDs]}), + {result, undefined, UserList}; _Err -> ?ERROR_MSG("Error processing ~p: ~p", [{LUser, LServer, JIDs}, _Err]), - {error, ?ERRT_INTERNAL_SERVER_ERROR(Lang, <<"Database failure">>)} + {error, xmpp:err_internal_server_error(<<"Database failure">>, Lang)} end. +-spec process_blocklist_unblock_all(binary(), binary(), undefined | binary()) -> + {error, error()} | + {result, undefined} | + {result, undefined, userlist()}. process_blocklist_unblock_all(LUser, LServer, Lang) -> Filter = fun (List) -> lists:filter(fun (#listitem{action = A}) -> A =/= deny @@ -176,18 +182,23 @@ process_blocklist_unblock_all(LUser, LServer, Lang) -> end, Mod = db_mod(LServer), case Mod:unblock_by_filter(LUser, LServer, Filter) of - {atomic, ok} -> {result, []}; + {atomic, ok} -> {result, undefined}; {atomic, {ok, Default, List}} -> UserList = make_userlist(Default, List), broadcast_list_update(LUser, LServer, Default, UserList), broadcast_blocklist_event(LUser, LServer, unblock_all), - {result, [], UserList}; + {result, undefined, UserList}; _Err -> ?ERROR_MSG("Error processing ~p: ~p", [{LUser, LServer}, _Err]), - {error, ?ERRT_INTERNAL_SERVER_ERROR(Lang, <<"Database failure">>)} + {error, xmpp:err_internal_server_error(<<"Database failure">>, Lang)} end. +-spec process_blocklist_unblock(binary(), binary(), [ljid()], + undefined | binary()) -> + {error, error()} | + {result, undefined} | + {result, undefined, userlist()}. process_blocklist_unblock(LUser, LServer, JIDs, Lang) -> Filter = fun (List) -> lists:filter(fun (#listitem{action = deny, type = jid, @@ -199,56 +210,53 @@ process_blocklist_unblock(LUser, LServer, JIDs, Lang) -> end, Mod = db_mod(LServer), case Mod:unblock_by_filter(LUser, LServer, Filter) of - {atomic, ok} -> {result, []}; + {atomic, ok} -> {result, undefined}; {atomic, {ok, Default, List}} -> UserList = make_userlist(Default, List), broadcast_list_update(LUser, LServer, Default, UserList), broadcast_blocklist_event(LUser, LServer, - {unblock, JIDs}), - {result, [], UserList}; + {unblock, [jid:make(J) || J <- JIDs]}), + {result, undefined, UserList}; _Err -> ?ERROR_MSG("Error processing ~p: ~p", [{LUser, LServer, JIDs}, _Err]), - {error, ?ERRT_INTERNAL_SERVER_ERROR(Lang, <<"Database failure">>)} + {error, xmpp:err_internal_server_error(<<"Database failure">>, Lang)} end. +-spec make_userlist(binary(), [listitem()]) -> userlist(). make_userlist(Name, List) -> NeedDb = mod_privacy:is_list_needdb(List), #userlist{name = Name, list = List, needdb = NeedDb}. +-spec broadcast_list_update(binary(), binary(), binary(), userlist()) -> + {broadcast, + {privacy_list, userlist(), binary() | none}}. broadcast_list_update(LUser, LServer, Name, UserList) -> - ejabberd_sm:route(jid:make(LUser, LServer, - <<"">>), + ejabberd_sm:route(jid:make(LUser, LServer, <<"">>), jid:make(LUser, LServer, <<"">>), {broadcast, {privacy_list, UserList, Name}}). +-spec broadcast_blocklist_event(binary(), binary(), block_event()) -> + {broadcast, {blocking, block_event()}}. broadcast_blocklist_event(LUser, LServer, Event) -> JID = jid:make(LUser, LServer, <<"">>), ejabberd_sm:route(JID, JID, {broadcast, {blocking, Event}}). +-spec process_blocklist_get(binary(), binary(), undefined | binary()) -> + {error, error()} | {result, block_list()}. process_blocklist_get(LUser, LServer, Lang) -> Mod = db_mod(LServer), case Mod:process_blocklist_get(LUser, LServer) of error -> - {error, ?ERRT_INTERNAL_SERVER_ERROR(Lang, <<"Database failure">>)}; + {error, xmpp:err_internal_server_error(<<"Database failure">>, Lang)}; List -> - JIDs = list_to_blocklist_jids(List, []), - Items = lists:map(fun (JID) -> - ?DEBUG("JID: ~p", [JID]), - #xmlel{name = <<"item">>, - attrs = - [{<<"jid">>, - jid:to_string(JID)}], - children = []} - end, - JIDs), - {result, - [#xmlel{name = <<"blocklist">>, - attrs = [{<<"xmlns">>, ?NS_BLOCKING}], - children = Items}]} + LJIDs = list_to_blocklist_jids(List, []), + Items = [jid:make(J) || J <- LJIDs], + {result, #block_list{items = Items}} end. +-spec db_mod(binary()) -> module(). db_mod(LServer) -> DBType = gen_mod:db_type(LServer, mod_privacy), gen_mod:db_mod(DBType, ?MODULE). diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index e88c1fb5b..f61ba31d4 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -100,7 +100,7 @@ stop(Host) -> process_iq(IQ) -> xmpp:make_error(IQ, xmpp:err_not_allowed()). --spec process_iq_get({error, error()} | iq(), +-spec process_iq_get({error, error()} | {result, xmpp_element() | undefined}, iq(), userlist()) -> {error, error()} | {result, privacy_query()}. process_iq_get(_, #iq{from = From, lang = Lang, sub_els = [#privacy_query{lists = Lists}]}, @@ -215,7 +215,8 @@ decode_value(Type, Value) -> end. -spec process_iq_set({error, error()} | - {result, privacy_query() | undefined, userlist()}, + {result, xmpp_element() | undefined} | + {result, xmpp_element() | undefined, userlist()}, iq()) -> {error, error()} | {result, undefined, userlist()}. process_iq_set(_, #iq{from = From, lang = Lang, diff --git a/src/xmpp_codec.erl b/src/xmpp_codec.erl index 976a7bfeb..f6e5f0f1a 100644 --- a/src/xmpp_codec.erl +++ b/src/xmpp_codec.erl @@ -1899,7 +1899,7 @@ encode({block, _} = Block) -> encode({unblock, _} = Unblock) -> encode_unblock(Unblock, [{<<"xmlns">>, <<"urn:xmpp:blocking">>}]); -encode({block_list} = Blocklist) -> +encode({block_list, _} = Blocklist) -> encode_block_list(Blocklist, [{<<"xmlns">>, <<"urn:xmpp:blocking">>}]); encode({identity, _, _, _, _} = Identity) -> @@ -2351,7 +2351,7 @@ get_name({privacy_list, _, _}) -> <<"list">>; get_name({privacy_query, _, _, _}) -> <<"query">>; get_name({block, _}) -> <<"block">>; get_name({unblock, _}) -> <<"unblock">>; -get_name({block_list}) -> <<"blocklist">>; +get_name({block_list, _}) -> <<"blocklist">>; get_name({identity, _, _, _, _}) -> <<"identity">>; get_name({disco_info, _, _, _, _}) -> <<"query">>; get_name({disco_item, _, _, _}) -> <<"item">>; @@ -2520,7 +2520,7 @@ get_ns({privacy_query, _, _, _}) -> <<"jabber:iq:privacy">>; get_ns({block, _}) -> <<"urn:xmpp:blocking">>; get_ns({unblock, _}) -> <<"urn:xmpp:blocking">>; -get_ns({block_list}) -> <<"urn:xmpp:blocking">>; +get_ns({block_list, _}) -> <<"urn:xmpp:blocking">>; get_ns({identity, _, _, _, _}) -> <<"http://jabber.org/protocol/disco#info">>; get_ns({disco_info, _, _, _, _}) -> @@ -2796,7 +2796,7 @@ pp(privacy_list, 2) -> [name, items]; pp(privacy_query, 3) -> [lists, default, active]; pp(block, 1) -> [items]; pp(unblock, 1) -> [items]; -pp(block_list, 0) -> []; +pp(block_list, 1) -> [items]; pp(identity, 4) -> [category, type, lang, name]; pp(disco_info, 4) -> [node, identities, features, xdata]; @@ -22454,13 +22454,52 @@ encode_disco_identity_attr_name(_val, _acc) -> decode_block_list(__TopXMLNS, __IgnoreEls, {xmlel, <<"blocklist">>, _attrs, _els}) -> - {block_list}. + Items = decode_block_list_els(__TopXMLNS, __IgnoreEls, + _els, []), + {block_list, Items}. -encode_block_list({block_list}, _xmlns_attrs) -> - _els = [], +decode_block_list_els(__TopXMLNS, __IgnoreEls, [], + Items) -> + lists:reverse(Items); +decode_block_list_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"urn:xmpp:blocking">> -> + decode_block_list_els(__TopXMLNS, __IgnoreEls, _els, + case decode_block_item(__TopXMLNS, __IgnoreEls, + _el) + of + undefined -> Items; + _new_el -> [_new_el | Items] + end); + <<"urn:xmpp:blocking">> -> + decode_block_list_els(__TopXMLNS, __IgnoreEls, _els, + case decode_block_item(<<"urn:xmpp:blocking">>, + __IgnoreEls, _el) + of + undefined -> Items; + _new_el -> [_new_el | Items] + end); + _ -> + decode_block_list_els(__TopXMLNS, __IgnoreEls, _els, + Items) + end; +decode_block_list_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Items) -> + decode_block_list_els(__TopXMLNS, __IgnoreEls, _els, + Items). + +encode_block_list({block_list, Items}, _xmlns_attrs) -> + _els = lists:reverse('encode_block_list_$items'(Items, + [])), _attrs = _xmlns_attrs, {xmlel, <<"blocklist">>, _attrs, _els}. +'encode_block_list_$items'([], _acc) -> _acc; +'encode_block_list_$items'([Items | _els], _acc) -> + 'encode_block_list_$items'(_els, + [encode_block_item(Items, []) | _acc]). + decode_unblock(__TopXMLNS, __IgnoreEls, {xmlel, <<"unblock">>, _attrs, _els}) -> Items = decode_unblock_els(__TopXMLNS, __IgnoreEls, diff --git a/tools/xmpp_codec.spec b/tools/xmpp_codec.spec index a94b317de..6c74a7ab1 100644 --- a/tools/xmpp_codec.spec +++ b/tools/xmpp_codec.spec @@ -176,7 +176,9 @@ -xml(block_list, #elem{name = <<"blocklist">>, xmlns = <<"urn:xmpp:blocking">>, - result = {block_list}}). + result = {block_list, '$items'}, + refs = [#ref{name = block_item, + label = '$items'}]}). -xml(disco_identity, #elem{name = <<"identity">>, From 5d90292849029c2f2e35d61840d85678d4644e21 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Tue, 19 Jul 2016 15:33:17 +0300 Subject: [PATCH 004/151] Fix hooks de-registration --- src/mod_vcard.erl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index de9fce00d..f738648d6 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -115,9 +115,9 @@ loop(Host, ServerHost) -> loop(Host, ServerHost); stop -> ejabberd_router:unregister_route(Host), - ejabberd_hooks:delete(disco_local_items, Host, ?MODULE, disco_items, 50), - ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, disco_features, 50), - ejabberd_hooks:delete(disco_local_identity, Host, ?MODULE, disco_identity, 50), + ejabberd_hooks:delete(disco_local_items, Host, ?MODULE, disco_items, 100), + ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, disco_features, 100), + ejabberd_hooks:delete(disco_local_identity, Host, ?MODULE, disco_identity, 100), gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_SEARCH), gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VCARD), gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS), From 179fcd9521ef8db4626ca110ba80c502d810c814 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Mon, 25 Jul 2016 13:50:30 +0300 Subject: [PATCH 005/151] Rewrite mod_mam and mod_muc to use XML generator --- include/mod_muc_room.hrl | 3 +- include/xmpp_codec.hrl | 155 +- src/ejabberd_router.erl | 31 +- src/mod_disco.erl | 4 +- src/mod_last.erl | 2 +- src/mod_mam.erl | 723 +++---- src/mod_mam_mnesia.erl | 28 +- src/mod_mam_sql.erl | 71 +- src/mod_muc.erl | 675 +++--- src/mod_muc_admin.erl | 12 +- src/mod_muc_log.erl | 36 +- src/mod_muc_room.erl | 4453 ++++++++++++++++---------------------- src/mod_private.erl | 2 +- src/xmpp.erl | 240 +- src/xmpp_codec.erl | 2390 +++++++++++++++----- src/xmpp_util.erl | 14 +- tools/xmpp_codec.spec | 264 ++- 17 files changed, 4871 insertions(+), 4232 deletions(-) diff --git a/include/mod_muc_room.hrl b/include/mod_muc_room.hrl index d985f3f3b..fc20f44c6 100644 --- a/include/mod_muc_room.hrl +++ b/include/mod_muc_room.hrl @@ -71,6 +71,7 @@ -type config() :: #config{}. -type role() :: moderator | participant | visitor | none. +-type affiliation() :: admin | member | outcast | owner | none. -record(user, { @@ -120,5 +121,3 @@ host = <<>> :: binary() | '_' | '$2'}). -type muc_online_users() :: #muc_online_users{}. - --type muc_room_state() :: #state{}. diff --git a/include/xmpp_codec.hrl b/include/xmpp_codec.hrl index 7b8275ed5..85601035d 100644 --- a/include/xmpp_codec.hrl +++ b/include/xmpp_codec.hrl @@ -11,13 +11,20 @@ -record(csi, {type :: active | inactive}). -type csi() :: #csi{}. --record(hint, {type :: 'no-copy' | 'no-store' | 'no-storage' | - 'store' | 'no-permanent-store'}). +-record(hint, {type :: 'no-copy' | 'no-store' | 'no-storage' | 'store' | + 'no-permanent-store' | 'no-permanent-storage'}). -type hint() :: #hint{}. -record(feature_register, {}). -type feature_register() :: #feature_register{}. +-record(address, {type :: 'bcc' | 'cc' | 'noreply' | 'ofrom' | 'replyroom' | 'replyto' | 'to', + jid :: any(), + desc :: binary(), + node :: binary(), + delivered :: any()}). +-type address() :: #address{}. + -record(sasl_success, {text :: any()}). -type sasl_success() :: #sasl_success{}. @@ -55,6 +62,9 @@ stored :: non_neg_integer()}). -type expire() :: #expire{}. +-record(muc_unsubscribe, {}). +-type muc_unsubscribe() :: #muc_unsubscribe{}. + -record(pubsub_unsubscribe, {node :: binary(), jid :: any(), subid :: binary()}). @@ -81,7 +91,7 @@ type :: 'member' | 'none' | 'outcast' | 'owner' | 'publish-only' | 'publisher'}). -type pubsub_affiliation() :: #pubsub_affiliation{}. --record(muc_decline, {reason :: binary(), +-record(muc_decline, {reason = <<>> :: 'undefined' | binary(), from :: any(), to :: any()}). -type muc_decline() :: #muc_decline{}. @@ -90,9 +100,20 @@ xmlns :: binary()}). -type sm_a() :: #sm_a{}. +-record(muc_subscribe, {nick :: binary(), + events = [] :: [binary()]}). +-type muc_subscribe() :: #muc_subscribe{}. + +-record(stanza_id, {by :: any(), + id :: binary()}). +-type stanza_id() :: #stanza_id{}. + -record(starttls_proceed, {}). -type starttls_proceed() :: #starttls_proceed{}. +-record(client_id, {id :: binary()}). +-type client_id() :: #client_id{}. + -record(sm_resumed, {h :: non_neg_integer(), previd :: binary(), xmlns :: binary()}). @@ -116,9 +137,19 @@ -record(gone, {uri :: binary()}). -type gone() :: #gone{}. +-record(x_conference, {jid :: any(), + password = <<>> :: binary(), + reason = <<>> :: binary(), + continue :: any(), + thread = <<>> :: binary()}). +-type x_conference() :: #x_conference{}. + -record(private, {xml_els = [] :: [any()]}). -type private() :: #private{}. +-record(nick, {name :: binary()}). +-type nick() :: #nick{}. + -record(p1_ack, {}). -type p1_ack() :: #p1_ack{}. @@ -163,6 +194,9 @@ error = [] :: [{integer(),'undefined' | binary()}]}). -type stat() :: #stat{}. +-record(addresses, {list = [] :: [#address{}]}). +-type addresses() :: #addresses{}. + -record('see-other-host', {host :: binary()}). -type 'see-other-host'() :: #'see-other-host'{}. @@ -194,6 +228,9 @@ -record(pubsub_event, {items = [] :: [#pubsub_event_items{}]}). -type pubsub_event() :: #pubsub_event{}. +-record(muc_unique, {name = <<>> :: binary()}). +-type muc_unique() :: #muc_unique{}. + -record(sasl_response, {text :: any()}). -type sasl_response() :: #sasl_response{}. @@ -217,19 +254,11 @@ -record(feature_csi, {xmlns :: binary()}). -type feature_csi() :: #feature_csi{}. --record(muc_user_destroy, {reason :: binary(), - jid :: any()}). --type muc_user_destroy() :: #muc_user_destroy{}. - -record(disco_item, {jid :: any(), name :: binary(), node :: binary()}). -type disco_item() :: #disco_item{}. --record(disco_items, {node :: binary(), - items = [] :: [#disco_item{}]}). --type disco_items() :: #disco_items{}. - -record(unblock, {items = [] :: [any()]}). -type unblock() :: #unblock{}. @@ -239,10 +268,8 @@ -record(compression, {methods = [] :: [binary()]}). -type compression() :: #compression{}. --record(muc_owner_destroy, {jid :: any(), - reason :: binary(), - password :: binary()}). --type muc_owner_destroy() :: #muc_owner_destroy{}. +-record(muc_subscriptions, {list = [] :: [any()]}). +-type muc_subscriptions() :: #muc_subscriptions{}. -record(pubsub_subscription, {jid :: any(), node :: binary(), @@ -252,7 +279,7 @@ -record(muc_item, {actor :: #muc_actor{}, continue :: binary(), - reason :: binary(), + reason = <<>> :: 'undefined' | binary(), affiliation :: 'admin' | 'member' | 'none' | 'outcast' | 'owner', role :: 'moderator' | 'none' | 'participant' | 'visitor', jid :: any(), @@ -267,8 +294,8 @@ -record(mam_prefs, {xmlns :: binary(), default :: 'always' | 'never' | 'roster', - always = [] :: [any()], - never = [] :: [any()]}). + always :: [any()], + never :: [any()]}). -type mam_prefs() :: #mam_prefs{}. -record(caps, {node :: binary(), @@ -350,13 +377,17 @@ -record(block_list, {items = [] :: [any()]}). -type block_list() :: #block_list{}. +-record(xdata_option, {label :: binary(), + value :: binary()}). +-type xdata_option() :: #xdata_option{}. + -record(xdata_field, {label :: binary(), type :: 'boolean' | 'fixed' | 'hidden' | 'jid-multi' | 'jid-single' | 'list-multi' | 'list-single' | 'text-multi' | 'text-private' | 'text-single', var :: binary(), required = false :: boolean(), desc :: binary(), values = [] :: [binary()], - options = [] :: [binary()]}). + options = [] :: [#xdata_option{}]}). -type xdata_field() :: #xdata_field{}. -record(version, {name :: binary(), @@ -364,11 +395,6 @@ os :: binary()}). -type version() :: #version{}. --record(muc_invite, {reason :: binary(), - from :: any(), - to :: any()}). --type muc_invite() :: #muc_invite{}. - -record(bind, {jid :: any(), resource :: any()}). -type bind() :: #bind{}. @@ -376,13 +402,11 @@ -record(rosterver_feature, {}). -type rosterver_feature() :: #rosterver_feature{}. --record(muc_user, {decline :: #muc_decline{}, - destroy :: #muc_user_destroy{}, - invites = [] :: [#muc_invite{}], - items = [] :: [#muc_item{}], - status_codes = [] :: [pos_integer()], - password :: binary()}). --type muc_user() :: #muc_user{}. +-record(muc_invite, {reason = <<>> :: 'undefined' | binary(), + from :: any(), + to :: any(), + continue :: binary()}). +-type muc_invite() :: #muc_invite{}. -record(carbons_disable, {}). -type carbons_disable() :: #carbons_disable{}. @@ -400,7 +424,7 @@ -type vcard_org() :: #vcard_org{}. -record(rsm_set, {'after' :: binary(), - before :: 'none' | binary(), + before :: binary(), count :: non_neg_integer(), first :: #rsm_first{}, index :: non_neg_integer(), @@ -414,6 +438,11 @@ complete :: any()}). -type mam_fin() :: #mam_fin{}. +-record(disco_items, {node :: binary(), + items = [] :: [#disco_item{}], + rsm :: #rsm_set{}}). +-type disco_items() :: #disco_items{}. + -record(vcard_tel, {home = false :: boolean(), work = false :: boolean(), voice = false :: boolean(), @@ -430,6 +459,20 @@ number :: binary()}). -type vcard_tel() :: #vcard_tel{}. +-record(muc_destroy, {xmlns :: binary(), + jid :: any(), + reason = <<>> :: 'undefined' | binary(), + password :: binary()}). +-type muc_destroy() :: #muc_destroy{}. + +-record(muc_user, {decline :: #muc_decline{}, + destroy :: #muc_destroy{}, + invites = [] :: [#muc_invite{}], + items = [] :: [#muc_item{}], + status_codes = [] :: [pos_integer()], + password :: binary()}). +-type muc_user() :: #muc_user{}. + -record(vcard_key, {type :: binary(), cred :: binary()}). -type vcard_key() :: #vcard_key{}. @@ -530,14 +573,11 @@ start :: any(), 'end' :: any(), with :: any(), + withtext :: binary(), rsm :: #rsm_set{}, xdata :: #xdata{}}). -type mam_query() :: #mam_query{}. --record(muc_owner, {destroy :: #muc_owner_destroy{}, - config :: #xdata{}}). --type muc_owner() :: #muc_owner{}. - -record(pubsub_options, {node :: binary(), jid :: any(), subid :: binary(), @@ -592,6 +632,11 @@ fetch = false :: boolean()}). -type offline() :: #offline{}. +-record(muc_owner, {destroy :: #muc_destroy{}, + config :: #xdata{}, + items = [] :: [#muc_item{}]}). +-type muc_owner() :: #muc_owner{}. + -record(sasl_mechanisms, {list = [] :: [binary()]}). -type sasl_mechanisms() :: #sasl_mechanisms{}. @@ -709,6 +754,7 @@ -type xmpp_element() :: compression() | pubsub_subscription() | + xdata_option() | version() | pubsub_affiliation() | muc_admin() | @@ -726,7 +772,9 @@ rsm_set() | 'see-other-host'() | hint() | + stanza_id() | starttls_proceed() | + client_id() | sm_resumed() | forwarded() | xevent() | @@ -742,8 +790,11 @@ pubsub_event_item() | muc_item() | vcard_temp() | + address() | sasl_success() | + addresses() | pubsub_event_items() | + muc_subscriptions() | disco_items() | pubsub_options() | compress() | @@ -751,33 +802,25 @@ muc_history() | identity() | feature_csi() | - muc_user_destroy() | privacy_query() | delay() | vcard_tel() | - vcard_logo() | - disco_info() | vcard_geo() | vcard_photo() | - feature_register() | - register() | - muc_owner() | pubsub() | - sm_r() | + muc_owner() | muc_actor() | - error() | - stream_error() | - muc_user() | - vcard_adr() | carbons_private() | mix_leave() | - muc_invite() | + muc_subscribe() | rosterver_feature() | + muc_invite() | vcard_xupdate() | carbons_disable() | bookmark_conference() | offline() | time() | + muc_unique() | sasl_response() | pubsub_subscribe() | presence() | @@ -786,6 +829,7 @@ starttls_failure() | sasl_challenge() | gone() | + x_conference() | private() | compress_failure() | sasl_failure() | @@ -794,6 +838,7 @@ sm_resume() | carbons_enable() | expire() | + muc_unsubscribe() | pubsub_unsubscribe() | muc_decline() | chatstate() | @@ -803,6 +848,7 @@ search() | pubsub_publish() | unblock() | + nick() | p1_ack() | block() | mix_join() | @@ -832,11 +878,20 @@ starttls() | mam_prefs() | sasl_mechanisms() | + muc_destroy() | vcard_key() | csi() | roster_query() | - muc_owner_destroy() | mam_query() | bookmark_url() | vcard_email() | - vcard_label(). + vcard_label() | + vcard_logo() | + disco_info() | + feature_register() | + register() | + sm_r() | + error() | + stream_error() | + muc_user() | + vcard_adr(). diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl index 5924d92c0..83ffd932b 100644 --- a/src/ejabberd_router.erl +++ b/src/ejabberd_router.erl @@ -72,7 +72,7 @@ start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). --spec route(jid(), jid(), xmlel() | xmpp_element()) -> ok. +-spec route(jid(), jid(), xmlel() | stanza()) -> ok. route(From, To, Packet) -> case catch do_route(From, To, Packet) of @@ -85,13 +85,21 @@ route(From, To, Packet) -> %% Route the error packet only if the originating packet is not an error itself. %% RFC3920 9.3.1 --spec route_error(jid(), jid(), xmlel(), xmlel()) -> ok. +-spec route_error(jid(), jid(), xmlel(), xmlel()) -> ok; + (jid(), jid(), stanza(), error()) -> ok. -route_error(From, To, ErrPacket, OrigPacket) -> +route_error(From, To, #xmlel{} = ErrPacket, #xmlel{} = OrigPacket) -> #xmlel{attrs = Attrs} = OrigPacket, case <<"error">> == fxml:get_attr_s(<<"type">>, Attrs) of false -> route(From, To, ErrPacket); true -> ok + end; +route_error(From, To, Packet, #error{} = Err) -> + Type = xmpp:get_type(Packet), + if Type == error; Type == result -> + ok; + true -> + ejabberd_router:route(From, To, xmpp:make_error(Packet, Err)) end. -spec register_route(binary()) -> term(). @@ -406,11 +414,16 @@ do_route(OrigFrom, OrigTo, OrigPacket) -> end. -spec do_route(jid(), jid(), xmlel() | xmpp_element(), #route{}) -> any(). -do_route(From, To, Packet, - #route{local_hint = {apply, Module, Function}, pid = Pid}) - when is_pid(Pid) andalso node(Pid) == node() -> - try - Module:Function(From, To, xmpp:decode(Packet, [ignore_els])) +do_route(From, To, Packet, #route{local_hint = LocalHint, + pid = Pid}) when is_pid(Pid) -> + try xmpp:decode(Packet, [ignore_els]) of + Pkt -> + case LocalHint of + {apply, Module, Function} when node(Pid) == node() -> + Module:Function(From, To, Pkt); + _ -> + Pid ! {route, From, To, Pkt} + end catch error:{xmpp_codec, Why} -> ?ERROR_MSG("failed to decode xml element ~p when " "routing from ~s to ~s: ~s", @@ -418,8 +431,6 @@ do_route(From, To, Packet, xmpp:format_error(Why)]), drop end; -do_route(From, To, Packet, #route{pid = Pid}) when is_pid(Pid) -> - Pid ! {route, From, To, xmpp:encode(Packet)}; do_route(_From, _To, _Packet, _Route) -> drop. diff --git a/src/mod_disco.erl b/src/mod_disco.erl index 03fdab209..0d3f242a0 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -295,7 +295,7 @@ process_sm_iq_items(#iq{type = get, lang = Lang, end; false -> Txt = <<"Not subscribed">>, - xmpp:make_error(IQ, xmpp:err_service_unavailable(Txt, Lang)) + xmpp:make_error(IQ, xmpp:err_subscription_required(Txt, Lang)) end. -spec get_sm_items({error, error()} | {result, [disco_item()]} | empty, @@ -371,7 +371,7 @@ process_sm_iq_info(#iq{type = get, lang = Lang, end; false -> Txt = <<"Not subscribed">>, - xmpp:make_error(IQ, xmpp:err_service_unavailable(Txt, Lang)) + xmpp:make_error(IQ, xmpp:err_subscription_required(Txt, Lang)) end. -spec get_sm_identity([identity()], jid(), jid(), diff --git a/src/mod_last.erl b/src/mod_last.erl index b267aa89b..6d0edebf0 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -140,7 +140,7 @@ process_sm_iq(#iq{from = From, to = To, lang = Lang} = IQ) -> end; true -> Txt = <<"Not subscribed">>, - xmpp:make_error(IQ, xmpp:err_not_subscribed(Txt, Lang)) + xmpp:make_error(IQ, xmpp:err_subscription_required(Txt, Lang)) end. %% @spec (LUser::string(), LServer::string()) -> diff --git a/src/mod_mam.erl b/src/mod_mam.erl index 10eb098da..b4ee17720 100644 --- a/src/mod_mam.erl +++ b/src/mod_mam.erl @@ -34,12 +34,12 @@ -export([start/2, stop/1, depends/2]). -export([user_send_packet/4, user_send_packet_strip_tag/4, user_receive_packet/5, - process_iq_v0_2/3, process_iq_v0_3/3, disco_sm_features/5, - remove_user/2, remove_room/3, mod_opt_type/1, muc_process_iq/4, + process_iq_v0_2/1, process_iq_v0_3/1, disco_sm_features/5, + remove_user/2, remove_room/3, mod_opt_type/1, muc_process_iq/2, muc_filter_message/5, message_is_archived/5, delete_old_messages/2, get_commands_spec/0, msg_to_el/4, get_room_config/4, set_room_option/4]). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("logger.hrl"). -include("mod_muc_room.hrl"). -include("ejabberd_commands.hrl"). @@ -54,17 +54,12 @@ -callback delete_old_messages(binary() | global, erlang:timestamp(), all | chat | groupchat) -> any(). --callback extended_fields() -> [xmlel()]. +-callback extended_fields() -> [xdata_field()]. -callback store(xmlel(), binary(), {binary(), binary()}, chat | groupchat, jid(), binary(), recv | send) -> {ok, binary()} | any(). -callback write_prefs(binary(), binary(), #archive_prefs{}, binary()) -> ok | any(). -callback get_prefs(binary(), binary()) -> {ok, #archive_prefs{}} | error. --callback select(binary(), jid(), jid(), - none | erlang:timestamp(), - none | erlang:timestamp(), - none | ljid() | {text, binary()}, - none | #rsm_in{}, - chat | groupchat) -> +-callback select(binary(), jid(), jid(), mam_query(), chat | groupchat) -> {[{binary(), non_neg_integer(), xmlel()}], boolean(), non_neg_integer()}. %%%=================================================================== @@ -200,14 +195,10 @@ get_room_config(X, RoomState, _From, Lang) -> true -> <<"1">>; _ -> <<"0">> end, - XField = #xmlel{name = <<"field">>, - attrs = - [{<<"type">>, <<"boolean">>}, - {<<"label">>, translate:translate(Lang, Label)}, - {<<"var">>, Var}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = [{xmlcdata, Val}]}]}, + XField = #xdata_field{type = boolean, + label = translate:translate(Lang, Label), + var = Var, + values = [Val]}, X ++ [XField]. set_room_option(_Acc, <<"muc#roomconfig_mam">> = Opt, Vals, Lang) -> @@ -222,7 +213,7 @@ set_room_option(_Acc, <<"muc#roomconfig_mam">> = Opt, Vals, Lang) -> catch _:{case_clause, _} -> Txt = <<"Value of '~s' should be boolean">>, ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), - {error, ?ERRT_BAD_REQUEST(Lang, ErrTxt)} + {error, xmpp:err_bad_request(Lang, ErrTxt)} end; set_room_option(Acc, _Opt, _Vals, _Lang) -> Acc. @@ -236,16 +227,7 @@ user_receive_packet(Pkt, C2SState, JID, Peer, To) -> NewPkt = strip_my_archived_tag(Pkt, LServer), case store_msg(C2SState, NewPkt, LUser, LServer, Peer, recv) of {ok, ID} -> - Archived = #xmlel{name = <<"archived">>, - attrs = [{<<"by">>, LServer}, - {<<"xmlns">>, ?NS_MAM_TMP}, - {<<"id">>, ID}]}, - StanzaID = #xmlel{name = <<"stanza-id">>, - attrs = [{<<"by">>, LServer}, - {<<"xmlns">>, ?NS_SID_0}, - {<<"id">>, ID}]}, - NewEls = [Archived, StanzaID|NewPkt#xmlel.children], - NewPkt#xmlel{children = NewEls}; + set_stanza_id(NewPkt, LServer, ID); _ -> NewPkt end; @@ -259,19 +241,10 @@ user_send_packet(Pkt, C2SState, JID, Peer) -> case should_archive(Pkt, LServer) of true -> NewPkt = strip_my_archived_tag(Pkt, LServer), - case store_msg(C2SState, jlib:replace_from_to(JID, Peer, NewPkt), + case store_msg(C2SState, xmpp:set_from_to(NewPkt, JID, Peer), LUser, LServer, Peer, send) of {ok, ID} -> - Archived = #xmlel{name = <<"archived">>, - attrs = [{<<"by">>, LServer}, - {<<"xmlns">>, ?NS_MAM_TMP}, - {<<"id">>, ID}]}, - StanzaID = #xmlel{name = <<"stanza-id">>, - attrs = [{<<"by">>, LServer}, - {<<"xmlns">>, ?NS_SID_0}, - {<<"id">>, ID}]}, - NewEls = [Archived, StanzaID|NewPkt#xmlel.children], - NewPkt#xmlel{children = NewEls}; + set_stanza_id(NewPkt, LServer, ID); _ -> NewPkt end; @@ -291,16 +264,7 @@ muc_filter_message(Pkt, #state{config = Config} = MUCState, StorePkt = strip_x_jid_tags(NewPkt), case store_muc(MUCState, StorePkt, RoomJID, From, FromNick) of {ok, ID} -> - Archived = #xmlel{name = <<"archived">>, - attrs = [{<<"by">>, LServer}, - {<<"xmlns">>, ?NS_MAM_TMP}, - {<<"id">>, ID}]}, - StanzaID = #xmlel{name = <<"stanza-id">>, - attrs = [{<<"by">>, LServer}, - {<<"xmlns">>, ?NS_SID_0}, - {<<"id">>, ID}]}, - NewEls = [Archived, StanzaID|NewPkt#xmlel.children], - NewPkt#xmlel{children = NewEls}; + set_stanza_id(NewPkt, LServer, ID); _ -> NewPkt end; @@ -308,71 +272,98 @@ muc_filter_message(Pkt, #state{config = Config} = MUCState, Pkt end. +set_stanza_id(Pkt, LServer, ID) -> + Archived = #mam_archived{by = jid:make(LServer), id = ID}, + StanzaID = #stanza_id{by = jid:make(LServer), id = ID}, + NewEls = [Archived, StanzaID|xmpp:get_els(Pkt)], + xmpp:set_els(Pkt, NewEls). + % Query archive v0.2 -process_iq_v0_2(#jid{lserver = LServer} = From, - #jid{lserver = LServer} = To, - #iq{type = get, sub_el = #xmlel{name = <<"query">>} = SubEl} = IQ) -> - Fs = parse_query_v0_2(SubEl), - process_iq(LServer, From, To, IQ, SubEl, Fs, chat); -process_iq_v0_2(From, To, IQ) -> - process_iq(From, To, IQ). +process_iq_v0_2(#iq{from = #jid{lserver = LServer}, + to = #jid{lserver = LServer}, + type = get, sub_els = [#mam_query{}]} = IQ) -> + process_iq(LServer, IQ, chat); +process_iq_v0_2(IQ) -> + process_iq(IQ). % Query archive v0.3 -process_iq_v0_3(#jid{lserver = LServer} = From, - #jid{lserver = LServer} = To, - #iq{type = set, sub_el = #xmlel{name = <<"query">>} = SubEl} = IQ) -> - process_iq(LServer, From, To, IQ, SubEl, get_xdata_fields(SubEl), chat); -process_iq_v0_3(#jid{lserver = LServer}, - #jid{lserver = LServer}, - #iq{type = get, sub_el = #xmlel{name = <<"query">>}} = IQ) -> +process_iq_v0_3(#iq{from = #jid{lserver = LServer}, + to = #jid{lserver = LServer}, + type = set, sub_els = [#mam_query{}]} = IQ) -> + process_iq(LServer, IQ, chat); +process_iq_v0_3(#iq{from = #jid{lserver = LServer}, + to = #jid{lserver = LServer}, + type = get, sub_els = [#mam_query{}]} = IQ) -> process_iq(LServer, IQ); -process_iq_v0_3(From, To, IQ) -> - process_iq(From, To, IQ). +process_iq_v0_3(IQ) -> + process_iq(IQ). -muc_process_iq(#iq{type = set, - sub_el = #xmlel{name = <<"query">>, - attrs = Attrs} = SubEl} = IQ, - MUCState, From, To) -> - case fxml:get_attr_s(<<"xmlns">>, Attrs) of - NS when NS == ?NS_MAM_0; NS == ?NS_MAM_1 -> - muc_process_iq(IQ, MUCState, From, To, get_xdata_fields(SubEl)); - _ -> - IQ +muc_process_iq(#iq{type = T, lang = Lang, + from = From, + sub_els = [#mam_query{xmlns = NS}]} = IQ, + MUCState) + when (T == set andalso (NS == ?NS_MAM_0 orelse NS == ?NS_MAM_1)) orelse + (T == get andalso NS == ?NS_MAM_TMP) -> + case may_enter_room(From, MUCState) of + true -> + LServer = MUCState#state.server_host, + Role = mod_muc_room:get_role(From, MUCState), + process_iq(LServer, IQ, {groupchat, Role, MUCState}); + false -> + Text = <<"Only members may query archives of this room">>, + xmpp:make_error(IQ, xmpp:err_forbidden(Text, Lang)) end; muc_process_iq(#iq{type = get, - sub_el = #xmlel{name = <<"query">>, - attrs = Attrs} = SubEl} = IQ, - MUCState, From, To) -> - case fxml:get_attr_s(<<"xmlns">>, Attrs) of - ?NS_MAM_TMP -> - muc_process_iq(IQ, MUCState, From, To, parse_query_v0_2(SubEl)); - NS when NS == ?NS_MAM_0; NS == ?NS_MAM_1 -> - LServer = MUCState#state.server_host, - process_iq(LServer, IQ); - _ -> - IQ - end; -muc_process_iq(IQ, _MUCState, _From, _To) -> + sub_els = [#mam_query{xmlns = NS}]} = IQ, + MUCState) when NS == ?NS_MAM_0; NS == ?NS_MAM_1 -> + LServer = MUCState#state.server_host, + process_iq(LServer, IQ); +muc_process_iq(IQ, _MUCState) -> IQ. -get_xdata_fields(SubEl) -> - case {fxml:get_subtag_with_xmlns(SubEl, <<"x">>, ?NS_XDATA), - fxml:get_subtag_with_xmlns(SubEl, <<"set">>, ?NS_RSM)} of - {#xmlel{} = XData, false} -> - jlib:parse_xdata_submit(XData); - {#xmlel{} = XData, #xmlel{}} -> - [{<<"set">>, SubEl} | jlib:parse_xdata_submit(XData)]; - {false, #xmlel{}} -> - [{<<"set">>, SubEl}]; - {false, false} -> - [] - end. +parse_query(#mam_query{xdata = #xdata{fields = Fs}} = Query, Lang) -> + try + lists:foldl( + fun(#xdata_field{var = <<"start">>, values = [Data|_]}, Q) -> + case jlib:datetime_string_to_timestamp(Data) of + undefined -> throw({error, <<"start">>}); + {_, _, _} = TS -> Q#mam_query{start = TS} + end; + (#xdata_field{var = <<"end">>, values = [Data|_]}, Q) -> + case jlib:datetime_string_to_timestamp(Data) of + undefined -> throw({error, <<"end">>}); + {_, _, _} = TS -> Q#mam_query{'end' = TS} + end; + (#xdata_field{var = <<"with">>, values = [Data|_]}, Q) -> + case jid:from_string(Data) of + error -> throw({error, <<"with">>}); + J -> Q#mam_query{with = J} + end; + (#xdata_field{var = <<"withtext">>, values = [Data|_]}, Q) -> + case Data of + <<"">> -> throw({error, <<"withtext">>}); + _ -> Q#mam_query{withtext = Data} + end; + (#xdata_field{var = <<"FORM_TYPE">>, values = [NS|_]}, Q) -> + case Query#mam_query.xmlns of + NS -> Q; + _ -> throw({error, <<"FORM_TYPE">>}) + end; + (#xdata_field{}, Acc) -> + Acc + end, Query, Fs) + catch throw:{error, Var} -> + Txt = io_lib:format("Incorrect value of field '~s'", [Var]), + {error, xmpp:err_bad_request(iolist_to_binary(Txt), Lang)} + end; +parse_query(Query, _Lang) -> + Query. disco_sm_features(empty, From, To, Node, Lang) -> disco_sm_features({result, []}, From, To, Node, Lang); disco_sm_features({result, OtherFeatures}, #jid{luser = U, lserver = S}, - #jid{luser = U, lserver = S}, <<>>, _Lang) -> + #jid{luser = U, lserver = S}, undefined, _Lang) -> {result, [?NS_MAM_TMP, ?NS_MAM_0, ?NS_MAM_1 | OtherFeatures]}; disco_sm_features(Acc, _From, _To, _Node, _Lang) -> Acc. @@ -440,210 +431,155 @@ delete_old_messages(_TypeBin, _Days) -> %%% Internal functions %%%=================================================================== -process_iq(LServer, #iq{sub_el = #xmlel{attrs = Attrs}} = IQ) -> - NS = case fxml:get_attr_s(<<"xmlns">>, Attrs) of - ?NS_MAM_0 -> - ?NS_MAM_0; - _ -> - ?NS_MAM_1 - end, - CommonFields = [#xmlel{name = <<"field">>, - attrs = [{<<"type">>, <<"hidden">>}, - {<<"var">>, <<"FORM_TYPE">>}], - children = [#xmlel{name = <<"value">>, - children = [{xmlcdata, NS}]}]}, - #xmlel{name = <<"field">>, - attrs = [{<<"type">>, <<"jid-single">>}, - {<<"var">>, <<"with">>}]}, - #xmlel{name = <<"field">>, - attrs = [{<<"type">>, <<"text-single">>}, - {<<"var">>, <<"start">>}]}, - #xmlel{name = <<"field">>, - attrs = [{<<"type">>, <<"text-single">>}, - {<<"var">>, <<"end">>}]}], +process_iq(LServer, #iq{sub_els = [#mam_query{xmlns = NS}]} = IQ) -> + CommonFields = [#xdata_field{type = hidden, + var = <<"FORM_TYPE">>, + values = [NS]}, + #xdata_field{type = 'jid-single', var = <<"with">>}, + #xdata_field{type = 'text-single', var = <<"start">>}, + #xdata_field{type = 'text-single', var = <<"end">>}], Mod = gen_mod:db_mod(LServer, ?MODULE), ExtendedFields = Mod:extended_fields(), - Fields = ExtendedFields ++ CommonFields, - Form = #xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_XDATA}, {<<"type">>, <<"form">>}], - children = Fields}, - IQ#iq{type = result, - sub_el = [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, NS}], - children = [Form]}]}. + Fields = CommonFields ++ ExtendedFields, + Form = #xdata{type = form, fields = Fields}, + xmpp:make_iq_result(IQ, #mam_query{xmlns = NS, xdata = Form}). % Preference setting (both v0.2 & v0.3) -process_iq(#jid{luser = LUser, lserver = LServer}, - #jid{lserver = LServer}, - #iq{type = set, lang = Lang, sub_el = #xmlel{name = <<"prefs">>} = SubEl} = IQ) -> - try {case fxml:get_tag_attr_s(<<"default">>, SubEl) of - <<"always">> -> always; - <<"never">> -> never; - <<"roster">> -> roster - end, - lists:foldl( - fun(#xmlel{name = <<"always">>, children = Els}, {A, N}) -> - {get_jids(Els) ++ A, N}; - (#xmlel{name = <<"never">>, children = Els}, {A, N}) -> - {A, get_jids(Els) ++ N}; - (_, {A, N}) -> - {A, N} - end, {[], []}, SubEl#xmlel.children)} of - {Default, {Always0, Never0}} -> - Always = lists:usort(Always0), - Never = lists:usort(Never0), - case write_prefs(LUser, LServer, LServer, Default, Always, Never) of - ok -> - NewPrefs = prefs_el(Default, Always, Never, IQ#iq.xmlns), - IQ#iq{type = result, sub_el = [NewPrefs]}; - _Err -> - Txt = <<"Database failure">>, - IQ#iq{type = error, - sub_el = [SubEl, ?ERRT_INTERNAL_SERVER_ERROR(Lang, Txt)]} - end - catch _:_ -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_BAD_REQUEST]} +process_iq(#iq{type = set, lang = Lang, + sub_els = [#mam_prefs{default = undefined, xmlns = NS}]} = IQ) -> + Why = {missing_attr, <<"default">>, <<"prefs">>, NS}, + ErrTxt = xmpp:format_error(Why), + xmpp:make_error(IQ, xmpp:err_bad_request(ErrTxt, Lang)); +process_iq(#iq{from = #jid{luser = LUser, lserver = LServer}, + to = #jid{lserver = LServer}, + type = set, lang = Lang, + sub_els = [#mam_prefs{xmlns = NS, + default = Default, + always = Always0, + never = Never0}]} = IQ) -> + Always = lists:usort(get_jids(Always0)), + Never = lists:usort(get_jids(Never0)), + case write_prefs(LUser, LServer, LServer, Default, Always, Never) of + ok -> + NewPrefs = prefs_el(Default, Always, Never, NS), + xmpp:make_iq_result(IQ, NewPrefs); + _Err -> + Txt = <<"Database failure">>, + xmpp:make_error(IQ, xmpp:err_internal_server_error(Txt, Lang)) end; -process_iq(#jid{luser = LUser, lserver = LServer}, - #jid{lserver = LServer}, - #iq{type = get, sub_el = #xmlel{name = <<"prefs">>}} = IQ) -> +process_iq(#iq{from = #jid{luser = LUser, lserver = LServer}, + to = #jid{lserver = LServer}, + type = get, sub_els = [#mam_prefs{xmlns = NS}]} = IQ) -> Prefs = get_prefs(LUser, LServer), PrefsEl = prefs_el(Prefs#archive_prefs.default, Prefs#archive_prefs.always, Prefs#archive_prefs.never, - IQ#iq.xmlns), - IQ#iq{type = result, sub_el = [PrefsEl]}; -process_iq(_, _, #iq{sub_el = SubEl} = IQ) -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}. + NS), + xmpp:make_iq_result(IQ, PrefsEl); +process_iq(IQ) -> + xmpp:make_error(IQ, xmpp:err_not_allowed()). -process_iq(LServer, #jid{luser = LUser} = From, To, IQ, SubEl, Fs, MsgType) -> +process_iq(LServer, #iq{from = #jid{luser = LUser}, lang = Lang, + sub_els = [SubEl]} = IQ, MsgType) -> case MsgType of chat -> maybe_activate_mam(LUser, LServer); {groupchat, _Role, _MUCState} -> ok end, - case catch lists:foldl( - fun({<<"start">>, [Data|_]}, {_, End, With, RSM}) -> - {{_, _, _} = jlib:datetime_string_to_timestamp(Data), - End, With, RSM}; - ({<<"end">>, [Data|_]}, {Start, _, With, RSM}) -> - {Start, - {_, _, _} = jlib:datetime_string_to_timestamp(Data), - With, RSM}; - ({<<"with">>, [Data|_]}, {Start, End, _, RSM}) -> - {Start, End, jid:tolower(jid:from_string(Data)), RSM}; - ({<<"withtext">>, [Data|_]}, {Start, End, _, RSM}) -> - {Start, End, {text, Data}, RSM}; - ({<<"set">>, El}, {Start, End, With, _}) -> - {Start, End, With, jlib:rsm_decode(El)}; - (_, Acc) -> - Acc - end, {none, [], none, none}, Fs) of - {'EXIT', _} -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_BAD_REQUEST]}; - {_Start, _End, _With, #rsm_in{index = Index}} when is_integer(Index) -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_FEATURE_NOT_IMPLEMENTED]}; - {Start, End, With, RSM} -> - NS = fxml:get_tag_attr_s(<<"xmlns">>, SubEl), - select_and_send(LServer, From, To, Start, End, - With, limit_max(RSM, NS), IQ, MsgType) + case parse_query(SubEl, Lang) of + #mam_query{rsm = #rsm_set{index = I}} when is_integer(I) -> + xmpp:make_error(IQ, xmpp:err_feature_not_implemented()); + #mam_query{rsm = RSM, xmlns = NS} = Query -> + NewRSM = limit_max(RSM, NS), + NewQuery = Query#mam_query{rsm = NewRSM}, + select_and_send(LServer, NewQuery, IQ, MsgType); + {error, Err} -> + xmpp:make_error(IQ, Err) end. -muc_process_iq(#iq{lang = Lang, sub_el = SubEl} = IQ, MUCState, From, To, Fs) -> - case may_enter_room(From, MUCState) of +should_archive(#message{type = T}, _LServer) when T == error; T == result -> + false; +should_archive(#message{body = Body} = Pkt, LServer) -> + case is_resent(Pkt, LServer) of true -> - LServer = MUCState#state.server_host, - Role = mod_muc_room:get_role(From, MUCState), - process_iq(LServer, From, To, IQ, SubEl, Fs, - {groupchat, Role, MUCState}); + false; false -> - Text = <<"Only members may query archives of this room">>, - Error = ?ERRT_FORBIDDEN(Lang, Text), - IQ#iq{type = error, sub_el = [SubEl, Error]} - end. - -parse_query_v0_2(Query) -> - lists:flatmap( - fun (#xmlel{name = <<"start">>} = El) -> - [{<<"start">>, [fxml:get_tag_cdata(El)]}]; - (#xmlel{name = <<"end">>} = El) -> - [{<<"end">>, [fxml:get_tag_cdata(El)]}]; - (#xmlel{name = <<"with">>} = El) -> - [{<<"with">>, [fxml:get_tag_cdata(El)]}]; - (#xmlel{name = <<"withtext">>} = El) -> - [{<<"withtext">>, [fxml:get_tag_cdata(El)]}]; - (#xmlel{name = <<"set">>}) -> - [{<<"set">>, Query}]; - (_) -> - [] - end, Query#xmlel.children). - -should_archive(#xmlel{name = <<"message">>} = Pkt, LServer) -> - case fxml:get_attr_s(<<"type">>, Pkt#xmlel.attrs) of - <<"error">> -> - false; - <<"groupchat">> -> - false; - _ -> - case is_resent(Pkt, LServer) of - true -> + case check_store_hint(Pkt) of + store -> + true; + no_store -> false; - false -> - case check_store_hint(Pkt) of - store -> - true; - no_store -> - false; - none -> - case fxml:get_subtag_cdata(Pkt, <<"body">>) of - <<>> -> - %% Empty body - false; - _ -> - true - end - end - end - end; -should_archive(#xmlel{}, _LServer) -> - false. - -strip_my_archived_tag(Pkt, LServer) -> - NewEls = lists:filter( - fun(#xmlel{name = Tag, attrs = Attrs}) - when Tag == <<"archived">>; Tag == <<"stanza-id">> -> - case catch jid:nameprep( - fxml:get_attr_s( - <<"by">>, Attrs)) of - LServer -> + none -> + case xmpp:get_text(Body) of + <<>> -> + %% Empty body false; _ -> true - end; - (_) -> - true - end, Pkt#xmlel.children), - Pkt#xmlel{children = NewEls}. + end + end + end; +should_archive(_, _LServer) -> + false. + +strip_my_archived_tag(Pkt, LServer) -> + NewPkt = xmpp:decode_els( + Pkt, fun(El) -> + case xmpp:get_name(El) of + <<"archived">> -> + xmpp:get_ns(El) == ?NS_MAM_TMP; + <<"stanza-id">> -> + xmpp:get_ns(El) == ?NS_SID_0; + _ -> + false + end + end), + NewEls = lists:filter( + fun(#mam_archived{by = #jid{luser = <<>>} = By}) -> + By#jid.lserver /= LServer; + (#stanza_id{by = #jid{luser = <<>>} = By}) -> + By#jid.lserver /= LServer; + (_) -> + true + end, xmpp:get_els(NewPkt)), + xmpp:set_els(NewPkt, NewEls). strip_x_jid_tags(Pkt) -> + NewPkt = xmpp:decode_els( + Pkt, fun(El) -> + case xmpp:get_name(El) of + <<"x">> -> + case xmpp:get_ns(El) of + ?NS_MUC_USER -> true; + ?NS_MUC_ADMIN -> true; + ?NS_MUC_OWNER -> true; + _ -> false + end; + _ -> + false + end + end), NewEls = lists:filter( - fun(#xmlel{name = <<"x">>} = XEl) -> - not lists:any(fun(ItemEl) -> - fxml:get_tag_attr(<<"jid">>, ItemEl) - /= false - end, fxml:get_subtags(XEl, <<"item">>)); - (_) -> - true - end, Pkt#xmlel.children), - Pkt#xmlel{children = NewEls}. + fun(El) -> + Items = case El of + #muc_user{items = Is} -> Is; + #muc_admin{items = Is} -> Is; + #muc_owner{items = Is} -> Is; + _ -> [] + end, + not lists:any(fun(#muc_item{jid = JID}) -> + JID /= undefined + end, Items) + end, xmpp:get_els(NewPkt)), + xmpp:set_els(NewPkt, NewEls). should_archive_peer(C2SState, #archive_prefs{default = Default, always = Always, never = Never}, Peer) -> - LPeer = jid:tolower(Peer), + LPeer = jid:remove_resource(jid:tolower(Peer)), case lists:member(LPeer, Always) of true -> true; @@ -667,30 +603,30 @@ should_archive_peer(C2SState, end end. -should_archive_muc(Pkt) -> - case fxml:get_attr_s(<<"type">>, Pkt#xmlel.attrs) of - <<"groupchat">> -> - case check_store_hint(Pkt) of - store -> - true; - no_store -> - false; - none -> - case fxml:get_subtag_cdata(Pkt, <<"body">>) of - <<>> -> - case fxml:get_subtag_cdata(Pkt, <<"subject">>) of - <<>> -> - false; - _ -> - true - end; +should_archive_muc(#message{type = groupchat, + body = Body, subject = Subj} = Pkt) -> + case check_store_hint(Pkt) of + store -> + true; + no_store -> + false; + none -> + case xmpp:get_text(Body) of + <<"">> -> + case xmpp:get_text(Subj) of + <<"">> -> + false; _ -> true - end + end; + _ -> + true end; _ -> false - end. + end; +should_archive_muc(_) -> + false. check_store_hint(Pkt) -> case has_store_hint(Pkt) of @@ -705,30 +641,24 @@ check_store_hint(Pkt) -> end end. + +-spec has_store_hint(message()) -> boolean(). has_store_hint(Message) -> - fxml:get_subtag_with_xmlns(Message, <<"store">>, ?NS_HINTS) - /= false. + xmpp:has_subtag(Message, #hint{type = 'store'}). +-spec has_no_store_hint(message()) -> boolean(). has_no_store_hint(Message) -> - fxml:get_subtag_with_xmlns(Message, <<"no-store">>, ?NS_HINTS) - /= false orelse - fxml:get_subtag_with_xmlns(Message, <<"no-storage">>, ?NS_HINTS) - /= false orelse - fxml:get_subtag_with_xmlns(Message, <<"no-permanent-store">>, ?NS_HINTS) - /= false orelse - fxml:get_subtag_with_xmlns(Message, <<"no-permanent-storage">>, ?NS_HINTS) - /= false. + xmpp:has_subtag(Message, #hint{type = 'no-store'}) orelse + xmpp:has_subtag(Message, #hint{type = 'no-storage'}) orelse + xmpp:has_subtag(Message, #hint{type = 'no-permanent-store'}) orelse + xmpp:has_subtag(Message, #hint{type = 'no-permanent-storage'}). +-spec is_resent(message(), binary()) -> boolean(). is_resent(Pkt, LServer) -> - case fxml:get_subtag_with_xmlns(Pkt, <<"stanza-id">>, ?NS_SID_0) of - #xmlel{attrs = Attrs} -> - case fxml:get_attr(<<"by">>, Attrs) of - {value, LServer} -> - true; - _ -> - false - end; - false -> + case xmpp:get_subtag(Pkt, #stanza_id{}) of + #stanza_id{by = #jid{luser = <<>>, lserver = LServer}} -> + true; + _ -> false end. @@ -744,7 +674,8 @@ store_msg(C2SState, Pkt, LUser, LServer, Peer, Dir) -> true -> US = {LUser, LServer}, Mod = gen_mod:db_mod(LServer, ?MODULE), - Mod:store(Pkt, LServer, US, chat, Peer, <<"">>, Dir); + El = xmpp:encode(Pkt), + Mod:store(El, LServer, US, chat, Peer, <<"">>, Dir); false -> pass end. @@ -755,7 +686,8 @@ store_muc(MUCState, Pkt, RoomJID, Peer, Nick) -> LServer = MUCState#state.server_host, {U, S, _} = jid:tolower(RoomJID), Mod = gen_mod:db_mod(LServer, ?MODULE), - Mod:store(Pkt, LServer, {U, S}, groupchat, Peer, Nick, recv); + El = xmpp:encode(Pkt), + Mod:store(El, LServer, {U, S}, groupchat, Peer, Nick, recv); false -> pass end. @@ -796,20 +728,10 @@ get_prefs(LUser, LServer) -> end. prefs_el(Default, Always, Never, NS) -> - Default1 = jlib:atom_to_binary(Default), - JFun = fun(L) -> - [#xmlel{name = <<"jid">>, - children = [{xmlcdata, jid:to_string(J)}]} - || J <- L] - end, - Always1 = #xmlel{name = <<"always">>, - children = JFun(Always)}, - Never1 = #xmlel{name = <<"never">>, - children = JFun(Never)}, - #xmlel{name = <<"prefs">>, - attrs = [{<<"xmlns">>, NS}, - {<<"default">>, Default1}], - children = [Always1, Never1]}. + #mam_prefs{default = Default, + always = [jid:make(LJ) || LJ <- Always], + never = [jid:make(LJ) || LJ <- Never], + xmlns = NS}. maybe_activate_mam(LUser, LServer) -> ActivateOpt = gen_mod:get_module_opt(LServer, ?MODULE, @@ -838,21 +760,19 @@ maybe_activate_mam(LUser, LServer) -> ok end. -select_and_send(LServer, From, To, Start, End, With, RSM, IQ, MsgType) -> - {Msgs, IsComplete, Count} = select_and_start(LServer, From, To, Start, End, - With, RSM, MsgType), +select_and_send(LServer, Query, #iq{from = From, to = To} = IQ, MsgType) -> + {Msgs, IsComplete, Count} = + case MsgType of + chat -> + select(LServer, From, From, Query, MsgType); + {groupchat, _Role, _MUCState} -> + select(LServer, From, To, Query, MsgType) + end, SortedMsgs = lists:keysort(2, Msgs), - send(From, To, SortedMsgs, RSM, Count, IsComplete, IQ). + send(SortedMsgs, Count, IsComplete, IQ). -select_and_start(LServer, From, To, Start, End, With, RSM, MsgType) -> - case MsgType of - chat -> - select(LServer, From, From, Start, End, With, RSM, MsgType); - {groupchat, _Role, _MUCState} -> - select(LServer, From, To, Start, End, With, RSM, MsgType) - end. - -select(_LServer, JidRequestor, JidArchive, Start, End, _With, RSM, +select(_LServer, JidRequestor, JidArchive, + #mam_query{start = Start, 'end' = End, rsm = RSM}, {groupchat, _Role, #state{config = #config{mam = false}, history = History}} = MsgType) -> #lqueue{len = L, queue = Q} = History, @@ -864,7 +784,7 @@ select(_LServer, JidRequestor, JidArchive, Start, End, _With, RSM, case match_interval(Now, Start, End) and match_rsm(Now, RSM) of true -> - {[{jlib:integer_to_binary(TS), TS, + {[{integer_to_binary(TS), TS, msg_to_el(#archive_msg{ type = groupchat, timestamp = Now, @@ -879,31 +799,27 @@ select(_LServer, JidRequestor, JidArchive, Start, End, _With, RSM, end, 0, queue:to_list(Q)), Msgs = lists:flatten(Msgs0), case RSM of - #rsm_in{max = Max, direction = before} -> + #rsm_set{max = Max, before = Before} when is_binary(Before) -> {NewMsgs, IsComplete} = filter_by_max(lists:reverse(Msgs), Max), {NewMsgs, IsComplete, L}; - #rsm_in{max = Max} -> + #rsm_set{max = Max} -> {NewMsgs, IsComplete} = filter_by_max(Msgs, Max), {NewMsgs, IsComplete, L}; _ -> {Msgs, true, L} end; -select(LServer, JidRequestor, JidArchive, Start, End, With, RSM, MsgType) -> +select(LServer, JidRequestor, JidArchive, Query, MsgType) -> Mod = gen_mod:db_mod(LServer, ?MODULE), - Mod:select(LServer, JidRequestor, JidArchive, Start, End, With, RSM, - MsgType). + Mod:select(LServer, JidRequestor, JidArchive, Query, MsgType). msg_to_el(#archive_msg{timestamp = TS, packet = Pkt1, nick = Nick, peer = Peer}, MsgType, JidRequestor, #jid{lserver = LServer} = JidArchive) -> Pkt2 = maybe_update_from_to(Pkt1, JidRequestor, JidArchive, Peer, MsgType, Nick), - Pkt3 = #xmlel{name = <<"forwarded">>, - attrs = [{<<"xmlns">>, ?NS_FORWARD}], - children = [fxml:replace_tag_attr( - <<"xmlns">>, <<"jabber:client">>, Pkt2)]}, - jlib:add_delay_info(Pkt3, LServer, TS). + #forwarded{sub_els = [Pkt2], + delay = #delay{stamp = TS, from = jid:make(LServer)}}. -maybe_update_from_to(#xmlel{children = Els} = Pkt, JidRequestor, JidArchive, +maybe_update_from_to(#message{sub_els = Els} = Pkt, JidRequestor, JidArchive, Peer, {groupchat, Role, #state{config = #config{anonymous = Anon}}}, Nick) -> @@ -919,18 +835,13 @@ maybe_update_from_to(#xmlel{children = Els} = Pkt, JidRequestor, JidArchive, end, Items = case ExposeJID of true -> - [#xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_MUC_USER}], - children = - [#xmlel{name = <<"item">>, - attrs = [{<<"jid">>, - jid:to_string(Peer)}]}]}]; + [#muc_user{items = [#muc_item{jid = Peer}]}]; false -> [] end, - Pkt1 = Pkt#xmlel{children = Items ++ Els}, - Pkt2 = jlib:replace_from(jid:replace_resource(JidArchive, Nick), Pkt1), - jlib:remove_attr(<<"to">>, Pkt2); + Pkt#message{from = jid:replace_resource(JidArchive, Nick), + to = undefined, + sub_els = Items ++ Els}; maybe_update_from_to(Pkt, _JidRequestor, _JidArchive, _Peer, chat, _Nick) -> Pkt. @@ -966,62 +877,46 @@ is_bare_copy(#jid{luser = U, lserver = S, lresource = R}, To) -> false end. -send(From, To, Msgs, RSM, Count, IsComplete, #iq{sub_el = SubEl} = IQ) -> - QID = fxml:get_tag_attr_s(<<"queryid">>, SubEl), - NS = fxml:get_tag_attr_s(<<"xmlns">>, SubEl), - QIDAttr = if QID /= <<>> -> - [{<<"queryid">>, QID}]; - true -> - [] - end, - CompleteAttr = if NS == ?NS_MAM_TMP -> - []; - NS == ?NS_MAM_0; NS == ?NS_MAM_1 -> - [{<<"complete">>, jlib:atom_to_binary(IsComplete)}] - end, +-spec send([{binary(), integer(), xmlel()}], + non_neg_integer(), boolean(), iq()) -> iq() | ignore. +send(Msgs, Count, IsComplete, + #iq{from = From, to = To, + sub_els = [#mam_query{id = QID, xmlns = NS}]} = IQ) -> Els = lists:map( fun({ID, _IDInt, El}) -> - #xmlel{name = <<"message">>, - children = [#xmlel{name = <<"result">>, - attrs = [{<<"xmlns">>, NS}, - {<<"id">>, ID}|QIDAttr], - children = [El]}]} + #message{sub_els = [#mam_result{xmlns = NS, + id = ID, + queryid = QID, + sub_els = [El]}]} end, Msgs), - RSMOut = make_rsm_out(Msgs, RSM, Count, QIDAttr ++ CompleteAttr, NS), + RSMOut = make_rsm_out(Msgs, Count), + Result = if NS == ?NS_MAM_TMP -> + #mam_query{xmlns = NS, id = QID, rsm = RSMOut}; + true -> + #mam_fin{id = QID, rsm = RSMOut, complete = IsComplete} + end, if NS == ?NS_MAM_TMP; NS == ?NS_MAM_1 -> lists:foreach( fun(El) -> ejabberd_router:route(To, From, El) end, Els), - IQ#iq{type = result, sub_el = RSMOut}; + xmpp:make_iq_result(IQ, Result); NS == ?NS_MAM_0 -> - ejabberd_router:route( - To, From, jlib:iq_to_xml(IQ#iq{type = result, sub_el = []})), + ejabberd_router:route(To, From, xmpp:make_iq_result(IQ)), lists:foreach( fun(El) -> ejabberd_router:route(To, From, El) end, Els), - ejabberd_router:route( - To, From, #xmlel{name = <<"message">>, - children = RSMOut}), + ejabberd_router:route(To, From, #message{sub_els = [Result]}), ignore end. -make_rsm_out([], _, Count, Attrs, NS) -> - Tag = if NS == ?NS_MAM_TMP -> <<"query">>; - true -> <<"fin">> - end, - [#xmlel{name = Tag, attrs = [{<<"xmlns">>, NS}|Attrs], - children = jlib:rsm_encode(#rsm_out{count = Count})}]; -make_rsm_out([{FirstID, _, _}|_] = Msgs, _, Count, Attrs, NS) -> +-spec make_rsm_out([{binary(), integer(), xmlel()}], non_neg_integer()) -> rsm_set(). +make_rsm_out([], Count) -> + #rsm_set{count = Count}; +make_rsm_out([{FirstID, _, _}|_] = Msgs, Count) -> {LastID, _, _} = lists:last(Msgs), - Tag = if NS == ?NS_MAM_TMP -> <<"query">>; - true -> <<"fin">> - end, - [#xmlel{name = Tag, attrs = [{<<"xmlns">>, NS}|Attrs], - children = jlib:rsm_encode( - #rsm_out{first = FirstID, count = Count, - last = LastID})}]. + #rsm_set{first = #rsm_first{data = FirstID}, last = LastID, count = Count}. filter_by_max(Msgs, undefined) -> {Msgs, true}; @@ -1030,23 +925,24 @@ filter_by_max(Msgs, Len) when is_integer(Len), Len >= 0 -> filter_by_max(_Msgs, _Junk) -> {[], true}. +-spec limit_max(rsm_set(), binary()) -> rsm_set(). limit_max(RSM, ?NS_MAM_TMP) -> RSM; % XEP-0313 v0.2 doesn't require clients to support RSM. -limit_max(#rsm_in{max = Max} = RSM, _NS) when not is_integer(Max) -> - RSM#rsm_in{max = ?DEF_PAGE_SIZE}; -limit_max(#rsm_in{max = Max} = RSM, _NS) when Max > ?MAX_PAGE_SIZE -> - RSM#rsm_in{max = ?MAX_PAGE_SIZE}; +limit_max(#rsm_set{max = Max} = RSM, _NS) when not is_integer(Max) -> + RSM#rsm_set{max = ?DEF_PAGE_SIZE}; +limit_max(#rsm_set{max = Max} = RSM, _NS) when Max > ?MAX_PAGE_SIZE -> + RSM#rsm_set{max = ?MAX_PAGE_SIZE}; limit_max(RSM, _NS) -> RSM. match_interval(Now, Start, End) -> (Now >= Start) and (Now =< End). -match_rsm(Now, #rsm_in{id = ID, direction = aft}) when ID /= <<"">> -> - Now1 = (catch usec_to_now(jlib:binary_to_integer(ID))), +match_rsm(Now, #rsm_set{'after' = ID}) when is_binary(ID), ID /= <<"">> -> + Now1 = (catch usec_to_now(binary_to_integer(ID))), Now > Now1; -match_rsm(Now, #rsm_in{id = ID, direction = before}) when ID /= <<"">> -> - Now1 = (catch usec_to_now(jlib:binary_to_integer(ID))), +match_rsm(Now, #rsm_set{before = ID}) when is_binary(ID), ID /= <<"">> -> + Now1 = (catch usec_to_now(binary_to_integer(ID))), Now < Now1; match_rsm(_Now, _) -> true. @@ -1066,15 +962,10 @@ datetime_to_now(DateTime, USecs) -> calendar:datetime_to_gregorian_seconds({{1970, 1, 1}, {0, 0, 0}}), {Seconds div 1000000, Seconds rem 1000000, USecs}. -get_jids(Els) -> - lists:flatmap( - fun(#xmlel{name = <<"jid">>} = El) -> - J = jid:from_string(fxml:get_tag_cdata(El)), - [jid:tolower(jid:remove_resource(J)), - jid:tolower(J)]; - (_) -> - [] - end, Els). +get_jids(undefined) -> + []; +get_jids(Js) -> + [jid:tolower(jid:remove_resource(J)) || J <- Js]. get_commands_spec() -> [#ejabberd_commands{name = delete_old_mam_messages, tags = [purge], diff --git a/src/mod_mam_mnesia.erl b/src/mod_mam_mnesia.erl index be14d0fff..cbe7c336c 100644 --- a/src/mod_mam_mnesia.erl +++ b/src/mod_mam_mnesia.erl @@ -12,10 +12,10 @@ %% API -export([init/2, remove_user/2, remove_room/3, delete_old_messages/3, - extended_fields/0, store/7, write_prefs/4, get_prefs/2, select/8]). + extended_fields/0, store/7, write_prefs/4, get_prefs/2, select/5]). -include_lib("stdlib/include/ms_transform.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("logger.hrl"). -include("mod_mam.hrl"). @@ -132,7 +132,8 @@ get_prefs(LUser, LServer) -> select(_LServer, JidRequestor, #jid{luser = LUser, lserver = LServer} = JidArchive, - Start, End, With, RSM, MsgType) -> + #mam_query{start = Start, 'end' = End, + with = With, rsm = RSM}, MsgType) -> MS = make_matchspec(LUser, LServer, Start, End, With), Msgs = mnesia:dirty_select(archive_msg, MS), SortedMsgs = lists:keysort(#archive_msg.timestamp, Msgs), @@ -174,7 +175,7 @@ make_matchspec(LUser, LServer, Start, End, {_, _, _} = With) -> Peer == With -> Msg end); -make_matchspec(LUser, LServer, Start, End, none) -> +make_matchspec(LUser, LServer, Start, End, undefined) -> ets:fun2ms( fun(#archive_msg{timestamp = TS, us = US, @@ -184,28 +185,27 @@ make_matchspec(LUser, LServer, Start, End, none) -> Msg end). -filter_by_rsm(Msgs, none) -> +filter_by_rsm(Msgs, undefined) -> {Msgs, true}; -filter_by_rsm(_Msgs, #rsm_in{max = Max}) when Max < 0 -> +filter_by_rsm(_Msgs, #rsm_set{max = Max}) when Max < 0 -> {[], true}; -filter_by_rsm(Msgs, #rsm_in{max = Max, direction = Direction, id = ID}) -> - NewMsgs = case Direction of - aft when ID /= <<"">> -> +filter_by_rsm(Msgs, #rsm_set{max = Max, before = Before, 'after' = After}) -> + NewMsgs = if is_binary(After), After /= <<"">> -> lists:filter( fun(#archive_msg{id = I}) -> - ?BIN_GREATER_THAN(I, ID) + ?BIN_GREATER_THAN(I, After) end, Msgs); - before when ID /= <<"">> -> + is_binary(Before), Before /= <<"">> -> lists:foldl( fun(#archive_msg{id = I} = Msg, Acc) - when ?BIN_LESS_THAN(I, ID) -> + when ?BIN_LESS_THAN(I, Before) -> [Msg|Acc]; (_, Acc) -> Acc end, [], Msgs); - before when ID == <<"">> -> + is_binary(Before), Before == <<"">> -> lists:reverse(Msgs); - _ -> + true -> Msgs end, filter_by_max(NewMsgs, Max). diff --git a/src/mod_mam_sql.erl b/src/mod_mam_sql.erl index 20ed8d4f1..6e5231989 100644 --- a/src/mod_mam_sql.erl +++ b/src/mod_mam_sql.erl @@ -14,10 +14,10 @@ %% API -export([init/2, remove_user/2, remove_room/3, delete_old_messages/3, - extended_fields/0, store/7, write_prefs/4, get_prefs/2, select/8]). + extended_fields/0, store/7, write_prefs/4, get_prefs/2, select/5]). -include_lib("stdlib/include/ms_transform.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_mam.hrl"). -include("logger.hrl"). -include("ejabberd_sql_pt.hrl"). @@ -51,9 +51,7 @@ delete_old_messages(ServerHost, TimeStamp, Type) -> ok. extended_fields() -> - [#xmlel{name = <<"field">>, - attrs = [{<<"type">>, <<"text-single">>}, - {<<"var">>, <<"withtext">>}]}]. + [#xdata_field{type = 'text-single', var = <<"withtext">>}]. store(Pkt, LServer, {LUser, LHost}, Type, Peer, Nick, _Dir) -> TSinteger = p1_time_compat:system_time(micro_seconds), @@ -126,13 +124,12 @@ get_prefs(LUser, LServer) -> end. select(LServer, JidRequestor, #jid{luser = LUser} = JidArchive, - Start, End, With, RSM, MsgType) -> + MAMQuery, MsgType) -> User = case MsgType of chat -> LUser; {groupchat, _Role, _MUCState} -> jid:to_string(JidArchive) end, - {Query, CountQuery} = make_sql_query(User, LServer, - Start, End, With, RSM), + {Query, CountQuery} = make_sql_query(User, LServer, MAMQuery), % TODO from XEP-0313 v0.2: "To conserve resources, a server MAY place a % reasonable limit on how many stanzas may be pushed to a client in one % request. If a query returns a number of stanzas greater than this limit @@ -142,10 +139,7 @@ select(LServer, JidRequestor, #jid{luser = LUser} = JidArchive, case {ejabberd_sql:sql_query(LServer, Query), ejabberd_sql:sql_query(LServer, CountQuery)} of {{selected, _, Res}, {selected, _, [[Count]]}} -> - {Max, Direction} = case RSM of - #rsm_in{max = M, direction = D} -> {M, D}; - _ -> {undefined, undefined} - end, + {Max, Direction, _} = get_max_direction_id(MAMQuery#mam_query.rsm), {Res1, IsComplete} = if Max >= 0 andalso Max /= undefined andalso length(Res) > Max -> if Direction == before -> @@ -200,15 +194,10 @@ usec_to_now(Int) -> Sec = Secs rem 1000000, {MSec, Sec, USec}. -make_sql_query(User, LServer, Start, End, With, RSM) -> - {Max, Direction, ID} = case RSM of - #rsm_in{} -> - {RSM#rsm_in.max, - RSM#rsm_in.direction, - RSM#rsm_in.id}; - none -> - {none, none, <<>>} - end, +make_sql_query(User, LServer, + #mam_query{start = Start, 'end' = End, with = With, + withtext = WithText, rsm = RSM}) -> + {Max, Direction, ID} = get_max_direction_id(RSM), ODBCType = ejabberd_config:get_option( {sql_type, LServer}, ejabberd_sql:opt_type(sql_type)), @@ -228,12 +217,16 @@ make_sql_query(User, LServer, Start, End, With, RSM) -> true -> [] end, - WithClause = case With of - {text, <<>>} -> - []; - {text, Txt} -> - [<<" and match (txt) against ('">>, - Escape(Txt), <<"')">>]; + WithTextClause = case WithText of + {text, <<>>} -> + []; + {text, Txt} -> + [<<" and match (txt) against ('">>, + Escape(Txt), <<"')">>]; + undefined -> + [] + end, + WithClause = case catch jid:tolower(With) of {_, _, <<>>} -> [<<" and bare_peer='">>, Escape(jid:to_string(With)), @@ -242,7 +235,7 @@ make_sql_query(User, LServer, Start, End, With, RSM) -> [<<" and peer='">>, Escape(jid:to_string(With)), <<"'">>]; - none -> + _ -> [] end, PageClause = case catch jlib:binary_to_integer(ID) of @@ -250,7 +243,7 @@ make_sql_query(User, LServer, Start, End, With, RSM) -> case Direction of before -> [<<" AND timestamp < ">>, ID]; - aft -> + 'after' -> [<<" AND timestamp > ">>, ID]; _ -> [] @@ -276,7 +269,7 @@ make_sql_query(User, LServer, Start, End, With, RSM) -> Query = [<<"SELECT ">>, TopClause, <<" timestamp, xml, peer, kind, nick" " FROM archive WHERE username='">>, - SUser, <<"'">>, WithClause, StartClause, EndClause, + SUser, <<"'">>, WithClause, WithTextClause, StartClause, EndClause, PageClause], QueryPage = @@ -294,4 +287,20 @@ make_sql_query(User, LServer, Start, End, With, RSM) -> end, {QueryPage, [<<"SELECT COUNT(*) FROM archive WHERE username='">>, - SUser, <<"'">>, WithClause, StartClause, EndClause, <<";">>]}. + SUser, <<"'">>, WithClause, WithTextClause, StartClause, EndClause, <<";">>]}. + +-spec get_max_direction_id(rsm_set() | undefined) -> + {integer() | undefined, + before | 'after' | undefined, + binary()}. +get_max_direction_id(RSM) -> + case RSM of + #rsm_set{max = Max, before = Before} when is_binary(Before) -> + {Max, before, Before}; + #rsm_set{max = Max, 'after' = After} when is_binary(After) -> + {Max, 'after', After}; + #rsm_set{max = Max} -> + {Max, undefined, <<>>}; + _ -> + {undefined, undefined, <<>>} + end. diff --git a/src/mod_muc.erl b/src/mod_muc.erl index a86f580d3..294456ee2 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -43,7 +43,12 @@ forget_room/3, create_room/5, shutdown_rooms/1, - process_iq_disco_items/4, + process_disco_info/1, + process_disco_items/1, + process_vcard/1, + process_register/1, + process_muc_unique/1, + process_mucsub/1, broadcast_service_message/2, export/1, import/1, @@ -58,7 +63,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_muc.hrl"). -record(state, @@ -154,17 +159,6 @@ forget_room(ServerHost, Host, Name) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:forget_room(LServer, Host, Name). -process_iq_disco_items(Host, From, To, - #iq{lang = Lang} = IQ) -> - Rsm = jlib:rsm_decode(IQ), - DiscoNode = fxml:get_tag_attr_s(<<"node">>, IQ#iq.sub_el), - Res = IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_DISCO_ITEMS}], - children = iq_disco_items(Host, From, Lang, DiscoNode, Rsm)}]}, - ejabberd_router:route(To, From, jlib:iq_to_xml(Res)). - can_use_nick(_ServerHost, _Host, _JID, <<"">>) -> false; can_use_nick(ServerHost, Host, JID, Nick) -> LServer = jid:nameprep(ServerHost), @@ -176,6 +170,8 @@ can_use_nick(ServerHost, Host, JID, Nick) -> %%==================================================================== init([Host, Opts]) -> + IQDisc = gen_mod:get_opt(iqdisc, Opts, fun gen_iq_handler:check_type/1, + one_queue), MyHost = gen_mod:get_opt_host(Host, Opts, <<"conference.@HOST@">>), Mod = gen_mod:db_mod(Host, Opts, ?MODULE), @@ -255,6 +251,18 @@ init([Host, Opts]) -> RoomShaper = gen_mod:get_opt(room_shaper, Opts, fun(A) when is_atom(A) -> A end, none), + gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_REGISTER, + ?MODULE, process_register, IQDisc), + gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_VCARD, + ?MODULE, process_vcard, IQDisc), + gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_MUCSUB, + ?MODULE, process_mucsub, IQDisc), + gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_MUC_UNIQUE, + ?MODULE, process_muc_unique, IQDisc), + gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_INFO, + ?MODULE, process_disco_info, IQDisc), + gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_ITEMS, + ?MODULE, process_disco_items, IQDisc), ejabberd_router:register_route(MyHost, Host), load_permanent_rooms(MyHost, Host, {Access, AccessCreate, AccessAdmin, AccessPersistent}, @@ -314,8 +322,14 @@ handle_info({mnesia_system_event, {mnesia_down, Node}}, State) -> {noreply, State}; handle_info(_Info, State) -> {noreply, State}. -terminate(_Reason, State) -> - ejabberd_router:unregister_route(State#state.host), +terminate(_Reason, #state{host = MyHost}) -> + ejabberd_router:unregister_route(MyHost), + gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_REGISTER), + gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_VCARD), + gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_MUCSUB), + gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_MUC_UNIQUE), + gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_INFO), + gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_ITEMS), ok. code_change(_OldVsn, State, _Extra) -> {ok, State}. @@ -331,197 +345,162 @@ do_route(Host, ServerHost, Access, HistorySize, RoomShaper, allow -> do_route1(Host, ServerHost, Access, HistorySize, RoomShaper, From, To, Packet, DefRoomOpts); - _ -> - #xmlel{attrs = Attrs} = Packet, - Lang = fxml:get_attr_s(<<"xml:lang">>, Attrs), + deny -> + Lang = xmpp:get_lang(Packet), ErrText = <<"Access denied by service policy">>, - Err = jlib:make_error_reply(Packet, - ?ERRT_FORBIDDEN(Lang, ErrText)), - ejabberd_router:route_error(To, From, Err, Packet) + Err = xmpp:err_forbidden(ErrText, Lang), + ejabberd_router:route_error(To, From, Packet, Err) end. - +do_route1(_Host, _ServerHost, _Access, _HistorySize, _RoomShaper, + From, #jid{luser = <<"">>, lresource = <<"">>} = To, + #iq{} = IQ, _DefRoomOpts) -> + ejabberd_local:process_iq(From, To, IQ); +do_route1(Host, ServerHost, Access, _HistorySize, _RoomShaper, + From, #jid{luser = <<"">>, lresource = <<"">>} = To, + #message{lang = Lang, body = Body, type = Type} = Packet, _) -> + {_AccessRoute, _AccessCreate, AccessAdmin, _AccessPersistent} = Access, + if Type == error -> + ok; + true -> + case acl:match_rule(ServerHost, AccessAdmin, From) of + allow -> + Msg = xmpp:get_text(Body), + broadcast_service_message(Host, Msg); + deny -> + ErrText = <<"Only service administrators are allowed " + "to send service messages">>, + Err = xmpp:make_error( + Packet, xmpp:err_forbidden(ErrText, Lang)), + ejabberd_router:route(To, From, Err) + end + end; +do_route1(_Host, _ServerHost, _Access, _HistorySize, _RoomShaper, + From, #jid{luser = <<"">>} = To, Packet, _DefRoomOpts) -> + Err = xmpp:err_item_not_found(), + ejabberd_router:route_error(To, From, Packet, Err); do_route1(Host, ServerHost, Access, HistorySize, RoomShaper, From, To, Packet, DefRoomOpts) -> - {_AccessRoute, AccessCreate, AccessAdmin, _AccessPersistent} = Access, + {_AccessRoute, AccessCreate, _AccessAdmin, _AccessPersistent} = Access, {Room, _, Nick} = jid:tolower(To), - #xmlel{name = Name, attrs = Attrs} = Packet, - case Room of - <<"">> -> - case Nick of - <<"">> -> - case Name of - <<"iq">> -> - case jlib:iq_query_info(Packet) of - #iq{type = get, xmlns = (?NS_DISCO_INFO) = XMLNS, - sub_el = _SubEl, lang = Lang} = - IQ -> - Info = ejabberd_hooks:run_fold(disco_info, - ServerHost, [], - [ServerHost, ?MODULE, - <<"">>, <<"">>]), - Res = IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = - [{<<"xmlns">>, XMLNS}], - children = - iq_disco_info( - ServerHost, Lang) ++ - Info}]}, - ejabberd_router:route(To, From, - jlib:iq_to_xml(Res)); - #iq{type = get, xmlns = ?NS_DISCO_ITEMS} = IQ -> - spawn(?MODULE, process_iq_disco_items, - [Host, From, To, IQ]); - #iq{type = get, xmlns = (?NS_REGISTER) = XMLNS, - lang = Lang, sub_el = _SubEl} = - IQ -> - Res = IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = - [{<<"xmlns">>, XMLNS}], - children = - iq_get_register_info(ServerHost, - Host, - From, - Lang)}]}, - ejabberd_router:route(To, From, - jlib:iq_to_xml(Res)); - #iq{type = set, xmlns = (?NS_REGISTER) = XMLNS, - lang = Lang, sub_el = SubEl} = - IQ -> - case process_iq_register_set(ServerHost, Host, From, - SubEl, Lang) - of - {result, IQRes} -> - Res = IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = - [{<<"xmlns">>, - XMLNS}], - children = IQRes}]}, - ejabberd_router:route(To, From, - jlib:iq_to_xml(Res)); - {error, Error} -> - Err = jlib:make_error_reply(Packet, Error), - ejabberd_router:route(To, From, Err) - end; - #iq{type = get, xmlns = (?NS_VCARD) = XMLNS, - lang = Lang, sub_el = _SubEl} = - IQ -> - Res = IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"vCard">>, - attrs = - [{<<"xmlns">>, XMLNS}], - children = - iq_get_vcard(Lang)}]}, - ejabberd_router:route(To, From, - jlib:iq_to_xml(Res)); - #iq{type = get, xmlns = ?NS_MUCSUB, - sub_el = #xmlel{name = <<"subscriptions">>} = SubEl} = IQ -> - RoomJIDs = get_subscribed_rooms(ServerHost, Host, From), - Subs = lists:map( - fun(J) -> - #xmlel{name = <<"subscription">>, - attrs = [{<<"jid">>, - jid:to_string(J)}]} - end, RoomJIDs), - Res = IQ#iq{type = result, - sub_el = [SubEl#xmlel{children = Subs}]}, - ejabberd_router:route(To, From, jlib:iq_to_xml(Res)); - #iq{type = get, xmlns = ?NS_MUC_UNIQUE} = IQ -> - Res = IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"unique">>, - attrs = - [{<<"xmlns">>, - ?NS_MUC_UNIQUE}], - children = - [iq_get_unique(From)]}]}, - ejabberd_router:route(To, From, - jlib:iq_to_xml(Res)); - #iq{} -> - Err = jlib:make_error_reply(Packet, - ?ERR_FEATURE_NOT_IMPLEMENTED), - ejabberd_router:route(To, From, Err); - _ -> ok - end; - <<"message">> -> - case fxml:get_attr_s(<<"type">>, Attrs) of - <<"error">> -> ok; - _ -> - case acl:match_rule(ServerHost, AccessAdmin, From) - of - allow -> - Msg = fxml:get_path_s(Packet, - [{elem, <<"body">>}, - cdata]), - broadcast_service_message(Host, Msg); - _ -> - Lang = fxml:get_attr_s(<<"xml:lang">>, Attrs), - ErrText = - <<"Only service administrators are allowed " - "to send service messages">>, - Err = jlib:make_error_reply(Packet, - ?ERRT_FORBIDDEN(Lang, - ErrText)), - ejabberd_router:route(To, From, Err) - end - end; - <<"presence">> -> ok - end; - _ -> - case fxml:get_attr_s(<<"type">>, Attrs) of - <<"error">> -> ok; - <<"result">> -> ok; - _ -> - Err = jlib:make_error_reply(Packet, - ?ERR_ITEM_NOT_FOUND), - ejabberd_router:route(To, From, Err) - end - end; - _ -> - case mnesia:dirty_read(muc_online_room, {Room, Host}) of - [] -> - Type = fxml:get_attr_s(<<"type">>, Attrs), - case {Name, Type} of - {<<"presence">>, <<"">>} -> - case check_user_can_create_room(ServerHost, - AccessCreate, From, Room) and - check_create_roomid(ServerHost, Room) of - true -> - {ok, Pid} = start_new_room(Host, ServerHost, Access, - Room, HistorySize, - RoomShaper, From, Nick, DefRoomOpts), - register_room(Host, Room, Pid), - mod_muc_room:route(Pid, From, Nick, Packet), - ok; - false -> - Lang = fxml:get_attr_s(<<"xml:lang">>, Attrs), - ErrText = <<"Room creation is denied by service policy">>, - Err = jlib:make_error_reply( - Packet, ?ERRT_FORBIDDEN(Lang, ErrText)), - ejabberd_router:route(To, From, Err) - end; - _ -> - Lang = fxml:get_attr_s(<<"xml:lang">>, Attrs), - ErrText = <<"Conference room does not exist">>, - Err = jlib:make_error_reply(Packet, - ?ERRT_ITEM_NOT_FOUND(Lang, ErrText)), + case mnesia:dirty_read(muc_online_room, {Room, Host}) of + [] -> + case Packet of + #presence{type = available, lang = Lang} -> + case check_user_can_create_room( + ServerHost, AccessCreate, From, Room) and + check_create_roomid(ServerHost, Room) of + true -> + {ok, Pid} = start_new_room( + Host, ServerHost, Access, + Room, HistorySize, + RoomShaper, From, Nick, DefRoomOpts), + register_room(Host, Room, Pid), + mod_muc_room:route(Pid, From, Nick, Packet), + ok; + false -> + ErrText = <<"Room creation is denied by service policy">>, + Err = xmpp:make_error( + Packet, xmpp:err_forbidden(ErrText, Lang)), ejabberd_router:route(To, From, Err) end; - [R] -> - Pid = R#muc_online_room.pid, - ?DEBUG("MUC: send to process ~p~n", [Pid]), - mod_muc_room:route(Pid, From, Nick, Packet), - ok - end + _ -> + Lang = xmpp:get_lang(Packet), + ErrText = <<"Conference room does not exist">>, + Err = xmpp:err_item_not_found(ErrText, Lang), + ejabberd_router:route_error(To, From, Packet, Err) + end; + [R] -> + Pid = R#muc_online_room.pid, + ?DEBUG("MUC: send to process ~p~n", [Pid]), + mod_muc_room:route(Pid, From, Nick, Packet), + ok end. +-spec process_vcard(iq()) -> iq(). +process_vcard(#iq{type = get, lang = Lang} = IQ) -> + Desc = translate:translate(Lang, <<"ejabberd MUC module">>), + Copyright = <<"Copyright (c) 2003-2016 ProcessOne">>, + xmpp:make_iq_result( + IQ, #vcard_temp{fn = <<"ejabberd/mod_muc">>, + url = ?EJABBERD_URI, + desc = <>}); +process_vcard(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)). + +-spec process_register(iq()) -> iq(). +process_register(#iq{type = get, from = From, to = To, lang = Lang} = IQ) -> + Host = To#jid.lserver, + ServerHost = ejabberd_router:host_of_route(Host), + xmpp:make_iq_result(IQ, iq_get_register_info(ServerHost, Host, From, Lang)); +process_register(#iq{type = set, from = From, to = To, + lang = Lang, sub_els = [El]} = IQ) -> + Host = To#jid.lserver, + ServerHost = ejabberd_router:host_of_route(Host), + case process_iq_register_set(ServerHost, Host, From, El, Lang) of + {result, Result} -> + xmpp:make_iq_result(IQ, Result); + {error, Err} -> + xmpp:make_error(IQ, Err) + end. + +-spec process_disco_info(iq()) -> iq(). +process_disco_info(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_disco_info(#iq{type = get, to = To, lang = Lang, + sub_els = [#disco_info{node = undefined}]} = IQ) -> + ServerHost = ejabberd_router:host_of_route(To#jid.lserver), + X = ejabberd_hooks:run_fold(disco_info, ServerHost, [], + [ServerHost, ?MODULE, undefined, Lang]), + MAMFeatures = case gen_mod:is_loaded(ServerHost, mod_mam) of + true -> [?NS_MAM_TMP, ?NS_MAM_0, ?NS_MAM_1]; + false -> [] + end, + Features = [?NS_DISCO_INFO, ?NS_DISCO_ITEMS, + ?NS_REGISTER, ?NS_MUC, ?NS_RSM, + ?NS_VCARD, ?NS_MUCSUB, ?NS_MUC_UNIQUE | MAMFeatures], + Identity = #identity{category = <<"conference">>, + type = <<"text">>, + name = translate:translate(Lang, <<"Chatrooms">>)}, + xmpp:make_iq_result( + IQ, #disco_info{features = Features, + identities = [Identity], + xdata = X}); +process_disco_info(#iq{type = get, lang = Lang} = IQ) -> + xmpp:make_error(IQ, xmpp:err_item_not_found(<<"No info available">>, Lang)). + +-spec process_disco_items(iq()) -> iq(). +process_disco_items(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_disco_items(#iq{type = get, from = From, to = To, lang = Lang, + sub_els = [#disco_items{node = Node, rsm = RSM}]} = IQ) -> + Host = To#jid.lserver, + xmpp:make_iq_result( + IQ, #disco_items{node = Node, + items = iq_disco_items(Host, From, Lang, Node, RSM)}). + +-spec process_muc_unique(iq()) -> iq(). +process_muc_unique(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_muc_unique(#iq{from = From, type = get} = IQ) -> + Name = p1_sha:sha(term_to_binary([From, p1_time_compat:timestamp(), + randoms:get_string()])), + xmpp:make_iq_result(IQ, #muc_unique{name = Name}). + +-spec process_mucsub(iq()) -> iq(). +process_mucsub(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_mucsub(#iq{type = get, from = From, to = To} = IQ) -> + Host = To#jid.lserver, + ServerHost = ejabberd_router:host_of_route(Host), + RoomJIDs = get_subscribed_rooms(ServerHost, Host, From), + xmpp:make_iq_result(IQ, #muc_subscriptions{list = RoomJIDs}). + check_user_can_create_room(ServerHost, AccessCreate, From, _RoomID) -> case acl:match_rule(ServerHost, AccessCreate, From) of @@ -583,61 +562,21 @@ register_room(Host, Room, Pid) -> end, mnesia:transaction(F). - -iq_disco_info(ServerHost, Lang) -> - [#xmlel{name = <<"identity">>, - attrs = - [{<<"category">>, <<"conference">>}, - {<<"type">>, <<"text">>}, - {<<"name">>, - translate:translate(Lang, <<"Chatrooms">>)}], - children = []}, - #xmlel{name = <<"feature">>, - attrs = [{<<"var">>, ?NS_DISCO_INFO}], children = []}, - #xmlel{name = <<"feature">>, - attrs = [{<<"var">>, ?NS_DISCO_ITEMS}], children = []}, - #xmlel{name = <<"feature">>, - attrs = [{<<"var">>, ?NS_MUC}], children = []}, - #xmlel{name = <<"feature">>, - attrs = [{<<"var">>, ?NS_MUC_UNIQUE}], children = []}, - #xmlel{name = <<"feature">>, - attrs = [{<<"var">>, ?NS_REGISTER}], children = []}, - #xmlel{name = <<"feature">>, - attrs = [{<<"var">>, ?NS_RSM}], children = []}, - #xmlel{name = <<"feature">>, - attrs = [{<<"var">>, ?NS_MUCSUB}], children = []}, - #xmlel{name = <<"feature">>, - attrs = [{<<"var">>, ?NS_VCARD}], children = []}] ++ - case gen_mod:is_loaded(ServerHost, mod_mam) of - true -> - [#xmlel{name = <<"feature">>, - attrs = [{<<"var">>, ?NS_MAM_TMP}]}, - #xmlel{name = <<"feature">>, - attrs = [{<<"var">>, ?NS_MAM_0}]}, - #xmlel{name = <<"feature">>, - attrs = [{<<"var">>, ?NS_MAM_1}]}]; - false -> - [] - end. - -iq_disco_items(Host, From, Lang, <<>>, none) -> +iq_disco_items(Host, From, Lang, undefined, undefined) -> Rooms = get_vh_rooms(Host), case erlang:length(Rooms) < ?MAX_ROOMS_DISCOITEMS of true -> iq_disco_items_list(Host, Rooms, {get_disco_item, all, From, Lang}); false -> - iq_disco_items(Host, From, Lang, <<"nonemptyrooms">>, none) + iq_disco_items(Host, From, Lang, <<"nonemptyrooms">>, undefined) end; -iq_disco_items(Host, From, Lang, <<"nonemptyrooms">>, none) -> - XmlEmpty = #xmlel{name = <<"item">>, - attrs = - [{<<"jid">>, <<"conference.localhost">>}, - {<<"node">>, <<"emptyrooms">>}, - {<<"name">>, translate:translate(Lang, <<"Empty Rooms">>)}], - children = []}, +iq_disco_items(Host, From, Lang, <<"nonemptyrooms">>, undefined) -> + Empty = #disco_item{jid = jid:make(<<"conference.localhost">>), + node = <<"emptyrooms">>, + name = translate:translate(Lang, <<"Empty Rooms">>)}, Query = {get_disco_item, only_non_empty, From, Lang}, - [XmlEmpty | iq_disco_items_list(Host, get_vh_rooms(Host), Query)]; -iq_disco_items(Host, From, Lang, <<"emptyrooms">>, none) -> + [Empty | iq_disco_items_list(Host, get_vh_rooms(Host), Query)]; +iq_disco_items(Host, From, Lang, <<"emptyrooms">>, undefined) -> iq_disco_items_list(Host, get_vh_rooms(Host), {get_disco_item, 0, From, Lang}); iq_disco_items(Host, From, Lang, _DiscoNode, Rsm) -> {Rooms, RsmO} = get_vh_rooms(Host, Rsm), @@ -645,62 +584,55 @@ iq_disco_items(Host, From, Lang, _DiscoNode, Rsm) -> iq_disco_items_list(Host, Rooms, {get_disco_item, all, From, Lang}) ++ RsmOut. iq_disco_items_list(Host, Rooms, Query) -> - lists:zf(fun (#muc_online_room{name_host = - {Name, _Host}, - pid = Pid}) -> - case catch gen_fsm:sync_send_all_state_event(Pid, - Query, - 100) - of - {item, Desc} -> - flush(), - {true, - #xmlel{name = <<"item">>, - attrs = - [{<<"jid">>, - jid:to_string({Name, Host, - <<"">>})}, - {<<"name">>, Desc}], - children = []}}; - _ -> false - end - end, Rooms). + lists:zf( + fun(#muc_online_room{name_host = {Name, _Host}, pid = Pid}) -> + case catch gen_fsm:sync_send_all_state_event(Pid, Query, 100) of + {item, Desc} -> + flush(), + {true, #disco_item{jid = jid:make(Name, Host), + name = Desc}}; + _ -> + false + end + end, Rooms). -get_vh_rooms(Host, #rsm_in{max=M, direction=Direction, id=I, index=Index})-> - AllRooms = lists:sort(get_vh_rooms(Host)), - Count = erlang:length(AllRooms), - Guard = case Direction of - _ when Index =/= undefined -> [{'==', {element, 2, '$1'}, Host}]; - aft -> [{'==', {element, 2, '$1'}, Host}, {'>=',{element, 1, '$1'} ,I}]; - before when I =/= []-> [{'==', {element, 2, '$1'}, Host}, {'=<',{element, 1, '$1'} ,I}]; - _ -> [{'==', {element, 2, '$1'}, Host}] - end, - L = lists:sort( - mnesia:dirty_select(muc_online_room, - [{#muc_online_room{name_host = '$1', _ = '_'}, - Guard, - ['$_']}])), - L2 = if - Index == undefined andalso Direction == before -> - lists:reverse(lists:sublist(lists:reverse(L), 1, M)); - Index == undefined -> - lists:sublist(L, 1, M); - Index > Count orelse Index < 0 -> - []; - true -> - lists:sublist(L, Index+1, M) - end, - if L2 == [] -> {L2, #rsm_out{count = Count}}; - true -> - H = hd(L2), - NewIndex = get_room_pos(H, AllRooms), - T = lists:last(L2), - {F, _} = H#muc_online_room.name_host, - {Last, _} = T#muc_online_room.name_host, - {L2, - #rsm_out{first = F, last = Last, count = Count, - index = NewIndex}} - end. +get_vh_rooms(_, _) -> + todo. +%% get_vh_rooms(Host, #rsm_in{max=M, direction=Direction, id=I, index=Index})-> +%% AllRooms = lists:sort(get_vh_rooms(Host)), +%% Count = erlang:length(AllRooms), +%% Guard = case Direction of +%% _ when Index =/= undefined -> [{'==', {element, 2, '$1'}, Host}]; +%% aft -> [{'==', {element, 2, '$1'}, Host}, {'>=',{element, 1, '$1'} ,I}]; +%% before when I =/= []-> [{'==', {element, 2, '$1'}, Host}, {'=<',{element, 1, '$1'} ,I}]; +%% _ -> [{'==', {element, 2, '$1'}, Host}] +%% end, +%% L = lists:sort( +%% mnesia:dirty_select(muc_online_room, +%% [{#muc_online_room{name_host = '$1', _ = '_'}, +%% Guard, +%% ['$_']}])), +%% L2 = if +%% Index == undefined andalso Direction == before -> +%% lists:reverse(lists:sublist(lists:reverse(L), 1, M)); +%% Index == undefined -> +%% lists:sublist(L, 1, M); +%% Index > Count orelse Index < 0 -> +%% []; +%% true -> +%% lists:sublist(L, Index+1, M) +%% end, +%% if L2 == [] -> {L2, #rsm_out{count = Count}}; +%% true -> +%% H = hd(L2), +%% NewIndex = get_room_pos(H, AllRooms), +%% T = lists:last(L2), +%% {F, _} = H#muc_online_room.name_host, +%% {Last, _} = T#muc_online_room.name_host, +%% {L2, +%% #rsm_out{first = F, last = Last, count = Count, +%% index = NewIndex}} +%% end. get_subscribed_rooms(ServerHost, Host, From) -> Rooms = get_rooms(ServerHost, Host), @@ -730,60 +662,32 @@ get_room_pos(Desired, [_ | Rooms], HeadPosition) -> flush() -> receive _ -> flush() after 0 -> ok end. --define(XFIELD(Type, Label, Var, Val), - #xmlel{name = <<"field">>, - attrs = - [{<<"type">>, Type}, - {<<"label">>, translate:translate(Lang, Label)}, - {<<"var">>, Var}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = [{xmlcdata, Val}]}]}). - -iq_get_unique(From) -> - {xmlcdata, - p1_sha:sha(term_to_binary([From, p1_time_compat:timestamp(), - randoms:get_string()]))}. - get_nick(ServerHost, Host, From) -> LServer = jid:nameprep(ServerHost), Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:get_nick(LServer, Host, From). iq_get_register_info(ServerHost, Host, From, Lang) -> - {Nick, Registered} = case get_nick(ServerHost, Host, - From) - of - error -> {<<"">>, []}; - N -> - {N, - [#xmlel{name = <<"registered">>, attrs = [], - children = []}]} + {Nick, Registered} = case get_nick(ServerHost, Host, From) of + error -> {<<"">>, false}; + N -> {N, true} end, - Registered ++ - [#xmlel{name = <<"instructions">>, attrs = [], - children = - [{xmlcdata, - translate:translate(Lang, - <<"You need a client that supports x:data " - "to register the nickname">>)}]}, - #xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_XDATA}, - {<<"type">>, <<"form">>}], - children = - [#xmlel{name = <<"title">>, attrs = [], - children = - [{xmlcdata, - <<(translate:translate(Lang, - <<"Nickname Registration at ">>))/binary, - Host/binary>>}]}, - #xmlel{name = <<"instructions">>, attrs = [], - children = - [{xmlcdata, - translate:translate(Lang, - <<"Enter nickname you want to register">>)}]}, - ?XFIELD(<<"text-single">>, <<"Nickname">>, <<"nick">>, - Nick)]}]. + Title = <<(translate:translate( + Lang, <<"Nickname Registration at ">>))/binary, Host/binary>>, + Inst = translate:translate(Lang, <<"Enter nickname you want to register">>), + Field = #xdata_field{type = 'text-single', + label = translate:translate(Lang, <<"Nickname">>), + var = <<"nick">>, + values = [Nick]}, + X = #xdata{type = form, title = Title, + instructions = [Inst], fields = [Field]}, + #register{nick = Nick, + registered = Registered, + instructions = + translate:translate( + Lang, <<"You need a client that supports x:data " + "to register the nickname">>), + xdata = X}. set_nick(ServerHost, Host, From, Nick) -> LServer = jid:nameprep(ServerHost), @@ -793,66 +697,43 @@ set_nick(ServerHost, Host, From, Nick) -> iq_set_register_info(ServerHost, Host, From, Nick, Lang) -> case set_nick(ServerHost, Host, From, Nick) of - {atomic, ok} -> {result, []}; + {atomic, ok} -> {result, undefined}; {atomic, false} -> ErrText = <<"That nickname is registered by another " "person">>, - {error, ?ERRT_CONFLICT(Lang, ErrText)}; + {error, xmpp:err_conflict(ErrText, Lang)}; _ -> Txt = <<"Database failure">>, - {error, ?ERRT_INTERNAL_SERVER_ERROR(Lang, Txt)} + {error, xmpp:err_internal_server_error(Txt, Lang)} end. -process_iq_register_set(ServerHost, Host, From, SubEl, - Lang) -> - #xmlel{children = Els} = SubEl, - case fxml:get_subtag(SubEl, <<"remove">>) of - false -> - case fxml:remove_cdata(Els) of - [#xmlel{name = <<"x">>} = XEl] -> - case {fxml:get_tag_attr_s(<<"xmlns">>, XEl), - fxml:get_tag_attr_s(<<"type">>, XEl)} - of - {?NS_XDATA, <<"cancel">>} -> {result, []}; - {?NS_XDATA, <<"submit">>} -> - XData = jlib:parse_xdata_submit(XEl), - case XData of - invalid -> - Txt = <<"Incorrect data form">>, - {error, ?ERRT_BAD_REQUEST(Lang, Txt)}; - _ -> - case lists:keysearch(<<"nick">>, 1, XData) of - {value, {_, [Nick]}} when Nick /= <<"">> -> - iq_set_register_info(ServerHost, Host, From, - Nick, Lang); - _ -> - ErrText = - <<"You must fill in field \"Nickname\" " - "in the form">>, - {error, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)} - end - end; - _ -> {error, ?ERR_BAD_REQUEST} - end; - _ -> {error, ?ERR_BAD_REQUEST} - end; - _ -> - iq_set_register_info(ServerHost, Host, From, <<"">>, - Lang) +process_iq_register_set(ServerHost, Host, From, + #register{remove = true}, Lang) -> + iq_set_register_info(ServerHost, Host, From, <<"">>, Lang); +process_iq_register_set(_ServerHost, _Host, _From, + #register{xdata = #xdata{type = cancel}}, _Lang) -> + {result, undefined}; +process_iq_register_set(ServerHost, Host, From, + #register{nick = Nick, xdata = XData}, Lang) -> + case XData of + #xdata{type = submit, fields = Fs} -> + case lists:keyfind(<<"nick">>, #xdata_field.var, Fs) of + #xdata_field{values = [N]} -> + iq_set_register_info(ServerHost, Host, From, N, Lang); + _ -> + ErrText = <<"You must fill in field \"Nickname\" in the form">>, + {error, xmpp:err_not_acceptable(ErrText, Lang)} + end; + #xdata{} -> + Txt = <<"Incorrect data form">>, + {error, xmpp:err_bad_request(Txt, Lang)}; + _ when is_binary(Nick), Nick /= <<"">> -> + iq_set_register_info(ServerHost, Host, From, Nick, Lang); + _ -> + ErrText = <<"You must fill in field \"Nickname\" in the form">>, + {error, xmpp:err_not_acceptable(ErrText, Lang)} end. -iq_get_vcard(Lang) -> - [#xmlel{name = <<"FN">>, attrs = [], - children = [{xmlcdata, <<"ejabberd/mod_muc">>}]}, - #xmlel{name = <<"URL">>, attrs = [], - children = [{xmlcdata, ?EJABBERD_URI}]}, - #xmlel{name = <<"DESC">>, attrs = [], - children = - [{xmlcdata, - <<(translate:translate(Lang, - <<"ejabberd MUC module">>))/binary, - "\nCopyright (c) 2003-2016 ProcessOne">>}]}]. - broadcast_service_message(Host, Msg) -> lists:foreach( fun(#muc_online_room{pid = Pid}) -> diff --git a/src/mod_muc_admin.erl b/src/mod_muc_admin.erl index 0b5e79f60..a7ba16138 100644 --- a/src/mod_muc_admin.erl +++ b/src/mod_muc_admin.erl @@ -24,7 +24,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_muc_room.hrl"). -include("mod_muc.hrl"). -include("ejabberd_http.hrl"). @@ -241,7 +241,7 @@ web_menu_host(Acc, _Host, Lang) -> -define(TDTD(L, N), ?XE(<<"tr">>, [?XCT(<<"td">>, L), - ?XC(<<"td">>, jlib:integer_to_binary(N)) + ?XC(<<"td">>, integer_to_binary(N)) ])). web_page_main(_, #request{path=[<<"muc">>], lang = Lang} = _Request) -> @@ -283,7 +283,7 @@ get_sort_query(Q) -> get_sort_query2(Q) -> {value, {_, String}} = lists:keysearch(<<"sort">>, 1, Q), - Integer = jlib:binary_to_integer(String), + Integer = binary_to_integer(String), case Integer >= 0 of true -> {ok, {normal, Integer}}; false -> {ok, {reverse, abs(Integer)}} @@ -309,7 +309,7 @@ make_rooms_page(Host, Lang, {Sort_direction, Sort_column}) -> {Titles_TR, _} = lists:mapfoldl( fun(Title, Num_column) -> - NCS = jlib:integer_to_binary(Num_column), + NCS = integer_to_binary(Num_column), TD = ?XE(<<"td">>, [?CT(Title), ?C(<<" ">>), ?AC(<<"?sort=", NCS/binary>>, <<"<">>), @@ -383,7 +383,7 @@ prepare_room_info(Room_info) -> Just_created, Title} = Room_info, [NameHost, - jlib:integer_to_binary(Num_participants), + integer_to_binary(Num_participants), Ts_last_message, jlib:atom_to_binary(Public), jlib:atom_to_binary(Persistent), @@ -830,7 +830,7 @@ get_options(Config) -> Fields = [jlib:atom_to_binary(Field) || Field <- record_info(fields, config)], [config | ValuesRaw] = tuple_to_list(Config), Values = lists:map(fun(V) when is_atom(V) -> jlib:atom_to_binary(V); - (V) when is_integer(V) -> jlib:integer_to_binary(V); + (V) when is_integer(V) -> integer_to_binary(V); (V) when is_tuple(V); is_list(V) -> list_to_binary(hd(io_lib:format("~w", [V]))); (V) -> V end, ValuesRaw), lists:zip(Fields, Values). diff --git a/src/mod_muc_log.erl b/src/mod_muc_log.erl index ec4711b43..4b129ce81 100644 --- a/src/mod_muc_log.erl +++ b/src/mod_muc_log.erl @@ -46,7 +46,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_muc.hrl"). -include("mod_muc_room.hrl"). @@ -196,15 +196,13 @@ code_change(_OldVsn, State, _Extra) -> {ok, State}. add_to_log2(text, {Nick, Packet}, Room, Opts, State) -> case has_no_permanent_store_hint(Packet) of false -> - case {fxml:get_subtag(Packet, <<"subject">>), - fxml:get_subtag(Packet, <<"body">>)} - of - {false, false} -> ok; - {false, SubEl} -> - Message = {body, fxml:get_tag_cdata(SubEl)}, + case {Packet#message.subject, Packet#message.body} of + {[], []} -> ok; + {[], Body} -> + Message = {body, xmpp:get_text(Body)}, add_message_to_log(Nick, Message, Room, Opts, State); - {SubEl, _} -> - Message = {subject, fxml:get_tag_cdata(SubEl)}, + {Subj, _} -> + Message = {subject, xmpp:get_text(Subj)}, add_message_to_log(Nick, Message, Room, Opts, State) end; true -> ok @@ -1035,7 +1033,7 @@ roomconfig_to_string(Options, Lang, FileFormat) -> max_users -> <<"
", OptText/binary, ": \"", - (htmlize(jlib:integer_to_binary(T), + (htmlize(integer_to_binary(T), FileFormat))/binary, "\"
">>; title -> @@ -1053,7 +1051,7 @@ roomconfig_to_string(Options, Lang, FileFormat) -> allow_private_messages_from_visitors -> <<"
", OptText/binary, ": \"", - (htmlize(?T((jlib:atom_to_binary(T))), + (htmlize(?T(jlib:atom_to_binary(T)), FileFormat))/binary, "\"
">>; _ -> <<"\"", T/binary, "\"">> @@ -1168,7 +1166,7 @@ get_room_occupants(RoomJIDString) -> [{U#user.jid, U#user.nick, U#user.role} || {_, U} <- (?DICT):to_list(StateData#state.users)]. --spec get_room_state(binary(), binary()) -> muc_room_state(). +-spec get_room_state(binary(), binary()) -> mod_muc_room:state(). get_room_state(RoomName, MucService) -> case mnesia:dirty_read(muc_online_room, @@ -1180,7 +1178,7 @@ get_room_state(RoomName, MucService) -> [] -> #state{} end. --spec get_room_state(pid()) -> muc_room_state(). +-spec get_room_state(pid()) -> mod_muc_room:state(). get_room_state(RoomPid) -> {ok, R} = gen_fsm:sync_send_all_state_event(RoomPid, @@ -1204,14 +1202,10 @@ fjoin(FileList) -> list_to_binary(filename:join([binary_to_list(File) || File <- FileList])). has_no_permanent_store_hint(Packet) -> - fxml:get_subtag_with_xmlns(Packet, <<"no-store">>, ?NS_HINTS) - =/= false orelse - fxml:get_subtag_with_xmlns(Packet, <<"no-storage">>, ?NS_HINTS) - =/= false orelse - fxml:get_subtag_with_xmlns(Packet, <<"no-permanent-store">>, ?NS_HINTS) - =/= false orelse - fxml:get_subtag_with_xmlns(Packet, <<"no-permanent-storage">>, ?NS_HINTS) - =/= false. + xmpp:has_subtag(Packet, #hint{type = 'no-store'}) orelse + xmpp:has_subtag(Packet, #hint{type = 'no-storage'}) orelse + xmpp:has_subtag(Packet, #hint{type = 'no-permanent-store'}) orelse + xmpp:has_subtag(Packet, #hint{type = 'no-permanent-storage'}). mod_opt_type(access_log) -> fun (A) when is_atom(A) -> A end; diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl index 773953c4a..29b7942cf 100644 --- a/src/mod_muc_room.erl +++ b/src/mod_muc_room.erl @@ -51,7 +51,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_muc_room.hrl"). @@ -72,6 +72,18 @@ -endif. +-type state() :: #state{}. +-type fsm_stop() :: {stop, normal, state()}. +-type fsm_next() :: {next_state, normal_state, state()}. +-type fsm_transition() :: fsm_stop() | fsm_next(). +-type history_element() :: {binary(), %% nick + message(), %% message itself + boolean(), %% have subject + erlang:timestamp(), + non_neg_integer()}. + +-export_type([state/0]). + %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- @@ -133,349 +145,187 @@ init([Host, ServerHost, Access, Room, HistorySize, RoomShaper, Opts]) -> {ok, normal_state, State}. normal_state({route, From, <<"">>, - #xmlel{name = <<"message">>, attrs = Attrs, - children = Els} = - Packet}, - StateData) -> - Lang = fxml:get_attr_s(<<"xml:lang">>, Attrs), + #message{type = Type, lang = Lang} = Packet}, StateData) -> case is_user_online(From, StateData) orelse - is_user_allowed_message_nonparticipant(From, StateData) - of - true -> - case fxml:get_attr_s(<<"type">>, Attrs) of - <<"groupchat">> -> - Activity = get_user_activity(From, StateData), - Now = p1_time_compat:system_time(micro_seconds), - MinMessageInterval = - trunc(gen_mod:get_module_opt(StateData#state.server_host, - mod_muc, min_message_interval, fun(MMI) when is_number(MMI) -> MMI end, 0) - * 1000000), - Size = element_size(Packet), - {MessageShaper, MessageShaperInterval} = - shaper:update(Activity#activity.message_shaper, Size), - if Activity#activity.message /= undefined -> - ErrText = <<"Traffic rate limit is exceeded">>, - Err = jlib:make_error_reply(Packet, - ?ERRT_RESOURCE_CONSTRAINT(Lang, - ErrText)), - ejabberd_router:route(StateData#state.jid, From, Err), - {next_state, normal_state, StateData}; - Now >= - Activity#activity.message_time + MinMessageInterval, - MessageShaperInterval == 0 -> - {RoomShaper, RoomShaperInterval} = - shaper:update(StateData#state.room_shaper, Size), - RoomQueueEmpty = - queue:is_empty(StateData#state.room_queue), - if RoomShaperInterval == 0, RoomQueueEmpty -> - NewActivity = Activity#activity{message_time = - Now, - message_shaper = - MessageShaper}, - StateData1 = store_user_activity(From, - NewActivity, - StateData), - StateData2 = StateData1#state{room_shaper = - RoomShaper}, - process_groupchat_message(From, Packet, - StateData2); - true -> - StateData1 = if RoomQueueEmpty -> - erlang:send_after(RoomShaperInterval, - self(), - process_room_queue), - StateData#state{room_shaper = - RoomShaper}; - true -> StateData - end, - NewActivity = Activity#activity{message_time = - Now, - message_shaper = - MessageShaper, - message = Packet}, - RoomQueue = queue:in({message, From}, - StateData#state.room_queue), - StateData2 = store_user_activity(From, - NewActivity, - StateData1), - StateData3 = StateData2#state{room_queue = - RoomQueue}, - {next_state, normal_state, StateData3} - end; - true -> - MessageInterval = (Activity#activity.message_time + - MinMessageInterval - - Now) - div 1000, - Interval = lists:max([MessageInterval, - MessageShaperInterval]), - erlang:send_after(Interval, self(), - {process_user_message, From}), - NewActivity = Activity#activity{message = Packet, - message_shaper = - MessageShaper}, - StateData1 = store_user_activity(From, NewActivity, - StateData), - {next_state, normal_state, StateData1} - end; - <<"error">> -> - case is_user_online(From, StateData) of - true -> - ErrorText = <<"It is not allowed to send error messages to the" - " room. The participant (~s) has sent an error " - "message (~s) and got kicked from the room">>, - NewState = expulse_participant(Packet, From, StateData, - translate:translate(Lang, - ErrorText)), - close_room_if_temporary_and_empty(NewState); - _ -> {next_state, normal_state, StateData} - end; - <<"chat">> -> - ErrText = - <<"It is not allowed to send private messages " - "to the conference">>, - Err = jlib:make_error_reply(Packet, - ?ERRT_NOT_ACCEPTABLE(Lang, - ErrText)), - ejabberd_router:route(StateData#state.jid, From, Err), - {next_state, normal_state, StateData}; - Type when (Type == <<"">>) or (Type == <<"normal">>) -> - IsInvitation = is_invitation(Els), - IsVoiceRequest = is_voice_request(Els) and - is_visitor(From, StateData), - IsVoiceApprovement = is_voice_approvement(Els) and - not is_visitor(From, StateData), - if IsInvitation -> - case catch check_invitation(From, Packet, Lang, StateData) - of - {error, Error} -> - Err = jlib:make_error_reply(Packet, Error), - ejabberd_router:route(StateData#state.jid, From, Err), - {next_state, normal_state, StateData}; - IJID -> - Config = StateData#state.config, - case Config#config.members_only of - true -> - case get_affiliation(IJID, StateData) of - none -> - NSD = set_affiliation(IJID, member, - StateData), - send_affiliation(IJID, member, - StateData), - store_room(NSD), - {next_state, normal_state, NSD}; - _ -> {next_state, normal_state, StateData} - end; - false -> {next_state, normal_state, StateData} - end - end; - IsVoiceRequest -> - NewStateData = case - (StateData#state.config)#config.allow_voice_requests - of - true -> - MinInterval = - (StateData#state.config)#config.voice_request_min_interval, - BareFrom = - jid:remove_resource(jid:tolower(From)), - NowPriority = -p1_time_compat:system_time(micro_seconds), - CleanPriority = NowPriority + - MinInterval * - 1000000, - Times = - clean_treap(StateData#state.last_voice_request_time, - CleanPriority), - case treap:lookup(BareFrom, Times) - of - error -> - Times1 = - treap:insert(BareFrom, - NowPriority, - true, Times), - NSD = - StateData#state{last_voice_request_time - = - Times1}, - send_voice_request(From, NSD), - NSD; - {ok, _, _} -> - ErrText = - <<"Please, wait for a while before sending " - "new voice request">>, - Err = - jlib:make_error_reply(Packet, - ?ERRT_NOT_ACCEPTABLE(Lang, - ErrText)), - ejabberd_router:route(StateData#state.jid, - From, Err), - StateData#state{last_voice_request_time - = Times} - end; - false -> - ErrText = - <<"Voice requests are disabled in this " - "conference">>, - Err = jlib:make_error_reply(Packet, - ?ERRT_FORBIDDEN(Lang, - ErrText)), - ejabberd_router:route(StateData#state.jid, - From, Err), - StateData - end, - {next_state, normal_state, NewStateData}; - IsVoiceApprovement -> - NewStateData = case is_moderator(From, StateData) of - true -> - case - extract_jid_from_voice_approvement(Els) - of - error -> - ErrText = - <<"Failed to extract JID from your voice " - "request approval">>, - Err = - jlib:make_error_reply(Packet, - ?ERRT_BAD_REQUEST(Lang, - ErrText)), - ejabberd_router:route(StateData#state.jid, - From, Err), - StateData; - {ok, TargetJid} -> - case is_visitor(TargetJid, - StateData) - of - true -> - Reason = <<>>, - NSD = - set_role(TargetJid, - participant, - StateData), - catch - send_new_presence(TargetJid, - Reason, - NSD, - StateData), - NSD; - _ -> StateData - end - end; - _ -> - ErrText = - <<"Only moderators can approve voice requests">>, - Err = jlib:make_error_reply(Packet, - ?ERRT_NOT_ALLOWED(Lang, - ErrText)), - ejabberd_router:route(StateData#state.jid, - From, Err), - StateData - end, - {next_state, normal_state, NewStateData}; - true -> {next_state, normal_state, StateData} - end; - _ -> - ErrText = <<"Improper message type">>, - Err = jlib:make_error_reply(Packet, - ?ERRT_NOT_ACCEPTABLE(Lang, - ErrText)), - ejabberd_router:route(StateData#state.jid, From, Err), - {next_state, normal_state, StateData} - end; - _ -> - case fxml:get_attr_s(<<"type">>, Attrs) of - <<"error">> -> ok; - _ -> - handle_roommessage_from_nonparticipant(Packet, Lang, - StateData, From) - end, - {next_state, normal_state, StateData} + is_user_allowed_message_nonparticipant(From, StateData) of + true when Type == groupchat -> + Activity = get_user_activity(From, StateData), + Now = p1_time_compat:system_time(micro_seconds), + MinMessageInterval = trunc(gen_mod:get_module_opt( + StateData#state.server_host, + mod_muc, min_message_interval, + fun(MMI) when is_number(MMI) -> MMI end, 0) + * 1000000), + Size = element_size(Packet), + {MessageShaper, MessageShaperInterval} = + shaper:update(Activity#activity.message_shaper, Size), + if Activity#activity.message /= undefined -> + ErrText = <<"Traffic rate limit is exceeded">>, + Err = xmpp:make_error( + Packet, + xmpp:err_resource_constraint(ErrText, Lang)), + ejabberd_router:route(StateData#state.jid, From, Err), + {next_state, normal_state, StateData}; + Now >= Activity#activity.message_time + MinMessageInterval, + MessageShaperInterval == 0 -> + {RoomShaper, RoomShaperInterval} = + shaper:update(StateData#state.room_shaper, Size), + RoomQueueEmpty = queue:is_empty(StateData#state.room_queue), + if RoomShaperInterval == 0, RoomQueueEmpty -> + NewActivity = Activity#activity{ + message_time = Now, + message_shaper = MessageShaper}, + StateData1 = store_user_activity(From, + NewActivity, + StateData), + StateData2 = StateData1#state{room_shaper = + RoomShaper}, + process_groupchat_message(From, Packet, + StateData2); + true -> + StateData1 = if RoomQueueEmpty -> + erlang:send_after(RoomShaperInterval, + self(), + process_room_queue), + StateData#state{room_shaper = + RoomShaper}; + true -> StateData + end, + NewActivity = Activity#activity{ + message_time = Now, + message_shaper = MessageShaper, + message = Packet}, + RoomQueue = queue:in({message, From}, + StateData#state.room_queue), + StateData2 = store_user_activity(From, + NewActivity, + StateData1), + StateData3 = StateData2#state{room_queue = RoomQueue}, + {next_state, normal_state, StateData3} + end; + true -> + MessageInterval = (Activity#activity.message_time + + MinMessageInterval - Now) div 1000, + Interval = lists:max([MessageInterval, + MessageShaperInterval]), + erlang:send_after(Interval, self(), + {process_user_message, From}), + NewActivity = Activity#activity{ + message = Packet, + message_shaper = MessageShaper}, + StateData1 = store_user_activity(From, NewActivity, StateData), + {next_state, normal_state, StateData1} + end; + true when Type == error -> + case is_user_online(From, StateData) of + true -> + ErrorText = <<"It is not allowed to send error messages to the" + " room. The participant (~s) has sent an error " + "message (~s) and got kicked from the room">>, + NewState = expulse_participant(Packet, From, StateData, + translate:translate(Lang, + ErrorText)), + close_room_if_temporary_and_empty(NewState); + _ -> + {next_state, normal_state, StateData} + end; + true when Type == chat -> + ErrText = <<"It is not allowed to send private messages " + "to the conference">>, + Err = xmpp:err_not_acceptable(ErrText, Lang), + ejabberd_router:route_error(StateData#state.jid, From, Packet, Err), + {next_state, normal_state, StateData}; + true when Type == normal -> + {next_state, normal_state, + try xmpp:decode_els(Packet) of + Pkt -> process_normal_message(From, Pkt, StateData) + catch _:{xmpp_codec, Why} -> + Txt = xmpp:format_error(Why), + Err = xmpp:err_bad_request(Txt, Lang), + ejabberd_router:route_error( + StateData#state.jid, From, Packet, Err), + StateData + end}; + true -> + ErrText = <<"Improper message type">>, + Err = xmpp:err_not_acceptable(ErrText, Lang), + ejabberd_router:route_error(StateData#state.jid, From, Packet, Err), + {next_state, normal_state, StateData}; + false when Type /= error -> + handle_roommessage_from_nonparticipant(Packet, StateData, From); + false -> + {next_state, normal_state, StateData} end; normal_state({route, From, <<"">>, - #xmlel{name = <<"iq">>} = Packet}, - StateData) -> - case jlib:iq_query_info(Packet) of - reply -> - {next_state, normal_state, StateData}; - IQ0 -> - case ejabberd_hooks:run_fold( - muc_process_iq, - StateData#state.server_host, - IQ0, [StateData, From, StateData#state.jid]) of - ignore -> - {next_state, normal_state, StateData}; - #iq{type = T} = IQRes when T == error; T == result -> - ejabberd_router:route(StateData#state.jid, From, jlib:iq_to_xml(IQRes)), - {next_state, normal_state, StateData}; - #iq{type = Type, xmlns = XMLNS, lang = Lang, - sub_el = #xmlel{name = SubElName, attrs = Attrs} = SubEl} = IQ - when (XMLNS == (?NS_MUC_ADMIN)) or - (XMLNS == (?NS_MUC_OWNER)) - or (XMLNS == (?NS_DISCO_INFO)) - or (XMLNS == (?NS_DISCO_ITEMS)) - or (XMLNS == (?NS_VCARD)) - or (XMLNS == (?NS_MUCSUB)) - or (XMLNS == (?NS_CAPTCHA)) -> - Res1 = case XMLNS of - ?NS_MUC_ADMIN -> - process_iq_admin(From, Type, Lang, SubEl, StateData); - ?NS_MUC_OWNER -> - process_iq_owner(From, Type, Lang, SubEl, StateData); - ?NS_DISCO_INFO -> - case fxml:get_attr(<<"node">>, Attrs) of - false -> process_iq_disco_info(From, Type, Lang, StateData); - {value, _} -> - Txt = <<"Disco info is not available for this node">>, - {error, ?ERRT_SERVICE_UNAVAILABLE(Lang, Txt)} - end; - ?NS_DISCO_ITEMS -> - process_iq_disco_items(From, Type, Lang, StateData); - ?NS_VCARD -> - process_iq_vcard(From, Type, Lang, SubEl, StateData); - ?NS_MUCSUB -> - process_iq_mucsub(From, Packet, IQ, StateData); - ?NS_CAPTCHA -> - process_iq_captcha(From, Type, Lang, SubEl, StateData) - end, - {IQRes, NewStateData} = - case Res1 of - {result, Res, SD} -> - {IQ#iq{type = result, - sub_el = - [#xmlel{name = SubElName, - attrs = - [{<<"xmlns">>, - XMLNS}], - children = Res}]}, - SD}; - {ignore, SD} -> {ignore, SD}; - {error, Error, ResStateData} -> - {IQ#iq{type = error, - sub_el = [SubEl, Error]}, - ResStateData}; - {error, Error} -> - {IQ#iq{type = error, - sub_el = [SubEl, Error]}, - StateData} - end, - if IQRes /= ignore -> - ejabberd_router:route( - StateData#state.jid, From, jlib:iq_to_xml(IQRes)); - true -> - ok + #iq{type = Type, lang = Lang, sub_els = [_]} = IQ0}, + StateData) when Type == get; Type == set -> + try + case ejabberd_hooks:run_fold( + muc_process_iq, + StateData#state.server_host, + xmpp:set_from_to(xmpp:decode_els(IQ0), + From, StateData#state.jid), + [StateData]) of + ignore -> + {next_state, normal_state, StateData}; + #iq{type = T} = IQRes when T == error; T == result -> + ejabberd_router:route(StateData#state.jid, From, IQRes), + {next_state, normal_state, StateData}; + #iq{sub_els = [SubEl]} = IQ -> + Res1 = case xmpp:get_ns(SubEl) of + ?NS_MUC_ADMIN -> + process_iq_admin(From, IQ, StateData); + ?NS_MUC_OWNER -> + process_iq_owner(From, IQ, StateData); + ?NS_DISCO_INFO when SubEl#disco_info.node == undefined -> + process_iq_disco_info(From, IQ, StateData); + ?NS_DISCO_INFO -> + Txt = <<"Disco info is not available for this node">>, + {error, xmpp:err_service_unavailable(Txt, Lang)}; + ?NS_DISCO_ITEMS -> + process_iq_disco_items(From, IQ, StateData); + ?NS_VCARD -> + process_iq_vcard(From, IQ, StateData); + ?NS_MUCSUB -> + process_iq_mucsub(From, IQ, StateData); + ?NS_CAPTCHA -> + process_iq_captcha(From, IQ, StateData); + _ -> + {error, xmpp:err_feature_not_implemented()} + end, + {IQRes, NewStateData} = + case Res1 of + {result, Res, SD} -> + {xmpp:make_iq_result(IQ, Res), SD}; + {result, Res} -> + {xmpp:make_iq_result(IQ, Res), StateData}; + {ignore, SD} -> + {ignore, SD}; + {error, Error, ResStateData} -> + {xmpp:make_error(IQ0, Error), ResStateData}; + {error, Error} -> + {xmpp:make_error(IQ0, Error), StateData} end, - case NewStateData of - stop -> {stop, normal, StateData}; - _ -> {next_state, normal_state, NewStateData} - end; - _ -> - Err = jlib:make_error_reply(Packet, - ?ERR_FEATURE_NOT_IMPLEMENTED), - ejabberd_router:route(StateData#state.jid, From, Err), - {next_state, normal_state, StateData} - end + if IQRes /= ignore -> + ejabberd_router:route(StateData#state.jid, From, IQRes); + true -> + ok + end, + case NewStateData of + stop -> {stop, normal, StateData}; + _ -> {next_state, normal_state, NewStateData} + end + end + catch _:{xmpp_codec, Why} -> + ErrTxt = xmpp:format_error(Why), + Err = xmpp:make_error(IQ0, xmpp:err_bad_request(ErrTxt, Lang)), + ejabberd_router:route(StateData#state.jid, From, Err) end; -normal_state({route, From, Nick, - #xmlel{name = <<"presence">>} = Packet}, - StateData) -> +normal_state({route, From, <<"">>, #iq{} = IQ}, StateData) -> + Err = xmpp:err_bad_request(), + ejabberd_router:route_error(StateData#state.jid, From, IQ, Err), + {next_state, normal_state, StateData}; +normal_state({route, From, Nick, #presence{} = Packet}, StateData) -> Activity = get_user_activity(From, StateData), Now = p1_time_compat:system_time(micro_seconds), MinPresenceInterval = @@ -485,185 +335,135 @@ normal_state({route, From, Nick, I end, 0) * 1000000), - if (Now >= - Activity#activity.presence_time + MinPresenceInterval) - and (Activity#activity.presence == undefined) -> - NewActivity = Activity#activity{presence_time = Now}, - StateData1 = store_user_activity(From, NewActivity, - StateData), - process_presence(From, Nick, Packet, StateData1); + if (Now >= Activity#activity.presence_time + MinPresenceInterval) + and (Activity#activity.presence == undefined) -> + NewActivity = Activity#activity{presence_time = Now}, + StateData1 = store_user_activity(From, NewActivity, + StateData), + process_presence(From, Nick, Packet, StateData1); true -> - if Activity#activity.presence == undefined -> - Interval = (Activity#activity.presence_time + - MinPresenceInterval - - Now) - div 1000, - erlang:send_after(Interval, self(), - {process_user_presence, From}); - true -> ok - end, - NewActivity = Activity#activity{presence = - {Nick, Packet}}, - StateData1 = store_user_activity(From, NewActivity, - StateData), - {next_state, normal_state, StateData1} + if Activity#activity.presence == undefined -> + Interval = (Activity#activity.presence_time + + MinPresenceInterval - Now) div 1000, + erlang:send_after(Interval, self(), + {process_user_presence, From}); + true -> ok + end, + NewActivity = Activity#activity{presence = {Nick, Packet}}, + StateData1 = store_user_activity(From, NewActivity, + StateData), + {next_state, normal_state, StateData1} end; normal_state({route, From, ToNick, - #xmlel{name = <<"message">>, attrs = Attrs} = Packet}, + #message{type = Type, lang = Lang} = Packet}, StateData) -> - Type = fxml:get_attr_s(<<"type">>, Attrs), - Lang = fxml:get_attr_s(<<"xml:lang">>, Attrs), - case decide_fate_message(Type, Packet, From, StateData) - of - {expulse_sender, Reason} -> - ?DEBUG(Reason, []), - ErrorText = <<"It is not allowed to send error messages to the" - " room. The participant (~s) has sent an error " - "message (~s) and got kicked from the room">>, - NewState = expulse_participant(Packet, From, StateData, - translate:translate(Lang, ErrorText)), - {next_state, normal_state, NewState}; - forget_message -> {next_state, normal_state, StateData}; - continue_delivery -> - case - {(StateData#state.config)#config.allow_private_messages, - is_user_online(From, StateData)} - of - {true, true} -> - case Type of - <<"groupchat">> -> - ErrText = - <<"It is not allowed to send private messages " - "of type \"groupchat\"">>, - Err = jlib:make_error_reply(Packet, - ?ERRT_BAD_REQUEST(Lang, - ErrText)), - ejabberd_router:route(jid:replace_resource(StateData#state.jid, - ToNick), - From, Err); - _ -> - case find_jids_by_nick(ToNick, StateData) of - false -> - ErrText = - <<"Recipient is not in the conference room">>, - Err = jlib:make_error_reply(Packet, - ?ERRT_ITEM_NOT_FOUND(Lang, - ErrText)), - ejabberd_router:route(jid:replace_resource(StateData#state.jid, - ToNick), - From, Err); + case decide_fate_message(Packet, From, StateData) of + {expulse_sender, Reason} -> + ?DEBUG(Reason, []), + ErrorText = <<"It is not allowed to send error messages to the" + " room. The participant (~s) has sent an error " + "message (~s) and got kicked from the room">>, + NewState = expulse_participant(Packet, From, StateData, + translate:translate(Lang, ErrorText)), + {next_state, normal_state, NewState}; + forget_message -> + {next_state, normal_state, StateData}; + continue_delivery -> + case {(StateData#state.config)#config.allow_private_messages, + is_user_online(From, StateData)} of + {true, true} when Type == groupchat -> + ErrText = <<"It is not allowed to send private messages " + "of type \"groupchat\"">>, + Err = xmpp:err_bad_request(ErrText, Lang), + ejabberd_router:route_error( + jid:replace_resource(StateData#state.jid, ToNick), + From, Packet, Err); + {true, true} -> + case find_jids_by_nick(ToNick, StateData) of + [] -> + ErrText = <<"Recipient is not in the conference room">>, + Err = xmpp:err_item_not_found(ErrText, Lang), + ejabberd_router:route_error( + jid:replace_resource(StateData#state.jid, ToNick), + From, Packet, Err); ToJIDs -> SrcIsVisitor = is_visitor(From, StateData), - DstIsModerator = is_moderator(hd(ToJIDs), - StateData), + DstIsModerator = is_moderator(hd(ToJIDs), StateData), PmFromVisitors = (StateData#state.config)#config.allow_private_messages_from_visitors, if SrcIsVisitor == false; PmFromVisitors == anyone; (PmFromVisitors == moderators) and - DstIsModerator -> - {ok, #user{nick = FromNick}} = - (?DICT):find(jid:tolower(From), - StateData#state.users), - FromNickJID = - jid:replace_resource(StateData#state.jid, - FromNick), - X = #xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_MUC_USER}]}, - PrivMsg = fxml:append_subtags(Packet, [X]), - [ejabberd_router:route(FromNickJID, ToJID, PrivMsg) - || ToJID <- ToJIDs]; + DstIsModerator -> + {ok, #user{nick = FromNick}} = + (?DICT):find(jid:tolower(From), + StateData#state.users), + FromNickJID = + jid:replace_resource(StateData#state.jid, + FromNick), + X = #muc_user{}, + PrivMsg = xmpp:set_subtag(Packet, X), + [ejabberd_router:route(FromNickJID, ToJID, PrivMsg) + || ToJID <- ToJIDs]; true -> - ErrText = - <<"It is not allowed to send private messages">>, - Err = jlib:make_error_reply(Packet, - ?ERRT_FORBIDDEN(Lang, - ErrText)), - ejabberd_router:route(jid:replace_resource(StateData#state.jid, - ToNick), - From, Err) + ErrText = <<"It is not allowed to send private messages">>, + Err = xmpp:err_forbidden(ErrText, Lang), + ejabberd_router:route_error( + jid:replace_resource(StateData#state.jid, ToNick), + From, Packet, Err) end - end - end; - {true, false} -> - ErrText = - <<"Only occupants are allowed to send messages " - "to the conference">>, - Err = jlib:make_error_reply(Packet, - ?ERRT_NOT_ACCEPTABLE(Lang, - ErrText)), - ejabberd_router:route(jid:replace_resource(StateData#state.jid, - ToNick), - From, Err); - {false, _} -> - ErrText = - <<"It is not allowed to send private messages">>, - Err = jlib:make_error_reply(Packet, - ?ERRT_FORBIDDEN(Lang, ErrText)), - ejabberd_router:route(jid:replace_resource(StateData#state.jid, - ToNick), - From, Err) - end, + end; + {true, false} -> + ErrText = <<"Only occupants are allowed to send messages " + "to the conference">>, + Err = xmpp:err_not_acceptable(ErrText, Lang), + ejabberd_router:route_error( + jid:replace_resource(StateData#state.jid, ToNick), + From, Packet, Err); + {false, _} -> + ErrText = <<"It is not allowed to send private messages">>, + Err = xmpp:err_forbidden(ErrText, Lang), + ejabberd_router:route_error( + jid:replace_resource(StateData#state.jid, ToNick), + From, Packet, Err) + end, {next_state, normal_state, StateData} end; normal_state({route, From, ToNick, - #xmlel{name = <<"iq">>, attrs = Attrs} = Packet}, + #iq{id = StanzaId, lang = Lang} = Packet}, StateData) -> - Lang = fxml:get_attr_s(<<"xml:lang">>, Attrs), - StanzaId = fxml:get_attr_s(<<"id">>, Attrs), case {(StateData#state.config)#config.allow_query_users, - is_user_online_iq(StanzaId, From, StateData)} - of - {true, {true, NewId, FromFull}} -> - case find_jid_by_nick(ToNick, StateData) of - false -> - case jlib:iq_query_info(Packet) of - reply -> ok; - _ -> - ErrText = <<"Recipient is not in the conference room">>, - Err = jlib:make_error_reply(Packet, - ?ERRT_ITEM_NOT_FOUND(Lang, - ErrText)), - ejabberd_router:route(jid:replace_resource(StateData#state.jid, - ToNick), - From, Err) - end; - ToJID -> - {ok, #user{nick = FromNick}} = - (?DICT):find(jid:tolower(FromFull), - StateData#state.users), - {ToJID2, Packet2} = handle_iq_vcard(FromFull, ToJID, - StanzaId, NewId, Packet), - ejabberd_router:route(jid:replace_resource(StateData#state.jid, - FromNick), - ToJID2, Packet2) - end; - {_, {false, _, _}} -> - case jlib:iq_query_info(Packet) of - reply -> ok; - _ -> - ErrText = - <<"Only occupants are allowed to send queries " - "to the conference">>, - Err = jlib:make_error_reply(Packet, - ?ERRT_NOT_ACCEPTABLE(Lang, - ErrText)), - ejabberd_router:route(jid:replace_resource(StateData#state.jid, - ToNick), - From, Err) - end; - _ -> - case jlib:iq_query_info(Packet) of - reply -> ok; - _ -> - ErrText = <<"Queries to the conference members are " - "not allowed in this room">>, - Err = jlib:make_error_reply(Packet, - ?ERRT_NOT_ALLOWED(Lang, ErrText)), - ejabberd_router:route(jid:replace_resource(StateData#state.jid, - ToNick), - From, Err) - end + is_user_online_iq(StanzaId, From, StateData)} of + {true, {true, NewId, FromFull}} -> + case find_jid_by_nick(ToNick, StateData) of + false -> + ErrText = <<"Recipient is not in the conference room">>, + Err = xmpp:err_item_not_found(ErrText, Lang), + ejabberd_router:route_error( + jid:replace_resource(StateData#state.jid, ToNick), + From, Packet, Err); + ToJID -> + {ok, #user{nick = FromNick}} = + (?DICT):find(jid:tolower(FromFull), StateData#state.users), + {ToJID2, Packet2} = handle_iq_vcard(ToJID, NewId, Packet), + ejabberd_router:route( + jid:replace_resource(StateData#state.jid, FromNick), + ToJID2, Packet2) + end; + {_, {false, _, _}} -> + ErrText = <<"Only occupants are allowed to send queries " + "to the conference">>, + Err = xmpp:err_not_acceptable(ErrText, Lang), + ejabberd_router:route_error( + jid:replace_resource(StateData#state.jid, ToNick), + From, Packet, Err); + _ -> + ErrText = <<"Queries to the conference members are " + "not allowed in this room">>, + Err = xmpp:err_not_allowed(ErrText, Lang), + ejabberd_router:route_error( + jid:replace_resource(StateData#state.jid, ToNick), + From, Packet, Err) end, {next_state, normal_state, StateData}; normal_state(_Event, StateData) -> @@ -671,11 +471,7 @@ normal_state(_Event, StateData) -> handle_event({service_message, Msg}, _StateName, StateData) -> - MessagePkt = #xmlel{name = <<"message">>, - attrs = [{<<"type">>, <<"groupchat">>}], - children = - [#xmlel{name = <<"body">>, attrs = [], - children = [{xmlcdata, Msg}]}]}, + MessagePkt = #message{type = groupchat, body = xmpp:mk_text(Msg)}, send_wrapped_multiple( StateData#state.jid, StateData#state.users, @@ -687,22 +483,9 @@ handle_event({service_message, Msg}, _StateName, {next_state, normal_state, NSD}; handle_event({destroy, Reason}, _StateName, StateData) -> - {result, [], stop} = destroy_room(#xmlel{name = - <<"destroy">>, - attrs = - [{<<"xmlns">>, ?NS_MUC_OWNER}], - children = - case Reason of - none -> []; - _Else -> - [#xmlel{name = - <<"reason">>, - attrs = [], - children = - [{xmlcdata, - Reason}]}] - end}, - StateData), + {result, undefined, stop} = + destroy_room(#muc_destroy{xmlns = ?NS_MUC_OWNER, reason = Reason}, + StateData), ?INFO_MSG("Destroyed MUC room ~s with reason: ~p", [jid:to_string(StateData#state.jid), Reason]), add_to_log(room_existence, destroyed, StateData), @@ -710,7 +493,7 @@ handle_event({destroy, Reason}, _StateName, handle_event(destroy, StateName, StateData) -> ?INFO_MSG("Destroyed MUC room ~s", [jid:to_string(StateData#state.jid)]), - handle_event({destroy, none}, StateName, StateData); + handle_event({destroy, undefined}, StateName, StateData); handle_event({set_affiliations, Affiliations}, StateName, StateData) -> {next_state, StateName, @@ -741,7 +524,7 @@ handle_sync_event(get_state, _From, StateName, {reply, {ok, StateData}, StateName, StateData}; handle_sync_event({change_config, Config}, _From, StateName, StateData) -> - {result, [], NSD} = change_config(Config, StateData), + {result, undefined, NSD} = change_config(Config, StateData), {reply, {ok, NSD#state.config}, StateName, NSD}; handle_sync_event({change_state, NewStateData}, _From, StateName, _StateData) -> @@ -821,12 +604,11 @@ handle_info({captcha_failed, From}, normal_state, {ok, {Nick, Packet}} -> Robots = (?DICT):erase(From, StateData#state.robots), Txt = <<"The CAPTCHA verification has failed">>, - Err = jlib:make_error_reply( - Packet, ?ERRT_NOT_AUTHORIZED(?MYLANG, Txt)), - ejabberd_router:route % TODO: s/Nick/""/ - (jid:replace_resource(StateData#state.jid, - Nick), - From, Err), + Lang = xmpp:get_lang(Packet), + Err = xmpp:err_not_authorized(Txt, Lang), + ejabberd_router:route_error( + jid:replace_resource(StateData#state.jid, Nick), + From, Packet, Err), StateData#state{robots = Robots}; _ -> StateData end, @@ -845,22 +627,12 @@ terminate(Reason, _StateName, StateData) -> "because of a system shutdown">>; _ -> <<"Room terminates">> end, - ItemAttrs = [{<<"affiliation">>, <<"none">>}, - {<<"role">>, <<"none">>}], - ReasonEl = #xmlel{name = <<"reason">>, attrs = [], - children = [{xmlcdata, ReasonT}]}, - Packet = #xmlel{name = <<"presence">>, - attrs = [{<<"type">>, <<"unavailable">>}], - children = - [#xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_MUC_USER}], - children = - [#xmlel{name = <<"item">>, - attrs = ItemAttrs, - children = [ReasonEl]}, - #xmlel{name = <<"status">>, - attrs = [{<<"code">>, <<"332">>}], - children = []}]}]}, + Packet = #presence{ + type = unavailable, + sub_els = [#muc_user{items = [#muc_item{affiliation = none, + reason = ReasonT, + role = none}], + status_codes = [332]}]}, (?DICT):fold(fun (LJID, Info, _) -> Nick = Info#user.nick, case Reason of @@ -883,14 +655,12 @@ terminate(Reason, _StateName, StateData) -> %%%---------------------------------------------------------------------- %%% Internal functions %%%---------------------------------------------------------------------- - +-spec route(pid(), jid(), binary(), stanza()) -> ok. route(Pid, From, ToNick, Packet) -> gen_fsm:send_event(Pid, {route, From, ToNick, Packet}). -process_groupchat_message(From, - #xmlel{name = <<"message">>, attrs = Attrs} = Packet, - StateData) -> - Lang = fxml:get_attr_s(<<"xml:lang">>, Attrs), +-spec process_groupchat_message(jid(), message(), state()) -> fsm_next(). +process_groupchat_message(From, #message{lang = Lang} = Packet, StateData) -> case is_user_online(From, StateData) orelse is_user_allowed_message_nonparticipant(From, StateData) of @@ -932,7 +702,7 @@ process_groupchat_message(From, drop -> {next_state, normal_state, StateData}; NewPacket1 -> - NewPacket = fxml:remove_subtags(NewPacket1, <<"nick">>, {<<"xmlns">>, ?NS_NICK}), + NewPacket = xmpp:remove_subtag(NewPacket1, #nick{}), Node = if Subject == false -> ?NS_MUCSUB_NODES_MESSAGES; true -> ?NS_MUCSUB_NODES_SUBJECT end, @@ -951,41 +721,136 @@ process_groupchat_message(From, {next_state, normal_state, NewStateData2} end; _ -> - Err = case - (StateData#state.config)#config.allow_change_subj - of + Err = case (StateData#state.config)#config.allow_change_subj of true -> - ?ERRT_FORBIDDEN(Lang, - <<"Only moderators and participants are " - "allowed to change the subject in this " - "room">>); + xmpp:err_forbidden( + <<"Only moderators and participants are " + "allowed to change the subject in this " + "room">>, Lang); _ -> - ?ERRT_FORBIDDEN(Lang, - <<"Only moderators are allowed to change " - "the subject in this room">>) + xmpp:err_forbidden( + <<"Only moderators are allowed to change " + "the subject in this room">>, Lang) end, - ejabberd_router:route(StateData#state.jid, From, - jlib:make_error_reply(Packet, Err)), + ejabberd_router:route_error( + StateData#state.jid, From, Packet, Err), {next_state, normal_state, StateData} end; true -> ErrText = <<"Visitors are not allowed to send messages " "to all occupants">>, - Err = jlib:make_error_reply(Packet, - ?ERRT_FORBIDDEN(Lang, ErrText)), - ejabberd_router:route(StateData#state.jid, From, Err), + Err = xmpp:err_forbidden(ErrText, Lang), + ejabberd_router:route_error( + StateData#state.jid, From, Packet, Err), {next_state, normal_state, StateData} end; false -> - ErrText = - <<"Only occupants are allowed to send messages " - "to the conference">>, - Err = jlib:make_error_reply(Packet, - ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)), - ejabberd_router:route(StateData#state.jid, From, Err), + ErrText = <<"Only occupants are allowed to send messages " + "to the conference">>, + Err = xmpp:err_not_acceptable(ErrText, Lang), + ejabberd_router:route_error(StateData#state.jid, From, Packet, Err), {next_state, normal_state, StateData} end. +-spec process_normal_message(jid(), message(), state()) -> state(). +process_normal_message(From, #message{lang = Lang} = Pkt, StateData) -> + IsInvitation = is_invitation(Pkt), + IsVoiceRequest = is_voice_request(Pkt) and + is_visitor(From, StateData), + IsVoiceApprovement = is_voice_approvement(Pkt) and + not is_visitor(From, StateData), + if IsInvitation -> + case check_invitation(From, Pkt, StateData) of + {error, Error} -> + ejabberd_router:route_error(StateData#state.jid, From, Pkt, Error), + StateData; + IJID -> + Config = StateData#state.config, + case Config#config.members_only of + true -> + case get_affiliation(IJID, StateData) of + none -> + NSD = set_affiliation(IJID, member, StateData), + send_affiliation(IJID, member, StateData), + store_room(NSD), + NSD; + _ -> + StateData + end; + false -> + StateData + end + end; + IsVoiceRequest -> + case (StateData#state.config)#config.allow_voice_requests of + true -> + MinInterval = (StateData#state.config)#config.voice_request_min_interval, + BareFrom = jid:remove_resource(jid:tolower(From)), + NowPriority = -p1_time_compat:system_time(micro_seconds), + CleanPriority = NowPriority + MinInterval * 1000000, + Times = clean_treap(StateData#state.last_voice_request_time, + CleanPriority), + case treap:lookup(BareFrom, Times) of + error -> + Times1 = treap:insert(BareFrom, + NowPriority, + true, Times), + NSD = StateData#state{last_voice_request_time = Times1}, + send_voice_request(From, Lang, NSD), + NSD; + {ok, _, _} -> + ErrText = <<"Please, wait for a while before sending " + "new voice request">>, + Err = xmpp:err_not_acceptable(ErrText, Lang), + ejabberd_router:route_error( + StateData#state.jid, From, Pkt, Err), + StateData#state{last_voice_request_time = Times} + end; + false -> + ErrText = <<"Voice requests are disabled in this conference">>, + Err = xmpp:err_forbidden(ErrText, Lang), + ejabberd_router:route_error( + StateData#state.jid, From, Pkt, Err), + StateData + end; + IsVoiceApprovement -> + case is_moderator(From, StateData) of + true -> + case extract_jid_from_voice_approvement(Pkt) of + error -> + ErrText = <<"Failed to extract JID from your voice " + "request approval">>, + Err = xmpp:err_bad_request(ErrText, Lang), + ejabberd_router:route_error( + StateData#state.jid, From, Pkt, Err), + StateData; + TargetJid -> + case is_visitor(TargetJid, StateData) of + true -> + Reason = <<>>, + NSD = set_role(TargetJid, + participant, + StateData), + catch send_new_presence(TargetJid, + Reason, + NSD, + StateData), + NSD; + _ -> + StateData + end + end; + _ -> + ErrText = <<"Only moderators can approve voice requests">>, + Err = xmpp:err_not_allowed(ErrText, Lang), + ejabberd_router:route_error( + StateData#state.jid, From, Pkt, Err), + StateData + end; + true -> + StateData + end. + %% @doc Check if this non participant can send message to room. %% %% XEP-0045 v1.23: @@ -993,6 +858,7 @@ process_groupchat_message(From, %% an implementation MAY allow users with certain privileges %% (e.g., a room owner, room admin, or service-level admin) %% to send messages to the room even if those users are not occupants. +-spec is_user_allowed_message_nonparticipant(jid(), state()) -> boolean(). is_user_allowed_message_nonparticipant(JID, StateData) -> case get_service_affiliation(JID, StateData) of @@ -1002,6 +868,7 @@ is_user_allowed_message_nonparticipant(JID, %% @doc Get information of this participant, or default values. %% If the JID is not a participant, return values for a service message. +-spec get_participant_data(jid(), state()) -> {binary(), role(), boolean()}. get_participant_data(From, StateData) -> case (?DICT):find(jid:tolower(From), StateData#state.users) @@ -1011,14 +878,11 @@ get_participant_data(From, StateData) -> error -> {<<"">>, moderator, false} end. -process_presence(From, Nick, - #xmlel{name = <<"presence">>, attrs = Attrs0} = Packet0, - StateData) -> - Type0 = fxml:get_attr_s(<<"type">>, Attrs0), +-spec process_presence(jid(), binary(), presence(), state()) -> fsm_transition(). +process_presence(From, Nick, #presence{type = Type0} = Packet0, StateData) -> IsOnline = is_user_online(From, StateData), - IsSubscriber = is_subscriber(From, StateData), - if Type0 == <<"">>; - IsOnline and ((Type0 == <<"unavailable">>) or (Type0 == <<"error">>)) -> + if Type0 == available; + IsOnline and ((Type0 == unavailable) or (Type0 == error)) -> case ejabberd_hooks:run_fold(muc_filter_presence, StateData#state.server_host, Packet0, @@ -1027,119 +891,104 @@ process_presence(From, Nick, From, Nick]) of drop -> {next_state, normal_state, StateData}; - #xmlel{attrs = Attrs} = Packet -> - Type = fxml:get_attr_s(<<"type">>, Attrs), - Lang = fxml:get_attr_s(<<"xml:lang">>, Attrs), - StateData1 = case Type of - <<"unavailable">> -> - NewPacket = case - {(StateData#state.config)#config.allow_visitor_status, - is_visitor(From, StateData)} - of - {false, true} -> - strip_status(Packet); - _ -> Packet - end, - NewState = add_user_presence_un(From, NewPacket, - StateData), - case (?DICT):find(Nick, StateData#state.nicks) of - {ok, [_, _ | _]} -> ok; - _ -> send_new_presence(From, NewState, StateData) - end, - Reason = case fxml:get_subtag(NewPacket, - <<"status">>) - of - false -> <<"">>; - Status_el -> - fxml:get_tag_cdata(Status_el) - end, - remove_online_user(From, NewState, IsSubscriber, Reason); - <<"error">> -> - ErrorText = <<"It is not allowed to send error messages to the" - " room. The participant (~s) has sent an error " - "message (~s) and got kicked from the room">>, - expulse_participant(Packet, From, StateData, - translate:translate(Lang, - ErrorText)); - <<"">> -> - if not IsOnline -> - add_new_user(From, Nick, Packet, StateData); - true -> - case is_nick_change(From, Nick, StateData) of - true -> - case {nick_collision(From, Nick, StateData), - mod_muc:can_use_nick(StateData#state.server_host, - StateData#state.host, - From, Nick), - {(StateData#state.config)#config.allow_visitor_nickchange, - is_visitor(From, StateData)}} - of - {_, _, {false, true}} -> - ErrText = - <<"Visitors are not allowed to change their " - "nicknames in this room">>, - Err = jlib:make_error_reply(Packet, - ?ERRT_NOT_ALLOWED(Lang, - ErrText)), - ejabberd_router:route(jid:replace_resource(StateData#state.jid, - Nick), - From, Err), - StateData; - {true, _, _} -> - Lang = fxml:get_attr_s(<<"xml:lang">>, - Attrs), - ErrText = - <<"That nickname is already in use by another " - "occupant">>, - Err = jlib:make_error_reply(Packet, - ?ERRT_CONFLICT(Lang, - ErrText)), - ejabberd_router:route(jid:replace_resource(StateData#state.jid, - Nick), % TODO: s/Nick/""/ - From, Err), - StateData; - {_, false, _} -> - ErrText = - <<"That nickname is registered by another " - "person">>, - Err = jlib:make_error_reply(Packet, - ?ERRT_CONFLICT(Lang, - ErrText)), - ejabberd_router:route(jid:replace_resource(StateData#state.jid, - Nick), - From, Err), - StateData; - _ -> - case is_initial_presence(From, StateData) of - true -> - subscriber_becomes_available( - From, Nick, Packet, StateData); - false -> - change_nick(From, Nick, StateData) - end - end; - _NotNickChange -> - case is_initial_presence(From, StateData) of - true -> - subscriber_becomes_available( - From, Nick, Packet, StateData); - false -> - Stanza = maybe_strip_status_from_presence( - From, Packet, StateData), - NewState = add_user_presence(From, Stanza, - StateData), - send_new_presence(From, NewState, StateData), - NewState - end - end - end - end, - close_room_if_temporary_and_empty(StateData1) + #presence{} = Packet -> + close_room_if_temporary_and_empty( + do_process_presence(From, Nick, Packet, StateData)) end; true -> - {next_state, normal_state, StateData} + {next_state, normal_state, StateData} end. +-spec do_process_presence(jid(), binary(), presence(), state()) -> + state(). +do_process_presence(From, Nick, #presence{type = available, lang = Lang} = Packet, + StateData) -> + case is_user_online(From, StateData) of + false -> + add_new_user(From, Nick, Packet, StateData); + true -> + case is_nick_change(From, Nick, StateData) of + true -> + case {nick_collision(From, Nick, StateData), + mod_muc:can_use_nick(StateData#state.server_host, + StateData#state.host, + From, Nick), + {(StateData#state.config)#config.allow_visitor_nickchange, + is_visitor(From, StateData)}} of + {_, _, {false, true}} -> + ErrText = <<"Visitors are not allowed to change their " + "nicknames in this room">>, + Err = xmpp:err_not_allowed(ErrText, Lang), + ejabberd_router:route_error( + jid:replace_resource(StateData#state.jid, Nick), + From, Packet, Err), + StateData; + {true, _, _} -> + ErrText = <<"That nickname is already in use by another " + "occupant">>, + Err = xmpp:err_conflict(ErrText, Lang), + ejabberd_router:route_error( + jid:replace_resource(StateData#state.jid, Nick), + From, Packet, Err), + StateData; + {_, false, _} -> + ErrText = <<"That nickname is registered by another " + "person">>, + Err = xmpp:err_conflict(ErrText, Lang), + ejabberd_router:route_error( + jid:replace_resource(StateData#state.jid, Nick), + From, Packet, Err), + StateData; + _ -> + case is_initial_presence(From, StateData) of + true -> + subscriber_becomes_available( + From, Nick, Packet, StateData); + false -> + change_nick(From, Nick, StateData) + end + end; + _NotNickChange -> + case is_initial_presence(From, StateData) of + true -> + subscriber_becomes_available( + From, Nick, Packet, StateData); + false -> + Stanza = maybe_strip_status_from_presence( + From, Packet, StateData), + NewState = add_user_presence(From, Stanza, + StateData), + send_new_presence(From, NewState, StateData), + NewState + end + end + end; +do_process_presence(From, Nick, #presence{type = unavailable} = Packet, + StateData) -> + IsSubscriber = is_subscriber(From, StateData), + NewPacket = case {(StateData#state.config)#config.allow_visitor_status, + is_visitor(From, StateData)} of + {false, true} -> + strip_status(Packet); + _ -> Packet + end, + NewState = add_user_presence_un(From, NewPacket, StateData), + case (?DICT):find(Nick, StateData#state.nicks) of + {ok, [_, _ | _]} -> ok; + _ -> send_new_presence(From, NewState, StateData) + end, + Reason = xmpp:get_text(NewPacket#presence.status), + remove_online_user(From, NewState, IsSubscriber, Reason); +do_process_presence(From, _Nick, #presence{type = error, lang = Lang} = Packet, + StateData) -> + ErrorText = <<"It is not allowed to send error messages to the" + " room. The participant (~s) has sent an error " + "message (~s) and got kicked from the room">>, + expulse_participant(Packet, From, StateData, + translate:translate(Lang, ErrorText)). + +-spec maybe_strip_status_from_presence(jid(), presence(), + state()) -> presence(). maybe_strip_status_from_presence(From, Packet, StateData) -> case {(StateData#state.config)#config.allow_visitor_status, is_visitor(From, StateData)} of @@ -1148,6 +997,8 @@ maybe_strip_status_from_presence(From, Packet, StateData) -> _Allowed -> Packet end. +-spec subscriber_becomes_available(jid(), binary(), presence(), + state()) -> state(). subscriber_becomes_available(From, Nick, Packet, StateData) -> Stanza = maybe_strip_status_from_presence(From, Packet, StateData), State1 = add_user_presence(From, Stanza, StateData), @@ -1159,9 +1010,10 @@ subscriber_becomes_available(From, Nick, Packet, StateData) -> send_initial_presence(From, State3, StateData), State3. +-spec close_room_if_temporary_and_empty(state()) -> fsm_transition(). close_room_if_temporary_and_empty(StateData1) -> case not (StateData1#state.config)#config.persistent - andalso (?DICT):to_list(StateData1#state.users) == [] + andalso (?DICT):size(StateData1#state.users) == 0 of true -> ?INFO_MSG("Destroyed MUC room ~s because it's temporary " @@ -1172,10 +1024,12 @@ close_room_if_temporary_and_empty(StateData1) -> _ -> {next_state, normal_state, StateData1} end. +-spec is_user_online(jid(), state()) -> boolean(). is_user_online(JID, StateData) -> LJID = jid:tolower(JID), (?DICT):is_key(LJID, StateData#state.users). +-spec is_subscriber(jid(), state()) -> boolean(). is_subscriber(JID, StateData) -> LJID = jid:tolower(JID), case (?DICT):find(LJID, StateData#state.users) of @@ -1186,6 +1040,7 @@ is_subscriber(JID, StateData) -> end. %% Check if the user is occupant of the room, or at least is an admin or owner. +-spec is_occupant_or_admin(jid(), state()) -> boolean(). is_occupant_or_admin(JID, StateData) -> FAffiliation = get_affiliation(JID, StateData), FRole = get_role(JID, StateData), @@ -1200,6 +1055,8 @@ is_occupant_or_admin(JID, StateData) -> %%% %%% Handle IQ queries of vCard %%% +-spec is_user_online_iq(binary(), jid(), state()) -> + {boolean(), binary(), jid()}. is_user_online_iq(StanzaId, JID, StateData) when JID#jid.lresource /= <<"">> -> {is_user_online(JID, StateData), StanzaId, JID}; @@ -1207,93 +1064,55 @@ is_user_online_iq(StanzaId, JID, StateData) when JID#jid.lresource == <<"">> -> try stanzaid_unpack(StanzaId) of {OriginalId, Resource} -> - JIDWithResource = jid:replace_resource(JID, - Resource), + JIDWithResource = jid:replace_resource(JID, Resource), {is_user_online(JIDWithResource, StateData), OriginalId, JIDWithResource} catch _:_ -> {is_user_online(JID, StateData), StanzaId, JID} end. -handle_iq_vcard(FromFull, ToJID, StanzaId, NewId, - Packet) -> +-spec handle_iq_vcard(jid(), binary(), iq()) -> {jid(), iq()}. +handle_iq_vcard(ToJID, NewId, #iq{type = Type, sub_els = SubEls} = IQ) -> ToBareJID = jid:remove_resource(ToJID), - IQ = jlib:iq_query_info(Packet), - handle_iq_vcard2(FromFull, ToJID, ToBareJID, StanzaId, - NewId, IQ, Packet). - -handle_iq_vcard2(_FromFull, ToJID, ToBareJID, StanzaId, - _NewId, #iq{type = get, xmlns = ?NS_VCARD}, Packet) - when ToBareJID /= ToJID -> - {ToBareJID, change_stanzaid(StanzaId, ToJID, Packet)}; -handle_iq_vcard2(_FromFull, ToJID, _ToBareJID, - _StanzaId, NewId, _IQ, Packet) -> - {ToJID, change_stanzaid(NewId, Packet)}. + case SubEls of + [SubEl] when Type == get, ToBareJID /= ToJID -> + case xmpp:get_ns(SubEl) of + ?NS_VCARD -> + {ToBareJID, change_stanzaid(ToJID, IQ)}; + _ -> + {ToJID, xmpp:set_id(IQ, NewId)} + end; + _ -> + {ToJID, xmpp:set_id(IQ, NewId)} + end. +-spec stanzaid_pack(binary(), binary()) -> binary(). stanzaid_pack(OriginalId, Resource) -> <<"berd", (jlib:encode_base64(<<"ejab\000", OriginalId/binary, "\000", Resource/binary>>))/binary>>. +-spec stanzaid_unpack(binary()) -> {binary(), binary()}. stanzaid_unpack(<<"berd", StanzaIdBase64/binary>>) -> StanzaId = jlib:decode_base64(StanzaIdBase64), [<<"ejab">>, OriginalId, Resource] = str:tokens(StanzaId, <<"\000">>), {OriginalId, Resource}. -change_stanzaid(NewId, Packet) -> - #xmlel{name = Name, attrs = Attrs, children = Els} = - jlib:remove_attr(<<"id">>, Packet), - #xmlel{name = Name, attrs = [{<<"id">>, NewId} | Attrs], - children = Els}. - -change_stanzaid(PreviousId, ToJID, Packet) -> +-spec change_stanzaid(jid(), iq()) -> iq(). +change_stanzaid(ToJID, #iq{id = PreviousId} = Packet) -> NewId = stanzaid_pack(PreviousId, ToJID#jid.lresource), - change_stanzaid(NewId, Packet). - -%%% -%%% - -role_to_list(Role) -> - case Role of - moderator -> <<"moderator">>; - participant -> <<"participant">>; - visitor -> <<"visitor">>; - none -> <<"none">> - end. - -affiliation_to_list(Affiliation) -> - case Affiliation of - owner -> <<"owner">>; - admin -> <<"admin">>; - member -> <<"member">>; - outcast -> <<"outcast">>; - none -> <<"none">> - end. - -list_to_role(Role) -> - case Role of - <<"moderator">> -> moderator; - <<"participant">> -> participant; - <<"visitor">> -> visitor; - <<"none">> -> none - end. - -list_to_affiliation(Affiliation) -> - case Affiliation of - <<"owner">> -> owner; - <<"admin">> -> admin; - <<"member">> -> member; - <<"outcast">> -> outcast; - <<"none">> -> none - end. + xmpp:set_id(Packet, NewId). %% Decide the fate of the message and its sender %% Returns: continue_delivery | forget_message | {expulse_sender, Reason} -decide_fate_message(<<"error">>, Packet, From, - StateData) -> - PD = case check_error_kick(Packet) of +-spec decide_fate_message(message(), jid(), state()) -> + continue_delivery | forget_message | + {expulse_sender, binary()}. +decide_fate_message(#message{type = error, error = Err}, + From, StateData) -> + PD = case check_error_kick(Err) of %% If this is an error stanza and its condition matches a criteria true -> Reason = @@ -1311,67 +1130,61 @@ decide_fate_message(<<"error">>, Packet, From, end; Other -> Other end; -decide_fate_message(_, _, _, _) -> continue_delivery. +decide_fate_message(_, _, _) -> continue_delivery. %% Check if the elements of this error stanza indicate %% that the sender is a dead participant. %% If so, return true to kick the participant. -check_error_kick(Packet) -> - case get_error_condition(Packet) of - <<"gone">> -> true; - <<"internal-server-error">> -> true; - <<"item-not-found">> -> true; - <<"jid-malformed">> -> true; - <<"recipient-unavailable">> -> true; - <<"redirect">> -> true; - <<"remote-server-not-found">> -> true; - <<"remote-server-timeout">> -> true; - <<"service-unavailable">> -> true; - _ -> false - end. +-spec check_error_kick(error()) -> boolean(). +check_error_kick(#error{reason = Reason}) -> + case Reason of + #gone{} -> true; + 'internal-server-error' -> true; + 'item-not-found' -> true; + 'jid-malformed' -> true; + 'recipient-unavailable' -> true; + #redirect{} -> true; + 'remote-server-not-found' -> true; + 'remote-server-timeout' -> true; + 'service-unavailable' -> true; + _ -> false + end; +check_error_kick(undefined) -> + false. -get_error_condition(Packet) -> - case catch get_error_condition2(Packet) of - {condition, ErrorCondition} -> ErrorCondition; - {'EXIT', _} -> <<"badformed error stanza">> - end. - -get_error_condition2(Packet) -> - #xmlel{children = EEls} = fxml:get_subtag(Packet, - <<"error">>), - [Condition] = [Name - || #xmlel{name = Name, - attrs = [{<<"xmlns">>, ?NS_STANZAS}], - children = []} - <- EEls], - {condition, Condition}. +-spec get_error_condition(error()) -> string(). +get_error_condition(#error{reason = Reason}) -> + case Reason of + #gone{} -> "gone"; + #redirect{} -> "redirect"; + Atom -> atom_to_list(Atom) + end; +get_error_condition(undefined) -> + "undefined". +-spec make_reason(stanza(), jid(), state(), binary()) -> binary(). make_reason(Packet, From, StateData, Reason1) -> {ok, #user{nick = FromNick}} = (?DICT):find(jid:tolower(From), StateData#state.users), - Condition = get_error_condition(Packet), + Condition = get_error_condition(xmpp:get_error(Packet)), iolist_to_binary(io_lib:format(Reason1, [FromNick, Condition])). +-spec expulse_participant(stanza(), jid(), state(), binary()) -> + state(). expulse_participant(Packet, From, StateData, Reason1) -> IsSubscriber = is_subscriber(From, StateData), Reason2 = make_reason(Packet, From, StateData, Reason1), NewState = add_user_presence_un(From, - #xmlel{name = <<"presence">>, - attrs = - [{<<"type">>, - <<"unavailable">>}], - children = - [#xmlel{name = <<"status">>, - attrs = [], - children = - [{xmlcdata, - Reason2}]}]}, + #presence{type = unavailable, + status = xmpp:mk_text(Reason2)}, StateData), send_new_presence(From, NewState, StateData), remove_online_user(From, NewState, IsSubscriber). +-spec set_affiliation(jid(), affiliation(), state()) -> state(). set_affiliation(JID, Affiliation, StateData) -> set_affiliation(JID, Affiliation, StateData, <<"">>). +-spec set_affiliation(jid(), affiliation(), state(), binary()) -> state(). set_affiliation(JID, Affiliation, StateData, Reason) -> LJID = jid:remove_resource(jid:tolower(JID)), Affiliations = case Affiliation of @@ -1383,6 +1196,7 @@ set_affiliation(JID, Affiliation, StateData, Reason) -> end, StateData#state{affiliations = Affiliations}. +-spec get_affiliation(jid(), state()) -> affiliation(). get_affiliation(JID, StateData) -> {_AccessRoute, _AccessCreate, AccessAdmin, _AccessPersistent} = @@ -1423,6 +1237,7 @@ get_affiliation(JID, StateData) -> _ -> Res end. +-spec get_service_affiliation(jid(), state()) -> owner | none. get_service_affiliation(JID, StateData) -> {_AccessRoute, _AccessCreate, AccessAdmin, _AccessPersistent} = @@ -1434,6 +1249,7 @@ get_service_affiliation(JID, StateData) -> _ -> none end. +-spec set_role(jid(), role(), state()) -> state(). set_role(JID, Role, StateData) -> LJID = jid:tolower(JID), LJIDs = case LJID of @@ -1482,6 +1298,7 @@ set_role(JID, Role, StateData) -> end, StateData#state{users = Users, nicks = Nicks}. +-spec get_role(jid(), state()) -> role(). get_role(JID, StateData) -> LJID = jid:tolower(JID), case (?DICT):find(LJID, StateData#state.users) of @@ -1489,6 +1306,7 @@ get_role(JID, StateData) -> _ -> none end. +-spec get_default_role(affiliation(), state()) -> role(). get_default_role(Affiliation, StateData) -> case Affiliation of owner -> moderator; @@ -1507,12 +1325,15 @@ get_default_role(Affiliation, StateData) -> end end. +-spec is_visitor(jid(), state()) -> boolean(). is_visitor(Jid, StateData) -> get_role(Jid, StateData) =:= visitor. +-spec is_moderator(jid(), state()) -> boolean(). is_moderator(Jid, StateData) -> get_role(Jid, StateData) =:= moderator. +-spec get_max_users(state()) -> non_neg_integer(). get_max_users(StateData) -> MaxUsers = (StateData#state.config)#config.max_users, ServiceMaxUsers = get_service_max_users(StateData), @@ -1520,18 +1341,21 @@ get_max_users(StateData) -> true -> ServiceMaxUsers end. +-spec get_service_max_users(state()) -> pos_integer(). get_service_max_users(StateData) -> gen_mod:get_module_opt(StateData#state.server_host, mod_muc, max_users, fun(I) when is_integer(I), I>0 -> I end, ?MAX_USERS_DEFAULT). +-spec get_max_users_admin_threshold(state()) -> pos_integer(). get_max_users_admin_threshold(StateData) -> gen_mod:get_module_opt(StateData#state.server_host, mod_muc, max_users_admin_threshold, fun(I) when is_integer(I), I>0 -> I end, 5). +-spec get_user_activity(jid(), state()) -> #activity{}. get_user_activity(JID, StateData) -> case treap:lookup(jid:tolower(JID), StateData#state.activity) @@ -1552,6 +1376,7 @@ get_user_activity(JID, StateData) -> presence_shaper = PresenceShaper} end. +-spec store_user_activity(jid(), #activity{}, state()) -> state(). store_user_activity(JID, UserActivity, StateData) -> MinMessageInterval = trunc(gen_mod:get_module_opt(StateData#state.server_host, @@ -1613,6 +1438,7 @@ store_user_activity(JID, UserActivity, StateData) -> end, StateData1. +-spec clean_treap(treap:treap(), integer()) -> treap:treap(). clean_treap(Treap, CleanPriority) -> case treap:is_empty(Treap) of true -> Treap; @@ -1624,6 +1450,7 @@ clean_treap(Treap, CleanPriority) -> end end. +-spec prepare_room_queue(state()) -> state(). prepare_room_queue(StateData) -> case queue:out(StateData#state.room_queue) of {{value, {message, From}}, _RoomQueue} -> @@ -1647,6 +1474,7 @@ prepare_room_queue(StateData) -> {empty, _} -> StateData end. +-spec update_online_user(jid(), #user{}, state()) -> state(). update_online_user(JID, #user{nick = Nick, subscriptions = Nodes, is_subscriber = IsSubscriber} = User, StateData) -> LJID = jid:tolower(JID), @@ -1681,6 +1509,7 @@ update_online_user(JID, #user{nick = Nick, subscriptions = Nodes, end, NewStateData. +-spec add_online_user(jid(), binary(), role(), boolean(), [binary()], state()) -> state(). add_online_user(JID, Nick, Role, IsSubscriber, Nodes, StateData) -> tab_add_online_user(JID, StateData), User = #user{jid = JID, nick = Nick, role = Role, @@ -1693,9 +1522,11 @@ add_online_user(JID, Nick, Role, IsSubscriber, Nodes, StateData) -> end, StateData1. +-spec remove_online_user(jid(), state(), boolean()) -> state(). remove_online_user(JID, StateData, IsSubscriber) -> remove_online_user(JID, StateData, IsSubscriber, <<"">>). +-spec remove_online_user(jid(), state(), boolean(), binary()) -> state(). remove_online_user(JID, StateData, _IsSubscriber = true, _Reason) -> LJID = jid:tolower(JID), Users = case (?DICT):find(LJID, StateData#state.users) of @@ -1723,38 +1554,23 @@ remove_online_user(JID, StateData, _IsSubscriber, Reason) -> end, StateData#state{users = Users, nicks = Nicks}. -filter_presence(#xmlel{name = <<"presence">>, - attrs = Attrs, children = Els}) -> - FEls = lists:filter(fun (El) -> - case El of - {xmlcdata, _} -> false; - #xmlel{attrs = Attrs1} -> - XMLNS = fxml:get_attr_s(<<"xmlns">>, - Attrs1), - NS_MUC = ?NS_MUC, - Size = byte_size(NS_MUC), - case XMLNS of - <> -> - false; - _ -> - true - end - end - end, - Els), - #xmlel{name = <<"presence">>, attrs = Attrs, - children = FEls}. +-spec filter_presence(presence()) -> presence(). +filter_presence(Presence) -> + Els = lists:filter( + fun(El) -> + XMLNS = xmpp:get_ns(El), + case catch binary:part(XMLNS, 0, size(?NS_MUC)) of + ?NS_MUC -> false; + _ -> true + end + end, xmpp:get_els(Presence)), + xmpp:set_els(Presence, Els). -strip_status(#xmlel{name = <<"presence">>, - attrs = Attrs, children = Els}) -> - FEls = lists:filter(fun (#xmlel{name = <<"status">>}) -> - false; - (_) -> true - end, - Els), - #xmlel{name = <<"presence">>, attrs = Attrs, - children = FEls}. +-spec strip_status(presence()) -> presence(). +strip_status(Presence) -> + Presence#presence{status = []}. +-spec add_user_presence(jid(), presence(), state()) -> state(). add_user_presence(JID, Presence, StateData) -> LJID = jid:tolower(JID), FPresence = filter_presence(Presence), @@ -1765,6 +1581,7 @@ add_user_presence(JID, Presence, StateData) -> StateData#state.users), StateData#state{users = Users}. +-spec add_user_presence_un(jid(), presence(), state()) -> state(). add_user_presence_un(JID, Presence, StateData) -> LJID = jid:tolower(JID), FPresence = filter_presence(Presence), @@ -1778,15 +1595,17 @@ add_user_presence_un(JID, Presence, StateData) -> %% Find and return a list of the full JIDs of the users of Nick. %% Return jid record. +-spec find_jids_by_nick(binary(), state()) -> [jid()]. find_jids_by_nick(Nick, StateData) -> case (?DICT):find(Nick, StateData#state.nicks) of {ok, [User]} -> [jid:make(User)]; {ok, Users} -> [jid:make(LJID) || LJID <- Users]; - error -> false + error -> [] end. %% Find and return the full JID of the user of Nick with %% highest-priority presence. Return jid record. +-spec find_jid_by_nick(binary(), state()) -> jid() | false. find_jid_by_nick(Nick, StateData) -> case (?DICT):find(Nick, StateData#state.nicks) of {ok, [User]} -> jid:make(User); @@ -1811,6 +1630,8 @@ find_jid_by_nick(Nick, StateData) -> error -> false end. +-spec higher_presence(undefined | presence(), + undefined | presence()) -> boolean(). higher_presence(Pres1, Pres2) when Pres1 /= undefined, Pres2 /= undefined -> Pri1 = get_priority_from_presence(Pres1), Pri2 = get_priority_from_presence(Pres2), @@ -1818,26 +1639,20 @@ higher_presence(Pres1, Pres2) when Pres1 /= undefined, Pres2 /= undefined -> higher_presence(Pres1, Pres2) -> Pres1 > Pres2. -get_priority_from_presence(PresencePacket) -> - case fxml:get_subtag(PresencePacket, <<"priority">>) of - false -> 0; - SubEl -> - case catch - jlib:binary_to_integer(fxml:get_tag_cdata(SubEl)) - of - P when is_integer(P) -> P; - _ -> 0 - end +-spec get_priority_from_presence(presence()) -> integer(). +get_priority_from_presence(#presence{priority = Prio}) -> + case Prio of + undefined -> 0; + _ -> Prio end. -find_nick_by_jid(Jid, StateData) -> - [{_, #user{nick = Nick}}] = lists:filter(fun ({_, - #user{jid = FJid}}) -> - FJid == Jid - end, - (?DICT):to_list(StateData#state.users)), +-spec find_nick_by_jid(jid(), state()) -> binary(). +find_nick_by_jid(JID, StateData) -> + LJID = jid:tolower(JID), + {ok, #user{nick = Nick}} = (?DICT):find(LJID, StateData#state.users), Nick. +-spec is_nick_change(jid(), binary(), state()) -> boolean(). is_nick_change(JID, Nick, StateData) -> LJID = jid:tolower(JID), case Nick of @@ -1848,16 +1663,20 @@ is_nick_change(JID, Nick, StateData) -> Nick /= OldNick end. +-spec nick_collision(jid(), binary(), state()) -> boolean(). nick_collision(User, Nick, StateData) -> UserOfNick = find_jid_by_nick(Nick, StateData), (UserOfNick /= false andalso jid:remove_resource(jid:tolower(UserOfNick)) /= jid:remove_resource(jid:tolower(User))). -add_new_user(From, Nick, - #xmlel{name = Name, attrs = Attrs, children = Els} = Packet, - StateData) -> - Lang = fxml:get_attr_s(<<"xml:lang">>, Attrs), +-spec add_new_user(jid(), binary(), presence() | iq(), state()) -> + state() | + {error, error()} | + {ignore, state()} | + {result, xmpp_element(), state()}. +add_new_user(From, Nick, Packet, StateData) -> + Lang = xmpp:get_lang(Packet), UserRoomJID = jid:replace_resource(StateData#state.jid, Nick), MaxUsers = get_max_users(StateData), MaxAdminUsers = MaxUsers + @@ -1874,7 +1693,7 @@ add_new_user(From, Nick, fun(I) when is_integer(I), I>0 -> I end, 10), Collision = nick_collision(From, Nick, StateData), - IsSubscribeRequest = Name /= <<"presence">>, + IsSubscribeRequest = not is_record(Packet, presence), case {(ServiceAffiliation == owner orelse ((Affiliation == admin orelse Affiliation == owner) andalso NUsers < MaxAdminUsers) @@ -1887,72 +1706,72 @@ add_new_user(From, Nick, of {false, _, _, _} when NUsers >= MaxUsers orelse NUsers >= MaxAdminUsers -> Txt = <<"Too many users in this conference">>, - Err = ?ERRT_RESOURCE_CONSTRAINT(Lang, Txt), - ErrPacket = jlib:make_error_reply(Packet, Err), + Err = xmpp:err_resource_constraint(Txt, Lang), + ErrPacket = xmpp:make_error(Packet, Err), if not IsSubscribeRequest -> ejabberd_router:route(UserRoomJID, From, ErrPacket), StateData; true -> - {error, Err, StateData} + {error, Err} end; {false, _, _, _} when NConferences >= MaxConferences -> Txt = <<"You have joined too many conferences">>, - Err = ?ERRT_RESOURCE_CONSTRAINT(Lang, Txt), - ErrPacket = jlib:make_error_reply(Packet, Err), + Err = xmpp:err_resource_constraint(Txt, Lang), + ErrPacket = xmpp:make_error(Packet, Err), if not IsSubscribeRequest -> ejabberd_router:route(UserRoomJID, From, ErrPacket), StateData; true -> - {error, Err, StateData} + {error, Err} end; {false, _, _, _} -> - Err = ?ERR_SERVICE_UNAVAILABLE, - ErrPacket = jlib:make_error_reply(Packet, Err), + Err = xmpp:err_service_unavailable(), + ErrPacket = xmpp:make_error(Packet, Err), if not IsSubscribeRequest -> ejabberd_router:route(UserRoomJID, From, ErrPacket), StateData; true -> - {error, Err, StateData} + {error, Err} end; {_, _, _, none} -> Err = case Affiliation of outcast -> ErrText = <<"You have been banned from this room">>, - ?ERRT_FORBIDDEN(Lang, ErrText); + xmpp:err_forbidden(ErrText, Lang); _ -> ErrText = <<"Membership is required to enter this room">>, - ?ERRT_REGISTRATION_REQUIRED(Lang, ErrText) + xmpp:err_registration_required(ErrText, Lang) end, - ErrPacket = jlib:make_error_reply(Packet, Err), + ErrPacket = xmpp:make_error(Packet, Err), if not IsSubscribeRequest -> ejabberd_router:route(UserRoomJID, From, ErrPacket), StateData; true -> - {error, Err, StateData} + {error, Err} end; {_, true, _, _} -> ErrText = <<"That nickname is already in use by another occupant">>, - Err = ?ERRT_CONFLICT(Lang, ErrText), - ErrPacket = jlib:make_error_reply(Packet, Err), + Err = xmpp:err_conflict(ErrText, Lang), + ErrPacket = xmpp:make_error(Packet, Err), if not IsSubscribeRequest -> ejabberd_router:route(UserRoomJID, From, ErrPacket), StateData; true -> - {error, Err, StateData} + {error, Err} end; {_, _, false, _} -> ErrText = <<"That nickname is registered by another person">>, - Err = ?ERRT_CONFLICT(Lang, ErrText), - ErrPacket = jlib:make_error_reply(Packet, Err), + Err = xmpp:err_conflict(ErrText, Lang), + ErrPacket = xmpp:make_error(Packet, Err), if not IsSubscribeRequest -> ejabberd_router:route(UserRoomJID, From, ErrPacket), StateData; true -> - {error, Err, StateData} + {error, Err} end; {_, _, _, Role} -> case check_password(ServiceAffiliation, Affiliation, - Els, From, StateData) + Packet, From, StateData) of true -> Nodes = get_subscription_nodes(Packet), @@ -1965,7 +1784,7 @@ add_new_user(From, Nick, Nodes, StateData)), send_existing_presences(From, NewState), send_initial_presence(From, NewState, StateData), - Shift = count_stanza_shift(Nick, Els, NewState), + Shift = count_stanza_shift(Nick, Packet, NewState), case send_history(From, Shift, NewState) of true -> ok; _ -> send_subject(From, StateData) @@ -1985,20 +1804,20 @@ add_new_user(From, Nick, NewStateData#state{robots = Robots} end, if not IsSubscribeRequest -> ResultState; - true -> {result, subscription_nodes_to_events(Nodes), ResultState} + true -> {result, subscribe_result(Packet), ResultState} end; nopass -> ErrText = <<"A password is required to enter this room">>, - Err = ?ERRT_NOT_AUTHORIZED(Lang, ErrText), - ErrPacket = jlib:make_error_reply(Packet, Err), + Err = xmpp:err_not_authorized(ErrText, Lang), + ErrPacket = xmpp:make_error(Packet, Err), if not IsSubscribeRequest -> ejabberd_router:route(UserRoomJID, From, ErrPacket), StateData; true -> - {error, Err, StateData} + {error, Err} end; captcha_required -> - SID = fxml:get_attr_s(<<"id">>, Attrs), + SID = xmpp:get_id(Packet), RoomJID = StateData#state.jid, To = jid:replace_resource(RoomJID, Nick), Limiter = {From#jid.luser, From#jid.lserver}, @@ -2006,9 +1825,7 @@ add_new_user(From, Nick, Lang, Limiter, From) of {ok, ID, CaptchaEls} -> - MsgPkt = #xmlel{name = <<"message">>, - attrs = [{<<"id">>, ID}], - children = CaptchaEls}, + MsgPkt = #message{id = ID, sub_els = CaptchaEls}, Robots = (?DICT):store(From, {Nick, Packet}, StateData#state.robots), ejabberd_router:route(RoomJID, From, MsgPkt), @@ -2020,49 +1837,51 @@ add_new_user(From, Nick, end; {error, limit} -> ErrText = <<"Too many CAPTCHA requests">>, - Err = ?ERRT_RESOURCE_CONSTRAINT(Lang, ErrText), - ErrPacket = jlib:make_error_reply(Packet, Err), + Err = xmpp:err_resource_constraint(ErrText, Lang), + ErrPacket = xmpp:make_error(Packet, Err), if not IsSubscribeRequest -> ejabberd_router:route(UserRoomJID, From, ErrPacket), StateData; true -> - {error, Err, StateData} + {error, Err} end; _ -> ErrText = <<"Unable to generate a CAPTCHA">>, - Err = ?ERRT_INTERNAL_SERVER_ERROR(Lang, ErrText), - ErrPacket = jlib:make_error_reply(Packet, Err), + Err = xmpp:err_internal_server_error(ErrText, Lang), + ErrPacket = xmpp:make_error(Packet, Err), if not IsSubscribeRequest -> ejabberd_router:route(UserRoomJID, From, ErrPacket), StateData; true -> - {error, Err, StateData} + {error, Err} end end; _ -> ErrText = <<"Incorrect password">>, - Err = ?ERRT_NOT_AUTHORIZED(Lang, ErrText), - ErrPacket = jlib:make_error_reply(Packet, Err), + Err = xmpp:err_not_authorized(ErrText, Lang), + ErrPacket = xmpp:make_error(Packet, Err), if not IsSubscribeRequest -> ejabberd_router:route(UserRoomJID, From, ErrPacket), StateData; true -> - {error, Err, StateData} + {error, Err} end end end. -check_password(owner, _Affiliation, _Els, _From, +-spec check_password(affiliation(), affiliation(), + stanza(), jid(), state()) -> boolean() | nopass. +check_password(owner, _Affiliation, _Packet, _From, _StateData) -> %% Don't check pass if user is owner in MUC service (access_admin option) true; -check_password(_ServiceAffiliation, Affiliation, Els, +check_password(_ServiceAffiliation, Affiliation, Packet, From, StateData) -> case (StateData#state.config)#config.password_protected of false -> check_captcha(Affiliation, From, StateData); true -> - Pass = extract_password(Els), + Pass = extract_password(Packet), case Pass of false -> nopass; _ -> @@ -2073,6 +1892,7 @@ check_password(_ServiceAffiliation, Affiliation, Els, end end. +-spec check_captcha(affiliation(), jid(), state()) -> true | captcha_required. check_captcha(Affiliation, From, StateData) -> case (StateData#state.config)#config.captcha_protected andalso ejabberd_captcha:is_feature_available() @@ -2101,47 +1921,52 @@ check_captcha(Affiliation, From, StateData) -> _ -> true end. -extract_password([]) -> false; -extract_password([#xmlel{attrs = Attrs} = El | Els]) -> - case fxml:get_attr_s(<<"xmlns">>, Attrs) of - ?NS_MUC -> - case fxml:get_subtag(El, <<"password">>) of - false -> false; - SubEl -> fxml:get_tag_cdata(SubEl) - end; - _ -> extract_password(Els) - end; -extract_password([_ | Els]) -> extract_password(Els). +-spec extract_password(stanza()) -> binary() | false. +extract_password(Packet) -> + case xmpp:get_subtag(Packet, #muc{}) of + #muc{password = Password} when is_binary(Password) -> + Password; + _ -> + false + end. -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:universal_time()) - - 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]). +-spec count_stanza_shift(binary(), stanza(), state()) -> non_neg_integer(). +count_stanza_shift(Nick, Packet, StateData) -> + case xmpp:get_subtag(Packet, #muc_history{}) of + #muc_history{since = Since, + seconds = Seconds, + maxstanzas = MaxStanzas, + maxchars = MaxChars} -> + HL = lqueue_to_list(StateData#state.history), + Shift0 = case Since of + undefined -> 0; + _ -> + Sin = calendar:datetime_to_gregorian_seconds( + calendar:now_to_datetime(Since)), + count_seconds_shift(Sin, HL) + end, + Shift1 = case Seconds of + undefined -> 0; + _ -> + Sec = calendar:datetime_to_gregorian_seconds( + calendar:universal_time()) - Seconds, + count_seconds_shift(Sec, HL) + end, + Shift2 = case MaxStanzas of + undefined -> 0; + _ -> count_maxstanzas_shift(MaxStanzas, HL) + end, + Shift3 = case MaxChars of + undefined -> 0; + _ -> count_maxchars_shift(Nick, MaxChars, HL) + end, + lists:max([Shift0, Shift1, Shift2, Shift3]); + false -> + 0 + end. +-spec count_seconds_shift(non_neg_integer(), + [history_element()]) -> non_neg_integer(). count_seconds_shift(Seconds, HistoryList) -> lists:sum(lists:map(fun ({_Nick, _Packet, _HaveSubject, TimeStamp, _Size}) -> @@ -2153,12 +1978,16 @@ count_seconds_shift(Seconds, HistoryList) -> end, HistoryList)). +-spec count_maxstanzas_shift(non_neg_integer(), + [history_element()]) -> non_neg_integer(). count_maxstanzas_shift(MaxStanzas, HistoryList) -> S = length(HistoryList) - MaxStanzas, if S =< 0 -> 0; true -> S end. +-spec count_maxchars_shift(binary(), non_neg_integer(), + [history_element()]) -> integer(). count_maxchars_shift(Nick, MaxSize, HistoryList) -> NLen = byte_size(Nick) + 1, Sizes = lists:map(fun ({_Nick, _Packet, _HaveSubject, @@ -2168,41 +1997,20 @@ count_maxchars_shift(Nick, MaxSize, HistoryList) -> HistoryList), calc_shift(MaxSize, Sizes). +-spec calc_shift(non_neg_integer(), [non_neg_integer()]) -> integer(). calc_shift(MaxSize, Sizes) -> Total = lists:sum(Sizes), calc_shift(MaxSize, Total, 0, Sizes). +-spec calc_shift(non_neg_integer(), integer(), integer(), + [non_neg_integer()]) -> integer(). 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([#xmlel{attrs = Attrs} = El | Els], - Type) -> - case fxml:get_attr_s(<<"xmlns">>, Attrs) of - ?NS_MUC -> - AttrVal = fxml:get_path_s(El, - [{elem, <<"history">>}, {attr, Type}]), - case Type of - <<"since">> -> - case jlib:datetime_string_to_timestamp(AttrVal) of - undefined -> false; - TS -> calendar:now_to_universal_time(TS) - end; - _ -> - case catch jlib:binary_to_integer(AttrVal) of - IntVal when is_integer(IntVal) and (IntVal >= 0) -> - IntVal; - _ -> false - end - end; - _ -> extract_history(Els, Type) - end; -extract_history([_ | Els], Type) -> - extract_history(Els, Type). - +-spec is_room_overcrowded(state()) -> boolean(). is_room_overcrowded(StateData) -> MaxUsersPresence = gen_mod:get_module_opt(StateData#state.server_host, mod_muc, max_users_presence, @@ -2210,10 +2018,12 @@ is_room_overcrowded(StateData) -> ?DEFAULT_MAX_USERS_PRESENCE), (?DICT):size(StateData#state.users) > MaxUsersPresence. +-spec presence_broadcast_allowed(jid(), state()) -> boolean(). presence_broadcast_allowed(JID, StateData) -> Role = get_role(JID, StateData), lists:member(Role, (StateData#state.config)#config.presence_broadcast). +-spec is_initial_presence(jid(), state()) -> boolean(). is_initial_presence(From, StateData) -> LJID = jid:tolower(From), case (?DICT):find(LJID, StateData#state.users) of @@ -2223,18 +2033,22 @@ is_initial_presence(From, StateData) -> true end. +-spec send_initial_presence(jid(), state(), state()) -> ok. send_initial_presence(NJID, StateData, OldStateData) -> send_new_presence1(NJID, <<"">>, true, StateData, OldStateData). +-spec send_update_presence(jid(), state(), state()) -> ok. send_update_presence(JID, StateData, OldStateData) -> send_update_presence(JID, <<"">>, StateData, OldStateData). +-spec send_update_presence(jid(), binary(), state(), state()) -> ok. send_update_presence(JID, Reason, StateData, OldStateData) -> case is_room_overcrowded(StateData) of true -> ok; false -> send_update_presence1(JID, Reason, StateData, OldStateData) end. +-spec send_update_presence1(jid(), binary(), state(), state()) -> ok. send_update_presence1(JID, Reason, StateData, OldStateData) -> LJID = jid:tolower(JID), LJIDs = case LJID of @@ -2258,12 +2072,15 @@ send_update_presence1(JID, Reason, StateData, OldStateData) -> end, LJIDs). +-spec send_new_presence(jid(), state(), state()) -> ok. send_new_presence(NJID, StateData, OldStateData) -> send_new_presence(NJID, <<"">>, false, StateData, OldStateData). +-spec send_new_presence(jid(), binary(), state(), state()) -> ok. send_new_presence(NJID, Reason, StateData, OldStateData) -> send_new_presence(NJID, Reason, false, StateData, OldStateData). +-spec send_new_presence(jid(), binary(), boolean(), state(), state()) -> ok. send_new_presence(NJID, Reason, IsInitialPresence, StateData, OldStateData) -> case is_room_overcrowded(StateData) of true -> ok; @@ -2271,6 +2088,7 @@ send_new_presence(NJID, Reason, IsInitialPresence, StateData, OldStateData) -> OldStateData) end. +-spec is_ra_changed(jid() | ljid(), boolean(), state(), state()) -> boolean(). is_ra_changed(_, _IsInitialPresence = true, _, _) -> false; is_ra_changed(LJID, _IsInitialPresence = false, NewStateData, OldStateData) -> @@ -2289,6 +2107,7 @@ is_ra_changed(LJID, _IsInitialPresence = false, NewStateData, OldStateData) -> (NewRole /= OldRole) or (NewAff /= OldAff) end. +-spec send_new_presence1(jid(), binary(), boolean(), state(), state()) -> ok. send_new_presence1(NJID, Reason, IsInitialPresence, StateData, OldStateData) -> LNJID = jid:tolower(NJID), #user{nick = Nick} = (?DICT):fetch(LNJID, StateData#state.users), @@ -2301,15 +2120,9 @@ send_new_presence1(NJID, Reason, IsInitialPresence, StateData, OldStateData) -> {Role1, Presence1} = case presence_broadcast_allowed(NJID, StateData) of true -> {Role0, Presence0}; - false -> - {none, - #xmlel{name = <<"presence">>, - attrs = [{<<"type">>, <<"unavailable">>}], - children = []} - } + false -> {none, #presence{type = unavailable}} end, Affiliation = get_affiliation(LJID, StateData), - SAffiliation = affiliation_to_list(Affiliation), UserList = case not (presence_broadcast_allowed(NJID, StateData) orelse presence_broadcast_allowed(NJID, OldStateData)) of @@ -2323,59 +2136,38 @@ send_new_presence1(NJID, Reason, IsInitialPresence, StateData, OldStateData) -> {Role, Presence} = if LNJID == LUJID -> {Role0, Presence0}; true -> {Role1, Presence1} end, - SRole = role_to_list(Role), - ItemAttrs = case Info#user.role == moderator orelse - (StateData#state.config)#config.anonymous - == false - of - true -> - [{<<"jid">>, - jid:to_string(RealJID)}, - {<<"affiliation">>, SAffiliation}, - {<<"role">>, SRole}]; - _ -> - [{<<"affiliation">>, SAffiliation}, - {<<"role">>, SRole}] - end, - ItemEls = case Reason of - <<"">> -> []; - _ -> - [#xmlel{name = <<"reason">>, - attrs = [], - children = - [{xmlcdata, Reason}]}] - end, - StatusEls = status_els(IsInitialPresence, NJID, Info, - StateData), - Pres = if Presence == undefined -> #xmlel{name = <<"presence">>}; + Item0 = #muc_item{affiliation = Affiliation, + role = Role}, + Item1 = case Info#user.role == moderator orelse + (StateData#state.config)#config.anonymous + == false of + true -> Item0#muc_item{jid = RealJID}; + false -> Item0 + end, + Item = if is_binary(Reason), Reason /= <<"">> -> + Item1#muc_item{reason = Reason}; + true -> + Item1 + end, + StatusCodes = status_codes(IsInitialPresence, NJID, Info, + StateData), + Pres = if Presence == undefined -> #presence{}; true -> Presence end, - Packet = fxml:append_subtags(Pres, - [#xmlel{name = <<"x">>, - attrs = - [{<<"xmlns">>, - ?NS_MUC_USER}], - children = - [#xmlel{name = - <<"item">>, - attrs - = - ItemAttrs, - children - = - ItemEls} - | StatusEls]}]), + Packet = xmpp:set_subtag( + Pres, #muc_user{items = [Item], + status_codes = StatusCodes}), Node1 = case is_ra_changed(NJID, IsInitialPresence, StateData, OldStateData) of true -> ?NS_MUCSUB_NODES_AFFILIATIONS; false -> ?NS_MUCSUB_NODES_PRESENCE end, send_wrapped(jid:replace_resource(StateData#state.jid, Nick), Info#user.jid, Packet, Node1, StateData), - Type = fxml:get_tag_attr_s(<<"type">>, Packet), + Type = xmpp:get_type(Packet), IsSubscriber = Info#user.is_subscriber, IsOccupant = Info#user.last_presence /= undefined, if (IsSubscriber and not IsOccupant) and - (IsInitialPresence or (Type == <<"unavailable">>)) -> + (IsInitialPresence or (Type == unavailable)) -> Node2 = ?NS_MUCSUB_NODES_PARTICIPANTS, send_wrapped(jid:replace_resource(StateData#state.jid, Nick), Info#user.jid, Packet, Node2, StateData); @@ -2385,12 +2177,14 @@ send_new_presence1(NJID, Reason, IsInitialPresence, StateData, OldStateData) -> end, UserList). +-spec send_existing_presences(jid(), state()) -> ok. send_existing_presences(ToJID, StateData) -> case is_room_overcrowded(StateData) of true -> ok; false -> send_existing_presences1(ToJID, StateData) end. +-spec send_existing_presences1(jid(), state()) -> ok. send_existing_presences1(ToJID, StateData) -> LToJID = jid:tolower(ToJID), {ok, #user{jid = RealToJID, role = Role}} = @@ -2410,46 +2204,23 @@ send_existing_presences1(ToJID, StateData) -> {_, false} -> ok; _ -> FromAffiliation = get_affiliation(LJID, StateData), - ItemAttrs = case Role == moderator orelse - (StateData#state.config)#config.anonymous - == false - of - true -> - [{<<"jid">>, - jid:to_string(FromJID)}, - {<<"affiliation">>, - affiliation_to_list(FromAffiliation)}, - {<<"role">>, - role_to_list(FromRole)}]; - _ -> - [{<<"affiliation">>, - affiliation_to_list(FromAffiliation)}, - {<<"role">>, - role_to_list(FromRole)}] - end, - Packet = fxml:append_subtags( - Presence, - [#xmlel{name = - <<"x">>, - attrs = - [{<<"xmlns">>, - ?NS_MUC_USER}], - children = - [#xmlel{name - = - <<"item">>, - attrs - = - ItemAttrs, - children - = - []}]}]), + Item0 = #muc_item{affiliation = FromAffiliation, + role = FromRole}, + Item = case Role == moderator orelse + (StateData#state.config)#config.anonymous + == false of + true -> Item0#muc_item{jid = FromJID}; + false -> Item0 + end, + Packet = xmpp:set_subtag( + Presence, #muc_user{items = [Item]}), send_wrapped(jid:replace_resource(StateData#state.jid, FromNick), RealToJID, Packet, ?NS_MUCSUB_NODES_PRESENCE, StateData) end end, (?DICT):to_list(StateData#state.nicks)). +-spec set_nick(jid(), binary(), state()) -> state(). set_nick(JID, Nick, State) -> LJID = jid:tolower(JID), {ok, #user{nick = OldNick}} = (?DICT):find(LJID, State#state.users), @@ -2472,6 +2243,7 @@ set_nick(JID, Nick, State) -> end, State#state{users = Users, nicks = Nicks}. +-spec change_nick(jid(), binary(), state()) -> state(). change_nick(JID, Nick, StateData) -> LJID = jid:tolower(JID), {ok, #user{nick = OldNick}} = (?DICT):find(LJID, StateData#state.users), @@ -2492,6 +2264,7 @@ change_nick(JID, Nick, StateData) -> add_to_log(nickchange, {OldNick, Nick}, StateData), NewStateData. +-spec send_nick_changing(jid(), binary(), state(), boolean(), boolean()) -> ok. send_nick_changing(JID, OldNick, StateData, SendOldUnavailable, SendNewAvailable) -> {ok, @@ -2500,104 +2273,52 @@ send_nick_changing(JID, OldNick, StateData, (?DICT):find(jid:tolower(JID), StateData#state.users), Affiliation = get_affiliation(JID, StateData), - SAffiliation = affiliation_to_list(Affiliation), - SRole = role_to_list(Role), - lists:foreach(fun ({_LJID, Info}) when Presence /= undefined -> - ItemAttrs1 = case Info#user.role == moderator orelse - (StateData#state.config)#config.anonymous - == false - of - true -> - [{<<"jid">>, - jid:to_string(RealJID)}, - {<<"affiliation">>, SAffiliation}, - {<<"role">>, SRole}, - {<<"nick">>, Nick}]; - _ -> - [{<<"affiliation">>, SAffiliation}, - {<<"role">>, SRole}, - {<<"nick">>, Nick}] - end, - ItemAttrs2 = case Info#user.role == moderator orelse - (StateData#state.config)#config.anonymous - == false - of - true -> - [{<<"jid">>, - jid:to_string(RealJID)}, - {<<"affiliation">>, SAffiliation}, - {<<"role">>, SRole}]; - _ -> - [{<<"affiliation">>, SAffiliation}, - {<<"role">>, SRole}] - end, - Status110 = case JID == Info#user.jid of - true -> - [#xmlel{name = <<"status">>, - attrs = [{<<"code">>, <<"110">>}] - }]; - false -> - [] - end, - Packet1 = #xmlel{name = <<"presence">>, - attrs = - [{<<"type">>, - <<"unavailable">>}], - children = - [#xmlel{name = <<"x">>, - attrs = - [{<<"xmlns">>, - ?NS_MUC_USER}], - children = - [#xmlel{name = - <<"item">>, - attrs = - ItemAttrs1, - children = - []}, - #xmlel{name = - <<"status">>, - attrs = - [{<<"code">>, - <<"303">>}], - children = - []}|Status110]}]}, - Packet2 = fxml:append_subtags(Presence, - [#xmlel{name = <<"x">>, - attrs = - [{<<"xmlns">>, - ?NS_MUC_USER}], - children = - [#xmlel{name - = - <<"item">>, - attrs - = - ItemAttrs2, - children - = - []}|Status110]}]), - if SendOldUnavailable -> - send_wrapped(jid:replace_resource(StateData#state.jid, - OldNick), - Info#user.jid, Packet1, - ?NS_MUCSUB_NODES_PRESENCE, - StateData); - true -> ok + lists:foreach( + fun({_LJID, Info}) when Presence /= undefined -> + Item0 = #muc_item{affiliation = Affiliation, role = Role}, + Item1 = case Info#user.role == moderator orelse + (StateData#state.config)#config.anonymous + == false of + true -> Item0#muc_item{jid = RealJID, nick = Nick}; + false -> Item0#muc_item{nick = Nick} + end, + Item2 = case Info#user.role == moderator orelse + (StateData#state.config)#config.anonymous + == false of + true -> Item0#muc_item{jid = RealJID}; + false -> Item0 + end, + Status110 = case JID == Info#user.jid of + true -> [110]; + false -> [] end, - if SendNewAvailable -> - send_wrapped(jid:replace_resource(StateData#state.jid, - Nick), - Info#user.jid, Packet2, - ?NS_MUCSUB_NODES_PRESENCE, - StateData); - true -> ok - end; - (_) -> - ok - end, - (?DICT):to_list(StateData#state.users)). + Packet1 = #presence{type = unavailable, + sub_els = [#muc_user{ + items = [Item1], + status_codes = [303|Status110]}]}, + Packet2 = xmpp:set_subtag(Presence, + #muc_user{items = [Item2], + status_codes = Status110}), + if SendOldUnavailable -> + send_wrapped( + jid:replace_resource(StateData#state.jid, OldNick), + Info#user.jid, Packet1, ?NS_MUCSUB_NODES_PRESENCE, + StateData); + true -> ok + end, + if SendNewAvailable -> + send_wrapped( + jid:replace_resource(StateData#state.jid, Nick), + Info#user.jid, Packet2, ?NS_MUCSUB_NODES_PRESENCE, + StateData); + true -> ok + end; + (_) -> + ok + end, + (?DICT):to_list(StateData#state.users)). +-spec maybe_send_affiliation(jid(), affiliation(), state()) -> ok. maybe_send_affiliation(JID, Affiliation, StateData) -> LJID = jid:tolower(JID), IsOccupant = case LJID of @@ -2617,18 +2338,13 @@ maybe_send_affiliation(JID, Affiliation, StateData) -> send_affiliation(LJID, Affiliation, StateData) end. +-spec send_affiliation(ljid(), affiliation(), state()) -> ok. send_affiliation(LJID, Affiliation, StateData) -> - ItemAttrs = [{<<"jid">>, jid:to_string(LJID)}, - {<<"affiliation">>, affiliation_to_list(Affiliation)}, - {<<"role">>, <<"none">>}], - Message = #xmlel{name = <<"message">>, - attrs = [{<<"id">>, randoms:get_string()}], - children = - [#xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_MUC_USER}], - children = - [#xmlel{name = <<"item">>, - attrs = ItemAttrs}]}]}, + Item = #muc_item{jid = jid:make(LJID), + affiliation = Affiliation, + role = none}, + Message = #message{id = randoms:get_string(), + sub_els = [#muc_user{items = [Item]}]}, Recipients = case (StateData#state.config)#config.anonymous of true -> (?DICT):filter(fun(_, #user{role = moderator}) -> @@ -2643,43 +2359,33 @@ send_affiliation(LJID, Affiliation, StateData) -> StateData#state.server_host, Recipients, Message). -status_els(IsInitialPresence, JID, #user{jid = JID}, StateData) -> - Status = case IsInitialPresence of - true -> - S1 = case StateData#state.just_created of - true -> - [#xmlel{name = <<"status">>, - attrs = [{<<"code">>, <<"201">>}], - children = []}]; - false -> [] - end, - S2 = case (StateData#state.config)#config.anonymous of - true -> S1; - false -> - [#xmlel{name = <<"status">>, - attrs = [{<<"code">>, <<"100">>}], - children = []} | S1] - end, - S3 = case (StateData#state.config)#config.logging of - true -> - [#xmlel{name = <<"status">>, - attrs = [{<<"code">>, <<"170">>}], - children = []} | S2]; - false -> S2 - end, - S3; - false -> [] - end, - [#xmlel{name = <<"status">>, - attrs = - [{<<"code">>, - <<"110">>}], - children = []} | Status]; -status_els(_IsInitialPresence, _JID, _Info, _StateData) -> []. +-spec status_codes(boolean(), jid(), #user{}, state()) -> [pos_integer()]. +status_codes(IsInitialPresence, JID, #user{jid = JID}, StateData) -> + S0 = [110], + case IsInitialPresence of + true -> + S1 = case StateData#state.just_created of + true -> [201|S0]; + false -> S0 + end, + S2 = case (StateData#state.config)#config.anonymous of + true -> S1; + false -> [100|S1] + end, + S3 = case (StateData#state.config)#config.logging of + true -> [170|S2]; + false -> S2 + end, + S3; + false -> S0 + end; +status_codes(_IsInitialPresence, _JID, _Info, _StateData) -> []. +-spec lqueue_new(non_neg_integer()) -> lqueue(). lqueue_new(Max) -> #lqueue{queue = queue:new(), len = 0, max = Max}. +-spec lqueue_in(term(), lqueue()) -> lqueue(). %% If the message queue limit is set to 0, do not store messages. lqueue_in(_Item, LQ = #lqueue{max = 0}) -> LQ; %% Otherwise, rotate messages in the queue store. @@ -2692,39 +2398,33 @@ lqueue_in(Item, true -> #lqueue{queue = Q2, len = Len + 1, max = Max} end. +-spec lqueue_cut(queue:queue(), non_neg_integer()) -> queue:queue(). lqueue_cut(Q, 0) -> Q; lqueue_cut(Q, N) -> {_, Q1} = queue:out(Q), lqueue_cut(Q1, N - 1). +-spec lqueue_to_list(lqueue()) -> list(). lqueue_to_list(#lqueue{queue = Q1}) -> queue:to_list(Q1). - +-spec add_message_to_history(binary(), jid(), message(), state()) -> state(). add_message_to_history(FromNick, FromJID, Packet, StateData) -> - HaveSubject = case fxml:get_subtag(Packet, <<"subject">>) - of - false -> false; - _ -> true - end, + HaveSubject = Packet#message.subject /= [], TimeStamp = p1_time_compat:timestamp(), AddrPacket = case (StateData#state.config)#config.anonymous of true -> Packet; false -> - Address = #xmlel{name = <<"address">>, - attrs = [{<<"type">>, <<"ofrom">>}, - {<<"jid">>, - jid:to_string(FromJID)}], - children = []}, - Addresses = #xmlel{name = <<"addresses">>, - attrs = [{<<"xmlns">>, ?NS_ADDRESS}], - children = [Address]}, - fxml:append_subtags(Packet, [Addresses]) + Addresses = #addresses{ + list = [#address{type = ofrom, + jid = FromJID}]}, + xmpp:set_subtag(Packet, Addresses) end, - TSPacket = jlib:add_delay_info(AddrPacket, StateData#state.jid, TimeStamp), - SPacket = - jlib:replace_from_to(jid:replace_resource(StateData#state.jid, - FromNick), - StateData#state.jid, TSPacket), + TSPacket = xmpp_util:add_delay_info( + AddrPacket, StateData#state.jid, TimeStamp), + SPacket = xmpp:set_from_to( + TSPacket, + jid:replace_resource(StateData#state.jid, FromNick), + StateData#state.jid), Size = element_size(SPacket), Q1 = lqueue_in({FromNick, TSPacket, HaveSubject, calendar:now_to_universal_time(TimeStamp), Size}, @@ -2732,6 +2432,7 @@ add_message_to_history(FromNick, FromJID, Packet, StateData) -> add_to_log(text, {FromNick, Packet}, StateData), StateData#state{history = Q1}. +-spec send_history(jid(), integer(), state()) -> boolean(). send_history(JID, Shift, StateData) -> lists:foldl(fun ({Nick, Packet, HaveSubject, _TimeStamp, _Size}, @@ -2745,23 +2446,19 @@ send_history(JID, Shift, StateData) -> lists:nthtail(Shift, lqueue_to_list(StateData#state.history))). +-spec send_subject(jid(), state()) -> ok. send_subject(_JID, #state{subject_author = <<"">>}) -> ok; send_subject(JID, #state{subject_author = Nick} = StateData) -> Subject = StateData#state.subject, - Packet = #xmlel{name = <<"message">>, - attrs = [{<<"type">>, <<"groupchat">>}], - children = - [#xmlel{name = <<"subject">>, attrs = [], - children = [{xmlcdata, Subject}]}]}, + Packet = #message{type = groupchat, subject = xmpp:mk_text(Subject)}, ejabberd_router:route(jid:replace_resource(StateData#state.jid, Nick), JID, Packet). -check_subject(Packet) -> - case fxml:get_subtag(Packet, <<"subject">>) of - false -> false; - SubjEl -> fxml:get_tag_cdata(SubjEl) - end. +-spec check_subject(message()) -> false | binary(). +check_subject(#message{subject = []}) -> false; +check_subject(#message{subject = Subj}) -> xmpp:get_text(Subj). +-spec can_change_subject(role(), state()) -> boolean(). can_change_subject(Role, StateData) -> case (StateData#state.config)#config.allow_change_subj of @@ -2772,99 +2469,89 @@ can_change_subject(Role, StateData) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Admin stuff -process_iq_admin(From, set, Lang, SubEl, StateData) -> - #xmlel{children = Items} = SubEl, +-spec process_iq_admin(jid(), iq(), #state{}) -> {error, error()} | + {result, undefined, #state{}} | + {result, muc_admin()}. +process_iq_admin(_From, #iq{lang = Lang, sub_els = [#muc_admin{items = []}]}, + _StateData) -> + Txt = <<"No 'item' element found">>, + {error, xmpp:err_bad_request(Txt, Lang)}; +process_iq_admin(From, #iq{type = set, lang = Lang, + sub_els = [#muc_admin{items = Items}]}, + StateData) -> process_admin_items_set(From, Items, Lang, StateData); -process_iq_admin(From, get, Lang, SubEl, StateData) -> - case fxml:get_subtag(SubEl, <<"item">>) of - false -> - Txt = <<"No 'item' element found">>, - {error, ?ERRT_BAD_REQUEST(Lang, Txt)}; - Item -> - FAffiliation = get_affiliation(From, StateData), - FRole = get_role(From, StateData), - case fxml:get_tag_attr(<<"role">>, Item) of - false -> - case fxml:get_tag_attr(<<"affiliation">>, Item) of - false -> - Txt = <<"No 'affiliation' attribute found">>, - {error, ?ERRT_BAD_REQUEST(Lang, Txt)}; - {value, StrAffiliation} -> - case catch list_to_affiliation(StrAffiliation) of - {'EXIT', _} -> {error, ?ERR_BAD_REQUEST}; - SAffiliation -> - if (FAffiliation == owner) or - (FAffiliation == admin) or - ((FAffiliation == member) and not - (StateData#state.config)#config.anonymous) -> - Items = items_with_affiliation(SAffiliation, - StateData), - {result, Items, StateData}; - true -> - ErrText = - <<"Administrator privileges required">>, - {error, ?ERRT_FORBIDDEN(Lang, ErrText)} - end - end - end; - {value, StrRole} -> - case catch list_to_role(StrRole) of - {'EXIT', _} -> - Txt = <<"Incorrect value of 'role' attribute">>, - {error, ?ERRT_BAD_REQUEST(Lang, Txt)}; - SRole -> - if FRole == moderator -> - Items = items_with_role(SRole, StateData), - {result, Items, StateData}; - true -> - ErrText = <<"Moderator privileges required">>, - {error, ?ERRT_FORBIDDEN(Lang, ErrText)} - end - end - end - end. +process_iq_admin(From, #iq{type = get, lang = Lang, + sub_els = [#muc_admin{items = [Item]}]}, + StateData) -> + FAffiliation = get_affiliation(From, StateData), + FRole = get_role(From, StateData), + case Item of + #muc_item{role = undefined, affiliation = undefined} -> + Txt = <<"Neither 'role' nor 'affiliation' attribute found">>, + {error, xmpp:err_bad_request(Txt, Lang)}; + #muc_item{role = undefined, affiliation = Affiliation} -> + if (FAffiliation == owner) or + (FAffiliation == admin) or + ((FAffiliation == member) and + not (StateData#state.config)#config.anonymous) -> + Items = items_with_affiliation(Affiliation, StateData), + {result, #muc_admin{items = Items}}; + true -> + ErrText = <<"Administrator privileges required">>, + {error, xmpp:err_forbidden(ErrText, Lang)} + end; + #muc_item{role = Role} -> + if FRole == moderator -> + Items = items_with_role(Role, StateData), + {result, #muc_admin{items = Items}}; + true -> + ErrText = <<"Moderator privileges required">>, + {error, xmpp:err_forbidden(ErrText, Lang)} + end + end; +process_iq_admin(_From, #iq{type = get, lang = Lang}, _StateData) -> + ErrText = <<"Too many elements">>, + {error, xmpp:err_bad_request(ErrText, Lang)}. +-spec items_with_role(role(), state()) -> [muc_item()]. items_with_role(SRole, StateData) -> lists:map(fun ({_, U}) -> user_to_item(U, StateData) end, search_role(SRole, StateData)). +-spec items_with_affiliation(affiliation(), state()) -> [muc_item()]. items_with_affiliation(SAffiliation, StateData) -> - lists:map(fun ({JID, {Affiliation, Reason}}) -> - #xmlel{name = <<"item">>, - attrs = - [{<<"affiliation">>, - affiliation_to_list(Affiliation)}, - {<<"jid">>, jid:to_string(JID)}], - children = - [#xmlel{name = <<"reason">>, attrs = [], - children = [{xmlcdata, Reason}]}]}; - ({JID, Affiliation}) -> - #xmlel{name = <<"item">>, - attrs = - [{<<"affiliation">>, - affiliation_to_list(Affiliation)}, - {<<"jid">>, jid:to_string(JID)}], - children = []} - end, - search_affiliation(SAffiliation, StateData)). + lists:map( + fun({JID, {Affiliation, Reason}}) -> + #muc_item{affiliation = Affiliation, jid = JID, + reason = if is_binary(Reason), Reason /= <<"">> -> + Reason; + true -> + undefined + end}; + ({JID, Affiliation}) -> + #muc_item{affiliation = Affiliation, jid = JID} + end, + search_affiliation(SAffiliation, StateData)). +-spec user_to_item(#user{}, state()) -> muc_item(). user_to_item(#user{role = Role, nick = Nick, jid = JID}, StateData) -> Affiliation = get_affiliation(JID, StateData), - #xmlel{name = <<"item">>, - attrs = - [{<<"role">>, role_to_list(Role)}, - {<<"affiliation">>, affiliation_to_list(Affiliation)}, - {<<"nick">>, Nick}, - {<<"jid">>, jid:to_string(JID)}], - children = []}. + #muc_item{role = Role, + affiliation = Affiliation, + nick = Nick, + jid = JID}. +-spec search_role(role(), state()) -> [{ljid(), #user{}}]. search_role(Role, StateData) -> lists:filter(fun ({_, #user{role = R}}) -> Role == R end, (?DICT):to_list(StateData#state.users)). +-spec search_affiliation(affiliation(), state()) -> + [{ljid(), + affiliation() | {affiliation(), binary()}}]. search_affiliation(Affiliation, StateData) -> lists:filter(fun ({_, A}) -> case A of @@ -2874,11 +2561,14 @@ search_affiliation(Affiliation, StateData) -> end, (?DICT):to_list(StateData#state.affiliations)). +-spec process_admin_items_set(jid(), [muc_item()], binary() | undefined, + #state{}) -> {result, undefined, #state{}} | + {error, error()}. process_admin_items_set(UJID, Items, Lang, StateData) -> UAffiliation = get_affiliation(UJID, StateData), URole = get_role(UJID, StateData), - case find_changed_items(UJID, UAffiliation, URole, - Items, Lang, StateData, []) + case catch find_changed_items(UJID, UAffiliation, URole, + Items, Lang, StateData, []) of {result, Res} -> ?INFO_MSG("Processing MUC admin query from ~s in " @@ -2888,249 +2578,161 @@ process_admin_items_set(UJID, Items, Lang, StateData) -> NSD = lists:foldl(process_item_change(UJID), StateData, lists:flatten(Res)), store_room(NSD), - {result, [], NSD}; - Err -> Err + {result, undefined, NSD}; + {error, Err} -> {error, Err} end. +-spec process_item_change(jid()) -> function(). process_item_change(UJID) -> fun(E, SD) -> process_item_change(E, SD, UJID) end. -process_item_change(E, SD, UJID) -> - case catch case E of - {JID, affiliation, owner, _} when JID#jid.luser == <<"">> -> - %% If the provided JID does not have username, - %% forget the affiliation completely - SD; - {JID, role, none, Reason} -> - catch - send_kickban_presence(UJID, JID, - Reason, - <<"307">>, - SD), - set_role(JID, none, SD); - {JID, affiliation, none, Reason} -> - case (SD#state.config)#config.members_only of - true -> - catch - send_kickban_presence(UJID, JID, - Reason, - <<"321">>, - none, - SD), - maybe_send_affiliation(JID, none, SD), - SD1 = set_affiliation(JID, none, SD), - set_role(JID, none, SD1); - _ -> - SD1 = set_affiliation(JID, none, SD), - send_update_presence(JID, SD1, SD), - maybe_send_affiliation(JID, none, SD1), - SD1 - end; - {JID, affiliation, outcast, Reason} -> - catch - send_kickban_presence(UJID, JID, - Reason, - <<"301">>, - outcast, - SD), - maybe_send_affiliation(JID, outcast, SD), - set_affiliation(JID, - outcast, - set_role(JID, none, SD), - Reason); - {JID, affiliation, A, Reason} - when (A == admin) or (A == owner) -> - SD1 = set_affiliation(JID, A, SD, Reason), - SD2 = set_role(JID, moderator, SD1), - send_update_presence(JID, Reason, SD2, SD), - maybe_send_affiliation(JID, A, SD2), - SD2; - {JID, affiliation, member, Reason} -> - SD1 = set_affiliation(JID, member, SD, Reason), - SD2 = set_role(JID, participant, SD1), - send_update_presence(JID, Reason, SD2, SD), - maybe_send_affiliation(JID, member, SD2), - SD2; - {JID, role, Role, Reason} -> - SD1 = set_role(JID, Role, SD), - catch - send_new_presence(JID, Reason, SD1, SD), - SD1; - {JID, affiliation, A, _Reason} -> - SD1 = set_affiliation(JID, A, SD), - send_update_presence(JID, SD1, SD), - maybe_send_affiliation(JID, A, SD1), - SD1 - end - of - {'EXIT', ErrReason} -> - ?ERROR_MSG("MUC ITEMS SET ERR: ~p~n", [ErrReason]), - SD; - NSD -> NSD +-type admin_action() :: {jid(), affiliation | role, + affiliation() | role(), binary()}. + +-spec process_item_change(admin_action(), state(), jid()) -> state(). +process_item_change(Item, SD, UJID) -> + try case Item of + {JID, affiliation, owner, _} when JID#jid.luser == <<"">> -> + %% If the provided JID does not have username, + %% forget the affiliation completely + SD; + {JID, role, none, Reason} -> + catch send_kickban_presence(UJID, JID, Reason, 307, SD), + set_role(JID, none, SD); + {JID, affiliation, none, Reason} -> + case (SD#state.config)#config.members_only of + true -> + catch send_kickban_presence(UJID, JID, Reason, 321, none, SD), + maybe_send_affiliation(JID, none, SD), + SD1 = set_affiliation(JID, none, SD), + set_role(JID, none, SD1); + _ -> + SD1 = set_affiliation(JID, none, SD), + send_update_presence(JID, SD1, SD), + maybe_send_affiliation(JID, none, SD1), + SD1 + end; + {JID, affiliation, outcast, Reason} -> + catch send_kickban_presence(UJID, JID, Reason, 301, outcast, SD), + maybe_send_affiliation(JID, outcast, SD), + set_affiliation(JID, outcast, set_role(JID, none, SD), Reason); + {JID, affiliation, A, Reason} when (A == admin) or (A == owner) -> + SD1 = set_affiliation(JID, A, SD, Reason), + SD2 = set_role(JID, moderator, SD1), + send_update_presence(JID, Reason, SD2, SD), + maybe_send_affiliation(JID, A, SD2), + SD2; + {JID, affiliation, member, Reason} -> + SD1 = set_affiliation(JID, member, SD, Reason), + SD2 = set_role(JID, participant, SD1), + send_update_presence(JID, Reason, SD2, SD), + maybe_send_affiliation(JID, member, SD2), + SD2; + {JID, role, Role, Reason} -> + SD1 = set_role(JID, Role, SD), + catch send_new_presence(JID, Reason, SD1, SD), + SD1; + {JID, affiliation, A, _Reason} -> + SD1 = set_affiliation(JID, A, SD), + send_update_presence(JID, SD1, SD), + maybe_send_affiliation(JID, A, SD1), + SD1 + end + catch E:R -> + ?ERROR_MSG("failed to set item ~p from ~s: ~p", + [Item, jid:to_string(UJID), + {E, {R, erlang:get_stacktrace()}}]), + SD end. +-spec find_changed_items(jid(), affiliation(), role(), + [muc_item()], binary(), state(), [admin_action()]) -> + {result, [admin_action()]}. find_changed_items(_UJID, _UAffiliation, _URole, [], _Lang, _StateData, Res) -> {result, Res}; +find_changed_items(_UJID, _UAffiliation, _URole, + [#muc_item{jid = undefined, nick = undefined}|_], + Lang, _StateData, _Res) -> + Txt = <<"Neither 'jid' nor 'nick' attribute found">>, + throw({error, xmpp:err_bad_request(Txt, Lang)}); +find_changed_items(_UJID, _UAffiliation, _URole, + [#muc_item{role = undefined, affiliation = undefined}|_], + Lang, _StateData, _Res) -> + Txt = <<"Neither 'role' nor 'affiliation' attribute found">>, + throw({error, xmpp:err_bad_request(Txt, Lang)}); find_changed_items(UJID, UAffiliation, URole, - [{xmlcdata, _} | Items], Lang, StateData, Res) -> - find_changed_items(UJID, UAffiliation, URole, Items, - Lang, StateData, Res); -find_changed_items(UJID, UAffiliation, URole, - [#xmlel{name = <<"item">>, attrs = Attrs} = Item - | Items], + [#muc_item{jid = J, nick = Nick, reason = Reason0, + role = Role, affiliation = Affiliation}|Items], Lang, StateData, Res) -> - TJID = case fxml:get_attr(<<"jid">>, Attrs) of - {value, S} -> - case jid:from_string(S) of - error -> - ErrText = iolist_to_binary( - io_lib:format(translate:translate( - Lang, - <<"Jabber ID ~s is invalid">>), - [S])), - {error, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)}; - J -> {value, [J]} - end; - _ -> - case fxml:get_attr(<<"nick">>, Attrs) of - {value, N} -> - case find_jids_by_nick(N, StateData) of - false -> - ErrText = iolist_to_binary( - io_lib:format( - translate:translate( - Lang, - <<"Nickname ~s does not exist in the room">>), - [N])), - {error, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)}; - J -> {value, J} - end; - _ -> - Txt1 = <<"No 'nick' attribute found">>, - {error, ?ERRT_BAD_REQUEST(Lang, Txt1)} - end - end, - case TJID of - {value, [JID | _] = JIDs} -> - TAffiliation = get_affiliation(JID, StateData), - TRole = get_role(JID, StateData), - case fxml:get_attr(<<"role">>, Attrs) of - false -> - case fxml:get_attr(<<"affiliation">>, Attrs) of - false -> - Txt2 = <<"No 'affiliation' attribute found">>, - {error, ?ERRT_BAD_REQUEST(Lang, Txt2)}; - {value, StrAffiliation} -> - case catch list_to_affiliation(StrAffiliation) of - {'EXIT', _} -> - ErrText1 = iolist_to_binary( - io_lib:format( - translate:translate( - Lang, - <<"Invalid affiliation: ~s">>), - [StrAffiliation])), - {error, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText1)}; - SAffiliation -> - ServiceAf = get_service_affiliation(JID, StateData), - CanChangeRA = case can_change_ra(UAffiliation, - URole, - TAffiliation, - TRole, affiliation, - SAffiliation, - ServiceAf) - of - nothing -> nothing; - true -> true; - check_owner -> - case search_affiliation(owner, - StateData) - of - [{OJID, _}] -> - jid:remove_resource(OJID) - /= - jid:tolower(jid:remove_resource(UJID)); - _ -> true - end; - _ -> false - end, - case CanChangeRA of - nothing -> - find_changed_items(UJID, UAffiliation, URole, - Items, Lang, StateData, - Res); - true -> - Reason = fxml:get_path_s(Item, - [{elem, <<"reason">>}, - cdata]), - MoreRes = [{jid:remove_resource(Jidx), - affiliation, SAffiliation, Reason} - || Jidx <- JIDs], - find_changed_items(UJID, UAffiliation, URole, - Items, Lang, StateData, - [MoreRes | Res]); - false -> - Txt3 = <<"Changing role/affiliation is not allowed">>, - {error, ?ERRT_NOT_ALLOWED(Lang, Txt3)} - end - end - end; - {value, StrRole} -> - case catch list_to_role(StrRole) of - {'EXIT', _} -> - ErrText1 = iolist_to_binary( - io_lib:format(translate:translate( - Lang, - <<"Invalid role: ~s">>), - [StrRole])), - {error, ?ERRT_BAD_REQUEST(Lang, ErrText1)}; - SRole -> - ServiceAf = get_service_affiliation(JID, StateData), - CanChangeRA = case can_change_ra(UAffiliation, URole, - TAffiliation, TRole, - role, SRole, ServiceAf) - of - nothing -> nothing; - true -> true; - check_owner -> - case search_affiliation(owner, - StateData) - of - [{OJID, _}] -> - jid:remove_resource(OJID) - /= - jid:tolower(jid:remove_resource(UJID)); - _ -> true - end; - _ -> false - end, - case CanChangeRA of - nothing -> - find_changed_items(UJID, UAffiliation, URole, Items, - Lang, StateData, Res); - true -> - Reason = fxml:get_path_s(Item, - [{elem, <<"reason">>}, - cdata]), - MoreRes = [{Jidx, role, SRole, Reason} - || Jidx <- JIDs], - find_changed_items(UJID, UAffiliation, URole, Items, - Lang, StateData, - [MoreRes | Res]); - _ -> - Txt4 = <<"Changing role/affiliation is not allowed">>, - {error, ?ERRT_NOT_ALLOWED(Lang, Txt4)} - end + [JID | _] = JIDs = + if J /= undefined -> + [J]; + Nick /= undefined -> + case find_jids_by_nick(Nick, StateData) of + [] -> + ErrText = iolist_to_binary( + io_lib:format( + translate:translate( + Lang, + <<"Nickname ~s does not exist in the room">>), + [Nick])), + throw({error, xmpp:err_not_acceptable(ErrText, Lang)}); + JIDList -> + JIDList end - end; - Err -> Err - end; -find_changed_items(_UJID, _UAffiliation, _URole, _Items, - _Lang, _StateData, _Res) -> - {error, ?ERR_BAD_REQUEST}. + end, + {RoleOrAff, RoleOrAffValue} = if Role == undefined -> + {affiliation, Affiliation}; + true -> + {role, Role} + end, + TAffiliation = get_affiliation(JID, StateData), + TRole = get_role(JID, StateData), + ServiceAf = get_service_affiliation(JID, StateData), + CanChangeRA = case can_change_ra(UAffiliation, + URole, + TAffiliation, + TRole, RoleOrAff, RoleOrAffValue, + ServiceAf) of + nothing -> nothing; + true -> true; + check_owner -> + case search_affiliation(owner, StateData) of + [{OJID, _}] -> + jid:remove_resource(OJID) + /= + jid:tolower(jid:remove_resource(UJID)); + _ -> true + end; + _ -> false + end, + case CanChangeRA of + nothing -> + find_changed_items(UJID, UAffiliation, URole, + Items, Lang, StateData, + Res); + true -> + Reason = if is_binary(Reason0) -> Reason0; + true -> <<"">> + end, + MoreRes = [{jid:remove_resource(Jidx), + RoleOrAff, RoleOrAffValue, Reason} + || Jidx <- JIDs], + find_changed_items(UJID, UAffiliation, URole, + Items, Lang, StateData, + [MoreRes | Res]); + false -> + Txt = <<"Changing role/affiliation is not allowed">>, + throw({error, xmpp:err_not_allowed(Txt, Lang)}) + end. +-spec can_change_ra(affiliation(), role(), affiliation(), role(), + affiliation, affiliation(), affiliation()) -> boolean(); + (affiliation(), role(), affiliation(), role(), + role, role(), affiliation()) -> boolean(). can_change_ra(_FAffiliation, _FRole, owner, _TRole, affiliation, owner, owner) -> %% A room owner tries to add as persistent owner a @@ -3255,11 +2857,15 @@ can_change_ra(_FAffiliation, _FRole, _TAffiliation, _TRole, role, _Value, _ServiceAf) -> false. +-spec send_kickban_presence(jid(), jid(), binary(), + pos_integer(), state()) -> ok. send_kickban_presence(UJID, JID, Reason, Code, StateData) -> NewAffiliation = get_affiliation(JID, StateData), send_kickban_presence(UJID, JID, Reason, Code, NewAffiliation, StateData). +-spec send_kickban_presence(jid(), jid(), binary(), pos_integer(), + affiliation(), state()) -> ok. send_kickban_presence(UJID, JID, Reason, Code, NewAffiliation, StateData) -> LJID = jid:tolower(JID), @@ -3288,77 +2894,51 @@ send_kickban_presence(UJID, JID, Reason, Code, NewAffiliation, end, LJIDs). +-spec send_kickban_presence1(jid(), jid(), binary(), pos_integer(), + affiliation(), state()) -> ok. send_kickban_presence1(MJID, UJID, Reason, Code, Affiliation, StateData) -> {ok, #user{jid = RealJID, nick = Nick}} = (?DICT):find(jid:tolower(UJID), StateData#state.users), - SAffiliation = affiliation_to_list(Affiliation), - BannedJIDString = jid:to_string(RealJID), ActorNick = get_actor_nick(MJID, StateData), - lists:foreach(fun ({_LJID, Info}) -> - JidAttrList = case Info#user.role == moderator orelse - (StateData#state.config)#config.anonymous - == false - of - true -> - [{<<"jid">>, BannedJIDString}]; - false -> [] - end, - ItemAttrs = [{<<"affiliation">>, SAffiliation}, - {<<"role">>, <<"none">>}] - ++ JidAttrList, - ItemEls = case Reason of - <<"">> -> []; - _ -> - [#xmlel{name = <<"reason">>, - attrs = [], - children = - [{xmlcdata, Reason}]}] - end, - ItemElsActor = case MJID of - <<"">> -> []; - _ -> [#xmlel{name = <<"actor">>, - attrs = - [{<<"nick">>, ActorNick}]}] - end, - Packet = #xmlel{name = <<"presence">>, - attrs = - [{<<"type">>, <<"unavailable">>}], - children = - [#xmlel{name = <<"x">>, - attrs = - [{<<"xmlns">>, - ?NS_MUC_USER}], - children = - [#xmlel{name = - <<"item">>, - attrs = - ItemAttrs, - children = - ItemElsActor ++ ItemEls}, - #xmlel{name = - <<"status">>, - attrs = - [{<<"code">>, - Code}], - children = - []}]}]}, - RoomJIDNick = jid:replace_resource( - StateData#state.jid, Nick), - send_wrapped(RoomJIDNick, Info#user.jid, Packet, - ?NS_MUCSUB_NODES_AFFILIATIONS, StateData), - IsSubscriber = Info#user.is_subscriber, - IsOccupant = Info#user.last_presence /= undefined, - if (IsSubscriber and not IsOccupant) -> - send_wrapped(RoomJIDNick, Info#user.jid, Packet, - ?NS_MUCSUB_NODES_PARTICIPANTS, StateData); - true -> - ok - end - end, - (?DICT):to_list(StateData#state.users)). + lists:foreach( + fun({_LJID, Info}) -> + Item0 = #muc_item{affiliation = Affiliation, + role = none}, + Item1 = case Info#user.role == moderator orelse + (StateData#state.config)#config.anonymous + == false of + true -> Item0#muc_item{jid = RealJID}; + false -> Item0 + end, + Item2 = if is_binary(Reason), Reason /= <<"">> -> + Item1#muc_item{reason = Reason}; + true -> + Item1 + end, + Item = case ActorNick of + <<"">> -> Item2; + _ -> Item2#muc_item{actor = #muc_actor{nick = ActorNick}} + end, + Packet = #presence{type = unavailable, + sub_els = [#muc_user{items = [Item], + status_codes = [Code]}]}, + RoomJIDNick = jid:replace_resource(StateData#state.jid, Nick), + send_wrapped(RoomJIDNick, Info#user.jid, Packet, + ?NS_MUCSUB_NODES_AFFILIATIONS, StateData), + IsSubscriber = Info#user.is_subscriber, + IsOccupant = Info#user.last_presence /= undefined, + if (IsSubscriber and not IsOccupant) -> + send_wrapped(RoomJIDNick, Info#user.jid, Packet, + ?NS_MUCSUB_NODES_PARTICIPANTS, StateData); + true -> + ok + end + end, + (?DICT):to_list(StateData#state.users)). +-spec get_actor_nick(binary() | jid(), state()) -> binary(). get_actor_nick(<<"">>, _StateData) -> <<"">>; get_actor_nick(MJID, StateData) -> @@ -3369,97 +2949,86 @@ get_actor_nick(MJID, StateData) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Owner stuff - -process_iq_owner(From, set, Lang, SubEl, StateData) -> +-spec process_iq_owner(jid(), iq(), state()) -> + {result, undefined | muc_owner()} | + {result, undefined | muc_owner(), state() | stop} | + {error, error()}. +process_iq_owner(From, #iq{type = set, lang = Lang, + sub_els = [#muc_owner{destroy = Destroy, + config = Config, + items = Items}]}, + StateData) -> FAffiliation = get_affiliation(From, StateData), - case FAffiliation of - owner -> - #xmlel{children = Els} = SubEl, - case fxml:remove_cdata(Els) of - [#xmlel{name = <<"x">>} = XEl] -> - case {fxml:get_tag_attr_s(<<"xmlns">>, XEl), - fxml:get_tag_attr_s(<<"type">>, XEl)} - of - {?NS_XDATA, <<"cancel">>} -> {result, [], StateData}; - {?NS_XDATA, <<"submit">>} -> - case is_allowed_log_change(XEl, StateData, From) andalso - is_allowed_persistent_change(XEl, StateData, From) - andalso - is_allowed_room_name_desc_limits(XEl, StateData) - andalso - is_password_settings_correct(XEl, StateData) - of - true -> set_config(XEl, StateData, Lang); - false -> {error, ?ERR_NOT_ACCEPTABLE} - end; - _ -> - Txt = <<"Incorrect data form">>, - {error, ?ERRT_BAD_REQUEST(Lang, Txt)} - end; - [#xmlel{name = <<"destroy">>} = SubEl1] -> - ?INFO_MSG("Destroyed MUC room ~s by the owner ~s", - [jid:to_string(StateData#state.jid), - jid:to_string(From)]), - add_to_log(room_existence, destroyed, StateData), - destroy_room(SubEl1, StateData); - Items -> - process_admin_items_set(From, Items, Lang, StateData) - end; - _ -> - ErrText = <<"Owner privileges required">>, - {error, ?ERRT_FORBIDDEN(Lang, ErrText)} + if FAffiliation /= owner -> + ErrText = <<"Owner privileges required">>, + {error, xmpp:err_forbidden(ErrText, Lang)}; + Destroy /= undefined, Config == undefined, Items == [] -> + ?INFO_MSG("Destroyed MUC room ~s by the owner ~s", + [jid:to_string(StateData#state.jid), jid:to_string(From)]), + add_to_log(room_existence, destroyed, StateData), + destroy_room(Destroy, StateData); + Config /= undefined, Destroy == undefined, Items == [] -> + case Config of + #xdata{type = cancel} -> + {result, undefined}; + #xdata{type = submit} -> + case is_allowed_log_change(Config, StateData, From) andalso + is_allowed_persistent_change(Config, StateData, From) andalso + is_allowed_room_name_desc_limits(Config, StateData) andalso + is_password_settings_correct(Config, StateData) of + true -> set_config(Config, StateData, Lang); + false -> {error, xmpp:err_not_acceptable()} + end; + _ -> + Txt = <<"Incorrect data form">>, + {error, xmpp:err_bad_request(Txt, Lang)} + end; + Items /= [], Config == undefined, Destroy == undefined -> + process_admin_items_set(From, Items, Lang, StateData); + true -> + {error, xmpp:err_bad_request()} end; -process_iq_owner(From, get, Lang, SubEl, StateData) -> +process_iq_owner(From, #iq{type = get, lang = Lang, + sub_els = [#muc_owner{destroy = Destroy, + config = Config, + items = Items}]}, + StateData) -> FAffiliation = get_affiliation(From, StateData), - case FAffiliation of - owner -> - #xmlel{children = Els} = SubEl, - case fxml:remove_cdata(Els) of - [] -> get_config(Lang, StateData, From); - [Item] -> - case fxml:get_tag_attr(<<"affiliation">>, Item) of - false -> - Txt = <<"No 'affiliation' attribute found">>, - {error, ?ERRT_BAD_REQUEST(Lang, Txt)}; - {value, StrAffiliation} -> - case catch list_to_affiliation(StrAffiliation) of - {'EXIT', _} -> - ErrText = iolist_to_binary( - io_lib:format( - translate:translate( - Lang, - <<"Invalid affiliation: ~s">>), - [StrAffiliation])), - {error, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)}; - SAffiliation -> - Items = items_with_affiliation(SAffiliation, - StateData), - {result, Items, StateData} - end - end; - _ -> {error, ?ERR_FEATURE_NOT_IMPLEMENTED} - end; - _ -> - ErrText = <<"Owner privileges required">>, - {error, ?ERRT_FORBIDDEN(Lang, ErrText)} + if FAffiliation /= owner -> + ErrText = <<"Owner privileges required">>, + {error, xmpp:err_forbidden(ErrText, Lang)}; + Destroy == undefined, Config == undefined -> + case Items of + [] -> + {result, + #muc_owner{config = get_config(Lang, StateData, From)}}; + [#muc_item{affiliation = undefined}] -> + Txt = <<"No 'affiliation' attribute found">>, + {error, xmpp:err_bad_request(Txt, Lang)}; + [#muc_item{affiliation = Affiliation}] -> + Items = items_with_affiliation(Affiliation, StateData), + {result, #muc_owner{items = Items}}; + [_|_] -> + Txt = <<"Too many elements">>, + {error, xmpp:err_bad_request(Txt, Lang)} + end; + true -> + {error, xmpp:err_bad_request()} end. -is_allowed_log_change(XEl, StateData, From) -> - case lists:keymember(<<"muc#roomconfig_enablelogging">>, - 1, jlib:parse_xdata_submit(XEl)) - of - false -> true; - true -> - allow == - mod_muc_log:check_access_log(StateData#state.server_host, - From) +-spec is_allowed_log_change(xdata(), state(), jid()) -> boolean(). +is_allowed_log_change(X, StateData, From) -> + case xmpp_util:has_xdata_var(<<"muc#roomconfig_enablelogging">>, X) of + false -> true; + true -> + allow == + mod_muc_log:check_access_log(StateData#state.server_host, + From) end. -is_allowed_persistent_change(XEl, StateData, From) -> - case - lists:keymember(<<"muc#roomconfig_persistentroom">>, 1, - jlib:parse_xdata_submit(XEl)) - of +-spec is_allowed_persistent_change(xdata(), state(), jid()) -> boolean(). +is_allowed_persistent_change(X, StateData, From) -> + case xmpp_util:has_xdata_var(<<"muc#roomconfig_persistentroom">>, X) of false -> true; true -> {_AccessRoute, _AccessCreate, _AccessAdmin, @@ -3472,58 +3041,57 @@ is_allowed_persistent_change(XEl, StateData, From) -> %% Check if the Room Name and Room Description defined in the Data Form %% are conformant to the configured limits -is_allowed_room_name_desc_limits(XEl, StateData) -> - IsNameAccepted = case - lists:keysearch(<<"muc#roomconfig_roomname">>, 1, - jlib:parse_xdata_submit(XEl)) - of - {value, {_, [N]}} -> - byte_size(N) =< - gen_mod:get_module_opt(StateData#state.server_host, - mod_muc, max_room_name, - fun(infinity) -> infinity; - (I) when is_integer(I), - I>0 -> I - end, infinity); - _ -> true +-spec is_allowed_room_name_desc_limits(xdata(), state()) -> boolean(). +is_allowed_room_name_desc_limits(XData, StateData) -> + IsNameAccepted = case xmpp_util:get_xdata_values( + <<"muc#roomconfig_roomname">>, XData) of + [N] -> + byte_size(N) =< + gen_mod:get_module_opt( + StateData#state.server_host, + mod_muc, max_room_name, + fun(infinity) -> infinity; + (I) when is_integer(I), + I>0 -> I + end, infinity); + _ -> + true end, - IsDescAccepted = case - lists:keysearch(<<"muc#roomconfig_roomdesc">>, 1, - jlib:parse_xdata_submit(XEl)) - of - {value, {_, [D]}} -> - byte_size(D) =< - gen_mod:get_module_opt(StateData#state.server_host, - mod_muc, max_room_desc, - fun(infinity) -> infinity; - (I) when is_integer(I), - I>0 -> - I - end, infinity); - _ -> true + IsDescAccepted = case xmpp_util:get_xdata_values( + <<"muc#roomconfig_roomdesc">>, XData) of + [D] -> + byte_size(D) =< + gen_mod:get_module_opt( + StateData#state.server_host, + mod_muc, max_room_desc, + fun(infinity) -> infinity; + (I) when is_integer(I), + I>0 -> + I + end, infinity); + _ -> true end, IsNameAccepted and IsDescAccepted. %% Return false if: %% "the password for a password-protected room is blank" -is_password_settings_correct(XEl, StateData) -> +-spec is_password_settings_correct(xdata(), state()) -> boolean(). +is_password_settings_correct(XData, StateData) -> Config = StateData#state.config, OldProtected = Config#config.password_protected, OldPassword = Config#config.password, - NewProtected = case - lists:keysearch(<<"muc#roomconfig_passwordprotectedroom">>, - 1, jlib:parse_xdata_submit(XEl)) - of - {value, {_, [<<"1">>]}} -> true; - {value, {_, [<<"0">>]}} -> false; - _ -> undefined + NewProtected = case xmpp_util:get_xdata_values( + <<"muc#roomconfig_passwordprotectedroom">>, XData) of + [<<"1">>] -> true; + [<<"true">>] -> true; + [<<"0">>] -> false; + [<<"false">>] -> false; + _ -> undefined end, - NewPassword = case - lists:keysearch(<<"muc#roomconfig_roomsecret">>, 1, - jlib:parse_xdata_submit(XEl)) - of - {value, {_, [P]}} -> P; - _ -> undefined + NewPassword = case xmpp_util:get_xdata_values( + <<"muc#roomconfig_roomsecret">>, XData) of + [P] -> P; + _ -> undefined end, case {OldProtected, NewProtected, OldPassword, NewPassword} @@ -3535,40 +3103,35 @@ is_password_settings_correct(XEl, StateData) -> _ -> true end. --define(XFIELD(Type, Label, Var, Val), - #xmlel{name = <<"field">>, - attrs = - [{<<"type">>, Type}, - {<<"label">>, translate:translate(Lang, Label)}, - {<<"var">>, Var}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = [{xmlcdata, Val}]}]}). +-define(XFIELD(Type, Label, Var, Vals), + #xdata_field{type = Type, + label = translate:translate(Lang, Label), + var = Var, + values = Vals}). -define(BOOLXFIELD(Label, Var, Val), - ?XFIELD(<<"boolean">>, Label, Var, + ?XFIELD(boolean, Label, Var, case Val of - true -> <<"1">>; - _ -> <<"0">> + true -> [<<"1">>]; + _ -> [<<"0">>] end)). -define(STRINGXFIELD(Label, Var, Val), - ?XFIELD(<<"text-single">>, Label, Var, Val)). + ?XFIELD('text-single', Label, Var, [Val])). -define(PRIVATEXFIELD(Label, Var, Val), - ?XFIELD(<<"text-private">>, Label, Var, Val)). + ?XFIELD('text-private', Label, Var, [Val])). -define(JIDMULTIXFIELD(Label, Var, JIDList), - #xmlel{name = <<"field">>, - attrs = - [{<<"type">>, <<"jid-multi">>}, - {<<"label">>, translate:translate(Lang, Label)}, - {<<"var">>, Var}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = [{xmlcdata, jid:to_string(JID)}]} - || JID <- JIDList]}). + ?XFIELD('jid-multi', Label, Var, + [jid:to_string(JID) || JID <- JIDList])). +-spec make_options([{binary(), binary()}], binary()) -> [xdata_option()]. +make_options(Options, Lang) -> + [#xdata_option{label = translate:translate(Lang, Label), + value = Value} || {Label, Value} <- Options]. + +-spec get_default_room_maxusers(state()) -> non_neg_integer(). get_default_room_maxusers(RoomState) -> DefRoomOpts = gen_mod:get_module_opt(RoomState#state.server_host, @@ -3578,342 +3141,193 @@ get_default_room_maxusers(RoomState) -> RoomState2 = set_opts(DefRoomOpts, RoomState), (RoomState2#state.config)#config.max_users. +-spec get_config(binary(), state(), jid()) -> xdata(). get_config(Lang, StateData, From) -> - {_AccessRoute, _AccessCreate, _AccessAdmin, - AccessPersistent} = + {_AccessRoute, _AccessCreate, _AccessAdmin, AccessPersistent} = StateData#state.access, ServiceMaxUsers = get_service_max_users(StateData), - DefaultRoomMaxUsers = - get_default_room_maxusers(StateData), + DefaultRoomMaxUsers = get_default_room_maxusers(StateData), Config = StateData#state.config, - {MaxUsersRoomInteger, MaxUsersRoomString} = case - get_max_users(StateData) - of - N when is_integer(N) -> - {N, - jlib:integer_to_binary(N)}; - _ -> {0, <<"none">>} - end, - Res = [#xmlel{name = <<"title">>, attrs = [], - children = - [{xmlcdata, - iolist_to_binary( - io_lib:format( - translate:translate( - Lang, - <<"Configuration of room ~s">>), - [jid:to_string(StateData#state.jid)]))}]}, - #xmlel{name = <<"field">>, - attrs = - [{<<"type">>, <<"hidden">>}, - {<<"var">>, <<"FORM_TYPE">>}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = - [{xmlcdata, - <<"http://jabber.org/protocol/muc#roomconfig">>}]}]}, - ?STRINGXFIELD(<<"Room title">>, - <<"muc#roomconfig_roomname">>, (Config#config.title)), - ?STRINGXFIELD(<<"Room description">>, - <<"muc#roomconfig_roomdesc">>, - (Config#config.description))] - ++ - case acl:match_rule(StateData#state.server_host, - AccessPersistent, From) - of - allow -> - [?BOOLXFIELD(<<"Make room persistent">>, - <<"muc#roomconfig_persistentroom">>, - (Config#config.persistent))]; - _ -> [] - end - ++ - [?BOOLXFIELD(<<"Make room public searchable">>, - <<"muc#roomconfig_publicroom">>, - (Config#config.public)), - ?BOOLXFIELD(<<"Make participants list public">>, - <<"public_list">>, (Config#config.public_list)), - ?BOOLXFIELD(<<"Make room password protected">>, - <<"muc#roomconfig_passwordprotectedroom">>, - (Config#config.password_protected)), - ?PRIVATEXFIELD(<<"Password">>, - <<"muc#roomconfig_roomsecret">>, - case Config#config.password_protected of - true -> Config#config.password; - false -> <<"">> - end), - #xmlel{name = <<"field">>, - attrs = - [{<<"type">>, <<"list-single">>}, - {<<"label">>, - translate:translate(Lang, - <<"Maximum Number of Occupants">>)}, - {<<"var">>, <<"muc#roomconfig_maxusers">>}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = [{xmlcdata, MaxUsersRoomString}]}] - ++ - if is_integer(ServiceMaxUsers) -> []; - true -> - [#xmlel{name = <<"option">>, - attrs = - [{<<"label">>, - translate:translate(Lang, - <<"No limit">>)}], - children = - [#xmlel{name = <<"value">>, - attrs = [], - children = - [{xmlcdata, - <<"none">>}]}]}] - end - ++ - [#xmlel{name = <<"option">>, - attrs = - [{<<"label">>, - jlib:integer_to_binary(N)}], - children = - [#xmlel{name = <<"value">>, - attrs = [], - children = - [{xmlcdata, - jlib:integer_to_binary(N)}]}]} - || N - <- lists:usort([ServiceMaxUsers, - DefaultRoomMaxUsers, - MaxUsersRoomInteger - | ?MAX_USERS_DEFAULT_LIST]), - N =< ServiceMaxUsers]}, - #xmlel{name = <<"field">>, - attrs = - [{<<"type">>, <<"list-single">>}, - {<<"label">>, - translate:translate(Lang, - <<"Present real Jabber IDs to">>)}, - {<<"var">>, <<"muc#roomconfig_whois">>}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = - [{xmlcdata, - if Config#config.anonymous -> - <<"moderators">>; - true -> <<"anyone">> - end}]}, - #xmlel{name = <<"option">>, - attrs = - [{<<"label">>, - translate:translate(Lang, - <<"moderators only">>)}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = - [{xmlcdata, - <<"moderators">>}]}]}, - #xmlel{name = <<"option">>, - attrs = - [{<<"label">>, - translate:translate(Lang, - <<"anyone">>)}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = - [{xmlcdata, - <<"anyone">>}]}]}]}, - #xmlel{name = <<"field">>, - attrs = - [{<<"type">>, <<"list-multi">>}, - {<<"label">>, - translate:translate(Lang, - <<"Roles for which Presence is Broadcasted">>)}, - {<<"var">>, <<"muc#roomconfig_presencebroadcast">>}], - children = - lists:map( - fun(Role) -> - #xmlel{name = <<"value">>, attrs = [], - children = - [{xmlcdata, - atom_to_binary(Role, utf8)}]} - end, Config#config.presence_broadcast - ) ++ - [#xmlel{name = <<"option">>, - attrs = - [{<<"label">>, - translate:translate(Lang, - <<"Moderator">>)}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = - [{xmlcdata, - <<"moderator">>}]}]}, - #xmlel{name = <<"option">>, - attrs = - [{<<"label">>, - translate:translate(Lang, - <<"Participant">>)}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = - [{xmlcdata, - <<"participant">>}]}]}, - #xmlel{name = <<"option">>, - attrs = - [{<<"label">>, - translate:translate(Lang, - <<"Visitor">>)}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = - [{xmlcdata, - <<"visitor">>}]}]} - ]}, - ?BOOLXFIELD(<<"Make room members-only">>, - <<"muc#roomconfig_membersonly">>, - (Config#config.members_only)), - ?BOOLXFIELD(<<"Make room moderated">>, - <<"muc#roomconfig_moderatedroom">>, - (Config#config.moderated)), - ?BOOLXFIELD(<<"Default users as participants">>, - <<"members_by_default">>, - (Config#config.members_by_default)), - ?BOOLXFIELD(<<"Allow users to change the subject">>, - <<"muc#roomconfig_changesubject">>, - (Config#config.allow_change_subj)), - ?BOOLXFIELD(<<"Allow users to send private messages">>, - <<"allow_private_messages">>, - (Config#config.allow_private_messages)), - #xmlel{name = <<"field">>, - attrs = - [{<<"type">>, <<"list-single">>}, - {<<"label">>, - translate:translate(Lang, - <<"Allow visitors to send private messages to">>)}, - {<<"var">>, - <<"allow_private_messages_from_visitors">>}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = - [{xmlcdata, - case - Config#config.allow_private_messages_from_visitors - of - anyone -> <<"anyone">>; - moderators -> <<"moderators">>; - nobody -> <<"nobody">> - end}]}, - #xmlel{name = <<"option">>, - attrs = - [{<<"label">>, - translate:translate(Lang, - <<"nobody">>)}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = - [{xmlcdata, <<"nobody">>}]}]}, - #xmlel{name = <<"option">>, - attrs = - [{<<"label">>, - translate:translate(Lang, - <<"moderators only">>)}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = - [{xmlcdata, - <<"moderators">>}]}]}, - #xmlel{name = <<"option">>, - attrs = - [{<<"label">>, - translate:translate(Lang, - <<"anyone">>)}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = - [{xmlcdata, - <<"anyone">>}]}]}]}, - ?BOOLXFIELD(<<"Allow users to query other users">>, - <<"allow_query_users">>, - (Config#config.allow_query_users)), - ?BOOLXFIELD(<<"Allow users to send invites">>, - <<"muc#roomconfig_allowinvites">>, - (Config#config.allow_user_invites)), - ?BOOLXFIELD(<<"Allow visitors to send status text in " - "presence updates">>, - <<"muc#roomconfig_allowvisitorstatus">>, - (Config#config.allow_visitor_status)), - ?BOOLXFIELD(<<"Allow visitors to change nickname">>, - <<"muc#roomconfig_allowvisitornickchange">>, - (Config#config.allow_visitor_nickchange)), - ?BOOLXFIELD(<<"Allow visitors to send voice requests">>, - <<"muc#roomconfig_allowvoicerequests">>, - (Config#config.allow_voice_requests)), - ?BOOLXFIELD(<<"Allow subscription">>, - <<"muc#roomconfig_allow_subscription">>, - (Config#config.allow_subscription)), - ?STRINGXFIELD(<<"Minimum interval between voice requests " - "(in seconds)">>, - <<"muc#roomconfig_voicerequestmininterval">>, - (jlib:integer_to_binary(Config#config.voice_request_min_interval)))] - ++ - case ejabberd_captcha:is_feature_available() of - true -> - [?BOOLXFIELD(<<"Make room CAPTCHA protected">>, - <<"captcha_protected">>, - (Config#config.captcha_protected))]; - false -> [] - end ++ - [?JIDMULTIXFIELD(<<"Exclude Jabber IDs from CAPTCHA challenge">>, - <<"muc#roomconfig_captcha_whitelist">>, - ((?SETS):to_list(Config#config.captcha_whitelist)))] - ++ - case - mod_muc_log:check_access_log(StateData#state.server_host, - From) - of - allow -> - [?BOOLXFIELD(<<"Enable logging">>, - <<"muc#roomconfig_enablelogging">>, - (Config#config.logging))]; - _ -> [] - end, - X = ejabberd_hooks:run_fold(get_room_config, - StateData#state.server_host, - Res, - [StateData, From, Lang]), - {result, - [#xmlel{name = <<"instructions">>, attrs = [], - children = - [{xmlcdata, - translate:translate(Lang, - <<"You need an x:data capable client to " - "configure room">>)}]}, - #xmlel{name = <<"x">>, - attrs = - [{<<"xmlns">>, ?NS_XDATA}, {<<"type">>, <<"form">>}], - children = X}], - StateData}. + {MaxUsersRoomInteger, MaxUsersRoomString} = + case get_max_users(StateData) of + N when is_integer(N) -> + {N, integer_to_binary(N)}; + _ -> {0, <<"none">>} + end, + Title = iolist_to_binary( + io_lib:format( + translate:translate(Lang, <<"Configuration of room ~s">>), + [jid:to_string(StateData#state.jid)])), + Fs = [#xdata_field{type = hidden, + var = <<"FORM_TYPE">>, + values = [<<"http://jabber.org/protocol/muc#roomconfig">>]}, + ?STRINGXFIELD(<<"Room title">>, + <<"muc#roomconfig_roomname">>, (Config#config.title)), + ?STRINGXFIELD(<<"Room description">>, + <<"muc#roomconfig_roomdesc">>, + (Config#config.description))] ++ + case acl:match_rule(StateData#state.server_host, AccessPersistent, From) of + allow -> + [?BOOLXFIELD(<<"Make room persistent">>, + <<"muc#roomconfig_persistentroom">>, + (Config#config.persistent))]; + deny -> [] + end ++ + [?BOOLXFIELD(<<"Make room public searchable">>, + <<"muc#roomconfig_publicroom">>, + (Config#config.public)), + ?BOOLXFIELD(<<"Make participants list public">>, + <<"public_list">>, (Config#config.public_list)), + ?BOOLXFIELD(<<"Make room password protected">>, + <<"muc#roomconfig_passwordprotectedroom">>, + (Config#config.password_protected)), + ?PRIVATEXFIELD(<<"Password">>, + <<"muc#roomconfig_roomsecret">>, + case Config#config.password_protected of + true -> Config#config.password; + false -> <<"">> + end), + #xdata_field{type = 'list-single', + label = translate:translate( + Lang, <<"Maximum Number of Occupants">>), + var = <<"muc#roomconfig_maxusers">>, + values = [MaxUsersRoomString], + options = + if is_integer(ServiceMaxUsers) -> []; + true -> make_options( + [{<<"No limit">>, <<"none">>}], + Lang) + end ++ + make_options( + [{integer_to_binary(N), integer_to_binary(N)} + || N <- lists:usort([ServiceMaxUsers, + DefaultRoomMaxUsers, + MaxUsersRoomInteger + | ?MAX_USERS_DEFAULT_LIST]), + N =< ServiceMaxUsers], + Lang)}, + #xdata_field{type = 'list-single', + label = translate:translate( + Lang, <<"Present real Jabber IDs to">>), + var = <<"muc#roomconfig_whois">>, + values = [if Config#config.anonymous -> <<"moderators">>; + true -> <<"anyone">> + end], + options = make_options( + [{<<"moderators only">>, <<"moderators">>}, + {<<"anyone">>, <<"anyone">>}], + Lang)}, + #xdata_field{type = 'list-multi', + label = translate:translate( + Lang, + <<"Roles for which Presence is Broadcasted">>), + var = <<"muc#roomconfig_presencebroadcast">>, + values = [atom_to_binary(Role, utf8) + || Role <- Config#config.presence_broadcast], + options = make_options( + [{<<"Moderator">>, <<"moderator">>}, + {<<"Participant">>, <<"participant">>}, + {<<"Visitor">>, <<"visitor">>}], + Lang)}, + ?BOOLXFIELD(<<"Make room members-only">>, + <<"muc#roomconfig_membersonly">>, + (Config#config.members_only)), + ?BOOLXFIELD(<<"Make room moderated">>, + <<"muc#roomconfig_moderatedroom">>, + (Config#config.moderated)), + ?BOOLXFIELD(<<"Default users as participants">>, + <<"members_by_default">>, + (Config#config.members_by_default)), + ?BOOLXFIELD(<<"Allow users to change the subject">>, + <<"muc#roomconfig_changesubject">>, + (Config#config.allow_change_subj)), + ?BOOLXFIELD(<<"Allow users to send private messages">>, + <<"allow_private_messages">>, + (Config#config.allow_private_messages)), + #xdata_field{type = 'list-single', + label = translate:translate( + Lang, + <<"Allow visitors to send private messages to">>), + var = <<"allow_private_messages_from_visitors">>, + values = [case Config#config.allow_private_messages_from_visitors of + anyone -> <<"anyone">>; + moderators -> <<"moderators">>; + nobody -> <<"nobody">> + end], + options = make_options( + [{<<"nobody">>, <<"nobody">>}, + {<<"moderators only">>, <<"moderators">>}, + {<<"anyone">>, <<"anyone">>}], + Lang)}, + ?BOOLXFIELD(<<"Allow users to query other users">>, + <<"allow_query_users">>, + (Config#config.allow_query_users)), + ?BOOLXFIELD(<<"Allow users to send invites">>, + <<"muc#roomconfig_allowinvites">>, + (Config#config.allow_user_invites)), + ?BOOLXFIELD(<<"Allow visitors to send status text in " + "presence updates">>, + <<"muc#roomconfig_allowvisitorstatus">>, + (Config#config.allow_visitor_status)), + ?BOOLXFIELD(<<"Allow visitors to change nickname">>, + <<"muc#roomconfig_allowvisitornickchange">>, + (Config#config.allow_visitor_nickchange)), + ?BOOLXFIELD(<<"Allow visitors to send voice requests">>, + <<"muc#roomconfig_allowvoicerequests">>, + (Config#config.allow_voice_requests)), + ?BOOLXFIELD(<<"Allow subscription">>, + <<"muc#roomconfig_allow_subscription">>, + (Config#config.allow_subscription)), + ?STRINGXFIELD(<<"Minimum interval between voice requests " + "(in seconds)">>, + <<"muc#roomconfig_voicerequestmininterval">>, + integer_to_binary(Config#config.voice_request_min_interval))] + ++ + case ejabberd_captcha:is_feature_available() of + true -> + [?BOOLXFIELD(<<"Make room CAPTCHA protected">>, + <<"captcha_protected">>, + (Config#config.captcha_protected))]; + false -> [] + end ++ + [?JIDMULTIXFIELD(<<"Exclude Jabber IDs from CAPTCHA challenge">>, + <<"muc#roomconfig_captcha_whitelist">>, + ((?SETS):to_list(Config#config.captcha_whitelist)))] + ++ + case mod_muc_log:check_access_log(StateData#state.server_host, From) of + allow -> + [?BOOLXFIELD(<<"Enable logging">>, + <<"muc#roomconfig_enablelogging">>, + (Config#config.logging))]; + deny -> [] + end, + Fields = ejabberd_hooks:run_fold(get_room_config, + StateData#state.server_host, + Fs, + [StateData, From, Lang]), + #xdata{type = form, title = Title, fields = Fields}. -set_config(XEl, StateData, Lang) -> - XData = jlib:parse_xdata_submit(XEl), - case XData of - invalid -> {error, ?ERRT_BAD_REQUEST(Lang, <<"Incorrect data form">>)}; - _ -> - case set_xoption(XData, StateData#state.config, - StateData#state.server_host, Lang) of - #config{} = Config -> - Res = change_config(Config, StateData), - {result, _, NSD} = Res, - Type = case {(StateData#state.config)#config.logging, - Config#config.logging} - of - {true, false} -> roomconfig_change_disabledlogging; - {false, true} -> roomconfig_change_enabledlogging; - {_, _} -> roomconfig_change - end, - Users = [{U#user.jid, U#user.nick, U#user.role} - || {_, U} <- (?DICT):to_list(StateData#state.users)], - add_to_log(Type, Users, NSD), - Res; - Err -> Err - end +-spec set_config(xdata(), state(), binary()) -> {error, error()} | + {result, undefined, state()}. +set_config(#xdata{fields = Fields}, StateData, Lang) -> + Options = [{Var, Vals} || #xdata_field{var = Var, values = Vals} <- Fields], + case set_xoption(Options, StateData#state.config, + StateData#state.server_host, Lang) of + #config{} = Config -> + Res = change_config(Config, StateData), + {result, _, NSD} = Res, + Type = case {(StateData#state.config)#config.logging, + Config#config.logging} + of + {true, false} -> roomconfig_change_disabledlogging; + {false, true} -> roomconfig_change_enabledlogging; + {_, _} -> roomconfig_change + end, + Users = [{U#user.jid, U#user.nick, U#user.role} + || {_, U} <- (?DICT):to_list(StateData#state.users)], + add_to_log(Type, Users, NSD), + Res; + Err -> Err end. -define(SET_BOOL_XOPT(Opt, Val), @@ -3928,21 +3342,32 @@ set_config(XEl, StateData, Lang) -> _ -> Txt = <<"Value of '~s' should be boolean">>, ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), - {error, ?ERRT_BAD_REQUEST(Lang, ErrTxt)} + {error, xmpp:err_bad_request(ErrTxt, Lang)} end). -define(SET_NAT_XOPT(Opt, Val), - case catch jlib:binary_to_integer(Val) of + case catch binary_to_integer(Val) of I when is_integer(I), I > 0 -> set_xoption(Opts, Config#config{Opt = I}, ServerHost, Lang); _ -> Txt = <<"Value of '~s' should be integer">>, ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), - {error, ?ERRT_BAD_REQUEST(Lang, ErrTxt)} + {error, xmpp:err_bad_request(ErrTxt, Lang)} end). --define(SET_STRING_XOPT(Opt, Val), - set_xoption(Opts, Config#config{Opt = Val}, ServerHost, Lang)). +-define(SET_STRING_XOPT(Opt, Vals), + try + V = case Vals of + [] -> <<"">>; + [Val] -> Val; + _ when is_atom(Vals) -> Vals + end, + set_xoption(Opts, Config#config{Opt = V}, ServerHost, Lang) + catch _:_ -> + Txt = <<"Incorrect value of option '~s'">>, + ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), + {error, xmpp:err_bad_request(ErrTxt, Lang)} + end). -define(SET_JIDMULTI_XOPT(Opt, Vals), begin @@ -3957,15 +3382,17 @@ set_config(XEl, StateData, Lang) -> set_xoption(Opts, Config#config{Opt = Set}, ServerHost, Lang) end). +-spec set_xoption([{binary(), [binary()]}], #config{}, + binary(), binary()) -> #config{} | {error, error()}. set_xoption([], Config, _ServerHost, _Lang) -> Config; -set_xoption([{<<"muc#roomconfig_roomname">>, [Val]} +set_xoption([{<<"muc#roomconfig_roomname">>, Vals} | Opts], Config, ServerHost, Lang) -> - ?SET_STRING_XOPT(title, Val); -set_xoption([{<<"muc#roomconfig_roomdesc">>, [Val]} + ?SET_STRING_XOPT(title, Vals); +set_xoption([{<<"muc#roomconfig_roomdesc">>, Vals} | Opts], Config, ServerHost, Lang) -> - ?SET_STRING_XOPT(description, Val); + ?SET_STRING_XOPT(description, Vals); set_xoption([{<<"muc#roomconfig_changesubject">>, [Val]} | Opts], Config, ServerHost, Lang) -> @@ -3994,7 +3421,7 @@ set_xoption([{<<"allow_private_messages_from_visitors">>, _ -> Txt = <<"Value of 'allow_private_messages_from_visitors' " "should be anyone|moderators|nobody">>, - {error, ?ERRT_BAD_REQUEST(Lang, Txt)} + {error, xmpp:err_bad_request(Txt, Lang)} end; set_xoption([{<<"muc#roomconfig_allowvisitorstatus">>, [Val]} @@ -4045,10 +3472,10 @@ set_xoption([{<<"muc#roomconfig_passwordprotectedroom">>, | Opts], Config, ServerHost, Lang) -> ?SET_BOOL_XOPT(password_protected, Val); -set_xoption([{<<"muc#roomconfig_roomsecret">>, [Val]} +set_xoption([{<<"muc#roomconfig_roomsecret">>, Vals} | Opts], Config, ServerHost, Lang) -> - ?SET_STRING_XOPT(password, Val); + ?SET_STRING_XOPT(password, Vals); set_xoption([{<<"anonymous">>, [Val]} | Opts], Config, ServerHost, Lang) -> ?SET_BOOL_XOPT(anonymous, Val); @@ -4069,7 +3496,7 @@ set_xoption([{<<"muc#roomconfig_presencebroadcast">>, Vals} | Opts], error -> Txt = <<"Value of 'muc#roomconfig_presencebroadcast' should " "be moderator|participant|visitor">>, - {error, ?ERRT_BAD_REQUEST(Lang, Txt)}; + {error, xmpp:err_bad_request(Txt, Lang)}; {M, P, V} -> Res = if M -> [moderator]; true -> [] end ++ @@ -4101,7 +3528,7 @@ set_xoption([{<<"muc#roomconfig_whois">>, [Val]} _ -> Txt = <<"Value of 'muc#roomconfig_whois' should be " "moderators|anyone">>, - {error, ?ERRT_BAD_REQUEST(Lang, Txt)} + {error, xmpp:err_bad_request(Txt, Lang)} end; set_xoption([{<<"muc#roomconfig_maxusers">>, [Val]} | Opts], @@ -4125,7 +3552,7 @@ set_xoption([{<<"FORM_TYPE">>, _} | Opts], Config, ServerHost, Lang) -> set_xoption([{Opt, Vals} | Opts], Config, ServerHost, Lang) -> Txt = <<"Unknown option '~s'">>, ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), - Err = {error, ?ERRT_BAD_REQUEST(Lang, ErrTxt)}, + Err = {error, xmpp:err_bad_request(ErrTxt, Lang)}, case ejabberd_hooks:run_fold(set_room_option, ServerHost, Err, @@ -4136,6 +3563,7 @@ set_xoption([{Opt, Vals} | Opts], Config, ServerHost, Lang) -> set_xoption(Opts, setelement(Pos, Config, Val), ServerHost, Lang) end. +-spec change_config(#config{}, state()) -> {result, undefined, state()}. change_config(Config, StateData) -> send_config_change_info(Config, StateData), NSD = remove_subscriptions(StateData#state{config = Config}), @@ -4154,57 +3582,54 @@ change_config(Config, StateData) -> Config#config.members_only} of {false, true} -> - NSD1 = remove_nonmembers(NSD), {result, [], NSD1}; - _ -> {result, [], NSD} + NSD1 = remove_nonmembers(NSD), {result, undefined, NSD1}; + _ -> {result, undefined, NSD} end. +-spec send_config_change_info(#config{}, state()) -> ok. send_config_change_info(Config, #state{config = Config}) -> ok; send_config_change_info(New, #state{config = Old} = StateData) -> Codes = case {Old#config.logging, New#config.logging} of - {false, true} -> [<<"170">>]; - {true, false} -> [<<"171">>]; + {false, true} -> [170]; + {true, false} -> [171]; _ -> [] end ++ case {Old#config.anonymous, New#config.anonymous} of - {true, false} -> [<<"172">>]; - {false, true} -> [<<"173">>]; + {true, false} -> [172]; + {false, true} -> [173]; _ -> [] end ++ case Old#config{anonymous = New#config.anonymous, logging = New#config.logging} of New -> []; - _ -> [<<"104">>] + _ -> [104] end, - StatusEls = [#xmlel{name = <<"status">>, - attrs = [{<<"code">>, Code}], - children = []} || Code <- Codes], - Message = #xmlel{name = <<"message">>, - attrs = [{<<"type">>, <<"groupchat">>}, - {<<"id">>, randoms:get_string()}], - children = [#xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_MUC_USER}], - children = StatusEls}]}, + Message = #message{type = groupchat, + id = randoms:get_string(), + sub_els = [#muc_user{status_codes = Codes}]}, send_wrapped_multiple(StateData#state.jid, StateData#state.users, Message, ?NS_MUCSUB_NODES_CONFIG, StateData). +-spec remove_nonmembers(state()) -> state(). remove_nonmembers(StateData) -> lists:foldl(fun ({_LJID, #user{jid = JID}}, SD) -> Affiliation = get_affiliation(JID, SD), case Affiliation of none -> catch send_kickban_presence(<<"">>, JID, <<"">>, - <<"322">>, SD), + 322, SD), set_role(JID, none, SD); _ -> SD end end, StateData, (?DICT):to_list(StateData#state.users)). +-spec set_opts([{atom(), any()}], state()) -> state(). set_opts([], StateData) -> StateData; set_opts([{Opt, Val} | Opts], StateData) -> NSD = case Opt of @@ -4342,7 +3767,7 @@ set_opts([{Opt, Val} | Opts], StateData) -> -define(MAKE_CONFIG_OPT(Opt), {Opt, Config#config.Opt}). - +-spec make_opts(state()) -> [{atom(), any()}]. make_opts(StateData) -> Config = StateData#state.config, Subscribers = (?DICT):fold( @@ -4381,243 +3806,221 @@ make_opts(StateData) -> {subject_author, StateData#state.subject_author}, {subscribers, Subscribers}]. +-spec destroy_room(muc_destroy(), state()) -> {result, undefined, stop}. destroy_room(DEl, StateData) -> - lists:foreach(fun ({_LJID, Info}) -> - Nick = Info#user.nick, - ItemAttrs = [{<<"affiliation">>, <<"none">>}, - {<<"role">>, <<"none">>}], - Packet = #xmlel{name = <<"presence">>, - attrs = - [{<<"type">>, <<"unavailable">>}], - children = - [#xmlel{name = <<"x">>, - attrs = - [{<<"xmlns">>, - ?NS_MUC_USER}], - children = - [#xmlel{name = - <<"item">>, - attrs = - ItemAttrs, - children = - []}, - DEl]}]}, - send_wrapped(jid:replace_resource(StateData#state.jid, - Nick), - Info#user.jid, Packet, - ?NS_MUCSUB_NODES_CONFIG, StateData) - end, - (?DICT):to_list(StateData#state.users)), + Destroy = DEl#muc_destroy{xmlns = ?NS_MUC_USER}, + lists:foreach( + fun({_LJID, Info}) -> + Nick = Info#user.nick, + Item = #muc_item{affiliation = none, + role = none}, + Packet = #presence{ + type = unavailable, + sub_els = [#muc_user{items = [Item], + destroy = Destroy}]}, + send_wrapped(jid:replace_resource(StateData#state.jid, Nick), + Info#user.jid, Packet, + ?NS_MUCSUB_NODES_CONFIG, StateData) + end, + (?DICT):to_list(StateData#state.users)), case (StateData#state.config)#config.persistent of true -> mod_muc:forget_room(StateData#state.server_host, StateData#state.host, StateData#state.room); false -> ok end, - {result, [], stop}. + {result, undefined, stop}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Disco --define(FEATURE(Var), - #xmlel{name = <<"feature">>, attrs = [{<<"var">>, Var}], - children = []}). - -define(CONFIG_OPT_TO_FEATURE(Opt, Fiftrue, Fiffalse), case Opt of - true -> ?FEATURE(Fiftrue); - false -> ?FEATURE(Fiffalse) + true -> Fiftrue; + false -> Fiffalse end). -process_iq_disco_info(_From, set, Lang, _StateData) -> +-spec process_iq_disco_info(jid(), iq(), state()) -> + {result, disco_info()} | {error, error()}. +process_iq_disco_info(_From, #iq{type = set, lang = Lang}, _StateData) -> Txt = <<"Value 'set' of 'type' attribute is not allowed">>, - {error, ?ERRT_NOT_ALLOWED(Lang, Txt)}; -process_iq_disco_info(_From, get, Lang, StateData) -> + {error, xmpp:err_not_allowed(Txt, Lang)}; +process_iq_disco_info(_From, #iq{type = get, lang = Lang}, StateData) -> Config = StateData#state.config, - {result, - [#xmlel{name = <<"identity">>, - attrs = - [{<<"category">>, <<"conference">>}, - {<<"type">>, <<"text">>}, - {<<"name">>, get_title(StateData)}], - children = []}, - #xmlel{name = <<"feature">>, - attrs = [{<<"var">>, ?NS_VCARD}], children = []}, - #xmlel{name = <<"feature">>, - attrs = [{<<"var">>, ?NS_MUC}], children = []}, - ?CONFIG_OPT_TO_FEATURE((Config#config.public), - <<"muc_public">>, <<"muc_hidden">>), - ?CONFIG_OPT_TO_FEATURE((Config#config.persistent), - <<"muc_persistent">>, <<"muc_temporary">>), - ?CONFIG_OPT_TO_FEATURE((Config#config.members_only), - <<"muc_membersonly">>, <<"muc_open">>), - ?CONFIG_OPT_TO_FEATURE((Config#config.anonymous), - <<"muc_semianonymous">>, <<"muc_nonanonymous">>), - ?CONFIG_OPT_TO_FEATURE((Config#config.moderated), - <<"muc_moderated">>, <<"muc_unmoderated">>), - ?CONFIG_OPT_TO_FEATURE((Config#config.password_protected), - <<"muc_passwordprotected">>, <<"muc_unsecured">>)] - ++ case Config#config.allow_subscription of - true -> [?FEATURE(?NS_MUCSUB)]; - false -> [] - end - ++ case {gen_mod:is_loaded(StateData#state.server_host, mod_mam), - Config#config.mam} of - {true, true} -> - [?FEATURE(?NS_MAM_TMP), - ?FEATURE(?NS_MAM_0), - ?FEATURE(?NS_MAM_1)]; - _ -> - [] - end - ++ iq_disco_info_extras(Lang, StateData), - StateData}. + Feats = [?NS_VCARD, ?NS_MUC, + ?CONFIG_OPT_TO_FEATURE((Config#config.public), + <<"muc_public">>, <<"muc_hidden">>), + ?CONFIG_OPT_TO_FEATURE((Config#config.persistent), + <<"muc_persistent">>, <<"muc_temporary">>), + ?CONFIG_OPT_TO_FEATURE((Config#config.members_only), + <<"muc_membersonly">>, <<"muc_open">>), + ?CONFIG_OPT_TO_FEATURE((Config#config.anonymous), + <<"muc_semianonymous">>, <<"muc_nonanonymous">>), + ?CONFIG_OPT_TO_FEATURE((Config#config.moderated), + <<"muc_moderated">>, <<"muc_unmoderated">>), + ?CONFIG_OPT_TO_FEATURE((Config#config.password_protected), + <<"muc_passwordprotected">>, <<"muc_unsecured">>)] + ++ case Config#config.allow_subscription of + true -> [?NS_MUCSUB]; + false -> [] + end + ++ case {gen_mod:is_loaded(StateData#state.server_host, mod_mam), + Config#config.mam} of + {true, true} -> + [?NS_MAM_TMP, ?NS_MAM_0, ?NS_MAM_1]; + _ -> + [] + end, + {result, #disco_info{xdata = [iq_disco_info_extras(Lang, StateData)], + identities = [#identity{category = <<"conference">>, + type = <<"text">>, + name = get_title(StateData)}], + features = Feats}}. --define(RFIELDT(Type, Var, Val), - #xmlel{name = <<"field">>, - attrs = [{<<"type">>, Type}, {<<"var">>, Var}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = [{xmlcdata, Val}]}]}). +-spec mk_rfieldt('boolean' | 'fixed' | 'hidden' | + 'jid-multi' | 'jid-single' | 'list-multi' | + 'list-single' | 'text-multi' | 'text-private' | + 'text-single', binary(), binary()) -> xdata_field(). +mk_rfieldt(Type, Var, Val) -> + #xdata_field{type = Type, var = Var, values = [Val]}. --define(RFIELD(Label, Var, Val), - #xmlel{name = <<"field">>, - attrs = - [{<<"label">>, translate:translate(Lang, Label)}, - {<<"var">>, Var}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = [{xmlcdata, Val}]}]}). +-spec mk_rfield(binary(), binary(), binary(), binary()) -> xdata_field(). +mk_rfield(Label, Var, Val, Lang) -> + #xdata_field{type = 'text-single', + label = translate:translate(Lang, Label), + var = Var, + values = [Val]}. +-spec iq_disco_info_extras(binary(), state()) -> xdata(). iq_disco_info_extras(Lang, StateData) -> Len = (?DICT):size(StateData#state.users), - RoomDescription = - (StateData#state.config)#config.description, - [#xmlel{name = <<"x">>, - attrs = - [{<<"xmlns">>, ?NS_XDATA}, {<<"type">>, <<"result">>}], - children = - [?RFIELDT(<<"hidden">>, <<"FORM_TYPE">>, - <<"http://jabber.org/protocol/muc#roominfo">>), - ?RFIELD(<<"Room description">>, - <<"muc#roominfo_description">>, RoomDescription), - ?RFIELD(<<"Number of occupants">>, - <<"muc#roominfo_occupants">>, - (iolist_to_binary(integer_to_list(Len))))]}]. + RoomDescription = (StateData#state.config)#config.description, + #xdata{type = result, + fields = [mk_rfieldt(hidden, <<"FORM_TYPE">>, + "http://jabber.org/protocol/muc#roominfo"), + mk_rfield(<<"Room description">>, + <<"muc#roominfo_description">>, + RoomDescription, Lang), + mk_rfield(<<"Number of occupants">>, + <<"muc#roominfo_occupants">>, + integer_to_binary(Len), Lang)]}. -process_iq_disco_items(_From, set, Lang, _StateData) -> +-spec process_iq_disco_items(jid(), iq(), state()) -> + {error, error()} | {result, disco_items()}. +process_iq_disco_items(_From, #iq{type = set, lang = Lang}, _StateData) -> Txt = <<"Value 'set' of 'type' attribute is not allowed">>, - {error, ?ERRT_NOT_ALLOWED(Lang, Txt)}; -process_iq_disco_items(From, get, Lang, StateData) -> + {error, xmpp:err_not_allowed(Txt, Lang)}; +process_iq_disco_items(From, #iq{type = get, lang = Lang}, StateData) -> case (StateData#state.config)#config.public_list of true -> - {result, get_mucroom_disco_items(StateData), StateData}; + {result, get_mucroom_disco_items(StateData)}; _ -> case is_occupant_or_admin(From, StateData) of true -> - {result, get_mucroom_disco_items(StateData), StateData}; + {result, get_mucroom_disco_items(StateData)}; _ -> Txt = <<"Only occupants or administrators can perform this query">>, - {error, ?ERRT_FORBIDDEN(Lang, Txt)} + {error, xmpp:err_forbidden(Txt, Lang)} end end. -process_iq_captcha(_From, get, Lang, _SubEl, - _StateData) -> +-spec process_iq_captcha(jid(), iq(), state()) -> {error, error()} | + {result, undefined}. +process_iq_captcha(_From, #iq{type = get, lang = Lang}, _StateData) -> Txt = <<"Value 'get' of 'type' attribute is not allowed">>, - {error, ?ERRT_NOT_ALLOWED(Lang, Txt)}; -process_iq_captcha(_From, set, Lang, SubEl, - StateData) -> + {error, xmpp:err_not_allowed(Txt, Lang)}; +process_iq_captcha(_From, #iq{type = set, lang = Lang, sub_els = [SubEl]}, + _StateData) -> case ejabberd_captcha:process_reply(SubEl) of - ok -> {result, [], StateData}; + ok -> {result, undefined}; {error, malformed} -> Txt = <<"Incorrect CAPTCHA submit">>, - {error, ?ERRT_BAD_REQUEST(Lang, Txt)}; + {error, xmpp:err_bad_request(Txt, Lang)}; _ -> Txt = <<"The CAPTCHA verification has failed">>, - {error, ?ERRT_NOT_ALLOWED(Lang, Txt)} + {error, xmpp:err_not_allowed(Txt, Lang)} end. -process_iq_vcard(_From, get, _Lang, _SubEl, StateData) -> +-spec process_iq_vcard(jid(), iq(), state()) -> + {result, vcard_temp() | xmlel()} | + {result, undefined, state()} | + {error, error()}. +process_iq_vcard(_From, #iq{type = get}, StateData) -> #state{config = #config{vcard = VCardRaw}} = StateData, case fxml_stream:parse_element(VCardRaw) of - #xmlel{children = VCardEls} -> - {result, VCardEls, StateData}; + #xmlel{} = VCard -> + {result, VCard}; {error, _} -> - {result, [], StateData} + {result, #vcard_temp{}} end; -process_iq_vcard(From, set, Lang, SubEl, StateData) -> +process_iq_vcard(From, #iq{type = set, lang = Lang, sub_els = [SubEl]}, + StateData) -> case get_affiliation(From, StateData) of owner -> - VCardRaw = fxml:element_to_binary(SubEl), + VCardRaw = fxml:element_to_binary(xmpp:encode(SubEl)), Config = StateData#state.config, NewConfig = Config#config{vcard = VCardRaw}, change_config(NewConfig, StateData); _ -> ErrText = <<"Owner privileges required">>, - {error, ?ERRT_FORBIDDEN(Lang, ErrText)} + {error, xmpp:err_forbidden(ErrText, Lang)} end. -process_iq_mucsub(From, Packet, +-spec process_iq_mucsub(jid(), iq(), state()) -> + {error, error()} | + {result, undefined | muc_subscribe(), state()} | + {ignore, state()}. +process_iq_mucsub(_From, #iq{type = set, lang = Lang, + sub_els = [#muc_subscribe{}]}, + #state{config = #config{allow_subscription = false}}) -> + {error, xmpp:err_not_allowed(<<"Subscriptions are not allowed">>, Lang)}; +process_iq_mucsub(From, #iq{type = set, lang = Lang, - sub_el = #xmlel{name = <<"subscribe">>} = SubEl}, - #state{config = Config} = StateData) -> - case fxml:get_tag_attr_s(<<"nick">>, SubEl) of - <<"">> -> - Err = ?ERRT_BAD_REQUEST(Lang, <<"Missing 'nick' attribute">>), - {error, Err}; - Nick when Config#config.allow_subscription -> - LJID = jid:tolower(From), - case (?DICT):find(LJID, StateData#state.users) of - {ok, #user{role = Role, nick = Nick1}} when Nick1 /= Nick -> - Nodes = get_subscription_nodes(Packet), - case {nick_collision(From, Nick, StateData), - mod_muc:can_use_nick(StateData#state.server_host, - StateData#state.host, - From, Nick)} of - {true, _} -> - ErrText = <<"That nickname is already in use by another occupant">>, - {error, ?ERRT_CONFLICT(Lang, ErrText)}; - {_, false} -> - ErrText = <<"That nickname is registered by another person">>, - {error, ?ERRT_CONFLICT(Lang, ErrText)}; - _ -> - NewStateData = add_online_user( - From, Nick, Role, true, Nodes, StateData), - {result, subscription_nodes_to_events(Nodes), NewStateData} - end; - {ok, #user{role = Role}} -> - Nodes = get_subscription_nodes(Packet), + sub_els = [#muc_subscribe{nick = Nick}]} = Packet, + StateData) -> + LJID = jid:tolower(From), + case (?DICT):find(LJID, StateData#state.users) of + {ok, #user{role = Role, nick = Nick1}} when Nick1 /= Nick -> + Nodes = get_subscription_nodes(Packet), + case {nick_collision(From, Nick, StateData), + mod_muc:can_use_nick(StateData#state.server_host, + StateData#state.host, + From, Nick)} of + {true, _} -> + ErrText = <<"That nickname is already in use by another occupant">>, + {error, xmpp:err_conflict(ErrText, Lang)}; + {_, false} -> + ErrText = <<"That nickname is registered by another person">>, + {error, xmpp:err_conflict(ErrText, Lang)}; + _ -> NewStateData = add_online_user( From, Nick, Role, true, Nodes, StateData), - {result, subscription_nodes_to_events(Nodes), NewStateData}; - error -> - add_new_user(From, Nick, Packet, StateData) + {result, subscribe_result(Packet), NewStateData} end; - _ -> - Err = ?ERRT_NOT_ALLOWED(Lang, <<"Subscriptions are not allowed">>), - {error, Err} + {ok, #user{role = Role}} -> + Nodes = get_subscription_nodes(Packet), + NewStateData = add_online_user( + From, Nick, Role, true, Nodes, StateData), + {result, subscribe_result(Packet), NewStateData}; + error -> + add_new_user(From, Nick, Packet, StateData) end; -process_iq_mucsub(From, _Packet, - #iq{type = set, - sub_el = #xmlel{name = <<"unsubscribe">>}}, +process_iq_mucsub(From, #iq{type = set, sub_els = [#muc_unsubscribe{}]}, StateData) -> LJID = jid:tolower(From), case ?DICT:find(LJID, StateData#state.users) of {ok, #user{is_subscriber = true} = User} -> NewStateData = remove_subscription(From, User, StateData), store_room(NewStateData), - {result, [], NewStateData}; + {result, undefined, NewStateData}; _ -> - {result, [], StateData} + {result, undefined, StateData} end; -process_iq_mucsub(_From, _Packet, #iq{type = set, lang = Lang}, _StateData) -> - Txt = <<"Unrecognized subscription command">>, - {error, ?ERRT_BAD_REQUEST(Lang, Txt)}; -process_iq_mucsub(_From, _Packet, #iq{type = get, lang = Lang}, _StateData) -> +process_iq_mucsub(_From, #iq{type = get, lang = Lang}, _StateData) -> Txt = <<"Value 'get' of 'type' attribute is not allowed">>, - {error, ?ERRT_BAD_REQUEST(Lang, Txt)}. + {error, xmpp:err_bad_request(Txt, Lang)}. +-spec remove_subscription(jid(), #user{}, state()) -> state(). remove_subscription(JID, #user{is_subscriber = true} = User, StateData) -> case User#user.last_presence of undefined -> @@ -4631,6 +4034,7 @@ remove_subscription(JID, #user{is_subscriber = true} = User, StateData) -> remove_subscription(_JID, #user{}, StateData) -> StateData. +-spec remove_subscriptions(state()) -> state(). remove_subscriptions(StateData) -> if not (StateData#state.config)#config.allow_subscription -> dict:fold( @@ -4641,41 +4045,32 @@ remove_subscriptions(StateData) -> StateData end. -get_subscription_nodes(#xmlel{name = <<"iq">>} = Packet) -> - case fxml:get_subtag_with_xmlns(Packet, <<"subscribe">>, ?NS_MUCSUB) of - #xmlel{children = Els} -> - lists:flatmap( - fun(#xmlel{name = <<"event">>, attrs = Attrs}) -> - Node = fxml:get_attr_s(<<"node">>, Attrs), - case lists:member(Node, [?NS_MUCSUB_NODES_PRESENCE, - ?NS_MUCSUB_NODES_MESSAGES, - ?NS_MUCSUB_NODES_AFFILIATIONS, - ?NS_MUCSUB_NODES_SUBJECT, - ?NS_MUCSUB_NODES_CONFIG, - ?NS_MUCSUB_NODES_PARTICIPANTS]) of - true -> - [Node]; - false -> - [] - end; - (_) -> - [] - end, Els); - false -> - [] - end; +-spec get_subscription_nodes(iq()) -> [binary()]. +get_subscription_nodes(#iq{sub_els = [#muc_subscribe{events = Nodes}]}) -> + lists:filter( + fun(Node) -> + lists:member(Node, [?NS_MUCSUB_NODES_PRESENCE, + ?NS_MUCSUB_NODES_MESSAGES, + ?NS_MUCSUB_NODES_AFFILIATIONS, + ?NS_MUCSUB_NODES_SUBJECT, + ?NS_MUCSUB_NODES_CONFIG, + ?NS_MUCSUB_NODES_PARTICIPANTS]) + end, Nodes); get_subscription_nodes(_) -> []. -subscription_nodes_to_events(Nodes) -> - [#xmlel{name = <<"event">>, attrs = [{<<"node">>, Node}]} || Node <- Nodes]. +-spec subscribe_result(iq()) -> muc_subscribe(). +subscribe_result(#iq{sub_els = [#muc_subscribe{nick = Nick}]} = Packet) -> + #muc_subscribe{nick = Nick, events = get_subscription_nodes(Packet)}. +-spec get_title(state()) -> binary(). get_title(StateData) -> case (StateData#state.config)#config.title of <<"">> -> StateData#state.room; Name -> Name end. +-spec get_roomdesc_reply(jid(), state(), binary()) -> {item, binary()} | false. get_roomdesc_reply(JID, StateData, Tail) -> IsOccupantOrAdmin = is_occupant_or_admin(JID, StateData), @@ -4689,352 +4084,215 @@ get_roomdesc_reply(JID, StateData, Tail) -> true -> false end. +-spec get_roomdesc_tail(state(), binary()) -> binary(). get_roomdesc_tail(StateData, Lang) -> Desc = case (StateData#state.config)#config.public of true -> <<"">>; _ -> translate:translate(Lang, <<"private, ">>) end, - Len = (?DICT):fold(fun (_, _, Acc) -> Acc + 1 end, 0, - StateData#state.users), + Len = (?DICT):size(StateData#state.users), <<" (", Desc/binary, (iolist_to_binary(integer_to_list(Len)))/binary, ")">>. +-spec get_mucroom_disco_items(state()) -> disco_items(). get_mucroom_disco_items(StateData) -> - lists:map(fun ({_LJID, Info}) -> + Items = lists:map( + fun({_LJID, Info}) -> Nick = Info#user.nick, - #xmlel{name = <<"item">>, - attrs = - [{<<"jid">>, - jid:to_string({StateData#state.room, - StateData#state.host, - Nick})}, - {<<"name">>, Nick}], - children = []} + #disco_item{jid = jid:make(StateData#state.room, + StateData#state.host, + Nick), + name = Nick} end, - (?DICT):to_list(StateData#state.users)). + (?DICT):to_list(StateData#state.users)), + #disco_items{items = Items}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Voice request support -is_voice_request(Els) -> - lists:foldl(fun (#xmlel{name = <<"x">>, attrs = Attrs} = - El, - false) -> - case fxml:get_attr_s(<<"xmlns">>, Attrs) of - ?NS_XDATA -> - case jlib:parse_xdata_submit(El) of - [_ | _] = Fields -> - case {lists:keysearch(<<"FORM_TYPE">>, 1, - Fields), - lists:keysearch(<<"muc#role">>, 1, - Fields)} - of - {{value, - {_, - [<<"http://jabber.org/protocol/muc#request">>]}}, - {value, {_, [<<"participant">>]}}} -> - true; - _ -> false - end; - _ -> false - end; - _ -> false - end; - (_, Acc) -> Acc - end, - false, Els). +-spec is_voice_request(message()) -> boolean(). +is_voice_request(Packet) -> + Els = xmpp:get_els(Packet), + lists:any( + fun(#xdata{} = X) -> + case {xmpp_util:get_xdata_values(<<"FORM_TYPE">>, X), + xmpp_util:get_xdata_values(<<"muc#role">>, X)} of + {[<<"http://jabber.org/protocol/muc#request">>], + [<<"participant">>]} -> + true; + _ -> + false + end; + (_) -> + false + end, Els). +-spec prepare_request_form(jid(), binary(), binary()) -> message(). prepare_request_form(Requester, Nick, Lang) -> - #xmlel{name = <<"message">>, - attrs = [{<<"type">>, <<"normal">>}], - children = - [#xmlel{name = <<"x">>, - attrs = - [{<<"xmlns">>, ?NS_XDATA}, {<<"type">>, <<"form">>}], - children = - [#xmlel{name = <<"title">>, attrs = [], - children = - [{xmlcdata, - translate:translate(Lang, - <<"Voice request">>)}]}, - #xmlel{name = <<"instructions">>, attrs = [], - children = - [{xmlcdata, - translate:translate(Lang, - <<"Either approve or decline the voice " - "request.">>)}]}, - #xmlel{name = <<"field">>, - attrs = - [{<<"var">>, <<"FORM_TYPE">>}, - {<<"type">>, <<"hidden">>}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = - [{xmlcdata, - <<"http://jabber.org/protocol/muc#request">>}]}]}, - #xmlel{name = <<"field">>, - attrs = - [{<<"var">>, <<"muc#role">>}, - {<<"type">>, <<"hidden">>}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = - [{xmlcdata, - <<"participant">>}]}]}, - ?STRINGXFIELD(<<"User JID">>, <<"muc#jid">>, - (jid:to_string(Requester))), - ?STRINGXFIELD(<<"Nickname">>, <<"muc#roomnick">>, - Nick), - ?BOOLXFIELD(<<"Grant voice to this person?">>, - <<"muc#request_allow">>, - (jlib:binary_to_atom(<<"false">>)))]}]}. + Title = translate:translate(Lang, <<"Voice request">>), + Instruction = translate:translate( + Lang, <<"Either approve or decline the voice request.">>), + Fs = [#xdata_field{var = <<"FORM_TYPE">>, + type = hidden, + values = [<<"http://jabber.org/protocol/muc#request">>]}, + #xdata_field{var = <<"muc#role">>, + type = hidden, + values = [<<"participant">>]}, + ?STRINGXFIELD(<<"User JID">>, <<"muc#jid">>, + jid:to_string(Requester)), + ?STRINGXFIELD(<<"Nickname">>, <<"muc#roomnick">>, Nick), + ?BOOLXFIELD(<<"Grant voice to this person?">>, + <<"muc#request_allow">>, false)], + #message{type = normal, + sub_els = [#xdata{type = form, + title = Title, + instructions = [Instruction], + fields = Fs}]}. -send_voice_request(From, StateData) -> +-spec send_voice_request(jid(), binary(), state()) -> ok. +send_voice_request(From, Lang, StateData) -> Moderators = search_role(moderator, StateData), FromNick = find_nick_by_jid(From, StateData), lists:foreach(fun ({_, User}) -> ejabberd_router:route( StateData#state.jid, User#user.jid, - prepare_request_form(From, FromNick, <<"">>)) + prepare_request_form(From, FromNick, Lang)) end, Moderators). -is_voice_approvement(Els) -> - lists:foldl(fun (#xmlel{name = <<"x">>, attrs = Attrs} = - El, - false) -> - case fxml:get_attr_s(<<"xmlns">>, Attrs) of - ?NS_XDATA -> - case jlib:parse_xdata_submit(El) of - [_ | _] = Fs -> - case {lists:keysearch(<<"FORM_TYPE">>, 1, - Fs), - lists:keysearch(<<"muc#role">>, 1, - Fs), - lists:keysearch(<<"muc#request_allow">>, - 1, Fs)} - of - {{value, - {_, - [<<"http://jabber.org/protocol/muc#request">>]}}, - {value, {_, [<<"participant">>]}}, - {value, {_, [Flag]}}} - when Flag == <<"true">>; - Flag == <<"1">> -> - true; - _ -> false - end; - _ -> false - end; - _ -> false - end; - (_, Acc) -> Acc - end, - false, Els). +-spec is_voice_approvement(message()) -> boolean(). +is_voice_approvement(Packet) -> + Els = xmpp:get_els(Packet), + lists:any( + fun(#xdata{} = X) -> + case {xmpp_util:get_xdata_values(<<"FORM_TYPE">>, X), + xmpp_util:get_xdata_values(<<"muc#role">>, X), + xmpp_util:get_xdata_values(<<"muc#request_allow">>, X)} of + {[<<"http://jabber.org/protocol/muc#request">>], + [<<"participant">>], [Flag]} when Flag == <<"true">>; + Flag == <<"1">> -> + true; + _ -> + false + end; + (_) -> + false + end, Els). -extract_jid_from_voice_approvement(Els) -> - lists:foldl(fun (#xmlel{name = <<"x">>} = El, error) -> - Fields = case jlib:parse_xdata_submit(El) of - invalid -> []; - Res -> Res - end, - lists:foldl(fun ({<<"muc#jid">>, [JIDStr]}, error) -> - case jid:from_string(JIDStr) of - error -> error; - J -> {ok, J} - end; - (_, Acc) -> Acc - end, - error, Fields); - (_, Acc) -> Acc - end, - error, Els). +-spec extract_jid_from_voice_approvement(message()) -> jid() | error. +extract_jid_from_voice_approvement(Packet) -> + Els = xmpp:get_els(Packet), + lists:foldl( + fun(#xdata{} = X, error) -> + case {xmpp_util:get_xdata_values(<<"FORM_TYPE">>, X), + xmpp_util:get_xdata_values(<<"muc#role">>, X), + xmpp_util:get_xdata_values(<<"muc#request_allow">>, X), + xmpp_util:get_xdata_values(<<"muc#jid">>, X)} of + {[<<"http://jabber.org/protocol/muc#request">>], + [<<"participant">>], [Flag], [J]} when Flag == <<"true">>; + Flag == <<"1">> -> + jid:from_string(J); + _ -> + error + end; + (_, Acc) -> + Acc + end, error, Els). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Invitation support -is_invitation(Els) -> - lists:foldl(fun (#xmlel{name = <<"x">>, attrs = Attrs} = - El, - false) -> - case fxml:get_attr_s(<<"xmlns">>, Attrs) of - ?NS_MUC_USER -> - case fxml:get_subtag(El, <<"invite">>) of - false -> false; - _ -> true - end; - _ -> false - end; - (_, Acc) -> Acc - end, - false, Els). +-spec is_invitation(message()) -> boolean(). +is_invitation(Packet) -> + Els = xmpp:get_els(Packet), + lists:any( + fun(#muc_user{invites = [_|_]}) -> true; + (_) -> false + end, Els). -check_invitation(From, Packet, Lang, StateData) -> +-spec check_invitation(jid(), message(), state()) -> {error, error()} | jid(). +check_invitation(From, Packet, StateData) -> + Lang = xmpp:get_lang(Packet), FAffiliation = get_affiliation(From, StateData), - CanInvite = - (StateData#state.config)#config.allow_user_invites - orelse - FAffiliation == admin orelse FAffiliation == owner, - InviteEl = case fxml:get_subtag_with_xmlns(Packet, <<"x">>, ?NS_MUC_USER) of - false -> - Txt1 = <<"No 'x' element found">>, - throw({error, ?ERRT_BAD_REQUEST(Lang, Txt1)}); - XEl -> - case fxml:get_subtag(XEl, <<"invite">>) of - false -> - Txt2 = <<"No 'invite' element found">>, - throw({error, ?ERRT_BAD_REQUEST(Lang, Txt2)}); - InviteEl1 -> - InviteEl1 - end - end, - JID = case - jid:from_string(fxml:get_tag_attr_s(<<"to">>, - InviteEl)) - of - error -> - Txt = <<"Incorrect value of 'to' attribute">>, - throw({error, ?ERRT_JID_MALFORMED(Lang, Txt)}); - JID1 -> JID1 - end, + CanInvite = (StateData#state.config)#config.allow_user_invites + orelse + FAffiliation == admin orelse FAffiliation == owner, case CanInvite of - false -> - Txt3 = <<"Invitations are not allowed in this conference">>, - throw({error, ?ERRT_NOT_ALLOWED(Lang, Txt3)}); - true -> - Reason = fxml:get_path_s(InviteEl, - [{elem, <<"reason">>}, cdata]), - ContinueEl = case fxml:get_path_s(InviteEl, - [{elem, <<"continue">>}]) - of - <<>> -> []; - Continue1 -> [Continue1] - end, - IEl = [#xmlel{name = <<"invite">>, - attrs = [{<<"from">>, jid:to_string(From)}], - children = - [#xmlel{name = <<"reason">>, attrs = [], - children = [{xmlcdata, Reason}]}] - ++ ContinueEl}], - PasswdEl = case - (StateData#state.config)#config.password_protected - of - true -> - [#xmlel{name = <<"password">>, attrs = [], - children = - [{xmlcdata, - (StateData#state.config)#config.password}]}]; - _ -> [] - end, - Body = #xmlel{name = <<"body">>, attrs = [], - children = - [{xmlcdata, - iolist_to_binary( - [io_lib:format( - translate:translate( - Lang, - <<"~s invites you to the room ~s">>), - [jid:to_string(From), - jid:to_string({StateData#state.room, - StateData#state.host, - <<"">>})]), - case - (StateData#state.config)#config.password_protected - of + false -> + Txt = <<"Invitations are not allowed in this conference">>, + {error, xmpp:err_not_allowed(Txt, Lang)}; + true -> + case xmpp:get_subtag(Packet, #muc_user{}) of + #muc_user{invites = [#muc_invite{to = undefined}]} -> + Txt = <<"No 'to' attribute found">>, + {error, xmpp:err_bad_request(Txt, Lang)}; + #muc_user{invites = [#muc_invite{to = JID, reason = Reason} = I]} -> + Invite = I#muc_invite{to = undefined, from = From}, + Password = case (StateData#state.config)#config.password_protected of + true -> + (StateData#state.config)#config.password; + false -> + undefined + end, + XUser = #muc_user{password = Password, invites = [Invite]}, + XConference = #x_conference{jid = jid:make(StateData#state.room, + StateData#state.host), + reason = Reason}, + Body = iolist_to_binary( + [io_lib:format( + translate:translate( + Lang, + <<"~s invites you to the room ~s">>), + [jid:to_string(From), + jid:to_string({StateData#state.room, + StateData#state.host, + <<"">>})]), + case (StateData#state.config)#config.password_protected of true -> <<", ", - (translate:translate(Lang, - <<"the password is">>))/binary, + (translate:translate( + Lang, <<"the password is">>))/binary, " '", ((StateData#state.config)#config.password)/binary, "'">>; _ -> <<"">> - end - , - case Reason of - <<"">> -> <<"">>; - _ -> <<" (", Reason/binary, ") ">> - end])}]}, - Msg = #xmlel{name = <<"message">>, - attrs = [{<<"type">>, <<"normal">>}], - children = - [#xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_MUC_USER}], - children = IEl ++ PasswdEl}, - #xmlel{name = <<"x">>, - attrs = - [{<<"xmlns">>, ?NS_XCONFERENCE}, - {<<"jid">>, - jid:to_string({StateData#state.room, - StateData#state.host, - <<"">>})}], - children = [{xmlcdata, Reason}]}, - Body]}, - ejabberd_router:route(StateData#state.jid, JID, Msg), - JID + end, + case Reason of + <<"">> -> <<"">>; + _ -> <<" (", Reason/binary, ") ">> + end]), + Msg = #message{type = normal, + body = xmpp:mk_text(Body), + sub_els = [XUser, XConference]}, + ejabberd_router:route(StateData#state.jid, JID, Msg), + JID; + #muc_user{invites = [_|_]} -> + Txt = <<"Multiple elements are not allowed">>, + {error, xmpp:err_forbidden(Txt, Lang)}; + _ -> + Txt = <<"No element found">>, + {error, xmpp:err_bad_request(Txt, Lang)} + end end. %% Handle a message sent to the room by a non-participant. %% If it is a decline, send to the inviter. %% Otherwise, an error message is sent to the sender. -handle_roommessage_from_nonparticipant(Packet, Lang, - StateData, From) -> - case catch check_decline_invitation(Packet) of - {true, Decline_data} -> - send_decline_invitation(Decline_data, - StateData#state.jid, From); - _ -> - send_error_only_occupants(Packet, Lang, - StateData#state.jid, From) +-spec handle_roommessage_from_nonparticipant(message(), state(), jid()) -> ok. +handle_roommessage_from_nonparticipant(Packet, StateData, From) -> + case xmpp:get_subtag(Packet, #muc_user{}) of + #muc_user{decline = #muc_decline{to = #jid{} = To} = Decline} = XUser -> + NewDecline = Decline#muc_decline{to = undefined, from = From}, + NewXUser = XUser#muc_user{decline = NewDecline}, + NewPacket = xmpp:set_subtag(Packet, NewXUser), + ejabberd_router:route(StateData#state.jid, To, NewPacket); + _ -> + ErrText = <<"Only occupants are allowed to send messages " + "to the conference">>, + Err = xmpp:err_not_acceptable(ErrText, xmpp:get_lang(Packet)), + ejabberd_router:route_error(StateData#state.jid, From, Packet, Err) end. -%% Check in the packet is a decline. -%% If so, also returns the splitted packet. -%% This function must be catched, -%% because it crashes when the packet is not a decline message. -check_decline_invitation(Packet) -> - #xmlel{name = <<"message">>} = Packet, - XEl = fxml:get_subtag(Packet, <<"x">>), - (?NS_MUC_USER) = fxml:get_tag_attr_s(<<"xmlns">>, XEl), - DEl = fxml:get_subtag(XEl, <<"decline">>), - ToString = fxml:get_tag_attr_s(<<"to">>, DEl), - ToJID = jid:from_string(ToString), - {true, {Packet, XEl, DEl, ToJID}}. - -%% Send the decline to the inviter user. -%% The original stanza must be slightly modified. -send_decline_invitation({Packet, XEl, DEl, ToJID}, - RoomJID, FromJID) -> - FromString = - jid:to_string(jid:remove_resource(FromJID)), - #xmlel{name = <<"decline">>, attrs = DAttrs, - children = DEls} = - DEl, - DAttrs2 = lists:keydelete(<<"to">>, 1, DAttrs), - DAttrs3 = [{<<"from">>, FromString} | DAttrs2], - DEl2 = #xmlel{name = <<"decline">>, attrs = DAttrs3, - children = DEls}, - XEl2 = replace_subelement(XEl, DEl2), - Packet2 = replace_subelement(Packet, XEl2), - ejabberd_router:route(RoomJID, ToJID, Packet2). - -%% Given an element and a new subelement, -%% replace the instance of the subelement in element with the new subelement. -replace_subelement(#xmlel{name = Name, attrs = Attrs, - children = SubEls}, - NewSubEl) -> - {_, NameNewSubEl, _, _} = NewSubEl, - SubEls2 = lists:keyreplace(NameNewSubEl, 2, SubEls, NewSubEl), - #xmlel{name = Name, attrs = Attrs, children = SubEls2}. - -send_error_only_occupants(Packet, Lang, RoomJID, From) -> - ErrText = - <<"Only occupants are allowed to send messages " - "to the conference">>, - Err = jlib:make_error_reply(Packet, - ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)), - ejabberd_router:route(RoomJID, From, Err). - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Logging @@ -5055,6 +4313,7 @@ add_to_log(Type, Data, StateData) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Users number checking +-spec tab_add_online_user(jid(), state()) -> ok. tab_add_online_user(JID, StateData) -> {LUser, LServer, LResource} = jid:tolower(JID), US = {LUser, LServer}, @@ -5062,8 +4321,10 @@ tab_add_online_user(JID, StateData) -> Host = StateData#state.host, catch ets:insert(muc_online_users, #muc_online_users{us = US, resource = LResource, - room = Room, host = Host}). + room = Room, host = Host}), + ok. +-spec tab_remove_online_user(jid(), state()) -> ok. tab_remove_online_user(JID, StateData) -> {LUser, LServer, LResource} = jid:tolower(JID), US = {LUser, LServer}, @@ -5071,8 +4332,10 @@ tab_remove_online_user(JID, StateData) -> Host = StateData#state.host, catch ets:delete_object(muc_online_users, #muc_online_users{us = US, resource = LResource, - room = Room, host = Host}). + room = Room, host = Host}), + ok. +-spec tab_count_user(jid()) -> non_neg_integer(). tab_count_user(JID) -> {LUser, LServer, _} = jid:tolower(JID), US = {LUser, LServer}, @@ -5083,9 +4346,11 @@ tab_count_user(JID) -> _ -> 0 end. +-spec element_size(stanza()) -> non_neg_integer(). element_size(El) -> - byte_size(fxml:element_to_binary(El)). + byte_size(fxml:element_to_binary(xmpp:encode(El))). +-spec store_room(state()) -> ok. store_room(StateData) -> if (StateData#state.config)#config.persistent -> mod_muc:store_room(StateData#state.server_host, @@ -5095,6 +4360,7 @@ store_room(StateData) -> ok end. +-spec send_wrapped(jid(), jid(), stanza(), binary(), state()) -> ok. send_wrapped(From, To, Packet, Node, State) -> LTo = jid:tolower(To), case ?DICT:find(LTo, State#state.users) of @@ -5112,27 +4378,26 @@ send_wrapped(From, To, Packet, Node, State) -> ejabberd_router:route(From, To, Packet) end. +-spec wrap(jid(), jid(), stanza(), binary()) -> message(). wrap(From, To, Packet, Node) -> - Pkt1 = jlib:replace_from_to(From, To, Packet), - Pkt2 = #xmlel{attrs = Attrs} = jlib:remove_attr(<<"xmlns">>, Pkt1), - Pkt3 = Pkt2#xmlel{attrs = [{<<"xmlns">>, <<"jabber:client">>}|Attrs]}, - Item = #xmlel{name = <<"item">>, - attrs = [{<<"id">>, randoms:get_string()}], - children = [Pkt3]}, - Items = #xmlel{name = <<"items">>, attrs = [{<<"node">>, Node}], - children = [Item]}, - Event = #xmlel{name = <<"event">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB_EVENT}], - children = [Items]}, - #xmlel{name = <<"message">>, children = [Event]}. + El = xmpp:encode(xmpp:set_from_to(Packet, From, To)), + #message{ + sub_els = [#pubsub_event{ + items = [#pubsub_event_items{ + node = Node, + items = [#pubsub_event_item{ + id = randoms:get_string(), + xml_els = [El]}]}]}]}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Multicast +-spec send_multiple(jid(), binary(), [#user{}], stanza()) -> ok. send_multiple(From, Server, Users, Packet) -> JIDs = [ User#user.jid || {_, User} <- ?DICT:to_list(Users)], ejabberd_router_multicast:route_multicast(From, Server, JIDs, Packet). +-spec send_wrapped_multiple(jid(), [#user{}], stanza(), binary(), state()) -> ok. send_wrapped_multiple(From, Users, Packet, Node, State) -> lists:foreach( fun({_, #user{jid = To}}) -> @@ -5141,10 +4406,6 @@ send_wrapped_multiple(From, Users, Packet, Node, State) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Detect messange stanzas that don't have meaninful content - -has_body_or_subject(Packet) -> - [] /= lists:dropwhile(fun - (#xmlel{name = <<"body">>}) -> false; - (#xmlel{name = <<"subject">>}) -> false; - (_) -> true - end, Packet#xmlel.children). +-spec has_body_or_subject(message()) -> boolean(). +has_body_or_subject(#message{body = Body, subject = Subj}) -> + Body /= [] orelse Subj /= []. diff --git a/src/mod_private.erl b/src/mod_private.erl index 28d49bb3f..e6d0fd7cd 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -72,7 +72,7 @@ process_sm_iq(#iq{type = Type, lang = Lang, case filter_xmlels(Els0) of [] -> Txt = <<"No private data found in this query">>, - xmpp:make_error(IQ, xmpp:err_bad_format(Txt, Lang)); + xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)); Data when Type == set -> set_data(LUser, LServer, Data), xmpp:make_iq_result(IQ); diff --git a/src/xmpp.erl b/src/xmpp.erl index f17eefa21..369fb90c5 100644 --- a/src/xmpp.erl +++ b/src/xmpp.erl @@ -16,22 +16,33 @@ set_type/2, set_to/2, set_from/2, set_id/2, set_lang/2, set_error/2, set_els/2, set_from_to/3, format_error/1, is_stanza/1, set_subtag/2, get_subtag/2, - remove_subtag/2, has_subtag/2, decode_els/1, pp/1, - get_name/1, get_text/1, mk_text/1, mk_text/2]). + remove_subtag/2, has_subtag/2, decode_els/1, decode_els/2, + pp/1, get_name/1, get_text/1, mk_text/1, mk_text/2]). %% XMPP errors -export([err_bad_request/0, err_bad_request/2, - err_bad_format/0, err_bad_format/2, - err_not_allowed/0, err_not_allowed/2, - err_conflict/0, err_conflict/2, - err_forbidden/0, err_forbidden/2, - err_not_acceptable/0, err_not_acceptable/2, - err_internal_server_error/0, err_internal_server_error/2, - err_service_unavailable/0, err_service_unavailable/2, - err_item_not_found/0, err_item_not_found/2, - err_jid_malformed/0, err_jid_malformed/2, - err_not_authorized/0, err_not_authorized/2, - err_feature_not_implemented/0, err_feature_not_implemented/2]). + err_conflict/0, err_conflict/2, + err_feature_not_implemented/0, err_feature_not_implemented/2, + err_forbidden/0, err_forbidden/2, + err_gone/0, err_gone/2, + err_internal_server_error/0, err_internal_server_error/2, + err_item_not_found/0, err_item_not_found/2, + err_jid_malformed/0, err_jid_malformed/2, + err_not_acceptable/0, err_not_acceptable/2, + err_not_allowed/0, err_not_allowed/2, + err_not_authorized/0, err_not_authorized/2, + err_payment_required/0, err_payment_required/2, + err_policy_violation/0, err_policy_violation/2, + err_recipient_unavailable/0, err_recipient_unavailable/2, + err_redirect/0, err_redirect/2, + err_registration_required/0, err_registration_required/2, + err_remote_server_not_found/0, err_remote_server_not_found/2, + err_remote_server_timeout/0, err_remote_server_timeout/2, + err_resource_constraint/0, err_resource_constraint/2, + err_service_unavailable/0, err_service_unavailable/2, + err_subscription_required/0, err_subscription_required/2, + err_undefined_condition/0, err_undefined_condition/2, + err_unexpected_request/0, err_unexpected_request/2]). %% XMPP stream errors -export([serr_bad_format/0, serr_bad_format/2, @@ -246,9 +257,12 @@ decode(Pkt, _Opts) -> (message()) -> message(); (presence()) -> presence(). decode_els(Stanza) -> + decode_els(Stanza, fun xmpp_codec:is_known_tag/1). + +decode_els(Stanza, MatchFun) -> Els = lists:map( fun(#xmlel{} = El) -> - case xmpp_codec:is_known_tag(El) of + case MatchFun(El) of true -> decode(El); false -> El end; @@ -287,10 +301,10 @@ set_subtag(Stanza, Tag) -> set_els(Stanza, NewEls). set_subtag([El|Els], Tag, TagName, XMLNS) -> - case {get_name(El), get_ns(El)} of - {TagName, XMLNS} -> + case match_tag(El, TagName, XMLNS) of + true -> [Tag|Els]; - _ -> + false -> [El|set_subtag(Els, Tag, TagName, XMLNS)] end; set_subtag([], Tag, _, _) -> @@ -304,14 +318,14 @@ get_subtag(Stanza, Tag) -> get_subtag(Els, TagName, XMLNS). get_subtag([El|Els], TagName, XMLNS) -> - case {get_name(El), get_ns(El)} of - {TagName, XMLNS} -> + case match_tag(El, TagName, XMLNS) of + true -> try decode(El) catch _:{xmpp_codec, _Why} -> get_subtag(Els, TagName, XMLNS) end; - _ -> + false -> get_subtag(Els, TagName, XMLNS) end; get_subtag([], _, _) -> @@ -328,10 +342,10 @@ remove_subtag(Stanza, Tag) -> set_els(Stanza, NewEls). remove_subtag([El|Els], TagName, XMLNS) -> - case {get_name(El), get_ns(El)} of - {TagName, XMLNS} -> + case match_tag(El, TagName, XMLNS) of + true -> remove_subtag(Els, TagName, XMLNS); - _ -> + false -> [El|remove_subtag(Els, TagName, XMLNS)] end; remove_subtag([], _, _) -> @@ -345,10 +359,10 @@ has_subtag(Stanza, Tag) -> has_subtag(Els, TagName, XMLNS). has_subtag([El|Els], TagName, XMLNS) -> - case {get_name(El), get_ns(El)} of - {TagName, XMLNS} -> + case match_tag(El, TagName, XMLNS) of + true -> true; - _ -> + false -> has_subtag(Els, TagName, XMLNS) end; has_subtag([], _, _) -> @@ -385,14 +399,6 @@ err_bad_request() -> err_bad_request(Text, Lang) -> err(modify, 'bad-request', 400, Text, Lang). --spec err_bad_format() -> error(). -err_bad_format() -> - err(modify, 'bad-format', 406). - --spec err_bad_format(binary(), binary() | undefined) -> error(). -err_bad_format(Text, Lang) -> - err(modify, 'bad-format', 406, Text, Lang). - -spec err_conflict() -> error(). err_conflict() -> err(cancel, 'conflict', 409). @@ -401,14 +407,6 @@ err_conflict() -> err_conflict(Text, Lang) -> err(cancel, 'conflict', 409, Text, Lang). --spec err_not_allowed() -> error(). -err_not_allowed() -> - err(cancel, 'not-allowed', 405). - --spec err_not_allowed(binary(), binary() | undefined) -> error(). -err_not_allowed(Text, Lang) -> - err(cancel, 'not-allowed', 405, Text, Lang). - -spec err_feature_not_implemented() -> error(). err_feature_not_implemented() -> err(cancel, 'feature-not-implemented', 501). @@ -417,14 +415,6 @@ err_feature_not_implemented() -> err_feature_not_implemented(Text, Lang) -> err(cancel, 'feature-not-implemented', 501, Text, Lang). --spec err_item_not_found() -> error(). -err_item_not_found() -> - err(cancel, 'item-not-found', 404). - --spec err_item_not_found(binary(), binary() | undefined) -> error(). -err_item_not_found(Text, Lang) -> - err(cancel, 'item-not-found', 404, Text, Lang). - -spec err_forbidden() -> error(). err_forbidden() -> err(auth, 'forbidden', 403). @@ -433,14 +423,18 @@ err_forbidden() -> err_forbidden(Text, Lang) -> err(auth, 'forbidden', 403, Text, Lang). --spec err_not_acceptable() -> error(). -err_not_acceptable() -> - err(modify, 'not-acceptable', 406). +%% RFC 6120 says error type SHOULD be "cancel". +%% RFC 3920 and XEP-0082 says it SHOULD be "modify". +-spec err_gone() -> error(). +err_gone() -> + err(modify, 'gone', 302). --spec err_not_acceptable(binary(), binary() | undefined) -> error(). -err_not_acceptable(Text, Lang) -> - err(modify, 'not-acceptable', 406, Text, Lang). +-spec err_gone(binary(), binary() | undefined) -> error(). +err_gone(Text, Lang) -> + err(modify, 'gone', 302, Text, Lang). +%% RFC 6120 sasy error type SHOULD be "cancel". +%% RFC 3920 and XEP-0082 says it SHOULD be "wait". -spec err_internal_server_error() -> error(). err_internal_server_error() -> err(wait, 'internal-server-error', 500). @@ -449,13 +443,13 @@ err_internal_server_error() -> err_internal_server_error(Text, Lang) -> err(wait, 'internal-server-error', 500, Text, Lang). --spec err_service_unavailable() -> error(). -err_service_unavailable() -> - err(cancel, 'service-unavailable', 503). +-spec err_item_not_found() -> error(). +err_item_not_found() -> + err(cancel, 'item-not-found', 404). --spec err_service_unavailable(binary(), binary() | undefined) -> error(). -err_service_unavailable(Text, Lang) -> - err(cancel, 'service-unavailable', 503, Text, Lang). +-spec err_item_not_found(binary(), binary() | undefined) -> error(). +err_item_not_found(Text, Lang) -> + err(cancel, 'item-not-found', 404, Text, Lang). -spec err_jid_malformed() -> error(). err_jid_malformed() -> @@ -465,6 +459,22 @@ err_jid_malformed() -> err_jid_malformed(Text, Lang) -> err(modify, 'jid-malformed', 400, Text, Lang). +-spec err_not_acceptable() -> error(). +err_not_acceptable() -> + err(modify, 'not-acceptable', 406). + +-spec err_not_acceptable(binary(), binary() | undefined) -> error(). +err_not_acceptable(Text, Lang) -> + err(modify, 'not-acceptable', 406, Text, Lang). + +-spec err_not_allowed() -> error(). +err_not_allowed() -> + err(cancel, 'not-allowed', 405). + +-spec err_not_allowed(binary(), binary() | undefined) -> error(). +err_not_allowed(Text, Lang) -> + err(cancel, 'not-allowed', 405, Text, Lang). + -spec err_not_authorized() -> error(). err_not_authorized() -> err(auth, 'not-authorized', 401). @@ -473,6 +483,108 @@ err_not_authorized() -> err_not_authorized(Text, Lang) -> err(auth, 'not-authorized', 401, Text, Lang). +-spec err_payment_required() -> error(). +err_payment_required() -> + err(auth, 'not-authorized', 402). + +-spec err_payment_required(binary(), binary() | undefined) -> error(). +err_payment_required(Text, Lang) -> + err(auth, 'not-authorized', 402, Text, Lang). + +%% is defined in neither RFC 3920 nor XEP-0086. +%% We choose '403' error code (as in ). +-spec err_policy_violation() -> error(). +err_policy_violation() -> + err(modify, 'policy-violation', 403). + +-spec err_policy_violation(binary(), binary() | undefined) -> error(). +err_policy_violation(Text, Lang) -> + err(modify, 'policy-violation', 403, Text, Lang). + +-spec err_recipient_unavailable() -> error(). +err_recipient_unavailable() -> + err(wait, 'recipient-unavailable', 404). + +-spec err_recipient_unavailable(binary(), binary() | undefined) -> error(). +err_recipient_unavailable(Text, Lang) -> + err(wait, 'recipient-unavailable', 404, Text, Lang). + +-spec err_redirect() -> error(). +err_redirect() -> + err(modify, 'redirect', 302). + +-spec err_redirect(binary(), binary() | undefined) -> error(). +err_redirect(Text, Lang) -> + err(modify, 'redirect', 302, Text, Lang). + +-spec err_registration_required() -> error(). +err_registration_required() -> + err(auth, 'registration-required', 407). + +-spec err_registration_required(binary(), binary() | undefined) -> error(). +err_registration_required(Text, Lang) -> + err(auth, 'registration-required', 407, Text, Lang). + +-spec err_remote_server_not_found() -> error(). +err_remote_server_not_found() -> + err(cancel, 'remote-server-not-found', 404). + +-spec err_remote_server_not_found(binary(), binary() | undefined) -> error(). +err_remote_server_not_found(Text, Lang) -> + err(cancel, 'remote-server-not-found', 404, Text, Lang). + +-spec err_remote_server_timeout() -> error(). +err_remote_server_timeout() -> + err(wait, 'remote-server-timeout', 504). + +-spec err_remote_server_timeout(binary(), binary() | undefined) -> error(). +err_remote_server_timeout(Text, Lang) -> + err(wait, 'remote-server-timeout', 504, Text, Lang). + +-spec err_resource_constraint() -> error(). +err_resource_constraint() -> + err(wait, 'resource-constraint', 500). + +-spec err_resource_constraint(binary(), binary() | undefined) -> error(). +err_resource_constraint(Text, Lang) -> + err(wait, 'resource-constraint', 500, Text, Lang). + +-spec err_service_unavailable() -> error(). +err_service_unavailable() -> + err(cancel, 'service-unavailable', 503). + +-spec err_service_unavailable(binary(), binary() | undefined) -> error(). +err_service_unavailable(Text, Lang) -> + err(cancel, 'service-unavailable', 503, Text, Lang). + +-spec err_subscription_required() -> error(). +err_subscription_required() -> + err(auth, 'subscription-required', 407). + +-spec err_subscription_required(binary(), binary() | undefined) -> error(). +err_subscription_required(Text, Lang) -> + err(auth, 'subscription-required', 407, Text, Lang). + +%% No error type is defined for . +%% We choose "modify" as it's used in RFC 6120 example. +-spec err_undefined_condition() -> error(). +err_undefined_condition() -> + err(modify, 'undefined-condition', 500). + +-spec err_undefined_condition(binary(), binary() | undefined) -> error(). +err_undefined_condition(Text, Lang) -> + err(modify, 'undefined-condition', 500, Text, Lang). + +%% RFC 6120 says error type SHOULD be "wait" or "modify". +%% RFC 3920 and XEP-0082 says it SHOULD be "wait". +-spec err_unexpected_request() -> error(). +err_unexpected_request() -> + err(wait, 'unexpected-request', 400). + +-spec err_unexpected_request(binary(), binary() | undefined) -> error(). +err_unexpected_request(Text, Lang) -> + err(wait, 'unexpected-request', 400, Text, Lang). + %%%=================================================================== %%% Functions to construct stream errors %%%=================================================================== @@ -712,3 +824,7 @@ add_ns(#xmlel{name = Name} = El) when Name == <<"message">>; El#xmlel{attrs = Attrs}; add_ns(El) -> El. + +-spec match_tag(xmlel() | xmpp_element(), binary(), binary()) -> boolean(). +match_tag(El, TagName, XMLNS) -> + get_name(El) == TagName andalso get_ns(El) == XMLNS. diff --git a/src/xmpp_codec.erl b/src/xmpp_codec.erl index f6e5f0f1a..c59c347f9 100644 --- a/src/xmpp_codec.erl +++ b/src/xmpp_codec.erl @@ -15,6 +15,21 @@ decode(_el) -> decode(_el, []). decode({xmlel, _name, _attrs, _} = _el, Opts) -> IgnoreEls = proplists:get_bool(ignore_els, Opts), case {_name, get_attr(<<"xmlns">>, _attrs)} of + {<<"client-id">>, <<"urn:xmpp:sid:0">>} -> + decode_client_id(<<"urn:xmpp:sid:0">>, IgnoreEls, _el); + {<<"stanza-id">>, <<"urn:xmpp:sid:0">>} -> + decode_stanza_id(<<"urn:xmpp:sid:0">>, IgnoreEls, _el); + {<<"addresses">>, + <<"http://jabber.org/protocol/address">>} -> + decode_addresses(<<"http://jabber.org/protocol/address">>, + IgnoreEls, _el); + {<<"address">>, + <<"http://jabber.org/protocol/address">>} -> + decode_address(<<"http://jabber.org/protocol/address">>, + IgnoreEls, _el); + {<<"nick">>, <<"http://jabber.org/protocol/nick">>} -> + decode_nick(<<"http://jabber.org/protocol/nick">>, + IgnoreEls, _el); {<<"x">>, <<"jabber:x:expire">>} -> decode_expire(<<"jabber:x:expire">>, IgnoreEls, _el); {<<"x">>, <<"jabber:x:event">>} -> @@ -53,6 +68,9 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> {<<"instructions">>, <<"jabber:iq:search">>} -> decode_search_instructions(<<"jabber:iq:search">>, IgnoreEls, _el); + {<<"no-permanent-storage">>, <<"urn:xmpp:hints">>} -> + decode_hint_no_permanent_storage(<<"urn:xmpp:hints">>, + IgnoreEls, _el); {<<"no-permanent-store">>, <<"urn:xmpp:hints">>} -> decode_hint_no_permanent_store(<<"urn:xmpp:hints">>, IgnoreEls, _el); @@ -160,12 +178,24 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> {<<"prefs">>, <<"urn:xmpp:mam:tmp">>} -> decode_mam_prefs(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); + {<<"always">>, <<"urn:xmpp:mam:0">>} -> + decode_mam_always(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); + {<<"always">>, <<"urn:xmpp:mam:1">>} -> + decode_mam_always(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); {<<"always">>, <<"urn:xmpp:mam:tmp">>} -> decode_mam_always(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); + {<<"never">>, <<"urn:xmpp:mam:0">>} -> + decode_mam_never(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); + {<<"never">>, <<"urn:xmpp:mam:1">>} -> + decode_mam_never(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); {<<"never">>, <<"urn:xmpp:mam:tmp">>} -> decode_mam_never(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); + {<<"jid">>, <<"urn:xmpp:mam:0">>} -> + decode_mam_jid(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); + {<<"jid">>, <<"urn:xmpp:mam:1">>} -> + decode_mam_jid(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); {<<"jid">>, <<"urn:xmpp:mam:tmp">>} -> decode_mam_jid(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); {<<"result">>, <<"urn:xmpp:mam:0">>} -> @@ -185,6 +215,9 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> {<<"query">>, <<"urn:xmpp:mam:tmp">>} -> decode_mam_query(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); + {<<"withtext">>, <<"urn:xmpp:mam:tmp">>} -> + decode_mam_withtext(<<"urn:xmpp:mam:tmp">>, IgnoreEls, + _el); {<<"with">>, <<"urn:xmpp:mam:tmp">>} -> decode_mam_with(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); {<<"end">>, <<"urn:xmpp:mam:tmp">>} -> @@ -216,6 +249,28 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> {<<"after">>, <<"http://jabber.org/protocol/rsm">>} -> decode_rsm_after(<<"http://jabber.org/protocol/rsm">>, IgnoreEls, _el); + {<<"unsubscribe">>, <<"urn:xmpp:mucsub:0">>} -> + decode_muc_unsubscribe(<<"urn:xmpp:mucsub:0">>, + IgnoreEls, _el); + {<<"subscribe">>, <<"urn:xmpp:mucsub:0">>} -> + decode_muc_subscribe(<<"urn:xmpp:mucsub:0">>, IgnoreEls, + _el); + {<<"event">>, <<"urn:xmpp:mucsub:0">>} -> + decode_muc_subscribe_event(<<"urn:xmpp:mucsub:0">>, + IgnoreEls, _el); + {<<"subscriptions">>, <<"urn:xmpp:mucsub:0">>} -> + decode_muc_subscriptions(<<"urn:xmpp:mucsub:0">>, + IgnoreEls, _el); + {<<"subscription">>, <<"urn:xmpp:mucsub:0">>} -> + decode_muc_subscription(<<"urn:xmpp:mucsub:0">>, + IgnoreEls, _el); + {<<"x">>, <<"jabber:x:conference">>} -> + decode_x_conference(<<"jabber:x:conference">>, + IgnoreEls, _el); + {<<"unique">>, + <<"http://jabber.org/protocol/muc#unique">>} -> + decode_muc_unique(<<"http://jabber.org/protocol/muc#unique">>, + IgnoreEls, _el); {<<"x">>, <<"http://jabber.org/protocol/muc">>} -> decode_muc(<<"http://jabber.org/protocol/muc">>, IgnoreEls, _el); @@ -223,10 +278,6 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> <<"http://jabber.org/protocol/muc#admin">>} -> decode_muc_admin(<<"http://jabber.org/protocol/muc#admin">>, IgnoreEls, _el); - {<<"reason">>, - <<"http://jabber.org/protocol/muc#admin">>} -> - decode_muc_admin_reason(<<"http://jabber.org/protocol/muc#admin">>, - IgnoreEls, _el); {<<"continue">>, <<"http://jabber.org/protocol/muc#admin">>} -> decode_muc_admin_continue(<<"http://jabber.org/protocol/muc#admin">>, @@ -239,22 +290,26 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> <<"http://jabber.org/protocol/muc#admin">>} -> decode_muc_admin_item(<<"http://jabber.org/protocol/muc#admin">>, IgnoreEls, _el); + {<<"item">>, + <<"http://jabber.org/protocol/muc#owner">>} -> + decode_muc_owner_item(<<"http://jabber.org/protocol/muc#owner">>, + IgnoreEls, _el); {<<"query">>, <<"http://jabber.org/protocol/muc#owner">>} -> decode_muc_owner(<<"http://jabber.org/protocol/muc#owner">>, IgnoreEls, _el); - {<<"destroy">>, - <<"http://jabber.org/protocol/muc#owner">>} -> - decode_muc_owner_destroy(<<"http://jabber.org/protocol/muc#owner">>, - IgnoreEls, _el); - {<<"reason">>, - <<"http://jabber.org/protocol/muc#owner">>} -> - decode_muc_owner_reason(<<"http://jabber.org/protocol/muc#owner">>, - IgnoreEls, _el); {<<"password">>, <<"http://jabber.org/protocol/muc#owner">>} -> - decode_muc_owner_password(<<"http://jabber.org/protocol/muc#owner">>, - IgnoreEls, _el); + decode_muc_password(<<"http://jabber.org/protocol/muc#owner">>, + IgnoreEls, _el); + {<<"password">>, + <<"http://jabber.org/protocol/muc#user">>} -> + decode_muc_password(<<"http://jabber.org/protocol/muc#user">>, + IgnoreEls, _el); + {<<"password">>, + <<"http://jabber.org/protocol/muc">>} -> + decode_muc_password(<<"http://jabber.org/protocol/muc">>, + IgnoreEls, _el); {<<"x">>, <<"http://jabber.org/protocol/muc#user">>} -> decode_muc_user(<<"http://jabber.org/protocol/muc#user">>, IgnoreEls, _el); @@ -280,16 +335,28 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> IgnoreEls, _el); {<<"destroy">>, <<"http://jabber.org/protocol/muc#user">>} -> - decode_muc_user_destroy(<<"http://jabber.org/protocol/muc#user">>, - IgnoreEls, _el); + decode_muc_destroy(<<"http://jabber.org/protocol/muc#user">>, + IgnoreEls, _el); + {<<"destroy">>, + <<"http://jabber.org/protocol/muc#owner">>} -> + decode_muc_destroy(<<"http://jabber.org/protocol/muc#owner">>, + IgnoreEls, _el); {<<"decline">>, <<"http://jabber.org/protocol/muc#user">>} -> decode_muc_user_decline(<<"http://jabber.org/protocol/muc#user">>, IgnoreEls, _el); {<<"reason">>, <<"http://jabber.org/protocol/muc#user">>} -> - decode_muc_user_reason(<<"http://jabber.org/protocol/muc#user">>, - IgnoreEls, _el); + decode_muc_reason(<<"http://jabber.org/protocol/muc#user">>, + IgnoreEls, _el); + {<<"reason">>, + <<"http://jabber.org/protocol/muc#admin">>} -> + decode_muc_reason(<<"http://jabber.org/protocol/muc#admin">>, + IgnoreEls, _el); + {<<"reason">>, + <<"http://jabber.org/protocol/muc#owner">>} -> + decode_muc_reason(<<"http://jabber.org/protocol/muc#owner">>, + IgnoreEls, _el); {<<"history">>, <<"http://jabber.org/protocol/muc">>} -> decode_muc_history(<<"http://jabber.org/protocol/muc">>, IgnoreEls, _el); @@ -1002,6 +1069,10 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_policy_violation(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, IgnoreEls, _el); + {<<"payment-required">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> + decode_error_payment_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + IgnoreEls, _el); {<<"not-authorized">>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_not_authorized(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, @@ -1183,6 +1254,16 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> is_known_tag({xmlel, _name, _attrs, _} = _el) -> case {_name, get_attr(<<"xmlns">>, _attrs)} of + {<<"client-id">>, <<"urn:xmpp:sid:0">>} -> true; + {<<"stanza-id">>, <<"urn:xmpp:sid:0">>} -> true; + {<<"addresses">>, + <<"http://jabber.org/protocol/address">>} -> + true; + {<<"address">>, + <<"http://jabber.org/protocol/address">>} -> + true; + {<<"nick">>, <<"http://jabber.org/protocol/nick">>} -> + true; {<<"x">>, <<"jabber:x:expire">>} -> true; {<<"x">>, <<"jabber:x:event">>} -> true; {<<"id">>, <<"jabber:x:event">>} -> true; @@ -1197,6 +1278,8 @@ is_known_tag({xmlel, _name, _attrs, _} = _el) -> {<<"last">>, <<"jabber:iq:search">>} -> true; {<<"first">>, <<"jabber:iq:search">>} -> true; {<<"instructions">>, <<"jabber:iq:search">>} -> true; + {<<"no-permanent-storage">>, <<"urn:xmpp:hints">>} -> + true; {<<"no-permanent-store">>, <<"urn:xmpp:hints">>} -> true; {<<"store">>, <<"urn:xmpp:hints">>} -> true; @@ -1248,8 +1331,14 @@ is_known_tag({xmlel, _name, _attrs, _} = _el) -> {<<"prefs">>, <<"urn:xmpp:mam:0">>} -> true; {<<"prefs">>, <<"urn:xmpp:mam:1">>} -> true; {<<"prefs">>, <<"urn:xmpp:mam:tmp">>} -> true; + {<<"always">>, <<"urn:xmpp:mam:0">>} -> true; + {<<"always">>, <<"urn:xmpp:mam:1">>} -> true; {<<"always">>, <<"urn:xmpp:mam:tmp">>} -> true; + {<<"never">>, <<"urn:xmpp:mam:0">>} -> true; + {<<"never">>, <<"urn:xmpp:mam:1">>} -> true; {<<"never">>, <<"urn:xmpp:mam:tmp">>} -> true; + {<<"jid">>, <<"urn:xmpp:mam:0">>} -> true; + {<<"jid">>, <<"urn:xmpp:mam:1">>} -> true; {<<"jid">>, <<"urn:xmpp:mam:tmp">>} -> true; {<<"result">>, <<"urn:xmpp:mam:0">>} -> true; {<<"result">>, <<"urn:xmpp:mam:1">>} -> true; @@ -1258,6 +1347,7 @@ is_known_tag({xmlel, _name, _attrs, _} = _el) -> {<<"query">>, <<"urn:xmpp:mam:0">>} -> true; {<<"query">>, <<"urn:xmpp:mam:1">>} -> true; {<<"query">>, <<"urn:xmpp:mam:tmp">>} -> true; + {<<"withtext">>, <<"urn:xmpp:mam:tmp">>} -> true; {<<"with">>, <<"urn:xmpp:mam:tmp">>} -> true; {<<"end">>, <<"urn:xmpp:mam:tmp">>} -> true; {<<"start">>, <<"urn:xmpp:mam:tmp">>} -> true; @@ -1277,13 +1367,19 @@ is_known_tag({xmlel, _name, _attrs, _} = _el) -> true; {<<"after">>, <<"http://jabber.org/protocol/rsm">>} -> true; + {<<"unsubscribe">>, <<"urn:xmpp:mucsub:0">>} -> true; + {<<"subscribe">>, <<"urn:xmpp:mucsub:0">>} -> true; + {<<"event">>, <<"urn:xmpp:mucsub:0">>} -> true; + {<<"subscriptions">>, <<"urn:xmpp:mucsub:0">>} -> true; + {<<"subscription">>, <<"urn:xmpp:mucsub:0">>} -> true; + {<<"x">>, <<"jabber:x:conference">>} -> true; + {<<"unique">>, + <<"http://jabber.org/protocol/muc#unique">>} -> + true; {<<"x">>, <<"http://jabber.org/protocol/muc">>} -> true; {<<"query">>, <<"http://jabber.org/protocol/muc#admin">>} -> true; - {<<"reason">>, - <<"http://jabber.org/protocol/muc#admin">>} -> - true; {<<"continue">>, <<"http://jabber.org/protocol/muc#admin">>} -> true; @@ -1293,18 +1389,21 @@ is_known_tag({xmlel, _name, _attrs, _} = _el) -> {<<"item">>, <<"http://jabber.org/protocol/muc#admin">>} -> true; + {<<"item">>, + <<"http://jabber.org/protocol/muc#owner">>} -> + true; {<<"query">>, <<"http://jabber.org/protocol/muc#owner">>} -> true; - {<<"destroy">>, - <<"http://jabber.org/protocol/muc#owner">>} -> - true; - {<<"reason">>, - <<"http://jabber.org/protocol/muc#owner">>} -> - true; {<<"password">>, <<"http://jabber.org/protocol/muc#owner">>} -> true; + {<<"password">>, + <<"http://jabber.org/protocol/muc#user">>} -> + true; + {<<"password">>, + <<"http://jabber.org/protocol/muc">>} -> + true; {<<"x">>, <<"http://jabber.org/protocol/muc#user">>} -> true; {<<"item">>, @@ -1325,12 +1424,21 @@ is_known_tag({xmlel, _name, _attrs, _} = _el) -> {<<"destroy">>, <<"http://jabber.org/protocol/muc#user">>} -> true; + {<<"destroy">>, + <<"http://jabber.org/protocol/muc#owner">>} -> + true; {<<"decline">>, <<"http://jabber.org/protocol/muc#user">>} -> true; {<<"reason">>, <<"http://jabber.org/protocol/muc#user">>} -> true; + {<<"reason">>, + <<"http://jabber.org/protocol/muc#admin">>} -> + true; + {<<"reason">>, + <<"http://jabber.org/protocol/muc#owner">>} -> + true; {<<"history">>, <<"http://jabber.org/protocol/muc">>} -> true; {<<"query">>, @@ -1773,6 +1881,9 @@ is_known_tag({xmlel, _name, _attrs, _} = _el) -> {<<"policy-violation">>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; + {<<"payment-required">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> + true; {<<"not-authorized">>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; @@ -1914,7 +2025,7 @@ encode({disco_item, _, _, _} = Item) -> encode_disco_item(Item, [{<<"xmlns">>, <<"http://jabber.org/protocol/disco#items">>}]); -encode({disco_items, _, _} = Query) -> +encode({disco_items, _, _, _} = Query) -> encode_disco_items(Query, [{<<"xmlns">>, <<"http://jabber.org/protocol/disco#items">>}]); @@ -2107,6 +2218,9 @@ encode({vcard_temp, _, _, _, _, _, _, _, _, _, _, _, _, encode({vcard_xupdate, undefined, _} = X) -> encode_vcard_xupdate(X, [{<<"xmlns">>, <<"vcard-temp:x:update">>}]); +encode({xdata_option, _, _} = Option) -> + encode_xdata_field_option(Option, + [{<<"xmlns">>, <<"jabber:x:data">>}]); encode({xdata_field, _, _, _, _, _, _, _} = Field) -> encode_xdata_field(Field, [{<<"xmlns">>, <<"jabber:x:data">>}]); @@ -2206,11 +2320,9 @@ encode({muc_decline, _, _, _} = Decline) -> encode_muc_user_decline(Decline, [{<<"xmlns">>, <<"http://jabber.org/protocol/muc#user">>}]); -encode({muc_user_destroy, _, _} = Destroy) -> - encode_muc_user_destroy(Destroy, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/muc#user">>}]); -encode({muc_invite, _, _, _} = Invite) -> +encode({muc_destroy, _, _, _, _} = Destroy) -> + encode_muc_destroy(Destroy, []); +encode({muc_invite, _, _, _, _} = Invite) -> encode_muc_user_invite(Invite, [{<<"xmlns">>, <<"http://jabber.org/protocol/muc#user">>}]); @@ -2218,11 +2330,7 @@ encode({muc_user, _, _, _, _, _, _} = X) -> encode_muc_user(X, [{<<"xmlns">>, <<"http://jabber.org/protocol/muc#user">>}]); -encode({muc_owner_destroy, _, _, _} = Destroy) -> - encode_muc_owner_destroy(Destroy, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/muc#owner">>}]); -encode({muc_owner, _, _} = Query) -> +encode({muc_owner, _, _, _} = Query) -> encode_muc_owner(Query, [{<<"xmlns">>, <<"http://jabber.org/protocol/muc#owner">>}]); @@ -2237,13 +2345,29 @@ encode({muc_admin, _} = Query) -> encode({muc, _, _} = X) -> encode_muc(X, [{<<"xmlns">>, <<"http://jabber.org/protocol/muc">>}]); +encode({muc_unique, _} = Unique) -> + encode_muc_unique(Unique, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/muc#unique">>}]); +encode({x_conference, _, _, _, _, _} = X) -> + encode_x_conference(X, + [{<<"xmlns">>, <<"jabber:x:conference">>}]); +encode({muc_subscriptions, _} = Subscriptions) -> + encode_muc_subscriptions(Subscriptions, + [{<<"xmlns">>, <<"urn:xmpp:mucsub:0">>}]); +encode({muc_subscribe, _, _} = Subscribe) -> + encode_muc_subscribe(Subscribe, + [{<<"xmlns">>, <<"urn:xmpp:mucsub:0">>}]); +encode({muc_unsubscribe} = Unsubscribe) -> + encode_muc_unsubscribe(Unsubscribe, + [{<<"xmlns">>, <<"urn:xmpp:mucsub:0">>}]); encode({rsm_first, _, _} = First) -> encode_rsm_first(First, [{<<"xmlns">>, <<"http://jabber.org/protocol/rsm">>}]); encode({rsm_set, _, _, _, _, _, _, _} = Set) -> encode_rsm_set(Set, [{<<"xmlns">>, <<"http://jabber.org/protocol/rsm">>}]); -encode({mam_query, _, _, _, _, _, _, _} = Query) -> +encode({mam_query, _, _, _, _, _, _, _, _} = Query) -> encode_mam_query(Query, []); encode({mam_archived, _, _} = Archived) -> encode_mam_archived(Archived, @@ -2328,6 +2452,10 @@ encode({hint, 'no-permanent-store'} = No_permanent_store) -> encode_hint_no_permanent_store(No_permanent_store, [{<<"xmlns">>, <<"urn:xmpp:hints">>}]); +encode({hint, 'no-permanent-storage'} = + No_permanent_storage) -> + encode_hint_no_permanent_storage(No_permanent_storage, + [{<<"xmlns">>, <<"urn:xmpp:hints">>}]); encode({search_item, _, _, _, _, _} = Item) -> encode_search_item(Item, [{<<"xmlns">>, <<"jabber:iq:search">>}]); @@ -2338,7 +2466,24 @@ encode({xevent, _, _, _, _, _} = X) -> encode_xevent(X, [{<<"xmlns">>, <<"jabber:x:event">>}]); encode({expire, _, _} = X) -> encode_expire(X, - [{<<"xmlns">>, <<"jabber:x:expire">>}]). + [{<<"xmlns">>, <<"jabber:x:expire">>}]); +encode({nick, _} = Nick) -> + encode_nick(Nick, + [{<<"xmlns">>, <<"http://jabber.org/protocol/nick">>}]); +encode({address, _, _, _, _, _} = Address) -> + encode_address(Address, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/address">>}]); +encode({addresses, _} = Addresses) -> + encode_addresses(Addresses, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/address">>}]); +encode({stanza_id, _, _} = Stanza_id) -> + encode_stanza_id(Stanza_id, + [{<<"xmlns">>, <<"urn:xmpp:sid:0">>}]); +encode({client_id, _} = Client_id) -> + encode_client_id(Client_id, + [{<<"xmlns">>, <<"urn:xmpp:sid:0">>}]). get_name({last, _, _}) -> <<"query">>; get_name({version, _, _, _}) -> <<"query">>; @@ -2355,7 +2500,7 @@ get_name({block_list, _}) -> <<"blocklist">>; get_name({identity, _, _, _, _}) -> <<"identity">>; get_name({disco_info, _, _, _, _}) -> <<"query">>; get_name({disco_item, _, _, _}) -> <<"item">>; -get_name({disco_items, _, _}) -> <<"query">>; +get_name({disco_items, _, _, _}) -> <<"query">>; get_name({private, _}) -> <<"query">>; get_name({bookmark_conference, _, _, _, _, _}) -> <<"conference">>; @@ -2424,6 +2569,7 @@ get_name({vcard_temp, _, _, _, _, _, _, _, _, _, _, _, _}) -> <<"vCard">>; get_name({vcard_xupdate, undefined, _}) -> <<"x">>; +get_name({xdata_option, _, _}) -> <<"option">>; get_name({xdata_field, _, _, _, _, _, _, _}) -> <<"field">>; get_name({xdata, _, _, _, _, _, _}) -> <<"x">>; @@ -2456,18 +2602,22 @@ get_name({bytestreams, _, _, _, _, _, _}) -> <<"query">>; get_name({muc_history, _, _, _, _}) -> <<"history">>; get_name({muc_decline, _, _, _}) -> <<"decline">>; -get_name({muc_user_destroy, _, _}) -> <<"destroy">>; -get_name({muc_invite, _, _, _}) -> <<"invite">>; +get_name({muc_destroy, _, _, _, _}) -> <<"destroy">>; +get_name({muc_invite, _, _, _, _}) -> <<"invite">>; get_name({muc_user, _, _, _, _, _, _}) -> <<"x">>; -get_name({muc_owner_destroy, _, _, _}) -> <<"destroy">>; -get_name({muc_owner, _, _}) -> <<"query">>; +get_name({muc_owner, _, _, _}) -> <<"query">>; get_name({muc_item, _, _, _, _, _, _, _}) -> <<"item">>; get_name({muc_actor, _, _}) -> <<"actor">>; get_name({muc_admin, _}) -> <<"query">>; get_name({muc, _, _}) -> <<"x">>; +get_name({muc_unique, _}) -> <<"unique">>; +get_name({x_conference, _, _, _, _, _}) -> <<"x">>; +get_name({muc_subscriptions, _}) -> <<"subscriptions">>; +get_name({muc_subscribe, _, _}) -> <<"subscribe">>; +get_name({muc_unsubscribe}) -> <<"unsubscribe">>; get_name({rsm_first, _, _}) -> <<"first">>; get_name({rsm_set, _, _, _, _, _, _, _}) -> <<"set">>; -get_name({mam_query, _, _, _, _, _, _, _}) -> +get_name({mam_query, _, _, _, _, _, _, _, _}) -> <<"query">>; get_name({mam_archived, _, _}) -> <<"archived">>; get_name({mam_result, _, _, _, _}) -> <<"result">>; @@ -2501,10 +2651,17 @@ get_name({hint, 'no-storage'}) -> <<"no-storage">>; get_name({hint, store}) -> <<"store">>; get_name({hint, 'no-permanent-store'}) -> <<"no-permanent-store">>; +get_name({hint, 'no-permanent-storage'}) -> + <<"no-permanent-storage">>; get_name({search_item, _, _, _, _, _}) -> <<"item">>; get_name({search, _, _, _, _, _, _, _}) -> <<"query">>; get_name({xevent, _, _, _, _, _}) -> <<"x">>; -get_name({expire, _, _}) -> <<"x">>. +get_name({expire, _, _}) -> <<"x">>; +get_name({nick, _}) -> <<"nick">>; +get_name({address, _, _, _, _, _}) -> <<"address">>; +get_name({addresses, _}) -> <<"addresses">>; +get_name({stanza_id, _, _}) -> <<"stanza-id">>; +get_name({client_id, _}) -> <<"client-id">>. get_ns({last, _, _}) -> <<"jabber:iq:last">>; get_ns({version, _, _, _}) -> <<"jabber:iq:version">>; @@ -2527,7 +2684,7 @@ get_ns({disco_info, _, _, _, _}) -> <<"http://jabber.org/protocol/disco#info">>; get_ns({disco_item, _, _, _}) -> <<"http://jabber.org/protocol/disco#items">>; -get_ns({disco_items, _, _}) -> +get_ns({disco_items, _, _, _}) -> <<"http://jabber.org/protocol/disco#items">>; get_ns({private, _}) -> <<"jabber:iq:private">>; get_ns({bookmark_conference, _, _, _, _, _}) -> @@ -2624,6 +2781,7 @@ get_ns({vcard_temp, _, _, _, _, _, _, _, _, _, _, _, _, <<"vcard-temp">>; get_ns({vcard_xupdate, undefined, _}) -> <<"vcard-temp:x:update">>; +get_ns({xdata_option, _, _}) -> <<"jabber:x:data">>; get_ns({xdata_field, _, _, _, _, _, _, _}) -> <<"jabber:x:data">>; get_ns({xdata, _, _, _, _, _, _}) -> @@ -2675,25 +2833,32 @@ get_ns({muc_history, _, _, _, _}) -> <<"http://jabber.org/protocol/muc">>; get_ns({muc_decline, _, _, _}) -> <<"http://jabber.org/protocol/muc#user">>; -get_ns({muc_user_destroy, _, _}) -> - <<"http://jabber.org/protocol/muc#user">>; -get_ns({muc_invite, _, _, _}) -> +get_ns({muc_destroy, Xmlns, _, _, _}) -> Xmlns; +get_ns({muc_invite, _, _, _, _}) -> <<"http://jabber.org/protocol/muc#user">>; get_ns({muc_user, _, _, _, _, _, _}) -> <<"http://jabber.org/protocol/muc#user">>; -get_ns({muc_owner_destroy, _, _, _}) -> - <<"http://jabber.org/protocol/muc#owner">>; -get_ns({muc_owner, _, _}) -> +get_ns({muc_owner, _, _, _}) -> <<"http://jabber.org/protocol/muc#owner">>; get_ns({muc_admin, _}) -> <<"http://jabber.org/protocol/muc#admin">>; get_ns({muc, _, _}) -> <<"http://jabber.org/protocol/muc">>; +get_ns({muc_unique, _}) -> + <<"http://jabber.org/protocol/muc#unique">>; +get_ns({x_conference, _, _, _, _, _}) -> + <<"jabber:x:conference">>; +get_ns({muc_subscriptions, _}) -> + <<"urn:xmpp:mucsub:0">>; +get_ns({muc_subscribe, _, _}) -> + <<"urn:xmpp:mucsub:0">>; +get_ns({muc_unsubscribe}) -> <<"urn:xmpp:mucsub:0">>; get_ns({rsm_first, _, _}) -> <<"http://jabber.org/protocol/rsm">>; get_ns({rsm_set, _, _, _, _, _, _, _}) -> <<"http://jabber.org/protocol/rsm">>; -get_ns({mam_query, Xmlns, _, _, _, _, _, _}) -> Xmlns; +get_ns({mam_query, Xmlns, _, _, _, _, _, _, _}) -> + Xmlns; get_ns({mam_archived, _, _}) -> <<"urn:xmpp:mam:tmp">>; get_ns({mam_result, Xmlns, _, _, _}) -> Xmlns; get_ns({mam_prefs, Xmlns, _, _, _}) -> Xmlns; @@ -2729,12 +2894,22 @@ get_ns({hint, 'no-storage'}) -> <<"urn:xmpp:hints">>; get_ns({hint, store}) -> <<"urn:xmpp:hints">>; get_ns({hint, 'no-permanent-store'}) -> <<"urn:xmpp:hints">>; +get_ns({hint, 'no-permanent-storage'}) -> + <<"urn:xmpp:hints">>; get_ns({search_item, _, _, _, _, _}) -> <<"jabber:iq:search">>; get_ns({search, _, _, _, _, _, _, _}) -> <<"jabber:iq:search">>; get_ns({xevent, _, _, _, _, _}) -> <<"jabber:x:event">>; -get_ns({expire, _, _}) -> <<"jabber:x:expire">>. +get_ns({expire, _, _}) -> <<"jabber:x:expire">>; +get_ns({nick, _}) -> + <<"http://jabber.org/protocol/nick">>; +get_ns({address, _, _, _, _, _}) -> + <<"http://jabber.org/protocol/address">>; +get_ns({addresses, _}) -> + <<"http://jabber.org/protocol/address">>; +get_ns({stanza_id, _, _}) -> <<"urn:xmpp:sid:0">>; +get_ns({client_id, _}) -> <<"urn:xmpp:sid:0">>. dec_int(Val) -> dec_int(Val, infinity, infinity). @@ -2801,7 +2976,7 @@ pp(identity, 4) -> [category, type, lang, name]; pp(disco_info, 4) -> [node, identities, features, xdata]; pp(disco_item, 3) -> [jid, name, node]; -pp(disco_items, 2) -> [node, items]; +pp(disco_items, 3) -> [node, items, rsm]; pp(private, 1) -> [xml_els]; pp(bookmark_conference, 5) -> [name, jid, autojoin, nick, password]; @@ -2876,6 +3051,7 @@ pp(vcard_temp, 29) -> org, categories, note, prodid, rev, sort_string, sound, uid, url, class, key, desc]; pp(vcard_xupdate, 2) -> [us, hash]; +pp(xdata_option, 2) -> [label, value]; pp(xdata_field, 7) -> [label, type, var, required, desc, values, options]; pp(xdata, 6) -> @@ -2905,23 +3081,28 @@ pp(bytestreams, 6) -> pp(muc_history, 4) -> [maxchars, maxstanzas, seconds, since]; pp(muc_decline, 3) -> [reason, from, to]; -pp(muc_user_destroy, 2) -> [reason, jid]; -pp(muc_invite, 3) -> [reason, from, to]; +pp(muc_destroy, 4) -> [xmlns, jid, reason, password]; +pp(muc_invite, 4) -> [reason, from, to, continue]; pp(muc_user, 6) -> [decline, destroy, invites, items, status_codes, password]; -pp(muc_owner_destroy, 3) -> [jid, reason, password]; -pp(muc_owner, 2) -> [destroy, config]; +pp(muc_owner, 3) -> [destroy, config, items]; pp(muc_item, 7) -> [actor, continue, reason, affiliation, role, jid, nick]; pp(muc_actor, 2) -> [jid, nick]; pp(muc_admin, 1) -> [items]; pp(muc, 2) -> [history, password]; +pp(muc_unique, 1) -> [name]; +pp(x_conference, 5) -> + [jid, password, reason, continue, thread]; +pp(muc_subscriptions, 1) -> [list]; +pp(muc_subscribe, 2) -> [nick, events]; +pp(muc_unsubscribe, 0) -> []; pp(rsm_first, 2) -> [index, data]; pp(rsm_set, 7) -> ['after', before, count, first, index, last, max]; -pp(mam_query, 7) -> - [xmlns, id, start, 'end', with, rsm, xdata]; +pp(mam_query, 8) -> + [xmlns, id, start, 'end', with, withtext, rsm, xdata]; pp(mam_archived, 2) -> [by, id]; pp(mam_result, 4) -> [xmlns, queryid, id, sub_els]; pp(mam_prefs, 4) -> [xmlns, default, always, never]; @@ -2954,6 +3135,11 @@ pp(search, 7) -> pp(xevent, 5) -> [offline, delivered, displayed, composing, id]; pp(expire, 2) -> [seconds, stored]; +pp(nick, 1) -> [name]; +pp(address, 5) -> [type, jid, desc, node, delivered]; +pp(addresses, 1) -> [list]; +pp(stanza_id, 2) -> [by, id]; +pp(client_id, 1) -> [id]; pp(_, _) -> no. join([], _Sep) -> <<>>; @@ -3000,6 +3186,274 @@ dec_tzo(Val) -> M = jlib:binary_to_integer(M1), if H >= -12, H =< 12, M >= 0, M < 60 -> {H, M} end. +decode_client_id(__TopXMLNS, __IgnoreEls, + {xmlel, <<"client-id">>, _attrs, _els}) -> + Id = decode_client_id_attrs(__TopXMLNS, _attrs, + undefined), + {client_id, Id}. + +decode_client_id_attrs(__TopXMLNS, + [{<<"id">>, _val} | _attrs], _Id) -> + decode_client_id_attrs(__TopXMLNS, _attrs, _val); +decode_client_id_attrs(__TopXMLNS, [_ | _attrs], Id) -> + decode_client_id_attrs(__TopXMLNS, _attrs, Id); +decode_client_id_attrs(__TopXMLNS, [], Id) -> + decode_client_id_attr_id(__TopXMLNS, Id). + +encode_client_id({client_id, Id}, _xmlns_attrs) -> + _els = [], + _attrs = encode_client_id_attr_id(Id, _xmlns_attrs), + {xmlel, <<"client-id">>, _attrs, _els}. + +decode_client_id_attr_id(__TopXMLNS, undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"id">>, <<"client-id">>, __TopXMLNS}}); +decode_client_id_attr_id(__TopXMLNS, _val) -> _val. + +encode_client_id_attr_id(_val, _acc) -> + [{<<"id">>, _val} | _acc]. + +decode_stanza_id(__TopXMLNS, __IgnoreEls, + {xmlel, <<"stanza-id">>, _attrs, _els}) -> + {Id, By} = decode_stanza_id_attrs(__TopXMLNS, _attrs, + undefined, undefined), + {stanza_id, By, Id}. + +decode_stanza_id_attrs(__TopXMLNS, + [{<<"id">>, _val} | _attrs], _Id, By) -> + decode_stanza_id_attrs(__TopXMLNS, _attrs, _val, By); +decode_stanza_id_attrs(__TopXMLNS, + [{<<"by">>, _val} | _attrs], Id, _By) -> + decode_stanza_id_attrs(__TopXMLNS, _attrs, Id, _val); +decode_stanza_id_attrs(__TopXMLNS, [_ | _attrs], Id, + By) -> + decode_stanza_id_attrs(__TopXMLNS, _attrs, Id, By); +decode_stanza_id_attrs(__TopXMLNS, [], Id, By) -> + {decode_stanza_id_attr_id(__TopXMLNS, Id), + decode_stanza_id_attr_by(__TopXMLNS, By)}. + +encode_stanza_id({stanza_id, By, Id}, _xmlns_attrs) -> + _els = [], + _attrs = encode_stanza_id_attr_by(By, + encode_stanza_id_attr_id(Id, + _xmlns_attrs)), + {xmlel, <<"stanza-id">>, _attrs, _els}. + +decode_stanza_id_attr_id(__TopXMLNS, undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"id">>, <<"stanza-id">>, __TopXMLNS}}); +decode_stanza_id_attr_id(__TopXMLNS, _val) -> _val. + +encode_stanza_id_attr_id(_val, _acc) -> + [{<<"id">>, _val} | _acc]. + +decode_stanza_id_attr_by(__TopXMLNS, undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"by">>, <<"stanza-id">>, __TopXMLNS}}); +decode_stanza_id_attr_by(__TopXMLNS, _val) -> + case catch dec_jid(_val) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"by">>, <<"stanza-id">>, + __TopXMLNS}}); + _res -> _res + end. + +encode_stanza_id_attr_by(_val, _acc) -> + [{<<"by">>, enc_jid(_val)} | _acc]. + +decode_addresses(__TopXMLNS, __IgnoreEls, + {xmlel, <<"addresses">>, _attrs, _els}) -> + List = decode_addresses_els(__TopXMLNS, __IgnoreEls, + _els, []), + {addresses, List}. + +decode_addresses_els(__TopXMLNS, __IgnoreEls, [], + List) -> + lists:reverse(List); +decode_addresses_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"address">>, _attrs, _} = _el | _els], + List) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/address">> -> + decode_addresses_els(__TopXMLNS, __IgnoreEls, _els, + [decode_address(__TopXMLNS, __IgnoreEls, _el) + | List]); + <<"http://jabber.org/protocol/address">> -> + decode_addresses_els(__TopXMLNS, __IgnoreEls, _els, + [decode_address(<<"http://jabber.org/protocol/address">>, + __IgnoreEls, _el) + | List]); + _ -> + decode_addresses_els(__TopXMLNS, __IgnoreEls, _els, + List) + end; +decode_addresses_els(__TopXMLNS, __IgnoreEls, + [_ | _els], List) -> + decode_addresses_els(__TopXMLNS, __IgnoreEls, _els, + List). + +encode_addresses({addresses, List}, _xmlns_attrs) -> + _els = lists:reverse('encode_addresses_$list'(List, + [])), + _attrs = _xmlns_attrs, + {xmlel, <<"addresses">>, _attrs, _els}. + +'encode_addresses_$list'([], _acc) -> _acc; +'encode_addresses_$list'([List | _els], _acc) -> + 'encode_addresses_$list'(_els, + [encode_address(List, []) | _acc]). + +decode_address(__TopXMLNS, __IgnoreEls, + {xmlel, <<"address">>, _attrs, _els}) -> + {Type, Jid, Desc, Node, Delivered} = + decode_address_attrs(__TopXMLNS, _attrs, undefined, + undefined, undefined, undefined, undefined), + {address, Type, Jid, Desc, Node, Delivered}. + +decode_address_attrs(__TopXMLNS, + [{<<"type">>, _val} | _attrs], _Type, Jid, Desc, Node, + Delivered) -> + decode_address_attrs(__TopXMLNS, _attrs, _val, Jid, + Desc, Node, Delivered); +decode_address_attrs(__TopXMLNS, + [{<<"jid">>, _val} | _attrs], Type, _Jid, Desc, Node, + Delivered) -> + decode_address_attrs(__TopXMLNS, _attrs, Type, _val, + Desc, Node, Delivered); +decode_address_attrs(__TopXMLNS, + [{<<"desc">>, _val} | _attrs], Type, Jid, _Desc, Node, + Delivered) -> + decode_address_attrs(__TopXMLNS, _attrs, Type, Jid, + _val, Node, Delivered); +decode_address_attrs(__TopXMLNS, + [{<<"node">>, _val} | _attrs], Type, Jid, Desc, _Node, + Delivered) -> + decode_address_attrs(__TopXMLNS, _attrs, Type, Jid, + Desc, _val, Delivered); +decode_address_attrs(__TopXMLNS, + [{<<"delivered">>, _val} | _attrs], Type, Jid, Desc, + Node, _Delivered) -> + decode_address_attrs(__TopXMLNS, _attrs, Type, Jid, + Desc, Node, _val); +decode_address_attrs(__TopXMLNS, [_ | _attrs], Type, + Jid, Desc, Node, Delivered) -> + decode_address_attrs(__TopXMLNS, _attrs, Type, Jid, + Desc, Node, Delivered); +decode_address_attrs(__TopXMLNS, [], Type, Jid, Desc, + Node, Delivered) -> + {decode_address_attr_type(__TopXMLNS, Type), + decode_address_attr_jid(__TopXMLNS, Jid), + decode_address_attr_desc(__TopXMLNS, Desc), + decode_address_attr_node(__TopXMLNS, Node), + decode_address_attr_delivered(__TopXMLNS, Delivered)}. + +encode_address({address, Type, Jid, Desc, Node, + Delivered}, + _xmlns_attrs) -> + _els = [], + _attrs = encode_address_attr_delivered(Delivered, + encode_address_attr_node(Node, + encode_address_attr_desc(Desc, + encode_address_attr_jid(Jid, + encode_address_attr_type(Type, + _xmlns_attrs))))), + {xmlel, <<"address">>, _attrs, _els}. + +decode_address_attr_type(__TopXMLNS, undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"type">>, <<"address">>, __TopXMLNS}}); +decode_address_attr_type(__TopXMLNS, _val) -> + case catch dec_enum(_val, + [bcc, cc, noreply, ofrom, replyroom, replyto, to]) + of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"type">>, <<"address">>, + __TopXMLNS}}); + _res -> _res + end. + +encode_address_attr_type(_val, _acc) -> + [{<<"type">>, enc_enum(_val)} | _acc]. + +decode_address_attr_jid(__TopXMLNS, undefined) -> + undefined; +decode_address_attr_jid(__TopXMLNS, _val) -> + case catch dec_jid(_val) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"jid">>, <<"address">>, + __TopXMLNS}}); + _res -> _res + end. + +encode_address_attr_jid(undefined, _acc) -> _acc; +encode_address_attr_jid(_val, _acc) -> + [{<<"jid">>, enc_jid(_val)} | _acc]. + +decode_address_attr_desc(__TopXMLNS, undefined) -> + undefined; +decode_address_attr_desc(__TopXMLNS, _val) -> _val. + +encode_address_attr_desc(undefined, _acc) -> _acc; +encode_address_attr_desc(_val, _acc) -> + [{<<"desc">>, _val} | _acc]. + +decode_address_attr_node(__TopXMLNS, undefined) -> + undefined; +decode_address_attr_node(__TopXMLNS, _val) -> _val. + +encode_address_attr_node(undefined, _acc) -> _acc; +encode_address_attr_node(_val, _acc) -> + [{<<"node">>, _val} | _acc]. + +decode_address_attr_delivered(__TopXMLNS, undefined) -> + undefined; +decode_address_attr_delivered(__TopXMLNS, _val) -> + case catch dec_bool(_val) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"delivered">>, <<"address">>, + __TopXMLNS}}); + _res -> _res + end. + +encode_address_attr_delivered(undefined, _acc) -> _acc; +encode_address_attr_delivered(_val, _acc) -> + [{<<"delivered">>, enc_bool(_val)} | _acc]. + +decode_nick(__TopXMLNS, __IgnoreEls, + {xmlel, <<"nick">>, _attrs, _els}) -> + Name = decode_nick_els(__TopXMLNS, __IgnoreEls, _els, + <<>>), + {nick, Name}. + +decode_nick_els(__TopXMLNS, __IgnoreEls, [], Name) -> + decode_nick_cdata(__TopXMLNS, Name); +decode_nick_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Name) -> + decode_nick_els(__TopXMLNS, __IgnoreEls, _els, + <>); +decode_nick_els(__TopXMLNS, __IgnoreEls, [_ | _els], + Name) -> + decode_nick_els(__TopXMLNS, __IgnoreEls, _els, Name). + +encode_nick({nick, Name}, _xmlns_attrs) -> + _els = encode_nick_cdata(Name, []), + _attrs = _xmlns_attrs, + {xmlel, <<"nick">>, _attrs, _els}. + +decode_nick_cdata(__TopXMLNS, <<>>) -> + erlang:error({xmpp_codec, + {missing_cdata, <<>>, <<"nick">>, __TopXMLNS}}); +decode_nick_cdata(__TopXMLNS, _val) -> _val. + +encode_nick_cdata(_val, _acc) -> + [{xmlcdata, _val} | _acc]. + decode_expire(__TopXMLNS, __IgnoreEls, {xmlel, <<"x">>, _attrs, _els}) -> {Seconds, Stored} = decode_expire_attrs(__TopXMLNS, @@ -3745,6 +4199,19 @@ encode_search_instructions_cdata(undefined, _acc) -> encode_search_instructions_cdata(_val, _acc) -> [{xmlcdata, _val} | _acc]. +decode_hint_no_permanent_storage(__TopXMLNS, + __IgnoreEls, + {xmlel, <<"no-permanent-storage">>, _attrs, + _els}) -> + {hint, 'no-permanent-storage'}. + +encode_hint_no_permanent_storage({hint, + 'no-permanent-storage'}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"no-permanent-storage">>, _attrs, _els}. + decode_hint_no_permanent_store(__TopXMLNS, __IgnoreEls, {xmlel, <<"no-permanent-store">>, _attrs, _els}) -> @@ -5380,7 +5847,8 @@ encode_mam_fin_attr_complete(_val, _acc) -> decode_mam_prefs(__TopXMLNS, __IgnoreEls, {xmlel, <<"prefs">>, _attrs, _els}) -> {Never, Always} = decode_mam_prefs_els(__TopXMLNS, - __IgnoreEls, _els, [], []), + __IgnoreEls, _els, undefined, + undefined), {Default, Xmlns} = decode_mam_prefs_attrs(__TopXMLNS, _attrs, undefined, undefined), {mam_prefs, Xmlns, Default, Always, Never}. @@ -5392,10 +5860,23 @@ decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"always">>, _attrs, _} = _el | _els], Never, Always) -> case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> + <<"">> + when __TopXMLNS == <<"urn:xmpp:mam:1">>; + __TopXMLNS == <<"urn:xmpp:mam:0">>; + __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, Never, decode_mam_always(__TopXMLNS, __IgnoreEls, _el)); + <<"urn:xmpp:mam:0">> -> + decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, + Never, + decode_mam_always(<<"urn:xmpp:mam:0">>, + __IgnoreEls, _el)); + <<"urn:xmpp:mam:1">> -> + decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, + Never, + decode_mam_always(<<"urn:xmpp:mam:1">>, + __IgnoreEls, _el)); <<"urn:xmpp:mam:tmp">> -> decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, Never, @@ -5409,10 +5890,23 @@ decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"never">>, _attrs, _} = _el | _els], Never, Always) -> case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> + <<"">> + when __TopXMLNS == <<"urn:xmpp:mam:1">>; + __TopXMLNS == <<"urn:xmpp:mam:0">>; + __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, decode_mam_never(__TopXMLNS, __IgnoreEls, _el), Always); + <<"urn:xmpp:mam:0">> -> + decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, + decode_mam_never(<<"urn:xmpp:mam:0">>, + __IgnoreEls, _el), + Always); + <<"urn:xmpp:mam:1">> -> + decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, + decode_mam_never(<<"urn:xmpp:mam:1">>, + __IgnoreEls, _el), + Always); <<"urn:xmpp:mam:tmp">> -> decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, decode_mam_never(<<"urn:xmpp:mam:tmp">>, @@ -5454,11 +5948,11 @@ encode_mam_prefs({mam_prefs, Xmlns, Default, Always, _xmlns_attrs)), {xmlel, <<"prefs">>, _attrs, _els}. -'encode_mam_prefs_$never'([], _acc) -> _acc; +'encode_mam_prefs_$never'(undefined, _acc) -> _acc; 'encode_mam_prefs_$never'(Never, _acc) -> [encode_mam_never(Never, []) | _acc]. -'encode_mam_prefs_$always'([], _acc) -> _acc; +'encode_mam_prefs_$always'(undefined, _acc) -> _acc; 'encode_mam_prefs_$always'(Always, _acc) -> [encode_mam_always(Always, []) | _acc]. @@ -5497,12 +5991,31 @@ decode_mam_always_els(__TopXMLNS, __IgnoreEls, [], decode_mam_always_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"jid">>, _attrs, _} = _el | _els], Jids) -> case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> + <<"">> + when __TopXMLNS == <<"urn:xmpp:mam:1">>; + __TopXMLNS == <<"urn:xmpp:mam:0">>; + __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> decode_mam_always_els(__TopXMLNS, __IgnoreEls, _els, case decode_mam_jid(__TopXMLNS, __IgnoreEls, _el) of - [] -> Jids; + undefined -> Jids; + _new_el -> [_new_el | Jids] + end); + <<"urn:xmpp:mam:0">> -> + decode_mam_always_els(__TopXMLNS, __IgnoreEls, _els, + case decode_mam_jid(<<"urn:xmpp:mam:0">>, + __IgnoreEls, _el) + of + undefined -> Jids; + _new_el -> [_new_el | Jids] + end); + <<"urn:xmpp:mam:1">> -> + decode_mam_always_els(__TopXMLNS, __IgnoreEls, _els, + case decode_mam_jid(<<"urn:xmpp:mam:1">>, + __IgnoreEls, _el) + of + undefined -> Jids; _new_el -> [_new_el | Jids] end); <<"urn:xmpp:mam:tmp">> -> @@ -5510,7 +6023,7 @@ decode_mam_always_els(__TopXMLNS, __IgnoreEls, case decode_mam_jid(<<"urn:xmpp:mam:tmp">>, __IgnoreEls, _el) of - [] -> Jids; + undefined -> Jids; _new_el -> [_new_el | Jids] end); _ -> @@ -5545,11 +6058,30 @@ decode_mam_never_els(__TopXMLNS, __IgnoreEls, [], decode_mam_never_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"jid">>, _attrs, _} = _el | _els], Jids) -> case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> + <<"">> + when __TopXMLNS == <<"urn:xmpp:mam:1">>; + __TopXMLNS == <<"urn:xmpp:mam:0">>; + __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> decode_mam_never_els(__TopXMLNS, __IgnoreEls, _els, case decode_mam_jid(__TopXMLNS, __IgnoreEls, _el) of - [] -> Jids; + undefined -> Jids; + _new_el -> [_new_el | Jids] + end); + <<"urn:xmpp:mam:0">> -> + decode_mam_never_els(__TopXMLNS, __IgnoreEls, _els, + case decode_mam_jid(<<"urn:xmpp:mam:0">>, + __IgnoreEls, _el) + of + undefined -> Jids; + _new_el -> [_new_el | Jids] + end); + <<"urn:xmpp:mam:1">> -> + decode_mam_never_els(__TopXMLNS, __IgnoreEls, _els, + case decode_mam_jid(<<"urn:xmpp:mam:1">>, + __IgnoreEls, _el) + of + undefined -> Jids; _new_el -> [_new_el | Jids] end); <<"urn:xmpp:mam:tmp">> -> @@ -5557,7 +6089,7 @@ decode_mam_never_els(__TopXMLNS, __IgnoreEls, case decode_mam_jid(<<"urn:xmpp:mam:tmp">>, __IgnoreEls, _el) of - [] -> Jids; + undefined -> Jids; _new_el -> [_new_el | Jids] end); _ -> @@ -5759,104 +6291,125 @@ encode_mam_archived_attr_by(_val, _acc) -> decode_mam_query(__TopXMLNS, __IgnoreEls, {xmlel, <<"query">>, _attrs, _els}) -> - {Xdata, End, Start, With, Rsm} = + {Xdata, Withtext, End, Start, With, Rsm} = decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, undefined, undefined, undefined, undefined, - undefined), + undefined, undefined), {Id, Xmlns} = decode_mam_query_attrs(__TopXMLNS, _attrs, undefined, undefined), - {mam_query, Xmlns, Id, Start, End, With, Rsm, Xdata}. + {mam_query, Xmlns, Id, Start, End, With, Withtext, Rsm, + Xdata}. decode_mam_query_els(__TopXMLNS, __IgnoreEls, [], Xdata, - End, Start, With, Rsm) -> - {Xdata, End, Start, With, Rsm}; + Withtext, End, Start, With, Rsm) -> + {Xdata, Withtext, End, Start, With, Rsm}; decode_mam_query_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"start">>, _attrs, _} = _el | _els], Xdata, - End, Start, With, Rsm) -> + Withtext, End, Start, With, Rsm) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, End, + Xdata, Withtext, End, decode_mam_start(__TopXMLNS, __IgnoreEls, _el), With, Rsm); <<"urn:xmpp:mam:tmp">> -> decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, End, + Xdata, Withtext, End, decode_mam_start(<<"urn:xmpp:mam:tmp">>, __IgnoreEls, _el), With, Rsm); _ -> decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, End, Start, With, Rsm) + Xdata, Withtext, End, Start, With, Rsm) end; decode_mam_query_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"end">>, _attrs, _} = _el | _els], Xdata, - End, Start, With, Rsm) -> + Withtext, End, Start, With, Rsm) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, + Xdata, Withtext, decode_mam_end(__TopXMLNS, __IgnoreEls, _el), Start, With, Rsm); <<"urn:xmpp:mam:tmp">> -> decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, + Xdata, Withtext, decode_mam_end(<<"urn:xmpp:mam:tmp">>, __IgnoreEls, _el), Start, With, Rsm); _ -> decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, End, Start, With, Rsm) + Xdata, Withtext, End, Start, With, Rsm) end; decode_mam_query_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"with">>, _attrs, _} = _el | _els], Xdata, - End, Start, With, Rsm) -> + Withtext, End, Start, With, Rsm) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, End, Start, + Xdata, Withtext, End, Start, decode_mam_with(__TopXMLNS, __IgnoreEls, _el), Rsm); <<"urn:xmpp:mam:tmp">> -> decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, End, Start, + Xdata, Withtext, End, Start, decode_mam_with(<<"urn:xmpp:mam:tmp">>, __IgnoreEls, _el), Rsm); _ -> decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, End, Start, With, Rsm) + Xdata, Withtext, End, Start, With, Rsm) + end; +decode_mam_query_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"withtext">>, _attrs, _} = _el | _els], + Xdata, Withtext, End, Start, With, Rsm) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> + decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, + decode_mam_withtext(__TopXMLNS, __IgnoreEls, + _el), + End, Start, With, Rsm); + <<"urn:xmpp:mam:tmp">> -> + decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, + decode_mam_withtext(<<"urn:xmpp:mam:tmp">>, + __IgnoreEls, _el), + End, Start, With, Rsm); + _ -> + decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, Withtext, End, Start, With, Rsm) end; decode_mam_query_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"set">>, _attrs, _} = _el | _els], Xdata, - End, Start, With, Rsm) -> + Withtext, End, Start, With, Rsm) -> case get_attr(<<"xmlns">>, _attrs) of <<"http://jabber.org/protocol/rsm">> -> decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, End, Start, With, + Xdata, Withtext, End, Start, With, decode_rsm_set(<<"http://jabber.org/protocol/rsm">>, __IgnoreEls, _el)); _ -> decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, End, Start, With, Rsm) + Xdata, Withtext, End, Start, With, Rsm) end; decode_mam_query_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"x">>, _attrs, _} = _el | _els], Xdata, End, - Start, With, Rsm) -> + [{xmlel, <<"x">>, _attrs, _} = _el | _els], Xdata, + Withtext, End, Start, With, Rsm) -> case get_attr(<<"xmlns">>, _attrs) of <<"jabber:x:data">> -> decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, decode_xdata(<<"jabber:x:data">>, __IgnoreEls, _el), - End, Start, With, Rsm); + Withtext, End, Start, With, Rsm); _ -> decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, End, Start, With, Rsm) + Xdata, Withtext, End, Start, With, Rsm) end; decode_mam_query_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Xdata, End, Start, With, Rsm) -> + [_ | _els], Xdata, Withtext, End, Start, With, Rsm) -> decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, End, Start, With, Rsm). + Xdata, Withtext, End, Start, With, Rsm). decode_mam_query_attrs(__TopXMLNS, [{<<"queryid">>, _val} | _attrs], _Id, Xmlns) -> @@ -5872,14 +6425,15 @@ decode_mam_query_attrs(__TopXMLNS, [], Id, Xmlns) -> decode_mam_query_attr_xmlns(__TopXMLNS, Xmlns)}. encode_mam_query({mam_query, Xmlns, Id, Start, End, - With, Rsm, Xdata}, + With, Withtext, Rsm, Xdata}, _xmlns_attrs) -> _els = lists:reverse('encode_mam_query_$xdata'(Xdata, - 'encode_mam_query_$end'(End, - 'encode_mam_query_$start'(Start, - 'encode_mam_query_$with'(With, - 'encode_mam_query_$rsm'(Rsm, - [])))))), + 'encode_mam_query_$withtext'(Withtext, + 'encode_mam_query_$end'(End, + 'encode_mam_query_$start'(Start, + 'encode_mam_query_$with'(With, + 'encode_mam_query_$rsm'(Rsm, + []))))))), _attrs = encode_mam_query_attr_xmlns(Xmlns, encode_mam_query_attr_queryid(Id, _xmlns_attrs)), @@ -5891,6 +6445,10 @@ encode_mam_query({mam_query, Xmlns, Id, Start, End, [{<<"xmlns">>, <<"jabber:x:data">>}]) | _acc]. +'encode_mam_query_$withtext'(undefined, _acc) -> _acc; +'encode_mam_query_$withtext'(Withtext, _acc) -> + [encode_mam_withtext(Withtext, []) | _acc]. + 'encode_mam_query_$end'(undefined, _acc) -> _acc; 'encode_mam_query_$end'(End, _acc) -> [encode_mam_end(End, []) | _acc]. @@ -5925,6 +6483,37 @@ encode_mam_query_attr_xmlns(undefined, _acc) -> _acc; encode_mam_query_attr_xmlns(_val, _acc) -> [{<<"xmlns">>, _val} | _acc]. +decode_mam_withtext(__TopXMLNS, __IgnoreEls, + {xmlel, <<"withtext">>, _attrs, _els}) -> + Cdata = decode_mam_withtext_els(__TopXMLNS, __IgnoreEls, + _els, <<>>), + Cdata. + +decode_mam_withtext_els(__TopXMLNS, __IgnoreEls, [], + Cdata) -> + decode_mam_withtext_cdata(__TopXMLNS, Cdata); +decode_mam_withtext_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Cdata) -> + decode_mam_withtext_els(__TopXMLNS, __IgnoreEls, _els, + <>); +decode_mam_withtext_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Cdata) -> + decode_mam_withtext_els(__TopXMLNS, __IgnoreEls, _els, + Cdata). + +encode_mam_withtext(Cdata, _xmlns_attrs) -> + _els = encode_mam_withtext_cdata(Cdata, []), + _attrs = _xmlns_attrs, + {xmlel, <<"withtext">>, _attrs, _els}. + +decode_mam_withtext_cdata(__TopXMLNS, <<>>) -> + erlang:error({xmpp_codec, + {missing_cdata, <<>>, <<"withtext">>, __TopXMLNS}}); +decode_mam_withtext_cdata(__TopXMLNS, _val) -> _val. + +encode_mam_withtext_cdata(_val, _acc) -> + [{xmlcdata, _val} | _acc]. + decode_mam_with(__TopXMLNS, __IgnoreEls, {xmlel, <<"with">>, _attrs, _els}) -> Cdata = decode_mam_with_els(__TopXMLNS, __IgnoreEls, @@ -6455,10 +7044,10 @@ encode_rsm_before(Cdata, _xmlns_attrs) -> _attrs = _xmlns_attrs, {xmlel, <<"before">>, _attrs, _els}. -decode_rsm_before_cdata(__TopXMLNS, <<>>) -> none; +decode_rsm_before_cdata(__TopXMLNS, <<>>) -> <<>>; decode_rsm_before_cdata(__TopXMLNS, _val) -> _val. -encode_rsm_before_cdata(none, _acc) -> _acc; +encode_rsm_before_cdata(<<>>, _acc) -> _acc; encode_rsm_before_cdata(_val, _acc) -> [{xmlcdata, _val} | _acc]. @@ -6492,63 +7081,438 @@ encode_rsm_after_cdata(undefined, _acc) -> _acc; encode_rsm_after_cdata(_val, _acc) -> [{xmlcdata, _val} | _acc]. +decode_muc_unsubscribe(__TopXMLNS, __IgnoreEls, + {xmlel, <<"unsubscribe">>, _attrs, _els}) -> + {muc_unsubscribe}. + +encode_muc_unsubscribe({muc_unsubscribe}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"unsubscribe">>, _attrs, _els}. + +decode_muc_subscribe(__TopXMLNS, __IgnoreEls, + {xmlel, <<"subscribe">>, _attrs, _els}) -> + Events = decode_muc_subscribe_els(__TopXMLNS, + __IgnoreEls, _els, []), + Nick = decode_muc_subscribe_attrs(__TopXMLNS, _attrs, + undefined), + {muc_subscribe, Nick, Events}. + +decode_muc_subscribe_els(__TopXMLNS, __IgnoreEls, [], + Events) -> + lists:reverse(Events); +decode_muc_subscribe_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"event">>, _attrs, _} = _el | _els], + Events) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"urn:xmpp:mucsub:0">> -> + decode_muc_subscribe_els(__TopXMLNS, __IgnoreEls, _els, + [decode_muc_subscribe_event(__TopXMLNS, + __IgnoreEls, _el) + | Events]); + <<"urn:xmpp:mucsub:0">> -> + decode_muc_subscribe_els(__TopXMLNS, __IgnoreEls, _els, + [decode_muc_subscribe_event(<<"urn:xmpp:mucsub:0">>, + __IgnoreEls, _el) + | Events]); + _ -> + decode_muc_subscribe_els(__TopXMLNS, __IgnoreEls, _els, + Events) + end; +decode_muc_subscribe_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Events) -> + decode_muc_subscribe_els(__TopXMLNS, __IgnoreEls, _els, + Events). + +decode_muc_subscribe_attrs(__TopXMLNS, + [{<<"nick">>, _val} | _attrs], _Nick) -> + decode_muc_subscribe_attrs(__TopXMLNS, _attrs, _val); +decode_muc_subscribe_attrs(__TopXMLNS, [_ | _attrs], + Nick) -> + decode_muc_subscribe_attrs(__TopXMLNS, _attrs, Nick); +decode_muc_subscribe_attrs(__TopXMLNS, [], Nick) -> + decode_muc_subscribe_attr_nick(__TopXMLNS, Nick). + +encode_muc_subscribe({muc_subscribe, Nick, Events}, + _xmlns_attrs) -> + _els = + lists:reverse('encode_muc_subscribe_$events'(Events, + [])), + _attrs = encode_muc_subscribe_attr_nick(Nick, + _xmlns_attrs), + {xmlel, <<"subscribe">>, _attrs, _els}. + +'encode_muc_subscribe_$events'([], _acc) -> _acc; +'encode_muc_subscribe_$events'([Events | _els], _acc) -> + 'encode_muc_subscribe_$events'(_els, + [encode_muc_subscribe_event(Events, []) + | _acc]). + +decode_muc_subscribe_attr_nick(__TopXMLNS, undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"nick">>, <<"subscribe">>, + __TopXMLNS}}); +decode_muc_subscribe_attr_nick(__TopXMLNS, _val) -> + _val. + +encode_muc_subscribe_attr_nick(_val, _acc) -> + [{<<"nick">>, _val} | _acc]. + +decode_muc_subscribe_event(__TopXMLNS, __IgnoreEls, + {xmlel, <<"event">>, _attrs, _els}) -> + Node = decode_muc_subscribe_event_attrs(__TopXMLNS, + _attrs, undefined), + Node. + +decode_muc_subscribe_event_attrs(__TopXMLNS, + [{<<"node">>, _val} | _attrs], _Node) -> + decode_muc_subscribe_event_attrs(__TopXMLNS, _attrs, + _val); +decode_muc_subscribe_event_attrs(__TopXMLNS, + [_ | _attrs], Node) -> + decode_muc_subscribe_event_attrs(__TopXMLNS, _attrs, + Node); +decode_muc_subscribe_event_attrs(__TopXMLNS, [], + Node) -> + decode_muc_subscribe_event_attr_node(__TopXMLNS, Node). + +encode_muc_subscribe_event(Node, _xmlns_attrs) -> + _els = [], + _attrs = encode_muc_subscribe_event_attr_node(Node, + _xmlns_attrs), + {xmlel, <<"event">>, _attrs, _els}. + +decode_muc_subscribe_event_attr_node(__TopXMLNS, + undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"node">>, <<"event">>, __TopXMLNS}}); +decode_muc_subscribe_event_attr_node(__TopXMLNS, + _val) -> + _val. + +encode_muc_subscribe_event_attr_node(_val, _acc) -> + [{<<"node">>, _val} | _acc]. + +decode_muc_subscriptions(__TopXMLNS, __IgnoreEls, + {xmlel, <<"subscriptions">>, _attrs, _els}) -> + List = decode_muc_subscriptions_els(__TopXMLNS, + __IgnoreEls, _els, []), + {muc_subscriptions, List}. + +decode_muc_subscriptions_els(__TopXMLNS, __IgnoreEls, + [], List) -> + lists:reverse(List); +decode_muc_subscriptions_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"subscription">>, _attrs, _} = _el + | _els], + List) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"urn:xmpp:mucsub:0">> -> + decode_muc_subscriptions_els(__TopXMLNS, __IgnoreEls, + _els, + case decode_muc_subscription(__TopXMLNS, + __IgnoreEls, + _el) + of + undefined -> List; + _new_el -> [_new_el | List] + end); + <<"urn:xmpp:mucsub:0">> -> + decode_muc_subscriptions_els(__TopXMLNS, __IgnoreEls, + _els, + case + decode_muc_subscription(<<"urn:xmpp:mucsub:0">>, + __IgnoreEls, + _el) + of + undefined -> List; + _new_el -> [_new_el | List] + end); + _ -> + decode_muc_subscriptions_els(__TopXMLNS, __IgnoreEls, + _els, List) + end; +decode_muc_subscriptions_els(__TopXMLNS, __IgnoreEls, + [_ | _els], List) -> + decode_muc_subscriptions_els(__TopXMLNS, __IgnoreEls, + _els, List). + +encode_muc_subscriptions({muc_subscriptions, List}, + _xmlns_attrs) -> + _els = + lists:reverse('encode_muc_subscriptions_$list'(List, + [])), + _attrs = _xmlns_attrs, + {xmlel, <<"subscriptions">>, _attrs, _els}. + +'encode_muc_subscriptions_$list'([], _acc) -> _acc; +'encode_muc_subscriptions_$list'([List | _els], _acc) -> + 'encode_muc_subscriptions_$list'(_els, + [encode_muc_subscription(List, []) + | _acc]). + +decode_muc_subscription(__TopXMLNS, __IgnoreEls, + {xmlel, <<"subscription">>, _attrs, _els}) -> + Jid = decode_muc_subscription_attrs(__TopXMLNS, _attrs, + undefined), + Jid. + +decode_muc_subscription_attrs(__TopXMLNS, + [{<<"jid">>, _val} | _attrs], _Jid) -> + decode_muc_subscription_attrs(__TopXMLNS, _attrs, _val); +decode_muc_subscription_attrs(__TopXMLNS, [_ | _attrs], + Jid) -> + decode_muc_subscription_attrs(__TopXMLNS, _attrs, Jid); +decode_muc_subscription_attrs(__TopXMLNS, [], Jid) -> + decode_muc_subscription_attr_jid(__TopXMLNS, Jid). + +encode_muc_subscription(Jid, _xmlns_attrs) -> + _els = [], + _attrs = encode_muc_subscription_attr_jid(Jid, + _xmlns_attrs), + {xmlel, <<"subscription">>, _attrs, _els}. + +decode_muc_subscription_attr_jid(__TopXMLNS, + undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"jid">>, <<"subscription">>, + __TopXMLNS}}); +decode_muc_subscription_attr_jid(__TopXMLNS, _val) -> + case catch dec_jid(_val) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"jid">>, <<"subscription">>, + __TopXMLNS}}); + _res -> _res + end. + +encode_muc_subscription_attr_jid(_val, _acc) -> + [{<<"jid">>, enc_jid(_val)} | _acc]. + +decode_x_conference(__TopXMLNS, __IgnoreEls, + {xmlel, <<"x">>, _attrs, _els}) -> + {Jid, Password, Reason, Thread, Continue} = + decode_x_conference_attrs(__TopXMLNS, _attrs, undefined, + undefined, undefined, undefined, undefined), + {x_conference, Jid, Password, Reason, Continue, Thread}. + +decode_x_conference_attrs(__TopXMLNS, + [{<<"jid">>, _val} | _attrs], _Jid, Password, Reason, + Thread, Continue) -> + decode_x_conference_attrs(__TopXMLNS, _attrs, _val, + Password, Reason, Thread, Continue); +decode_x_conference_attrs(__TopXMLNS, + [{<<"password">>, _val} | _attrs], Jid, _Password, + Reason, Thread, Continue) -> + decode_x_conference_attrs(__TopXMLNS, _attrs, Jid, _val, + Reason, Thread, Continue); +decode_x_conference_attrs(__TopXMLNS, + [{<<"reason">>, _val} | _attrs], Jid, Password, + _Reason, Thread, Continue) -> + decode_x_conference_attrs(__TopXMLNS, _attrs, Jid, + Password, _val, Thread, Continue); +decode_x_conference_attrs(__TopXMLNS, + [{<<"thread">>, _val} | _attrs], Jid, Password, + Reason, _Thread, Continue) -> + decode_x_conference_attrs(__TopXMLNS, _attrs, Jid, + Password, Reason, _val, Continue); +decode_x_conference_attrs(__TopXMLNS, + [{<<"continue">>, _val} | _attrs], Jid, Password, + Reason, Thread, _Continue) -> + decode_x_conference_attrs(__TopXMLNS, _attrs, Jid, + Password, Reason, Thread, _val); +decode_x_conference_attrs(__TopXMLNS, [_ | _attrs], Jid, + Password, Reason, Thread, Continue) -> + decode_x_conference_attrs(__TopXMLNS, _attrs, Jid, + Password, Reason, Thread, Continue); +decode_x_conference_attrs(__TopXMLNS, [], Jid, Password, + Reason, Thread, Continue) -> + {decode_x_conference_attr_jid(__TopXMLNS, Jid), + decode_x_conference_attr_password(__TopXMLNS, Password), + decode_x_conference_attr_reason(__TopXMLNS, Reason), + decode_x_conference_attr_thread(__TopXMLNS, Thread), + decode_x_conference_attr_continue(__TopXMLNS, + Continue)}. + +encode_x_conference({x_conference, Jid, Password, + Reason, Continue, Thread}, + _xmlns_attrs) -> + _els = [], + _attrs = encode_x_conference_attr_continue(Continue, + encode_x_conference_attr_thread(Thread, + encode_x_conference_attr_reason(Reason, + encode_x_conference_attr_password(Password, + encode_x_conference_attr_jid(Jid, + _xmlns_attrs))))), + {xmlel, <<"x">>, _attrs, _els}. + +decode_x_conference_attr_jid(__TopXMLNS, undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"jid">>, <<"x">>, __TopXMLNS}}); +decode_x_conference_attr_jid(__TopXMLNS, _val) -> + case catch dec_jid(_val) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"jid">>, <<"x">>, __TopXMLNS}}); + _res -> _res + end. + +encode_x_conference_attr_jid(_val, _acc) -> + [{<<"jid">>, enc_jid(_val)} | _acc]. + +decode_x_conference_attr_password(__TopXMLNS, + undefined) -> + <<>>; +decode_x_conference_attr_password(__TopXMLNS, _val) -> + _val. + +encode_x_conference_attr_password(<<>>, _acc) -> _acc; +encode_x_conference_attr_password(_val, _acc) -> + [{<<"password">>, _val} | _acc]. + +decode_x_conference_attr_reason(__TopXMLNS, + undefined) -> + <<>>; +decode_x_conference_attr_reason(__TopXMLNS, _val) -> + _val. + +encode_x_conference_attr_reason(<<>>, _acc) -> _acc; +encode_x_conference_attr_reason(_val, _acc) -> + [{<<"reason">>, _val} | _acc]. + +decode_x_conference_attr_thread(__TopXMLNS, + undefined) -> + <<>>; +decode_x_conference_attr_thread(__TopXMLNS, _val) -> + _val. + +encode_x_conference_attr_thread(<<>>, _acc) -> _acc; +encode_x_conference_attr_thread(_val, _acc) -> + [{<<"thread">>, _val} | _acc]. + +decode_x_conference_attr_continue(__TopXMLNS, + undefined) -> + undefined; +decode_x_conference_attr_continue(__TopXMLNS, _val) -> + case catch dec_bool(_val) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"continue">>, <<"x">>, __TopXMLNS}}); + _res -> _res + end. + +encode_x_conference_attr_continue(undefined, _acc) -> + _acc; +encode_x_conference_attr_continue(_val, _acc) -> + [{<<"continue">>, enc_bool(_val)} | _acc]. + +decode_muc_unique(__TopXMLNS, __IgnoreEls, + {xmlel, <<"unique">>, _attrs, _els}) -> + Name = decode_muc_unique_els(__TopXMLNS, __IgnoreEls, + _els, <<>>), + {muc_unique, Name}. + +decode_muc_unique_els(__TopXMLNS, __IgnoreEls, [], + Name) -> + decode_muc_unique_cdata(__TopXMLNS, Name); +decode_muc_unique_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Name) -> + decode_muc_unique_els(__TopXMLNS, __IgnoreEls, _els, + <>); +decode_muc_unique_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Name) -> + decode_muc_unique_els(__TopXMLNS, __IgnoreEls, _els, + Name). + +encode_muc_unique({muc_unique, Name}, _xmlns_attrs) -> + _els = encode_muc_unique_cdata(Name, []), + _attrs = _xmlns_attrs, + {xmlel, <<"unique">>, _attrs, _els}. + +decode_muc_unique_cdata(__TopXMLNS, <<>>) -> <<>>; +decode_muc_unique_cdata(__TopXMLNS, _val) -> _val. + +encode_muc_unique_cdata(<<>>, _acc) -> _acc; +encode_muc_unique_cdata(_val, _acc) -> + [{xmlcdata, _val} | _acc]. + decode_muc(__TopXMLNS, __IgnoreEls, {xmlel, <<"x">>, _attrs, _els}) -> - History = decode_muc_els(__TopXMLNS, __IgnoreEls, _els, - undefined), - Password = decode_muc_attrs(__TopXMLNS, _attrs, - undefined), + {Password, History} = decode_muc_els(__TopXMLNS, + __IgnoreEls, _els, undefined, + undefined), {muc, History, Password}. -decode_muc_els(__TopXMLNS, __IgnoreEls, [], History) -> - History; +decode_muc_els(__TopXMLNS, __IgnoreEls, [], Password, + History) -> + {Password, History}; decode_muc_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"history">>, _attrs, _} = _el | _els], - History) -> + Password, History) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/muc">> -> + decode_muc_els(__TopXMLNS, __IgnoreEls, _els, Password, + decode_muc_history(__TopXMLNS, __IgnoreEls, _el)); + <<"http://jabber.org/protocol/muc">> -> + decode_muc_els(__TopXMLNS, __IgnoreEls, _els, Password, + decode_muc_history(<<"http://jabber.org/protocol/muc">>, + __IgnoreEls, _el)); + _ -> + decode_muc_els(__TopXMLNS, __IgnoreEls, _els, Password, + History) + end; +decode_muc_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"password">>, _attrs, _} = _el | _els], + Password, History) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"http://jabber.org/protocol/muc">> -> decode_muc_els(__TopXMLNS, __IgnoreEls, _els, - decode_muc_history(__TopXMLNS, __IgnoreEls, _el)); + decode_muc_password(__TopXMLNS, __IgnoreEls, _el), + History); + <<"http://jabber.org/protocol/muc#owner">> -> + decode_muc_els(__TopXMLNS, __IgnoreEls, _els, + decode_muc_password(<<"http://jabber.org/protocol/muc#owner">>, + __IgnoreEls, _el), + History); + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_els(__TopXMLNS, __IgnoreEls, _els, + decode_muc_password(<<"http://jabber.org/protocol/muc#user">>, + __IgnoreEls, _el), + History); <<"http://jabber.org/protocol/muc">> -> decode_muc_els(__TopXMLNS, __IgnoreEls, _els, - decode_muc_history(<<"http://jabber.org/protocol/muc">>, - __IgnoreEls, _el)); + decode_muc_password(<<"http://jabber.org/protocol/muc">>, + __IgnoreEls, _el), + History); _ -> - decode_muc_els(__TopXMLNS, __IgnoreEls, _els, History) + decode_muc_els(__TopXMLNS, __IgnoreEls, _els, Password, + History) end; decode_muc_els(__TopXMLNS, __IgnoreEls, [_ | _els], - History) -> - decode_muc_els(__TopXMLNS, __IgnoreEls, _els, History). - -decode_muc_attrs(__TopXMLNS, - [{<<"password">>, _val} | _attrs], _Password) -> - decode_muc_attrs(__TopXMLNS, _attrs, _val); -decode_muc_attrs(__TopXMLNS, [_ | _attrs], Password) -> - decode_muc_attrs(__TopXMLNS, _attrs, Password); -decode_muc_attrs(__TopXMLNS, [], Password) -> - decode_muc_attr_password(__TopXMLNS, Password). + Password, History) -> + decode_muc_els(__TopXMLNS, __IgnoreEls, _els, Password, + History). encode_muc({muc, History, Password}, _xmlns_attrs) -> - _els = lists:reverse('encode_muc_$history'(History, - [])), - _attrs = encode_muc_attr_password(Password, - _xmlns_attrs), + _els = lists:reverse('encode_muc_$password'(Password, + 'encode_muc_$history'(History, + []))), + _attrs = _xmlns_attrs, {xmlel, <<"x">>, _attrs, _els}. +'encode_muc_$password'(undefined, _acc) -> _acc; +'encode_muc_$password'(Password, _acc) -> + [encode_muc_password(Password, []) | _acc]. + 'encode_muc_$history'(undefined, _acc) -> _acc; 'encode_muc_$history'(History, _acc) -> [encode_muc_history(History, []) | _acc]. -decode_muc_attr_password(__TopXMLNS, undefined) -> - undefined; -decode_muc_attr_password(__TopXMLNS, _val) -> _val. - -encode_muc_attr_password(undefined, _acc) -> _acc; -encode_muc_attr_password(_val, _acc) -> - [{<<"password">>, _val} | _acc]. - decode_muc_admin(__TopXMLNS, __IgnoreEls, {xmlel, <<"query">>, _attrs, _els}) -> Items = decode_muc_admin_els(__TopXMLNS, __IgnoreEls, @@ -6593,37 +7557,6 @@ encode_muc_admin({muc_admin, Items}, _xmlns_attrs) -> 'encode_muc_admin_$items'(_els, [encode_muc_admin_item(Items, []) | _acc]). -decode_muc_admin_reason(__TopXMLNS, __IgnoreEls, - {xmlel, <<"reason">>, _attrs, _els}) -> - Cdata = decode_muc_admin_reason_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_muc_admin_reason_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_muc_admin_reason_cdata(__TopXMLNS, Cdata); -decode_muc_admin_reason_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_muc_admin_reason_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_muc_admin_reason_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_muc_admin_reason_els(__TopXMLNS, __IgnoreEls, - _els, Cdata). - -encode_muc_admin_reason(Cdata, _xmlns_attrs) -> - _els = encode_muc_admin_reason_cdata(Cdata, []), - _attrs = _xmlns_attrs, - {xmlel, <<"reason">>, _attrs, _els}. - -decode_muc_admin_reason_cdata(__TopXMLNS, <<>>) -> - undefined; -decode_muc_admin_reason_cdata(__TopXMLNS, _val) -> _val. - -encode_muc_admin_reason_cdata(undefined, _acc) -> _acc; -encode_muc_admin_reason_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - decode_muc_admin_continue(__TopXMLNS, __IgnoreEls, {xmlel, <<"continue">>, _attrs, _els}) -> Thread = decode_muc_admin_continue_attrs(__TopXMLNS, @@ -6724,7 +7657,7 @@ decode_muc_admin_item(__TopXMLNS, __IgnoreEls, {xmlel, <<"item">>, _attrs, _els}) -> {Actor, Continue, Reason} = decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, - undefined, undefined, undefined), + undefined, undefined, <<>>), {Affiliation, Role, Jid, Nick} = decode_muc_admin_item_attrs(__TopXMLNS, _attrs, undefined, undefined, undefined, undefined), @@ -6785,13 +7718,23 @@ decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, <<"http://jabber.org/protocol/muc#admin">> -> decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, Actor, Continue, - decode_muc_admin_reason(__TopXMLNS, - __IgnoreEls, _el)); + decode_muc_reason(__TopXMLNS, __IgnoreEls, + _el)); + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, Continue, + decode_muc_reason(<<"http://jabber.org/protocol/muc#user">>, + __IgnoreEls, _el)); <<"http://jabber.org/protocol/muc#admin">> -> decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, Actor, Continue, - decode_muc_admin_reason(<<"http://jabber.org/protocol/muc#admin">>, - __IgnoreEls, _el)); + decode_muc_reason(<<"http://jabber.org/protocol/muc#admin">>, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/muc#owner">> -> + decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, Continue, + decode_muc_reason(<<"http://jabber.org/protocol/muc#owner">>, + __IgnoreEls, _el)); _ -> decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, Actor, Continue, Reason) @@ -6857,10 +7800,9 @@ encode_muc_admin_item({muc_item, Actor, Continue, 'encode_muc_admin_item_$continue'(Continue, _acc) -> [encode_muc_admin_continue(Continue, []) | _acc]. -'encode_muc_admin_item_$reason'(undefined, _acc) -> - _acc; +'encode_muc_admin_item_$reason'(<<>>, _acc) -> _acc; 'encode_muc_admin_item_$reason'(Reason, _acc) -> - [encode_muc_admin_reason(Reason, []) | _acc]. + [encode_muc_reason(Reason, []) | _acc]. decode_muc_admin_item_attr_affiliation(__TopXMLNS, undefined) -> @@ -6926,62 +7868,302 @@ encode_muc_admin_item_attr_nick(undefined, _acc) -> encode_muc_admin_item_attr_nick(_val, _acc) -> [{<<"nick">>, _val} | _acc]. +decode_muc_owner_item(__TopXMLNS, __IgnoreEls, + {xmlel, <<"item">>, _attrs, _els}) -> + {Actor, Continue, Reason} = + decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, _els, + undefined, undefined, <<>>), + {Affiliation, Role, Jid, Nick} = + decode_muc_owner_item_attrs(__TopXMLNS, _attrs, + undefined, undefined, undefined, undefined), + {muc_item, Actor, Continue, Reason, Affiliation, Role, + Jid, Nick}. + +decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, [], + Actor, Continue, Reason) -> + {Actor, Continue, Reason}; +decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"actor">>, _attrs, _} = _el | _els], Actor, + Continue, Reason) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"http://jabber.org/protocol/muc#admin">> -> + decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, _els, + decode_muc_admin_actor(<<"http://jabber.org/protocol/muc#admin">>, + __IgnoreEls, _el), + Continue, Reason); + _ -> + decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, Continue, Reason) + end; +decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"continue">>, _attrs, _} = _el | _els], + Actor, Continue, Reason) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"http://jabber.org/protocol/muc#admin">> -> + decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, + decode_muc_admin_continue(<<"http://jabber.org/protocol/muc#admin">>, + __IgnoreEls, _el), + Reason); + _ -> + decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, Continue, Reason) + end; +decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"reason">>, _attrs, _} = _el | _els], + Actor, Continue, Reason) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/muc#owner">> -> + decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, Continue, + decode_muc_reason(__TopXMLNS, __IgnoreEls, + _el)); + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, Continue, + decode_muc_reason(<<"http://jabber.org/protocol/muc#user">>, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/muc#admin">> -> + decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, Continue, + decode_muc_reason(<<"http://jabber.org/protocol/muc#admin">>, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/muc#owner">> -> + decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, Continue, + decode_muc_reason(<<"http://jabber.org/protocol/muc#owner">>, + __IgnoreEls, _el)); + _ -> + decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, Continue, Reason) + end; +decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Actor, Continue, Reason) -> + decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, Continue, Reason). + +decode_muc_owner_item_attrs(__TopXMLNS, + [{<<"affiliation">>, _val} | _attrs], _Affiliation, + Role, Jid, Nick) -> + decode_muc_owner_item_attrs(__TopXMLNS, _attrs, _val, + Role, Jid, Nick); +decode_muc_owner_item_attrs(__TopXMLNS, + [{<<"role">>, _val} | _attrs], Affiliation, _Role, + Jid, Nick) -> + decode_muc_owner_item_attrs(__TopXMLNS, _attrs, + Affiliation, _val, Jid, Nick); +decode_muc_owner_item_attrs(__TopXMLNS, + [{<<"jid">>, _val} | _attrs], Affiliation, Role, + _Jid, Nick) -> + decode_muc_owner_item_attrs(__TopXMLNS, _attrs, + Affiliation, Role, _val, Nick); +decode_muc_owner_item_attrs(__TopXMLNS, + [{<<"nick">>, _val} | _attrs], Affiliation, Role, + Jid, _Nick) -> + decode_muc_owner_item_attrs(__TopXMLNS, _attrs, + Affiliation, Role, Jid, _val); +decode_muc_owner_item_attrs(__TopXMLNS, [_ | _attrs], + Affiliation, Role, Jid, Nick) -> + decode_muc_owner_item_attrs(__TopXMLNS, _attrs, + Affiliation, Role, Jid, Nick); +decode_muc_owner_item_attrs(__TopXMLNS, [], Affiliation, + Role, Jid, Nick) -> + {decode_muc_owner_item_attr_affiliation(__TopXMLNS, + Affiliation), + decode_muc_owner_item_attr_role(__TopXMLNS, Role), + decode_muc_owner_item_attr_jid(__TopXMLNS, Jid), + decode_muc_owner_item_attr_nick(__TopXMLNS, Nick)}. + +encode_muc_owner_item({muc_item, Actor, Continue, + Reason, Affiliation, Role, Jid, Nick}, + _xmlns_attrs) -> + _els = + lists:reverse('encode_muc_owner_item_$actor'(Actor, + 'encode_muc_owner_item_$continue'(Continue, + 'encode_muc_owner_item_$reason'(Reason, + [])))), + _attrs = encode_muc_owner_item_attr_nick(Nick, + encode_muc_owner_item_attr_jid(Jid, + encode_muc_owner_item_attr_role(Role, + encode_muc_owner_item_attr_affiliation(Affiliation, + _xmlns_attrs)))), + {xmlel, <<"item">>, _attrs, _els}. + +'encode_muc_owner_item_$actor'(undefined, _acc) -> _acc; +'encode_muc_owner_item_$actor'(Actor, _acc) -> + [encode_muc_admin_actor(Actor, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/muc#admin">>}]) + | _acc]. + +'encode_muc_owner_item_$continue'(undefined, _acc) -> + _acc; +'encode_muc_owner_item_$continue'(Continue, _acc) -> + [encode_muc_admin_continue(Continue, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/muc#admin">>}]) + | _acc]. + +'encode_muc_owner_item_$reason'(<<>>, _acc) -> _acc; +'encode_muc_owner_item_$reason'(Reason, _acc) -> + [encode_muc_reason(Reason, []) | _acc]. + +decode_muc_owner_item_attr_affiliation(__TopXMLNS, + undefined) -> + undefined; +decode_muc_owner_item_attr_affiliation(__TopXMLNS, + _val) -> + case catch dec_enum(_val, + [admin, member, none, outcast, owner]) + of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"affiliation">>, <<"item">>, + __TopXMLNS}}); + _res -> _res + end. + +encode_muc_owner_item_attr_affiliation(undefined, + _acc) -> + _acc; +encode_muc_owner_item_attr_affiliation(_val, _acc) -> + [{<<"affiliation">>, enc_enum(_val)} | _acc]. + +decode_muc_owner_item_attr_role(__TopXMLNS, + undefined) -> + undefined; +decode_muc_owner_item_attr_role(__TopXMLNS, _val) -> + case catch dec_enum(_val, + [moderator, none, participant, visitor]) + of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"role">>, <<"item">>, __TopXMLNS}}); + _res -> _res + end. + +encode_muc_owner_item_attr_role(undefined, _acc) -> + _acc; +encode_muc_owner_item_attr_role(_val, _acc) -> + [{<<"role">>, enc_enum(_val)} | _acc]. + +decode_muc_owner_item_attr_jid(__TopXMLNS, undefined) -> + undefined; +decode_muc_owner_item_attr_jid(__TopXMLNS, _val) -> + case catch dec_jid(_val) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"jid">>, <<"item">>, __TopXMLNS}}); + _res -> _res + end. + +encode_muc_owner_item_attr_jid(undefined, _acc) -> _acc; +encode_muc_owner_item_attr_jid(_val, _acc) -> + [{<<"jid">>, enc_jid(_val)} | _acc]. + +decode_muc_owner_item_attr_nick(__TopXMLNS, + undefined) -> + undefined; +decode_muc_owner_item_attr_nick(__TopXMLNS, _val) -> + _val. + +encode_muc_owner_item_attr_nick(undefined, _acc) -> + _acc; +encode_muc_owner_item_attr_nick(_val, _acc) -> + [{<<"nick">>, _val} | _acc]. + decode_muc_owner(__TopXMLNS, __IgnoreEls, {xmlel, <<"query">>, _attrs, _els}) -> - {Config, Destroy} = decode_muc_owner_els(__TopXMLNS, - __IgnoreEls, _els, undefined, - undefined), - {muc_owner, Destroy, Config}. + {Items, Config, Destroy} = + decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, [], + undefined, undefined), + {muc_owner, Destroy, Config, Items}. -decode_muc_owner_els(__TopXMLNS, __IgnoreEls, [], +decode_muc_owner_els(__TopXMLNS, __IgnoreEls, [], Items, Config, Destroy) -> - {Config, Destroy}; + {lists:reverse(Items), Config, Destroy}; decode_muc_owner_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"destroy">>, _attrs, _} = _el | _els], + [{xmlel, <<"destroy">>, _attrs, _} = _el | _els], Items, Config, Destroy) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"http://jabber.org/protocol/muc#owner">> -> decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, - Config, - decode_muc_owner_destroy(__TopXMLNS, __IgnoreEls, - _el)); + Items, Config, + decode_muc_destroy(__TopXMLNS, __IgnoreEls, + _el)); + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, + Items, Config, + decode_muc_destroy(<<"http://jabber.org/protocol/muc#user">>, + __IgnoreEls, _el)); <<"http://jabber.org/protocol/muc#owner">> -> decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, - Config, - decode_muc_owner_destroy(<<"http://jabber.org/protocol/muc#owner">>, - __IgnoreEls, _el)); + Items, Config, + decode_muc_destroy(<<"http://jabber.org/protocol/muc#owner">>, + __IgnoreEls, _el)); _ -> decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, - Config, Destroy) + Items, Config, Destroy) end; decode_muc_owner_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"x">>, _attrs, _} = _el | _els], Config, - Destroy) -> + [{xmlel, <<"x">>, _attrs, _} = _el | _els], Items, + Config, Destroy) -> case get_attr(<<"xmlns">>, _attrs) of <<"jabber:x:data">> -> decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, + Items, decode_xdata(<<"jabber:x:data">>, __IgnoreEls, _el), Destroy); _ -> decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, - Config, Destroy) + Items, Config, Destroy) end; decode_muc_owner_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Config, Destroy) -> + [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items, + Config, Destroy) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/muc#owner">> -> + decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, + [decode_muc_owner_item(__TopXMLNS, __IgnoreEls, + _el) + | Items], + Config, Destroy); + <<"http://jabber.org/protocol/muc#owner">> -> + decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, + [decode_muc_owner_item(<<"http://jabber.org/protocol/muc#owner">>, + __IgnoreEls, _el) + | Items], + Config, Destroy); + _ -> + decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, + Items, Config, Destroy) + end; +decode_muc_owner_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Items, Config, Destroy) -> decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, - Config, Destroy). + Items, Config, Destroy). -encode_muc_owner({muc_owner, Destroy, Config}, +encode_muc_owner({muc_owner, Destroy, Config, Items}, _xmlns_attrs) -> - _els = lists:reverse('encode_muc_owner_$config'(Config, - 'encode_muc_owner_$destroy'(Destroy, - []))), + _els = lists:reverse('encode_muc_owner_$items'(Items, + 'encode_muc_owner_$config'(Config, + 'encode_muc_owner_$destroy'(Destroy, + [])))), _attrs = _xmlns_attrs, {xmlel, <<"query">>, _attrs, _els}. +'encode_muc_owner_$items'([], _acc) -> _acc; +'encode_muc_owner_$items'([Items | _els], _acc) -> + 'encode_muc_owner_$items'(_els, + [encode_muc_owner_item(Items, []) | _acc]). + 'encode_muc_owner_$config'(undefined, _acc) -> _acc; 'encode_muc_owner_$config'(Config, _acc) -> [encode_xdata(Config, @@ -6990,242 +8172,142 @@ encode_muc_owner({muc_owner, Destroy, Config}, 'encode_muc_owner_$destroy'(undefined, _acc) -> _acc; 'encode_muc_owner_$destroy'(Destroy, _acc) -> - [encode_muc_owner_destroy(Destroy, []) | _acc]. + [encode_muc_destroy(Destroy, []) | _acc]. -decode_muc_owner_destroy(__TopXMLNS, __IgnoreEls, - {xmlel, <<"destroy">>, _attrs, _els}) -> - {Password, Reason} = - decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, - _els, undefined, undefined), - Jid = decode_muc_owner_destroy_attrs(__TopXMLNS, _attrs, - undefined), - {muc_owner_destroy, Jid, Reason, Password}. - -decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, - [], Password, Reason) -> - {Password, Reason}; -decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"password">>, _attrs, _} = _el | _els], - Password, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/muc#owner">> -> - decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, - _els, - decode_muc_owner_password(__TopXMLNS, - __IgnoreEls, - _el), - Reason); - <<"http://jabber.org/protocol/muc#owner">> -> - decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, - _els, - decode_muc_owner_password(<<"http://jabber.org/protocol/muc#owner">>, - __IgnoreEls, - _el), - Reason); - _ -> - decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, - _els, Password, Reason) - end; -decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"reason">>, _attrs, _} = _el | _els], - Password, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/muc#owner">> -> - decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, - _els, Password, - decode_muc_owner_reason(__TopXMLNS, - __IgnoreEls, - _el)); - <<"http://jabber.org/protocol/muc#owner">> -> - decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, - _els, Password, - decode_muc_owner_reason(<<"http://jabber.org/protocol/muc#owner">>, - __IgnoreEls, - _el)); - _ -> - decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, - _els, Password, Reason) - end; -decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Password, Reason) -> - decode_muc_owner_destroy_els(__TopXMLNS, __IgnoreEls, - _els, Password, Reason). - -decode_muc_owner_destroy_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], _Jid) -> - decode_muc_owner_destroy_attrs(__TopXMLNS, _attrs, - _val); -decode_muc_owner_destroy_attrs(__TopXMLNS, [_ | _attrs], - Jid) -> - decode_muc_owner_destroy_attrs(__TopXMLNS, _attrs, Jid); -decode_muc_owner_destroy_attrs(__TopXMLNS, [], Jid) -> - decode_muc_owner_destroy_attr_jid(__TopXMLNS, Jid). - -encode_muc_owner_destroy({muc_owner_destroy, Jid, - Reason, Password}, - _xmlns_attrs) -> - _els = - lists:reverse('encode_muc_owner_destroy_$password'(Password, - 'encode_muc_owner_destroy_$reason'(Reason, - []))), - _attrs = encode_muc_owner_destroy_attr_jid(Jid, - _xmlns_attrs), - {xmlel, <<"destroy">>, _attrs, _els}. - -'encode_muc_owner_destroy_$password'(undefined, _acc) -> - _acc; -'encode_muc_owner_destroy_$password'(Password, _acc) -> - [encode_muc_owner_password(Password, []) | _acc]. - -'encode_muc_owner_destroy_$reason'(undefined, _acc) -> - _acc; -'encode_muc_owner_destroy_$reason'(Reason, _acc) -> - [encode_muc_owner_reason(Reason, []) | _acc]. - -decode_muc_owner_destroy_attr_jid(__TopXMLNS, - undefined) -> - undefined; -decode_muc_owner_destroy_attr_jid(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"jid">>, <<"destroy">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_muc_owner_destroy_attr_jid(undefined, _acc) -> - _acc; -encode_muc_owner_destroy_attr_jid(_val, _acc) -> - [{<<"jid">>, enc_jid(_val)} | _acc]. - -decode_muc_owner_reason(__TopXMLNS, __IgnoreEls, - {xmlel, <<"reason">>, _attrs, _els}) -> - Cdata = decode_muc_owner_reason_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), +decode_muc_password(__TopXMLNS, __IgnoreEls, + {xmlel, <<"password">>, _attrs, _els}) -> + Cdata = decode_muc_password_els(__TopXMLNS, __IgnoreEls, + _els, <<>>), Cdata. -decode_muc_owner_reason_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_muc_owner_reason_cdata(__TopXMLNS, Cdata); -decode_muc_owner_reason_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_muc_owner_reason_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_muc_owner_reason_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_muc_owner_reason_els(__TopXMLNS, __IgnoreEls, - _els, Cdata). +decode_muc_password_els(__TopXMLNS, __IgnoreEls, [], + Cdata) -> + decode_muc_password_cdata(__TopXMLNS, Cdata); +decode_muc_password_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Cdata) -> + decode_muc_password_els(__TopXMLNS, __IgnoreEls, _els, + <>); +decode_muc_password_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Cdata) -> + decode_muc_password_els(__TopXMLNS, __IgnoreEls, _els, + Cdata). -encode_muc_owner_reason(Cdata, _xmlns_attrs) -> - _els = encode_muc_owner_reason_cdata(Cdata, []), - _attrs = _xmlns_attrs, - {xmlel, <<"reason">>, _attrs, _els}. - -decode_muc_owner_reason_cdata(__TopXMLNS, <<>>) -> - undefined; -decode_muc_owner_reason_cdata(__TopXMLNS, _val) -> _val. - -encode_muc_owner_reason_cdata(undefined, _acc) -> _acc; -encode_muc_owner_reason_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_muc_owner_password(__TopXMLNS, __IgnoreEls, - {xmlel, <<"password">>, _attrs, _els}) -> - Cdata = decode_muc_owner_password_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_muc_owner_password_els(__TopXMLNS, __IgnoreEls, - [], Cdata) -> - decode_muc_owner_password_cdata(__TopXMLNS, Cdata); -decode_muc_owner_password_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_muc_owner_password_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_muc_owner_password_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_muc_owner_password_els(__TopXMLNS, __IgnoreEls, - _els, Cdata). - -encode_muc_owner_password(Cdata, _xmlns_attrs) -> - _els = encode_muc_owner_password_cdata(Cdata, []), +encode_muc_password(Cdata, _xmlns_attrs) -> + _els = encode_muc_password_cdata(Cdata, []), _attrs = _xmlns_attrs, {xmlel, <<"password">>, _attrs, _els}. -decode_muc_owner_password_cdata(__TopXMLNS, <<>>) -> +decode_muc_password_cdata(__TopXMLNS, <<>>) -> undefined; -decode_muc_owner_password_cdata(__TopXMLNS, _val) -> - _val. +decode_muc_password_cdata(__TopXMLNS, _val) -> _val. -encode_muc_owner_password_cdata(undefined, _acc) -> - _acc; -encode_muc_owner_password_cdata(_val, _acc) -> +encode_muc_password_cdata(undefined, _acc) -> _acc; +encode_muc_password_cdata(_val, _acc) -> [{xmlcdata, _val} | _acc]. decode_muc_user(__TopXMLNS, __IgnoreEls, {xmlel, <<"x">>, _attrs, _els}) -> - {Status_codes, Items, Invites, Decline, Destroy} = + {Status_codes, Items, Invites, Password, Decline, + Destroy} = decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, [], - [], [], undefined, undefined), - Password = decode_muc_user_attrs(__TopXMLNS, _attrs, - undefined), + [], [], undefined, undefined, undefined), {muc_user, Decline, Destroy, Invites, Items, Status_codes, Password}. decode_muc_user_els(__TopXMLNS, __IgnoreEls, [], - Status_codes, Items, Invites, Decline, Destroy) -> + Status_codes, Items, Invites, Password, Decline, + Destroy) -> {lists:reverse(Status_codes), lists:reverse(Items), - lists:reverse(Invites), Decline, Destroy}; + lists:reverse(Invites), Password, Decline, Destroy}; decode_muc_user_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"decline">>, _attrs, _} = _el | _els], - Status_codes, Items, Invites, Decline, Destroy) -> + Status_codes, Items, Invites, Password, Decline, + Destroy) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"http://jabber.org/protocol/muc#user">> -> decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, + Status_codes, Items, Invites, Password, decode_muc_user_decline(__TopXMLNS, __IgnoreEls, _el), Destroy); <<"http://jabber.org/protocol/muc#user">> -> decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, + Status_codes, Items, Invites, Password, decode_muc_user_decline(<<"http://jabber.org/protocol/muc#user">>, __IgnoreEls, _el), Destroy); _ -> decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Decline, Destroy) + Status_codes, Items, Invites, Password, Decline, + Destroy) end; decode_muc_user_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"destroy">>, _attrs, _} = _el | _els], - Status_codes, Items, Invites, Decline, Destroy) -> + Status_codes, Items, Invites, Password, Decline, + Destroy) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"http://jabber.org/protocol/muc#user">> -> decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Decline, - decode_muc_user_destroy(__TopXMLNS, __IgnoreEls, - _el)); + Status_codes, Items, Invites, Password, Decline, + decode_muc_destroy(__TopXMLNS, __IgnoreEls, _el)); <<"http://jabber.org/protocol/muc#user">> -> decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Decline, - decode_muc_user_destroy(<<"http://jabber.org/protocol/muc#user">>, - __IgnoreEls, _el)); + Status_codes, Items, Invites, Password, Decline, + decode_muc_destroy(<<"http://jabber.org/protocol/muc#user">>, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/muc#owner">> -> + decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, + Status_codes, Items, Invites, Password, Decline, + decode_muc_destroy(<<"http://jabber.org/protocol/muc#owner">>, + __IgnoreEls, _el)); _ -> decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Decline, Destroy) + Status_codes, Items, Invites, Password, Decline, + Destroy) + end; +decode_muc_user_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"password">>, _attrs, _} = _el | _els], + Status_codes, Items, Invites, Password, Decline, + Destroy) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, + Status_codes, Items, Invites, + decode_muc_password(__TopXMLNS, __IgnoreEls, _el), + Decline, Destroy); + <<"http://jabber.org/protocol/muc#owner">> -> + decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, + Status_codes, Items, Invites, + decode_muc_password(<<"http://jabber.org/protocol/muc#owner">>, + __IgnoreEls, _el), + Decline, Destroy); + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, + Status_codes, Items, Invites, + decode_muc_password(<<"http://jabber.org/protocol/muc#user">>, + __IgnoreEls, _el), + Decline, Destroy); + <<"http://jabber.org/protocol/muc">> -> + decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, + Status_codes, Items, Invites, + decode_muc_password(<<"http://jabber.org/protocol/muc">>, + __IgnoreEls, _el), + Decline, Destroy); + _ -> + decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, + Status_codes, Items, Invites, Password, Decline, + Destroy) end; decode_muc_user_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"invite">>, _attrs, _} = _el | _els], - Status_codes, Items, Invites, Decline, Destroy) -> + Status_codes, Items, Invites, Password, Decline, + Destroy) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == @@ -7235,21 +8317,23 @@ decode_muc_user_els(__TopXMLNS, __IgnoreEls, [decode_muc_user_invite(__TopXMLNS, __IgnoreEls, _el) | Invites], - Decline, Destroy); + Password, Decline, Destroy); <<"http://jabber.org/protocol/muc#user">> -> decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, Status_codes, Items, [decode_muc_user_invite(<<"http://jabber.org/protocol/muc#user">>, __IgnoreEls, _el) | Invites], - Decline, Destroy); + Password, Decline, Destroy); _ -> decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Decline, Destroy) + Status_codes, Items, Invites, Password, Decline, + Destroy) end; decode_muc_user_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"item">>, _attrs, _} = _el | _els], - Status_codes, Items, Invites, Decline, Destroy) -> + Status_codes, Items, Invites, Password, Decline, + Destroy) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == @@ -7259,21 +8343,23 @@ decode_muc_user_els(__TopXMLNS, __IgnoreEls, [decode_muc_user_item(__TopXMLNS, __IgnoreEls, _el) | Items], - Invites, Decline, Destroy); + Invites, Password, Decline, Destroy); <<"http://jabber.org/protocol/muc#user">> -> decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, Status_codes, [decode_muc_user_item(<<"http://jabber.org/protocol/muc#user">>, __IgnoreEls, _el) | Items], - Invites, Decline, Destroy); + Invites, Password, Decline, Destroy); _ -> decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Decline, Destroy) + Status_codes, Items, Invites, Password, Decline, + Destroy) end; decode_muc_user_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"status">>, _attrs, _} = _el | _els], - Status_codes, Items, Invites, Decline, Destroy) -> + Status_codes, Items, Invites, Password, Decline, + Destroy) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == @@ -7285,7 +8371,7 @@ decode_muc_user_els(__TopXMLNS, __IgnoreEls, undefined -> Status_codes; _new_el -> [_new_el | Status_codes] end, - Items, Invites, Decline, Destroy); + Items, Invites, Password, Decline, Destroy); <<"http://jabber.org/protocol/muc#user">> -> decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, case @@ -7295,24 +8381,18 @@ decode_muc_user_els(__TopXMLNS, __IgnoreEls, undefined -> Status_codes; _new_el -> [_new_el | Status_codes] end, - Items, Invites, Decline, Destroy); + Items, Invites, Password, Decline, Destroy); _ -> decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Decline, Destroy) + Status_codes, Items, Invites, Password, Decline, + Destroy) end; decode_muc_user_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Status_codes, Items, Invites, Decline, Destroy) -> + Status_codes, Items, Invites, Password, Decline, + Destroy) -> decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Decline, Destroy). - -decode_muc_user_attrs(__TopXMLNS, - [{<<"password">>, _val} | _attrs], _Password) -> - decode_muc_user_attrs(__TopXMLNS, _attrs, _val); -decode_muc_user_attrs(__TopXMLNS, [_ | _attrs], - Password) -> - decode_muc_user_attrs(__TopXMLNS, _attrs, Password); -decode_muc_user_attrs(__TopXMLNS, [], Password) -> - decode_muc_user_attr_password(__TopXMLNS, Password). + Status_codes, Items, Invites, Password, Decline, + Destroy). encode_muc_user({muc_user, Decline, Destroy, Invites, Items, Status_codes, Password}, @@ -7321,11 +8401,11 @@ encode_muc_user({muc_user, Decline, Destroy, Invites, lists:reverse('encode_muc_user_$status_codes'(Status_codes, 'encode_muc_user_$items'(Items, 'encode_muc_user_$invites'(Invites, - 'encode_muc_user_$decline'(Decline, - 'encode_muc_user_$destroy'(Destroy, - [])))))), - _attrs = encode_muc_user_attr_password(Password, - _xmlns_attrs), + 'encode_muc_user_$password'(Password, + 'encode_muc_user_$decline'(Decline, + 'encode_muc_user_$destroy'(Destroy, + []))))))), + _attrs = _xmlns_attrs, {xmlel, <<"x">>, _attrs, _els}. 'encode_muc_user_$status_codes'([], _acc) -> _acc; @@ -7345,27 +8425,23 @@ encode_muc_user({muc_user, Decline, Destroy, Invites, 'encode_muc_user_$invites'(_els, [encode_muc_user_invite(Invites, []) | _acc]). +'encode_muc_user_$password'(undefined, _acc) -> _acc; +'encode_muc_user_$password'(Password, _acc) -> + [encode_muc_password(Password, []) | _acc]. + 'encode_muc_user_$decline'(undefined, _acc) -> _acc; 'encode_muc_user_$decline'(Decline, _acc) -> [encode_muc_user_decline(Decline, []) | _acc]. 'encode_muc_user_$destroy'(undefined, _acc) -> _acc; 'encode_muc_user_$destroy'(Destroy, _acc) -> - [encode_muc_user_destroy(Destroy, []) | _acc]. - -decode_muc_user_attr_password(__TopXMLNS, undefined) -> - undefined; -decode_muc_user_attr_password(__TopXMLNS, _val) -> _val. - -encode_muc_user_attr_password(undefined, _acc) -> _acc; -encode_muc_user_attr_password(_val, _acc) -> - [{<<"password">>, _val} | _acc]. + [encode_muc_destroy(Destroy, []) | _acc]. decode_muc_user_item(__TopXMLNS, __IgnoreEls, {xmlel, <<"item">>, _attrs, _els}) -> {Actor, Continue, Reason} = decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, - undefined, undefined, undefined), + undefined, undefined, <<>>), {Affiliation, Role, Jid, Nick} = decode_muc_user_item_attrs(__TopXMLNS, _attrs, undefined, undefined, undefined, undefined), @@ -7426,13 +8502,23 @@ decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, <<"http://jabber.org/protocol/muc#user">> -> decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, Actor, Continue, - decode_muc_user_reason(__TopXMLNS, - __IgnoreEls, _el)); + decode_muc_reason(__TopXMLNS, __IgnoreEls, + _el)); <<"http://jabber.org/protocol/muc#user">> -> decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, Actor, Continue, - decode_muc_user_reason(<<"http://jabber.org/protocol/muc#user">>, - __IgnoreEls, _el)); + decode_muc_reason(<<"http://jabber.org/protocol/muc#user">>, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/muc#admin">> -> + decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, Continue, + decode_muc_reason(<<"http://jabber.org/protocol/muc#admin">>, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/muc#owner">> -> + decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, + Actor, Continue, + decode_muc_reason(<<"http://jabber.org/protocol/muc#owner">>, + __IgnoreEls, _el)); _ -> decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, Actor, Continue, Reason) @@ -7498,9 +8584,9 @@ encode_muc_user_item({muc_item, Actor, Continue, Reason, 'encode_muc_user_item_$continue'(Continue, _acc) -> [encode_muc_user_continue(Continue, []) | _acc]. -'encode_muc_user_item_$reason'(undefined, _acc) -> _acc; +'encode_muc_user_item_$reason'(<<>>, _acc) -> _acc; 'encode_muc_user_item_$reason'(Reason, _acc) -> - [encode_muc_user_reason(Reason, []) | _acc]. + [encode_muc_reason(Reason, []) | _acc]. decode_muc_user_item_attr_affiliation(__TopXMLNS, undefined) -> @@ -7695,39 +8781,72 @@ encode_muc_user_actor_attr_nick(_val, _acc) -> decode_muc_user_invite(__TopXMLNS, __IgnoreEls, {xmlel, <<"invite">>, _attrs, _els}) -> - Reason = decode_muc_user_invite_els(__TopXMLNS, - __IgnoreEls, _els, undefined), + {Continue, Reason} = + decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, + _els, undefined, <<>>), {To, From} = decode_muc_user_invite_attrs(__TopXMLNS, _attrs, undefined, undefined), - {muc_invite, Reason, From, To}. + {muc_invite, Reason, From, To, Continue}. decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, [], - Reason) -> - Reason; + Continue, Reason) -> + {Continue, Reason}; decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"reason">>, _attrs, _} = _el | _els], - Reason) -> + Continue, Reason) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, + _els, Continue, + decode_muc_reason(__TopXMLNS, __IgnoreEls, + _el)); + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, + _els, Continue, + decode_muc_reason(<<"http://jabber.org/protocol/muc#user">>, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/muc#admin">> -> + decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, + _els, Continue, + decode_muc_reason(<<"http://jabber.org/protocol/muc#admin">>, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/muc#owner">> -> + decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, + _els, Continue, + decode_muc_reason(<<"http://jabber.org/protocol/muc#owner">>, + __IgnoreEls, _el)); + _ -> + decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, + _els, Continue, Reason) + end; +decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"continue">>, _attrs, _} = _el | _els], + Continue, Reason) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"http://jabber.org/protocol/muc#user">> -> decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, _els, - decode_muc_user_reason(__TopXMLNS, - __IgnoreEls, _el)); + decode_muc_user_continue(__TopXMLNS, + __IgnoreEls, _el), + Reason); <<"http://jabber.org/protocol/muc#user">> -> decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, _els, - decode_muc_user_reason(<<"http://jabber.org/protocol/muc#user">>, - __IgnoreEls, _el)); + decode_muc_user_continue(<<"http://jabber.org/protocol/muc#user">>, + __IgnoreEls, _el), + Reason); _ -> decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, - _els, Reason) + _els, Continue, Reason) end; decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Reason) -> + [_ | _els], Continue, Reason) -> decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, - _els, Reason). + _els, Continue, Reason). decode_muc_user_invite_attrs(__TopXMLNS, [{<<"to">>, _val} | _attrs], _To, From) -> @@ -7746,20 +8865,26 @@ decode_muc_user_invite_attrs(__TopXMLNS, [], To, {decode_muc_user_invite_attr_to(__TopXMLNS, To), decode_muc_user_invite_attr_from(__TopXMLNS, From)}. -encode_muc_user_invite({muc_invite, Reason, From, To}, +encode_muc_user_invite({muc_invite, Reason, From, To, + Continue}, _xmlns_attrs) -> _els = - lists:reverse('encode_muc_user_invite_$reason'(Reason, - [])), + lists:reverse('encode_muc_user_invite_$continue'(Continue, + 'encode_muc_user_invite_$reason'(Reason, + []))), _attrs = encode_muc_user_invite_attr_from(From, encode_muc_user_invite_attr_to(To, _xmlns_attrs)), {xmlel, <<"invite">>, _attrs, _els}. -'encode_muc_user_invite_$reason'(undefined, _acc) -> +'encode_muc_user_invite_$continue'(undefined, _acc) -> _acc; +'encode_muc_user_invite_$continue'(Continue, _acc) -> + [encode_muc_user_continue(Continue, []) | _acc]. + +'encode_muc_user_invite_$reason'(<<>>, _acc) -> _acc; 'encode_muc_user_invite_$reason'(Reason, _acc) -> - [encode_muc_user_reason(Reason, []) | _acc]. + [encode_muc_reason(Reason, []) | _acc]. decode_muc_user_invite_attr_to(__TopXMLNS, undefined) -> undefined; @@ -7792,69 +8917,125 @@ encode_muc_user_invite_attr_from(undefined, _acc) -> encode_muc_user_invite_attr_from(_val, _acc) -> [{<<"from">>, enc_jid(_val)} | _acc]. -decode_muc_user_destroy(__TopXMLNS, __IgnoreEls, - {xmlel, <<"destroy">>, _attrs, _els}) -> - Reason = decode_muc_user_destroy_els(__TopXMLNS, - __IgnoreEls, _els, undefined), - Jid = decode_muc_user_destroy_attrs(__TopXMLNS, _attrs, - undefined), - {muc_user_destroy, Reason, Jid}. +decode_muc_destroy(__TopXMLNS, __IgnoreEls, + {xmlel, <<"destroy">>, _attrs, _els}) -> + {Password, Reason} = decode_muc_destroy_els(__TopXMLNS, + __IgnoreEls, _els, undefined, + <<>>), + {Jid, Xmlns} = decode_muc_destroy_attrs(__TopXMLNS, + _attrs, undefined, undefined), + {muc_destroy, Xmlns, Jid, Reason, Password}. -decode_muc_user_destroy_els(__TopXMLNS, __IgnoreEls, [], - Reason) -> - Reason; -decode_muc_user_destroy_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"reason">>, _attrs, _} = _el | _els], - Reason) -> +decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, [], + Password, Reason) -> + {Password, Reason}; +decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"reason">>, _attrs, _} = _el | _els], + Password, Reason) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_destroy_els(__TopXMLNS, __IgnoreEls, - _els, - decode_muc_user_reason(__TopXMLNS, - __IgnoreEls, _el)); + <<"http://jabber.org/protocol/muc#user">>; + __TopXMLNS == + <<"http://jabber.org/protocol/muc#owner">> -> + decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, _els, + Password, + decode_muc_reason(__TopXMLNS, __IgnoreEls, + _el)); <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_destroy_els(__TopXMLNS, __IgnoreEls, - _els, - decode_muc_user_reason(<<"http://jabber.org/protocol/muc#user">>, - __IgnoreEls, _el)); + decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, _els, + Password, + decode_muc_reason(<<"http://jabber.org/protocol/muc#user">>, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/muc#admin">> -> + decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, _els, + Password, + decode_muc_reason(<<"http://jabber.org/protocol/muc#admin">>, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/muc#owner">> -> + decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, _els, + Password, + decode_muc_reason(<<"http://jabber.org/protocol/muc#owner">>, + __IgnoreEls, _el)); _ -> - decode_muc_user_destroy_els(__TopXMLNS, __IgnoreEls, - _els, Reason) + decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, _els, + Password, Reason) end; -decode_muc_user_destroy_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Reason) -> - decode_muc_user_destroy_els(__TopXMLNS, __IgnoreEls, - _els, Reason). +decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"password">>, _attrs, _} = _el | _els], + Password, Reason) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/muc#user">>; + __TopXMLNS == + <<"http://jabber.org/protocol/muc#owner">> -> + decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, _els, + decode_muc_password(__TopXMLNS, __IgnoreEls, + _el), + Reason); + <<"http://jabber.org/protocol/muc#owner">> -> + decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, _els, + decode_muc_password(<<"http://jabber.org/protocol/muc#owner">>, + __IgnoreEls, _el), + Reason); + <<"http://jabber.org/protocol/muc#user">> -> + decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, _els, + decode_muc_password(<<"http://jabber.org/protocol/muc#user">>, + __IgnoreEls, _el), + Reason); + <<"http://jabber.org/protocol/muc">> -> + decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, _els, + decode_muc_password(<<"http://jabber.org/protocol/muc">>, + __IgnoreEls, _el), + Reason); + _ -> + decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, _els, + Password, Reason) + end; +decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Password, Reason) -> + decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, _els, + Password, Reason). -decode_muc_user_destroy_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], _Jid) -> - decode_muc_user_destroy_attrs(__TopXMLNS, _attrs, _val); -decode_muc_user_destroy_attrs(__TopXMLNS, [_ | _attrs], - Jid) -> - decode_muc_user_destroy_attrs(__TopXMLNS, _attrs, Jid); -decode_muc_user_destroy_attrs(__TopXMLNS, [], Jid) -> - decode_muc_user_destroy_attr_jid(__TopXMLNS, Jid). +decode_muc_destroy_attrs(__TopXMLNS, + [{<<"jid">>, _val} | _attrs], _Jid, Xmlns) -> + decode_muc_destroy_attrs(__TopXMLNS, _attrs, _val, + Xmlns); +decode_muc_destroy_attrs(__TopXMLNS, + [{<<"xmlns">>, _val} | _attrs], Jid, _Xmlns) -> + decode_muc_destroy_attrs(__TopXMLNS, _attrs, Jid, _val); +decode_muc_destroy_attrs(__TopXMLNS, [_ | _attrs], Jid, + Xmlns) -> + decode_muc_destroy_attrs(__TopXMLNS, _attrs, Jid, + Xmlns); +decode_muc_destroy_attrs(__TopXMLNS, [], Jid, Xmlns) -> + {decode_muc_destroy_attr_jid(__TopXMLNS, Jid), + decode_muc_destroy_attr_xmlns(__TopXMLNS, Xmlns)}. -encode_muc_user_destroy({muc_user_destroy, Reason, Jid}, - _xmlns_attrs) -> +encode_muc_destroy({muc_destroy, Xmlns, Jid, Reason, + Password}, + _xmlns_attrs) -> _els = - lists:reverse('encode_muc_user_destroy_$reason'(Reason, - [])), - _attrs = encode_muc_user_destroy_attr_jid(Jid, - _xmlns_attrs), + lists:reverse('encode_muc_destroy_$password'(Password, + 'encode_muc_destroy_$reason'(Reason, + []))), + _attrs = encode_muc_destroy_attr_xmlns(Xmlns, + encode_muc_destroy_attr_jid(Jid, + _xmlns_attrs)), {xmlel, <<"destroy">>, _attrs, _els}. -'encode_muc_user_destroy_$reason'(undefined, _acc) -> - _acc; -'encode_muc_user_destroy_$reason'(Reason, _acc) -> - [encode_muc_user_reason(Reason, []) | _acc]. +'encode_muc_destroy_$password'(undefined, _acc) -> _acc; +'encode_muc_destroy_$password'(Password, _acc) -> + [encode_muc_password(Password, []) | _acc]. -decode_muc_user_destroy_attr_jid(__TopXMLNS, - undefined) -> +'encode_muc_destroy_$reason'(<<>>, _acc) -> _acc; +'encode_muc_destroy_$reason'(Reason, _acc) -> + [encode_muc_reason(Reason, []) | _acc]. + +decode_muc_destroy_attr_jid(__TopXMLNS, undefined) -> undefined; -decode_muc_user_destroy_attr_jid(__TopXMLNS, _val) -> +decode_muc_destroy_attr_jid(__TopXMLNS, _val) -> case catch dec_jid(_val) of {'EXIT', _} -> erlang:error({xmpp_codec, @@ -7863,15 +9044,22 @@ decode_muc_user_destroy_attr_jid(__TopXMLNS, _val) -> _res -> _res end. -encode_muc_user_destroy_attr_jid(undefined, _acc) -> - _acc; -encode_muc_user_destroy_attr_jid(_val, _acc) -> +encode_muc_destroy_attr_jid(undefined, _acc) -> _acc; +encode_muc_destroy_attr_jid(_val, _acc) -> [{<<"jid">>, enc_jid(_val)} | _acc]. +decode_muc_destroy_attr_xmlns(__TopXMLNS, undefined) -> + undefined; +decode_muc_destroy_attr_xmlns(__TopXMLNS, _val) -> _val. + +encode_muc_destroy_attr_xmlns(undefined, _acc) -> _acc; +encode_muc_destroy_attr_xmlns(_val, _acc) -> + [{<<"xmlns">>, _val} | _acc]. + decode_muc_user_decline(__TopXMLNS, __IgnoreEls, {xmlel, <<"decline">>, _attrs, _els}) -> Reason = decode_muc_user_decline_els(__TopXMLNS, - __IgnoreEls, _els, undefined), + __IgnoreEls, _els, <<>>), {To, From} = decode_muc_user_decline_attrs(__TopXMLNS, _attrs, undefined, undefined), {muc_decline, Reason, From, To}. @@ -7888,13 +9076,23 @@ decode_muc_user_decline_els(__TopXMLNS, __IgnoreEls, <<"http://jabber.org/protocol/muc#user">> -> decode_muc_user_decline_els(__TopXMLNS, __IgnoreEls, _els, - decode_muc_user_reason(__TopXMLNS, - __IgnoreEls, _el)); + decode_muc_reason(__TopXMLNS, __IgnoreEls, + _el)); <<"http://jabber.org/protocol/muc#user">> -> decode_muc_user_decline_els(__TopXMLNS, __IgnoreEls, _els, - decode_muc_user_reason(<<"http://jabber.org/protocol/muc#user">>, - __IgnoreEls, _el)); + decode_muc_reason(<<"http://jabber.org/protocol/muc#user">>, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/muc#admin">> -> + decode_muc_user_decline_els(__TopXMLNS, __IgnoreEls, + _els, + decode_muc_reason(<<"http://jabber.org/protocol/muc#admin">>, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/muc#owner">> -> + decode_muc_user_decline_els(__TopXMLNS, __IgnoreEls, + _els, + decode_muc_reason(<<"http://jabber.org/protocol/muc#owner">>, + __IgnoreEls, _el)); _ -> decode_muc_user_decline_els(__TopXMLNS, __IgnoreEls, _els, Reason) @@ -7931,10 +9129,9 @@ encode_muc_user_decline({muc_decline, Reason, From, To}, _xmlns_attrs)), {xmlel, <<"decline">>, _attrs, _els}. -'encode_muc_user_decline_$reason'(undefined, _acc) -> - _acc; +'encode_muc_user_decline_$reason'(<<>>, _acc) -> _acc; 'encode_muc_user_decline_$reason'(Reason, _acc) -> - [encode_muc_user_reason(Reason, []) | _acc]. + [encode_muc_reason(Reason, []) | _acc]. decode_muc_user_decline_attr_to(__TopXMLNS, undefined) -> @@ -7969,35 +9166,34 @@ encode_muc_user_decline_attr_from(undefined, _acc) -> encode_muc_user_decline_attr_from(_val, _acc) -> [{<<"from">>, enc_jid(_val)} | _acc]. -decode_muc_user_reason(__TopXMLNS, __IgnoreEls, - {xmlel, <<"reason">>, _attrs, _els}) -> - Cdata = decode_muc_user_reason_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), +decode_muc_reason(__TopXMLNS, __IgnoreEls, + {xmlel, <<"reason">>, _attrs, _els}) -> + Cdata = decode_muc_reason_els(__TopXMLNS, __IgnoreEls, + _els, <<>>), Cdata. -decode_muc_user_reason_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_muc_user_reason_cdata(__TopXMLNS, Cdata); -decode_muc_user_reason_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_muc_user_reason_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_muc_user_reason_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_muc_user_reason_els(__TopXMLNS, __IgnoreEls, - _els, Cdata). +decode_muc_reason_els(__TopXMLNS, __IgnoreEls, [], + Cdata) -> + decode_muc_reason_cdata(__TopXMLNS, Cdata); +decode_muc_reason_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Cdata) -> + decode_muc_reason_els(__TopXMLNS, __IgnoreEls, _els, + <>); +decode_muc_reason_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Cdata) -> + decode_muc_reason_els(__TopXMLNS, __IgnoreEls, _els, + Cdata). -encode_muc_user_reason(Cdata, _xmlns_attrs) -> - _els = encode_muc_user_reason_cdata(Cdata, []), +encode_muc_reason(Cdata, _xmlns_attrs) -> + _els = encode_muc_reason_cdata(Cdata, []), _attrs = _xmlns_attrs, {xmlel, <<"reason">>, _attrs, _els}. -decode_muc_user_reason_cdata(__TopXMLNS, <<>>) -> - undefined; -decode_muc_user_reason_cdata(__TopXMLNS, _val) -> _val. +decode_muc_reason_cdata(__TopXMLNS, <<>>) -> undefined; +decode_muc_reason_cdata(__TopXMLNS, _val) -> _val. -encode_muc_user_reason_cdata(undefined, _acc) -> _acc; -encode_muc_user_reason_cdata(_val, _acc) -> +encode_muc_reason_cdata(undefined, _acc) -> _acc; +encode_muc_reason_cdata(_val, _acc) -> [{xmlcdata, _val} | _acc]. decode_muc_history(__TopXMLNS, __IgnoreEls, @@ -10554,23 +11750,15 @@ decode_xdata_field_els(__TopXMLNS, __IgnoreEls, case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"jabber:x:data">> -> decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - case decode_xdata_field_option(__TopXMLNS, - __IgnoreEls, - _el) - of - undefined -> Options; - _new_el -> [_new_el | Options] - end, + [decode_xdata_field_option(__TopXMLNS, + __IgnoreEls, _el) + | Options], Values, Desc, Required); <<"jabber:x:data">> -> decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - case - decode_xdata_field_option(<<"jabber:x:data">>, - __IgnoreEls, _el) - of - undefined -> Options; - _new_el -> [_new_el | Options] - end, + [decode_xdata_field_option(<<"jabber:x:data">>, + __IgnoreEls, _el) + | Options], Values, Desc, Required); _ -> decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, @@ -10675,7 +11863,9 @@ decode_xdata_field_option(__TopXMLNS, __IgnoreEls, {xmlel, <<"option">>, _attrs, _els}) -> Value = decode_xdata_field_option_els(__TopXMLNS, __IgnoreEls, _els, error), - Value. + Label = decode_xdata_field_option_attrs(__TopXMLNS, + _attrs, undefined), + {xdata_option, Label, Value}. decode_xdata_field_option_els(__TopXMLNS, __IgnoreEls, [], Value) -> @@ -10712,16 +11902,42 @@ decode_xdata_field_option_els(__TopXMLNS, __IgnoreEls, decode_xdata_field_option_els(__TopXMLNS, __IgnoreEls, _els, Value). -encode_xdata_field_option(Value, _xmlns_attrs) -> +decode_xdata_field_option_attrs(__TopXMLNS, + [{<<"label">>, _val} | _attrs], _Label) -> + decode_xdata_field_option_attrs(__TopXMLNS, _attrs, + _val); +decode_xdata_field_option_attrs(__TopXMLNS, + [_ | _attrs], Label) -> + decode_xdata_field_option_attrs(__TopXMLNS, _attrs, + Label); +decode_xdata_field_option_attrs(__TopXMLNS, [], + Label) -> + decode_xdata_field_option_attr_label(__TopXMLNS, Label). + +encode_xdata_field_option({xdata_option, Label, Value}, + _xmlns_attrs) -> _els = lists:reverse('encode_xdata_field_option_$value'(Value, [])), - _attrs = _xmlns_attrs, + _attrs = encode_xdata_field_option_attr_label(Label, + _xmlns_attrs), {xmlel, <<"option">>, _attrs, _els}. 'encode_xdata_field_option_$value'(Value, _acc) -> [encode_xdata_field_value(Value, []) | _acc]. +decode_xdata_field_option_attr_label(__TopXMLNS, + undefined) -> + undefined; +decode_xdata_field_option_attr_label(__TopXMLNS, + _val) -> + _val. + +encode_xdata_field_option_attr_label(undefined, _acc) -> + _acc; +encode_xdata_field_option_attr_label(_val, _acc) -> + [{<<"label">>, _val} | _acc]. + decode_xdata_field_value(__TopXMLNS, __IgnoreEls, {xmlel, <<"value">>, _attrs, _els}) -> Cdata = decode_xdata_field_value_els(__TopXMLNS, @@ -19881,6 +21097,19 @@ decode_error_els(__TopXMLNS, __IgnoreEls, decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, Reason) end; +decode_error_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"payment-required">>, _attrs, _} = _el + | _els], + Text, Reason) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + decode_error_payment_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + __IgnoreEls, _el)); + _ -> + decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, + Reason) + end; decode_error_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"policy-violation">>, _attrs, _} = _el | _els], @@ -20132,6 +21361,12 @@ encode_error({error, Type, Code, By, Reason, Text}, [{<<"xmlns">>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) | _acc]; +'encode_error_$reason'('payment-required' = Reason, + _acc) -> + [encode_error_payment_required(Reason, + [{<<"xmlns">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + | _acc]; 'encode_error_$reason'('policy-violation' = Reason, _acc) -> [encode_error_policy_violation(Reason, @@ -20438,6 +21673,16 @@ encode_error_policy_violation('policy-violation', _attrs = _xmlns_attrs, {xmlel, <<"policy-violation">>, _attrs, _els}. +decode_error_payment_required(__TopXMLNS, __IgnoreEls, + {xmlel, <<"payment-required">>, _attrs, _els}) -> + 'payment-required'. + +encode_error_payment_required('payment-required', + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"payment-required">>, _attrs, _els}. + decode_error_not_authorized(__TopXMLNS, __IgnoreEls, {xmlel, <<"not-authorized">>, _attrs, _els}) -> 'not-authorized'. @@ -22069,17 +23314,18 @@ encode_private({private, __Xmls}, _xmlns_attrs) -> decode_disco_items(__TopXMLNS, __IgnoreEls, {xmlel, <<"query">>, _attrs, _els}) -> - Items = decode_disco_items_els(__TopXMLNS, __IgnoreEls, - _els, []), + {Items, Rsm} = decode_disco_items_els(__TopXMLNS, + __IgnoreEls, _els, [], undefined), Node = decode_disco_items_attrs(__TopXMLNS, _attrs, undefined), - {disco_items, Node, Items}. + {disco_items, Node, Items, Rsm}. decode_disco_items_els(__TopXMLNS, __IgnoreEls, [], - Items) -> - lists:reverse(Items); + Items, Rsm) -> + {lists:reverse(Items), Rsm}; decode_disco_items_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items) -> + [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items, + Rsm) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == @@ -22087,20 +23333,35 @@ decode_disco_items_els(__TopXMLNS, __IgnoreEls, decode_disco_items_els(__TopXMLNS, __IgnoreEls, _els, [decode_disco_item(__TopXMLNS, __IgnoreEls, _el) - | Items]); + | Items], + Rsm); <<"http://jabber.org/protocol/disco#items">> -> decode_disco_items_els(__TopXMLNS, __IgnoreEls, _els, [decode_disco_item(<<"http://jabber.org/protocol/disco#items">>, __IgnoreEls, _el) - | Items]); + | Items], + Rsm); _ -> decode_disco_items_els(__TopXMLNS, __IgnoreEls, _els, - Items) + Items, Rsm) end; decode_disco_items_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Items) -> + [{xmlel, <<"set">>, _attrs, _} = _el | _els], Items, + Rsm) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"http://jabber.org/protocol/rsm">> -> + decode_disco_items_els(__TopXMLNS, __IgnoreEls, _els, + Items, + decode_rsm_set(<<"http://jabber.org/protocol/rsm">>, + __IgnoreEls, _el)); + _ -> + decode_disco_items_els(__TopXMLNS, __IgnoreEls, _els, + Items, Rsm) + end; +decode_disco_items_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Items, Rsm) -> decode_disco_items_els(__TopXMLNS, __IgnoreEls, _els, - Items). + Items, Rsm). decode_disco_items_attrs(__TopXMLNS, [{<<"node">>, _val} | _attrs], _Node) -> @@ -22111,10 +23372,11 @@ decode_disco_items_attrs(__TopXMLNS, [_ | _attrs], decode_disco_items_attrs(__TopXMLNS, [], Node) -> decode_disco_items_attr_node(__TopXMLNS, Node). -encode_disco_items({disco_items, Node, Items}, +encode_disco_items({disco_items, Node, Items, Rsm}, _xmlns_attrs) -> _els = lists:reverse('encode_disco_items_$items'(Items, - [])), + 'encode_disco_items_$rsm'(Rsm, + []))), _attrs = encode_disco_items_attr_node(Node, _xmlns_attrs), {xmlel, <<"query">>, _attrs, _els}. @@ -22124,6 +23386,12 @@ encode_disco_items({disco_items, Node, Items}, 'encode_disco_items_$items'(_els, [encode_disco_item(Items, []) | _acc]). +'encode_disco_items_$rsm'(undefined, _acc) -> _acc; +'encode_disco_items_$rsm'(Rsm, _acc) -> + [encode_rsm_set(Rsm, + [{<<"xmlns">>, <<"http://jabber.org/protocol/rsm">>}]) + | _acc]. + decode_disco_items_attr_node(__TopXMLNS, undefined) -> undefined; decode_disco_items_attr_node(__TopXMLNS, _val) -> _val. diff --git a/src/xmpp_util.erl b/src/xmpp_util.erl index 42b251fc1..83f1f4adc 100644 --- a/src/xmpp_util.erl +++ b/src/xmpp_util.erl @@ -10,7 +10,8 @@ %% API -export([add_delay_info/3, add_delay_info/4, unwrap_carbon/1, - is_standalone_chat_state/1]). + is_standalone_chat_state/1, get_xdata_values/2, + has_xdata_var/2]). -include("xmpp.hrl"). @@ -76,6 +77,17 @@ is_standalone_chat_state(Stanza) -> false end. +-spec get_xdata_values(binary(), xdata()) -> [binary()]. +get_xdata_values(Var, #xdata{fields = Fields}) -> + case lists:keyfind(Var, #xdata_field.var, Fields) of + #xdata_field{values = Vals} -> Vals; + false -> [] + end. + +-spec has_xdata_var(binary(), xdata()) -> boolean(). +has_xdata_var(Var, #xdata{fields = Fields}) -> + lists:keymember(Var, #xdata_field.var, Fields). + %%%=================================================================== %%% Internal functions %%%=================================================================== diff --git a/tools/xmpp_codec.spec b/tools/xmpp_codec.spec index 6c74a7ab1..fdf16ed37 100644 --- a/tools/xmpp_codec.spec +++ b/tools/xmpp_codec.spec @@ -224,10 +224,12 @@ -xml(disco_items, #elem{name = <<"query">>, xmlns = <<"http://jabber.org/protocol/disco#items">>, - result = {disco_items, '$node', '$items'}, + result = {disco_items, '$node', '$items', '$rsm'}, attrs = [#attr{name = <<"node">>}], refs = [#ref{name = disco_item, - label = '$items'}]}). + label = '$items'}, + #ref{name = rsm_set, min = 0, max = 1, + label = '$rsm'}]}). -xml(private, #elem{name = <<"query">>, @@ -468,6 +470,10 @@ #elem{name = <<"not-authorized">>, xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, result = 'not-authorized'}). +-xml(error_payment_required, + #elem{name = <<"payment-required">>, + xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + result = 'payment-required'}). -xml(error_policy_violation, #elem{name = <<"policy-violation">>, xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, @@ -561,6 +567,8 @@ min = 0, max = 1, label = '$reason'}, #ref{name = error_not_authorized, min = 0, max = 1, label = '$reason'}, + #ref{name = error_payment_required, + min = 0, max = 1, label = '$reason'}, #ref{name = error_policy_violation, min = 0, max = 1, label = '$reason'}, #ref{name = error_recipient_unavailable, @@ -1582,7 +1590,8 @@ -xml(xdata_field_option, #elem{name = <<"option">>, xmlns = <<"jabber:x:data">>, - result = '$value', + result = {xdata_option, '$label', '$value'}, + attrs = [#attr{name = <<"label">>}], refs = [#ref{name = xdata_field_value, label = '$value', min = 1, max = 1}]}). @@ -1945,9 +1954,11 @@ dec = {dec_utc, []}, enc = {enc_utc, []}}]}). --xml(muc_user_reason, +-xml(muc_reason, #elem{name = <<"reason">>, - xmlns = <<"http://jabber.org/protocol/muc#user">>, + xmlns = [<<"http://jabber.org/protocol/muc#user">>, + <<"http://jabber.org/protocol/muc#admin">>, + <<"http://jabber.org/protocol/muc#owner">>], result = '$cdata'}). -xml(muc_user_decline, @@ -1960,31 +1971,39 @@ #attr{name = <<"from">>, dec = {dec_jid, []}, enc = {enc_jid, []}}], - refs = [#ref{name = muc_user_reason, min = 0, + refs = [#ref{name = muc_reason, min = 0, + default = <<"">>, max = 1, label = '$reason'}]}). --xml(muc_user_destroy, +-xml(muc_destroy, #elem{name = <<"destroy">>, - xmlns = <<"http://jabber.org/protocol/muc#user">>, - result = {muc_user_destroy, '$reason', '$jid'}, - attrs = [#attr{name = <<"jid">>, + xmlns = [<<"http://jabber.org/protocol/muc#user">>, + <<"http://jabber.org/protocol/muc#owner">>], + result = {muc_destroy, '$xmlns', '$jid', '$reason', '$password'}, + attrs = [#attr{name = <<"jid">>, dec = {dec_jid, []}, - enc = {enc_jid, []}}], - refs = [#ref{name = muc_user_reason, min = 0, - max = 1, label = '$reason'}]}). + enc = {enc_jid, []}}, + #attr{name = <<"xmlns">>}], + refs = [#ref{name = muc_reason, min = 0, + default = <<"">>, + max = 1, label = '$reason'}, + #ref{name = muc_password, min = 0, max = 1, + label = '$password'}]}). -xml(muc_user_invite, #elem{name = <<"invite">>, xmlns = <<"http://jabber.org/protocol/muc#user">>, - result = {muc_invite, '$reason', '$from', '$to'}, + result = {muc_invite, '$reason', '$from', '$to', '$continue'}, attrs = [#attr{name = <<"to">>, dec = {dec_jid, []}, enc = {enc_jid, []}}, #attr{name = <<"from">>, dec = {dec_jid, []}, enc = {enc_jid, []}}], - refs = [#ref{name = muc_user_reason, min = 0, - max = 1, label = '$reason'}]}). + refs = [#ref{name = muc_reason, min = 0, default = <<"">>, + max = 1, label = '$reason'}, + #ref{name = muc_user_continue, min = 0, max = 1, + label = '$continue'}]}). -xml(muc_user_actor, #elem{name = <<"actor">>, @@ -2018,7 +2037,7 @@ min = 0, max = 1, label = '$actor'}, #ref{name = muc_user_continue, min = 0, max = 1, label = '$continue'}, - #ref{name = muc_user_reason, + #ref{name = muc_reason, default = <<"">>, min = 0, max = 1, label = '$reason'}], attrs = [#attr{name = <<"affiliation">>, dec = {dec_enum, [[admin, member, none, @@ -2038,44 +2057,56 @@ xmlns = <<"http://jabber.org/protocol/muc#user">>, result = {muc_user, '$decline', '$destroy', '$invites', '$items', '$status_codes', '$password'}, - attrs = [#attr{name = <<"password">>}], refs = [#ref{name = muc_user_decline, min = 0, max = 1, label = '$decline'}, - #ref{name = muc_user_destroy, min = 0, max = 1, + #ref{name = muc_destroy, min = 0, max = 1, label = '$destroy'}, + #ref{name = muc_password, min = 0, max = 1, + label = '$password'}, #ref{name = muc_user_invite, label = '$invites'}, #ref{name = muc_user_item, label = '$items'}, #ref{name = muc_user_status, label = '$status_codes'}]}). --xml(muc_owner_password, +-xml(muc_password, #elem{name = <<"password">>, - xmlns = <<"http://jabber.org/protocol/muc#owner">>, + xmlns = [<<"http://jabber.org/protocol/muc#owner">>, + <<"http://jabber.org/protocol/muc#user">>, + <<"http://jabber.org/protocol/muc">>], result = '$cdata'}). --xml(muc_owner_reason, - #elem{name = <<"reason">>, - xmlns = <<"http://jabber.org/protocol/muc#owner">>, - result = '$cdata'}). - --xml(muc_owner_destroy, - #elem{name = <<"destroy">>, - xmlns = <<"http://jabber.org/protocol/muc#owner">>, - result = {muc_owner_destroy, '$jid', '$reason', '$password'}, - attrs = [#attr{name = <<"jid">>, - dec = {dec_jid, []}, - enc = {enc_jid, []}}], - refs = [#ref{name = muc_owner_password, min = 0, max = 1, - label = '$password'}, - #ref{name = muc_owner_reason, min = 0, max = 1, - label = '$reason'}]}). - -xml(muc_owner, #elem{name = <<"query">>, xmlns = <<"http://jabber.org/protocol/muc#owner">>, - result = {muc_owner, '$destroy', '$config'}, - refs = [#ref{name = muc_owner_destroy, min = 0, max = 1, - label = '$destroy'}, - #ref{name = xdata, min = 0, max = 1, label = '$config'}]}). + result = {muc_owner, '$destroy', '$config', '$items'}, + refs = [#ref{name = muc_destroy, min = 0, max = 1, + label = '$destroy'}, + #ref{name = xdata, min = 0, max = 1, + label = '$config'}, + #ref{name = muc_owner_item, label = '$items'}]}). + +-xml(muc_owner_item, + #elem{name = <<"item">>, + xmlns = <<"http://jabber.org/protocol/muc#owner">>, + result = {muc_item, '$actor', '$continue', '$reason', + '$affiliation', '$role', '$jid', '$nick'}, + refs = [#ref{name = muc_admin_actor, + min = 0, max = 1, label = '$actor'}, + #ref{name = muc_admin_continue, + min = 0, max = 1, label = '$continue'}, + #ref{name = muc_reason, default = <<"">>, + min = 0, max = 1, label = '$reason'}], + attrs = [#attr{name = <<"affiliation">>, + dec = {dec_enum, [[admin, member, none, + outcast, owner]]}, + enc = {enc_enum, []}}, + #attr{name = <<"role">>, + dec = {dec_enum, [[moderator, none, + participant, visitor]]}, + enc = {enc_enum, []}}, + #attr{name = <<"jid">>, + dec = {dec_jid, []}, + enc = {enc_jid, []}}, + #attr{name = <<"nick">>}]}). -xml(muc_admin_item, #elem{name = <<"item">>, @@ -2086,7 +2117,7 @@ min = 0, max = 1, label = '$actor'}, #ref{name = muc_admin_continue, min = 0, max = 1, label = '$continue'}, - #ref{name = muc_admin_reason, + #ref{name = muc_reason, default = <<"">>, min = 0, max = 1, label = '$reason'}], attrs = [#attr{name = <<"affiliation">>, dec = {dec_enum, [[admin, member, none, @@ -2116,11 +2147,6 @@ result = '$thread', attrs = [#attr{name = <<"thread">>}]}). --xml(muc_admin_reason, - #elem{name = <<"reason">>, - xmlns = <<"http://jabber.org/protocol/muc#admin">>, - result = '$cdata'}). - -xml(muc_admin, #elem{name = <<"query">>, xmlns = <<"http://jabber.org/protocol/muc#admin">>, @@ -2131,9 +2157,66 @@ #elem{name = <<"x">>, xmlns = <<"http://jabber.org/protocol/muc">>, result = {muc, '$history', '$password'}, - attrs = [#attr{name = <<"password">>}], refs = [#ref{name = muc_history, min = 0, max = 1, - label = '$history'}]}). + label = '$history'}, + #ref{name = muc_password, min = 0, max = 1, + label = '$password'}]}). + +-xml(muc_unique, + #elem{name = <<"unique">>, + xmlns = <<"http://jabber.org/protocol/muc#unique">>, + result = {muc_unique, '$name'}, + cdata = #cdata{default = <<"">>, + label = '$name'}}). + +-xml(x_conference, + #elem{name = <<"x">>, + xmlns = <<"jabber:x:conference">>, + result = {x_conference, '$jid', '$password', '$reason', + '$continue', '$thread'}, + attrs = [#attr{name = <<"jid">>, + required = true, + dec = {dec_jid, []}, + enc = {enc_jid, []}}, + #attr{name = <<"password">>, default = <<"">>}, + #attr{name = <<"reason">>, default = <<"">>}, + #attr{name = <<"thread">>, default = <<"">>}, + #attr{name = <<"continue">>, + dec = {dec_bool, []}, + enc = {enc_bool, []}}]}). + +-xml(muc_subscription, + #elem{name = <<"subscription">>, + xmlns = <<"urn:xmpp:mucsub:0">>, + result = '$jid', + attrs = [#attr{name = <<"jid">>, + required = true, + dec = {dec_jid, []}, + enc = {enc_jid, []}}]}). + +-xml(muc_subscriptions, + #elem{name = <<"subscriptions">>, + xmlns = <<"urn:xmpp:mucsub:0">>, + result = {muc_subscriptions, '$list'}, + refs = [#ref{name = muc_subscription, label = '$list'}]}). + +-xml(muc_subscribe_event, + #elem{name = <<"event">>, + xmlns = <<"urn:xmpp:mucsub:0">>, + result = '$node', + attrs = [#attr{name = <<"node">>, required = true}]}). + +-xml(muc_subscribe, + #elem{name = <<"subscribe">>, + xmlns = <<"urn:xmpp:mucsub:0">>, + result = {muc_subscribe, '$nick', '$events'}, + attrs = [#attr{name = <<"nick">>, required = true}], + refs = [#ref{name = muc_subscribe_event, label = '$events'}]}). + +-xml(muc_unsubscribe, + #elem{name = <<"unsubscribe">>, + xmlns = <<"urn:xmpp:mucsub:0">>, + result = {muc_unsubscribe}}). -xml(rsm_after, #elem{name = <<"after">>, @@ -2143,7 +2226,7 @@ -xml(rsm_before, #elem{name = <<"before">>, xmlns = <<"http://jabber.org/protocol/rsm">>, - cdata = #cdata{default = none}, + cdata = #cdata{default = <<"">>}, result = '$cdata'}). -xml(rsm_last, @@ -2215,16 +2298,23 @@ dec = {dec_jid, []}, enc = {enc_jid, []}}}). +-xml(mam_withtext, + #elem{name = <<"withtext">>, + xmlns = <<"urn:xmpp:mam:tmp">>, + result = '$cdata', + cdata = #cdata{required = true}}). + -xml(mam_query, #elem{name = <<"query">>, xmlns = [<<"urn:xmpp:mam:0">>, <<"urn:xmpp:mam:1">>, <<"urn:xmpp:mam:tmp">>], result = {mam_query, '$xmlns', '$id', '$start', '$end', '$with', - '$rsm', '$xdata'}, + '$withtext', '$rsm', '$xdata'}, attrs = [#attr{name = <<"queryid">>, label = '$id'}, #attr{name = <<"xmlns">>}], refs = [#ref{name = mam_start, min = 0, max = 1, label = '$start'}, #ref{name = mam_end, min = 0, max = 1, label = '$end'}, #ref{name = mam_with, min = 0, max = 1, label = '$with'}, + #ref{name = mam_withtext, min = 0, max = 1, label = '$withtext'}, #ref{name = rsm_set, min = 0, max = 1, label = '$rsm'}, #ref{name = xdata, min = 0, max = 1, label = '$xdata'}]}). @@ -2248,7 +2338,7 @@ -xml(mam_jid, #elem{name = <<"jid">>, - xmlns = <<"urn:xmpp:mam:tmp">>, + xmlns = [<<"urn:xmpp:mam:0">>, <<"urn:xmpp:mam:1">>, <<"urn:xmpp:mam:tmp">>], result = '$cdata', cdata = #cdata{required = true, dec = {dec_jid, []}, @@ -2256,15 +2346,15 @@ -xml(mam_never, #elem{name = <<"never">>, - xmlns = <<"urn:xmpp:mam:tmp">>, + xmlns = [<<"urn:xmpp:mam:0">>, <<"urn:xmpp:mam:1">>, <<"urn:xmpp:mam:tmp">>], result = '$jids', - refs = [#ref{name = mam_jid, label = '$jids', default = []}]}). + refs = [#ref{name = mam_jid, label = '$jids'}]}). -xml(mam_always, #elem{name = <<"always">>, - xmlns = <<"urn:xmpp:mam:tmp">>, + xmlns = [<<"urn:xmpp:mam:0">>, <<"urn:xmpp:mam:1">>, <<"urn:xmpp:mam:tmp">>], result = '$jids', - refs = [#ref{name = mam_jid, label = '$jids', default = []}]}). + refs = [#ref{name = mam_jid, label = '$jids'}]}). -xml(mam_prefs, #elem{name = <<"prefs">>, @@ -2275,9 +2365,9 @@ enc = {enc_enum, []}}, #attr{name = <<"xmlns">>}], refs = [#ref{name = mam_always, label = '$always', - min = 0, max = 1, default = []}, + min = 0, max = 1}, #ref{name = mam_never, label = '$never', - min = 0, max = 1, default = []}]}). + min = 0, max = 1}]}). -xml(mam_fin, #elem{name = <<"fin">>, @@ -2538,8 +2628,8 @@ #attr{name = <<"nick">>, label = '$nick'}]}). --record(hint, {type :: 'no-copy' | 'no-store' | 'no-storage' | - 'store' | 'no-permanent-store'}). +-record(hint, {type :: 'no-copy' | 'no-store' | 'no-storage' | 'store' | + 'no-permanent-store' | 'no-permanent-storage'}). -type hint() :: #hint{}. -xml(hint_no_copy, @@ -2567,6 +2657,11 @@ xmlns = <<"urn:xmpp:hints">>, result = {hint, 'no-permanent-store'}}). +-xml(hint_no_permanent_storage, + #elem{name = <<"no-permanent-storage">>, + xmlns = <<"urn:xmpp:hints">>, + result = {hint, 'no-permanent-storage'}}). + -xml(search_instructions, #elem{name = <<"instructions">>, xmlns = <<"jabber:iq:search">>, @@ -2679,6 +2774,53 @@ dec = {dec_int, [0, infinity]}, enc = {enc_int, []}}]}). +-xml(nick, + #elem{name = <<"nick">>, + xmlns = <<"http://jabber.org/protocol/nick">>, + result = {nick, '$name'}, + cdata = #cdata{label = '$name', + required = true}}). + +-xml(address, + #elem{name = <<"address">>, + xmlns = <<"http://jabber.org/protocol/address">>, + result = {address, '$type', '$jid', '$desc', '$node', '$delivered'}, + attrs = [#attr{name = <<"type">>, + required = true, + dec = {dec_enum, [[bcc, cc, noreply, ofrom, + replyroom, replyto, to]]}, + enc = {enc_enum, []}}, + #attr{name = <<"jid">>, + enc = {enc_jid, []}, + dec = {dec_jid, []}}, + #attr{name = <<"desc">>}, + #attr{name = <<"node">>}, + #attr{name = <<"delivered">>, + enc = {enc_bool, []}, + dec = {dec_bool, []}}]}). + +-xml(addresses, + #elem{name = <<"addresses">>, + xmlns = <<"http://jabber.org/protocol/address">>, + result = {addresses, '$list'}, + %% TODO: 'min' should be '1', but this is not implemented + refs = [#ref{name = address, label = '$list'}]}). + +-xml(stanza_id, + #elem{name = <<"stanza-id">>, + xmlns = <<"urn:xmpp:sid:0">>, + result = {stanza_id, '$by', '$id'}, + attrs = [#attr{name = <<"id">>, required = true}, + #attr{name = <<"by">>, required = true, + enc = {enc_jid, []}, + dec = {dec_jid, []}}]}). + +-xml(client_id, + #elem{name = <<"client-id">>, + xmlns = <<"urn:xmpp:sid:0">>, + result = {client_id, '$id'}, + attrs = [#attr{name = <<"id">>, required = true}]}). + dec_tzo(Val) -> [H1, M1] = str:tokens(Val, <<":">>), H = jlib:binary_to_integer(H1), From da310a517396bee93e96da9a3717230938064494 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Tue, 26 Jul 2016 09:52:29 +0300 Subject: [PATCH 006/151] Rewrite mod_adhoc and mod_announce to use XML generator --- include/xmpp_codec.hrl | 57 +++-- src/mod_adhoc.erl | 138 +++++------ src/mod_announce.erl | 355 ++++++++++----------------- src/xmpp_codec.erl | 544 ++++++++++++++++++++++++++++++++++++++++- src/xmpp_util.erl | 14 +- tools/xmpp_codec.spec | 56 +++++ 6 files changed, 840 insertions(+), 324 deletions(-) diff --git a/include/xmpp_codec.hrl b/include/xmpp_codec.hrl index 85601035d..b14c0d11f 100644 --- a/include/xmpp_codec.hrl +++ b/include/xmpp_codec.hrl @@ -18,6 +18,10 @@ -record(feature_register, {}). -type feature_register() :: #feature_register{}. +-record(adhoc_note, {type = info :: 'error' | 'info' | 'warn', + data = <<>> :: binary()}). +-type adhoc_note() :: #adhoc_note{}. + -record(address, {type :: 'bcc' | 'cc' | 'noreply' | 'ofrom' | 'replyroom' | 'replyto' | 'to', jid :: any(), desc :: binary(), @@ -419,6 +423,12 @@ sid :: binary()}). -type bytestreams() :: #bytestreams{}. +-record(adhoc_actions, {execute :: 'complete' | 'next' | 'prev', + prev = false :: boolean(), + next = false :: boolean(), + complete = false :: boolean()}). +-type adhoc_actions() :: #adhoc_actions{}. + -record(vcard_org, {name :: binary(), units = [] :: [binary()]}). -type vcard_org() :: #vcard_org{}. @@ -559,6 +569,16 @@ fields = [] :: [#xdata_field{}]}). -type xdata() :: #xdata{}. +-record(adhoc_command, {node :: binary(), + action = execute :: 'cancel' | 'complete' | 'execute' | 'next' | 'prev', + sid :: binary(), + status :: 'canceled' | 'completed' | 'executing', + lang :: binary(), + actions :: #adhoc_actions{}, + notes = [] :: [#adhoc_note{}], + xdata :: #xdata{}}). +-type adhoc_command() :: #adhoc_command{}. + -record(search, {instructions :: binary(), first :: binary(), last :: binary(), @@ -799,6 +819,7 @@ pubsub_options() | compress() | bytestreams() | + adhoc_actions() | muc_history() | identity() | feature_csi() | @@ -810,9 +831,7 @@ pubsub() | muc_owner() | muc_actor() | - carbons_private() | - mix_leave() | - muc_subscribe() | + adhoc_note() | rosterver_feature() | muc_invite() | vcard_xupdate() | @@ -820,28 +839,16 @@ bookmark_conference() | offline() | time() | - muc_unique() | - sasl_response() | - pubsub_subscribe() | - presence() | - message() | sm_enable() | starttls_failure() | sasl_challenge() | - gone() | x_conference() | private() | compress_failure() | sasl_failure() | bookmark_storage() | vcard_name() | - sm_resume() | - carbons_enable() | - expire() | - muc_unsubscribe() | - pubsub_unsubscribe() | muc_decline() | - chatstate() | sasl_auth() | p1_push() | legacy_auth() | @@ -866,10 +873,11 @@ rsm_first() | stat() | xdata_field() | + adhoc_command() | sm_failed() | ping() | - disco_item() | privacy_item() | + disco_item() | caps() | muc() | stream_features() | @@ -894,4 +902,19 @@ error() | stream_error() | muc_user() | - vcard_adr(). + vcard_adr() | + carbons_private() | + mix_leave() | + muc_subscribe() | + muc_unique() | + sasl_response() | + pubsub_subscribe() | + presence() | + message() | + gone() | + sm_resume() | + carbons_enable() | + expire() | + muc_unsubscribe() | + pubsub_unsubscribe() | + chatstate(). diff --git a/src/mod_adhoc.erl b/src/mod_adhoc.erl index e12e0de1e..9c8238900 100644 --- a/src/mod_adhoc.erl +++ b/src/mod_adhoc.erl @@ -31,18 +31,15 @@ -behaviour(gen_mod). --export([start/2, stop/1, process_local_iq/3, - process_sm_iq/3, get_local_commands/5, +-export([start/2, stop/1, process_local_iq/1, + process_sm_iq/1, get_local_commands/5, get_local_identity/5, get_local_features/5, get_sm_commands/5, get_sm_identity/5, get_sm_features/5, ping_item/4, ping_command/4, mod_opt_type/1, depends/2]). -include("ejabberd.hrl"). -include("logger.hrl"). - --include("jlib.hrl"). - --include("adhoc.hrl"). +-include("xmpp.hrl"). start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, fun gen_iq_handler:check_type/1, @@ -94,7 +91,7 @@ stop(Host) -> %------------------------------------------------------------------------- get_local_commands(Acc, _From, - #jid{server = Server, lserver = LServer} = _To, <<"">>, + #jid{server = Server, lserver = LServer} = _To, undefined, Lang) -> Display = gen_mod:get_module_opt(LServer, ?MODULE, report_commands_node, @@ -107,12 +104,9 @@ get_local_commands(Acc, _From, {result, I} -> I; _ -> [] end, - Nodes = [#xmlel{name = <<"item">>, - attrs = - [{<<"jid">>, Server}, {<<"node">>, ?NS_COMMANDS}, - {<<"name">>, - translate:translate(Lang, <<"Commands">>)}], - children = []}], + Nodes = [#disco_item{jid = jid:make(Server), + node = ?NS_COMMANDS, + name = translate:translate(Lang, <<"Commands">>)}], {result, Items ++ Nodes} end; get_local_commands(_Acc, From, @@ -128,7 +122,7 @@ get_local_commands(Acc, _From, _To, _Node, _Lang) -> %------------------------------------------------------------------------- get_sm_commands(Acc, _From, - #jid{lserver = LServer} = To, <<"">>, Lang) -> + #jid{lserver = LServer} = To, undefined, Lang) -> Display = gen_mod:get_module_opt(LServer, ?MODULE, report_commands_node, fun(B) when is_boolean(B) -> B end, @@ -140,13 +134,9 @@ get_sm_commands(Acc, _From, {result, I} -> I; _ -> [] end, - Nodes = [#xmlel{name = <<"item">>, - attrs = - [{<<"jid">>, jid:to_string(To)}, - {<<"node">>, ?NS_COMMANDS}, - {<<"name">>, - translate:translate(Lang, <<"Commands">>)}], - children = []}], + Nodes = [#disco_item{jid = To, + node = ?NS_COMMANDS, + name = translate:translate(Lang, <<"Commands">>)}], {result, Items ++ Nodes} end; get_sm_commands(_Acc, From, @@ -160,21 +150,14 @@ get_sm_commands(Acc, _From, _To, _Node, _Lang) -> Acc. %% On disco info request to the ad-hoc node, return automation/command-list. get_local_identity(Acc, _From, _To, ?NS_COMMANDS, Lang) -> - [#xmlel{name = <<"identity">>, - attrs = - [{<<"category">>, <<"automation">>}, - {<<"type">>, <<"command-list">>}, - {<<"name">>, - translate:translate(Lang, <<"Commands">>)}], - children = []} + [#identity{category = <<"automation">>, + type = <<"command-list">>, + name = translate:translate(Lang, <<"Commands">>)} | Acc]; get_local_identity(Acc, _From, _To, <<"ping">>, Lang) -> - [#xmlel{name = <<"identity">>, - attrs = - [{<<"category">>, <<"automation">>}, - {<<"type">>, <<"command-node">>}, - {<<"name">>, translate:translate(Lang, <<"Ping">>)}], - children = []} + [#identity{category = <<"automation">>, + type = <<"command-node">>, + name = translate:translate(Lang, <<"Ping">>)} | Acc]; get_local_identity(Acc, _From, _To, _Node, _Lang) -> Acc. @@ -183,13 +166,9 @@ get_local_identity(Acc, _From, _To, _Node, _Lang) -> %% On disco info request to the ad-hoc node, return automation/command-list. get_sm_identity(Acc, _From, _To, ?NS_COMMANDS, Lang) -> - [#xmlel{name = <<"identity">>, - attrs = - [{<<"category">>, <<"automation">>}, - {<<"type">>, <<"command-list">>}, - {<<"name">>, - translate:translate(Lang, <<"Commands">>)}], - children = []} + [#identity{category = <<"automation">>, + type = <<"command-list">>, + name = translate:translate(Lang, <<"Commands">>)} | Acc]; get_sm_identity(Acc, _From, _To, _Node, _Lang) -> Acc. @@ -225,34 +204,29 @@ get_sm_features(Acc, _From, _To, _Node, _Lang) -> Acc. %------------------------------------------------------------------------- -process_local_iq(From, To, IQ) -> - process_adhoc_request(From, To, IQ, - adhoc_local_commands). +process_local_iq(IQ) -> + process_adhoc_request(IQ, adhoc_local_commands). -process_sm_iq(From, To, IQ) -> - process_adhoc_request(From, To, IQ, adhoc_sm_commands). +process_sm_iq(IQ) -> + process_adhoc_request(IQ, adhoc_sm_commands). -process_adhoc_request(From, To, - #iq{sub_el = SubEl, lang = Lang} = IQ, Hook) -> - ?DEBUG("About to parse ~p...", [IQ]), - case adhoc:parse_request(IQ) of - {error, Error} -> - IQ#iq{type = error, sub_el = [SubEl, Error]}; - #adhoc_request{} = AdhocRequest -> - Host = To#jid.lserver, - case ejabberd_hooks:run_fold(Hook, Host, empty, - [From, To, AdhocRequest]) - of - ignore -> ignore; - empty -> - Txt = <<"No hook has processed this command">>, - IQ#iq{type = error, - sub_el = [SubEl, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)]}; - {error, Error} -> - IQ#iq{type = error, sub_el = [SubEl, Error]}; - Command -> IQ#iq{type = result, sub_el = [Command]} - end - end. +process_adhoc_request(#iq{from = From, to = To, + type = set, lang = Lang, + sub_els = [#adhoc_command{} = SubEl]} = IQ, Hook) -> + Host = To#jid.lserver, + case ejabberd_hooks:run_fold(Hook, Host, empty, [From, To, SubEl]) of + ignore -> + ignore; + empty -> + Txt = <<"No hook has processed this command">>, + xmpp:make_error(IQ, xmpp:err_item_not_found(Txt, Lang)); + {error, Error} -> + xmpp:make_error(IQ, Error); + Command -> + xmpp:make_iq_result(IQ, Command) + end; +process_adhoc_request(#iq{} = IQ, _Hooks) -> + xmpp:make_error(IQ, xmpp:err_bad_request()). ping_item(Acc, _From, #jid{server = Server} = _To, Lang) -> @@ -260,27 +234,25 @@ ping_item(Acc, _From, #jid{server = Server} = _To, {result, I} -> I; _ -> [] end, - Nodes = [#xmlel{name = <<"item">>, - attrs = - [{<<"jid">>, Server}, {<<"node">>, <<"ping">>}, - {<<"name">>, translate:translate(Lang, <<"Ping">>)}], - children = []}], + Nodes = [#disco_item{jid = jid:make(Server), + node = <<"ping">>, + name = translate:translate(Lang, <<"Ping">>)}], {result, Items ++ Nodes}. ping_command(_Acc, _From, _To, - #adhoc_request{lang = Lang, node = <<"ping">>, - sessionid = _Sessionid, action = Action} = - Request) -> - if Action == <<"">>; Action == <<"execute">> -> - adhoc:produce_response(Request, - #adhoc_response{status = completed, - notes = - [{<<"info">>, - translate:translate(Lang, - <<"Pong">>)}]}); + #adhoc_command{lang = Lang, node = <<"ping">>, + action = Action} = Request) -> + if Action == execute -> + xmpp_util:make_adhoc_response( + Request, + #adhoc_command{ + status = completed, + notes = [#adhoc_note{ + type = info, + data = translate:translate(Lang, <<"Pong">>)}]}); true -> Txt = <<"Incorrect value of 'action' attribute">>, - {error, ?ERRT_BAD_REQUEST(Lang, Txt)} + {error, xmpp:err_bad_request(Txt, Lang)} end; ping_command(Acc, _From, _To, _Request) -> Acc. diff --git a/src/mod_announce.erl b/src/mod_announce.erl index 52ff2de92..4b7498447 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -39,8 +39,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). --include("adhoc.hrl"). +-include("xmpp.hrl"). -include("mod_announce.hrl"). -callback init(binary(), gen_mod:opts()) -> any(). @@ -57,6 +56,7 @@ -define(NS_ADMINL(Sub), [<<"http:">>, <<"jabber.org">>, <<"protocol">>, <<"admin">>, <>]). +tokenize(undefined) -> []; tokenize(Node) -> str:tokens(Node, <<"/#">>). start(Host, Opts) -> @@ -131,7 +131,7 @@ stop(Host) -> {wait, Proc}. %% Announcing via messages to a custom resource -announce(From, #jid{luser = <<>>} = To, #xmlel{name = <<"message">>} = Packet) -> +announce(From, #jid{luser = <<>>} = To, #message{} = Packet) -> Proc = gen_mod:get_module_proc(To#jid.lserver, ?PROCNAME), case To#jid.lresource of <<"announce/all">> -> @@ -173,10 +173,9 @@ announce(_From, _To, _Packet) -> %%------------------------------------------------------------------------- %% Announcing via ad-hoc commands -define(INFO_COMMAND(Lang, Node), - [#xmlel{name = <<"identity">>, - attrs = [{<<"category">>, <<"automation">>}, - {<<"type">>, <<"command-node">>}, - {<<"name">>, get_title(Lang, Node)}]}]). + [#identity{category = <<"automation">>, + type = <<"command-node">>, + name = get_title(Lang, Node)}]). disco_identity(Acc, _From, _To, Node, Lang) -> LNode = tokenize(Node), @@ -210,7 +209,7 @@ disco_identity(Acc, _From, _To, Node, Lang) -> -define(INFO_RESULT(Allow, Feats, Lang), case Allow of deny -> - {error, ?ERRT_FORBIDDEN(Lang, <<"Denied by ACL">>)}; + {error, xmpp:err_forbidden(<<"Denied by ACL">>, Lang)}; allow -> {result, Feats} end). @@ -226,7 +225,7 @@ disco_features(Acc, From, #jid{lserver = LServer} = _To, <<"announce">>, Lang) - acl:match_rule(global, Access2, From)} of {deny, deny} -> Txt = <<"Denied by ACL">>, - {error, ?ERRT_FORBIDDEN(Lang, Txt)}; + {error, xmpp:err_forbidden(Txt, Lang)}; _ -> {result, []} end @@ -269,26 +268,19 @@ disco_features(Acc, From, #jid{lserver = LServer} = _To, Node, Lang) -> %%------------------------------------------------------------------------- -define(NODE_TO_ITEM(Lang, Server, Node), -( - #xmlel{ - name = <<"item">>, - attrs = [ - {<<"jid">>, Server}, - {<<"node">>, Node}, - {<<"name">>, get_title(Lang, Node)} - ] - } -)). + #disco_item{jid = jid:make(Server), + node = Node, + name = get_title(Lang, Node)}). -define(ITEMS_RESULT(Allow, Items, Lang), case Allow of deny -> - {error, ?ERRT_FORBIDDEN(Lang, <<"Denied by ACL">>)}; + {error, xmpp:err_forbidden(<<"Denied by ACL">>, Lang)}; allow -> {result, Items} end). -disco_items(Acc, From, #jid{lserver = LServer, server = Server} = _To, <<>>, Lang) -> +disco_items(Acc, From, #jid{lserver = LServer, server = Server} = _To, undefined, Lang) -> case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -393,15 +385,15 @@ announce_items(Acc, From, #jid{lserver = LServer, server = Server} = _To, Lang) commands_result(Allow, From, To, Request) -> case Allow of deny -> - Lang = Request#adhoc_request.lang, - {error, ?ERRT_FORBIDDEN(Lang, <<"Denied by ACL">>)}; + Lang = Request#adhoc_command.lang, + {error, xmpp:err_forbidden(<<"Denied by ACL">>, Lang)}; allow -> announce_commands(From, To, Request) end. announce_commands(Acc, From, #jid{lserver = LServer} = To, - #adhoc_request{ node = Node} = Request) -> + #adhoc_command{node = Node} = Request) -> LNode = tokenize(Node), F = fun() -> Access = get_access(global), @@ -440,59 +432,35 @@ announce_commands(Acc, From, #jid{lserver = LServer} = To, %%------------------------------------------------------------------------- announce_commands(From, To, - #adhoc_request{lang = Lang, + #adhoc_command{lang = Lang, node = Node, - action = Action, - xdata = XData} = Request) -> - %% If the "action" attribute is not present, it is - %% understood as "execute". If there was no - %% element in the first response (which there isn't in our - %% case), "execute" and "complete" are equivalent. - ActionIsExecute = lists:member(Action, [<<>>, <<"execute">>, <<"complete">>]), - if Action == <<"cancel">> -> + sid = SID, + xdata = XData, + action = Action} = Request) -> + ActionIsExecute = Action == execute orelse Action == complete, + if Action == cancel -> %% User cancels request - adhoc:produce_response(Request, #adhoc_response{status = canceled}); - XData == false, ActionIsExecute -> + #adhoc_command{status = canceled, lang = Lang, node = Node, + sid = SID}; + XData == undefined, ActionIsExecute -> %% User requests form - Elements = generate_adhoc_form(Lang, Node, To#jid.lserver), - adhoc:produce_response(Request, - #adhoc_response{status = executing,elements = [Elements]}); - XData /= false, ActionIsExecute -> - %% User returns form. - case jlib:parse_xdata_submit(XData) of - invalid -> - {error, ?ERRT_BAD_REQUEST(Lang, <<"Incorrect data form">>)}; - Fields -> - handle_adhoc_form(From, To, Request, Fields) - end; + Form = generate_adhoc_form(Lang, Node, To#jid.lserver), + #adhoc_command{status = executing, lang = Lang, node = Node, + sid = SID, xdata = Form}; + XData /= undefined, ActionIsExecute -> + handle_adhoc_form(From, To, Request); true -> - Txt = <<"Incorrect action or data form">>, - {error, ?ERRT_BAD_REQUEST(Lang, Txt)} + Txt = <<"Unexpected action">>, + {error, xmpp:err_bad_request(Txt, Lang)} end. --define(VVALUE(Val), -( - #xmlel{ - name = <<"value">>, - children = [{xmlcdata, Val}] - } -)). - -define(TVFIELD(Type, Var, Val), -( - #xmlel{ - name = <<"field">>, - attrs = [{<<"type">>, Type}, {<<"var">>, Var}], - children = vvaluel(Val) - } -)). - --define(HFIELD(), ?TVFIELD(<<"hidden">>, <<"FORM_TYPE">>, ?NS_ADMIN)). + #xdata_field{type = Type, var = Var, values = vvaluel(Val)}). vvaluel(Val) -> case Val of <<>> -> []; - _ -> [?VVALUE(Val)] + _ -> [Val] end. generate_adhoc_form(Lang, Node, ServerHost) -> @@ -503,49 +471,27 @@ generate_adhoc_form(Lang, Node, ServerHost) -> true -> {<<>>, <<>>} end, - #xmlel{ - name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_XDATA}, {<<"type">>, <<"form">>}], - children = [ - ?HFIELD(), - #xmlel{name = <<"title">>, children = [{xmlcdata, get_title(Lang, Node)}]} - ] - ++ - if (LNode == ?NS_ADMINL("delete-motd")) - or (LNode == ?NS_ADMINL("delete-motd-allhosts")) -> - [#xmlel{ - name = <<"field">>, - attrs = [ - {<<"var">>, <<"confirm">>}, - {<<"type">>, <<"boolean">>}, - {<<"label">>, - translate:translate(Lang, <<"Really delete message of the day?">>)} - ], - children = [ - #xmlel{name = <<"value">>, children = [{xmlcdata, <<"true">>}]} - ] - } - ]; - true -> - [#xmlel{ - name = <<"field">>, - attrs = [ - {<<"var">>, <<"subject">>}, - {<<"type">>, <<"text-single">>}, - {<<"label">>, translate:translate(Lang, <<"Subject">>)}], - children = vvaluel(OldSubject) - }, - #xmlel{ - name = <<"field">>, - attrs = [ - {<<"var">>, <<"body">>}, - {<<"type">>, <<"text-multi">>}, - {<<"label">>, translate:translate(Lang, <<"Message body">>)}], - children = vvaluel(OldBody) - } - ] - - end}. + Fs = if (LNode == ?NS_ADMINL("delete-motd")) + or (LNode == ?NS_ADMINL("delete-motd-allhosts")) -> + [#xdata_field{type = boolean, + var = <<"confirm">>, + label = translate:translate( + Lang, <<"Really delete message of the day?">>), + values = [<<"true">>]}]; + true -> + [#xdata_field{type = 'text-single', + var = <<"subject">>, + label = translate:translate(Lang, <<"Subject">>), + values = vvaluel(OldSubject)}, + #xdata_field{type = 'text-multi', + var = <<"body">>, + label = translate:translate(Lang, <<"Message body">>), + values = vvaluel(OldBody)}] + end, + #xdata{type = form, + title = get_title(Lang, Node), + fields = [#xdata_field{type = hidden, var = <<"FORM_TYPE">>, + values = [?NS_ADMIN]}|Fs]}. join_lines([]) -> <<>>; @@ -558,103 +504,73 @@ join_lines([], Acc) -> iolist_to_binary(lists:reverse(tl(Acc))). handle_adhoc_form(From, #jid{lserver = LServer} = To, - #adhoc_request{lang = Lang, - node = Node, - sessionid = SessionID}, - Fields) -> - Confirm = case lists:keysearch(<<"confirm">>, 1, Fields) of - {value, {<<"confirm">>, [<<"true">>]}} -> - true; - {value, {<<"confirm">>, [<<"1">>]}} -> - true; - _ -> - false + #adhoc_command{lang = Lang, node = Node, + sid = SessionID, xdata = XData}) -> + Confirm = case xmpp_util:get_xdata_values(<<"confirm">>, XData) of + [<<"true">>] -> true; + [<<"1">>] -> true; + _ -> false end, - Subject = case lists:keysearch(<<"subject">>, 1, Fields) of - {value, {<<"subject">>, SubjectLines}} -> - %% There really shouldn't be more than one - %% subject line, but can we stop them? - join_lines(SubjectLines); - _ -> - <<>> - end, - Body = case lists:keysearch(<<"body">>, 1, Fields) of - {value, {<<"body">>, BodyLines}} -> - join_lines(BodyLines); - _ -> - <<>> - end, - Response = #adhoc_response{lang = Lang, - node = Node, - sessionid = SessionID, - status = completed}, - Packet = #xmlel{ - name = <<"message">>, - attrs = [{<<"type">>, <<"headline">>}], - children = if Subject /= <<>> -> - [#xmlel{name = <<"subject">>, children = [{xmlcdata, Subject}]}]; - true -> - [] - end - ++ - if Body /= <<>> -> - [#xmlel{name = <<"body">>, children = [{xmlcdata, Body}]}]; - true -> - [] - end - }, + Subject = join_lines(xmpp_util:get_xdata_values(<<"subject">>, XData)), + Body = join_lines(xmpp_util:get_xdata_values(<<"body">>, XData)), + Response = #adhoc_command{lang = Lang, node = Node, sid = SessionID, + status = completed}, + Packet = #message{type = headline, + body = xmpp:mk_text(Body), + subject = xmpp:mk_text(Subject)}, Proc = gen_mod:get_module_proc(LServer, ?PROCNAME), case {Node, Body} of {?NS_ADMIN_DELETE_MOTD, _} -> if Confirm -> Proc ! {announce_motd_delete, From, To, Packet}, - adhoc:produce_response(Response); + Response; true -> - adhoc:produce_response(Response) + Response end; {?NS_ADMIN_DELETE_MOTD_ALLHOSTS, _} -> if Confirm -> Proc ! {announce_all_hosts_motd_delete, From, To, Packet}, - adhoc:produce_response(Response); + Response; true -> - adhoc:produce_response(Response) + Response end; {_, <<>>} -> %% An announce message with no body is definitely an operator error. %% Throw an error and give him/her a chance to send message again. - {error, ?ERRT_NOT_ACCEPTABLE(Lang, - <<"No body provided for announce message">>)}; + {error, xmpp:err_not_acceptable( + <<"No body provided for announce message">>, Lang)}; %% Now send the packet to ?PROCNAME. %% We don't use direct announce_* functions because it %% leads to large delay in response and queries processing {?NS_ADMIN_ANNOUNCE, _} -> Proc ! {announce_online, From, To, Packet}, - adhoc:produce_response(Response); + Response; {?NS_ADMIN_ANNOUNCE_ALLHOSTS, _} -> Proc ! {announce_all_hosts_online, From, To, Packet}, - adhoc:produce_response(Response); + Response; {?NS_ADMIN_ANNOUNCE_ALL, _} -> Proc ! {announce_all, From, To, Packet}, - adhoc:produce_response(Response); + Response; {?NS_ADMIN_ANNOUNCE_ALL_ALLHOSTS, _} -> Proc ! {announce_all_hosts_all, From, To, Packet}, - adhoc:produce_response(Response); + Response; {?NS_ADMIN_SET_MOTD, _} -> Proc ! {announce_motd, From, To, Packet}, - adhoc:produce_response(Response); + Response; {?NS_ADMIN_SET_MOTD_ALLHOSTS, _} -> Proc ! {announce_all_hosts_motd, From, To, Packet}, - adhoc:produce_response(Response); + Response; {?NS_ADMIN_EDIT_MOTD, _} -> Proc ! {announce_motd_update, From, To, Packet}, - adhoc:produce_response(Response); + Response; {?NS_ADMIN_EDIT_MOTD_ALLHOSTS, _} -> Proc ! {announce_all_hosts_motd_update, From, To, Packet}, - adhoc:produce_response(Response); - _ -> + Response; + Junk -> %% This can't happen, as we haven't registered any other %% command nodes. - {error, ?ERR_INTERNAL_SERVER_ERROR} + ?ERROR_MSG("got unexpected node/body = ~p", [Junk]), + {error, xmpp:err_internal_server_error()} end. get_title(Lang, <<"announce">>) -> @@ -687,15 +603,15 @@ announce_all(From, To, Packet) -> Access = get_access(Host), case acl:match_rule(Host, Access, From) of deny -> - Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), + Lang = xmpp:get_lang(Packet), Txt = <<"Denied by ACL">>, - Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)), + Err = xmpp:make_error(Packet, xmpp:err_forbidden(Txt, Lang)), ejabberd_router:route(To, From, Err); allow -> - Local = jid:make(<<>>, To#jid.server, <<>>), + Local = jid:make(To#jid.server), lists:foreach( fun({User, Server}) -> - Dest = jid:make(User, Server, <<>>), + Dest = jid:make(User, Server), ejabberd_router:route(Local, Dest, Packet) end, ejabberd_auth:get_vh_registered_users(Host)) end. @@ -704,15 +620,15 @@ announce_all_hosts_all(From, To, Packet) -> Access = get_access(global), case acl:match_rule(global, Access, From) of deny -> - Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), + Lang = xmpp:get_lang(Packet), Txt = <<"Denied by ACL">>, - Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)), + Err = xmpp:make_error(Packet, xmpp:err_forbidden(Txt, Lang)), ejabberd_router:route(To, From, Err); allow -> - Local = jid:make(<<>>, To#jid.server, <<>>), + Local = jid:make(To#jid.server), lists:foreach( fun({User, Server}) -> - Dest = jid:make(User, Server, <<>>), + Dest = jid:make(User, Server), ejabberd_router:route(Local, Dest, Packet) end, ejabberd_auth:dirty_get_registered_users()) end. @@ -722,9 +638,9 @@ announce_online(From, To, Packet) -> Access = get_access(Host), case acl:match_rule(Host, Access, From) of deny -> - Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), + Lang = xmpp:get_lang(Packet), Txt = <<"Denied by ACL">>, - Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)), + Err = xmpp:make_error(Packet, xmpp:err_forbidden(Txt, Lang)), ejabberd_router:route(To, From, Err); allow -> announce_online1(ejabberd_sm:get_vh_session_list(Host), @@ -736,9 +652,9 @@ announce_all_hosts_online(From, To, Packet) -> Access = get_access(global), case acl:match_rule(global, Access, From) of deny -> - Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), + Lang = xmpp:get_lang(Packet), Txt = <<"Denied by ACL">>, - Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)), + Err = xmpp:make_error(Packet, xmpp:err_forbidden(Txt, Lang)), ejabberd_router:route(To, From, Err); allow -> announce_online1(ejabberd_sm:dirty_get_sessions_list(), @@ -747,7 +663,7 @@ announce_all_hosts_online(From, To, Packet) -> end. announce_online1(Sessions, Server, Packet) -> - Local = jid:make(<<>>, Server, <<>>), + Local = jid:make(Server), lists:foreach( fun({U, S, R}) -> Dest = jid:make(U, S, R), @@ -759,9 +675,9 @@ announce_motd(From, To, Packet) -> Access = get_access(Host), case acl:match_rule(Host, Access, From) of deny -> - Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), + Lang = xmpp:get_lang(Packet), Txt = <<"Denied by ACL">>, - Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)), + Err = xmpp:make_error(Packet, xmpp:err_forbidden(Txt, Lang)), ejabberd_router:route(To, From, Err); allow -> announce_motd(Host, Packet) @@ -771,9 +687,9 @@ announce_all_hosts_motd(From, To, Packet) -> Access = get_access(global), case acl:match_rule(global, Access, From) of deny -> - Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), + Lang = xmpp:get_lang(Packet), Txt = <<"Denied by ACL">>, - Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)), + Err = xmpp:make_error(Packet, xmpp:err_forbidden(Txt, Lang)), ejabberd_router:route(To, From, Err); allow -> Hosts = ?MYHOSTS, @@ -793,9 +709,9 @@ announce_motd_update(From, To, Packet) -> Access = get_access(Host), case acl:match_rule(Host, Access, From) of deny -> - Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), + Lang = xmpp:get_lang(Packet), Txt = <<"Denied by ACL">>, - Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)), + Err = xmpp:make_error(Packet, xmpp:err_forbidden(Txt, Lang)), ejabberd_router:route(To, From, Err); allow -> announce_motd_update(Host, Packet) @@ -805,9 +721,9 @@ announce_all_hosts_motd_update(From, To, Packet) -> Access = get_access(global), case acl:match_rule(global, Access, From) of deny -> - Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), + Lang = xmpp:get_lang(Packet), Txt = <<"Denied by ACL">>, - Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)), + Err = xmpp:make_error(Packet, xmpp:err_forbidden(Txt, Lang)), ejabberd_router:route(To, From, Err); allow -> Hosts = ?MYHOSTS, @@ -817,16 +733,16 @@ announce_all_hosts_motd_update(From, To, Packet) -> announce_motd_update(LServer, Packet) -> announce_motd_delete(LServer), Mod = gen_mod:db_mod(LServer, ?MODULE), - Mod:set_motd(LServer, Packet). + Mod:set_motd(LServer, xmpp:encode(Packet)). announce_motd_delete(From, To, Packet) -> Host = To#jid.lserver, Access = get_access(Host), case acl:match_rule(Host, Access, From) of deny -> - Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), + Lang = xmpp:get_lang(Packet), Txt = <<"Denied by ACL">>, - Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)), + Err = xmpp:make_error(Packet, xmpp:err_forbidden(Txt, Lang)), ejabberd_router:route(To, From, Err); allow -> announce_motd_delete(Host) @@ -836,9 +752,9 @@ announce_all_hosts_motd_delete(From, To, Packet) -> Access = get_access(global), case acl:match_rule(global, Access, From) of deny -> - Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), + Lang = xmpp:get_lang(Packet), Txt = <<"Denied by ACL">>, - Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)), + Err = xmpp:make_error(Packet, xmpp:err_forbidden(Txt, Lang)), ejabberd_router:route(To, From, Err); allow -> Hosts = ?MYHOSTS, @@ -853,13 +769,19 @@ send_motd(#jid{luser = LUser, lserver = LServer} = JID) when LUser /= <<>> -> Mod = gen_mod:db_mod(LServer, ?MODULE), case Mod:get_motd(LServer) of {ok, Packet} -> - case Mod:is_motd_user(LUser, LServer) of - false -> - Local = jid:make(<<>>, LServer, <<>>), - ejabberd_router:route(Local, JID, Packet), - Mod:set_motd_user(LUser, LServer); - true -> - ok + try xmpp:decode(Packet, [ignore_els]) of + Msg -> + case Mod:is_motd_user(LUser, LServer) of + false -> + Local = jid:make(LServer), + ejabberd_router:route(Local, JID, Msg), + Mod:set_motd_user(LUser, LServer); + true -> + ok + end + catch _:{xmpp_codec, Why} -> + ?ERROR_MSG("failed to decode motd packet ~p: ~s", + [Packet, xmpp:format_error(Why)]) end; error -> ok @@ -871,31 +793,24 @@ get_stored_motd(LServer) -> Mod = gen_mod:db_mod(LServer, ?MODULE), case Mod:get_motd(LServer) of {ok, Packet} -> - {fxml:get_subtag_cdata(Packet, <<"subject">>), - fxml:get_subtag_cdata(Packet, <<"body">>)}; + try xmpp:decode(Packet, [ignore_els]) of + #message{body = Body, subject = Subject} -> + {xmpp:get_text(Subject), xmpp:get_text(Body)} + catch _:{xmpp_codec, Why} -> + ?ERROR_MSG("failed to decode motd packet ~p: ~s", + [Packet, xmpp:format_error(Why)]) + end; error -> {<<>>, <<>>} end. %% This function is similar to others, but doesn't perform any ACL verification send_announcement_to_all(Host, SubjectS, BodyS) -> - SubjectEls = if SubjectS /= <<>> -> - [#xmlel{name = <<"subject">>, children = [{xmlcdata, SubjectS}]}]; - true -> - [] - end, - BodyEls = if BodyS /= <<>> -> - [#xmlel{name = <<"body">>, children = [{xmlcdata, BodyS}]}]; - true -> - [] - end, - Packet = #xmlel{ - name = <<"message">>, - attrs = [{<<"type">>, <<"headline">>}], - children = SubjectEls ++ BodyEls - }, + Packet = #message{type = headline, + body = xmpp:mk_text(BodyS), + subject = xmpp:mk_text(SubjectS)}, Sessions = ejabberd_sm:dirty_get_sessions_list(), - Local = jid:make(<<>>, Host, <<>>), + Local = jid:make(Host), lists:foreach( fun({U, S, R}) -> Dest = jid:make(U, S, R), diff --git a/src/xmpp_codec.erl b/src/xmpp_codec.erl index c59c347f9..c8a4f002f 100644 --- a/src/xmpp_codec.erl +++ b/src/xmpp_codec.erl @@ -15,6 +15,30 @@ decode(_el) -> decode(_el, []). decode({xmlel, _name, _attrs, _} = _el, Opts) -> IgnoreEls = proplists:get_bool(ignore_els, Opts), case {_name, get_attr(<<"xmlns">>, _attrs)} of + {<<"command">>, + <<"http://jabber.org/protocol/commands">>} -> + decode_adhoc_command(<<"http://jabber.org/protocol/commands">>, + IgnoreEls, _el); + {<<"note">>, + <<"http://jabber.org/protocol/commands">>} -> + decode_adhoc_command_notes(<<"http://jabber.org/protocol/commands">>, + IgnoreEls, _el); + {<<"actions">>, + <<"http://jabber.org/protocol/commands">>} -> + decode_adhoc_command_actions(<<"http://jabber.org/protocol/commands">>, + IgnoreEls, _el); + {<<"complete">>, + <<"http://jabber.org/protocol/commands">>} -> + decode_adhoc_command_complete(<<"http://jabber.org/protocol/commands">>, + IgnoreEls, _el); + {<<"next">>, + <<"http://jabber.org/protocol/commands">>} -> + decode_adhoc_command_next(<<"http://jabber.org/protocol/commands">>, + IgnoreEls, _el); + {<<"prev">>, + <<"http://jabber.org/protocol/commands">>} -> + decode_adhoc_command_prev(<<"http://jabber.org/protocol/commands">>, + IgnoreEls, _el); {<<"client-id">>, <<"urn:xmpp:sid:0">>} -> decode_client_id(<<"urn:xmpp:sid:0">>, IgnoreEls, _el); {<<"stanza-id">>, <<"urn:xmpp:sid:0">>} -> @@ -1254,6 +1278,24 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> is_known_tag({xmlel, _name, _attrs, _} = _el) -> case {_name, get_attr(<<"xmlns">>, _attrs)} of + {<<"command">>, + <<"http://jabber.org/protocol/commands">>} -> + true; + {<<"note">>, + <<"http://jabber.org/protocol/commands">>} -> + true; + {<<"actions">>, + <<"http://jabber.org/protocol/commands">>} -> + true; + {<<"complete">>, + <<"http://jabber.org/protocol/commands">>} -> + true; + {<<"next">>, + <<"http://jabber.org/protocol/commands">>} -> + true; + {<<"prev">>, + <<"http://jabber.org/protocol/commands">>} -> + true; {<<"client-id">>, <<"urn:xmpp:sid:0">>} -> true; {<<"stanza-id">>, <<"urn:xmpp:sid:0">>} -> true; {<<"addresses">>, @@ -2483,7 +2525,20 @@ encode({stanza_id, _, _} = Stanza_id) -> [{<<"xmlns">>, <<"urn:xmpp:sid:0">>}]); encode({client_id, _} = Client_id) -> encode_client_id(Client_id, - [{<<"xmlns">>, <<"urn:xmpp:sid:0">>}]). + [{<<"xmlns">>, <<"urn:xmpp:sid:0">>}]); +encode({adhoc_actions, _, _, _, _} = Actions) -> + encode_adhoc_command_actions(Actions, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/commands">>}]); +encode({adhoc_note, _, _} = Note) -> + encode_adhoc_command_notes(Note, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/commands">>}]); +encode({adhoc_command, _, _, _, _, _, _, _, _} = + Command) -> + encode_adhoc_command(Command, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/commands">>}]). get_name({last, _, _}) -> <<"query">>; get_name({version, _, _, _}) -> <<"query">>; @@ -2661,7 +2716,11 @@ get_name({nick, _}) -> <<"nick">>; get_name({address, _, _, _, _, _}) -> <<"address">>; get_name({addresses, _}) -> <<"addresses">>; get_name({stanza_id, _, _}) -> <<"stanza-id">>; -get_name({client_id, _}) -> <<"client-id">>. +get_name({client_id, _}) -> <<"client-id">>; +get_name({adhoc_actions, _, _, _, _}) -> <<"actions">>; +get_name({adhoc_note, _, _}) -> <<"note">>; +get_name({adhoc_command, _, _, _, _, _, _, _, _}) -> + <<"command">>. get_ns({last, _, _}) -> <<"jabber:iq:last">>; get_ns({version, _, _, _}) -> <<"jabber:iq:version">>; @@ -2909,7 +2968,13 @@ get_ns({address, _, _, _, _, _}) -> get_ns({addresses, _}) -> <<"http://jabber.org/protocol/address">>; get_ns({stanza_id, _, _}) -> <<"urn:xmpp:sid:0">>; -get_ns({client_id, _}) -> <<"urn:xmpp:sid:0">>. +get_ns({client_id, _}) -> <<"urn:xmpp:sid:0">>; +get_ns({adhoc_actions, _, _, _, _}) -> + <<"http://jabber.org/protocol/commands">>; +get_ns({adhoc_note, _, _}) -> + <<"http://jabber.org/protocol/commands">>; +get_ns({adhoc_command, _, _, _, _, _, _, _, _}) -> + <<"http://jabber.org/protocol/commands">>. dec_int(Val) -> dec_int(Val, infinity, infinity). @@ -3140,6 +3205,11 @@ pp(address, 5) -> [type, jid, desc, node, delivered]; pp(addresses, 1) -> [list]; pp(stanza_id, 2) -> [by, id]; pp(client_id, 1) -> [id]; +pp(adhoc_actions, 4) -> [execute, prev, next, complete]; +pp(adhoc_note, 2) -> [type, data]; +pp(adhoc_command, 8) -> + [node, action, sid, status, lang, actions, notes, + xdata]; pp(_, _) -> no. join([], _Sep) -> <<>>; @@ -3186,6 +3256,474 @@ dec_tzo(Val) -> M = jlib:binary_to_integer(M1), if H >= -12, H =< 12, M >= 0, M < 60 -> {H, M} end. +decode_adhoc_command(__TopXMLNS, __IgnoreEls, + {xmlel, <<"command">>, _attrs, _els}) -> + {Xdata, Notes, Actions} = + decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, _els, + undefined, [], undefined), + {Node, Lang, Sid, Status, Action} = + decode_adhoc_command_attrs(__TopXMLNS, _attrs, + undefined, undefined, undefined, undefined, + undefined), + {adhoc_command, Node, Action, Sid, Status, Lang, + Actions, Notes, Xdata}. + +decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, [], + Xdata, Notes, Actions) -> + {Xdata, lists:reverse(Notes), Actions}; +decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"actions">>, _attrs, _} = _el | _els], + Xdata, Notes, Actions) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/commands">> -> + decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, Notes, + decode_adhoc_command_actions(__TopXMLNS, + __IgnoreEls, + _el)); + <<"http://jabber.org/protocol/commands">> -> + decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, Notes, + decode_adhoc_command_actions(<<"http://jabber.org/protocol/commands">>, + __IgnoreEls, + _el)); + _ -> + decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, Notes, Actions) + end; +decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"x">>, _attrs, _} = _el | _els], Xdata, + Notes, Actions) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"jabber:x:data">> -> + decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, _els, + decode_xdata(<<"jabber:x:data">>, + __IgnoreEls, _el), + Notes, Actions); + _ -> + decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, Notes, Actions) + end; +decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"note">>, _attrs, _} = _el | _els], Xdata, + Notes, Actions) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/commands">> -> + decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, + [decode_adhoc_command_notes(__TopXMLNS, + __IgnoreEls, _el) + | Notes], + Actions); + <<"http://jabber.org/protocol/commands">> -> + decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, + [decode_adhoc_command_notes(<<"http://jabber.org/protocol/commands">>, + __IgnoreEls, _el) + | Notes], + Actions); + _ -> + decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, Notes, Actions) + end; +decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Xdata, Notes, Actions) -> + decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, _els, + Xdata, Notes, Actions). + +decode_adhoc_command_attrs(__TopXMLNS, + [{<<"node">>, _val} | _attrs], _Node, Lang, Sid, + Status, Action) -> + decode_adhoc_command_attrs(__TopXMLNS, _attrs, _val, + Lang, Sid, Status, Action); +decode_adhoc_command_attrs(__TopXMLNS, + [{<<"xml:lang">>, _val} | _attrs], Node, _Lang, Sid, + Status, Action) -> + decode_adhoc_command_attrs(__TopXMLNS, _attrs, Node, + _val, Sid, Status, Action); +decode_adhoc_command_attrs(__TopXMLNS, + [{<<"sessionid">>, _val} | _attrs], Node, Lang, _Sid, + Status, Action) -> + decode_adhoc_command_attrs(__TopXMLNS, _attrs, Node, + Lang, _val, Status, Action); +decode_adhoc_command_attrs(__TopXMLNS, + [{<<"status">>, _val} | _attrs], Node, Lang, Sid, + _Status, Action) -> + decode_adhoc_command_attrs(__TopXMLNS, _attrs, Node, + Lang, Sid, _val, Action); +decode_adhoc_command_attrs(__TopXMLNS, + [{<<"action">>, _val} | _attrs], Node, Lang, Sid, + Status, _Action) -> + decode_adhoc_command_attrs(__TopXMLNS, _attrs, Node, + Lang, Sid, Status, _val); +decode_adhoc_command_attrs(__TopXMLNS, [_ | _attrs], + Node, Lang, Sid, Status, Action) -> + decode_adhoc_command_attrs(__TopXMLNS, _attrs, Node, + Lang, Sid, Status, Action); +decode_adhoc_command_attrs(__TopXMLNS, [], Node, Lang, + Sid, Status, Action) -> + {decode_adhoc_command_attr_node(__TopXMLNS, Node), + 'decode_adhoc_command_attr_xml:lang'(__TopXMLNS, Lang), + decode_adhoc_command_attr_sessionid(__TopXMLNS, Sid), + decode_adhoc_command_attr_status(__TopXMLNS, Status), + decode_adhoc_command_attr_action(__TopXMLNS, Action)}. + +encode_adhoc_command({adhoc_command, Node, Action, Sid, + Status, Lang, Actions, Notes, Xdata}, + _xmlns_attrs) -> + _els = + lists:reverse('encode_adhoc_command_$xdata'(Xdata, + 'encode_adhoc_command_$notes'(Notes, + 'encode_adhoc_command_$actions'(Actions, + [])))), + _attrs = encode_adhoc_command_attr_action(Action, + encode_adhoc_command_attr_status(Status, + encode_adhoc_command_attr_sessionid(Sid, + 'encode_adhoc_command_attr_xml:lang'(Lang, + encode_adhoc_command_attr_node(Node, + _xmlns_attrs))))), + {xmlel, <<"command">>, _attrs, _els}. + +'encode_adhoc_command_$xdata'(undefined, _acc) -> _acc; +'encode_adhoc_command_$xdata'(Xdata, _acc) -> + [encode_xdata(Xdata, + [{<<"xmlns">>, <<"jabber:x:data">>}]) + | _acc]. + +'encode_adhoc_command_$notes'([], _acc) -> _acc; +'encode_adhoc_command_$notes'([Notes | _els], _acc) -> + 'encode_adhoc_command_$notes'(_els, + [encode_adhoc_command_notes(Notes, []) + | _acc]). + +'encode_adhoc_command_$actions'(undefined, _acc) -> + _acc; +'encode_adhoc_command_$actions'(Actions, _acc) -> + [encode_adhoc_command_actions(Actions, []) | _acc]. + +decode_adhoc_command_attr_node(__TopXMLNS, undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"node">>, <<"command">>, __TopXMLNS}}); +decode_adhoc_command_attr_node(__TopXMLNS, _val) -> + _val. + +encode_adhoc_command_attr_node(_val, _acc) -> + [{<<"node">>, _val} | _acc]. + +'decode_adhoc_command_attr_xml:lang'(__TopXMLNS, + undefined) -> + undefined; +'decode_adhoc_command_attr_xml:lang'(__TopXMLNS, + _val) -> + _val. + +'encode_adhoc_command_attr_xml:lang'(undefined, _acc) -> + _acc; +'encode_adhoc_command_attr_xml:lang'(_val, _acc) -> + [{<<"xml:lang">>, _val} | _acc]. + +decode_adhoc_command_attr_sessionid(__TopXMLNS, + undefined) -> + undefined; +decode_adhoc_command_attr_sessionid(__TopXMLNS, _val) -> + _val. + +encode_adhoc_command_attr_sessionid(undefined, _acc) -> + _acc; +encode_adhoc_command_attr_sessionid(_val, _acc) -> + [{<<"sessionid">>, _val} | _acc]. + +decode_adhoc_command_attr_status(__TopXMLNS, + undefined) -> + undefined; +decode_adhoc_command_attr_status(__TopXMLNS, _val) -> + case catch dec_enum(_val, + [canceled, completed, executing]) + of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"status">>, <<"command">>, + __TopXMLNS}}); + _res -> _res + end. + +encode_adhoc_command_attr_status(undefined, _acc) -> + _acc; +encode_adhoc_command_attr_status(_val, _acc) -> + [{<<"status">>, enc_enum(_val)} | _acc]. + +decode_adhoc_command_attr_action(__TopXMLNS, + undefined) -> + execute; +decode_adhoc_command_attr_action(__TopXMLNS, _val) -> + case catch dec_enum(_val, + [cancel, complete, execute, next, prev]) + of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"action">>, <<"command">>, + __TopXMLNS}}); + _res -> _res + end. + +encode_adhoc_command_attr_action(execute, _acc) -> _acc; +encode_adhoc_command_attr_action(_val, _acc) -> + [{<<"action">>, enc_enum(_val)} | _acc]. + +decode_adhoc_command_notes(__TopXMLNS, __IgnoreEls, + {xmlel, <<"note">>, _attrs, _els}) -> + Data = decode_adhoc_command_notes_els(__TopXMLNS, + __IgnoreEls, _els, <<>>), + Type = decode_adhoc_command_notes_attrs(__TopXMLNS, + _attrs, undefined), + {adhoc_note, Type, Data}. + +decode_adhoc_command_notes_els(__TopXMLNS, __IgnoreEls, + [], Data) -> + decode_adhoc_command_notes_cdata(__TopXMLNS, Data); +decode_adhoc_command_notes_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Data) -> + decode_adhoc_command_notes_els(__TopXMLNS, __IgnoreEls, + _els, <>); +decode_adhoc_command_notes_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Data) -> + decode_adhoc_command_notes_els(__TopXMLNS, __IgnoreEls, + _els, Data). + +decode_adhoc_command_notes_attrs(__TopXMLNS, + [{<<"type">>, _val} | _attrs], _Type) -> + decode_adhoc_command_notes_attrs(__TopXMLNS, _attrs, + _val); +decode_adhoc_command_notes_attrs(__TopXMLNS, + [_ | _attrs], Type) -> + decode_adhoc_command_notes_attrs(__TopXMLNS, _attrs, + Type); +decode_adhoc_command_notes_attrs(__TopXMLNS, [], + Type) -> + decode_adhoc_command_notes_attr_type(__TopXMLNS, Type). + +encode_adhoc_command_notes({adhoc_note, Type, Data}, + _xmlns_attrs) -> + _els = encode_adhoc_command_notes_cdata(Data, []), + _attrs = encode_adhoc_command_notes_attr_type(Type, + _xmlns_attrs), + {xmlel, <<"note">>, _attrs, _els}. + +decode_adhoc_command_notes_attr_type(__TopXMLNS, + undefined) -> + info; +decode_adhoc_command_notes_attr_type(__TopXMLNS, + _val) -> + case catch dec_enum(_val, [info, warn, error]) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"type">>, <<"note">>, __TopXMLNS}}); + _res -> _res + end. + +encode_adhoc_command_notes_attr_type(info, _acc) -> + _acc; +encode_adhoc_command_notes_attr_type(_val, _acc) -> + [{<<"type">>, enc_enum(_val)} | _acc]. + +decode_adhoc_command_notes_cdata(__TopXMLNS, <<>>) -> + <<>>; +decode_adhoc_command_notes_cdata(__TopXMLNS, _val) -> + _val. + +encode_adhoc_command_notes_cdata(<<>>, _acc) -> _acc; +encode_adhoc_command_notes_cdata(_val, _acc) -> + [{xmlcdata, _val} | _acc]. + +decode_adhoc_command_actions(__TopXMLNS, __IgnoreEls, + {xmlel, <<"actions">>, _attrs, _els}) -> + {Next, Complete, Prev} = + decode_adhoc_command_actions_els(__TopXMLNS, + __IgnoreEls, _els, false, false, + false), + Execute = decode_adhoc_command_actions_attrs(__TopXMLNS, + _attrs, undefined), + {adhoc_actions, Execute, Prev, Next, Complete}. + +decode_adhoc_command_actions_els(__TopXMLNS, + __IgnoreEls, [], Next, Complete, Prev) -> + {Next, Complete, Prev}; +decode_adhoc_command_actions_els(__TopXMLNS, + __IgnoreEls, + [{xmlel, <<"prev">>, _attrs, _} = _el | _els], + Next, Complete, Prev) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/commands">> -> + decode_adhoc_command_actions_els(__TopXMLNS, + __IgnoreEls, _els, Next, Complete, + decode_adhoc_command_prev(__TopXMLNS, + __IgnoreEls, + _el)); + <<"http://jabber.org/protocol/commands">> -> + decode_adhoc_command_actions_els(__TopXMLNS, + __IgnoreEls, _els, Next, Complete, + decode_adhoc_command_prev(<<"http://jabber.org/protocol/commands">>, + __IgnoreEls, + _el)); + _ -> + decode_adhoc_command_actions_els(__TopXMLNS, + __IgnoreEls, _els, Next, Complete, + Prev) + end; +decode_adhoc_command_actions_els(__TopXMLNS, + __IgnoreEls, + [{xmlel, <<"next">>, _attrs, _} = _el | _els], + Next, Complete, Prev) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/commands">> -> + decode_adhoc_command_actions_els(__TopXMLNS, + __IgnoreEls, _els, + decode_adhoc_command_next(__TopXMLNS, + __IgnoreEls, + _el), + Complete, Prev); + <<"http://jabber.org/protocol/commands">> -> + decode_adhoc_command_actions_els(__TopXMLNS, + __IgnoreEls, _els, + decode_adhoc_command_next(<<"http://jabber.org/protocol/commands">>, + __IgnoreEls, + _el), + Complete, Prev); + _ -> + decode_adhoc_command_actions_els(__TopXMLNS, + __IgnoreEls, _els, Next, Complete, + Prev) + end; +decode_adhoc_command_actions_els(__TopXMLNS, + __IgnoreEls, + [{xmlel, <<"complete">>, _attrs, _} = _el + | _els], + Next, Complete, Prev) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/commands">> -> + decode_adhoc_command_actions_els(__TopXMLNS, + __IgnoreEls, _els, Next, + decode_adhoc_command_complete(__TopXMLNS, + __IgnoreEls, + _el), + Prev); + <<"http://jabber.org/protocol/commands">> -> + decode_adhoc_command_actions_els(__TopXMLNS, + __IgnoreEls, _els, Next, + decode_adhoc_command_complete(<<"http://jabber.org/protocol/commands">>, + __IgnoreEls, + _el), + Prev); + _ -> + decode_adhoc_command_actions_els(__TopXMLNS, + __IgnoreEls, _els, Next, Complete, + Prev) + end; +decode_adhoc_command_actions_els(__TopXMLNS, + __IgnoreEls, [_ | _els], Next, Complete, + Prev) -> + decode_adhoc_command_actions_els(__TopXMLNS, + __IgnoreEls, _els, Next, Complete, Prev). + +decode_adhoc_command_actions_attrs(__TopXMLNS, + [{<<"execute">>, _val} | _attrs], + _Execute) -> + decode_adhoc_command_actions_attrs(__TopXMLNS, _attrs, + _val); +decode_adhoc_command_actions_attrs(__TopXMLNS, + [_ | _attrs], Execute) -> + decode_adhoc_command_actions_attrs(__TopXMLNS, _attrs, + Execute); +decode_adhoc_command_actions_attrs(__TopXMLNS, [], + Execute) -> + decode_adhoc_command_actions_attr_execute(__TopXMLNS, + Execute). + +encode_adhoc_command_actions({adhoc_actions, Execute, + Prev, Next, Complete}, + _xmlns_attrs) -> + _els = + lists:reverse('encode_adhoc_command_actions_$next'(Next, + 'encode_adhoc_command_actions_$complete'(Complete, + 'encode_adhoc_command_actions_$prev'(Prev, + [])))), + _attrs = + encode_adhoc_command_actions_attr_execute(Execute, + _xmlns_attrs), + {xmlel, <<"actions">>, _attrs, _els}. + +'encode_adhoc_command_actions_$next'(false, _acc) -> + _acc; +'encode_adhoc_command_actions_$next'(Next, _acc) -> + [encode_adhoc_command_next(Next, []) | _acc]. + +'encode_adhoc_command_actions_$complete'(false, _acc) -> + _acc; +'encode_adhoc_command_actions_$complete'(Complete, + _acc) -> + [encode_adhoc_command_complete(Complete, []) | _acc]. + +'encode_adhoc_command_actions_$prev'(false, _acc) -> + _acc; +'encode_adhoc_command_actions_$prev'(Prev, _acc) -> + [encode_adhoc_command_prev(Prev, []) | _acc]. + +decode_adhoc_command_actions_attr_execute(__TopXMLNS, + undefined) -> + undefined; +decode_adhoc_command_actions_attr_execute(__TopXMLNS, + _val) -> + case catch dec_enum(_val, [complete, next, prev]) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"execute">>, <<"actions">>, + __TopXMLNS}}); + _res -> _res + end. + +encode_adhoc_command_actions_attr_execute(undefined, + _acc) -> + _acc; +encode_adhoc_command_actions_attr_execute(_val, _acc) -> + [{<<"execute">>, enc_enum(_val)} | _acc]. + +decode_adhoc_command_complete(__TopXMLNS, __IgnoreEls, + {xmlel, <<"complete">>, _attrs, _els}) -> + true. + +encode_adhoc_command_complete(true, _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"complete">>, _attrs, _els}. + +decode_adhoc_command_next(__TopXMLNS, __IgnoreEls, + {xmlel, <<"next">>, _attrs, _els}) -> + true. + +encode_adhoc_command_next(true, _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"next">>, _attrs, _els}. + +decode_adhoc_command_prev(__TopXMLNS, __IgnoreEls, + {xmlel, <<"prev">>, _attrs, _els}) -> + true. + +encode_adhoc_command_prev(true, _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"prev">>, _attrs, _els}. + decode_client_id(__TopXMLNS, __IgnoreEls, {xmlel, <<"client-id">>, _attrs, _els}) -> Id = decode_client_id_attrs(__TopXMLNS, _attrs, diff --git a/src/xmpp_util.erl b/src/xmpp_util.erl index 83f1f4adc..a4f37c926 100644 --- a/src/xmpp_util.erl +++ b/src/xmpp_util.erl @@ -11,7 +11,7 @@ %% API -export([add_delay_info/3, add_delay_info/4, unwrap_carbon/1, is_standalone_chat_state/1, get_xdata_values/2, - has_xdata_var/2]). + has_xdata_var/2, make_adhoc_response/1, make_adhoc_response/2]). -include("xmpp.hrl"). @@ -88,6 +88,18 @@ get_xdata_values(Var, #xdata{fields = Fields}) -> has_xdata_var(Var, #xdata{fields = Fields}) -> lists:keymember(Var, #xdata_field.var, Fields). +-spec make_adhoc_response(adhoc_command(), adhoc_command()) -> adhoc_command(). +make_adhoc_response(#adhoc_command{lang = Lang, node = Node, sid = SID}, + Command) -> + Command#adhoc_command{lang = Lang, node = Node, sid = SID}. + +-spec make_adhoc_response(adhoc_command()) -> adhoc_command(). +make_adhoc_response(#adhoc_command{sid = undefined} = Command) -> + SID = jlib:now_to_utc_string(p1_time_compat:timestamp()), + Command#adhoc_command{sid = SID}; +make_adhoc_response(Command) -> + Command. + %%%=================================================================== %%% Internal functions %%%=================================================================== diff --git a/tools/xmpp_codec.spec b/tools/xmpp_codec.spec index fdf16ed37..0e0145f72 100644 --- a/tools/xmpp_codec.spec +++ b/tools/xmpp_codec.spec @@ -2821,6 +2821,62 @@ result = {client_id, '$id'}, attrs = [#attr{name = <<"id">>, required = true}]}). +-xml(adhoc_command_prev, + #elem{name = <<"prev">>, + xmlns = <<"http://jabber.org/protocol/commands">>, + result = true}). +-xml(adhoc_command_next, + #elem{name = <<"next">>, + xmlns = <<"http://jabber.org/protocol/commands">>, + result = true}). +-xml(adhoc_command_complete, + #elem{name = <<"complete">>, + xmlns = <<"http://jabber.org/protocol/commands">>, + result = true}). + +-xml(adhoc_command_actions, + #elem{name = <<"actions">>, + xmlns = <<"http://jabber.org/protocol/commands">>, + result = {adhoc_actions, '$execute', '$prev', '$next', '$complete'}, + attrs = [#attr{name = <<"execute">>, + dec = {dec_enum, [[complete, next, prev]]}, + enc = {enc_enum, []}}], + refs = [#ref{name = adhoc_command_prev, min = 0, max = 1, + default = false, label = '$prev'}, + #ref{name = adhoc_command_next, min = 0, max = 1, + default = false, label = '$next'}, + #ref{name = adhoc_command_complete, min = 0, max = 1, + default = false, label = '$complete'}]}). + +-xml(adhoc_command_notes, + #elem{name = <<"note">>, + xmlns = <<"http://jabber.org/protocol/commands">>, + result = {adhoc_note, '$type', '$data'}, + attrs = [#attr{name = <<"type">>, default = info, + dec = {dec_enum, [[info, warn, error]]}, + enc = {enc_enum, []}}], + cdata = #cdata{default = <<"">>, label = '$data'}}). + +-xml(adhoc_command, + #elem{name = <<"command">>, + xmlns = <<"http://jabber.org/protocol/commands">>, + result = {adhoc_command, '$node', '$action', '$sid', + '$status', '$lang', '$actions', '$notes', '$xdata'}, + attrs = [#attr{name = <<"node">>, required = true}, + #attr{name = <<"xml:lang">>, label = '$lang'}, + #attr{name = <<"sessionid">>, label = '$sid'}, + #attr{name = <<"status">>, + dec = {dec_enum, [[canceled, completed, executing]]}, + enc = {enc_enum, []}}, + #attr{name = <<"action">>, default = execute, + dec = {dec_enum, [[cancel, complete, + execute, next, prev]]}, + enc = {enc_enum, []}}], + refs = [#ref{name = adhoc_command_actions, min = 0, max = 1, + label = '$actions'}, + #ref{name = xdata, min = 0, max = 1}, + #ref{name = adhoc_command_notes, label = '$notes'}]}). + dec_tzo(Val) -> [H1, M1] = str:tokens(Val, <<":">>), H = jlib:binary_to_integer(H1), From c26d38a8937d46837fbdcf047abbf249f6d95a56 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Tue, 26 Jul 2016 10:01:59 +0300 Subject: [PATCH 007/151] Remove jlib dependency from acl.erl --- src/acl.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/acl.erl b/src/acl.erl index 31a7547dd..7519e12e2 100644 --- a/src/acl.erl +++ b/src/acl.erl @@ -39,7 +39,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("jid.hrl"). -record(acl, {aclname, aclspec}). -record(access, {name :: aclname(), @@ -531,7 +531,7 @@ parse_ip_netmask(S) -> _ -> error end; [IPStr, MaskStr] -> - case catch jlib:binary_to_integer(MaskStr) of + case catch binary_to_integer(MaskStr) of Mask when is_integer(Mask), Mask >= 0 -> case inet_parse:address(binary_to_list(IPStr)) of {ok, {_, _, _, _} = IP} when Mask =< 32 -> From 23858469b7804739fa280aeb77fc7f41c1d0538e Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Tue, 26 Jul 2016 11:29:17 +0300 Subject: [PATCH 008/151] Get rid of "jlib.hrl" dependency in some files --- include/mod_privacy.hrl | 2 +- include/mod_roster.hrl | 6 +++--- src/cyrsasl.erl | 24 ------------------------ src/cyrsasl_scram.erl | 2 -- src/ejabberd_auth_anonymous.erl | 3 +-- src/ejabberd_oauth.erl | 2 +- src/ejabberd_sm.erl | 1 - src/ejabberd_sm_mnesia.erl | 1 - src/ejabberd_sm_redis.erl | 1 - src/ejabberd_sm_sql.erl | 1 - src/ejabberd_socket.erl | 3 +-- src/jid.erl | 1 + src/mod_announce_mnesia.erl | 2 +- src/mod_announce_riak.erl | 2 +- src/mod_announce_sql.erl | 2 +- src/mod_blocking_mnesia.erl | 1 - src/mod_blocking_riak.erl | 1 - src/mod_blocking_sql.erl | 1 - src/mod_muc_sql.erl | 2 +- src/mod_offline_mnesia.erl | 2 +- src/mod_offline_riak.erl | 2 +- src/mod_offline_sql.erl | 2 +- src/mod_privacy_mnesia.erl | 2 +- src/mod_privacy_riak.erl | 2 +- src/mod_privacy_sql.erl | 2 +- src/mod_private_mnesia.erl | 2 +- src/mod_private_riak.erl | 2 +- src/mod_private_sql.erl | 2 +- src/mod_roster_mnesia.erl | 1 - src/mod_roster_riak.erl | 1 - src/mod_roster_sql.erl | 1 - src/mod_vcard_mnesia.erl | 2 +- src/mod_vcard_riak.erl | 2 +- src/mod_vcard_sql.erl | 2 +- src/prosody2ejabberd.erl | 2 +- 35 files changed, 25 insertions(+), 62 deletions(-) diff --git a/include/mod_privacy.hrl b/include/mod_privacy.hrl index 0d263d659..dbd19a081 100644 --- a/include/mod_privacy.hrl +++ b/include/mod_privacy.hrl @@ -36,7 +36,7 @@ -type listitem() :: #listitem{}. -type listitem_type() :: none | jid | group | subscription. --type listitem_value() :: none | both | from | to | ljid() | binary(). +-type listitem_value() :: none | both | from | to | jid:ljid() | binary(). -type listitem_action() :: allow | deny. -record(userlist, {name = none :: none | binary(), diff --git a/include/mod_roster.hrl b/include/mod_roster.hrl index b05114e3e..818508703 100644 --- a/include/mod_roster.hrl +++ b/include/mod_roster.hrl @@ -20,15 +20,15 @@ -record(roster, { - usj = {<<>>, <<>>, {<<>>, <<>>, <<>>}} :: {binary(), binary(), ljid()} | '_', + usj = {<<>>, <<>>, {<<>>, <<>>, <<>>}} :: {binary(), binary(), jid:ljid()} | '_', us = {<<>>, <<>>} :: {binary(), binary()} | '_', - jid = {<<>>, <<>>, <<>>} :: ljid(), + jid = {<<>>, <<>>, <<>>} :: jid:ljid(), name = <<>> :: binary() | '_', subscription = none :: subscription() | '_', ask = none :: ask() | '_', groups = [] :: [binary()] | '_', askmessage = <<"">> :: binary() | '_', - xs = [] :: [xmlel()] | '_' + xs = [] :: [fxml:xmlel()] | '_' }). -record(roster_version, diff --git a/src/cyrsasl.erl b/src/cyrsasl.erl index 46b23384e..4b0f5a26b 100644 --- a/src/cyrsasl.erl +++ b/src/cyrsasl.erl @@ -102,30 +102,6 @@ register_mechanism(Mechanism, Module, PasswordType) -> true end. -%%% TODO: use callbacks -%%-include("ejabberd.hrl"). -%%-include("jlib.hrl"). -%%check_authzid(_State, Props) -> -%% AuthzId = fxml:get_attr_s(authzid, Props), -%% case jid:from_string(AuthzId) of -%% error -> -%% {error, "invalid-authzid"}; -%% JID -> -%% LUser = jid:nodeprep(fxml:get_attr_s(username, Props)), -%% {U, S, R} = jid:tolower(JID), -%% case R of -%% "" -> -%% {error, "invalid-authzid"}; -%% _ -> -%% case {LUser, ?MYNAME} of -%% {U, S} -> -%% ok; -%% _ -> -%% {error, "invalid-authzid"} -%% end -%% end -%% end. - check_credentials(_State, Props) -> User = proplists:get_value(authzid, Props, <<>>), case jid:nodeprep(User) of diff --git a/src/cyrsasl_scram.erl b/src/cyrsasl_scram.erl index 8643a8924..fdc40cd86 100644 --- a/src/cyrsasl_scram.erl +++ b/src/cyrsasl_scram.erl @@ -34,8 +34,6 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). - -behaviour(cyrsasl). -record(state, diff --git a/src/ejabberd_auth_anonymous.erl b/src/ejabberd_auth_anonymous.erl index 5a5b395bf..c0ad1fb21 100644 --- a/src/ejabberd_auth_anonymous.erl +++ b/src/ejabberd_auth_anonymous.erl @@ -50,8 +50,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). - --include("jlib.hrl"). +-include("jid.hrl"). %% Create the anonymous table if at least one virtual host has anonymous features enabled %% Register to login / logout events diff --git a/src/ejabberd_oauth.erl b/src/ejabberd_oauth.erl index 57c1baab2..4e9dc8d08 100644 --- a/src/ejabberd_oauth.erl +++ b/src/ejabberd_oauth.erl @@ -50,7 +50,7 @@ -export([oauth_issue_token/1, oauth_list_tokens/0, oauth_revoke_token/1, oauth_list_scopes/0]). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("ejabberd.hrl"). -include("logger.hrl"). diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index ec9ef43c6..bc550ef44 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -78,7 +78,6 @@ -include("ejabberd.hrl"). -include("logger.hrl"). -%%-include("jlib.hrl"). -include("xmpp.hrl"). -include("ejabberd_commands.hrl"). diff --git a/src/ejabberd_sm_mnesia.erl b/src/ejabberd_sm_mnesia.erl index b900da315..491872aee 100644 --- a/src/ejabberd_sm_mnesia.erl +++ b/src/ejabberd_sm_mnesia.erl @@ -26,7 +26,6 @@ -include("ejabberd.hrl"). -include("ejabberd_sm.hrl"). --include("jlib.hrl"). -include_lib("stdlib/include/ms_transform.hrl"). -record(state, {}). diff --git a/src/ejabberd_sm_redis.erl b/src/ejabberd_sm_redis.erl index d25f777e3..9c78acaf7 100644 --- a/src/ejabberd_sm_redis.erl +++ b/src/ejabberd_sm_redis.erl @@ -19,7 +19,6 @@ -include("ejabberd.hrl"). -include("ejabberd_sm.hrl"). -include("logger.hrl"). --include("jlib.hrl"). %%%=================================================================== %%% API diff --git a/src/ejabberd_sm_sql.erl b/src/ejabberd_sm_sql.erl index 8871bbca4..28796aca0 100644 --- a/src/ejabberd_sm_sql.erl +++ b/src/ejabberd_sm_sql.erl @@ -24,7 +24,6 @@ -include("ejabberd.hrl"). -include("ejabberd_sm.hrl"). -include("logger.hrl"). --include("jlib.hrl"). -include("ejabberd_sql_pt.hrl"). %%%=================================================================== diff --git a/src/ejabberd_socket.erl b/src/ejabberd_socket.erl index aa916867a..7160025e7 100644 --- a/src/ejabberd_socket.erl +++ b/src/ejabberd_socket.erl @@ -49,7 +49,6 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). -type sockmod() :: ejabberd_http_bind | ejabberd_http_ws | @@ -189,7 +188,7 @@ send(SocketData, Data) -> %% Can only be called when in c2s StateData#state.xml_socket is true %% This function is used for HTTP bind %% sockmod=ejabberd_http_ws|ejabberd_http_bind or any custom module --spec send_xml(socket_state(), xmlel()) -> any(). +-spec send_xml(socket_state(), fxml:xmlel()) -> any(). send_xml(SocketData, Data) -> catch diff --git a/src/jid.erl b/src/jid.erl index d81cbcefd..9e8ea9d23 100644 --- a/src/jid.erl +++ b/src/jid.erl @@ -44,6 +44,7 @@ -include("jid.hrl"). -export_type([jid/0]). +-export_type([ljid/0]). %%%=================================================================== %%% API diff --git a/src/mod_announce_mnesia.erl b/src/mod_announce_mnesia.erl index c43eb853b..b5a1f590e 100644 --- a/src/mod_announce_mnesia.erl +++ b/src/mod_announce_mnesia.erl @@ -13,7 +13,7 @@ -export([init/2, set_motd_users/2, set_motd/2, delete_motd/1, get_motd/1, is_motd_user/2, set_motd_user/2, import/2]). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_announce.hrl"). -include("logger.hrl"). diff --git a/src/mod_announce_riak.erl b/src/mod_announce_riak.erl index 7ced0b3ce..879eb196d 100644 --- a/src/mod_announce_riak.erl +++ b/src/mod_announce_riak.erl @@ -13,7 +13,7 @@ -export([init/2, set_motd_users/2, set_motd/2, delete_motd/1, get_motd/1, is_motd_user/2, set_motd_user/2, import/2]). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_announce.hrl"). %%%=================================================================== diff --git a/src/mod_announce_sql.erl b/src/mod_announce_sql.erl index 762c97ad6..37b4412d3 100644 --- a/src/mod_announce_sql.erl +++ b/src/mod_announce_sql.erl @@ -16,7 +16,7 @@ get_motd/1, is_motd_user/2, set_motd_user/2, import/1, import/2, export/1]). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_announce.hrl"). -include("ejabberd_sql_pt.hrl"). diff --git a/src/mod_blocking_mnesia.erl b/src/mod_blocking_mnesia.erl index 5a4bde64c..b64202717 100644 --- a/src/mod_blocking_mnesia.erl +++ b/src/mod_blocking_mnesia.erl @@ -14,7 +14,6 @@ -export([process_blocklist_block/3, unblock_by_filter/3, process_blocklist_get/2]). --include("jlib.hrl"). -include("mod_privacy.hrl"). %%%=================================================================== diff --git a/src/mod_blocking_riak.erl b/src/mod_blocking_riak.erl index 5dd5cfa92..1f15591ef 100644 --- a/src/mod_blocking_riak.erl +++ b/src/mod_blocking_riak.erl @@ -14,7 +14,6 @@ -export([process_blocklist_block/3, unblock_by_filter/3, process_blocklist_get/2]). --include("jlib.hrl"). -include("mod_privacy.hrl"). %%%=================================================================== diff --git a/src/mod_blocking_sql.erl b/src/mod_blocking_sql.erl index bffe5bd25..402d6de19 100644 --- a/src/mod_blocking_sql.erl +++ b/src/mod_blocking_sql.erl @@ -14,7 +14,6 @@ -export([process_blocklist_block/3, unblock_by_filter/3, process_blocklist_get/2]). --include("jlib.hrl"). -include("mod_privacy.hrl"). %%%=================================================================== diff --git a/src/mod_muc_sql.erl b/src/mod_muc_sql.erl index ff7ec1ebb..3139b5316 100644 --- a/src/mod_muc_sql.erl +++ b/src/mod_muc_sql.erl @@ -17,7 +17,7 @@ can_use_nick/4, get_rooms/2, get_nick/3, set_nick/4, import/1, import/2, export/1]). --include("jlib.hrl"). +-include("jid.hrl"). -include("mod_muc.hrl"). -include("logger.hrl"). -include("ejabberd_sql_pt.hrl"). diff --git a/src/mod_offline_mnesia.erl b/src/mod_offline_mnesia.erl index 6a1d9e309..e8db08ddf 100644 --- a/src/mod_offline_mnesia.erl +++ b/src/mod_offline_mnesia.erl @@ -15,7 +15,7 @@ read_message/3, remove_message/3, read_all_messages/2, remove_all_messages/2, count_messages/2, import/2]). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_offline.hrl"). -include("logger.hrl"). diff --git a/src/mod_offline_riak.erl b/src/mod_offline_riak.erl index 217e8f828..647f71dfd 100644 --- a/src/mod_offline_riak.erl +++ b/src/mod_offline_riak.erl @@ -15,7 +15,7 @@ read_message/3, remove_message/3, read_all_messages/2, remove_all_messages/2, count_messages/2, import/2]). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_offline.hrl"). %%%=================================================================== diff --git a/src/mod_offline_sql.erl b/src/mod_offline_sql.erl index feefd3dd0..b5033c710 100644 --- a/src/mod_offline_sql.erl +++ b/src/mod_offline_sql.erl @@ -18,7 +18,7 @@ remove_all_messages/2, count_messages/2, import/1, import/2, export/1]). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_offline.hrl"). -include("logger.hrl"). -include("ejabberd_sql_pt.hrl"). diff --git a/src/mod_privacy_mnesia.erl b/src/mod_privacy_mnesia.erl index 1a9172b5a..4642ba58e 100644 --- a/src/mod_privacy_mnesia.erl +++ b/src/mod_privacy_mnesia.erl @@ -17,7 +17,7 @@ set_privacy_list/4, get_user_list/2, get_user_lists/2, remove_user/2, import/2]). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_privacy.hrl"). -include("logger.hrl"). diff --git a/src/mod_privacy_riak.erl b/src/mod_privacy_riak.erl index 40e92005c..509ff5ebb 100644 --- a/src/mod_privacy_riak.erl +++ b/src/mod_privacy_riak.erl @@ -19,7 +19,7 @@ -export([privacy_schema/0]). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_privacy.hrl"). %%%=================================================================== diff --git a/src/mod_privacy_sql.erl b/src/mod_privacy_sql.erl index 66926f236..a1f743657 100644 --- a/src/mod_privacy_sql.erl +++ b/src/mod_privacy_sql.erl @@ -28,7 +28,7 @@ sql_get_privacy_list_id_t/2, sql_set_default_privacy_list/2, sql_set_privacy_list/2]). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_privacy.hrl"). -include("logger.hrl"). -include("ejabberd_sql_pt.hrl"). diff --git a/src/mod_private_mnesia.erl b/src/mod_private_mnesia.erl index 7a852c4f8..d1bf20c85 100644 --- a/src/mod_private_mnesia.erl +++ b/src/mod_private_mnesia.erl @@ -13,7 +13,7 @@ -export([init/2, set_data/3, get_data/3, get_all_data/2, remove_user/2, import/2]). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_private.hrl"). -include("logger.hrl"). diff --git a/src/mod_private_riak.erl b/src/mod_private_riak.erl index 11cfa4770..b05e7d725 100644 --- a/src/mod_private_riak.erl +++ b/src/mod_private_riak.erl @@ -14,7 +14,7 @@ -export([init/2, set_data/3, get_data/3, get_all_data/2, remove_user/2, import/2]). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_private.hrl"). %%%=================================================================== diff --git a/src/mod_private_sql.erl b/src/mod_private_sql.erl index 0e9d1b61e..eb113d923 100644 --- a/src/mod_private_sql.erl +++ b/src/mod_private_sql.erl @@ -14,7 +14,7 @@ -export([init/2, set_data/3, get_data/3, get_all_data/2, remove_user/2, import/1, import/2, export/1]). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_private.hrl"). %%%=================================================================== diff --git a/src/mod_roster_mnesia.erl b/src/mod_roster_mnesia.erl index ddfa34d68..398f105d5 100644 --- a/src/mod_roster_mnesia.erl +++ b/src/mod_roster_mnesia.erl @@ -17,7 +17,6 @@ remove_user/2, update_roster/4, del_roster/3, transaction/2, read_subscription_and_groups/3, import/2]). --include("jlib.hrl"). -include("mod_roster.hrl"). -include("logger.hrl"). diff --git a/src/mod_roster_riak.erl b/src/mod_roster_riak.erl index 38e873827..9ed5e7927 100644 --- a/src/mod_roster_riak.erl +++ b/src/mod_roster_riak.erl @@ -18,7 +18,6 @@ remove_user/2, update_roster/4, del_roster/3, transaction/2, read_subscription_and_groups/3, get_only_items/2, import/2]). --include("jlib.hrl"). -include("mod_roster.hrl"). %%%=================================================================== diff --git a/src/mod_roster_sql.erl b/src/mod_roster_sql.erl index 61f59a990..4d97aead0 100644 --- a/src/mod_roster_sql.erl +++ b/src/mod_roster_sql.erl @@ -20,7 +20,6 @@ read_subscription_and_groups/3, get_only_items/2, import/1, import/2, export/1]). --include("jlib.hrl"). -include("mod_roster.hrl"). -include("ejabberd_sql_pt.hrl"). diff --git a/src/mod_vcard_mnesia.erl b/src/mod_vcard_mnesia.erl index 781a135c8..67abed09b 100644 --- a/src/mod_vcard_mnesia.erl +++ b/src/mod_vcard_mnesia.erl @@ -14,7 +14,7 @@ -export([init/2, import/2, get_vcard/2, set_vcard/4, search/4, remove_user/2]). -include("ejabberd.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_vcard.hrl"). -include("logger.hrl"). diff --git a/src/mod_vcard_riak.erl b/src/mod_vcard_riak.erl index 386347387..397008a79 100644 --- a/src/mod_vcard_riak.erl +++ b/src/mod_vcard_riak.erl @@ -14,7 +14,7 @@ -export([init/2, get_vcard/2, set_vcard/4, search/4, remove_user/2, import/2]). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_vcard.hrl"). %%%=================================================================== diff --git a/src/mod_vcard_sql.erl b/src/mod_vcard_sql.erl index b8234bf9c..f448d0776 100644 --- a/src/mod_vcard_sql.erl +++ b/src/mod_vcard_sql.erl @@ -16,7 +16,7 @@ -export([init/2, get_vcard/2, set_vcard/4, search/4, remove_user/2, import/1, import/2, export/1]). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_vcard.hrl"). -include("logger.hrl"). -include("ejabberd_sql_pt.hrl"). diff --git a/src/prosody2ejabberd.erl b/src/prosody2ejabberd.erl index 204cfec2f..d5eca5ecb 100644 --- a/src/prosody2ejabberd.erl +++ b/src/prosody2ejabberd.erl @@ -12,7 +12,7 @@ -export([from_dir/1]). -include("ejabberd.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("logger.hrl"). -include("mod_roster.hrl"). -include("mod_offline.hrl"). From c409ed2f2c09ae79a22745e2a253023787017893 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Wed, 27 Jul 2016 10:45:08 +0300 Subject: [PATCH 009/151] Rewrite S2S and ejabberd_service code to use XML generator --- include/ejabberd.hrl | 2 +- include/ns.hrl | 4 + include/xmpp_codec.hrl | 38 +- src/ejabberd_c2s.erl | 191 ++++---- src/ejabberd_http_bind.erl | 2 - src/ejabberd_router.erl | 21 +- src/ejabberd_s2s.erl | 46 +- src/ejabberd_s2s_in.erl | 653 +++++++++++++------------- src/ejabberd_s2s_out.erl | 922 +++++++++++++++---------------------- src/ejabberd_service.erl | 379 +++++++-------- src/xmpp.erl | 13 +- src/xmpp_codec.erl | 531 ++++++++++++++++++++- tools/xmpp_codec.spec | 60 +++ 13 files changed, 1598 insertions(+), 1264 deletions(-) diff --git a/include/ejabberd.hrl b/include/ejabberd.hrl index 6316d7813..a97474d2b 100644 --- a/include/ejabberd.hrl +++ b/include/ejabberd.hrl @@ -39,7 +39,7 @@ -define(EJABBERD_URI, <<"http://www.process-one.net/en/ejabberd/">>). --define(S2STIMEOUT, 600000). +-define(S2STIMEOUT, timer:minutes(10)). %%-define(DBGFSM, true). diff --git a/include/ns.hrl b/include/ns.hrl index a150746e7..b30161565 100644 --- a/include/ns.hrl +++ b/include/ns.hrl @@ -18,6 +18,10 @@ %%% %%%---------------------------------------------------------------------- +-define(NS_COMPONENT, <<"jabber:component:accept">>). +-define(NS_SERVER, <<"jabber:server">>). +-define(NS_SERVER_DIALBACK, <<"jabber:server:dialback">>). +-define(NS_CLIENT, <<"jabber:client">>). -define(NS_DISCO_ITEMS, <<"http://jabber.org/protocol/disco#items">>). -define(NS_DISCO_INFO, diff --git a/include/xmpp_codec.hrl b/include/xmpp_codec.hrl index b14c0d11f..43bb6b098 100644 --- a/include/xmpp_codec.hrl +++ b/include/xmpp_codec.hrl @@ -104,6 +104,16 @@ xmlns :: binary()}). -type sm_a() :: #sm_a{}. +-record(stream_start, {from :: any(), + to :: any(), + id = <<>> :: binary(), + version = <<>> :: binary(), + xmlns :: binary(), + stream_xmlns = <<>> :: binary(), + db_xmlns = <<>> :: binary(), + lang = <<>> :: binary()}). +-type stream_start() :: #stream_start{}. + -record(muc_subscribe, {nick :: binary(), events = [] :: [binary()]}). -type muc_subscribe() :: #muc_subscribe{}. @@ -138,6 +148,9 @@ -record(sasl_challenge, {text :: any()}). -type sasl_challenge() :: #sasl_challenge{}. +-record(handshake, {data = <<>> :: binary()}). +-type handshake() :: #handshake{}. + -record(gone, {uri :: binary()}). -type gone() :: #gone{}. @@ -672,6 +685,21 @@ text :: #text{}}). -type error() :: #error{}. +-record(db_verify, {from :: any(), + to :: any(), + id :: binary(), + type :: 'error' | 'invalid' | 'valid', + key = <<>> :: binary(), + error :: #error{}}). +-type db_verify() :: #db_verify{}. + +-record(db_result, {from :: any(), + to :: any(), + type :: 'error' | 'invalid' | 'valid', + key = <<>> :: binary(), + error :: #error{}}). +-type db_result() :: #db_result{}. + -record(presence, {id :: binary(), type = available :: 'available' | 'error' | 'probe' | 'subscribe' | 'subscribed' | 'unavailable' | 'unsubscribe' | 'unsubscribed', lang :: binary(), @@ -772,12 +800,12 @@ utc :: any()}). -type time() :: #time{}. --type xmpp_element() :: compression() | +-type xmpp_element() :: muc_admin() | + compression() | pubsub_subscription() | xdata_option() | version() | pubsub_affiliation() | - muc_admin() | mam_fin() | sm_a() | carbons_sent() | @@ -790,8 +818,10 @@ compressed() | block_list() | rsm_set() | + db_result() | 'see-other-host'() | hint() | + stream_start() | stanza_id() | starttls_proceed() | client_id() | @@ -831,6 +861,7 @@ pubsub() | muc_owner() | muc_actor() | + vcard_name() | adhoc_note() | rosterver_feature() | muc_invite() | @@ -842,12 +873,12 @@ sm_enable() | starttls_failure() | sasl_challenge() | + handshake() | x_conference() | private() | compress_failure() | sasl_failure() | bookmark_storage() | - vcard_name() | muc_decline() | sasl_auth() | p1_push() | @@ -891,6 +922,7 @@ csi() | roster_query() | mam_query() | + db_verify() | bookmark_url() | vcard_email() | vcard_label() | diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 8d217a354..1ae9a7c29 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -320,42 +320,46 @@ get_subscribed(FsmRef) -> (?GEN_FSM):sync_send_all_state_event(FsmRef, get_subscribed, 1000). -wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> - DefaultLang = ?MYLANG, - case fxml:get_attr_s(<<"xmlns:stream">>, Attrs) of - ?NS_STREAM -> - Server = - case StateData#state.server of - <<"">> -> - jid:nameprep(fxml:get_attr_s(<<"to">>, Attrs)); - S -> S - end, - Lang = case fxml:get_attr_s(<<"xml:lang">>, Attrs) of - Lang1 when byte_size(Lang1) =< 35 -> - %% As stated in BCP47, 4.4.1: - %% Protocols or specifications that - %% specify limited buffer sizes for - %% language tags MUST allow for - %% language tags of at least 35 characters. - Lang1; - _ -> - %% Do not store long language tag to - %% avoid possible DoS/flood attacks - <<"">> - end, - StreamVersion = case fxml:get_attr_s(<<"version">>, Attrs) of - <<"1.0">> -> - <<"1.0">>; - _ -> - <<"">> - end, +wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) -> + try xmpp:decode(#xmlel{name = Name, attrs = Attrs}) of + #stream_start{xmlns = NS_CLIENT, stream_xmlns = NS_STREAM, lang = Lang} + when NS_CLIENT /= ?NS_CLIENT; NS_STREAM /= ?NS_STREAM -> + send_header(StateData, ?MYNAME, <<"">>, Lang), + send_element(StateData, xmpp:serr_invalid_namespace()), + {stop, normal, StateData}; + #stream_start{lang = Lang} when byte_size(Lang) > 35 -> + %% As stated in BCP47, 4.4.1: + %% Protocols or specifications that specify limited buffer sizes for + %% language tags MUST allow for language tags of at least 35 characters. + %% Do not store long language tag to avoid possible DoS/flood attacks + send_header(StateData, ?MYNAME, <<"">>, ?MYLANG), + Txt = <<"Too long value of 'xml:lang' attribute">>, + send_element(StateData, + xmpp:serr_policy_violation(Txt, ?MYLANG)), + {stop, normal, StateData}; + #stream_start{to = undefined, lang = Lang} -> + Txt = <<"Missing 'to' attribute">>, + send_header(StateData, ?MYNAME, <<"">>, Lang), + send_element(StateData, + xmpp:serr_improper_addressing(Txt, Lang)), + {stop, normal, StateData}; + #stream_start{to = #jid{lserver = To}, lang = Lang, + version = Version} -> + Server = case StateData#state.server of + <<"">> -> To; + S -> S + end, + StreamVersion = case Version of + <<"1.0">> -> <<"1.0">>; + _ -> <<"">> + end, IsBlacklistedIP = is_ip_blacklisted(StateData#state.ip, Lang), case lists:member(Server, ?MYHOSTS) of true when IsBlacklistedIP == false -> change_shaper(StateData, jid:make(<<"">>, Server, <<"">>)), case StreamVersion of <<"1.0">> -> - send_header(StateData, Server, <<"1.0">>, DefaultLang), + send_header(StateData, Server, <<"1.0">>, ?MYLANG), case StateData#state.authenticated of false -> TLS = StateData#state.tls, @@ -458,7 +462,7 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> end end; _ -> - send_header(StateData, Server, <<"">>, DefaultLang), + send_header(StateData, Server, <<"">>, ?MYLANG), if not StateData#state.tls_enabled and StateData#state.tls_required -> send_element( @@ -477,17 +481,18 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> {true, LogReason, ReasonT} = IsBlacklistedIP, ?INFO_MSG("Connection attempt from blacklisted IP ~s: ~s", [jlib:ip_to_list(IP), LogReason]), - send_header(StateData, Server, StreamVersion, DefaultLang), + send_header(StateData, Server, StreamVersion, ?MYLANG), send_element(StateData, xmpp:serr_policy_violation(ReasonT, Lang)), {stop, normal, StateData}; _ -> - send_header(StateData, ?MYNAME, StreamVersion, DefaultLang), + send_header(StateData, ?MYNAME, StreamVersion, ?MYLANG), send_element(StateData, xmpp:serr_host_unknown()), {stop, normal, StateData} - end; - _ -> - send_header(StateData, ?MYNAME, <<"">>, DefaultLang), - send_element(StateData, xmpp:serr_invalid_namespace()), + end + catch _:{xmpp_codec, Why} -> + Txt = xmpp:format_error(Why), + send_header(StateData, ?MYNAME, <<"">>, ?MYLANG), + send_element(StateData, xmpp:serr_not_well_formed(Txt, ?MYLANG)), {stop, normal, StateData} end; wait_for_stream(timeout, StateData) -> @@ -854,38 +859,36 @@ resource_conflict_action(U, S, R) -> {accept_resource, Rnew} end. --spec decode_subels(stanza()) -> stanza(). -decode_subels(#iq{sub_els = [El], type = T} = IQ) when T == set; T == get -> - NewEl = case xmpp:get_ns(El) of - ?NS_BIND when T == set -> xmpp:decode(El); - ?NS_AUTH -> xmpp:decode(El); - ?NS_PRIVACY -> xmpp:decode(El); - ?NS_BLOCKING -> xmpp:decode(El); - _ -> El - end, - IQ#iq{sub_els = [NewEl]}; -decode_subels(Pkt) -> - Pkt. - --spec decode_element(xmlel(), state_name(), state()) -> fsm_next(). +-spec decode_element(xmlel(), state_name(), state()) -> fsm_transition(). decode_element(#xmlel{} = El, StateName, StateData) -> - try - Pkt0 = xmpp:decode(El, [ignore_els]), - Pkt = decode_subels(Pkt0), - ?MODULE:StateName(Pkt, StateData) + try case xmpp:decode(El, [ignore_els]) of + #iq{sub_els = [_], type = T} = Pkt when T == set; T == get -> + NewPkt = xmpp:decode_els( + Pkt, + fun(SubEl) when StateName == session_established -> + case xmpp:get_ns(SubEl) of + ?NS_PRIVACY -> true; + ?NS_BLOCKING -> true; + _ -> false + end; + (SubEl) -> + xmpp_codec:is_known_tag(SubEl) + end), + ?MODULE:StateName(NewPkt, StateData); + Pkt -> + ?MODULE:StateName(Pkt, StateData) + end catch error:{xmpp_codec, Why} -> - Type = xmpp:get_type(El), NS = xmpp:get_ns(El), case xmpp:is_stanza(El) of - true when Type /= <<"result">>, Type /= <<"error">> -> + true -> Lang = xmpp:get_lang(El), Txt = xmpp:format_error(Why), - Err = xmpp:make_error(El, xmpp:err_bad_request(Txt, Lang)), - send_element(StateData, Err); - _ when NS == ?NS_STREAM_MGMT_2; NS == ?NS_STREAM_MGMT_3 -> + send_error(StateData, El, xmpp:err_bad_request(Txt, Lang)); + false when NS == ?NS_STREAM_MGMT_2; NS == ?NS_STREAM_MGMT_3 -> Err = #sm_failed{reason = 'bad-request', xmlns = NS}, send_element(StateData, Err); - _ -> + false -> ok end, fsm_next_state(StateName, StateData) @@ -951,13 +954,7 @@ wait_for_bind(stop, StateData) -> wait_for_bind(Pkt, StateData) -> case xmpp:is_stanza(Pkt) of true -> - Type = xmpp:get_type(Pkt), - if Type /= error, Type /= result -> - Err = xmpp:make_error(Pkt, xmpp:err_not_acceptable()), - send_element(StateData, Err); - true -> - ok - end; + send_error(StateData, Pkt, xmpp:err_not_acceptable()); false -> ok end, @@ -1046,7 +1043,7 @@ session_established(closed, StateData) -> {stop, normal, StateData}; session_established(stop, StateData) -> {stop, normal, StateData}; -session_established(Pkt, StateData) -> +session_established(Pkt, StateData) when ?is_stanza(Pkt) -> FromJID = StateData#state.jid, case check_from(Pkt, FromJID) of 'invalid-from' -> @@ -1055,11 +1052,13 @@ session_established(Pkt, StateData) -> _ -> NewStateData = update_num_stanzas_in(StateData, Pkt), session_established2(Pkt, NewStateData) - end. + end; +session_established(_Pkt, StateData) -> + fsm_next_state(session_established, StateData). -spec session_established2(xmpp_element(), state()) -> fsm_next(). %% Process packets sent by user (coming from user on c2s XMPP connection) -session_established2(Pkt, StateData) when ?is_stanza(Pkt) -> +session_established2(Pkt, StateData) -> User = StateData#state.user, Server = StateData#state.server, FromJID = StateData#state.jid, @@ -1116,11 +1115,7 @@ session_established2(Pkt, StateData) when ?is_stanza(Pkt) -> end, ejabberd_hooks:run(c2s_loop_debug, [{xmlstreamelement, Pkt}]), - fsm_next_state(session_established, NewState); -session_established2(Pkt, StateData) -> - ejabberd_hooks:run(c2s_loop_debug, - [{xmlstreamelement, Pkt}]), - fsm_next_state(session_established, StateData). + fsm_next_state(session_established, NewState). wait_for_resume({xmlstreamelement, _El} = Event, StateData) -> Result = session_established(Event, StateData), @@ -1573,6 +1568,16 @@ send_element(StateData, #xmlel{} = El) -> send_element(StateData, Pkt) -> send_element(StateData, xmpp:encode(Pkt)). +-spec send_error(state(), xmlel() | stanza(), error()) -> ok. +send_error(StateData, Stanza, Error) -> + Type = xmpp:get_type(Stanza), + if Type == error; Type == result; + Type == <<"error">>; Type == <<"result">> -> + ok; + true -> + send_element(StateData, xmpp:make_error(Stanza, Error)) + end. + -spec send_stanza(state(), xmpp_element()) -> state(). send_stanza(StateData, Stanza) when StateData#state.csi_state == inactive -> csi_filter_stanza(StateData, Stanza); @@ -2136,28 +2141,24 @@ is_ip_blacklisted({IP, _Port}, Lang) -> %% Check from attributes %% returns invalid-from|NewElement +-spec check_from(stanza(), jid()) -> 'invalid-from' | stanza(). check_from(Pkt, FromJID) -> - case xmpp:is_stanza(Pkt) of - false -> + JID = xmpp:get_from(Pkt), + case JID of + undefined -> Pkt; - true -> - JID = xmpp:get_from(Pkt), - case JID of - undefined -> + #jid{} -> + if + (JID#jid.luser == FromJID#jid.luser) and + (JID#jid.lserver == FromJID#jid.lserver) and + (JID#jid.lresource == FromJID#jid.lresource) -> Pkt; - #jid{} -> - if - (JID#jid.luser == FromJID#jid.luser) and - (JID#jid.lserver == FromJID#jid.lserver) and - (JID#jid.lresource == FromJID#jid.lresource) -> - Pkt; - (JID#jid.luser == FromJID#jid.luser) and - (JID#jid.lserver == FromJID#jid.lserver) and - (JID#jid.lresource == <<"">>) -> - Pkt; - true -> - 'invalid-from' - end + (JID#jid.luser == FromJID#jid.luser) and + (JID#jid.lserver == FromJID#jid.lserver) and + (JID#jid.lresource == <<"">>) -> + Pkt; + true -> + 'invalid-from' end end. diff --git a/src/ejabberd_http_bind.erl b/src/ejabberd_http_bind.erl index ea8cd792f..6fa38110c 100644 --- a/src/ejabberd_http_bind.erl +++ b/src/ejabberd_http_bind.erl @@ -125,8 +125,6 @@ %% Wait 100ms before continue processing, to allow the client provide more related stanzas. -define(BOSH_VERSION, <<"1.8">>). --define(NS_CLIENT, <<"jabber:client">>). - -define(NS_BOSH, <<"urn:xmpp:xbosh">>). -define(NS_HTTP_BIND, diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl index 83ffd932b..d65edc6e3 100644 --- a/src/ejabberd_router.erl +++ b/src/ejabberd_router.erl @@ -389,7 +389,13 @@ do_route(OrigFrom, OrigTo, OrigPacket) -> {From, To, Packet} -> LDstDomain = To#jid.lserver, case mnesia:dirty_read(route, LDstDomain) of - [] -> ejabberd_s2s:route(From, To, Packet); + [] -> + try xmpp:decode(Packet, [ignore_els]) of + Pkt -> + ejabberd_s2s:route(From, To, Pkt) + catch _:{xmpp_codec, Why} -> + log_decoding_error(From, To, Packet, Why) + end; [R] -> do_route(From, To, Packet, R); Rs -> @@ -425,15 +431,18 @@ do_route(From, To, Packet, #route{local_hint = LocalHint, Pid ! {route, From, To, Pkt} end catch error:{xmpp_codec, Why} -> - ?ERROR_MSG("failed to decode xml element ~p when " - "routing from ~s to ~s: ~s", - [Packet, jid:to_string(From), jid:to_string(To), - xmpp:format_error(Why)]), - drop + log_decoding_error(From, To, Packet, Why) end; do_route(_From, _To, _Packet, _Route) -> drop. +-spec log_decoding_error(jid(), jid(), xmlel() | xmpp_element(), term()) -> ok. +log_decoding_error(From, To, Packet, Reason) -> + ?ERROR_MSG("failed to decode xml element ~p when " + "routing from ~s to ~s: ~s", + [Packet, jid:to_string(From), jid:to_string(To), + xmpp:format_error(Reason)]). + -spec get_component_number(binary()) -> pos_integer() | undefined. get_component_number(LDomain) -> ejabberd_config:get_option( diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl index 19de64adb..e585257e8 100644 --- a/src/ejabberd_s2s.erl +++ b/src/ejabberd_s2s.erl @@ -55,7 +55,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("ejabberd_commands.hrl"). @@ -89,7 +89,7 @@ start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). --spec route(jid(), jid(), xmlel()) -> ok. +-spec route(jid(), jid(), xmpp_element()) -> ok. route(From, To, Packet) -> case catch do_route(From, To, Packet) of @@ -222,6 +222,7 @@ check_peer_certificate(SockMod, Sock, Peer) -> {error, <<"Cannot get peer certificate">>} end. +-spec make_key({binary(), binary()}, binary()) -> binary(). make_key({From, To}, StreamID) -> Secret = ejabberd_config:get_option(shared_key, fun(V) -> V end), p1_sha:to_hexlist( @@ -275,7 +276,7 @@ code_change(_OldVsn, State, _Extra) -> %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- - +-spec clean_table_from_bad_node(node()) -> any(). clean_table_from_bad_node(Node) -> F = fun() -> Es = mnesia:select( @@ -289,6 +290,7 @@ clean_table_from_bad_node(Node) -> end, mnesia:async_dirty(F). +-spec do_route(jid(), jid(), stanza()) -> ok | false. do_route(From, To, Packet) -> ?DEBUG("s2s manager~n\tfrom ~p~n\tto ~p~n\tpacket " "~P~n", @@ -296,28 +298,16 @@ do_route(From, To, Packet) -> case find_connection(From, To) of {atomic, Pid} when is_pid(Pid) -> ?DEBUG("sending to process ~p~n", [Pid]), - #xmlel{name = Name, attrs = Attrs, children = Els} = - Packet, - NewAttrs = - jlib:replace_from_to_attrs(jid:to_string(From), - jid:to_string(To), Attrs), #jid{lserver = MyServer} = From, ejabberd_hooks:run(s2s_send_packet, MyServer, [From, To, Packet]), - send_element(Pid, - #xmlel{name = Name, attrs = NewAttrs, children = Els}), + send_element(Pid, xmpp:set_from_to(Packet, From, To)), ok; {aborted, _Reason} -> - case fxml:get_tag_attr_s(<<"type">>, Packet) of - <<"error">> -> ok; - <<"result">> -> ok; - _ -> - Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), - Txt = <<"No s2s connection found">>, - Err = jlib:make_error_reply( - Packet, ?ERRT_SERVICE_UNAVAILABLE(Lang, Txt)), - ejabberd_router:route(To, From, Err) - end, + Lang = xmpp:get_lang(Packet), + Txt = <<"No s2s connection found">>, + Err = xmpp:err_service_unavailable(Txt, Lang), + ejabberd_router:route_error(To, From, Packet, Err), false end. @@ -367,9 +357,11 @@ find_connection(From, To) -> end end. +-spec choose_connection(jid(), [#s2s{}]) -> pid(). choose_connection(From, Connections) -> choose_pid(From, [C#s2s.pid || C <- Connections]). +-spec choose_pid(jid(), [pid()]) -> pid(). choose_pid(From, Pids) -> Pids1 = case [P || P <- Pids, node(P) == node()] of [] -> Pids; @@ -417,22 +409,21 @@ new_connection(MyServer, Server, From, FromTo, end, TRes. +-spec max_s2s_connections_number({binary(), binary()}) -> integer(). max_s2s_connections_number({From, To}) -> - case acl:match_rule(From, max_s2s_connections, - jid:make(<<"">>, To, <<"">>)) - of + case acl:match_rule(From, max_s2s_connections, jid:make(To)) of Max when is_integer(Max) -> Max; _ -> ?DEFAULT_MAX_S2S_CONNECTIONS_NUMBER end. +-spec max_s2s_connections_number_per_node({binary(), binary()}) -> integer(). max_s2s_connections_number_per_node({From, To}) -> - case acl:match_rule(From, max_s2s_connections_per_node, - jid:make(<<"">>, To, <<"">>)) - of + case acl:match_rule(From, max_s2s_connections_per_node, jid:make(To)) of Max when is_integer(Max) -> Max; _ -> ?DEFAULT_MAX_S2S_CONNECTIONS_NUMBER_PER_NODE end. +-spec needed_connections_number([#s2s{}], integer(), integer()) -> integer(). needed_connections_number(Ls, MaxS2SConnectionsNumber, MaxS2SConnectionsNumberPerNode) -> LocalLs = [L || L <- Ls, node(L#s2s.pid) == node()], @@ -444,6 +435,7 @@ needed_connections_number(Ls, MaxS2SConnectionsNumber, %% Description: Return true if the destination must be considered as a %% service. %% -------------------------------------------------------------------- +-spec is_service(jid(), jid()) -> boolean(). is_service(From, To) -> LFromDomain = From#jid.lserver, case ejabberd_config:get_option( @@ -541,7 +533,7 @@ allow_host1(MyHost, S2SHost) -> s2s_access, fun(A) -> A end, all), - JID = jid:make(<<"">>, S2SHost, <<"">>), + JID = jid:make(S2SHost), case acl:match_rule(MyHost, Rule, JID) of deny -> false; allow -> diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index d8d0a400a..04b961b3d 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -42,7 +42,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -define(DICT, dict). @@ -62,40 +62,19 @@ connections = (?DICT):new() :: ?TDICT, timer = make_ref() :: reference()}). -%-define(DBGFSM, true). +-type state_name() :: wait_for_stream | wait_for_features | stream_established. +-type state() :: #state{}. +-type fsm_next() :: {next_state, state_name(), state()}. +-type fsm_stop() :: {stop, normal, state()}. +-type fsm_transition() :: fsm_stop() | fsm_next(). +%%-define(DBGFSM, true). -ifdef(DBGFSM). - -define(FSMOPTS, [{debug, [trace]}]). - -else. - -define(FSMOPTS, []). - -endif. --define(STREAM_HEADER(Version), - <<"">>). - --define(STREAM_TRAILER, <<"">>). - --define(INVALID_NAMESPACE_ERR, - fxml:element_to_binary(?SERR_INVALID_NAMESPACE)). - --define(HOST_UNKNOWN_ERR, - fxml:element_to_binary(?SERR_HOST_UNKNOWN)). - --define(INVALID_FROM_ERR, - fxml:element_to_binary(?SERR_INVALID_FROM)). - --define(INVALID_XML_ERR, - fxml:element_to_binary(?SERR_XML_NOT_WELL_FORMED)). - start(SockData, Opts) -> supervisor:start_child(ejabberd_s2s_in_sup, [SockData, Opts]). @@ -185,319 +164,252 @@ init([{SockMod, Socket}, Opts]) -> %% {next_state, NextStateName, NextStateData, Timeout} | %% {stop, Reason, NewStateData} %%---------------------------------------------------------------------- - -wait_for_stream({xmlstreamstart, _Name, Attrs}, - StateData) -> - case {fxml:get_attr_s(<<"xmlns">>, Attrs), - fxml:get_attr_s(<<"xmlns:db">>, Attrs), - fxml:get_attr_s(<<"to">>, Attrs), - fxml:get_attr_s(<<"version">>, Attrs) == <<"1.0">>} - of - {<<"jabber:server">>, _, Server, true} - when StateData#state.tls and - not StateData#state.authenticated -> - send_text(StateData, - ?STREAM_HEADER(<<" version='1.0'">>)), - Auth = if StateData#state.tls_enabled -> - case jid:nameprep(fxml:get_attr_s(<<"from">>, Attrs)) of - From when From /= <<"">>, From /= error -> - {Result, Message} = - ejabberd_s2s:check_peer_certificate(StateData#state.sockmod, - StateData#state.socket, - From), - {Result, From, Message}; - _ -> - {error, <<"(unknown)">>, - <<"Got no valid 'from' attribute">>} - end; - true -> - {no_verify, <<"(unknown)">>, - <<"TLS not (yet) enabled">>} - end, - StartTLS = if StateData#state.tls_enabled -> []; - not StateData#state.tls_enabled and +wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) -> + try xmpp:decode(#xmlel{name = Name, attrs = Attrs}) of + #stream_start{xmlns = NS_SERVER, stream_xmlns = NS_STREAM} + when NS_SERVER /= ?NS_SERVER; NS_STREAM /= ?NS_STREAM -> + send_header(StateData, <<" version='1.0'">>), + send_element(StateData, xmpp:serr_invalid_namespace()), + {stop, normal, StateData}; + #stream_start{to = #jid{lserver = Server}, + from = #jid{lserver = From}, + version = <<"1.0">>} + when StateData#state.tls and not StateData#state.authenticated -> + send_header(StateData, <<" version='1.0'">>), + Auth = if StateData#state.tls_enabled -> + {Result, Message} = + ejabberd_s2s:check_peer_certificate( + StateData#state.sockmod, + StateData#state.socket, + From), + {Result, From, Message}; + true -> + {no_verify, <<"(unknown)">>, <<"TLS not (yet) enabled">>} + end, + StartTLS = if StateData#state.tls_enabled -> []; + not StateData#state.tls_enabled and not StateData#state.tls_required -> - [#xmlel{name = <<"starttls">>, - attrs = [{<<"xmlns">>, ?NS_TLS}], - children = []}]; - not StateData#state.tls_enabled and + [#starttls{required = false}]; + not StateData#state.tls_enabled and StateData#state.tls_required -> - [#xmlel{name = <<"starttls">>, - attrs = [{<<"xmlns">>, ?NS_TLS}], - children = - [#xmlel{name = <<"required">>, - attrs = [], children = []}]}] - end, - case Auth of - {error, RemoteServer, CertError} - when StateData#state.tls_certverify -> - ?INFO_MSG("Closing s2s connection: ~s <--> ~s (~s)", - [StateData#state.server, RemoteServer, CertError]), - send_text(StateData, - <<(fxml:element_to_binary(?SERRT_POLICY_VIOLATION(<<"en">>, - CertError)))/binary, - (?STREAM_TRAILER)/binary>>), - {stop, normal, StateData}; - {VerifyResult, RemoteServer, Msg} -> - {SASL, NewStateData} = case VerifyResult of - ok -> - {[#xmlel{name = <<"mechanisms">>, - attrs = [{<<"xmlns">>, ?NS_SASL}], - children = - [#xmlel{name = <<"mechanism">>, - attrs = [], - children = - [{xmlcdata, - <<"EXTERNAL">>}]}]}], - StateData#state{auth_domain = RemoteServer}}; - error -> - ?DEBUG("Won't accept certificate of ~s: ~s", - [RemoteServer, Msg]), - {[], StateData}; - no_verify -> - {[], StateData} - end, - send_element(NewStateData, - #xmlel{name = <<"stream:features">>, attrs = [], - children = - SASL ++ - StartTLS ++ - ejabberd_hooks:run_fold(s2s_stream_features, - Server, [], - [Server])}), - {next_state, wait_for_feature_request, - NewStateData#state{server = Server}} - end; - {<<"jabber:server">>, _, Server, true} - when StateData#state.authenticated -> - send_text(StateData, - ?STREAM_HEADER(<<" version='1.0'">>)), - send_element(StateData, - #xmlel{name = <<"stream:features">>, attrs = [], - children = - ejabberd_hooks:run_fold(s2s_stream_features, - Server, [], - [Server])}), - {next_state, stream_established, StateData}; - {<<"jabber:server">>, <<"jabber:server:dialback">>, - _Server, _} when - (StateData#state.tls_required and StateData#state.tls_enabled) - or (not StateData#state.tls_required) -> - send_text(StateData, ?STREAM_HEADER(<<"">>)), - {next_state, stream_established, StateData}; - _ -> - send_text(StateData, ?INVALID_NAMESPACE_ERR), - {stop, normal, StateData} + [#starttls{required = true}] + end, + case Auth of + {error, RemoteServer, CertError} + when StateData#state.tls_certverify -> + ?INFO_MSG("Closing s2s connection: ~s <--> ~s (~s)", + [StateData#state.server, RemoteServer, CertError]), + send_element(StateData, + xmpp:serr_policy_violation(CertError, ?MYLANG)), + {stop, normal, StateData}; + {VerifyResult, RemoteServer, Msg} -> + {SASL, NewStateData} = + case VerifyResult of + ok -> + {[#sasl_mechanisms{list = [<<"EXTERNAL">>]}], + StateData#state{auth_domain = RemoteServer}}; + error -> + ?DEBUG("Won't accept certificate of ~s: ~s", + [RemoteServer, Msg]), + {[], StateData}; + no_verify -> + {[], StateData} + end, + send_element(NewStateData, + #stream_features{ + sub_els = SASL ++ StartTLS ++ + ejabberd_hooks:run_fold( + s2s_stream_features, Server, [], + [Server])}), + {next_state, wait_for_feature_request, + NewStateData#state{server = Server}} + end; + #stream_start{to = #jid{lserver = Server}, + version = <<"1.0">>} when StateData#state.authenticated -> + send_header(StateData, <<" version='1.0'">>), + send_element(StateData, + #stream_features{ + sub_els = ejabberd_hooks:run_fold( + s2s_stream_features, Server, [], + [Server])}), + {next_state, stream_established, StateData}; + #stream_start{db_xmlns = ?NS_SERVER_DIALBACK} + when (StateData#state.tls_required and StateData#state.tls_enabled) + or (not StateData#state.tls_required) -> + send_header(StateData, <<"">>), + {next_state, stream_established, StateData}; + #stream_start{} -> + send_header(StateData, <<" version='1.0'">>), + send_element(StateData, xmpp:serr_undefined_condition()), + {stop, normal, StateData} + catch _:{xmpp_codec, Why} -> + Txt = xmpp:format_error(Why), + send_header(StateData, <<" version='1.0'">>), + send_element(StateData, xmpp:serr_not_well_formed(Txt, ?MYLANG)), + {stop, normal, StateData} end; wait_for_stream({xmlstreamerror, _}, StateData) -> - send_text(StateData, - <<(?STREAM_HEADER(<<"">>))/binary, - (?INVALID_XML_ERR)/binary, (?STREAM_TRAILER)/binary>>), + send_header(StateData, <<"">>), + send_element(StateData, xmpp:serr_not_well_formed()), {stop, normal, StateData}; wait_for_stream(timeout, StateData) -> + send_header(StateData, <<"">>), + send_element(StateData, xmpp:serr_connection_timeout()), {stop, normal, StateData}; wait_for_stream(closed, StateData) -> {stop, normal, StateData}. -wait_for_feature_request({xmlstreamelement, El}, - StateData) -> - #xmlel{name = Name, attrs = Attrs} = El, - TLS = StateData#state.tls, - TLSEnabled = StateData#state.tls_enabled, - SockMod = - (StateData#state.sockmod):get_sockmod(StateData#state.socket), - case {fxml:get_attr_s(<<"xmlns">>, Attrs), Name} of - {?NS_TLS, <<"starttls">>} - when TLS == true, TLSEnabled == false, - SockMod == gen_tcp -> - ?DEBUG("starttls", []), - Socket = StateData#state.socket, - TLSOpts1 = case - ejabberd_config:get_option( - {domain_certfile, StateData#state.server}, - fun iolist_to_binary/1) of - undefined -> StateData#state.tls_options; - CertFile -> - [{certfile, CertFile} | lists:keydelete(certfile, 1, - StateData#state.tls_options)] - end, - TLSOpts = case ejabberd_config:get_option( - {s2s_tls_compression, StateData#state.server}, - fun(true) -> true; - (false) -> false - end, false) of - true -> lists:delete(compression_none, TLSOpts1); - false -> [compression_none | TLSOpts1] - end, - TLSSocket = (StateData#state.sockmod):starttls(Socket, - TLSOpts, - fxml:element_to_binary(#xmlel{name - = - <<"proceed">>, - attrs - = - [{<<"xmlns">>, - ?NS_TLS}], - children - = - []})), - {next_state, wait_for_stream, - StateData#state{socket = TLSSocket, streamid = new_id(), - tls_enabled = true, tls_options = TLSOpts}}; - {?NS_SASL, <<"auth">>} when TLSEnabled -> - Mech = fxml:get_attr_s(<<"mechanism">>, Attrs), - case Mech of - <<"EXTERNAL">> when StateData#state.auth_domain /= <<"">> -> - AuthDomain = StateData#state.auth_domain, - AllowRemoteHost = ejabberd_s2s:allow_host(<<"">>, - AuthDomain), - if AllowRemoteHost -> - (StateData#state.sockmod):reset_stream(StateData#state.socket), - send_element(StateData, - #xmlel{name = <<"success">>, - attrs = [{<<"xmlns">>, ?NS_SASL}], - children = []}), - ?INFO_MSG("Accepted s2s EXTERNAL authentication for ~s (TLS=~p)", - [AuthDomain, StateData#state.tls_enabled]), - change_shaper(StateData, <<"">>, - jid:make(<<"">>, AuthDomain, <<"">>)), - {next_state, wait_for_stream, - StateData#state{streamid = new_id(), - authenticated = true}}; - true -> - send_element(StateData, - #xmlel{name = <<"failure">>, - attrs = [{<<"xmlns">>, ?NS_SASL}], - children = []}), - send_text(StateData, ?STREAM_TRAILER), - {stop, normal, StateData} - end; - _ -> - send_element(StateData, - #xmlel{name = <<"failure">>, - attrs = [{<<"xmlns">>, ?NS_SASL}], - children = - [#xmlel{name = <<"invalid-mechanism">>, - attrs = [], children = []}]}), - {stop, normal, StateData} - end; - _ -> - stream_established({xmlstreamelement, El}, StateData) +wait_for_feature_request({xmlstreamelement, El}, StateData) -> + decode_element(El, wait_for_feature_request, StateData); +wait_for_feature_request(#starttls{}, + #state{tls = true, tls_enabled = false} = StateData) -> + case (StateData#state.sockmod):get_sockmod(StateData#state.socket) of + gen_tcp -> + ?DEBUG("starttls", []), + Socket = StateData#state.socket, + TLSOpts1 = case + ejabberd_config:get_option( + {domain_certfile, StateData#state.server}, + fun iolist_to_binary/1) of + undefined -> StateData#state.tls_options; + CertFile -> + lists:keystore(certfile, 1, + StateData#state.tls_options, + {certfile, CertFile}) + end, + TLSOpts = case ejabberd_config:get_option( + {s2s_tls_compression, StateData#state.server}, + fun(true) -> true; + (false) -> false + end, false) of + true -> lists:delete(compression_none, TLSOpts1); + false -> [compression_none | TLSOpts1] + end, + TLSSocket = (StateData#state.sockmod):starttls( + Socket, TLSOpts, + fxml:element_to_binary(#starttls_proceed{})), + {next_state, wait_for_stream, + StateData#state{socket = TLSSocket, streamid = new_id(), + tls_enabled = true, tls_options = TLSOpts}}; + _ -> + Txt = <<"Unsupported TLS transport">>, + send_element(StateData, xmpp:serr_policy_violation(Txt, ?MYLANG)), + {stop, normal, StateData} end; -wait_for_feature_request({xmlstreamend, _Name}, - StateData) -> - send_text(StateData, ?STREAM_TRAILER), +wait_for_feature_request(#sasl_auth{mechanism = Mech}, + #state{tls_enabled = true} = StateData) -> + case Mech of + <<"EXTERNAL">> when StateData#state.auth_domain /= <<"">> -> + AuthDomain = StateData#state.auth_domain, + AllowRemoteHost = ejabberd_s2s:allow_host(<<"">>, AuthDomain), + if AllowRemoteHost -> + (StateData#state.sockmod):reset_stream(StateData#state.socket), + send_element(StateData, #sasl_success{}), + ?INFO_MSG("Accepted s2s EXTERNAL authentication for ~s (TLS=~p)", + [AuthDomain, StateData#state.tls_enabled]), + change_shaper(StateData, <<"">>, jid:make(AuthDomain)), + {next_state, wait_for_stream, + StateData#state{streamid = new_id(), + authenticated = true}}; + true -> + send_element(StateData, #sasl_failure{}), + {stop, normal, StateData} + end; + _ -> + send_element(StateData, #sasl_failure{reason = 'invalid-mechanism'}), + {stop, normal, StateData} + end; +wait_for_feature_request({xmlstreamend, _Name}, StateData) -> {stop, normal, StateData}; -wait_for_feature_request({xmlstreamerror, _}, - StateData) -> - send_text(StateData, - <<(?INVALID_XML_ERR)/binary, - (?STREAM_TRAILER)/binary>>), +wait_for_feature_request({xmlstreamerror, _}, StateData) -> + send_element(StateData, xmpp:serr_not_well_formed()), {stop, normal, StateData}; wait_for_feature_request(closed, StateData) -> - {stop, normal, StateData}. + {stop, normal, StateData}; +wait_for_feature_request(_Pkt, #state{tls_required = TLSRequired, + tls_enabled = TLSEnabled} = StateData) + when TLSRequired and not TLSEnabled -> + Txt = <<"Use of STARTTLS required">>, + send_element(StateData, xmpp:serr_policy_violation(Txt, ?MYLANG)), + {stop, normal, StateData}; +wait_for_feature_request(El, StateData) -> + stream_established({xmlstreamelement, El}, StateData). stream_established({xmlstreamelement, El}, StateData) -> cancel_timer(StateData#state.timer), Timer = erlang:start_timer(?S2STIMEOUT, self(), []), - case is_key_packet(El) of - {key, To, From, Id, Key} -> - ?DEBUG("GET KEY: ~p", [{To, From, Id, Key}]), - LTo = jid:nameprep(To), - LFrom = jid:nameprep(From), - case {ejabberd_s2s:allow_host(LTo, LFrom), - lists:member(LTo, - ejabberd_router:dirty_get_all_domains())} - of - {true, true} -> - ejabberd_s2s_out:terminate_if_waiting_delay(LTo, LFrom), - ejabberd_s2s_out:start(LTo, LFrom, - {verify, self(), Key, - StateData#state.streamid}), - Conns = (?DICT):store({LFrom, LTo}, - wait_for_verification, - StateData#state.connections), - change_shaper(StateData, LTo, - jid:make(<<"">>, LFrom, <<"">>)), - {next_state, stream_established, - StateData#state{connections = Conns, timer = Timer}}; - {_, false} -> - send_text(StateData, ?HOST_UNKNOWN_ERR), - {stop, normal, StateData}; - {false, _} -> - send_text(StateData, ?INVALID_FROM_ERR), - {stop, normal, StateData} - end; - {verify, To, From, Id, Key} -> - ?DEBUG("VERIFY KEY: ~p", [{To, From, Id, Key}]), - LTo = jid:nameprep(To), - LFrom = jid:nameprep(From), - Type = case ejabberd_s2s:make_key({LTo, LFrom}, Id) of - Key -> <<"valid">>; - _ -> <<"invalid">> - end, - send_element(StateData, - #xmlel{name = <<"db:verify">>, - attrs = - [{<<"from">>, To}, {<<"to">>, From}, - {<<"id">>, Id}, {<<"type">>, Type}], - children = []}), - {next_state, stream_established, - StateData#state{timer = Timer}}; - _ -> - NewEl = jlib:remove_attr(<<"xmlns">>, El), - #xmlel{name = Name, attrs = Attrs} = NewEl, - From_s = fxml:get_attr_s(<<"from">>, Attrs), - From = jid:from_string(From_s), - To_s = fxml:get_attr_s(<<"to">>, Attrs), - To = jid:from_string(To_s), - if (To /= error) and (From /= error) -> - LFrom = From#jid.lserver, - LTo = To#jid.lserver, - if StateData#state.authenticated -> - case LFrom == StateData#state.auth_domain andalso - lists:member(LTo, - ejabberd_router:dirty_get_all_domains()) - of - true -> - if (Name == <<"iq">>) or (Name == <<"message">>) - or (Name == <<"presence">>) -> - ejabberd_hooks:run(s2s_receive_packet, LTo, - [From, To, NewEl]), - ejabberd_router:route(From, To, NewEl); - true -> error - end; - false -> error - end; - true -> - case (?DICT):find({LFrom, LTo}, - StateData#state.connections) - of - {ok, established} -> - if (Name == <<"iq">>) or (Name == <<"message">>) - or (Name == <<"presence">>) -> - ejabberd_hooks:run(s2s_receive_packet, LTo, - [From, To, NewEl]), - ejabberd_router:route(From, To, NewEl); - true -> error - end; - _ -> error - end - end; - true -> error - end, - ejabberd_hooks:run(s2s_loop_debug, - [{xmlstreamelement, El}]), - {next_state, stream_established, - StateData#state{timer = Timer}} + decode_element(El, stream_established, StateData#state{timer = Timer}); +stream_established(#db_result{to = To, from = From, key = Key}, + StateData) -> + ?DEBUG("GET KEY: ~p", [{To, From, Key}]), + LTo = To#jid.lserver, + LFrom = From#jid.lserver, + case {ejabberd_s2s:allow_host(LTo, LFrom), + lists:member(LTo, ejabberd_router:dirty_get_all_domains())} of + {true, true} -> + ejabberd_s2s_out:terminate_if_waiting_delay(LTo, LFrom), + ejabberd_s2s_out:start(LTo, LFrom, + {verify, self(), Key, + StateData#state.streamid}), + Conns = (?DICT):store({LFrom, LTo}, + wait_for_verification, + StateData#state.connections), + change_shaper(StateData, LTo, jid:make(LFrom)), + {next_state, stream_established, + StateData#state{connections = Conns}}; + {_, false} -> + send_element(StateData, xmpp:serr_host_unknown()), + {stop, normal, StateData}; + {false, _} -> + send_element(StateData, xmpp:serr_invalid_from()), + {stop, normal, StateData} end; +stream_established(#db_verify{to = To, from = From, id = Id, key = Key}, + StateData) -> + ?DEBUG("VERIFY KEY: ~p", [{To, From, Id, Key}]), + LTo = jid:nameprep(To), + LFrom = jid:nameprep(From), + Type = case ejabberd_s2s:make_key({LTo, LFrom}, Id) of + Key -> valid; + _ -> invalid + end, + send_element(StateData, + #db_verify{from = To, to = From, id = Id, type = Type}), + {next_state, stream_established, StateData}; +stream_established(Pkt, StateData) when ?is_stanza(Pkt) -> + From = xmpp:get_from(Pkt), + To = xmpp:get_to(Pkt), + if To /= undefined, From /= undefined -> + LFrom = From#jid.lserver, + LTo = To#jid.lserver, + if StateData#state.authenticated -> + case LFrom == StateData#state.auth_domain andalso + lists:member(LTo, ejabberd_router:dirty_get_all_domains()) of + true -> + ejabberd_hooks:run(s2s_receive_packet, LTo, + [From, To, Pkt]), + ejabberd_router:route(From, To, Pkt); + false -> + send_error(StateData, Pkt, xmpp:err_not_authorized()) + end; + true -> + case (?DICT):find({LFrom, LTo}, StateData#state.connections) of + {ok, established} -> + ejabberd_hooks:run(s2s_receive_packet, LTo, + [From, To, Pkt]), + ejabberd_router:route(From, To, Pkt); + _ -> + send_error(StateData, Pkt, xmpp:err_not_authorized()) + end + end; + true -> + send_error(StateData, Pkt, xmpp:err_jid_malformed()) + end, + ejabberd_hooks:run(s2s_loop_debug, [{xmlstreamelement, Pkt}]), + {next_state, stream_established, StateData}; stream_established({valid, From, To}, StateData) -> send_element(StateData, - #xmlel{name = <<"db:result">>, - attrs = - [{<<"from">>, To}, {<<"to">>, From}, - {<<"type">>, <<"valid">>}], - children = []}), + #db_result{from = To, to = From, type = valid}), ?INFO_MSG("Accepted s2s dialback authentication for ~s (TLS=~p)", [From, StateData#state.tls_enabled]), LFrom = jid:nameprep(From), @@ -508,11 +420,7 @@ stream_established({valid, From, To}, StateData) -> {next_state, stream_established, NSD}; stream_established({invalid, From, To}, StateData) -> send_element(StateData, - #xmlel{name = <<"db:result">>, - attrs = - [{<<"from">>, To}, {<<"to">>, From}, - {<<"type">>, <<"invalid">>}], - children = []}), + #db_result{from = To, to = From, type = invalid}), LFrom = jid:nameprep(From), LTo = jid:nameprep(To), NSD = StateData#state{connections = @@ -522,14 +430,16 @@ stream_established({invalid, From, To}, StateData) -> stream_established({xmlstreamend, _Name}, StateData) -> {stop, normal, StateData}; stream_established({xmlstreamerror, _}, StateData) -> - send_text(StateData, - <<(?INVALID_XML_ERR)/binary, - (?STREAM_TRAILER)/binary>>), + send_element(StateData, xmpp:serr_not_well_formed()), {stop, normal, StateData}; stream_established(timeout, StateData) -> + send_element(StateData, xmpp:serr_connection_timeout()), {stop, normal, StateData}; stream_established(closed, StateData) -> - {stop, normal, StateData}. + {stop, normal, StateData}; +stream_established(Pkt, StateData) -> + ejabberd_hooks:run(s2s_loop_debug, [{xmlstreamelement, Pkt}]), + {next_state, stream_established, StateData}. %%---------------------------------------------------------------------- %% Func: StateName/3 @@ -589,8 +499,14 @@ code_change(_OldVsn, StateName, StateData, _Extra) -> handle_info({send_text, Text}, StateName, StateData) -> send_text(StateData, Text), {next_state, StateName, StateData}; -handle_info({timeout, Timer, _}, _StateName, +handle_info({timeout, Timer, _}, StateName, #state{timer = Timer} = StateData) -> + if StateName == wait_for_stream -> + send_header(StateData, <<"">>); + true -> + ok + end, + send_element(StateData, xmpp:serr_connection_timeout()), {stop, normal, StateData}; handle_info(_, StateName, StateData) -> {next_state, StateName, StateData}. @@ -603,6 +519,7 @@ terminate(Reason, _StateName, StateData) -> || Host <- get_external_hosts(StateData)]; _ -> ok end, + catch send_trailer(StateData), (StateData#state.sockmod):close(StateData#state.socket), ok. @@ -621,39 +538,69 @@ print_state(State) -> State. %%% Internal functions %%%---------------------------------------------------------------------- +-spec send_text(state(), iodata()) -> ok. send_text(StateData, Text) -> (StateData#state.sockmod):send(StateData#state.socket, Text). +-spec send_element(state(), xmpp_element()) -> ok. send_element(StateData, El) -> - send_text(StateData, fxml:element_to_binary(El)). + El1 = fix_ns(xmpp:encode(El)), + send_text(StateData, fxml:element_to_binary(El1)). +-spec send_error(state(), xmlel() | stanza(), error()) -> ok. +send_error(StateData, Stanza, Error) -> + Type = xmpp:get_type(Stanza), + if Type == error; Type == result; + Type == <<"error">>; Type == <<"result">> -> + ok; + true -> + send_element(StateData, xmpp:make_error(Stanza, Error)) + end. + +-spec send_trailer(state()) -> ok. +send_trailer(StateData) -> + send_text(StateData, <<"">>). + +-spec send_header(state(), binary()) -> ok. +send_header(StateData, Version) -> + send_text(StateData, + <<"">>). + +-spec change_shaper(state(), binary(), jid()) -> ok. change_shaper(StateData, Host, JID) -> Shaper = acl:match_rule(Host, StateData#state.shaper, JID), (StateData#state.sockmod):change_shaper(StateData#state.socket, Shaper). +-spec fix_ns(xmlel()) -> xmlel(). +fix_ns(#xmlel{name = Name} = El) when Name == <<"message">>; + Name == <<"iq">>; + Name == <<"presence">>; + Name == <<"db:verify">>, + Name == <<"db:result">> -> + Attrs = lists:filter( + fun({<<"xmlns">>, _}) -> false; + (_) -> true + end, El#xmlel.attrs), + El#xmlel{attrs = Attrs}; +fix_ns(El) -> + El. + +-spec new_id() -> binary(). new_id() -> randoms:get_string(). +-spec cancel_timer(reference()) -> ok. cancel_timer(Timer) -> erlang:cancel_timer(Timer), receive {timeout, Timer, _} -> ok after 0 -> ok end. -is_key_packet(#xmlel{name = Name, attrs = Attrs, - children = Els}) - when Name == <<"db:result">> -> - {key, fxml:get_attr_s(<<"to">>, Attrs), - fxml:get_attr_s(<<"from">>, Attrs), - fxml:get_attr_s(<<"id">>, Attrs), fxml:get_cdata(Els)}; -is_key_packet(#xmlel{name = Name, attrs = Attrs, - children = Els}) - when Name == <<"db:verify">> -> - {verify, fxml:get_attr_s(<<"to">>, Attrs), - fxml:get_attr_s(<<"from">>, Attrs), - fxml:get_attr_s(<<"id">>, Attrs), fxml:get_cdata(Els)}; -is_key_packet(_) -> false. - fsm_limit_opts(Opts) -> case lists:keysearch(max_fsm_queue, 1, Opts) of {value, {_, N}} when is_integer(N) -> [{max_queue, N}]; @@ -666,6 +613,22 @@ fsm_limit_opts(Opts) -> end end. +-spec decode_element(xmlel(), state_name(), state()) -> fsm_transition(). +decode_element(#xmlel{} = El, StateName, StateData) -> + try xmpp:decode(El) of + Pkt -> ?MODULE:StateName(Pkt, StateData) + catch error:{xmpp_codec, Why} -> + case xmpp:is_stanza(El) of + true -> + Lang = xmpp:get_lang(El), + Txt = xmpp:format_error(Why), + send_error(StateData, El, xmpp:err_bad_request(Txt, Lang)); + false -> + ok + end, + {next_state, StateName, StateData} + end. + opt_type(domain_certfile) -> fun iolist_to_binary/1; opt_type(max_fsm_queue) -> fun (I) when is_integer(I), I > 0 -> I end; diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index a30f2f438..024e51e7a 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -50,8 +50,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). - --include("jlib.hrl"). +-include("xmpp.hrl"). -record(state, {socket :: ejabberd_socket:socket_state(), @@ -75,6 +74,17 @@ bridge :: {atom(), atom()}, timer = make_ref() :: reference()}). +-type state_name() :: open_socket | wait_for_stream | + wait_for_validation | wait_for_features | + wait_for_auth_result | wait_for_starttls_proceed | + relay_to_bridge | reopen_socket | wait_before_retry | + stream_established. +-type state() :: #state{}. +-type fsm_stop() :: {stop, normal, state()}. +-type fsm_next() :: {next_state, state_name(), state(), non_neg_integer()} | + {next_state, state_name(), state()}. +-type fsm_transition() :: fsm_stop() | fsm_next(). + %%-define(DBGFSM, true). -ifdef(DBGFSM). @@ -102,17 +112,6 @@ "s' xmlns='jabber:server' xmlns:db='jabber:ser" "ver:dialback' from='~s' to='~s'~s>">>). --define(STREAM_TRAILER, <<"">>). - --define(INVALID_NAMESPACE_ERR, - fxml:element_to_binary(?SERR_INVALID_NAMESPACE)). - --define(HOST_UNKNOWN_ERR, - fxml:element_to_binary(?SERR_HOST_UNKNOWN)). - --define(INVALID_XML_ERR, - fxml:element_to_binary(?SERR_XML_NOT_WELL_FORMED)). - -define(SOCKET_DEFAULT_RESULT, {error, badarg}). %%%---------------------------------------------------------------------- @@ -236,10 +235,7 @@ open_socket(init, StateData) -> NewStateData = StateData#state{socket = Socket, tls_enabled = false, streamid = new_id()}, - send_text(NewStateData, - io_lib:format(?STREAM_HEADER, - [StateData#state.myname, - StateData#state.server, Version])), + send_header(NewStateData, Version), {next_state, wait_for_stream, NewStateData, ?FSMTIMEOUT}; {error, _Reason} -> @@ -259,18 +255,8 @@ open_socket(init, StateData) -> _ -> wait_before_reconnect(StateData) end end; -open_socket(closed, StateData) -> - ?INFO_MSG("s2s connection: ~s -> ~s (stopped in " - "open socket)", - [StateData#state.myname, StateData#state.server]), - {stop, normal, StateData}; -open_socket(timeout, StateData) -> - ?INFO_MSG("s2s connection: ~s -> ~s (timeout in " - "open socket)", - [StateData#state.myname, StateData#state.server]), - {stop, normal, StateData}; -open_socket(_, StateData) -> - {next_state, open_socket, StateData}. +open_socket(Event, StateData) -> + handle_unexpected_event(Event, open_socket, StateData). open_socket1({_, _, _, _} = Addr, Port) -> open_socket2(inet, Addr, Port); @@ -309,466 +295,215 @@ open_socket2(Type, Addr, Port) -> %%---------------------------------------------------------------------- -wait_for_stream({xmlstreamstart, _Name, Attrs}, - StateData) -> - {CertCheckRes, CertCheckMsg, StateData0} = - if StateData#state.tls_certverify, StateData#state.tls_enabled -> - {Res, Msg} = - ejabberd_s2s:check_peer_certificate(ejabberd_socket, - StateData#state.socket, - StateData#state.server), - ?DEBUG("Certificate verification result for ~s: ~s", - [StateData#state.server, Msg]), - {Res, Msg, StateData#state{tls_certverify = false}}; +wait_for_stream({xmlstreamstart, Name, Attrs}, StateData0) -> + {CertCheckRes, CertCheckMsg, StateData} = + if StateData0#state.tls_certverify, StateData0#state.tls_enabled -> + {Res, Msg} = + ejabberd_s2s:check_peer_certificate(ejabberd_socket, + StateData0#state.socket, + StateData0#state.server), + ?DEBUG("Certificate verification result for ~s: ~s", + [StateData0#state.server, Msg]), + {Res, Msg, StateData0#state{tls_certverify = false}}; true -> - {no_verify, <<"Not verified">>, StateData} + {no_verify, <<"Not verified">>, StateData0} end, - RemoteStreamID = fxml:get_attr_s(<<"id">>, Attrs), - NewStateData = StateData0#state{remote_streamid = RemoteStreamID}, - case {fxml:get_attr_s(<<"xmlns">>, Attrs), - fxml:get_attr_s(<<"xmlns:db">>, Attrs), - fxml:get_attr_s(<<"version">>, Attrs) == <<"1.0">>} - of - _ when CertCheckRes == error -> - send_text(NewStateData, - <<(fxml:element_to_binary(?SERRT_POLICY_VIOLATION(<<"en">>, - CertCheckMsg)))/binary, - (?STREAM_TRAILER)/binary>>), - ?INFO_MSG("Closing s2s connection: ~s -> ~s (~s)", - [NewStateData#state.myname, - NewStateData#state.server, - CertCheckMsg]), - {stop, normal, NewStateData}; - {<<"jabber:server">>, <<"jabber:server:dialback">>, - false} -> - send_db_request(NewStateData); - {<<"jabber:server">>, <<"jabber:server:dialback">>, - true} - when NewStateData#state.use_v10 -> - {next_state, wait_for_features, NewStateData, ?FSMTIMEOUT}; - %% Clause added to handle Tigase's workaround for an old ejabberd bug: - {<<"jabber:server">>, <<"jabber:server:dialback">>, - true} - when not NewStateData#state.use_v10 -> - send_db_request(NewStateData); - {<<"jabber:server">>, <<"">>, true} - when NewStateData#state.use_v10 -> - {next_state, wait_for_features, - NewStateData#state{db_enabled = false}, ?FSMTIMEOUT}; - {NSProvided, DB, _} -> - send_text(NewStateData, ?INVALID_NAMESPACE_ERR), - ?INFO_MSG("Closing s2s connection: ~s -> ~s (invalid " - "namespace).~nNamespace provided: ~p~nNamespac" - "e expected: \"jabber:server\"~nxmlns:db " - "provided: ~p~nAll attributes: ~p", - [NewStateData#state.myname, NewStateData#state.server, - NSProvided, DB, Attrs]), - {stop, normal, NewStateData} + try xmpp:decode(#xmlel{name = Name, attrs = Attrs}) of + _ when CertCheckRes == error -> + send_element(StateData, + xmpp:serr_policy_violation(CertCheckMsg, ?MYLANG)), + ?INFO_MSG("Closing s2s connection: ~s -> ~s (~s)", + [StateData#state.myname, StateData#state.server, + CertCheckMsg]), + {stop, normal, StateData}; + #stream_start{xmlns = NS_SERVER, stream_xmlns = NS_STREAM} + when NS_SERVER /= ?NS_SERVER; NS_STREAM /= ?NS_STREAM -> + send_header(StateData, <<" version='1.0'">>), + send_element(StateData, xmpp:serr_invalid_namespace()), + {stop, normal, StateData}; + #stream_start{db_xmlns = ?NS_SERVER_DIALBACK, id = ID, + version = V} when V /= <<"1.0">> -> + send_db_request(StateData#state{remote_streamid = ID}); + #stream_start{db_xmlns = ?NS_SERVER_DIALBACK, id = ID} + when StateData#state.use_v10 -> + {next_state, wait_for_features, + StateData#state{remote_streamid = ID}, ?FSMTIMEOUT}; + #stream_start{db_xmlns = ?NS_SERVER_DIALBACK, id = ID} + when not StateData#state.use_v10 -> + %% Handle Tigase's workaround for an old ejabberd bug: + send_db_request(StateData#state{remote_streamid = ID}); + #stream_start{id = ID} when StateData#state.use_v10 -> + {next_state, wait_for_features, + StateData#state{db_enabled = false, remote_streamid = ID}, + ?FSMTIMEOUT}; + #stream_start{} -> + send_header(StateData, <<"">>), + send_element(StateData, xmpp:serr_invalid_namespace()), + {stop, normal, StateData} + catch _:{xmpp_codec, Why} -> + Txt = xmpp:format_error(Why), + send_header(StateData, <<" version='1.0'">>), + send_element(StateData, xmpp:serr_not_well_formed(Txt, ?MYLANG)), + {stop, normal, StateData} end; -wait_for_stream({xmlstreamerror, _}, StateData) -> - send_text(StateData, - <<(?INVALID_XML_ERR)/binary, - (?STREAM_TRAILER)/binary>>), - ?INFO_MSG("Closing s2s connection: ~s -> ~s (invalid " - "xml)", - [StateData#state.myname, StateData#state.server]), - {stop, normal, StateData}; -wait_for_stream({xmlstreamend, _Name}, StateData) -> - ?INFO_MSG("Closing s2s connection: ~s -> ~s (xmlstreamend)", - [StateData#state.myname, StateData#state.server]), - {stop, normal, StateData}; -wait_for_stream(timeout, StateData) -> - ?INFO_MSG("Closing s2s connection: ~s -> ~s (timeout " - "in wait_for_stream)", - [StateData#state.myname, StateData#state.server]), - {stop, normal, StateData}; -wait_for_stream(closed, StateData) -> - ?INFO_MSG("Closing s2s connection: ~s -> ~s (close " - "in wait_for_stream)", - [StateData#state.myname, StateData#state.server]), - {stop, normal, StateData}. +wait_for_stream(Event, StateData) -> + handle_unexpected_event(Event, wait_for_stream, StateData). -wait_for_validation({xmlstreamelement, El}, - StateData) -> - case is_verify_res(El) of - {result, To, From, Id, Type} -> - ?DEBUG("recv result: ~p", [{From, To, Id, Type}]), - case {Type, StateData#state.tls_enabled, - StateData#state.tls_required} - of - {<<"valid">>, Enabled, Required} - when (Enabled == true) or (Required == false) -> - send_queue(StateData, StateData#state.queue), - ?INFO_MSG("Connection established: ~s -> ~s with " - "TLS=~p", - [StateData#state.myname, StateData#state.server, - StateData#state.tls_enabled]), - ejabberd_hooks:run(s2s_connect_hook, - [StateData#state.myname, - StateData#state.server]), - {next_state, stream_established, - StateData#state{queue = queue:new()}}; - {<<"valid">>, Enabled, Required} - when (Enabled == false) and (Required == true) -> - ?INFO_MSG("Closing s2s connection: ~s -> ~s (TLS " - "is required but unavailable)", - [StateData#state.myname, StateData#state.server]), - {stop, normal, StateData}; - _ -> - ?INFO_MSG("Closing s2s connection: ~s -> ~s (invalid " - "dialback key)", - [StateData#state.myname, StateData#state.server]), - {stop, normal, StateData} - end; - {verify, To, From, Id, Type} -> - ?DEBUG("recv verify: ~p", [{From, To, Id, Type}]), - case StateData#state.verify of - false -> - NextState = wait_for_validation, - {next_state, NextState, StateData, - get_timeout_interval(NextState)}; - {Pid, _Key, _SID} -> - case Type of - <<"valid">> -> - p1_fsm:send_event(Pid, - {valid, StateData#state.server, - StateData#state.myname}); - _ -> - p1_fsm:send_event(Pid, - {invalid, StateData#state.server, - StateData#state.myname}) - end, - if StateData#state.verify == false -> - {stop, normal, StateData}; - true -> - NextState = wait_for_validation, - {next_state, NextState, StateData, - get_timeout_interval(NextState)} - end - end; - _ -> - {next_state, wait_for_validation, StateData, - (?FSMTIMEOUT) * 3} +wait_for_validation({xmlstreamelement, El}, StateData) -> + decode_element(El, wait_for_validation, StateData); +wait_for_validation(#db_result{to = To, from = From, type = Type}, StateData) -> + ?DEBUG("recv result: ~p", [{From, To, Type}]), + case {Type, StateData#state.tls_enabled, StateData#state.tls_required} of + {valid, Enabled, Required} when (Enabled == true) or (Required == false) -> + send_queue(StateData, StateData#state.queue), + ?INFO_MSG("Connection established: ~s -> ~s with " + "TLS=~p", + [StateData#state.myname, StateData#state.server, + StateData#state.tls_enabled]), + ejabberd_hooks:run(s2s_connect_hook, + [StateData#state.myname, + StateData#state.server]), + {next_state, stream_established, StateData#state{queue = queue:new()}}; + {valid, Enabled, Required} when (Enabled == false) and (Required == true) -> + ?INFO_MSG("Closing s2s connection: ~s -> ~s (TLS " + "is required but unavailable)", + [StateData#state.myname, StateData#state.server]), + {stop, normal, StateData}; + _ -> + ?INFO_MSG("Closing s2s connection: ~s -> ~s (invalid " + "dialback key result)", + [StateData#state.myname, StateData#state.server]), + {stop, normal, StateData} + end; +wait_for_validation(#db_verify{to = To, from = From, id = Id, type = Type}, + StateData) -> + ?DEBUG("recv verify: ~p", [{From, To, Id, Type}]), + case StateData#state.verify of + false -> + NextState = wait_for_validation, + {next_state, NextState, StateData, get_timeout_interval(NextState)}; + {Pid, _Key, _SID} -> + case Type of + valid -> + p1_fsm:send_event(Pid, + {valid, StateData#state.server, + StateData#state.myname}); + _ -> + p1_fsm:send_event(Pid, + {invalid, StateData#state.server, + StateData#state.myname}) + end, + if StateData#state.verify == false -> + {stop, normal, StateData}; + true -> + NextState = wait_for_validation, + {next_state, NextState, StateData, get_timeout_interval(NextState)} + end end; -wait_for_validation({xmlstreamend, _Name}, StateData) -> - ?INFO_MSG("wait for validation: ~s -> ~s (xmlstreamend)", - [StateData#state.myname, StateData#state.server]), - {stop, normal, StateData}; -wait_for_validation({xmlstreamerror, _}, StateData) -> - ?INFO_MSG("wait for validation: ~s -> ~s (xmlstreamerror)", - [StateData#state.myname, StateData#state.server]), - send_text(StateData, - <<(?INVALID_XML_ERR)/binary, - (?STREAM_TRAILER)/binary>>), - {stop, normal, StateData}; wait_for_validation(timeout, #state{verify = {VPid, VKey, SID}} = StateData) - when is_pid(VPid) and is_binary(VKey) and - is_binary(SID) -> - ?DEBUG("wait_for_validation: ~s -> ~s (timeout " - "in verify connection)", + when is_pid(VPid) and is_binary(VKey) and is_binary(SID) -> + ?DEBUG("wait_for_validation: ~s -> ~s (timeout in verify connection)", [StateData#state.myname, StateData#state.server]), {stop, normal, StateData}; -wait_for_validation(timeout, StateData) -> - ?INFO_MSG("wait_for_validation: ~s -> ~s (connect " - "timeout)", - [StateData#state.myname, StateData#state.server]), - {stop, normal, StateData}; -wait_for_validation(closed, StateData) -> - ?INFO_MSG("wait for validation: ~s -> ~s (closed)", - [StateData#state.myname, StateData#state.server]), - {stop, normal, StateData}. +wait_for_validation(Event, StateData) -> + handle_unexpected_event(Event, wait_for_validation, StateData). wait_for_features({xmlstreamelement, El}, StateData) -> - case El of - #xmlel{name = <<"stream:features">>, children = Els} -> - {SASLEXT, StartTLS, StartTLSRequired} = lists:foldl(fun - (#xmlel{name = - <<"mechanisms">>, - attrs = - Attrs1, - children - = - Els1} = - _El1, - {_SEXT, STLS, - STLSReq} = - Acc) -> - case - fxml:get_attr_s(<<"xmlns">>, - Attrs1) - of - ?NS_SASL -> - NewSEXT = - lists:any(fun - (#xmlel{name - = - <<"mechanism">>, - children - = - Els2}) -> - case - fxml:get_cdata(Els2) - of - <<"EXTERNAL">> -> - true; - _ -> - false - end; - (_) -> - false - end, - Els1), - {NewSEXT, - STLS, - STLSReq}; - _ -> Acc - end; - (#xmlel{name = - <<"starttls">>, - attrs = - Attrs1} = - El1, - {SEXT, _STLS, - _STLSReq} = - Acc) -> - case - fxml:get_attr_s(<<"xmlns">>, - Attrs1) - of - ?NS_TLS -> - Req = - case - fxml:get_subtag(El1, - <<"required">>) - of - #xmlel{} -> - true; - false -> - false - end, - {SEXT, - true, - Req}; - _ -> Acc - end; - (_, Acc) -> Acc - end, - {false, false, - false}, - Els), - if not SASLEXT and not StartTLS and - StateData#state.authenticated -> - send_queue(StateData, StateData#state.queue), - ?INFO_MSG("Connection established: ~s -> ~s with " - "SASL EXTERNAL and TLS=~p", - [StateData#state.myname, StateData#state.server, - StateData#state.tls_enabled]), - ejabberd_hooks:run(s2s_connect_hook, - [StateData#state.myname, - StateData#state.server]), - {next_state, stream_established, - StateData#state{queue = queue:new()}}; - SASLEXT and StateData#state.try_auth and - (StateData#state.new /= false) and - (StateData#state.tls_enabled or - not StateData#state.tls_required) -> - send_element(StateData, - #xmlel{name = <<"auth">>, - attrs = - [{<<"xmlns">>, ?NS_SASL}, - {<<"mechanism">>, <<"EXTERNAL">>}], - children = - [{xmlcdata, - jlib:encode_base64(StateData#state.myname)}]}), - {next_state, wait_for_auth_result, - StateData#state{try_auth = false}, ?FSMTIMEOUT}; - StartTLS and StateData#state.tls and - not StateData#state.tls_enabled -> - send_element(StateData, - #xmlel{name = <<"starttls">>, - attrs = [{<<"xmlns">>, ?NS_TLS}], - children = []}), - {next_state, wait_for_starttls_proceed, StateData, - ?FSMTIMEOUT}; - StartTLSRequired and not StateData#state.tls -> - ?DEBUG("restarted: ~p", - [{StateData#state.myname, StateData#state.server}]), - ejabberd_socket:close(StateData#state.socket), - {next_state, reopen_socket, - StateData#state{socket = undefined, use_v10 = false}, - ?FSMTIMEOUT}; - StateData#state.db_enabled -> - send_db_request(StateData); - true -> - ?DEBUG("restarted: ~p", - [{StateData#state.myname, StateData#state.server}]), - ejabberd_socket:close(StateData#state.socket), - {next_state, reopen_socket, - StateData#state{socket = undefined, use_v10 = false}, - ?FSMTIMEOUT} - end; - _ -> - send_text(StateData, - <<(fxml:element_to_binary(?SERR_BAD_FORMAT))/binary, - (?STREAM_TRAILER)/binary>>), - ?INFO_MSG("Closing s2s connection: ~s -> ~s (bad " - "format)", - [StateData#state.myname, StateData#state.server]), - {stop, normal, StateData} + decode_element(El, wait_for_features, StateData); +wait_for_features(#stream_features{sub_els = Els}, StateData) -> + {SASLEXT, StartTLS, StartTLSRequired} = + lists:foldl( + fun(#sasl_mechanisms{list = Mechs}, {_, STLS, STLSReq}) -> + {lists:member(<<"EXTERNAL">>, Mechs), STLS, STLSReq}; + (#starttls{required = Required}, {SEXT, _, _}) -> + {SEXT, true, Required}; + (_, Acc) -> + Acc + end, {false, false, false}, Els), + if not SASLEXT and not StartTLS and StateData#state.authenticated -> + send_queue(StateData, StateData#state.queue), + ?INFO_MSG("Connection established: ~s -> ~s with " + "SASL EXTERNAL and TLS=~p", + [StateData#state.myname, StateData#state.server, + StateData#state.tls_enabled]), + ejabberd_hooks:run(s2s_connect_hook, + [StateData#state.myname, + StateData#state.server]), + {next_state, stream_established, + StateData#state{queue = queue:new()}}; + SASLEXT and StateData#state.try_auth and + (StateData#state.new /= false) and + (StateData#state.tls_enabled or + not StateData#state.tls_required) -> + send_element(StateData, + #sasl_auth{mechanism = <<"EXTERNAL">>, + text = StateData#state.myname}), + {next_state, wait_for_auth_result, + StateData#state{try_auth = false}, ?FSMTIMEOUT}; + StartTLS and StateData#state.tls and + not StateData#state.tls_enabled -> + send_element(StateData, #starttls{}), + {next_state, wait_for_starttls_proceed, StateData, ?FSMTIMEOUT}; + StartTLSRequired and not StateData#state.tls -> + ?DEBUG("restarted: ~p", + [{StateData#state.myname, StateData#state.server}]), + ejabberd_socket:close(StateData#state.socket), + {next_state, reopen_socket, + StateData#state{socket = undefined, use_v10 = false}, + ?FSMTIMEOUT}; + StateData#state.db_enabled -> + send_db_request(StateData); + true -> + ?DEBUG("restarted: ~p", + [{StateData#state.myname, StateData#state.server}]), + ejabberd_socket:close(StateData#state.socket), + {next_state, reopen_socket, + StateData#state{socket = undefined, use_v10 = false}, ?FSMTIMEOUT} end; -wait_for_features({xmlstreamend, _Name}, StateData) -> - ?INFO_MSG("wait_for_features: xmlstreamend", []), - {stop, normal, StateData}; -wait_for_features({xmlstreamerror, _}, StateData) -> - send_text(StateData, - <<(?INVALID_XML_ERR)/binary, - (?STREAM_TRAILER)/binary>>), - ?INFO_MSG("wait for features: xmlstreamerror", []), - {stop, normal, StateData}; -wait_for_features(timeout, StateData) -> - ?INFO_MSG("wait for features: timeout", []), - {stop, normal, StateData}; -wait_for_features(closed, StateData) -> - ?INFO_MSG("wait for features: closed", []), - {stop, normal, StateData}. +wait_for_features(Event, StateData) -> + handle_unexpected_event(Event, wait_for_features, StateData). -wait_for_auth_result({xmlstreamelement, El}, - StateData) -> - case El of - #xmlel{name = <<"success">>, attrs = Attrs} -> - case fxml:get_attr_s(<<"xmlns">>, Attrs) of - ?NS_SASL -> - ?DEBUG("auth: ~p", - [{StateData#state.myname, StateData#state.server}]), - ejabberd_socket:reset_stream(StateData#state.socket), - send_text(StateData, - io_lib:format(?STREAM_HEADER, - [StateData#state.myname, - StateData#state.server, - <<" version='1.0'">>])), - {next_state, wait_for_stream, - StateData#state{streamid = new_id(), - authenticated = true}, - ?FSMTIMEOUT}; - _ -> - send_text(StateData, - <<(fxml:element_to_binary(?SERR_BAD_FORMAT))/binary, - (?STREAM_TRAILER)/binary>>), - ?INFO_MSG("Closing s2s connection: ~s -> ~s (bad " - "format)", - [StateData#state.myname, StateData#state.server]), - {stop, normal, StateData} - end; - #xmlel{name = <<"failure">>, attrs = Attrs} -> - case fxml:get_attr_s(<<"xmlns">>, Attrs) of - ?NS_SASL -> - ?DEBUG("restarted: ~p", - [{StateData#state.myname, StateData#state.server}]), - ejabberd_socket:close(StateData#state.socket), - {next_state, reopen_socket, - StateData#state{socket = undefined}, ?FSMTIMEOUT}; - _ -> - send_text(StateData, - <<(fxml:element_to_binary(?SERR_BAD_FORMAT))/binary, - (?STREAM_TRAILER)/binary>>), - ?INFO_MSG("Closing s2s connection: ~s -> ~s (bad " - "format)", - [StateData#state.myname, StateData#state.server]), - {stop, normal, StateData} - end; - _ -> - send_text(StateData, - <<(fxml:element_to_binary(?SERR_BAD_FORMAT))/binary, - (?STREAM_TRAILER)/binary>>), - ?INFO_MSG("Closing s2s connection: ~s -> ~s (bad " - "format)", - [StateData#state.myname, StateData#state.server]), - {stop, normal, StateData} - end; -wait_for_auth_result({xmlstreamend, _Name}, - StateData) -> - ?INFO_MSG("wait for auth result: xmlstreamend", []), - {stop, normal, StateData}; -wait_for_auth_result({xmlstreamerror, _}, StateData) -> - send_text(StateData, - <<(?INVALID_XML_ERR)/binary, - (?STREAM_TRAILER)/binary>>), - ?INFO_MSG("wait for auth result: xmlstreamerror", []), - {stop, normal, StateData}; -wait_for_auth_result(timeout, StateData) -> - ?INFO_MSG("wait for auth result: timeout", []), - {stop, normal, StateData}; -wait_for_auth_result(closed, StateData) -> - ?INFO_MSG("wait for auth result: closed", []), - {stop, normal, StateData}. +wait_for_auth_result({xmlstreamelement, El}, StateData) -> + decode_element(El, wait_for_auth_result, StateData); +wait_for_auth_result(#sasl_success{}, StateData) -> + ?DEBUG("auth: ~p", [{StateData#state.myname, StateData#state.server}]), + ejabberd_socket:reset_stream(StateData#state.socket), + send_header(StateData, <<" version='1.0'">>), + {next_state, wait_for_stream, + StateData#state{streamid = new_id(), authenticated = true}, + ?FSMTIMEOUT}; +wait_for_auth_result(#sasl_failure{}, StateData) -> + ?DEBUG("restarted: ~p", [{StateData#state.myname, StateData#state.server}]), + ejabberd_socket:close(StateData#state.socket), + {next_state, reopen_socket, + StateData#state{socket = undefined}, ?FSMTIMEOUT}; +wait_for_auth_result(Event, StateData) -> + handle_unexpected_event(Event, wait_for_auth_result, StateData). -wait_for_starttls_proceed({xmlstreamelement, El}, - StateData) -> - case El of - #xmlel{name = <<"proceed">>, attrs = Attrs} -> - case fxml:get_attr_s(<<"xmlns">>, Attrs) of - ?NS_TLS -> - ?DEBUG("starttls: ~p", - [{StateData#state.myname, StateData#state.server}]), - Socket = StateData#state.socket, - TLSOpts = case - ejabberd_config:get_option( - {domain_certfile, StateData#state.myname}, - fun iolist_to_binary/1) - of - undefined -> StateData#state.tls_options; - CertFile -> - [{certfile, CertFile} - | lists:keydelete(certfile, 1, - StateData#state.tls_options)] - end, - TLSSocket = ejabberd_socket:starttls(Socket, TLSOpts), - NewStateData = StateData#state{socket = TLSSocket, - streamid = new_id(), - tls_enabled = true, - tls_options = TLSOpts}, - send_text(NewStateData, - io_lib:format(?STREAM_HEADER, - [NewStateData#state.myname, - NewStateData#state.server, - <<" version='1.0'">>])), - {next_state, wait_for_stream, NewStateData, - ?FSMTIMEOUT}; - _ -> - send_text(StateData, - <<(fxml:element_to_binary(?SERR_BAD_FORMAT))/binary, - (?STREAM_TRAILER)/binary>>), - ?INFO_MSG("Closing s2s connection: ~s -> ~s (bad " - "format)", - [StateData#state.myname, StateData#state.server]), - {stop, normal, StateData} - end; - _ -> - ?INFO_MSG("Closing s2s connection: ~s -> ~s (bad " - "format)", - [StateData#state.myname, StateData#state.server]), - {stop, normal, StateData} - end; -wait_for_starttls_proceed({xmlstreamend, _Name}, - StateData) -> - ?INFO_MSG("wait for starttls proceed: xmlstreamend", - []), - {stop, normal, StateData}; -wait_for_starttls_proceed({xmlstreamerror, _}, - StateData) -> - send_text(StateData, - <<(?INVALID_XML_ERR)/binary, - (?STREAM_TRAILER)/binary>>), - ?INFO_MSG("wait for starttls proceed: xmlstreamerror", - []), - {stop, normal, StateData}; -wait_for_starttls_proceed(timeout, StateData) -> - ?INFO_MSG("wait for starttls proceed: timeout", []), - {stop, normal, StateData}; -wait_for_starttls_proceed(closed, StateData) -> - ?INFO_MSG("wait for starttls proceed: closed", []), - {stop, normal, StateData}. +wait_for_starttls_proceed({xmlstreamelement, El}, StateData) -> + decode_element(El, wait_for_starttls_proceed, StateData); +wait_for_starttls_proceed(#starttls_proceed{}, StateData) -> + ?DEBUG("starttls: ~p", [{StateData#state.myname, StateData#state.server}]), + Socket = StateData#state.socket, + TLSOpts = case ejabberd_config:get_option( + {domain_certfile, StateData#state.myname}, + fun iolist_to_binary/1) of + undefined -> StateData#state.tls_options; + CertFile -> + [{certfile, CertFile} + | lists:keydelete(certfile, 1, + StateData#state.tls_options)] + end, + TLSSocket = ejabberd_socket:starttls(Socket, TLSOpts), + NewStateData = StateData#state{socket = TLSSocket, + streamid = new_id(), + tls_enabled = true, + tls_options = TLSOpts}, + send_header(NewStateData, <<" version='1.0'">>), + {next_state, wait_for_stream, NewStateData, ?FSMTIMEOUT}; +wait_for_starttls_proceed(Event, StateData) -> + handle_unexpected_event(Event, wait_for_starttls_proceed, StateData). reopen_socket({xmlstreamelement, _El}, StateData) -> {next_state, reopen_socket, StateData, ?FSMTIMEOUT}; @@ -797,47 +532,69 @@ relay_to_bridge(_Event, StateData) -> {next_state, relay_to_bridge, StateData}. stream_established({xmlstreamelement, El}, StateData) -> - ?DEBUG("s2S stream established", []), - case is_verify_res(El) of - {verify, VTo, VFrom, VId, VType} -> - ?DEBUG("recv verify: ~p", [{VFrom, VTo, VId, VType}]), - case StateData#state.verify of - {VPid, _VKey, _SID} -> - case VType of - <<"valid">> -> - p1_fsm:send_event(VPid, - {valid, StateData#state.server, - StateData#state.myname}); - _ -> - p1_fsm:send_event(VPid, - {invalid, StateData#state.server, - StateData#state.myname}) - end; - _ -> ok - end; - _ -> ok + decode_element(El, stream_established, StateData); +stream_established(#db_verify{to = VTo, from = VFrom, id = VId, type = VType}, + StateData) -> + ?DEBUG("recv verify: ~p", [{VFrom, VTo, VId, VType}]), + case StateData#state.verify of + {VPid, _VKey, _SID} -> + case VType of + valid -> + p1_fsm:send_event(VPid, + {valid, StateData#state.server, + StateData#state.myname}); + _ -> + p1_fsm:send_event(VPid, + {invalid, StateData#state.server, + StateData#state.myname}) + end; + _ -> ok end, {next_state, stream_established, StateData}; -stream_established({xmlstreamend, _Name}, StateData) -> - ?INFO_MSG("Connection closed in stream established: " - "~s -> ~s (xmlstreamend)", - [StateData#state.myname, StateData#state.server]), - {stop, normal, StateData}; -stream_established({xmlstreamerror, _}, StateData) -> - send_text(StateData, - <<(?INVALID_XML_ERR)/binary, - (?STREAM_TRAILER)/binary>>), - ?INFO_MSG("stream established: ~s -> ~s (xmlstreamerror)", - [StateData#state.myname, StateData#state.server]), - {stop, normal, StateData}; -stream_established(timeout, StateData) -> - ?INFO_MSG("stream established: ~s -> ~s (timeout)", - [StateData#state.myname, StateData#state.server]), - {stop, normal, StateData}; -stream_established(closed, StateData) -> - ?INFO_MSG("stream established: ~s -> ~s (closed)", - [StateData#state.myname, StateData#state.server]), - {stop, normal, StateData}. +stream_established(Event, StateData) -> + handle_unexpected_event(Event, stream_established, StateData). + +-spec handle_unexpected_event(term(), state_name(), state()) -> fsm_transition(). +handle_unexpected_event(Event, StateName, StateData) -> + case Event of + {xmlstreamerror, _} -> + send_element(StateData, xmpp:serr_not_well_formed()), + ?INFO_MSG("Closing s2s connection ~s -> ~s in state ~s: " + "got invalid XML from peer", + [StateData#state.myname, StateData#state.server, + StateName]), + {stop, normal, StateData}; + {xmlstreamend, _} -> + ?INFO_MSG("Closing s2s connection ~s -> ~s in state ~s: " + "XML stream closed by peer", + [StateData#state.myname, StateData#state.server]), + {stop, normal, StateData}; + timeout -> + send_element(StateData, xmpp:serr_connection_timeout()), + ?INFO_MSG("Closing s2s connection ~s -> ~s in state ~s: " + "timed out during establishing an XML stream", + [StateData#state.myname, StateData#state.server, + StateName]), + {stop, normal, StateData}; + closed -> + ?INFO_MSG("Closing s2s connection ~s -> ~s in state ~s: " + "connection socket closed", + [StateData#state.myname, StateData#state.server, + StateName]), + {stop, normal, StateData}; + Pkt when StateName == wait_for_stream; + StateName == wait_for_features; + StateName == wait_for_auth_result; + StateName == wait_for_starttls_proceed -> + send_element(StateData, xmpp:serr_bad_format()), + ?INFO_MSG("Closing s2s connection ~s -> ~s in state ~s: " + "got unexpected event ~p", + [StateData#state.myname, StateData#state.server, + StateName, Pkt]), + {stop, normal, StateData}; + _ -> + {next_state, StateName, StateData, get_timeout_interval(StateName)} + end. %%---------------------------------------------------------------------- %% Func: StateName/3 @@ -917,7 +674,7 @@ handle_info({send_element, El}, StateName, StateData) -> %% In this state we bounce all message: We are waiting before %% trying to reconnect wait_before_retry -> - bounce_element(El, ?ERR_REMOTE_SERVER_NOT_FOUND), + bounce_element(El, xmpp:err_remote_server_not_found()), {next_state, StateName, StateData}; relay_to_bridge -> {Mod, Fun} = StateData#state.bridge, @@ -926,7 +683,7 @@ handle_info({send_element, El}, StateName, StateData) -> {'EXIT', Reason} -> ?ERROR_MSG("Error while relaying to bridge: ~p", [Reason]), - bounce_element(El, ?ERR_INTERNAL_SERVER_ERROR), + bounce_element(El, xmpp:err_internal_server_error()), wait_before_reconnect(StateData); _ -> {next_state, StateName, StateData} end; @@ -966,12 +723,13 @@ terminate(Reason, StateName, StateData) -> StateData#state.server}, self()) end, - bounce_queue(StateData#state.queue, - ?ERR_REMOTE_SERVER_NOT_FOUND), - bounce_messages(?ERR_REMOTE_SERVER_NOT_FOUND), + bounce_queue(StateData#state.queue, xmpp:err_remote_server_not_found()), + bounce_messages(xmpp:err_remote_server_not_found()), case StateData#state.socket of undefined -> ok; - _Socket -> ejabberd_socket:close(StateData#state.socket) + _Socket -> + catch send_trailer(StateData), + ejabberd_socket:close(StateData#state.socket) end, ok. @@ -981,12 +739,30 @@ print_state(State) -> State. %%% Internal functions %%%---------------------------------------------------------------------- +-spec send_text(state(), iodata()) -> ok. send_text(StateData, Text) -> ejabberd_socket:send(StateData#state.socket, Text). +-spec send_element(state(), xmpp_element()) -> ok. send_element(StateData, El) -> - send_text(StateData, fxml:element_to_binary(El)). + El1 = fix_ns(xmpp:encode(El)), + send_text(StateData, fxml:element_to_binary(El1)). +-spec send_header(state(), binary()) -> ok. +send_header(StateData, Version) -> + Txt = io_lib:format( + "", + [StateData#state.myname, StateData#state.server, Version]), + send_text(StateData, Txt). + +-spec send_trailer(state()) -> ok. +send_trailer(StateData) -> + send_text(StateData, <<"">>). + +-spec send_queue(state(), queue:queue()) -> ok. send_queue(StateData, Q) -> case queue:out(Q) of {{value, El}, Q1} -> @@ -994,21 +770,28 @@ send_queue(StateData, Q) -> {empty, _Q1} -> ok end. -%% Bounce a single message (xmlelement) -bounce_element(El, Error) -> - #xmlel{attrs = Attrs} = El, - case fxml:get_attr_s(<<"type">>, Attrs) of - <<"error">> -> ok; - <<"result">> -> ok; - _ -> - Err = jlib:make_error_reply(El, Error), - From = jid:from_string(fxml:get_tag_attr_s(<<"from">>, - El)), - To = jid:from_string(fxml:get_tag_attr_s(<<"to">>, - El)), - ejabberd_router:route(To, From, Err) - end. +-spec fix_ns(xmlel()) -> xmlel(). +fix_ns(#xmlel{name = Name} = El) when Name == <<"message">>; + Name == <<"iq">>; + Name == <<"presence">>; + Name == <<"db:verify">>, + Name == <<"db:result">> -> + Attrs = lists:filter( + fun({<<"xmlns">>, _}) -> false; + (_) -> true + end, El#xmlel.attrs), + El#xmlel{attrs = Attrs}; +fix_ns(El) -> + El. +%% Bounce a single message (xmlelement) +-spec bounce_element(stanza(), error()) -> ok. +bounce_element(El, Error) -> + From = xmpp:get_from(El), + To = xmpp:get_to(El), + ejabberd_router:route_error(To, From, El, Error). + +-spec bounce_queue(queue:queue(), error()) -> ok. bounce_queue(Q, Error) -> case queue:out(Q) of {{value, El}, Q1} -> @@ -1016,12 +799,15 @@ bounce_queue(Q, Error) -> {empty, _} -> ok end. +-spec new_id() -> binary(). new_id() -> randoms:get_string(). +-spec cancel_timer(reference()) -> ok. cancel_timer(Timer) -> erlang:cancel_timer(Timer), receive {timeout, Timer, _} -> ok after 0 -> ok end. +-spec bounce_messages(error()) -> ok. bounce_messages(Error) -> receive {send_element, El} -> @@ -1029,6 +815,7 @@ bounce_messages(Error) -> after 0 -> ok end. +-spec send_db_request(state()) -> fsm_transition(). send_db_request(StateData) -> Server = StateData#state.server, New = case StateData#state.new of @@ -1045,22 +832,18 @@ send_db_request(StateData) -> {StateData#state.myname, Server}, StateData#state.remote_streamid), send_element(StateData, - #xmlel{name = <<"db:result">>, - attrs = - [{<<"from">>, StateData#state.myname}, - {<<"to">>, Server}], - children = [{xmlcdata, Key1}]}) + #db_result{from = jid:make(StateData#state.myname), + to = jid:make(Server), + key = Key1}) end, case StateData#state.verify of false -> ok; {_Pid, Key2, SID} -> send_element(StateData, - #xmlel{name = <<"db:verify">>, - attrs = - [{<<"from">>, StateData#state.myname}, - {<<"to">>, StateData#state.server}, - {<<"id">>, SID}], - children = [{xmlcdata, Key2}]}) + #db_verify{from = jid:make(StateData#state.myname), + to = StateData#state.server, + id = SID, + key = Key2}) end, {next_state, wait_for_validation, NewStateData, (?FSMTIMEOUT) * 6} @@ -1068,20 +851,6 @@ send_db_request(StateData) -> _:_ -> {stop, normal, NewStateData} end. -is_verify_res(#xmlel{name = Name, attrs = Attrs}) - when Name == <<"db:result">> -> - {result, fxml:get_attr_s(<<"to">>, Attrs), - fxml:get_attr_s(<<"from">>, Attrs), - fxml:get_attr_s(<<"id">>, Attrs), - fxml:get_attr_s(<<"type">>, Attrs)}; -is_verify_res(#xmlel{name = Name, attrs = Attrs}) - when Name == <<"db:verify">> -> - {verify, fxml:get_attr_s(<<"to">>, Attrs), - fxml:get_attr_s(<<"from">>, Attrs), - fxml:get_attr_s(<<"id">>, Attrs), - fxml:get_attr_s(<<"type">>, Attrs)}; -is_verify_res(_) -> false. - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% SRV support @@ -1190,12 +959,14 @@ get_addrs(Host, Family) -> [] end. +-spec outgoing_s2s_port() -> pos_integer(). outgoing_s2s_port() -> ejabberd_config:get_option( outgoing_s2s_port, fun(I) when is_integer(I), I > 0, I =< 65536 -> I end, 5269). +-spec outgoing_s2s_families() -> [ipv4 | ipv6]. outgoing_s2s_families() -> ejabberd_config:get_option( outgoing_s2s_families, @@ -1207,6 +978,7 @@ outgoing_s2s_families() -> Families end, [ipv4, ipv6]). +-spec outgoing_s2s_timeout() -> pos_integer(). outgoing_s2s_timeout() -> ejabberd_config:get_option( outgoing_s2s_timeout, @@ -1256,21 +1028,24 @@ log_s2s_out(_, Myname, Server, Tls) -> %% Calculate timeout depending on which state we are in: %% Can return integer > 0 | infinity +-spec get_timeout_interval(state_name()) -> pos_integer() | infinity. get_timeout_interval(StateName) -> case StateName of %% Validation implies dialback: Networking can take longer: wait_for_validation -> (?FSMTIMEOUT) * 6; %% When stream is established, we only rely on S2S Timeout timer: stream_established -> infinity; + relay_to_bridge -> infinity; + open_socket -> infinity; _ -> ?FSMTIMEOUT end. %% This function is intended to be called at the end of a state %% function that want to wait for a reconnect delay before stopping. +-spec wait_before_reconnect(state()) -> fsm_next(). wait_before_reconnect(StateData) -> - bounce_queue(StateData#state.queue, - ?ERR_REMOTE_SERVER_NOT_FOUND), - bounce_messages(?ERR_REMOTE_SERVER_NOT_FOUND), + bounce_queue(StateData#state.queue, xmpp:err_remote_server_not_found()), + bounce_messages(xmpp:err_remote_server_not_found()), cancel_timer(StateData#state.timer), Delay = case StateData#state.delay_to_retry of undefined_delay -> @@ -1282,6 +1057,7 @@ wait_before_reconnect(StateData) -> StateData#state{timer = Timer, delay_to_retry = Delay, queue = queue:new()}}. +-spec get_max_retry_delay() -> pos_integer(). get_max_retry_delay() -> case ejabberd_config:get_option( s2s_max_retry_delay, @@ -1291,6 +1067,7 @@ get_max_retry_delay() -> end. %% Terminate s2s_out connections that are in state wait_before_retry +-spec terminate_if_waiting_delay(ljid(), ljid()) -> ok. terminate_if_waiting_delay(From, To) -> FromTo = {From, To}, Pids = ejabberd_s2s:get_connections_pids(FromTo), @@ -1299,6 +1076,7 @@ terminate_if_waiting_delay(From, To) -> end, Pids). +-spec fsm_limit_opts() -> [{max_queue, pos_integer()}]. fsm_limit_opts() -> case ejabberd_config:get_option( max_fsm_queue, @@ -1307,6 +1085,24 @@ fsm_limit_opts() -> N -> [{max_queue, N}] end. +-spec decode_element(xmlel(), state_name(), state()) -> fsm_next(). +decode_element(#xmlel{} = El, StateName, StateData) -> + try xmpp:decode(El) of + Pkt -> ?MODULE:StateName(Pkt, StateData) + catch error:{xmpp_codec, Why} -> + Type = xmpp:get_type(El), + case xmpp:is_stanza(El) of + true when Type /= <<"result">>, Type /= <<"error">> -> + Lang = xmpp:get_lang(El), + Txt = xmpp:format_error(Why), + Err = xmpp:make_error(El, xmpp:err_bad_request(Txt, Lang)), + send_element(StateData, Err); + false -> + ok + end, + {next_state, StateName, StateData, get_timeout_interval(StateName)} + end. + opt_type(domain_certfile) -> fun iolist_to_binary/1; opt_type(max_fsm_queue) -> fun (I) when is_integer(I), I > 0 -> I end; diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index 465fb587a..432253e09 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -46,8 +46,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). - --include("jlib.hrl"). +-include("xmpp.hrl"). -record(state, {socket :: ejabberd_socket:socket_state(), @@ -58,44 +57,19 @@ access :: atom(), check_from = true :: boolean()}). +-type state_name() :: wait_for_stream | wait_for_handshake | stream_established. +-type state() :: #state{}. +-type fsm_next() :: {next_state, state_name(), state()}. +-type fsm_stop() :: {stop, normal, state()}. +-type fsm_transition() :: fsm_stop() | fsm_next(). + %-define(DBGFSM, true). - -ifdef(DBGFSM). - -define(FSMOPTS, [{debug, [trace]}]). - -else. - -define(FSMOPTS, []). - -endif. --define(STREAM_HEADER, - <<"">>). - --define(STREAM_TRAILER, <<"">>). - --define(INVALID_HEADER_ERR, - <<"Invalid " - "Stream Header">>). - --define(INVALID_HANDSHAKE_ERR, - <<"Invalid Handshake">>). - --define(INVALID_XML_ERR, - fxml:element_to_binary(?SERR_XML_NOT_WELL_FORMED)). - --define(INVALID_NS_ERR, - fxml:element_to_binary(?SERR_INVALID_NAMESPACE)). - %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- @@ -112,14 +86,6 @@ socket_type() -> xml_stream. %%%---------------------------------------------------------------------- %%% 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("(~w) External service connected", [Socket]), Access = case lists:keysearch(access, 1, Opts) of @@ -157,177 +123,127 @@ init([{SockMod, Socket}, Opts]) -> streamid = new_id(), host_opts = HostOpts, access = Access, check_from = CheckFrom}}. -%%---------------------------------------------------------------------- -%% Func: StateName/2 -%% Returns: {next_state, NextStateName, NextStateData} | -%% {next_state, NextStateName, NextStateData, Timeout} | -%% {stop, Reason, NewStateData} -%%---------------------------------------------------------------------- - -wait_for_stream({xmlstreamstart, _Name, Attrs}, - StateData) -> - case fxml:get_attr_s(<<"xmlns">>, Attrs) of - <<"jabber:component:accept">> -> - To = fxml:get_attr_s(<<"to">>, Attrs), - Host = jid:nameprep(To), - if Host == error -> - Header = io_lib:format(?STREAM_HEADER, - [<<"none">>, ?MYNAME]), - send_text(StateData, - <<(list_to_binary(Header))/binary, - (?INVALID_XML_ERR)/binary, - (?STREAM_TRAILER)/binary>>), - {stop, normal, StateData}; - true -> - Header = io_lib:format(?STREAM_HEADER, - [StateData#state.streamid, fxml:crypt(To)]), - send_text(StateData, Header), - HostOpts = case dict:is_key(Host, StateData#state.host_opts) of - true -> - StateData#state.host_opts; - false -> - case dict:find(global, StateData#state.host_opts) of - {ok, GlobalPass} -> - dict:from_list([{Host, GlobalPass}]); - error -> - StateData#state.host_opts - end - end, - {next_state, wait_for_handshake, - StateData#state{host = Host, host_opts = HostOpts}} - end; - _ -> - send_text(StateData, ?INVALID_HEADER_ERR), - {stop, normal, StateData} +wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) -> + try xmpp:decode(#xmlel{name = Name, attrs = Attrs}) of + #stream_start{xmlns = ?NS_COMPONENT, to = To} when is_record(To, jid) -> + Host = To#jid.lserver, + send_header(StateData, To), + HostOpts = case dict:is_key(Host, StateData#state.host_opts) of + true -> + StateData#state.host_opts; + false -> + case dict:find(global, StateData#state.host_opts) of + {ok, GlobalPass} -> + dict:from_list([{Host, GlobalPass}]); + error -> + StateData#state.host_opts + end + end, + {next_state, wait_for_handshake, + StateData#state{host = Host, host_opts = HostOpts}}; + #stream_start{xmlns = ?NS_COMPONENT} -> + send_header(StateData, ?MYNAME), + send_element(StateData, xmpp:serr_improper_addressing()), + {stop, normal, StateData}; + #stream_start{} -> + send_header(StateData, ?MYNAME), + send_element(StateData, xmpp:serr_invalid_namespace()), + {stop, normal, StateData} + catch _:{xmpp_codec, Why} -> + Txt = xmpp:format_error(Why), + send_header(StateData, ?MYNAME), + send_element(StateData, xmpp:serr_invalid_xml(Txt, ?MYLANG)), + {stop, normal, StateData} end; wait_for_stream({xmlstreamerror, _}, StateData) -> - Header = io_lib:format(?STREAM_HEADER, - [<<"none">>, ?MYNAME]), - send_text(StateData, - <<(list_to_binary(Header))/binary, (?INVALID_XML_ERR)/binary, - (?STREAM_TRAILER)/binary>>), + send_header(StateData, ?MYNAME), + send_element(StateData, xmpp:serr_not_well_formed()), {stop, normal, StateData}; wait_for_stream(closed, StateData) -> {stop, normal, StateData}. wait_for_handshake({xmlstreamelement, El}, StateData) -> - #xmlel{name = Name, children = Els} = El, - case {Name, fxml:get_cdata(Els)} of - {<<"handshake">>, Digest} -> - case dict:find(StateData#state.host, StateData#state.host_opts) of - {ok, Password} -> - case p1_sha:sha(<<(StateData#state.streamid)/binary, - Password/binary>>) of - Digest -> - send_text(StateData, <<"">>), - lists:foreach( - fun (H) -> - ejabberd_router:register_route(H, ?MYNAME), - ?INFO_MSG("Route registered for service ~p~n", - [H]) - end, dict:fetch_keys(StateData#state.host_opts)), - {next_state, stream_established, StateData}; - _ -> - send_text(StateData, ?INVALID_HANDSHAKE_ERR), - {stop, normal, StateData} - end; - _ -> - send_text(StateData, ?INVALID_HANDSHAKE_ERR), - {stop, normal, StateData} - end; - _ -> {next_state, wait_for_handshake, StateData} + decode_element(El, wait_for_handshake, StateData); +wait_for_handshake(#handshake{data = Digest}, StateData) -> + case dict:find(StateData#state.host, StateData#state.host_opts) of + {ok, Password} -> + case p1_sha:sha(<<(StateData#state.streamid)/binary, + Password/binary>>) of + Digest -> + send_element(StateData, #handshake{}), + lists:foreach( + fun (H) -> + ejabberd_router:register_route(H, ?MYNAME), + ?INFO_MSG("Route registered for service ~p~n", + [H]) + end, dict:fetch_keys(StateData#state.host_opts)), + {next_state, stream_established, StateData}; + _ -> + send_element(StateData, xmpp:serr_not_authorized()), + {stop, normal, StateData} + end; + _ -> + send_element(StateData, xmpp:serr_not_authorized()), + {stop, normal, StateData} end; wait_for_handshake({xmlstreamend, _Name}, StateData) -> {stop, normal, StateData}; wait_for_handshake({xmlstreamerror, _}, StateData) -> - send_text(StateData, - <<(?INVALID_XML_ERR)/binary, - (?STREAM_TRAILER)/binary>>), + send_element(StateData, xmpp:serr_not_well_formed()), {stop, normal, StateData}; wait_for_handshake(closed, StateData) -> - {stop, normal, StateData}. + {stop, normal, StateData}; +wait_for_handshake(_Pkt, StateData) -> + {next_state, wait_for_handshake, StateData}. stream_established({xmlstreamelement, El}, StateData) -> - NewEl = jlib:remove_attr(<<"xmlns">>, El), - #xmlel{name = Name, attrs = Attrs} = NewEl, - From = fxml:get_attr_s(<<"from">>, Attrs), - FromJID = case StateData#state.check_from of - %% If the admin does not want to check the from field - %% when accept packets from any address. - %% In this case, the component can send packet of - %% behalf of the server users. - false -> jid:from_string(From); - %% The default is the standard behaviour in XEP-0114 - _ -> - FromJID1 = jid:from_string(From), - case FromJID1 of - #jid{lserver = Server} -> - case dict:is_key(Server, StateData#state.host_opts) of - true -> FromJID1; - false -> error - end; - _ -> error - end - end, - To = fxml:get_attr_s(<<"to">>, Attrs), - ToJID = case To of - <<"">> -> error; - _ -> jid:from_string(To) - end, - if ((Name == <<"iq">>) or (Name == <<"message">>) or - (Name == <<"presence">>)) - and (ToJID /= error) - and (FromJID /= error) -> - ejabberd_router:route(FromJID, ToJID, NewEl); + decode_element(El, stream_established, StateData); +stream_established(El, StateData) when ?is_stanza(El) -> + From = xmpp:get_from(El), + To = xmpp:get_to(El), + Lang = xmpp:get_lang(El), + if From == undefined orelse To == undefined -> + send_error(StateData, El, xmpp:err_jid_malformed()); true -> - Lang = fxml:get_tag_attr_s(<<"xml:lang">>, El), - Txt = <<"Incorrect stanza name or from/to JID">>, - Err = jlib:make_error_reply(NewEl, ?ERRT_BAD_REQUEST(Lang, Txt)), - send_element(StateData, Err), - error + FromJID = case StateData#state.check_from of + false -> + %% If the admin does not want to check the from field + %% when accept packets from any address. + %% In this case, the component can send packet of + %% behalf of the server users. + From; + _ -> + %% The default is the standard behaviour in XEP-0114 + case From of + #jid{lserver = Server} -> + case dict:is_key(Server, StateData#state.host_opts) of + true -> From; + false -> error + end; + _ -> error + end + end, + if FromJID /= error -> + ejabberd_router:route(FromJID, To, El); + true -> + Txt = <<"Incorrect value of 'from' or 'to' attribute">>, + send_error(StateData, El, xmpp:err_not_allowed(Txt, Lang)) + end end, {next_state, stream_established, StateData}; stream_established({xmlstreamend, _Name}, StateData) -> {stop, normal, StateData}; stream_established({xmlstreamerror, _}, StateData) -> - send_text(StateData, - <<(?INVALID_XML_ERR)/binary, - (?STREAM_TRAILER)/binary>>), + send_element(StateData, xmpp:serr_not_well_formed()), {stop, normal, StateData}; stream_established(closed, StateData) -> - {stop, normal, StateData}. + {stop, normal, StateData}; +stream_established(_Event, StateData) -> + {next_state, stream_established, 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}. @@ -335,12 +251,6 @@ handle_sync_event(_Event, _From, StateName, 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({send_text, Text}, StateName, StateData) -> send_text(StateData, Text), {next_state, StateName, StateData}; @@ -349,34 +259,20 @@ handle_info({send_element, El}, StateName, StateData) -> {next_state, StateName, StateData}; handle_info({route, From, To, Packet}, StateName, StateData) -> - case acl:match_rule(global, StateData#state.access, - From) - of + case acl:match_rule(global, StateData#state.access, From) of allow -> - #xmlel{name = Name, attrs = Attrs, children = Els} = - Packet, - Attrs2 = - jlib:replace_from_to_attrs(jid:to_string(From), - jid:to_string(To), Attrs), - Text = fxml:element_to_binary(#xmlel{name = Name, - attrs = Attrs2, children = Els}), - send_text(StateData, Text); - deny -> - Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), - Txt = <<"Denied by ACL">>, - Err = jlib:make_error_reply(Packet, ?ERRT_NOT_ALLOWED(Lang, Txt)), - ejabberd_router:route_error(To, From, Err, Packet) + Pkt = xmpp:set_from_to(Packet, From, To), + send_element(StateData, Pkt); + deny -> + Lang = xmpp:get_lang(Packet), + Err = xmpp:err_not_allowed(<<"Denied by ACL">>, Lang), + ejabberd_router:route_error(To, From, Packet, Err) end, {next_state, StateName, StateData}; handle_info(Info, StateName, StateData) -> ?ERROR_MSG("Unexpected info: ~p", [Info]), {next_state, StateName, StateData}. -%%---------------------------------------------------------------------- -%% Func: terminate/3 -%% Purpose: Shutdown the fsm -%% Returns: any -%%---------------------------------------------------------------------- terminate(Reason, StateName, StateData) -> ?INFO_MSG("terminated: ~p", [Reason]), case StateName of @@ -387,6 +283,7 @@ terminate(Reason, StateName, StateData) -> dict:fetch_keys(StateData#state.host_opts)); _ -> ok end, + catch send_trailer(StateData), (StateData#state.sockmod):close(StateData#state.socket), ok. @@ -401,13 +298,69 @@ print_state(State) -> State. %%% Internal functions %%%---------------------------------------------------------------------- +-spec send_text(state(), iodata()) -> ok. send_text(StateData, Text) -> (StateData#state.sockmod):send(StateData#state.socket, Text). +-spec send_element(state(), xmpp_element()) -> ok. send_element(StateData, El) -> - send_text(StateData, fxml:element_to_binary(El)). + El1 = fix_ns(xmpp:encode(El)), + send_text(StateData, fxml:element_to_binary(El1)). +-spec send_error(state(), xmlel() | stanza(), error()) -> ok. +send_error(StateData, Stanza, Error) -> + Type = xmpp:get_type(Stanza), + if Type == error; Type == result; + Type == <<"error">>; Type == <<"result">> -> + ok; + true -> + send_element(StateData, xmpp:make_error(Stanza, Error)) + end. + +-spec send_header(state(), binary()) -> ok. +send_header(StateData, Host) -> + send_text(StateData, + io_lib:format( + <<"">>, + [StateData#state.streamid, fxml:crypt(Host)])). + +-spec send_trailer(state()) -> ok. +send_trailer(StateData) -> + send_text(StateData, <<"">>). + +-spec fix_ns(xmlel()) -> xmlel(). +fix_ns(#xmlel{name = Name} = El) when Name == <<"message">>; + Name == <<"iq">>; + Name == <<"presence">> -> + Attrs = lists:filter( + fun({<<"xmlns">>, _}) -> false; + (_) -> true + end, El#xmlel.attrs), + El#xmlel{attrs = Attrs}; +fix_ns(El) -> + El. + +-spec decode_element(xmlel(), state_name(), state()) -> fsm_transition(). +decode_element(#xmlel{} = El, StateName, StateData) -> + try xmpp:decode(El, [ignore_els]) of + Pkt -> ?MODULE:StateName(Pkt, StateData) + catch error:{xmpp_codec, Why} -> + case xmpp:is_stanza(El) of + true -> + Lang = xmpp:get_lang(El), + Txt = xmpp:format_error(Why), + send_error(StateData, El, xmpp:err_bad_request(Txt, Lang)); + false -> + ok + end, + {next_state, StateName, StateData} + end. + +-spec new_id() -> binary(). new_id() -> randoms:get_string(). transform_listen_option({hosts, Hosts, O}, Opts) -> diff --git a/src/xmpp.erl b/src/xmpp.erl index 369fb90c5..5b7e3d1cc 100644 --- a/src/xmpp.erl +++ b/src/xmpp.erl @@ -71,10 +71,6 @@ serr_unsupported_stanza_type/0, serr_unsupported_stanza_type/2, serr_unsupported_version/0, serr_unsupported_version/2]). --ifndef(NS_CLIENT). --define(NS_CLIENT, <<"jabber:client">>). --endif. - -include("xmpp.hrl"). %%%=================================================================== @@ -246,9 +242,14 @@ get_name(Pkt) -> decode(El) -> decode(El, []). --spec decode(xmlel() | xmpp_element(), [proplists:property()]) -> +-spec decode(xmlel() | xmpp_element(), + [proplists:property()] | + fun((xmlel() | xmpp_element()) -> boolean())) -> {ok, xmpp_element()} | {error, any()}. -decode(#xmlel{} = El, Opts) -> +decode(#xmlel{} = El, MatchFun) when is_function(MatchFun) -> + Pkt = xmpp_codec:decode(add_ns(El), [ignore_els]), + decode_els(Pkt, MatchFun); +decode(#xmlel{} = El, Opts) when is_list(Opts) -> xmpp_codec:decode(add_ns(El), Opts); decode(Pkt, _Opts) -> Pkt. diff --git a/src/xmpp_codec.erl b/src/xmpp_codec.erl index c8a4f002f..7eb06b11e 100644 --- a/src/xmpp_codec.erl +++ b/src/xmpp_codec.erl @@ -15,6 +15,21 @@ decode(_el) -> decode(_el, []). decode({xmlel, _name, _attrs, _} = _el, Opts) -> IgnoreEls = proplists:get_bool(ignore_els, Opts), case {_name, get_attr(<<"xmlns">>, _attrs)} of + {<<"stream:stream">>, <<"jabber:client">>} -> + decode_stream_start(<<"jabber:client">>, IgnoreEls, + _el); + {<<"stream:stream">>, <<"jabber:server">>} -> + decode_stream_start(<<"jabber:server">>, IgnoreEls, + _el); + {<<"stream:stream">>, <<"jabber:component:accept">>} -> + decode_stream_start(<<"jabber:component:accept">>, + IgnoreEls, _el); + {<<"handshake">>, <<"jabber:client">>} -> + decode_handshake(<<"jabber:client">>, IgnoreEls, _el); + {<<"db:verify">>, <<"jabber:client">>} -> + decode_db_verify(<<"jabber:client">>, IgnoreEls, _el); + {<<"db:result">>, <<"jabber:client">>} -> + decode_db_result(<<"jabber:client">>, IgnoreEls, _el); {<<"command">>, <<"http://jabber.org/protocol/commands">>} -> decode_adhoc_command(<<"http://jabber.org/protocol/commands">>, @@ -1278,6 +1293,13 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> is_known_tag({xmlel, _name, _attrs, _} = _el) -> case {_name, get_attr(<<"xmlns">>, _attrs)} of + {<<"stream:stream">>, <<"jabber:client">>} -> true; + {<<"stream:stream">>, <<"jabber:server">>} -> true; + {<<"stream:stream">>, <<"jabber:component:accept">>} -> + true; + {<<"handshake">>, <<"jabber:client">>} -> true; + {<<"db:verify">>, <<"jabber:client">>} -> true; + {<<"db:result">>, <<"jabber:client">>} -> true; {<<"command">>, <<"http://jabber.org/protocol/commands">>} -> true; @@ -2538,7 +2560,19 @@ encode({adhoc_command, _, _, _, _, _, _, _, _} = Command) -> encode_adhoc_command(Command, [{<<"xmlns">>, - <<"http://jabber.org/protocol/commands">>}]). + <<"http://jabber.org/protocol/commands">>}]); +encode({db_result, _, _, _, _, _} = Db_result) -> + encode_db_result(Db_result, + [{<<"xmlns">>, <<"jabber:client">>}]); +encode({db_verify, _, _, _, _, _, _} = Db_verify) -> + encode_db_verify(Db_verify, + [{<<"xmlns">>, <<"jabber:client">>}]); +encode({handshake, _} = Handshake) -> + encode_handshake(Handshake, + [{<<"xmlns">>, <<"jabber:client">>}]); +encode({stream_start, _, _, _, _, _, _, _, _} = + Stream_stream) -> + encode_stream_start(Stream_stream, []). get_name({last, _, _}) -> <<"query">>; get_name({version, _, _, _}) -> <<"query">>; @@ -2720,7 +2754,13 @@ get_name({client_id, _}) -> <<"client-id">>; get_name({adhoc_actions, _, _, _, _}) -> <<"actions">>; get_name({adhoc_note, _, _}) -> <<"note">>; get_name({adhoc_command, _, _, _, _, _, _, _, _}) -> - <<"command">>. + <<"command">>; +get_name({db_result, _, _, _, _, _}) -> <<"db:result">>; +get_name({db_verify, _, _, _, _, _, _}) -> + <<"db:verify">>; +get_name({handshake, _}) -> <<"handshake">>; +get_name({stream_start, _, _, _, _, _, _, _, _}) -> + <<"stream:stream">>. get_ns({last, _, _}) -> <<"jabber:iq:last">>; get_ns({version, _, _, _}) -> <<"jabber:iq:version">>; @@ -2974,7 +3014,14 @@ get_ns({adhoc_actions, _, _, _, _}) -> get_ns({adhoc_note, _, _}) -> <<"http://jabber.org/protocol/commands">>; get_ns({adhoc_command, _, _, _, _, _, _, _, _}) -> - <<"http://jabber.org/protocol/commands">>. + <<"http://jabber.org/protocol/commands">>; +get_ns({db_result, _, _, _, _, _}) -> + <<"jabber:client">>; +get_ns({db_verify, _, _, _, _, _, _}) -> + <<"jabber:client">>; +get_ns({handshake, _}) -> <<"jabber:client">>; +get_ns({stream_start, _, _, _, _, Xmlns, _, _, _}) -> + Xmlns. dec_int(Val) -> dec_int(Val, infinity, infinity). @@ -3210,6 +3257,12 @@ pp(adhoc_note, 2) -> [type, data]; pp(adhoc_command, 8) -> [node, action, sid, status, lang, actions, notes, xdata]; +pp(db_result, 5) -> [from, to, type, key, error]; +pp(db_verify, 6) -> [from, to, id, type, key, error]; +pp(handshake, 1) -> [data]; +pp(stream_start, 8) -> + [from, to, id, version, xmlns, stream_xmlns, db_xmlns, + lang]; pp(_, _) -> no. join([], _Sep) -> <<>>; @@ -3256,6 +3309,478 @@ dec_tzo(Val) -> M = jlib:binary_to_integer(M1), if H >= -12, H =< 12, M >= 0, M < 60 -> {H, M} end. +decode_stream_start(__TopXMLNS, __IgnoreEls, + {xmlel, <<"stream:stream">>, _attrs, _els}) -> + {From, To, Xmlns, Stream_xmlns, Db_xmlns, Lang, Version, + Id} = + decode_stream_start_attrs(__TopXMLNS, _attrs, undefined, + undefined, undefined, undefined, undefined, + undefined, undefined, undefined), + {stream_start, From, To, Id, Version, Xmlns, + Stream_xmlns, Db_xmlns, Lang}. + +decode_stream_start_attrs(__TopXMLNS, + [{<<"from">>, _val} | _attrs], _From, To, Xmlns, + Stream_xmlns, Db_xmlns, Lang, Version, Id) -> + decode_stream_start_attrs(__TopXMLNS, _attrs, _val, To, + Xmlns, Stream_xmlns, Db_xmlns, Lang, Version, Id); +decode_stream_start_attrs(__TopXMLNS, + [{<<"to">>, _val} | _attrs], From, _To, Xmlns, + Stream_xmlns, Db_xmlns, Lang, Version, Id) -> + decode_stream_start_attrs(__TopXMLNS, _attrs, From, + _val, Xmlns, Stream_xmlns, Db_xmlns, Lang, + Version, Id); +decode_stream_start_attrs(__TopXMLNS, + [{<<"xmlns">>, _val} | _attrs], From, To, _Xmlns, + Stream_xmlns, Db_xmlns, Lang, Version, Id) -> + decode_stream_start_attrs(__TopXMLNS, _attrs, From, To, + _val, Stream_xmlns, Db_xmlns, Lang, Version, Id); +decode_stream_start_attrs(__TopXMLNS, + [{<<"xmlns:stream">>, _val} | _attrs], From, To, + Xmlns, _Stream_xmlns, Db_xmlns, Lang, Version, Id) -> + decode_stream_start_attrs(__TopXMLNS, _attrs, From, To, + Xmlns, _val, Db_xmlns, Lang, Version, Id); +decode_stream_start_attrs(__TopXMLNS, + [{<<"xmlns:db">>, _val} | _attrs], From, To, Xmlns, + Stream_xmlns, _Db_xmlns, Lang, Version, Id) -> + decode_stream_start_attrs(__TopXMLNS, _attrs, From, To, + Xmlns, Stream_xmlns, _val, Lang, Version, Id); +decode_stream_start_attrs(__TopXMLNS, + [{<<"xml:lang">>, _val} | _attrs], From, To, Xmlns, + Stream_xmlns, Db_xmlns, _Lang, Version, Id) -> + decode_stream_start_attrs(__TopXMLNS, _attrs, From, To, + Xmlns, Stream_xmlns, Db_xmlns, _val, Version, Id); +decode_stream_start_attrs(__TopXMLNS, + [{<<"version">>, _val} | _attrs], From, To, Xmlns, + Stream_xmlns, Db_xmlns, Lang, _Version, Id) -> + decode_stream_start_attrs(__TopXMLNS, _attrs, From, To, + Xmlns, Stream_xmlns, Db_xmlns, Lang, _val, Id); +decode_stream_start_attrs(__TopXMLNS, + [{<<"id">>, _val} | _attrs], From, To, Xmlns, + Stream_xmlns, Db_xmlns, Lang, Version, _Id) -> + decode_stream_start_attrs(__TopXMLNS, _attrs, From, To, + Xmlns, Stream_xmlns, Db_xmlns, Lang, Version, + _val); +decode_stream_start_attrs(__TopXMLNS, [_ | _attrs], + From, To, Xmlns, Stream_xmlns, Db_xmlns, Lang, + Version, Id) -> + decode_stream_start_attrs(__TopXMLNS, _attrs, From, To, + Xmlns, Stream_xmlns, Db_xmlns, Lang, Version, Id); +decode_stream_start_attrs(__TopXMLNS, [], From, To, + Xmlns, Stream_xmlns, Db_xmlns, Lang, Version, Id) -> + {decode_stream_start_attr_from(__TopXMLNS, From), + decode_stream_start_attr_to(__TopXMLNS, To), + decode_stream_start_attr_xmlns(__TopXMLNS, Xmlns), + 'decode_stream_start_attr_xmlns:stream'(__TopXMLNS, + Stream_xmlns), + 'decode_stream_start_attr_xmlns:db'(__TopXMLNS, + Db_xmlns), + 'decode_stream_start_attr_xml:lang'(__TopXMLNS, Lang), + decode_stream_start_attr_version(__TopXMLNS, Version), + decode_stream_start_attr_id(__TopXMLNS, Id)}. + +encode_stream_start({stream_start, From, To, Id, + Version, Xmlns, Stream_xmlns, Db_xmlns, Lang}, + _xmlns_attrs) -> + _els = [], + _attrs = encode_stream_start_attr_id(Id, + encode_stream_start_attr_version(Version, + 'encode_stream_start_attr_xml:lang'(Lang, + 'encode_stream_start_attr_xmlns:db'(Db_xmlns, + 'encode_stream_start_attr_xmlns:stream'(Stream_xmlns, + encode_stream_start_attr_xmlns(Xmlns, + encode_stream_start_attr_to(To, + encode_stream_start_attr_from(From, + _xmlns_attrs)))))))), + {xmlel, <<"stream:stream">>, _attrs, _els}. + +decode_stream_start_attr_from(__TopXMLNS, undefined) -> + undefined; +decode_stream_start_attr_from(__TopXMLNS, _val) -> + case catch dec_jid(_val) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"from">>, <<"stream:stream">>, + __TopXMLNS}}); + _res -> _res + end. + +encode_stream_start_attr_from(undefined, _acc) -> _acc; +encode_stream_start_attr_from(_val, _acc) -> + [{<<"from">>, enc_jid(_val)} | _acc]. + +decode_stream_start_attr_to(__TopXMLNS, undefined) -> + undefined; +decode_stream_start_attr_to(__TopXMLNS, _val) -> + case catch dec_jid(_val) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"to">>, <<"stream:stream">>, + __TopXMLNS}}); + _res -> _res + end. + +encode_stream_start_attr_to(undefined, _acc) -> _acc; +encode_stream_start_attr_to(_val, _acc) -> + [{<<"to">>, enc_jid(_val)} | _acc]. + +decode_stream_start_attr_xmlns(__TopXMLNS, undefined) -> + undefined; +decode_stream_start_attr_xmlns(__TopXMLNS, _val) -> + _val. + +encode_stream_start_attr_xmlns(undefined, _acc) -> _acc; +encode_stream_start_attr_xmlns(_val, _acc) -> + [{<<"xmlns">>, _val} | _acc]. + +'decode_stream_start_attr_xmlns:stream'(__TopXMLNS, + undefined) -> + <<>>; +'decode_stream_start_attr_xmlns:stream'(__TopXMLNS, + _val) -> + _val. + +'encode_stream_start_attr_xmlns:stream'(<<>>, _acc) -> + _acc; +'encode_stream_start_attr_xmlns:stream'(_val, _acc) -> + [{<<"xmlns:stream">>, _val} | _acc]. + +'decode_stream_start_attr_xmlns:db'(__TopXMLNS, + undefined) -> + <<>>; +'decode_stream_start_attr_xmlns:db'(__TopXMLNS, _val) -> + _val. + +'encode_stream_start_attr_xmlns:db'(<<>>, _acc) -> _acc; +'encode_stream_start_attr_xmlns:db'(_val, _acc) -> + [{<<"xmlns:db">>, _val} | _acc]. + +'decode_stream_start_attr_xml:lang'(__TopXMLNS, + undefined) -> + <<>>; +'decode_stream_start_attr_xml:lang'(__TopXMLNS, _val) -> + _val. + +'encode_stream_start_attr_xml:lang'(<<>>, _acc) -> _acc; +'encode_stream_start_attr_xml:lang'(_val, _acc) -> + [{<<"xml:lang">>, _val} | _acc]. + +decode_stream_start_attr_version(__TopXMLNS, + undefined) -> + <<>>; +decode_stream_start_attr_version(__TopXMLNS, _val) -> + _val. + +encode_stream_start_attr_version(<<>>, _acc) -> _acc; +encode_stream_start_attr_version(_val, _acc) -> + [{<<"version">>, _val} | _acc]. + +decode_stream_start_attr_id(__TopXMLNS, undefined) -> + <<>>; +decode_stream_start_attr_id(__TopXMLNS, _val) -> _val. + +encode_stream_start_attr_id(<<>>, _acc) -> _acc; +encode_stream_start_attr_id(_val, _acc) -> + [{<<"id">>, _val} | _acc]. + +decode_handshake(__TopXMLNS, __IgnoreEls, + {xmlel, <<"handshake">>, _attrs, _els}) -> + Data = decode_handshake_els(__TopXMLNS, __IgnoreEls, + _els, <<>>), + {handshake, Data}. + +decode_handshake_els(__TopXMLNS, __IgnoreEls, [], + Data) -> + decode_handshake_cdata(__TopXMLNS, Data); +decode_handshake_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Data) -> + decode_handshake_els(__TopXMLNS, __IgnoreEls, _els, + <>); +decode_handshake_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Data) -> + decode_handshake_els(__TopXMLNS, __IgnoreEls, _els, + Data). + +encode_handshake({handshake, Data}, _xmlns_attrs) -> + _els = encode_handshake_cdata(Data, []), + _attrs = _xmlns_attrs, + {xmlel, <<"handshake">>, _attrs, _els}. + +decode_handshake_cdata(__TopXMLNS, <<>>) -> <<>>; +decode_handshake_cdata(__TopXMLNS, _val) -> _val. + +encode_handshake_cdata(<<>>, _acc) -> _acc; +encode_handshake_cdata(_val, _acc) -> + [{xmlcdata, _val} | _acc]. + +decode_db_verify(__TopXMLNS, __IgnoreEls, + {xmlel, <<"db:verify">>, _attrs, _els}) -> + {Key, Error} = decode_db_verify_els(__TopXMLNS, + __IgnoreEls, _els, <<>>, undefined), + {From, To, Id, Type} = + decode_db_verify_attrs(__TopXMLNS, _attrs, undefined, + undefined, undefined, undefined), + {db_verify, From, To, Id, Type, Key, Error}. + +decode_db_verify_els(__TopXMLNS, __IgnoreEls, [], Key, + Error) -> + {decode_db_verify_cdata(__TopXMLNS, Key), Error}; +decode_db_verify_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Key, Error) -> + decode_db_verify_els(__TopXMLNS, __IgnoreEls, _els, + <>, Error); +decode_db_verify_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"error">>, _attrs, _} = _el | _els], Key, + Error) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:client">> -> + decode_db_verify_els(__TopXMLNS, __IgnoreEls, _els, Key, + decode_error(__TopXMLNS, __IgnoreEls, _el)); + <<"jabber:client">> -> + decode_db_verify_els(__TopXMLNS, __IgnoreEls, _els, Key, + decode_error(<<"jabber:client">>, __IgnoreEls, + _el)); + _ -> + decode_db_verify_els(__TopXMLNS, __IgnoreEls, _els, Key, + Error) + end; +decode_db_verify_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Key, Error) -> + decode_db_verify_els(__TopXMLNS, __IgnoreEls, _els, Key, + Error). + +decode_db_verify_attrs(__TopXMLNS, + [{<<"from">>, _val} | _attrs], _From, To, Id, Type) -> + decode_db_verify_attrs(__TopXMLNS, _attrs, _val, To, Id, + Type); +decode_db_verify_attrs(__TopXMLNS, + [{<<"to">>, _val} | _attrs], From, _To, Id, Type) -> + decode_db_verify_attrs(__TopXMLNS, _attrs, From, _val, + Id, Type); +decode_db_verify_attrs(__TopXMLNS, + [{<<"id">>, _val} | _attrs], From, To, _Id, Type) -> + decode_db_verify_attrs(__TopXMLNS, _attrs, From, To, + _val, Type); +decode_db_verify_attrs(__TopXMLNS, + [{<<"type">>, _val} | _attrs], From, To, Id, _Type) -> + decode_db_verify_attrs(__TopXMLNS, _attrs, From, To, Id, + _val); +decode_db_verify_attrs(__TopXMLNS, [_ | _attrs], From, + To, Id, Type) -> + decode_db_verify_attrs(__TopXMLNS, _attrs, From, To, Id, + Type); +decode_db_verify_attrs(__TopXMLNS, [], From, To, Id, + Type) -> + {decode_db_verify_attr_from(__TopXMLNS, From), + decode_db_verify_attr_to(__TopXMLNS, To), + decode_db_verify_attr_id(__TopXMLNS, Id), + decode_db_verify_attr_type(__TopXMLNS, Type)}. + +encode_db_verify({db_verify, From, To, Id, Type, Key, + Error}, + _xmlns_attrs) -> + _els = lists:reverse(encode_db_verify_cdata(Key, + 'encode_db_verify_$error'(Error, + []))), + _attrs = encode_db_verify_attr_type(Type, + encode_db_verify_attr_id(Id, + encode_db_verify_attr_to(To, + encode_db_verify_attr_from(From, + _xmlns_attrs)))), + {xmlel, <<"db:verify">>, _attrs, _els}. + +'encode_db_verify_$error'(undefined, _acc) -> _acc; +'encode_db_verify_$error'(Error, _acc) -> + [encode_error(Error, []) | _acc]. + +decode_db_verify_attr_from(__TopXMLNS, undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"from">>, <<"db:verify">>, + __TopXMLNS}}); +decode_db_verify_attr_from(__TopXMLNS, _val) -> + case catch dec_jid(_val) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"from">>, <<"db:verify">>, + __TopXMLNS}}); + _res -> _res + end. + +encode_db_verify_attr_from(_val, _acc) -> + [{<<"from">>, enc_jid(_val)} | _acc]. + +decode_db_verify_attr_to(__TopXMLNS, undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"to">>, <<"db:verify">>, __TopXMLNS}}); +decode_db_verify_attr_to(__TopXMLNS, _val) -> + case catch dec_jid(_val) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"to">>, <<"db:verify">>, + __TopXMLNS}}); + _res -> _res + end. + +encode_db_verify_attr_to(_val, _acc) -> + [{<<"to">>, enc_jid(_val)} | _acc]. + +decode_db_verify_attr_id(__TopXMLNS, undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"id">>, <<"db:verify">>, __TopXMLNS}}); +decode_db_verify_attr_id(__TopXMLNS, _val) -> _val. + +encode_db_verify_attr_id(_val, _acc) -> + [{<<"id">>, _val} | _acc]. + +decode_db_verify_attr_type(__TopXMLNS, undefined) -> + undefined; +decode_db_verify_attr_type(__TopXMLNS, _val) -> + case catch dec_enum(_val, [valid, invalid, error]) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"type">>, <<"db:verify">>, + __TopXMLNS}}); + _res -> _res + end. + +encode_db_verify_attr_type(undefined, _acc) -> _acc; +encode_db_verify_attr_type(_val, _acc) -> + [{<<"type">>, enc_enum(_val)} | _acc]. + +decode_db_verify_cdata(__TopXMLNS, <<>>) -> <<>>; +decode_db_verify_cdata(__TopXMLNS, _val) -> _val. + +encode_db_verify_cdata(<<>>, _acc) -> _acc; +encode_db_verify_cdata(_val, _acc) -> + [{xmlcdata, _val} | _acc]. + +decode_db_result(__TopXMLNS, __IgnoreEls, + {xmlel, <<"db:result">>, _attrs, _els}) -> + {Key, Error} = decode_db_result_els(__TopXMLNS, + __IgnoreEls, _els, <<>>, undefined), + {From, To, Type} = decode_db_result_attrs(__TopXMLNS, + _attrs, undefined, undefined, + undefined), + {db_result, From, To, Type, Key, Error}. + +decode_db_result_els(__TopXMLNS, __IgnoreEls, [], Key, + Error) -> + {decode_db_result_cdata(__TopXMLNS, Key), Error}; +decode_db_result_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Key, Error) -> + decode_db_result_els(__TopXMLNS, __IgnoreEls, _els, + <>, Error); +decode_db_result_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"error">>, _attrs, _} = _el | _els], Key, + Error) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:client">> -> + decode_db_result_els(__TopXMLNS, __IgnoreEls, _els, Key, + decode_error(__TopXMLNS, __IgnoreEls, _el)); + <<"jabber:client">> -> + decode_db_result_els(__TopXMLNS, __IgnoreEls, _els, Key, + decode_error(<<"jabber:client">>, __IgnoreEls, + _el)); + _ -> + decode_db_result_els(__TopXMLNS, __IgnoreEls, _els, Key, + Error) + end; +decode_db_result_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Key, Error) -> + decode_db_result_els(__TopXMLNS, __IgnoreEls, _els, Key, + Error). + +decode_db_result_attrs(__TopXMLNS, + [{<<"from">>, _val} | _attrs], _From, To, Type) -> + decode_db_result_attrs(__TopXMLNS, _attrs, _val, To, + Type); +decode_db_result_attrs(__TopXMLNS, + [{<<"to">>, _val} | _attrs], From, _To, Type) -> + decode_db_result_attrs(__TopXMLNS, _attrs, From, _val, + Type); +decode_db_result_attrs(__TopXMLNS, + [{<<"type">>, _val} | _attrs], From, To, _Type) -> + decode_db_result_attrs(__TopXMLNS, _attrs, From, To, + _val); +decode_db_result_attrs(__TopXMLNS, [_ | _attrs], From, + To, Type) -> + decode_db_result_attrs(__TopXMLNS, _attrs, From, To, + Type); +decode_db_result_attrs(__TopXMLNS, [], From, To, + Type) -> + {decode_db_result_attr_from(__TopXMLNS, From), + decode_db_result_attr_to(__TopXMLNS, To), + decode_db_result_attr_type(__TopXMLNS, Type)}. + +encode_db_result({db_result, From, To, Type, Key, + Error}, + _xmlns_attrs) -> + _els = lists:reverse(encode_db_result_cdata(Key, + 'encode_db_result_$error'(Error, + []))), + _attrs = encode_db_result_attr_type(Type, + encode_db_result_attr_to(To, + encode_db_result_attr_from(From, + _xmlns_attrs))), + {xmlel, <<"db:result">>, _attrs, _els}. + +'encode_db_result_$error'(undefined, _acc) -> _acc; +'encode_db_result_$error'(Error, _acc) -> + [encode_error(Error, []) | _acc]. + +decode_db_result_attr_from(__TopXMLNS, undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"from">>, <<"db:result">>, + __TopXMLNS}}); +decode_db_result_attr_from(__TopXMLNS, _val) -> + case catch dec_jid(_val) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"from">>, <<"db:result">>, + __TopXMLNS}}); + _res -> _res + end. + +encode_db_result_attr_from(_val, _acc) -> + [{<<"from">>, enc_jid(_val)} | _acc]. + +decode_db_result_attr_to(__TopXMLNS, undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"to">>, <<"db:result">>, __TopXMLNS}}); +decode_db_result_attr_to(__TopXMLNS, _val) -> + case catch dec_jid(_val) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"to">>, <<"db:result">>, + __TopXMLNS}}); + _res -> _res + end. + +encode_db_result_attr_to(_val, _acc) -> + [{<<"to">>, enc_jid(_val)} | _acc]. + +decode_db_result_attr_type(__TopXMLNS, undefined) -> + undefined; +decode_db_result_attr_type(__TopXMLNS, _val) -> + case catch dec_enum(_val, [valid, invalid, error]) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"type">>, <<"db:result">>, + __TopXMLNS}}); + _res -> _res + end. + +encode_db_result_attr_type(undefined, _acc) -> _acc; +encode_db_result_attr_type(_val, _acc) -> + [{<<"type">>, enc_enum(_val)} | _acc]. + +decode_db_result_cdata(__TopXMLNS, <<>>) -> <<>>; +decode_db_result_cdata(__TopXMLNS, _val) -> _val. + +encode_db_result_cdata(<<>>, _acc) -> _acc; +encode_db_result_cdata(_val, _acc) -> + [{xmlcdata, _val} | _acc]. + decode_adhoc_command(__TopXMLNS, __IgnoreEls, {xmlel, <<"command">>, _attrs, _els}) -> {Xdata, Notes, Actions} = diff --git a/tools/xmpp_codec.spec b/tools/xmpp_codec.spec index 0e0145f72..7503eab10 100644 --- a/tools/xmpp_codec.spec +++ b/tools/xmpp_codec.spec @@ -2877,6 +2877,66 @@ #ref{name = xdata, min = 0, max = 1}, #ref{name = adhoc_command_notes, label = '$notes'}]}). +-xml(db_result, + #elem{name = <<"db:result">>, + xmlns = <<"jabber:client">>, + result = {db_result, '$from', '$to', '$type', '$key', '$error'}, + refs = [#ref{name = error, min = 0, max = 1}], + cdata = #cdata{default = <<"">>, label = '$key'}, + attrs = [#attr{name = <<"from">>, required = true, + dec = {dec_jid, []}, enc = {enc_jid, []}}, + #attr{name = <<"to">>, required = true, + dec = {dec_jid, []}, enc = {enc_jid, []}}, + #attr{name = <<"type">>, + dec = {dec_enum, [[valid, invalid, error]]}, + enc = {enc_enum, []}}]}). + +-xml(db_verify, + #elem{name = <<"db:verify">>, + xmlns = <<"jabber:client">>, + result = {db_verify, '$from', '$to', '$id', '$type', '$key', '$error'}, + refs = [#ref{name = error, min = 0, max = 1}], + cdata = #cdata{default = <<"">>, label = '$key'}, + attrs = [#attr{name = <<"from">>, required = true, + dec = {dec_jid, []}, enc = {enc_jid, []}}, + #attr{name = <<"to">>, required = true, + dec = {dec_jid, []}, enc = {enc_jid, []}}, + #attr{name = <<"id">>, required = true}, + #attr{name = <<"type">>, + dec = {dec_enum, [[valid, invalid, error]]}, + enc = {enc_enum, []}}]}). + +-xml(handshake, + #elem{name = <<"handshake">>, + xmlns = <<"jabber:client">>, + result = {handshake, '$data'}, + cdata = #cdata{default = <<"">>, label = '$data'}}). + +-xml(stream_start, + #elem{name = <<"stream:stream">>, + xmlns = [<<"jabber:client">>, <<"jabber:server">>, + <<"jabber:component:accept">>], + result = {stream_start, '$from', '$to', '$id', + '$version', '$xmlns', '$stream_xmlns', + '$db_xmlns', '$lang'}, + attrs = [#attr{name = <<"from">>, + dec = {dec_jid, []}, + enc = {enc_jid, []}}, + #attr{name = <<"to">>, + dec = {dec_jid, []}, + enc = {enc_jid, []}}, + #attr{name = <<"xmlns">>}, + #attr{name = <<"xmlns:stream">>, + label = '$stream_xmlns', + default = <<"">>}, + #attr{name = <<"xmlns:db">>, + label = '$db_xmlns', + default = <<"">>}, + #attr{name = <<"xml:lang">>, label = '$lang', + default = <<"">>}, + #attr{name = <<"version">>, default = <<"">>}, + #attr{name = <<"id">>, default = <<"">>}]}). + dec_tzo(Val) -> [H1, M1] = str:tokens(Val, <<":">>), H = jlib:binary_to_integer(H1), From 1097d31d636899d31a4062ec8d48ce58b55c0206 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Wed, 27 Jul 2016 18:05:11 +0300 Subject: [PATCH 010/151] Fix type spec for set_from_to/3 --- src/xmpp.erl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/xmpp.erl b/src/xmpp.erl index 5b7e3d1cc..6e8145190 100644 --- a/src/xmpp.erl +++ b/src/xmpp.erl @@ -205,9 +205,9 @@ set_to(#iq{} = IQ, J) -> IQ#iq{to = J}; set_to(#message{} = Msg, J) -> Msg#message{to = J}; set_to(#presence{} = Pres, J) -> Pres#presence{to = J}. --spec set_from_to(iq(), jid:jid(), jid:jid()) -> iq(); - (message(), jid:jid(), jid:jid()) -> message(); - (presence(), jid:jid(), jid:jid()) -> presence(). +-spec set_from_to(iq(), undefined | jid:jid(), undefined | jid:jid()) -> iq(); + (message(), undefined | jid:jid(), undefined | jid:jid()) -> message(); + (presence(), undefined | jid:jid(), undefined | jid:jid()) -> presence(). set_from_to(#iq{} = IQ, F, T) -> IQ#iq{from = F, to = T}; set_from_to(#message{} = Msg, F, T) -> Msg#message{from = F, to = T}; set_from_to(#presence{} = Pres, F, T) -> Pres#presence{from = F, to = T}. From 8275e95a1606670fc6334d9832de519c67550dcb Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Wed, 27 Jul 2016 18:06:34 +0300 Subject: [PATCH 011/151] Swap variables in their correct places --- src/mod_mam.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod_mam.erl b/src/mod_mam.erl index b4ee17720..0aaf484c5 100644 --- a/src/mod_mam.erl +++ b/src/mod_mam.erl @@ -213,7 +213,7 @@ set_room_option(_Acc, <<"muc#roomconfig_mam">> = Opt, Vals, Lang) -> catch _:{case_clause, _} -> Txt = <<"Value of '~s' should be boolean">>, ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), - {error, xmpp:err_bad_request(Lang, ErrTxt)} + {error, xmpp:err_bad_request(ErrTxt, Lang)} end; set_room_option(Acc, _Opt, _Vals, _Lang) -> Acc. From 96e912b09acb172f6f6cc8037377384c855ae472 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Wed, 27 Jul 2016 18:06:54 +0300 Subject: [PATCH 012/151] Rewrite mod_register to use XML generator --- src/mod_register.erl | 529 ++++++++++++++++--------------------------- 1 file changed, 201 insertions(+), 328 deletions(-) diff --git a/src/mod_register.erl b/src/mod_register.erl index 45cd78fef..3f9c33123 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -35,14 +35,13 @@ -export([start/2, stop/1, stream_feature_register/2, unauthenticated_iq_register/4, try_register/5, - process_iq/3, send_registration_notifications/3, + process_iq/1, send_registration_notifications/3, transform_options/1, transform_module_options/1, mod_opt_type/1, opt_type/1, depends/2]). -include("ejabberd.hrl"). -include("logger.hrl"). - --include("jlib.hrl"). +-include("xmpp.hrl"). start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, fun gen_iq_handler:check_type/1, @@ -79,329 +78,223 @@ stream_feature_register(Acc, Host) -> AF = gen_mod:get_module_opt(Host, ?MODULE, access_from, fun(A) -> A end, all), - case (AF /= none) and lists:keymember(<<"mechanisms">>, 2, Acc) of + case (AF /= none) and lists:keymember(sasl_mechanisms, 1, Acc) of true -> - [#xmlel{name = <<"register">>, - attrs = [{<<"xmlns">>, ?NS_FEATURE_IQREGISTER}], - children = []} - | Acc]; + [#feature_register{}|Acc]; false -> Acc end. unauthenticated_iq_register(_Acc, Server, - #iq{xmlns = ?NS_REGISTER} = IQ, IP) -> + #iq{sub_els = [#register{}]} = IQ, IP) -> Address = case IP of {A, _Port} -> A; _ -> undefined end, - ResIQ = process_iq(jid:make(<<"">>, <<"">>, - <<"">>), - jid:make(<<"">>, Server, <<"">>), IQ, Address), - Res1 = jlib:replace_from_to(jid:make(<<"">>, - Server, <<"">>), - jid:make(<<"">>, <<"">>, <<"">>), - jlib:iq_to_xml(ResIQ)), - jlib:remove_attr(<<"to">>, Res1); + ResIQ = process_iq(xmpp:set_from_to(IQ, jid:make(<<>>), jid:make(Server)), + Address), + xmpp:set_from_to(ResIQ, jid:make(Server), undefined); unauthenticated_iq_register(Acc, _Server, _IQ, _IP) -> Acc. -process_iq(From, To, IQ) -> - process_iq(From, To, IQ, jid:tolower(From)). +process_iq(#iq{from = From} = IQ) -> + process_iq(IQ, jid:tolower(From)). -process_iq(From, To, - #iq{type = Type, lang = Lang, sub_el = SubEl, id = ID} = - IQ, - Source) -> - IsCaptchaEnabled = case - gen_mod:get_module_opt(To#jid.lserver, ?MODULE, - captcha_protected, - fun(B) when is_boolean(B) -> B end, - false) - of - true -> true; - _ -> false - end, - case Type of - set -> - UTag = fxml:get_subtag(SubEl, <<"username">>), - PTag = fxml:get_subtag(SubEl, <<"password">>), - RTag = fxml:get_subtag(SubEl, <<"remove">>), - Server = To#jid.lserver, - Access = gen_mod:get_module_opt(Server, ?MODULE, access, - fun(A) -> A end, - all), - AllowRemove = allow == - acl:match_rule(Server, Access, From), - if (UTag /= false) and (RTag /= false) and - AllowRemove -> - User = fxml:get_tag_cdata(UTag), - case From of - #jid{user = User, lserver = Server} -> - ejabberd_auth:remove_user(User, Server), - IQ#iq{type = result, sub_el = []}; - _ -> - if PTag /= false -> - Password = fxml:get_tag_cdata(PTag), - case ejabberd_auth:remove_user(User, Server, - Password) - of - ok -> IQ#iq{type = result, sub_el = []}; - %% TODO FIXME: This piece of - %% code does not work since - %% the code have been changed - %% to allow several auth - %% modules. lists:foreach can - %% only return ok: - not_allowed -> - Txt = <<"Removal is not allowed">>, - IQ#iq{type = error, - sub_el = [SubEl, - ?ERRT_NOT_ALLOWED(Lang, Txt)]}; - not_exists -> - Txt = <<"No such user">>, - IQ#iq{type = error, - sub_el = - [SubEl, - ?ERRT_ITEM_NOT_FOUND(Lang, Txt)]}; - Err -> - ?ERROR_MSG("failed to remove user ~s@~s: ~p", - [User, Server, Err]), - IQ#iq{type = error, - sub_el = - [SubEl, - ?ERR_INTERNAL_SERVER_ERROR]} - end; - true -> - Txt = <<"No password in this query">>, - IQ#iq{type = error, - sub_el = [SubEl, ?ERRT_BAD_REQUEST(Lang, Txt)]} - end - end; - (UTag == false) and (RTag /= false) and AllowRemove -> - case From of - #jid{user = User, lserver = Server, - resource = Resource} -> - ResIQ = #iq{type = result, xmlns = ?NS_REGISTER, - id = ID, sub_el = []}, - ejabberd_router:route(jid:make(User, Server, - Resource), - jid:make(User, Server, - Resource), - jlib:iq_to_xml(ResIQ)), - ejabberd_auth:remove_user(User, Server), - ignore; - _ -> - Txt = <<"The query is only allowed from local users">>, - IQ#iq{type = error, - sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]} - end; - (UTag /= false) and (PTag /= false) -> - User = fxml:get_tag_cdata(UTag), - Password = fxml:get_tag_cdata(PTag), - try_register_or_set_password(User, Server, Password, - From, IQ, SubEl, Source, Lang, - not IsCaptchaEnabled); - IsCaptchaEnabled -> - case ejabberd_captcha:process_reply(SubEl) of - ok -> - case process_xdata_submit(SubEl) of - {ok, User, Password} -> - try_register_or_set_password(User, Server, - Password, From, IQ, - SubEl, Source, Lang, - true); - _ -> - Txt = <<"Incorrect data form">>, - IQ#iq{type = error, - sub_el = [SubEl, ?ERRT_BAD_REQUEST(Lang, Txt)]} - end; - {error, malformed} -> - Txt = <<"Incorrect CAPTCHA submit">>, - IQ#iq{type = error, - sub_el = [SubEl, ?ERRT_BAD_REQUEST(Lang, Txt)]}; - _ -> - ErrText = <<"The CAPTCHA verification has failed">>, - IQ#iq{type = error, - sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, ErrText)]} - end; - true -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_BAD_REQUEST]} - end; - get -> - {IsRegistered, UsernameSubels, QuerySubels} = case From - of - #jid{user = User, - lserver = - Server} -> - case - ejabberd_auth:is_user_exists(User, - Server) - of - true -> - {true, - [{xmlcdata, - User}], - [#xmlel{name - = - <<"registered">>, - attrs - = - [], - children - = - []}]}; - false -> - {false, - [{xmlcdata, - User}], - []} - end; - _ -> {false, [], []} - end, - if IsCaptchaEnabled and not IsRegistered -> - TopInstrEl = #xmlel{name = <<"instructions">>, - attrs = [], - children = - [{xmlcdata, - translate:translate(Lang, - <<"You need a client that supports x:data " - "and CAPTCHA to register">>)}]}, - InstrEl = #xmlel{name = <<"instructions">>, attrs = [], - children = - [{xmlcdata, - translate:translate(Lang, - <<"Choose a username and password to register " - "with this server">>)}]}, - UField = #xmlel{name = <<"field">>, - attrs = - [{<<"type">>, <<"text-single">>}, - {<<"label">>, - translate:translate(Lang, <<"User">>)}, - {<<"var">>, <<"username">>}], - children = - [#xmlel{name = <<"required">>, attrs = [], - children = []}]}, - PField = #xmlel{name = <<"field">>, - attrs = - [{<<"type">>, <<"text-private">>}, - {<<"label">>, - translate:translate(Lang, - <<"Password">>)}, - {<<"var">>, <<"password">>}], - children = - [#xmlel{name = <<"required">>, attrs = [], - children = []}]}, - case ejabberd_captcha:create_captcha_x(ID, To, Lang, - Source, - [InstrEl, UField, - PField]) - of - {ok, CaptchaEls} -> - IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = - [{<<"xmlns">>, - ?NS_REGISTER}], - children = - [TopInstrEl | CaptchaEls]}]}; - {error, limit} -> - ErrText = <<"Too many CAPTCHA requests">>, - IQ#iq{type = error, - sub_el = - [SubEl, - ?ERRT_RESOURCE_CONSTRAINT(Lang, ErrText)]}; - _Err -> - ErrText = <<"Unable to generate a CAPTCHA">>, - IQ#iq{type = error, - sub_el = - [SubEl, - ?ERRT_INTERNAL_SERVER_ERROR(Lang, ErrText)]} - end; - true -> - IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = - [{<<"xmlns">>, - ?NS_REGISTER}], - children = - [#xmlel{name = <<"instructions">>, - attrs = [], - children = - [{xmlcdata, - translate:translate(Lang, - <<"Choose a username and password to register " - "with this server">>)}]}, - #xmlel{name = <<"username">>, - attrs = [], - children = UsernameSubels}, - #xmlel{name = <<"password">>, - attrs = [], children = []} - | QuerySubels]}]} - end +process_iq(#iq{from = From, to = To} = IQ, Source) -> + IsCaptchaEnabled = + case gen_mod:get_module_opt(To#jid.lserver, ?MODULE, + captcha_protected, + fun(B) when is_boolean(B) -> B end, + false) of + true -> true; + false -> false + end, + Server = To#jid.lserver, + Access = gen_mod:get_module_opt(Server, ?MODULE, access, + fun(A) -> A end, all), + AllowRemove = allow == acl:match_rule(Server, Access, From), + process_iq(IQ, Source, IsCaptchaEnabled, AllowRemove). + +process_iq(#iq{type = set, lang = Lang, + sub_els = [#register{remove = true}]} = IQ, + _Source, _IsCaptchaEnabled, _AllowRemove = false) -> + Txt = <<"Denied by ACL">>, + xmpp:make_error(IQ, xmpp:err_forbidden(Txt, Lang)); +process_iq(#iq{type = set, lang = Lang, to = To, from = From, + sub_els = [#register{remove = true, + username = User, + password = Password}]} = IQ, + _Source, _IsCaptchaEnabled, _AllowRemove = true) -> + Server = To#jid.lserver, + if is_binary(User) -> + case From of + #jid{user = User, lserver = Server} -> + ejabberd_auth:remove_user(User, Server), + xmpp:make_iq_result(IQ); + _ -> + if is_binary(Password) -> + ejabberd_auth:remove_user(User, Server, Password), + xmpp:make_iq_result(IQ); + true -> + Txt = <<"No 'password' found in this query">>, + xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)) + end + end; + true -> + case From of + #jid{user = User, lserver = Server, resource = Resource} -> + ResIQ = xmpp:make_iq_result(IQ), + ejabberd_router:route(jid:make(User, Server, Resource), + jid:make(User, Server, Resource), + ResIQ), + ejabberd_auth:remove_user(User, Server), + ignore; + _ -> + Txt = <<"The query is only allowed from local users">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)) + end + end; +process_iq(#iq{type = set, to = To, + sub_els = [#register{username = User, + password = Password}]} = IQ, + Source, IsCaptchaEnabled, _AllowRemove) when is_binary(User), + is_binary(Password) -> + Server = To#jid.lserver, + try_register_or_set_password( + User, Server, Password, IQ, Source, not IsCaptchaEnabled); +process_iq(#iq{type = set, to = To, + lang = Lang, sub_els = [#register{xdata = #xdata{} = X}]} = IQ, + Source, true, _AllowRemove) -> + Server = To#jid.lserver, + case ejabberd_captcha:process_reply(X) of + ok -> + case process_xdata_submit(X) of + {ok, User, Password} -> + try_register_or_set_password( + User, Server, Password, IQ, Source, true); + _ -> + Txt = <<"Incorrect data form">>, + xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)) + end; + {error, malformed} -> + Txt = <<"Incorrect CAPTCHA submit">>, + xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)); + _ -> + ErrText = <<"The CAPTCHA verification has failed">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(ErrText, Lang)) + end; +process_iq(#iq{type = set} = IQ, _Source, _IsCaptchaEnabled, _AllowRemove) -> + xmpp:make_error(IQ, xmpp:err_bad_request()); +process_iq(#iq{type = get, from = From, to = To, id = ID, lang = Lang} = IQ, + Source, IsCaptchaEnabled, _AllowRemove) -> + Server = To#jid.lserver, + {IsRegistered, Username} = + case From of + #jid{user = User, lserver = Server} -> + case ejabberd_auth:is_user_exists(User, Server) of + true -> + {true, User}; + false -> + {false, User} + end; + _ -> + {false, <<"">>} + end, + if IsCaptchaEnabled and not IsRegistered -> + TopInstr = translate:translate( + Lang, <<"You need a client that supports x:data " + "and CAPTCHA to register">>), + Instr = translate:translate( + Lang, <<"Choose a username and password to register " + "with this server">>), + UField = #xdata_field{type = 'text-single', + label = translate:translate(Lang, <<"User">>), + var = <<"username">>, + required = true}, + PField = #xdata_field{type = 'text-private', + label = translate:translate(Lang, <<"Password">>), + var = <<"password">>, + required = true}, + X = #xdata{type = form, instructions = [Instr], + fields = [UField, PField]}, + case ejabberd_captcha:create_captcha_x(ID, To, Lang, Source, X) of + {ok, Captcha} -> + xmpp:make_iq_result( + IQ, #register{instructions = TopInstr, + xdata = Captcha}); + {error, limit} -> + ErrText = <<"Too many CAPTCHA requests">>, + xmpp:make_error( + IQ, xmpp:err_resource_constraint(ErrText, Lang)); + _Err -> + ErrText = <<"Unable to generate a CAPTCHA">>, + xmpp:make_error( + IQ, xmpp:err_internal_server_error(ErrText, Lang)) + end; + true -> + Instr = <<"Choose a username and password to register with this server">>, + xmpp:make_iq_result( + IQ, + #register{instructions = translate:translate(Lang, Instr), + username = Username, + password = <<"">>, + registered = IsRegistered}) end. try_register_or_set_password(User, Server, Password, - From, IQ, SubEl, Source, Lang, CaptchaSucceed) -> + #iq{from = From, lang = Lang} = IQ, + Source, CaptchaSucceed) -> case From of - #jid{user = User, lserver = Server} -> - try_set_password(User, Server, Password, IQ, SubEl, - Lang); - _ when CaptchaSucceed -> - case check_from(From, Server) of - allow -> - case try_register(User, Server, Password, Source, Lang) - of - ok -> IQ#iq{type = result, sub_el = []}; - {error, Error} -> - IQ#iq{type = error, sub_el = [SubEl, Error]} - end; - deny -> - Txt = <<"Denied by ACL">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_FORBIDDEN(Lang, Txt)]} - end; - _ -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]} + #jid{user = User, lserver = Server} -> + try_set_password(User, Server, Password, IQ); + _ when CaptchaSucceed -> + case check_from(From, Server) of + allow -> + case try_register(User, Server, Password, Source, Lang) of + ok -> + xmpp:make_iq_result(IQ); + {error, Error} -> + xmpp:make_error(IQ, Error) + end; + deny -> + Txt = <<"Denied by ACL">>, + xmpp:make_error(IQ, xmpp:err_forbidden(Txt, Lang)) + end; + _ -> + xmpp:make_error(IQ, xmpp:err_not_allowed()) end. %% @doc Try to change password and return IQ response -try_set_password(User, Server, Password, IQ, SubEl, - Lang) -> +try_set_password(User, Server, Password, #iq{lang = Lang} = IQ) -> case is_strong_password(Server, Password) of true -> - case ejabberd_auth:set_password(User, Server, Password) - of - ok -> IQ#iq{type = result, sub_el = []}; + case ejabberd_auth:set_password(User, Server, Password) of + ok -> + xmpp:make_iq_result(IQ); {error, empty_password} -> Txt = <<"Empty password">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_BAD_REQUEST(Lang, Txt)]}; + xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)); {error, not_allowed} -> Txt = <<"Changing password is not allowed">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]}; + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); {error, invalid_jid} -> - IQ#iq{type = error, - sub_el = [SubEl, ?ERR_JID_MALFORMED]}; + xmpp:make_error(IQ, xmpp:err_jid_malformed()); Err -> ?ERROR_MSG("failed to register user ~s@~s: ~p", [User, Server, Err]), - IQ#iq{type = error, - sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]} + xmpp:make_error(IQ, xmpp:err_internal_server_error()) end; error_preparing_password -> ErrText = <<"The password contains unacceptable characters">>, - IQ#iq{type = error, - sub_el = [SubEl, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)]}; + xmpp:make_error(IQ, xmpp:err_not_acceptable(ErrText, Lang)); false -> ErrText = <<"The password is too weak">>, - IQ#iq{type = error, - sub_el = [SubEl, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)]} + xmpp:make_error(IQ, xmpp:err_not_acceptable(ErrText, Lang)) end. try_register(User, Server, Password, SourceRaw, Lang) -> case jid:is_nodename(User) of - false -> {error, ?ERRT_BAD_REQUEST(Lang, <<"Malformed username">>)}; + false -> {error, xmpp:err_bad_request(<<"Malformed username">>, Lang)}; _ -> JID = jid:make(User, Server, <<"">>), Access = gen_mod:get_module_opt(Server, ?MODULE, access, @@ -411,8 +304,8 @@ try_register(User, Server, Password, SourceRaw, Lang) -> case {acl:match_rule(Server, Access, JID), check_ip_access(SourceRaw, IPAccess)} of - {deny, _} -> {error, ?ERRT_FORBIDDEN(Lang, <<"Denied by ACL">>)}; - {_, deny} -> {error, ?ERRT_FORBIDDEN(Lang, <<"Denied by ACL">>)}; + {deny, _} -> {error, xmpp:err_forbidden(<<"Denied by ACL">>, Lang)}; + {_, deny} -> {error, xmpp:err_forbidden(<<"Denied by ACL">>, Lang)}; {allow, allow} -> Source = may_remove_resource(SourceRaw), case check_timeout(Source) of @@ -432,35 +325,35 @@ try_register(User, Server, Password, SourceRaw, Lang) -> case Error of {atomic, exists} -> Txt = <<"User already exists">>, - {error, ?ERRT_CONFLICT(Lang, Txt)}; + {error, xmpp:err_conflict(Txt, Lang)}; {error, invalid_jid} -> - {error, ?ERR_JID_MALFORMED}; + {error, xmpp:err_jid_malformed()}; {error, not_allowed} -> - {error, ?ERR_NOT_ALLOWED}; + {error, xmpp:err_not_allowed()}; {error, too_many_users} -> Txt = <<"Too many users registered">>, - {error, ?ERRT_RESOURCE_CONSTRAINT(Lang, Txt)}; + {error, xmpp:err_resource_constraint(Txt, Lang)}; {error, _} -> ?ERROR_MSG("failed to register user " "~s@~s: ~p", [User, Server, Error]), - {error, ?ERR_INTERNAL_SERVER_ERROR} + {error, xmpp:err_internal_server_error()} end end; error_preparing_password -> remove_timeout(Source), ErrText = <<"The password contains unacceptable characters">>, - {error, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)}; + {error, xmpp:err_not_acceptable(ErrText, Lang)}; false -> remove_timeout(Source), ErrText = <<"The password is too weak">>, - {error, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)} + {error, xmpp:err_not_acceptable(ErrText, Lang)} end; false -> ErrText = <<"Users are not allowed to register accounts " "so quickly">>, - {error, ?ERRT_RESOURCE_CONSTRAINT(Lang, ErrText)} + {error, xmpp:err_resource_constraint(ErrText, Lang)} end end end. @@ -479,20 +372,10 @@ send_welcome_message(JID) -> of {<<"">>, <<"">>} -> ok; {Subj, Body} -> - ejabberd_router:route(jid:make(<<"">>, Host, - <<"">>), - JID, - #xmlel{name = <<"message">>, - attrs = [{<<"type">>, <<"normal">>}], - children = - [#xmlel{name = <<"subject">>, - attrs = [], - children = - [{xmlcdata, Subj}]}, - #xmlel{name = <<"body">>, - attrs = [], - children = - [{xmlcdata, Body}]}]}); + ejabberd_router:route( + jid:make(Host), JID, + #message{subject = xmpp:mk_text(Subj), + body = xmpp:mk_text(Body)}); _ -> ok end. @@ -516,13 +399,9 @@ send_registration_notifications(Mod, UJID, Source) -> lists:foreach( fun(JID) -> ejabberd_router:route( - jid:make(<<"">>, Host, <<"">>), - JID, - #xmlel{name = <<"message">>, - attrs = [{<<"type">>, <<"chat">>}], - children = [#xmlel{name = <<"body">>, - attrs = [], - children = [{xmlcdata,Body}]}]}) + jid:make(Host), JID, + #message{type = chat, + body = xmpp:mk_text(Body)}) end, JIDs) end. @@ -633,17 +512,11 @@ write_time({{Y, Mo, D}, {H, Mi, S}}) -> io_lib:format("~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w", [Y, Mo, D, H, Mi, S]). -process_xdata_submit(El) -> - case fxml:get_subtag(El, <<"x">>) of - false -> error; - Xdata -> - Fields = jlib:parse_xdata_submit(Xdata), - case catch {proplists:get_value(<<"username">>, Fields), - proplists:get_value(<<"password">>, Fields)} - of - {[User | _], [Pass | _]} -> {ok, User, Pass}; - _ -> error - end +process_xdata_submit(X) -> + case {xmpp_util:get_xdata_values(<<"username">>, X), + xmpp_util:get_xdata_values(<<"password">>, X)} of + {[User], [Pass]} -> {ok, User, Pass}; + _ -> error end. is_strong_password(Server, Password) -> From b31ebd2ea012ba2a81ec095189f46974e1905929 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Thu, 28 Jul 2016 15:10:41 +0300 Subject: [PATCH 013/151] Rewrite captcha to use XML generator --- include/xmpp_codec.hrl | 42 +- src/ejabberd_captcha.erl | 259 ++++-------- src/mod_muc_room.erl | 5 +- src/mod_register.erl | 4 +- src/mod_register_web.erl | 4 +- src/xmpp_codec.erl | 845 +++++++++++++++++++++++++++++++-------- tools/xmpp_codec.spec | 64 ++- 7 files changed, 862 insertions(+), 361 deletions(-) diff --git a/include/xmpp_codec.hrl b/include/xmpp_codec.hrl index 43bb6b098..1ede0ff1d 100644 --- a/include/xmpp_codec.hrl +++ b/include/xmpp_codec.hrl @@ -294,6 +294,12 @@ type :: 'none' | 'pending' | 'subscribed' | 'unconfigured'}). -type pubsub_subscription() :: #pubsub_subscription{}. +-record(bob_data, {cid :: binary(), + 'max-age' :: non_neg_integer(), + type :: binary(), + data = <<>> :: any()}). +-type bob_data() :: #bob_data{}. + -record(muc_item, {actor :: #muc_actor{}, continue :: binary(), reason = <<>> :: 'undefined' | binary(), @@ -404,7 +410,8 @@ required = false :: boolean(), desc :: binary(), values = [] :: [binary()], - options = [] :: [#xdata_option{}]}). + options = [] :: [#xdata_option{}], + sub_els = [] :: [any()]}). -type xdata_field() :: #xdata_field{}. -record(version, {name :: binary(), @@ -482,6 +489,15 @@ number :: binary()}). -type vcard_tel() :: #vcard_tel{}. +-record(media_uri, {type :: binary(), + uri = <<>> :: binary()}). +-type media_uri() :: #media_uri{}. + +-record(media, {height :: non_neg_integer(), + width :: non_neg_integer(), + uri = [] :: [#media_uri{}]}). +-type media() :: #media{}. + -record(muc_destroy, {xmlns :: binary(), jid :: any(), reason = <<>> :: 'undefined' | binary(), @@ -531,6 +547,11 @@ url = [] :: [#bookmark_url{}]}). -type bookmark_storage() :: #bookmark_storage{}. +-record(oob_x, {url :: binary(), + desc = <<>> :: binary(), + sid = <<>> :: binary()}). +-type oob_x() :: #oob_x{}. + -record(vcard_sound, {phonetic :: binary(), binval :: any(), extval :: binary()}). @@ -582,6 +603,9 @@ fields = [] :: [#xdata_field{}]}). -type xdata() :: #xdata{}. +-record(xcaptcha, {xdata :: #xdata{}}). +-type xcaptcha() :: #xcaptcha{}. + -record(adhoc_command, {node :: binary(), action = execute :: 'cancel' | 'complete' | 'execute' | 'next' | 'prev', sid :: binary(), @@ -647,7 +671,8 @@ misc :: 'none' | binary(), text :: 'none' | binary(), key :: 'none' | binary(), - xdata :: #xdata{}}). + xdata :: #xdata{}, + sub_els = [] :: [any()]}). -type register() :: #register{}. -record(disco_info, {node :: binary(), @@ -807,6 +832,8 @@ version() | pubsub_affiliation() | mam_fin() | + bob_data() | + media() | sm_a() | carbons_sent() | mam_archived() | @@ -880,11 +907,8 @@ sasl_failure() | bookmark_storage() | muc_decline() | - sasl_auth() | - p1_push() | legacy_auth() | search() | - pubsub_publish() | unblock() | nick() | p1_ack() | @@ -892,6 +916,7 @@ mix_join() | xmpp_session() | xdata() | + xcaptcha() | iq() | streamhost() | bind() | @@ -917,6 +942,7 @@ starttls() | mam_prefs() | sasl_mechanisms() | + media_uri() | muc_destroy() | vcard_key() | csi() | @@ -949,4 +975,8 @@ expire() | muc_unsubscribe() | pubsub_unsubscribe() | - chatstate(). + chatstate() | + sasl_auth() | + p1_push() | + oob_x() | + pubsub_publish(). diff --git a/src/ejabberd_captcha.erl b/src/ejabberd_captcha.erl index 157700c47..df74a68b1 100644 --- a/src/ejabberd_captcha.erl +++ b/src/ejabberd_captcha.erl @@ -41,31 +41,17 @@ -export([create_captcha/6, build_captcha_html/2, check_captcha/2, process_reply/1, process/2, is_feature_available/0, create_captcha_x/5, - create_captcha_x/6, opt_type/1]). - --include("jlib.hrl"). + opt_type/1]). +-include("xmpp.hrl"). -include("ejabberd.hrl"). -include("logger.hrl"). - -include("ejabberd_http.hrl"). --define(VFIELD(Type, Var, Value), - #xmlel{name = <<"field">>, - attrs = [{<<"type">>, Type}, {<<"var">>, Var}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = [Value]}]}). - --define(CAPTCHA_TEXT(Lang), - translate:translate(Lang, - <<"Enter the text you see">>)). - -define(CAPTCHA_LIFETIME, 120000). - -define(LIMIT_PERIOD, 60*1000*1000). --type error() :: efbig | enodata | limit | malformed_image | timeout. +-type image_error() :: efbig | enodata | limit | malformed_image | timeout. -record(state, {limits = treap:empty() :: treap:treap()}). @@ -79,188 +65,82 @@ start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). +-spec captcha_text(undefined | binary()) -> binary(). +captcha_text(Lang) -> + translate:translate(Lang, <<"Enter the text you see">>). + +-spec mk_ocr_field(binary() | undefined, binary(), binary()) -> xdata_field(). +mk_ocr_field(Lang, CID, Type) -> + URI = #media_uri{type = Type, uri = <<"cid:", CID/binary>>}, + #xdata_field{var = <<"ocr">>, + label = captcha_text(Lang), + required = true, + sub_els = [#media{uri = [URI]}]}. + +mk_field(Type, Var, Value) -> + #xdata_field{type = Type, var = Var, values = [Value]}. + -spec create_captcha(binary(), jid(), jid(), - binary(), any(), any()) -> {error, error()} | - {ok, binary(), [xmlel()]}. + binary(), any(), any()) -> {error, image_error()} | + {ok, binary(), [text()], [xmlel()]}. create_captcha(SID, From, To, Lang, Limiter, Args) -> case create_image(Limiter) of {ok, Type, Key, Image} -> Id = <<(randoms:get_string())/binary>>, - B64Image = jlib:encode_base64((Image)), JID = jid:to_string(From), - CID = <<"sha1+", (p1_sha:sha(Image))/binary, - "@bob.xmpp.org">>, - Data = #xmlel{name = <<"data">>, - attrs = - [{<<"xmlns">>, ?NS_BOB}, {<<"cid">>, CID}, - {<<"max-age">>, <<"0">>}, {<<"type">>, Type}], - children = [{xmlcdata, B64Image}]}, - Captcha = #xmlel{name = <<"captcha">>, - attrs = [{<<"xmlns">>, ?NS_CAPTCHA}], - children = - [#xmlel{name = <<"x">>, - attrs = - [{<<"xmlns">>, ?NS_XDATA}, - {<<"type">>, <<"form">>}], - children = - [?VFIELD(<<"hidden">>, - <<"FORM_TYPE">>, - {xmlcdata, ?NS_CAPTCHA}), - ?VFIELD(<<"hidden">>, <<"from">>, - {xmlcdata, - jid:to_string(To)}), - ?VFIELD(<<"hidden">>, - <<"challenge">>, - {xmlcdata, Id}), - ?VFIELD(<<"hidden">>, <<"sid">>, - {xmlcdata, SID}), - #xmlel{name = <<"field">>, - attrs = - [{<<"var">>, <<"ocr">>}, - {<<"label">>, - ?CAPTCHA_TEXT(Lang)}], - children = - [#xmlel{name = - <<"required">>, - attrs = [], - children = []}, - #xmlel{name = - <<"media">>, - attrs = - [{<<"xmlns">>, - ?NS_MEDIA}], - children = - [#xmlel{name - = - <<"uri">>, - attrs - = - [{<<"type">>, - Type}], - children - = - [{xmlcdata, - <<"cid:", - CID/binary>>}]}]}]}]}]}, + CID = <<"sha1+", (p1_sha:sha(Image))/binary, "@bob.xmpp.org">>, + Data = #bob_data{cid = CID, 'max-age' = 0, type = Type, + data = Image}, + Fs = [mk_field(hidden, <<"FORM_TYPE">>, ?NS_CAPTCHA), + mk_field(hidden, <<"from">>, jid:to_string(To)), + mk_field(hidden, <<"challenge">>, Id), + mk_field(hidden, <<"sid">>, SID), + mk_ocr_field(Lang, CID, Type)], + X = #xdata{type = form, fields = Fs}, + Captcha = #xcaptcha{xdata = X}, BodyString1 = translate:translate(Lang, <<"Your messages to ~s are being blocked. " "To unblock them, visit ~s">>), BodyString = iolist_to_binary(io_lib:format(BodyString1, [JID, get_url(Id)])), - Body = #xmlel{name = <<"body">>, attrs = [], - children = [{xmlcdata, BodyString}]}, - OOB = #xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_OOB}], - children = - [#xmlel{name = <<"url">>, attrs = [], - children = [{xmlcdata, get_url(Id)}]}]}, + Body = xmpp:mk_text(BodyString, Lang), + OOB = #oob_x{url = get_url(Id)}, Tref = erlang:send_after(?CAPTCHA_LIFETIME, ?MODULE, {remove_id, Id}), ets:insert(captcha, #captcha{id = Id, pid = self(), key = Key, tref = Tref, args = Args}), - {ok, Id, [Body, OOB, Captcha, Data]}; + {ok, Id, Body, [OOB, Captcha, Data]}; Err -> Err end. --spec create_captcha_x(binary(), jid(), binary(), - any(), [xmlel()]) -> {ok, [xmlel()]} | - {error, error()}. +-spec create_captcha_x(binary(), jid(), binary(), any(), xdata()) -> + {ok, xdata()} | {error, image_error()}. -create_captcha_x(SID, To, Lang, Limiter, HeadEls) -> - create_captcha_x(SID, To, Lang, Limiter, HeadEls, []). - --spec create_captcha_x(binary(), jid(), binary(), - any(), [xmlel()], [xmlel()]) -> {ok, [xmlel()]} | - {error, error()}. - -create_captcha_x(SID, To, Lang, Limiter, HeadEls, - TailEls) -> +create_captcha_x(SID, To, Lang, Limiter, #xdata{fields = Fs} = X) -> case create_image(Limiter) of {ok, Type, Key, Image} -> Id = <<(randoms:get_string())/binary>>, - B64Image = jlib:encode_base64((Image)), - CID = <<"sha1+", (p1_sha:sha(Image))/binary, - "@bob.xmpp.org">>, - Data = #xmlel{name = <<"data">>, - attrs = - [{<<"xmlns">>, ?NS_BOB}, {<<"cid">>, CID}, - {<<"max-age">>, <<"0">>}, {<<"type">>, Type}], - children = [{xmlcdata, B64Image}]}, + CID = <<"sha1+", (p1_sha:sha(Image))/binary, "@bob.xmpp.org">>, + Data = #bob_data{cid = CID, 'max-age' = 0, type = Type, data = Image}, HelpTxt = translate:translate(Lang, <<"If you don't see the CAPTCHA image here, " "visit the web page.">>), Imageurl = get_url(<>), - Captcha = #xmlel{name = <<"x">>, - attrs = - [{<<"xmlns">>, ?NS_XDATA}, - {<<"type">>, <<"form">>}], - children = - [?VFIELD(<<"hidden">>, <<"FORM_TYPE">>, - {xmlcdata, ?NS_CAPTCHA}) - | HeadEls] - ++ - [#xmlel{name = <<"field">>, - attrs = [{<<"type">>, <<"fixed">>}], - children = - [#xmlel{name = <<"value">>, - attrs = [], - children = - [{xmlcdata, - HelpTxt}]}]}, - #xmlel{name = <<"field">>, - attrs = - [{<<"type">>, <<"hidden">>}, - {<<"var">>, <<"captchahidden">>}], - children = - [#xmlel{name = <<"value">>, - attrs = [], - children = - [{xmlcdata, - <<"workaround-for-psi">>}]}]}, - #xmlel{name = <<"field">>, - attrs = - [{<<"type">>, <<"text-single">>}, - {<<"label">>, - translate:translate(Lang, - <<"CAPTCHA web page">>)}, - {<<"var">>, <<"url">>}], - children = - [#xmlel{name = <<"value">>, - attrs = [], - children = - [{xmlcdata, - Imageurl}]}]}, - ?VFIELD(<<"hidden">>, <<"from">>, - {xmlcdata, jid:to_string(To)}), - ?VFIELD(<<"hidden">>, <<"challenge">>, - {xmlcdata, Id}), - ?VFIELD(<<"hidden">>, <<"sid">>, - {xmlcdata, SID}), - #xmlel{name = <<"field">>, - attrs = - [{<<"var">>, <<"ocr">>}, - {<<"label">>, - ?CAPTCHA_TEXT(Lang)}], - children = - [#xmlel{name = <<"required">>, - attrs = [], children = []}, - #xmlel{name = <<"media">>, - attrs = - [{<<"xmlns">>, - ?NS_MEDIA}], - children = - [#xmlel{name = - <<"uri">>, - attrs = - [{<<"type">>, - Type}], - children = - [{xmlcdata, - <<"cid:", - CID/binary>>}]}]}]}] - ++ TailEls}, + NewFs = [mk_field(hidden, <<"FORM_TYPE">>, ?NS_CAPTCHA)|Fs] ++ + [#xdata_field{type = fixed, values = [HelpTxt]}, + #xdata_field{type = hidden, var = <<"captchahidden">>, + values = [<<"workaround-for-psi">>]}, + #xdata_field{type = 'text-single', var = <<"url">>, + label = translate:translate( + Lang, <<"CAPTCHA web page">>), + values = [Imageurl]}, + mk_field(hidden, <<"from">>, jid:to_string(To)), + mk_field(hidden, <<"challenge">>, Id), + mk_field(hidden, <<"sid">>, SID), + mk_ocr_field(Lang, CID, Type)], + Captcha = X#xdata{type = form, fields = NewFs}, Tref = erlang:send_after(?CAPTCHA_LIFETIME, ?MODULE, {remove_id, Id}), ets:insert(captcha, @@ -281,7 +161,7 @@ build_captcha_html(Id, Lang) -> attrs = [{<<"src">>, get_url(<>)}], children = []}, - TextEl = {xmlcdata, ?CAPTCHA_TEXT(Lang)}, + TextEl = {xmlcdata, captcha_text(Lang)}, IdEl = #xmlel{name = <<"input">>, attrs = [{<<"type">>, <<"hidden">>}, {<<"name">>, <<"id">>}, @@ -317,27 +197,24 @@ build_captcha_html(Id, Lang) -> _ -> captcha_not_found end. --spec process_reply(xmlel()) -> ok | {error, bad_match | not_found | malformed}. +-spec process_reply(xmpp_element()) -> ok | {error, bad_match | not_found | malformed}. -process_reply(#xmlel{} = El) -> - case fxml:get_subtag(El, <<"x">>) of - false -> {error, malformed}; - Xdata -> - Fields = jlib:parse_xdata_submit(Xdata), - case catch {proplists:get_value(<<"challenge">>, - Fields), - proplists:get_value(<<"ocr">>, Fields)} - of - {[Id | _], [OCR | _]} -> - case check_captcha(Id, OCR) of - captcha_valid -> ok; - captcha_non_valid -> {error, bad_match}; - captcha_not_found -> {error, not_found} - end; - _ -> {error, malformed} - end +process_reply(#xdata{} = X) -> + case {xmpp_util:get_xdata_values(<<"challenge">>, X), + xmpp_util:get_xdata_values(<<"ocr">>, X)} of + {[Id], [OCR]} -> + case check_captcha(Id, OCR) of + captcha_valid -> ok; + captcha_non_valid -> {error, bad_match}; + captcha_not_found -> {error, not_found} + end; + _ -> + {error, malformed} end; -process_reply(_) -> {error, malformed}. +process_reply(#xcaptcha{xdata = #xdata{} = X}) -> + process_reply(X); +process_reply(_) -> + {error, malformed}. process(_Handlers, #request{method = 'GET', lang = Lang, diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl index 29b7942cf..a539ab848 100644 --- a/src/mod_muc_room.erl +++ b/src/mod_muc_room.erl @@ -1824,8 +1824,9 @@ add_new_user(From, Nick, Packet, StateData) -> case ejabberd_captcha:create_captcha(SID, RoomJID, To, Lang, Limiter, From) of - {ok, ID, CaptchaEls} -> - MsgPkt = #message{id = ID, sub_els = CaptchaEls}, + {ok, ID, Body, CaptchaEls} -> + MsgPkt = #message{id = ID, body = Body, + sub_els = CaptchaEls}, Robots = (?DICT):store(From, {Nick, Packet}, StateData#state.robots), ejabberd_router:route(RoomJID, From, MsgPkt), diff --git a/src/mod_register.erl b/src/mod_register.erl index 3f9c33123..1ed266d47 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -218,10 +218,10 @@ process_iq(#iq{type = get, from = From, to = To, id = ID, lang = Lang} = IQ, X = #xdata{type = form, instructions = [Instr], fields = [UField, PField]}, case ejabberd_captcha:create_captcha_x(ID, To, Lang, Source, X) of - {ok, Captcha} -> + {ok, CaptchaEls} -> xmpp:make_iq_result( IQ, #register{instructions = TopInstr, - xdata = Captcha}); + sub_els = CaptchaEls}); {error, limit} -> ErrText = <<"Too many CAPTCHA requests">>, xmpp:make_error( diff --git a/src/mod_register_web.erl b/src/mod_register_web.erl index 76de1677f..20b370fb9 100644 --- a/src/mod_register_web.erl +++ b/src/mod_register_web.erl @@ -60,7 +60,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("ejabberd_http.hrl"). @@ -334,7 +334,7 @@ build_captcha_li_list2(Lang, IP) -> case ejabberd_captcha:create_captcha(SID, From, To, Lang, IP, Args) of - {ok, Id, _} -> + {ok, Id, _, _} -> {_, {CImg, CText, CId, CKey}} = ejabberd_captcha:build_captcha_html(Id, Lang), [?XE(<<"li">>, diff --git a/src/xmpp_codec.erl b/src/xmpp_codec.erl index 7eb06b11e..113be860b 100644 --- a/src/xmpp_codec.erl +++ b/src/xmpp_codec.erl @@ -15,6 +15,22 @@ decode(_el) -> decode(_el, []). decode({xmlel, _name, _attrs, _} = _el, Opts) -> IgnoreEls = proplists:get_bool(ignore_els, Opts), case {_name, get_attr(<<"xmlns">>, _attrs)} of + {<<"x">>, <<"jabber:x:oob">>} -> + decode_oob_x(<<"jabber:x:oob">>, IgnoreEls, _el); + {<<"desc">>, <<"jabber:x:oob">>} -> + decode_oob_desc(<<"jabber:x:oob">>, IgnoreEls, _el); + {<<"url">>, <<"jabber:x:oob">>} -> + decode_oob_url(<<"jabber:x:oob">>, IgnoreEls, _el); + {<<"media">>, <<"urn:xmpp:media-element">>} -> + decode_media(<<"urn:xmpp:media-element">>, IgnoreEls, + _el); + {<<"uri">>, <<"urn:xmpp:media-element">>} -> + decode_media_uri(<<"urn:xmpp:media-element">>, + IgnoreEls, _el); + {<<"captcha">>, <<"urn:xmpp:captcha">>} -> + decode_captcha(<<"urn:xmpp:captcha">>, IgnoreEls, _el); + {<<"data">>, <<"urn:xmpp:bob">>} -> + decode_bob_data(<<"urn:xmpp:bob">>, IgnoreEls, _el); {<<"stream:stream">>, <<"jabber:client">>} -> decode_stream_start(<<"jabber:client">>, IgnoreEls, _el); @@ -1293,6 +1309,13 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> is_known_tag({xmlel, _name, _attrs, _} = _el) -> case {_name, get_attr(<<"xmlns">>, _attrs)} of + {<<"x">>, <<"jabber:x:oob">>} -> true; + {<<"desc">>, <<"jabber:x:oob">>} -> true; + {<<"url">>, <<"jabber:x:oob">>} -> true; + {<<"media">>, <<"urn:xmpp:media-element">>} -> true; + {<<"uri">>, <<"urn:xmpp:media-element">>} -> true; + {<<"captcha">>, <<"urn:xmpp:captcha">>} -> true; + {<<"data">>, <<"urn:xmpp:bob">>} -> true; {<<"stream:stream">>, <<"jabber:client">>} -> true; {<<"stream:stream">>, <<"jabber:server">>} -> true; {<<"stream:stream">>, <<"jabber:component:accept">>} -> @@ -2216,7 +2239,7 @@ encode({feature_register} = Register) -> [{<<"xmlns">>, <<"http://jabber.org/features/iq-register">>}]); encode({register, _, _, _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _} = + _, _, _, _, _, _, _, _, _} = Query) -> encode_register(Query, [{<<"xmlns">>, <<"jabber:iq:register">>}]); @@ -2285,7 +2308,7 @@ encode({vcard_xupdate, undefined, _} = X) -> encode({xdata_option, _, _} = Option) -> encode_xdata_field_option(Option, [{<<"xmlns">>, <<"jabber:x:data">>}]); -encode({xdata_field, _, _, _, _, _, _, _} = Field) -> +encode({xdata_field, _, _, _, _, _, _, _, _} = Field) -> encode_xdata_field(Field, [{<<"xmlns">>, <<"jabber:x:data">>}]); encode({xdata, _, _, _, _, _, _} = X) -> @@ -2572,7 +2595,21 @@ encode({handshake, _} = Handshake) -> [{<<"xmlns">>, <<"jabber:client">>}]); encode({stream_start, _, _, _, _, _, _, _, _} = Stream_stream) -> - encode_stream_start(Stream_stream, []). + encode_stream_start(Stream_stream, []); +encode({bob_data, _, _, _, _} = Data) -> + encode_bob_data(Data, + [{<<"xmlns">>, <<"urn:xmpp:bob">>}]); +encode({xcaptcha, _} = Captcha) -> + encode_captcha(Captcha, + [{<<"xmlns">>, <<"urn:xmpp:captcha">>}]); +encode({media_uri, _, _} = Uri) -> + encode_media_uri(Uri, + [{<<"xmlns">>, <<"urn:xmpp:media-element">>}]); +encode({media, _, _, _} = Media) -> + encode_media(Media, + [{<<"xmlns">>, <<"urn:xmpp:media-element">>}]); +encode({oob_x, _, _, _} = X) -> + encode_oob_x(X, [{<<"xmlns">>, <<"jabber:x:oob">>}]). get_name({last, _, _}) -> <<"query">>; get_name({version, _, _, _}) -> <<"query">>; @@ -2628,7 +2665,7 @@ get_name({p1_ack}) -> <<"ack">>; get_name({caps, _, _, _, _}) -> <<"c">>; get_name({feature_register}) -> <<"register">>; get_name({register, _, _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, _}) -> + _, _, _, _, _, _, _, _, _, _}) -> <<"query">>; get_name({xmpp_session, _}) -> <<"session">>; get_name({ping}) -> <<"ping">>; @@ -2659,7 +2696,7 @@ get_name({vcard_temp, _, _, _, _, _, _, _, _, _, _, _, <<"vCard">>; get_name({vcard_xupdate, undefined, _}) -> <<"x">>; get_name({xdata_option, _, _}) -> <<"option">>; -get_name({xdata_field, _, _, _, _, _, _, _}) -> +get_name({xdata_field, _, _, _, _, _, _, _, _}) -> <<"field">>; get_name({xdata, _, _, _, _, _, _}) -> <<"x">>; get_name({pubsub_subscription, _, _, _, _}) -> @@ -2760,7 +2797,12 @@ get_name({db_verify, _, _, _, _, _, _}) -> <<"db:verify">>; get_name({handshake, _}) -> <<"handshake">>; get_name({stream_start, _, _, _, _, _, _, _, _}) -> - <<"stream:stream">>. + <<"stream:stream">>; +get_name({bob_data, _, _, _, _}) -> <<"data">>; +get_name({xcaptcha, _}) -> <<"captcha">>; +get_name({media_uri, _, _}) -> <<"uri">>; +get_name({media, _, _, _}) -> <<"media">>; +get_name({oob_x, _, _, _}) -> <<"x">>. get_ns({last, _, _}) -> <<"jabber:iq:last">>; get_ns({version, _, _, _}) -> <<"jabber:iq:version">>; @@ -2848,7 +2890,7 @@ get_ns({caps, _, _, _, _}) -> get_ns({feature_register}) -> <<"http://jabber.org/features/iq-register">>; get_ns({register, _, _, _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _}) -> + _, _, _, _, _, _, _, _, _}) -> <<"jabber:iq:register">>; get_ns({xmpp_session, _}) -> <<"urn:ietf:params:xml:ns:xmpp-session">>; @@ -2881,7 +2923,7 @@ get_ns({vcard_temp, _, _, _, _, _, _, _, _, _, _, _, _, get_ns({vcard_xupdate, undefined, _}) -> <<"vcard-temp:x:update">>; get_ns({xdata_option, _, _}) -> <<"jabber:x:data">>; -get_ns({xdata_field, _, _, _, _, _, _, _}) -> +get_ns({xdata_field, _, _, _, _, _, _, _, _}) -> <<"jabber:x:data">>; get_ns({xdata, _, _, _, _, _, _}) -> <<"jabber:x:data">>; @@ -3021,7 +3063,14 @@ get_ns({db_verify, _, _, _, _, _, _}) -> <<"jabber:client">>; get_ns({handshake, _}) -> <<"jabber:client">>; get_ns({stream_start, _, _, _, _, Xmlns, _, _, _}) -> - Xmlns. + Xmlns; +get_ns({bob_data, _, _, _, _}) -> <<"urn:xmpp:bob">>; +get_ns({xcaptcha, _}) -> <<"urn:xmpp:captcha">>; +get_ns({media_uri, _, _}) -> + <<"urn:xmpp:media-element">>; +get_ns({media, _, _, _}) -> + <<"urn:xmpp:media-element">>; +get_ns({oob_x, _, _, _}) -> <<"jabber:x:oob">>. dec_int(Val) -> dec_int(Val, infinity, infinity). @@ -3129,10 +3178,11 @@ pp(p1_rebind, 0) -> []; pp(p1_ack, 0) -> []; pp(caps, 4) -> [node, version, hash, exts]; pp(feature_register, 0) -> []; -pp(register, 21) -> +pp(register, 22) -> [registered, remove, instructions, username, nick, password, name, first, last, email, address, city, - state, zip, phone, url, date, misc, text, key, xdata]; + state, zip, phone, url, date, misc, text, key, xdata, + sub_els]; pp(xmpp_session, 1) -> [optional]; pp(ping, 0) -> []; pp(time, 2) -> [tzo, utc]; @@ -3164,8 +3214,9 @@ pp(vcard_temp, 29) -> uid, url, class, key, desc]; pp(vcard_xupdate, 2) -> [us, hash]; pp(xdata_option, 2) -> [label, value]; -pp(xdata_field, 7) -> - [label, type, var, required, desc, values, options]; +pp(xdata_field, 8) -> + [label, type, var, required, desc, values, options, + sub_els]; pp(xdata, 6) -> [type, instructions, title, reported, items, fields]; pp(pubsub_subscription, 4) -> [jid, node, subid, type]; @@ -3263,6 +3314,11 @@ pp(handshake, 1) -> [data]; pp(stream_start, 8) -> [from, to, id, version, xmlns, stream_xmlns, db_xmlns, lang]; +pp(bob_data, 4) -> [cid, 'max-age', type, data]; +pp(xcaptcha, 1) -> [xdata]; +pp(media_uri, 2) -> [type, uri]; +pp(media, 3) -> [height, width, uri]; +pp(oob_x, 3) -> [url, desc, sid]; pp(_, _) -> no. join([], _Sep) -> <<>>; @@ -3309,6 +3365,423 @@ dec_tzo(Val) -> M = jlib:binary_to_integer(M1), if H >= -12, H =< 12, M >= 0, M < 60 -> {H, M} end. +decode_oob_x(__TopXMLNS, __IgnoreEls, + {xmlel, <<"x">>, _attrs, _els}) -> + {Desc, Url} = decode_oob_x_els(__TopXMLNS, __IgnoreEls, + _els, <<>>, error), + Sid = decode_oob_x_attrs(__TopXMLNS, _attrs, undefined), + {oob_x, Url, Desc, Sid}. + +decode_oob_x_els(__TopXMLNS, __IgnoreEls, [], Desc, + Url) -> + {Desc, + case Url of + error -> + erlang:error({xmpp_codec, + {missing_tag, <<"url">>, __TopXMLNS}}); + {value, Url1} -> Url1 + end}; +decode_oob_x_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"url">>, _attrs, _} = _el | _els], Desc, + Url) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:x:oob">> -> + decode_oob_x_els(__TopXMLNS, __IgnoreEls, _els, Desc, + {value, + decode_oob_url(__TopXMLNS, __IgnoreEls, _el)}); + <<"jabber:x:oob">> -> + decode_oob_x_els(__TopXMLNS, __IgnoreEls, _els, Desc, + {value, + decode_oob_url(<<"jabber:x:oob">>, __IgnoreEls, + _el)}); + _ -> + decode_oob_x_els(__TopXMLNS, __IgnoreEls, _els, Desc, + Url) + end; +decode_oob_x_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"desc">>, _attrs, _} = _el | _els], Desc, + Url) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"jabber:x:oob">> -> + decode_oob_x_els(__TopXMLNS, __IgnoreEls, _els, + decode_oob_desc(__TopXMLNS, __IgnoreEls, _el), Url); + <<"jabber:x:oob">> -> + decode_oob_x_els(__TopXMLNS, __IgnoreEls, _els, + decode_oob_desc(<<"jabber:x:oob">>, __IgnoreEls, + _el), + Url); + _ -> + decode_oob_x_els(__TopXMLNS, __IgnoreEls, _els, Desc, + Url) + end; +decode_oob_x_els(__TopXMLNS, __IgnoreEls, [_ | _els], + Desc, Url) -> + decode_oob_x_els(__TopXMLNS, __IgnoreEls, _els, Desc, + Url). + +decode_oob_x_attrs(__TopXMLNS, + [{<<"sid">>, _val} | _attrs], _Sid) -> + decode_oob_x_attrs(__TopXMLNS, _attrs, _val); +decode_oob_x_attrs(__TopXMLNS, [_ | _attrs], Sid) -> + decode_oob_x_attrs(__TopXMLNS, _attrs, Sid); +decode_oob_x_attrs(__TopXMLNS, [], Sid) -> + decode_oob_x_attr_sid(__TopXMLNS, Sid). + +encode_oob_x({oob_x, Url, Desc, Sid}, _xmlns_attrs) -> + _els = lists:reverse('encode_oob_x_$desc'(Desc, + 'encode_oob_x_$url'(Url, []))), + _attrs = encode_oob_x_attr_sid(Sid, _xmlns_attrs), + {xmlel, <<"x">>, _attrs, _els}. + +'encode_oob_x_$desc'(<<>>, _acc) -> _acc; +'encode_oob_x_$desc'(Desc, _acc) -> + [encode_oob_desc(Desc, []) | _acc]. + +'encode_oob_x_$url'(Url, _acc) -> + [encode_oob_url(Url, []) | _acc]. + +decode_oob_x_attr_sid(__TopXMLNS, undefined) -> <<>>; +decode_oob_x_attr_sid(__TopXMLNS, _val) -> _val. + +encode_oob_x_attr_sid(<<>>, _acc) -> _acc; +encode_oob_x_attr_sid(_val, _acc) -> + [{<<"sid">>, _val} | _acc]. + +decode_oob_desc(__TopXMLNS, __IgnoreEls, + {xmlel, <<"desc">>, _attrs, _els}) -> + Cdata = decode_oob_desc_els(__TopXMLNS, __IgnoreEls, + _els, <<>>), + Cdata. + +decode_oob_desc_els(__TopXMLNS, __IgnoreEls, [], + Cdata) -> + decode_oob_desc_cdata(__TopXMLNS, Cdata); +decode_oob_desc_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Cdata) -> + decode_oob_desc_els(__TopXMLNS, __IgnoreEls, _els, + <>); +decode_oob_desc_els(__TopXMLNS, __IgnoreEls, [_ | _els], + Cdata) -> + decode_oob_desc_els(__TopXMLNS, __IgnoreEls, _els, + Cdata). + +encode_oob_desc(Cdata, _xmlns_attrs) -> + _els = encode_oob_desc_cdata(Cdata, []), + _attrs = _xmlns_attrs, + {xmlel, <<"desc">>, _attrs, _els}. + +decode_oob_desc_cdata(__TopXMLNS, <<>>) -> <<>>; +decode_oob_desc_cdata(__TopXMLNS, _val) -> _val. + +encode_oob_desc_cdata(<<>>, _acc) -> _acc; +encode_oob_desc_cdata(_val, _acc) -> + [{xmlcdata, _val} | _acc]. + +decode_oob_url(__TopXMLNS, __IgnoreEls, + {xmlel, <<"url">>, _attrs, _els}) -> + Cdata = decode_oob_url_els(__TopXMLNS, __IgnoreEls, + _els, <<>>), + Cdata. + +decode_oob_url_els(__TopXMLNS, __IgnoreEls, [], + Cdata) -> + decode_oob_url_cdata(__TopXMLNS, Cdata); +decode_oob_url_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Cdata) -> + decode_oob_url_els(__TopXMLNS, __IgnoreEls, _els, + <>); +decode_oob_url_els(__TopXMLNS, __IgnoreEls, [_ | _els], + Cdata) -> + decode_oob_url_els(__TopXMLNS, __IgnoreEls, _els, + Cdata). + +encode_oob_url(Cdata, _xmlns_attrs) -> + _els = encode_oob_url_cdata(Cdata, []), + _attrs = _xmlns_attrs, + {xmlel, <<"url">>, _attrs, _els}. + +decode_oob_url_cdata(__TopXMLNS, <<>>) -> + erlang:error({xmpp_codec, + {missing_cdata, <<>>, <<"url">>, __TopXMLNS}}); +decode_oob_url_cdata(__TopXMLNS, _val) -> _val. + +encode_oob_url_cdata(_val, _acc) -> + [{xmlcdata, _val} | _acc]. + +decode_media(__TopXMLNS, __IgnoreEls, + {xmlel, <<"media">>, _attrs, _els}) -> + Uri = decode_media_els(__TopXMLNS, __IgnoreEls, _els, + []), + {Height, Width} = decode_media_attrs(__TopXMLNS, _attrs, + undefined, undefined), + {media, Height, Width, Uri}. + +decode_media_els(__TopXMLNS, __IgnoreEls, [], Uri) -> + lists:reverse(Uri); +decode_media_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"uri">>, _attrs, _} = _el | _els], Uri) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == <<"urn:xmpp:media-element">> -> + decode_media_els(__TopXMLNS, __IgnoreEls, _els, + [decode_media_uri(__TopXMLNS, __IgnoreEls, _el) + | Uri]); + <<"urn:xmpp:media-element">> -> + decode_media_els(__TopXMLNS, __IgnoreEls, _els, + [decode_media_uri(<<"urn:xmpp:media-element">>, + __IgnoreEls, _el) + | Uri]); + _ -> + decode_media_els(__TopXMLNS, __IgnoreEls, _els, Uri) + end; +decode_media_els(__TopXMLNS, __IgnoreEls, [_ | _els], + Uri) -> + decode_media_els(__TopXMLNS, __IgnoreEls, _els, Uri). + +decode_media_attrs(__TopXMLNS, + [{<<"height">>, _val} | _attrs], _Height, Width) -> + decode_media_attrs(__TopXMLNS, _attrs, _val, Width); +decode_media_attrs(__TopXMLNS, + [{<<"width">>, _val} | _attrs], Height, _Width) -> + decode_media_attrs(__TopXMLNS, _attrs, Height, _val); +decode_media_attrs(__TopXMLNS, [_ | _attrs], Height, + Width) -> + decode_media_attrs(__TopXMLNS, _attrs, Height, Width); +decode_media_attrs(__TopXMLNS, [], Height, Width) -> + {decode_media_attr_height(__TopXMLNS, Height), + decode_media_attr_width(__TopXMLNS, Width)}. + +encode_media({media, Height, Width, Uri}, + _xmlns_attrs) -> + _els = lists:reverse('encode_media_$uri'(Uri, [])), + _attrs = encode_media_attr_width(Width, + encode_media_attr_height(Height, + _xmlns_attrs)), + {xmlel, <<"media">>, _attrs, _els}. + +'encode_media_$uri'([], _acc) -> _acc; +'encode_media_$uri'([Uri | _els], _acc) -> + 'encode_media_$uri'(_els, + [encode_media_uri(Uri, []) | _acc]). + +decode_media_attr_height(__TopXMLNS, undefined) -> + undefined; +decode_media_attr_height(__TopXMLNS, _val) -> + case catch dec_int(_val, 0, infinity) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"height">>, <<"media">>, + __TopXMLNS}}); + _res -> _res + end. + +encode_media_attr_height(undefined, _acc) -> _acc; +encode_media_attr_height(_val, _acc) -> + [{<<"height">>, enc_int(_val)} | _acc]. + +decode_media_attr_width(__TopXMLNS, undefined) -> + undefined; +decode_media_attr_width(__TopXMLNS, _val) -> + case catch dec_int(_val, 0, inifinity) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"width">>, <<"media">>, + __TopXMLNS}}); + _res -> _res + end. + +encode_media_attr_width(undefined, _acc) -> _acc; +encode_media_attr_width(_val, _acc) -> + [{<<"width">>, enc_int(_val)} | _acc]. + +decode_media_uri(__TopXMLNS, __IgnoreEls, + {xmlel, <<"uri">>, _attrs, _els}) -> + Uri = decode_media_uri_els(__TopXMLNS, __IgnoreEls, + _els, <<>>), + Type = decode_media_uri_attrs(__TopXMLNS, _attrs, + undefined), + {media_uri, Type, Uri}. + +decode_media_uri_els(__TopXMLNS, __IgnoreEls, [], + Uri) -> + decode_media_uri_cdata(__TopXMLNS, Uri); +decode_media_uri_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Uri) -> + decode_media_uri_els(__TopXMLNS, __IgnoreEls, _els, + <>); +decode_media_uri_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Uri) -> + decode_media_uri_els(__TopXMLNS, __IgnoreEls, _els, + Uri). + +decode_media_uri_attrs(__TopXMLNS, + [{<<"type">>, _val} | _attrs], _Type) -> + decode_media_uri_attrs(__TopXMLNS, _attrs, _val); +decode_media_uri_attrs(__TopXMLNS, [_ | _attrs], + Type) -> + decode_media_uri_attrs(__TopXMLNS, _attrs, Type); +decode_media_uri_attrs(__TopXMLNS, [], Type) -> + decode_media_uri_attr_type(__TopXMLNS, Type). + +encode_media_uri({media_uri, Type, Uri}, + _xmlns_attrs) -> + _els = encode_media_uri_cdata(Uri, []), + _attrs = encode_media_uri_attr_type(Type, _xmlns_attrs), + {xmlel, <<"uri">>, _attrs, _els}. + +decode_media_uri_attr_type(__TopXMLNS, undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"type">>, <<"uri">>, __TopXMLNS}}); +decode_media_uri_attr_type(__TopXMLNS, _val) -> _val. + +encode_media_uri_attr_type(_val, _acc) -> + [{<<"type">>, _val} | _acc]. + +decode_media_uri_cdata(__TopXMLNS, <<>>) -> <<>>; +decode_media_uri_cdata(__TopXMLNS, _val) -> _val. + +encode_media_uri_cdata(<<>>, _acc) -> _acc; +encode_media_uri_cdata(_val, _acc) -> + [{xmlcdata, _val} | _acc]. + +decode_captcha(__TopXMLNS, __IgnoreEls, + {xmlel, <<"captcha">>, _attrs, _els}) -> + Xdata = decode_captcha_els(__TopXMLNS, __IgnoreEls, + _els, error), + {xcaptcha, Xdata}. + +decode_captcha_els(__TopXMLNS, __IgnoreEls, [], + Xdata) -> + case Xdata of + error -> + erlang:error({xmpp_codec, + {missing_tag, <<"x">>, __TopXMLNS}}); + {value, Xdata1} -> Xdata1 + end; +decode_captcha_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"x">>, _attrs, _} = _el | _els], Xdata) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"jabber:x:data">> -> + decode_captcha_els(__TopXMLNS, __IgnoreEls, _els, + {value, + decode_xdata(<<"jabber:x:data">>, __IgnoreEls, + _el)}); + _ -> + decode_captcha_els(__TopXMLNS, __IgnoreEls, _els, Xdata) + end; +decode_captcha_els(__TopXMLNS, __IgnoreEls, [_ | _els], + Xdata) -> + decode_captcha_els(__TopXMLNS, __IgnoreEls, _els, + Xdata). + +encode_captcha({xcaptcha, Xdata}, _xmlns_attrs) -> + _els = lists:reverse('encode_captcha_$xdata'(Xdata, + [])), + _attrs = _xmlns_attrs, + {xmlel, <<"captcha">>, _attrs, _els}. + +'encode_captcha_$xdata'(Xdata, _acc) -> + [encode_xdata(Xdata, + [{<<"xmlns">>, <<"jabber:x:data">>}]) + | _acc]. + +decode_bob_data(__TopXMLNS, __IgnoreEls, + {xmlel, <<"data">>, _attrs, _els}) -> + Data = decode_bob_data_els(__TopXMLNS, __IgnoreEls, + _els, <<>>), + {Cid, Max_age, Type} = decode_bob_data_attrs(__TopXMLNS, + _attrs, undefined, undefined, + undefined), + {bob_data, Cid, Max_age, Type, Data}. + +decode_bob_data_els(__TopXMLNS, __IgnoreEls, [], + Data) -> + decode_bob_data_cdata(__TopXMLNS, Data); +decode_bob_data_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Data) -> + decode_bob_data_els(__TopXMLNS, __IgnoreEls, _els, + <>); +decode_bob_data_els(__TopXMLNS, __IgnoreEls, [_ | _els], + Data) -> + decode_bob_data_els(__TopXMLNS, __IgnoreEls, _els, + Data). + +decode_bob_data_attrs(__TopXMLNS, + [{<<"cid">>, _val} | _attrs], _Cid, Max_age, Type) -> + decode_bob_data_attrs(__TopXMLNS, _attrs, _val, Max_age, + Type); +decode_bob_data_attrs(__TopXMLNS, + [{<<"max-age">>, _val} | _attrs], Cid, _Max_age, + Type) -> + decode_bob_data_attrs(__TopXMLNS, _attrs, Cid, _val, + Type); +decode_bob_data_attrs(__TopXMLNS, + [{<<"type">>, _val} | _attrs], Cid, Max_age, _Type) -> + decode_bob_data_attrs(__TopXMLNS, _attrs, Cid, Max_age, + _val); +decode_bob_data_attrs(__TopXMLNS, [_ | _attrs], Cid, + Max_age, Type) -> + decode_bob_data_attrs(__TopXMLNS, _attrs, Cid, Max_age, + Type); +decode_bob_data_attrs(__TopXMLNS, [], Cid, Max_age, + Type) -> + {decode_bob_data_attr_cid(__TopXMLNS, Cid), + 'decode_bob_data_attr_max-age'(__TopXMLNS, Max_age), + decode_bob_data_attr_type(__TopXMLNS, Type)}. + +encode_bob_data({bob_data, Cid, Max_age, Type, Data}, + _xmlns_attrs) -> + _els = encode_bob_data_cdata(Data, []), + _attrs = encode_bob_data_attr_type(Type, + 'encode_bob_data_attr_max-age'(Max_age, + encode_bob_data_attr_cid(Cid, + _xmlns_attrs))), + {xmlel, <<"data">>, _attrs, _els}. + +decode_bob_data_attr_cid(__TopXMLNS, undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"cid">>, <<"data">>, __TopXMLNS}}); +decode_bob_data_attr_cid(__TopXMLNS, _val) -> _val. + +encode_bob_data_attr_cid(_val, _acc) -> + [{<<"cid">>, _val} | _acc]. + +'decode_bob_data_attr_max-age'(__TopXMLNS, undefined) -> + undefined; +'decode_bob_data_attr_max-age'(__TopXMLNS, _val) -> + case catch dec_int(_val, 0, infinity) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"max-age">>, <<"data">>, + __TopXMLNS}}); + _res -> _res + end. + +'encode_bob_data_attr_max-age'(undefined, _acc) -> _acc; +'encode_bob_data_attr_max-age'(_val, _acc) -> + [{<<"max-age">>, enc_int(_val)} | _acc]. + +decode_bob_data_attr_type(__TopXMLNS, undefined) -> + undefined; +decode_bob_data_attr_type(__TopXMLNS, _val) -> _val. + +encode_bob_data_attr_type(undefined, _acc) -> _acc; +encode_bob_data_attr_type(_val, _acc) -> + [{<<"type">>, _val} | _acc]. + +decode_bob_data_cdata(__TopXMLNS, <<>>) -> <<>>; +decode_bob_data_cdata(__TopXMLNS, _val) -> + case catch base64:decode(_val) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_cdata_value, <<>>, <<"data">>, __TopXMLNS}}); + _res -> _res + end. + +encode_bob_data_cdata(<<>>, _acc) -> _acc; +encode_bob_data_cdata(_val, _acc) -> + [{xmlcdata, base64:encode(_val)} | _acc]. + decode_stream_start(__TopXMLNS, __IgnoreEls, {xmlel, <<"stream:stream">>, _attrs, _els}) -> {From, To, Xmlns, Stream_xmlns, Db_xmlns, Lang, Version, @@ -12727,60 +13200,62 @@ encode_xdata_instructions_cdata(_val, _acc) -> decode_xdata_field(__TopXMLNS, __IgnoreEls, {xmlel, <<"field">>, _attrs, _els}) -> - {Options, Values, Desc, Required} = + {Options, Values, Desc, Required, __Els} = decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - [], [], undefined, false), + [], [], undefined, false, []), {Label, Type, Var} = decode_xdata_field_attrs(__TopXMLNS, _attrs, undefined, undefined, undefined), {xdata_field, Label, Type, Var, Required, Desc, Values, - Options}. + Options, __Els}. decode_xdata_field_els(__TopXMLNS, __IgnoreEls, [], - Options, Values, Desc, Required) -> + Options, Values, Desc, Required, __Els) -> {lists:reverse(Options), lists:reverse(Values), Desc, - Required}; + Required, lists:reverse(__Els)}; decode_xdata_field_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"required">>, _attrs, _} = _el | _els], - Options, Values, Desc, Required) -> + Options, Values, Desc, Required, __Els) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"jabber:x:data">> -> decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, Options, Values, Desc, decode_xdata_field_required(__TopXMLNS, - __IgnoreEls, _el)); + __IgnoreEls, _el), + __Els); <<"jabber:x:data">> -> decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, Options, Values, Desc, decode_xdata_field_required(<<"jabber:x:data">>, - __IgnoreEls, _el)); + __IgnoreEls, _el), + __Els); _ -> decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, Values, Desc, Required) + Options, Values, Desc, Required, __Els) end; decode_xdata_field_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"desc">>, _attrs, _} = _el | _els], Options, - Values, Desc, Required) -> + Values, Desc, Required, __Els) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"jabber:x:data">> -> decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, Options, Values, decode_xdata_field_desc(__TopXMLNS, __IgnoreEls, _el), - Required); + Required, __Els); <<"jabber:x:data">> -> decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, Options, Values, decode_xdata_field_desc(<<"jabber:x:data">>, __IgnoreEls, _el), - Required); + Required, __Els); _ -> decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, Values, Desc, Required) + Options, Values, Desc, Required, __Els) end; decode_xdata_field_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"value">>, _attrs, _} = _el | _els], Options, - Values, Desc, Required) -> + Values, Desc, Required, __Els) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"jabber:x:data">> -> decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, @@ -12791,7 +13266,7 @@ decode_xdata_field_els(__TopXMLNS, __IgnoreEls, undefined -> Values; _new_el -> [_new_el | Values] end, - Desc, Required); + Desc, Required, __Els); <<"jabber:x:data">> -> decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, Options, @@ -12802,35 +13277,53 @@ decode_xdata_field_els(__TopXMLNS, __IgnoreEls, undefined -> Values; _new_el -> [_new_el | Values] end, - Desc, Required); + Desc, Required, __Els); _ -> decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, Values, Desc, Required) + Options, Values, Desc, Required, __Els) end; decode_xdata_field_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"option">>, _attrs, _} = _el | _els], - Options, Values, Desc, Required) -> + Options, Values, Desc, Required, __Els) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"jabber:x:data">> -> decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, [decode_xdata_field_option(__TopXMLNS, __IgnoreEls, _el) | Options], - Values, Desc, Required); + Values, Desc, Required, __Els); <<"jabber:x:data">> -> decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, [decode_xdata_field_option(<<"jabber:x:data">>, __IgnoreEls, _el) | Options], - Values, Desc, Required); + Values, Desc, Required, __Els); _ -> decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, Values, Desc, Required) + Options, Values, Desc, Required, __Els) end; decode_xdata_field_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Options, Values, Desc, Required) -> + [{xmlel, _, _, _} = _el | _els], Options, Values, Desc, + Required, __Els) -> + if __IgnoreEls -> + decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, + Options, Values, Desc, Required, + [_el | __Els]); + true -> + case is_known_tag(_el) of + true -> + decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, + Options, Values, Desc, Required, + [decode(_el) | __Els]); + false -> + decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, + Options, Values, Desc, Required, __Els) + end + end; +decode_xdata_field_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Options, Values, Desc, Required, __Els) -> decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, Values, Desc, Required). + Options, Values, Desc, Required, __Els). decode_xdata_field_attrs(__TopXMLNS, [{<<"label">>, _val} | _attrs], _Label, Type, Var) -> @@ -12855,14 +13348,14 @@ decode_xdata_field_attrs(__TopXMLNS, [], Label, Type, decode_xdata_field_attr_var(__TopXMLNS, Var)}. encode_xdata_field({xdata_field, Label, Type, Var, - Required, Desc, Values, Options}, + Required, Desc, Values, Options, __Els}, _xmlns_attrs) -> - _els = - lists:reverse('encode_xdata_field_$options'(Options, - 'encode_xdata_field_$values'(Values, - 'encode_xdata_field_$desc'(Desc, - 'encode_xdata_field_$required'(Required, - []))))), + _els = [encode(_el) || _el <- __Els] ++ + lists:reverse('encode_xdata_field_$options'(Options, + 'encode_xdata_field_$values'(Values, + 'encode_xdata_field_$desc'(Desc, + 'encode_xdata_field_$required'(Required, + []))))), _attrs = encode_xdata_field_attr_var(Var, encode_xdata_field_attr_type(Type, encode_xdata_field_attr_label(Label, @@ -18909,29 +19402,31 @@ decode_register(__TopXMLNS, __IgnoreEls, {xmlel, <<"query">>, _attrs, _els}) -> {Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email} = + Username, Remove, Key, City, Nick, Url, Email, __Els} = decode_register_els(__TopXMLNS, __IgnoreEls, _els, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, false, undefined, undefined, undefined, undefined, undefined, false, undefined, undefined, - undefined, undefined, undefined), + undefined, undefined, undefined, []), {register, Registered, Remove, Instructions, Username, Nick, Password, Name, First, Last, Email, Address, City, - State, Zip, Phone, Url, Date, Misc, Text, Key, Xdata}. + State, Zip, Phone, Url, Date, Misc, Text, Key, Xdata, + __Els}. decode_register_els(__TopXMLNS, __IgnoreEls, [], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email) -> + Username, Remove, Key, City, Nick, Url, Email, __Els) -> {Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email}; + Username, Remove, Key, City, Nick, Url, Email, + lists:reverse(__Els)}; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"x">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email) -> + Username, Remove, Key, City, Nick, Url, Email, __Els) -> case get_attr(<<"xmlns">>, _attrs) of <<"jabber:x:data">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, @@ -18939,19 +19434,20 @@ decode_register_els(__TopXMLNS, __IgnoreEls, _el), Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email); + Username, Remove, Key, City, Nick, Url, Email, + __Els); _ -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, - Email) + Email, __Els) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"registered">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email) -> + Username, Remove, Key, City, Nick, Url, Email, __Els) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, @@ -18960,7 +19456,7 @@ decode_register_els(__TopXMLNS, __IgnoreEls, decode_register_registered(__TopXMLNS, __IgnoreEls, _el), Date, Phone, State, Name, Username, Remove, Key, - City, Nick, Url, Email); + City, Nick, Url, Email, __Els); <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, @@ -18968,19 +19464,19 @@ decode_register_els(__TopXMLNS, __IgnoreEls, decode_register_registered(<<"jabber:iq:register">>, __IgnoreEls, _el), Date, Phone, State, Name, Username, Remove, Key, - City, Nick, Url, Email); + City, Nick, Url, Email, __Els); _ -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, - Email) + Email, __Els) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"remove">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email) -> + Username, Remove, Key, City, Nick, Url, Email, __Els) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, @@ -18989,7 +19485,7 @@ decode_register_els(__TopXMLNS, __IgnoreEls, Name, Username, decode_register_remove(__TopXMLNS, __IgnoreEls, _el), - Key, City, Nick, Url, Email); + Key, City, Nick, Url, Email, __Els); <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, @@ -18997,19 +19493,19 @@ decode_register_els(__TopXMLNS, __IgnoreEls, Name, Username, decode_register_remove(<<"jabber:iq:register">>, __IgnoreEls, _el), - Key, City, Nick, Url, Email); + Key, City, Nick, Url, Email, __Els); _ -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, - Email) + Email, __Els) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"instructions">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email) -> + Username, Remove, Key, City, Nick, Url, Email, __Els) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, @@ -19018,7 +19514,7 @@ decode_register_els(__TopXMLNS, __IgnoreEls, __IgnoreEls, _el), Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, - Nick, Url, Email); + Nick, Url, Email, __Els); <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, @@ -19026,19 +19522,19 @@ decode_register_els(__TopXMLNS, __IgnoreEls, __IgnoreEls, _el), Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, - Nick, Url, Email); + Nick, Url, Email, __Els); _ -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, - Email) + Email, __Els) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"username">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email) -> + Username, Remove, Key, City, Nick, Url, Email, __Els) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, @@ -19047,7 +19543,7 @@ decode_register_els(__TopXMLNS, __IgnoreEls, Name, decode_register_username(__TopXMLNS, __IgnoreEls, _el), - Remove, Key, City, Nick, Url, Email); + Remove, Key, City, Nick, Url, Email, __Els); <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, @@ -19055,19 +19551,19 @@ decode_register_els(__TopXMLNS, __IgnoreEls, Name, decode_register_username(<<"jabber:iq:register">>, __IgnoreEls, _el), - Remove, Key, City, Nick, Url, Email); + Remove, Key, City, Nick, Url, Email, __Els); _ -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, - Email) + Email, __Els) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"nick">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email) -> + Username, Remove, Key, City, Nick, Url, Email, __Els) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, @@ -19076,7 +19572,7 @@ decode_register_els(__TopXMLNS, __IgnoreEls, Name, Username, Remove, Key, City, decode_register_nick(__TopXMLNS, __IgnoreEls, _el), - Url, Email); + Url, Email, __Els); <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, @@ -19084,19 +19580,19 @@ decode_register_els(__TopXMLNS, __IgnoreEls, Name, Username, Remove, Key, City, decode_register_nick(<<"jabber:iq:register">>, __IgnoreEls, _el), - Url, Email); + Url, Email, __Els); _ -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, - Email) + Email, __Els) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"password">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email) -> + Username, Remove, Key, City, Nick, Url, Email, __Els) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, @@ -19105,7 +19601,7 @@ decode_register_els(__TopXMLNS, __IgnoreEls, decode_register_password(__TopXMLNS, __IgnoreEls, _el), Registered, Date, Phone, State, Name, Username, - Remove, Key, City, Nick, Url, Email); + Remove, Key, City, Nick, Url, Email, __Els); <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, @@ -19113,19 +19609,19 @@ decode_register_els(__TopXMLNS, __IgnoreEls, decode_register_password(<<"jabber:iq:register">>, __IgnoreEls, _el), Registered, Date, Phone, State, Name, Username, - Remove, Key, City, Nick, Url, Email); + Remove, Key, City, Nick, Url, Email, __Els); _ -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, - Email) + Email, __Els) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"name">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email) -> + Username, Remove, Key, City, Nick, Url, Email, __Els) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, @@ -19133,26 +19629,28 @@ decode_register_els(__TopXMLNS, __IgnoreEls, First, Password, Registered, Date, Phone, State, decode_register_name(__TopXMLNS, __IgnoreEls, _el), - Username, Remove, Key, City, Nick, Url, Email); + Username, Remove, Key, City, Nick, Url, Email, + __Els); <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, decode_register_name(<<"jabber:iq:register">>, __IgnoreEls, _el), - Username, Remove, Key, City, Nick, Url, Email); + Username, Remove, Key, City, Nick, Url, Email, + __Els); _ -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, - Email) + Email, __Els) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"first">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email) -> + Username, Remove, Key, City, Nick, Url, Email, __Els) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, @@ -19160,26 +19658,28 @@ decode_register_els(__TopXMLNS, __IgnoreEls, decode_register_first(__TopXMLNS, __IgnoreEls, _el), Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email); + Username, Remove, Key, City, Nick, Url, Email, + __Els); <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, decode_register_first(<<"jabber:iq:register">>, __IgnoreEls, _el), Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email); + Username, Remove, Key, City, Nick, Url, Email, + __Els); _ -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, - Email) + Email, __Els) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"last">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email) -> + Username, Remove, Key, City, Nick, Url, Email, __Els) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, @@ -19188,7 +19688,7 @@ decode_register_els(__TopXMLNS, __IgnoreEls, _el), First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, - Email); + Email, __Els); <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, @@ -19196,19 +19696,19 @@ decode_register_els(__TopXMLNS, __IgnoreEls, __IgnoreEls, _el), First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, - Email); + Email, __Els); _ -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, - Email) + Email, __Els) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"email">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email) -> + Username, Remove, Key, City, Nick, Url, Email, __Els) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, @@ -19216,26 +19716,28 @@ decode_register_els(__TopXMLNS, __IgnoreEls, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, decode_register_email(__TopXMLNS, __IgnoreEls, - _el)); + _el), + __Els); <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, decode_register_email(<<"jabber:iq:register">>, - __IgnoreEls, _el)); + __IgnoreEls, _el), + __Els); _ -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, - Email) + Email, __Els) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"address">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email) -> + Username, Remove, Key, City, Nick, Url, Email, __Els) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, @@ -19244,7 +19746,7 @@ decode_register_els(__TopXMLNS, __IgnoreEls, _el), Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, - Remove, Key, City, Nick, Url, Email); + Remove, Key, City, Nick, Url, Email, __Els); <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, @@ -19252,19 +19754,19 @@ decode_register_els(__TopXMLNS, __IgnoreEls, __IgnoreEls, _el), Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, - Remove, Key, City, Nick, Url, Email); + Remove, Key, City, Nick, Url, Email, __Els); _ -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, - Email) + Email, __Els) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"city">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email) -> + Username, Remove, Key, City, Nick, Url, Email, __Els) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, @@ -19273,7 +19775,7 @@ decode_register_els(__TopXMLNS, __IgnoreEls, Name, Username, Remove, Key, decode_register_city(__TopXMLNS, __IgnoreEls, _el), - Nick, Url, Email); + Nick, Url, Email, __Els); <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, @@ -19281,19 +19783,19 @@ decode_register_els(__TopXMLNS, __IgnoreEls, Name, Username, Remove, Key, decode_register_city(<<"jabber:iq:register">>, __IgnoreEls, _el), - Nick, Url, Email); + Nick, Url, Email, __Els); _ -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, - Email) + Email, __Els) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"state">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email) -> + Username, Remove, Key, City, Nick, Url, Email, __Els) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, @@ -19302,7 +19804,7 @@ decode_register_els(__TopXMLNS, __IgnoreEls, decode_register_state(__TopXMLNS, __IgnoreEls, _el), Name, Username, Remove, Key, City, Nick, Url, - Email); + Email, __Els); <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, @@ -19310,19 +19812,19 @@ decode_register_els(__TopXMLNS, __IgnoreEls, decode_register_state(<<"jabber:iq:register">>, __IgnoreEls, _el), Name, Username, Remove, Key, City, Nick, Url, - Email); + Email, __Els); _ -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, - Email) + Email, __Els) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"zip">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email) -> + Username, Remove, Key, City, Nick, Url, Email, __Els) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, @@ -19330,7 +19832,7 @@ decode_register_els(__TopXMLNS, __IgnoreEls, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, - Email); + Email, __Els); <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, decode_register_zip(<<"jabber:iq:register">>, @@ -19338,19 +19840,19 @@ decode_register_els(__TopXMLNS, __IgnoreEls, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, - Email); + Email, __Els); _ -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, - Email) + Email, __Els) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"phone">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email) -> + Username, Remove, Key, City, Nick, Url, Email, __Els) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, @@ -19359,7 +19861,7 @@ decode_register_els(__TopXMLNS, __IgnoreEls, decode_register_phone(__TopXMLNS, __IgnoreEls, _el), State, Name, Username, Remove, Key, City, Nick, - Url, Email); + Url, Email, __Els); <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, @@ -19367,19 +19869,19 @@ decode_register_els(__TopXMLNS, __IgnoreEls, decode_register_phone(<<"jabber:iq:register">>, __IgnoreEls, _el), State, Name, Username, Remove, Key, City, Nick, - Url, Email); + Url, Email, __Els); _ -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, - Email) + Email, __Els) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"url">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email) -> + Username, Remove, Key, City, Nick, Url, Email, __Els) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, @@ -19387,7 +19889,7 @@ decode_register_els(__TopXMLNS, __IgnoreEls, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, decode_register_url(__TopXMLNS, __IgnoreEls, _el), - Email); + Email, __Els); <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, @@ -19395,19 +19897,19 @@ decode_register_els(__TopXMLNS, __IgnoreEls, Name, Username, Remove, Key, City, Nick, decode_register_url(<<"jabber:iq:register">>, __IgnoreEls, _el), - Email); + Email, __Els); _ -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, - Email) + Email, __Els) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"date">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email) -> + Username, Remove, Key, City, Nick, Url, Email, __Els) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, @@ -19416,7 +19918,7 @@ decode_register_els(__TopXMLNS, __IgnoreEls, decode_register_date(__TopXMLNS, __IgnoreEls, _el), Phone, State, Name, Username, Remove, Key, City, - Nick, Url, Email); + Nick, Url, Email, __Els); <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, @@ -19424,19 +19926,19 @@ decode_register_els(__TopXMLNS, __IgnoreEls, decode_register_date(<<"jabber:iq:register">>, __IgnoreEls, _el), Phone, State, Name, Username, Remove, Key, City, - Nick, Url, Email); + Nick, Url, Email, __Els); _ -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, - Email) + Email, __Els) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"misc">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email) -> + Username, Remove, Key, City, Nick, Url, Email, __Els) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, @@ -19445,7 +19947,8 @@ decode_register_els(__TopXMLNS, __IgnoreEls, _el), Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email); + Username, Remove, Key, City, Nick, Url, Email, + __Els); <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, @@ -19453,19 +19956,20 @@ decode_register_els(__TopXMLNS, __IgnoreEls, __IgnoreEls, _el), Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email); + Username, Remove, Key, City, Nick, Url, Email, + __Els); _ -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, - Email) + Email, __Els) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"text">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email) -> + Username, Remove, Key, City, Nick, Url, Email, __Els) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, @@ -19474,7 +19978,7 @@ decode_register_els(__TopXMLNS, __IgnoreEls, _el), Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, - Url, Email); + Url, Email, __Els); <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, @@ -19482,19 +19986,19 @@ decode_register_els(__TopXMLNS, __IgnoreEls, __IgnoreEls, _el), Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, - Url, Email); + Url, Email, __Els); _ -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, - Email) + Email, __Els) end; decode_register_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"key">>, _attrs, _} = _el | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email) -> + Username, Remove, Key, City, Nick, Url, Email, __Els) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, @@ -19502,7 +20006,7 @@ decode_register_els(__TopXMLNS, __IgnoreEls, First, Password, Registered, Date, Phone, State, Name, Username, Remove, decode_register_key(__TopXMLNS, __IgnoreEls, _el), - City, Nick, Url, Email); + City, Nick, Url, Email, __Els); <<"jabber:iq:register">> -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, @@ -19510,50 +20014,79 @@ decode_register_els(__TopXMLNS, __IgnoreEls, Name, Username, Remove, decode_register_key(<<"jabber:iq:register">>, __IgnoreEls, _el), - City, Nick, Url, Email); + City, Nick, Url, Email, __Els); _ -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, - Email) + Email, __Els) + end; +decode_register_els(__TopXMLNS, __IgnoreEls, + [{xmlel, _, _, _} = _el | _els], Zip, Xdata, Misc, + Address, Instructions, Text, Last, First, Password, + Registered, Date, Phone, State, Name, Username, Remove, + Key, City, Nick, Url, Email, __Els) -> + if __IgnoreEls -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, Last, + First, Password, Registered, Date, Phone, State, + Name, Username, Remove, Key, City, Nick, Url, + Email, [_el | __Els]); + true -> + case is_known_tag(_el) of + true -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, + Last, First, Password, Registered, Date, + Phone, State, Name, Username, Remove, Key, + City, Nick, Url, Email, + [decode(_el) | __Els]); + false -> + decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, + Xdata, Misc, Address, Instructions, Text, + Last, First, Password, Registered, Date, + Phone, State, Name, Username, Remove, Key, + City, Nick, Url, Email, __Els) + end end; decode_register_els(__TopXMLNS, __IgnoreEls, [_ | _els], Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email) -> + Username, Remove, Key, City, Nick, Url, Email, __Els) -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email). + Username, Remove, Key, City, Nick, Url, Email, __Els). encode_register({register, Registered, Remove, Instructions, Username, Nick, Password, Name, First, Last, Email, Address, City, State, Zip, Phone, Url, - Date, Misc, Text, Key, Xdata}, + Date, Misc, Text, Key, Xdata, __Els}, _xmlns_attrs) -> - _els = lists:reverse('encode_register_$zip'(Zip, - 'encode_register_$xdata'(Xdata, - 'encode_register_$misc'(Misc, - 'encode_register_$address'(Address, - 'encode_register_$instructions'(Instructions, - 'encode_register_$text'(Text, - 'encode_register_$last'(Last, - 'encode_register_$first'(First, - 'encode_register_$password'(Password, - 'encode_register_$registered'(Registered, - 'encode_register_$date'(Date, - 'encode_register_$phone'(Phone, - 'encode_register_$state'(State, - 'encode_register_$name'(Name, - 'encode_register_$username'(Username, - 'encode_register_$remove'(Remove, - 'encode_register_$key'(Key, - 'encode_register_$city'(City, - 'encode_register_$nick'(Nick, - 'encode_register_$url'(Url, - 'encode_register_$email'(Email, - [])))))))))))))))))))))), + _els = [encode(_el) || _el <- __Els] ++ + lists:reverse('encode_register_$zip'(Zip, + 'encode_register_$xdata'(Xdata, + 'encode_register_$misc'(Misc, + 'encode_register_$address'(Address, + 'encode_register_$instructions'(Instructions, + 'encode_register_$text'(Text, + 'encode_register_$last'(Last, + 'encode_register_$first'(First, + 'encode_register_$password'(Password, + 'encode_register_$registered'(Registered, + 'encode_register_$date'(Date, + 'encode_register_$phone'(Phone, + 'encode_register_$state'(State, + 'encode_register_$name'(Name, + 'encode_register_$username'(Username, + 'encode_register_$remove'(Remove, + 'encode_register_$key'(Key, + 'encode_register_$city'(City, + 'encode_register_$nick'(Nick, + 'encode_register_$url'(Url, + 'encode_register_$email'(Email, + [])))))))))))))))))))))), _attrs = _xmlns_attrs, {xmlel, <<"query">>, _attrs, _els}. diff --git a/tools/xmpp_codec.spec b/tools/xmpp_codec.spec index 7503eab10..f72e250f2 100644 --- a/tools/xmpp_codec.spec +++ b/tools/xmpp_codec.spec @@ -1010,7 +1010,7 @@ '$username', '$nick', '$password', '$name', '$first', '$last', '$email', '$address', '$city', '$state', '$zip', '$phone', '$url', - '$date', '$misc', '$text', '$key', '$xdata'}, + '$date', '$misc', '$text', '$key', '$xdata', '$_els'}, refs = [#ref{name = xdata, min = 0, max = 1, label = '$xdata'}, #ref{name = register_registered, min = 0, max = 1, @@ -1600,7 +1600,7 @@ #elem{name = <<"field">>, xmlns = <<"jabber:x:data">>, result = {xdata_field, '$label', '$type', '$var', - '$required', '$desc', '$values', '$options'}, + '$required', '$desc', '$values', '$options', '$_els'}, attrs = [#attr{name = <<"label">>}, #attr{name = <<"type">>, enc = {enc_enum, []}, @@ -2937,6 +2937,66 @@ #attr{name = <<"version">>, default = <<"">>}, #attr{name = <<"id">>, default = <<"">>}]}). +-xml(bob_data, + #elem{name = <<"data">>, + xmlns = <<"urn:xmpp:bob">>, + result = {bob_data, '$cid', '$max-age', '$type', '$data'}, + attrs = [#attr{name = <<"cid">>, required = true}, + #attr{name = <<"max-age">>, + dec = {dec_int, [0, infinity]}, + enc = {enc_int, []}}, + #attr{name = <<"type">>}], + cdata = #cdata{label = '$data', default = <<"">>, + dec = {base64, decode, []}, + enc = {base64, encode, []}}}). + +-xml(captcha, + #elem{name = <<"captcha">>, + xmlns = <<"urn:xmpp:captcha">>, + result = {xcaptcha, '$xdata'}, + refs = [#ref{name = xdata, min = 1, max = 1}]}). + +-xml(media_uri, + #elem{name = <<"uri">>, + xmlns = <<"urn:xmpp:media-element">>, + result = {media_uri, '$type', '$uri'}, + attrs = [#attr{name = <<"type">>, required = true}], + cdata = #cdata{label = '$uri', default = <<"">>}}). + +-xml(media, + #elem{name = <<"media">>, + xmlns = <<"urn:xmpp:media-element">>, + result = {media, '$height', '$width', '$uri'}, + attrs = [#attr{name = <<"height">>, + dec = {dec_int, [0, infinity]}, + enc = {enc_int, []}}, + #attr{name = <<"width">>, + dec = {dec_int, [0, inifinity]}, + enc = {enc_int, []}}], + refs = [#ref{name = media_uri, label = '$uri'}]}). + +-xml(oob_url, + #elem{name = <<"url">>, + xmlns = <<"jabber:x:oob">>, + result = '$cdata', + cdata = #cdata{required = true}}). + +-xml(oob_desc, + #elem{name = <<"desc">>, + xmlns = <<"jabber:x:oob">>, + result = '$cdata', + cdata = #cdata{default = <<"">>}}). + +-xml(oob_x, + #elem{name = <<"x">>, + xmlns = <<"jabber:x:oob">>, + result = {oob_x, '$url', '$desc', '$sid'}, + attrs = [#attr{name = <<"sid">>, default = <<"">>}], + refs = [#ref{name = oob_url, min = 1, max = 1, + label = '$url'}, + #ref{name = oob_desc, default = <<"">>, + min = 0, max = 1, label = '$desc'}]}). + dec_tzo(Val) -> [H1, M1] = str:tokens(Val, <<":">>), H = jlib:binary_to_integer(H1), From f91f2bc3d28f7f23ba4084827046bd183f06cf08 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Fri, 29 Jul 2016 13:21:00 +0300 Subject: [PATCH 014/151] Rewrite several modules to use XML generator --- src/ejabberd_xmlrpc.erl | 2 +- src/mod_admin_extra.erl | 196 ++++++++------------ src/mod_http_api.erl | 2 +- src/mod_http_fileserver.erl | 3 - src/mod_metrics.erl | 2 +- src/mod_pres_counter.erl | 41 ++--- src/mod_private.erl | 2 +- src/mod_proxy65_service.erl | 347 ++++++++++++++++-------------------- src/mod_proxy65_sm.erl | 4 +- src/mod_service_log.erl | 21 +-- src/mod_vcard.erl | 4 +- 11 files changed, 252 insertions(+), 372 deletions(-) diff --git a/src/ejabberd_xmlrpc.erl b/src/ejabberd_xmlrpc.erl index 6680451e4..6259b4efd 100644 --- a/src/ejabberd_xmlrpc.erl +++ b/src/ejabberd_xmlrpc.erl @@ -42,7 +42,7 @@ -include("ejabberd_http.hrl"). -include("mod_roster.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -record(state, {access_commands = [] :: list(), diff --git a/src/mod_admin_extra.erl b/src/mod_admin_extra.erl index 8f6724281..a147a5881 100644 --- a/src/mod_admin_extra.erl +++ b/src/mod_admin_extra.erl @@ -54,7 +54,7 @@ -include("ejabberd_commands.hrl"). -include("mod_roster.hrl"). -include("ejabberd_sm.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). %%% %%% gen_mod @@ -879,20 +879,22 @@ set_presence(User, Host, Resource, Type, Show, Status, Priority) when is_integer(Priority) -> BPriority = integer_to_binary(Priority), set_presence(User, Host, Resource, Type, Show, Status, BPriority); -set_presence(User, Host, Resource, Type, Show, Status, Priority) -> +set_presence(User, Host, Resource, Type, Show, Status, Priority0) -> + Priority = if is_integer(Priority0) -> Priority0; + true -> binary_to_integer(Priority0) + end, case ejabberd_sm:get_session_pid(User, Host, Resource) of none -> error; Pid -> - USR = jid:to_string(jid:make(User, Host, Resource)), - US = jid:to_string(jid:make(User, Host, <<>>)), - Message = {route_xmlstreamelement, - {xmlel, <<"presence">>, - [{<<"from">>, USR}, {<<"to">>, US}, {<<"type">>, Type}], - [{xmlel, <<"show">>, [], [{xmlcdata, Show}]}, - {xmlel, <<"status">>, [], [{xmlcdata, Status}]}, - {xmlel, <<"priority">>, [], [{xmlcdata, Priority}]}]}}, - Pid ! Message, + From = jid:make(User, Host, Resource), + To = jid:make(User, Host), + Presence = #presence{from = From, to = To, + type = jlib:binary_to_atom(Type), + show = jlib:binary_to_atom(Show), + status = xmpp:mk_text(Status), + priority = Priority}, + Pid ! {route, From, To, Presence}, ok end. @@ -930,20 +932,12 @@ user_sessions_info(User, Host) -> %%% set_nickname(User, Host, Nickname) -> - R = mod_vcard:process_sm_iq( - {jid, User, Host, <<>>, User, Host, <<>>}, - {jid, User, Host, <<>>, User, Host, <<>>}, - {iq, <<>>, set, <<>>, <<"en">>, - {xmlel, <<"vCard">>, [ - {<<"xmlns">>, <<"vcard-temp">>}], [ - {xmlel, <<"NICKNAME">>, [], [{xmlcdata, Nickname}]} - ] - }}), - case R of - {iq, <<>>, result, <<>>, _L, []} -> - ok; - _ -> - error + VCard = xmpp:encode(#vcard_temp{nickname = Nickname}), + case mod_vcard:set_vcard(User, jid:nameprep(Host), VCard) of + {error, badarg} -> + error; + ok -> + ok end. get_vcard(User, Host, Name) -> @@ -967,26 +961,17 @@ set_vcard(User, Host, Name, Subname, SomeContent) -> %% %% Internal vcard -get_module_resource(Server) -> - case gen_mod:get_module_opt(Server, ?MODULE, module_resource, fun(A) -> A end, none) of - none -> list_to_binary(atom_to_list(?MODULE)); - R when is_binary(R) -> R - end. - get_vcard_content(User, Server, Data) -> - [{_, Module, Function, _Opts}] = ets:lookup(sm_iqtable, {?NS_VCARD, Server}), - JID = jid:make(User, Server, get_module_resource(Server)), - IQ = #iq{type = get, xmlns = ?NS_VCARD}, - IQr = Module:Function(JID, JID, IQ), - [A1] = IQr#iq.sub_el, - case A1#xmlel.children of - [_|_] -> - case get_vcard(Data, A1) of + case mod_vcard:get_vcard(jid:nodeprep(User), jid:nameprep(Server)) of + [_|_] = Els -> + case get_vcard(Data, Els) of [false] -> throw(error_no_value_found_in_vcard); ElemList -> ?DEBUG("ELS ~p", [ElemList]), [fxml:get_tag_cdata(Elem) || Elem <- ElemList] end; [] -> - throw(error_no_vcard_found) + throw(error_no_vcard_found); + error -> + throw(database_failure) end. get_vcard([<<"TEL">>, TelType], {_, _, _, OldEls}) -> @@ -1011,25 +996,19 @@ set_vcard_content(User, Server, Data, SomeContent) -> [Bin | _] when is_binary(Bin) -> SomeContent; Bin when is_binary(Bin) -> [SomeContent] end, - [{_, Module, Function, _Opts}] = ets:lookup(sm_iqtable, {?NS_VCARD, Server}), - JID = jid:make(User, Server, get_module_resource(Server)), - IQ = #iq{type = get, xmlns = ?NS_VCARD}, - IQr = Module:Function(JID, JID, IQ), - %% Get old vcard - A4 = case IQr#iq.sub_el of + A4 = case mod_vcard:get_vcard(jid:nodeprep(User), jid:nameprep(Server)) of [A1] -> {_, _, _, A2} = A1, update_vcard_els(Data, ContentList, A2); [] -> - update_vcard_els(Data, ContentList, []) + update_vcard_els(Data, ContentList, []); + error -> + throw(database_failure) end, - %% Build new vcard SubEl = {xmlel, <<"vCard">>, [{<<"xmlns">>,<<"vcard-temp">>}], A4}, - IQ2 = #iq{type=set, sub_el = SubEl}, - - Module:Function(JID, JID, IQ2), + mod_vcard:set_vcard(User, jid:nameprep(Server), SubEl), ok. take_vcard_tel(TelType, [{xmlel, <<"TEL">>, _, SubEls}=OldEl | OldEls], NewEls, Taken) -> @@ -1090,11 +1069,7 @@ add_rosteritem(LU, LS, User, Server, Nick, Group, Subscription, Xattrs) -> subscribe(LU, LS, User, Server, Nick, Group, Subscription, _Xattrs) -> ItemEl = build_roster_item(User, Server, {add, Nick, Subscription, Group}), - mod_roster:set_items( - LU, LS, - {xmlel, <<"query">>, - [{<<"xmlns">>, ?NS_ROSTER}], - [ItemEl]}). + mod_roster:set_items(LU, LS, #roster_query{items = [ItemEl]}). delete_rosteritem(LocalUser, LocalServer, User, Server) -> case unsubscribe(LocalUser, LocalServer, User, Server) of @@ -1107,11 +1082,7 @@ delete_rosteritem(LocalUser, LocalServer, User, Server) -> unsubscribe(LU, LS, User, Server) -> ItemEl = build_roster_item(User, Server, remove), - mod_roster:set_items( - LU, LS, - {xmlel, <<"query">>, - [{<<"xmlns">>, ?NS_ROSTER}], - [ItemEl]}). + mod_roster:set_items(LU, LS, #roster_query{items = [ItemEl]}). %% ----------------------------- %% Get Roster @@ -1201,28 +1172,16 @@ push_roster_item(LU, LS, R, U, S, Action) -> ejabberd_router:route(jid:remove_resource(LJID), LJID, ResIQ). build_roster_item(U, S, {add, Nick, Subs, Group}) -> - {xmlel, <<"item">>, - [{<<"jid">>, jid:to_string(jid:make(U, S, <<>>))}, - {<<"name">>, Nick}, - {<<"subscription">>, Subs}], - [{xmlel, <<"group">>, [], [{xmlcdata, Group}]}] - }; + #roster_item{jid = jid:make(U, S), + name = Nick, + subscription = jlib:binary_to_atom(Subs), + groups = [Group]}; build_roster_item(U, S, remove) -> - {xmlel, <<"item">>, - [{<<"jid">>, jid:to_string(jid:make(U, S, <<>>))}, - {<<"subscription">>, <<"remove">>}], - [] - }. + #roster_item{jid = jid:make(U, S), subscription = remove}. build_iq_roster_push(Item) -> - {xmlel, <<"iq">>, - [{<<"type">>, <<"set">>}, {<<"id">>, <<"push">>}], - [{xmlel, <<"query">>, - [{<<"xmlns">>, ?NS_ROSTER}], - [Item] - } - ] - }. + #iq{type = set, id = <<"push">>, + sub_els = [#roster_query{items = [Item]}]}. build_broadcast(U, S, {add, _Nick, Subs, _Group}) -> build_broadcast(U, S, list_to_atom(binary_to_list(Subs))); @@ -1268,17 +1227,9 @@ get_last(User, Server) -> %% Cluth private_get(Username, Host, Element, Ns) -> - From = jid:make(Username, Host, <<>>), - To = jid:make(Username, Host, <<>>), - IQ = {iq, <<>>, get, ?NS_PRIVATE, <<>>, - {xmlel, <<"query">>, - [{<<"xmlns">>,?NS_PRIVATE}], - [{xmlel, Element, [{<<"xmlns">>, Ns}], []}]}}, - ResIq = mod_private:process_sm_iq(From, To, IQ), - [{xmlel, <<"query">>, - [{<<"xmlns">>, ?NS_PRIVATE}], - [SubEl]}] = ResIq#iq.sub_el, - binary_to_list(fxml:element_to_binary(SubEl)). + Els = mod_private:get_data(jid:nodeprep(Username), jid:nameprep(Host), + [Ns, Element]), + binary_to_list(fxml:element_to_binary(xmpp:encode(#private{xml_els = Els}))). private_set(Username, Host, ElementString) -> case fxml_stream:parse_element(ElementString) of @@ -1291,13 +1242,9 @@ private_set(Username, Host, ElementString) -> end. private_set2(Username, Host, Xml) -> - From = jid:make(Username, Host, <<>>), - To = jid:make(Username, Host, <<>>), - IQ = {iq, <<>>, set, ?NS_PRIVATE, <<>>, - {xmlel, <<"query">>, - [{<<"xmlns">>, ?NS_PRIVATE}], - [Xml]}}, - mod_private:process_sm_iq(From, To, IQ), + NS = fxml:get_tag_attr_s(<<"xmlns">>, Xml), + mod_private:set_data(jid:nodeprep(Username), jid:nameprep(Host), + [{NS, Xml}]), ok. %%% @@ -1395,23 +1342,25 @@ send_packet_all_resources(FromJID, ToU, ToS, ToR, Packet) -> ejabberd_router:route(FromJID, ToJID, Packet). build_packet(Type, Subject, Body) -> - Tail = if Subject == <<"">>; Type == <<"chat">> -> []; - true -> [{xmlel, <<"subject">>, [], [{xmlcdata, Subject}]}] - end, - {xmlel, <<"message">>, - [{<<"type">>, Type}, {<<"id">>, randoms:get_string()}], - [{xmlel, <<"body">>, [], [{xmlcdata, Body}]} | Tail] - }. + #message{type = jlib:binary_to_atom(Type), + body = xmpp:mk_text(Body), + subject = xmpp:mk_text(Subject)}. send_stanza(FromString, ToString, Stanza) -> - case fxml_stream:parse_element(Stanza) of - {error, Error} -> - {error, Error}; - XmlEl -> - #xmlel{attrs = Attrs} = XmlEl, - From = jid:from_string(proplists:get_value(<<"from">>, Attrs, FromString)), - To = jid:from_string(proplists:get_value(<<"to">>, Attrs, ToString)), - ejabberd_router:route(From, To, XmlEl) + try + #xmlel{} = El = fxml_stream:parse_element(Stanza), + #jid{} = From = jid:from_string(FromString), + #jid{} = To = jid:to_string(ToString), + Pkt = xmpp:decode(El, [ignore_els]), + ejabberd_router:route(From, To, Pkt) + catch _:{xmpp_codec, Why} -> + io:format("incorrect stanza: ~s~n", [xmpp:format_error(Why)]), + {error, Why}; + _:{badmatch, {error, Why}} -> + io:format("invalid xml: ~p~n", [Why]), + {error, Why}; + _:{badmatch, error} -> + {error, "JID malformed"} end. send_stanza_c2s(Username, Host, Resource, Stanza) -> @@ -1427,17 +1376,15 @@ send_stanza_c2s(Username, Host, Resource, Stanza) -> end. privacy_set(Username, Host, QueryS) -> - From = jid:make(Username, Host, <<"">>), - To = jid:make(<<"">>, Host, <<"">>), + From = jid:make(Username, Host), + To = jid:make(Host), QueryEl = fxml_stream:parse_element(QueryS), - StanzaEl = {xmlel, <<"iq">>, [{<<"type">>, <<"set">>}], [QueryEl]}, - IQ = jlib:iq_query_info(StanzaEl), - ejabberd_hooks:run_fold( - privacy_iq_set, - Host, - {error, ?ERR_FEATURE_NOT_IMPLEMENTED}, - [From, To, IQ] - ), + SubEl = xmpp:decode(QueryEl), + IQ = #iq{type = set, id = <<"push">>, sub_els = [SubEl]}, + ejabberd_hooks:run_fold(privacy_iq_set, + Host, + {error, xmpp:err_feature_not_implemented()}, + [From, To, IQ]), ok. %%% @@ -1618,5 +1565,4 @@ is_glob_match(String, <<"!", Glob/binary>>) -> is_glob_match(String, Glob) -> is_regexp_match(String, ejabberd_regexp:sh_to_awk(Glob)). -mod_opt_type(module_resource) -> fun (A) -> A end; -mod_opt_type(_) -> [module_resource]. +mod_opt_type(_) -> []. diff --git a/src/mod_http_api.erl b/src/mod_http_api.erl index 815ed3ab6..f3a69aa80 100644 --- a/src/mod_http_api.erl +++ b/src/mod_http_api.erl @@ -77,7 +77,7 @@ -export([start/2, stop/1, process/2, mod_opt_type/1, depends/2]). -include("ejabberd.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("logger.hrl"). -include("ejabberd_http.hrl"). diff --git a/src/mod_http_fileserver.erl b/src/mod_http_fileserver.erl index 37e02edd8..728a2d137 100644 --- a/src/mod_http_fileserver.erl +++ b/src/mod_http_fileserver.erl @@ -51,9 +51,6 @@ -include("ejabberd.hrl"). -include("logger.hrl"). -include("ejabberd_http.hrl"). - --include("jlib.hrl"). - -include_lib("kernel/include/file.hrl"). -record(state, diff --git a/src/mod_metrics.erl b/src/mod_metrics.erl index f1d487e0e..cb7946a28 100644 --- a/src/mod_metrics.erl +++ b/src/mod_metrics.erl @@ -31,7 +31,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("jid.hrl"). -define(HOOKS, [offline_message_hook, sm_register_connection_hook, sm_remove_connection_hook, diff --git a/src/mod_pres_counter.erl b/src/mod_pres_counter.erl index e6f2cfbab..786ba97f2 100644 --- a/src/mod_pres_counter.erl +++ b/src/mod_pres_counter.erl @@ -33,7 +33,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -record(pres_counter, {dir, start, count, logged = false}). @@ -52,27 +52,24 @@ depends(_Host, _Opts) -> []. check_packet(_, _User, Server, _PrivacyList, - {From, To, #xmlel{name = Name, attrs = Attrs}}, Dir) -> - case Name of - <<"presence">> -> - IsSubscription = case fxml:get_attr_s(<<"type">>, Attrs) - of - <<"subscribe">> -> true; - <<"subscribed">> -> true; - <<"unsubscribe">> -> true; - <<"unsubscribed">> -> true; - _ -> false - end, - if IsSubscription -> - JID = case Dir of - in -> To; - out -> From - end, - update(Server, JID, Dir); - true -> allow - end; - _ -> allow - end. + {From, To, #presence{type = Type}}, Dir) -> + IsSubscription = case Type of + subscribe -> true; + subscribed -> true; + unsubscribe -> true; + unsubscribed -> true; + _ -> false + end, + if IsSubscription -> + JID = case Dir of + in -> To; + out -> From + end, + update(Server, JID, Dir); + true -> allow + end; +check_packet(_, _User, _Server, _PrivacyList, _Pkt, _Dir) -> + allow. update(Server, JID, Dir) -> StormCount = gen_mod:get_module_opt(Server, ?MODULE, count, diff --git a/src/mod_private.erl b/src/mod_private.erl index e6d0fd7cd..6236b1012 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -32,7 +32,7 @@ -behaviour(gen_mod). -export([start/2, stop/1, process_sm_iq/1, import/3, - remove_user/2, get_data/2, export/1, import/1, + remove_user/2, get_data/2, get_data/3, export/1, import/1, mod_opt_type/1, set_data/3, depends/2]). -include("ejabberd.hrl"). diff --git a/src/mod_proxy65_service.erl b/src/mod_proxy65_service.erl index 7db6f9da2..e90ff21bd 100644 --- a/src/mod_proxy65_service.erl +++ b/src/mod_proxy65_service.erl @@ -33,24 +33,17 @@ -export([init/1, handle_info/2, handle_call/3, handle_cast/2, terminate/2, code_change/3]). --export([start_link/2, add_listener/2, +-export([start_link/2, add_listener/2, process_disco_info/1, + process_disco_items/1, process_vcard/1, process_bytestreams/1, transform_module_options/1, delete_listener/1]). -include("ejabberd.hrl"). -include("logger.hrl"). - --include("jlib.hrl"). +-include("xmpp.hrl"). -define(PROCNAME, ejabberd_mod_proxy65_service). --record(state, - {myhost = <<"">> :: binary(), - serverhost = <<"">> :: binary(), - name = <<"">> :: binary(), - stream_addr = [] :: [attr()], - port = 0 :: inet:port_number(), - ip = {127,0,0,1} :: inet:ip_address(), - acl = none :: atom()}). +-record(state, {myhost = <<"">> :: binary()}). %%%------------------------ %%% gen_server callbacks @@ -62,34 +55,32 @@ start_link(Host, Opts) -> [Host, Opts], []). init([Host, Opts]) -> - State = parse_options(Host, Opts), - ejabberd_router:register_route(State#state.myhost, Host), - {ok, State}. + IQDisc = gen_mod:get_opt(iqdisc, Opts, fun gen_iq_handler:check_type/1, + one_queue), + MyHost = gen_mod:get_opt_host(Host, Opts, <<"proxy.@HOST@">>), + gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_INFO, + ?MODULE, process_disco_info, IQDisc), + gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_ITEMS, + ?MODULE, process_disco_items, IQDisc), + gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_VCARD, + ?MODULE, process_vcard, IQDisc), + gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_BYTESTREAMS, + ?MODULE, process_bytestreams, IQDisc), + ejabberd_router:register_route(MyHost, Host), + {ok, #state{myhost = MyHost}}. terminate(_Reason, #state{myhost = MyHost}) -> - ejabberd_router:unregister_route(MyHost), ok. + ejabberd_router:unregister_route(MyHost), + gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_INFO), + gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_ITEMS), + gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_VCARD), + gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_BYTESTREAMS). -handle_info({route, From, To, - #xmlel{name = <<"iq">>} = Packet}, - State) -> - IQ = jlib:iq_query_info(Packet), - case catch process_iq(From, IQ, State) of - Result when is_record(Result, iq) -> - ejabberd_router:route(To, From, jlib:iq_to_xml(Result)); - {'EXIT', Reason} -> - ?ERROR_MSG("Error when processing IQ stanza: ~p", - [Reason]), - Err = jlib:make_error_reply(Packet, - ?ERR_INTERNAL_SERVER_ERROR), - ejabberd_router:route(To, From, Err); - _ -> ok - end, +handle_info({route, From, To, #iq{} = Packet}, State) -> + ejabberd_router:process_iq(From, To, Packet), {noreply, State}; handle_info(_Info, State) -> {noreply, State}. -handle_call(get_port_ip, _From, State) -> - {reply, {port_ip, State#state.port, State#state.ip}, - State}; handle_call(_Request, _From, State) -> {reply, ok, State}. @@ -102,185 +93,122 @@ code_change(_OldVsn, State, _Extra) -> {ok, State}. %%%------------------------ add_listener(Host, Opts) -> - State = parse_options(Host, Opts), NewOpts = [Host | Opts], - ejabberd_listener:add_listener({State#state.port, - State#state.ip}, + ejabberd_listener:add_listener(get_port_ip(Host), mod_proxy65_stream, NewOpts). delete_listener(Host) -> - Proc = gen_mod:get_module_proc(Host, ?PROCNAME), - {port_ip, Port, IP} = gen_server:call(Proc, - get_port_ip), - catch ejabberd_listener:delete_listener({Port, IP}, + catch ejabberd_listener:delete_listener(get_port_ip(Host), mod_proxy65_stream). %%%------------------------ %%% IQ Processing %%%------------------------ +-spec process_disco_info(iq()) -> iq(). +process_disco_info(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_disco_info(#iq{type = get, to = To, lang = Lang} = IQ) -> + Host = ejabberd_router:host_of_route(To#jid.lserver), + Name = gen_mod:get_module_opt(Host, mod_proxy65, name, + fun iolist_to_binary/1, + <<"SOCKS5 Bytestreams">>), + Info = ejabberd_hooks:run_fold(disco_info, Host, + [], [Host, ?MODULE, <<"">>, <<"">>]), + xmpp:make_iq_result( + IQ, #disco_info{xdata = Info, + identities = [#identity{category = <<"proxy">>, + type = <<"bytestreams">>, + name = translate:translate(Lang, Name)}], + features = [?NS_DISCO_INFO, ?NS_DISCO_ITEMS, + ?NS_VCARD, ?NS_BYTESTREAMS]}). -%% disco#info request -process_iq(_, - #iq{type = get, xmlns = ?NS_DISCO_INFO, lang = Lang} = - IQ, - #state{name = Name, serverhost = ServerHost}) -> - Info = ejabberd_hooks:run_fold(disco_info, ServerHost, - [], [ServerHost, ?MODULE, <<"">>, <<"">>]), - IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_DISCO_INFO}], - children = iq_disco_info(Lang, Name) ++ Info}]}; -%% disco#items request -process_iq(_, - #iq{type = get, xmlns = ?NS_DISCO_ITEMS} = IQ, _) -> - IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_DISCO_ITEMS}], - children = []}]}; -%% vCard request -process_iq(_, - #iq{type = get, xmlns = ?NS_VCARD, lang = Lang} = IQ, - _) -> - IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"vCard">>, - attrs = [{<<"xmlns">>, ?NS_VCARD}], - children = iq_vcard(Lang)}]}; -%% bytestreams info request -process_iq(JID, - #iq{type = get, sub_el = SubEl, lang = Lang, - xmlns = ?NS_BYTESTREAMS} = - IQ, - #state{acl = ACL, stream_addr = StreamAddr, - serverhost = ServerHost}) -> +-spec process_disco_items(iq()) -> iq(). +process_disco_items(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_disco_items(#iq{type = get} = IQ) -> + xmpp:make_iq_result(IQ, #disco_items{}). + +-spec process_vcard(iq()) -> iq(). +process_vcard(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_vcard(#iq{type = get, lang = Lang} = IQ) -> + Desc = translate:translate(Lang, <<"ejabberd SOCKS5 Bytestreams module">>), + Copyright = <<"Copyright (c) 2003-2016 ProcessOne">>, + xmpp:make_iq_result( + IQ, #vcard_temp{fn = <<"ejabberd/mod_proxy65">>, + url = ?EJABBERD_URI, + desc = <>}). + +-spec process_bytestreams(iq()) -> iq(). +process_bytestreams(#iq{type = get, from = JID, to = To, lang = Lang} = IQ) -> + Host = To#jid.lserver, + ServerHost = ejabberd_router:host_of_route(Host), + ACL = gen_mod:get_module_opt(ServerHost, mod_proxy65, access, + fun acl:access_rules_validator/1, + all), case acl:match_rule(ServerHost, ACL, JID) of - allow -> - StreamHostEl = [#xmlel{name = <<"streamhost">>, - attrs = StreamAddr, children = []}], - IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_BYTESTREAMS}], - children = StreamHostEl}]}; - deny -> - Txt = <<"Denied by ACL">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_FORBIDDEN(Lang, Txt)]} + allow -> + StreamHost = get_streamhost(Host, ServerHost), + xmpp:make_iq_result(IQ, #bytestreams{hosts = [StreamHost]}); + deny -> + xmpp:make_error(IQ, xmpp:err_forbidden(<<"Denied by ACL">>, Lang)) end; -%% bytestream activation request -process_iq(InitiatorJID, - #iq{type = set, sub_el = SubEl, lang = Lang, - xmlns = ?NS_BYTESTREAMS} = - IQ, - #state{acl = ACL, serverhost = ServerHost}) -> +process_bytestreams(#iq{type = set, lang = Lang, + sub_els = [#bytestreams{sid = undefined}]} = IQ) -> + Why = {missing_attr, <<"sid">>, <<"query">>, ?NS_BYTESTREAMS}, + Txt = xmpp:format_error(Why), + xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)); +process_bytestreams(#iq{type = set, lang = Lang, + sub_els = [#bytestreams{sid = SID}]} = IQ) + when SID == <<"">> orelse length(SID) > 128 -> + Why = {bad_attr_value, <<"sid">>, <<"query">>, ?NS_BYTESTREAMS}, + Txt = xmpp:format_error(Why), + xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)); +process_bytestreams(#iq{type = set, lang = Lang, + sub_els = [#bytestreams{activate = undefined}]} = IQ) -> + Why = {missing_cdata, <<"">>, <<"activate">>, ?NS_BYTESTREAMS}, + Txt = xmpp:format_error(Why), + xmpp:make_error(IQ, xmpp:err_jid_malformed(Txt, Lang)); +process_bytestreams(#iq{type = set, lang = Lang, from = InitiatorJID, to = To, + sub_els = [#bytestreams{activate = TargetJID, + sid = SID}]} = IQ) -> + ServerHost = ejabberd_router:host_of_route(To#jid.lserver), + ACL = gen_mod:get_module_opt(ServerHost, mod_proxy65, access, + fun acl:access_rules_validator/1, + all), case acl:match_rule(ServerHost, ACL, InitiatorJID) of - allow -> - ActivateEl = fxml:get_path_s(SubEl, - [{elem, <<"activate">>}]), - SID = fxml:get_tag_attr_s(<<"sid">>, SubEl), - case catch - jid:from_string(fxml:get_tag_cdata(ActivateEl)) - of - TargetJID - when is_record(TargetJID, jid), SID /= <<"">>, - byte_size(SID) =< 128, TargetJID /= InitiatorJID -> - Target = - jid:to_string(jid:tolower(TargetJID)), - Initiator = - jid:to_string(jid:tolower(InitiatorJID)), - SHA1 = p1_sha:sha(<>), - case mod_proxy65_sm:activate_stream(SHA1, InitiatorJID, - TargetJID, ServerHost) - of - ok -> IQ#iq{type = result, sub_el = []}; - false -> - Txt = <<"Failed to activate bytestream">>, - IQ#iq{type = error, - sub_el = [SubEl, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)]}; - limit -> - Txt = <<"Too many active bytestreams">>, - IQ#iq{type = error, - sub_el = [SubEl, ?ERRT_RESOURCE_CONSTRAINT(Lang, Txt)]}; - conflict -> - Txt = <<"Bytestream already activated">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_CONFLICT(Lang, Txt)]}; - _ -> - IQ#iq{type = error, - sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]} - end; - _ -> - Txt = <<"Malformed JID">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_BAD_REQUEST(Lang, Txt)]} - end; - deny -> - Txt = <<"Denied by ACL">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_FORBIDDEN(Lang, Txt)]} - end; -%% Unknown "set" or "get" request -process_iq(_, #iq{type = Type, sub_el = SubEl} = IQ, _) - when Type == get; Type == set -> - IQ#iq{type = error, - sub_el = [SubEl, ?ERR_SERVICE_UNAVAILABLE]}; -%% IQ "result" or "error". -process_iq(_, _, _) -> ok. - + allow -> + Target = jid:to_string(jid:tolower(TargetJID)), + Initiator = jid:to_string(jid:tolower(InitiatorJID)), + SHA1 = p1_sha:sha(<>), + case mod_proxy65_sm:activate_stream(SHA1, InitiatorJID, + TargetJID, ServerHost) of + ok -> + xmpp:make_iq_result(IQ); + false -> + Txt = <<"Failed to activate bytestream">>, + xmpp:make_error(IQ, xmpp:err_item_not_found(Txt, Lang)); + limit -> + Txt = <<"Too many active bytestreams">>, + xmpp:make_error(IQ, xmpp:err_resource_constraint(Txt, Lang)); + conflict -> + Txt = <<"Bytestream already activated">>, + xmpp:make_error(IQ, xmpp:err_conflict(Txt, Lang)); + Err -> + ?ERROR_MSG("failed to activate bytestream from ~s to ~s: ~p", + [Initiator, Target, Err]), + xmpp:make_error(IQ, xmpp:err_internal_server_error()) + end; + deny -> + Txt = <<"Denied by ACL">>, + xmpp:make_error(IQ, xmpp:err_forbidden(Txt, Lang)) + end. %%%------------------------- %%% Auxiliary functions. %%%------------------------- --define(FEATURE(Feat), - #xmlel{name = <<"feature">>, - attrs = [{<<"var">>, Feat}], children = []}). - -iq_disco_info(Lang, Name) -> - [#xmlel{name = <<"identity">>, - attrs = - [{<<"category">>, <<"proxy">>}, - {<<"type">>, <<"bytestreams">>}, - {<<"name">>, translate:translate(Lang, Name)}], - children = []}, - ?FEATURE((?NS_DISCO_INFO)), ?FEATURE((?NS_VCARD)), - ?FEATURE((?NS_BYTESTREAMS))]. - -iq_vcard(Lang) -> - [#xmlel{name = <<"FN">>, attrs = [], - children = [{xmlcdata, <<"ejabberd/mod_proxy65">>}]}, - #xmlel{name = <<"URL">>, attrs = [], - children = [{xmlcdata, ?EJABBERD_URI}]}, - #xmlel{name = <<"DESC">>, attrs = [], - children = - [{xmlcdata, - <<(translate:translate(Lang, - <<"ejabberd SOCKS5 Bytestreams module">>))/binary, - "\nCopyright (c) 2003-2016 ProcessOne">>}]}]. - -parse_options(ServerHost, Opts) -> - MyHost = gen_mod:get_opt_host(ServerHost, Opts, - <<"proxy.@HOST@">>), - Port = gen_mod:get_opt(port, Opts, - fun(P) when is_integer(P), P>0, P<65536 -> P end, - 7777), - ACL = gen_mod:get_opt(access, Opts, fun acl:access_rules_validator/1, - all), - Name = gen_mod:get_opt(name, Opts, fun iolist_to_binary/1, - <<"SOCKS5 Bytestreams">>), - IP = gen_mod:get_opt(ip, Opts, - fun(S) -> - {ok, Addr} = inet_parse:address( - binary_to_list( - iolist_to_binary(S))), - Addr - end, get_my_ip()), - HostName = gen_mod:get_opt(hostname, Opts, - fun iolist_to_binary/1, - jlib:ip_to_list(IP)), - StreamAddr = [{<<"jid">>, MyHost}, - {<<"host">>, HostName}, - {<<"port">>, jlib:integer_to_binary(Port)}], - #state{myhost = MyHost, serverhost = ServerHost, - name = Name, port = Port, ip = IP, - stream_addr = StreamAddr, acl = ACL}. - transform_module_options(Opts) -> lists:map( fun({ip, IP}) when is_tuple(IP) -> @@ -291,6 +219,33 @@ transform_module_options(Opts) -> Opt end, Opts). +-spec get_streamhost(binary(), binary()) -> streamhost(). +get_streamhost(Host, ServerHost) -> + {Port, IP} = get_port_ip(ServerHost), + HostName = gen_mod:get_module_opt(ServerHost, mod_proxy65, hostname, + fun iolist_to_binary/1, + jlib:ip_to_list(IP)), + #streamhost{jid = jid:make(Host), + host = HostName, + port = Port}. + +-spec get_port_ip(binary()) -> {pos_integer(), inet:ip_address()}. +get_port_ip(Host) -> + Port = gen_mod:get_module_opt(Host, mod_proxy65, port, + fun(P) when is_integer(P), P>0, P<65536 -> + P + end, + 7777), + IP = gen_mod:get_module_opt(Host, mod_proxy65, ip, + fun(S) -> + {ok, Addr} = inet_parse:address( + binary_to_list( + iolist_to_binary(S))), + Addr + end, get_my_ip()), + {Port, IP}. + +-spec get_my_ip() -> inet:ip_address(). get_my_ip() -> {ok, MyHostName} = inet:gethostname(), case inet:getaddr(MyHostName, inet) of diff --git a/src/mod_proxy65_sm.erl b/src/mod_proxy65_sm.erl index d86b06c4b..7ef4d390e 100644 --- a/src/mod_proxy65_sm.erl +++ b/src/mod_proxy65_sm.erl @@ -38,14 +38,12 @@ -record(state, {max_connections = infinity :: non_neg_integer() | infinity}). --include("jlib.hrl"). - -record(bytestream, {sha1 = <<"">> :: binary() | '$1', target :: pid() | '_', initiator :: pid() | '_', active = false :: boolean() | '_', - jid_i = {<<"">>, <<"">>, <<"">>} :: ljid() | '_'}). + jid_i = {<<"">>, <<"">>, <<"">>} :: jid:ljid() | '_'}). -define(PROCNAME, ejabberd_mod_proxy65_sm). diff --git a/src/mod_service_log.erl b/src/mod_service_log.erl index ae264bbc9..8f11b0ead 100644 --- a/src/mod_service_log.erl +++ b/src/mod_service_log.erl @@ -62,9 +62,7 @@ log_user_receive(Packet, _C2SState, _JID, From, To) -> log_packet(From, To, Packet, To#jid.lserver), Packet. -log_packet(From, To, - #xmlel{name = Name, attrs = Attrs, children = Els}, - Host) -> +log_packet(From, To, Packet, Host) -> Loggers = gen_mod:get_module_opt(Host, ?MODULE, loggers, fun(L) -> lists:map( @@ -76,22 +74,11 @@ log_packet(From, To, end end, L) end, []), - ServerJID = #jid{user = <<"">>, server = Host, - resource = <<"">>, luser = <<"">>, lserver = Host, - lresource = <<"">>}, - NewAttrs = - jlib:replace_from_to_attrs(jid:to_string(From), - jid:to_string(To), Attrs), - FixedPacket = #xmlel{name = Name, attrs = NewAttrs, - children = Els}, + ServerJID = jid:make(Host), + FixedPacket = xmpp:set_from_to(Packet, From, To), lists:foreach(fun (Logger) -> ejabberd_router:route(ServerJID, - #jid{user = <<"">>, - server = Logger, - resource = <<"">>, - luser = <<"">>, - lserver = Logger, - lresource = <<"">>}, + jid:make(Logger), #xmlel{name = <<"route">>, attrs = [], children = diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index f738648d6..b75b6575b 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -35,7 +35,7 @@ -export([start/2, init/3, stop/1, get_sm_features/5, process_local_iq/1, process_sm_iq/1, string2lower/1, remove_user/2, export/1, import/1, import/3, depends/2, - process_search/1, process_vcard/1, + process_search/1, process_vcard/1, get_vcard/2, disco_items/5, disco_features/5, disco_identity/5, mod_opt_type/1, set_vcard/3, make_vcard_search/4]). @@ -336,7 +336,7 @@ make_vcard_search(User, LUser, LServer, VCARD) -> orgunit = OrgUnit, lorgunit = LOrgUnit}. --spec set_vcard(binary(), binary(), xmlel()) -> any(). +-spec set_vcard(binary(), binary(), xmlel()) -> {error, badarg} | ok. set_vcard(User, LServer, VCARD) -> case jid:nodeprep(User) of error -> From 9bf1bac7df54f5be9cdca9a5d7a36160c40e25dd Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Fri, 29 Jul 2016 17:39:13 +0300 Subject: [PATCH 015/151] Rewrite mod_vcard_ldap to use XML generator --- src/ejabberd_config.erl | 1 + src/gen_mod.erl | 24 +- src/mod_vcard.erl | 80 ++--- src/mod_vcard_ldap.erl | 736 ++++++++++----------------------------- src/mod_vcard_mnesia.erl | 55 ++- src/mod_vcard_riak.erl | 11 +- src/mod_vcard_sql.erl | 52 ++- 7 files changed, 335 insertions(+), 624 deletions(-) diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index 87a918704..5a39df043 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -1010,6 +1010,7 @@ replace_module(mod_private_odbc) -> {mod_private, sql}; replace_module(mod_roster_odbc) -> {mod_roster, sql}; replace_module(mod_shared_roster_odbc) -> {mod_shared_roster, sql}; replace_module(mod_vcard_odbc) -> {mod_vcard, sql}; +replace_module(mod_vcard_ldap) -> {mod_vcard, ldap}; replace_module(mod_vcard_xupdate_odbc) -> {mod_vcard_xupdate, sql}; replace_module(mod_pubsub_odbc) -> {mod_pubsub, sql}; replace_module(Module) -> diff --git a/src/gen_mod.erl b/src/gen_mod.erl index c4306577c..e5b504897 100644 --- a/src/gen_mod.erl +++ b/src/gen_mod.erl @@ -48,7 +48,7 @@ opts = [] :: opts() | '_' | '$2'}). -type opts() :: [{atom(), any()}]. --type db_type() :: sql | mnesia | riak. +-type db_type() :: sql | mnesia | riak | ldap. -callback start(binary(), opts()) -> any(). -callback stop(binary()) -> any(). @@ -147,7 +147,7 @@ start_module(Host, Module) -> -spec start_module(binary(), atom(), opts()) -> any(). start_module(Host, Module, Opts0) -> - Opts = validate_opts(Module, Opts0), + Opts = validate_opts(Host, Module, Opts0), ets:insert(ejabberd_modules, #ejabberd_module{module_host = {Module, Host}, opts = Opts}), @@ -308,10 +308,10 @@ get_opt_host(Host, Opts, Default) -> Val = get_opt(host, Opts, fun iolist_to_binary/1, Default), ejabberd_regexp:greplace(Val, <<"@HOST@">>, Host). -validate_opts(Module, Opts) -> +validate_opts(Host, Module, Opts) -> lists:filtermap( fun({Opt, Val}) -> - case catch Module:mod_opt_type(Opt) of + case catch validate_opt(Host, Module, Opt, Opts) of VFun when is_function(VFun) -> try VFun(Val) of _ -> @@ -346,6 +346,22 @@ validate_opts(Module, Opts) -> false end, Opts). +validate_opt(Host, Module, Opt, Opts) -> + case Module:mod_opt_type(Opt) of + VFun1 when is_function(VFun1) -> + VFun1; + L1 when is_list(L1) -> + DBModule = db_mod(Host, Opts, Module), + try DBModule:mod_opt_type(Opt) of + VFun2 when is_function(VFun2) -> + VFun2; + L2 when is_list(L2) -> + lists:usort(L1 ++ L2) + catch _:undef -> + L1 + end + end. + -spec db_type(binary() | global, module()) -> db_type(); (opts(), module()) -> db_type(). diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index b75b6575b..231c42dc0 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -49,12 +49,15 @@ -define(PROCNAME, ejabberd_mod_vcard). -callback init(binary(), gen_mod:opts()) -> any(). +-callback stop(binary()) -> any(). -callback import(binary(), #vcard{} | #vcard_search{}) -> ok | pass. -callback get_vcard(binary(), binary()) -> [xmlel()] | error. -callback set_vcard(binary(), binary(), xmlel(), #vcard_search{}) -> {atomic, any()}. +-callback search_fields(binary()) -> [{binary(), binary()}]. +-callback search_reported(binary()) -> [{binary(), binary()}]. -callback search(binary(), [{binary(), [binary()]}], boolean(), - infinity | pos_integer()) -> [binary()]. + infinity | pos_integer()) -> [{binary(), binary()}]. -callback remove_user(binary(), binary()) -> {atomic, any()}. start(Host, Opts) -> @@ -134,6 +137,8 @@ stop(Host) -> ?NS_VCARD), ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 50), + Mod = gen_mod:db_type(Host, ?MODULE), + Mod:stop(Host), Proc = gen_mod:get_module_proc(Host, ?PROCNAME), Proc ! stop, {wait, Proc}. @@ -214,7 +219,8 @@ process_vcard(#iq{type = get, lang = Lang} = IQ) -> -spec process_search(iq()) -> iq(). process_search(#iq{type = get, to = To, lang = Lang} = IQ) -> - xmpp:make_iq_result(IQ, mk_search_form(To, Lang)); + ServerHost = ejabberd_router:host_of_route(To#jid.lserver), + xmpp:make_iq_result(IQ, mk_search_form(To, ServerHost, Lang)); process_search(#iq{type = set, to = To, lang = Lang, sub_els = [#search{xdata = #xdata{type = submit, fields = Fs}}]} = IQ) -> @@ -366,22 +372,13 @@ mk_tfield(Label, Var, Lang) -> mk_field(Var, Val) -> #xdata_field{var = Var, values = [Val]}. --spec mk_search_form(jid(), undefined | binary()) -> search(). -mk_search_form(JID, Lang) -> +-spec mk_search_form(jid(), binary(), undefined | binary()) -> search(). +mk_search_form(JID, ServerHost, Lang) -> Title = <<(translate:translate(Lang, <<"Search users in ">>))/binary, (jid:to_string(JID))/binary>>, - Fs = [mk_tfield(<<"User">>, <<"user">>, Lang), - mk_tfield(<<"Full Name">>, <<"fn">>, Lang), - mk_tfield(<<"Name">>, <<"first">>, Lang), - mk_tfield(<<"Middle Name">>, <<"middle">>, Lang), - mk_tfield(<<"Family Name">>, <<"last">>, Lang), - mk_tfield(<<"Nickname">>, <<"nick">>, Lang), - mk_tfield(<<"Birthday">>, <<"bday">>, Lang), - mk_tfield(<<"Country">>, <<"ctry">>, Lang), - mk_tfield(<<"City">>, <<"locality">>, Lang), - mk_tfield(<<"Email">>, <<"email">>, Lang), - mk_tfield(<<"Organization Name">>, <<"orgname">>, Lang), - mk_tfield(<<"Organization Unit">>, <<"orgunit">>, Lang)], + Mod = gen_mod:db_mod(ServerHost, ?MODULE), + SearchFields = Mod:search_fields(ServerHost), + Fs = [mk_tfield(Label, Var, Lang) || {Label, Var} <- SearchFields], X = #xdata{type = form, title = Title, instructions = @@ -398,55 +395,20 @@ mk_search_form(JID, Lang) -> -spec search_result(undefined | binary(), jid(), binary(), [xdata_field()]) -> xdata(). search_result(Lang, JID, ServerHost, XFields) -> + Mod = gen_mod:db_mod(ServerHost, ?MODULE), + Reported = [mk_tfield(Label, Var, Lang) || + {Label, Var} <- Mod:search_reported(ServerHost)], #xdata{type = result, title = <<(translate:translate(Lang, <<"Search Results for ">>))/binary, (jid:to_string(JID))/binary>>, - reported = [mk_tfield(<<"Jabber ID">>, <<"jid">>, Lang), - mk_tfield(<<"Full Name">>, <<"fn">>, Lang), - mk_tfield(<<"Name">>, <<"first">>, Lang), - mk_tfield(<<"Middle Name">>, <<"middle">>, Lang), - mk_tfield(<<"Family Name">>, <<"last">>, Lang), - mk_tfield(<<"Nickname">>, <<"nick">>, Lang), - mk_tfield(<<"Birthday">>, <<"bday">>, Lang), - mk_tfield(<<"Country">>, <<"ctry">>, Lang), - mk_tfield(<<"City">>, <<"locality">>, Lang), - mk_tfield(<<"Email">>, <<"email">>, Lang), - mk_tfield(<<"Organization Name">>, <<"orgname">>, Lang), - mk_tfield(<<"Organization Unit">>, <<"orgunit">>, Lang)], - items = lists:map(fun (R) -> record_to_item(ServerHost, R) end, + reported = Reported, + items = lists:map(fun (Item) -> item_to_field(Item) end, search(ServerHost, XFields))}. --spec record_to_item(binary(), [binary()] | #vcard_search{}) -> [xdata_field()]. -record_to_item(LServer, - [Username, FN, Family, Given, Middle, Nickname, BDay, - CTRY, Locality, EMail, OrgName, OrgUnit]) -> - [mk_field(<<"jid">>, <>), - mk_field(<<"fn">>, FN), - mk_field(<<"last">>, Family), - mk_field(<<"first">>, Given), - mk_field(<<"middle">>, Middle), - mk_field(<<"nick">>, Nickname), - mk_field(<<"bday">>, BDay), - mk_field(<<"ctry">>, CTRY), - mk_field(<<"locality">>, Locality), - mk_field(<<"email">>, EMail), - mk_field(<<"orgname">>, OrgName), - mk_field(<<"orgunit">>, OrgUnit)]; -record_to_item(_LServer, #vcard_search{} = R) -> - {User, Server} = R#vcard_search.user, - [mk_field(<<"jid">>, <>), - mk_field(<<"fn">>, (R#vcard_search.fn)), - mk_field(<<"last">>, (R#vcard_search.family)), - mk_field(<<"first">>, (R#vcard_search.given)), - mk_field(<<"middle">>, (R#vcard_search.middle)), - mk_field(<<"nick">>, (R#vcard_search.nickname)), - mk_field(<<"bday">>, (R#vcard_search.bday)), - mk_field(<<"ctry">>, (R#vcard_search.ctry)), - mk_field(<<"locality">>, (R#vcard_search.locality)), - mk_field(<<"email">>, (R#vcard_search.email)), - mk_field(<<"orgname">>, (R#vcard_search.orgname)), - mk_field(<<"orgunit">>, (R#vcard_search.orgunit))]. +-spec item_to_field([{binary(), binary()}]) -> [xdata_field()]. +item_to_field(Items) -> + [mk_field(Var, Value) || {Var, Value} <- Items]. -spec search(binary(), [xdata_field()]) -> [binary()]. search(LServer, XFields) -> diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl index a0ad305a9..74b20d2ff 100644 --- a/src/mod_vcard_ldap.erl +++ b/src/mod_vcard_ldap.erl @@ -1,53 +1,30 @@ -%%%---------------------------------------------------------------------- -%%% File : mod_vcard_ldap.erl -%%% Author : Alexey Shchepin -%%% Purpose : Support for VCards from LDAP storage. -%%% Created : 2 Jan 2003 by Alexey Shchepin +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc %%% -%%% -%%% ejabberd, Copyright (C) 2002-2016 ProcessOne -%%% -%%% This program is free software; you can redistribute it and/or -%%% modify it under the terms of the GNU General Public License as -%%% published by the Free Software Foundation; either version 2 of the -%%% License, or (at your option) any later version. -%%% -%%% This program is distributed in the hope that it will be useful, -%%% but WITHOUT ANY WARRANTY; without even the implied warranty of -%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -%%% General Public License for more details. -%%% -%%% You should have received a copy of the GNU General Public License along -%%% with this program; if not, write to the Free Software Foundation, Inc., -%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -%%% -%%%---------------------u------------------------------------------------- - +%%% @end +%%% Created : 29 Jul 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- -module(mod_vcard_ldap). --behaviour(ejabberd_config). - --author('alexey@process-one.net'). - -behaviour(gen_server). +-behaviour(mod_vcard). --behaviour(gen_mod). +%% API +-export([start_link/2]). +-export([init/2, stop/1, get_vcard/2, set_vcard/4, search/4, + remove_user/2, import/2, search_fields/1, search_reported/1, + mod_opt_type/1, opt_type/1]). -%% gen_server callbacks. --export([init/1, handle_info/2, handle_call/3, - handle_cast/2, terminate/2, code_change/3]). - --export([start/2, start_link/2, stop/1, - get_sm_features/5, process_local_iq/3, process_sm_iq/3, - remove_user/1, route/4, transform_module_options/1, - mod_opt_type/1, opt_type/1, depends/2]). +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). -include("ejabberd.hrl"). -include("logger.hrl"). - -include("eldap.hrl"). - --include("jlib.hrl"). +-include("xmpp.hrl"). -define(PROCNAME, ejabberd_mod_vcard_ldap). @@ -74,59 +51,14 @@ deref_aliases = never :: never | searching | finding | always, matches = 0 :: non_neg_integer()}). --define(VCARD_MAP, - [{<<"NICKNAME">>, <<"%u">>, []}, - {<<"FN">>, <<"%s">>, [<<"displayName">>]}, - {<<"FAMILY">>, <<"%s">>, [<<"sn">>]}, - {<<"GIVEN">>, <<"%s">>, [<<"givenName">>]}, - {<<"MIDDLE">>, <<"%s">>, [<<"initials">>]}, - {<<"ORGNAME">>, <<"%s">>, [<<"o">>]}, - {<<"ORGUNIT">>, <<"%s">>, [<<"ou">>]}, - {<<"CTRY">>, <<"%s">>, [<<"c">>]}, - {<<"LOCALITY">>, <<"%s">>, [<<"l">>]}, - {<<"STREET">>, <<"%s">>, [<<"street">>]}, - {<<"REGION">>, <<"%s">>, [<<"st">>]}, - {<<"PCODE">>, <<"%s">>, [<<"postalCode">>]}, - {<<"TITLE">>, <<"%s">>, [<<"title">>]}, - {<<"URL">>, <<"%s">>, [<<"labeleduri">>]}, - {<<"DESC">>, <<"%s">>, [<<"description">>]}, - {<<"TEL">>, <<"%s">>, [<<"telephoneNumber">>]}, - {<<"EMAIL">>, <<"%s">>, [<<"mail">>]}, - {<<"BDAY">>, <<"%s">>, [<<"birthDay">>]}, - {<<"ROLE">>, <<"%s">>, [<<"employeeType">>]}, - {<<"PHOTO">>, <<"%s">>, [<<"jpegPhoto">>]}]). +%%%=================================================================== +%%% API +%%%=================================================================== +start_link(Host, Opts) -> + Proc = gen_mod:get_module_proc(Host, ?PROCNAME), + gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []). --define(SEARCH_FIELDS, - [{<<"User">>, <<"%u">>}, - {<<"Full Name">>, <<"displayName">>}, - {<<"Given Name">>, <<"givenName">>}, - {<<"Middle Name">>, <<"initials">>}, - {<<"Family Name">>, <<"sn">>}, - {<<"Nickname">>, <<"%u">>}, - {<<"Birthday">>, <<"birthDay">>}, - {<<"Country">>, <<"c">>}, {<<"City">>, <<"l">>}, - {<<"Email">>, <<"mail">>}, - {<<"Organization Name">>, <<"o">>}, - {<<"Organization Unit">>, <<"ou">>}]). - --define(SEARCH_REPORTED, - [{<<"Full Name">>, <<"FN">>}, - {<<"Given Name">>, <<"FIRST">>}, - {<<"Middle Name">>, <<"MIDDLE">>}, - {<<"Family Name">>, <<"LAST">>}, - {<<"Nickname">>, <<"NICK">>}, - {<<"Birthday">>, <<"BDAY">>}, - {<<"Country">>, <<"CTRY">>}, - {<<"City">>, <<"LOCALITY">>}, - {<<"Email">>, <<"EMAIL">>}, - {<<"Organization Name">>, <<"ORGNAME">>}, - {<<"Organization Unit">>, <<"ORGUNIT">>}]). - -handle_cast(_Request, State) -> {noreply, State}. - -code_change(_OldVsn, State, _Extra) -> {ok, State}. - -start(Host, Opts) -> +init(Host, Opts) -> Proc = gen_mod:get_module_proc(Host, ?PROCNAME), ChildSpec = {Proc, {?MODULE, start_link, [Host, Opts]}, transient, 1000, worker, [?MODULE]}, @@ -138,141 +70,127 @@ stop(Host) -> supervisor:terminate_child(ejabberd_sup, Proc), supervisor:delete_child(ejabberd_sup, Proc). -depends(_Host, _Opts) -> - []. - -terminate(_Reason, State) -> - Host = State#state.serverhost, - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, - ?NS_VCARD), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, - ?NS_VCARD), - ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, - get_sm_features, 50), - case State#state.search of - true -> - ejabberd_router:unregister_route(State#state.myhost); - _ -> ok +get_vcard(LUser, LServer) -> + {ok, State} = eldap_utils:get_state(LServer, ?PROCNAME), + VCardMap = State#state.vcard_map, + case find_ldap_user(LUser, State) of + #eldap_entry{attributes = Attributes} -> + ldap_attributes_to_vcard(Attributes, VCardMap, + {LUser, LServer}); + _ -> + [] end. -start_link(Host, Opts) -> - Proc = gen_mod:get_module_proc(Host, ?PROCNAME), - gen_server:start_link({local, Proc}, ?MODULE, - [Host, Opts], []). +set_vcard(_LUser, _LServer, _VCard, _VCardSearch) -> + {atomic, not_implemented}. +search_fields(LServer) -> + {ok, State} = eldap_utils:get_state(LServer, ?PROCNAME), + State#state.search_fields. + +search_reported(LServer) -> + {ok, State} = eldap_utils:get_state(LServer, ?PROCNAME), + State#state.search_reported. + +search(LServer, Data, _AllowReturnAll, MaxMatch) -> + {ok, State} = eldap_utils:get_state(LServer, ?PROCNAME), + Base = State#state.base, + SearchFilter = State#state.search_filter, + Eldap_ID = State#state.eldap_id, + UIDs = State#state.uids, + ReportedAttrs = State#state.search_reported_attrs, + Filter = eldap:'and'([SearchFilter, + eldap_utils:make_filter(Data, UIDs)]), + case eldap_pool:search(Eldap_ID, + [{base, Base}, {filter, Filter}, {limit, MaxMatch}, + {deref_aliases, State#state.deref_aliases}, + {attributes, ReportedAttrs}]) + of + #eldap_search_result{entries = E} -> + search_items(E, State); + _ -> + [] + end. + +search_items(Entries, State) -> + LServer = State#state.serverhost, + SearchReported = State#state.search_reported, + VCardMap = State#state.vcard_map, + UIDs = State#state.uids, + Attributes = lists:map(fun (E) -> + #eldap_entry{attributes = Attrs} = E, Attrs + end, + Entries), + lists:flatmap( + fun(Attrs) -> + case eldap_utils:find_ldap_attrs(UIDs, Attrs) of + {U, UIDAttrFormat} -> + case eldap_utils:get_user_part(U, UIDAttrFormat) of + {ok, Username} -> + case ejabberd_auth:is_user_exists(Username, + LServer) of + true -> + RFields = lists:map( + fun({_, VCardName}) -> + {VCardName, + map_vcard_attr(VCardName, + Attrs, + VCardMap, + {Username, + ?MYNAME})} + end, + SearchReported), + J = <>, + [{<<"jid">>, J} | RFields]; + _ -> + [] + end; + _ -> + [] + end; + <<"">> -> + [] + end + end, Attributes). + +remove_user(_User, _Server) -> + {atomic, not_implemented}. + +import(_, _) -> + pass. + +%%%=================================================================== +%%% gen_server callbacks +%%%=================================================================== init([Host, Opts]) -> State = parse_options(Host, Opts), - IQDisc = gen_mod:get_opt(iqdisc, Opts, fun gen_iq_handler:check_type/1, - one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, - ?NS_VCARD, ?MODULE, process_local_iq, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, - ?NS_VCARD, ?MODULE, process_sm_iq, IQDisc), - ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, - get_sm_features, 50), eldap_pool:start_link(State#state.eldap_id, State#state.servers, State#state.backups, State#state.port, State#state.dn, State#state.password, State#state.tls_options), - case State#state.search of - true -> - ejabberd_router:register_route(State#state.myhost, Host); - _ -> ok - end, {ok, State}. -handle_info({route, From, To, Packet}, State) -> - case catch do_route(State, From, To, Packet) of - Pid when is_pid(Pid) -> ok; - _ -> - Err = jlib:make_error_reply(Packet, - ?ERR_INTERNAL_SERVER_ERROR), - ejabberd_router:route(To, From, Err) - end, - {noreply, State}; -handle_info(_Info, State) -> {noreply, State}. - -get_sm_features({error, _Error} = Acc, _From, _To, - _Node, _Lang) -> - Acc; -get_sm_features(Acc, _From, _To, Node, _Lang) -> - case Node of - <<"">> -> - case Acc of - {result, Features} -> {result, [?NS_VCARD | Features]}; - empty -> {result, [?NS_VCARD]} - end; - _ -> Acc - end. - -process_local_iq(_From, _To, - #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> - case Type of - set -> - Txt = <<"Value 'set' of 'type' attribute is not allowed">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]}; - get -> - IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"vCard">>, - attrs = [{<<"xmlns">>, ?NS_VCARD}], - children = - [#xmlel{name = <<"FN">>, attrs = [], - children = - [{xmlcdata, <<"ejabberd">>}]}, - #xmlel{name = <<"URL">>, attrs = [], - children = [{xmlcdata, ?EJABBERD_URI}]}, - #xmlel{name = <<"DESC">>, attrs = [], - children = - [{xmlcdata, - <<(translate:translate(Lang, - <<"Erlang Jabber Server">>))/binary, - "\nCopyright (c) 2002-2016 ProcessOne">>}]}, - #xmlel{name = <<"BDAY">>, attrs = [], - children = - [{xmlcdata, <<"2002-11-16">>}]}]}]} - end. - -process_sm_iq(_From, #jid{lserver = LServer} = To, - #iq{sub_el = SubEl} = IQ) -> - case catch process_vcard_ldap(To, IQ, LServer) of - {'EXIT', _} -> - IQ#iq{type = error, - sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]}; - Other -> Other - end. - -process_vcard_ldap(To, IQ, Server) -> - {ok, State} = eldap_utils:get_state(Server, ?PROCNAME), - #iq{type = Type, sub_el = SubEl, lang = Lang} = IQ, - case Type of - set -> - Txt = <<"Value 'set' of 'type' attribute is not allowed">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]}; - get -> - #jid{luser = LUser} = To, - LServer = State#state.serverhost, - case ejabberd_auth:is_user_exists(LUser, LServer) of - true -> - VCardMap = State#state.vcard_map, - case find_ldap_user(LUser, State) of - #eldap_entry{attributes = Attributes} -> - Vcard = ldap_attributes_to_vcard(Attributes, VCardMap, - {LUser, LServer}), - IQ#iq{type = result, sub_el = Vcard}; - _ -> IQ#iq{type = result, sub_el = []} - end; - _ -> IQ#iq{type = result, sub_el = []} - end - end. - handle_call(get_state, _From, State) -> {reply, {ok, State}, State}; -handle_call(stop, _From, State) -> - {stop, normal, ok, State}; handle_call(_Request, _From, State) -> - {reply, bad_request, State}. + Reply = ok, + {reply, Reply, State}. +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== find_ldap_user(User, State) -> Base = State#state.base, RFC2254_Filter = State#state.user_filter, @@ -403,309 +321,6 @@ ldap_attribute_to_vcard(vCardA, {<<"pcode">>, Value}) -> children = [{xmlcdata, Value}]}; ldap_attribute_to_vcard(_, _) -> none. --define(TLFIELD(Type, Label, Var), - #xmlel{name = <<"field">>, - attrs = - [{<<"type">>, Type}, - {<<"label">>, translate:translate(Lang, Label)}, - {<<"var">>, Var}], - children = []}). - --define(FORM(JID, SearchFields), - [#xmlel{name = <<"instructions">>, attrs = [], - children = - [{xmlcdata, - translate:translate(Lang, - <<"You need an x:data capable client to " - "search">>)}]}, - #xmlel{name = <<"x">>, - attrs = - [{<<"xmlns">>, ?NS_XDATA}, {<<"type">>, <<"form">>}], - children = - [#xmlel{name = <<"title">>, attrs = [], - children = - [{xmlcdata, - <<(translate:translate(Lang, - <<"Search users in ">>))/binary, - (jid:to_string(JID))/binary>>}]}, - #xmlel{name = <<"instructions">>, attrs = [], - children = - [{xmlcdata, - translate:translate(Lang, - <<"Fill in fields to search for any matching " - "Jabber User">>)}]}] - ++ - lists:map(fun ({X, Y}) -> - ?TLFIELD(<<"text-single">>, X, Y) - end, - SearchFields)}]). - -do_route(State, From, To, Packet) -> - spawn(?MODULE, route, [State, From, To, Packet]). - -route(State, From, To, Packet) -> - #jid{user = User, resource = Resource} = To, - ServerHost = State#state.serverhost, - if (User /= <<"">>) or (Resource /= <<"">>) -> - Err = jlib:make_error_reply(Packet, - ?ERR_SERVICE_UNAVAILABLE), - ejabberd_router:route(To, From, Err); - true -> - IQ = jlib:iq_query_info(Packet), - case IQ of - #iq{type = Type, xmlns = ?NS_SEARCH, lang = Lang, - sub_el = SubEl} -> - case Type of - set -> - XDataEl = find_xdata_el(SubEl), - case XDataEl of - false -> - Txt = <<"Data form not found">>, - Err = jlib:make_error_reply( - Packet, ?ERRT_BAD_REQUEST(Lang, Txt)), - ejabberd_router:route(To, From, Err); - _ -> - XData = jlib:parse_xdata_submit(XDataEl), - case XData of - invalid -> - Txt = <<"Incorrect data form">>, - Err = jlib:make_error_reply( - Packet, ?ERRT_BAD_REQUEST(Lang, Txt)), - ejabberd_router:route(To, From, Err); - _ -> - ResIQ = IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = - [{<<"xmlns">>, - ?NS_SEARCH}], - children = - [#xmlel{name = - <<"x">>, - attrs = - [{<<"xmlns">>, - ?NS_XDATA}, - {<<"type">>, - <<"result">>}], - children - = - search_result(Lang, - To, - State, - XData)}]}]}, - ejabberd_router:route(To, From, - jlib:iq_to_xml(ResIQ)) - end - end; - get -> - SearchFields = State#state.search_fields, - ResIQ = IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = - [{<<"xmlns">>, - ?NS_SEARCH}], - children = - ?FORM(To, SearchFields)}]}, - ejabberd_router:route(To, From, jlib:iq_to_xml(ResIQ)) - end; - #iq{type = Type, xmlns = ?NS_DISCO_INFO, lang = Lang} -> - case Type of - set -> - Txt = <<"Value 'set' of 'type' attribute is not allowed">>, - Err = jlib:make_error_reply(Packet, ?ERRT_NOT_ALLOWED(Lang, Txt)), - ejabberd_router:route(To, From, Err); - get -> - Info = ejabberd_hooks:run_fold(disco_info, ServerHost, - [], - [ServerHost, ?MODULE, - <<"">>, <<"">>]), - ResIQ = IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = - [{<<"xmlns">>, - ?NS_DISCO_INFO}], - children = - [#xmlel{name = - <<"identity">>, - attrs = - [{<<"category">>, - <<"directory">>}, - {<<"type">>, - <<"user">>}, - {<<"name">>, - translate:translate(Lang, - <<"vCard User Search">>)}], - children = []}, - #xmlel{name = - <<"feature">>, - attrs = - [{<<"var">>, - ?NS_SEARCH}], - children = []}, - #xmlel{name = - <<"feature">>, - attrs = - [{<<"var">>, - ?NS_VCARD}], - children = []}] - ++ Info}]}, - ejabberd_router:route(To, From, jlib:iq_to_xml(ResIQ)) - end; - #iq{type = Type, lang = Lang, xmlns = ?NS_DISCO_ITEMS} -> - case Type of - set -> - Txt = <<"Value 'set' of 'type' attribute is not allowed">>, - Err = jlib:make_error_reply(Packet, ?ERRT_NOT_ALLOWED(Lang, Txt)), - ejabberd_router:route(To, From, Err); - get -> - ResIQ = IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = - [{<<"xmlns">>, - ?NS_DISCO_ITEMS}], - children = []}]}, - ejabberd_router:route(To, From, jlib:iq_to_xml(ResIQ)) - end; - #iq{type = get, xmlns = ?NS_VCARD, lang = Lang} -> - ResIQ = IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"vCard">>, - attrs = [{<<"xmlns">>, ?NS_VCARD}], - children = iq_get_vcard(Lang)}]}, - ejabberd_router:route(To, From, jlib:iq_to_xml(ResIQ)); - _ -> - Err = jlib:make_error_reply(Packet, - ?ERR_SERVICE_UNAVAILABLE), - ejabberd_router:route(To, From, Err) - end - end. - -iq_get_vcard(Lang) -> - [#xmlel{name = <<"FN">>, attrs = [], - children = [{xmlcdata, <<"ejabberd/mod_vcard">>}]}, - #xmlel{name = <<"URL">>, attrs = [], - children = [{xmlcdata, ?EJABBERD_URI}]}, - #xmlel{name = <<"DESC">>, attrs = [], - children = - [{xmlcdata, - <<(translate:translate(Lang, - <<"ejabberd vCard module">>))/binary, - "\nCopyright (c) 2003-2016 ProcessOne">>}]}]. - --define(LFIELD(Label, Var), - #xmlel{name = <<"field">>, - attrs = - [{<<"label">>, translate:translate(Lang, Label)}, - {<<"var">>, Var}], - children = []}). - -search_result(Lang, JID, State, Data) -> - SearchReported = State#state.search_reported, - Header = [#xmlel{name = <<"title">>, attrs = [], - children = - [{xmlcdata, - <<(translate:translate(Lang, - <<"Search Results for ">>))/binary, - (jid:to_string(JID))/binary>>}]}, - #xmlel{name = <<"reported">>, attrs = [], - children = - [?TLFIELD(<<"text-single">>, <<"Jabber ID">>, - <<"jid">>)] - ++ - lists:map(fun ({Name, Value}) -> - ?TLFIELD(<<"text-single">>, Name, - Value) - end, - SearchReported)}], - case search(State, Data) of - error -> Header; - Result -> Header ++ Result - end. - --define(FIELD(Var, Val), - #xmlel{name = <<"field">>, attrs = [{<<"var">>, Var}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = [{xmlcdata, Val}]}]}). - -search(State, Data) -> - Base = State#state.base, - SearchFilter = State#state.search_filter, - Eldap_ID = State#state.eldap_id, - UIDs = State#state.uids, - Limit = State#state.matches, - ReportedAttrs = State#state.search_reported_attrs, - Filter = eldap:'and'([SearchFilter, - eldap_utils:make_filter(Data, UIDs)]), - case eldap_pool:search(Eldap_ID, - [{base, Base}, {filter, Filter}, {limit, Limit}, - {deref_aliases, State#state.deref_aliases}, - {attributes, ReportedAttrs}]) - of - #eldap_search_result{entries = E} -> - search_items(E, State); - _ -> error - end. - -search_items(Entries, State) -> - LServer = State#state.serverhost, - SearchReported = State#state.search_reported, - VCardMap = State#state.vcard_map, - UIDs = State#state.uids, - Attributes = lists:map(fun (E) -> - #eldap_entry{attributes = Attrs} = E, Attrs - end, - Entries), - lists:flatmap(fun (Attrs) -> - case eldap_utils:find_ldap_attrs(UIDs, Attrs) of - {U, UIDAttrFormat} -> - case eldap_utils:get_user_part(U, UIDAttrFormat) - of - {ok, Username} -> - case - ejabberd_auth:is_user_exists(Username, - LServer) - of - true -> - RFields = lists:map(fun ({_, - VCardName}) -> - {VCardName, - map_vcard_attr(VCardName, - Attrs, - VCardMap, - {Username, - ?MYNAME})} - end, - SearchReported), - Result = [?FIELD(<<"jid">>, - <>)] - ++ - [?FIELD(Name, Value) - || {Name, Value} - <- RFields], - [#xmlel{name = <<"item">>, - attrs = [], - children = Result}]; - _ -> [] - end; - _ -> [] - end; - <<"">> -> [] - end - end, - Attributes). - -remove_user(_User) -> true. - -%%%----------------------- -%%% Auxiliary functions. -%%%----------------------- - map_vcard_attr(VCardName, Attributes, Pattern, UD) -> Res = lists:filter(fun ({Name, _, _}) -> eldap_utils:case_insensitive_match(Name, @@ -725,19 +340,54 @@ process_pattern(Str, {User, Domain}, AttrValues) -> [{<<"%u">>, User}, {<<"%d">>, Domain}] ++ [{<<"%s">>, V, 1} || V <- AttrValues]). -find_xdata_el(#xmlel{children = SubEls}) -> - find_xdata_el1(SubEls). +default_vcard_map() -> + [{<<"NICKNAME">>, <<"%u">>, []}, + {<<"FN">>, <<"%s">>, [<<"displayName">>]}, + {<<"FAMILY">>, <<"%s">>, [<<"sn">>]}, + {<<"GIVEN">>, <<"%s">>, [<<"givenName">>]}, + {<<"MIDDLE">>, <<"%s">>, [<<"initials">>]}, + {<<"ORGNAME">>, <<"%s">>, [<<"o">>]}, + {<<"ORGUNIT">>, <<"%s">>, [<<"ou">>]}, + {<<"CTRY">>, <<"%s">>, [<<"c">>]}, + {<<"LOCALITY">>, <<"%s">>, [<<"l">>]}, + {<<"STREET">>, <<"%s">>, [<<"street">>]}, + {<<"REGION">>, <<"%s">>, [<<"st">>]}, + {<<"PCODE">>, <<"%s">>, [<<"postalCode">>]}, + {<<"TITLE">>, <<"%s">>, [<<"title">>]}, + {<<"URL">>, <<"%s">>, [<<"labeleduri">>]}, + {<<"DESC">>, <<"%s">>, [<<"description">>]}, + {<<"TEL">>, <<"%s">>, [<<"telephoneNumber">>]}, + {<<"EMAIL">>, <<"%s">>, [<<"mail">>]}, + {<<"BDAY">>, <<"%s">>, [<<"birthDay">>]}, + {<<"ROLE">>, <<"%s">>, [<<"employeeType">>]}, + {<<"PHOTO">>, <<"%s">>, [<<"jpegPhoto">>]}]. -find_xdata_el1([]) -> false; -find_xdata_el1([#xmlel{name = Name, attrs = Attrs, - children = SubEls} - | Els]) -> - case fxml:get_attr_s(<<"xmlns">>, Attrs) of - ?NS_XDATA -> - #xmlel{name = Name, attrs = Attrs, children = SubEls}; - _ -> find_xdata_el1(Els) - end; -find_xdata_el1([_ | Els]) -> find_xdata_el1(Els). +default_search_fields() -> + [{<<"User">>, <<"%u">>}, + {<<"Full Name">>, <<"displayName">>}, + {<<"Given Name">>, <<"givenName">>}, + {<<"Middle Name">>, <<"initials">>}, + {<<"Family Name">>, <<"sn">>}, + {<<"Nickname">>, <<"%u">>}, + {<<"Birthday">>, <<"birthDay">>}, + {<<"Country">>, <<"c">>}, + {<<"City">>, <<"l">>}, + {<<"Email">>, <<"mail">>}, + {<<"Organization Name">>, <<"o">>}, + {<<"Organization Unit">>, <<"ou">>}]. + +default_search_reported() -> + [{<<"Full Name">>, <<"FN">>}, + {<<"Given Name">>, <<"FIRST">>}, + {<<"Middle Name">>, <<"MIDDLE">>}, + {<<"Family Name">>, <<"LAST">>}, + {<<"Nickname">>, <<"NICK">>}, + {<<"Birthday">>, <<"BDAY">>}, + {<<"Country">>, <<"CTRY">>}, + {<<"City">>, <<"LOCALITY">>}, + {<<"Email">>, <<"EMAIL">>}, + {<<"Organization Name">>, <<"ORGNAME">>}, + {<<"Organization Unit">>, <<"ORGUNIT">>}]. parse_options(Host, Opts) -> MyHost = gen_mod:get_opt_host(Host, Opts, @@ -784,19 +434,19 @@ parse_options(Host, Opts) -> [iolist_to_binary(E) || E <- L]} end, Ls) - end, ?VCARD_MAP), + end, default_vcard_map()), SearchFields = gen_mod:get_opt(ldap_search_fields, Opts, fun(Ls) -> [{iolist_to_binary(S), iolist_to_binary(P)} || {S, P} <- Ls] - end, ?SEARCH_FIELDS), + end, default_search_fields()), SearchReported = gen_mod:get_opt(ldap_search_reported, Opts, fun(Ls) -> [{iolist_to_binary(S), iolist_to_binary(P)} || {S, P} <- Ls] - end, ?SEARCH_REPORTED), + end, default_search_reported()), UIDAttrs = [UAttr || {UAttr, _} <- UIDs], VCardMapAttrs = lists:usort(lists:append([A || {_, _, A} <- VCardMap]) @@ -834,27 +484,11 @@ parse_options(Host, Opts) -> search_reported_attrs = SearchReportedAttrs, matches = Matches}. -transform_module_options(Opts) -> - lists:map( - fun({ldap_vcard_map, Map}) -> - NewMap = lists:map( - fun({Field, Pattern, Attrs}) -> - {Field, [{Pattern, Attrs}]}; - (Opt) -> - Opt - end, Map), - {ldap_vcard_map, NewMap}; - (Opt) -> - Opt - end, Opts). - check_filter(F) -> NewF = iolist_to_binary(F), {ok, _} = eldap_filter:parse(NewF), NewF. -mod_opt_type(host) -> fun iolist_to_binary/1; -mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1; mod_opt_type(ldap_filter) -> fun check_filter/1; mod_opt_type(ldap_search_fields) -> fun (Ls) -> @@ -882,12 +516,6 @@ mod_opt_type(ldap_vcard_map) -> end, Ls) end; -mod_opt_type(matches) -> - fun (infinity) -> 0; - (I) when is_integer(I), I > 0 -> I - end; -mod_opt_type(search) -> - fun (B) when is_boolean(B) -> B end; mod_opt_type(deref_aliases) -> fun (never) -> never; (searching) -> searching; @@ -926,9 +554,9 @@ mod_opt_type(ldap_tls_verify) -> (false) -> false end; mod_opt_type(_) -> - [host, iqdisc, ldap_filter, ldap_search_fields, + [ldap_filter, ldap_search_fields, ldap_search_reported, ldap_uids, ldap_vcard_map, - matches, search, deref_aliases, ldap_backups, ldap_base, + deref_aliases, ldap_backups, ldap_base, ldap_deref_aliases, ldap_encrypt, ldap_password, ldap_port, ldap_rootdn, ldap_servers, ldap_tls_cacertfile, ldap_tls_certfile, ldap_tls_depth, diff --git a/src/mod_vcard_mnesia.erl b/src/mod_vcard_mnesia.erl index 67abed09b..3b64c29ef 100644 --- a/src/mod_vcard_mnesia.erl +++ b/src/mod_vcard_mnesia.erl @@ -11,7 +11,8 @@ -behaviour(mod_vcard). %% API --export([init/2, import/2, get_vcard/2, set_vcard/4, search/4, remove_user/2]). +-export([init/2, stop/1, import/2, get_vcard/2, set_vcard/4, search/4, + search_fields/1, search_reported/1, remove_user/2]). -include("ejabberd.hrl"). -include("xmpp.hrl"). @@ -43,6 +44,9 @@ init(_Host, _Opts) -> mnesia:add_table_index(vcard_search, lorgname), mnesia:add_table_index(vcard_search, lorgunit). +stop(_Host) -> + ok. + get_vcard(LUser, LServer) -> US = {LUser, LServer}, F = fun () -> mnesia:read({vcard, US}) end, @@ -71,15 +75,44 @@ search(LServer, Data, AllowReturnAll, MaxMatch) -> {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]), []; Rs -> + Fields = lists:map(fun record_to_item/1, Rs), case MaxMatch of infinity -> - Rs; + Fields; Val -> - lists:sublist(Rs, Val) + lists:sublist(Fields, Val) end end end. +search_fields(_LServer) -> + [{<<"User">>, <<"user">>}, + {<<"Full Name">>, <<"fn">>}, + {<<"Name">>, <<"first">>}, + {<<"Middle Name">>, <<"middle">>}, + {<<"Family Name">>, <<"last">>}, + {<<"Nickname">>, <<"nick">>}, + {<<"Birthday">>, <<"bday">>}, + {<<"Country">>, <<"ctry">>}, + {<<"City">>, <<"locality">>}, + {<<"Email">>, <<"email">>}, + {<<"Organization Name">>, <<"orgname">>}, + {<<"Organization Unit">>, <<"orgunit">>}]. + +search_reported(_LServer) -> + [{<<"Jabber ID">>, <<"jid">>}, + {<<"Full Name">>, <<"fn">>}, + {<<"Name">>, <<"first">>}, + {<<"Middle Name">>, <<"middle">>}, + {<<"Family Name">>, <<"last">>}, + {<<"Nickname">>, <<"nick">>}, + {<<"Birthday">>, <<"bday">>}, + {<<"Country">>, <<"ctry">>}, + {<<"City">>, <<"locality">>}, + {<<"Email">>, <<"email">>}, + {<<"Organization Name">>, <<"orgname">>}, + {<<"Organization Unit">>, <<"orgunit">>}]. + remove_user(LUser, LServer) -> US = {LUser, LServer}, F = fun () -> @@ -211,3 +244,19 @@ parts_to_string(Parts) -> str:strip(list_to_binary( lists:map(fun (S) -> <> end, Parts)), right, $.). + +-spec record_to_item(#vcard_search{}) -> [{binary(), binary()}]. +record_to_item(R) -> + {User, Server} = R#vcard_search.user, + [{<<"jid">>, <>}, + {<<"fn">>, (R#vcard_search.fn)}, + {<<"last">>, (R#vcard_search.family)}, + {<<"first">>, (R#vcard_search.given)}, + {<<"middle">>, (R#vcard_search.middle)}, + {<<"nick">>, (R#vcard_search.nickname)}, + {<<"bday">>, (R#vcard_search.bday)}, + {<<"ctry">>, (R#vcard_search.ctry)}, + {<<"locality">>, (R#vcard_search.locality)}, + {<<"email">>, (R#vcard_search.email)}, + {<<"orgname">>, (R#vcard_search.orgname)}, + {<<"orgunit">>, (R#vcard_search.orgunit)}]. diff --git a/src/mod_vcard_riak.erl b/src/mod_vcard_riak.erl index 397008a79..23f05f17d 100644 --- a/src/mod_vcard_riak.erl +++ b/src/mod_vcard_riak.erl @@ -12,7 +12,7 @@ %% API -export([init/2, get_vcard/2, set_vcard/4, search/4, remove_user/2, - import/2]). + search_fields/1, search_reported/1, import/2, stop/1]). -include("xmpp.hrl"). -include("mod_vcard.hrl"). @@ -23,6 +23,9 @@ init(_Host, _Opts) -> ok. +stop(_Host) -> + ok. + get_vcard(LUser, LServer) -> case ejabberd_riak:get(vcard, vcard_schema(), {LUser, LServer}) of {ok, R} -> @@ -89,6 +92,12 @@ set_vcard(LUser, LServer, VCARD, search(_LServer, _Data, _AllowReturnAll, _MaxMatch) -> []. +search_fields(_LServer) -> + []. + +search_reported(_LServer) -> + []. + remove_user(LUser, LServer) -> {atomic, ejabberd_riak:delete(vcard, {LUser, LServer})}. diff --git a/src/mod_vcard_sql.erl b/src/mod_vcard_sql.erl index f448d0776..f8ac6be97 100644 --- a/src/mod_vcard_sql.erl +++ b/src/mod_vcard_sql.erl @@ -13,8 +13,8 @@ -behaviour(mod_vcard). %% API --export([init/2, get_vcard/2, set_vcard/4, search/4, remove_user/2, - import/1, import/2, export/1]). +-export([init/2, stop/1, get_vcard/2, set_vcard/4, search/4, remove_user/2, + search_fields/1, search_reported/1, import/1, import/2, export/1]). -include("xmpp.hrl"). -include("mod_vcard.hrl"). @@ -27,6 +27,9 @@ init(_Host, _Opts) -> ok. +stop(_Host) -> + ok. + get_vcard(LUser, LServer) -> case catch sql_queries:get_vcard(LServer, LUser) of {selected, [{SVCARD}]} -> @@ -93,12 +96,40 @@ search(LServer, Data, AllowReturnAll, MaxMatch) -> <<"middle">>, <<"nickname">>, <<"bday">>, <<"ctry">>, <<"locality">>, <<"email">>, <<"orgname">>, <<"orgunit">>], Rs} when is_list(Rs) -> - Rs; + [row_to_item(LServer, R) || R <- Rs]; Error -> ?ERROR_MSG("~p", [Error]), [] end end. +search_fields(_LServer) -> + [{<<"User">>, <<"user">>}, + {<<"Full Name">>, <<"fn">>}, + {<<"Name">>, <<"first">>}, + {<<"Middle Name">>, <<"middle">>}, + {<<"Family Name">>, <<"last">>}, + {<<"Nickname">>, <<"nick">>}, + {<<"Birthday">>, <<"bday">>}, + {<<"Country">>, <<"ctry">>}, + {<<"City">>, <<"locality">>}, + {<<"Email">>, <<"email">>}, + {<<"Organization Name">>, <<"orgname">>}, + {<<"Organization Unit">>, <<"orgunit">>}]. + +search_reported(_LServer) -> + [{<<"Jabber ID">>, <<"jid">>}, + {<<"Full Name">>, <<"fn">>}, + {<<"Name">>, <<"first">>}, + {<<"Middle Name">>, <<"middle">>}, + {<<"Family Name">>, <<"last">>}, + {<<"Nickname">>, <<"nick">>}, + {<<"Birthday">>, <<"bday">>}, + {<<"Country">>, <<"ctry">>}, + {<<"City">>, <<"locality">>}, + {<<"Email">>, <<"email">>}, + {<<"Organization Name">>, <<"orgname">>}, + {<<"Organization Unit">>, <<"orgunit">>}]. + remove_user(LUser, LServer) -> ejabberd_sql:sql_transaction( LServer, @@ -240,3 +271,18 @@ make_val(Match, Field, Val) -> <<"">> -> Condition; _ -> [Match, <<" and ">>, Condition] end. + +row_to_item(LServer, [Username, FN, Family, Given, Middle, Nickname, BDay, + CTRY, Locality, EMail, OrgName, OrgUnit]) -> + [{<<"jid">>, <>}, + {<<"fn">>, FN}, + {<<"last">>, Family}, + {<<"first">>, Given}, + {<<"middle">>, Middle}, + {<<"nick">>, Nickname}, + {<<"bday">>, BDay}, + {<<"ctry">>, CTRY}, + {<<"locality">>, Locality}, + {<<"email">>, EMail}, + {<<"orgname">>, OrgName}, + {<<"orgunit">>, OrgUnit}]. From a093e9d441b95401a99fd36c1ce506148cf6f631 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sat, 30 Jul 2016 08:37:34 +0300 Subject: [PATCH 016/151] Rewrite mod_shared_roster to use XML generator --- src/mod_shared_roster.erl | 130 +++++++++------------------------ src/mod_shared_roster_ldap.erl | 2 +- 2 files changed, 36 insertions(+), 96 deletions(-) diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index b472e1aab..079a2f44c 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -29,7 +29,7 @@ -behaviour(gen_mod). --export([start/2, stop/1, item_to_xml/1, export/1, +-export([start/2, stop/1, export/1, import/1, webadmin_menu/3, webadmin_page/3, get_user_roster/2, get_subscription_lists/3, get_jid_info/4, import/3, process_item/2, @@ -44,7 +44,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_roster.hrl"). @@ -172,53 +172,33 @@ get_user_roster(Items, US) -> end end, SRUsers, Items), - ModVcard = get_vcard_module(S), SRItems = [#roster{usj = {U, S, {U1, S1, <<"">>}}, us = US, jid = {U1, S1, <<"">>}, - name = get_rosteritem_name(ModVcard, U1, S1), + name = get_rosteritem_name(U1, S1), subscription = both, ask = none, groups = GroupNames} || {{U1, S1}, GroupNames} <- dict:to_list(SRUsersRest)], SRItems ++ NewItems1. -get_vcard_module(Server) -> - Modules = gen_mod:loaded_modules(Server), - [M - || M <- Modules, - (M == mod_vcard) or (M == mod_vcard_ldap)]. - -get_rosteritem_name([], _, _) -> <<"">>; -get_rosteritem_name([ModVcard], U, S) -> - From = jid:make(<<"">>, S, jlib:atom_to_binary(?MODULE)), - To = jid:make(U, S, <<"">>), - case lists:member(To#jid.lserver, ?MYHOSTS) of +get_rosteritem_name(U, S) -> + case gen_mod:is_loaded(S, mod_vcard) of true -> - IQ = {iq, <<"">>, get, <<"vcard-temp">>, <<"">>, - #xmlel{name = <<"vCard">>, - attrs = [{<<"xmlns">>, <<"vcard-temp">>}], - children = []}}, - IQ_Vcard = ModVcard:process_sm_iq(From, To, IQ), - case catch get_rosteritem_name_vcard(IQ_Vcard#iq.sub_el) of - {'EXIT', Err} -> - ?ERROR_MSG("Error found when trying to get the " - "vCard of ~s@~s in ~p:~n ~p", - [U, S, ModVcard, Err]), - <<"">>; - NickName -> - NickName - end; + SubEls = mod_vcard:get_vcard(U, S), + get_rosteritem_name_vcard(SubEls); false -> <<"">> end. -get_rosteritem_name_vcard([]) -> <<"">>; -get_rosteritem_name_vcard([Vcard]) -> +-spec get_rosteritem_name_vcard([xmlel()]) -> binary(). +get_rosteritem_name_vcard([Vcard|_]) -> case fxml:get_path_s(Vcard, [{elem, <<"NICKNAME">>}, cdata]) of <<"">> -> fxml:get_path_s(Vcard, [{elem, <<"FN">>}, cdata]); Nickname -> Nickname - end. + end; +get_rosteritem_name_vcard(_) -> + <<"">>. %% This function rewrites the roster entries when moving or renaming %% them in the user contact list. @@ -305,16 +285,12 @@ set_new_rosteritems(UserFrom, ServerFrom, UserTo, RIFrom. set_item(User, Server, Resource, Item) -> - ResIQ = #iq{type = set, xmlns = ?NS_ROSTER, - id = <<"push", (randoms:get_string())/binary>>, - sub_el = - [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_ROSTER}], - children = [mod_roster:item_to_xml(Item)]}]}, - ejabberd_router:route(jid:make(User, Server, - Resource), - jid:make(<<"">>, Server, <<"">>), - jlib:iq_to_xml(ResIQ)). + ResIQ = #iq{type = set, id = <<"push", (randoms:get_string())/binary>>, + sub_els = [#roster_query{ + items = [mod_roster:encode_item(Item)]}]}, + ejabberd_router:route(jid:make(User, Server, Resource), + jid:make(Server), + ResIQ). get_subscription_lists({F, T}, User, Server) -> LUser = jid:nodeprep(User), @@ -574,13 +550,13 @@ add_user_to_group(Host, US, Group) -> {LUser, LServer} = US, case ejabberd_regexp:run(LUser, <<"^@.+@\$">>) of match -> - GroupOpts = (?MODULE):get_group_opts(Host, Group), + GroupOpts = mod_shared_roster:get_group_opts(Host, Group), MoreGroupOpts = case LUser of <<"@all@">> -> [{all_users, true}]; <<"@online@">> -> [{online_users, true}]; _ -> [] end, - (?MODULE):set_group_opts(Host, Group, + mod_shared_roster:set_group_opts(Host, Group, GroupOpts ++ MoreGroupOpts); nomatch -> DisplayedToGroups = displayed_to_groups(Group, Host), @@ -612,7 +588,7 @@ remove_user_from_group(Host, US, Group) -> {LUser, LServer} = US, case ejabberd_regexp:run(LUser, <<"^@.+@\$">>) of match -> - GroupOpts = (?MODULE):get_group_opts(Host, Group), + GroupOpts = mod_shared_roster:get_group_opts(Host, Group), NewGroupOpts = case LUser of <<"@all@">> -> lists:filter(fun (X) -> X /= {all_users, true} @@ -623,7 +599,7 @@ remove_user_from_group(Host, US, Group) -> end, GroupOpts) end, - (?MODULE):set_group_opts(Host, Group, NewGroupOpts); + mod_shared_roster:set_group_opts(Host, Group, NewGroupOpts); nomatch -> Mod = gen_mod:db_mod(Host, ?MODULE), Result = Mod:remove_user_from_group(Host, US, Group), @@ -730,13 +706,9 @@ displayed_to_groups(GroupName, LServer) -> [Name || {Name, _} <- Gs]. push_item(User, Server, Item) -> - Stanza = jlib:iq_to_xml(#iq{type = set, - xmlns = ?NS_ROSTER, - id = <<"push", (randoms:get_string())/binary>>, - sub_el = - [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_ROSTER}], - children = [item_to_xml(Item)]}]}), + Stanza = #iq{type = set, id = <<"push", (randoms:get_string())/binary>>, + sub_els = [#roster_query{ + items = [mod_roster:encode_item(Item)]}]}, lists:foreach(fun (Resource) -> JID = jid:make(User, Server, Resource), ejabberd_router:route(jid:remove_resource(JID), JID, Stanza) @@ -752,38 +724,6 @@ push_roster_item(User, Server, ContactU, ContactS, groups = [GroupName]}, push_item(User, Server, Item). -item_to_xml(Item) -> - Attrs1 = [{<<"jid">>, - jid:to_string(Item#roster.jid)}], - Attrs2 = case Item#roster.name of - <<"">> -> Attrs1; - Name -> [{<<"name">>, Name} | Attrs1] - end, - Attrs3 = case Item#roster.subscription of - none -> [{<<"subscription">>, <<"none">>} | Attrs2]; - from -> [{<<"subscription">>, <<"from">>} | Attrs2]; - to -> [{<<"subscription">>, <<"to">>} | Attrs2]; - both -> [{<<"subscription">>, <<"both">>} | Attrs2]; - remove -> [{<<"subscription">>, <<"remove">>} | Attrs2] - end, - Attrs4 = case ask_to_pending(Item#roster.ask) of - out -> [{<<"ask">>, <<"subscribe">>} | Attrs3]; - both -> [{<<"ask">>, <<"subscribe">>} | Attrs3]; - _ -> Attrs3 - end, - SubEls1 = lists:map(fun (G) -> - #xmlel{name = <<"group">>, attrs = [], - children = [{xmlcdata, G}]} - end, - Item#roster.groups), - SubEls = SubEls1 ++ Item#roster.xs, - #xmlel{name = <<"item">>, attrs = Attrs4, - children = SubEls}. - -ask_to_pending(subscribe) -> out; -ask_to_pending(unsubscribe) -> none; -ask_to_pending(Ask) -> Ask. - user_available(New) -> LUser = New#jid.luser, LServer = New#jid.lserver, @@ -850,7 +790,7 @@ webadmin_page(Acc, _, _) -> Acc. list_shared_roster_groups(Host, Query, Lang) -> Res = list_sr_groups_parse_query(Host, Query), - SRGroups = (?MODULE):list_groups(Host), + SRGroups = mod_shared_roster:list_groups(Host), FGroups = (?XAE(<<"table">>, [], [?XE(<<"tbody">>, (lists:map(fun (Group) -> @@ -901,15 +841,15 @@ list_sr_groups_parse_query(Host, Query) -> list_sr_groups_parse_addnew(Host, Query) -> case lists:keysearch(<<"namenew">>, 1, Query) of {value, {_, Group}} when Group /= <<"">> -> - (?MODULE):create_group(Host, Group), ok; + mod_shared_roster:create_group(Host, Group), ok; _ -> error end. list_sr_groups_parse_delete(Host, Query) -> - SRGroups = (?MODULE):list_groups(Host), + SRGroups = mod_shared_roster:list_groups(Host), lists:foreach(fun (Group) -> case lists:member({<<"selected">>, Group}, Query) of - true -> (?MODULE):delete_group(Host, Group); + true -> mod_shared_roster:delete_group(Host, Group); _ -> ok end end, @@ -919,14 +859,14 @@ list_sr_groups_parse_delete(Host, Query) -> shared_roster_group(Host, Group, Query, Lang) -> Res = shared_roster_group_parse_query(Host, Group, Query), - GroupOpts = (?MODULE):get_group_opts(Host, Group), + GroupOpts = mod_shared_roster:get_group_opts(Host, Group), Name = get_opt(GroupOpts, name, <<"">>), Description = get_opt(GroupOpts, description, <<"">>), AllUsers = get_opt(GroupOpts, all_users, false), OnlineUsers = get_opt(GroupOpts, online_users, false), DisplayedGroups = get_opt(GroupOpts, displayed_groups, []), - Members = (?MODULE):get_group_explicit_users(Host, + Members = mod_shared_roster:get_group_explicit_users(Host, Group), FMembers = iolist_to_binary( [if AllUsers -> <<"@all@\n">>; @@ -1003,7 +943,7 @@ shared_roster_group_parse_query(Host, Group, Query) -> DispGroupsOpt = if DispGroups == [] -> []; true -> [{displayed_groups, DispGroups}] end, - OldMembers = (?MODULE):get_group_explicit_users(Host, + OldMembers = mod_shared_roster:get_group_explicit_users(Host, Group), SJIDs = str:tokens(SMembers, <<", \r\n">>), NewMembers = lists:foldl(fun (_SJID, error) -> error; @@ -1040,7 +980,7 @@ shared_roster_group_parse_query(Host, Group, Query) -> RemovedDisplayedGroups = CurrentDisplayedGroups -- DispGroups, displayed_groups_update(OldMembers, RemovedDisplayedGroups, remove), displayed_groups_update(OldMembers, AddedDisplayedGroups, both), - (?MODULE):set_group_opts(Host, Group, + mod_shared_roster:set_group_opts(Host, Group, NameOpt ++ DispGroupsOpt ++ DescriptionOpt ++ @@ -1050,13 +990,13 @@ shared_roster_group_parse_query(Host, Group, Query) -> AddedMembers = NewMembers -- OldMembers, RemovedMembers = OldMembers -- NewMembers, lists:foreach(fun (US) -> - (?MODULE):remove_user_from_group(Host, + mod_shared_roster:remove_user_from_group(Host, US, Group) end, RemovedMembers), lists:foreach(fun (US) -> - (?MODULE):add_user_to_group(Host, US, + mod_shared_roster:add_user_to_group(Host, US, Group) end, AddedMembers), diff --git a/src/mod_shared_roster_ldap.erl b/src/mod_shared_roster_ldap.erl index 22f50d302..06dd0e3a9 100644 --- a/src/mod_shared_roster_ldap.erl +++ b/src/mod_shared_roster_ldap.erl @@ -45,7 +45,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("mod_roster.hrl"). -include("eldap.hrl"). From f19d2fdcffb3474aeea1050746ac30a778607954 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sat, 30 Jul 2016 08:39:30 +0300 Subject: [PATCH 017/151] Rewrite mod_shared_roster backends module to use XML generator --- src/mod_shared_roster_mnesia.erl | 1 - src/mod_shared_roster_riak.erl | 1 - src/mod_shared_roster_sql.erl | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/mod_shared_roster_mnesia.erl b/src/mod_shared_roster_mnesia.erl index ca2e55e2f..eb7c3c37d 100644 --- a/src/mod_shared_roster_mnesia.erl +++ b/src/mod_shared_roster_mnesia.erl @@ -17,7 +17,6 @@ get_user_displayed_groups/3, is_user_in_group/3, add_user_to_group/3, remove_user_from_group/3, import/2]). --include("jlib.hrl"). -include("mod_roster.hrl"). -include("mod_shared_roster.hrl"). -include("logger.hrl"). diff --git a/src/mod_shared_roster_riak.erl b/src/mod_shared_roster_riak.erl index 0df35e37d..49d6edfcd 100644 --- a/src/mod_shared_roster_riak.erl +++ b/src/mod_shared_roster_riak.erl @@ -17,7 +17,6 @@ get_user_displayed_groups/3, is_user_in_group/3, add_user_to_group/3, remove_user_from_group/3, import/2]). --include("jlib.hrl"). -include("mod_roster.hrl"). -include("mod_shared_roster.hrl"). diff --git a/src/mod_shared_roster_sql.erl b/src/mod_shared_roster_sql.erl index 2b186fd0b..5cffffeb3 100644 --- a/src/mod_shared_roster_sql.erl +++ b/src/mod_shared_roster_sql.erl @@ -20,7 +20,7 @@ add_user_to_group/3, remove_user_from_group/3, import/1, import/2, export/1]). --include("jlib.hrl"). +-include("jid.hrl"). -include("mod_roster.hrl"). -include("mod_shared_roster.hrl"). -include("ejabberd_sql_pt.hrl"). From d2d3b961eb5738c03216ef436a8575da80a5a2e4 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sat, 30 Jul 2016 13:30:29 +0300 Subject: [PATCH 018/151] Rewrite mod_sic to use XML generator --- include/ns.hrl | 2 + include/xmpp_codec.hrl | 10 ++- src/mod_sic.erl | 83 +++++++++---------- src/xmpp_codec.erl | 184 ++++++++++++++++++++++++++++++++++++++++- tools/xmpp_codec.spec | 34 ++++++++ 5 files changed, 263 insertions(+), 50 deletions(-) diff --git a/include/ns.hrl b/include/ns.hrl index b30161565..7955129ef 100644 --- a/include/ns.hrl +++ b/include/ns.hrl @@ -161,6 +161,8 @@ -define(NS_HTTP_UPLOAD_OLD, <<"eu:siacs:conversations:http:upload">>). -define(NS_THUMBS_1, <<"urn:xmpp:thumbs:1">>). -define(NS_NICK, <<"http://jabber.org/protocol/nick">>). +-define(NS_SIC_0, <<"urn:xmpp:sic:0">>). +-define(NS_SIC_1, <<"urn:xmpp:sic:1">>). -define(NS_MIX_0, <<"urn:xmpp:mix:0">>). -define(NS_MIX_SERVICEINFO_0, <<"urn:xmpp:mix:0#serviceinfo">>). -define(NS_MIX_NODES_MESSAGES, <<"urn:xmpp:mix:nodes:messages">>). diff --git a/include/xmpp_codec.hrl b/include/xmpp_codec.hrl index 1ede0ff1d..88c94a76b 100644 --- a/include/xmpp_codec.hrl +++ b/include/xmpp_codec.hrl @@ -343,6 +343,11 @@ items = [] :: [#pubsub_item{}]}). -type pubsub_items() :: #pubsub_items{}. +-record(sic, {ip :: any(), + port :: non_neg_integer(), + xmlns :: binary()}). +-type sic() :: #sic{}. + -record(carbons_sent, {forwarded :: #forwarded{}}). -type carbons_sent() :: #carbons_sent{}. @@ -909,7 +914,6 @@ muc_decline() | legacy_auth() | search() | - unblock() | nick() | p1_ack() | block() | @@ -939,6 +943,7 @@ stream_features() | stats() | pubsub_items() | + sic() | starttls() | mam_prefs() | sasl_mechanisms() | @@ -979,4 +984,5 @@ sasl_auth() | p1_push() | oob_x() | - pubsub_publish(). + pubsub_publish() | + unblock(). diff --git a/src/mod_sic.erl b/src/mod_sic.erl index 49b65a0ee..4bb4eb9eb 100644 --- a/src/mod_sic.erl +++ b/src/mod_sic.erl @@ -31,73 +31,66 @@ -behaviour(gen_mod). --export([start/2, stop/1, process_local_iq/3, - process_sm_iq/3, mod_opt_type/1, depends/2]). +-export([start/2, stop/1, process_local_iq/1, + process_sm_iq/1, mod_opt_type/1, depends/2]). -include("ejabberd.hrl"). -include("logger.hrl"). - --include("jlib.hrl"). - --define(NS_SIC, <<"urn:xmpp:sic:0">>). +-include("xmpp.hrl"). start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, fun gen_iq_handler:check_type/1, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, - ?NS_SIC, ?MODULE, process_local_iq, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, - ?NS_SIC, ?MODULE, process_sm_iq, IQDisc). + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_SIC_0, + ?MODULE, process_local_iq, IQDisc), + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_SIC_0, + ?MODULE, process_sm_iq, IQDisc), + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_SIC_1, + ?MODULE, process_local_iq, IQDisc), + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_SIC_1, + ?MODULE, process_sm_iq, IQDisc). stop(Host) -> - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, - ?NS_SIC), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, - ?NS_SIC). + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_SIC_0), + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_SIC_0), + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_SIC_1), + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_SIC_1). depends(_Host, _Opts) -> []. -process_local_iq(#jid{user = User, server = Server, - resource = Resource}, - _To, #iq{type = get, sub_el = _SubEl} = IQ) -> +process_local_iq(#iq{from = #jid{user = User, server = Server, + resource = Resource}, + type = get} = IQ) -> get_ip({User, Server, Resource}, IQ); -process_local_iq(_From, _To, - #iq{type = set, sub_el = SubEl, lang = Lang} = IQ) -> +process_local_iq(#iq{type = set, lang = Lang} = IQ) -> Txt = <<"Value 'set' of 'type' attribute is not allowed">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]}. + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)). -process_sm_iq(#jid{user = User, server = Server, - resource = Resource}, - #jid{user = User, server = Server}, - #iq{type = get, sub_el = _SubEl} = IQ) -> +process_sm_iq(#iq{from = #jid{user = User, server = Server, + resource = Resource}, + to = #jid{user = User, server = Server}, + type = get} = IQ) -> get_ip({User, Server, Resource}, IQ); -process_sm_iq(_From, _To, - #iq{type = get, sub_el = SubEl, lang = Lang} = IQ) -> +process_sm_iq(#iq{type = get, lang = Lang} = IQ) -> Txt = <<"Query to another users is forbidden">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_FORBIDDEN(Lang, Txt)]}; -process_sm_iq(_From, _To, - #iq{type = set, sub_el = SubEl, lang = Lang} = IQ) -> + xmpp:make_error(IQ, xmpp:err_forbidden(Txt, Lang)); +process_sm_iq(#iq{type = set, lang = Lang} = IQ) -> Txt = <<"Value 'set' of 'type' attribute is not allowed">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]}. + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)). get_ip({User, Server, Resource}, - #iq{lang = Lang, - sub_el = - #xmlel{name = Name, attrs = Attrs} = SubEl} = - IQ) -> + #iq{lang = Lang, sub_els = [#sic{xmlns = NS}]} = IQ) -> case ejabberd_sm:get_user_ip(User, Server, Resource) of - {IP, _} when is_tuple(IP) -> - IQ#iq{type = result, - sub_el = - [#xmlel{name = Name, attrs = Attrs, - children = - [{xmlcdata, - iolist_to_binary(jlib:ip_to_list(IP))}]}]}; - _ -> - Txt = <<"User session not found">>, - IQ#iq{type = error, - sub_el = [SubEl, ?ERRT_INTERNAL_SERVER_ERROR(Lang, Txt)]} + {IP, Port} when is_tuple(IP) -> + Result = case NS of + ?NS_SIC_0 -> #sic{ip = IP, xmlns = NS}; + ?NS_SIC_1 -> #sic{ip = IP, port = Port, xmlns = NS} + end, + xmpp:make_iq_result(IQ, Result); + _ -> + Txt = <<"User session not found">>, + xmpp:make_error(IQ, xmpp:err_item_not_found(Txt, Lang)) end. mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1; diff --git a/src/xmpp_codec.erl b/src/xmpp_codec.erl index 113be860b..11bd741f4 100644 --- a/src/xmpp_codec.erl +++ b/src/xmpp_codec.erl @@ -15,6 +15,16 @@ decode(_el) -> decode(_el, []). decode({xmlel, _name, _attrs, _} = _el, Opts) -> IgnoreEls = proplists:get_bool(ignore_els, Opts), case {_name, get_attr(<<"xmlns">>, _attrs)} of + {<<"address">>, <<"urn:xmpp:sic:0">>} -> + decode_sic(<<"urn:xmpp:sic:0">>, IgnoreEls, _el); + {<<"address">>, <<"urn:xmpp:sic:1">>} -> + decode_sic(<<"urn:xmpp:sic:1">>, IgnoreEls, _el); + {<<"port">>, <<"urn:xmpp:sic:1">>} -> + decode_sip_port(<<"urn:xmpp:sic:1">>, IgnoreEls, _el); + {<<"ip">>, <<"urn:xmpp:sic:0">>} -> + decode_sic_ip(<<"urn:xmpp:sic:0">>, IgnoreEls, _el); + {<<"ip">>, <<"urn:xmpp:sic:1">>} -> + decode_sic_ip(<<"urn:xmpp:sic:1">>, IgnoreEls, _el); {<<"x">>, <<"jabber:x:oob">>} -> decode_oob_x(<<"jabber:x:oob">>, IgnoreEls, _el); {<<"desc">>, <<"jabber:x:oob">>} -> @@ -1309,6 +1319,11 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> is_known_tag({xmlel, _name, _attrs, _} = _el) -> case {_name, get_attr(<<"xmlns">>, _attrs)} of + {<<"address">>, <<"urn:xmpp:sic:0">>} -> true; + {<<"address">>, <<"urn:xmpp:sic:1">>} -> true; + {<<"port">>, <<"urn:xmpp:sic:1">>} -> true; + {<<"ip">>, <<"urn:xmpp:sic:0">>} -> true; + {<<"ip">>, <<"urn:xmpp:sic:1">>} -> true; {<<"x">>, <<"jabber:x:oob">>} -> true; {<<"desc">>, <<"jabber:x:oob">>} -> true; {<<"url">>, <<"jabber:x:oob">>} -> true; @@ -2609,7 +2624,9 @@ encode({media, _, _, _} = Media) -> encode_media(Media, [{<<"xmlns">>, <<"urn:xmpp:media-element">>}]); encode({oob_x, _, _, _} = X) -> - encode_oob_x(X, [{<<"xmlns">>, <<"jabber:x:oob">>}]). + encode_oob_x(X, [{<<"xmlns">>, <<"jabber:x:oob">>}]); +encode({sic, _, _, _} = Address) -> + encode_sic(Address, []). get_name({last, _, _}) -> <<"query">>; get_name({version, _, _, _}) -> <<"query">>; @@ -2802,7 +2819,8 @@ get_name({bob_data, _, _, _, _}) -> <<"data">>; get_name({xcaptcha, _}) -> <<"captcha">>; get_name({media_uri, _, _}) -> <<"uri">>; get_name({media, _, _, _}) -> <<"media">>; -get_name({oob_x, _, _, _}) -> <<"x">>. +get_name({oob_x, _, _, _}) -> <<"x">>; +get_name({sic, _, _, _}) -> <<"address">>. get_ns({last, _, _}) -> <<"jabber:iq:last">>; get_ns({version, _, _, _}) -> <<"jabber:iq:version">>; @@ -3070,7 +3088,8 @@ get_ns({media_uri, _, _}) -> <<"urn:xmpp:media-element">>; get_ns({media, _, _, _}) -> <<"urn:xmpp:media-element">>; -get_ns({oob_x, _, _, _}) -> <<"jabber:x:oob">>. +get_ns({oob_x, _, _, _}) -> <<"jabber:x:oob">>; +get_ns({sic, _, _, Xmlns}) -> Xmlns. dec_int(Val) -> dec_int(Val, infinity, infinity). @@ -3319,8 +3338,18 @@ pp(xcaptcha, 1) -> [xdata]; pp(media_uri, 2) -> [type, uri]; pp(media, 3) -> [height, width, uri]; pp(oob_x, 3) -> [url, desc, sid]; +pp(sic, 3) -> [ip, port, xmlns]; pp(_, _) -> no. +enc_ip({0, 0, 0, 0, 0, 65535, A, B}) -> + enc_ip({(A bsr 8) band 255, A band 255, + (B bsr 8) band 255, B band 255}); +enc_ip(Addr) -> list_to_binary(inet_parse:ntoa(Addr)). + +dec_ip(S) -> + {ok, Addr} = inet_parse:address(binary_to_list(S)), + Addr. + join([], _Sep) -> <<>>; join([H | T], Sep) -> <> || X <- T >>/binary>>. @@ -3365,6 +3394,155 @@ dec_tzo(Val) -> M = jlib:binary_to_integer(M1), if H >= -12, H =< 12, M >= 0, M < 60 -> {H, M} end. +decode_sic(__TopXMLNS, __IgnoreEls, + {xmlel, <<"address">>, _attrs, _els}) -> + {Ip, Port} = decode_sic_els(__TopXMLNS, __IgnoreEls, + _els, undefined, undefined), + Xmlns = decode_sic_attrs(__TopXMLNS, _attrs, undefined), + {sic, Ip, Port, Xmlns}. + +decode_sic_els(__TopXMLNS, __IgnoreEls, [], Ip, Port) -> + {Ip, Port}; +decode_sic_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"ip">>, _attrs, _} = _el | _els], Ip, + Port) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == <<"urn:xmpp:sic:1">>; + __TopXMLNS == <<"urn:xmpp:sic:0">> -> + decode_sic_els(__TopXMLNS, __IgnoreEls, _els, + decode_sic_ip(__TopXMLNS, __IgnoreEls, _el), Port); + <<"urn:xmpp:sic:0">> -> + decode_sic_els(__TopXMLNS, __IgnoreEls, _els, + decode_sic_ip(<<"urn:xmpp:sic:0">>, __IgnoreEls, _el), + Port); + <<"urn:xmpp:sic:1">> -> + decode_sic_els(__TopXMLNS, __IgnoreEls, _els, + decode_sic_ip(<<"urn:xmpp:sic:1">>, __IgnoreEls, _el), + Port); + _ -> + decode_sic_els(__TopXMLNS, __IgnoreEls, _els, Ip, Port) + end; +decode_sic_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"port">>, _attrs, _} = _el | _els], Ip, + Port) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> when __TopXMLNS == <<"urn:xmpp:sic:1">> -> + decode_sic_els(__TopXMLNS, __IgnoreEls, _els, Ip, + decode_sip_port(__TopXMLNS, __IgnoreEls, _el)); + <<"urn:xmpp:sic:1">> -> + decode_sic_els(__TopXMLNS, __IgnoreEls, _els, Ip, + decode_sip_port(<<"urn:xmpp:sic:1">>, __IgnoreEls, + _el)); + _ -> + decode_sic_els(__TopXMLNS, __IgnoreEls, _els, Ip, Port) + end; +decode_sic_els(__TopXMLNS, __IgnoreEls, [_ | _els], Ip, + Port) -> + decode_sic_els(__TopXMLNS, __IgnoreEls, _els, Ip, Port). + +decode_sic_attrs(__TopXMLNS, + [{<<"xmlns">>, _val} | _attrs], _Xmlns) -> + decode_sic_attrs(__TopXMLNS, _attrs, _val); +decode_sic_attrs(__TopXMLNS, [_ | _attrs], Xmlns) -> + decode_sic_attrs(__TopXMLNS, _attrs, Xmlns); +decode_sic_attrs(__TopXMLNS, [], Xmlns) -> + decode_sic_attr_xmlns(__TopXMLNS, Xmlns). + +encode_sic({sic, Ip, Port, Xmlns}, _xmlns_attrs) -> + _els = lists:reverse('encode_sic_$ip'(Ip, + 'encode_sic_$port'(Port, []))), + _attrs = encode_sic_attr_xmlns(Xmlns, _xmlns_attrs), + {xmlel, <<"address">>, _attrs, _els}. + +'encode_sic_$ip'(undefined, _acc) -> _acc; +'encode_sic_$ip'(Ip, _acc) -> + [encode_sic_ip(Ip, []) | _acc]. + +'encode_sic_$port'(undefined, _acc) -> _acc; +'encode_sic_$port'(Port, _acc) -> + [encode_sip_port(Port, []) | _acc]. + +decode_sic_attr_xmlns(__TopXMLNS, undefined) -> + undefined; +decode_sic_attr_xmlns(__TopXMLNS, _val) -> _val. + +encode_sic_attr_xmlns(undefined, _acc) -> _acc; +encode_sic_attr_xmlns(_val, _acc) -> + [{<<"xmlns">>, _val} | _acc]. + +decode_sip_port(__TopXMLNS, __IgnoreEls, + {xmlel, <<"port">>, _attrs, _els}) -> + Cdata = decode_sip_port_els(__TopXMLNS, __IgnoreEls, + _els, <<>>), + Cdata. + +decode_sip_port_els(__TopXMLNS, __IgnoreEls, [], + Cdata) -> + decode_sip_port_cdata(__TopXMLNS, Cdata); +decode_sip_port_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Cdata) -> + decode_sip_port_els(__TopXMLNS, __IgnoreEls, _els, + <>); +decode_sip_port_els(__TopXMLNS, __IgnoreEls, [_ | _els], + Cdata) -> + decode_sip_port_els(__TopXMLNS, __IgnoreEls, _els, + Cdata). + +encode_sip_port(Cdata, _xmlns_attrs) -> + _els = encode_sip_port_cdata(Cdata, []), + _attrs = _xmlns_attrs, + {xmlel, <<"port">>, _attrs, _els}. + +decode_sip_port_cdata(__TopXMLNS, <<>>) -> + erlang:error({xmpp_codec, + {missing_cdata, <<>>, <<"port">>, __TopXMLNS}}); +decode_sip_port_cdata(__TopXMLNS, _val) -> + case catch dec_int(_val, 0, 65535) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_cdata_value, <<>>, <<"port">>, __TopXMLNS}}); + _res -> _res + end. + +encode_sip_port_cdata(_val, _acc) -> + [{xmlcdata, enc_int(_val)} | _acc]. + +decode_sic_ip(__TopXMLNS, __IgnoreEls, + {xmlel, <<"ip">>, _attrs, _els}) -> + Cdata = decode_sic_ip_els(__TopXMLNS, __IgnoreEls, _els, + <<>>), + Cdata. + +decode_sic_ip_els(__TopXMLNS, __IgnoreEls, [], Cdata) -> + decode_sic_ip_cdata(__TopXMLNS, Cdata); +decode_sic_ip_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Cdata) -> + decode_sic_ip_els(__TopXMLNS, __IgnoreEls, _els, + <>); +decode_sic_ip_els(__TopXMLNS, __IgnoreEls, [_ | _els], + Cdata) -> + decode_sic_ip_els(__TopXMLNS, __IgnoreEls, _els, Cdata). + +encode_sic_ip(Cdata, _xmlns_attrs) -> + _els = encode_sic_ip_cdata(Cdata, []), + _attrs = _xmlns_attrs, + {xmlel, <<"ip">>, _attrs, _els}. + +decode_sic_ip_cdata(__TopXMLNS, <<>>) -> + erlang:error({xmpp_codec, + {missing_cdata, <<>>, <<"ip">>, __TopXMLNS}}); +decode_sic_ip_cdata(__TopXMLNS, _val) -> + case catch dec_ip(_val) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_cdata_value, <<>>, <<"ip">>, __TopXMLNS}}); + _res -> _res + end. + +encode_sic_ip_cdata(_val, _acc) -> + [{xmlcdata, enc_ip(_val)} | _acc]. + decode_oob_x(__TopXMLNS, __IgnoreEls, {xmlel, <<"x">>, _attrs, _els}) -> {Desc, Url} = decode_oob_x_els(__TopXMLNS, __IgnoreEls, diff --git a/tools/xmpp_codec.spec b/tools/xmpp_codec.spec index f72e250f2..9cb14282c 100644 --- a/tools/xmpp_codec.spec +++ b/tools/xmpp_codec.spec @@ -2997,6 +2997,30 @@ #ref{name = oob_desc, default = <<"">>, min = 0, max = 1, label = '$desc'}]}). +-xml(sic_ip, + #elem{name = <<"ip">>, + xmlns = [<<"urn:xmpp:sic:0">>, <<"urn:xmpp:sic:1">>], + result = '$cdata', + cdata = #cdata{required = true, + dec = {dec_ip, []}, + enc = {enc_ip, []}}}). + +-xml(sip_port, + #elem{name = <<"port">>, + xmlns = <<"urn:xmpp:sic:1">>, + result = '$cdata', + cdata = #cdata{required = true, + dec = {dec_int, [0, 65535]}, + enc = {enc_int, []}}}). + +-xml(sic, + #elem{name = <<"address">>, + xmlns = [<<"urn:xmpp:sic:0">>, <<"urn:xmpp:sic:1">>], + result = {sic, '$ip', '$port', '$xmlns'}, + attrs = [#attr{name = <<"xmlns">>}], + refs = [#ref{name = sic_ip, min = 0, max = 1, label = '$ip'}, + #ref{name = sip_port, min = 0, max = 1, label = '$port'}]}). + dec_tzo(Val) -> [H1, M1] = str:tokens(Val, <<":">>), H = jlib:binary_to_integer(H1), @@ -3050,6 +3074,16 @@ join([], _Sep) -> <<>>; join([H | T], Sep) -> <> || X <- T >>)/binary>>. +dec_ip(S) -> + {ok, Addr} = inet_parse:address(binary_to_list(S)), + Addr. + +enc_ip({0,0,0,0,0,16#ffff,A,B}) -> + enc_ip({(A bsr 8) band 16#ff, A band 16#ff, + (B bsr 8) band 16#ff, B band 16#ff}); +enc_ip(Addr) -> + list_to_binary(inet_parse:ntoa(Addr)). + %% Local Variables: %% mode: erlang %% End: From 792e6a7c1c5f5fa0c1a9f7bb2cb25a1c21bae3a6 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sat, 30 Jul 2016 17:48:52 +0300 Subject: [PATCH 019/151] Rewrite mod_http_upload to use XML generator --- include/xmpp_codec.hrl | 22 +- src/mod_http_upload.erl | 197 ++++------- src/mod_http_upload_quota.erl | 2 +- src/xmpp_codec.erl | 629 +++++++++++++++++++++++++++++++++- tools/xmpp_codec.spec | 72 ++++ 5 files changed, 784 insertions(+), 138 deletions(-) diff --git a/include/xmpp_codec.hrl b/include/xmpp_codec.hrl index 88c94a76b..caabb101d 100644 --- a/include/xmpp_codec.hrl +++ b/include/xmpp_codec.hrl @@ -91,6 +91,12 @@ since :: any()}). -type muc_history() :: #muc_history{}. +-record(thumbnail, {uri :: binary(), + 'media-type' = <<>> :: binary(), + width :: non_neg_integer(), + height :: non_neg_integer()}). +-type thumbnail() :: #thumbnail{}. + -record(pubsub_affiliation, {node :: binary(), type :: 'member' | 'none' | 'outcast' | 'owner' | 'publish-only' | 'publisher'}). -type pubsub_affiliation() :: #pubsub_affiliation{}. @@ -387,6 +393,11 @@ items = [] :: [#pubsub_item{}]}). -type pubsub_retract() :: #pubsub_retract{}. +-record(upload_slot, {get :: binary(), + put :: binary(), + xmlns :: binary()}). +-type upload_slot() :: #upload_slot{}. + -record(mix_participant, {jid :: any(), nick :: binary()}). -type mix_participant() :: #mix_participant{}. @@ -405,6 +416,12 @@ -record(block_list, {items = [] :: [any()]}). -type block_list() :: #block_list{}. +-record(upload_request, {filename :: binary(), + size :: non_neg_integer(), + 'content-type' = <<>> :: binary(), + xmlns :: binary()}). +-type upload_request() :: #upload_request{}. + -record(xdata_option, {label :: binary(), value :: binary()}). -type xdata_option() :: #xdata_option{}. @@ -837,15 +854,16 @@ version() | pubsub_affiliation() | mam_fin() | + sm_a() | bob_data() | media() | - sm_a() | carbons_sent() | mam_archived() | p1_rebind() | sasl_abort() | carbons_received() | pubsub_retract() | + upload_slot() | mix_participant() | compressed() | block_list() | @@ -887,6 +905,7 @@ feature_csi() | privacy_query() | delay() | + thumbnail() | vcard_tel() | vcard_geo() | vcard_photo() | @@ -932,6 +951,7 @@ mam_result() | rsm_first() | stat() | + upload_request() | xdata_field() | adhoc_command() | sm_failed() | diff --git a/src/mod_http_upload.erl b/src/mod_http_upload.erl index b166f2b66..63dc2dfe2 100644 --- a/src/mod_http_upload.erl +++ b/src/mod_http_upload.erl @@ -92,7 +92,7 @@ -include("ejabberd.hrl"). -include("ejabberd_http.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("logger.hrl"). -record(state, @@ -360,9 +360,8 @@ handle_cast(Request, State) -> -spec handle_info(timeout | _, state()) -> {noreply, state()}. -handle_info({route, From, To, #xmlel{name = <<"iq">>} = Stanza}, State) -> - Request = jlib:iq_query_info(Stanza), - {Reply, NewState} = case process_iq(From, Request, State) of +handle_info({route, From, To, #iq{} = IQ}, State) -> + {Reply, NewState} = case process_iq(From, IQ, State) of R when is_record(R, iq) -> {R, State}; {R, S} -> @@ -371,7 +370,7 @@ handle_info({route, From, To, #xmlel{name = <<"iq">>} = Stanza}, State) -> {none, State} end, if Reply /= none -> - ejabberd_router:route(To, From, jlib:iq_to_xml(Reply)); + ejabberd_router:route(To, From, Reply); true -> ok end, @@ -531,89 +530,48 @@ expand_host(Subject, Host) -> %% XMPP request handling. --spec process_iq(jid(), iq_request() | reply | invalid, state()) - -> {iq_reply(), state()} | iq_reply() | not_request. +-spec process_iq(jid(), iq(), state()) -> {iq(), state()} | iq() | not_request. process_iq(_From, - #iq{type = get, xmlns = ?NS_DISCO_INFO, lang = Lang} = IQ, + #iq{type = get, lang = Lang, sub_els = [#disco_info{}]} = IQ, #state{server_host = ServerHost, name = Name}) -> AddInfo = ejabberd_hooks:run_fold(disco_info, ServerHost, [], [ServerHost, ?MODULE, <<"">>, <<"">>]), - IQ#iq{type = result, - sub_el = [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_DISCO_INFO}], - children = iq_disco_info(ServerHost, Lang, Name) - ++ AddInfo}]}; -process_iq(From, - #iq{type = get, xmlns = XMLNS, lang = Lang, sub_el = SubEl} = IQ, - #state{server_host = ServerHost, access = Access} = State) - when XMLNS == ?NS_HTTP_UPLOAD; - XMLNS == ?NS_HTTP_UPLOAD_OLD -> + xmpp:make_iq_result(IQ, iq_disco_info(ServerHost, Lang, Name, AddInfo)); +process_iq(From, #iq{type = get, lang = Lang, + sub_els = [#upload_request{filename = File, + size = Size, + 'content-type' = CType, + xmlns = XMLNS}]} = IQ, + #state{server_host = ServerHost, access = Access} = State) -> case acl:match_rule(ServerHost, Access, From) of allow -> - case parse_request(SubEl, Lang) of - {ok, File, Size, ContentType} -> - case create_slot(State, From, File, Size, ContentType, - Lang) of - {ok, Slot} -> - {ok, Timer} = timer:send_after(?SLOT_TIMEOUT, - {slot_timed_out, - Slot}), - NewState = add_slot(Slot, Size, Timer, State), - SlotEl = slot_el(Slot, State, XMLNS), - {IQ#iq{type = result, sub_el = [SlotEl]}, NewState}; - {ok, PutURL, GetURL} -> - SlotEl = slot_el(PutURL, GetURL, XMLNS), - IQ#iq{type = result, sub_el = [SlotEl]}; - {error, Error} -> - IQ#iq{type = error, sub_el = [SubEl, Error]} - end; + ContentType = yield_content_type(CType), + case create_slot(State, From, File, Size, ContentType, Lang) of + {ok, Slot} -> + {ok, Timer} = timer:send_after(?SLOT_TIMEOUT, + {slot_timed_out, + Slot}), + NewState = add_slot(Slot, Size, Timer, State), + Slot = mk_slot(Slot, State, XMLNS), + {xmpp:make_iq_result(IQ, Slot), NewState}; + {ok, PutURL, GetURL} -> + Slot = mk_slot(PutURL, GetURL, XMLNS), + xmpp:make_iq_result(IQ, Slot); {error, Error} -> - ?DEBUG("Cannot parse request from ~s", - [jid:to_string(From)]), - IQ#iq{type = error, sub_el = [SubEl, Error]} + xmpp:make_error(IQ, Error) end; deny -> ?DEBUG("Denying HTTP upload slot request from ~s", [jid:to_string(From)]), Txt = <<"Denied by ACL">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_FORBIDDEN(Lang, Txt)]} + xmpp:make_error(IQ, xmpp:err_forbidden(Txt, Lang)) end; -process_iq(_From, #iq{sub_el = SubEl} = IQ, _State) -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; -process_iq(_From, reply, _State) -> - not_request; -process_iq(_From, invalid, _State) -> +process_iq(_From, #iq{type = T} = IQ, _State) when T == get; T == set -> + xmpp:make_error(IQ, xmpp:err_not_allowed()); +process_iq(_From, #iq{}, _State) -> not_request. --spec parse_request(xmlel(), binary()) - -> {ok, binary(), pos_integer(), binary()} | {error, xmlel()}. - -parse_request(#xmlel{name = <<"request">>, attrs = Attrs} = Request, Lang) -> - case fxml:get_attr(<<"xmlns">>, Attrs) of - {value, XMLNS} when XMLNS == ?NS_HTTP_UPLOAD; - XMLNS == ?NS_HTTP_UPLOAD_OLD -> - case {fxml:get_subtag_cdata(Request, <<"filename">>), - fxml:get_subtag_cdata(Request, <<"size">>), - fxml:get_subtag_cdata(Request, <<"content-type">>)} of - {File, SizeStr, ContentType} when byte_size(File) > 0 -> - case catch jlib:binary_to_integer(SizeStr) of - Size when is_integer(Size), Size > 0 -> - {ok, File, Size, yield_content_type(ContentType)}; - _ -> - Text = <<"Please specify file size.">>, - {error, ?ERRT_BAD_REQUEST(Lang, Text)} - end; - _ -> - Text = <<"Please specify file name.">>, - {error, ?ERRT_BAD_REQUEST(Lang, Text)} - end; - _ -> - Text = <<"No or invalid XML namespace">>, - {error, ?ERRT_BAD_REQUEST(Lang, Text)} - end; -parse_request(_El, _Lang) -> {error, ?ERR_BAD_REQUEST}. - -spec create_slot(state(), jid(), binary(), pos_integer(), binary(), binary()) -> {ok, slot()} | {ok, binary(), binary()} | {error, xmlel()}. @@ -624,7 +582,7 @@ create_slot(#state{service_url = undefined, max_size = MaxSize}, " Bytes.">>, ?INFO_MSG("Rejecting file ~s from ~s (too large: ~B bytes)", [File, jid:to_string(JID), Size]), - {error, ?ERRT_NOT_ACCEPTABLE(Lang, Text)}; + {error, xmpp:err_not_acceptable(Text, Lang)}; create_slot(#state{service_url = undefined, jid_in_url = JIDinURL, secret_length = SecretLength, @@ -642,8 +600,8 @@ create_slot(#state{service_url = undefined, [jid:to_string(JID), File]), {ok, [UserStr, RandStr, FileStr]}; deny -> - {error, ?ERR_SERVICE_UNAVAILABLE}; - #xmlel{} = Error -> + {error, xmpp:err_service_unavailable()}; + #error{} = Error -> {error, Error} end; create_slot(#state{service_url = ServiceURL}, @@ -669,28 +627,28 @@ create_slot(#state{service_url = ServiceURL}, ?ERROR_MSG("Can't parse data received for ~s from <~s>: ~p", [jid:to_string(JID), ServiceURL, Lines]), Txt = <<"Failed to parse HTTP response">>, - {error, ?ERRT_SERVICE_UNAVAILABLE(Lang, Txt)} + {error, xmpp:err_service_unavailable(Txt, Lang)} end; {ok, {402, _Body}} -> ?INFO_MSG("Got status code 402 for ~s from <~s>", [jid:to_string(JID), ServiceURL]), - {error, ?ERR_RESOURCE_CONSTRAINT}; + {error, xmpp:err_resource_constraint()}; {ok, {403, _Body}} -> ?INFO_MSG("Got status code 403 for ~s from <~s>", [jid:to_string(JID), ServiceURL]), - {error, ?ERR_NOT_ALLOWED}; + {error, xmpp:err_not_allowed()}; {ok, {413, _Body}} -> ?INFO_MSG("Got status code 413 for ~s from <~s>", [jid:to_string(JID), ServiceURL]), - {error, ?ERR_NOT_ACCEPTABLE}; + {error, xmpp:err_not_acceptable()}; {ok, {Code, _Body}} -> ?ERROR_MSG("Got unexpected status code for ~s from <~s>: ~B", [jid:to_string(JID), ServiceURL, Code]), - {error, ?ERR_SERVICE_UNAVAILABLE}; + {error, xmpp:err_service_unavailable()}; {error, Reason} -> ?ERROR_MSG("Error requesting upload slot for ~s from <~s>: ~p", [jid:to_string(JID), ServiceURL, Reason]), - {error, ?ERR_SERVICE_UNAVAILABLE} + {error, xmpp:err_service_unavailable()} end. -spec add_slot(slot(), pos_integer(), timer:tref(), state()) -> state(). @@ -710,19 +668,12 @@ del_slot(Slot, #state{slots = Slots} = State) -> NewSlots = maps:remove(Slot, Slots), State#state{slots = NewSlots}. --spec slot_el(slot() | binary(), state() | binary(), binary()) -> xmlel(). +-spec mk_slot(slot() | binary(), state() | binary(), binary()) -> xmlel(). -slot_el(Slot, #state{put_url = PutPrefix, get_url = GetPrefix}, XMLNS) -> +mk_slot(Slot, #state{put_url = PutPrefix, get_url = GetPrefix}, XMLNS) -> PutURL = str:join([PutPrefix | Slot], <<$/>>), GetURL = str:join([GetPrefix | Slot], <<$/>>), - slot_el(PutURL, GetURL, XMLNS); -slot_el(PutURL, GetURL, XMLNS) -> - #xmlel{name = <<"slot">>, - attrs = [{<<"xmlns">>, XMLNS}], - children = [#xmlel{name = <<"put">>, - children = [{xmlcdata, PutURL}]}, - #xmlel{name = <<"get">>, - children = [{xmlcdata, GetURL}]}]}. + #upload_slot{get = GetURL, put = PutURL, xmlns = XMLNS}. -spec make_user_string(jid(), sha1 | node) -> binary(). @@ -762,44 +713,30 @@ map_int_to_char(N) when N =< 61 -> N + 61. % Lower-case character. yield_content_type(<<"">>) -> ?DEFAULT_CONTENT_TYPE; yield_content_type(Type) -> Type. --spec iq_disco_info(binary(), binary(), binary()) -> [xmlel()]. +-spec iq_disco_info(binary(), binary(), binary(), [xdata()]) -> [xmlel()]. -iq_disco_info(Host, Lang, Name) -> +iq_disco_info(Host, Lang, Name, AddInfo) -> Form = case gen_mod:get_module_opt(Host, ?MODULE, max_size, fun(I) when is_integer(I), I > 0 -> I; (infinity) -> infinity end, 104857600) of infinity -> - []; + AddInfo; MaxSize -> MaxSizeStr = jlib:integer_to_binary(MaxSize), - Fields = [#xmlel{name = <<"field">>, - attrs = [{<<"type">>, <<"hidden">>}, - {<<"var">>, <<"FORM_TYPE">>}], - children = [#xmlel{name = <<"value">>, - children = - [{xmlcdata, - ?NS_HTTP_UPLOAD}]}]}, - #xmlel{name = <<"field">>, - attrs = [{<<"var">>, <<"max-file-size">>}], - children = [#xmlel{name = <<"value">>, - children = - [{xmlcdata, - MaxSizeStr}]}]}], - [#xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_XDATA}, - {<<"type">>, <<"result">>}], - children = Fields}] + Fields = [#xdata_field{type = hidden, + var = <<"FORM_TYPE">>, + values = [?NS_HTTP_UPLOAD]}, + #xdata_field{var = <<"max-file-size">>, + values = [MaxSizeStr]}], + [#xdata{type = result, fields = Fields}|AddInfo] end, - [#xmlel{name = <<"identity">>, - attrs = [{<<"category">>, <<"store">>}, - {<<"type">>, <<"file">>}, - {<<"name">>, translate:translate(Lang, Name)}]}, - #xmlel{name = <<"feature">>, - attrs = [{<<"var">>, ?NS_HTTP_UPLOAD}]}, - #xmlel{name = <<"feature">>, - attrs = [{<<"var">>, ?NS_HTTP_UPLOAD_OLD}]} | Form]. + #disco_info{identities = [#identity{category = <<"store">>, + type = <<"file">>, + name = translate:translate(Lang, Name)}], + features = [?NS_HTTP_UPLOAD, ?NS_HTTP_UPLOAD_OLD], + xdata = Form}. %% HTTP request handling. @@ -984,20 +921,14 @@ convert(Path, #media_info{type = T, width = W, height = H}) -> thumb_el(Path, URI) -> ContentType = guess_content_type(Path), - case identify(Path) of - {ok, #media_info{height = H, width = W}} -> - #xmlel{name = <<"thumbnail">>, - attrs = [{<<"xmlns">>, ?NS_THUMBS_1}, - {<<"media-type">>, ContentType}, - {<<"uri">>, URI}, - {<<"height">>, jlib:integer_to_binary(H)}, - {<<"width">>, jlib:integer_to_binary(W)}]}; - pass -> - #xmlel{name = <<"thumbnail">>, - attrs = [{<<"xmlns">>, ?NS_THUMBS_1}, - {<<"uri">>, URI}, - {<<"media-type">>, ContentType}]} - end. + xmpp:encode( + case identify(Path) of + {ok, #media_info{height = H, width = W}} -> + #thumbnail{'media-type' = ContentType, uri = URI, + height = H, width = W}; + pass -> + #thumbnail{uri = URI, 'media-type' = ContentType} + end). %%-------------------------------------------------------------------- %% Remove user. diff --git a/src/mod_http_upload_quota.erl b/src/mod_http_upload_quota.erl index 35e266ddf..056edbedb 100644 --- a/src/mod_http_upload_quota.erl +++ b/src/mod_http_upload_quota.erl @@ -53,7 +53,7 @@ %% ejabberd_hooks callback. -export([handle_slot_request/5]). --include("jlib.hrl"). +-include("jid.hrl"). -include("logger.hrl"). -include_lib("kernel/include/file.hrl"). diff --git a/src/xmpp_codec.erl b/src/xmpp_codec.erl index 11bd741f4..8d87712df 100644 --- a/src/xmpp_codec.erl +++ b/src/xmpp_codec.erl @@ -15,6 +15,56 @@ decode(_el) -> decode(_el, []). decode({xmlel, _name, _attrs, _} = _el, Opts) -> IgnoreEls = proplists:get_bool(ignore_els, Opts), case {_name, get_attr(<<"xmlns">>, _attrs)} of + {<<"thumbnail">>, <<"urn:xmpp:thumbs:1">>} -> + decode_thumbnail(<<"urn:xmpp:thumbs:1">>, IgnoreEls, + _el); + {<<"slot">>, <<"urn:xmpp:http:upload">>} -> + decode_upload_slot(<<"urn:xmpp:http:upload">>, + IgnoreEls, _el); + {<<"slot">>, + <<"eu:siacs:conversations:http:upload">>} -> + decode_upload_slot(<<"eu:siacs:conversations:http:upload">>, + IgnoreEls, _el); + {<<"put">>, <<"urn:xmpp:http:upload">>} -> + decode_upload_put(<<"urn:xmpp:http:upload">>, IgnoreEls, + _el); + {<<"put">>, <<"eu:siacs:conversations:http:upload">>} -> + decode_upload_put(<<"eu:siacs:conversations:http:upload">>, + IgnoreEls, _el); + {<<"get">>, <<"urn:xmpp:http:upload">>} -> + decode_upload_get(<<"urn:xmpp:http:upload">>, IgnoreEls, + _el); + {<<"get">>, <<"eu:siacs:conversations:http:upload">>} -> + decode_upload_get(<<"eu:siacs:conversations:http:upload">>, + IgnoreEls, _el); + {<<"request">>, <<"urn:xmpp:http:upload">>} -> + decode_upload_request(<<"urn:xmpp:http:upload">>, + IgnoreEls, _el); + {<<"request">>, + <<"eu:siacs:conversations:http:upload">>} -> + decode_upload_request(<<"eu:siacs:conversations:http:upload">>, + IgnoreEls, _el); + {<<"content-type">>, <<"urn:xmpp:http:upload">>} -> + decode_upload_content_type(<<"urn:xmpp:http:upload">>, + IgnoreEls, _el); + {<<"content-type">>, + <<"eu:siacs:conversations:http:upload">>} -> + decode_upload_content_type(<<"eu:siacs:conversations:http:upload">>, + IgnoreEls, _el); + {<<"size">>, <<"urn:xmpp:http:upload">>} -> + decode_upload_size(<<"urn:xmpp:http:upload">>, + IgnoreEls, _el); + {<<"size">>, + <<"eu:siacs:conversations:http:upload">>} -> + decode_upload_size(<<"eu:siacs:conversations:http:upload">>, + IgnoreEls, _el); + {<<"filename">>, <<"urn:xmpp:http:upload">>} -> + decode_upload_filename(<<"urn:xmpp:http:upload">>, + IgnoreEls, _el); + {<<"filename">>, + <<"eu:siacs:conversations:http:upload">>} -> + decode_upload_filename(<<"eu:siacs:conversations:http:upload">>, + IgnoreEls, _el); {<<"address">>, <<"urn:xmpp:sic:0">>} -> decode_sic(<<"urn:xmpp:sic:0">>, IgnoreEls, _el); {<<"address">>, <<"urn:xmpp:sic:1">>} -> @@ -1319,6 +1369,34 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> is_known_tag({xmlel, _name, _attrs, _} = _el) -> case {_name, get_attr(<<"xmlns">>, _attrs)} of + {<<"thumbnail">>, <<"urn:xmpp:thumbs:1">>} -> true; + {<<"slot">>, <<"urn:xmpp:http:upload">>} -> true; + {<<"slot">>, + <<"eu:siacs:conversations:http:upload">>} -> + true; + {<<"put">>, <<"urn:xmpp:http:upload">>} -> true; + {<<"put">>, <<"eu:siacs:conversations:http:upload">>} -> + true; + {<<"get">>, <<"urn:xmpp:http:upload">>} -> true; + {<<"get">>, <<"eu:siacs:conversations:http:upload">>} -> + true; + {<<"request">>, <<"urn:xmpp:http:upload">>} -> true; + {<<"request">>, + <<"eu:siacs:conversations:http:upload">>} -> + true; + {<<"content-type">>, <<"urn:xmpp:http:upload">>} -> + true; + {<<"content-type">>, + <<"eu:siacs:conversations:http:upload">>} -> + true; + {<<"size">>, <<"urn:xmpp:http:upload">>} -> true; + {<<"size">>, + <<"eu:siacs:conversations:http:upload">>} -> + true; + {<<"filename">>, <<"urn:xmpp:http:upload">>} -> true; + {<<"filename">>, + <<"eu:siacs:conversations:http:upload">>} -> + true; {<<"address">>, <<"urn:xmpp:sic:0">>} -> true; {<<"address">>, <<"urn:xmpp:sic:1">>} -> true; {<<"port">>, <<"urn:xmpp:sic:1">>} -> true; @@ -2626,7 +2704,14 @@ encode({media, _, _, _} = Media) -> encode({oob_x, _, _, _} = X) -> encode_oob_x(X, [{<<"xmlns">>, <<"jabber:x:oob">>}]); encode({sic, _, _, _} = Address) -> - encode_sic(Address, []). + encode_sic(Address, []); +encode({upload_request, _, _, _, _} = Request) -> + encode_upload_request(Request, []); +encode({upload_slot, _, _, _} = Slot) -> + encode_upload_slot(Slot, []); +encode({thumbnail, _, _, _, _} = Thumbnail) -> + encode_thumbnail(Thumbnail, + [{<<"xmlns">>, <<"urn:xmpp:thumbs:1">>}]). get_name({last, _, _}) -> <<"query">>; get_name({version, _, _, _}) -> <<"query">>; @@ -2820,7 +2905,10 @@ get_name({xcaptcha, _}) -> <<"captcha">>; get_name({media_uri, _, _}) -> <<"uri">>; get_name({media, _, _, _}) -> <<"media">>; get_name({oob_x, _, _, _}) -> <<"x">>; -get_name({sic, _, _, _}) -> <<"address">>. +get_name({sic, _, _, _}) -> <<"address">>; +get_name({upload_request, _, _, _, _}) -> <<"request">>; +get_name({upload_slot, _, _, _}) -> <<"slot">>; +get_name({thumbnail, _, _, _, _}) -> <<"thumbnail">>. get_ns({last, _, _}) -> <<"jabber:iq:last">>; get_ns({version, _, _, _}) -> <<"jabber:iq:version">>; @@ -3089,7 +3177,11 @@ get_ns({media_uri, _, _}) -> get_ns({media, _, _, _}) -> <<"urn:xmpp:media-element">>; get_ns({oob_x, _, _, _}) -> <<"jabber:x:oob">>; -get_ns({sic, _, _, Xmlns}) -> Xmlns. +get_ns({sic, _, _, Xmlns}) -> Xmlns; +get_ns({upload_request, _, _, _, Xmlns}) -> Xmlns; +get_ns({upload_slot, _, _, Xmlns}) -> Xmlns; +get_ns({thumbnail, _, _, _, _}) -> + <<"urn:xmpp:thumbs:1">>. dec_int(Val) -> dec_int(Val, infinity, infinity). @@ -3339,6 +3431,10 @@ pp(media_uri, 2) -> [type, uri]; pp(media, 3) -> [height, width, uri]; pp(oob_x, 3) -> [url, desc, sid]; pp(sic, 3) -> [ip, port, xmlns]; +pp(upload_request, 4) -> + [filename, size, 'content-type', xmlns]; +pp(upload_slot, 3) -> [get, put, xmlns]; +pp(thumbnail, 4) -> [uri, 'media-type', width, height]; pp(_, _) -> no. enc_ip({0, 0, 0, 0, 0, 65535, A, B}) -> @@ -3394,6 +3490,533 @@ dec_tzo(Val) -> M = jlib:binary_to_integer(M1), if H >= -12, H =< 12, M >= 0, M < 60 -> {H, M} end. +decode_thumbnail(__TopXMLNS, __IgnoreEls, + {xmlel, <<"thumbnail">>, _attrs, _els}) -> + {Uri, Media_type, Width, Height} = + decode_thumbnail_attrs(__TopXMLNS, _attrs, undefined, + undefined, undefined, undefined), + {thumbnail, Uri, Media_type, Width, Height}. + +decode_thumbnail_attrs(__TopXMLNS, + [{<<"uri">>, _val} | _attrs], _Uri, Media_type, Width, + Height) -> + decode_thumbnail_attrs(__TopXMLNS, _attrs, _val, + Media_type, Width, Height); +decode_thumbnail_attrs(__TopXMLNS, + [{<<"media-type">>, _val} | _attrs], Uri, _Media_type, + Width, Height) -> + decode_thumbnail_attrs(__TopXMLNS, _attrs, Uri, _val, + Width, Height); +decode_thumbnail_attrs(__TopXMLNS, + [{<<"width">>, _val} | _attrs], Uri, Media_type, _Width, + Height) -> + decode_thumbnail_attrs(__TopXMLNS, _attrs, Uri, + Media_type, _val, Height); +decode_thumbnail_attrs(__TopXMLNS, + [{<<"height">>, _val} | _attrs], Uri, Media_type, Width, + _Height) -> + decode_thumbnail_attrs(__TopXMLNS, _attrs, Uri, + Media_type, Width, _val); +decode_thumbnail_attrs(__TopXMLNS, [_ | _attrs], Uri, + Media_type, Width, Height) -> + decode_thumbnail_attrs(__TopXMLNS, _attrs, Uri, + Media_type, Width, Height); +decode_thumbnail_attrs(__TopXMLNS, [], Uri, Media_type, + Width, Height) -> + {decode_thumbnail_attr_uri(__TopXMLNS, Uri), + 'decode_thumbnail_attr_media-type'(__TopXMLNS, + Media_type), + decode_thumbnail_attr_width(__TopXMLNS, Width), + decode_thumbnail_attr_height(__TopXMLNS, Height)}. + +encode_thumbnail({thumbnail, Uri, Media_type, Width, + Height}, + _xmlns_attrs) -> + _els = [], + _attrs = encode_thumbnail_attr_height(Height, + encode_thumbnail_attr_width(Width, + 'encode_thumbnail_attr_media-type'(Media_type, + encode_thumbnail_attr_uri(Uri, + _xmlns_attrs)))), + {xmlel, <<"thumbnail">>, _attrs, _els}. + +decode_thumbnail_attr_uri(__TopXMLNS, undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"uri">>, <<"thumbnail">>, + __TopXMLNS}}); +decode_thumbnail_attr_uri(__TopXMLNS, _val) -> _val. + +encode_thumbnail_attr_uri(_val, _acc) -> + [{<<"uri">>, _val} | _acc]. + +'decode_thumbnail_attr_media-type'(__TopXMLNS, + undefined) -> + <<>>; +'decode_thumbnail_attr_media-type'(__TopXMLNS, _val) -> + _val. + +'encode_thumbnail_attr_media-type'(<<>>, _acc) -> _acc; +'encode_thumbnail_attr_media-type'(_val, _acc) -> + [{<<"media-type">>, _val} | _acc]. + +decode_thumbnail_attr_width(__TopXMLNS, undefined) -> + undefined; +decode_thumbnail_attr_width(__TopXMLNS, _val) -> + case catch dec_int(_val, 0, infinity) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"width">>, <<"thumbnail">>, + __TopXMLNS}}); + _res -> _res + end. + +encode_thumbnail_attr_width(undefined, _acc) -> _acc; +encode_thumbnail_attr_width(_val, _acc) -> + [{<<"width">>, enc_int(_val)} | _acc]. + +decode_thumbnail_attr_height(__TopXMLNS, undefined) -> + undefined; +decode_thumbnail_attr_height(__TopXMLNS, _val) -> + case catch dec_int(_val, 0, infinity) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"height">>, <<"thumbnail">>, + __TopXMLNS}}); + _res -> _res + end. + +encode_thumbnail_attr_height(undefined, _acc) -> _acc; +encode_thumbnail_attr_height(_val, _acc) -> + [{<<"height">>, enc_int(_val)} | _acc]. + +decode_upload_slot(__TopXMLNS, __IgnoreEls, + {xmlel, <<"slot">>, _attrs, _els}) -> + {Put, Get} = decode_upload_slot_els(__TopXMLNS, + __IgnoreEls, _els, undefined, + undefined), + Xmlns = decode_upload_slot_attrs(__TopXMLNS, _attrs, + undefined), + {upload_slot, Get, Put, Xmlns}. + +decode_upload_slot_els(__TopXMLNS, __IgnoreEls, [], Put, + Get) -> + {Put, Get}; +decode_upload_slot_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"get">>, _attrs, _} = _el | _els], Put, + Get) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"eu:siacs:conversations:http:upload">>; + __TopXMLNS == <<"urn:xmpp:http:upload">> -> + decode_upload_slot_els(__TopXMLNS, __IgnoreEls, _els, + Put, + decode_upload_get(__TopXMLNS, __IgnoreEls, + _el)); + <<"urn:xmpp:http:upload">> -> + decode_upload_slot_els(__TopXMLNS, __IgnoreEls, _els, + Put, + decode_upload_get(<<"urn:xmpp:http:upload">>, + __IgnoreEls, _el)); + <<"eu:siacs:conversations:http:upload">> -> + decode_upload_slot_els(__TopXMLNS, __IgnoreEls, _els, + Put, + decode_upload_get(<<"eu:siacs:conversations:http:upload">>, + __IgnoreEls, _el)); + _ -> + decode_upload_slot_els(__TopXMLNS, __IgnoreEls, _els, + Put, Get) + end; +decode_upload_slot_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"put">>, _attrs, _} = _el | _els], Put, + Get) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"eu:siacs:conversations:http:upload">>; + __TopXMLNS == <<"urn:xmpp:http:upload">> -> + decode_upload_slot_els(__TopXMLNS, __IgnoreEls, _els, + decode_upload_put(__TopXMLNS, __IgnoreEls, + _el), + Get); + <<"urn:xmpp:http:upload">> -> + decode_upload_slot_els(__TopXMLNS, __IgnoreEls, _els, + decode_upload_put(<<"urn:xmpp:http:upload">>, + __IgnoreEls, _el), + Get); + <<"eu:siacs:conversations:http:upload">> -> + decode_upload_slot_els(__TopXMLNS, __IgnoreEls, _els, + decode_upload_put(<<"eu:siacs:conversations:http:upload">>, + __IgnoreEls, _el), + Get); + _ -> + decode_upload_slot_els(__TopXMLNS, __IgnoreEls, _els, + Put, Get) + end; +decode_upload_slot_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Put, Get) -> + decode_upload_slot_els(__TopXMLNS, __IgnoreEls, _els, + Put, Get). + +decode_upload_slot_attrs(__TopXMLNS, + [{<<"xmlns">>, _val} | _attrs], _Xmlns) -> + decode_upload_slot_attrs(__TopXMLNS, _attrs, _val); +decode_upload_slot_attrs(__TopXMLNS, [_ | _attrs], + Xmlns) -> + decode_upload_slot_attrs(__TopXMLNS, _attrs, Xmlns); +decode_upload_slot_attrs(__TopXMLNS, [], Xmlns) -> + decode_upload_slot_attr_xmlns(__TopXMLNS, Xmlns). + +encode_upload_slot({upload_slot, Get, Put, Xmlns}, + _xmlns_attrs) -> + _els = lists:reverse('encode_upload_slot_$put'(Put, + 'encode_upload_slot_$get'(Get, + []))), + _attrs = encode_upload_slot_attr_xmlns(Xmlns, + _xmlns_attrs), + {xmlel, <<"slot">>, _attrs, _els}. + +'encode_upload_slot_$put'(undefined, _acc) -> _acc; +'encode_upload_slot_$put'(Put, _acc) -> + [encode_upload_put(Put, []) | _acc]. + +'encode_upload_slot_$get'(undefined, _acc) -> _acc; +'encode_upload_slot_$get'(Get, _acc) -> + [encode_upload_get(Get, []) | _acc]. + +decode_upload_slot_attr_xmlns(__TopXMLNS, undefined) -> + undefined; +decode_upload_slot_attr_xmlns(__TopXMLNS, _val) -> _val. + +encode_upload_slot_attr_xmlns(undefined, _acc) -> _acc; +encode_upload_slot_attr_xmlns(_val, _acc) -> + [{<<"xmlns">>, _val} | _acc]. + +decode_upload_put(__TopXMLNS, __IgnoreEls, + {xmlel, <<"put">>, _attrs, _els}) -> + Cdata = decode_upload_put_els(__TopXMLNS, __IgnoreEls, + _els, <<>>), + Cdata. + +decode_upload_put_els(__TopXMLNS, __IgnoreEls, [], + Cdata) -> + decode_upload_put_cdata(__TopXMLNS, Cdata); +decode_upload_put_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Cdata) -> + decode_upload_put_els(__TopXMLNS, __IgnoreEls, _els, + <>); +decode_upload_put_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Cdata) -> + decode_upload_put_els(__TopXMLNS, __IgnoreEls, _els, + Cdata). + +encode_upload_put(Cdata, _xmlns_attrs) -> + _els = encode_upload_put_cdata(Cdata, []), + _attrs = _xmlns_attrs, + {xmlel, <<"put">>, _attrs, _els}. + +decode_upload_put_cdata(__TopXMLNS, <<>>) -> + erlang:error({xmpp_codec, + {missing_cdata, <<>>, <<"put">>, __TopXMLNS}}); +decode_upload_put_cdata(__TopXMLNS, _val) -> _val. + +encode_upload_put_cdata(_val, _acc) -> + [{xmlcdata, _val} | _acc]. + +decode_upload_get(__TopXMLNS, __IgnoreEls, + {xmlel, <<"get">>, _attrs, _els}) -> + Cdata = decode_upload_get_els(__TopXMLNS, __IgnoreEls, + _els, <<>>), + Cdata. + +decode_upload_get_els(__TopXMLNS, __IgnoreEls, [], + Cdata) -> + decode_upload_get_cdata(__TopXMLNS, Cdata); +decode_upload_get_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Cdata) -> + decode_upload_get_els(__TopXMLNS, __IgnoreEls, _els, + <>); +decode_upload_get_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Cdata) -> + decode_upload_get_els(__TopXMLNS, __IgnoreEls, _els, + Cdata). + +encode_upload_get(Cdata, _xmlns_attrs) -> + _els = encode_upload_get_cdata(Cdata, []), + _attrs = _xmlns_attrs, + {xmlel, <<"get">>, _attrs, _els}. + +decode_upload_get_cdata(__TopXMLNS, <<>>) -> + erlang:error({xmpp_codec, + {missing_cdata, <<>>, <<"get">>, __TopXMLNS}}); +decode_upload_get_cdata(__TopXMLNS, _val) -> _val. + +encode_upload_get_cdata(_val, _acc) -> + [{xmlcdata, _val} | _acc]. + +decode_upload_request(__TopXMLNS, __IgnoreEls, + {xmlel, <<"request">>, _attrs, _els}) -> + {Content_type, Size, Filename} = + decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, + <<>>, error, error), + Xmlns = decode_upload_request_attrs(__TopXMLNS, _attrs, + undefined), + {upload_request, Filename, Size, Content_type, Xmlns}. + +decode_upload_request_els(__TopXMLNS, __IgnoreEls, [], + Content_type, Size, Filename) -> + {Content_type, + case Size of + error -> + erlang:error({xmpp_codec, + {missing_tag, <<"size">>, __TopXMLNS}}); + {value, Size1} -> Size1 + end, + case Filename of + error -> + erlang:error({xmpp_codec, + {missing_tag, <<"filename">>, __TopXMLNS}}); + {value, Filename1} -> Filename1 + end}; +decode_upload_request_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"filename">>, _attrs, _} = _el | _els], + Content_type, Size, Filename) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"eu:siacs:conversations:http:upload">>; + __TopXMLNS == <<"urn:xmpp:http:upload">> -> + decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, + Content_type, Size, + {value, + decode_upload_filename(__TopXMLNS, + __IgnoreEls, _el)}); + <<"urn:xmpp:http:upload">> -> + decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, + Content_type, Size, + {value, + decode_upload_filename(<<"urn:xmpp:http:upload">>, + __IgnoreEls, _el)}); + <<"eu:siacs:conversations:http:upload">> -> + decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, + Content_type, Size, + {value, + decode_upload_filename(<<"eu:siacs:conversations:http:upload">>, + __IgnoreEls, _el)}); + _ -> + decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, + Content_type, Size, Filename) + end; +decode_upload_request_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"size">>, _attrs, _} = _el | _els], + Content_type, Size, Filename) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"eu:siacs:conversations:http:upload">>; + __TopXMLNS == <<"urn:xmpp:http:upload">> -> + decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, + Content_type, + {value, + decode_upload_size(__TopXMLNS, __IgnoreEls, + _el)}, + Filename); + <<"urn:xmpp:http:upload">> -> + decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, + Content_type, + {value, + decode_upload_size(<<"urn:xmpp:http:upload">>, + __IgnoreEls, _el)}, + Filename); + <<"eu:siacs:conversations:http:upload">> -> + decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, + Content_type, + {value, + decode_upload_size(<<"eu:siacs:conversations:http:upload">>, + __IgnoreEls, _el)}, + Filename); + _ -> + decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, + Content_type, Size, Filename) + end; +decode_upload_request_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"content-type">>, _attrs, _} = _el | _els], + Content_type, Size, Filename) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"eu:siacs:conversations:http:upload">>; + __TopXMLNS == <<"urn:xmpp:http:upload">> -> + decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, + decode_upload_content_type(__TopXMLNS, + __IgnoreEls, + _el), + Size, Filename); + <<"urn:xmpp:http:upload">> -> + decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, + decode_upload_content_type(<<"urn:xmpp:http:upload">>, + __IgnoreEls, + _el), + Size, Filename); + <<"eu:siacs:conversations:http:upload">> -> + decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, + decode_upload_content_type(<<"eu:siacs:conversations:http:upload">>, + __IgnoreEls, + _el), + Size, Filename); + _ -> + decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, + Content_type, Size, Filename) + end; +decode_upload_request_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Content_type, Size, Filename) -> + decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, + Content_type, Size, Filename). + +decode_upload_request_attrs(__TopXMLNS, + [{<<"xmlns">>, _val} | _attrs], _Xmlns) -> + decode_upload_request_attrs(__TopXMLNS, _attrs, _val); +decode_upload_request_attrs(__TopXMLNS, [_ | _attrs], + Xmlns) -> + decode_upload_request_attrs(__TopXMLNS, _attrs, Xmlns); +decode_upload_request_attrs(__TopXMLNS, [], Xmlns) -> + decode_upload_request_attr_xmlns(__TopXMLNS, Xmlns). + +encode_upload_request({upload_request, Filename, Size, + Content_type, Xmlns}, + _xmlns_attrs) -> + _els = + lists:reverse('encode_upload_request_$content-type'(Content_type, + 'encode_upload_request_$size'(Size, + 'encode_upload_request_$filename'(Filename, + [])))), + _attrs = encode_upload_request_attr_xmlns(Xmlns, + _xmlns_attrs), + {xmlel, <<"request">>, _attrs, _els}. + +'encode_upload_request_$content-type'(<<>>, _acc) -> + _acc; +'encode_upload_request_$content-type'(Content_type, + _acc) -> + [encode_upload_content_type(Content_type, []) | _acc]. + +'encode_upload_request_$size'(Size, _acc) -> + [encode_upload_size(Size, []) | _acc]. + +'encode_upload_request_$filename'(Filename, _acc) -> + [encode_upload_filename(Filename, []) | _acc]. + +decode_upload_request_attr_xmlns(__TopXMLNS, + undefined) -> + undefined; +decode_upload_request_attr_xmlns(__TopXMLNS, _val) -> + _val. + +encode_upload_request_attr_xmlns(undefined, _acc) -> + _acc; +encode_upload_request_attr_xmlns(_val, _acc) -> + [{<<"xmlns">>, _val} | _acc]. + +decode_upload_content_type(__TopXMLNS, __IgnoreEls, + {xmlel, <<"content-type">>, _attrs, _els}) -> + Cdata = decode_upload_content_type_els(__TopXMLNS, + __IgnoreEls, _els, <<>>), + Cdata. + +decode_upload_content_type_els(__TopXMLNS, __IgnoreEls, + [], Cdata) -> + decode_upload_content_type_cdata(__TopXMLNS, Cdata); +decode_upload_content_type_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Cdata) -> + decode_upload_content_type_els(__TopXMLNS, __IgnoreEls, + _els, <>); +decode_upload_content_type_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Cdata) -> + decode_upload_content_type_els(__TopXMLNS, __IgnoreEls, + _els, Cdata). + +encode_upload_content_type(Cdata, _xmlns_attrs) -> + _els = encode_upload_content_type_cdata(Cdata, []), + _attrs = _xmlns_attrs, + {xmlel, <<"content-type">>, _attrs, _els}. + +decode_upload_content_type_cdata(__TopXMLNS, <<>>) -> + <<>>; +decode_upload_content_type_cdata(__TopXMLNS, _val) -> + _val. + +encode_upload_content_type_cdata(<<>>, _acc) -> _acc; +encode_upload_content_type_cdata(_val, _acc) -> + [{xmlcdata, _val} | _acc]. + +decode_upload_size(__TopXMLNS, __IgnoreEls, + {xmlel, <<"size">>, _attrs, _els}) -> + Cdata = decode_upload_size_els(__TopXMLNS, __IgnoreEls, + _els, <<>>), + Cdata. + +decode_upload_size_els(__TopXMLNS, __IgnoreEls, [], + Cdata) -> + decode_upload_size_cdata(__TopXMLNS, Cdata); +decode_upload_size_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Cdata) -> + decode_upload_size_els(__TopXMLNS, __IgnoreEls, _els, + <>); +decode_upload_size_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Cdata) -> + decode_upload_size_els(__TopXMLNS, __IgnoreEls, _els, + Cdata). + +encode_upload_size(Cdata, _xmlns_attrs) -> + _els = encode_upload_size_cdata(Cdata, []), + _attrs = _xmlns_attrs, + {xmlel, <<"size">>, _attrs, _els}. + +decode_upload_size_cdata(__TopXMLNS, <<>>) -> + erlang:error({xmpp_codec, + {missing_cdata, <<>>, <<"size">>, __TopXMLNS}}); +decode_upload_size_cdata(__TopXMLNS, _val) -> + case catch dec_int(_val, 0, infinity) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_cdata_value, <<>>, <<"size">>, __TopXMLNS}}); + _res -> _res + end. + +encode_upload_size_cdata(_val, _acc) -> + [{xmlcdata, enc_int(_val)} | _acc]. + +decode_upload_filename(__TopXMLNS, __IgnoreEls, + {xmlel, <<"filename">>, _attrs, _els}) -> + Cdata = decode_upload_filename_els(__TopXMLNS, + __IgnoreEls, _els, <<>>), + Cdata. + +decode_upload_filename_els(__TopXMLNS, __IgnoreEls, [], + Cdata) -> + decode_upload_filename_cdata(__TopXMLNS, Cdata); +decode_upload_filename_els(__TopXMLNS, __IgnoreEls, + [{xmlcdata, _data} | _els], Cdata) -> + decode_upload_filename_els(__TopXMLNS, __IgnoreEls, + _els, <>); +decode_upload_filename_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Cdata) -> + decode_upload_filename_els(__TopXMLNS, __IgnoreEls, + _els, Cdata). + +encode_upload_filename(Cdata, _xmlns_attrs) -> + _els = encode_upload_filename_cdata(Cdata, []), + _attrs = _xmlns_attrs, + {xmlel, <<"filename">>, _attrs, _els}. + +decode_upload_filename_cdata(__TopXMLNS, <<>>) -> + erlang:error({xmpp_codec, + {missing_cdata, <<>>, <<"filename">>, __TopXMLNS}}); +decode_upload_filename_cdata(__TopXMLNS, _val) -> _val. + +encode_upload_filename_cdata(_val, _acc) -> + [{xmlcdata, _val} | _acc]. + decode_sic(__TopXMLNS, __IgnoreEls, {xmlel, <<"address">>, _attrs, _els}) -> {Ip, Port} = decode_sic_els(__TopXMLNS, __IgnoreEls, diff --git a/tools/xmpp_codec.spec b/tools/xmpp_codec.spec index 9cb14282c..293f12d17 100644 --- a/tools/xmpp_codec.spec +++ b/tools/xmpp_codec.spec @@ -3021,6 +3021,78 @@ refs = [#ref{name = sic_ip, min = 0, max = 1, label = '$ip'}, #ref{name = sip_port, min = 0, max = 1, label = '$port'}]}). +-xml(upload_filename, + #elem{name = <<"filename">>, + xmlns = [<<"urn:xmpp:http:upload">>, + <<"eu:siacs:conversations:http:upload">>], + result = '$cdata', + cdata = #cdata{required = true}}). + +-xml(upload_size, + #elem{name = <<"size">>, + xmlns = [<<"urn:xmpp:http:upload">>, + <<"eu:siacs:conversations:http:upload">>], + result = '$cdata', + cdata = #cdata{required = true, + dec = {dec_int, [0, infinity]}, + enc = {enc_int, []}}}). + +-xml(upload_content_type, + #elem{name = <<"content-type">>, + xmlns = [<<"urn:xmpp:http:upload">>, + <<"eu:siacs:conversations:http:upload">>], + result = '$cdata', + cdata = #cdata{default = <<"">>}}). + +-xml(upload_request, + #elem{name = <<"request">>, + xmlns = [<<"urn:xmpp:http:upload">>, + <<"eu:siacs:conversations:http:upload">>], + result = {upload_request, '$filename', '$size', + '$content-type', '$xmlns'}, + attrs = [#attr{name = <<"xmlns">>}], + refs = [#ref{name = upload_filename, label = '$filename', + min = 1, max = 1}, + #ref{name = upload_size, label = '$size', min = 1, max = 1}, + #ref{name = upload_content_type, label = '$content-type', + min = 0, max = 1, default = <<"">>}]}). + +-xml(upload_get, + #elem{name = <<"get">>, + xmlns = [<<"urn:xmpp:http:upload">>, + <<"eu:siacs:conversations:http:upload">>], + result = '$cdata', + cdata = #cdata{required = true}}). + +-xml(upload_put, + #elem{name = <<"put">>, + xmlns = [<<"urn:xmpp:http:upload">>, + <<"eu:siacs:conversations:http:upload">>], + result = '$cdata', + cdata = #cdata{required = true}}). + +-xml(upload_slot, + #elem{name = <<"slot">>, + xmlns = [<<"urn:xmpp:http:upload">>, + <<"eu:siacs:conversations:http:upload">>], + result = {upload_slot, '$get', '$put', '$xmlns'}, + attrs = [#attr{name = <<"xmlns">>}], + refs = [#ref{name = upload_get, min = 0, max = 1, label = '$get'}, + #ref{name = upload_put, min = 0, max = 1, label = '$put'}]}). + +-xml(thumbnail, + #elem{name = <<"thumbnail">>, + xmlns = <<"urn:xmpp:thumbs:1">>, + result = {thumbnail, '$uri', '$media-type', '$width', '$height'}, + attrs = [#attr{name = <<"uri">>, required = true}, + #attr{name = <<"media-type">>, default = <<"">>}, + #attr{name = <<"width">>, + dec = {dec_int, [0, infinity]}, + enc = {enc_int, []}}, + #attr{name = <<"height">>, + dec = {dec_int, [0, infinity]}, + enc = {enc_int, []}}]}). + dec_tzo(Val) -> [H1, M1] = str:tokens(Val, <<":">>), H = jlib:binary_to_integer(H1), From 5cd1cf5096e21988ca517fa358e8ab5ad7a5cc55 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sat, 30 Jul 2016 18:37:57 +0300 Subject: [PATCH 020/151] Get rid of "jlib.hrl" dependency in some modules --- src/ejabberd_http.erl | 2 +- src/ejabberd_http_ws.erl | 2 +- src/ejabberd_web.erl | 2 +- src/ejabberd_websocket.erl | 2 +- src/gen_pubsub_nodetree.erl | 27 +++++++++++++-------------- src/mod_http_bind.erl | 2 +- src/node_buddy.erl | 1 - src/node_club.erl | 1 - src/node_hometree.erl | 1 - src/node_hometree_sql.erl | 1 - src/node_mb.erl | 1 - src/node_online.erl | 2 +- src/node_pep.erl | 1 - src/node_pep_sql.erl | 1 - src/node_private.erl | 1 - src/node_public.erl | 1 - src/nodetree_virtual.erl | 1 - 17 files changed, 19 insertions(+), 30 deletions(-) diff --git a/src/ejabberd_http.erl b/src/ejabberd_http.erl index 6b53f46c6..1c8de2fbf 100644 --- a/src/ejabberd_http.erl +++ b/src/ejabberd_http.erl @@ -39,7 +39,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("ejabberd_http.hrl"). diff --git a/src/ejabberd_http_ws.erl b/src/ejabberd_http_ws.erl index e66cf33a5..02df19e63 100644 --- a/src/ejabberd_http_ws.erl +++ b/src/ejabberd_http_ws.erl @@ -39,7 +39,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("ejabberd_http.hrl"). diff --git a/src/ejabberd_web.erl b/src/ejabberd_web.erl index 459423aa4..523feb9c7 100644 --- a/src/ejabberd_web.erl +++ b/src/ejabberd_web.erl @@ -34,7 +34,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("ejabberd_http.hrl"). diff --git a/src/ejabberd_websocket.erl b/src/ejabberd_websocket.erl index 0cdd9bac5..76568aa2d 100644 --- a/src/ejabberd_websocket.erl +++ b/src/ejabberd_websocket.erl @@ -47,7 +47,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("ejabberd_http.hrl"). diff --git a/src/gen_pubsub_nodetree.erl b/src/gen_pubsub_nodetree.erl index 73583af02..a18bc8d39 100644 --- a/src/gen_pubsub_nodetree.erl +++ b/src/gen_pubsub_nodetree.erl @@ -25,7 +25,6 @@ -module(gen_pubsub_nodetree). --include("jlib.hrl"). -type(host() :: mod_pubsub:host()). -type(nodeId() :: mod_pubsub:nodeId()). @@ -42,25 +41,25 @@ -callback options() -> nodeOptions(). -callback set_node(PubsubNode :: pubsubNode()) -> - ok | {result, NodeIdx::nodeIdx()} | {error, xmlel()}. + ok | {result, NodeIdx::nodeIdx()} | {error, fxml:xmlel()}. -callback get_node(Host :: host(), NodeId :: nodeId(), - From :: jid()) -> + From :: jid:jid()) -> pubsubNode() | - {error, xmlel()}. + {error, fxml:xmlel()}. -callback get_node(Host :: host(), NodeId :: nodeId()) -> pubsubNode() | - {error, xmlel()}. + {error, fxml:xmlel()}. -callback get_node(NodeIdx :: nodeIdx()) -> pubsubNode() | - {error, xmlel()}. + {error, fxml:xmlel()}. -callback get_nodes(Host :: host(), - From :: jid())-> + From :: jid:jid())-> [pubsubNode()]. -callback get_nodes(Host :: host())-> @@ -68,33 +67,33 @@ -callback get_parentnodes(Host :: host(), NodeId :: nodeId(), - From :: jid()) -> + From :: jid:jid()) -> [pubsubNode()] | - {error, xmlel()}. + {error, fxml:xmlel()}. -callback get_parentnodes_tree(Host :: host(), NodeId :: nodeId(), - From :: jid()) -> + From :: jid:jid()) -> [{0, [pubsubNode(),...]}]. -callback get_subnodes(Host :: host(), NodeId :: nodeId(), - From :: jid()) -> + From :: jid:jid()) -> [pubsubNode()]. -callback get_subnodes_tree(Host :: host(), NodeId :: nodeId(), - From :: jid()) -> + From :: jid:jid()) -> [pubsubNode()]. -callback create_node(Host :: host(), NodeId :: nodeId(), Type :: binary(), - Owner :: jid(), + Owner :: jid:jid(), Options :: nodeOptions(), Parents :: [nodeId()]) -> {ok, NodeIdx::nodeIdx()} | - {error, xmlel()} | + {error, fxml:xmlel()} | {error, {virtual, {host(), nodeId()}}}. -callback delete_node(Host :: host(), diff --git a/src/mod_http_bind.erl b/src/mod_http_bind.erl index 9a3a379f7..471b38c00 100644 --- a/src/mod_http_bind.erl +++ b/src/mod_http_bind.erl @@ -42,7 +42,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("ejabberd_http.hrl"). diff --git a/src/node_buddy.erl b/src/node_buddy.erl index bdaa4a89a..fb2fd1f2e 100644 --- a/src/node_buddy.erl +++ b/src/node_buddy.erl @@ -28,7 +28,6 @@ -author('christophe.romain@process-one.net'). -include("pubsub.hrl"). --include("jlib.hrl"). -export([init/3, terminate/2, options/0, features/0, create_node_permission/6, create_node/2, delete_node/1, diff --git a/src/node_club.erl b/src/node_club.erl index 7f6ae6520..837fa6fbb 100644 --- a/src/node_club.erl +++ b/src/node_club.erl @@ -28,7 +28,6 @@ -author('christophe.romain@process-one.net'). -include("pubsub.hrl"). --include("jlib.hrl"). -export([init/3, terminate/2, options/0, features/0, create_node_permission/6, create_node/2, delete_node/1, diff --git a/src/node_hometree.erl b/src/node_hometree.erl index def7b983d..67c5e9332 100644 --- a/src/node_hometree.erl +++ b/src/node_hometree.erl @@ -28,7 +28,6 @@ -author('christophe.romain@process-one.net'). -include("pubsub.hrl"). --include("jlib.hrl"). -export([init/3, terminate/2, options/0, features/0, create_node_permission/6, create_node/2, delete_node/1, diff --git a/src/node_hometree_sql.erl b/src/node_hometree_sql.erl index d9af49843..661a2aab4 100644 --- a/src/node_hometree_sql.erl +++ b/src/node_hometree_sql.erl @@ -28,7 +28,6 @@ -author('christophe.romain@process-one.net'). -include("pubsub.hrl"). --include("jlib.hrl"). -export([init/3, terminate/2, options/0, features/0, create_node_permission/6, create_node/2, delete_node/1, diff --git a/src/node_mb.erl b/src/node_mb.erl index 6c7f09780..0c3bd3722 100644 --- a/src/node_mb.erl +++ b/src/node_mb.erl @@ -28,7 +28,6 @@ -author('ecestari@process-one.net'). -include("pubsub.hrl"). --include("jlib.hrl"). %%% @doc The module {@module} is the pep microblog PubSub plugin. %%%

To be used, mod_pubsub must be configured:

diff --git a/src/node_online.erl b/src/node_online.erl
index 1c2ab5a03..4b01d2a2c 100644
--- a/src/node_online.erl
+++ b/src/node_online.erl
@@ -28,7 +28,7 @@
 -author('christophe.romain@process-one.net').
 
 -include("pubsub.hrl").
--include("jlib.hrl").
+-include("jid.hrl").
 
 -export([init/3, terminate/2, options/0, features/0,
     create_node_permission/6, create_node/2, delete_node/1,
diff --git a/src/node_pep.erl b/src/node_pep.erl
index 1677ed4bd..f3b5836cf 100644
--- a/src/node_pep.erl
+++ b/src/node_pep.erl
@@ -31,7 +31,6 @@
 -author('christophe.romain@process-one.net').
 
 -include("pubsub.hrl").
--include("jlib.hrl").
 -include("logger.hrl").
 
 -export([init/3, terminate/2, options/0, features/0,
diff --git a/src/node_pep_sql.erl b/src/node_pep_sql.erl
index ec7795475..ac42cb94f 100644
--- a/src/node_pep_sql.erl
+++ b/src/node_pep_sql.erl
@@ -31,7 +31,6 @@
 -author('christophe.romain@process-one.net').
 
 -include("pubsub.hrl").
--include("jlib.hrl").
 -include("logger.hrl").
 
 -export([init/3, terminate/2, options/0, features/0,
diff --git a/src/node_private.erl b/src/node_private.erl
index 0cd04b9dd..1888ce33d 100644
--- a/src/node_private.erl
+++ b/src/node_private.erl
@@ -28,7 +28,6 @@
 -author('christophe.romain@process-one.net').
 
 -include("pubsub.hrl").
--include("jlib.hrl").
 
 -export([init/3, terminate/2, options/0, features/0,
     create_node_permission/6, create_node/2, delete_node/1,
diff --git a/src/node_public.erl b/src/node_public.erl
index 0786d9995..ca200e002 100644
--- a/src/node_public.erl
+++ b/src/node_public.erl
@@ -28,7 +28,6 @@
 -author('christophe.romain@process-one.net').
 
 -include("pubsub.hrl").
--include("jlib.hrl").
 
 -export([init/3, terminate/2, options/0, features/0,
     create_node_permission/6, create_node/2, delete_node/1,
diff --git a/src/nodetree_virtual.erl b/src/nodetree_virtual.erl
index 934950dd2..31802db2b 100644
--- a/src/nodetree_virtual.erl
+++ b/src/nodetree_virtual.erl
@@ -35,7 +35,6 @@
 -author('christophe.romain@process-one.net').
 
 -include("pubsub.hrl").
--include("jlib.hrl").
 
 -export([init/3, terminate/2, options/0, set_node/1,
     get_node/3, get_node/2, get_node/1, get_nodes/2,

From eb1d385d4e00b33bf327a3ff25f9c0f71c98a96b Mon Sep 17 00:00:00 2001
From: Evgeniy Khramtsov 
Date: Sat, 30 Jul 2016 18:42:17 +0300
Subject: [PATCH 021/151] Get rid of "jlib.hrl" dependency in mod_service_log

---
 src/mod_service_log.erl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/mod_service_log.erl b/src/mod_service_log.erl
index 8f11b0ead..a88b04b58 100644
--- a/src/mod_service_log.erl
+++ b/src/mod_service_log.erl
@@ -35,7 +35,7 @@
 -include("ejabberd.hrl").
 -include("logger.hrl").
 
--include("jlib.hrl").
+-include("xmpp.hrl").
 
 start(Host, _Opts) ->
     ejabberd_hooks:add(user_send_packet, Host, ?MODULE,

From 0bcbd12776a03902f356c3ac48465cc901670393 Mon Sep 17 00:00:00 2001
From: Evgeniy Khramtsov 
Date: Sun, 31 Jul 2016 08:51:47 +0300
Subject: [PATCH 022/151] Rewrite mod_mix to use XML generator

---
 include/xmpp_codec.hrl | 104 ++++----
 src/mod_mix.erl        | 116 +++-----
 src/mod_muc_room.erl   |   3 +-
 src/xmpp.erl           |  20 +-
 src/xmpp_codec.erl     | 591 +++++++++++++++++++----------------------
 tools/xmpp_codec.spec  |  24 +-
 6 files changed, 383 insertions(+), 475 deletions(-)

diff --git a/include/xmpp_codec.hrl b/include/xmpp_codec.hrl
index caabb101d..acbc81e4a 100644
--- a/include/xmpp_codec.hrl
+++ b/include/xmpp_codec.hrl
@@ -15,6 +15,14 @@
 		       'no-permanent-store' | 'no-permanent-storage'}).
 -type hint() :: #hint{}.
 
+-record(iq, {id :: binary(),
+             type :: 'error' | 'get' | 'result' | 'set',
+             lang :: binary(),
+             from :: any(),
+             to :: any(),
+             sub_els = [] :: [any()]}).
+-type iq() :: #iq{}.
+
 -record(feature_register, {}).
 -type feature_register() :: #feature_register{}.
 
@@ -170,6 +178,14 @@
 -record(private, {xml_els = [] :: [any()]}).
 -type private() :: #private{}.
 
+-record(db_verify, {from :: any(),
+                    to :: any(),
+                    id :: binary(),
+                    type :: 'error' | 'invalid' | 'valid',
+                    key = <<>> :: binary(),
+                    sub_els = [] :: [any()]}).
+-type db_verify() :: #db_verify{}.
+
 -record(nick, {name :: binary()}).
 -type nick() :: #nick{}.
 
@@ -267,6 +283,17 @@
                            jid :: any()}).
 -type pubsub_subscribe() :: #pubsub_subscribe{}.
 
+-record(message, {id :: binary(),
+                  type = normal :: 'chat' | 'error' | 'groupchat' | 'headline' | 'normal',
+                  lang :: binary(),
+                  from :: any(),
+                  to :: any(),
+                  subject = [] :: [#text{}],
+                  body = [] :: [#text{}],
+                  thread :: binary(),
+                  sub_els = [] :: [any()]}).
+-type message() :: #message{}.
+
 -record(sasl_auth, {mechanism :: binary(),
                     text :: any()}).
 -type sasl_auth() :: #sasl_auth{}.
@@ -349,6 +376,17 @@
                        items = [] :: [#pubsub_item{}]}).
 -type pubsub_items() :: #pubsub_items{}.
 
+-record(presence, {id :: binary(),
+                   type = available :: 'available' | 'error' | 'probe' | 'subscribe' | 'subscribed' | 'unavailable' | 'unsubscribe' | 'unsubscribed',
+                   lang :: binary(),
+                   from :: any(),
+                   to :: any(),
+                   show :: 'away' | 'chat' | 'dnd' | 'xa',
+                   status = [] :: [#text{}],
+                   priority :: integer(),
+                   sub_els = [] :: [any()]}).
+-type presence() :: #presence{}.
+
 -record(sic, {ip :: any(),
               port :: non_neg_integer(),
               xmlns :: binary()}).
@@ -385,6 +423,13 @@
                       userid :: binary()}).
 -type vcard_email() :: #vcard_email{}.
 
+-record(db_result, {from :: any(),
+                    to :: any(),
+                    type :: 'error' | 'invalid' | 'valid',
+                    key = <<>> :: binary(),
+                    sub_els = [] :: [any()]}).
+-type db_result() :: #db_result{}.
+
 -record(carbons_received, {forwarded :: #forwarded{}}).
 -type carbons_received() :: #carbons_received{}.
 
@@ -729,57 +774,10 @@
                 code :: non_neg_integer(),
                 by :: binary(),
                 reason :: atom() | #gone{} | #redirect{},
-                text :: #text{}}).
+                text :: #text{},
+                sub_els = [] :: [any()]}).
 -type error() :: #error{}.
 
--record(db_verify, {from :: any(),
-                    to :: any(),
-                    id :: binary(),
-                    type :: 'error' | 'invalid' | 'valid',
-                    key = <<>> :: binary(),
-                    error :: #error{}}).
--type db_verify() :: #db_verify{}.
-
--record(db_result, {from :: any(),
-                    to :: any(),
-                    type :: 'error' | 'invalid' | 'valid',
-                    key = <<>> :: binary(),
-                    error :: #error{}}).
--type db_result() :: #db_result{}.
-
--record(presence, {id :: binary(),
-                   type = available :: 'available' | 'error' | 'probe' | 'subscribe' | 'subscribed' | 'unavailable' | 'unsubscribe' | 'unsubscribed',
-                   lang :: binary(),
-                   from :: any(),
-                   to :: any(),
-                   show :: 'away' | 'chat' | 'dnd' | 'xa',
-                   status = [] :: [#text{}],
-                   priority :: integer(),
-                   error :: #error{},
-                   sub_els = [] :: [any()]}).
--type presence() :: #presence{}.
-
--record(message, {id :: binary(),
-                  type = normal :: 'chat' | 'error' | 'groupchat' | 'headline' | 'normal',
-                  lang :: binary(),
-                  from :: any(),
-                  to :: any(),
-                  subject = [] :: [#text{}],
-                  body = [] :: [#text{}],
-                  thread :: binary(),
-                  error :: #error{},
-                  sub_els = [] :: [any()]}).
--type message() :: #message{}.
-
--record(iq, {id :: binary(),
-             type :: 'error' | 'get' | 'result' | 'set',
-             lang :: binary(),
-             from :: any(),
-             to :: any(),
-             error :: #error{},
-             sub_els = [] :: [any()]}).
--type iq() :: #iq{}.
-
 -record(mix_join, {jid :: any(),
                    subscribe = [] :: [binary()]}).
 -type mix_join() :: #mix_join{}.
@@ -861,6 +859,7 @@
                         mam_archived() |
                         p1_rebind() |
                         sasl_abort() |
+                        db_result() |
                         carbons_received() |
                         pubsub_retract() |
                         upload_slot() |
@@ -868,7 +867,6 @@
                         compressed() |
                         block_list() |
                         rsm_set() |
-                        db_result() |
                         'see-other-host'() |
                         hint() |
                         stream_start() |
@@ -939,8 +937,8 @@
                         mix_join() |
                         xmpp_session() |
                         xdata() |
-                        xcaptcha() |
                         iq() |
+                        xcaptcha() |
                         streamhost() |
                         bind() |
                         last() |
@@ -971,9 +969,9 @@
                         muc_destroy() |
                         vcard_key() |
                         csi() |
+                        db_verify() |
                         roster_query() |
                         mam_query() |
-                        db_verify() |
                         bookmark_url() |
                         vcard_email() |
                         vcard_label() |
@@ -992,8 +990,8 @@
                         muc_unique() |
                         sasl_response() |
                         pubsub_subscribe() |
-                        presence() |
                         message() |
+                        presence() |
                         gone() |
                         sm_resume() |
                         carbons_enable() |
diff --git a/src/mod_mix.erl b/src/mod_mix.erl
index b373ad13d..3ba173b9f 100644
--- a/src/mod_mix.erl
+++ b/src/mod_mix.erl
@@ -12,7 +12,7 @@
 -behaviour(gen_mod).
 
 %% API
--export([start_link/2, start/2, stop/1, process_iq/3,
+-export([start_link/2, start/2, stop/1, process_iq/1,
 	 disco_items/5, disco_identity/5, disco_info/5,
 	 disco_features/5, mod_opt_type/1, depends/2]).
 
@@ -21,8 +21,7 @@
 	 terminate/2, code_change/3]).
 
 -include("logger.hrl").
--include("jlib.hrl").
--include("pubsub.hrl").
+-include("xmpp.hrl").
 
 -define(PROCNAME, ejabberd_mod_mix).
 -define(NODES, [?NS_MIX_NODES_MESSAGES,
@@ -57,84 +56,59 @@ disco_features(_Acc, _From, _To, _Node, _Lang) ->
     {result, [?NS_MIX_0]}.
 
 disco_items(_Acc, _From, To, _Node, _Lang) when To#jid.luser /= <<"">> ->
-    To_s = jid:to_string(jid:remove_resource(To)),
-    {result, [#xmlel{name = <<"item">>,
-		     attrs = [{<<"jid">>, To_s},
-			      {<<"node">>, Node}]} || Node <- ?NODES]};
+    BareTo = jid:remove_resource(To),
+    {result, [#disco_item{jid = BareTo, node = Node} || Node <- ?NODES]};
 disco_items(_Acc, _From, _To, _Node, _Lang) ->
     {result, []}.
 
 disco_identity(Acc, _From, To, _Node, _Lang) when To#jid.luser == <<"">> ->
-    Acc ++ [#xmlel{name = <<"identity">>,
-		   attrs =
-		       [{<<"category">>, <<"conference">>},
-			{<<"name">>, <<"MIX service">>},
-			{<<"type">>, <<"text">>}]}];
+    Acc ++ [#identity{category = <<"conference">>,
+		      name = <<"MIX service">>,
+		      type = <<"text">>}];
 disco_identity(Acc, _From, _To, _Node, _Lang) ->
-    Acc ++ [#xmlel{name = <<"identity">>,
-		   attrs =
-		       [{<<"category">>, <<"conference">>},
-			{<<"type">>, <<"mix">>}]}].
+    Acc ++ [#identity{category = <<"conference">>,
+		      type = <<"mix">>}].
 
 disco_info(_Acc, _From, To, _Node, _Lang) when is_atom(To) ->
-    [#xmlel{name = <<"x">>,
-	    attrs = [{<<"xmlns">>, ?NS_XDATA},
-		     {<<"type">>, <<"result">>}],
-	    children = [#xmlel{name = <<"field">>,
-			       attrs = [{<<"var">>, <<"FORM_TYPE">>},
-					{<<"type">>, <<"hidden">>}],
-			       children = [#xmlel{name = <<"value">>,
-						  children = [{xmlcdata,
-							       ?NS_MIX_SERVICEINFO_0}]}]}]}];
+    [#xdata{type = result,
+	    fields = [#xdata_field{var = <<"FORM_TYPE">>,
+				   type = hidden,
+				   values = [?NS_MIX_SERVICEINFO_0]}]}];
 disco_info(Acc, _From, _To, _Node, _Lang) ->
     Acc.
 
-process_iq(From, To,
-	   #iq{type = set, sub_el = #xmlel{name = <<"join">>} = SubEl} = IQ) ->
-    Nodes = lists:flatmap(
-	      fun(#xmlel{name = <<"subscribe">>, attrs = Attrs}) ->
-		      Node = fxml:get_attr_s(<<"node">>, Attrs),
-		      case lists:member(Node, ?NODES) of
-			  true -> [Node];
-			  false -> []
-		      end;
-		 (_) ->
-		      []
-	      end, SubEl#xmlel.children),
+process_iq(#iq{type = set, from = From, to = To,
+	       sub_els = [#mix_join{subscribe = SubNodes}]} = IQ) ->
+    Nodes = [Node || Node <- SubNodes, lists:member(Node, ?NODES)],
     case subscribe_nodes(From, To, Nodes) of
 	{result, _} ->
 	    case publish_participant(From, To) of
 		{result, _} ->
-		    LFrom_s = jid:to_string(jid:tolower(jid:remove_resource(From))),
-		    Subscribe = [#xmlel{name = <<"subscribe">>,
-					attrs = [{<<"node">>, Node}]} || Node <- Nodes],
-		    IQ#iq{type = result,
-			  sub_el = [#xmlel{name = <<"join">>,
-					   attrs = [{<<"jid">>, LFrom_s},
-						    {<<"xmlns">>, ?NS_MIX_0}],
-					   children = Subscribe}]};
+		    BareFrom = jid:remove_resource(From),
+		    xmpp:make_iq_result(
+		      IQ, #mix_join{jid = BareFrom, subscribe = Nodes});
 		{error, Err} ->
-		    IQ#iq{type = error, sub_el = [SubEl, Err]}
+		    xmpp:make_error(IQ, Err)
 	    end;
 	{error, Err} ->
-	    IQ#iq{type = error, sub_el = [SubEl, Err]}
+	    xmpp:make_error(IQ, Err)
     end;
-process_iq(From, To,
-	   #iq{type = set, sub_el = #xmlel{name = <<"leave">>} = SubEl} = IQ) ->
+process_iq(#iq{type = set, from = From, to = To,
+	       sub_els = [#mix_leave{}]} = IQ) ->
     case delete_participant(From, To) of
 	{result, _} ->
 	    case unsubscribe_nodes(From, To, ?NODES) of
 		{result, _} ->
-		    IQ#iq{type = result, sub_el = []};
+		    xmpp:make_iq_result(IQ);
 		{error, Err} ->
-		    IQ#iq{type = error, sub_el = [SubEl, Err]}
+		    xmpp:make_error(IQ, Err)
 	    end;
 	{error, Err} ->
-	    IQ#iq{type = error, sub_el = [SubEl, Err]}
+	    xmpp:make_error(IQ, Err)
     end;
-process_iq(_From, _To, #iq{sub_el = SubEl, lang = Lang} = IQ) ->
+process_iq(#iq{lang = Lang} = IQ) ->
     Txt = <<"Unsupported MIX query">>,
-    IQ#iq{type = error, sub_el = [SubEl, ?ERRT_BAD_REQUEST(Lang, Txt)]}.
+    xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)).
 
 %%%===================================================================
 %%% gen_server callbacks
@@ -185,8 +159,8 @@ handle_info({route, From, To, Packet}, State) ->
 	    try
 		?ERROR_MSG("failed to route packet ~p from '~s' to '~s': ~p",
 			   [Packet, jid:to_string(From), jid:to_string(To), Err]),
-		ErrPkt = jlib:make_error_reply(Packet, ?ERR_INTERNAL_SERVER_ERROR),
-		ejabberd_router:route_error(To, From, ErrPkt, Packet)
+		Error = xmpp:err_internal_server_error(),
+		ejabberd_router:route_error(To, From, Packet, Error)
 	    catch _:_ ->
 		    ok
 	    end;
@@ -220,20 +194,11 @@ code_change(_OldVsn, State, _Extra) ->
 %%%===================================================================
 %%% Internal functions
 %%%===================================================================
-do_route(_State, From, To, #xmlel{name = <<"iq">>} = Packet) ->
-    if To#jid.luser == <<"">> ->
-	    ejabberd_local:process_iq(From, To, Packet);
-       true ->
-	    ejabberd_sm:process_iq(From, To, Packet)
-    end;
-do_route(_State, From, To, #xmlel{name = <<"presence">>} = Packet)
+do_route(_State, From, To, #iq{} = Packet) ->
+    ejabberd_router:process_iq(From, To, Packet);
+do_route(_State, From, To, #presence{type = unavailable})
   when To#jid.luser /= <<"">> ->
-    case fxml:get_tag_attr_s(<<"type">>, Packet) of
-	<<"unavailable">> ->
-	    delete_presence(From, To);
-	_ ->
-	    ok
-    end;
+    delete_presence(From, To);
 do_route(_State, _From, _To, _Packet) ->
     ok.
 
@@ -284,15 +249,14 @@ unsubscribe_nodes(From, To, Nodes) ->
       end, {result, []}, Nodes).
 
 publish_participant(From, To) ->
-    LFrom = jid:tolower(jid:remove_resource(From)),
+    BareFrom = jid:remove_resource(From),
+    LFrom = jid:tolower(BareFrom),
     LTo = jid:tolower(jid:remove_resource(To)),
-    Participant = #xmlel{name = <<"participant">>,
-			 attrs = [{<<"xmlns">>, ?NS_MIX_0},
-				  {<<"jid">>, jid:to_string(LFrom)}]},
+    Participant = #mix_participant{jid = BareFrom},
     ItemID = p1_sha:sha(jid:to_string(LFrom)),
     mod_pubsub:publish_item(
       LTo, To#jid.lserver, ?NS_MIX_NODES_PARTICIPANTS,
-      From, ItemID, [Participant]).
+      From, ItemID, [xmpp:encode(Participant)]).
 
 delete_presence(From, To) ->
     LFrom = jid:tolower(From),
@@ -300,8 +264,8 @@ delete_presence(From, To) ->
     case mod_pubsub:get_items(LTo, ?NS_MIX_NODES_PRESENCE) of
 	Items when is_list(Items) ->
 	    lists:foreach(
-	      fun(#pubsub_item{modification = {_, LJID},
-			       itemid = {ItemID, _}}) when LJID == LFrom ->
+	      fun({pubsub_item, {ItemID, _}, _, {_, LJID}, _})
+		    when LJID == LFrom ->
 		      delete_item(From, To, ?NS_MIX_NODES_PRESENCE, ItemID);
 		 (_) ->
 		      ok
diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl
index a539ab848..68064fcb7 100644
--- a/src/mod_muc_room.erl
+++ b/src/mod_muc_room.erl
@@ -1110,8 +1110,9 @@ change_stanzaid(ToJID, #iq{id = PreviousId} = Packet) ->
 -spec decide_fate_message(message(), jid(), state()) ->
 				 continue_delivery | forget_message |
 				 {expulse_sender, binary()}.
-decide_fate_message(#message{type = error, error = Err},
+decide_fate_message(#message{type = error} = Msg,
 		    From, StateData) ->
+    Err = xmpp:get_error(Msg),
     PD = case check_error_kick(Err) of
 	   %% If this is an error stanza and its condition matches a criteria
 	   true ->
diff --git a/src/xmpp.erl b/src/xmpp.erl
index 6e8145190..a927a6a9a 100644
--- a/src/xmpp.erl
+++ b/src/xmpp.erl
@@ -88,10 +88,10 @@ make_iq_result(#iq{type = Type, from = From, to = To} = IQ, El)
 	     end,
     IQ#iq{type = result, to = From, from = To, sub_els = SubEls}.
 
--spec make_error(message(), error()) -> message();
-		(presence(), error()) -> presence();
-		(iq(), error()) -> iq();
-		(xmlel(), error()) -> xmlel().
+-spec make_error(message(), error() | xmlel()) -> message();
+		(presence(), error() | xmlel()) -> presence();
+		(iq(), error() | xmlel()) -> iq();
+		(xmlel(), error() | xmlel()) -> xmlel().
 make_error(#message{type = Type, from = From, to = To, sub_els = Els} = Msg,
 	   Err) when Type /= error ->
     Msg#message{type = error, from = To, to = From, sub_els = Els ++ [Err]};
@@ -159,9 +159,11 @@ get_to(#message{to = J}) -> J;
 get_to(#presence{to = J}) -> J.
 
 -spec get_error(iq() | message() | presence()) -> undefined | error().
-get_error(#iq{error = E}) -> E;
-get_error(#message{error = E}) -> E;
-get_error(#presence{error = E}) -> E.
+get_error(Stanza) ->
+    case get_subtag(Stanza, #error{}) of
+	false -> undefined;
+	Error -> Error
+    end.
 
 -spec get_els(iq() | message() | presence()) -> [xmpp_element() | xmlel()];
 	     (xmlel()) -> [xmlel()].
@@ -215,9 +217,7 @@ set_from_to(#presence{} = Pres, F, T) -> Pres#presence{from = F, to = T}.
 -spec set_error(iq(), error()) -> iq();
 	       (message(), error()) -> message();
 	       (presence(), error()) -> presence().
-set_error(#iq{} = IQ, E) -> IQ#iq{error = E};
-set_error(#message{} = Msg, E) -> Msg#message{error = E};
-set_error(#presence{} = Pres, E) -> Pres#presence{error = E}.
+set_error(Stanza, E) -> set_subtag(Stanza, E).
 
 -spec set_els(iq(), [xmpp_element() | xmlel()]) -> iq();
 	     (message(), [xmpp_element() | xmlel()]) -> message();
diff --git a/src/xmpp_codec.erl b/src/xmpp_codec.erl
index 8d87712df..6fddf97ed 100644
--- a/src/xmpp_codec.erl
+++ b/src/xmpp_codec.erl
@@ -2230,13 +2230,13 @@ encode({stats, _} = Query) ->
     encode_stats(Query,
 		 [{<<"xmlns">>,
 		   <<"http://jabber.org/protocol/stats">>}]);
-encode({iq, _, _, _, _, _, _, _} = Iq) ->
+encode({iq, _, _, _, _, _, _} = Iq) ->
     encode_iq(Iq, [{<<"xmlns">>, <<"jabber:client">>}]);
-encode({message, _, _, _, _, _, _, _, _, _, _} =
+encode({message, _, _, _, _, _, _, _, _, _} =
 	   Message) ->
     encode_message(Message,
 		   [{<<"xmlns">>, <<"jabber:client">>}]);
-encode({presence, _, _, _, _, _, _, _, _, _, _} =
+encode({presence, _, _, _, _, _, _, _, _, _} =
 	   Presence) ->
     encode_presence(Presence,
 		    [{<<"xmlns">>, <<"jabber:client">>}]);
@@ -2248,7 +2248,7 @@ encode({redirect, _} = Redirect) ->
     encode_error_redirect(Redirect,
 			  [{<<"xmlns">>,
 			    <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]);
-encode({error, _, _, _, _, _} = Error) ->
+encode({error, _, _, _, _, _, _} = Error) ->
     encode_error(Error,
 		 [{<<"xmlns">>, <<"jabber:client">>}]);
 encode({bind, _, _} = Bind) ->
@@ -2736,14 +2736,14 @@ get_name({bookmark_url, _, _}) -> <<"url">>;
 get_name({bookmark_storage, _, _}) -> <<"storage">>;
 get_name({stat, _, _, _, _}) -> <<"stat">>;
 get_name({stats, _}) -> <<"query">>;
-get_name({iq, _, _, _, _, _, _, _}) -> <<"iq">>;
-get_name({message, _, _, _, _, _, _, _, _, _, _}) ->
+get_name({iq, _, _, _, _, _, _}) -> <<"iq">>;
+get_name({message, _, _, _, _, _, _, _, _, _}) ->
     <<"message">>;
-get_name({presence, _, _, _, _, _, _, _, _, _, _}) ->
+get_name({presence, _, _, _, _, _, _, _, _, _}) ->
     <<"presence">>;
 get_name({gone, _}) -> <<"gone">>;
 get_name({redirect, _}) -> <<"redirect">>;
-get_name({error, _, _, _, _, _}) -> <<"error">>;
+get_name({error, _, _, _, _, _, _}) -> <<"error">>;
 get_name({bind, _, _}) -> <<"bind">>;
 get_name({legacy_auth, _, _, _, _}) -> <<"query">>;
 get_name({sasl_auth, _, _}) -> <<"auth">>;
@@ -2943,17 +2943,17 @@ get_ns({stat, _, _, _, _}) ->
     <<"http://jabber.org/protocol/stats">>;
 get_ns({stats, _}) ->
     <<"http://jabber.org/protocol/stats">>;
-get_ns({iq, _, _, _, _, _, _, _}) ->
+get_ns({iq, _, _, _, _, _, _}) -> <<"jabber:client">>;
+get_ns({message, _, _, _, _, _, _, _, _, _}) ->
     <<"jabber:client">>;
-get_ns({message, _, _, _, _, _, _, _, _, _, _}) ->
-    <<"jabber:client">>;
-get_ns({presence, _, _, _, _, _, _, _, _, _, _}) ->
+get_ns({presence, _, _, _, _, _, _, _, _, _}) ->
     <<"jabber:client">>;
 get_ns({gone, _}) ->
     <<"urn:ietf:params:xml:ns:xmpp-stanzas">>;
 get_ns({redirect, _}) ->
     <<"urn:ietf:params:xml:ns:xmpp-stanzas">>;
-get_ns({error, _, _, _, _, _}) -> <<"jabber:client">>;
+get_ns({error, _, _, _, _, _, _}) ->
+    <<"jabber:client">>;
 get_ns({bind, _, _}) ->
     <<"urn:ietf:params:xml:ns:xmpp-bind">>;
 get_ns({legacy_auth, _, _, _, _}) ->
@@ -3256,16 +3256,16 @@ pp(bookmark_url, 2) -> [name, url];
 pp(bookmark_storage, 2) -> [conference, url];
 pp(stat, 4) -> [name, units, value, error];
 pp(stats, 1) -> [stat];
-pp(iq, 7) -> [id, type, lang, from, to, error, sub_els];
-pp(message, 10) ->
-    [id, type, lang, from, to, subject, body, thread, error,
+pp(iq, 6) -> [id, type, lang, from, to, sub_els];
+pp(message, 9) ->
+    [id, type, lang, from, to, subject, body, thread,
      sub_els];
-pp(presence, 10) ->
+pp(presence, 9) ->
     [id, type, lang, from, to, show, status, priority,
-     error, sub_els];
+     sub_els];
 pp(gone, 1) -> [uri];
 pp(redirect, 1) -> [uri];
-pp(error, 5) -> [type, code, by, reason, text];
+pp(error, 6) -> [type, code, by, reason, text, sub_els];
 pp(bind, 2) -> [jid, resource];
 pp(legacy_auth, 4) ->
     [username, password, digest, resource];
@@ -3419,8 +3419,8 @@ pp(adhoc_note, 2) -> [type, data];
 pp(adhoc_command, 8) ->
     [node, action, sid, status, lang, actions, notes,
      xdata];
-pp(db_result, 5) -> [from, to, type, key, error];
-pp(db_verify, 6) -> [from, to, id, type, key, error];
+pp(db_result, 5) -> [from, to, type, key, sub_els];
+pp(db_verify, 6) -> [from, to, id, type, key, sub_els];
 pp(handshake, 1) -> [data];
 pp(stream_start, 8) ->
     [from, to, id, version, xmlns, stream_xmlns, db_xmlns,
@@ -4789,39 +4789,36 @@ encode_handshake_cdata(_val, _acc) ->
 
 decode_db_verify(__TopXMLNS, __IgnoreEls,
 		 {xmlel, <<"db:verify">>, _attrs, _els}) ->
-    {Key, Error} = decode_db_verify_els(__TopXMLNS,
-					__IgnoreEls, _els, <<>>, undefined),
+    {Key, __Els} = decode_db_verify_els(__TopXMLNS,
+					__IgnoreEls, _els, <<>>, []),
     {From, To, Id, Type} =
 	decode_db_verify_attrs(__TopXMLNS, _attrs, undefined,
 			       undefined, undefined, undefined),
-    {db_verify, From, To, Id, Type, Key, Error}.
+    {db_verify, From, To, Id, Type, Key, __Els}.
 
 decode_db_verify_els(__TopXMLNS, __IgnoreEls, [], Key,
-		     Error) ->
-    {decode_db_verify_cdata(__TopXMLNS, Key), Error};
+		     __Els) ->
+    {decode_db_verify_cdata(__TopXMLNS, Key),
+     lists:reverse(__Els)};
 decode_db_verify_els(__TopXMLNS, __IgnoreEls,
-		     [{xmlcdata, _data} | _els], Key, Error) ->
+		     [{xmlcdata, _data} | _els], Key, __Els) ->
     decode_db_verify_els(__TopXMLNS, __IgnoreEls, _els,
-			 <>, Error);
+			 <>, __Els);
 decode_db_verify_els(__TopXMLNS, __IgnoreEls,
-		     [{xmlel, <<"error">>, _attrs, _} = _el | _els], Key,
-		     Error) ->
-    case get_attr(<<"xmlns">>, _attrs) of
-      <<"">> when __TopXMLNS == <<"jabber:client">> ->
-	  decode_db_verify_els(__TopXMLNS, __IgnoreEls, _els, Key,
-			       decode_error(__TopXMLNS, __IgnoreEls, _el));
-      <<"jabber:client">> ->
-	  decode_db_verify_els(__TopXMLNS, __IgnoreEls, _els, Key,
-			       decode_error(<<"jabber:client">>, __IgnoreEls,
-					    _el));
-      _ ->
-	  decode_db_verify_els(__TopXMLNS, __IgnoreEls, _els, Key,
-			       Error)
-    end;
-decode_db_verify_els(__TopXMLNS, __IgnoreEls,
-		     [_ | _els], Key, Error) ->
-    decode_db_verify_els(__TopXMLNS, __IgnoreEls, _els, Key,
-			 Error).
+		     [{xmlel, _, _, _} = _el | _els], Key, __Els) ->
+    if __IgnoreEls ->
+	   decode_db_verify_els(__TopXMLNS, __IgnoreEls, _els, Key,
+				[_el | __Els]);
+       true ->
+	   case is_known_tag(_el) of
+	     true ->
+		 decode_db_verify_els(__TopXMLNS, __IgnoreEls, _els, Key,
+				      [decode(_el) | __Els]);
+	     false ->
+		 decode_db_verify_els(__TopXMLNS, __IgnoreEls, _els, Key,
+				      __Els)
+	   end
+    end.
 
 decode_db_verify_attrs(__TopXMLNS,
 		       [{<<"from">>, _val} | _attrs], _From, To, Id, Type) ->
@@ -4851,11 +4848,10 @@ decode_db_verify_attrs(__TopXMLNS, [], From, To, Id,
      decode_db_verify_attr_type(__TopXMLNS, Type)}.
 
 encode_db_verify({db_verify, From, To, Id, Type, Key,
-		  Error},
+		  __Els},
 		 _xmlns_attrs) ->
-    _els = lists:reverse(encode_db_verify_cdata(Key,
-						'encode_db_verify_$error'(Error,
-									  []))),
+    _els = [encode(_el) || _el <- __Els] ++
+	     encode_db_verify_cdata(Key, []),
     _attrs = encode_db_verify_attr_type(Type,
 					encode_db_verify_attr_id(Id,
 								 encode_db_verify_attr_to(To,
@@ -4863,10 +4859,6 @@ encode_db_verify({db_verify, From, To, Id, Type, Key,
 														     _xmlns_attrs)))),
     {xmlel, <<"db:verify">>, _attrs, _els}.
 
-'encode_db_verify_$error'(undefined, _acc) -> _acc;
-'encode_db_verify_$error'(Error, _acc) ->
-    [encode_error(Error, []) | _acc].
-
 decode_db_verify_attr_from(__TopXMLNS, undefined) ->
     erlang:error({xmpp_codec,
 		  {missing_attr, <<"from">>, <<"db:verify">>,
@@ -4930,39 +4922,36 @@ encode_db_verify_cdata(_val, _acc) ->
 
 decode_db_result(__TopXMLNS, __IgnoreEls,
 		 {xmlel, <<"db:result">>, _attrs, _els}) ->
-    {Key, Error} = decode_db_result_els(__TopXMLNS,
-					__IgnoreEls, _els, <<>>, undefined),
+    {Key, __Els} = decode_db_result_els(__TopXMLNS,
+					__IgnoreEls, _els, <<>>, []),
     {From, To, Type} = decode_db_result_attrs(__TopXMLNS,
 					      _attrs, undefined, undefined,
 					      undefined),
-    {db_result, From, To, Type, Key, Error}.
+    {db_result, From, To, Type, Key, __Els}.
 
 decode_db_result_els(__TopXMLNS, __IgnoreEls, [], Key,
-		     Error) ->
-    {decode_db_result_cdata(__TopXMLNS, Key), Error};
+		     __Els) ->
+    {decode_db_result_cdata(__TopXMLNS, Key),
+     lists:reverse(__Els)};
 decode_db_result_els(__TopXMLNS, __IgnoreEls,
-		     [{xmlcdata, _data} | _els], Key, Error) ->
+		     [{xmlcdata, _data} | _els], Key, __Els) ->
     decode_db_result_els(__TopXMLNS, __IgnoreEls, _els,
-			 <>, Error);
+			 <>, __Els);
 decode_db_result_els(__TopXMLNS, __IgnoreEls,
-		     [{xmlel, <<"error">>, _attrs, _} = _el | _els], Key,
-		     Error) ->
-    case get_attr(<<"xmlns">>, _attrs) of
-      <<"">> when __TopXMLNS == <<"jabber:client">> ->
-	  decode_db_result_els(__TopXMLNS, __IgnoreEls, _els, Key,
-			       decode_error(__TopXMLNS, __IgnoreEls, _el));
-      <<"jabber:client">> ->
-	  decode_db_result_els(__TopXMLNS, __IgnoreEls, _els, Key,
-			       decode_error(<<"jabber:client">>, __IgnoreEls,
-					    _el));
-      _ ->
-	  decode_db_result_els(__TopXMLNS, __IgnoreEls, _els, Key,
-			       Error)
-    end;
-decode_db_result_els(__TopXMLNS, __IgnoreEls,
-		     [_ | _els], Key, Error) ->
-    decode_db_result_els(__TopXMLNS, __IgnoreEls, _els, Key,
-			 Error).
+		     [{xmlel, _, _, _} = _el | _els], Key, __Els) ->
+    if __IgnoreEls ->
+	   decode_db_result_els(__TopXMLNS, __IgnoreEls, _els, Key,
+				[_el | __Els]);
+       true ->
+	   case is_known_tag(_el) of
+	     true ->
+		 decode_db_result_els(__TopXMLNS, __IgnoreEls, _els, Key,
+				      [decode(_el) | __Els]);
+	     false ->
+		 decode_db_result_els(__TopXMLNS, __IgnoreEls, _els, Key,
+				      __Els)
+	   end
+    end.
 
 decode_db_result_attrs(__TopXMLNS,
 		       [{<<"from">>, _val} | _attrs], _From, To, Type) ->
@@ -4987,21 +4976,16 @@ decode_db_result_attrs(__TopXMLNS, [], From, To,
      decode_db_result_attr_type(__TopXMLNS, Type)}.
 
 encode_db_result({db_result, From, To, Type, Key,
-		  Error},
+		  __Els},
 		 _xmlns_attrs) ->
-    _els = lists:reverse(encode_db_result_cdata(Key,
-						'encode_db_result_$error'(Error,
-									  []))),
+    _els = [encode(_el) || _el <- __Els] ++
+	     encode_db_result_cdata(Key, []),
     _attrs = encode_db_result_attr_type(Type,
 					encode_db_result_attr_to(To,
 								 encode_db_result_attr_from(From,
 											    _xmlns_attrs))),
     {xmlel, <<"db:result">>, _attrs, _els}.
 
-'encode_db_result_$error'(undefined, _acc) -> _acc;
-'encode_db_result_$error'(Error, _acc) ->
-    [encode_error(Error, []) | _acc].
-
 decode_db_result_attr_from(__TopXMLNS, undefined) ->
     erlang:error({xmpp_codec,
 		  {missing_attr, <<"from">>, <<"db:result">>,
@@ -23335,329 +23319,363 @@ encode_bind_jid_cdata(_val, _acc) ->
 
 decode_error(__TopXMLNS, __IgnoreEls,
 	     {xmlel, <<"error">>, _attrs, _els}) ->
-    {Text, Reason} = decode_error_els(__TopXMLNS,
-				      __IgnoreEls, _els, undefined, undefined),
+    {Text, Reason, __Els} = decode_error_els(__TopXMLNS,
+					     __IgnoreEls, _els, undefined,
+					     undefined, []),
     {Type, Code, By} = decode_error_attrs(__TopXMLNS,
 					  _attrs, undefined, undefined,
 					  undefined),
-    {error, Type, Code, By, Reason, Text}.
+    {error, Type, Code, By, Reason, Text, __Els}.
 
 decode_error_els(__TopXMLNS, __IgnoreEls, [], Text,
-		 Reason) ->
-    {Text, Reason};
+		 Reason, __Els) ->
+    {Text, Reason, lists:reverse(__Els)};
 decode_error_els(__TopXMLNS, __IgnoreEls,
 		 [{xmlel, <<"text">>, _attrs, _} = _el | _els], Text,
-		 Reason) ->
+		 Reason, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"urn:ietf:params:xml:ns:xmpp-stanzas">> ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els,
 			   decode_error_text(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>,
 					     __IgnoreEls, _el),
-			   Reason);
+			   Reason, __Els);
       _ ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
-			   Reason)
+			   Reason, __Els)
     end;
 decode_error_els(__TopXMLNS, __IgnoreEls,
 		 [{xmlel, <<"bad-request">>, _attrs, _} = _el | _els],
-		 Text, Reason) ->
+		 Text, Reason, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"urn:ietf:params:xml:ns:xmpp-stanzas">> ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
 			   decode_error_bad_request(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>,
-						    __IgnoreEls, _el));
+						    __IgnoreEls, _el),
+			   __Els);
       _ ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
-			   Reason)
+			   Reason, __Els)
     end;
 decode_error_els(__TopXMLNS, __IgnoreEls,
 		 [{xmlel, <<"conflict">>, _attrs, _} = _el | _els], Text,
-		 Reason) ->
+		 Reason, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"urn:ietf:params:xml:ns:xmpp-stanzas">> ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
 			   decode_error_conflict(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>,
-						 __IgnoreEls, _el));
+						 __IgnoreEls, _el),
+			   __Els);
       _ ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
-			   Reason)
+			   Reason, __Els)
     end;
 decode_error_els(__TopXMLNS, __IgnoreEls,
 		 [{xmlel, <<"feature-not-implemented">>, _attrs, _} = _el
 		  | _els],
-		 Text, Reason) ->
+		 Text, Reason, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"urn:ietf:params:xml:ns:xmpp-stanzas">> ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
 			   decode_error_feature_not_implemented(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>,
 								__IgnoreEls,
-								_el));
+								_el),
+			   __Els);
       _ ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
-			   Reason)
+			   Reason, __Els)
     end;
 decode_error_els(__TopXMLNS, __IgnoreEls,
 		 [{xmlel, <<"forbidden">>, _attrs, _} = _el | _els],
-		 Text, Reason) ->
+		 Text, Reason, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"urn:ietf:params:xml:ns:xmpp-stanzas">> ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
 			   decode_error_forbidden(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>,
-						  __IgnoreEls, _el));
+						  __IgnoreEls, _el),
+			   __Els);
       _ ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
-			   Reason)
+			   Reason, __Els)
     end;
 decode_error_els(__TopXMLNS, __IgnoreEls,
 		 [{xmlel, <<"gone">>, _attrs, _} = _el | _els], Text,
-		 Reason) ->
+		 Reason, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"urn:ietf:params:xml:ns:xmpp-stanzas">> ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
 			   decode_error_gone(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>,
-					     __IgnoreEls, _el));
+					     __IgnoreEls, _el),
+			   __Els);
       _ ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
-			   Reason)
+			   Reason, __Els)
     end;
 decode_error_els(__TopXMLNS, __IgnoreEls,
 		 [{xmlel, <<"internal-server-error">>, _attrs, _} = _el
 		  | _els],
-		 Text, Reason) ->
+		 Text, Reason, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"urn:ietf:params:xml:ns:xmpp-stanzas">> ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
 			   decode_error_internal_server_error(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>,
-							      __IgnoreEls,
-							      _el));
+							      __IgnoreEls, _el),
+			   __Els);
       _ ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
-			   Reason)
+			   Reason, __Els)
     end;
 decode_error_els(__TopXMLNS, __IgnoreEls,
 		 [{xmlel, <<"item-not-found">>, _attrs, _} = _el | _els],
-		 Text, Reason) ->
+		 Text, Reason, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"urn:ietf:params:xml:ns:xmpp-stanzas">> ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
 			   decode_error_item_not_found(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>,
-						       __IgnoreEls, _el));
+						       __IgnoreEls, _el),
+			   __Els);
       _ ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
-			   Reason)
+			   Reason, __Els)
     end;
 decode_error_els(__TopXMLNS, __IgnoreEls,
 		 [{xmlel, <<"jid-malformed">>, _attrs, _} = _el | _els],
-		 Text, Reason) ->
+		 Text, Reason, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"urn:ietf:params:xml:ns:xmpp-stanzas">> ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
 			   decode_error_jid_malformed(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>,
-						      __IgnoreEls, _el));
+						      __IgnoreEls, _el),
+			   __Els);
       _ ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
-			   Reason)
+			   Reason, __Els)
     end;
 decode_error_els(__TopXMLNS, __IgnoreEls,
 		 [{xmlel, <<"not-acceptable">>, _attrs, _} = _el | _els],
-		 Text, Reason) ->
+		 Text, Reason, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"urn:ietf:params:xml:ns:xmpp-stanzas">> ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
 			   decode_error_not_acceptable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>,
-						       __IgnoreEls, _el));
+						       __IgnoreEls, _el),
+			   __Els);
       _ ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
-			   Reason)
+			   Reason, __Els)
     end;
 decode_error_els(__TopXMLNS, __IgnoreEls,
 		 [{xmlel, <<"not-allowed">>, _attrs, _} = _el | _els],
-		 Text, Reason) ->
+		 Text, Reason, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"urn:ietf:params:xml:ns:xmpp-stanzas">> ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
 			   decode_error_not_allowed(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>,
-						    __IgnoreEls, _el));
+						    __IgnoreEls, _el),
+			   __Els);
       _ ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
-			   Reason)
+			   Reason, __Els)
     end;
 decode_error_els(__TopXMLNS, __IgnoreEls,
 		 [{xmlel, <<"not-authorized">>, _attrs, _} = _el | _els],
-		 Text, Reason) ->
+		 Text, Reason, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"urn:ietf:params:xml:ns:xmpp-stanzas">> ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
 			   decode_error_not_authorized(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>,
-						       __IgnoreEls, _el));
+						       __IgnoreEls, _el),
+			   __Els);
       _ ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
-			   Reason)
+			   Reason, __Els)
     end;
 decode_error_els(__TopXMLNS, __IgnoreEls,
 		 [{xmlel, <<"payment-required">>, _attrs, _} = _el
 		  | _els],
-		 Text, Reason) ->
+		 Text, Reason, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"urn:ietf:params:xml:ns:xmpp-stanzas">> ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
 			   decode_error_payment_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>,
-							 __IgnoreEls, _el));
+							 __IgnoreEls, _el),
+			   __Els);
       _ ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
-			   Reason)
+			   Reason, __Els)
     end;
 decode_error_els(__TopXMLNS, __IgnoreEls,
 		 [{xmlel, <<"policy-violation">>, _attrs, _} = _el
 		  | _els],
-		 Text, Reason) ->
+		 Text, Reason, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"urn:ietf:params:xml:ns:xmpp-stanzas">> ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
 			   decode_error_policy_violation(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>,
-							 __IgnoreEls, _el));
+							 __IgnoreEls, _el),
+			   __Els);
       _ ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
-			   Reason)
+			   Reason, __Els)
     end;
 decode_error_els(__TopXMLNS, __IgnoreEls,
 		 [{xmlel, <<"recipient-unavailable">>, _attrs, _} = _el
 		  | _els],
-		 Text, Reason) ->
+		 Text, Reason, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"urn:ietf:params:xml:ns:xmpp-stanzas">> ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
 			   decode_error_recipient_unavailable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>,
-							      __IgnoreEls,
-							      _el));
+							      __IgnoreEls, _el),
+			   __Els);
       _ ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
-			   Reason)
+			   Reason, __Els)
     end;
 decode_error_els(__TopXMLNS, __IgnoreEls,
 		 [{xmlel, <<"redirect">>, _attrs, _} = _el | _els], Text,
-		 Reason) ->
+		 Reason, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"urn:ietf:params:xml:ns:xmpp-stanzas">> ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
 			   decode_error_redirect(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>,
-						 __IgnoreEls, _el));
+						 __IgnoreEls, _el),
+			   __Els);
       _ ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
-			   Reason)
+			   Reason, __Els)
     end;
 decode_error_els(__TopXMLNS, __IgnoreEls,
 		 [{xmlel, <<"registration-required">>, _attrs, _} = _el
 		  | _els],
-		 Text, Reason) ->
+		 Text, Reason, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"urn:ietf:params:xml:ns:xmpp-stanzas">> ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
 			   decode_error_registration_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>,
-							      __IgnoreEls,
-							      _el));
+							      __IgnoreEls, _el),
+			   __Els);
       _ ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
-			   Reason)
+			   Reason, __Els)
     end;
 decode_error_els(__TopXMLNS, __IgnoreEls,
 		 [{xmlel, <<"remote-server-not-found">>, _attrs, _} = _el
 		  | _els],
-		 Text, Reason) ->
+		 Text, Reason, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"urn:ietf:params:xml:ns:xmpp-stanzas">> ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
 			   decode_error_remote_server_not_found(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>,
 								__IgnoreEls,
-								_el));
+								_el),
+			   __Els);
       _ ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
-			   Reason)
+			   Reason, __Els)
     end;
 decode_error_els(__TopXMLNS, __IgnoreEls,
 		 [{xmlel, <<"remote-server-timeout">>, _attrs, _} = _el
 		  | _els],
-		 Text, Reason) ->
+		 Text, Reason, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"urn:ietf:params:xml:ns:xmpp-stanzas">> ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
 			   decode_error_remote_server_timeout(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>,
-							      __IgnoreEls,
-							      _el));
+							      __IgnoreEls, _el),
+			   __Els);
       _ ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
-			   Reason)
+			   Reason, __Els)
     end;
 decode_error_els(__TopXMLNS, __IgnoreEls,
 		 [{xmlel, <<"resource-constraint">>, _attrs, _} = _el
 		  | _els],
-		 Text, Reason) ->
+		 Text, Reason, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"urn:ietf:params:xml:ns:xmpp-stanzas">> ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
 			   decode_error_resource_constraint(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>,
-							    __IgnoreEls, _el));
+							    __IgnoreEls, _el),
+			   __Els);
       _ ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
-			   Reason)
+			   Reason, __Els)
     end;
 decode_error_els(__TopXMLNS, __IgnoreEls,
 		 [{xmlel, <<"service-unavailable">>, _attrs, _} = _el
 		  | _els],
-		 Text, Reason) ->
+		 Text, Reason, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"urn:ietf:params:xml:ns:xmpp-stanzas">> ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
 			   decode_error_service_unavailable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>,
-							    __IgnoreEls, _el));
+							    __IgnoreEls, _el),
+			   __Els);
       _ ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
-			   Reason)
+			   Reason, __Els)
     end;
 decode_error_els(__TopXMLNS, __IgnoreEls,
 		 [{xmlel, <<"subscription-required">>, _attrs, _} = _el
 		  | _els],
-		 Text, Reason) ->
+		 Text, Reason, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"urn:ietf:params:xml:ns:xmpp-stanzas">> ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
 			   decode_error_subscription_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>,
-							      __IgnoreEls,
-							      _el));
+							      __IgnoreEls, _el),
+			   __Els);
       _ ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
-			   Reason)
+			   Reason, __Els)
     end;
 decode_error_els(__TopXMLNS, __IgnoreEls,
 		 [{xmlel, <<"undefined-condition">>, _attrs, _} = _el
 		  | _els],
-		 Text, Reason) ->
+		 Text, Reason, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"urn:ietf:params:xml:ns:xmpp-stanzas">> ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
 			   decode_error_undefined_condition(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>,
-							    __IgnoreEls, _el));
+							    __IgnoreEls, _el),
+			   __Els);
       _ ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
-			   Reason)
+			   Reason, __Els)
     end;
 decode_error_els(__TopXMLNS, __IgnoreEls,
 		 [{xmlel, <<"unexpected-request">>, _attrs, _} = _el
 		  | _els],
-		 Text, Reason) ->
+		 Text, Reason, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"urn:ietf:params:xml:ns:xmpp-stanzas">> ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
 			   decode_error_unexpected_request(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>,
-							   __IgnoreEls, _el));
+							   __IgnoreEls, _el),
+			   __Els);
       _ ->
 	  decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
-			   Reason)
+			   Reason, __Els)
+    end;
+decode_error_els(__TopXMLNS, __IgnoreEls,
+		 [{xmlel, _, _, _} = _el | _els], Text, Reason, __Els) ->
+    if __IgnoreEls ->
+	   decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
+			    Reason, [_el | __Els]);
+       true ->
+	   case is_known_tag(_el) of
+	     true ->
+		 decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
+				  Reason, [decode(_el) | __Els]);
+	     false ->
+		 decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
+				  Reason, __Els)
+	   end
     end;
 decode_error_els(__TopXMLNS, __IgnoreEls, [_ | _els],
-		 Text, Reason) ->
+		 Text, Reason, __Els) ->
     decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text,
-		     Reason).
+		     Reason, __Els).
 
 decode_error_attrs(__TopXMLNS,
 		   [{<<"type">>, _val} | _attrs], _Type, Code, By) ->
@@ -23677,11 +23695,13 @@ decode_error_attrs(__TopXMLNS, [], Type, Code, By) ->
      decode_error_attr_code(__TopXMLNS, Code),
      decode_error_attr_by(__TopXMLNS, By)}.
 
-encode_error({error, Type, Code, By, Reason, Text},
+encode_error({error, Type, Code, By, Reason, Text,
+	      __Els},
 	     _xmlns_attrs) ->
-    _els = lists:reverse('encode_error_$text'(Text,
-					      'encode_error_$reason'(Reason,
-								     []))),
+    _els = [encode(_el) || _el <- __Els] ++
+	     lists:reverse('encode_error_$text'(Text,
+						'encode_error_$reason'(Reason,
+								       []))),
     _attrs = encode_error_attr_by(By,
 				  encode_error_attr_code(Code,
 							 encode_error_attr_type(Type,
@@ -24212,119 +24232,100 @@ encode_error_bad_request('bad-request', _xmlns_attrs) ->
 
 decode_presence(__TopXMLNS, __IgnoreEls,
 		{xmlel, <<"presence">>, _attrs, _els}) ->
-    {Error, Status, Show, Priority, __Els} =
-	decode_presence_els(__TopXMLNS, __IgnoreEls, _els,
-			    undefined, [], undefined, undefined, []),
+    {Status, Show, Priority, __Els} =
+	decode_presence_els(__TopXMLNS, __IgnoreEls, _els, [],
+			    undefined, undefined, []),
     {Id, Type, From, To, Lang} =
 	decode_presence_attrs(__TopXMLNS, _attrs, undefined,
 			      undefined, undefined, undefined, undefined),
     {presence, Id, Type, Lang, From, To, Show, Status,
-     Priority, Error, __Els}.
+     Priority, __Els}.
 
-decode_presence_els(__TopXMLNS, __IgnoreEls, [], Error,
-		    Status, Show, Priority, __Els) ->
-    {Error, lists:reverse(Status), Show, Priority,
+decode_presence_els(__TopXMLNS, __IgnoreEls, [], Status,
+		    Show, Priority, __Els) ->
+    {lists:reverse(Status), Show, Priority,
      lists:reverse(__Els)};
 decode_presence_els(__TopXMLNS, __IgnoreEls,
-		    [{xmlel, <<"error">>, _attrs, _} = _el | _els], Error,
-		    Status, Show, Priority, __Els) ->
+		    [{xmlel, <<"show">>, _attrs, _} = _el | _els], Status,
+		    Show, Priority, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"">> when __TopXMLNS == <<"jabber:client">> ->
 	  decode_presence_els(__TopXMLNS, __IgnoreEls, _els,
-			      decode_error(__TopXMLNS, __IgnoreEls, _el),
-			      Status, Show, Priority, __Els);
-      <<"jabber:client">> ->
-	  decode_presence_els(__TopXMLNS, __IgnoreEls, _els,
-			      decode_error(<<"jabber:client">>, __IgnoreEls,
-					   _el),
-			      Status, Show, Priority, __Els);
-      _ ->
-	  decode_presence_els(__TopXMLNS, __IgnoreEls, _els,
-			      Error, Status, Show, Priority, __Els)
-    end;
-decode_presence_els(__TopXMLNS, __IgnoreEls,
-		    [{xmlel, <<"show">>, _attrs, _} = _el | _els], Error,
-		    Status, Show, Priority, __Els) ->
-    case get_attr(<<"xmlns">>, _attrs) of
-      <<"">> when __TopXMLNS == <<"jabber:client">> ->
-	  decode_presence_els(__TopXMLNS, __IgnoreEls, _els,
-			      Error, Status,
+			      Status,
 			      decode_presence_show(__TopXMLNS, __IgnoreEls,
 						   _el),
 			      Priority, __Els);
       <<"jabber:client">> ->
 	  decode_presence_els(__TopXMLNS, __IgnoreEls, _els,
-			      Error, Status,
+			      Status,
 			      decode_presence_show(<<"jabber:client">>,
 						   __IgnoreEls, _el),
 			      Priority, __Els);
       _ ->
 	  decode_presence_els(__TopXMLNS, __IgnoreEls, _els,
-			      Error, Status, Show, Priority, __Els)
+			      Status, Show, Priority, __Els)
     end;
 decode_presence_els(__TopXMLNS, __IgnoreEls,
-		    [{xmlel, <<"status">>, _attrs, _} = _el | _els], Error,
-		    Status, Show, Priority, __Els) ->
+		    [{xmlel, <<"status">>, _attrs, _} = _el | _els], Status,
+		    Show, Priority, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"">> when __TopXMLNS == <<"jabber:client">> ->
 	  decode_presence_els(__TopXMLNS, __IgnoreEls, _els,
-			      Error,
 			      [decode_presence_status(__TopXMLNS, __IgnoreEls,
 						      _el)
 			       | Status],
 			      Show, Priority, __Els);
       <<"jabber:client">> ->
 	  decode_presence_els(__TopXMLNS, __IgnoreEls, _els,
-			      Error,
 			      [decode_presence_status(<<"jabber:client">>,
 						      __IgnoreEls, _el)
 			       | Status],
 			      Show, Priority, __Els);
       _ ->
 	  decode_presence_els(__TopXMLNS, __IgnoreEls, _els,
-			      Error, Status, Show, Priority, __Els)
+			      Status, Show, Priority, __Els)
     end;
 decode_presence_els(__TopXMLNS, __IgnoreEls,
 		    [{xmlel, <<"priority">>, _attrs, _} = _el | _els],
-		    Error, Status, Show, Priority, __Els) ->
+		    Status, Show, Priority, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"">> when __TopXMLNS == <<"jabber:client">> ->
 	  decode_presence_els(__TopXMLNS, __IgnoreEls, _els,
-			      Error, Status, Show,
+			      Status, Show,
 			      decode_presence_priority(__TopXMLNS, __IgnoreEls,
 						       _el),
 			      __Els);
       <<"jabber:client">> ->
 	  decode_presence_els(__TopXMLNS, __IgnoreEls, _els,
-			      Error, Status, Show,
+			      Status, Show,
 			      decode_presence_priority(<<"jabber:client">>,
 						       __IgnoreEls, _el),
 			      __Els);
       _ ->
 	  decode_presence_els(__TopXMLNS, __IgnoreEls, _els,
-			      Error, Status, Show, Priority, __Els)
+			      Status, Show, Priority, __Els)
     end;
 decode_presence_els(__TopXMLNS, __IgnoreEls,
-		    [{xmlel, _, _, _} = _el | _els], Error, Status, Show,
-		    Priority, __Els) ->
+		    [{xmlel, _, _, _} = _el | _els], Status, Show, Priority,
+		    __Els) ->
     if __IgnoreEls ->
 	   decode_presence_els(__TopXMLNS, __IgnoreEls, _els,
-			       Error, Status, Show, Priority, [_el | __Els]);
+			       Status, Show, Priority, [_el | __Els]);
        true ->
 	   case is_known_tag(_el) of
 	     true ->
 		 decode_presence_els(__TopXMLNS, __IgnoreEls, _els,
-				     Error, Status, Show, Priority,
+				     Status, Show, Priority,
 				     [decode(_el) | __Els]);
 	     false ->
 		 decode_presence_els(__TopXMLNS, __IgnoreEls, _els,
-				     Error, Status, Show, Priority, __Els)
+				     Status, Show, Priority, __Els)
 	   end
     end;
 decode_presence_els(__TopXMLNS, __IgnoreEls, [_ | _els],
-		    Error, Status, Show, Priority, __Els) ->
+		    Status, Show, Priority, __Els) ->
     decode_presence_els(__TopXMLNS, __IgnoreEls, _els,
-			Error, Status, Show, Priority, __Els).
+			Status, Show, Priority, __Els).
 
 decode_presence_attrs(__TopXMLNS,
 		      [{<<"id">>, _val} | _attrs], _Id, Type, From, To,
@@ -24364,14 +24365,13 @@ decode_presence_attrs(__TopXMLNS, [], Id, Type, From,
      'decode_presence_attr_xml:lang'(__TopXMLNS, Lang)}.
 
 encode_presence({presence, Id, Type, Lang, From, To,
-		 Show, Status, Priority, Error, __Els},
+		 Show, Status, Priority, __Els},
 		_xmlns_attrs) ->
     _els = [encode(_el) || _el <- __Els] ++
-	     lists:reverse('encode_presence_$error'(Error,
-						    'encode_presence_$status'(Status,
-									      'encode_presence_$show'(Show,
-												      'encode_presence_$priority'(Priority,
-																  []))))),
+	     lists:reverse('encode_presence_$status'(Status,
+						     'encode_presence_$show'(Show,
+									     'encode_presence_$priority'(Priority,
+													 [])))),
     _attrs = 'encode_presence_attr_xml:lang'(Lang,
 					     encode_presence_attr_to(To,
 								     encode_presence_attr_from(From,
@@ -24380,10 +24380,6 @@ encode_presence({presence, Id, Type, Lang, From, To,
 																		 _xmlns_attrs))))),
     {xmlel, <<"presence">>, _attrs, _els}.
 
-'encode_presence_$error'(undefined, _acc) -> _acc;
-'encode_presence_$error'(Error, _acc) ->
-    [encode_error(Error, []) | _acc].
-
 'encode_presence_$status'([], _acc) -> _acc;
 'encode_presence_$status'([Status | _els], _acc) ->
     'encode_presence_$status'(_els,
@@ -24598,117 +24594,100 @@ encode_presence_show_cdata(_val, _acc) ->
 
 decode_message(__TopXMLNS, __IgnoreEls,
 	       {xmlel, <<"message">>, _attrs, _els}) ->
-    {Error, Thread, Subject, Body, __Els} =
+    {Thread, Subject, Body, __Els} =
 	decode_message_els(__TopXMLNS, __IgnoreEls, _els,
-			   undefined, undefined, [], [], []),
+			   undefined, [], [], []),
     {Id, Type, From, To, Lang} =
 	decode_message_attrs(__TopXMLNS, _attrs, undefined,
 			     undefined, undefined, undefined, undefined),
     {message, Id, Type, Lang, From, To, Subject, Body,
-     Thread, Error, __Els}.
+     Thread, __Els}.
 
-decode_message_els(__TopXMLNS, __IgnoreEls, [], Error,
-		   Thread, Subject, Body, __Els) ->
-    {Error, Thread, lists:reverse(Subject),
-     lists:reverse(Body), lists:reverse(__Els)};
+decode_message_els(__TopXMLNS, __IgnoreEls, [], Thread,
+		   Subject, Body, __Els) ->
+    {Thread, lists:reverse(Subject), lists:reverse(Body),
+     lists:reverse(__Els)};
 decode_message_els(__TopXMLNS, __IgnoreEls,
-		   [{xmlel, <<"error">>, _attrs, _} = _el | _els], Error,
+		   [{xmlel, <<"subject">>, _attrs, _} = _el | _els],
 		   Thread, Subject, Body, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"">> when __TopXMLNS == <<"jabber:client">> ->
 	  decode_message_els(__TopXMLNS, __IgnoreEls, _els,
-			     decode_error(__TopXMLNS, __IgnoreEls, _el), Thread,
-			     Subject, Body, __Els);
-      <<"jabber:client">> ->
-	  decode_message_els(__TopXMLNS, __IgnoreEls, _els,
-			     decode_error(<<"jabber:client">>, __IgnoreEls,
-					  _el),
-			     Thread, Subject, Body, __Els);
-      _ ->
-	  decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error,
-			     Thread, Subject, Body, __Els)
-    end;
-decode_message_els(__TopXMLNS, __IgnoreEls,
-		   [{xmlel, <<"subject">>, _attrs, _} = _el | _els], Error,
-		   Thread, Subject, Body, __Els) ->
-    case get_attr(<<"xmlns">>, _attrs) of
-      <<"">> when __TopXMLNS == <<"jabber:client">> ->
-	  decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error,
 			     Thread,
 			     [decode_message_subject(__TopXMLNS, __IgnoreEls,
 						     _el)
 			      | Subject],
 			     Body, __Els);
       <<"jabber:client">> ->
-	  decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error,
+	  decode_message_els(__TopXMLNS, __IgnoreEls, _els,
 			     Thread,
 			     [decode_message_subject(<<"jabber:client">>,
 						     __IgnoreEls, _el)
 			      | Subject],
 			     Body, __Els);
       _ ->
-	  decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error,
+	  decode_message_els(__TopXMLNS, __IgnoreEls, _els,
 			     Thread, Subject, Body, __Els)
     end;
 decode_message_els(__TopXMLNS, __IgnoreEls,
-		   [{xmlel, <<"thread">>, _attrs, _} = _el | _els], Error,
-		   Thread, Subject, Body, __Els) ->
+		   [{xmlel, <<"thread">>, _attrs, _} = _el | _els], Thread,
+		   Subject, Body, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"">> when __TopXMLNS == <<"jabber:client">> ->
-	  decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error,
+	  decode_message_els(__TopXMLNS, __IgnoreEls, _els,
 			     decode_message_thread(__TopXMLNS, __IgnoreEls,
 						   _el),
 			     Subject, Body, __Els);
       <<"jabber:client">> ->
-	  decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error,
+	  decode_message_els(__TopXMLNS, __IgnoreEls, _els,
 			     decode_message_thread(<<"jabber:client">>,
 						   __IgnoreEls, _el),
 			     Subject, Body, __Els);
       _ ->
-	  decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error,
+	  decode_message_els(__TopXMLNS, __IgnoreEls, _els,
 			     Thread, Subject, Body, __Els)
     end;
 decode_message_els(__TopXMLNS, __IgnoreEls,
-		   [{xmlel, <<"body">>, _attrs, _} = _el | _els], Error,
-		   Thread, Subject, Body, __Els) ->
+		   [{xmlel, <<"body">>, _attrs, _} = _el | _els], Thread,
+		   Subject, Body, __Els) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"">> when __TopXMLNS == <<"jabber:client">> ->
-	  decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error,
+	  decode_message_els(__TopXMLNS, __IgnoreEls, _els,
 			     Thread, Subject,
 			     [decode_message_body(__TopXMLNS, __IgnoreEls, _el)
 			      | Body],
 			     __Els);
       <<"jabber:client">> ->
-	  decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error,
+	  decode_message_els(__TopXMLNS, __IgnoreEls, _els,
 			     Thread, Subject,
 			     [decode_message_body(<<"jabber:client">>,
 						  __IgnoreEls, _el)
 			      | Body],
 			     __Els);
       _ ->
-	  decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error,
+	  decode_message_els(__TopXMLNS, __IgnoreEls, _els,
 			     Thread, Subject, Body, __Els)
     end;
 decode_message_els(__TopXMLNS, __IgnoreEls,
-		   [{xmlel, _, _, _} = _el | _els], Error, Thread, Subject,
-		   Body, __Els) ->
+		   [{xmlel, _, _, _} = _el | _els], Thread, Subject, Body,
+		   __Els) ->
     if __IgnoreEls ->
-	   decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error,
+	   decode_message_els(__TopXMLNS, __IgnoreEls, _els,
 			      Thread, Subject, Body, [_el | __Els]);
        true ->
 	   case is_known_tag(_el) of
 	     true ->
-		 decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error,
+		 decode_message_els(__TopXMLNS, __IgnoreEls, _els,
 				    Thread, Subject, Body,
 				    [decode(_el) | __Els]);
 	     false ->
-		 decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error,
+		 decode_message_els(__TopXMLNS, __IgnoreEls, _els,
 				    Thread, Subject, Body, __Els)
 	   end
     end;
 decode_message_els(__TopXMLNS, __IgnoreEls, [_ | _els],
-		   Error, Thread, Subject, Body, __Els) ->
-    decode_message_els(__TopXMLNS, __IgnoreEls, _els, Error,
+		   Thread, Subject, Body, __Els) ->
+    decode_message_els(__TopXMLNS, __IgnoreEls, _els,
 		       Thread, Subject, Body, __Els).
 
 decode_message_attrs(__TopXMLNS,
@@ -24749,14 +24728,13 @@ decode_message_attrs(__TopXMLNS, [], Id, Type, From, To,
      'decode_message_attr_xml:lang'(__TopXMLNS, Lang)}.
 
 encode_message({message, Id, Type, Lang, From, To,
-		Subject, Body, Thread, Error, __Els},
+		Subject, Body, Thread, __Els},
 	       _xmlns_attrs) ->
     _els = [encode(_el) || _el <- __Els] ++
-	     lists:reverse('encode_message_$error'(Error,
-						   'encode_message_$thread'(Thread,
-									    'encode_message_$subject'(Subject,
-												      'encode_message_$body'(Body,
-															     []))))),
+	     lists:reverse('encode_message_$thread'(Thread,
+						    'encode_message_$subject'(Subject,
+									      'encode_message_$body'(Body,
+												     [])))),
     _attrs = 'encode_message_attr_xml:lang'(Lang,
 					    encode_message_attr_to(To,
 								   encode_message_attr_from(From,
@@ -24765,10 +24743,6 @@ encode_message({message, Id, Type, Lang, From, To,
 																	    _xmlns_attrs))))),
     {xmlel, <<"message">>, _attrs, _els}.
 
-'encode_message_$error'(undefined, _acc) -> _acc;
-'encode_message_$error'(Error, _acc) ->
-    [encode_error(Error, []) | _acc].
-
 'encode_message_$thread'(undefined, _acc) -> _acc;
 'encode_message_$thread'(Thread, _acc) ->
     [encode_message_thread(Thread, []) | _acc].
@@ -24991,51 +24965,33 @@ encode_message_subject_cdata(_val, _acc) ->
 
 decode_iq(__TopXMLNS, __IgnoreEls,
 	  {xmlel, <<"iq">>, _attrs, _els}) ->
-    {Error, __Els} = decode_iq_els(__TopXMLNS, __IgnoreEls,
-				   _els, undefined, []),
+    __Els = decode_iq_els(__TopXMLNS, __IgnoreEls, _els,
+			  []),
     {Id, Type, From, To, Lang} = decode_iq_attrs(__TopXMLNS,
 						 _attrs, undefined, undefined,
 						 undefined, undefined,
 						 undefined),
-    {iq, Id, Type, Lang, From, To, Error, __Els}.
+    {iq, Id, Type, Lang, From, To, __Els}.
 
-decode_iq_els(__TopXMLNS, __IgnoreEls, [], Error,
-	      __Els) ->
-    {Error, lists:reverse(__Els)};
+decode_iq_els(__TopXMLNS, __IgnoreEls, [], __Els) ->
+    lists:reverse(__Els);
 decode_iq_els(__TopXMLNS, __IgnoreEls,
-	      [{xmlel, <<"error">>, _attrs, _} = _el | _els], Error,
-	      __Els) ->
-    case get_attr(<<"xmlns">>, _attrs) of
-      <<"">> when __TopXMLNS == <<"jabber:client">> ->
-	  decode_iq_els(__TopXMLNS, __IgnoreEls, _els,
-			decode_error(__TopXMLNS, __IgnoreEls, _el), __Els);
-      <<"jabber:client">> ->
-	  decode_iq_els(__TopXMLNS, __IgnoreEls, _els,
-			decode_error(<<"jabber:client">>, __IgnoreEls, _el),
-			__Els);
-      _ ->
-	  decode_iq_els(__TopXMLNS, __IgnoreEls, _els, Error,
-			__Els)
-    end;
-decode_iq_els(__TopXMLNS, __IgnoreEls,
-	      [{xmlel, _, _, _} = _el | _els], Error, __Els) ->
+	      [{xmlel, _, _, _} = _el | _els], __Els) ->
     if __IgnoreEls ->
-	   decode_iq_els(__TopXMLNS, __IgnoreEls, _els, Error,
+	   decode_iq_els(__TopXMLNS, __IgnoreEls, _els,
 			 [_el | __Els]);
        true ->
 	   case is_known_tag(_el) of
 	     true ->
-		 decode_iq_els(__TopXMLNS, __IgnoreEls, _els, Error,
+		 decode_iq_els(__TopXMLNS, __IgnoreEls, _els,
 			       [decode(_el) | __Els]);
 	     false ->
-		 decode_iq_els(__TopXMLNS, __IgnoreEls, _els, Error,
-			       __Els)
+		 decode_iq_els(__TopXMLNS, __IgnoreEls, _els, __Els)
 	   end
     end;
 decode_iq_els(__TopXMLNS, __IgnoreEls, [_ | _els],
-	      Error, __Els) ->
-    decode_iq_els(__TopXMLNS, __IgnoreEls, _els, Error,
-		  __Els).
+	      __Els) ->
+    decode_iq_els(__TopXMLNS, __IgnoreEls, _els, __Els).
 
 decode_iq_attrs(__TopXMLNS, [{<<"id">>, _val} | _attrs],
 		_Id, Type, From, To, Lang) ->
@@ -25072,10 +25028,9 @@ decode_iq_attrs(__TopXMLNS, [], Id, Type, From, To,
      decode_iq_attr_to(__TopXMLNS, To),
      'decode_iq_attr_xml:lang'(__TopXMLNS, Lang)}.
 
-encode_iq({iq, Id, Type, Lang, From, To, Error, __Els},
+encode_iq({iq, Id, Type, Lang, From, To, __Els},
 	  _xmlns_attrs) ->
-    _els = [encode(_el) || _el <- __Els] ++
-	     lists:reverse('encode_iq_$error'(Error, [])),
+    _els = [encode(_el) || _el <- __Els],
     _attrs = 'encode_iq_attr_xml:lang'(Lang,
 				       encode_iq_attr_to(To,
 							 encode_iq_attr_from(From,
@@ -25084,10 +25039,6 @@ encode_iq({iq, Id, Type, Lang, From, To, Error, __Els},
 														   _xmlns_attrs))))),
     {xmlel, <<"iq">>, _attrs, _els}.
 
-'encode_iq_$error'(undefined, _acc) -> _acc;
-'encode_iq_$error'(Error, _acc) ->
-    [encode_error(Error, []) | _acc].
-
 decode_iq_attr_id(__TopXMLNS, undefined) ->
     erlang:error({xmpp_codec,
 		  {missing_attr, <<"id">>, <<"iq">>, __TopXMLNS}});
diff --git a/tools/xmpp_codec.spec b/tools/xmpp_codec.spec
index 293f12d17..964b631c2 100644
--- a/tools/xmpp_codec.spec
+++ b/tools/xmpp_codec.spec
@@ -316,8 +316,7 @@
 -xml(iq,
      #elem{name = <<"iq">>,
            xmlns = <<"jabber:client">>,
-           result = {iq, '$id', '$type', '$lang', '$from', '$to',
-                     '$error', '$_els'},
+           result = {iq, '$id', '$type', '$lang', '$from', '$to', '$_els'},
            attrs = [#attr{name = <<"id">>,
                           required = true},
                     #attr{name = <<"type">>,
@@ -331,8 +330,7 @@
                           dec = {dec_jid, []},
                           enc = {enc_jid, []}},
                     #attr{name = <<"xml:lang">>,
-                          label = '$lang'}],
-           refs = [#ref{name = error, min = 0, max = 1, label = '$error'}]}).
+                          label = '$lang'}]}).
 
 -xml(message_subject,
      #elem{name = <<"subject">>,
@@ -357,7 +355,7 @@
      #elem{name = <<"message">>,
            xmlns = <<"jabber:client">>,
            result = {message, '$id', '$type', '$lang', '$from', '$to',
-                     '$subject', '$body', '$thread', '$error', '$_els'},
+                     '$subject', '$body', '$thread', '$_els'},
            attrs = [#attr{name = <<"id">>},
                     #attr{name = <<"type">>,
                           default = normal,
@@ -372,8 +370,7 @@
                           enc = {enc_jid, []}},
                     #attr{name = <<"xml:lang">>,
                           label = '$lang'}],
-           refs = [#ref{name = error, min = 0, max = 1, label = '$error'},
-                   #ref{name = message_subject, label = '$subject'},
+           refs = [#ref{name = message_subject, label = '$subject'},
                    #ref{name = message_thread, min = 0, max = 1, label = '$thread'},
                    #ref{name = message_body, label = '$body'}]}).
 
@@ -403,7 +400,7 @@
      #elem{name = <<"presence">>,
            xmlns = <<"jabber:client">>,
            result = {presence, '$id', '$type', '$lang', '$from', '$to',
-                     '$show', '$status', '$priority', '$error', '$_els'},
+                     '$show', '$status', '$priority', '$_els'},
            attrs = [#attr{name = <<"id">>},
                     #attr{name = <<"type">>,
 			  default = available,
@@ -419,8 +416,7 @@
                           enc = {enc_jid, []}},
                     #attr{name = <<"xml:lang">>,
                           label = '$lang'}],
-           refs = [#ref{name = error, min = 0, max = 1, label = '$error'},
-                   #ref{name = presence_show, min = 0, max = 1, label = '$show'},
+           refs = [#ref{name = presence_show, min = 0, max = 1, label = '$show'},
                    #ref{name = presence_status, label = '$status'},
                    #ref{name = presence_priority, min = 0, max = 1,
                         label = '$priority'}]}).
@@ -531,7 +527,7 @@
 -xml(error,
      #elem{name = <<"error">>,
            xmlns = <<"jabber:client">>,
-           result = {error, '$type', '$code', '$by', '$reason', '$text'},
+           result = {error, '$type', '$code', '$by', '$reason', '$text', '$_els'},
            attrs = [#attr{name = <<"type">>,
                           label = '$type',
                           required = true,
@@ -2880,8 +2876,7 @@
 -xml(db_result,
      #elem{name = <<"db:result">>,
 	   xmlns = <<"jabber:client">>,
-	   result = {db_result, '$from', '$to', '$type', '$key', '$error'},
-	   refs = [#ref{name = error, min = 0, max = 1}],
+	   result = {db_result, '$from', '$to', '$type', '$key', '$_els'},
 	   cdata = #cdata{default = <<"">>, label = '$key'},
 	   attrs = [#attr{name = <<"from">>, required = true,
 			  dec = {dec_jid, []}, enc = {enc_jid, []}},
@@ -2894,8 +2889,7 @@
 -xml(db_verify,
      #elem{name = <<"db:verify">>,
 	   xmlns = <<"jabber:client">>,
-	   result = {db_verify, '$from', '$to', '$id', '$type', '$key', '$error'},
-	   refs = [#ref{name = error, min = 0, max = 1}],
+	   result = {db_verify, '$from', '$to', '$id', '$type', '$key', '$_els'},
 	   cdata = #cdata{default = <<"">>, label = '$key'},
 	   attrs = [#attr{name = <<"from">>, required = true,
 			  dec = {dec_jid, []}, enc = {enc_jid, []}},

From e258462b6b811baa2500a2d1c843ecbecf9382a7 Mon Sep 17 00:00:00 2001
From: Evgeniy Khramtsov 
Date: Sun, 31 Jul 2016 14:17:17 +0300
Subject: [PATCH 023/151] Improve vCard creation from LDAP result

---
 src/mod_vcard_ldap.erl | 146 ++++++++++++-----------------------------
 1 file changed, 43 insertions(+), 103 deletions(-)

diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl
index 74b20d2ff..191676224 100644
--- a/src/mod_vcard_ldap.erl
+++ b/src/mod_vcard_ldap.erl
@@ -75,8 +75,9 @@ get_vcard(LUser, LServer) ->
     VCardMap = State#state.vcard_map,
     case find_ldap_user(LUser, State) of
 	#eldap_entry{attributes = Attributes} ->
-	    ldap_attributes_to_vcard(Attributes, VCardMap,
-				     {LUser, LServer});
+	    VCard = ldap_attributes_to_vcard(Attributes, VCardMap,
+					     {LUser, LServer}),
+	    [xmpp:encode(VCard)];
 	_ ->
 	    []
     end.
@@ -218,108 +219,47 @@ ldap_attributes_to_vcard(Attributes, VCardMap, UD) ->
 					      UD)}
 		      end,
 		      VCardMap),
-    Elts = [ldap_attribute_to_vcard(vCard, Attr)
-	    || Attr <- Attrs],
-    NElts = [ldap_attribute_to_vcard(vCardN, Attr)
-	     || Attr <- Attrs],
-    OElts = [ldap_attribute_to_vcard(vCardO, Attr)
-	     || Attr <- Attrs],
-    AElts = [ldap_attribute_to_vcard(vCardA, Attr)
-	     || Attr <- Attrs],
-    [#xmlel{name = <<"vCard">>,
-	    attrs = [{<<"xmlns">>, ?NS_VCARD}],
-	    children =
-		lists:append([X || X <- Elts, X /= none],
-			     [#xmlel{name = <<"N">>, attrs = [],
-				     children = [X || X <- NElts, X /= none]},
-			      #xmlel{name = <<"ORG">>, attrs = [],
-				     children = [X || X <- OElts, X /= none]},
-			      #xmlel{name = <<"ADR">>, attrs = [],
-				     children =
-					 [X || X <- AElts, X /= none]}])}].
+    lists:foldl(fun ldap_attribute_to_vcard/2, #vcard_temp{}, Attrs).
 
-ldap_attribute_to_vcard(vCard, {<<"fn">>, Value}) ->
-    #xmlel{name = <<"FN">>, attrs = [],
-	   children = [{xmlcdata, Value}]};
-ldap_attribute_to_vcard(vCard,
-			{<<"nickname">>, Value}) ->
-    #xmlel{name = <<"NICKNAME">>, attrs = [],
-	   children = [{xmlcdata, Value}]};
-ldap_attribute_to_vcard(vCard, {<<"title">>, Value}) ->
-    #xmlel{name = <<"TITLE">>, attrs = [],
-	   children = [{xmlcdata, Value}]};
-ldap_attribute_to_vcard(vCard, {<<"bday">>, Value}) ->
-    #xmlel{name = <<"BDAY">>, attrs = [],
-	   children = [{xmlcdata, Value}]};
-ldap_attribute_to_vcard(vCard, {<<"url">>, Value}) ->
-    #xmlel{name = <<"URL">>, attrs = [],
-	   children = [{xmlcdata, Value}]};
-ldap_attribute_to_vcard(vCard, {<<"desc">>, Value}) ->
-    #xmlel{name = <<"DESC">>, attrs = [],
-	   children = [{xmlcdata, Value}]};
-ldap_attribute_to_vcard(vCard, {<<"role">>, Value}) ->
-    #xmlel{name = <<"ROLE">>, attrs = [],
-	   children = [{xmlcdata, Value}]};
-ldap_attribute_to_vcard(vCard, {<<"tel">>, Value}) ->
-    #xmlel{name = <<"TEL">>, attrs = [],
-	   children =
-	       [#xmlel{name = <<"VOICE">>, attrs = [], children = []},
-		#xmlel{name = <<"WORK">>, attrs = [], children = []},
-		#xmlel{name = <<"NUMBER">>, attrs = [],
-		       children = [{xmlcdata, Value}]}]};
-ldap_attribute_to_vcard(vCard, {<<"email">>, Value}) ->
-    #xmlel{name = <<"EMAIL">>, attrs = [],
-	   children =
-	       [#xmlel{name = <<"INTERNET">>, attrs = [],
-		       children = []},
-		#xmlel{name = <<"PREF">>, attrs = [], children = []},
-		#xmlel{name = <<"USERID">>, attrs = [],
-		       children = [{xmlcdata, Value}]}]};
-ldap_attribute_to_vcard(vCard, {<<"photo">>, Value}) ->
-    #xmlel{name = <<"PHOTO">>, attrs = [],
-	   children =
-	       [#xmlel{name = <<"TYPE">>, attrs = [],
-		       children = [{xmlcdata, <<"image/jpeg">>}]},
-		#xmlel{name = <<"BINVAL">>, attrs = [],
-		       children = [{xmlcdata, jlib:encode_base64(Value)}]}]};
-ldap_attribute_to_vcard(vCardN,
-			{<<"family">>, Value}) ->
-    #xmlel{name = <<"FAMILY">>, attrs = [],
-	   children = [{xmlcdata, Value}]};
-ldap_attribute_to_vcard(vCardN, {<<"given">>, Value}) ->
-    #xmlel{name = <<"GIVEN">>, attrs = [],
-	   children = [{xmlcdata, Value}]};
-ldap_attribute_to_vcard(vCardN,
-			{<<"middle">>, Value}) ->
-    #xmlel{name = <<"MIDDLE">>, attrs = [],
-	   children = [{xmlcdata, Value}]};
-ldap_attribute_to_vcard(vCardO,
-			{<<"orgname">>, Value}) ->
-    #xmlel{name = <<"ORGNAME">>, attrs = [],
-	   children = [{xmlcdata, Value}]};
-ldap_attribute_to_vcard(vCardO,
-			{<<"orgunit">>, Value}) ->
-    #xmlel{name = <<"ORGUNIT">>, attrs = [],
-	   children = [{xmlcdata, Value}]};
-ldap_attribute_to_vcard(vCardA,
-			{<<"locality">>, Value}) ->
-    #xmlel{name = <<"LOCALITY">>, attrs = [],
-	   children = [{xmlcdata, Value}]};
-ldap_attribute_to_vcard(vCardA,
-			{<<"street">>, Value}) ->
-    #xmlel{name = <<"STREET">>, attrs = [],
-	   children = [{xmlcdata, Value}]};
-ldap_attribute_to_vcard(vCardA, {<<"ctry">>, Value}) ->
-    #xmlel{name = <<"CTRY">>, attrs = [],
-	   children = [{xmlcdata, Value}]};
-ldap_attribute_to_vcard(vCardA,
-			{<<"region">>, Value}) ->
-    #xmlel{name = <<"REGION">>, attrs = [],
-	   children = [{xmlcdata, Value}]};
-ldap_attribute_to_vcard(vCardA, {<<"pcode">>, Value}) ->
-    #xmlel{name = <<"PCODE">>, attrs = [],
-	   children = [{xmlcdata, Value}]};
-ldap_attribute_to_vcard(_, _) -> none.
+-spec ldap_attribute_to_vcard({binary(), binary()}, vcard_temp()) -> vcard_temp().
+ldap_attribute_to_vcard({Attr, Value}, V) ->
+    Ts = V#vcard_temp.tel,
+    Es = V#vcard_temp.email,
+    N = case V#vcard_temp.n of
+	    undefined -> #vcard_name{};
+	    _ -> V#vcard_temp.n
+	end,
+    O = case V#vcard_temp.org of
+	    undefined -> #vcard_org{};
+	    _ -> V#vcard_temp.org
+	end,
+    A = case V#vcard_temp.adr of
+	    [] -> #vcard_adr{};
+	    As -> hd(As)
+	end,
+    case Attr of
+	<<"fn">> -> V#vcard_temp{fn = Value};
+	<<"nickname">> -> V#vcard_temp{nickname = Value};
+	<<"title">> -> V#vcard_temp{title = Value};
+	<<"bday">> -> V#vcard_temp{bday = Value};
+	<<"url">> -> V#vcard_temp{url = Value};
+	<<"desc">> -> V#vcard_temp{desc = Value};
+	<<"role">> -> V#vcard_temp{role = Value};
+	<<"tel">> -> V#vcard_temp{tel = [#vcard_tel{number = Value}|Ts]};
+	<<"email">> -> V#vcard_temp{email = [#vcard_email{userid = Value}|Es]};
+	<<"photo">> -> V#vcard_temp{photo = #vcard_photo{binval = Value}};
+	<<"family">> -> V#vcard_temp{n = N#vcard_name{family = V}};
+	<<"given">> -> V#vcard_temp{n = N#vcard_name{given = V}};
+	<<"middle">> -> V#vcard_temp{n = N#vcard_name{middle = V}};
+	<<"orgname">> -> V#vcard_temp{org = O#vcard_org{name = V}};
+	<<"orgunit">> -> V#vcard_temp{org = O#vcard_org{units = [Value]}};
+	<<"locality">> -> V#vcard_temp{adr = [A#vcard_adr{locality = Value}]};
+	<<"street">> -> V#vcard_temp{adr = [A#vcard_adr{street = Value}]};
+	<<"ctry">> -> V#vcard_temp{adr = [A#vcard_adr{ctry = Value}]};
+	<<"region">> -> V#vcard_temp{adr = [A#vcard_adr{region = Value}]};
+	<<"pcode">> -> V#vcard_temp{adr = [A#vcard_adr{pcode = Value}]};
+	_ -> V
+    end.
 
 map_vcard_attr(VCardName, Attributes, Pattern, UD) ->
     Res = lists:filter(fun ({Name, _, _}) ->

From c0272ae7669b548a3cd568229748377feba71e57 Mon Sep 17 00:00:00 2001
From: Evgeniy Khramtsov 
Date: Sun, 31 Jul 2016 14:51:16 +0300
Subject: [PATCH 024/151] Rewrite mod_stats to use XML generator

---
 include/xmpp_codec.hrl |  14 +++--
 src/mod_stats.erl      | 104 ++++++++++++----------------------
 src/xmpp_codec.erl     | 123 ++++++++++++++++++++++++-----------------
 tools/xmpp_codec.spec  |  17 +++---
 4 files changed, 126 insertions(+), 132 deletions(-)

diff --git a/include/xmpp_codec.hrl b/include/xmpp_codec.hrl
index acbc81e4a..e3eb31285 100644
--- a/include/xmpp_codec.hrl
+++ b/include/xmpp_codec.hrl
@@ -227,10 +227,14 @@
                     nick :: binary()}).
 -type muc_actor() :: #muc_actor{}.
 
+-record(stat_error, {code :: integer(),
+                     reason = <<>> :: binary()}).
+-type stat_error() :: #stat_error{}.
+
 -record(stat, {name :: binary(),
-               units :: binary(),
-               value :: binary(),
-               error = [] :: [{integer(),'undefined' | binary()}]}).
+               units = <<>> :: binary(),
+               value = <<>> :: binary(),
+               error :: #stat_error{}}).
 -type stat() :: #stat{}.
 
 -record(addresses, {list = [] :: [#address{}]}).
@@ -367,7 +371,8 @@
 -record(stream_features, {sub_els = [] :: [any()]}).
 -type stream_features() :: #stream_features{}.
 
--record(stats, {stat = [] :: [#stat{}]}).
+-record(stats, {list = [] :: [#stat{}],
+                node = <<>> :: binary()}).
 -type stats() :: #stats{}.
 
 -record(pubsub_items, {node :: binary(),
@@ -980,6 +985,7 @@
                         feature_register() |
                         register() |
                         sm_r() |
+                        stat_error() |
                         error() |
                         stream_error() |
                         muc_user() |
diff --git a/src/mod_stats.erl b/src/mod_stats.erl
index 99059839a..c4b8ddb15 100644
--- a/src/mod_stats.erl
+++ b/src/mod_stats.erl
@@ -31,65 +31,39 @@
 
 -behaviour(gen_mod).
 
--export([start/2, stop/1, process_local_iq/3,
-	 mod_opt_type/1, depends/2]).
+-export([start/2, stop/1, process_iq/1, mod_opt_type/1, depends/2]).
 
 -include("ejabberd.hrl").
 -include("logger.hrl").
--include("jlib.hrl").
+-include("xmpp.hrl").
 
 start(Host, Opts) ->
     IQDisc = gen_mod:get_opt(iqdisc, Opts, fun gen_iq_handler:check_type/1,
                              one_queue),
-    gen_iq_handler:add_iq_handler(ejabberd_local, Host,
-				  ?NS_STATS, ?MODULE, process_local_iq, IQDisc).
+    gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_STATS,
+				  ?MODULE, process_iq, IQDisc).
 
 stop(Host) ->
-    gen_iq_handler:remove_iq_handler(ejabberd_local, Host,
-				     ?NS_STATS).
+    gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_STATS).
 
 depends(_Host, _Opts) ->
     [].
 
-process_local_iq(_From, To,
-		 #iq{id = _ID, type = Type, xmlns = XMLNS,
-		     sub_el = SubEl, lang = Lang} =
-		     IQ) ->
-    case Type of
-      set ->
-	  Txt = <<"Value 'set' of 'type' attribute is not allowed">>,
-	  IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]};
-      get ->
-	  #xmlel{children = Els} = SubEl,
-	  Node = str:tokens(fxml:get_tag_attr_s(<<"node">>, SubEl),
-			    <<"/">>),
-	  Names = get_names(Els, []),
-	  case get_local_stats(To#jid.server, Node, Names, Lang) of
-	    {result, Res} ->
-		IQ#iq{type = result,
-		      sub_el =
-			  [#xmlel{name = <<"query">>,
-				  attrs = [{<<"xmlns">>, XMLNS}],
-				  children = Res}]};
-	    {error, Error} ->
-		IQ#iq{type = error, sub_el = [SubEl, Error]}
-	  end
+process_iq(#iq{type = set, lang = Lang} = IQ) ->
+    Txt = <<"Value 'set' of 'type' attribute is not allowed">>,
+    xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang));
+process_iq(#iq{type = get, to = To, lang = Lang,
+	       sub_els = [#stats{} = Stats]} = IQ) ->
+    Node = str:tokens(Stats#stats.node, <<"/">>),
+    Names = [Name || #stat{name = Name} <- Stats#stats.list],
+    case get_local_stats(To#jid.server, Node, Names, Lang) of
+	{result, List} ->
+	    xmpp:make_iq_result(IQ, Stats#stats{list = List});
+	{error, Error} ->
+	    xmpp:make_error(IQ, Error)
     end.
 
-get_names([], Res) -> Res;
-get_names([#xmlel{name = <<"stat">>, attrs = Attrs}
-	   | Els],
-	  Res) ->
-    Name = fxml:get_attr_s(<<"name">>, Attrs),
-    case Name of
-      <<"">> -> get_names(Els, Res);
-      _ -> get_names(Els, [Name | Res])
-    end;
-get_names([_ | Els], Res) -> get_names(Els, Res).
-
--define(STAT(Name),
-	#xmlel{name = <<"stat">>, attrs = [{<<"name">>, Name}],
-	       children = []}).
+-define(STAT(Name), #stat{name = Name}).
 
 get_local_stats(_Server, [], [], _Lang) ->
     {result,
@@ -115,7 +89,7 @@ get_local_stats(_Server, [<<"running nodes">>, ENode],
     case search_running_node(ENode) of
       false ->
 	    Txt = <<"No running node found">>,
-	    {error, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)};
+	    {error, xmpp:err_item_not_found(Txt, Lang)};
       Node ->
 	  {result,
 	   lists:map(fun (Name) -> get_node_stat(Node, Name) end,
@@ -123,27 +97,19 @@ get_local_stats(_Server, [<<"running nodes">>, ENode],
     end;
 get_local_stats(_Server, _, _, Lang) ->
     Txt = <<"No statistics found for this item">>,
-    {error, ?ERRT_FEATURE_NOT_IMPLEMENTED(Lang, Txt)}.
+    {error, xmpp:err_feature_not_implemented(Txt, Lang)}.
 
--define(STATVAL(Val, Unit),
-	#xmlel{name = <<"stat">>,
-	       attrs =
-		   [{<<"name">>, Name}, {<<"units">>, Unit},
-		    {<<"value">>, Val}],
-	       children = []}).
+-define(STATVAL(Val, Unit), #stat{name = Name, units = Unit, value = Val}).
 
 -define(STATERR(Code, Desc),
-	#xmlel{name = <<"stat">>, attrs = [{<<"name">>, Name}],
-	       children =
-		   [#xmlel{name = <<"error">>,
-			   attrs = [{<<"code">>, Code}],
-			   children = [{xmlcdata, Desc}]}]}).
+	#stat{name = Name,
+	      error = #stat_error{code = Code, reason = Desc}}).
 
 get_local_stat(Server, [], Name)
     when Name == <<"users/online">> ->
     case catch ejabberd_sm:get_vh_session_list(Server) of
       {'EXIT', _Reason} ->
-	  ?STATERR(<<"500">>, <<"Internal Server Error">>);
+	  ?STATERR(500, <<"Internal Server Error">>);
       Users ->
 	  ?STATVAL((iolist_to_binary(integer_to_list(length(Users)))),
 		   <<"users">>)
@@ -154,7 +120,7 @@ get_local_stat(Server, [], Name)
 	   ejabberd_auth:get_vh_registered_users_number(Server)
 	of
       {'EXIT', _Reason} ->
-	  ?STATERR(<<"500">>, <<"Internal Server Error">>);
+	  ?STATERR(500, <<"Internal Server Error">>);
       NUsers ->
 	  ?STATVAL((iolist_to_binary(integer_to_list(NUsers))),
 		   <<"users">>)
@@ -163,7 +129,7 @@ get_local_stat(_Server, [], Name)
     when Name == <<"users/all-hosts/online">> ->
     case catch mnesia:table_info(session, size) of
       {'EXIT', _Reason} ->
-	  ?STATERR(<<"500">>, <<"Internal Server Error">>);
+	  ?STATERR(500, <<"Internal Server Error">>);
       Users ->
 	  ?STATVAL((iolist_to_binary(integer_to_list(Users))),
 		   <<"users">>)
@@ -178,7 +144,7 @@ get_local_stat(_Server, [], Name)
     ?STATVAL((iolist_to_binary(integer_to_list(NumUsers))),
 	     <<"users">>);
 get_local_stat(_Server, _, Name) ->
-    ?STATERR(<<"404">>, <<"Not Found">>).
+    ?STATERR(404, <<"Not Found">>).
 
 get_node_stat(Node, Name)
     when Name == <<"time/uptime">> ->
@@ -186,7 +152,7 @@ get_node_stat(Node, Name)
 			[wall_clock])
 	of
       {badrpc, _Reason} ->
-	  ?STATERR(<<"500">>, <<"Internal Server Error">>);
+	  ?STATERR(500, <<"Internal Server Error">>);
       CPUTime ->
 	  ?STATVAL(list_to_binary(
                      io_lib:format("~.3f",
@@ -198,7 +164,7 @@ get_node_stat(Node, Name)
     case catch ejabberd_cluster:call(Node, erlang, statistics, [runtime])
 	of
       {badrpc, _Reason} ->
-	  ?STATERR(<<"500">>, <<"Internal Server Error">>);
+	  ?STATERR(500, <<"Internal Server Error">>);
       RunTime ->
 	  ?STATVAL(list_to_binary(
                      io_lib:format("~.3f",
@@ -211,7 +177,7 @@ get_node_stat(Node, Name)
 			dirty_get_my_sessions_list, [])
 	of
       {badrpc, _Reason} ->
-	  ?STATERR(<<"500">>, <<"Internal Server Error">>);
+	  ?STATERR(500, <<"Internal Server Error">>);
       Users ->
 	  ?STATVAL((iolist_to_binary(integer_to_list(length(Users)))),
 		   <<"users">>)
@@ -222,7 +188,7 @@ get_node_stat(Node, Name)
 			[transaction_commits])
 	of
       {badrpc, _Reason} ->
-	  ?STATERR(<<"500">>, <<"Internal Server Error">>);
+	  ?STATERR(500, <<"Internal Server Error">>);
       Transactions ->
 	  ?STATVAL((iolist_to_binary(integer_to_list(Transactions))),
 		   <<"transactions">>)
@@ -233,7 +199,7 @@ get_node_stat(Node, Name)
 			[transaction_failures])
 	of
       {badrpc, _Reason} ->
-	  ?STATERR(<<"500">>, <<"Internal Server Error">>);
+	  ?STATERR(500, <<"Internal Server Error">>);
       Transactions ->
 	  ?STATVAL((iolist_to_binary(integer_to_list(Transactions))),
 		   <<"transactions">>)
@@ -244,7 +210,7 @@ get_node_stat(Node, Name)
 			[transaction_restarts])
 	of
       {badrpc, _Reason} ->
-	  ?STATERR(<<"500">>, <<"Internal Server Error">>);
+	  ?STATERR(500, <<"Internal Server Error">>);
       Transactions ->
 	  ?STATVAL((iolist_to_binary(integer_to_list(Transactions))),
 		   <<"transactions">>)
@@ -255,13 +221,13 @@ get_node_stat(Node, Name)
 			[transaction_log_writes])
 	of
       {badrpc, _Reason} ->
-	  ?STATERR(<<"500">>, <<"Internal Server Error">>);
+	  ?STATERR(500, <<"Internal Server Error">>);
       Transactions ->
 	  ?STATVAL((iolist_to_binary(integer_to_list(Transactions))),
 		   <<"transactions">>)
     end;
 get_node_stat(_, Name) ->
-    ?STATERR(<<"404">>, <<"Not Found">>).
+    ?STATERR(404, <<"Not Found">>).
 
 search_running_node(SNode) ->
     search_running_node(SNode,
diff --git a/src/xmpp_codec.erl b/src/xmpp_codec.erl
index 6fddf97ed..e0a5d47c9 100644
--- a/src/xmpp_codec.erl
+++ b/src/xmpp_codec.erl
@@ -2222,11 +2222,15 @@ encode({bookmark_url, _, _} = Url) ->
 encode({bookmark_storage, _, _} = Storage) ->
     encode_bookmarks_storage(Storage,
 			     [{<<"xmlns">>, <<"storage:bookmarks">>}]);
+encode({stat_error, _, _} = Error) ->
+    encode_stat_error(Error,
+		      [{<<"xmlns">>,
+			<<"http://jabber.org/protocol/stats">>}]);
 encode({stat, _, _, _, _} = Stat) ->
     encode_stat(Stat,
 		[{<<"xmlns">>,
 		  <<"http://jabber.org/protocol/stats">>}]);
-encode({stats, _} = Query) ->
+encode({stats, _, _} = Query) ->
     encode_stats(Query,
 		 [{<<"xmlns">>,
 		   <<"http://jabber.org/protocol/stats">>}]);
@@ -2734,8 +2738,9 @@ get_name({bookmark_conference, _, _, _, _, _}) ->
     <<"conference">>;
 get_name({bookmark_url, _, _}) -> <<"url">>;
 get_name({bookmark_storage, _, _}) -> <<"storage">>;
+get_name({stat_error, _, _}) -> <<"error">>;
 get_name({stat, _, _, _, _}) -> <<"stat">>;
-get_name({stats, _}) -> <<"query">>;
+get_name({stats, _, _}) -> <<"query">>;
 get_name({iq, _, _, _, _, _, _}) -> <<"iq">>;
 get_name({message, _, _, _, _, _, _, _, _, _}) ->
     <<"message">>;
@@ -2939,9 +2944,11 @@ get_ns({bookmark_conference, _, _, _, _, _}) ->
 get_ns({bookmark_url, _, _}) -> <<"storage:bookmarks">>;
 get_ns({bookmark_storage, _, _}) ->
     <<"storage:bookmarks">>;
+get_ns({stat_error, _, _}) ->
+    <<"http://jabber.org/protocol/stats">>;
 get_ns({stat, _, _, _, _}) ->
     <<"http://jabber.org/protocol/stats">>;
-get_ns({stats, _}) ->
+get_ns({stats, _, _}) ->
     <<"http://jabber.org/protocol/stats">>;
 get_ns({iq, _, _, _, _, _, _}) -> <<"jabber:client">>;
 get_ns({message, _, _, _, _, _, _, _, _, _}) ->
@@ -3254,8 +3261,9 @@ pp(bookmark_conference, 5) ->
     [name, jid, autojoin, nick, password];
 pp(bookmark_url, 2) -> [name, url];
 pp(bookmark_storage, 2) -> [conference, url];
+pp(stat_error, 2) -> [code, reason];
 pp(stat, 4) -> [name, units, value, error];
-pp(stats, 1) -> [stat];
+pp(stats, 2) -> [list, node];
 pp(iq, 6) -> [id, type, lang, from, to, sub_els];
 pp(message, 9) ->
     [id, type, lang, from, to, subject, body, thread,
@@ -25097,53 +25105,70 @@ encode_iq_attr_to(_val, _acc) ->
 
 decode_stats(__TopXMLNS, __IgnoreEls,
 	     {xmlel, <<"query">>, _attrs, _els}) ->
-    Stat = decode_stats_els(__TopXMLNS, __IgnoreEls, _els,
+    List = decode_stats_els(__TopXMLNS, __IgnoreEls, _els,
 			    []),
-    {stats, Stat}.
+    Node = decode_stats_attrs(__TopXMLNS, _attrs,
+			      undefined),
+    {stats, List, Node}.
 
-decode_stats_els(__TopXMLNS, __IgnoreEls, [], Stat) ->
-    lists:reverse(Stat);
+decode_stats_els(__TopXMLNS, __IgnoreEls, [], List) ->
+    lists:reverse(List);
 decode_stats_els(__TopXMLNS, __IgnoreEls,
-		 [{xmlel, <<"stat">>, _attrs, _} = _el | _els], Stat) ->
+		 [{xmlel, <<"stat">>, _attrs, _} = _el | _els], List) ->
     case get_attr(<<"xmlns">>, _attrs) of
       <<"">>
 	  when __TopXMLNS ==
 		 <<"http://jabber.org/protocol/stats">> ->
 	  decode_stats_els(__TopXMLNS, __IgnoreEls, _els,
-			   [decode_stat(__TopXMLNS, __IgnoreEls, _el) | Stat]);
+			   [decode_stat(__TopXMLNS, __IgnoreEls, _el) | List]);
       <<"http://jabber.org/protocol/stats">> ->
 	  decode_stats_els(__TopXMLNS, __IgnoreEls, _els,
 			   [decode_stat(<<"http://jabber.org/protocol/stats">>,
 					__IgnoreEls, _el)
-			    | Stat]);
+			    | List]);
       _ ->
-	  decode_stats_els(__TopXMLNS, __IgnoreEls, _els, Stat)
+	  decode_stats_els(__TopXMLNS, __IgnoreEls, _els, List)
     end;
 decode_stats_els(__TopXMLNS, __IgnoreEls, [_ | _els],
-		 Stat) ->
-    decode_stats_els(__TopXMLNS, __IgnoreEls, _els, Stat).
+		 List) ->
+    decode_stats_els(__TopXMLNS, __IgnoreEls, _els, List).
 
-encode_stats({stats, Stat}, _xmlns_attrs) ->
-    _els = lists:reverse('encode_stats_$stat'(Stat, [])),
-    _attrs = _xmlns_attrs,
+decode_stats_attrs(__TopXMLNS,
+		   [{<<"node">>, _val} | _attrs], _Node) ->
+    decode_stats_attrs(__TopXMLNS, _attrs, _val);
+decode_stats_attrs(__TopXMLNS, [_ | _attrs], Node) ->
+    decode_stats_attrs(__TopXMLNS, _attrs, Node);
+decode_stats_attrs(__TopXMLNS, [], Node) ->
+    decode_stats_attr_node(__TopXMLNS, Node).
+
+encode_stats({stats, List, Node}, _xmlns_attrs) ->
+    _els = lists:reverse('encode_stats_$list'(List, [])),
+    _attrs = encode_stats_attr_node(Node, _xmlns_attrs),
     {xmlel, <<"query">>, _attrs, _els}.
 
-'encode_stats_$stat'([], _acc) -> _acc;
-'encode_stats_$stat'([Stat | _els], _acc) ->
-    'encode_stats_$stat'(_els,
-			 [encode_stat(Stat, []) | _acc]).
+'encode_stats_$list'([], _acc) -> _acc;
+'encode_stats_$list'([List | _els], _acc) ->
+    'encode_stats_$list'(_els,
+			 [encode_stat(List, []) | _acc]).
+
+decode_stats_attr_node(__TopXMLNS, undefined) -> <<>>;
+decode_stats_attr_node(__TopXMLNS, _val) -> _val.
+
+encode_stats_attr_node(<<>>, _acc) -> _acc;
+encode_stats_attr_node(_val, _acc) ->
+    [{<<"node">>, _val} | _acc].
 
 decode_stat(__TopXMLNS, __IgnoreEls,
 	    {xmlel, <<"stat">>, _attrs, _els}) ->
     Error = decode_stat_els(__TopXMLNS, __IgnoreEls, _els,
-			    []),
+			    undefined),
     {Name, Units, Value} = decode_stat_attrs(__TopXMLNS,
 					     _attrs, undefined, undefined,
 					     undefined),
     {stat, Name, Units, Value, Error}.
 
 decode_stat_els(__TopXMLNS, __IgnoreEls, [], Error) ->
-    lists:reverse(Error);
+    Error;
 decode_stat_els(__TopXMLNS, __IgnoreEls,
 		[{xmlel, <<"error">>, _attrs, _} = _el | _els],
 		Error) ->
@@ -25152,13 +25177,11 @@ decode_stat_els(__TopXMLNS, __IgnoreEls,
 	  when __TopXMLNS ==
 		 <<"http://jabber.org/protocol/stats">> ->
 	  decode_stat_els(__TopXMLNS, __IgnoreEls, _els,
-			  [decode_stat_error(__TopXMLNS, __IgnoreEls, _el)
-			   | Error]);
+			  decode_stat_error(__TopXMLNS, __IgnoreEls, _el));
       <<"http://jabber.org/protocol/stats">> ->
 	  decode_stat_els(__TopXMLNS, __IgnoreEls, _els,
-			  [decode_stat_error(<<"http://jabber.org/protocol/stats">>,
-					     __IgnoreEls, _el)
-			   | Error]);
+			  decode_stat_error(<<"http://jabber.org/protocol/stats">>,
+					    __IgnoreEls, _el));
       _ ->
 	  decode_stat_els(__TopXMLNS, __IgnoreEls, _els, Error)
     end;
@@ -25196,10 +25219,9 @@ encode_stat({stat, Name, Units, Value, Error},
 										 _xmlns_attrs))),
     {xmlel, <<"stat">>, _attrs, _els}.
 
-'encode_stat_$error'([], _acc) -> _acc;
-'encode_stat_$error'([Error | _els], _acc) ->
-    'encode_stat_$error'(_els,
-			 [encode_stat_error(Error, []) | _acc]).
+'encode_stat_$error'(undefined, _acc) -> _acc;
+'encode_stat_$error'(Error, _acc) ->
+    [encode_stat_error(Error, []) | _acc].
 
 decode_stat_attr_name(__TopXMLNS, undefined) ->
     erlang:error({xmpp_codec,
@@ -25209,41 +25231,39 @@ decode_stat_attr_name(__TopXMLNS, _val) -> _val.
 encode_stat_attr_name(_val, _acc) ->
     [{<<"name">>, _val} | _acc].
 
-decode_stat_attr_units(__TopXMLNS, undefined) ->
-    undefined;
+decode_stat_attr_units(__TopXMLNS, undefined) -> <<>>;
 decode_stat_attr_units(__TopXMLNS, _val) -> _val.
 
-encode_stat_attr_units(undefined, _acc) -> _acc;
+encode_stat_attr_units(<<>>, _acc) -> _acc;
 encode_stat_attr_units(_val, _acc) ->
     [{<<"units">>, _val} | _acc].
 
-decode_stat_attr_value(__TopXMLNS, undefined) ->
-    undefined;
+decode_stat_attr_value(__TopXMLNS, undefined) -> <<>>;
 decode_stat_attr_value(__TopXMLNS, _val) -> _val.
 
-encode_stat_attr_value(undefined, _acc) -> _acc;
+encode_stat_attr_value(<<>>, _acc) -> _acc;
 encode_stat_attr_value(_val, _acc) ->
     [{<<"value">>, _val} | _acc].
 
 decode_stat_error(__TopXMLNS, __IgnoreEls,
 		  {xmlel, <<"error">>, _attrs, _els}) ->
-    Cdata = decode_stat_error_els(__TopXMLNS, __IgnoreEls,
-				  _els, <<>>),
+    Reason = decode_stat_error_els(__TopXMLNS, __IgnoreEls,
+				   _els, <<>>),
     Code = decode_stat_error_attrs(__TopXMLNS, _attrs,
 				   undefined),
-    {Code, Cdata}.
+    {stat_error, Code, Reason}.
 
 decode_stat_error_els(__TopXMLNS, __IgnoreEls, [],
-		      Cdata) ->
-    decode_stat_error_cdata(__TopXMLNS, Cdata);
+		      Reason) ->
+    decode_stat_error_cdata(__TopXMLNS, Reason);
 decode_stat_error_els(__TopXMLNS, __IgnoreEls,
-		      [{xmlcdata, _data} | _els], Cdata) ->
+		      [{xmlcdata, _data} | _els], Reason) ->
     decode_stat_error_els(__TopXMLNS, __IgnoreEls, _els,
-			  <>);
+			  <>);
 decode_stat_error_els(__TopXMLNS, __IgnoreEls,
-		      [_ | _els], Cdata) ->
+		      [_ | _els], Reason) ->
     decode_stat_error_els(__TopXMLNS, __IgnoreEls, _els,
-			  Cdata).
+			  Reason).
 
 decode_stat_error_attrs(__TopXMLNS,
 			[{<<"code">>, _val} | _attrs], _Code) ->
@@ -25254,8 +25274,9 @@ decode_stat_error_attrs(__TopXMLNS, [_ | _attrs],
 decode_stat_error_attrs(__TopXMLNS, [], Code) ->
     decode_stat_error_attr_code(__TopXMLNS, Code).
 
-encode_stat_error({Code, Cdata}, _xmlns_attrs) ->
-    _els = encode_stat_error_cdata(Cdata, []),
+encode_stat_error({stat_error, Code, Reason},
+		  _xmlns_attrs) ->
+    _els = encode_stat_error_cdata(Reason, []),
     _attrs = encode_stat_error_attr_code(Code,
 					 _xmlns_attrs),
     {xmlel, <<"error">>, _attrs, _els}.
@@ -25274,10 +25295,10 @@ decode_stat_error_attr_code(__TopXMLNS, _val) ->
 encode_stat_error_attr_code(_val, _acc) ->
     [{<<"code">>, enc_int(_val)} | _acc].
 
-decode_stat_error_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_stat_error_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_stat_error_cdata(__TopXMLNS, _val) -> _val.
 
-encode_stat_error_cdata(undefined, _acc) -> _acc;
+encode_stat_error_cdata(<<>>, _acc) -> _acc;
 encode_stat_error_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
diff --git a/tools/xmpp_codec.spec b/tools/xmpp_codec.spec
index 964b631c2..a50b58b59 100644
--- a/tools/xmpp_codec.spec
+++ b/tools/xmpp_codec.spec
@@ -289,7 +289,8 @@
 -xml(stat_error,
      #elem{name = <<"error">>,
            xmlns = <<"http://jabber.org/protocol/stats">>,
-           result = {'$code', '$cdata'},
+           result = {stat_error, '$code', '$reason'},
+	   cdata = #cdata{default = <<"">>, label = '$reason'},
            attrs = [#attr{name = <<"code">>,
                           required = true,
                           enc = {enc_int, []},
@@ -301,17 +302,17 @@
            result = {stat, '$name', '$units', '$value', '$error'},
            attrs = [#attr{name = <<"name">>,
                           required = true},
-                    #attr{name = <<"units">>},
-                    #attr{name = <<"value">>}],
-           refs = [#ref{name = stat_error,
-                        label = '$error'}]}).
+                    #attr{name = <<"units">>, default = <<"">>},
+                    #attr{name = <<"value">>, default = <<"">>}],
+           refs = [#ref{name = stat_error, label = '$error',
+			min = 0, max = 1}]}).
 
 -xml(stats,
      #elem{name = <<"query">>,
            xmlns = <<"http://jabber.org/protocol/stats">>,
-           result = {stats, '$stat'},
-           refs = [#ref{name = stat,
-                        label = '$stat'}]}).
+           result = {stats, '$list', '$node'},
+	   attrs = [#attr{name = <<"node">>, default = <<"">>}],
+           refs = [#ref{name = stat, label = '$list'}]}).
 
 -xml(iq,
      #elem{name = <<"iq">>,

From 5d06c6acbf9dfc69085f29ce38fe0ac6bdf5d9b0 Mon Sep 17 00:00:00 2001
From: Evgeniy Khramtsov 
Date: Wed, 3 Aug 2016 10:34:54 +0300
Subject: [PATCH 025/151] Rewrite mod_configure to use XML generator

---
 src/mod_configure.erl | 1876 ++++++++++++++++-------------------------
 1 file changed, 729 insertions(+), 1147 deletions(-)

diff --git a/src/mod_configure.erl b/src/mod_configure.erl
index 97c944842..342a15232 100644
--- a/src/mod_configure.erl
+++ b/src/mod_configure.erl
@@ -40,10 +40,8 @@
 
 -include("ejabberd.hrl").
 -include("logger.hrl").
-
--include("jlib.hrl").
+-include("xmpp.hrl").
 -include("ejabberd_sm.hrl").
--include("adhoc.hrl").
 
 -define(T(Lang, Text), translate:translate(Lang, Text)).
 
@@ -102,29 +100,19 @@ depends(_Host, _Opts) ->
 %%%-----------------------------------------------------------------------
 
 -define(INFO_IDENTITY(Category, Type, Name, Lang),
-	[#xmlel{name = <<"identity">>,
-		attrs =
-		    [{<<"category">>, Category}, {<<"type">>, Type},
-		     {<<"name">>, ?T(Lang, Name)}],
-		children = []}]).
+	[#identity{category = Category, type = Type, name = ?T(Lang, Name)}]).
 
 -define(INFO_COMMAND(Name, Lang),
 	?INFO_IDENTITY(<<"automation">>, <<"command-node">>,
 		       Name, Lang)).
 
 -define(NODEJID(To, Name, Node),
-	#xmlel{name = <<"item">>,
-	       attrs =
-		   [{<<"jid">>, jid:to_string(To)},
-		    {<<"name">>, ?T(Lang, Name)}, {<<"node">>, Node}],
-	       children = []}).
+	#disco_item{jid = To, name = ?T(Lang, Name), node = Node}).
 
 -define(NODE(Name, Node),
-	#xmlel{name = <<"item">>,
-	       attrs =
-		   [{<<"jid">>, Server}, {<<"name">>, ?T(Lang, Name)},
-		    {<<"node">>, Node}],
-	       children = []}).
+	#disco_item{jid = jid:make(Server),
+		    node = Node,
+		    name = ?T(Lang, Name)}).
 
 -define(NS_ADMINX(Sub),
 	<<(?NS_ADMIN)/binary, "#", Sub/binary>>).
@@ -133,6 +121,7 @@ depends(_Host, _Opts) ->
 	[<<"http:">>, <<"jabber.org">>, <<"protocol">>,
 	 <<"admin">>, Sub]).
 
+tokenize(undefined) -> [];
 tokenize(Node) -> str:tokens(Node, <<"/#">>).
 
 get_sm_identity(Acc, _From, _To, Node, Lang) ->
@@ -204,7 +193,7 @@ get_local_identity(Acc, _From, _To, Node, Lang) ->
 
 -define(INFO_RESULT(Allow, Feats, Lang),
 	case Allow of
-	  deny -> {error, ?ERRT_FORBIDDEN(Lang, <<"Denied by ACL">>)};
+	  deny -> {error, xmpp:err_forbidden(<<"Denied by ACL">>, Lang)};
 	  allow -> {result, Feats}
 	end).
 
@@ -291,12 +280,8 @@ adhoc_sm_items(Acc, From, #jid{lserver = LServer} = To,
 		    {result, Its} -> Its;
 		    empty -> []
 		  end,
-	  Nodes = [#xmlel{name = <<"item">>,
-			  attrs =
-			      [{<<"jid">>, jid:to_string(To)},
-			       {<<"name">>, ?T(Lang, <<"Configuration">>)},
-			       {<<"node">>, <<"config">>}],
-			  children = []}],
+	  Nodes = [#disco_item{jid = To, node = <<"config">>,
+			       name = ?T(Lang, <<"Configuration">>)}],
 	  {result, Items ++ Nodes};
       _ -> Acc
     end.
@@ -315,7 +300,7 @@ get_sm_items(Acc, From,
 		    empty -> []
 		  end,
 	  case {acl:match_rule(LServer, configure, From), Node} of
-	    {allow, <<"">>} ->
+	    {allow, undefined} ->
 		Nodes = [?NODEJID(To, <<"Configuration">>,
 				  <<"config">>),
 			 ?NODEJID(To, <<"User Management">>, <<"user">>)],
@@ -323,7 +308,7 @@ get_sm_items(Acc, From,
 		 Items ++ Nodes ++ get_user_resources(User, Server)};
 	    {allow, <<"config">>} -> {result, []};
 	    {_, <<"config">>} ->
-		  {error, ?ERRT_FORBIDDEN(Lang, <<"Denied by ACL">>)};
+		  {error, xmpp:err_forbidden(<<"Denied by ACL">>, Lang)};
 	    _ -> Acc
 	  end
     end.
@@ -331,13 +316,8 @@ get_sm_items(Acc, From,
 get_user_resources(User, Server) ->
     Rs = ejabberd_sm:get_user_resources(User, Server),
     lists:map(fun (R) ->
-		      #xmlel{name = <<"item">>,
-			     attrs =
-				 [{<<"jid">>,
-				   <>},
-				  {<<"name">>, User}],
-			     children = []}
+		      #disco_item{jid = jid:make(User, Server, R),
+				  name = User}
 	      end,
 	      lists:sort(Rs)).
 
@@ -383,25 +363,19 @@ recursively_get_local_items(PermLev, LServer, Node,
 	      {result, Res} -> Res;
 	      {error, _Error} -> []
 	    end,
-    Nodes = lists:flatten(lists:map(fun (N) ->
-					    S = fxml:get_tag_attr_s(<<"jid">>,
-								   N),
-					    Nd = fxml:get_tag_attr_s(<<"node">>,
-								    N),
-					    if (S /= Server) or
-						 (Nd == <<"">>) ->
-						   [];
-					       true ->
-						   [N,
-						    recursively_get_local_items(PermLev,
-										LServer,
-										Nd,
-										Server,
-										Lang)]
-					    end
-				    end,
-				    Items)),
-    Nodes.
+    lists:flatten(
+      lists:map(
+	fun(#disco_item{jid = #jid{server = S}, node = Nd} = Item) ->
+		if (S /= Server) or
+		   (Nd == <<"">>) ->
+			[];
+		   true ->
+			[Item,
+			 recursively_get_local_items(
+			   PermLev, LServer, Nd, Server, Lang)]
+		end
+	end,
+	Items)).
 
 get_permission_level(JID) ->
     case acl:match_rule(global, configure, JID) of
@@ -425,7 +399,7 @@ get_permission_level(JID) ->
 	end).
 
 get_local_items(Acc, From, #jid{lserver = LServer} = To,
-		<<"">>, Lang) ->
+		undefined, Lang) ->
     case gen_mod:is_loaded(LServer, mod_adhoc) of
       false -> Acc;
       _ ->
@@ -453,7 +427,7 @@ get_local_items(Acc, From, #jid{lserver = LServer} = To,
       _ ->
 	  LNode = tokenize(Node),
 	  Allow = acl:match_rule(LServer, configure, From),
-	  Err = ?ERRT_FORBIDDEN(Lang, <<"Denied by ACL">>),
+	  Err = xmpp:err_forbidden(<<"Denied by ACL">>, Lang),
 	  case LNode of
 	    [<<"config">>] ->
 		?ITEMS_RESULT(Allow, LNode, {error, Err});
@@ -570,27 +544,18 @@ get_local_items({_, Host},
 		_Lang) ->
     Users = ejabberd_auth:get_vh_registered_users(Host),
     SUsers = lists:sort([{S, U} || {U, S} <- Users]),
-    case catch begin
-		   [S1, S2] = ejabberd_regexp:split(Diap, <<"-">>),
-		   N1 = jlib:binary_to_integer(S1),
-		   N2 = jlib:binary_to_integer(S2),
-		   Sub = lists:sublist(SUsers, N1, N2 - N1 + 1),
-		   lists:map(fun ({S, U}) ->
-				     #xmlel{name = <<"item">>,
-					    attrs =
-						[{<<"jid">>,
-						  <>},
-						 {<<"name">>,
-						  <>}],
-					    children = []}
-			     end,
-			     Sub)
-	       end
-    of
-	{'EXIT', _Reason} -> ?ERR_NOT_ACCEPTABLE;
-	Res -> {result, Res}
+    try
+	[S1, S2] = ejabberd_regexp:split(Diap, <<"-">>),
+	N1 = jlib:binary_to_integer(S1),
+	N2 = jlib:binary_to_integer(S2),
+	Sub = lists:sublist(SUsers, N1, N2 - N1 + 1),
+	{result, lists:map(
+		   fun({S, U}) ->
+			   #disco_item{jid = jid:make(U, S),
+				       name = <>}
+		   end, Sub)}
+    catch _:_ ->
+	    xmpp:err_not_acceptable()
     end;
 get_local_items({_, Host}, [<<"outgoing s2s">>],
 		_Server, Lang) ->
@@ -676,24 +641,18 @@ get_local_items(_Host,
 		_Lang) ->
     {result, []};
 get_local_items(_Host, _, _Server, _Lang) ->
-    {error, ?ERR_ITEM_NOT_FOUND}.
+    {error, xmpp:err_item_not_found()}.
 
 get_online_vh_users(Host) ->
     case catch ejabberd_sm:get_vh_session_list(Host) of
       {'EXIT', _Reason} -> [];
       USRs ->
 	  SURs = lists:sort([{S, U, R} || {U, S, R} <- USRs]),
-	  lists:map(fun ({S, U, R}) ->
-			    #xmlel{name = <<"item">>,
-				   attrs =
-				       [{<<"jid">>,
-					 <>},
-					{<<"name">>,
-					 <>}],
-				   children = []}
-		    end,
-		    SURs)
+	  lists:map(
+	    fun({S, U, R}) ->
+		    #disco_item{jid = jid:make(U, S, R),
+				name = <>}
+		    end, SURs)
     end.
 
 get_all_vh_users(Host) ->
@@ -704,16 +663,10 @@ get_all_vh_users(Host) ->
 	  SUsers = lists:sort([{S, U} || {U, S} <- Users]),
 	  case length(SUsers) of
 	    N when N =< 100 ->
-		lists:map(fun ({S, U}) ->
-				  #xmlel{name = <<"item">>,
-					 attrs =
-					     [{<<"jid">>,
-					       <>},
-					      {<<"name">>,
-					       <>}],
-					 children = []}
-			  end,
-			  SUsers);
+		lists:map(fun({S, U}) ->
+				  #disco_item{jid = jid:make(U, S),
+					      name = <>}
+			  end, SUsers);
 	    N ->
 		NParts = trunc(math:sqrt(N * 6.17999999999999993783e-1))
 			   + 1,
@@ -730,13 +683,9 @@ get_all_vh_users(Host) ->
 					     end,
 				  Name = <>,
-				  #xmlel{name = <<"item">>,
-					 attrs =
-					     [{<<"jid">>, Host},
-					      {<<"node">>,
-					       <<"all users/", Node/binary>>},
-					      {<<"name">>, Name}],
-					 children = []}
+				  #disco_item{jid = jid:make(Host),
+					      node = <<"all users/", Node/binary>>,
+					      name = Name}
 			  end,
 			  lists:seq(1, N, M))
 	  end
@@ -750,59 +699,45 @@ get_outgoing_s2s(Host, Lang) ->
 	  TConns = [TH
 		    || {FH, TH} <- Connections,
 		       Host == FH orelse str:suffix(DotHost, FH)],
-	  lists:map(fun (T) ->
-			    #xmlel{name = <<"item">>,
-				   attrs =
-				       [{<<"jid">>, Host},
-					{<<"node">>,
-					 <<"outgoing s2s/", T/binary>>},
-					{<<"name">>,
-					 iolist_to_binary(io_lib:format(?T(Lang,
-									   <<"To ~s">>),
-									[T]))}],
-				   children = []}
-		    end,
-		    lists:usort(TConns))
+	  lists:map(
+	    fun (T) ->
+		    Name = iolist_to_binary(
+			     io_lib:format(?T(Lang, <<"To ~s">>),[T])),
+		    #disco_item{jid = jid:make(Host),
+				node = <<"outgoing s2s/", T/binary>>,
+				name = Name}
+	    end, lists:usort(TConns))
     end.
 
 get_outgoing_s2s(Host, Lang, To) ->
     case catch ejabberd_s2s:dirty_get_connections() of
       {'EXIT', _Reason} -> [];
       Connections ->
-	  lists:map(fun ({F, _T}) ->
-			    #xmlel{name = <<"item">>,
-				   attrs =
-				       [{<<"jid">>, Host},
-					{<<"node">>,
-					 <<"outgoing s2s/", To/binary, "/",
-					   F/binary>>},
-					{<<"name">>,
-					 iolist_to_binary(io_lib:format(?T(Lang,
-									   <<"From ~s">>),
-									[F]))}],
-				   children = []}
-		    end,
-		    lists:keysort(1,
-				  lists:filter(fun (E) -> element(2, E) == To
-					       end,
-					       Connections)))
+	  lists:map(
+	    fun ({F, _T}) ->
+		    Node = <<"outgoing s2s/", To/binary, "/", F/binary>>,
+		    Name = iolist_to_binary(
+			     io_lib:format(?T(Lang, <<"From ~s">>), [F])),
+		    #disco_item{jid = jid:make(Host), node = Node, name = Name}
+	    end,
+	    lists:keysort(1,
+			  lists:filter(fun (E) -> element(2, E) == To
+				       end,
+				       Connections)))
     end.
 
 get_running_nodes(Server, _Lang) ->
     case catch mnesia:system_info(running_db_nodes) of
       {'EXIT', _Reason} -> [];
       DBNodes ->
-	  lists:map(fun (N) ->
-			    S = iolist_to_binary(atom_to_list(N)),
-			    #xmlel{name = <<"item">>,
-				   attrs =
-				       [{<<"jid">>, Server},
-					{<<"node">>,
-					 <<"running nodes/", S/binary>>},
-					{<<"name">>, S}],
-				   children = []}
-		    end,
-		    lists:sort(DBNodes))
+	  lists:map(
+	    fun (N) ->
+		    S = iolist_to_binary(atom_to_list(N)),
+		    #disco_item{jid = jid:make(Server),
+				node = <<"running nodes/", S/binary>>,
+				name = S}
+	    end,
+	    lists:sort(DBNodes))
     end.
 
 get_stopped_nodes(_Lang) ->
@@ -812,17 +747,14 @@ get_stopped_nodes(_Lang) ->
 	of
       {'EXIT', _Reason} -> [];
       DBNodes ->
-	  lists:map(fun (N) ->
-			    S = iolist_to_binary(atom_to_list(N)),
-			    #xmlel{name = <<"item">>,
-				   attrs =
-				       [{<<"jid">>, ?MYNAME},
-					{<<"node">>,
-					 <<"stopped nodes/", S/binary>>},
-					{<<"name">>, S}],
-				   children = []}
-		    end,
-		    lists:sort(DBNodes))
+	  lists:map(
+	    fun (N) ->
+		    S = iolist_to_binary(atom_to_list(N)),
+		    #disco_item{jid = jid:make(?MYNAME),
+				node = <<"stopped nodes/", S/binary>>,
+				name = S}
+	    end,
+	    lists:sort(DBNodes))
     end.
 
 %%-------------------------------------------------------------------------
@@ -830,13 +762,13 @@ get_stopped_nodes(_Lang) ->
 -define(COMMANDS_RESULT(LServerOrGlobal, From, To,
 			Request, Lang),
 	case acl:match_rule(LServerOrGlobal, configure, From) of
-	  deny -> {error, ?ERRT_FORBIDDEN(Lang, <<"Denied by ACL">>)};
+	  deny -> {error, xmpp:err_forbidden(<<"Denied by ACL">>, Lang)};
 	  allow -> adhoc_local_commands(From, To, Request)
 	end).
 
 adhoc_local_commands(Acc, From,
 		     #jid{lserver = LServer} = To,
-		     #adhoc_request{node = Node, lang = Lang} = Request) ->
+		     #adhoc_command{node = Node, lang = Lang} = Request) ->
     LNode = tokenize(Node),
     case LNode of
       [<<"running nodes">>, _ENode, <<"DB">>] ->
@@ -860,171 +792,107 @@ adhoc_local_commands(Acc, From,
 
 adhoc_local_commands(From,
 		     #jid{lserver = LServer} = _To,
-		     #adhoc_request{lang = Lang, node = Node,
-				    sessionid = SessionID, action = Action,
-				    xdata = XData} =
-			 Request) ->
+		     #adhoc_command{lang = Lang, node = Node,
+				    sid = SessionID, action = Action,
+				    xdata = XData} = Request) ->
     LNode = tokenize(Node),
-    ActionIsExecute = lists:member(Action,
-				   [<<"">>, <<"execute">>, <<"complete">>]),
-    if Action == <<"cancel">> ->
-	   adhoc:produce_response(Request,
-				  #adhoc_response{status = canceled});
-       XData == false, ActionIsExecute ->
+    ActionIsExecute = Action == execute orelse Action == complete,
+    if Action == cancel ->
+	    #adhoc_command{status = canceled, lang = Lang,
+			   node = Node, sid = SessionID};
+       XData == undefined, ActionIsExecute ->
 	   case get_form(LServer, LNode, Lang) of
 	     {result, Form} ->
-		 adhoc:produce_response(Request,
-					#adhoc_response{status = executing,
-							elements = Form});
+		 xmpp_util:make_adhoc_response(
+		   Request,
+		   #adhoc_command{status = executing, xdata = Form});
 	     {result, Status, Form} ->
-		 adhoc:produce_response(Request,
-					#adhoc_response{status = Status,
-							elements = Form});
+		 xmpp_util:make_adhoc_response(
+		   Request,
+		   #adhoc_command{status = Status, xdata = Form});
 	     {error, Error} -> {error, Error}
 	   end;
-       XData /= false, ActionIsExecute ->
-	   case jlib:parse_xdata_submit(XData) of
-	     invalid ->
-		 {error, ?ERRT_BAD_REQUEST(Lang, <<"Incorrect data form">>)};
-	     Fields ->
-		 case catch set_form(From, LServer, LNode, Lang, Fields)
-		     of
-		   {result, Res} ->
-		       adhoc:produce_response(#adhoc_response{lang = Lang,
-							      node = Node,
-							      sessionid =
-								  SessionID,
-							      elements = Res,
-							      status =
-								  completed});
-		   {'EXIT', _} -> {error, ?ERR_BAD_REQUEST};
-		   {error, Error} -> {error, Error}
-		 end
-	   end;
+       XData /= undefined, ActionIsExecute ->
+	    case catch set_form(From, LServer, LNode, Lang, XData) of
+		{result, Res} ->
+		    xmpp_util:make_adhoc_response(
+		      Request,
+		      #adhoc_command{xdata = Res, status = completed});
+		{'EXIT', _} -> {error, xmpp:err_bad_request()};
+		{error, Error} -> {error, Error}
+	    end;
        true ->
-	  {error, ?ERRT_BAD_REQUEST(Lang, <<"Incorrect action or data form">>)}
+	  {error, xmpp:err_bad_request(<<"Unexpected action">>, Lang)}
     end.
 
 -define(TVFIELD(Type, Var, Val),
-	#xmlel{name = <<"field">>,
-	       attrs = [{<<"type">>, Type}, {<<"var">>, Var}],
-	       children =
-		   [#xmlel{name = <<"value">>, attrs = [],
-			   children = [{xmlcdata, Val}]}]}).
+	#xdata_field{type = Type, var = Var, values = [Val]}).
 
 -define(HFIELD(),
-	?TVFIELD(<<"hidden">>, <<"FORM_TYPE">>, (?NS_ADMIN))).
+	?TVFIELD(hidden, <<"FORM_TYPE">>, (?NS_ADMIN))).
 
 -define(TLFIELD(Type, Label, Var),
-	#xmlel{name = <<"field">>,
-	       attrs =
-		   [{<<"type">>, Type}, {<<"label">>, ?T(Lang, Label)},
-		    {<<"var">>, Var}],
-	       children = []}).
+	#xdata_field{type = Type, label = ?T(Lang, Label), var = Var}).
 
 -define(XFIELD(Type, Label, Var, Val),
-	#xmlel{name = <<"field">>,
-	       attrs =
-		   [{<<"type">>, Type}, {<<"label">>, ?T(Lang, Label)},
-		    {<<"var">>, Var}],
-	       children =
-		   [#xmlel{name = <<"value">>, attrs = [],
-			   children = [{xmlcdata, Val}]}]}).
+	#xdata_field{type = Type, label = ?T(Lang, Label),
+		     var = Var, values = [Val]}).
 
 -define(XMFIELD(Type, Label, Var, Vals),
-	#xmlel{name = <<"field">>,
-	       attrs =
-		   [{<<"type">>, Type}, {<<"label">>, ?T(Lang, Label)},
-		    {<<"var">>, Var}],
-	       children =
-		   [#xmlel{name = <<"value">>, attrs = [],
-			   children = [{xmlcdata, Val}]}
-		    || Val <- Vals]}).
+	#xdata_field{type = Type, label = ?T(Lang, Label),
+		     var = Var, values = Vals}).
 
 -define(TABLEFIELD(Table, Val),
-	#xmlel{name = <<"field">>,
-	       attrs =
-		   [{<<"type">>, <<"list-single">>},
-		    {<<"label">>, iolist_to_binary(atom_to_list(Table))},
-		    {<<"var">>, iolist_to_binary(atom_to_list(Table))}],
-	       children =
-		   [#xmlel{name = <<"value">>, attrs = [],
-			   children =
-			       [{xmlcdata,
-				 iolist_to_binary(atom_to_list(Val))}]},
-		    #xmlel{name = <<"option">>,
-			   attrs = [{<<"label">>, ?T(Lang, <<"RAM copy">>)}],
-			   children =
-			       [#xmlel{name = <<"value">>, attrs = [],
-				       children =
-					   [{xmlcdata, <<"ram_copies">>}]}]},
-		    #xmlel{name = <<"option">>,
-			   attrs =
-			       [{<<"label">>,
-				 ?T(Lang, <<"RAM and disc copy">>)}],
-			   children =
-			       [#xmlel{name = <<"value">>, attrs = [],
-				       children =
-					   [{xmlcdata, <<"disc_copies">>}]}]},
-		    #xmlel{name = <<"option">>,
-			   attrs =
-			       [{<<"label">>, ?T(Lang, <<"Disc only copy">>)}],
-			   children =
-			       [#xmlel{name = <<"value">>, attrs = [],
-				       children =
-					   [{xmlcdata,
-					     <<"disc_only_copies">>}]}]},
-		    #xmlel{name = <<"option">>,
-			   attrs = [{<<"label">>, ?T(Lang, <<"Remote copy">>)}],
-			   children =
-			       [#xmlel{name = <<"value">>, attrs = [],
-				       children =
-					   [{xmlcdata, <<"unknown">>}]}]}]}).
+	#xdata_field{
+	   type = 'list-single',
+	   label = iolist_to_binary(atom_to_list(Table)),
+	   var = iolist_to_binary(atom_to_list(Table)),
+	   values = [iolist_to_binary(atom_to_list(Val))],
+	   options = [#xdata_option{label = ?T(Lang, <<"RAM copy">>),
+				    value = <<"ram_copies">>},
+		      #xdata_option{label = ?T(Lang, <<"RAM and disc copy">>),
+				    value = <<"disc_copies">>},
+		      #xdata_option{label = ?T(Lang, <<"Disc only copy">>),
+				    value =  <<"disc_only_copies">>},
+		      #xdata_option{label = ?T(Lang, <<"Remote copy">>),
+				    value = <<"unknown">>}]}).
 
 get_form(_Host, [<<"running nodes">>, ENode, <<"DB">>],
 	 Lang) ->
     case search_running_node(ENode) of
       false ->
 	  Txt = <<"No running node found">>,
-	  {error, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)};
+	  {error, xmpp:err_item_not_found(Txt, Lang)};
       Node ->
 	  case ejabberd_cluster:call(Node, mnesia, system_info, [tables]) of
 	    {badrpc, Reason} ->
 		?ERROR_MSG("RPC call mnesia:system_info(tables) on node "
 			   "~s failed: ~p", [Node, Reason]),
-		{error, ?ERR_INTERNAL_SERVER_ERROR};
+		{error, xmpp:err_internal_server_error()};
 	    Tables ->
 		STables = lists:sort(Tables),
-		{result,
-		 [#xmlel{name = <<"x">>,
-			 attrs = [{<<"xmlns">>, ?NS_XDATA}],
-			 children =
-			     [?HFIELD(),
-			      #xmlel{name = <<"title">>, attrs = [],
-				     children =
-					 [{xmlcdata,
-					   <<(?T(Lang,
-						 <<"Database Tables Configuration at ">>))/binary,
-					     ENode/binary>>}]},
-			      #xmlel{name = <<"instructions">>, attrs = [],
-				     children =
-					 [{xmlcdata,
-					   ?T(Lang,
-					      <<"Choose storage type of tables">>)}]}
-			      | lists:map(fun (Table) ->
-						  case ejabberd_cluster:call(Node, mnesia,
-								table_info,
-								[Table,
-								 storage_type])
-						      of
-						    {badrpc, _} ->
-							?TABLEFIELD(Table,
-								    unknown);
-						    Type ->
-							?TABLEFIELD(Table, Type)
-						  end
-					  end,
-					  STables)]}]}
+		Title = <<(?T(Lang, <<"Database Tables Configuration at ">>))/binary,
+			  ENode/binary>>,
+		Instr = ?T(Lang, <<"Choose storage type of tables">>),
+		try
+		    Fs = lists:map(
+			   fun(Table) ->
+				   case ejabberd_cluster:call(
+					  Node, mnesia, table_info,
+					  [Table, storage_type]) of
+				       Type when is_atom(Type) ->
+					   ?TABLEFIELD(Table, Type)
+				   end
+			   end, STables),
+		    {result, #xdata{title = Title,
+				    type = form,
+				    instructions = [Instr],
+				    fields = [?HFIELD()|Fs]}}
+		catch _:{case_clause, {badrpc, Reason}} ->
+			?ERROR_MSG("RPC call mnesia:table_info/2 "
+				   "on node ~s failed: ~p", [Node, Reason]),
+			{error, xmpp:err_internal_server_error()}
+		end
 	  end
     end;
 get_form(Host,
@@ -1033,37 +901,26 @@ get_form(Host,
     case search_running_node(ENode) of
       false ->
 	  Txt = <<"No running node found">>,
-	  {error, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)};
+	  {error, xmpp:err_item_not_found(Txt, Lang)};
       Node ->
 	  case ejabberd_cluster:call(Node, gen_mod, loaded_modules, [Host]) of
 	    {badrpc, Reason} ->
 		?ERROR_MSG("RPC call gen_mod:loaded_modules(~s) on node "
 			   "~s failed: ~p", [Host, Node, Reason]),
-		{error, ?ERR_INTERNAL_SERVER_ERROR};
+		{error, xmpp:err_internal_server_error()};
 	    Modules ->
 		SModules = lists:sort(Modules),
-		{result,
-		 [#xmlel{name = <<"x">>,
-			 attrs = [{<<"xmlns">>, ?NS_XDATA}],
-			 children =
-			     [?HFIELD(),
-			      #xmlel{name = <<"title">>, attrs = [],
-				     children =
-					 [{xmlcdata,
-					   <<(?T(Lang,
-						 <<"Stop Modules at ">>))/binary,
-					     ENode/binary>>}]},
-			      #xmlel{name = <<"instructions">>, attrs = [],
-				     children =
-					 [{xmlcdata,
-					   ?T(Lang,
-					      <<"Choose modules to stop">>)}]}
-			      | lists:map(fun (M) ->
-						  S = jlib:atom_to_binary(M),
-						  ?XFIELD(<<"boolean">>, S, S,
-							  <<"0">>)
-					  end,
-					  SModules)]}]}
+		Title = <<(?T(Lang, <<"Stop Modules at ">>))/binary,
+			  ENode/binary>>,
+		Instr = ?T(Lang, <<"Choose modules to stop">>),
+		Fs = lists:map(fun(M) ->
+				       S = jlib:atom_to_binary(M),
+				       ?XFIELD(boolean, S, S, <<"0">>)
+			       end, SModules),
+		{result, #xdata{title = Title,
+				type = form,
+				instructions = [Instr],
+				fields = [?HFIELD()|Fs]}}
 	  end
     end;
 get_form(_Host,
@@ -1071,153 +928,88 @@ get_form(_Host,
 	  <<"start">>],
 	 Lang) ->
     {result,
-     [#xmlel{name = <<"x">>,
-	     attrs = [{<<"xmlns">>, ?NS_XDATA}],
-	     children =
-		 [?HFIELD(),
-		  #xmlel{name = <<"title">>, attrs = [],
-			 children =
-			     [{xmlcdata,
-			       <<(?T(Lang, <<"Start Modules at ">>))/binary,
-				 ENode/binary>>}]},
-		  #xmlel{name = <<"instructions">>, attrs = [],
-			 children =
-			     [{xmlcdata,
-			       ?T(Lang,
-				  <<"Enter list of {Module, [Options]}">>)}]},
-		  ?XFIELD(<<"text-multi">>,
-			  <<"List of modules to start">>, <<"modules">>,
-			  <<"[].">>)]}]};
+     #xdata{title = <<(?T(Lang, <<"Start Modules at ">>))/binary, ENode/binary>>,
+	    type = form,
+	    instructions = [?T(Lang, <<"Enter list of {Module, [Options]}">>)],
+	    fields = [?HFIELD(),
+		      ?XFIELD('text-multi',
+			      <<"List of modules to start">>, <<"modules">>,
+			      <<"[].">>)]}};
 get_form(_Host,
 	 [<<"running nodes">>, ENode, <<"backup">>,
 	  <<"backup">>],
 	 Lang) ->
     {result,
-     [#xmlel{name = <<"x">>,
-	     attrs = [{<<"xmlns">>, ?NS_XDATA}],
-	     children =
-		 [?HFIELD(),
-		  #xmlel{name = <<"title">>, attrs = [],
-			 children =
-			     [{xmlcdata,
-			       <<(?T(Lang, <<"Backup to File at ">>))/binary,
-				 ENode/binary>>}]},
-		  #xmlel{name = <<"instructions">>, attrs = [],
-			 children =
-			     [{xmlcdata,
-			       ?T(Lang, <<"Enter path to backup file">>)}]},
-		  ?XFIELD(<<"text-single">>, <<"Path to File">>,
-			  <<"path">>, <<"">>)]}]};
+     #xdata{title = <<(?T(Lang, <<"Backup to File at ">>))/binary, ENode/binary>>,
+	    type = form,
+	    instructions = [?T(Lang, <<"Enter path to backup file">>)],
+	    fields = [?HFIELD(),
+		      ?XFIELD('text-single', <<"Path to File">>,
+			      <<"path">>, <<"">>)]}};
 get_form(_Host,
 	 [<<"running nodes">>, ENode, <<"backup">>,
 	  <<"restore">>],
 	 Lang) ->
     {result,
-     [#xmlel{name = <<"x">>,
-	     attrs = [{<<"xmlns">>, ?NS_XDATA}],
-	     children =
-		 [?HFIELD(),
-		  #xmlel{name = <<"title">>, attrs = [],
-			 children =
-			     [{xmlcdata,
-			       <<(?T(Lang,
-				     <<"Restore Backup from File at ">>))/binary,
-				 ENode/binary>>}]},
-		  #xmlel{name = <<"instructions">>, attrs = [],
-			 children =
-			     [{xmlcdata,
-			       ?T(Lang, <<"Enter path to backup file">>)}]},
-		  ?XFIELD(<<"text-single">>, <<"Path to File">>,
-			  <<"path">>, <<"">>)]}]};
+     #xdata{title = <<(?T(Lang, <<"Restore Backup from File at ">>))/binary,
+		      ENode/binary>>,
+	    type = form,
+	    instructions = [?T(Lang, <<"Enter path to backup file">>)],
+	    fields = [?HFIELD(),
+		      ?XFIELD('text-single', <<"Path to File">>,
+			      <<"path">>, <<"">>)]}};
 get_form(_Host,
 	 [<<"running nodes">>, ENode, <<"backup">>,
 	  <<"textfile">>],
 	 Lang) ->
     {result,
-     [#xmlel{name = <<"x">>,
-	     attrs = [{<<"xmlns">>, ?NS_XDATA}],
-	     children =
-		 [?HFIELD(),
-		  #xmlel{name = <<"title">>, attrs = [],
-			 children =
-			     [{xmlcdata,
-			       <<(?T(Lang,
-				     <<"Dump Backup to Text File at ">>))/binary,
-				 ENode/binary>>}]},
-		  #xmlel{name = <<"instructions">>, attrs = [],
-			 children =
-			     [{xmlcdata,
-			       ?T(Lang, <<"Enter path to text file">>)}]},
-		  ?XFIELD(<<"text-single">>, <<"Path to File">>,
-			  <<"path">>, <<"">>)]}]};
+     #xdata{title = <<(?T(Lang, <<"Dump Backup to Text File at ">>))/binary,
+		      ENode/binary>>,
+	    type = form,
+	    instructions = [?T(Lang, <<"Enter path to text file">>)],
+	    fields = [?HFIELD(),
+		      ?XFIELD('text-single', <<"Path to File">>,
+			      <<"path">>, <<"">>)]}};
 get_form(_Host,
 	 [<<"running nodes">>, ENode, <<"import">>, <<"file">>],
 	 Lang) ->
     {result,
-     [#xmlel{name = <<"x">>,
-	     attrs = [{<<"xmlns">>, ?NS_XDATA}],
-	     children =
-		 [?HFIELD(),
-		  #xmlel{name = <<"title">>, attrs = [],
-			 children =
-			     [{xmlcdata,
-			       <<(?T(Lang,
-				     <<"Import User from File at ">>))/binary,
-				 ENode/binary>>}]},
-		  #xmlel{name = <<"instructions">>, attrs = [],
-			 children =
-			     [{xmlcdata,
-			       ?T(Lang,
-				  <<"Enter path to jabberd14 spool file">>)}]},
-		  ?XFIELD(<<"text-single">>, <<"Path to File">>,
-			  <<"path">>, <<"">>)]}]};
+     #xdata{title = <<(?T(Lang, <<"Import User from File at ">>))/binary,
+		      ENode/binary>>,
+	    type = form,
+	    instructions = [?T(Lang, <<"Enter path to jabberd14 spool file">>)],
+	    fields = [?HFIELD(),
+		      ?XFIELD('text-single', <<"Path to File">>,
+			      <<"path">>, <<"">>)]}};
 get_form(_Host,
 	 [<<"running nodes">>, ENode, <<"import">>, <<"dir">>],
 	 Lang) ->
     {result,
-     [#xmlel{name = <<"x">>,
-	     attrs = [{<<"xmlns">>, ?NS_XDATA}],
-	     children =
-		 [?HFIELD(),
-		  #xmlel{name = <<"title">>, attrs = [],
-			 children =
-			     [{xmlcdata,
-			       <<(?T(Lang,
-				     <<"Import Users from Dir at ">>))/binary,
-				 ENode/binary>>}]},
-		  #xmlel{name = <<"instructions">>, attrs = [],
-			 children =
-			     [{xmlcdata,
-			       ?T(Lang,
-				  <<"Enter path to jabberd14 spool dir">>)}]},
-		  ?XFIELD(<<"text-single">>, <<"Path to Dir">>,
-			  <<"path">>, <<"">>)]}]};
+     #xdata{title = <<(?T(Lang, <<"Import Users from Dir at ">>))/binary,
+		      ENode/binary>>,
+	    type = form,
+	    instructions = [?T(Lang, <<"Enter path to jabberd14 spool dir">>)],
+	    fields = [?HFIELD(),
+		      ?XFIELD('text-single', <<"Path to Dir">>,
+			      <<"path">>, <<"">>)]}};
 get_form(_Host,
 	 [<<"running nodes">>, _ENode, <<"restart">>], Lang) ->
-    Make_option = fun (LabelNum, LabelUnit, Value) ->
-			  #xmlel{name = <<"option">>,
-				 attrs =
-				     [{<<"label">>,
-				       <>}],
-				 children =
-				     [#xmlel{name = <<"value">>, attrs = [],
-					     children = [{xmlcdata, Value}]}]}
-		  end,
+    Make_option =
+	fun (LabelNum, LabelUnit, Value) ->
+		#xdata_option{
+		   label = <>,
+		   value = Value}
+	end,
     {result,
-     [#xmlel{name = <<"x">>,
-	     attrs = [{<<"xmlns">>, ?NS_XDATA}],
-	     children =
-		 [?HFIELD(),
-		  #xmlel{name = <<"title">>, attrs = [],
-			 children =
-			     [{xmlcdata, ?T(Lang, <<"Restart Service">>)}]},
-		  #xmlel{name = <<"field">>,
-			 attrs =
-			     [{<<"type">>, <<"list-single">>},
-			      {<<"label">>, ?T(Lang, <<"Time delay">>)},
-			      {<<"var">>, <<"delay">>}],
-			 children =
+     #xdata{title = ?T(Lang, <<"Restart Service">>),
+	    type = form,
+	    fields = [?HFIELD(),
+		      #xdata_field{
+			 type = 'list-single',
+			 label = ?T(Lang, <<"Time delay">>),
+			 var = <<"delay">>,
+			 required = true,
+			 options =
 			     [Make_option(<<"">>, <<"immediately">>, <<"1">>),
 			      Make_option(<<"15 ">>, <<"seconds">>, <<"15">>),
 			      Make_option(<<"30 ">>, <<"seconds">>, <<"30">>),
@@ -1229,55 +1021,35 @@ get_form(_Host,
 			      Make_option(<<"5 ">>, <<"minutes">>, <<"300">>),
 			      Make_option(<<"10 ">>, <<"minutes">>, <<"600">>),
 			      Make_option(<<"15 ">>, <<"minutes">>, <<"900">>),
-			      Make_option(<<"30 ">>, <<"minutes">>, <<"1800">>),
-			      #xmlel{name = <<"required">>, attrs = [],
-				     children = []}]},
-		  #xmlel{name = <<"field">>,
-			 attrs =
-			     [{<<"type">>, <<"fixed">>},
-			      {<<"label">>,
-			       ?T(Lang,
-				  <<"Send announcement to all online users "
-				    "on all hosts">>)}],
-			 children = []},
-		  #xmlel{name = <<"field">>,
-			 attrs =
-			     [{<<"var">>, <<"subject">>},
-			      {<<"type">>, <<"text-single">>},
-			      {<<"label">>, ?T(Lang, <<"Subject">>)}],
-			 children = []},
-		  #xmlel{name = <<"field">>,
-			 attrs =
-			     [{<<"var">>, <<"announcement">>},
-			      {<<"type">>, <<"text-multi">>},
-			      {<<"label">>, ?T(Lang, <<"Message body">>)}],
-			 children = []}]}]};
+			      Make_option(<<"30 ">>, <<"minutes">>, <<"1800">>)]},
+		      #xdata_field{type = fixed,
+				   label = ?T(Lang,
+					      <<"Send announcement to all online users "
+						"on all hosts">>)},
+		      #xdata_field{var = <<"subject">>,
+				   type = 'text-single',
+				   label = ?T(Lang, <<"Subject">>)},
+		      #xdata_field{var = <<"announcement">>,
+				   type = 'text-multi',
+				   label = ?T(Lang, <<"Message body">>)}]}};
 get_form(_Host,
 	 [<<"running nodes">>, _ENode, <<"shutdown">>], Lang) ->
-    Make_option = fun (LabelNum, LabelUnit, Value) ->
-			  #xmlel{name = <<"option">>,
-				 attrs =
-				     [{<<"label">>,
-				       <>}],
-				 children =
-				     [#xmlel{name = <<"value">>, attrs = [],
-					     children = [{xmlcdata, Value}]}]}
-		  end,
+    Make_option =
+	fun (LabelNum, LabelUnit, Value) ->
+		#xdata_option{
+		   label = <>,
+		   value = Value}
+	end,
     {result,
-     [#xmlel{name = <<"x">>,
-	     attrs = [{<<"xmlns">>, ?NS_XDATA}],
-	     children =
-		 [?HFIELD(),
-		  #xmlel{name = <<"title">>, attrs = [],
-			 children =
-			     [{xmlcdata, ?T(Lang, <<"Shut Down Service">>)}]},
-		  #xmlel{name = <<"field">>,
-			 attrs =
-			     [{<<"type">>, <<"list-single">>},
-			      {<<"label">>, ?T(Lang, <<"Time delay">>)},
-			      {<<"var">>, <<"delay">>}],
-			 children =
+     #xdata{title = ?T(Lang, <<"Shut Down Service">>),
+	    type = form,
+	    fields = [?HFIELD(),
+		      #xdata_field{
+			 type = 'list-single',
+			 label = ?T(Lang, <<"Time delay">>),
+			 var = <<"delay">>,
+			 required = true,
+			 options =
 			     [Make_option(<<"">>, <<"immediately">>, <<"1">>),
 			      Make_option(<<"15 ">>, <<"seconds">>, <<"15">>),
 			      Make_option(<<"30 ">>, <<"seconds">>, <<"30">>),
@@ -1289,323 +1061,191 @@ get_form(_Host,
 			      Make_option(<<"5 ">>, <<"minutes">>, <<"300">>),
 			      Make_option(<<"10 ">>, <<"minutes">>, <<"600">>),
 			      Make_option(<<"15 ">>, <<"minutes">>, <<"900">>),
-			      Make_option(<<"30 ">>, <<"minutes">>, <<"1800">>),
-			      #xmlel{name = <<"required">>, attrs = [],
-				     children = []}]},
-		  #xmlel{name = <<"field">>,
-			 attrs =
-			     [{<<"type">>, <<"fixed">>},
-			      {<<"label">>,
-			       ?T(Lang,
-				  <<"Send announcement to all online users "
-				    "on all hosts">>)}],
-			 children = []},
-		  #xmlel{name = <<"field">>,
-			 attrs =
-			     [{<<"var">>, <<"subject">>},
-			      {<<"type">>, <<"text-single">>},
-			      {<<"label">>, ?T(Lang, <<"Subject">>)}],
-			 children = []},
-		  #xmlel{name = <<"field">>,
-			 attrs =
-			     [{<<"var">>, <<"announcement">>},
-			      {<<"type">>, <<"text-multi">>},
-			      {<<"label">>, ?T(Lang, <<"Message body">>)}],
-			 children = []}]}]};
+			      Make_option(<<"30 ">>, <<"minutes">>, <<"1800">>)]},
+		      #xdata_field{type = fixed,
+				   label = ?T(Lang,
+					      <<"Send announcement to all online users "
+						"on all hosts">>)},
+		      #xdata_field{var = <<"subject">>,
+				   type = 'text-single',
+				   label = ?T(Lang, <<"Subject">>)},
+		      #xdata_field{var = <<"announcement">>,
+				   type = 'text-multi',
+				   label = ?T(Lang, <<"Message body">>)}]}};
 get_form(Host, [<<"config">>, <<"acls">>], Lang) ->
+    ACLs = str:tokens(
+	     iolist_to_binary(
+	       io_lib:format("~p.",
+			     [ets:select(
+				acl,
+				ets:fun2ms(
+				  fun({acl, {Name, H}, Spec}) when H == Host ->
+					  {acl, Name, Spec}
+				  end))])),
+	     <<"\n">>),
     {result,
-     [#xmlel{name = <<"x">>,
-	     attrs = [{<<"xmlns">>, ?NS_XDATA}],
-	     children =
-		 [?HFIELD(),
-		  #xmlel{name = <<"title">>, attrs = [],
-			 children =
-			     [{xmlcdata,
-			       ?T(Lang,
-				  <<"Access Control List Configuration">>)}]},
-		  #xmlel{name = <<"field">>,
-			 attrs =
-			     [{<<"type">>, <<"text-multi">>},
-			      {<<"label">>,
-			       ?T(Lang, <<"Access control lists">>)},
-			      {<<"var">>, <<"acls">>}],
-			 children =
-			     lists:map(fun (S) ->
-					       #xmlel{name = <<"value">>,
-						      attrs = [],
-						      children =
-							  [{xmlcdata, S}]}
-				       end,
-				       str:tokens(iolist_to_binary(io_lib:format("~p.",
-										 [ets:select(acl,
-											     [{{acl,
-												{'$1',
-												 '$2'},
-												'$3'},
-											       [{'==',
-												 '$2',
-												 Host}],
-											       [{{acl,
-												  '$1',
-												  '$3'}}]}])])),
-						  <<"\n">>))}]}]};
+     #xdata{title = ?T(Lang, <<"Access Control List Configuration">>),
+	    type = form,
+	    fields = [?HFIELD(),
+		      #xdata_field{type = 'text-multi',
+				   label = ?T(Lang, <<"Access control lists">>),
+				   var = <<"acls">>,
+				   values = ACLs}]}};
 get_form(Host, [<<"config">>, <<"access">>], Lang) ->
+    Accs = str:tokens(
+	     iolist_to_binary(
+	       io_lib:format("~p.",
+			     [ets:select(
+				access,
+				ets:fun2ms(
+				  fun({access, {Name, H}, Acc}) when H == Host ->
+					  {access, Name, Acc}
+				  end))])),
+	     <<"\n">>),
     {result,
-     [#xmlel{name = <<"x">>,
-	     attrs = [{<<"xmlns">>, ?NS_XDATA}],
-	     children =
-		 [?HFIELD(),
-		  #xmlel{name = <<"title">>, attrs = [],
-			 children =
-			     [{xmlcdata,
-			       ?T(Lang, <<"Access Configuration">>)}]},
-		  #xmlel{name = <<"field">>,
-			 attrs =
-			     [{<<"type">>, <<"text-multi">>},
-			      {<<"label">>, ?T(Lang, <<"Access rules">>)},
-			      {<<"var">>, <<"access">>}],
-			 children =
-			     lists:map(fun (S) ->
-					       #xmlel{name = <<"value">>,
-						      attrs = [],
-						      children =
-							  [{xmlcdata, S}]}
-				       end,
-				       str:tokens(iolist_to_binary(io_lib:format("~p.",
-										 [ets:select(access,
-											     [{{access,
-												{'$1',
-												 '$2'},
-												'$3'},
-											       [{'==',
-												 '$2',
-												 Host}],
-											       [{{access,
-												  '$1',
-												  '$3'}}]}])])),
-						  <<"\n">>))}]}]};
+     #xdata{title = ?T(Lang, <<"Access Configuration">>),
+	    type = form,
+	    fields = [?HFIELD(),
+		      #xdata_field{type = 'text-multi',
+				   label = ?T(Lang, <<"Access rules">>),
+				   var = <<"access">>,
+				   values = Accs}]}};
 get_form(_Host, ?NS_ADMINL(<<"add-user">>), Lang) ->
     {result,
-     [#xmlel{name = <<"x">>,
-	     attrs = [{<<"xmlns">>, ?NS_XDATA}],
-	     children =
-		 [?HFIELD(),
-		  #xmlel{name = <<"title">>, attrs = [],
-			 children = [{xmlcdata, ?T(Lang, <<"Add User">>)}]},
-		  #xmlel{name = <<"field">>,
-			 attrs =
-			     [{<<"type">>, <<"jid-single">>},
-			      {<<"label">>, ?T(Lang, <<"Jabber ID">>)},
-			      {<<"var">>, <<"accountjid">>}],
-			 children =
-			     [#xmlel{name = <<"required">>, attrs = [],
-				     children = []}]},
-		  #xmlel{name = <<"field">>,
-			 attrs =
-			     [{<<"type">>, <<"text-private">>},
-			      {<<"label">>, ?T(Lang, <<"Password">>)},
-			      {<<"var">>, <<"password">>}],
-			 children =
-			     [#xmlel{name = <<"required">>, attrs = [],
-				     children = []}]},
-		  #xmlel{name = <<"field">>,
-			 attrs =
-			     [{<<"type">>, <<"text-private">>},
-			      {<<"label">>,
-			       ?T(Lang, <<"Password Verification">>)},
-			      {<<"var">>, <<"password-verify">>}],
-			 children =
-			     [#xmlel{name = <<"required">>, attrs = [],
-				     children = []}]}]}]};
+     #xdata{title = ?T(Lang, <<"Add User">>),
+	    type = form,
+	    fields = [?HFIELD(),
+		      #xdata_field{type = 'jid-single',
+				   label = ?T(Lang, <<"Jabber ID">>),
+				   required = true,
+				   var = <<"accountjid">>},
+		      #xdata_field{type = 'text-private',
+				   label = ?T(Lang, <<"Password">>),
+				   required = true,
+				   var = <<"password">>},
+		      #xdata_field{type = 'text-private',
+				   label = ?T(Lang, <<"Password Verification">>),
+				   required = true,
+				   var = <<"password-verify">>}]}};
 get_form(_Host, ?NS_ADMINL(<<"delete-user">>), Lang) ->
     {result,
-     [#xmlel{name = <<"x">>,
-	     attrs = [{<<"xmlns">>, ?NS_XDATA}],
-	     children =
-		 [?HFIELD(),
-		  #xmlel{name = <<"title">>, attrs = [],
-			 children = [{xmlcdata, ?T(Lang, <<"Delete User">>)}]},
-		  #xmlel{name = <<"field">>,
-			 attrs =
-			     [{<<"type">>, <<"jid-multi">>},
-			      {<<"label">>, ?T(Lang, <<"Jabber ID">>)},
-			      {<<"var">>, <<"accountjids">>}],
-			 children =
-			     [#xmlel{name = <<"required">>, attrs = [],
-				     children = []}]}]}]};
+     #xdata{title = ?T(Lang, <<"Delete User">>),
+	    type = form,
+	    fields = [?HFIELD(),
+		      #xdata_field{type = 'jid-multi',
+				   label = ?T(Lang, <<"Jabber ID">>),
+				   required = true,
+				   var = <<"accountjids">>}]}};
 get_form(_Host, ?NS_ADMINL(<<"end-user-session">>),
 	 Lang) ->
     {result,
-     [#xmlel{name = <<"x">>,
-	     attrs = [{<<"xmlns">>, ?NS_XDATA}],
-	     children =
-		 [?HFIELD(),
-		  #xmlel{name = <<"title">>, attrs = [],
-			 children =
-			     [{xmlcdata, ?T(Lang, <<"End User Session">>)}]},
-		  #xmlel{name = <<"field">>,
-			 attrs =
-			     [{<<"type">>, <<"jid-single">>},
-			      {<<"label">>, ?T(Lang, <<"Jabber ID">>)},
-			      {<<"var">>, <<"accountjid">>}],
-			 children =
-			     [#xmlel{name = <<"required">>, attrs = [],
-				     children = []}]}]}]};
+     #xdata{title = ?T(Lang, <<"End User Session">>),
+	    type = form,
+	    fields = [?HFIELD(),
+		      #xdata_field{type = 'jid-single',
+				   label = ?T(Lang, <<"Jabber ID">>),
+				   required = true,
+				   var = <<"accountjid">>}]}};
 get_form(_Host, ?NS_ADMINL(<<"get-user-password">>),
 	 Lang) ->
     {result,
-     [#xmlel{name = <<"x">>,
-	     attrs = [{<<"xmlns">>, ?NS_XDATA}],
-	     children =
-		 [?HFIELD(),
-		  #xmlel{name = <<"title">>, attrs = [],
-			 children =
-			     [{xmlcdata, ?T(Lang, <<"Get User Password">>)}]},
-		  #xmlel{name = <<"field">>,
-			 attrs =
-			     [{<<"type">>, <<"jid-single">>},
-			      {<<"label">>, ?T(Lang, <<"Jabber ID">>)},
-			      {<<"var">>, <<"accountjid">>}],
-			 children =
-			     [#xmlel{name = <<"required">>, attrs = [],
-				     children = []}]}]}]};
+     #xdata{title = ?T(Lang, <<"Get User Password">>),
+	    type = form,
+	    fields = [?HFIELD(),
+		      #xdata_field{type = 'jid-single',
+				   label = ?T(Lang, <<"Jabber ID">>),
+				   var = <<"accountjid">>,
+				   required = true}]}};
 get_form(_Host, ?NS_ADMINL(<<"change-user-password">>),
 	 Lang) ->
     {result,
-     [#xmlel{name = <<"x">>,
-	     attrs = [{<<"xmlns">>, ?NS_XDATA}],
-	     children =
-		 [?HFIELD(),
-		  #xmlel{name = <<"title">>, attrs = [],
-			 children =
-			     [{xmlcdata, ?T(Lang, <<"Get User Password">>)}]},
-		  #xmlel{name = <<"field">>,
-			 attrs =
-			     [{<<"type">>, <<"jid-single">>},
-			      {<<"label">>, ?T(Lang, <<"Jabber ID">>)},
-			      {<<"var">>, <<"accountjid">>}],
-			 children =
-			     [#xmlel{name = <<"required">>, attrs = [],
-				     children = []}]},
-		  #xmlel{name = <<"field">>,
-			 attrs =
-			     [{<<"type">>, <<"text-private">>},
-			      {<<"label">>, ?T(Lang, <<"Password">>)},
-			      {<<"var">>, <<"password">>}],
-			 children =
-			     [#xmlel{name = <<"required">>, attrs = [],
-				     children = []}]}]}]};
+     #xdata{title = ?T(Lang, <<"Get User Password">>),
+	    type = form,
+	    fields = [?HFIELD(),
+		      #xdata_field{type = 'jid-single',
+				   label = ?T(Lang, <<"Jabber ID">>),
+				   required = true,
+				   var = <<"accountjid">>},
+		      #xdata_field{type = 'text-private',
+				   label = ?T(Lang, <<"Password">>),
+				   required = true,
+				   var = <<"password">>}]}};
 get_form(_Host, ?NS_ADMINL(<<"get-user-lastlogin">>),
 	 Lang) ->
     {result,
-     [#xmlel{name = <<"x">>,
-	     attrs = [{<<"xmlns">>, ?NS_XDATA}],
-	     children =
-		 [?HFIELD(),
-		  #xmlel{name = <<"title">>, attrs = [],
-			 children =
-			     [{xmlcdata,
-			       ?T(Lang, <<"Get User Last Login Time">>)}]},
-		  #xmlel{name = <<"field">>,
-			 attrs =
-			     [{<<"type">>, <<"jid-single">>},
-			      {<<"label">>, ?T(Lang, <<"Jabber ID">>)},
-			      {<<"var">>, <<"accountjid">>}],
-			 children =
-			     [#xmlel{name = <<"required">>, attrs = [],
-				     children = []}]}]}]};
+     #xdata{title = ?T(Lang, <<"Get User Last Login Time">>),
+	    type = form,
+	    fields = [?HFIELD(),
+		      #xdata_field{type = 'jid-single',
+				   label = ?T(Lang, <<"Jabber ID">>),
+				   var = <<"accountjid">>,
+				   required = true}]}};
 get_form(_Host, ?NS_ADMINL(<<"user-stats">>), Lang) ->
     {result,
-     [#xmlel{name = <<"x">>,
-	     attrs = [{<<"xmlns">>, ?NS_XDATA}],
-	     children =
-		 [?HFIELD(),
-		  #xmlel{name = <<"title">>, attrs = [],
-			 children =
-			     [{xmlcdata, ?T(Lang, <<"Get User Statistics">>)}]},
-		  #xmlel{name = <<"field">>,
-			 attrs =
-			     [{<<"type">>, <<"jid-single">>},
-			      {<<"label">>, ?T(Lang, <<"Jabber ID">>)},
-			      {<<"var">>, <<"accountjid">>}],
-			 children =
-			     [#xmlel{name = <<"required">>, attrs = [],
-				     children = []}]}]}]};
+     #xdata{title = ?T(Lang, <<"Get User Statistics">>),
+	    type = form,
+	    fields = [?HFIELD(),
+		      #xdata_field{type = 'jid-single',
+				   label = ?T(Lang, <<"Jabber ID">>),
+				   var = <<"accountjid">>,
+				   required = true}]}};
 get_form(Host,
 	 ?NS_ADMINL(<<"get-registered-users-num">>), Lang) ->
     Num = list_to_binary(
             io_lib:format("~p",
 			  [ejabberd_auth:get_vh_registered_users_number(Host)])),
     {result, completed,
-     [#xmlel{name = <<"x">>,
-	     attrs = [{<<"xmlns">>, ?NS_XDATA}],
-	     children =
-		 [?HFIELD(),
-		  #xmlel{name = <<"field">>,
-			 attrs =
-			     [{<<"type">>, <<"text-single">>},
-			      {<<"label">>,
-			       ?T(Lang, <<"Number of registered users">>)},
-			      {<<"var">>, <<"registeredusersnum">>}],
-			 children =
-			     [#xmlel{name = <<"value">>, attrs = [],
-				     children = [{xmlcdata, Num}]}]}]}]};
+     #xdata{type = form,
+	    fields = [?HFIELD(),
+		      #xdata_field{type = 'text-single',
+				   label = ?T(Lang, <<"Number of registered users">>),
+				   var = <<"registeredusersnum">>,
+				   values = [Num]}]}};
 get_form(Host, ?NS_ADMINL(<<"get-online-users-num">>),
 	 Lang) ->
     Num = list_to_binary(
             io_lib:format("~p",
                           [length(ejabberd_sm:get_vh_session_list(Host))])),
     {result, completed,
-     [#xmlel{name = <<"x">>,
-	     attrs = [{<<"xmlns">>, ?NS_XDATA}],
-	     children =
-		 [?HFIELD(),
-		  #xmlel{name = <<"field">>,
-			 attrs =
-			     [{<<"type">>, <<"text-single">>},
-			      {<<"label">>,
-			       ?T(Lang, <<"Number of online users">>)},
-			      {<<"var">>, <<"onlineusersnum">>}],
-			 children =
-			     [#xmlel{name = <<"value">>, attrs = [],
-				     children = [{xmlcdata, Num}]}]}]}]};
+     #xdata{type = form,
+	    fields = [?HFIELD(),
+		      #xdata_field{type = 'text-single',
+				   label = ?T(Lang, <<"Number of online users">>),
+				   var = <<"onlineusersnum">>,
+				   values = [Num]}]}};
 get_form(_Host, _, _Lang) ->
-    {error, ?ERR_SERVICE_UNAVAILABLE}.
+    {error, xmpp:err_service_unavailable()}.
 
 set_form(_From, _Host,
 	 [<<"running nodes">>, ENode, <<"DB">>], Lang, XData) ->
     case search_running_node(ENode) of
       false ->
 	  Txt = <<"No running node found">>,
-	  {error, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)};
+	  {error, xmpp:err_item_not_found(Txt, Lang)};
       Node ->
-	  lists:foreach(fun ({SVar, SVals}) ->
-				Table = jlib:binary_to_atom(SVar),
-				Type = case SVals of
-					 [<<"unknown">>] -> unknown;
-					 [<<"ram_copies">>] -> ram_copies;
-					 [<<"disc_copies">>] -> disc_copies;
-					 [<<"disc_only_copies">>] ->
-					     disc_only_copies;
-					 _ -> false
-				       end,
-				if Type == false -> ok;
-				   Type == unknown ->
-				       mnesia:del_table_copy(Table, Node);
-				   true ->
-				       case mnesia:add_table_copy(Table, Node,
-								  Type)
-					   of
-					 {aborted, _} ->
-					     mnesia:change_table_copy_type(Table,
-									   Node,
-									   Type);
-					 _ -> ok
-				       end
-				end
-			end,
-			XData),
-	  {result, []}
+	  lists:foreach(
+	    fun(#xdata_field{var = SVar, values = SVals}) ->
+		    Table = jlib:binary_to_atom(SVar),
+		    Type = case SVals of
+			       [<<"unknown">>] -> unknown;
+			       [<<"ram_copies">>] -> ram_copies;
+			       [<<"disc_copies">>] -> disc_copies;
+			       [<<"disc_only_copies">>] -> disc_only_copies;
+			       _ -> false
+			   end,
+		    if Type == false -> ok;
+		       Type == unknown ->
+			    mnesia:del_table_copy(Table, Node);
+		       true ->
+			    case mnesia:add_table_copy(Table, Node, Type) of
+				{aborted, _} ->
+				    mnesia:change_table_copy_type(
+				      Table, Node, Type);
+				_ -> ok
+			    end
+		    end
+	    end, XData#xdata.fields),
+	    {result, undefined}
     end;
 set_form(_From, Host,
 	 [<<"running nodes">>, ENode, <<"modules">>, <<"stop">>],
@@ -1613,187 +1253,193 @@ set_form(_From, Host,
     case search_running_node(ENode) of
       false ->
 	  Txt = <<"No running node found">>,
-	  {error, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)};
+	  {error, xmpp:err_item_not_found(Txt, Lang)};
       Node ->
-	  lists:foreach(fun ({Var, Vals}) ->
-				case Vals of
-				  [<<"1">>] ->
-				      Module = jlib:binary_to_atom(Var),
-				      ejabberd_cluster:call(Node, gen_mod, stop_module,
-					       [Host, Module]);
-				  _ -> ok
-				end
-			end,
-			XData),
-	  {result, []}
+	  lists:foreach(
+	    fun(#xdata_field{var = Var, values = Vals}) ->
+		    case Vals of
+			[<<"1">>] ->
+			    Module = jlib:binary_to_atom(Var),
+			    ejabberd_cluster:call(Node, gen_mod, stop_module,
+						  [Host, Module]);
+			_ -> ok
+		    end
+	    end, XData#xdata.fields),
+	  {result, undefined}
     end;
 set_form(_From, Host,
 	 [<<"running nodes">>, ENode, <<"modules">>,
 	  <<"start">>],
 	 Lang, XData) ->
     case search_running_node(ENode) of
-      false ->
-	  Txt = <<"No running node found">>,
-	  {error, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)};
-      Node ->
-	  case lists:keysearch(<<"modules">>, 1, XData) of
-	    false ->
-		Txt = <<"No 'modules' found in data form">>,
-		{error, ?ERRT_BAD_REQUEST(Lang, Txt)};
-	    {value, {_, Strings}} ->
-		String = lists:foldl(fun (S, Res) ->
-					     <>
-				     end,
-				     <<"">>, Strings),
-		case erl_scan:string(binary_to_list(String)) of
-		  {ok, Tokens, _} ->
-		      case erl_parse:parse_term(Tokens) of
-			{ok, Modules} ->
-			    lists:foreach(fun ({Module, Args}) ->
-						  ejabberd_cluster:call(Node, gen_mod,
-							   start_module,
-							   [Host, Module, Args])
-					  end,
-					  Modules),
-			    {result, []};
-			_ -> {error, ?ERRT_BAD_REQUEST(Lang, <<"Parse failed">>)}
-		      end;
-		  _ -> {error, ?ERRT_BAD_REQUEST(Lang, <<"Scan failed">>)}
-		end
-	  end
+	false ->
+	    Txt = <<"No running node found">>,
+	    {error, xmpp:err_item_not_found(Txt, Lang)};
+	Node ->
+	    case xmpp_util:get_xdata_values(<<"modules">>, XData) of
+		[] ->
+		    Txt = <<"No 'modules' found in data form">>,
+		    {error, xmpp:err_bad_request(Txt, Lang)};
+		Strings ->
+		    String = lists:foldl(fun (S, Res) ->
+						 <>
+					 end, <<"">>, Strings),
+		    case erl_scan:string(binary_to_list(String)) of
+			{ok, Tokens, _} ->
+			    case erl_parse:parse_term(Tokens) of
+				{ok, Modules} ->
+				    lists:foreach(
+				      fun ({Module, Args}) ->
+					      ejabberd_cluster:call(
+						Node, gen_mod, start_module,
+						[Host, Module, Args])
+				      end,
+				      Modules),
+				    {result, undefined};
+				_ ->
+				    Txt = <<"Parse failed">>,
+				    {error, xmpp:err_bad_request(Txt, Lang)}
+			    end;
+			_ ->
+			    Txt = <<"Scan failed">>,
+			    {error, xmpp:err_bad_request(Txt, Lang)}
+		    end
+	    end
     end;
 set_form(_From, _Host,
 	 [<<"running nodes">>, ENode, <<"backup">>,
 	  <<"backup">>],
 	 Lang, XData) ->
     case search_running_node(ENode) of
-      false ->
-	  Txt = <<"No running node found">>,
-	  {error, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)};
-      Node ->
-	  case lists:keysearch(<<"path">>, 1, XData) of
-	    false ->
-		Txt = <<"No 'path' found in data form">>,
-		{error, ?ERRT_BAD_REQUEST(Lang, Txt)};
-	    {value, {_, [String]}} ->
-		case ejabberd_cluster:call(Node, mnesia, backup, [String]) of
-		  {badrpc, Reason} ->
-		      ?ERROR_MSG("RPC call mnesia:backup(~s) to node ~s "
-				 "failed: ~p", [String, Node, Reason]),
-		      {error, ?ERR_INTERNAL_SERVER_ERROR};
-		  {error, Reason} ->
-		      ?ERROR_MSG("RPC call mnesia:backup(~s) to node ~s "
-				 "failed: ~p", [String, Node, Reason]),
-		      {error, ?ERR_INTERNAL_SERVER_ERROR};
-		  _ -> {result, []}
-		end;
-	    _ ->
-		Txt = <<"Incorrect value of 'path' in data form">>,
-	        {error, ?ERRT_BAD_REQUEST(Lang, Txt)}
-	  end
+	false ->
+	    Txt = <<"No running node found">>,
+	    {error, xmpp:err_item_not_found(Txt, Lang)};
+	Node ->
+	    case xmpp_util:get_xdata_values(<<"path">>, XData) of
+		[] ->
+		    Txt = <<"No 'path' found in data form">>,
+		    {error, xmpp:err_bad_request(Txt, Lang)};
+		[String] ->
+		    case ejabberd_cluster:call(Node, mnesia, backup, [String]) of
+			{badrpc, Reason} ->
+			    ?ERROR_MSG("RPC call mnesia:backup(~s) to node ~s "
+				       "failed: ~p", [String, Node, Reason]),
+			    {error, xmpp:err_internal_server_error()};
+			{error, Reason} ->
+			    ?ERROR_MSG("RPC call mnesia:backup(~s) to node ~s "
+				       "failed: ~p", [String, Node, Reason]),
+			    {error, xmpp:err_internal_server_error()};
+			_ ->
+			    {result, undefined}
+		    end;
+		_ ->
+		    Txt = <<"Incorrect value of 'path' in data form">>,
+		    {error, xmpp:err_bad_request(Txt, Lang)}
+	    end
     end;
 set_form(_From, _Host,
 	 [<<"running nodes">>, ENode, <<"backup">>,
 	  <<"restore">>],
 	 Lang, XData) ->
     case search_running_node(ENode) of
-      false ->
-	  Txt = <<"No running node found">>,
-	  {error, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)};
-      Node ->
-	  case lists:keysearch(<<"path">>, 1, XData) of
-	    false ->
-		Txt = <<"No 'path' found in data form">>,
-		{error, ?ERRT_BAD_REQUEST(Lang, Txt)};
-	    {value, {_, [String]}} ->
-		case ejabberd_cluster:call(Node, ejabberd_admin, restore, [String])
-		    of
-		  {badrpc, Reason} ->
-		      ?ERROR_MSG("RPC call ejabberd_admin:restore(~s) to node "
-				 "~s failed: ~p", [String, Node, Reason]),
-		      {error, ?ERR_INTERNAL_SERVER_ERROR};
-		  {error, Reason} ->
-		      ?ERROR_MSG("RPC call ejabberd_admin:restore(~s) to node "
-				 "~s failed: ~p", [String, Node, Reason]),
-		      {error, ?ERR_INTERNAL_SERVER_ERROR};
-		  _ -> {result, []}
-		end;
-	    _ ->
-		Txt = <<"Incorrect value of 'path' in data form">>,
-	        {error, ?ERRT_BAD_REQUEST(Lang, Txt)}
-	  end
+	false ->
+	    Txt = <<"No running node found">>,
+	    {error, xmpp:err_item_not_found(Txt, Lang)};
+	Node ->
+	    case xmpp_util:get_xdata_values(<<"path">>, XData) of
+		[] ->
+		    Txt = <<"No 'path' found in data form">>,
+		    {error, xmpp:err_bad_request(Txt, Lang)};
+		[String] ->
+		    case ejabberd_cluster:call(Node, ejabberd_admin,
+					       restore, [String]) of
+			{badrpc, Reason} ->
+			    ?ERROR_MSG("RPC call ejabberd_admin:restore(~s) to node "
+				       "~s failed: ~p", [String, Node, Reason]),
+			    {error, xmpp:err_internal_server_error()};
+			{error, Reason} ->
+			    ?ERROR_MSG("RPC call ejabberd_admin:restore(~s) to node "
+				       "~s failed: ~p", [String, Node, Reason]),
+			    {error, xmpp:err_internal_server_error()};
+			_ ->
+			    {result, undefined}
+		    end;
+		_ ->
+		    Txt = <<"Incorrect value of 'path' in data form">>,
+		    {error, xmpp:err_bad_request(Txt, Lang)}
+	    end
     end;
 set_form(_From, _Host,
 	 [<<"running nodes">>, ENode, <<"backup">>,
 	  <<"textfile">>],
 	 Lang, XData) ->
     case search_running_node(ENode) of
-      false ->
-	  Txt = <<"No running node found">>,
-	  {error, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)};
-      Node ->
-	  case lists:keysearch(<<"path">>, 1, XData) of
-	    false ->
-		Txt = <<"No 'path' found in data form">>,
-		{error, ?ERRT_BAD_REQUEST(Lang, Txt)};
-	    {value, {_, [String]}} ->
-		case ejabberd_cluster:call(Node, ejabberd_admin, dump_to_textfile,
-			      [String])
-		    of
-		  {badrpc, Reason} ->
-		      ?ERROR_MSG("RPC call ejabberd_admin:dump_to_textfile(~s) "
-				 "to node ~s failed: ~p", [String, Node, Reason]),
-		      {error, ?ERR_INTERNAL_SERVER_ERROR};
-		  {error, Reason} ->
-		      ?ERROR_MSG("RPC call ejabberd_admin:dump_to_textfile(~s) "
-				 "to node ~s failed: ~p", [String, Node, Reason]),
-		      {error, ?ERR_INTERNAL_SERVER_ERROR};
-		  _ -> {result, []}
-		end;
-	    _ ->
-		Txt = <<"Incorrect value of 'path' in data form">>,
-	        {error, ?ERRT_BAD_REQUEST(Lang, Txt)}
-	  end
+	false ->
+	    Txt = <<"No running node found">>,
+	    {error, xmpp:err_item_not_found(Txt, Lang)};
+	Node ->
+	    case xmpp_util:get_xdata_values(<<"path">>, XData) of
+		[] ->
+		    Txt = <<"No 'path' found in data form">>,
+		    {error, xmpp:err_bad_request(Txt, Lang)};
+		[String] ->
+		    case ejabberd_cluster:call(Node, ejabberd_admin,
+					       dump_to_textfile, [String]) of
+			{badrpc, Reason} ->
+			    ?ERROR_MSG("RPC call ejabberd_admin:dump_to_textfile(~s) "
+				       "to node ~s failed: ~p", [String, Node, Reason]),
+			    {error, xmpp:err_internal_server_error()};
+			{error, Reason} ->
+			    ?ERROR_MSG("RPC call ejabberd_admin:dump_to_textfile(~s) "
+				       "to node ~s failed: ~p", [String, Node, Reason]),
+			    {error, xmpp:err_internal_server_error()};
+			_ ->
+			    {result, undefined}
+		    end;
+		_ ->
+		    Txt = <<"Incorrect value of 'path' in data form">>,
+		    {error, xmpp:err_bad_request(Txt, Lang)}
+	    end
     end;
 set_form(_From, _Host,
 	 [<<"running nodes">>, ENode, <<"import">>, <<"file">>],
 	 Lang, XData) ->
     case search_running_node(ENode) of
-      false ->
-	  Txt = <<"No running node found">>,
-	  {error, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)};
-      Node ->
-	  case lists:keysearch(<<"path">>, 1, XData) of
-	    false ->
-		Txt = <<"No 'path' found in data form">>,
-		{error, ?ERRT_BAD_REQUEST(Lang, Txt)};
-	    {value, {_, [String]}} ->
-		ejabberd_cluster:call(Node, jd2ejd, import_file, [String]),
-		{result, []};
-	    _ ->
-		Txt = <<"Incorrect value of 'path' in data form">>,
-	        {error, ?ERRT_BAD_REQUEST(Lang, Txt)}
-	  end
+	false ->
+	    Txt = <<"No running node found">>,
+	    {error, xmpp:err_item_not_found(Txt, Lang)};
+	Node ->
+	    case xmpp_util:get_xdata_values(<<"path">>, XData) of
+		[] ->
+		    Txt = <<"No 'path' found in data form">>,
+		    {error, xmpp:err_bad_request(Txt, Lang)};
+		[String] ->
+		    ejabberd_cluster:call(Node, jd2ejd, import_file, [String]),
+		    {result, undefined};
+		_ ->
+		    Txt = <<"Incorrect value of 'path' in data form">>,
+		    {error, xmpp:err_bad_request(Txt, Lang)}
+	    end
     end;
 set_form(_From, _Host,
 	 [<<"running nodes">>, ENode, <<"import">>, <<"dir">>],
 	 Lang, XData) ->
     case search_running_node(ENode) of
-      false ->
-	  Txt = <<"No running node found">>,
-	  {error, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)};
-      Node ->
-	  case lists:keysearch(<<"path">>, 1, XData) of
-	    false ->
-		Txt = <<"No 'path' found in data form">>,
-		{error, ?ERRT_BAD_REQUEST(Lang, Txt)};
-	    {value, {_, [String]}} ->
-		ejabberd_cluster:call(Node, jd2ejd, import_dir, [String]),
-		{result, []};
-	    _ ->
-		Txt = <<"Incorrect value of 'path' in data form">>,
-	        {error, ?ERRT_BAD_REQUEST(Lang, Txt)}
-	  end
+	false ->
+	    Txt = <<"No running node found">>,
+	    {error, xmpp:err_item_not_found(Txt, Lang)};
+	Node ->
+	    case xmpp_util:get_xdata_values(<<"path">>, XData) of
+		[] ->
+		    Txt = <<"No 'path' found in data form">>,
+		    {error, xmpp:err_bad_request(Txt, Lang)};
+		[String] ->
+		    ejabberd_cluster:call(Node, jd2ejd, import_dir, [String]),
+		    {result, undefined};
+		_ ->
+		    Txt = <<"Incorrect value of 'path' in data form">>,
+		    {error, xmpp:err_bad_request(Txt, Lang)}
+	    end
     end;
 set_form(From, Host,
 	 [<<"running nodes">>, ENode, <<"restart">>], _Lang,
@@ -1805,75 +1451,72 @@ set_form(From, Host,
     stop_node(From, Host, ENode, stop, XData);
 set_form(_From, Host, [<<"config">>, <<"acls">>], Lang,
 	 XData) ->
-    case lists:keysearch(<<"acls">>, 1, XData) of
-      {value, {_, Strings}} ->
-	  String = lists:foldl(fun (S, Res) ->
-				       <>
-			       end,
-			       <<"">>, Strings),
-	  case erl_scan:string(binary_to_list(String)) of
-	    {ok, Tokens, _} ->
-		case erl_parse:parse_term(Tokens) of
-		  {ok, ACLs} ->
-		      acl:add_list(Host, ACLs, true),
-                      {result, []};
-		  _ -> {error, ?ERRT_BAD_REQUEST(Lang, <<"Parse failed">>)}
-		end;
-	    _ -> {error, ?ERRT_BAD_REQUEST(Lang, <<"Scan failed">>)}
-	  end;
-      _ ->
-	  Txt = <<"No 'acls' found in data form">>,
-	  {error, ?ERRT_BAD_REQUEST(Lang, Txt)}
+    case xmpp_util:get_xdata_values(<<"acls">>, XData) of
+	[] ->
+	    Txt = <<"No 'acls' found in data form">>,
+	    {error, xmpp:err_bad_request(Txt, Lang)};
+	Strings ->
+	    String = lists:foldl(fun (S, Res) ->
+					 <>
+				 end, <<"">>, Strings),
+	    case erl_scan:string(binary_to_list(String)) of
+		{ok, Tokens, _} ->
+		    case erl_parse:parse_term(Tokens) of
+			{ok, ACLs} ->
+			    acl:add_list(Host, ACLs, true),
+			    {result, undefined};
+			_ ->
+			    Txt = <<"Parse failed">>,
+			    {error, xmpp:err_bad_request(Txt, Lang)}
+		    end;
+		_ ->
+		    {error, xmpp:err_bad_request(<<"Scan failed">>, Lang)}
+	    end
     end;
 set_form(_From, Host, [<<"config">>, <<"access">>],
 	 Lang, XData) ->
-    SetAccess = fun (Rs) ->
-			mnesia:transaction(fun () ->
-						   Os = mnesia:select(access,
-								      [{{access,
-									 {'$1',
-									  '$2'},
-									 '$3'},
-									[{'==',
-									  '$2',
-									  Host}],
-									['$_']}]),
-						   lists:foreach(fun (O) ->
-									 mnesia:delete_object(O)
-								 end,
-								 Os),
-						   lists:foreach(fun ({access,
-								       Name,
-								       Rules}) ->
-									 mnesia:write({access,
-										       {Name,
-											Host},
-										       Rules})
-								 end,
-								 Rs)
-					   end)
-		end,
-    case lists:keysearch(<<"access">>, 1, XData) of
-      {value, {_, Strings}} ->
-	  String = lists:foldl(fun (S, Res) ->
-				       <>
-			       end,
-			       <<"">>, Strings),
-	  case erl_scan:string(binary_to_list(String)) of
-	    {ok, Tokens, _} ->
-		case erl_parse:parse_term(Tokens) of
-		  {ok, Rs} ->
-		      case SetAccess(Rs) of
-			{atomic, _} -> {result, []};
-			_ -> {error, ?ERR_BAD_REQUEST}
-		      end;
-		  _ -> {error, ?ERRT_BAD_REQUEST(Lang, <<"Parse failed">>)}
-		end;
-	    _ -> {error, ?ERRT_BAD_REQUEST(Lang, <<"Scan failed">>)}
-	  end;
-      _ ->
-	  Txt = <<"No 'access' found in data form">>,
-	  {error, ?ERRT_BAD_REQUEST(Lang, Txt)}
+    SetAccess =
+	fun(Rs) ->
+		mnesia:transaction(
+		  fun () ->
+			  Os = mnesia:select(
+				 access,
+				 ets:fun2ms(
+				   fun({access, {_, H}, _} = O) when H == Host ->
+					   O
+				   end)),
+			  lists:foreach(fun mnesia:delete_object/1, Os),
+			  lists:foreach(
+			    fun({access, Name, Rules}) ->
+				    mnesia:write({access, {Name, Host}, Rules})
+			    end, Rs)
+		  end)
+	end,
+    case xmpp_util:get_xdata_values(<<"access">>, XData) of
+	[] ->
+	    Txt = <<"No 'access' found in data form">>,
+	    {error, xmpp:err_bad_request(Txt, Lang)};
+	Strings ->
+	    String = lists:foldl(fun (S, Res) ->
+					 <>
+				 end, <<"">>, Strings),
+	    case erl_scan:string(binary_to_list(String)) of
+		{ok, Tokens, _} ->
+		    case erl_parse:parse_term(Tokens) of
+			{ok, Rs} ->
+			    case SetAccess(Rs) of
+				{atomic, _} ->
+				    {result, undefined};
+				_ ->
+				    {error, xmpp:err_bad_request()}
+			    end;
+			_ ->
+			    Txt = <<"Parse failed">>,
+			    {error, xmpp:err_bad_request(Txt, Lang)}
+		    end;
+		_ ->
+		    {error, xmpp:err_bad_request(<<"Scan failed">>, Lang)}
+	    end
     end;
 set_form(From, Host, ?NS_ADMINL(<<"add-user">>), _Lang,
 	 XData) ->
@@ -1887,7 +1530,7 @@ set_form(From, Host, ?NS_ADMINL(<<"add-user">>), _Lang,
     true = Server == Host orelse
 	     get_permission_level(From) == global,
     ejabberd_auth:try_register(User, Server, Password),
-    {result, []};
+    {result, undefined};
 set_form(From, Host, ?NS_ADMINL(<<"delete-user">>),
 	 _Lang, XData) ->
     AccountStringList = get_values(<<"accountjids">>,
@@ -1905,7 +1548,7 @@ set_form(From, Host, ?NS_ADMINL(<<"delete-user">>),
 		     AccountStringList),
     [ejabberd_auth:remove_user(User, Server)
      || {User, Server} <- ASL2],
-    {result, []};
+    {result, undefined};
 set_form(From, Host, ?NS_ADMINL(<<"end-user-session">>),
 	 Lang, XData) ->
     AccountString = get_value(<<"accountjid">>, XData),
@@ -1914,7 +1557,7 @@ set_form(From, Host, ?NS_ADMINL(<<"end-user-session">>),
     LServer = JID#jid.lserver,
     true = LServer == Host orelse
 	     get_permission_level(From) == global,
-    Xmlelement = ?SERRT_POLICY_VIOLATION(Lang, <<"has been kicked">>),
+    Xmlelement = xmpp:serr_policy_violation(<<"has been kicked">>, Lang),
     case JID#jid.lresource of
       <<>> ->
 	  SIDs = mnesia:dirty_select(session,
@@ -1933,7 +1576,7 @@ set_form(From, Host, ?NS_ADMINL(<<"end-user-session">>),
 					     [{{'$1', '$2'}}]}]),
 	  Pid ! {kick, kicked_by_admin, Xmlelement}
     end,
-    {result, []};
+    {result, undefined};
 set_form(From, Host,
 	 ?NS_ADMINL(<<"get-user-password">>), Lang, XData) ->
     AccountString = get_value(<<"accountjid">>, XData),
@@ -1945,14 +1588,12 @@ set_form(From, Host,
     Password = ejabberd_auth:get_password(User, Server),
     true = is_binary(Password),
     {result,
-     [#xmlel{name = <<"x">>,
-	     attrs = [{<<"xmlns">>, ?NS_XDATA}],
-	     children =
-		 [?HFIELD(),
-		  ?XFIELD(<<"jid-single">>, <<"Jabber ID">>,
-			  <<"accountjid">>, AccountString),
-		  ?XFIELD(<<"text-single">>, <<"Password">>,
-			  <<"password">>, Password)]}]};
+     #xdata{type = form,
+	    fields = [?HFIELD(),
+		      ?XFIELD('jid-single', <<"Jabber ID">>,
+			      <<"accountjid">>, AccountString),
+		      ?XFIELD('text-single', <<"Password">>,
+			      <<"password">>, Password)]}};
 set_form(From, Host,
 	 ?NS_ADMINL(<<"change-user-password">>), _Lang, XData) ->
     AccountString = get_value(<<"accountjid">>, XData),
@@ -1964,7 +1605,7 @@ set_form(From, Host,
 	     get_permission_level(From) == global,
     true = ejabberd_auth:is_user_exists(User, Server),
     ejabberd_auth:set_password(User, Server, Password),
-    {result, []};
+    {result, undefined};
 set_form(From, Host,
 	 ?NS_ADMINL(<<"get-user-lastlogin">>), Lang, XData) ->
     AccountString = get_value(<<"accountjid">>, XData),
@@ -1991,15 +1632,12 @@ set_form(From, Host,
 	      _ -> ?T(Lang, <<"Online">>)
 	    end,
     {result,
-     [#xmlel{name = <<"x">>,
-	     attrs =
-		 [{<<"xmlns">>, ?NS_XDATA}, {<<"type">>, <<"result">>}],
-	     children =
-		 [?HFIELD(),
-		  ?XFIELD(<<"jid-single">>, <<"Jabber ID">>,
-			  <<"accountjid">>, AccountString),
-		  ?XFIELD(<<"text-single">>, <<"Last login">>,
-			  <<"lastlogin">>, FLast)]}]};
+     #xdata{type = form,
+	    fields = [?HFIELD(),
+		      ?XFIELD('jid-single', <<"Jabber ID">>,
+			      <<"accountjid">>, AccountString),
+		      ?XFIELD('text-single', <<"Last login">>,
+			      <<"lastlogin">>, FLast)]}};
 set_form(From, Host, ?NS_ADMINL(<<"user-stats">>), Lang,
 	 XData) ->
     AccountString = get_value(<<"accountjid">>, XData),
@@ -2019,27 +1657,24 @@ set_form(From, Host, ?NS_ADMINL(<<"user-stats">>), Lang,
 				    [{User, Server}]),
     Rostersize = jlib:integer_to_binary(erlang:length(Items)),
     {result,
-     [#xmlel{name = <<"x">>,
-	     attrs = [{<<"xmlns">>, ?NS_XDATA}],
-	     children =
-		 [?HFIELD(),
-		  ?XFIELD(<<"jid-single">>, <<"Jabber ID">>,
-			  <<"accountjid">>, AccountString),
-		  ?XFIELD(<<"text-single">>, <<"Roster size">>,
-			  <<"rostersize">>, Rostersize),
-		  ?XMFIELD(<<"text-multi">>, <<"IP addresses">>,
-			   <<"ipaddresses">>, IPs),
-		  ?XMFIELD(<<"text-multi">>, <<"Resources">>,
-			   <<"onlineresources">>, Resources)]}]};
+     #xdata{type = form,
+	    fields = [?HFIELD(),
+		      ?XFIELD('jid-single', <<"Jabber ID">>,
+			      <<"accountjid">>, AccountString),
+		      ?XFIELD('text-single', <<"Roster size">>,
+			      <<"rostersize">>, Rostersize),
+		      ?XMFIELD('text-multi', <<"IP addresses">>,
+			       <<"ipaddresses">>, IPs),
+		      ?XMFIELD('text-multi', <<"Resources">>,
+			       <<"onlineresources">>, Resources)]}};
 set_form(_From, _Host, _, _Lang, _XData) ->
-    {error, ?ERR_SERVICE_UNAVAILABLE}.
+    {error, xmpp:err_service_unavailable()}.
 
 get_value(Field, XData) -> hd(get_values(Field, XData)).
 
 get_values(Field, XData) ->
-    {value, {_, ValueList}} = lists:keysearch(Field, 1,
-					      XData),
-    ValueList.
+    [_|_] = Values = xmpp_util:get_xdata_values(Field, XData),
+    Values.
 
 search_running_node(SNode) ->
     search_running_node(SNode,
@@ -2053,57 +1688,34 @@ search_running_node(SNode, [Node | Nodes]) ->
     end.
 
 stop_node(From, Host, ENode, Action, XData) ->
-    Delay = jlib:binary_to_integer(get_value(<<"delay">>,
-					       XData)),
+    Delay = jlib:binary_to_integer(get_value(<<"delay">>, XData)),
     Subject = case get_value(<<"subject">>, XData) of
-		<<"">> -> [];
-		S ->
-		    [#xmlel{name = <<"field">>,
-			    attrs = [{<<"var">>, <<"subject">>}],
-			    children =
-				[#xmlel{name = <<"value">>, attrs = [],
-					children = [{xmlcdata, S}]}]}]
+		  <<"">> ->
+		      [];
+		  S ->
+		      [#xdata_field{var = <<"subject">>, values = [S]}]
 	      end,
-    Announcement = case get_values(<<"announcement">>,
-				   XData)
-		       of
-		     [] -> [];
-		     As ->
-			 [#xmlel{name = <<"field">>,
-				 attrs = [{<<"var">>, <<"body">>}],
-				 children =
-				     [#xmlel{name = <<"value">>, attrs = [],
-					     children = [{xmlcdata, Line}]}
-				      || Line <- As]}]
+    Announcement = case get_values(<<"announcement">>, XData) of
+		       [] ->
+			   [];
+		       As ->
+			   [#xdata_field{var = <<"body">>, values = As}]
 		   end,
     case Subject ++ Announcement of
-      [] -> ok;
-      SubEls ->
-	  Request = #adhoc_request{node =
-				       ?NS_ADMINX(<<"announce-allhosts">>),
-				   action = <<"complete">>,
-				   xdata =
-				       #xmlel{name = <<"x">>,
-					      attrs =
-						  [{<<"xmlns">>,
-						    ?NS_XDATA},
-						   {<<"type">>, <<"submit">>}],
-					      children = SubEls},
-				   others =
-				       [#xmlel{name = <<"x">>,
-					       attrs =
-						   [{<<"xmlns">>,
-						     ?NS_XDATA},
-						    {<<"type">>, <<"submit">>}],
-					       children = SubEls}]},
-	  To = jid:make(<<"">>, Host, <<"">>),
-	  mod_announce:announce_commands(empty, From, To, Request)
+	[] ->
+	    ok;
+	Fields ->
+	    Request = #adhoc_command{node = ?NS_ADMINX(<<"announce-allhosts">>),
+				     action = complete,
+				     xdata = #xdata{type = submit,
+						    fields = Fields}},
+	    To = jid:make(Host),
+	    mod_announce:announce_commands(empty, From, To, Request)
     end,
     Time = timer:seconds(Delay),
     Node = jlib:binary_to_atom(ENode),
-    {ok, _} = timer:apply_after(Time, rpc, call,
-				[Node, init, Action, []]),
-    {result, []}.
+    {ok, _} = timer:apply_after(Time, rpc, call, [Node, init, Action, []]),
+    {result, undefined}.
 
 get_last_info(User, Server) ->
     case gen_mod:is_loaded(Server, mod_last) of
@@ -2114,111 +1726,81 @@ get_last_info(User, Server) ->
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 adhoc_sm_commands(_Acc, From,
-		  #jid{user = User, server = Server, lserver = LServer} =
-		      _To,
-		  #adhoc_request{lang = Lang, node = <<"config">>,
-				 action = Action, xdata = XData} =
-		      Request) ->
+		  #jid{user = User, server = Server, lserver = LServer},
+		  #adhoc_command{lang = Lang, node = <<"config">>,
+				 action = Action, xdata = XData} = Request) ->
     case acl:match_rule(LServer, configure, From) of
-      deny -> {error, ?ERRT_FORBIDDEN(Lang, <<"Denied by ACL">>)};
-      allow ->
-	  ActionIsExecute = lists:member(Action,
-					 [<<"">>, <<"execute">>,
-					  <<"complete">>]),
-	  if Action == <<"cancel">> ->
-		 adhoc:produce_response(Request,
-					#adhoc_response{status = canceled});
-	     XData == false, ActionIsExecute ->
-		 case get_sm_form(User, Server, <<"config">>, Lang) of
-		   {result, Form} ->
-		       adhoc:produce_response(Request,
-					      #adhoc_response{status =
-								  executing,
-							      elements = Form});
-		   {error, Error} -> {error, Error}
-		 end;
-	     XData /= false, ActionIsExecute ->
-		 case jlib:parse_xdata_submit(XData) of
-		   invalid ->
-		       Txt = <<"Incorrect data form">>,
-		       {error, ?ERRT_BAD_REQUEST(Lang, Txt)};
-		   Fields ->
-		       set_sm_form(User, Server, <<"config">>, Request, Fields)
-		 end;
-	     true ->
-		Txt = <<"Incorrect action or data form">>,
-		{error, ?ERRT_BAD_REQUEST(Lang, Txt)}
-	  end
+	deny ->
+	    {error, xmpp:err_forbidden(<<"Denied by ACL">>, Lang)};
+	allow ->
+	    ActionIsExecute = Action == execute orelse Action == complete,
+	    if Action == cancel ->
+		    xmpp_util:make_adhoc_response(
+		      Request, #adhoc_command{status = canceled});
+	       XData == undefined, ActionIsExecute ->
+		    case get_sm_form(User, Server, <<"config">>, Lang) of
+			{result, Form} ->
+			    xmpp_util:make_adhoc_response(
+			      Request, #adhoc_command{status = executing,
+						      xdata = Form});
+			{error, Error} ->
+			    {error, Error}
+		    end;
+	       XData /= undefined, ActionIsExecute ->
+		    set_sm_form(User, Server, <<"config">>, Request);
+	       true ->
+		    Txt = <<"Unexpected action">>,
+		    {error, xmpp:err_bad_request(Txt, Lang)}
+	    end
     end;
 adhoc_sm_commands(Acc, _From, _To, _Request) -> Acc.
 
 get_sm_form(User, Server, <<"config">>, Lang) ->
     {result,
-     [#xmlel{name = <<"x">>,
-	     attrs = [{<<"xmlns">>, ?NS_XDATA}],
-	     children =
-		 [?HFIELD(),
-		  #xmlel{name = <<"title">>, attrs = [],
-			 children =
-			     [{xmlcdata,
-			       <<(?T(Lang, <<"Administration of ">>))/binary,
-				 User/binary>>}]},
-		  #xmlel{name = <<"field">>,
-			 attrs =
-			     [{<<"type">>, <<"list-single">>},
-			      {<<"label">>, ?T(Lang, <<"Action on user">>)},
-			      {<<"var">>, <<"action">>}],
-			 children =
-			     [#xmlel{name = <<"value">>, attrs = [],
-				     children = [{xmlcdata, <<"edit">>}]},
-			      #xmlel{name = <<"option">>,
-				     attrs =
-					 [{<<"label">>,
-					   ?T(Lang, <<"Edit Properties">>)}],
-				     children =
-					 [#xmlel{name = <<"value">>, attrs = [],
-						 children =
-						     [{xmlcdata,
-						       <<"edit">>}]}]},
-			      #xmlel{name = <<"option">>,
-				     attrs =
-					 [{<<"label">>,
-					   ?T(Lang, <<"Remove User">>)}],
-				     children =
-					 [#xmlel{name = <<"value">>, attrs = [],
-						 children =
-						     [{xmlcdata,
-						       <<"remove">>}]}]}]},
-		  ?XFIELD(<<"text-private">>, <<"Password">>,
-			  <<"password">>,
-			  (ejabberd_auth:get_password_s(User, Server)))]}]};
+     #xdata{type = form,
+	    title = <<(?T(Lang, <<"Administration of ">>))/binary, User/binary>>,
+	    fields =
+		[?HFIELD(),
+		 #xdata_field{
+		    type = 'list-single',
+		    label = ?T(Lang, <<"Action on user">>),
+		    var = <<"action">>,
+		    values = [<<"edit">>],
+		    options = [#xdata_option{
+				  label = ?T(Lang, <<"Edit Properties">>),
+				  value = <<"edit">>},
+			       #xdata_option{
+				  label = ?T(Lang, <<"Remove User">>),
+				  value = <<"remove">>}]},
+		 ?XFIELD('text-private', <<"Password">>,
+			 <<"password">>,
+			 ejabberd_auth:get_password_s(User, Server))]}};
 get_sm_form(_User, _Server, _Node, _Lang) ->
-    {error, ?ERR_SERVICE_UNAVAILABLE}.
+    {error, xmpp:err_service_unavailable()}.
 
 set_sm_form(User, Server, <<"config">>,
-	    #adhoc_request{lang = Lang, node = Node,
-			   sessionid = SessionID},
-	    XData) ->
-    Response = #adhoc_response{lang = Lang, node = Node,
-			       sessionid = SessionID, status = completed},
-    case lists:keysearch(<<"action">>, 1, XData) of
-      {value, {_, [<<"edit">>]}} ->
-	  case lists:keysearch(<<"password">>, 1, XData) of
-	    {value, {_, [Password]}} ->
-		ejabberd_auth:set_password(User, Server, Password),
-		adhoc:produce_response(Response);
-	    _ ->
-		Txt = <<"No 'password' found in data form">>,
-		{error, ?ERRT_NOT_ACCEPTABLE(Lang, Txt)}
-	  end;
-      {value, {_, [<<"remove">>]}} ->
-	  catch ejabberd_auth:remove_user(User, Server),
-	  adhoc:produce_response(Response);
-      _ ->
-	  Txt = <<"Incorrect value of 'action' in data form">>,
-	  {error, ?ERRT_NOT_ACCEPTABLE(Lang, Txt)}
+	    #adhoc_command{lang = Lang, node = Node,
+			   sid = SessionID, xdata = XData}) ->
+    Response = #adhoc_command{lang = Lang, node = Node,
+			      sid = SessionID, status = completed},
+    case xmpp_util:get_xdata_values(<<"action">>, XData) of
+	[<<"edit">>] ->
+	    case xmpp_util:get_xdata_values(<<"password">>, XData) of
+		[Password] ->
+		    ejabberd_auth:set_password(User, Server, Password),
+		    xmpp_util:make_adhoc_response(Response);
+		_ ->
+		    Txt = <<"No 'password' found in data form">>,
+		    {error, xmpp:err_not_acceptable(Txt, Lang)}
+	    end;
+	[<<"remove">>] ->
+	    catch ejabberd_auth:remove_user(User, Server),
+	    xmpp_util:make_adhoc_response(Response);
+	_ ->
+	    Txt = <<"Incorrect value of 'action' in data form">>,
+	    {error, xmpp:err_not_acceptable(Txt, Lang)}
     end;
-set_sm_form(_User, _Server, _Node, _Request, _Fields) ->
-    {error, ?ERR_SERVICE_UNAVAILABLE}.
+set_sm_form(_User, _Server, _Node, _Request) ->
+    {error, xmpp:err_service_unavailable()}.
 
 mod_opt_type(_) -> [].

From a417fbf45b88bae2163397cc9e06a7bc22b20f7a Mon Sep 17 00:00:00 2001
From: Evgeniy Khramtsov 
Date: Wed, 3 Aug 2016 20:57:05 +0300
Subject: [PATCH 026/151] Rewrite mod_irc to use XML generator

---
 src/mod_irc.erl            | 1225 ++++++++++++--------------------
 src/mod_irc_connection.erl | 1368 +++++++++++++-----------------------
 src/mod_irc_mnesia.erl     |    2 +-
 src/mod_irc_riak.erl       |    2 +-
 src/mod_irc_sql.erl        |    2 +-
 src/xmpp.erl               |   18 +-
 6 files changed, 972 insertions(+), 1645 deletions(-)

diff --git a/src/mod_irc.erl b/src/mod_irc.erl
index 2206028b7..91f43716f 100644
--- a/src/mod_irc.erl
+++ b/src/mod_irc.erl
@@ -34,7 +34,8 @@
 %% API
 -export([start_link/2, start/2, stop/1, export/1, import/1,
 	 import/3, closed_connection/3, get_connection_params/3,
-	 data_to_binary/2]).
+	 data_to_binary/2, process_disco_info/1, process_disco_items/1,
+	 process_register/1, process_vcard/1, process_command/1]).
 
 -export([init/1, handle_call/3, handle_cast/2,
 	 handle_info/2, terminate/2, code_change/3,
@@ -42,11 +43,7 @@
 
 -include("ejabberd.hrl").
 -include("logger.hrl").
-
--include("jlib.hrl").
-
--include("adhoc.hrl").
-
+-include("xmpp.hrl").
 -include("mod_irc.hrl").
 
 -define(DEFAULT_IRC_ENCODING, <<"iso8859-15">>).
@@ -125,6 +122,18 @@ init([Host, Opts]) ->
     catch ets:new(irc_connection,
 		  [named_table, public,
 		   {keypos, #irc_connection.jid_server_host}]),
+    IQDisc = gen_mod:get_opt(iqdisc, Opts, fun gen_iq_handler:check_type/1,
+                             one_queue),
+    gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_INFO,
+				  ?MODULE, process_disco_info, IQDisc),
+    gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_ITEMS,
+				  ?MODULE, process_disco_items, IQDisc),
+    gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_REGISTER,
+				  ?MODULE, process_register, IQDisc),
+    gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_VCARD,
+				  ?MODULE, process_vcard, IQDisc),
+    gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_COMMANDS,
+				  ?MODULE, process_command, IQDisc),
     ejabberd_router:register_route(MyHost, Host),
     {ok,
      #state{host = MyHost, server_host = Host,
@@ -176,8 +185,13 @@ handle_info(_Info, State) -> {noreply, State}.
 %% cleaning up. When it returns, the gen_server terminates with Reason.
 %% The return value is ignored.
 %%--------------------------------------------------------------------
-terminate(_Reason, State) ->
-    ejabberd_router:unregister_route(State#state.host), ok.
+terminate(_Reason, #state{host = MyHost}) ->
+    ejabberd_router:unregister_route(MyHost),
+    gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_INFO),
+    gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_ITEMS),
+    gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_REGISTER),
+    gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_VCARD),
+    gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_COMMANDS).
 
 %%--------------------------------------------------------------------
 %% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
@@ -203,287 +217,222 @@ stop_supervisor(Host) ->
     supervisor:terminate_child(ejabberd_sup, Proc),
     supervisor:delete_child(ejabberd_sup, Proc).
 
-do_route(Host, ServerHost, Access, From, To, Packet) ->
+do_route(Host, ServerHost, Access, From,
+	 #jid{luser = LUser, lresource = LResource} = To, Packet) ->
     case acl:match_rule(ServerHost, Access, From) of
-      allow -> do_route1(Host, ServerHost, From, To, Packet);
-      _ ->
-	  #xmlel{attrs = Attrs} = Packet,
-	  Lang = fxml:get_attr_s(<<"xml:lang">>, Attrs),
-	  ErrText = <<"Access denied by service policy">>,
-	  Err = jlib:make_error_reply(Packet,
-				      ?ERRT_FORBIDDEN(Lang, ErrText)),
-	  ejabberd_router:route(To, From, Err)
+	allow ->
+	    case Packet of
+		#iq{} when LUser == <<"">>, LResource == <<"">> ->
+		    ejabberd_router:process_iq(From, To, Packet);
+		#iq{} when LUser == <<"">>, LResource /= <<"">> ->
+		    Err = xmpp:err_service_unavailable(),
+		    ejabberd_router:route_error(To, From, Packet, Err);
+		_ ->
+		    sm_route(Host, ServerHost, From, To, Packet)
+	    end;
+	deny ->
+	    Lang = xmpp:get_lang(Packet),
+	    Err = xmpp:err_forbidden(<<"Denied by ACL">>, Lang),
+	    ejabberd_router:route_error(To, From, Packet, Err)
     end.
 
-do_route1(Host, ServerHost, From, To, Packet) ->
+process_disco_info(#iq{type = set, lang = Lang} = IQ) ->
+    Txt = <<"Value 'set' of 'type' attribute is not allowed">>,
+    xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang));
+process_disco_info(#iq{type = get, lang = Lang, to = To,
+		       sub_els = [#disco_info{node = Node}]} = IQ) ->
+    ServerHost = ejabberd_router:host_of_route(To#jid.lserver),
+    Info = ejabberd_hooks:run_fold(disco_info, ServerHost,
+				   [], [ServerHost, ?MODULE, <<"">>, <<"">>]),
+    case iq_disco(ServerHost, Node, Lang) of
+	undefined ->
+	    xmpp:make_iq_result(IQ, #disco_info{});
+	DiscoInfo ->
+	    xmpp:make_iq_result(IQ, DiscoInfo#disco_info{xdata = Info})
+    end.
+
+process_disco_items(#iq{type = set, lang = Lang} = IQ) ->
+    Txt = <<"Value 'set' of 'type' attribute is not allowed">>,
+    xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang));
+process_disco_items(#iq{type = get, lang = Lang, to = To,
+			sub_els = [#disco_items{node = Node}]} = IQ) ->
+    case Node of
+	undefined ->
+	    xmpp:make_iq_result(IQ, #disco_items{});
+	<<"join">> ->
+	    xmpp:make_iq_result(IQ, #disco_items{});
+	<<"register">> ->
+	    xmpp:make_iq_result(IQ, #disco_items{});
+	?NS_COMMANDS ->
+	    Host = To#jid.lserver,
+	    ServerHost = ejabberd_router:host_of_route(Host),
+	    xmpp:make_iq_result(
+	      IQ, #disco_items{node = Node,
+			       items = command_items(ServerHost, Host, Lang)});
+	_ ->
+	    Txt = <<"Node not found">>,
+	    xmpp:make_error(IQ, xmpp:err_item_not_found(Txt, Lang))
+    end.
+
+process_register(#iq{type = get, to = To, from = From, lang = Lang} = IQ) ->
+    Host = To#jid.lserver,
+    ServerHost = ejabberd_router:host_of_route(Host),
+    case get_form(ServerHost, Host, From, Lang) of
+	{result, Res} ->
+	    xmpp:make_iq_result(IQ, Res);
+	{error, Error} ->
+	    xmpp:make_error(IQ, Error)
+    end;
+process_register(#iq{type = set, lang = Lang, to = To, from = From,
+		     sub_els = [#register{xdata = #xdata{} = X}]} = IQ) ->
+    case X#xdata.type of
+	cancel ->
+	    xmpp:make_iq_result(IQ, #register{});
+	submit ->
+	    Host = To#jid.lserver,
+	    ServerHost = ejabberd_router:host_of_route(Host),
+	    case set_form(ServerHost, Host, From, Lang, X) of
+		{result, Res} ->
+		    xmpp:make_iq_result(IQ, Res);
+		{error, Error} ->
+		    xmpp:make_error(IQ, Error)
+	    end;
+	_ ->
+	    Txt = <<"Incorrect value of 'type' attribute">>,
+	    xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang))
+    end;
+process_register(#iq{type = set, lang = Lang} = IQ) ->
+    Txt = <<"No data form found">>,
+    xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)).
+
+process_vcard(#iq{type = set, lang = Lang} = IQ) ->
+    Txt = <<"Value 'set' of 'type' attribute is not allowed">>,
+    xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang));
+process_vcard(#iq{type = get, lang = Lang} = IQ) ->
+    xmpp:make_iq_result(IQ, iq_get_vcard(Lang)).
+
+process_command(#iq{type = get, lang = Lang} = IQ) ->
+    Txt = <<"Value 'get' of 'type' attribute is not allowed">>,
+    xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang));
+process_command(#iq{type = set, lang = Lang, to = To, from = From,
+		    sub_els = [#adhoc_command{node = Node} = Request]} = IQ) ->
+    Host = To#jid.lserver,
+    ServerHost = ejabberd_router:host_of_route(Host),
+    case lists:keyfind(Node, 1, commands(ServerHost)) of
+	{_, _, Function} ->
+	    try Function(From, To, Request) of
+		ignore ->
+		    ignore;
+		{error, Error} ->
+		    xmpp:make_error(IQ, Error);
+		Command ->
+		    xmpp:make_iq_result(IQ, Command)
+	    catch E:R ->
+		    ?ERROR_MSG("ad-hoc handler failed: ~p",
+			       [{E, {R, erlang:get_stacktrace()}}]),
+		    xmpp:make_error(IQ, xmpp:internal_server_error())
+	    end;
+	_ ->
+	    Txt = <<"Node not found">>,
+	    xmpp:make_error(IQ, xmpp:err_item_not_found(Txt, Lang))
+    end.
+
+sm_route(Host, ServerHost, From, To, Packet) ->
     #jid{user = ChanServ, resource = Resource} = To,
-    #xmlel{} = Packet,
-    case ChanServ of
-      <<"">> ->
-	  case Resource of
-	    <<"">> ->
-		case jlib:iq_query_info(Packet) of
-		  #iq{type = get, xmlns = (?NS_DISCO_INFO) = XMLNS,
-		      sub_el = SubEl, lang = Lang} =
-		      IQ ->
-		      Node = fxml:get_tag_attr_s(<<"node">>, SubEl),
-		      Info = ejabberd_hooks:run_fold(disco_info, ServerHost,
-						     [],
-						     [ServerHost, ?MODULE,
-						      <<"">>, <<"">>]),
-		      case iq_disco(ServerHost, Node, Lang) of
-			[] ->
-			    Res = IQ#iq{type = result,
-					sub_el =
-					    [#xmlel{name = <<"query">>,
-						    attrs =
-							[{<<"xmlns">>, XMLNS}],
-						    children = []}]},
-			    ejabberd_router:route(To, From,
-						  jlib:iq_to_xml(Res));
-			DiscoInfo ->
-			    Res = IQ#iq{type = result,
-					sub_el =
-					    [#xmlel{name = <<"query">>,
-						    attrs =
-							[{<<"xmlns">>, XMLNS}],
-						    children =
-							DiscoInfo ++ Info}]},
-			    ejabberd_router:route(To, From, jlib:iq_to_xml(Res))
-		      end;
-		  #iq{type = get, xmlns = (?NS_DISCO_ITEMS) = XMLNS,
-		      sub_el = SubEl, lang = Lang} =
-		      IQ ->
-		      Node = fxml:get_tag_attr_s(<<"node">>, SubEl),
-		      case Node of
-			<<>> ->
-			    ResIQ = IQ#iq{type = result,
-					  sub_el =
-					      [#xmlel{name = <<"query">>,
-						      attrs =
-							  [{<<"xmlns">>,
-							    XMLNS}],
-						      children = []}]},
-			    Res = jlib:iq_to_xml(ResIQ);
-			<<"join">> ->
-			    ResIQ = IQ#iq{type = result,
-					  sub_el =
-					      [#xmlel{name = <<"query">>,
-						      attrs =
-							  [{<<"xmlns">>,
-							    XMLNS}],
-						      children = []}]},
-			    Res = jlib:iq_to_xml(ResIQ);
-			<<"register">> ->
-			    ResIQ = IQ#iq{type = result,
-					  sub_el =
-					      [#xmlel{name = <<"query">>,
-						      attrs =
-							  [{<<"xmlns">>,
-							    XMLNS}],
-						      children = []}]},
-			    Res = jlib:iq_to_xml(ResIQ);
-			?NS_COMMANDS ->
-			    ResIQ = IQ#iq{type = result,
-					  sub_el =
-					      [#xmlel{name = <<"query">>,
-						      attrs =
-							  [{<<"xmlns">>, XMLNS},
-							   {<<"node">>, Node}],
-						      children =
-							  command_items(ServerHost,
-									Host,
-									Lang)}]},
-			    Res = jlib:iq_to_xml(ResIQ);
-			_ ->
-			    Txt = <<"Node not found">>,
-			    Res = jlib:make_error_reply(
-				    Packet, ?ERRT_ITEM_NOT_FOUND(Lang, Txt))
-		      end,
-		      ejabberd_router:route(To, From, Res);
-		  #iq{xmlns = ?NS_REGISTER} = IQ ->
-		      process_register(ServerHost, Host, From, To, IQ);
-		  #iq{type = get, xmlns = (?NS_VCARD) = XMLNS,
-		      lang = Lang} =
-		      IQ ->
-		      Res = IQ#iq{type = result,
-				  sub_el =
-				      [#xmlel{name = <<"vCard">>,
-					      attrs = [{<<"xmlns">>, XMLNS}],
-					      children = iq_get_vcard(Lang)}]},
-		      ejabberd_router:route(To, From, jlib:iq_to_xml(Res));
-		  #iq{type = set, xmlns = ?NS_COMMANDS, lang = Lang,
-		      sub_el = SubEl} =
-		      IQ ->
-		      Request = adhoc:parse_request(IQ),
-		      case lists:keysearch(Request#adhoc_request.node, 1,
-					   commands(ServerHost))
-			  of
-			{value, {_, _, Function}} ->
-			    case catch Function(From, To, Request) of
-			      {'EXIT', Reason} ->
-				  ?ERROR_MSG("~p~nfor ad-hoc handler of ~p",
-					     [Reason, {From, To, IQ}]),
-				  Res = IQ#iq{type = error,
-					      sub_el =
-						  [SubEl,
-						   ?ERR_INTERNAL_SERVER_ERROR]};
-			      ignore -> Res = ignore;
-			      {error, Error} ->
-				  Res = IQ#iq{type = error,
-					      sub_el = [SubEl, Error]};
-			      Command ->
-				  Res = IQ#iq{type = result, sub_el = [Command]}
-			    end,
-			    if Res /= ignore ->
-				   ejabberd_router:route(To, From,
-							 jlib:iq_to_xml(Res));
-			       true -> ok
-			    end;
-			_ ->
-			    Txt = <<"Node not found">>,
-			    Err = jlib:make_error_reply(
-				    Packet, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)),
-			    ejabberd_router:route(To, From, Err)
-		      end;
-		  #iq{} = _IQ ->
-		      Err = jlib:make_error_reply(Packet,
-						  ?ERR_FEATURE_NOT_IMPLEMENTED),
-		      ejabberd_router:route(To, From, Err);
-		  _ -> ok
-		end;
-	    _ ->
-		Err = jlib:make_error_reply(Packet, ?ERR_BAD_REQUEST),
-		ejabberd_router:route(To, From, Err)
-	  end;
-      _ ->
-	  case str:tokens(ChanServ, <<"%">>) of
-	    [<<_, _/binary>> = Channel, <<_, _/binary>> = Server] ->
-		case ets:lookup(irc_connection, {From, Server, Host}) of
-		  [] ->
-		      ?DEBUG("open new connection~n", []),
-		      {Username, Encoding, Port, Password} =
-			  get_connection_params(Host, ServerHost, From, Server),
-		      ConnectionUsername = case Packet of
+    case str:tokens(ChanServ, <<"%">>) of
+	[<<_, _/binary>> = Channel, <<_, _/binary>> = Server] ->
+	    case ets:lookup(irc_connection, {From, Server, Host}) of
+		[] ->
+		    ?DEBUG("open new connection~n", []),
+		    {Username, Encoding, Port, Password} =
+			get_connection_params(Host, ServerHost, From, Server),
+		    ConnectionUsername = case Packet of
 					     %% If the user tries to join a
 					     %% chatroom, the packet for sure
 					     %% contains the desired username.
-					     #xmlel{name = <<"presence">>} ->
-						 Resource;
+					     #presence{} -> Resource;
 					     %% Otherwise, there is no firm
 					     %% conclusion from the packet.
 					     %% Better to use the configured
 					     %% username (which defaults to the
 					     %% username part of the JID).
 					     _ -> Username
-					   end,
-		      Ident = extract_ident(Packet),
-		      RemoteAddr = extract_ip_address(Packet),
-		      RealName = get_realname(ServerHost),
-		      WebircPassword = get_webirc_password(ServerHost),
-		      {ok, Pid} = mod_irc_connection:start(From, Host,
-							   ServerHost, Server,
-							   ConnectionUsername,
-							   Encoding, Port,
-							   Password, Ident, RemoteAddr, RealName, WebircPassword, ?MODULE),
-		      ets:insert(irc_connection,
-				 #irc_connection{jid_server_host =
-						     {From, Server, Host},
-						 pid = Pid}),
-		      mod_irc_connection:route_chan(Pid, Channel, Resource,
-						    Packet),
-		      ok;
-		  [R] ->
-		      Pid = R#irc_connection.pid,
-		      ?DEBUG("send to process ~p~n", [Pid]),
-		      mod_irc_connection:route_chan(Pid, Channel, Resource,
-						    Packet),
-		      ok
-		end;
-	    _ ->
-		Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet),
-		case str:tokens(ChanServ, <<"!">>) of
-		  [<<_, _/binary>> = Nick, <<_, _/binary>> = Server] ->
-		      case ets:lookup(irc_connection, {From, Server, Host}) of
+					 end,
+		    Ident = extract_ident(Packet),
+		    RemoteAddr = extract_ip_address(Packet),
+		    RealName = get_realname(ServerHost),
+		    WebircPassword = get_webirc_password(ServerHost),
+		    {ok, Pid} = mod_irc_connection:start(
+				  From, Host, ServerHost, Server,
+				  ConnectionUsername, Encoding, Port,
+				  Password, Ident, RemoteAddr, RealName,
+				  WebircPassword, ?MODULE),
+		    ets:insert(irc_connection,
+			       #irc_connection{
+				  jid_server_host = {From, Server, Host},
+				  pid = Pid}),
+		    mod_irc_connection:route_chan(Pid, Channel, Resource, Packet);
+		[R] ->
+		    Pid = R#irc_connection.pid,
+		    ?DEBUG("send to process ~p~n", [Pid]),
+		    mod_irc_connection:route_chan(Pid, Channel, Resource, Packet)
+	    end;
+	_ ->
+	    Lang = xmpp:get_lang(Packet),
+	    case str:tokens(ChanServ, <<"!">>) of
+		[<<_, _/binary>> = Nick, <<_, _/binary>> = Server] ->
+		    case ets:lookup(irc_connection, {From, Server, Host}) of
 			[] ->
 			    Txt = <<"IRC connection not found">>,
-			    Err = jlib:make_error_reply(
-				    Packet, ?ERRT_SERVICE_UNAVAILABLE(Lang, Txt)),
-			    ejabberd_router:route(To, From, Err);
+			    Err = xmpp:err_service_unavailable(Txt, Lang),
+			    ejabberd_router:route_error(To, From, Packet, Err);
 			[R] ->
 			    Pid = R#irc_connection.pid,
 			    ?DEBUG("send to process ~p~n", [Pid]),
-			    mod_irc_connection:route_nick(Pid, Nick, Packet),
-			    ok
-		      end;
-		  _ ->
-		      Txt = <<"Failed to parse chanserv">>,
-		      Err = jlib:make_error_reply(
-			      Packet, ?ERRT_BAD_REQUEST(Lang, Txt)),
-		      ejabberd_router:route(To, From, Err)
-		end
-	  end
+			    mod_irc_connection:route_nick(Pid, Nick, Packet)
+		    end;
+		_ ->
+		    Txt = <<"Failed to parse chanserv">>,
+		    Err = xmpp:err_bad_request(Txt, Lang),
+		    ejabberd_router:route_error(To, From, Packet, Err)
+	    end
     end.
 
 closed_connection(Host, From, Server) ->
     ets:delete(irc_connection, {From, Server, Host}).
 
-iq_disco(_ServerHost, <<>>, Lang) ->
-    [#xmlel{name = <<"identity">>,
-	    attrs =
-		[{<<"category">>, <<"conference">>},
-		 {<<"type">>, <<"irc">>},
-		 {<<"name">>,
-		  translate:translate(Lang, <<"IRC Transport">>)}],
-	    children = []},
-     #xmlel{name = <<"feature">>,
-	    attrs = [{<<"var">>, ?NS_DISCO_INFO}], children = []},
-     #xmlel{name = <<"feature">>,
-	    attrs = [{<<"var">>, ?NS_MUC}], children = []},
-     #xmlel{name = <<"feature">>,
-	    attrs = [{<<"var">>, ?NS_REGISTER}], children = []},
-     #xmlel{name = <<"feature">>,
-	    attrs = [{<<"var">>, ?NS_VCARD}], children = []},
-     #xmlel{name = <<"feature">>,
-	    attrs = [{<<"var">>, ?NS_COMMANDS}], children = []}];
+iq_disco(_ServerHost, undefined, Lang) ->
+    #disco_info{
+       identities = [#identity{category = <<"conference">>,
+			       type = <<"irc">>,
+			       name = translate:translate(Lang, <<"IRC Transport">>)}],
+       features = [?NS_DISCO_INFO, ?NS_DISCO_ITEMS, ?NS_MUC,
+		   ?NS_REGISTER, ?NS_VCARD, ?NS_COMMANDS]};
 iq_disco(ServerHost, Node, Lang) ->
-    case lists:keysearch(Node, 1, commands(ServerHost)) of
-      {value, {_, Name, _}} ->
-	  [#xmlel{name = <<"identity">>,
-		  attrs =
-		      [{<<"category">>, <<"automation">>},
-		       {<<"type">>, <<"command-node">>},
-		       {<<"name">>, translate:translate(Lang, Name)}],
-		  children = []},
-	   #xmlel{name = <<"feature">>,
-		  attrs = [{<<"var">>, ?NS_COMMANDS}], children = []},
-	   #xmlel{name = <<"feature">>,
-		  attrs = [{<<"var">>, ?NS_XDATA}], children = []}];
-      _ -> []
+    case lists:keyfind(Node, commands(ServerHost)) of
+	{_, Name, _} ->
+	    #disco_info{
+	       identities = [#identity{category = <<"automation">>,
+				       type = <<"command-node">>,
+				       name = translate:translate(Lang, Name)}],
+	       features = [?NS_COMMANDS, ?NS_XDATA]};
+	_ ->
+	    undefined
     end.
 
 iq_get_vcard(Lang) ->
-    [#xmlel{name = <<"FN">>, attrs = [],
-	    children = [{xmlcdata, <<"ejabberd/mod_irc">>}]},
-     #xmlel{name = <<"URL">>, attrs = [],
-	    children = [{xmlcdata, ?EJABBERD_URI}]},
-     #xmlel{name = <<"DESC">>, attrs = [],
-	    children =
-		[{xmlcdata,
-		  <<(translate:translate(Lang,
-					 <<"ejabberd IRC module">>))/binary,
-		    "\nCopyright (c) 2003-2016 ProcessOne">>}]}].
+    Desc = translate:translate(Lang, <<"ejabberd IRC module">>),
+    Copyright = <<"Copyright (c) 2003-2016 ProcessOne">>,
+    #vcard_temp{fn = <<"ejabberd/mod_irc">>,
+		url = ?EJABBERD_URI,
+		desc = <>}.
 
 command_items(ServerHost, Host, Lang) ->
-    lists:map(fun ({Node, Name, _Function}) ->
-		      #xmlel{name = <<"item">>,
-			     attrs =
-				 [{<<"jid">>, Host}, {<<"node">>, Node},
-				  {<<"name">>,
-				   translate:translate(Lang, Name)}],
-			     children = []}
-	      end,
-	      commands(ServerHost)).
+    lists:map(fun({Node, Name, _Function}) ->
+		      #disco_item{jid = jid:make(Host),
+				  node = Node,
+				  name = translate:translate(Lang, Name)}
+	      end, commands(ServerHost)).
 
 commands(ServerHost) ->
     [{<<"join">>, <<"Join channel">>, fun adhoc_join/3},
@@ -494,243 +443,120 @@ commands(ServerHost) ->
 	      adhoc_register(ServerHost, From, To, Request)
       end}].
 
-process_register(ServerHost, Host, From, To,
-		 #iq{} = IQ) ->
-    case catch process_irc_register(ServerHost, Host, From,
-				    To, IQ)
-	of
-      {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]);
-      ResIQ ->
-	  if ResIQ /= ignore ->
-		 ejabberd_router:route(To, From, jlib:iq_to_xml(ResIQ));
-	     true -> ok
-	  end
-    end.
-
-find_xdata_el(#xmlel{children = SubEls}) ->
-    find_xdata_el1(SubEls).
-
-find_xdata_el1([]) -> false;
-find_xdata_el1([#xmlel{name = Name, attrs = Attrs,
-		       children = SubEls}
-		| Els]) ->
-    case fxml:get_attr_s(<<"xmlns">>, Attrs) of
-      ?NS_XDATA ->
-	  #xmlel{name = Name, attrs = Attrs, children = SubEls};
-      _ -> find_xdata_el1(Els)
-    end;
-find_xdata_el1([_ | Els]) -> find_xdata_el1(Els).
-
-process_irc_register(ServerHost, Host, From, _To,
-		     #iq{type = Type, xmlns = XMLNS, lang = Lang,
-			 sub_el = SubEl} =
-			 IQ) ->
-    case Type of
-      set ->
-	  XDataEl = find_xdata_el(SubEl),
-	  case XDataEl of
-	    false ->
-		Txt1 = <<"No data form found">>,
-		IQ#iq{type = error,
-		      sub_el = [SubEl, ?ERRT_NOT_ACCEPTABLE(Lang, Txt1)]};
-	    #xmlel{attrs = Attrs} ->
-		case fxml:get_attr_s(<<"type">>, Attrs) of
-		  <<"cancel">> ->
-		      IQ#iq{type = result,
-			    sub_el =
-				[#xmlel{name = <<"query">>,
-					attrs = [{<<"xmlns">>, XMLNS}],
-					children = []}]};
-		  <<"submit">> ->
-		      XData = jlib:parse_xdata_submit(XDataEl),
-		      case XData of
-			invalid ->
-			    Txt2 = <<"Incorrect data form">>,
-			    IQ#iq{type = error,
-				  sub_el = [SubEl, ?ERRT_BAD_REQUEST(Lang, Txt2)]};
-			_ ->
-			    Node = str:tokens(fxml:get_tag_attr_s(<<"node">>,
-								 SubEl),
-					      <<"/">>),
-			    case set_form(ServerHost, Host, From, Node, Lang,
-					  XData)
-				of
-			      {result, Res} ->
-				  IQ#iq{type = result,
-					sub_el =
-					    [#xmlel{name = <<"query">>,
-						    attrs =
-							[{<<"xmlns">>, XMLNS}],
-						    children = Res}]};
-			      {error, Error} ->
-				  IQ#iq{type = error, sub_el = [SubEl, Error]}
-			    end
-		      end;
-		  _ ->
-		      Txt3 = <<"Incorrect value of 'type' attribute">>,
-		      IQ#iq{type = error,
-			    sub_el = [SubEl, ?ERRT_BAD_REQUEST(Lang, Txt3)]}
-		end
-	  end;
-      get ->
-	  Node = str:tokens(fxml:get_tag_attr_s(<<"node">>, SubEl),
-			    <<"/">>),
-	  case get_form(ServerHost, Host, From, Node, Lang) of
-	    {result, Res} ->
-		IQ#iq{type = result,
-		      sub_el =
-			  [#xmlel{name = <<"query">>,
-				  attrs = [{<<"xmlns">>, XMLNS}],
-				  children = Res}]};
-	    {error, Error} ->
-		IQ#iq{type = error, sub_el = [SubEl, Error]}
-	  end
-    end.
-
 get_data(ServerHost, Host, From) ->
     LServer = jid:nameprep(ServerHost),
     Mod = gen_mod:db_mod(LServer, ?MODULE),
     Mod:get_data(LServer, Host, From).
 
-get_form(ServerHost, Host, From, [], Lang) ->
+get_form(ServerHost, Host, From, Lang) ->
     #jid{user = User, server = Server} = From,
     DefaultEncoding = get_default_encoding(Host),
     Customs = case get_data(ServerHost, Host, From) of
-		error ->
+		  error ->
 		      Txt1 = <<"Database failure">>,
-		      {error, ?ERRT_INTERNAL_SERVER_ERROR(Lang, Txt1)};
-		empty -> {User, []};
-		Data -> get_username_and_connection_params(Data)
+		      {error, xmpp:err_internal_server_error(Txt1, Lang)};
+		  empty -> {User, []};
+		  Data -> get_username_and_connection_params(Data)
 	      end,
     case Customs of
-      {error, _Error} -> Customs;
-      {Username, ConnectionsParams} ->
-	  {result,
-	   [#xmlel{name = <<"instructions">>, attrs = [],
-		   children =
-		       [{xmlcdata,
-			 translate:translate(Lang,
-					     <<"You need an x:data capable client to "
-					       "configure mod_irc settings">>)}]},
-	    #xmlel{name = <<"x">>,
-		   attrs = [{<<"xmlns">>, ?NS_XDATA}],
-		   children =
-		       [#xmlel{name = <<"title">>, attrs = [],
-			       children =
-				   [{xmlcdata,
-				     <<(translate:translate(Lang,
-							    <<"Registration in mod_irc for ">>))/binary,
-				       User/binary, "@", Server/binary>>}]},
-			#xmlel{name = <<"instructions">>, attrs = [],
-			       children =
-				   [{xmlcdata,
-				     translate:translate(Lang,
-							 <<"Enter username, encodings, ports and "
-							   "passwords you wish to use for connecting "
-							   "to IRC servers">>)}]},
-			#xmlel{name = <<"field">>,
-			       attrs =
-				   [{<<"type">>, <<"text-single">>},
-				    {<<"label">>,
-				     translate:translate(Lang,
-							 <<"IRC Username">>)},
-				    {<<"var">>, <<"username">>}],
-			       children =
-				   [#xmlel{name = <<"value">>, attrs = [],
-					   children = [{xmlcdata, Username}]}]},
-			#xmlel{name = <<"field">>,
-			       attrs = [{<<"type">>, <<"fixed">>}],
-			       children =
-				   [#xmlel{name = <<"value">>, attrs = [],
-					   children =
-					       [{xmlcdata,
-						 iolist_to_binary(
-                                                   io_lib:format(
-                                                     translate:translate(
-                                                       Lang,
-                                                       <<"If you want to specify"
-                                                         " different ports, "
-                                                         "passwords, encodings "
-                                                         "for IRC servers, "
-                                                         "fill this list with "
-                                                         "values in format "
-                                                         "'{\"irc server\", "
-                                                         "\"encoding\", port, "
-                                                         "\"password\"}'.  "
-                                                         "By default this "
-                                                         "service use \"~s\" "
-                                                         "encoding, port ~p, "
-                                                         "empty password.">>),
-                                                     [DefaultEncoding,
-                                                      ?DEFAULT_IRC_PORT]))}]}]},
-			#xmlel{name = <<"field">>,
-			       attrs = [{<<"type">>, <<"fixed">>}],
-			       children =
-				   [#xmlel{name = <<"value">>, attrs = [],
-					   children =
-					       [{xmlcdata,
-						 translate:translate(Lang,
-								     <<"Example: [{\"irc.lucky.net\", \"koi8-r\", "
-								       "6667, \"secret\"}, {\"vendetta.fef.net\", "
-								       "\"iso8859-1\", 7000}, {\"irc.sometestserver.n"
-								       "et\", \"utf-8\"}].">>)}]}]},
-			#xmlel{name = <<"field">>,
-			       attrs =
-				   [{<<"type">>, <<"text-multi">>},
-				    {<<"label">>,
-				     translate:translate(Lang,
-							 <<"Connections parameters">>)},
-				    {<<"var">>, <<"connections_params">>}],
-			       children =
-				   lists:map(fun (S) ->
-						     #xmlel{name = <<"value">>,
-							    attrs = [],
-							    children =
-								[{xmlcdata, S}]}
-					     end,
-					     str:tokens(list_to_binary(
-                                                          io_lib:format(
-                                                            "~p.",
-                                                            [conn_params_to_list(
-                                                               ConnectionsParams)])),
-							<<"\n">>))}]}]}
-    end;
-get_form(_ServerHost, _Host, _, _, _Lang) ->
-    {error, ?ERR_SERVICE_UNAVAILABLE}.
+	{error, _Error} ->
+	    Customs;
+	{Username, ConnectionsParams} ->
+	    Fs = [#xdata_field{type = 'text-single',
+			       label =  translate:translate(Lang, <<"IRC Username">>),
+			       var = <<"username">>,
+			       values = [Username]},
+		  #xdata_field{type = fixed,
+			       values = [iolist_to_binary(
+					   io_lib:format(
+					     translate:translate(
+					       Lang,
+					       <<"If you want to specify"
+						 " different ports, "
+						 "passwords, encodings "
+						 "for IRC servers, "
+						 "fill this list with "
+						 "values in format "
+						 "'{\"irc server\", "
+						 "\"encoding\", port, "
+						 "\"password\"}'.  "
+						 "By default this "
+						 "service use \"~s\" "
+						 "encoding, port ~p, "
+						 "empty password.">>),
+					     [DefaultEncoding, ?DEFAULT_IRC_PORT]))]},
+		  #xdata_field{type = fixed,
+			       values = [translate:translate(
+					   Lang,
+					   <<"Example: [{\"irc.lucky.net\", \"koi8-r\", "
+					     "6667, \"secret\"}, {\"vendetta.fef.net\", "
+					     "\"iso8859-1\", 7000}, {\"irc.sometestserver.n"
+					     "et\", \"utf-8\"}].">>)]},
+		  #xdata_field{type = 'text-multi',
+			       label = translate:translate(
+					 Lang, <<"Connections parameters">>),
+			       var = <<"connections_params">>,
+			       values = str:tokens(list_to_binary(
+						     io_lib:format(
+						       "~p.",
+						       [conn_params_to_list(
+							  ConnectionsParams)])),
+						   <<"\n">>)}],
+	    X = #xdata{type = form,
+		       title = <<(translate:translate(
+				    Lang, <<"Registration in mod_irc for ">>))/binary,
+				 User/binary, "@", Server/binary>>,
+		       instructions =
+			   [translate:translate(
+			      Lang,
+			      <<"Enter username, encodings, ports and "
+				"passwords you wish to use for connecting "
+				"to IRC servers">>)],
+		       fields = Fs},
+	    {result,
+	     #register{instructions = 
+			   translate:translate(Lang,
+					       <<"You need an x:data capable client to "
+						 "configure mod_irc settings">>),
+		       xdata = X}}
+    end.
 
 set_data(ServerHost, Host, From, Data) ->
     LServer = jid:nameprep(ServerHost),
     Mod = gen_mod:db_mod(LServer, ?MODULE),
     Mod:set_data(LServer, Host, From, data_to_binary(From, Data)).
 
-set_form(ServerHost, Host, From, [], Lang, XData) ->
-    case {lists:keysearch(<<"username">>, 1, XData),
-	  lists:keysearch(<<"connections_params">>, 1, XData)}
-	of
-      {{value, {_, [Username]}}, {value, {_, Strings}}} ->
-	  EncString = lists:foldl(fun (S, Res) ->
-					  <>
-				  end,
-				  <<"">>, Strings),
-	  case erl_scan:string(binary_to_list(EncString)) of
-	    {ok, Tokens, _} ->
-		case erl_parse:parse_term(Tokens) of
-		  {ok, ConnectionsParams} ->
-		      case set_data(ServerHost, Host, From,
-				    [{username, Username},
-				     {connections_params, ConnectionsParams}])
-			  of
-			{atomic, _} -> {result, []};
-			_ -> {error, ?ERRT_NOT_ACCEPTABLE(Lang, <<"Database failure">>)}
-		      end;
-		  _ -> {error, ?ERRT_NOT_ACCEPTABLE(Lang, <<"Parse error">>)}
-		end;
-	    _ -> {error, ?ERRT_NOT_ACCEPTABLE(Lang, <<"Scan error">>)}
-	  end;
-      _ -> {error, ?ERR_NOT_ACCEPTABLE}
-    end;
-set_form(_ServerHost, _Host, _, _, _Lang, _XData) ->
-    {error, ?ERR_SERVICE_UNAVAILABLE}.
+set_form(ServerHost, Host, From, Lang, XData) ->
+    case {xmpp_util:get_xdata_values(<<"username">>, XData),
+	  xmpp_util:get_xdata_values(<<"connections_params">>, XData)} of
+	{[Username], [_|_] = Strings} ->
+	    EncString = lists:foldl(fun (S, Res) ->
+					    <>
+				    end, <<"">>, Strings),
+	    case erl_scan:string(binary_to_list(EncString)) of
+		{ok, Tokens, _} ->
+		    case erl_parse:parse_term(Tokens) of
+			{ok, ConnectionsParams} ->
+			    case set_data(ServerHost, Host, From,
+					  [{username, Username},
+					   {connections_params, ConnectionsParams}]) of
+				{atomic, _} ->
+				    {result, undefined};
+				_ ->
+				    Txt = <<"Database failure">>,
+				    {error, xmpp:err_internal_server_error(Txt, Lang)}
+			    end;
+			_ ->
+			    Txt = <<"Parse error">>,
+			    {error, xmpp:err_not_acceptable(Txt, Lang)}
+		    end;
+		_ ->
+		    {error, xmpp:err_not_acceptable(<<"Scan error">>, Lang)}
+	    end;
+	_ ->
+	    Txt = <<"Incorrect value in data form">>,
+	    {error, xmpp:err_not_acceptable(Txt, Lang)}
+    end.
 
 get_connection_params(Host, From, IRCServer) ->
     [_ | HostTail] = str:tokens(Host, <<".">>),
@@ -805,212 +631,118 @@ get_connection_params(Host, ServerHost, From,
 	   iolist_to_binary(NewPassword)}
     end.
 
-adhoc_join(_From, _To,
-	   #adhoc_request{action = <<"cancel">>} = Request) ->
-    adhoc:produce_response(Request,
-			   #adhoc_response{status = canceled});
-adhoc_join(From, To,
-	   #adhoc_request{lang = Lang, node = _Node,
-			  action = _Action, xdata = XData} =
-	       Request) ->
-    if XData == false ->
-	   Form = #xmlel{name = <<"x">>,
-			 attrs =
-			     [{<<"xmlns">>, ?NS_XDATA},
-			      {<<"type">>, <<"form">>}],
-			 children =
-			     [#xmlel{name = <<"title">>, attrs = [],
-				     children =
-					 [{xmlcdata,
-					   translate:translate(Lang,
-							       <<"Join IRC channel">>)}]},
-			      #xmlel{name = <<"field">>,
-				     attrs =
-					 [{<<"var">>, <<"channel">>},
-					  {<<"type">>, <<"text-single">>},
-					  {<<"label">>,
-					   translate:translate(Lang,
-							       <<"IRC channel (don't put the first #)">>)}],
-				     children =
-					 [#xmlel{name = <<"required">>,
-						 attrs = [], children = []}]},
-			      #xmlel{name = <<"field">>,
-				     attrs =
-					 [{<<"var">>, <<"server">>},
-					  {<<"type">>, <<"text-single">>},
-					  {<<"label">>,
-					   translate:translate(Lang,
-							       <<"IRC server">>)}],
-				     children =
-					 [#xmlel{name = <<"required">>,
-						 attrs = [], children = []}]}]},
-	   adhoc:produce_response(Request,
-				  #adhoc_response{status = executing,
-						  elements = [Form]});
+adhoc_join(_From, _To, #adhoc_command{action = cancel} = Request) ->
+    xmpp_util:make_adhoc_response(Request, #adhoc_command{status = canceled});
+adhoc_join(_From, _To, #adhoc_command{lang = Lang, xdata = undefined} = Request) ->
+    X = #xdata{type = form,
+	       title = translate:translate(Lang, <<"Join IRC channel">>),
+	       fields = [#xdata_field{var = <<"channel">>,
+				      type = 'text-single',
+				      label = translate:translate(
+						Lang, <<"IRC channel (don't put the first #)">>),
+				      required = true},
+			 #xdata_field{var = <<"server">>,
+				      type = 'text-single',
+				      label = translate:translate(Lang, <<"IRC server">>),
+				      required = true}]},
+    xmpp_utils:make_adhoc_response(
+      Request, #adhoc_command{status = executing, xdata = X});
+adhoc_join(From, To, #adhoc_command{lang = Lang, xdata = X} = Request) ->
+    Channel = case xmpp_util:get_xdata_values(<<"channel">>, X) of
+		  [C] -> C;
+		  _ -> false
+	      end,
+    Server = case xmpp_util:get_xdata_values(<<"server">>, X) of
+		 [S] -> S;
+		 _ -> false
+	     end,
+    if Channel /= false, Server /= false ->
+	    RoomJID = jid:make(<>,
+			       To#jid.server),
+	    Reason = translate:translate(Lang, <<"Join the IRC channel here.">>),
+	    Body = iolist_to_binary(
+		     io_lib:format(
+		       translate:translate(
+			 Lang, <<"Join the IRC channel in this Jabber ID: ~s">>),
+		       [jid:to_string(RoomJID)])),
+	    Invite = #message{
+			body = xmpp:mk_text(Body, Lang),
+			sub_els = [#muc_user{
+				      invites = [#muc_invite{from = From,
+							     reason = Reason}]},
+				   #x_conference{reason = Reason,
+						 jid = RoomJID}]},
+	    ejabberd_router:route(RoomJID, From, Invite),
+	    xmpp_util:make_adhoc_response(
+	      Request, #adhoc_command{status = completed});
        true ->
-	   case jlib:parse_xdata_submit(XData) of
-	     invalid ->
-		 Txt1 = <<"Incorrect data form">>,
-		 {error, ?ERRT_BAD_REQUEST(Lang, Txt1)};
-	     Fields ->
-		 Channel = case lists:keysearch(<<"channel">>, 1, Fields)
-			       of
-			     {value, {<<"channel">>, [C]}} -> C;
-			     _ -> false
-			   end,
-		 Server = case lists:keysearch(<<"server">>, 1, Fields)
-			      of
-			    {value, {<<"server">>, [S]}} -> S;
-			    _ -> false
-			  end,
-		 if Channel /= false, Server /= false ->
-			RoomJID = <>,
-			Invite = #xmlel{name = <<"message">>, attrs = [],
-					children =
-					    [#xmlel{name = <<"x">>,
-						    attrs =
-							[{<<"xmlns">>,
-							  ?NS_MUC_USER}],
-						    children =
-							[#xmlel{name =
-								    <<"invite">>,
-								attrs =
-								    [{<<"from">>,
-								      jid:to_string(From)}],
-								children =
-								    [#xmlel{name
-										=
-										<<"reason">>,
-									    attrs
-										=
-										[],
-									    children
-										=
-										[{xmlcdata,
-										  translate:translate(Lang,
-												      <<"Join the IRC channel here.">>)}]}]}]},
-					     #xmlel{name = <<"x">>,
-						    attrs =
-							[{<<"xmlns">>,
-							  ?NS_XCONFERENCE}],
-						    children =
-							[{xmlcdata,
-							  translate:translate(Lang,
-									      <<"Join the IRC channel here.">>)}]},
-					     #xmlel{name = <<"body">>,
-						    attrs = [],
-						    children =
-							[{xmlcdata,
-							  iolist_to_binary(
-                                                            io_lib:format(
-                                                              translate:translate(
-                                                                Lang,
-                                                                <<"Join the IRC channel in this Jabber ID: ~s">>),
-                                                              [RoomJID]))}]}]},
-			ejabberd_router:route(jid:from_string(RoomJID), From,
-					      Invite),
-			adhoc:produce_response(Request,
-					       #adhoc_response{status =
-								   completed});
-		    true -> {error, ?ERR_BAD_REQUEST}
-		 end
-	   end
+	    Txt = <<"Missing 'channel' or 'server' in the data form">>,
+	    {error, xmpp:err_bad_request(Txt, Lang)}
     end.
 
+-spec adhoc_register(binary(), jid(), jid(), adhoc_command()) ->
+			    adhoc_command() | {error, error()}.
 adhoc_register(_ServerHost, _From, _To,
-	       #adhoc_request{action = <<"cancel">>} = Request) ->
-    adhoc:produce_response(Request,
-			   #adhoc_response{status = canceled});
+	       #adhoc_command{action = cancel} = Request) ->
+    xmpp_util:make_adhoc_response(Request, #adhoc_command{status = canceled});
 adhoc_register(ServerHost, From, To,
-	       #adhoc_request{lang = Lang, node = _Node, xdata = XData,
-			      action = Action} =
-		   Request) ->
+	       #adhoc_command{lang = Lang, xdata = X,
+			      action = Action} = Request) ->
     #jid{user = User} = From,
     #jid{lserver = Host} = To,
-    if XData == false ->
-	   case get_data(ServerHost, Host, From) of
-	     error -> Username = User, ConnectionsParams = [];
-	     empty -> Username = User, ConnectionsParams = [];
-	     Data ->
-		 {Username, ConnectionsParams} =
-                       get_username_and_connection_params(Data)
-	   end,
-	   Error = false;
+    {Username, ConnectionsParams} =
+	if X == undefined ->
+		case get_data(ServerHost, Host, From) of
+		    error -> {User, []};
+		    empty -> {User, []};
+		    Data -> get_username_and_connection_params(Data)
+		end;
+	   true ->
+		{case xmpp_util:get_xdata_values(<<"username">>, X) of
+		     [U] -> U;
+		     _ -> User
+		 end, parse_connections_params(X)}
+	end,
+    if Action == complete ->
+	    case set_data(ServerHost, Host, From,
+			  [{username, Username},
+			   {connections_params, ConnectionsParams}]) of
+		{atomic, _} ->
+		    xmpp_util:make_adhoc_response(
+		      Request, #adhoc_command{status = completed});
+		_ ->
+		    Txt = <<"Database failure">>,
+		    {error, xmpp:err_internal_server_error(Txt, Lang)}
+	    end;
        true ->
-	   case jlib:parse_xdata_submit(XData) of
-	     invalid ->
-		 Txt1 = <<"Incorrect data form">>,
-		 Error = {error, ?ERRT_BAD_REQUEST(Lang, Txt1)},
-		 Username = false,
-		 ConnectionsParams = false;
-	     Fields ->
-		 Username = case lists:keysearch(<<"username">>, 1,
-						 Fields)
-				of
-			      {value, {<<"username">>, U}} -> U;
-			      _ -> User
-			    end,
-		 ConnectionsParams = parse_connections_params(Fields),
-		 Error = false
-	   end
-    end,
-    if Error /= false -> Error;
-       Action == <<"complete">> ->
-	   case set_data(ServerHost, Host, From,
-			 [{username, Username},
-			  {connections_params, ConnectionsParams}])
-	       of
-	     {atomic, _} ->
-		 adhoc:produce_response(Request,
-					#adhoc_response{status = completed});
-	     _ ->
-		 Txt2 = <<"Database failure">>,
-		 {error, ?ERRT_INTERNAL_SERVER_ERROR(Lang, Txt2)}
-	   end;
-       true ->
-	   Form = generate_adhoc_register_form(Lang, Username,
-					       ConnectionsParams),
-	   adhoc:produce_response(Request,
-				  #adhoc_response{status = executing,
-						  elements = [Form],
-						  actions =
-						      [<<"next">>,
-						       <<"complete">>]})
+	    Form = generate_adhoc_register_form(Lang, Username,
+						ConnectionsParams),
+	    xmpp_util:make_adhoc_response(
+	      Request, #adhoc_command{
+			  status = executing,
+			  xdata = Form,
+			  actions = #adhoc_actions{next = true,
+						   complete = true}})
     end.
 
 generate_adhoc_register_form(Lang, Username,
 			     ConnectionsParams) ->
-    #xmlel{name = <<"x">>,
-	   attrs =
-	       [{<<"xmlns">>, ?NS_XDATA}, {<<"type">>, <<"form">>}],
-	   children =
-	       [#xmlel{name = <<"title">>, attrs = [],
-		       children =
-			   [{xmlcdata,
-			     translate:translate(Lang, <<"IRC settings">>)}]},
-		#xmlel{name = <<"instructions">>, attrs = [],
-		       children =
-			   [{xmlcdata,
-			     translate:translate(Lang,
-						 <<"Enter username and encodings you wish "
-						   "to use for connecting to IRC servers. "
-						   " Press 'Next' to get more fields to "
-						   "fill in.  Press 'Complete' to save settings.">>)}]},
-		#xmlel{name = <<"field">>,
-		       attrs =
-			   [{<<"var">>, <<"username">>},
-			    {<<"type">>, <<"text-single">>},
-			    {<<"label">>,
-			     translate:translate(Lang, <<"IRC username">>)}],
-		       children =
-			   [#xmlel{name = <<"required">>, attrs = [],
-				   children = []},
-			    #xmlel{name = <<"value">>, attrs = [],
-				   children = [{xmlcdata, Username}]}]}]
-		 ++
-		 generate_connection_params_fields(Lang,
-						   ConnectionsParams, 1, [])}.
+    #xdata{type = form,
+	   title = translate:translate(Lang, <<"IRC settings">>),
+	   instructions = [translate:translate(
+			     Lang,
+			     <<"Enter username and encodings you wish "
+			       "to use for connecting to IRC servers. "
+			       " Press 'Next' to get more fields to "
+			       "fill in.  Press 'Complete' to save settings.">>)],
+	   fields = [#xdata_field{
+			var = <<"username">>,
+			type = 'text-single',
+			label = translate:translate(Lang, <<"IRC username">>),
+			required = true,
+			values = [Username]}
+		     | generate_connection_params_fields(
+			 Lang, ConnectionsParams, 1, [])]}.
 
 generate_connection_params_fields(Lang, [], Number,
 				  Acc) ->
@@ -1061,91 +793,67 @@ generate_connection_params_field(Lang, Server, Encoding,
 		   end,
     NumberString =
 	iolist_to_binary(integer_to_list(Number)),
-    [#xmlel{name = <<"field">>,
-	    attrs =
-		[{<<"var">>, <<"password", NumberString/binary>>},
-		 {<<"type">>, <<"text-single">>},
-		 {<<"label">>,
-		  iolist_to_binary(
-                    io_lib:format(
-                      translate:translate(Lang, <<"Password ~b">>),
-                      [Number]))}],
-	    children =
-		[#xmlel{name = <<"value">>, attrs = [],
-			children = [{xmlcdata, PasswordUsed}]}]},
-     #xmlel{name = <<"field">>,
-	    attrs =
-		[{<<"var">>, <<"port", NumberString/binary>>},
-		 {<<"type">>, <<"text-single">>},
-		 {<<"label">>,
-		  iolist_to_binary(
-                    io_lib:format(translate:translate(Lang, <<"Port ~b">>),
-                                  [Number]))}],
-	    children =
-		[#xmlel{name = <<"value">>, attrs = [],
-			children = [{xmlcdata, PortUsed}]}]},
-     #xmlel{name = <<"field">>,
-	    attrs =
-		[{<<"var">>, <<"encoding", NumberString/binary>>},
-		 {<<"type">>, <<"list-single">>},
-		 {<<"label">>,
-		  list_to_binary(
-                    io_lib:format(translate:translate(
-                                    Lang,
-                                    <<"Encoding for server ~b">>),
-                                  [Number]))}],
-	    children =
-		[#xmlel{name = <<"value">>, attrs = [],
-			children = [{xmlcdata, EncodingUsed}]}
-		 | lists:map(fun (E) ->
-				     #xmlel{name = <<"option">>,
-					    attrs = [{<<"label">>, E}],
-					    children =
-						[#xmlel{name = <<"value">>,
-							attrs = [],
-							children =
-							    [{xmlcdata, E}]}]}
-			     end,
-			     ?POSSIBLE_ENCODINGS)]},
-     #xmlel{name = <<"field">>,
-	    attrs =
-		[{<<"var">>, <<"server", NumberString/binary>>},
-		 {<<"type">>, <<"text-single">>},
-		 {<<"label">>,
-		  list_to_binary(
-                    io_lib:format(translate:translate(Lang, <<"Server ~b">>),
-                                  [Number]))}],
-	    children =
-		[#xmlel{name = <<"value">>, attrs = [],
-			children = [{xmlcdata, Server}]}]}].
+    [#xdata_field{var = <<"password", NumberString/binary>>,
+		  type = 'text-single',
+		  label =  iolist_to_binary(
+			     io_lib:format(
+			       translate:translate(Lang, <<"Password ~b">>),
+			       [Number])),
+		  values = [PasswordUsed]},
+     #xdata_field{var = <<"port", NumberString/binary>>,
+		  type = 'text-single',
+		  label = iolist_to_binary(
+			    io_lib:format(
+			      translate:translate(Lang, <<"Port ~b">>),
+			      [Number])),
+		  values = [PortUsed]},
+     #xdata_field{var = <<"encoding", NumberString/binary>>,
+		  type = 'list-single',
+		  label = list_to_binary(
+			    io_lib:format(
+			      translate:translate(Lang, <<"Encoding for server ~b">>),
+			      [Number])),
+		  values = [EncodingUsed],
+		  options = [#xdata_option{label = E, value = E}
+			     || E <- ?POSSIBLE_ENCODINGS]},
+     #xdata_field{var = <<"server", NumberString/binary>>,
+		  type = 'text-single',
+		  label = list_to_binary(
+			    io_lib:format(
+			      translate:translate(Lang, <<"Server ~b">>),
+			      [Number])),
+		  values = [Server]}].
 
-parse_connections_params(Fields) ->
+parse_connections_params(#xdata{fields = Fields}) ->
     Servers = lists:flatmap(
-                fun({<<"server", Var/binary>>, Value}) ->
-                        [{Var, Value}];
+                fun(#xdata_field{var = <<"server", Var/binary>>,
+				 values = Values}) ->
+                        [{Var, Values}];
                    (_) ->
                         []
                 end, Fields),
     Encodings = lists:flatmap(
-                  fun({<<"encoding", Var/binary>>, Value}) ->
-                          [{Var, Value}];
+                  fun(#xdata_field{var = <<"encoding", Var/binary>>,
+				   values = Values}) ->
+                          [{Var, Values}];
                      (_) ->
                           []
                   end, Fields),
     Ports = lists:flatmap(
-              fun({<<"port", Var/binary>>, Value}) ->
-                      [{Var, Value}];
+              fun(#xdata_field{var = <<"port", Var/binary>>,
+			       values = Values}) ->
+                      [{Var, Values}];
                  (_) ->
                       []
               end, Fields),
     Passwords = lists:flatmap(
-                  fun({<<"password", Var/binary>>, Value}) ->
-                          [{Var, Value}];
+                  fun(#xdata_field{var = <<"password", Var/binary>>,
+				   values = Values}) ->
+                          [{Var, Values}];
                      (_) ->
                           []
                   end, Fields),
-    parse_connections_params(Servers, Encodings, Ports,
-			     Passwords).
+    parse_connections_params(Servers, Encodings, Ports, Passwords).
 
 retrieve_connections_params(ConnectionParams,
 			    ServerN) ->
@@ -1263,28 +971,19 @@ mod_opt_type(host) -> fun iolist_to_binary/1;
 mod_opt_type(_) ->
     [access, db_type, default_encoding, host].
 
+-spec extract_ident(stanza()) -> binary().
 extract_ident(Packet) ->
-    case fxml:get_subtag(Packet, <<"headers">>) of
-	{xmlel, _Name, _Attrs, Headers} ->
-	    extract_header(<<"X-Irc-Ident">>, Headers);
-	_ ->
-	    "chatmovil"
-    end.
+    Hdrs = extract_headers(Packet),
+    proplists:get_value(<<"X-Irc-Ident">>, Hdrs, <<"chatmovil">>).
 
+-spec extract_ip_address(stanza()) -> binary().
 extract_ip_address(Packet) ->
-    case fxml:get_subtag(Packet, <<"headers">>) of
-	{xmlel, _Name, _Attrs, Headers} ->
-	    extract_header(<<"X-Forwarded-For">>, Headers);
-	_ ->
-	    "127.0.0.1"
-    end.
+    Hdrs = extract_headers(Packet),
+    proplists:get_value(<<"X-Forwarded-For">>, Hdrs, <<"127.0.0.1">>).
 
-extract_header(HeaderName, [{xmlel, _Name, _Attrs, [{xmlcdata, Value}]} | Tail]) ->
-    case fxml:get_attr(<<"name">>, _Attrs) of
-	{value, HeaderName} ->
-	    binary_to_list(Value);
-	_ ->
-	    extract_header(HeaderName, Tail)
-    end;
-extract_header(_HeaderName, _Headers) ->
-	false.
+-spec extract_headers(stanza()) -> [{binary(), binary()}].
+extract_headers(Packet) ->
+    case xmpp:get_subtag(Packet, #shim{}) of
+	#shim{headers = Hs} -> Hs;
+	false -> []
+    end.
diff --git a/src/mod_irc_connection.erl b/src/mod_irc_connection.erl
index 098c8c286..fb301330a 100644
--- a/src/mod_irc_connection.erl
+++ b/src/mod_irc_connection.erl
@@ -41,8 +41,7 @@
 
 -include("ejabberd.hrl").
 -include("logger.hrl").
-
--include("jlib.hrl").
+-include("xmpp.hrl").
 
 -define(SETS, gb_sets).
 
@@ -66,6 +65,8 @@
 	 inbuf = <<"">>        :: binary(),
          outbuf = <<"">>       :: binary()}).
 
+-type state() :: #state{}.
+
 %-define(DBGFSM, true).
 
 -ifdef(DBGFSM).
@@ -228,27 +229,13 @@ code_change(_OldVsn, StateName, StateData, _Extra) ->
                                           (iolist_to_binary(S))/binary>>}
 	end).
 
-get_password_from_presence(#xmlel{name = <<"presence">>,
-				  children = Els}) ->
-    case lists:filter(fun (El) ->
-			      case El of
-				#xmlel{name = <<"x">>, attrs = Attrs} ->
-				    case fxml:get_attr_s(<<"xmlns">>, Attrs) of
-				      ?NS_MUC -> true;
-				      _ -> false
-				    end;
-				_ -> false
-			      end
-		      end,
-		      Els)
-	of
-      [ElXMUC | _] ->
-	  case fxml:get_subtag(ElXMUC, <<"password">>) of
-	    #xmlel{name = <<"password">>} = PasswordTag ->
-		{true, fxml:get_tag_cdata(PasswordTag)};
-	    _ -> false
-	  end;
-      _ -> false
+-spec get_password_from_presence(presence()) -> {true, binary()} | false.
+get_password_from_presence(#presence{} = Pres) ->
+    case xmpp:get_subtag(Pres, #muc{}) of
+	#muc{password = Password} ->
+	    {true, Password};
+	_ ->
+	    false
     end.
 
 %%----------------------------------------------------------------------
@@ -257,284 +244,243 @@ get_password_from_presence(#xmlel{name = <<"presence">>,
 %%          {next_state, NextStateName, NextStateData, Timeout} |
 %%          {stop, Reason, NewStateData}
 %%----------------------------------------------------------------------
-handle_info({route_chan, Channel, Resource,
-	     #xmlel{name = <<"presence">>, attrs = Attrs} =
-		 Presence},
+handle_info({route_chan, _, _, #presence{type = error}}, _, StateData) ->
+    {stop, normal, StateData};
+handle_info({route_chan, Channel, _, #presence{type = unavailable}},
 	    StateName, StateData) ->
-    NewStateData = case fxml:get_attr_s(<<"type">>, Attrs) of
-		     <<"unavailable">> ->
-			 send_stanza_unavailable(Channel, StateData),
-			 S1 = (?SEND((io_lib:format("PART #~s\r\n",
-						    [Channel])))),
-			 S1#state{channels =
-				      dict:erase(Channel, S1#state.channels)};
-		     <<"subscribe">> -> StateData;
-		     <<"subscribed">> -> StateData;
-		     <<"unsubscribe">> -> StateData;
-		     <<"unsubscribed">> -> StateData;
-		     <<"error">> -> stop;
-		     _ ->
-			 Nick = case Resource of
-				  <<"">> -> StateData#state.nick;
-				  _ -> Resource
-				end,
-			 S1 = if Nick /= StateData#state.nick ->
-				     S11 = (?SEND((io_lib:format("NICK ~s\r\n",
-								 [Nick])))),
-				     S11#state{nickchannel = Channel};
-				 true -> StateData
+    send_stanza_unavailable(Channel, StateData),
+    S1 = (?SEND((io_lib:format("PART #~s\r\n", [Channel])))),
+    S2 = S1#state{channels = dict:erase(Channel, S1#state.channels)},
+    {next_state, StateName, S2};
+handle_info({route_chan, Channel, Resource,
+	     #presence{type = available} = Presence},
+	    StateName, StateData) ->
+    Nick = case Resource of
+	       <<"">> -> StateData#state.nick;
+	       _ -> Resource
+	   end,
+    S1 = if Nick /= StateData#state.nick ->
+		 S11 = (?SEND((io_lib:format("NICK ~s\r\n", [Nick])))),
+		 S11#state{nickchannel = Channel};
+	    true -> StateData
+	 end,
+    {next_state, StateName,
+     case dict:is_key(Channel, S1#state.channels) of
+	 true -> S1;
+	 _ ->
+	     case get_password_from_presence(Presence) of
+		 {true, Password} ->
+		     S2 = ?SEND((io_lib:format("JOIN #~s ~s\r\n",
+					       [Channel, Password])));
+		 _ ->
+		     S2 = ?SEND((io_lib:format("JOIN #~s\r\n", [Channel])))
+	     end,
+	     S2#state{channels = dict:store(Channel, ?SETS:new(),
+					    S1#state.channels)}
+     end};
+handle_info({route_chan, Channel, _Resource, #message{type = groupchat} = Msg},
+	    StateName, StateData) ->
+    {next_state, StateName,
+    case xmpp:get_text(Msg#message.subject) of
+	<<"">> ->
+	    ejabberd_router:route(
+	      jid:make(
+		iolist_to_binary([Channel,
+				  <<"%">>,
+				  StateData#state.server]),
+		StateData#state.host,
+		StateData#state.nick),
+	      StateData#state.user, Msg),
+	    Body = xmpp:get_text(Msg#message.body),
+	    case Body of
+		<<"/quote ", Rest/binary>> ->
+		    ?SEND(<>);
+		<<"/msg ", Rest/binary>> ->
+		    ?SEND(<<"PRIVMSG ", Rest/binary, "\r\n">>);
+		<<"/me ", Rest/binary>> ->
+		    Strings = str:tokens(Rest, <<"\n">>),
+		    Res = iolist_to_binary(
+			    lists:map(
+			      fun (S) ->
+				      io_lib:format(
+					"PRIVMSG #~s :\001ACTION ~s\001\r\n",
+					[Channel, S])
 			      end,
-			 case dict:is_key(Channel, S1#state.channels) of
-			   true -> S1;
-			   _ ->
-			       case get_password_from_presence(Presence) of
-				 {true, Password} ->
-				     S2 =
-					 (?SEND((io_lib:format("JOIN #~s ~s\r\n",
-							       [Channel,
-								Password]))));
-				 _ ->
-				     S2 = (?SEND((io_lib:format("JOIN #~s\r\n",
-								[Channel]))))
-			       end,
-			       S2#state{channels =
-					    dict:store(Channel, (?SETS):new(),
-						       S1#state.channels)}
-			 end
-		   end,
-    if NewStateData == stop -> {stop, normal, StateData};
-       true ->
-	   case dict:fetch_keys(NewStateData#state.channels) of
-	     [] -> {stop, normal, NewStateData};
-	     _ -> {next_state, StateName, NewStateData}
-	   end
-    end;
+			      Strings)),
+		    ?SEND(Res);
+		<<"/ctcp ", Rest/binary>> ->
+		    Words = str:tokens(Rest, <<" ">>),
+		    case Words of
+			[CtcpDest | _] ->
+			    CtcpCmd = str:to_upper(
+					str:substr(
+					  Rest, str:str(Rest, <<" ">>) + 1)),
+			    Res = io_lib:format("PRIVMSG ~s :\001~s\001\r\n",
+						[CtcpDest, CtcpCmd]),
+			    ?SEND(Res);
+			_ -> ok
+		    end;
+		_ ->
+		    Strings = str:tokens(Body, <<"\n">>),
+		    Res = iolist_to_binary(
+			    lists:map(
+			      fun (S) ->
+				      io_lib:format("PRIVMSG #~s :~s\r\n",
+						    [Channel, S])
+			      end, Strings)),
+		    ?SEND(Res)
+	    end;
+	Subject ->
+	    Strings = str:tokens(Subject, <<"\n">>),
+	    Res = iolist_to_binary(
+		    lists:map(
+		      fun (S) ->
+			      io_lib:format("TOPIC #~s :~s\r\n",
+					    [Channel, S])
+		      end,
+		      Strings)),
+	    ?SEND(Res)
+    end};
+handle_info({route_chan, _Channel, Resource, #message{type = Type} = Msg},
+	    StateName, StateData) when Type == chat; Type == normal ->
+    Body = xmpp:get_text(Msg#message.body),
+    {next_state, StateName,
+     case Body of
+	 <<"/quote ", Rest/binary>> ->
+	     ?SEND(<>);
+	 <<"/msg ", Rest/binary>> ->
+	     ?SEND(<<"PRIVMSG ", Rest/binary, "\r\n">>);
+	 <<"/me ", Rest/binary>> ->
+	     Strings = str:tokens(Rest, <<"\n">>),
+	     Res = iolist_to_binary(
+		     lists:map(
+		       fun (S) ->
+			       io_lib:format(
+				 "PRIVMSG ~s :\001ACTION ~s\001\r\n",
+				 [Resource, S])
+		       end, Strings)),
+	     ?SEND(Res);
+	 <<"/ctcp ", Rest/binary>> ->
+	     Words = str:tokens(Rest, <<" ">>),
+	     case Words of
+		 [CtcpDest | _] ->
+		     CtcpCmd = str:to_upper(
+				 str:substr(
+				   Rest, str:str(Rest, <<" ">>) + 1)),
+		     Res = io_lib:format("PRIVMSG ~s :~s\r\n",
+					 [CtcpDest,
+					  <<"\001", CtcpCmd/binary, "\001">>]),
+		     ?SEND(Res);
+		 _ -> ok
+	     end;
+	 _ ->
+	     Strings = str:tokens(Body, <<"\n">>),
+	     Res = iolist_to_binary(
+		     lists:map(
+		       fun (S) ->
+			       io_lib:format("PRIVMSG ~s :~s\r\n",
+					     [Resource, S])
+		       end, Strings)),
+	     ?SEND(Res)
+     end};
+handle_info({route_chan, _, _, #message{type = error}}, _, StateData) ->
+    {stop, normal, StateData};
 handle_info({route_chan, Channel, Resource,
-	     #xmlel{name = <<"message">>, attrs = Attrs} = El},
-	    StateName, StateData) ->
-    NewStateData = case fxml:get_attr_s(<<"type">>, Attrs) of
-		     <<"groupchat">> ->
-			 case fxml:get_path_s(El, [{elem, <<"subject">>}, cdata])
-			     of
-			   <<"">> ->
-			       ejabberd_router:route(
-                                 jid:make(
-                                   iolist_to_binary([Channel,
-                                                     <<"%">>,
-                                                     StateData#state.server]),
-                                   StateData#state.host,
-                                   StateData#state.nick),
-                                 StateData#state.user, El),
-			       Body = fxml:get_path_s(El,
-						     [{elem, <<"body">>},
-						      cdata]),
-			       case Body of
-				 <<"/quote ", Rest/binary>> ->
-				     ?SEND(<>);
-				 <<"/msg ", Rest/binary>> ->
-				     ?SEND(<<"PRIVMSG ", Rest/binary, "\r\n">>);
-				 <<"/me ", Rest/binary>> ->
-				     Strings = str:tokens(Rest, <<"\n">>),
-				     Res = iolist_to_binary(
-                                             lists:map(
-                                               fun (S) ->
-                                                       io_lib:format(
-                                                         "PRIVMSG #~s :\001ACTION ~s\001\r\n",
-                                                         [Channel, S])
-                                               end,
-                                               Strings)),
-				     ?SEND(Res);
-				 <<"/ctcp ", Rest/binary>> ->
-				     Words = str:tokens(Rest, <<" ">>),
-				     case Words of
-				       [CtcpDest | _] ->
-					   CtcpCmd = str:to_upper(
-                                                       str:substr(Rest,
-                                                                  str:str(Rest,
-                                                                          <<" ">>)
-                                                                  + 1)),
-					   Res =
-					       io_lib:format("PRIVMSG ~s :\001~s\001\r\n",
-							     [CtcpDest,
-							      CtcpCmd]),
-					   ?SEND(Res);
-				       _ -> ok
-				     end;
-				 _ ->
-				     Strings = str:tokens(Body, <<"\n">>),
-				     Res = iolist_to_binary(
-                                             lists:map(
-                                               fun (S) ->
-                                                       io_lib:format("PRIVMSG #~s :~s\r\n",
-                                                                     [Channel, S])
-                                               end,
-                                               Strings)),
-				     ?SEND(Res)
-			       end;
-			   Subject ->
-			       Strings = str:tokens(Subject, <<"\n">>),
-			       Res = iolist_to_binary(
-                                       lists:map(
-                                         fun (S) ->
-                                                 io_lib:format("TOPIC #~s :~s\r\n",
-                                                               [Channel, S])
-                                         end,
-                                         Strings)),
-			       ?SEND(Res)
-			 end;
-		     Type
-			 when Type == <<"chat">>;
-			      Type == <<"">>;
-			      Type == <<"normal">> ->
-			 Body = fxml:get_path_s(El, [{elem, <<"body">>}, cdata]),
-			 case Body of
-			   <<"/quote ", Rest/binary>> ->
-			       ?SEND(<>);
-			   <<"/msg ", Rest/binary>> ->
-			       ?SEND(<<"PRIVMSG ", Rest/binary, "\r\n">>);
-			   <<"/me ", Rest/binary>> ->
-			       Strings = str:tokens(Rest, <<"\n">>),
-			       Res = iolist_to_binary(
-                                       lists:map(
-                                         fun (S) ->
-                                                 io_lib:format(
-                                                   "PRIVMSG ~s :\001ACTION ~s\001\r\n",
-                                                   [Resource, S])
-                                         end,
-                                         Strings)),
-			       ?SEND(Res);
-			   <<"/ctcp ", Rest/binary>> ->
-			       Words = str:tokens(Rest, <<" ">>),
-			       case Words of
-				 [CtcpDest | _] ->
-				     CtcpCmd = str:to_upper(
-                                                 str:substr(Rest,
-                                                            str:str(Rest,
-                                                                    <<" ">>)
-                                                            + 1)),
-				     Res = io_lib:format("PRIVMSG ~s :~s\r\n",
-							 [CtcpDest,
-							  <<"\001",
-							    CtcpCmd/binary,
-							    "\001">>]),
-				     ?SEND(Res);
-				 _ -> ok
-			       end;
-			   _ ->
-			       Strings = str:tokens(Body, <<"\n">>),
-			       Res = iolist_to_binary(
-                                       lists:map(
-                                         fun (S) ->
-                                                 io_lib:format(
-                                                   "PRIVMSG ~s :~s\r\n",
-                                                   [Resource, S])
-                                         end,
-                                         Strings)),
-			       ?SEND(Res)
-			 end;
-		     <<"error">> -> stop;
-		     _ -> StateData
-		   end,
-    if NewStateData == stop -> {stop, normal, StateData};
-       true -> {next_state, StateName, NewStateData}
-    end;
-handle_info({route_chan, Channel, Resource,
-	     #xmlel{name = <<"iq">>} = El},
-	    StateName, StateData) ->
+	     #iq{type = T, sub_els = [_]} = Packet},
+	    StateName, StateData) when T == set; T == get ->
     From = StateData#state.user,
-    To = jid:make(iolist_to_binary([Channel, <<"%">>,
-                                         StateData#state.server]),
-		       StateData#state.host, StateData#state.nick),
-    _ = case jlib:iq_query_info(El) of
-	  #iq{xmlns = ?NS_MUC_ADMIN} = IQ ->
-	      iq_admin(StateData, Channel, From, To, IQ);
-	  #iq{xmlns = ?NS_VERSION} ->
-	      Res = io_lib:format("PRIVMSG ~s :\001VERSION\001\r\n",
-				  [Resource]),
-	      _ = (?SEND(Res)),
-	      Err = jlib:make_error_reply(El,
-					  ?ERR_FEATURE_NOT_IMPLEMENTED),
-	      ejabberd_router:route(To, From, Err);
-	  #iq{xmlns = ?NS_TIME} ->
-	      Res = io_lib:format("PRIVMSG ~s :\001TIME\001\r\n",
-				  [Resource]),
-	      _ = (?SEND(Res)),
-	      Err = jlib:make_error_reply(El,
-					  ?ERR_FEATURE_NOT_IMPLEMENTED),
-	      ejabberd_router:route(To, From, Err);
-	  #iq{xmlns = ?NS_VCARD} ->
-	      Res = io_lib:format("WHOIS ~s \r\n", [Resource]),
-	      _ = (?SEND(Res)),
-	      Err = jlib:make_error_reply(El,
-					  ?ERR_FEATURE_NOT_IMPLEMENTED),
-	      ejabberd_router:route(To, From, Err);
-	  #iq{} ->
-	      Err = jlib:make_error_reply(El,
-					  ?ERR_FEATURE_NOT_IMPLEMENTED),
-	      ejabberd_router:route(To, From, Err);
-	  _ -> ok
-	end,
+    To = jid:make(iolist_to_binary([Channel, <<"%">>, StateData#state.server]),
+		  StateData#state.host, StateData#state.nick),
+    try xmpp:decode_els(Packet) of
+	#iq{sub_els = [SubEl]} = IQ ->
+	    case xmpp:get_ns(SubEl) of
+		?NS_MUC_ADMIN ->
+		    iq_admin(StateData, Channel, From, To, IQ);
+		?NS_VERSION ->
+		    Res = io_lib:format("PRIVMSG ~s :\001VERSION\001\r\n",
+					[Resource]),
+		    _ = (?SEND(Res)),
+		    Err = xmpp:err_feature_not_implemented(),
+		    ejabberd_router:route_error(To, From, Packet, Err);
+		?NS_TIME ->
+		    Res = io_lib:format("PRIVMSG ~s :\001TIME\001\r\n",
+					[Resource]),
+		    _ = (?SEND(Res)),
+		    Err = xmpp:err_feature_not_implemented(),
+		    ejabberd_router:route_error(To, From, Packet, Err);
+		?NS_VCARD ->
+		    Res = io_lib:format("WHOIS ~s \r\n", [Resource]),
+		    _ = (?SEND(Res)),
+		    Err = xmpp:err_feature_not_implemented(),
+		    ejabberd_router:route_error(To, From, Packet, Err);
+		_ ->
+		    Err = xmpp:err_feature_not_implemented(),
+		    ejabberd_router:route_error(To, From, Packet, Err)
+	    end
+    catch _:{xmpp_codec, Why} ->
+	    Err = xmpp:err_bad_request(
+		    xmpp:format_error(Why), xmpp:get_lang(Packet)),
+	    ejabberd_router:route_error(To, From, Packet, Err)
+    end,
     {next_state, StateName, StateData};
-handle_info({route_chan, _Channel, _Resource, _Packet},
-	    StateName, StateData) ->
+handle_info({route_chan, Channel, _, #iq{} = IQ}, StateName, StateData) ->
+    From = StateData#state.user,
+    To = jid:make(iolist_to_binary([Channel, <<"%">>, StateData#state.server]),
+		  StateData#state.host, StateData#state.nick),
+    Err = xmpp:err_feature_not_implemented(),
+    ejabberd_router:route_error(To, From, IQ, Err),
     {next_state, StateName, StateData};
-handle_info({route_nick, Nick,
-	     #xmlel{name = <<"message">>, attrs = Attrs} = El},
+handle_info({route_nick, Nick, #message{type = chat} = Msg},
 	    StateName, StateData) ->
-    NewStateData = case fxml:get_attr_s(<<"type">>, Attrs) of
-		     <<"chat">> ->
-			 Body = fxml:get_path_s(El, [{elem, <<"body">>}, cdata]),
-			 case Body of
-			   <<"/quote ", Rest/binary>> ->
-			       ?SEND(<>);
-			   <<"/msg ", Rest/binary>> ->
-			       ?SEND(<<"PRIVMSG ", Rest/binary, "\r\n">>);
-			   <<"/me ", Rest/binary>> ->
-			       Strings = str:tokens(Rest, <<"\n">>),
-			       Res = iolist_to_binary(
-                                       lists:map(
-                                         fun (S) ->
-                                                 io_lib:format(
-                                                   "PRIVMSG ~s :\001ACTION ~s\001\r\n",
-                                                   [Nick, S])
-                                         end,
-                                         Strings)),
-			       ?SEND(Res);
-			   <<"/ctcp ", Rest/binary>> ->
-			       Words = str:tokens(Rest, <<" ">>),
-			       case Words of
-				 [CtcpDest | _] ->
-				     CtcpCmd = str:to_upper(
-                                                 str:substr(Rest,
-                                                            str:str(Rest,
-                                                                    <<" ">>)
-                                                            + 1)),
-				     Res = io_lib:format("PRIVMSG ~s :~s\r\n",
-							 [CtcpDest,
-							  <<"\001",
-							    CtcpCmd/binary,
-							    "\001">>]),
-				     ?SEND(Res);
-				 _ -> ok
-			       end;
-			   _ ->
-			       Strings = str:tokens(Body, <<"\n">>),
-			       Res = iolist_to_binary(
-                                       lists:map(
-                                         fun (S) ->
-                                                 io_lib:format(
-                                                   "PRIVMSG ~s :~s\r\n",
-                                                   [Nick, S])
-                                         end,
-                                         Strings)),
-			       ?SEND(Res)
-			 end;
-		     <<"error">> -> stop;
-		     _ -> StateData
-		   end,
-    if NewStateData == stop -> {stop, normal, StateData};
-       true -> {next_state, StateName, NewStateData}
-    end;
+    Body = xmpp:get_text(Msg#message.body),
+    {next_state, StateName,
+     case Body of
+	 <<"/quote ", Rest/binary>> ->
+	     ?SEND(<>);
+	 <<"/msg ", Rest/binary>> ->
+	     ?SEND(<<"PRIVMSG ", Rest/binary, "\r\n">>);
+	 <<"/me ", Rest/binary>> ->
+	     Strings = str:tokens(Rest, <<"\n">>),
+	     Res = iolist_to_binary(
+		     lists:map(
+		       fun (S) ->
+			       io_lib:format(
+				 "PRIVMSG ~s :\001ACTION ~s\001\r\n",
+				 [Nick, S])
+		       end,
+		       Strings)),
+	     ?SEND(Res);
+	 <<"/ctcp ", Rest/binary>> ->
+	     Words = str:tokens(Rest, <<" ">>),
+	     case Words of
+		 [CtcpDest | _] ->
+		     CtcpCmd = str:to_upper(
+				 str:substr(Rest,
+					    str:str(Rest,
+						    <<" ">>)
+					    + 1)),
+		     Res = io_lib:format("PRIVMSG ~s :~s\r\n",
+					 [CtcpDest,
+					  <<"\001",
+					    CtcpCmd/binary,
+					    "\001">>]),
+		     ?SEND(Res);
+		 _ -> ok
+	     end;
+	 _ ->
+	     Strings = str:tokens(Body, <<"\n">>),
+	     Res = iolist_to_binary(
+		     lists:map(
+		       fun (S) ->
+			       io_lib:format(
+				 "PRIVMSG ~s :~s\r\n",
+				 [Nick, S])
+		       end,
+		       Strings)),
+	     ?SEND(Res)
+     end};
+handle_info({route_nick, _, #message{type = error}}, _, StateData) ->
+    {stop, normal, StateData};
 handle_info({route_nick, _Nick, _Packet}, StateName,
 	    StateData) ->
     {next_state, StateName, StateData};
@@ -561,13 +507,13 @@ handle_info({ircstring, <<$:, String/binary>>},
 				     {error,
 				      {error,
 				       error_unknown_num(StateData, String,
-							 <<"cancel">>),
+							 cancel),
 				       StateData}};
 				 [_, <<$5, _, _>> | _] ->
 				     {error,
 				      {error,
 				       error_unknown_num(StateData, String,
-							 <<"cancel">>),
+							 cancel),
 				       StateData}};
 				 _ ->
 				     ?DEBUG("unknown irc command '~s'~n",
@@ -702,11 +648,8 @@ terminate(_Reason, _StateName, FullStateData) ->
     {Error, StateData} = case FullStateData of
 			   {error, SError, SStateData} -> {SError, SStateData};
 			   _ ->
-			       {#xmlel{name = <<"error">>,
-				       attrs = [{<<"code">>, <<"502">>}],
-				       children =
-					   [{xmlcdata,
-					     <<"Server Connect Failed">>}]},
+			       {xmpp:err_internal_server_error(
+				  <<"Server Connect Failed">>, ?MYLANG),
 				FullStateData}
 			 end,
     (StateData#state.mod):closed_connection(StateData#state.host,
@@ -714,9 +657,7 @@ terminate(_Reason, _StateName, FullStateData) ->
                                             StateData#state.server),
     bounce_messages(<<"Server Connect Failed">>),
     lists:foreach(fun (Chan) ->
-			  Stanza = #xmlel{name = <<"presence">>,
-					  attrs = [{<<"type">>, <<"error">>}],
-					  children = [Error]},
+			  Stanza = xmpp:make_error(#presence{}, Error),
 			  send_stanza(Chan, StateData, Stanza)
 		  end,
 		  dict:fetch_keys(StateData#state.channels)),
@@ -726,34 +667,24 @@ terminate(_Reason, _StateName, FullStateData) ->
     end,
     ok.
 
+-spec send_stanza(binary(), state(), stanza()) -> ok.
 send_stanza(Chan, StateData, Stanza) ->
     ejabberd_router:route(
-      jid:make(
-        iolist_to_binary([Chan,
-                          <<"%">>,
-                          StateData#state.server]),
-        StateData#state.host,
-        StateData#state.nick),
+      jid:make(iolist_to_binary([Chan, <<"%">>, StateData#state.server]),
+	       StateData#state.host,
+	       StateData#state.nick),
       StateData#state.user, Stanza).
 
+-spec send_stanza_unavailable(binary(), state()) -> ok.
 send_stanza_unavailable(Chan, StateData) ->
-    Affiliation = <<"member">>,
-    Role = <<"none">>,
-    Stanza = #xmlel{name = <<"presence">>,
-		    attrs = [{<<"type">>, <<"unavailable">>}],
-		    children =
-			[#xmlel{name = <<"x">>,
-				attrs = [{<<"xmlns">>, ?NS_MUC_USER}],
-				children =
-				    [#xmlel{name = <<"item">>,
-					    attrs =
-						[{<<"affiliation">>,
-						  Affiliation},
-						 {<<"role">>, Role}],
-					    children = []},
-				     #xmlel{name = <<"status">>,
-					    attrs = [{<<"code">>, <<"110">>}],
-					    children = []}]}]},
+    Affiliation = member,
+    Role = none,
+    Stanza = #presence{
+		type = unavailable,
+		sub_els = [#muc_user{
+			      items = [#muc_item{affiliation = Affiliation,
+						 role = Role}],
+			      status_codes = [110]}]},
     send_stanza(Chan, StateData, Stanza).
 
 %%%----------------------------------------------------------------------
@@ -776,20 +707,14 @@ send_text(#state{socket = Socket, encoding = Encoding},
 
 bounce_messages(Reason) ->
     receive
-      {send_element, El} ->
-	  #xmlel{attrs = Attrs} = El,
-	  case fxml:get_attr_s(<<"type">>, Attrs) of
-	    <<"error">> -> ok;
-	    _ ->
-		Err = jlib:make_error_reply(El, <<"502">>, Reason),
-		From = jid:from_string(fxml:get_attr_s(<<"from">>,
-							 Attrs)),
-		To = jid:from_string(fxml:get_attr_s(<<"to">>,
-						       Attrs)),
-		ejabberd_router:route(To, From, Err)
-	  end,
-	  bounce_messages(Reason)
-      after 0 -> ok
+	{send_element, El} ->
+	    From = xmpp:get_from(El),
+	    To = xmpp:get_to(El),
+	    Lang = xmpp:get_lang(El),
+	    Err = xmpp:err_internal_server_error(Reason, Lang),
+	    ejabberd_router:route_error(To, From, El, Err),
+	    bounce_messages(Reason)
+    after 0 -> ok
     end.
 
 route_chan(Pid, Channel, Resource, Packet) ->
@@ -842,51 +767,32 @@ process_channel_list_user(StateData, Chan, User) ->
 				       {U2, <<"admin">>, <<"moderator">>};
 				   _ -> {User1, <<"member">>, <<"participant">>}
 				 end,
-    ejabberd_router:route(jid:make(iolist_to_binary([Chan,
-                                                          <<"%">>,
-                                                          StateData#state.server]),
-					StateData#state.host, User2),
-			  StateData#state.user,
-			  #xmlel{name = <<"presence">>, attrs = [],
-				 children =
-				     [#xmlel{name = <<"x">>,
-					     attrs =
-						 [{<<"xmlns">>, ?NS_MUC_USER}],
-					     children =
-						 [#xmlel{name = <<"item">>,
-							 attrs =
-							     [{<<"affiliation">>,
-							       Affiliation},
-							      {<<"role">>,
-							       Role}],
-							 children = []}]}]}),
+    ejabberd_router:route(
+      jid:make(iolist_to_binary([Chan, <<"%">>, StateData#state.server]),
+	       StateData#state.host, User2),
+      StateData#state.user,
+      #presence{
+	 sub_els = [#muc_user{items = [#muc_item{affiliation = Affiliation,
+						 role = Role}]}]}),
     case catch dict:update(Chan,
 			   fun (Ps) -> (?SETS):add_element(User2, Ps) end,
-			   StateData#state.channels)
-	of
-      {'EXIT', _} -> StateData;
-      NS -> StateData#state{channels = NS}
+			   StateData#state.channels) of
+	{'EXIT', _} -> StateData;
+	NS -> StateData#state{channels = NS}
     end.
 
 process_channel_topic(StateData, Chan, String) ->
     Msg = ejabberd_regexp:replace(String, <<".*332[^:]*:">>,
 				  <<"">>),
-    Msg1 = filter_message(Msg),
-    ejabberd_router:route(jid:make(iolist_to_binary([Chan,
-                                                          <<"%">>,
-                                                          StateData#state.server]),
-					StateData#state.host, <<"">>),
-			  StateData#state.user,
-			  #xmlel{name = <<"message">>,
-				 attrs = [{<<"type">>, <<"groupchat">>}],
-				 children =
-				     [#xmlel{name = <<"subject">>, attrs = [],
-					     children = [{xmlcdata, Msg1}]},
-				      #xmlel{name = <<"body">>, attrs = [],
-					     children =
-						 [{xmlcdata,
-						   <<"Topic for #", Chan/binary,
-						     ": ", Msg1/binary>>}]}]}).
+    Subject = filter_message(Msg),
+    Body = <<"Topic for #", Chan/binary, ": ", Subject/binary>>,
+    ejabberd_router:route(
+      jid:make(iolist_to_binary([Chan, <<"%">>, StateData#state.server]),
+	       StateData#state.host),
+      StateData#state.user,
+      #message{type = groupchat,
+	       subject = xmpp:mk_text(Subject),
+	       body = xmpp:mk_text(Body)}).
 
 process_channel_topic_who(StateData, Chan, String) ->
     Words = str:tokens(String, <<" ">>),
@@ -901,30 +807,17 @@ process_channel_topic_who(StateData, Chan, String) ->
 	     _ -> String
 	   end,
     Msg2 = filter_message(Msg1),
-    ejabberd_router:route(jid:make(iolist_to_binary([Chan,
-                                                          <<"%">>,
-                                                          StateData#state.server]),
-					StateData#state.host, <<"">>),
-			  StateData#state.user,
-			  #xmlel{name = <<"message">>,
-				 attrs = [{<<"type">>, <<"groupchat">>}],
-				 children =
-				     [#xmlel{name = <<"body">>, attrs = [],
-					     children = [{xmlcdata, Msg2}]}]}).
+    ejabberd_router:route(
+      jid:make(iolist_to_binary([Chan, <<"%">>, StateData#state.server]),
+	       StateData#state.host, <<"">>),
+      StateData#state.user,
+      #message{type = groupchat, body = xmpp:mk_text(Msg2)}).
 
 error_nick_in_use(_StateData, String) ->
     Msg = ejabberd_regexp:replace(String,
 				  <<".*433 +[^ ]* +">>, <<"">>),
     Msg1 = filter_message(Msg),
-    #xmlel{name = <<"error">>,
-	   attrs =
-	       [{<<"code">>, <<"409">>}, {<<"type">>, <<"cancel">>}],
-	   children =
-	       [#xmlel{name = <<"conflict">>,
-		       attrs = [{<<"xmlns">>, ?NS_STANZAS}], children = []},
-		#xmlel{name = <<"text">>,
-		       attrs = [{<<"xmlns">>, ?NS_STANZAS}],
-		       children = [{xmlcdata, Msg1}]}]}.
+    xmpp:err_conflict(Msg1, ?MYLANG).
 
 process_nick_in_use(StateData, String) ->
     Error = error_nick_in_use(StateData, String),
@@ -933,121 +826,73 @@ process_nick_in_use(StateData, String) ->
 	  % Shouldn't happen with a well behaved server
 	  StateData;
       Chan ->
-	  ejabberd_router:route(jid:make(iolist_to_binary([Chan,
-                                                                <<"%">>,
-                                                                StateData#state.server]),
-					      StateData#state.host,
-					      StateData#state.nick),
-				StateData#state.user,
-				#xmlel{name = <<"presence">>,
-				       attrs = [{<<"type">>, <<"error">>}],
-				       children = [Error]}),
-	  StateData#state{nickchannel = undefined}
+	  ejabberd_router:route(
+	    jid:make(iolist_to_binary([Chan, <<"%">>, StateData#state.server]),
+		     StateData#state.host,
+		     StateData#state.nick),
+	    StateData#state.user,
+	    xmpp:make_error(#presence{}, Error)),
+	    StateData#state{nickchannel = undefined}
     end.
 
 process_num_error(StateData, String) ->
-    Error = error_unknown_num(StateData, String,
-			      <<"continue">>),
-    lists:foreach(fun (Chan) ->
-			  ejabberd_router:route(
-                            jid:make(
-                              iolist_to_binary(
-                                [Chan,
-                                 <<"%">>,
-                                 StateData#state.server]),
-                              StateData#state.host,
-                              StateData#state.nick),
-                            StateData#state.user,
-                            #xmlel{name = <<"message">>,
-                                   attrs =
-                                       [{<<"type">>,
-                                         <<"error">>}],
-                                   children = [Error]})
-		  end,
-		  dict:fetch_keys(StateData#state.channels)),
+    Error = error_unknown_num(StateData, String, continue),
+    lists:foreach(
+      fun(Chan) ->
+	      ejabberd_router:route(
+		jid:make(iolist_to_binary([Chan, $%, StateData#state.server]),
+			 StateData#state.host,
+			 StateData#state.nick),
+		StateData#state.user,
+		xmpp:make_error(#message{}, Error))
+      end, dict:fetch_keys(StateData#state.channels)),
     StateData.
 
 process_endofwhois(StateData, _String, Nick) ->
-    ejabberd_router:route(jid:make(iolist_to_binary([Nick,
-                                                          <<"!">>,
-                                                          StateData#state.server]),
-					StateData#state.host, <<"">>),
-			  StateData#state.user,
-			  #xmlel{name = <<"message">>,
-				 attrs = [{<<"type">>, <<"chat">>}],
-				 children =
-				     [#xmlel{name = <<"body">>, attrs = [],
-					     children =
-						 [{xmlcdata,
-						   <<"End of WHOIS">>}]}]}).
+    ejabberd_router:route(
+      jid:make(iolist_to_binary([Nick, <<"!">>, StateData#state.server]),
+	       StateData#state.host),
+      StateData#state.user,
+      #message{type = chat, body = xmpp:mk_text(<<"End of WHOIS">>)}).
 
 process_whois311(StateData, String, Nick, Ident,
 		 Irchost) ->
     Fullname = ejabberd_regexp:replace(String,
 				       <<".*311[^:]*:">>, <<"">>),
-    ejabberd_router:route(jid:make(iolist_to_binary([Nick,
-                                                          <<"!">>,
-                                                          StateData#state.server]),
-					StateData#state.host, <<"">>),
-			  StateData#state.user,
-			  #xmlel{name = <<"message">>,
-				 attrs = [{<<"type">>, <<"chat">>}],
-				 children =
-				     [#xmlel{name = <<"body">>, attrs = [],
-					     children =
-						 [{xmlcdata,
-						   iolist_to_binary(
-                                                     [<<"WHOIS: ">>,
-                                                      Nick,
-                                                      <<" is ">>,
-                                                      Ident,
-                                                      <<"@">>,
-                                                      Irchost,
-                                                      <<" : ">>,
-                                                      Fullname])}]}]}).
+    ejabberd_router:route(
+      jid:make(iolist_to_binary([Nick, <<"!">>, StateData#state.server]),
+	       StateData#state.host, <<"">>),
+      StateData#state.user,
+      #message{type = chat,
+	       body = xmpp:mk_text(
+			iolist_to_binary(
+			  [<<"WHOIS: ">>, Nick, <<" is ">>, Ident,
+			   <<"@">>, Irchost, <<" : ">>, Fullname]))}).
 
 process_whois312(StateData, String, Nick, Ircserver) ->
     Ircserverdesc = ejabberd_regexp:replace(String,
 					    <<".*312[^:]*:">>, <<"">>),
-    ejabberd_router:route(jid:make(iolist_to_binary([Nick,
-                                                          <<"!">>,
-                                                          StateData#state.server]),
-					StateData#state.host, <<"">>),
-			  StateData#state.user,
-			  #xmlel{name = <<"message">>,
-				 attrs = [{<<"type">>, <<"chat">>}],
-				 children =
-				     [#xmlel{name = <<"body">>, attrs = [],
-					     children =
-						 [{xmlcdata,
-						   iolist_to_binary(
-                                                     [<<"WHOIS: ">>,
-                                                      Nick,
-                                                      <<" use ">>,
-                                                      Ircserver,
-                                                      <<" : ">>,
-                                                      Ircserverdesc])}]}]}).
+    ejabberd_router:route(
+      jid:make(iolist_to_binary([Nick, <<"!">>, StateData#state.server]),
+	       StateData#state.host, <<"">>),
+      StateData#state.user,
+      #message{type = chat,
+	       body = xmpp:mk_text(
+			iolist_to_binary(
+			  [<<"WHOIS: ">>, Nick, <<" use ">>, Ircserver,
+			   <<" : ">>, Ircserverdesc]))}).
 
 process_whois319(StateData, String, Nick) ->
     Chanlist = ejabberd_regexp:replace(String,
 				       <<".*319[^:]*:">>, <<"">>),
-    ejabberd_router:route(jid:make(iolist_to_binary(
-                                          [Nick,
-                                           <<"!">>,
-                                           StateData#state.server]),
-					StateData#state.host, <<"">>),
-			  StateData#state.user,
-			  #xmlel{name = <<"message">>,
-				 attrs = [{<<"type">>, <<"chat">>}],
-				 children =
-				     [#xmlel{name = <<"body">>, attrs = [],
-					     children =
-						 [{xmlcdata,
-						   iolist_to_binary(
-                                                     [<<"WHOIS: ">>,
-                                                      Nick,
-                                                      <<" is on ">>,
-                                                      Chanlist])}]}]}).
+    ejabberd_router:route(
+      jid:make(iolist_to_binary([Nick, <<"!">>, StateData#state.server]),
+	       StateData#state.host, <<"">>),
+      StateData#state.user,
+      #message{type = chat,
+	       body = xmpp:mk_text(
+			iolist_to_binary(
+			  [<<"WHOIS: ">>, Nick, <<" is on ">>, Chanlist]))}).
 
 process_chanprivmsg(StateData, Chan, From, String) ->
     [FromUser | _] = str:tokens(From, <<"!">>),
@@ -1059,17 +904,11 @@ process_chanprivmsg(StateData, Chan, From, String) ->
 	     _ -> Msg
 	   end,
     Msg2 = filter_message(Msg1),
-    ejabberd_router:route(jid:make(iolist_to_binary(
-                                          [Chan,
-                                           <<"%">>,
-                                           StateData#state.server]),
-					StateData#state.host, FromUser),
-			  StateData#state.user,
-			  #xmlel{name = <<"message">>,
-				 attrs = [{<<"type">>, <<"groupchat">>}],
-				 children =
-				     [#xmlel{name = <<"body">>, attrs = [],
-					     children = [{xmlcdata, Msg2}]}]}).
+    ejabberd_router:route(
+      jid:make(iolist_to_binary([Chan, <<"%">>, StateData#state.server]),
+	       StateData#state.host, FromUser),
+      StateData#state.user,
+      #message{type = groupchat, body = xmpp:mk_text(Msg2)}).
 
 process_channotice(StateData, Chan, From, String) ->
     [FromUser | _] = str:tokens(From, <<"!">>),
@@ -1081,17 +920,11 @@ process_channotice(StateData, Chan, From, String) ->
 	     _ -> <<"/me NOTICE: ", Msg/binary>>
 	   end,
     Msg2 = filter_message(Msg1),
-    ejabberd_router:route(jid:make(iolist_to_binary(
-                                          [Chan,
-                                           <<"%">>,
-                                           StateData#state.server]),
-					StateData#state.host, FromUser),
-			  StateData#state.user,
-			  #xmlel{name = <<"message">>,
-				 attrs = [{<<"type">>, <<"groupchat">>}],
-				 children =
-				     [#xmlel{name = <<"body">>, attrs = [],
-					     children = [{xmlcdata, Msg2}]}]}).
+    ejabberd_router:route(
+      jid:make(iolist_to_binary([Chan, <<"%">>, StateData#state.server]),
+	       StateData#state.host, FromUser),
+      StateData#state.user,
+      #message{type = groupchat, body = xmpp:mk_text(Msg2)}).
 
 process_privmsg(StateData, _Nick, From, String) ->
     [FromUser | _] = str:tokens(From, <<"!">>),
@@ -1103,17 +936,11 @@ process_privmsg(StateData, _Nick, From, String) ->
 	     _ -> Msg
 	   end,
     Msg2 = filter_message(Msg1),
-    ejabberd_router:route(jid:make(iolist_to_binary(
-                                          [FromUser,
-                                           <<"!">>,
-                                           StateData#state.server]),
-					StateData#state.host, <<"">>),
-			  StateData#state.user,
-			  #xmlel{name = <<"message">>,
-				 attrs = [{<<"type">>, <<"chat">>}],
-				 children =
-				     [#xmlel{name = <<"body">>, attrs = [],
-					     children = [{xmlcdata, Msg2}]}]}).
+    ejabberd_router:route(
+      jid:make(iolist_to_binary([FromUser, <<"!">>, StateData#state.server]),
+	       StateData#state.host, <<"">>),
+      StateData#state.user,
+      #message{type = chat, body = xmpp:mk_text(Msg2)}).
 
 process_notice(StateData, _Nick, From, String) ->
     [FromUser | _] = str:tokens(From, <<"!">>),
@@ -1125,17 +952,11 @@ process_notice(StateData, _Nick, From, String) ->
 	     _ -> <<"/me NOTICE: ", Msg/binary>>
 	   end,
     Msg2 = filter_message(Msg1),
-    ejabberd_router:route(jid:make(iolist_to_binary(
-                                          [FromUser,
-                                           <<"!">>,
-                                           StateData#state.server]),
-					StateData#state.host, <<"">>),
-			  StateData#state.user,
-			  #xmlel{name = <<"message">>,
-				 attrs = [{<<"type">>, <<"chat">>}],
-				 children =
-				     [#xmlel{name = <<"body">>, attrs = [],
-					     children = [{xmlcdata, Msg2}]}]}).
+    ejabberd_router:route(
+      jid:make(iolist_to_binary([FromUser, <<"!">>, StateData#state.server]),
+	       StateData#state.host),
+      StateData#state.user,
+      #message{type = chat, body = xmpp:mk_text(Msg2)}).
 
 process_version(StateData, _Nick, From) ->
     [FromUser | _] = str:tokens(From, <<"!">>),
@@ -1160,54 +981,30 @@ process_topic(StateData, Chan, From, String) ->
     Msg = ejabberd_regexp:replace(String,
 				  <<".*TOPIC[^:]*:">>, <<"">>),
     Msg1 = filter_message(Msg),
-    ejabberd_router:route(jid:make(iolist_to_binary(
-                                          [Chan,
-                                           <<"%">>,
-                                           StateData#state.server]),
-					StateData#state.host, FromUser),
-			  StateData#state.user,
-			  #xmlel{name = <<"message">>,
-				 attrs = [{<<"type">>, <<"groupchat">>}],
-				 children =
-				     [#xmlel{name = <<"subject">>, attrs = [],
-					     children = [{xmlcdata, Msg1}]},
-				      #xmlel{name = <<"body">>, attrs = [],
-					     children =
-						 [{xmlcdata,
-						   <<"/me has changed the subject to: ",
-						     Msg1/binary>>}]}]}).
+    ejabberd_router:route(
+      jid:make(iolist_to_binary([Chan, <<"%">>, StateData#state.server]),
+	       StateData#state.host, FromUser),
+      StateData#state.user,
+      #message{type = groupchat,
+	       subject = xmpp:mk_text(Msg1),
+	       body = xmpp:mk_text(<<"/me has changed the subject to: ",
+				     Msg1/binary>>)}).
 
 process_part(StateData, Chan, From, String) ->
     [FromUser | FromIdent] = str:tokens(From, <<"!">>),
     Msg = ejabberd_regexp:replace(String,
 				  <<".*PART[^:]*:">>, <<"">>),
     Msg1 = filter_message(Msg),
-    ejabberd_router:route(jid:make(iolist_to_binary(
-                                          [Chan,
-                                           <<"%">>,
-                                           StateData#state.server]),
-					StateData#state.host, FromUser),
-			  StateData#state.user,
-			  #xmlel{name = <<"presence">>,
-				 attrs = [{<<"type">>, <<"unavailable">>}],
-				 children =
-				     [#xmlel{name = <<"x">>,
-					     attrs =
-						 [{<<"xmlns">>, ?NS_MUC_USER}],
-					     children =
-						 [#xmlel{name = <<"item">>,
-							 attrs =
-							     [{<<"affiliation">>,
-							       <<"member">>},
-							      {<<"role">>,
-							       <<"none">>}],
-							 children = []}]},
-				      #xmlel{name = <<"status">>, attrs = [],
-					     children =
-						 [{xmlcdata,
-                                                   list_to_binary(
-                                                     [Msg1, " (",
-                                                      FromIdent, ")"])}]}]}),
+    ejabberd_router:route(
+      jid:make(iolist_to_binary([Chan, <<"%">>, StateData#state.server]),
+	       StateData#state.host, FromUser),
+      StateData#state.user,
+      #presence{type = unavailable,
+		sub_els = [#muc_user{
+			      items = [#muc_item{affiliation = member,
+						 role = none}]}],
+		status = xmpp:mk_text(
+			   list_to_binary([Msg1, " (", FromIdent, ")"]))}),
     case catch dict:update(Chan,
 			   fun (Ps) -> remove_element(FromUser, Ps) end,
 			   StateData#state.channels)
@@ -1221,81 +1018,40 @@ process_quit(StateData, From, String) ->
     Msg = ejabberd_regexp:replace(String,
 				  <<".*QUIT[^:]*:">>, <<"">>),
     Msg1 = filter_message(Msg),
-    dict:map(fun (Chan, Ps) ->
-		     case (?SETS):is_member(FromUser, Ps) of
-		       true ->
-			   ejabberd_router:route(jid:make(iolist_to_binary(
-                                                                 [Chan,
-                                                                  <<"%">>,
-                                                                  StateData#state.server]),
-							       StateData#state.host,
-							       FromUser),
-						 StateData#state.user,
-						 #xmlel{name = <<"presence">>,
-							attrs =
-							    [{<<"type">>,
-							      <<"unavailable">>}],
-							children =
-							    [#xmlel{name =
-									<<"x">>,
-								    attrs =
-									[{<<"xmlns">>,
-									  ?NS_MUC_USER}],
-								    children =
-									[#xmlel{name
-										    =
-										    <<"item">>,
-										attrs
-										    =
-										    [{<<"affiliation">>,
-										      <<"member">>},
-										     {<<"role">>,
-										      <<"none">>}],
-										children
-										    =
-										    []}]},
-							     #xmlel{name =
-									<<"status">>,
-								    attrs = [],
-								    children =
-									[{xmlcdata,
-                                                                          list_to_binary(
-                                                                            [Msg1, " (",
-                                                                             FromIdent,
-                                                                             ")"])}]}]}),
-			   remove_element(FromUser, Ps);
-		       _ -> Ps
-		     end
-	     end,
-	     StateData#state.channels),
+    dict:map(
+      fun(Chan, Ps) ->
+	      case (?SETS):is_member(FromUser, Ps) of
+		  true ->
+		      ejabberd_router:route(
+			jid:make(iolist_to_binary([Chan, $%, StateData#state.server]),
+				 StateData#state.host,
+				 FromUser),
+			StateData#state.user,
+			#presence{type = unavailable,
+				  sub_els = [#muc_user{
+						items = [#muc_item{
+							    affiliation = member,
+							    role = none}]}],
+				  status = xmpp:mk_text(
+					     list_to_binary([Msg1, " (", FromIdent, ")"]))}),
+		      remove_element(FromUser, Ps);
+		  _ ->
+		      Ps
+	      end
+      end, StateData#state.channels),
     StateData.
 
 process_join(StateData, Channel, From, _String) ->
     [FromUser | FromIdent] = str:tokens(From, <<"!">>),
     [Chan | _] = binary:split(Channel, <<":#">>),
-    ejabberd_router:route(jid:make(iolist_to_binary(
-                                          [Chan,
-                                           <<"%">>,
-                                           StateData#state.server]),
-					StateData#state.host, FromUser),
-			  StateData#state.user,
-			  #xmlel{name = <<"presence">>, attrs = [],
-				 children =
-				     [#xmlel{name = <<"x">>,
-					     attrs =
-						 [{<<"xmlns">>, ?NS_MUC_USER}],
-					     children =
-						 [#xmlel{name = <<"item">>,
-							 attrs =
-							     [{<<"affiliation">>,
-							       <<"member">>},
-							      {<<"role">>,
-							       <<"participant">>}],
-							 children = []}]},
-				      #xmlel{name = <<"status">>, attrs = [],
-					     children =
-						 [{xmlcdata,
-                                                   list_to_binary(FromIdent)}]}]}),
+    ejabberd_router:route(
+      jid:make(iolist_to_binary([Chan, <<"%">>, StateData#state.server]),
+	       StateData#state.host, FromUser),
+      StateData#state.user,
+      #presence{
+	 sub_els = [#muc_user{items = [#muc_item{affiliation = member,
+						 role = participant}]}],
+	 status = xmpp:mk_text(list_to_binary(FromIdent))}),
     case catch dict:update(Chan,
 			   fun (Ps) -> (?SETS):add_element(FromUser, Ps) end,
 			   StateData#state.channels)
@@ -1306,160 +1062,67 @@ process_join(StateData, Channel, From, _String) ->
 
 process_mode_o(StateData, Chan, _From, Nick,
 	       Affiliation, Role) ->
-    ejabberd_router:route(jid:make(iolist_to_binary(
-                                          [Chan,
-                                           <<"%">>,
-                                           StateData#state.server]),
-					StateData#state.host, Nick),
-			  StateData#state.user,
-			  #xmlel{name = <<"presence">>, attrs = [],
-				 children =
-				     [#xmlel{name = <<"x">>,
-					     attrs =
-						 [{<<"xmlns">>, ?NS_MUC_USER}],
-					     children =
-						 [#xmlel{name = <<"item">>,
-							 attrs =
-							     [{<<"affiliation">>,
-							       Affiliation},
-							      {<<"role">>,
-							       Role}],
-							 children = []}]}]}).
+    ejabberd_router:route(
+      jid:make(iolist_to_binary([Chan, <<"%">>, StateData#state.server]),
+	       StateData#state.host, Nick),
+      StateData#state.user,
+      #presence{
+	 sub_els = [#muc_user{items = [#muc_item{affiliation = Affiliation,
+						 role = Role}]}]}).
 
 process_kick(StateData, Chan, From, Nick, String) ->
     Msg = lists:last(str:tokens(String, <<":">>)),
     Msg2 = <>,
-    ejabberd_router:route(jid:make(iolist_to_binary(
-                                          [Chan,
-                                           <<"%">>,
-                                           StateData#state.server]),
-					StateData#state.host, <<"">>),
-			  StateData#state.user,
-			  #xmlel{name = <<"message">>,
-				 attrs = [{<<"type">>, <<"groupchat">>}],
-				 children =
-				     [#xmlel{name = <<"body">>, attrs = [],
-					     children = [{xmlcdata, Msg2}]}]}),
-    ejabberd_router:route(jid:make(iolist_to_binary(
-                                          [Chan,
-                                           <<"%">>,
-                                           StateData#state.server]),
-					StateData#state.host, Nick),
-			  StateData#state.user,
-			  #xmlel{name = <<"presence">>,
-				 attrs = [{<<"type">>, <<"unavailable">>}],
-				 children =
-				     [#xmlel{name = <<"x">>,
-					     attrs =
-						 [{<<"xmlns">>, ?NS_MUC_USER}],
-					     children =
-						 [#xmlel{name = <<"item">>,
-							 attrs =
-							     [{<<"affiliation">>,
-							       <<"none">>},
-							      {<<"role">>,
-							       <<"none">>}],
-							 children = []},
-						  #xmlel{name = <<"status">>,
-							 attrs =
-							     [{<<"code">>,
-							       <<"307">>}],
-							 children = []}]}]}).
+    ejabberd_router:route(
+      jid:make(iolist_to_binary([Chan, <<"%">>, StateData#state.server]),
+	       StateData#state.host),
+      StateData#state.user,
+      #message{type = groupchat, body = xmpp:mk_text(Msg2)}),
+    ejabberd_router:route(
+      jid:make(iolist_to_binary([Chan, <<"%">>, StateData#state.server]),
+	       StateData#state.host, Nick),
+      StateData#state.user,
+      #presence{type = unavailable,
+		sub_els = [#muc_user{items = [#muc_item{
+						 affiliation = none,
+						 role = none}],
+				     status_codes = [307]}]}).
 
 process_nick(StateData, From, NewNick) ->
     [FromUser | _] = str:tokens(From, <<"!">>),
     [Nick | _] = binary:split(NewNick, <<":">>),
-    NewChans = dict:map(fun (Chan, Ps) ->
-				case (?SETS):is_member(FromUser, Ps) of
-				  true ->
-				      ejabberd_router:route(jid:make(
-                                                              iolist_to_binary(
-                                                                [Chan,
-                                                                 <<"%">>,
-                                                                 StateData#state.server]),
-                                                              StateData#state.host,
-                                                              FromUser),
-							    StateData#state.user,
-							    #xmlel{name =
-								       <<"presence">>,
-								   attrs =
-								       [{<<"type">>,
-									 <<"unavailable">>}],
-								   children =
-								       [#xmlel{name
-										   =
-										   <<"x">>,
-									       attrs
-										   =
-										   [{<<"xmlns">>,
-										     ?NS_MUC_USER}],
-									       children
-										   =
-										   [#xmlel{name
-											       =
-											       <<"item">>,
-											   attrs
-											       =
-											       [{<<"affiliation">>,
-												 <<"member">>},
-												{<<"role">>,
-												 <<"participant">>},
-												{<<"nick">>,
-												 Nick}],
-											   children
-											       =
-											       []},
-										    #xmlel{name
-											       =
-											       <<"status">>,
-											   attrs
-											       =
-											       [{<<"code">>,
-												 <<"303">>}],
-											   children
-											       =
-											       []}]}]}),
-				      ejabberd_router:route(jid:make(
-                                                              iolist_to_binary(
-                                                                [Chan,
-                                                                 <<"%">>,
-                                                                 StateData#state.server]),
-                                                              StateData#state.host,
-                                                              Nick),
-							    StateData#state.user,
-							    #xmlel{name =
-								       <<"presence">>,
-								   attrs = [],
-								   children =
-								       [#xmlel{name
-										   =
-										   <<"x">>,
-									       attrs
-										   =
-										   [{<<"xmlns">>,
-										     ?NS_MUC_USER}],
-									       children
-										   =
-										   [#xmlel{name
-											       =
-											       <<"item">>,
-											   attrs
-											       =
-											       [{<<"affiliation">>,
-												 <<"member">>},
-												{<<"role">>,
-												 <<"participant">>}],
-											   children
-											       =
-											       []}]}]}),
-				      (?SETS):add_element(Nick,
-							  remove_element(FromUser,
-									 Ps));
-				  _ -> Ps
-				end
-			end,
-			StateData#state.channels),
+    NewChans =
+	dict:map(
+	  fun(Chan, Ps) ->
+		  case (?SETS):is_member(FromUser, Ps) of
+		      true ->
+			  ejabberd_router:route(
+			    jid:make(iolist_to_binary([Chan, $%, StateData#state.server]),
+				     StateData#state.host,
+				     FromUser),
+			    StateData#state.user,
+			    #presence{
+			       type = unavailable,
+			       sub_els = [#muc_user{
+					     items = [#muc_item{
+							 affiliation = member,
+							 role = participant,
+							 nick = Nick}],
+					     status_codes = [303]}]}),
+			  ejabberd_router:route(
+			    jid:make(iolist_to_binary([Chan, $%, StateData#state.server]),
+				     StateData#state.host, Nick),
+			    StateData#state.user,
+			    #presence{
+			       sub_els = [#muc_user{
+					     items = [#muc_item{
+							 affiliation = member,
+							 role = participant}]}]}),
+			  (?SETS):add_element(Nick, remove_element(FromUser, Ps));
+		      _ -> Ps
+		  end
+	  end, StateData#state.channels),
     if FromUser == StateData#state.nick ->
 	   StateData#state{nick = Nick, nickchannel = undefined,
 			   channels = NewChans};
@@ -1467,43 +1130,23 @@ process_nick(StateData, From, NewNick) ->
     end.
 
 process_error(StateData, String) ->
-    lists:foreach(fun (Chan) ->
-			  ejabberd_router:route(jid:make(
-                                                  iolist_to_binary(
-                                                    [Chan,
-                                                     <<"%">>,
-                                                     StateData#state.server]),
-                                                  StateData#state.host,
-                                                  StateData#state.nick),
-						StateData#state.user,
-						#xmlel{name = <<"presence">>,
-						       attrs =
-							   [{<<"type">>,
-							     <<"error">>}],
-						       children =
-							   [#xmlel{name =
-								       <<"error">>,
-								   attrs =
-								       [{<<"code">>,
-									 <<"502">>}],
-								   children =
-								       [{xmlcdata,
-									 String}]}]})
-		  end,
-		  dict:fetch_keys(StateData#state.channels)).
+    lists:foreach(
+      fun(Chan) ->
+	      ejabberd_router:route(
+		jid:make(iolist_to_binary([Chan, $%, StateData#state.server]),
+			 StateData#state.host,
+			 StateData#state.nick),
+		StateData#state.user,
+		xmpp:make_error(
+		  #presence{},
+		  xmpp:err_internal_server_error(String, ?MYLANG)))
+      end, dict:fetch_keys(StateData#state.channels)).
 
 error_unknown_num(_StateData, String, Type) ->
     Msg = ejabberd_regexp:replace(String,
 				  <<".*[45][0-9][0-9] +[^ ]* +">>, <<"">>),
     Msg1 = filter_message(Msg),
-    #xmlel{name = <<"error">>,
-	   attrs = [{<<"code">>, <<"500">>}, {<<"type">>, Type}],
-	   children =
-	       [#xmlel{name = <<"undefined-condition">>,
-		       attrs = [{<<"xmlns">>, ?NS_STANZAS}], children = []},
-		#xmlel{name = <<"text">>,
-		       attrs = [{<<"xmlns">>, ?NS_STANZAS}],
-		       children = [{xmlcdata, Msg1}]}]}.
+    xmpp:err_undefined_condition(Type, Msg1, ?MYLANG).
 
 remove_element(E, Set) ->
     case (?SETS):is_element(E, Set) of
@@ -1512,49 +1155,33 @@ remove_element(E, Set) ->
     end.
 
 iq_admin(StateData, Channel, From, To,
-	 #iq{type = Type, xmlns = XMLNS, sub_el = SubEl} = IQ) ->
-    case catch process_iq_admin(StateData, Channel, Type,
-				SubEl)
-	of
-      {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]);
-      Res ->
-	  if Res /= ignore ->
-		 ResIQ = case Res of
-			   {result, ResEls} ->
-			       IQ#iq{type = result,
-				     sub_el =
-					 [#xmlel{name = <<"query">>,
-						 attrs = [{<<"xmlns">>, XMLNS}],
-						 children = ResEls}]};
-			   {error, Error} ->
-			       IQ#iq{type = error, sub_el = [SubEl, Error]}
-			 end,
-		 ejabberd_router:route(To, From, jlib:iq_to_xml(ResIQ));
-	     true -> ok
-	  end
+	 #iq{type = Type, sub_els = [SubEl]} = IQ) ->
+    try process_iq_admin(StateData, Channel, Type, SubEl) of
+	ignore ->
+	    ignore;
+	{result, Result} ->
+	    ejabberd_router:route(To, From, xmpp:make_iq_result(IQ, Result));
+	{error, Error} ->
+	    ejabberd_router:route_error(To, From, IQ, Error)
+    catch E:R ->
+	    ?ERROR_MSG("failed to process admin query from ~s: ~p",
+		       [jid:to_string(From), {E, {R, erlang:get_stacktrace()}}]),
+	    ejabberd_router:route_error(
+	      To, From, IQ, xmpp:internal_server_error())
     end.
 
-process_iq_admin(StateData, Channel, set, SubEl) ->
-    case fxml:get_subtag(SubEl, <<"item">>) of
-      false -> {error, ?ERR_BAD_REQUEST};
-      ItemEl ->
-	  Nick = fxml:get_tag_attr_s(<<"nick">>, ItemEl),
-	  Affiliation = fxml:get_tag_attr_s(<<"affiliation">>,
-					   ItemEl),
-	  Role = fxml:get_tag_attr_s(<<"role">>, ItemEl),
-	  Reason = fxml:get_path_s(ItemEl,
-				  [{elem, <<"reason">>}, cdata]),
-	  process_admin(StateData, Channel, Nick, Affiliation,
-			Role, Reason)
-    end;
-process_iq_admin(_StateData, _Channel, get, _SubEl) ->
-    {error, ?ERR_FEATURE_NOT_IMPLEMENTED}.
+process_iq_admin(_StateData, _Channel, set, #muc_admin{items = []}) ->
+    {error, xmpp:err_bad_request()};
+process_iq_admin(StateData, Channel, set, #muc_admin{items = [Item|_]}) ->
+    process_admin(StateData, Channel, Item);
+process_iq_admin(_StateData, _Channel, _, _SubEl) ->
+    {error, xmpp:err_feature_not_implemented()}.
 
-process_admin(_StateData, _Channel, <<"">>,
-	      _Affiliation, _Role, _Reason) ->
-    {error, ?ERR_FEATURE_NOT_IMPLEMENTED};
-process_admin(StateData, Channel, Nick, _Affiliation,
-	      <<"none">>, Reason) ->
+process_admin(_StateData, _Channel, #muc_item{nick = <<"">>}) ->
+    {error, xmpp:err_feature_not_implemented()};
+process_admin(StateData, Channel, #muc_item{nick = Nick,
+					    reason = Reason,
+					    role = none}) ->
     case Reason of
       <<"">> ->
 	  send_text(StateData,
@@ -1564,10 +1191,9 @@ process_admin(StateData, Channel, Nick, _Affiliation,
 		    io_lib:format("KICK #~s ~s :~s\r\n",
 				  [Channel, Nick, Reason]))
     end,
-    {result, []};
-process_admin(_StateData, _Channel, _Nick, _Affiliation,
-	      _Role, _Reason) ->
-    {error, ?ERR_FEATURE_NOT_IMPLEMENTED}.
+    {result, undefined};
+process_admin(_StateData, _Channel, _Item) ->
+    {error, xmpp:err_feature_not_implemented()}.
 
 filter_message(Msg) ->
     list_to_binary(
diff --git a/src/mod_irc_mnesia.erl b/src/mod_irc_mnesia.erl
index 9f8117ad3..95cceb54c 100644
--- a/src/mod_irc_mnesia.erl
+++ b/src/mod_irc_mnesia.erl
@@ -13,7 +13,7 @@
 %% API
 -export([init/2, get_data/3, set_data/4, import/2]).
 
--include("jlib.hrl").
+-include("jid.hrl").
 -include("mod_irc.hrl").
 -include("logger.hrl").
 
diff --git a/src/mod_irc_riak.erl b/src/mod_irc_riak.erl
index 6ac7befdf..a71859c5c 100644
--- a/src/mod_irc_riak.erl
+++ b/src/mod_irc_riak.erl
@@ -13,7 +13,7 @@
 %% API
 -export([init/2, get_data/3, set_data/4, import/2]).
 
--include("jlib.hrl").
+-include("jid.hrl").
 -include("mod_irc.hrl").
 
 %%%===================================================================
diff --git a/src/mod_irc_sql.erl b/src/mod_irc_sql.erl
index 8aa428e54..7905db91f 100644
--- a/src/mod_irc_sql.erl
+++ b/src/mod_irc_sql.erl
@@ -15,7 +15,7 @@
 %% API
 -export([init/2, get_data/3, set_data/4, import/1, import/2, export/1]).
 
--include("jlib.hrl").
+-include("jid.hrl").
 -include("mod_irc.hrl").
 -include("ejabberd_sql_pt.hrl").
 
diff --git a/src/xmpp.erl b/src/xmpp.erl
index a927a6a9a..b43243157 100644
--- a/src/xmpp.erl
+++ b/src/xmpp.erl
@@ -41,7 +41,7 @@
          err_resource_constraint/0, err_resource_constraint/2,
          err_service_unavailable/0, err_service_unavailable/2,
          err_subscription_required/0, err_subscription_required/2,
-         err_undefined_condition/0, err_undefined_condition/2,
+         err_undefined_condition/1, err_undefined_condition/3,
          err_unexpected_request/0, err_unexpected_request/2]).
 
 %% XMPP stream errors
@@ -567,14 +567,16 @@ err_subscription_required(Text, Lang) ->
     err(auth, 'subscription-required', 407, Text, Lang).
 
 %% No error type is defined for .
-%% We choose "modify" as it's used in RFC 6120 example.
--spec err_undefined_condition() -> error().
-err_undefined_condition() ->
-    err(modify, 'undefined-condition', 500).
+%% Let user provide the type.
+-spec err_undefined_condition('auth' | 'cancel' | 'continue' |
+			      'modify' | 'wait') -> error().
+err_undefined_condition(Type) ->
+    err(Type, 'undefined-condition', 500).
 
--spec err_undefined_condition(binary(), binary() | undefined) -> error().
-err_undefined_condition(Text, Lang) ->
-    err(modify, 'undefined-condition', 500, Text, Lang).
+-spec err_undefined_condition('auth' | 'cancel' | 'continue' | 'modify' | 'wait',
+			      binary(), binary() | undefined) -> error().
+err_undefined_condition(Type, Text, Lang) ->
+    err(Type, 'undefined-condition', 500, Text, Lang).
 
 %% RFC 6120 says error type SHOULD be "wait" or "modify".
 %% RFC 3920 and XEP-0082 says it SHOULD be "wait".

From abb4446b51d3f516e89106a694660676df75edde Mon Sep 17 00:00:00 2001
From: Evgeniy Khramtsov 
Date: Wed, 3 Aug 2016 21:00:22 +0300
Subject: [PATCH 027/151] Fix calls to undefined functions

---
 src/mod_irc.erl            | 6 +++---
 src/mod_irc_connection.erl | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/mod_irc.erl b/src/mod_irc.erl
index 91f43716f..1960c988d 100644
--- a/src/mod_irc.erl
+++ b/src/mod_irc.erl
@@ -330,7 +330,7 @@ process_command(#iq{type = set, lang = Lang, to = To, from = From,
 	    catch E:R ->
 		    ?ERROR_MSG("ad-hoc handler failed: ~p",
 			       [{E, {R, erlang:get_stacktrace()}}]),
-		    xmpp:make_error(IQ, xmpp:internal_server_error())
+		    xmpp:make_error(IQ, xmpp:err_internal_server_error())
 	    end;
 	_ ->
 	    Txt = <<"Node not found">>,
@@ -409,7 +409,7 @@ iq_disco(_ServerHost, undefined, Lang) ->
        features = [?NS_DISCO_INFO, ?NS_DISCO_ITEMS, ?NS_MUC,
 		   ?NS_REGISTER, ?NS_VCARD, ?NS_COMMANDS]};
 iq_disco(ServerHost, Node, Lang) ->
-    case lists:keyfind(Node, commands(ServerHost)) of
+    case lists:keyfind(Node, 1, commands(ServerHost)) of
 	{_, Name, _} ->
 	    #disco_info{
 	       identities = [#identity{category = <<"automation">>,
@@ -645,7 +645,7 @@ adhoc_join(_From, _To, #adhoc_command{lang = Lang, xdata = undefined} = Request)
 				      type = 'text-single',
 				      label = translate:translate(Lang, <<"IRC server">>),
 				      required = true}]},
-    xmpp_utils:make_adhoc_response(
+    xmpp_util:make_adhoc_response(
       Request, #adhoc_command{status = executing, xdata = X});
 adhoc_join(From, To, #adhoc_command{lang = Lang, xdata = X} = Request) ->
     Channel = case xmpp_util:get_xdata_values(<<"channel">>, X) of
diff --git a/src/mod_irc_connection.erl b/src/mod_irc_connection.erl
index fb301330a..694accf45 100644
--- a/src/mod_irc_connection.erl
+++ b/src/mod_irc_connection.erl
@@ -1167,7 +1167,7 @@ iq_admin(StateData, Channel, From, To,
 	    ?ERROR_MSG("failed to process admin query from ~s: ~p",
 		       [jid:to_string(From), {E, {R, erlang:get_stacktrace()}}]),
 	    ejabberd_router:route_error(
-	      To, From, IQ, xmpp:internal_server_error())
+	      To, From, IQ, xmpp:err_internal_server_error())
     end.
 
 process_iq_admin(_StateData, _Channel, set, #muc_admin{items = []}) ->

From bc33a3873dbb0828714eef69094213575fc979b6 Mon Sep 17 00:00:00 2001
From: Evgeniy Khramtsov 
Date: Thu, 4 Aug 2016 11:49:17 +0300
Subject: [PATCH 028/151] Rewrite multicast code to use XML generator

---
 src/ejabberd_router_multicast.erl |  12 +-
 src/mod_multicast.erl             | 494 ++++++++++++------------------
 2 files changed, 202 insertions(+), 304 deletions(-)

diff --git a/src/ejabberd_router_multicast.erl b/src/ejabberd_router_multicast.erl
index fa32c8ed7..967699007 100644
--- a/src/ejabberd_router_multicast.erl
+++ b/src/ejabberd_router_multicast.erl
@@ -43,9 +43,10 @@
 
 -include("ejabberd.hrl").
 -include("logger.hrl").
--include("jlib.hrl").
+-include("xmpp.hrl").
 
--record(route_multicast, {domain, pid}).
+-record(route_multicast, {domain = <<"">> :: binary(),
+			  pid = self() :: pid()}).
 -record(state, {}).
 
 %%====================================================================
@@ -58,7 +59,7 @@
 start_link() ->
     gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
 
-
+-spec route_multicast(jid(), binary(), [jid()], stanza()) -> ok.
 route_multicast(From, Domain, Destinations, Packet) ->
     case catch do_route(From, Domain, Destinations, Packet) of
 	{'EXIT', Reason} ->
@@ -68,6 +69,7 @@ route_multicast(From, Domain, Destinations, Packet) ->
 	    ok
     end.
 
+-spec register_route(binary()) -> any().
 register_route(Domain) ->
     case jid:nameprep(Domain) of
 	error ->
@@ -81,6 +83,7 @@ register_route(Domain) ->
 	    mnesia:transaction(F)
     end.
 
+-spec unregister_route(binary()) -> any().
 unregister_route(Domain) ->
     case jid:nameprep(Domain) of
 	error ->
@@ -206,6 +209,7 @@ code_change(_OldVsn, State, _Extra) ->
 %%--------------------------------------------------------------------
 %% From = #jid
 %% Destinations = [#jid]
+-spec do_route(jid(), binary(), [jid()], stanza()) -> any().
 do_route(From, Domain, Destinations, Packet) ->
 
     ?DEBUG("route_multicast~n\tfrom ~s~n\tdomain ~s~n\tdestinations ~p~n\tpacket ~p~n",
@@ -226,6 +230,7 @@ do_route(From, Domain, Destinations, Packet) ->
 	    Pid ! {route_trusted, From, Destinations, Packet}
     end.
 
+-spec pick_multicast_pid([#route_multicast{}]) -> pid().
 pick_multicast_pid(Rs) ->
     List = case [R || R <- Rs, node(R#route_multicast.pid) == node()] of
 	[] -> Rs;
@@ -233,5 +238,6 @@ pick_multicast_pid(Rs) ->
     end,
     (hd(List))#route_multicast.pid.
 
+-spec do_route_normal(jid(), [jid()], stanza()) -> any().
 do_route_normal(From, Destinations, Packet) ->
     [ejabberd_router:route(From, To, Packet) || To <- Destinations].
diff --git a/src/mod_multicast.erl b/src/mod_multicast.erl
index df385c28c..f1c090ae4 100644
--- a/src/mod_multicast.erl
+++ b/src/mod_multicast.erl
@@ -45,16 +45,20 @@
 -include("ejabberd.hrl").
 -include("logger.hrl").
 
--include("jlib.hrl").
+-include("xmpp.hrl").
 
 -record(state,
 	{lserver, lservice, access, service_limits}).
+-type state() :: #state{}.
 
 -record(multicastc, {rserver, response, ts}).
 
 %% ts: timestamp (in seconds) when the cache item was last updated
 
--record(dest, {jid_string, jid_jid, type, full_xml}).
+-record(dest, {jid_string = none :: binary(),
+	       jid_jid :: jid(),
+	       type :: atom(),
+	       full_xml :: address()}).
 
 %% jid_string = string()
 %% jid_jid = jid()
@@ -168,10 +172,8 @@ handle_cast(_Msg, State) -> {noreply, State}.
 %% Description: Handling all non call/cast messages
 %%--------------------------------------------------------------------
 
-handle_info({route, From, To,
-	     #xmlel{name = <<"iq">>, attrs = Attrs} = Packet},
-	    State) ->
-    case catch handle_iq(From, To, #xmlel{attrs = Attrs} = Packet, State) of
+handle_info({route, From, To, #iq{} = Packet}, State) ->
+    case catch handle_iq(From, To, Packet, State) of
         {'EXIT', Reason} ->
             ?ERROR_MSG("Error when processing IQ stanza: ~p",
                        [Reason]);
@@ -179,13 +181,10 @@ handle_info({route, From, To,
     end,
     {noreply, State};
 %% XEP33 allows only 'message' and 'presence' stanza type
-handle_info({route, From, To,
-	     #xmlel{name = Stanza_type} = Packet},
+handle_info({route, From, To, Packet},
 	    #state{lservice = LServiceS, lserver = LServerS,
 		   access = Access, service_limits = SLimits} =
-		State)
-    when (Stanza_type == <<"message">>) or
-	   (Stanza_type == <<"presence">>) ->
+		State) when ?is_stanza(Packet) ->
     route_untrusted(LServiceS, LServerS, Access, SLimits,
 		    From, To, Packet),
     {noreply, State};
@@ -220,91 +219,59 @@ code_change(_OldVsn, State, _Extra) -> {ok, State}.
 %%% IQ Request Processing
 %%%------------------------
 
-handle_iq(From, To, #xmlel{attrs = Attrs} = Packet, State) ->
-    IQ = jlib:iq_query_info(Packet),
-    case catch process_iq(From, IQ, State) of
-        Result when is_record(Result, iq) ->
-            ejabberd_router:route(To, From, jlib:iq_to_xml(Result));
-        {'EXIT', Reason} ->
-            ?ERROR_MSG("Error when processing IQ stanza: ~p",
-                       [Reason]),
-            Err = jlib:make_error_reply(Packet,
-                                        ?ERR_INTERNAL_SERVER_ERROR),
-            ejabberd_router:route(To, From, Err);
-        reply ->
-            LServiceS = jts(To),
-            case fxml:get_attr_s(<<"type">>, Attrs) of
-                <<"result">> ->
-                    process_iqreply_result(From, LServiceS, Packet, State);
-                <<"error">> ->
-                    process_iqreply_error(From, LServiceS, Packet)
-            end;
-        ok -> ok
+handle_iq(From, To, Packet, State) ->
+    try
+	IQ = xmpp:decode_els(Packet),
+	case process_iq(From, IQ, State) of
+	    {result, SubEl} ->
+		ejabberd_router:route(To, From, xmpp:make_iq_result(Packet, SubEl));
+	    {error, Error} ->
+		ejabberd_router:route_error(To, From, Packet, Error);
+	    reply ->
+		LServiceS = jid:to_string(To),
+		case Packet#iq.type of
+		    result ->
+			process_iqreply_result(From, LServiceS, IQ);
+		    error ->
+			process_iqreply_error(From, LServiceS, IQ)
+		end
+	end
+    catch _:{xmpp_codec, Why} ->
+	    Lang = xmpp:get_lang(Packet),
+	    Err = xmpp:err_bad_request(xmpp:format_error(Why), Lang),
+	    ejabberd_router:route_error(To, From, Packet, Err)
     end.
 
-process_iq(From,
-	   #iq{type = get, xmlns = ?NS_DISCO_INFO, lang = Lang} =
-	       IQ,
-	   State) ->
-    IQ#iq{type = result,
-	  sub_el =
-	      [#xmlel{name = <<"query">>,
-		      attrs = [{<<"xmlns">>, ?NS_DISCO_INFO}],
-		      children = iq_disco_info(From, Lang, State)}]};
-%% disco#items request
-process_iq(_,
-	   #iq{type = get, xmlns = ?NS_DISCO_ITEMS} = IQ, _) ->
-    IQ#iq{type = result,
-	  sub_el =
-	      [#xmlel{name = <<"query">>,
-		      attrs = [{<<"xmlns">>, ?NS_DISCO_ITEMS}],
-		      children = []}]};
-%% vCard request
-process_iq(_,
-	   #iq{type = get, xmlns = ?NS_VCARD, lang = Lang} = IQ,
-	   _) ->
-    IQ#iq{type = result,
-	  sub_el =
-	      [#xmlel{name = <<"vCard">>,
-		      attrs = [{<<"xmlns">>, ?NS_VCARD}],
-		      children = iq_vcard(Lang)}]};
-%% Unknown "set" or "get" request
-process_iq(_, #iq{type = Type, sub_el = SubEl} = IQ, _)
-    when Type == get; Type == set ->
-    IQ#iq{type = error,
-	  sub_el = [SubEl, ?ERR_SERVICE_UNAVAILABLE]};
-%% IQ "result" or "error".
-process_iq(_, reply, _) -> reply;
-%% IQ "result" or "error".
-process_iq(_, _, _) -> ok.
+-spec process_iq(jid(), iq(), state()) -> {result, xmpp_element()} |
+					  {error, error()} | reply.
+process_iq(From, #iq{type = get, lang = Lang,
+		     sub_els = [#disco_info{}]}, State) ->
+    {result, iq_disco_info(From, Lang, State)};
+process_iq(_, #iq{type = get, sub_els = [#disco_items{}]}, _) ->
+    {result, #disco_items{}};
+process_iq(_, #iq{type = get, lang = Lang, sub_els = [#vcard_temp{}]}, _) ->
+    {result, iq_vcard(Lang)};
+process_iq(_, #iq{type = T}, _) when T == set; T == get ->
+    {error, xmpp:err_service_unavailable()};
+process_iq(_, _, _) ->
+    reply.
 
--define(FEATURE(Feat),
-	#xmlel{name = <<"feature">>,
-	       attrs = [{<<"var">>, Feat}], children = []}).
+-define(FEATURE(Feat), Feat).
 
 iq_disco_info(From, Lang, State) ->
-    [#xmlel{name = <<"identity">>,
-	    attrs =
-		[{<<"category">>, <<"service">>},
-		 {<<"type">>, <<"multicast">>},
-		 {<<"name">>,
-		  translate:translate(Lang, <<"Multicast">>)}],
-	    children = []},
-     ?FEATURE((?NS_DISCO_INFO)), ?FEATURE((?NS_DISCO_ITEMS)),
-     ?FEATURE((?NS_VCARD)), ?FEATURE((?NS_ADDRESS))]
-      ++ iq_disco_info_extras(From, State).
+    #disco_info{
+       identities = [#identity{category = <<"service">>,
+			       type = <<"multicast">>,
+			       name = translate:translate(Lang, <<"Multicast">>)}],
+       features = [?NS_DISCO_INFO, ?NS_DISCO_ITEMS, ?NS_VCARD, ?NS_ADDRESS],
+       xdata = iq_disco_info_extras(From, State)}.
 
 iq_vcard(Lang) ->
-    [#xmlel{name = <<"FN">>, attrs = [],
-	    children = [{xmlcdata, <<"ejabberd/mod_multicast">>}]},
-     #xmlel{name = <<"URL">>, attrs = [],
-	    children = [{xmlcdata, ?EJABBERD_URI}]},
-     #xmlel{name = <<"DESC">>, attrs = [],
-	    children =
-		[{xmlcdata,
-                  <<(translate:translate(Lang,
-                                      <<"ejabberd Multicast service">>))/binary,
-                                        "\nCopyright (c) 2002-2016 ProcessOne">>}]}].
+    Desc = translate:translate(Lang, <<"ejabberd Multicast service">>),
+    Copyright = <<"Copyright (c) 2002-2016 ProcessOne">>,
+    #vcard_temp{fn = <<"ejabberd/mod_multicast">>,
+		url = ?EJABBERD_URI,
+		desc = <>}.
 
 %%%-------------------------
 %%% Route
@@ -313,19 +280,14 @@ iq_vcard(Lang) ->
 route_trusted(LServiceS, LServerS, FromJID,
 	      Destinations, Packet) ->
     Packet_stripped = Packet,
-    AAttrs = [{<<"xmlns">>, ?NS_ADDRESS}],
+    AAttrs = [],
     Delivereds = [],
-    Dests2 = lists:map(fun (D) ->
-			       DS = jts(D),
-			       XML = #xmlel{name = <<"address">>,
-					    attrs =
-						[{<<"type">>, <<"bcc">>},
-						 {<<"jid">>, DS}],
-					    children = []},
-			       #dest{jid_string = DS, jid_jid = D,
-				     type = <<"bcc">>, full_xml = XML}
-		       end,
-		       Destinations),
+    Dests2 = lists:map(
+	       fun(D) ->
+		       #dest{jid_string = jid:to_string(D),
+			     jid_jid = D, type = bcc,
+			     full_xml = #address{type = bcc, jid = D}}
+	       end, Destinations),
     Groups = group_dests(Dests2),
     route_common(LServerS, LServiceS, FromJID, Groups,
 		 Delivereds, Packet_stripped, AAttrs).
@@ -363,20 +325,19 @@ route_untrusted(LServiceS, LServerS, Access, SLimits,
 route_untrusted2(LServiceS, LServerS, Access, SLimits,
 		 FromJID, Packet) ->
     ok = check_access(LServerS, Access, FromJID),
-    {ok, Packet_stripped, AAttrs, Addresses} =
-	strip_addresses_element(Packet),
-    {To_deliver, Delivereds} =
-	split_addresses_todeliver(Addresses),
+    {ok, Packet_stripped, Addresses} = strip_addresses_element(Packet),
+    {To_deliver, Delivereds} = split_addresses_todeliver(Addresses),
     Dests = convert_dest_record(To_deliver),
     {Dests2, Not_jids} = split_dests_jid(Dests),
     report_not_jid(FromJID, Packet, Not_jids),
-    ok = check_limit_dests(SLimits, FromJID, Packet,
-			   Dests2),
+    ok = check_limit_dests(SLimits, FromJID, Packet, Dests2),
     Groups = group_dests(Dests2),
     ok = check_relay(FromJID#jid.server, LServerS, Groups),
     route_common(LServerS, LServiceS, FromJID, Groups,
-		 Delivereds, Packet_stripped, AAttrs).
+		 Delivereds, Packet_stripped, []).
 
+-spec route_common(binary(), binary(), jid(), [#group{}],
+		   [address()], stanza(), list()) -> any().
 route_common(LServerS, LServiceS, FromJID, Groups,
 	     Delivereds, Packet_stripped, AAttrs) ->
     Groups2 = look_cached_servers(LServerS, Groups),
@@ -435,52 +396,39 @@ check_access(LServerS, Access, From) ->
 %%% Strip 'addresses' XML element
 %%%-------------------------
 
+-spec strip_addresses_element(stanza()) -> {ok, stanza(), [address()]}.
 strip_addresses_element(Packet) ->
-    case fxml:get_subtag(Packet, <<"addresses">>) of
-      #xmlel{name = <<"addresses">>, attrs = AAttrs,
-	     children = Addresses} ->
-	  case fxml:get_attr_s(<<"xmlns">>, AAttrs) of
-	    ?NS_ADDRESS ->
-		#xmlel{name = Name, attrs = Attrs, children = Els} =
-		    Packet,
-		Els_stripped = lists:keydelete(<<"addresses">>, 2, Els),
-		Packet_stripped = #xmlel{name = Name, attrs = Attrs,
-					 children = Els_stripped},
-		{ok, Packet_stripped, AAttrs, fxml:remove_cdata(Addresses)};
-	    _ -> throw(ewxmlns)
-	  end;
-      _ -> throw(eadsele)
+    case xmpp:get_subtag(Packet, #addresses{}) of
+	#addresses{list = Addrs} ->
+	    PacketStripped = xmpp:remove_subtag(Packet, #addresses{}),
+	    {ok, PacketStripped, Addrs};
+	undefined ->
+	    throw(eadsele)
     end.
 
 %%%-------------------------
 %%% Split Addresses
 %%%-------------------------
 
+-spec split_addresses_todeliver([address()]) -> {[address()], [address()]}.
 split_addresses_todeliver(Addresses) ->
-    lists:partition(fun (XML) ->
-			    case XML of
-			      #xmlel{name = <<"address">>, attrs = Attrs} ->
-				  case fxml:get_attr_s(<<"delivered">>, Attrs) of
-				    <<"true">> -> false;
-				    _ ->
-					Type = fxml:get_attr_s(<<"type">>,
-							      Attrs),
-					case Type of
-					  <<"to">> -> true;
-					  <<"cc">> -> true;
-					  <<"bcc">> -> true;
-					  _ -> false
-					end
-				  end;
-			      _ -> false
-			    end
-		    end,
-		    Addresses).
+    lists:partition(
+      fun(#address{delivered = true}) ->
+	      false;
+	 (#address{type = Type}) ->
+	      case Type of
+		  to -> true;
+		  cc -> true;
+		  bcc -> true;
+		  _ -> false
+	      end
+      end, Addresses).
 
 %%%-------------------------
 %%% Check does not exceed limit of destinations
 %%%-------------------------
 
+-spec check_limit_dests(_, jid(), stanza(), [address()]) -> ok.
 check_limit_dests(SLimits, FromJID, Packet,
 		  Addresses) ->
     SenderT = sender_type(FromJID),
@@ -497,24 +445,22 @@ check_limit_dests(SLimits, FromJID, Packet,
 %%% Convert Destination XML to record
 %%%-------------------------
 
-convert_dest_record(XMLs) ->
-    lists:map(fun (XML) ->
-		      case fxml:get_tag_attr_s(<<"jid">>, XML) of
-			<<"">> -> #dest{jid_string = none, full_xml = XML};
-			JIDS ->
-			    Type = fxml:get_tag_attr_s(<<"type">>, XML),
-			    JIDJ = stj(JIDS),
-			    #dest{jid_string = JIDS, jid_jid = JIDJ,
-				  type = Type, full_xml = XML}
-		      end
-	      end,
-	      XMLs).
+-spec convert_dest_record([address()]) -> [#dest{}].
+convert_dest_record(Addrs) ->
+    lists:map(
+      fun(#address{jid = undefined} = Addr) ->
+	      #dest{jid_string = none, full_xml = Addr};
+	 (#address{jid = JID, type = Type} = Addr) ->
+	      #dest{jid_string = jid:to_string(JID), jid_jid = JID,
+		    type = Type, full_xml = Addr}
+      end, Addrs).
 
 %%%-------------------------
 %%% Split destinations by existence of JID
 %%% and send error messages for other dests
 %%%-------------------------
 
+-spec split_dests_jid([#dest{}]) -> {[#dest{}], [#dest{}]}.
 split_dests_jid(Dests) ->
     lists:partition(fun (Dest) ->
 			    case Dest#dest.jid_string of
@@ -524,8 +470,9 @@ split_dests_jid(Dests) ->
 		    end,
 		    Dests).
 
+-spec report_not_jid(jid(), stanza(), #dest{}) -> any().
 report_not_jid(From, Packet, Dests) ->
-    Dests2 = [fxml:element_to_binary(Dest#dest.full_xml)
+    Dests2 = [fxml:element_to_binary(xmpp:encode(Dest#dest.full_xml))
 	      || Dest <- Dests],
     [route_error(From, From, Packet, jid_malformed,
 		 <<"This service can not process the address: ",
@@ -536,6 +483,7 @@ report_not_jid(From, Packet, Dests) ->
 %%% Group destinations by their servers
 %%%-------------------------
 
+-spec group_dests([#dest{}]) -> [#group{}].
 group_dests(Dests) ->
     D = lists:foldl(fun (Dest, Dict) ->
 			    ServerS = (Dest#dest.jid_jid)#jid.server,
@@ -575,18 +523,17 @@ build_other_xml(Dests) ->
     lists:foldl(fun (Dest, R) ->
 			XML = Dest#dest.full_xml,
 			case Dest#dest.type of
-			  <<"to">> -> [add_delivered(XML) | R];
-			  <<"cc">> -> [add_delivered(XML) | R];
-			  <<"bcc">> -> R;
+			  to -> [add_delivered(XML) | R];
+			  cc -> [add_delivered(XML) | R];
+			  bcc -> R;
 			  _ -> [XML | R]
 			end
 		end,
 		[], Dests).
 
-add_delivered(#xmlel{name = Name, attrs = Attrs,
-		     children = Els}) ->
-    Attrs2 = [{<<"delivered">>, <<"true">>} | Attrs],
-    #xmlel{name = Name, attrs = Attrs2, children = Els}.
+-spec add_delivered(address()) -> address().
+add_delivered(Addr) ->
+    Addr#address{delivered = true}.
 
 %%%-------------------------
 %%% Add preliminary packets
@@ -636,7 +583,7 @@ decide_action_group(Group) ->
 
 route_packet(From, ToDest, Packet, AAttrs, Others, Addresses) ->
     Dests = case ToDest#dest.type of
-	      <<"bcc">> -> [];
+	      bcc -> [];
 	      _ -> [ToDest]
 	    end,
     route_packet2(From, ToDest#dest.jid_string, Dests,
@@ -652,20 +599,20 @@ route_packet_multicast(From, ToS, Packet, AAttrs, Dests,
 		   Addresses)
      || DFragment <- Fragmented_dests].
 
-route_packet2(From, ToS, Dests, Packet, AAttrs,
+-spec route_packet2(jid(), binary(), [#dest{}], stanza(), list(), [address()]) -> ok.
+route_packet2(From, ToS, Dests, Packet, _AAttrs,
 	      Addresses) ->
-    #xmlel{name = T, attrs = A, children = C} = Packet,
-    C2 = case append_dests(Dests, Addresses) of
-	   [] -> C;
-	   ACs ->
-	       [#xmlel{name = <<"addresses">>, attrs = AAttrs,
-		       children = ACs}
-		| C]
-	 end,
-    Packet2 = #xmlel{name = T, attrs = A, children = C2},
+    Els = case append_dests(Dests, Addresses) of
+	      [] ->
+		  xmpp:get_els(Packet);
+	      ACs ->
+		  [#addresses{list = ACs}|xmpp:get_els(Packet)]
+	  end,
+    Packet2 = xmpp:set_els(Packet, Els),
     ToJID = stj(ToS),
     ejabberd_router:route(From, ToJID, Packet2).
 
+-spec append_dests([#dest{}], {[address()], [address()]} | [address()]) -> [address()].
 append_dests(_Dests, {Others, Addresses}) ->
     Addresses++Others;
 append_dests([], Addresses) -> Addresses;
@@ -676,12 +623,14 @@ append_dests([Dest | Dests], Addresses) ->
 %%% Check relay
 %%%-------------------------
 
+-spec check_relay(binary(), binary(), [#group{}]) -> ok.
 check_relay(RS, LS, Gs) ->
     case check_relay_required(RS, LS, Gs) of
       false -> ok;
       true -> throw(edrelay)
     end.
 
+-spec check_relay_required(binary(), binary(), [#group{}]) -> boolean().
 check_relay_required(RServer, LServerS, Groups) ->
     case lists:suffix(str:tokens(LServerS, <<".">>),
                       str:tokens(RServer, <<".">>)) of
@@ -689,6 +638,7 @@ check_relay_required(RServer, LServerS, Groups) ->
       false -> check_relay_required(LServerS, Groups)
     end.
 
+-spec check_relay_required(binary(), [#group{}]) -> boolean().
 check_relay_required(LServerS, Groups) ->
     lists:any(fun (Group) -> Group#group.server /= LServerS
 	      end,
@@ -701,19 +651,16 @@ check_relay_required(LServerS, Groups) ->
 send_query_info(RServerS, LServiceS) ->
     case str:str(RServerS, <<"echo.">>) of
       1 -> false;
-      _ -> send_query(RServerS, LServiceS, ?NS_DISCO_INFO)
+      _ -> send_query(RServerS, LServiceS, #disco_info{})
     end.
 
 send_query_items(RServerS, LServiceS) ->
-    send_query(RServerS, LServiceS, ?NS_DISCO_ITEMS).
+    send_query(RServerS, LServiceS, #disco_items{}).
 
-send_query(RServerS, LServiceS, XMLNS) ->
-    Packet = #xmlel{name = <<"iq">>,
-		    attrs = [{<<"to">>, RServerS}, {<<"type">>, <<"get">>}],
-		    children =
-			[#xmlel{name = <<"query">>,
-				attrs = [{<<"xmlns">>, XMLNS}],
-				children = []}]},
+-spec send_query(binary(), binary(), [disco_info()|disco_items()]) -> ok.
+send_query(RServerS, LServiceS, SubEl) ->
+    Packet = #iq{id = randoms:get_string(),
+		 type = get, sub_els = [SubEl]},
     ejabberd_router:route(stj(LServiceS), stj(RServerS),
 			  Packet).
 
@@ -733,49 +680,40 @@ process_iqreply_error(From, LServiceS, _Packet) ->
 %%% Check protocol support: Receive response: Disco
 %%%-------------------------
 
-process_iqreply_result(From, LServiceS, Packet, State) ->
-    #xmlel{name = <<"query">>, attrs = Attrs2,
-	   children = Els2} =
-	fxml:get_subtag(Packet, <<"query">>),
-    case fxml:get_attr_s(<<"xmlns">>, Attrs2) of
-      ?NS_DISCO_INFO ->
-	  process_discoinfo_result(From, LServiceS, Els2, State);
-      ?NS_DISCO_ITEMS ->
-	  process_discoitems_result(From, LServiceS, Els2)
+-spec process_iqreply_result(jid(), binary(), iq()) -> any().
+process_iqreply_result(From, LServiceS, #iq{sub_els = [SubEl]}) ->
+    case SubEl of
+	#disco_info{} ->
+	    process_discoinfo_result(From, LServiceS, SubEl);
+	#disco_items{} ->
+	    process_discoitems_result(From, LServiceS, SubEl);
+	_ ->
+	    ok
     end.
 
 %%%-------------------------
 %%% Check protocol support: Receive response: Disco Info
 %%%-------------------------
 
-process_discoinfo_result(From, LServiceS, Els,
-			 _State) ->
+process_discoinfo_result(From, LServiceS, DiscoInfo) ->
     FromS = jts(From),
     case search_waiter(FromS, LServiceS, info) of
       {found_waiter, Waiter} ->
-	  process_discoinfo_result2(From, FromS, LServiceS, Els,
+	  process_discoinfo_result2(From, FromS, LServiceS, DiscoInfo,
 				    Waiter);
       _ -> ok
     end.
 
-process_discoinfo_result2(From, FromS, LServiceS, Els,
+process_discoinfo_result2(From, FromS, LServiceS,
+			  #disco_info{features = Feats} = DiscoInfo,
 			  Waiter) ->
-    Multicast_support =
-	lists:any(
-	    fun(XML) ->
-		    case XML of
-			#xmlel{name = <<"feature">>, attrs = Attrs} ->
-			    (?NS_ADDRESS) == fxml:get_attr_s(<<"var">>, Attrs);
-			_ -> false
-		    end
-	    end,
-	    Els),
+    Multicast_support = lists:member(?NS_ADDRESS, Feats),
     Group = Waiter#waiter.group,
     RServer = Group#group.server,
     case Multicast_support of
 	true ->
 	    SenderT = sender_type(From),
-	    RLimits = get_limits_xml(Els, SenderT),
+	    RLimits = get_limits_xml(DiscoInfo, SenderT),
 	    add_response(RServer, {multicast_supported, FromS, RLimits}),
 	    FromM = Waiter#waiter.sender,
 	    DestsM = Group#group.dests,
@@ -799,90 +737,58 @@ process_discoinfo_result2(From, FromS, LServiceS, Els,
 	  end
     end.
 
-get_limits_xml(Els, SenderT) ->
-    LimitOpts = get_limits_els(Els),
+get_limits_xml(DiscoInfo, SenderT) ->
+    LimitOpts = get_limits_els(DiscoInfo),
     build_remote_limit_record(LimitOpts, SenderT).
 
-get_limits_els(Els) ->
-    lists:foldl(fun (XML, R) ->
-			case XML of
-			  #xmlel{name = <<"x">>, attrs = Attrs,
-				 children = SubEls} ->
-			      case ((?NS_XDATA) ==
-				      fxml:get_attr_s(<<"xmlns">>, Attrs))
-				     and
-				     (<<"result">> ==
-					fxml:get_attr_s(<<"type">>, Attrs))
-				  of
-				true -> get_limits_fields(SubEls) ++ R;
-				false -> R
-			      end;
-			  _ -> R
-			end
-		end,
-		[], Els).
+-spec get_limits_els(disco_info()) -> [{atom(), integer()}].
+get_limits_els(DiscoInfo) ->
+    lists:flatmap(
+      fun(#xdata{type = result} = X) ->
+	      get_limits_fields(X);
+	 (_) ->
+	      []
+      end, DiscoInfo#disco_info.xdata).
 
-get_limits_fields(Fields) ->
-    {Head, Tail} = lists:partition(fun (Field) ->
-					   case Field of
-					     #xmlel{name = <<"field">>,
-						    attrs = Attrs} ->
-						 (<<"FORM_TYPE">> ==
-						    fxml:get_attr_s(<<"var">>,
-								   Attrs))
-						   and
-						   (<<"hidden">> ==
-						      fxml:get_attr_s(<<"type">>,
-								     Attrs));
-					     _ -> false
-					   end
-				   end,
-				   Fields),
+-spec get_limits_fields(xdata()) -> [{atom(), integer()}].
+get_limits_fields(X) ->
+    {Head, Tail} = lists:partition(
+		     fun(#xdata_field{var = Var, type = Type}) ->
+			     Var == <<"FORM_TYPE">> andalso Type == hidden
+		     end, X#xdata.fields),
     case Head of
       [] -> [];
       _ -> get_limits_values(Tail)
     end.
 
-get_limits_values(Values) ->
-    lists:foldl(fun (Value, R) ->
-			case Value of
-			  #xmlel{name = <<"field">>, attrs = Attrs,
-				 children = SubEls} ->
-			      [#xmlel{name = <<"value">>, children = SubElsV}] =
-				  SubEls,
-			      Number = fxml:get_cdata(SubElsV),
-			      Name = fxml:get_attr_s(<<"var">>, Attrs),
-			      [{jlib:binary_to_atom(Name),
-				jlib:binary_to_integer(Number)}
-			       | R];
-			  _ -> R
-			end
-		end,
-		[], Values).
+-spec get_limits_values([xdata_field()]) -> [{atom(), integer()}].
+get_limits_values(Fields) ->
+    lists:flatmap(
+      fun(#xdata_field{var = Name, values = [Number]}) ->
+	      try
+		  [{binary_to_atom(Name, utf8), binary_to_integer(Number)}]
+	      catch _:badarg ->
+		      []
+	      end;
+	 (_) ->
+	      []
+      end, Fields).
 
 %%%-------------------------
 %%% Check protocol support: Receive response: Disco Items
 %%%-------------------------
 
-process_discoitems_result(From, LServiceS, Els) ->
+process_discoitems_result(From, LServiceS, #disco_items{items = Items}) ->
     FromS = jts(From),
     case search_waiter(FromS, LServiceS, items) of
         {found_waiter, Waiter} ->
-            List = lists:foldl(
-                     fun(XML, Res) ->
-                             case XML of
-                                 #xmlel{name = <<"item">>, attrs = Attrs} ->
-                                     SJID = fxml:get_attr_s(<<"jid">>, Attrs),
-                                     case jid:from_string(SJID) of
-                                         #jid{luser = <<"">>,
-                                              lresource = <<"">>} ->
-                                             [SJID | Res];
-                                         _ -> Res
-                                     end;
-                                 _ -> Res
-                             end
-                     end,
-                     [], Els),
+            List = lists:flatmap(
+		     fun(#disco_item{jid = #jid{luser = <<"">>,
+						lresource = <<"">>} = J}) ->
+			     [J];
+			(_) ->
+			     []
+		     end, Items),
             case List of
                 [] ->
                     received_awaiter(FromS, Waiter, LServiceS);
@@ -1109,9 +1015,7 @@ get_limit_value(Name, Default, LimitOpts) ->
       false -> {default, Default}
     end.
 
-type_of_stanza(#xmlel{name = <<"message">>}) -> message;
-type_of_stanza(#xmlel{name = <<"presence">>}) ->
-    presence.
+type_of_stanza(Stanza) -> element(1, Stanza).
 
 get_limit_number(message, Limits) ->
     Limits#limits.message;
@@ -1144,17 +1048,10 @@ fragment_dests(Dests, Limit_number) ->
 %% Some parts of code are borrowed from mod_muc_room.erl
 
 -define(RFIELDT(Type, Var, Val),
-	#xmlel{name = <<"field">>,
-	       attrs = [{<<"var">>, Var}, {<<"type">>, Type}],
-	       children =
-		   [#xmlel{name = <<"value">>, attrs = [],
-			   children = [{xmlcdata, Val}]}]}).
+	#xdata_field{type = Type, var = Var, values = [Val]}).
 
 -define(RFIELDV(Var, Val),
-	#xmlel{name = <<"field">>, attrs = [{<<"var">>, Var}],
-	       children =
-		   [#xmlel{name = <<"value">>, attrs = [],
-			   children = [{xmlcdata, Val}]}]}).
+	#xdata_field{var = Var, values = [Val]}).
 
 iq_disco_info_extras(From, State) ->
     SenderT = sender_type(From),
@@ -1162,12 +1059,9 @@ iq_disco_info_extras(From, State) ->
     case iq_disco_info_extras2(SenderT, Service_limits) of
       [] -> [];
       List_limits_xmpp ->
-	  [#xmlel{name = <<"x">>,
-		  attrs =
-		      [{<<"xmlns">>, ?NS_XDATA}, {<<"type">>, <<"result">>}],
-		  children =
-		      [?RFIELDT(<<"hidden">>, <<"FORM_TYPE">>, (?NS_ADDRESS))]
-			++ List_limits_xmpp}]
+	    #xdata{type = result,
+		   fields = [?RFIELDT(hidden, <<"FORM_TYPE">>, ?NS_ADDRESS)
+			     | List_limits_xmpp]}
     end.
 
 sender_type(From) ->
@@ -1198,22 +1092,20 @@ to_binary(A) -> list_to_binary(hd(io_lib:format("~p", [A]))).
 %%%-------------------------
 
 route_error(From, To, Packet, ErrType, ErrText) ->
-    #xmlel{attrs = Attrs} = Packet,
-    Lang = fxml:get_attr_s(<<"xml:lang">>, Attrs),
-    Reply = make_reply(ErrType, Lang, ErrText),
-    Err = jlib:make_error_reply(Packet, Reply),
-    ejabberd_router:route(From, To, Err).
+    Lang = xmpp:get_lang(Packet),
+    Err = make_reply(ErrType, Lang, ErrText),
+    ejabberd_router:route_error(From, To, Packet, Err).
 
 make_reply(bad_request, Lang, ErrText) ->
-    ?ERRT_BAD_REQUEST(Lang, ErrText);
+    xmpp:err_bad_request(ErrText, Lang);
 make_reply(jid_malformed, Lang, ErrText) ->
-    ?ERRT_JID_MALFORMED(Lang, ErrText);
+    xmpp:err_jid_malformed(ErrText, Lang);
 make_reply(not_acceptable, Lang, ErrText) ->
-    ?ERRT_NOT_ACCEPTABLE(Lang, ErrText);
+    xmpp:err_not_acceptable(ErrText, Lang);
 make_reply(internal_server_error, Lang, ErrText) ->
-    ?ERRT_INTERNAL_SERVER_ERROR(Lang, ErrText);
+    xmpp:err_internal_server_error(ErrText, Lang);
 make_reply(forbidden, Lang, ErrText) ->
-    ?ERRT_FORBIDDEN(Lang, ErrText).
+    xmpp:err_forbidden(ErrText, Lang).
 
 stj(String) -> jid:from_string(String).
 

From cbdc106427d6d1e6e9371796645fa2f64b64c9a5 Mon Sep 17 00:00:00 2001
From: Evgeniy Khramtsov 
Date: Thu, 4 Aug 2016 12:34:12 +0300
Subject: [PATCH 029/151] Rewrite jd2ejd to use XML generator

---
 src/jd2ejd.erl | 66 ++++++++++++++++++++++++--------------------------
 1 file changed, 31 insertions(+), 35 deletions(-)

diff --git a/src/jd2ejd.erl b/src/jd2ejd.erl
index 099387c9a..8afd9c80a 100644
--- a/src/jd2ejd.erl
+++ b/src/jd2ejd.erl
@@ -32,8 +32,7 @@
 
 -include("ejabberd.hrl").
 -include("logger.hrl").
-
--include("jlib.hrl").
+-include("xmpp.hrl").
 
 %%%----------------------------------------------------------------------
 %%% API
@@ -112,7 +111,9 @@ process_xdb(User, Server,
 
 xdb_data(_User, _Server, {xmlcdata, _CData}) -> ok;
 xdb_data(User, Server, #xmlel{attrs = Attrs} = El) ->
-    From = jid:make(User, Server, <<"">>),
+    From = jid:make(User, Server),
+    LUser = From#jid.luser,
+    LServer = From#jid.lserver,
     case fxml:get_attr_s(<<"xmlns">>, Attrs) of
       ?NS_AUTH ->
 	  Password = fxml:get_tag_cdata(El),
@@ -128,29 +129,21 @@ xdb_data(User, Server, #xmlel{attrs = Attrs} = El) ->
 					 Status),
 	  ok;
       ?NS_VCARD ->
-	  catch mod_vcard:process_sm_iq(From,
-					jid:make(<<"">>, Server, <<"">>),
-					#iq{type = set, xmlns = ?NS_VCARD,
-					    sub_el = El}),
+	  catch mod_vcard:set_vcard(User, LServer, El),
 	  ok;
       <<"jabber:x:offline">> ->
 	  process_offline(Server, From, El), ok;
       XMLNS ->
 	  case fxml:get_attr_s(<<"j_private_flag">>, Attrs) of
 	    <<"1">> ->
-		catch mod_private:process_sm_iq(From,
-						jid:make(<<"">>, Server,
-							      <<"">>),
-						#iq{type = set,
-						    xmlns = ?NS_PRIVATE,
-						    sub_el =
-							#xmlel{name =
-								   <<"query">>,
-							       attrs = [],
-							       children =
-								   [jlib:remove_attr(<<"j_private_flag">>,
-										     jlib:remove_attr(<<"xdbns">>,
-												      El))]}});
+		NewAttrs = lists:filter(
+			     fun({<<"j_private_flag">>, _}) -> false;
+				({<<"xdbns">>, _}) -> false;
+				(_) -> true
+			     end, Attrs),
+		catch mod_private:set_data(
+			LUser, LServer,
+			[{XMLNS, El#xmlel{attrs = NewAttrs}}]);
 	    _ ->
 		?DEBUG("jd2ejd: Unknown namespace \"~s\"~n", [XMLNS])
 	  end,
@@ -159,18 +152,21 @@ xdb_data(User, Server, #xmlel{attrs = Attrs} = El) ->
 
 process_offline(Server, To, #xmlel{children = Els}) ->
     LServer = jid:nameprep(Server),
-    lists:foreach(fun (#xmlel{attrs = Attrs} = El) ->
-			  FromS = fxml:get_attr_s(<<"from">>, Attrs),
-			  From = case FromS of
-				   <<"">> ->
-				       jid:make(<<"">>, Server, <<"">>);
-				   _ -> jid:from_string(FromS)
-				 end,
-			  case From of
-			    error -> ok;
-			    _ ->
-				ejabberd_hooks:run(offline_message_hook,
-						   LServer, [From, To, El])
-			  end
-		  end,
-		  Els).
+    lists:foreach(
+      fun(#xmlel{} = El) ->
+	      try xmpp:decode(El, [ignore_els]) of
+		  #message{from = JID} ->
+		      From = case JID of
+				 undefined -> jid:make(Server);
+				 _ -> JID
+			     end,
+		      ejabberd_hooks:run(offline_message_hook,
+					 LServer, [From, To, El]);
+		  _ ->
+		      ok
+	      catch _:{xmpp_codec, Why} ->
+		      Txt = xmpp:format_error(Why),
+		      ?ERROR_MSG("failed to decode XML '~s': ~s",
+				 [fxml:element_to_binary(El), Txt])
+	      end
+      end, Els).

From 8b81b9ecb1ee9287d848f6860dbc5abdaec72e96 Mon Sep 17 00:00:00 2001
From: Evgeniy Khramtsov 
Date: Thu, 4 Aug 2016 13:37:07 +0300
Subject: [PATCH 030/151] Rewrite PIEFXIS code to use XML generator

---
 src/ejabberd_piefxis.erl | 247 +++++++++++++++++----------------------
 src/jd2ejd.erl           |   3 +-
 src/mod_privacy.erl      |   2 +-
 src/mod_roster.erl       |  11 +-
 4 files changed, 118 insertions(+), 145 deletions(-)

diff --git a/src/ejabberd_piefxis.erl b/src/ejabberd_piefxis.erl
index 758001239..6a2b5e644 100644
--- a/src/ejabberd_piefxis.erl
+++ b/src/ejabberd_piefxis.erl
@@ -48,7 +48,7 @@
 
 -include("ejabberd.hrl").
 -include("logger.hrl").
--include("jlib.hrl").
+-include("xmpp.hrl").
 -include("mod_privacy.hrl").
 -include("mod_roster.hrl").
 
@@ -209,31 +209,28 @@ parse_scram_password(PassData) ->
     iterationcount = list_to_integer(binary_to_list(IterationCountBin))
   }.
 
+-spec get_vcard(binary(), binary()) -> [xmlel()].
 get_vcard(User, Server) ->
-    JID = jid:make(User, Server, <<>>),
-    case mod_vcard:process_sm_iq(JID, JID, #iq{type = get}) of
-        #iq{type = result, sub_el = [_|_] = VCardEls} ->
-            VCardEls;
-        _ ->
-            []
+    LUser = jid:nodeprep(User),
+    LServer = jid:nameprep(Server),
+    case mod_vcard:get_vcard(LUser, LServer) of
+	error -> [];
+	Els -> Els
     end.
 
+-spec get_offline(binary(), binary()) -> [xmlel()].
 get_offline(User, Server) ->
-    case mod_offline:get_offline_els(User, Server) of
+    LUser = jid:nodeprep(User),
+    LServer = jid:nameprep(Server),
+    case mod_offline:get_offline_els(LUser, LServer) of
         [] ->
             [];
         Els ->
-            NewEls = lists:map(
-                       fun(#xmlel{attrs = Attrs} = El) ->
-                               NewAttrs = lists:keystore(<<"xmlns">>, 1,
-                                                         Attrs,
-                                                         {<<"xmlns">>,
-                                                          <<"jabber:client">>}),
-                               El#xmlel{attrs = NewAttrs}
-                       end, Els),
+            NewEls = lists:map(fun xmpp:encode/1, Els),
             [#xmlel{name = <<"offline-messages">>, children = NewEls}]
     end.
 
+-spec get_privacy(binary(), binary()) -> [xmlel()].
 get_privacy(User, Server) ->
     case mod_privacy:get_user_lists(User, Server) of
         {ok, #privacy{default = Default,
@@ -241,25 +238,16 @@ get_privacy(User, Server) ->
             XLists = lists:map(
                        fun({Name, Items}) ->
                                XItems = lists:map(
-                                          fun mod_privacy:item_to_xml/1, Items),
-                               #xmlel{name = <<"list">>,
-                                      attrs = [{<<"name">>, Name}],
-                                      children = XItems}
+					  fun mod_privacy:encode_list_item/1,
+					  Items),
+			       #privacy_list{name = Name, items = XItems}
                        end, Lists),
-            DefaultEl = case Default of
-                            none ->
-                                [];
-                            _ ->
-                                [#xmlel{name = <<"default">>,
-                                        attrs = [{<<"name">>, Default}]}]
-                        end,
-            [#xmlel{name = <<"query">>,
-                    attrs = [{<<"xmlns">>, ?NS_PRIVACY}],
-                    children = DefaultEl ++ XLists}];
+	    [xmpp:encode(#privacy_query{default = Default, lists = XLists})];
         _ ->
             []
     end.
 
+-spec get_roster(binary(), binary()) -> [xmlel()].
 get_roster(User, Server) ->
     JID = jid:make(User, Server, <<>>),
     case mod_roster:get_roster(User, Server) of
@@ -272,18 +260,11 @@ get_roster(User, Server) ->
                           Status = if is_binary(Msg) -> (Msg);
                                       true -> <<"">>
                                    end,
-                          [#xmlel{name = <<"presence">>,
-                                  attrs =
-                                      [{<<"from">>,
-                                        jid:to_string(R#roster.jid)},
-                                       {<<"to">>, jid:to_string(JID)},
-                                       {<<"xmlns">>, <<"jabber:client">>},
-                                       {<<"type">>, <<"subscribe">>}],
-                                  children =
-                                      [#xmlel{name = <<"status">>,
-                                              attrs = [],
-                                              children =
-                                                  [{xmlcdata, Status}]}]}];
+			  [xmpp:encode(
+			     #presence{from = jid:make(R#roster.jid),
+				       to = JID,
+				       type = subscribe,
+				       status = xmpp:mk_text(Status)})];
                      (_) ->
                           []
                   end, Items),
@@ -291,21 +272,18 @@ get_roster(User, Server) ->
                    fun(#roster{ask = in, subscription = none}) ->
                            [];
                       (R) ->
-                           [mod_roster:item_to_xml(R)]
+                           [mod_roster:encode_item(R)]
                    end, Items),
-            [#xmlel{name = <<"query">>,
-                    attrs = [{<<"xmlns">>, ?NS_ROSTER}],
-                    children = Rs} | Subs];
+	    [xmpp:encode(#roster_query{items = Rs}) | Subs];
         _ ->
             []
     end.
 
+-spec get_private(binary(), binary()) -> [xmlel()].
 get_private(User, Server) ->
     case mod_private:get_data(User, Server) of
         [_|_] = Els ->
-            [#xmlel{name = <<"query">>,
-                    attrs = [{<<"xmlns">>, ?NS_PRIVATE}],
-                    children = Els}];
+	    [xmpp:encode(#private{xml_els = Els})];
         _ ->
             []
     end.
@@ -451,129 +429,124 @@ process_user_els([], State) ->
 
 process_user_el(#xmlel{name = Name, attrs = Attrs, children = Els} = El,
                 State) ->
-    case {Name, fxml:get_attr_s(<<"xmlns">>, Attrs)} of
-        {<<"query">>, ?NS_ROSTER} ->
-            process_roster(El, State);
-        {<<"query">>, ?NS_PRIVACY} ->
-            %% Make sure  elements go before  and 
-            NewEls = lists:reverse(lists:keysort(#xmlel.name, Els)),
-            process_privacy_el(El#xmlel{children = NewEls}, State);
-        {<<"query">>, ?NS_PRIVATE} ->
-            process_private(El, State);
-        {<<"vCard">>, ?NS_VCARD} ->
-            process_vcard(El, State);
-        {<<"offline-messages">>, _} ->
-            process_offline_msgs(Els, State);
-        {<<"presence">>, <<"jabber:client">>} ->
-            process_presence(El, State);
-        _ ->
-            {ok, State}
+    try
+	case {Name, fxml:get_attr_s(<<"xmlns">>, Attrs)} of
+	    {<<"query">>, ?NS_ROSTER} ->
+		process_roster(xmpp:decode(El), State);
+	    {<<"query">>, ?NS_PRIVACY} ->
+		%% Make sure  elements go before  and 
+		process_privacy(xmpp:decode(El), State);
+	    {<<"query">>, ?NS_PRIVATE} ->
+		process_private(xmpp:decode(El), State);
+	    {<<"vCard">>, ?NS_VCARD} ->
+		process_vcard(El, State);
+	    {<<"offline-messages">>, _} ->
+		Msgs = [xmpp:decode(E, [ignore_els]) || E <- Els],
+		process_offline_msgs(Msgs, State);
+	    {<<"presence">>, <<"jabber:client">>} ->
+		process_presence(xmpp:decode(El, [ignore_els]), State);
+	    _ ->
+		{ok, State}
+	end
+    catch _:{xmpp_codec, Why} ->
+	    ErrTxt = xmpp:format_error(Why),
+	    stop("failed to decode XML '~s': ~s",
+		 [fxml:element_to_binary(El), ErrTxt])
     end.
 
-process_privacy_el(#xmlel{children = [#xmlel{} = SubEl|SubEls]} = El, State) ->
-    case process_privacy(#xmlel{children = [SubEl]}, State) of
+-spec process_offline_msgs([stanza()], state()) -> {ok, state()} | {error, _}.
+process_offline_msgs([#message{} = Msg|Msgs], State) ->
+    case process_offline_msg(Msg, State) of
         {ok, NewState} ->
-            process_privacy_el(El#xmlel{children = SubEls}, NewState);
+            process_offline_msgs(Msgs, NewState);
         Err ->
             Err
     end;
-process_privacy_el(#xmlel{children = [_|SubEls]} = El, State) ->
-    process_privacy_el(El#xmlel{children = SubEls}, State);
-process_privacy_el(#xmlel{children = []}, State) ->
-    {ok, State}.
-
-process_offline_msgs([#xmlel{} = El|Els], State) ->
-    case process_offline_msg(El, State) of
-        {ok, NewState} ->
-            process_offline_msgs(Els, NewState);
-        Err ->
-            Err
-    end;
-process_offline_msgs([_|Els], State) ->
-    process_offline_msgs(Els, State);
+process_offline_msgs([_|Msgs], State) ->
+    process_offline_msgs(Msgs, State);
 process_offline_msgs([], State) ->
     {ok, State}.
 
-process_roster(El, State = #state{user = U, server = S}) ->
-    case mod_roster:set_items(U, S, El) of
+-spec process_roster(roster_query(), state()) -> {ok, state()} | {error, _}.
+process_roster(RosterQuery, State = #state{user = U, server = S}) ->
+    case mod_roster:set_items(U, S, RosterQuery) of
         {atomic, _} ->
             {ok, State};
         Err ->
             stop("Failed to write roster: ~p", [Err])
     end.
 
-process_privacy(El, State = #state{user = U, server = S}) ->
-    JID = jid:make(U, S, <<"">>),
-    case mod_privacy:process_iq_set(
-           [], JID, JID, #iq{type = set, sub_el = El}) of
-        {error, Error} = Err ->
-            #xmlel{children = Els} = El,
-            Name = case fxml:remove_cdata(Els) of
-              [#xmlel{name = N}] -> N;
-              _ -> undefined
-            end,
-            #xmlel{attrs = Attrs} = Error,
-            ErrorCode = case lists:keysearch(<<"code">>, 1, Attrs) of
-              {value, {_, V}} -> V;
-              false -> undefined
-            end,
-            if 
-              ErrorCode == <<"404">>, Name == <<"default">> ->
-                {ok, State};
-              true ->
-                stop("Failed to write privacy: ~p", [Err])
+-spec process_privacy(privacy_query(), state()) -> {ok, state()} | {error, _}.
+process_privacy(#privacy_query{lists = Lists,
+			       default = Default,
+			       active = Active} = PrivacyQuery,
+		State = #state{user = U, server = S}) ->
+    JID = jid:make(U, S),
+    IQ = #iq{type = set, id = randoms:get_string(),
+	     from = JID, to = JID, sub_els = [PrivacyQuery]},
+    Txt = <<"No module is handling this query">>,
+    Error = {error, xmpp:err_feature_not_implemented(Txt, ?MYLANG)},
+    case mod_privacy:process_iq_set(Error, IQ) of
+        {error, #error{reason = Reason}} = Err ->
+	    if Reason == 'item-not-found', Lists == [],
+	       Active == undefined, Default /= undefined ->
+		    %% Failed to set default list because there is no
+		    %% list with such name. We shouldn't stop here.
+		    {ok, State};
+	       true ->
+		    stop("Failed to write privacy: ~p", [Err])
             end;
         _ ->
             {ok, State}
     end.
 
-process_private(El, State = #state{user = U, server = S}) ->
-    JID = jid:make(U, S, <<"">>),
-    case mod_private:process_sm_iq(
-           JID, JID, #iq{type = set, sub_el = El}) of
+-spec process_private(private(), state()) -> {ok, state()} | {error, _}.
+process_private(Private, State = #state{user = U, server = S}) ->
+    JID = jid:make(U, S),
+    IQ = #iq{type = set, id = randoms:get_string(),
+	     from = JID, to = JID, sub_els = [Private]},
+    case mod_private:process_sm_iq(IQ) of
         #iq{type = result} ->
             {ok, State};
         Err ->
             stop("Failed to write private: ~p", [Err])
     end.
 
+-spec process_vcard(xmlel(), state()) -> {ok, state()} | {error, _}.
 process_vcard(El, State = #state{user = U, server = S}) ->
-    JID = jid:make(U, S, <<"">>),
-    case mod_vcard:process_sm_iq(
-           JID, JID, #iq{type = set, sub_el = El}) of
+    JID = jid:make(U, S),
+    IQ = #iq{type = set, id = randoms:get_string(),
+	     from = JID, to = JID, sub_els = [El]},
+    case mod_vcard:process_sm_iq(IQ) of
         #iq{type = result} ->
             {ok, State};
         Err ->
             stop("Failed to write vcard: ~p", [Err])
     end.
 
-process_offline_msg(El, State = #state{user = U, server = S}) ->
-    FromS = fxml:get_attr_s(<<"from">>, El#xmlel.attrs),
-    case jid:from_string(FromS) of
-        #jid{} = From ->
-            To = jid:make(U, S, <<>>),
-            NewEl = jlib:replace_from_to(From, To, El),
-            case catch mod_offline:store_packet(From, To, NewEl) of
-                {'EXIT', _} = Err ->
-                    stop("Failed to store offline message: ~p", [Err]);
-                _ ->
-                    {ok, State}
-            end;
-        _ ->
-            stop("Invalid 'from' = ~s", [FromS])
+-spec process_offline_msg(message(), state()) -> {ok, state()} | {error, _}.
+process_offline_msg(#message{from = undefined}, _State) ->
+    stop("No 'from' attribute found", []);
+process_offline_msg(Msg, State = #state{user = U, server = S}) ->
+    From = xmpp:get_from(Msg),
+    To = jid:make(U, S, <<>>),
+    NewMsg = xmpp:set_from_to(Msg, From, To),
+    case catch mod_offline:store_packet(From, To, NewMsg) of
+	{'EXIT', _} = Err ->
+	    stop("Failed to store offline message: ~p", [Err]);
+	_ ->
+	    {ok, State}
     end.
 
-process_presence(El, #state{user = U, server = S} = State) ->
-    FromS = fxml:get_attr_s(<<"from">>, El#xmlel.attrs),
-    case jid:from_string(FromS) of
-        #jid{} = From ->
-            To = jid:make(U, S, <<>>),
-            NewEl = jlib:replace_from_to(From, To, El),
-            ejabberd_router:route(From, To, NewEl),
-            {ok, State};
-        _ ->
-            stop("Invalid 'from' = ~s", [FromS])
-    end.
+-spec process_presence(presence(), state()) -> {ok, state()} | {error, _}.
+process_presence(#presence{from = undefined}, _State) ->
+    stop("No 'from' attribute found", []);
+process_presence(Pres, #state{user = U, server = S} = State) ->
+    From = xmpp:get_from(Pres),
+    To = jid:make(U, S, <<>>),
+    NewPres = xmpp:set_from_to(Pres, From, To),
+    ejabberd_router:route(From, To, NewPres),
+    {ok, State}.
 
 stop(Fmt, Args) ->
     ?ERROR_MSG(Fmt, Args),
diff --git a/src/jd2ejd.erl b/src/jd2ejd.erl
index 8afd9c80a..81732547b 100644
--- a/src/jd2ejd.erl
+++ b/src/jd2ejd.erl
@@ -120,7 +120,8 @@ xdb_data(User, Server, #xmlel{attrs = Attrs} = El) ->
 	  ejabberd_auth:set_password(User, Server, Password),
 	  ok;
       ?NS_ROSTER ->
-	  catch mod_roster:set_items(User, Server, El), ok;
+	  catch mod_roster:set_items(User, Server, xmpp:decode(El)),
+	  ok;
       ?NS_LAST ->
 	  TimeStamp = fxml:get_attr_s(<<"last">>, Attrs),
 	  Status = fxml:get_tag_cdata(El),
diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl
index f61ba31d4..da947ace1 100644
--- a/src/mod_privacy.erl
+++ b/src/mod_privacy.erl
@@ -33,7 +33,7 @@
 
 -export([start/2, stop/1, process_iq/1, export/1, import/1,
 	 process_iq_set/2, process_iq_get/3, get_user_list/3,
-	 check_packet/6, remove_user/2,
+	 check_packet/6, remove_user/2, encode_list_item/1,
 	 is_list_needdb/1, updated_list/3,
          item_to_xml/1, get_user_lists/2, import/3,
 	 set_privacy_list/1, mod_opt_type/1, depends/2]).
diff --git a/src/mod_roster.erl b/src/mod_roster.erl
index 58dc51983..51fe08ba5 100644
--- a/src/mod_roster.erl
+++ b/src/mod_roster.erl
@@ -688,15 +688,14 @@ send_unsubscribing_presence(From, Item) ->
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-set_items(User, Server, SubEl) ->
-    #xmlel{children = Els} = SubEl,
+-spec set_items(binary(), binary(), roster_query()) -> any().
+set_items(User, Server, #roster_query{items = Items}) ->
     LUser = jid:nodeprep(User),
     LServer = jid:nameprep(Server),
     F = fun () ->
-		lists:foreach(fun (El) ->
-				      process_item_set_t(LUser, LServer, El)
-			      end,
-			      Els)
+		lists:foreach(fun (Item) ->
+				      process_item_set_t(LUser, LServer, Item)
+			      end, Items)
 	end,
     transaction(LServer, F).
 

From ca217dc1054cc4ba749559c1507f9101e76856bc Mon Sep 17 00:00:00 2001
From: Evgeniy Khramtsov 
Date: Thu, 4 Aug 2016 13:41:38 +0300
Subject: [PATCH 031/151] Rewrite HTTP Bind and Web Admin code to use XML
 generator

---
 src/ejabberd_http_bind.erl | 2 +-
 src/ejabberd_web_admin.erl | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/ejabberd_http_bind.erl b/src/ejabberd_http_bind.erl
index 6fa38110c..1a238607a 100644
--- a/src/ejabberd_http_bind.erl
+++ b/src/ejabberd_http_bind.erl
@@ -62,7 +62,7 @@
 -include("ejabberd.hrl").
 -include("logger.hrl").
 
--include("jlib.hrl").
+-include("xmpp.hrl").
 
 -include("ejabberd_http.hrl").
 
diff --git a/src/ejabberd_web_admin.erl b/src/ejabberd_web_admin.erl
index 3281f6430..e62b4d257 100644
--- a/src/ejabberd_web_admin.erl
+++ b/src/ejabberd_web_admin.erl
@@ -38,7 +38,7 @@
 -include("ejabberd.hrl").
 -include("logger.hrl").
 
--include("jlib.hrl").
+-include("xmpp.hrl").
 
 -include("ejabberd_http.hrl").
 

From b487ccfb34079dbd5d9839d329d8f07b54ad77c1 Mon Sep 17 00:00:00 2001
From: Evgeniy Khramtsov 
Date: Thu, 4 Aug 2016 16:45:33 +0300
Subject: [PATCH 032/151] Delete mod_configure2

The module doesn't work properly for many years and nobody reported
this, which means nobody is using it. Also, mod_configure does
the same (and more) in a standard compliant way (XEP-0133).
---
 src/mod_configure2.erl | 223 -----------------------------------------
 1 file changed, 223 deletions(-)
 delete mode 100644 src/mod_configure2.erl

diff --git a/src/mod_configure2.erl b/src/mod_configure2.erl
deleted file mode 100644
index 85b7740d0..000000000
--- a/src/mod_configure2.erl
+++ /dev/null
@@ -1,223 +0,0 @@
-%%%----------------------------------------------------------------------
-%%% File    : mod_configure2.erl
-%%% Author  : Alexey Shchepin 
-%%% Purpose : Support for online configuration of ejabberd
-%%% Created : 26 Oct 2003 by Alexey Shchepin 
-%%%
-%%%
-%%% ejabberd, Copyright (C) 2002-2016   ProcessOne
-%%%
-%%% This program is free software; you can redistribute it and/or
-%%% modify it under the terms of the GNU General Public License as
-%%% published by the Free Software Foundation; either version 2 of the
-%%% License, or (at your option) any later version.
-%%%
-%%% This program is distributed in the hope that it will be useful,
-%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
-%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-%%% General Public License for more details.
-%%%
-%%% You should have received a copy of the GNU General Public License along
-%%% with this program; if not, write to the Free Software Foundation, Inc.,
-%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-%%%
-%%%----------------------------------------------------------------------
-
--module(mod_configure2).
-
--behaviour(ejabberd_config).
-
--author('alexey@process-one.net').
-
--behaviour(gen_mod).
-
--export([start/2, stop/1, process_local_iq/3,
-	 mod_opt_type/1, opt_type/1, depends/2]).
-
--include("ejabberd.hrl").
--include("logger.hrl").
-
--include("jlib.hrl").
-
--define(NS_ECONFIGURE,
-	<<"http://ejabberd.jabberstudio.org/protocol/con"
-	  "figure">>).
-
-start(Host, Opts) ->
-    IQDisc = gen_mod:get_opt(iqdisc, Opts, fun gen_iq_handler:check_type/1,
-                             one_queue),
-    gen_iq_handler:add_iq_handler(ejabberd_local, Host,
-				  ?NS_ECONFIGURE, ?MODULE, process_local_iq,
-				  IQDisc),
-    ok.
-
-stop(Host) ->
-    gen_iq_handler:remove_iq_handler(ejabberd_local, Host,
-				     ?NS_ECONFIGURE).
-
-process_local_iq(From, To,
-		 #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) ->
-    case acl:match_rule(To#jid.lserver, configure, From) of
-      deny ->
-	  Txt = <<"Denied by ACL">>,
-	  IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]};
-      allow ->
-	  case Type of
-	    set ->
-		Txt = <<"Value 'set' of 'type' attribute is not allowed">>,
-		IQ#iq{type = error,
-		      sub_el = [SubEl, ?ERRT_FEATURE_NOT_IMPLEMENTED(Lang, Txt)]};
-	    %%case fxml:get_tag_attr_s("type", SubEl) of
-	    %%    "cancel" ->
-	    %%        IQ#iq{type = result,
-	    %%		   sub_el = [{xmlelement, "query",
-	    %%			      [{"xmlns", XMLNS}], []}]};
-	    %%    "submit" ->
-	    %%        XData = jlib:parse_xdata_submit(SubEl),
-	    %%        case XData of
-	    %%    	invalid ->
-	    %%    	    IQ#iq{type = error,
-	    %%			  sub_el = [SubEl, ?ERR_BAD_REQUEST]};
-	    %%    	_ ->
-	    %%    	    Node =
-	    %%    		string:tokens(
-	    %%    		  fxml:get_tag_attr_s("node", SubEl),
-	    %%    		  "/"),
-	    %%    	    case set_form(Node, Lang, XData) of
-	    %%    		{result, Res} ->
-	    %%    		    IQ#iq{type = result,
-	    %%				  sub_el = [{xmlelement, "query",
-	    %%					     [{"xmlns", XMLNS}],
-	    %%					     Res
-	    %%					    }]};
-	    %%    		{error, Error} ->
-	    %%    		    IQ#iq{type = error,
-	    %%				  sub_el = [SubEl, Error]}
-	    %%    	    end
-	    %%        end;
-	    %%    _ ->
-	    %%        IQ#iq{type = error,
-	    %%		   sub_el = [SubEl, ?ERR_NOT_ALLOWED]}
-	    %%end;
-	    get ->
-		case process_get(SubEl, Lang) of
-		  {result, Res} -> IQ#iq{type = result, sub_el = [Res]};
-		  {error, Error} ->
-		      IQ#iq{type = error, sub_el = [SubEl, Error]}
-		end
-	  end
-    end.
-
-process_get(#xmlel{name = <<"info">>}, _Lang) ->
-    S2SConns = ejabberd_s2s:dirty_get_connections(),
-    TConns = lists:usort([element(2, C) || C <- S2SConns]),
-    Attrs = [{<<"registered-users">>,
-	      iolist_to_binary(integer_to_list(mnesia:table_info(passwd,
-								 size)))},
-	     {<<"online-users">>,
-	      iolist_to_binary(integer_to_list(mnesia:table_info(presence,
-								 size)))},
-	     {<<"running-nodes">>,
-	      iolist_to_binary(integer_to_list(length(mnesia:system_info(running_db_nodes))))},
-	     {<<"stopped-nodes">>,
-	      iolist_to_binary(integer_to_list(length(lists:usort(mnesia:system_info(db_nodes)
-								     ++
-								     mnesia:system_info(extra_db_nodes))
-							 --
-							 mnesia:system_info(running_db_nodes))))},
-	     {<<"outgoing-s2s-servers">>,
-	      iolist_to_binary(integer_to_list(length(TConns)))}],
-    {result,
-     #xmlel{name = <<"info">>,
-	    attrs = [{<<"xmlns">>, ?NS_ECONFIGURE} | Attrs],
-	    children = []}};
-process_get(#xmlel{name = <<"welcome-message">>,
-		   attrs = Attrs}, _Lang) ->
-    {Subj, Body} = ejabberd_config:get_option(
-                     welcome_message,
-                     fun({Subj, Body}) ->
-                             {iolist_to_binary(Subj),
-                              iolist_to_binary(Body)}
-                     end,
-                     {<<"">>, <<"">>}),
-    {result,
-     #xmlel{name = <<"welcome-message">>, attrs = Attrs,
-	    children =
-		[#xmlel{name = <<"subject">>, attrs = [],
-			children = [{xmlcdata, Subj}]},
-		 #xmlel{name = <<"body">>, attrs = [],
-			children = [{xmlcdata, Body}]}]}};
-process_get(#xmlel{name = <<"registration-watchers">>,
-		   attrs = Attrs}, _Lang) ->
-    SubEls = ejabberd_config:get_option(
-               registration_watchers,
-               fun(JIDs) when is_list(JIDs) ->
-                       lists:map(
-                         fun(J) ->
-                                 #xmlel{name = <<"jid">>, attrs = [],
-                                        children = [{xmlcdata,
-                                                     iolist_to_binary(J)}]}
-                         end, JIDs)
-               end, []),
-    {result,
-     #xmlel{name = <<"registration_watchers">>,
-	    attrs = Attrs, children = SubEls}};
-process_get(#xmlel{name = <<"acls">>, attrs = Attrs}, _Lang) ->
-    Str = iolist_to_binary(io_lib:format("~p.",
-					 [ets:tab2list(acl)])),
-    {result,
-     #xmlel{name = <<"acls">>, attrs = Attrs,
-	    children = [{xmlcdata, Str}]}};
-process_get(#xmlel{name = <<"access">>,
-		   attrs = Attrs}, _Lang) ->
-    Str = iolist_to_binary(io_lib:format("~p.",
-					 [ets:select(local_config,
-						     [{{local_config, {access, '$1'},
-							'$2'},
-						       [],
-						       [{{access, '$1',
-							  '$2'}}]}])])),
-    {result,
-     #xmlel{name = <<"access">>, attrs = Attrs,
-	    children = [{xmlcdata, Str}]}};
-process_get(#xmlel{name = <<"last">>, attrs = Attrs}, Lang) ->
-    case catch mnesia:dirty_select(last_activity,
-				   [{{last_activity, '_', '$1', '_'}, [],
-				     ['$1']}])
-	of
-      {'EXIT', _Reason} ->
-	  Txt = <<"Database failure">>,
-	  {error, ?ERRT_INTERNAL_SERVER_ERROR(Lang, Txt)};
-      Vals ->
-	  TimeStamp = p1_time_compat:system_time(seconds),
-	  Str = list_to_binary(
-                  [[jlib:integer_to_binary(TimeStamp - V),
-                    <<" ">>] || V <- Vals]),
-	  {result,
-	   #xmlel{name = <<"last">>, attrs = Attrs,
-		  children = [{xmlcdata, Str}]}}
-    end;
-%%process_get({xmlelement, Name, Attrs, SubEls}) ->
-%%    {result, };
-process_get(_, _) -> {error, ?ERR_BAD_REQUEST}.
-
-depends(_Host, _Opts) ->
-    [].
-
-mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1;
-mod_opt_type(_) -> [iqdisc].
-
-opt_type(registration_watchers) ->
-    fun (JIDs) when is_list(JIDs) ->
-	    lists:map(fun (J) ->
-			      #xmlel{name = <<"jid">>, attrs = [],
-				     children =
-					 [{xmlcdata, iolist_to_binary(J)}]}
-		      end,
-		      JIDs)
-    end;
-opt_type(welcome_message) ->
-    fun ({Subj, Body}) ->
-	    {iolist_to_binary(Subj), iolist_to_binary(Body)}
-    end;
-opt_type(_) -> [registration_watchers, welcome_message].

From 4ff8d7918a0557414f8bf7b1aa1c0f875fb76216 Mon Sep 17 00:00:00 2001
From: Evgeniy Khramtsov 
Date: Fri, 5 Aug 2016 08:41:08 +0300
Subject: [PATCH 033/151] Change code to reflect recent changes in fxml_gen

---
 include/xmpp_codec.hrl      |  420 ++++++-------
 src/ejabberd_c2s.erl        |    4 +-
 src/mod_adhoc.erl           |    4 +-
 src/mod_announce.erl        |    3 +-
 src/mod_blocking.erl        |    9 +-
 src/mod_caps.erl            |   20 +-
 src/mod_configure.erl       |    5 +-
 src/mod_disco.erl           |   30 +-
 src/mod_irc.erl             |    4 +-
 src/mod_mam.erl             |    2 +-
 src/mod_muc.erl             |    6 +-
 src/mod_muc_room.erl        |   29 +-
 src/mod_offline.erl         |    5 +-
 src/mod_privacy.erl         |   17 +-
 src/mod_proxy65_service.erl |    5 -
 src/mod_vcard.erl           |   27 +-
 src/translate.erl           |    4 +-
 src/xmpp.erl                |  121 ++--
 src/xmpp_codec.erl          | 1110 +++++++++++++++--------------------
 src/xmpp_util.erl           |    2 +-
 tools/xmpp_codec.spec       |   67 ++-
 21 files changed, 846 insertions(+), 1048 deletions(-)

diff --git a/include/xmpp_codec.hrl b/include/xmpp_codec.hrl
index e3eb31285..935607de9 100644
--- a/include/xmpp_codec.hrl
+++ b/include/xmpp_codec.hrl
@@ -1,7 +1,7 @@
 %% Created automatically by XML generator (fxml_gen.erl)
 %% Source: xmpp_codec.spec
 
--record(vcard_xupdate, {us :: {binary(), binary()},
+-record(vcard_xupdate, {us = {<<>>, <<>>} :: {binary(), binary()},
 			hash :: binary()}).
 -type vcard_xupdate() :: #vcard_xupdate{}.
 
@@ -15,12 +15,12 @@
 		       'no-permanent-store' | 'no-permanent-storage'}).
 -type hint() :: #hint{}.
 
--record(iq, {id :: binary(),
+-record(iq, {id = <<>> :: binary(),
              type :: 'error' | 'get' | 'result' | 'set',
-             lang :: binary(),
-             from :: any(),
-             to :: any(),
-             sub_els = [] :: [any()]}).
+             lang = <<>> :: binary(),
+             from :: jid:jid(),
+             to :: jid:jid(),
+             sub_els = [] :: [xmpp_element() | fxml:xmlel()]}).
 -type iq() :: #iq{}.
 
 -record(feature_register, {}).
@@ -31,37 +31,37 @@
 -type adhoc_note() :: #adhoc_note{}.
 
 -record(address, {type :: 'bcc' | 'cc' | 'noreply' | 'ofrom' | 'replyroom' | 'replyto' | 'to',
-                  jid :: any(),
-                  desc :: binary(),
-                  node :: binary(),
-                  delivered :: any()}).
+                  jid :: jid:jid(),
+                  desc = <<>> :: binary(),
+                  node = <<>> :: binary(),
+                  delivered :: boolean()}).
 -type address() :: #address{}.
 
--record(sasl_success, {text :: any()}).
+-record(sasl_success, {text = <<>> :: binary()}).
 -type sasl_success() :: #sasl_success{}.
 
--record(mam_result, {xmlns :: binary(),
-                     queryid :: binary(),
-                     id :: binary(),
-                     sub_els = [] :: [any()]}).
+-record(mam_result, {xmlns = <<>> :: binary(),
+                     queryid = <<>> :: binary(),
+                     id = <<>> :: binary(),
+                     sub_els = [] :: [xmpp_element() | fxml:xmlel()]}).
 -type mam_result() :: #mam_result{}.
 
 -record(rsm_first, {index :: non_neg_integer(),
-                    data :: binary()}).
+                    data = <<>> :: binary()}).
 -type rsm_first() :: #rsm_first{}.
 
--record(text, {lang :: binary(),
-               data :: binary()}).
+-record(text, {lang = <<>> :: binary(),
+               data = <<>> :: binary()}).
 -type text() :: #text{}.
 
--record(streamhost, {jid :: any(),
-                     host :: binary(),
+-record(streamhost, {jid :: jid:jid(),
+                     host = <<>> :: binary(),
                      port = 1080 :: non_neg_integer()}).
 -type streamhost() :: #streamhost{}.
 
 -record(sm_resume, {h :: non_neg_integer(),
-                    previd :: binary(),
-                    xmlns :: binary()}).
+                    previd = <<>> :: binary(),
+                    xmlns = <<>> :: binary()}).
 -type sm_resume() :: #sm_resume{}.
 
 -record(carbons_enable, {}).
@@ -77,9 +77,9 @@
 -record(muc_unsubscribe, {}).
 -type muc_unsubscribe() :: #muc_unsubscribe{}.
 
--record(pubsub_unsubscribe, {node :: binary(),
-                             jid :: any(),
-                             subid :: binary()}).
+-record(pubsub_unsubscribe, {node = <<>> :: binary(),
+                             jid :: jid:jid(),
+                             subid = <<>> :: binary()}).
 -type pubsub_unsubscribe() :: #pubsub_unsubscribe{}.
 
 -record(mix_leave, {}).
@@ -88,122 +88,122 @@
 -record(ping, {}).
 -type ping() :: #ping{}.
 
--record(delay, {stamp :: any(),
-                from :: any(),
+-record(delay, {stamp :: erlang:timestamp(),
+                from :: jid:jid(),
                 desc = <<>> :: binary()}).
 -type delay() :: #delay{}.
 
 -record(muc_history, {maxchars :: non_neg_integer(),
                       maxstanzas :: non_neg_integer(),
                       seconds :: non_neg_integer(),
-                      since :: any()}).
+                      since :: erlang:timestamp()}).
 -type muc_history() :: #muc_history{}.
 
--record(thumbnail, {uri :: binary(),
+-record(thumbnail, {uri = <<>> :: binary(),
                     'media-type' = <<>> :: binary(),
                     width :: non_neg_integer(),
                     height :: non_neg_integer()}).
 -type thumbnail() :: #thumbnail{}.
 
--record(pubsub_affiliation, {node :: binary(),
+-record(pubsub_affiliation, {node = <<>> :: binary(),
                              type :: 'member' | 'none' | 'outcast' | 'owner' | 'publish-only' | 'publisher'}).
 -type pubsub_affiliation() :: #pubsub_affiliation{}.
 
--record(muc_decline, {reason = <<>> :: 'undefined' | binary(),
-                      from :: any(),
-                      to :: any()}).
+-record(muc_decline, {reason = <<>> :: binary(),
+                      from :: jid:jid(),
+                      to :: jid:jid()}).
 -type muc_decline() :: #muc_decline{}.
 
 -record(sm_a, {h :: non_neg_integer(),
-               xmlns :: binary()}).
+               xmlns = <<>> :: binary()}).
 -type sm_a() :: #sm_a{}.
 
--record(stream_start, {from :: any(),
-                       to :: any(),
+-record(stream_start, {from :: jid:jid(),
+                       to :: jid:jid(),
                        id = <<>> :: binary(),
                        version = <<>> :: binary(),
-                       xmlns :: binary(),
+                       xmlns = <<>> :: binary(),
                        stream_xmlns = <<>> :: binary(),
                        db_xmlns = <<>> :: binary(),
                        lang = <<>> :: binary()}).
 -type stream_start() :: #stream_start{}.
 
--record(muc_subscribe, {nick :: binary(),
+-record(muc_subscribe, {nick = <<>> :: binary(),
                         events = [] :: [binary()]}).
 -type muc_subscribe() :: #muc_subscribe{}.
 
--record(stanza_id, {by :: any(),
-                    id :: binary()}).
+-record(stanza_id, {by :: jid:jid(),
+                    id = <<>> :: binary()}).
 -type stanza_id() :: #stanza_id{}.
 
 -record(starttls_proceed, {}).
 -type starttls_proceed() :: #starttls_proceed{}.
 
--record(client_id, {id :: binary()}).
+-record(client_id, {id = <<>> :: binary()}).
 -type client_id() :: #client_id{}.
 
 -record(sm_resumed, {h :: non_neg_integer(),
-                     previd :: binary(),
-                     xmlns :: binary()}).
+                     previd = <<>> :: binary(),
+                     xmlns = <<>> :: binary()}).
 -type sm_resumed() :: #sm_resumed{}.
 
 -record(forwarded, {delay :: #delay{},
-                    sub_els = [] :: [any()]}).
+                    sub_els = [] :: [xmpp_element() | fxml:xmlel()]}).
 -type forwarded() :: #forwarded{}.
 
 -record(sm_enable, {max :: non_neg_integer(),
-                    resume = false :: any(),
-                    xmlns :: binary()}).
+                    resume = false :: boolean(),
+                    xmlns = <<>> :: binary()}).
 -type sm_enable() :: #sm_enable{}.
 
 -record(starttls_failure, {}).
 -type starttls_failure() :: #starttls_failure{}.
 
--record(sasl_challenge, {text :: any()}).
+-record(sasl_challenge, {text = <<>> :: binary()}).
 -type sasl_challenge() :: #sasl_challenge{}.
 
 -record(handshake, {data = <<>> :: binary()}).
 -type handshake() :: #handshake{}.
 
--record(gone, {uri :: binary()}).
+-record(gone, {uri = <<>> :: binary()}).
 -type gone() :: #gone{}.
 
--record(x_conference, {jid :: any(),
+-record(x_conference, {jid :: jid:jid(),
                        password = <<>> :: binary(),
                        reason = <<>> :: binary(),
-                       continue :: any(),
+                       continue :: boolean(),
                        thread = <<>> :: binary()}).
 -type x_conference() :: #x_conference{}.
 
--record(private, {xml_els = [] :: [any()]}).
+-record(private, {xml_els = [] :: [fxml:xmlel()]}).
 -type private() :: #private{}.
 
--record(db_verify, {from :: any(),
-                    to :: any(),
-                    id :: binary(),
+-record(db_verify, {from :: jid:jid(),
+                    to :: jid:jid(),
+                    id = <<>> :: binary(),
                     type :: 'error' | 'invalid' | 'valid',
                     key = <<>> :: binary(),
-                    sub_els = [] :: [any()]}).
+                    sub_els = [] :: [xmpp_element() | fxml:xmlel()]}).
 -type db_verify() :: #db_verify{}.
 
--record(nick, {name :: binary()}).
+-record(nick, {name = <<>> :: binary()}).
 -type nick() :: #nick{}.
 
 -record(p1_ack, {}).
 -type p1_ack() :: #p1_ack{}.
 
--record(feature_sm, {xmlns :: binary()}).
+-record(feature_sm, {xmlns = <<>> :: binary()}).
 -type feature_sm() :: #feature_sm{}.
 
--record(pubsub_item, {id :: binary(),
-                      xml_els = [] :: [any()]}).
+-record(pubsub_item, {id = <<>> :: binary(),
+                      xml_els = [] :: [fxml:xmlel()]}).
 -type pubsub_item() :: #pubsub_item{}.
 
--record(pubsub_publish, {node :: binary(),
+-record(pubsub_publish, {node = <<>> :: binary(),
                          items = [] :: [#pubsub_item{}]}).
 -type pubsub_publish() :: #pubsub_publish{}.
 
--record(roster_item, {jid :: any(),
+-record(roster_item, {jid :: jid:jid(),
                       name = <<>> :: binary(),
                       groups = [] :: [binary()],
                       subscription = none :: 'both' | 'from' | 'none' | 'remove' | 'to',
@@ -214,24 +214,24 @@
                        ver :: binary()}).
 -type roster_query() :: #roster_query{}.
 
--record(pubsub_event_item, {id :: binary(),
-                            node :: binary(),
-                            publisher :: binary(),
-                            xml_els = [] :: [any()]}).
+-record(pubsub_event_item, {id = <<>> :: binary(),
+                            node = <<>> :: binary(),
+                            publisher = <<>> :: binary(),
+                            xml_els = [] :: [fxml:xmlel()]}).
 -type pubsub_event_item() :: #pubsub_event_item{}.
 
--record(sm_r, {xmlns :: binary()}).
+-record(sm_r, {xmlns = <<>> :: binary()}).
 -type sm_r() :: #sm_r{}.
 
--record(muc_actor, {jid :: any(),
-                    nick :: binary()}).
+-record(muc_actor, {jid :: jid:jid(),
+                    nick = <<>> :: binary()}).
 -type muc_actor() :: #muc_actor{}.
 
 -record(stat_error, {code :: integer(),
                      reason = <<>> :: binary()}).
 -type stat_error() :: #stat_error{}.
 
--record(stat, {name :: binary(),
+-record(stat, {name = <<>> :: binary(),
                units = <<>> :: binary(),
                value = <<>> :: binary(),
                error :: #stat_error{}}).
@@ -240,7 +240,7 @@
 -record(addresses, {list = [] :: [#address{}]}).
 -type addresses() :: #addresses{}.
 
--record('see-other-host', {host :: binary()}).
+-record('see-other-host', {host :: binary() | inet:ip_address() | {binary() | inet:ip_address(),non_neg_integer()}}).
 -type 'see-other-host'() :: #'see-other-host'{}.
 
 -record(compress, {methods = [] :: [binary()]}).
@@ -253,17 +253,17 @@
                status = <<>> :: binary()}).
 -type last() :: #last{}.
 
--record(redirect, {uri :: binary()}).
+-record(redirect, {uri = <<>> :: binary()}).
 -type redirect() :: #redirect{}.
 
--record(sm_enabled, {id :: binary(),
-                     location :: binary(),
+-record(sm_enabled, {id = <<>> :: binary(),
+                     location = <<>> :: binary(),
                      max :: non_neg_integer(),
-                     resume = false :: any(),
-                     xmlns :: binary()}).
+                     resume = false :: boolean(),
+                     xmlns = <<>> :: binary()}).
 -type sm_enabled() :: #sm_enabled{}.
 
--record(pubsub_event_items, {node :: binary(),
+-record(pubsub_event_items, {node = <<>> :: binary(),
                              retract = [] :: [binary()],
                              items = [] :: [#pubsub_event_item{}]}).
 -type pubsub_event_items() :: #pubsub_event_items{}.
@@ -274,134 +274,134 @@
 -record(muc_unique, {name = <<>> :: binary()}).
 -type muc_unique() :: #muc_unique{}.
 
--record(sasl_response, {text :: any()}).
+-record(sasl_response, {text = <<>> :: binary()}).
 -type sasl_response() :: #sasl_response{}.
 
--record(legacy_auth, {username :: 'none' | binary(),
-                      password :: 'none' | binary(),
-                      digest :: 'none' | binary(),
-                      resource :: 'none' | binary()}).
+-record(legacy_auth, {username :: binary(),
+                      password :: binary(),
+                      digest :: binary(),
+                      resource :: binary()}).
 -type legacy_auth() :: #legacy_auth{}.
 
--record(pubsub_subscribe, {node :: binary(),
-                           jid :: any()}).
+-record(pubsub_subscribe, {node = <<>> :: binary(),
+                           jid :: jid:jid()}).
 -type pubsub_subscribe() :: #pubsub_subscribe{}.
 
--record(message, {id :: binary(),
+-record(message, {id = <<>> :: binary(),
                   type = normal :: 'chat' | 'error' | 'groupchat' | 'headline' | 'normal',
-                  lang :: binary(),
-                  from :: any(),
-                  to :: any(),
+                  lang = <<>> :: binary(),
+                  from :: jid:jid(),
+                  to :: jid:jid(),
                   subject = [] :: [#text{}],
                   body = [] :: [#text{}],
                   thread :: binary(),
-                  sub_els = [] :: [any()]}).
+                  sub_els = [] :: [xmpp_element() | fxml:xmlel()]}).
 -type message() :: #message{}.
 
--record(sasl_auth, {mechanism :: binary(),
-                    text :: any()}).
+-record(sasl_auth, {mechanism = <<>> :: binary(),
+                    text = <<>> :: binary()}).
 -type sasl_auth() :: #sasl_auth{}.
 
 -record(p1_push, {}).
 -type p1_push() :: #p1_push{}.
 
--record(feature_csi, {xmlns :: binary()}).
+-record(feature_csi, {xmlns = <<>> :: binary()}).
 -type feature_csi() :: #feature_csi{}.
 
--record(disco_item, {jid :: any(),
-                     name :: binary(),
-                     node :: binary()}).
+-record(disco_item, {jid :: jid:jid(),
+                     name = <<>> :: binary(),
+                     node = <<>> :: binary()}).
 -type disco_item() :: #disco_item{}.
 
--record(unblock, {items = [] :: [any()]}).
+-record(unblock, {items = [] :: [jid:jid()]}).
 -type unblock() :: #unblock{}.
 
--record(block, {items = [] :: [any()]}).
+-record(block, {items = [] :: [jid:jid()]}).
 -type block() :: #block{}.
 
 -record(compression, {methods = [] :: [binary()]}).
 -type compression() :: #compression{}.
 
--record(muc_subscriptions, {list = [] :: [any()]}).
+-record(muc_subscriptions, {list = [] :: [jid:jid()]}).
 -type muc_subscriptions() :: #muc_subscriptions{}.
 
--record(pubsub_subscription, {jid :: any(),
-                              node :: binary(),
-                              subid :: binary(),
+-record(pubsub_subscription, {jid :: jid:jid(),
+                              node = <<>> :: binary(),
+                              subid = <<>> :: binary(),
                               type :: 'none' | 'pending' | 'subscribed' | 'unconfigured'}).
 -type pubsub_subscription() :: #pubsub_subscription{}.
 
--record(bob_data, {cid :: binary(),
+-record(bob_data, {cid = <<>> :: binary(),
                    'max-age' :: non_neg_integer(),
-                   type :: binary(),
-                   data = <<>> :: any()}).
+                   type = <<>> :: binary(),
+                   data = <<>> :: binary()}).
 -type bob_data() :: #bob_data{}.
 
 -record(muc_item, {actor :: #muc_actor{},
                    continue :: binary(),
-                   reason = <<>> :: 'undefined' | binary(),
+                   reason = <<>> :: binary(),
                    affiliation :: 'admin' | 'member' | 'none' | 'outcast' | 'owner',
                    role :: 'moderator' | 'none' | 'participant' | 'visitor',
-                   jid :: any(),
-                   nick :: binary()}).
+                   jid :: jid:jid(),
+                   nick = <<>> :: binary()}).
 -type muc_item() :: #muc_item{}.
 
 -record(muc_admin, {items = [] :: [#muc_item{}]}).
 -type muc_admin() :: #muc_admin{}.
 
--record(shim, {headers = [] :: [{binary(),'undefined' | binary()}]}).
+-record(shim, {headers = [] :: [{binary(),binary()}]}).
 -type shim() :: #shim{}.
 
--record(mam_prefs, {xmlns :: binary(),
+-record(mam_prefs, {xmlns = <<>> :: binary(),
                     default :: 'always' | 'never' | 'roster',
-                    always :: [any()],
-                    never :: [any()]}).
+                    always :: [jid:jid()],
+                    never :: [jid:jid()]}).
 -type mam_prefs() :: #mam_prefs{}.
 
--record(caps, {node :: binary(),
-               version :: binary(),
-               hash :: binary(),
-               exts = [] :: any()}).
+-record(caps, {node = <<>> :: binary(),
+               version = <<>> :: binary(),
+               hash = <<>> :: binary(),
+               exts = [] :: binary() | []}).
 -type caps() :: #caps{}.
 
 -record(muc, {history :: #muc_history{},
               password :: binary()}).
 -type muc() :: #muc{}.
 
--record(stream_features, {sub_els = [] :: [any()]}).
+-record(stream_features, {sub_els = [] :: [xmpp_element() | fxml:xmlel()]}).
 -type stream_features() :: #stream_features{}.
 
 -record(stats, {list = [] :: [#stat{}],
                 node = <<>> :: binary()}).
 -type stats() :: #stats{}.
 
--record(pubsub_items, {node :: binary(),
+-record(pubsub_items, {node = <<>> :: binary(),
                        max_items :: non_neg_integer(),
-                       subid :: binary(),
+                       subid = <<>> :: binary(),
                        items = [] :: [#pubsub_item{}]}).
 -type pubsub_items() :: #pubsub_items{}.
 
--record(presence, {id :: binary(),
+-record(presence, {id = <<>> :: binary(),
                    type = available :: 'available' | 'error' | 'probe' | 'subscribe' | 'subscribed' | 'unavailable' | 'unsubscribe' | 'unsubscribed',
-                   lang :: binary(),
-                   from :: any(),
-                   to :: any(),
+                   lang = <<>> :: binary(),
+                   from :: jid:jid(),
+                   to :: jid:jid(),
                    show :: 'away' | 'chat' | 'dnd' | 'xa',
                    status = [] :: [#text{}],
                    priority :: integer(),
-                   sub_els = [] :: [any()]}).
+                   sub_els = [] :: [xmpp_element() | fxml:xmlel()]}).
 -type presence() :: #presence{}.
 
--record(sic, {ip :: any(),
+-record(sic, {ip :: inet:ip_address(),
               port :: non_neg_integer(),
-              xmlns :: binary()}).
+              xmlns = <<>> :: binary()}).
 -type sic() :: #sic{}.
 
 -record(carbons_sent, {forwarded :: #forwarded{}}).
 -type carbons_sent() :: #carbons_sent{}.
 
--record(mam_archived, {by :: any(),
-                       id :: binary()}).
+-record(mam_archived, {by :: jid:jid(),
+                       id = <<>> :: binary()}).
 -type mam_archived() :: #mam_archived{}.
 
 -record(p1_rebind, {}).
@@ -428,28 +428,28 @@
                       userid :: binary()}).
 -type vcard_email() :: #vcard_email{}.
 
--record(db_result, {from :: any(),
-                    to :: any(),
+-record(db_result, {from :: jid:jid(),
+                    to :: jid:jid(),
                     type :: 'error' | 'invalid' | 'valid',
                     key = <<>> :: binary(),
-                    sub_els = [] :: [any()]}).
+                    sub_els = [] :: [xmpp_element() | fxml:xmlel()]}).
 -type db_result() :: #db_result{}.
 
 -record(carbons_received, {forwarded :: #forwarded{}}).
 -type carbons_received() :: #carbons_received{}.
 
--record(pubsub_retract, {node :: binary(),
-                         notify = false :: any(),
+-record(pubsub_retract, {node = <<>> :: binary(),
+                         notify = false :: boolean(),
                          items = [] :: [#pubsub_item{}]}).
 -type pubsub_retract() :: #pubsub_retract{}.
 
 -record(upload_slot, {get :: binary(),
                       put :: binary(),
-                      xmlns :: binary()}).
+                      xmlns = <<>> :: binary()}).
 -type upload_slot() :: #upload_slot{}.
 
--record(mix_participant, {jid :: any(),
-                          nick :: binary()}).
+-record(mix_participant, {jid :: jid:jid(),
+                          nick = <<>> :: binary()}).
 -type mix_participant() :: #mix_participant{}.
 
 -record(vcard_geo, {lat :: binary(),
@@ -463,27 +463,27 @@
                        text = [] :: [#text{}]}).
 -type sasl_failure() :: #sasl_failure{}.
 
--record(block_list, {items = [] :: [any()]}).
+-record(block_list, {items = [] :: [jid:jid()]}).
 -type block_list() :: #block_list{}.
 
 -record(upload_request, {filename :: binary(),
                          size :: non_neg_integer(),
                          'content-type' = <<>> :: binary(),
-                         xmlns :: binary()}).
+                         xmlns = <<>> :: binary()}).
 -type upload_request() :: #upload_request{}.
 
--record(xdata_option, {label :: binary(),
+-record(xdata_option, {label = <<>> :: binary(),
                        value :: binary()}).
 -type xdata_option() :: #xdata_option{}.
 
--record(xdata_field, {label :: binary(),
+-record(xdata_field, {label = <<>> :: binary(),
                       type :: 'boolean' | 'fixed' | 'hidden' | 'jid-multi' | 'jid-single' | 'list-multi' | 'list-single' | 'text-multi' | 'text-private' | 'text-single',
-                      var :: binary(),
+                      var = <<>> :: binary(),
                       required = false :: boolean(),
                       desc :: binary(),
                       values = [] :: [binary()],
                       options = [] :: [#xdata_option{}],
-                      sub_els = [] :: [any()]}).
+                      sub_els = [] :: [xmpp_element() | fxml:xmlel()]}).
 -type xdata_field() :: #xdata_field{}.
 
 -record(version, {name :: binary(),
@@ -491,16 +491,16 @@
                   os :: binary()}).
 -type version() :: #version{}.
 
--record(bind, {jid :: any(),
-               resource :: any()}).
+-record(bind, {jid :: jid:jid(),
+               resource :: binary()}).
 -type bind() :: #bind{}.
 
 -record(rosterver_feature, {}).
 -type rosterver_feature() :: #rosterver_feature{}.
 
--record(muc_invite, {reason = <<>> :: 'undefined' | binary(),
-                     from :: any(),
-                     to :: any(),
+-record(muc_invite, {reason = <<>> :: binary(),
+                     from :: jid:jid(),
+                     to :: jid:jid(),
                      continue :: binary()}).
 -type muc_invite() :: #muc_invite{}.
 
@@ -508,11 +508,11 @@
 -type carbons_disable() :: #carbons_disable{}.
 
 -record(bytestreams, {hosts = [] :: [#streamhost{}],
-                      used :: any(),
-                      activate :: any(),
-                      dstaddr :: binary(),
+                      used :: jid:jid(),
+                      activate :: jid:jid(),
+                      dstaddr = <<>> :: binary(),
                       mode = tcp :: 'tcp' | 'udp',
-                      sid :: binary()}).
+                      sid = <<>> :: binary()}).
 -type bytestreams() :: #bytestreams{}.
 
 -record(adhoc_actions, {execute :: 'complete' | 'next' | 'prev',
@@ -534,13 +534,13 @@
                   max :: non_neg_integer()}).
 -type rsm_set() :: #rsm_set{}.
 
--record(mam_fin, {id :: binary(),
+-record(mam_fin, {id = <<>> :: binary(),
                   rsm :: #rsm_set{},
-                  stable :: any(),
-                  complete :: any()}).
+                  stable :: boolean(),
+                  complete :: boolean()}).
 -type mam_fin() :: #mam_fin{}.
 
--record(disco_items, {node :: binary(),
+-record(disco_items, {node = <<>> :: binary(),
                       items = [] :: [#disco_item{}],
                       rsm :: #rsm_set{}}).
 -type disco_items() :: #disco_items{}.
@@ -561,7 +561,7 @@
                     number :: binary()}).
 -type vcard_tel() :: #vcard_tel{}.
 
--record(media_uri, {type :: binary(),
+-record(media_uri, {type = <<>> :: binary(),
                     uri = <<>> :: binary()}).
 -type media_uri() :: #media_uri{}.
 
@@ -570,9 +570,9 @@
                 uri = [] :: [#media_uri{}]}).
 -type media() :: #media{}.
 
--record(muc_destroy, {xmlns :: binary(),
-                      jid :: any(),
-                      reason = <<>> :: 'undefined' | binary(),
+-record(muc_destroy, {xmlns = <<>> :: binary(),
+                      jid :: jid:jid(),
+                      reason = <<>> :: binary(),
                       password :: binary()}).
 -type muc_destroy() :: #muc_destroy{}.
 
@@ -595,15 +595,15 @@
                      suffix :: binary()}).
 -type vcard_name() :: #vcard_name{}.
 
--record(identity, {category :: binary(),
-                   type :: binary(),
-                   lang :: binary(),
-                   name :: binary()}).
+-record(identity, {category = <<>> :: binary(),
+                   type = <<>> :: binary(),
+                   lang = <<>> :: binary(),
+                   name = <<>> :: binary()}).
 -type identity() :: #identity{}.
 
--record(bookmark_conference, {name :: binary(),
-                              jid :: any(),
-                              autojoin = false :: any(),
+-record(bookmark_conference, {name = <<>> :: binary(),
+                              jid :: jid:jid(),
+                              autojoin = false :: boolean(),
                               nick :: binary(),
                               password :: binary()}).
 -type bookmark_conference() :: #bookmark_conference{}.
@@ -611,8 +611,8 @@
 -record(xmpp_session, {optional = false :: boolean()}).
 -type xmpp_session() :: #xmpp_session{}.
 
--record(bookmark_url, {name :: binary(),
-                       url :: binary()}).
+-record(bookmark_url, {name = <<>> :: binary(),
+                       url = <<>> :: binary()}).
 -type bookmark_url() :: #bookmark_url{}.
 
 -record(bookmark_storage, {conference = [] :: [#bookmark_conference{}],
@@ -625,12 +625,12 @@
 -type oob_x() :: #oob_x{}.
 
 -record(vcard_sound, {phonetic :: binary(),
-                      binval :: any(),
+                      binval :: binary(),
                       extval :: binary()}).
 -type vcard_sound() :: #vcard_sound{}.
 
 -record(vcard_photo, {type :: binary(),
-                      binval :: any(),
+                      binval :: binary(),
                       extval :: binary()}).
 -type vcard_photo() :: #vcard_photo{}.
 
@@ -660,7 +660,7 @@
                     ctry :: binary()}).
 -type vcard_adr() :: #vcard_adr{}.
 
--record(search_item, {jid :: any(),
+-record(search_item, {jid :: jid:jid(),
                       first :: binary(),
                       last :: binary(),
                       nick :: binary(),
@@ -678,11 +678,11 @@
 -record(xcaptcha, {xdata :: #xdata{}}).
 -type xcaptcha() :: #xcaptcha{}.
 
--record(adhoc_command, {node :: binary(),
+-record(adhoc_command, {node = <<>> :: binary(),
                         action = execute :: 'cancel' | 'complete' | 'execute' | 'next' | 'prev',
-                        sid :: binary(),
+                        sid = <<>> :: binary(),
                         status :: 'canceled' | 'completed' | 'executing',
-                        lang :: binary(),
+                        lang = <<>> :: binary(),
                         actions :: #adhoc_actions{},
                         notes = [] :: [#adhoc_note{}],
                         xdata :: #xdata{}}).
@@ -697,23 +697,23 @@
                  xdata :: #xdata{}}).
 -type search() :: #search{}.
 
--record(mam_query, {xmlns :: binary(),
-                    id :: binary(),
-                    start :: any(),
-                    'end' :: any(),
-                    with :: any(),
+-record(mam_query, {xmlns = <<>> :: binary(),
+                    id = <<>> :: binary(),
+                    start :: erlang:timestamp(),
+                    'end' :: erlang:timestamp(),
+                    with :: jid:jid(),
                     withtext :: binary(),
                     rsm :: #rsm_set{},
                     xdata :: #xdata{}}).
 -type mam_query() :: #mam_query{}.
 
--record(pubsub_options, {node :: binary(),
-                         jid :: any(),
-                         subid :: binary(),
+-record(pubsub_options, {node = <<>> :: binary(),
+                         jid :: jid:jid(),
+                         subid = <<>> :: binary(),
                          xdata :: #xdata{}}).
 -type pubsub_options() :: #pubsub_options{}.
 
--record(pubsub, {subscriptions :: {'none' | binary(),[#pubsub_subscription{}]},
+-record(pubsub, {subscriptions :: {binary(),[#pubsub_subscription{}]},
                  affiliations :: [#pubsub_affiliation{}],
                  publish :: #pubsub_publish{},
                  subscribe :: #pubsub_subscribe{},
@@ -726,34 +726,34 @@
 -record(register, {registered = false :: boolean(),
                    remove = false :: boolean(),
                    instructions :: binary(),
-                   username :: 'none' | binary(),
-                   nick :: 'none' | binary(),
-                   password :: 'none' | binary(),
-                   name :: 'none' | binary(),
-                   first :: 'none' | binary(),
-                   last :: 'none' | binary(),
-                   email :: 'none' | binary(),
-                   address :: 'none' | binary(),
-                   city :: 'none' | binary(),
-                   state :: 'none' | binary(),
-                   zip :: 'none' | binary(),
-                   phone :: 'none' | binary(),
-                   url :: 'none' | binary(),
-                   date :: 'none' | binary(),
-                   misc :: 'none' | binary(),
-                   text :: 'none' | binary(),
-                   key :: 'none' | binary(),
+                   username :: binary(),
+                   nick :: binary(),
+                   password :: binary(),
+                   name :: binary(),
+                   first :: binary(),
+                   last :: binary(),
+                   email :: binary(),
+                   address :: binary(),
+                   city :: binary(),
+                   state :: binary(),
+                   zip :: binary(),
+                   phone :: binary(),
+                   url :: binary(),
+                   date :: binary(),
+                   misc :: binary(),
+                   text :: binary(),
+                   key :: binary(),
                    xdata :: #xdata{},
-                   sub_els = [] :: [any()]}).
+                   sub_els = [] :: [xmpp_element() | fxml:xmlel()]}).
 -type register() :: #register{}.
 
--record(disco_info, {node :: binary(),
+-record(disco_info, {node = <<>> :: binary(),
                      identities = [] :: [#identity{}],
                      features = [] :: [binary()],
                      xdata = [] :: [#xdata{}]}).
 -type disco_info() :: #disco_info{}.
 
--record(offline_item, {node :: binary(),
+-record(offline_item, {node = <<>> :: binary(),
                        action :: 'remove' | 'view'}).
 -type offline_item() :: #offline_item{}.
 
@@ -772,32 +772,32 @@
 
 -record(sm_failed, {reason :: atom() | #gone{} | #redirect{},
                     h :: non_neg_integer(),
-                    xmlns :: binary()}).
+                    xmlns = <<>> :: binary()}).
 -type sm_failed() :: #sm_failed{}.
 
 -record(error, {type :: 'auth' | 'cancel' | 'continue' | 'modify' | 'wait',
                 code :: non_neg_integer(),
-                by :: binary(),
+                by = <<>> :: binary(),
                 reason :: atom() | #gone{} | #redirect{},
                 text :: #text{},
-                sub_els = [] :: [any()]}).
+                sub_els = [] :: [xmpp_element() | fxml:xmlel()]}).
 -type error() :: #error{}.
 
--record(mix_join, {jid :: any(),
+-record(mix_join, {jid :: jid:jid(),
                    subscribe = [] :: [binary()]}).
 -type mix_join() :: #mix_join{}.
 
 -record(privacy_item, {order :: non_neg_integer(),
                        action :: 'allow' | 'deny',
                        type :: 'group' | 'jid' | 'subscription',
-                       value :: binary(),
+                       value = <<>> :: binary(),
                        message = false :: boolean(),
                        iq = false :: boolean(),
                        presence_in = false :: boolean(),
                        presence_out = false :: boolean()}).
 -type privacy_item() :: #privacy_item{}.
 
--record(privacy_list, {name :: binary(),
+-record(privacy_list, {name = <<>> :: binary(),
                        items = [] :: [#privacy_item{}]}).
 -type privacy_list() :: #privacy_list{}.
 
@@ -811,7 +811,7 @@
 -type stream_error() :: #stream_error{}.
 
 -record(vcard_logo, {type :: binary(),
-                     binval :: any(),
+                     binval :: binary(),
                      extval :: binary()}).
 -type vcard_logo() :: #vcard_logo{}.
 
@@ -846,8 +846,8 @@
                      desc :: binary()}).
 -type vcard_temp() :: #vcard_temp{}.
 
--record(time, {tzo :: any(),
-               utc :: any()}).
+-record(time, {tzo :: {integer(),integer()},
+               utc :: erlang:timestamp()}).
 -type time() :: #time{}.
 
 -type xmpp_element() :: muc_admin() |
diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl
index 1ae9a7c29..b13e7fe00 100644
--- a/src/ejabberd_c2s.erl
+++ b/src/ejabberd_c2s.erl
@@ -519,10 +519,10 @@ wait_for_auth(Pkt, StateData) when ?IS_STREAM_MGMT_PACKET(Pkt) ->
 wait_for_auth(#iq{type = get,
 		  sub_els = [#legacy_auth{username = U}]} = IQ, StateData) ->
     Username = case U of
-		   undefined -> none;
+		   undefined -> <<"">>;
 		   _ -> U
 	       end,
-    Auth = #legacy_auth{username = Username, password = none, resource = none},
+    Auth = #legacy_auth{username = Username, password = <<>>, resource = <<>>},
     Res = case ejabberd_auth:plain_password_required(StateData#state.server) of
 	      false ->
 		  xmpp:make_iq_result(IQ, Auth#legacy_auth{digest = none});
diff --git a/src/mod_adhoc.erl b/src/mod_adhoc.erl
index 9c8238900..22bde2586 100644
--- a/src/mod_adhoc.erl
+++ b/src/mod_adhoc.erl
@@ -91,7 +91,7 @@ stop(Host) ->
 %-------------------------------------------------------------------------
 
 get_local_commands(Acc, _From,
-		   #jid{server = Server, lserver = LServer} = _To, undefined,
+		   #jid{server = Server, lserver = LServer} = _To, <<"">>,
 		   Lang) ->
     Display = gen_mod:get_module_opt(LServer, ?MODULE,
 				     report_commands_node,
@@ -122,7 +122,7 @@ get_local_commands(Acc, _From, _To, _Node, _Lang) ->
 %-------------------------------------------------------------------------
 
 get_sm_commands(Acc, _From,
-		#jid{lserver = LServer} = To, undefined, Lang) ->
+		#jid{lserver = LServer} = To, <<"">>, Lang) ->
     Display = gen_mod:get_module_opt(LServer, ?MODULE,
 				     report_commands_node,
                                      fun(B) when is_boolean(B) -> B end,
diff --git a/src/mod_announce.erl b/src/mod_announce.erl
index 4b7498447..1a42a460b 100644
--- a/src/mod_announce.erl
+++ b/src/mod_announce.erl
@@ -56,7 +56,6 @@
 -define(NS_ADMINL(Sub), [<<"http:">>, <<"jabber.org">>, <<"protocol">>,
                          <<"admin">>, <>]).
 
-tokenize(undefined) -> [];
 tokenize(Node) -> str:tokens(Node, <<"/#">>).
 
 start(Host, Opts) ->
@@ -280,7 +279,7 @@ disco_features(Acc, From, #jid{lserver = LServer} = _To, Node, Lang) ->
 		{result, Items}
 	end).
 
-disco_items(Acc, From, #jid{lserver = LServer, server = Server} = _To, undefined, Lang) ->
+disco_items(Acc, From, #jid{lserver = LServer, server = Server} = _To, <<"">>, Lang) ->
     case gen_mod:is_loaded(LServer, mod_adhoc) of
 	false ->
 	    Acc;
diff --git a/src/mod_blocking.erl b/src/mod_blocking.erl
index 743b78efd..bc3080871 100644
--- a/src/mod_blocking.erl
+++ b/src/mod_blocking.erl
@@ -135,7 +135,7 @@ list_to_blocklist_jids([_ | Items], JIDs) ->
     list_to_blocklist_jids(Items, JIDs).
 
 -spec process_blocklist_block(binary(), binary(), [ljid()],
-			      undefined | binary()) ->
+			      binary()) ->
 				     {error, error()} |
 				     {result, undefined, userlist()}.
 process_blocklist_block(LUser, LServer, JIDs, Lang) ->
@@ -170,7 +170,7 @@ process_blocklist_block(LUser, LServer, JIDs, Lang) ->
 	    {error, xmpp:err_internal_server_error(<<"Database failure">>, Lang)}
     end.
 
--spec process_blocklist_unblock_all(binary(), binary(), undefined | binary()) ->
+-spec process_blocklist_unblock_all(binary(), binary(), binary()) ->
 					   {error, error()} |
 					   {result, undefined} |
 					   {result, undefined, userlist()}.
@@ -194,8 +194,7 @@ process_blocklist_unblock_all(LUser, LServer, Lang) ->
 	    {error, xmpp:err_internal_server_error(<<"Database failure">>, Lang)}
     end.
 
--spec process_blocklist_unblock(binary(), binary(), [ljid()],
-				undefined | binary()) ->
+-spec process_blocklist_unblock(binary(), binary(), [ljid()], binary()) ->
 				       {error, error()} |
 				       {result, undefined} |
 				       {result, undefined, userlist()}.
@@ -243,7 +242,7 @@ broadcast_blocklist_event(LUser, LServer, Event) ->
     ejabberd_sm:route(JID, JID,
                       {broadcast, {blocking, Event}}).
 
--spec process_blocklist_get(binary(), binary(), undefined | binary()) ->
+-spec process_blocklist_get(binary(), binary(), binary()) ->
 				   {error, error()} | {result, block_list()}.
 process_blocklist_get(LUser, LServer, Lang) ->
     Mod = db_mod(LServer),
diff --git a/src/mod_caps.erl b/src/mod_caps.erl
index 7c7ebf7b3..d5033ffd8 100644
--- a/src/mod_caps.erl
+++ b/src/mod_caps.erl
@@ -35,8 +35,6 @@
 
 -behaviour(gen_mod).
 
--compile(export_all).
-
 -export([read_caps/1, caps_stream_features/2,
 	 disco_features/5, disco_identity/5, disco_info/5,
 	 get_features/2, export/1, import_info/0, import/5,
@@ -162,38 +160,38 @@ caps_stream_features(Acc, MyHost) ->
 
 -spec disco_features({error, error()} | {result, [binary()]} | empty,
 		     jid(), jid(),
-		     undefined | binary(), undefined | binary()) ->
+		     binary(), binary()) ->
 			    {error, error()} | {result, [binary()]}.
 disco_features(Acc, From, To, Node, Lang) ->
     case is_valid_node(Node) of
         true ->
             ejabberd_hooks:run_fold(disco_local_features,
                                     To#jid.lserver, empty,
-                                    [From, To, undefined, Lang]);
+                                    [From, To, <<"">>, Lang]);
         false ->
             Acc
     end.
 
 -spec disco_identity([identity()], jid(), jid(),
-		     undefined | binary(), undefined | binary()) ->
+		     binary(), binary()) ->
 			    [identity()].
 disco_identity(Acc, From, To, Node, Lang) ->
     case is_valid_node(Node) of
         true ->
             ejabberd_hooks:run_fold(disco_local_identity,
                                     To#jid.lserver, [],
-                                    [From, To, undefined, Lang]);
+                                    [From, To, <<"">>, Lang]);
         false ->
             Acc
     end.
 
 -spec disco_info([xdata()], binary(), module(),
-		 undefined | binary(), undefined | binary()) ->	[xdata()].
+		 binary(), binary()) -> [xdata()].
 disco_info(Acc, Host, Module, Node, Lang) ->
     case is_valid_node(Node) of
         true ->
             ejabberd_hooks:run_fold(disco_info, Host, [],
-                                    [Host, Module, undefined, Lang]);
+                                    [Host, Module, <<"">>, Lang]);
         false ->
             Acc
     end.
@@ -485,7 +483,7 @@ concat_info(#disco_info{xdata = Xs}) ->
       [concat_xdata_fields(Fs) || #xdata{type = result, fields = Fs} <- Xs]).
 
 concat_xdata_fields(Fields) ->
-    Form = case lists:keysearch(<<"FORM_TYPE">>, #xdata_field.var, Fields) of
+    Form = case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var, Fields) of
 	       #xdata_field{values = Values} -> Values;
 	       false -> []
 	   end,
@@ -509,9 +507,7 @@ gb_trees_fold_iter(F, Acc, Iter) ->
 now_ts() ->
     p1_time_compat:system_time(seconds).
 
--spec is_valid_node(undefined | binary()) -> boolean().
-is_valid_node(undefined) ->
-    false;
+-spec is_valid_node(binary()) -> boolean().
 is_valid_node(Node) ->
     case str:tokens(Node, <<"#">>) of
         [?EJABBERD_URI|_] ->
diff --git a/src/mod_configure.erl b/src/mod_configure.erl
index 342a15232..07a1c7333 100644
--- a/src/mod_configure.erl
+++ b/src/mod_configure.erl
@@ -121,7 +121,6 @@ depends(_Host, _Opts) ->
 	[<<"http:">>, <<"jabber.org">>, <<"protocol">>,
 	 <<"admin">>, Sub]).
 
-tokenize(undefined) -> [];
 tokenize(Node) -> str:tokens(Node, <<"/#">>).
 
 get_sm_identity(Acc, _From, _To, Node, Lang) ->
@@ -300,7 +299,7 @@ get_sm_items(Acc, From,
 		    empty -> []
 		  end,
 	  case {acl:match_rule(LServer, configure, From), Node} of
-	    {allow, undefined} ->
+	    {allow, <<"">>} ->
 		Nodes = [?NODEJID(To, <<"Configuration">>,
 				  <<"config">>),
 			 ?NODEJID(To, <<"User Management">>, <<"user">>)],
@@ -399,7 +398,7 @@ get_permission_level(JID) ->
 	end).
 
 get_local_items(Acc, From, #jid{lserver = LServer} = To,
-		undefined, Lang) ->
+		<<"">>, Lang) ->
     case gen_mod:is_loaded(LServer, mod_adhoc) of
       false -> Acc;
       _ ->
diff --git a/src/mod_disco.erl b/src/mod_disco.erl
index 0d3f242a0..e78b8f72f 100644
--- a/src/mod_disco.erl
+++ b/src/mod_disco.erl
@@ -190,9 +190,8 @@ process_local_iq_info(#iq{type = get, lang = Lang,
     end.
 
 -spec get_local_identity([identity()], jid(), jid(),
-			 undefined | binary(), undefined | binary()) ->
-				[identity()].
-get_local_identity(Acc, _From, _To, undefined, _Lang) ->
+			 binary(), binary()) ->	[identity()].
+get_local_identity(Acc, _From, _To, <<"">>, _Lang) ->
     Acc ++ [#identity{category = <<"server">>,
 		      type = <<"im">>,
 		      name = <<"ejabberd">>}];
@@ -200,13 +199,12 @@ get_local_identity(Acc, _From, _To, _Node, _Lang) ->
     Acc.
 
 -spec get_local_features({error, error()} | {result, [binary()]} | empty,
-			 jid(), jid(),
-			 undefined | binary(), undefined | binary()) ->
+			 jid(), jid(), binary(), binary()) ->
 				{error, error()} | {result, [binary()]}.
 get_local_features({error, _Error} = Acc, _From, _To,
 		   _Node, _Lang) ->
     Acc;
-get_local_features(Acc, _From, To, undefined, _Lang) ->
+get_local_features(Acc, _From, To, <<"">>, _Lang) ->
     Feats = case Acc of
 		{result, Features} -> Features;
 		empty -> []
@@ -226,12 +224,12 @@ get_local_features(Acc, _From, _To, _Node, Lang) ->
 
 -spec get_local_services({error, error()} | {result, [disco_item()]} | empty,
 			 jid(), jid(),
-			 undefined | binary(), undefined | binary()) ->
+			 binary(), binary()) ->
 				{error, error()} | {result, [disco_item()]}.
 get_local_services({error, _Error} = Acc, _From, _To,
 		   _Node, _Lang) ->
     Acc;
-get_local_services(Acc, _From, To, undefined, _Lang) ->
+get_local_services(Acc, _From, To, <<"">>, _Lang) ->
     Items = case Acc of
 	      {result, Its} -> Its;
 	      empty -> []
@@ -300,13 +298,13 @@ process_sm_iq_items(#iq{type = get, lang = Lang,
 
 -spec get_sm_items({error, error()} | {result, [disco_item()]} | empty,
 		   jid(), jid(),
-		   undefined | binary(), undefined | binary()) ->
+		   binary(), binary()) ->
 			  {error, error()} | {result, [disco_item()]}.
 get_sm_items({error, _Error} = Acc, _From, _To, _Node,
 	     _Lang) ->
     Acc;
 get_sm_items(Acc, From,
-	     #jid{user = User, server = Server} = To, undefined, _Lang) ->
+	     #jid{user = User, server = Server} = To, <<"">>, _Lang) ->
     Items = case Acc of
 	      {result, Its} -> Its;
 	      empty -> []
@@ -375,8 +373,7 @@ process_sm_iq_info(#iq{type = get, lang = Lang,
     end.
 
 -spec get_sm_identity([identity()], jid(), jid(),
-		      undefined | binary(), undefined | binary()) ->
-			     [identity()].
+		      binary(), binary()) -> [identity()].
 get_sm_identity(Acc, _From,
 		#jid{luser = LUser, lserver = LServer}, _Node, _Lang) ->
     Acc ++
@@ -387,8 +384,7 @@ get_sm_identity(Acc, _From,
       end.
 
 -spec get_sm_features({error, error()} | {result, [binary()]} | empty,
-		      jid(), jid(),
-		      undefined | binary(), undefined | binary()) ->
+		      jid(), jid(), binary(), binary()) ->
 			     {error, error()} | {result, [binary()]}.
 get_sm_features(empty, From, To, _Node, Lang) ->
     #jid{luser = LFrom, lserver = LSFrom} = From,
@@ -428,10 +424,8 @@ transform_module_options(Opts) ->
 
 %%% Support for: XEP-0157 Contact Addresses for XMPP Services
 
--spec get_info([xdata()], binary(), module(),
-	       undefined | binary(), undefined | binary()) ->
-		      [xdata()].
-get_info(_A, Host, Mod, Node, _Lang) when Node == undefined ->
+-spec get_info([xdata()], binary(), module(), binary(), binary()) -> [xdata()].
+get_info(_A, Host, Mod, Node, _Lang) when Node == <<"">> ->
     Module = case Mod of
 	       undefined -> ?MODULE;
 	       _ -> Mod
diff --git a/src/mod_irc.erl b/src/mod_irc.erl
index 1960c988d..3c094ef9c 100644
--- a/src/mod_irc.erl
+++ b/src/mod_irc.erl
@@ -257,7 +257,7 @@ process_disco_items(#iq{type = set, lang = Lang} = IQ) ->
 process_disco_items(#iq{type = get, lang = Lang, to = To,
 			sub_els = [#disco_items{node = Node}]} = IQ) ->
     case Node of
-	undefined ->
+	<<"">> ->
 	    xmpp:make_iq_result(IQ, #disco_items{});
 	<<"join">> ->
 	    xmpp:make_iq_result(IQ, #disco_items{});
@@ -401,7 +401,7 @@ sm_route(Host, ServerHost, From, To, Packet) ->
 closed_connection(Host, From, Server) ->
     ets:delete(irc_connection, {From, Server, Host}).
 
-iq_disco(_ServerHost, undefined, Lang) ->
+iq_disco(_ServerHost, <<"">>, Lang) ->
     #disco_info{
        identities = [#identity{category = <<"conference">>,
 			       type = <<"irc">>,
diff --git a/src/mod_mam.erl b/src/mod_mam.erl
index 0aaf484c5..b83c423c7 100644
--- a/src/mod_mam.erl
+++ b/src/mod_mam.erl
@@ -363,7 +363,7 @@ disco_sm_features(empty, From, To, Node, Lang) ->
     disco_sm_features({result, []}, From, To, Node, Lang);
 disco_sm_features({result, OtherFeatures},
 		  #jid{luser = U, lserver = S},
-		  #jid{luser = U, lserver = S}, undefined, _Lang) ->
+		  #jid{luser = U, lserver = S}, <<"">>, _Lang) ->
     {result, [?NS_MAM_TMP, ?NS_MAM_0, ?NS_MAM_1 | OtherFeatures]};
 disco_sm_features(Acc, _From, _To, _Node, _Lang) ->
     Acc.
diff --git a/src/mod_muc.erl b/src/mod_muc.erl
index 294456ee2..3eca79fec 100644
--- a/src/mod_muc.erl
+++ b/src/mod_muc.erl
@@ -450,10 +450,10 @@ process_disco_info(#iq{type = set, lang = Lang} = IQ) ->
     Txt = <<"Value 'set' of 'type' attribute is not allowed">>,
     xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang));
 process_disco_info(#iq{type = get, to = To, lang = Lang,
-		       sub_els = [#disco_info{node = undefined}]} = IQ) ->
+		       sub_els = [#disco_info{node = <<"">>}]} = IQ) ->
     ServerHost = ejabberd_router:host_of_route(To#jid.lserver),
     X = ejabberd_hooks:run_fold(disco_info, ServerHost, [],
-				[ServerHost, ?MODULE, undefined, Lang]),
+				[ServerHost, ?MODULE, <<"">>, Lang]),
     MAMFeatures = case gen_mod:is_loaded(ServerHost, mod_mam) of
 		      true -> [?NS_MAM_TMP, ?NS_MAM_0, ?NS_MAM_1];
 		      false -> []
@@ -562,7 +562,7 @@ register_room(Host, Room, Pid) ->
     end,
     mnesia:transaction(F).
 
-iq_disco_items(Host, From, Lang, undefined, undefined) ->
+iq_disco_items(Host, From, Lang, <<"">>, undefined) ->
     Rooms = get_vh_rooms(Host),
     case erlang:length(Rooms) < ?MAX_ROOMS_DISCOITEMS of
 	true ->
diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl
index 68064fcb7..5814ca832 100644
--- a/src/mod_muc_room.erl
+++ b/src/mod_muc_room.erl
@@ -277,7 +277,7 @@ normal_state({route, From, <<"">>,
 			       process_iq_admin(From, IQ, StateData);
 			   ?NS_MUC_OWNER ->
 			       process_iq_owner(From, IQ, StateData);
-			   ?NS_DISCO_INFO when SubEl#disco_info.node == undefined ->
+			   ?NS_DISCO_INFO when SubEl#disco_info.node == <<>> ->
 			       process_iq_disco_info(From, IQ, StateData);
 			   ?NS_DISCO_INFO ->
 			       Txt = <<"Disco info is not available for this node">>,
@@ -2146,11 +2146,7 @@ send_new_presence1(NJID, Reason, IsInitialPresence, StateData, OldStateData) ->
 			  true -> Item0#muc_item{jid = RealJID};
 			  false -> Item0
 		      end,
-	      Item = if is_binary(Reason), Reason /= <<"">> ->
-			     Item1#muc_item{reason = Reason};
-			true ->
-			     Item1
-		     end,
+	      Item = Item1#muc_item{reason = Reason},
 	      StatusCodes = status_codes(IsInitialPresence, NJID, Info,
 					 StateData),
 	      Pres = if Presence == undefined -> #presence{};
@@ -2526,11 +2522,7 @@ items_with_affiliation(SAffiliation, StateData) ->
     lists:map(
       fun({JID, {Affiliation, Reason}}) ->
 	      #muc_item{affiliation = Affiliation, jid = JID,
-			reason = if is_binary(Reason), Reason /= <<"">> ->
-					 Reason;
-				    true ->
-					 undefined
-				 end};
+			reason = Reason};
 	 ({JID, Affiliation}) ->
 	      #muc_item{affiliation = Affiliation, jid = JID}
       end,
@@ -2563,7 +2555,7 @@ search_affiliation(Affiliation, StateData) ->
 		 end,
 		 (?DICT):to_list(StateData#state.affiliations)).
 
--spec process_admin_items_set(jid(), [muc_item()], binary() | undefined,
+-spec process_admin_items_set(jid(), [muc_item()], binary(),
 			      #state{}) -> {result, undefined, #state{}} |
 					   {error, error()}.
 process_admin_items_set(UJID, Items, Lang, StateData) ->
@@ -2666,13 +2658,13 @@ find_changed_items(_UJID, _UAffiliation, _URole,
     Txt = <<"Neither 'role' nor 'affiliation' attribute found">>,
     throw({error, xmpp:err_bad_request(Txt, Lang)});
 find_changed_items(UJID, UAffiliation, URole,
-		   [#muc_item{jid = J, nick = Nick, reason = Reason0,
+		   [#muc_item{jid = J, nick = Nick, reason = Reason,
 			      role = Role, affiliation = Affiliation}|Items],
 		   Lang, StateData, Res) ->
     [JID | _] = JIDs = 
 	if J /= undefined ->
 		[J];
-	   Nick /= undefined ->
+	   Nick /= <<"">> ->
 		case find_jids_by_nick(Nick, StateData) of
 		    [] ->
 			ErrText = iolist_to_binary(
@@ -2717,9 +2709,6 @@ find_changed_items(UJID, UAffiliation, URole,
 			       Items, Lang, StateData,
 			       Res);
 	true ->
-	    Reason = if is_binary(Reason0) -> Reason0;
-			true -> <<"">>
-		     end,
 	    MoreRes = [{jid:remove_resource(Jidx),
 			RoleOrAff, RoleOrAffValue, Reason}
 		       || Jidx <- JIDs],
@@ -2914,11 +2903,7 @@ send_kickban_presence1(MJID, UJID, Reason, Code, Affiliation,
 			  true -> Item0#muc_item{jid = RealJID};
 			  false -> Item0
 		      end,
-	      Item2 = if is_binary(Reason), Reason /= <<"">> ->
-			      Item1#muc_item{reason = Reason};
-			 true ->
-			      Item1
-		      end,
+	      Item2 = Item1#muc_item{reason = Reason},
 	      Item = case ActorNick of
 			 <<"">> -> Item2;
 			 _ -> Item2#muc_item{actor = #muc_actor{nick = ActorNick}}
diff --git a/src/mod_offline.erl b/src/mod_offline.erl
index 66edb6a7c..4d597a52c 100644
--- a/src/mod_offline.erl
+++ b/src/mod_offline.erl
@@ -250,7 +250,7 @@ receive_all(US, Msgs, DBType) ->
 		end
     end.
 
-get_sm_features(Acc, _From, _To, undefined, _Lang) ->
+get_sm_features(Acc, _From, _To, <<"">>, _Lang) ->
     Feats = case Acc of
 		{result, I} -> I;
 		_ -> []
@@ -297,8 +297,7 @@ get_sm_items(_Acc, #jid{luser = U, lserver = S, lresource = R} = JID,
 get_sm_items(Acc, _From, _To, _Node, _Lang) ->
     Acc.
 
--spec get_info([xdata()], jid(), jid(),
-	       undefined | binary(), undefined | binary()) -> [xdata()].
+-spec get_info([xdata()], jid(), jid(), binary(), binary()) -> [xdata()].
 get_info(_Acc, #jid{luser = U, lserver = S, lresource = R},
 	 #jid{luser = U, lserver = S}, ?NS_FLEX_OFFLINE, _Lang) ->
     N = jlib:integer_to_binary(count_offline_messages(U, S)),
diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl
index da947ace1..1da040d43 100644
--- a/src/mod_privacy.erl
+++ b/src/mod_privacy.erl
@@ -116,7 +116,7 @@ process_iq_get(_, #iq{from = From, lang = Lang,
 	    {error, xmpp:err_bad_request(Txt, Lang)}
     end.
 
--spec process_lists_get(binary(), binary(), binary(), undefined | binary()) ->
+-spec process_lists_get(binary(), binary(), binary(), binary()) ->
 			       {error, error()} | {result, privacy_query()}.
 process_lists_get(LUser, LServer, Active, Lang) ->
     Mod = gen_mod:db_mod(LServer, ?MODULE),
@@ -134,7 +134,7 @@ process_lists_get(LUser, LServer, Active, Lang) ->
 				     || ListName <- ListNames]}}
     end.
 
--spec process_list_get(binary(), binary(), binary(), undefined | binary()) ->
+-spec process_list_get(binary(), binary(), binary(), binary()) ->
 			      {error, error()} | {result, privacy_query()}.
 process_list_get(LUser, LServer, Name, Lang) ->
     Mod = gen_mod:db_mod(LServer, ?MODULE),
@@ -183,7 +183,7 @@ encode_list_item(#listitem{action = Action,
 			      presence_out = MatchPresenceOut}
     end.
 
--spec encode_value(listitem_type(), listitem_value()) -> undefined | binary().
+-spec encode_value(listitem_type(), listitem_value()) -> binary().
 encode_value(Type, Val) ->
     case Type of
 	jid -> jid:to_string(Val);
@@ -195,7 +195,7 @@ encode_value(Type, Val) ->
 		from -> <<"from">>;
 		none -> <<"none">>
 	    end;
-	none -> undefined
+	none -> <<"">>
     end.
 
 -spec decode_value(jid | subscription | group | undefined, binary()) ->
@@ -239,8 +239,7 @@ process_iq_set(_, #iq{from = From, lang = Lang,
     end.
 
 -spec process_default_set(binary(), binary(), none | binary(),
-			  undefined | binary()) -> {error, error()} |
-						   {result, undefined}.			 
+			  binary()) -> {error, error()} | {result, undefined}.
 process_default_set(LUser, LServer, Value, Lang) ->
     Mod = gen_mod:db_mod(LServer, ?MODULE),
     case Mod:process_default_set(LUser, LServer, Value) of
@@ -258,8 +257,7 @@ process_default_set(LUser, LServer, Value, Lang) ->
 	    {error, xmpp:err_internal_server_error()}
     end.
 
--spec process_active_set(binary(), binary(), none | binary(),
-			 undefined | binary()) ->
+-spec process_active_set(binary(), binary(), none | binary(), binary()) ->
 				{error, error()} |
 				{result, undefined, userlist()}.
 process_active_set(_LUser, _LServer, none, _Lang) ->
@@ -282,8 +280,7 @@ set_privacy_list(#privacy{us = {_, LServer}} = Privacy) ->
     Mod:set_privacy_list(Privacy).
 
 -spec process_lists_set(binary(), binary(), binary(), [privacy_item()],
-			undefined | binary()) -> {error, error()} |
-						 {result, undefined}.
+			binary()) -> {error, error()} | {result, undefined}.
 process_lists_set(LUser, LServer, Name, [], Lang) ->
     Mod = gen_mod:db_mod(LServer, ?MODULE),
     case Mod:remove_privacy_list(LUser, LServer, Name) of
diff --git a/src/mod_proxy65_service.erl b/src/mod_proxy65_service.erl
index e90ff21bd..789771d7d 100644
--- a/src/mod_proxy65_service.erl
+++ b/src/mod_proxy65_service.erl
@@ -156,11 +156,6 @@ process_bytestreams(#iq{type = get, from = JID, to = To, lang = Lang} = IQ) ->
 	deny ->
 	    xmpp:make_error(IQ, xmpp:err_forbidden(<<"Denied by ACL">>, Lang))
     end;
-process_bytestreams(#iq{type = set, lang = Lang,
-			sub_els = [#bytestreams{sid = undefined}]} = IQ) ->
-    Why = {missing_attr, <<"sid">>, <<"query">>, ?NS_BYTESTREAMS},
-    Txt = xmpp:format_error(Why),
-    xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang));
 process_bytestreams(#iq{type = set, lang = Lang,
 			sub_els = [#bytestreams{sid = SID}]} = IQ)
   when SID == <<"">> orelse length(SID) > 128 ->
diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl
index 231c42dc0..4653d6e2c 100644
--- a/src/mod_vcard.erl
+++ b/src/mod_vcard.erl
@@ -151,15 +151,14 @@ do_route(_, _, _) ->
     ok.
 
 -spec get_sm_features({error, error()} | empty | {result, [binary()]},
-		      jid(), jid(),
-		      undefined | binary(), undefined | binary()) ->
+		      jid(), jid(), binary(), binary()) ->
 			     {error, error()} | empty | {result, [binary()]}.
 get_sm_features({error, _Error} = Acc, _From, _To,
 		_Node, _Lang) ->
     Acc;
 get_sm_features(Acc, _From, _To, Node, _Lang) ->
     case Node of
-      undefined ->
+      <<"">> ->
 	  case Acc of
 	    {result, Features} ->
 		{result, [?NS_DISCO_INFO, ?NS_VCARD | Features]};
@@ -232,10 +231,9 @@ process_search(#iq{type = set, lang = Lang} = IQ) ->
     xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)).
 
 -spec disco_items({error, error()} | {result, [disco_item()]} | empty,
-		  jid(), jid(),
-		  undefined | binary(), undefined | binary()) ->
+		  jid(), jid(), binary(), binary()) ->
 			 {error, error()} | {result, [disco_item()]}.
-disco_items(empty, _From, _To, undefined, _Lang) ->
+disco_items(empty, _From, _To, <<"">>, _Lang) ->
     {result, []};
 disco_items(empty, _From, _To, _Node, Lang) ->
     {error, xmpp:err_item_not_found(<<"No services available">>, Lang)};
@@ -243,12 +241,11 @@ disco_items(Acc, _From, _To, _Node, _Lang) ->
     Acc.
 
 -spec disco_features({error, error()} | {result, [binary()]} | empty,
-		     jid(), jid(),
-		     undefined | binary(), undefined | binary()) ->
+		     jid(), jid(), binary(), binary()) ->
 			    {error, error()} | {result, [binary()]}.
 disco_features({error, _Error} = Acc, _From, _To, _Node, _Lang) ->
     Acc;
-disco_features(Acc, _From, _To, undefined, _Lang) ->
+disco_features(Acc, _From, _To, <<"">>, _Lang) ->
     Features = case Acc of
 		   {result, Fs} -> Fs;
 		   empty -> []
@@ -261,9 +258,9 @@ disco_features(empty, _From, _To, _Node, Lang) ->
 disco_features(Acc, _From, _To, _Node, _Lang) ->
     Acc.
 
--spec disco_identity([identity()], jid(), jid(), undefined | binary(),
-		     undefined | binary()) -> [identity()].
-disco_identity(Acc, _From, _To, undefined, Lang) ->
+-spec disco_identity([identity()], jid(), jid(),
+		     binary(),  binary()) -> [identity()].
+disco_identity(Acc, _From, _To, <<"">>, Lang) ->
     [#identity{category = <<"directory">>,
 	       type = <<"user">>,
 	       name = translate:translate(Lang, <<"vCard User Search">>)}|Acc];
@@ -362,7 +359,7 @@ string2lower(String) ->
       error -> str:to_lower(String)
     end.
 
--spec mk_tfield(binary(), binary(), undefined | binary()) -> xdata_field().
+-spec mk_tfield(binary(), binary(), binary()) -> xdata_field().
 mk_tfield(Label, Var, Lang) ->
     #xdata_field{type = 'text-single',
 		 label = translate:translate(Lang, Label),
@@ -372,7 +369,7 @@ mk_tfield(Label, Var, Lang) ->
 mk_field(Var, Val) ->
     #xdata_field{var = Var, values = [Val]}.
 
--spec mk_search_form(jid(), binary(), undefined | binary()) -> search().
+-spec mk_search_form(jid(), binary(), binary()) -> search().
 mk_search_form(JID, ServerHost, Lang) ->
     Title = <<(translate:translate(Lang, <<"Search users in ">>))/binary,
 	      (jid:to_string(JID))/binary>>,
@@ -393,7 +390,7 @@ mk_search_form(JID, ServerHost, Lang) ->
 		  Lang, <<"You need an x:data capable client to search">>),
 	    xdata = X}.
 
--spec search_result(undefined | binary(), jid(), binary(), [xdata_field()]) -> xdata().
+-spec search_result(binary(), jid(), binary(), [xdata_field()]) -> xdata().
 search_result(Lang, JID, ServerHost, XFields) ->
     Mod = gen_mod:db_mod(ServerHost, ?MODULE),
     Reported = [mk_tfield(Label, Var, Lang) ||
diff --git a/src/translate.erl b/src/translate.erl
index c8a924585..e9f61ab8c 100644
--- a/src/translate.erl
+++ b/src/translate.erl
@@ -126,10 +126,8 @@ load_file_loop(Fd, Line, File, Lang) ->
             ok
     end.
 
--spec translate(binary() | undefined, binary()) -> binary().
+-spec translate(binary(), binary()) -> binary().
 
-translate(undefined, Msg) ->
-    translate(?MYLANG, Msg);
 translate(Lang, Msg) ->
     LLang = ascii_tolower(Lang),
     case ets:lookup(translations, {LLang, Msg}) of
diff --git a/src/xmpp.erl b/src/xmpp.erl
index b43243157..c81474f10 100644
--- a/src/xmpp.erl
+++ b/src/xmpp.erl
@@ -119,15 +119,11 @@ make_error(#xmlel{attrs = Attrs, children = Els} = El, Err) ->
     Attrs3 = lists:keystore(<<"type">>, 1, Attrs2, {<<"type">>, <<"error">>}),
     El#xmlel{attrs = Attrs3, children = Els ++ [encode(Err)]}.
 
--spec get_id(iq() | message() | presence() | xmlel()) -> undefined | binary().
+-spec get_id(iq() | message() | presence() | xmlel()) -> binary().
 get_id(#iq{id = ID}) -> ID;
 get_id(#message{id = ID}) -> ID;
 get_id(#presence{id = ID}) -> ID;
-get_id(#xmlel{attrs = Attrs}) ->
-    case fxml:get_attr(<<"id">>, Attrs) of
-	{value, ID} -> ID;
-	false -> undefined
-    end.
+get_id(#xmlel{attrs = Attrs}) -> fxml:get_attr_s(<<"id">>, Attrs).
 
 -spec get_type(iq()) -> iq_type();
 	      (message()) -> message_type();
@@ -138,15 +134,11 @@ get_type(#message{type = T}) -> T;
 get_type(#presence{type = T}) -> T;
 get_type(#xmlel{attrs = Attrs}) -> fxml:get_attr_s(<<"type">>, Attrs).
 
--spec get_lang(iq() | message() | presence()) -> undefined | binary().
+-spec get_lang(iq() | message() | presence()) -> binary().
 get_lang(#iq{lang = L}) -> L;
 get_lang(#message{lang = L}) -> L;
 get_lang(#presence{lang = L}) -> L;
-get_lang(#xmlel{attrs = Attrs}) ->
-    case fxml:get_attr(<<"xml:lang">>, Attrs) of
-	{value, L} -> L;
-	false -> undefined
-    end.
+get_lang(#xmlel{attrs = Attrs}) -> fxml:get_attr_s(<<"xml:lang">>, Attrs).
 
 -spec get_from(iq() | message() | presence()) -> undefined | jid:jid().
 get_from(#iq{from = J}) -> J;
@@ -371,14 +363,13 @@ has_subtag([], _, _) ->
 
 -spec get_text([text()]) -> binary().
 get_text([]) -> <<"">>;
-get_text([#text{data = undefined}|_]) -> <<"">>;
 get_text([#text{data = Data}|_]) -> Data.
 
 -spec mk_text(binary()) -> [text()].
 mk_text(Text) ->
-    mk_text(Text, undefined).
+    mk_text(Text, <<"">>).
 
--spec mk_text(binary(), binary() | undefined) -> [text()].
+-spec mk_text(binary(), binary()) -> [text()].
 mk_text(<<"">>, _) ->
     [];
 mk_text(Text, Lang) ->
@@ -396,7 +387,7 @@ pp(Term) ->
 err_bad_request() ->
     err(modify, 'bad-request', 400).
 
--spec err_bad_request(binary(), binary() | undefined) -> error().
+-spec err_bad_request(binary(), binary()) -> error().
 err_bad_request(Text, Lang) ->
     err(modify, 'bad-request', 400, Text, Lang).
 
@@ -404,7 +395,7 @@ err_bad_request(Text, Lang) ->
 err_conflict() ->
     err(cancel, 'conflict', 409).
 
--spec err_conflict(binary(), binary() | undefined) -> error().
+-spec err_conflict(binary(), binary()) -> error().
 err_conflict(Text, Lang) ->
     err(cancel, 'conflict', 409, Text, Lang).
 
@@ -412,7 +403,7 @@ err_conflict(Text, Lang) ->
 err_feature_not_implemented() ->
     err(cancel, 'feature-not-implemented', 501).
 
--spec err_feature_not_implemented(binary(), binary() | undefined) -> error().
+-spec err_feature_not_implemented(binary(), binary()) -> error().
 err_feature_not_implemented(Text, Lang) ->
     err(cancel, 'feature-not-implemented', 501, Text, Lang).
 
@@ -420,7 +411,7 @@ err_feature_not_implemented(Text, Lang) ->
 err_forbidden() ->
     err(auth, 'forbidden', 403).
 
--spec err_forbidden(binary(), binary() | undefined) -> error().
+-spec err_forbidden(binary(), binary()) -> error().
 err_forbidden(Text, Lang) ->
     err(auth, 'forbidden', 403, Text, Lang).
 
@@ -430,7 +421,7 @@ err_forbidden(Text, Lang) ->
 err_gone() ->
     err(modify, 'gone', 302).
 
--spec err_gone(binary(), binary() | undefined) -> error().
+-spec err_gone(binary(), binary()) -> error().
 err_gone(Text, Lang) ->
     err(modify, 'gone', 302, Text, Lang).
 
@@ -440,7 +431,7 @@ err_gone(Text, Lang) ->
 err_internal_server_error() ->
     err(wait, 'internal-server-error', 500).
 
--spec err_internal_server_error(binary(), binary() | undefined) -> error().
+-spec err_internal_server_error(binary(), binary()) -> error().
 err_internal_server_error(Text, Lang) ->
     err(wait, 'internal-server-error', 500, Text, Lang).
 
@@ -448,7 +439,7 @@ err_internal_server_error(Text, Lang) ->
 err_item_not_found() ->
     err(cancel, 'item-not-found', 404).
 
--spec err_item_not_found(binary(), binary() | undefined) -> error().
+-spec err_item_not_found(binary(), binary()) -> error().
 err_item_not_found(Text, Lang) ->
     err(cancel, 'item-not-found', 404, Text, Lang).
 
@@ -456,7 +447,7 @@ err_item_not_found(Text, Lang) ->
 err_jid_malformed() ->
     err(modify, 'jid-malformed', 400).
 
--spec err_jid_malformed(binary(), binary() | undefined) -> error().
+-spec err_jid_malformed(binary(), binary()) -> error().
 err_jid_malformed(Text, Lang) ->
     err(modify, 'jid-malformed', 400, Text, Lang).
 
@@ -464,7 +455,7 @@ err_jid_malformed(Text, Lang) ->
 err_not_acceptable() ->
     err(modify, 'not-acceptable', 406).
 
--spec err_not_acceptable(binary(), binary() | undefined) -> error().
+-spec err_not_acceptable(binary(), binary()) -> error().
 err_not_acceptable(Text, Lang) ->
     err(modify, 'not-acceptable', 406, Text, Lang).
 
@@ -472,7 +463,7 @@ err_not_acceptable(Text, Lang) ->
 err_not_allowed() ->
     err(cancel, 'not-allowed', 405).
 
--spec err_not_allowed(binary(), binary() | undefined) -> error().
+-spec err_not_allowed(binary(), binary()) -> error().
 err_not_allowed(Text, Lang) ->
     err(cancel, 'not-allowed', 405, Text, Lang).
 
@@ -480,7 +471,7 @@ err_not_allowed(Text, Lang) ->
 err_not_authorized() ->
     err(auth, 'not-authorized', 401).
 
--spec err_not_authorized(binary(), binary() | undefined) -> error().
+-spec err_not_authorized(binary(), binary()) -> error().
 err_not_authorized(Text, Lang) ->
     err(auth, 'not-authorized', 401, Text, Lang).
 
@@ -488,7 +479,7 @@ err_not_authorized(Text, Lang) ->
 err_payment_required() ->
     err(auth, 'not-authorized', 402).
 
--spec err_payment_required(binary(), binary() | undefined) -> error().
+-spec err_payment_required(binary(), binary()) -> error().
 err_payment_required(Text, Lang) ->
     err(auth, 'not-authorized', 402, Text, Lang).
 
@@ -498,7 +489,7 @@ err_payment_required(Text, Lang) ->
 err_policy_violation() ->
     err(modify, 'policy-violation', 403).
 
--spec err_policy_violation(binary(), binary() | undefined) -> error().
+-spec err_policy_violation(binary(), binary()) -> error().
 err_policy_violation(Text, Lang) ->
     err(modify, 'policy-violation', 403, Text, Lang).
 
@@ -506,7 +497,7 @@ err_policy_violation(Text, Lang) ->
 err_recipient_unavailable() ->
     err(wait, 'recipient-unavailable', 404).
 
--spec err_recipient_unavailable(binary(), binary() | undefined) -> error().
+-spec err_recipient_unavailable(binary(), binary()) -> error().
 err_recipient_unavailable(Text, Lang) ->
     err(wait, 'recipient-unavailable', 404, Text, Lang).
 
@@ -514,7 +505,7 @@ err_recipient_unavailable(Text, Lang) ->
 err_redirect() ->
     err(modify, 'redirect', 302).
 
--spec err_redirect(binary(), binary() | undefined) -> error().
+-spec err_redirect(binary(), binary()) -> error().
 err_redirect(Text, Lang) ->
     err(modify, 'redirect', 302, Text, Lang).
 
@@ -522,7 +513,7 @@ err_redirect(Text, Lang) ->
 err_registration_required() ->
     err(auth, 'registration-required', 407).
 
--spec err_registration_required(binary(), binary() | undefined) -> error().
+-spec err_registration_required(binary(), binary()) -> error().
 err_registration_required(Text, Lang) ->
     err(auth, 'registration-required', 407, Text, Lang).
 
@@ -530,7 +521,7 @@ err_registration_required(Text, Lang) ->
 err_remote_server_not_found() ->
     err(cancel, 'remote-server-not-found', 404).
 
--spec err_remote_server_not_found(binary(), binary() | undefined) -> error().
+-spec err_remote_server_not_found(binary(), binary()) -> error().
 err_remote_server_not_found(Text, Lang) ->
     err(cancel, 'remote-server-not-found', 404, Text, Lang).
 
@@ -538,7 +529,7 @@ err_remote_server_not_found(Text, Lang) ->
 err_remote_server_timeout() ->
     err(wait, 'remote-server-timeout', 504).
 
--spec err_remote_server_timeout(binary(), binary() | undefined) -> error().
+-spec err_remote_server_timeout(binary(), binary()) -> error().
 err_remote_server_timeout(Text, Lang) ->
     err(wait, 'remote-server-timeout', 504, Text, Lang).
 
@@ -546,7 +537,7 @@ err_remote_server_timeout(Text, Lang) ->
 err_resource_constraint() ->
     err(wait, 'resource-constraint', 500).
 
--spec err_resource_constraint(binary(), binary() | undefined) -> error().
+-spec err_resource_constraint(binary(), binary()) -> error().
 err_resource_constraint(Text, Lang) ->
     err(wait, 'resource-constraint', 500, Text, Lang).
 
@@ -554,7 +545,7 @@ err_resource_constraint(Text, Lang) ->
 err_service_unavailable() ->
     err(cancel, 'service-unavailable', 503).
 
--spec err_service_unavailable(binary(), binary() | undefined) -> error().
+-spec err_service_unavailable(binary(), binary()) -> error().
 err_service_unavailable(Text, Lang) ->
     err(cancel, 'service-unavailable', 503, Text, Lang).
 
@@ -562,7 +553,7 @@ err_service_unavailable(Text, Lang) ->
 err_subscription_required() ->
     err(auth, 'subscription-required', 407).
 
--spec err_subscription_required(binary(), binary() | undefined) -> error().
+-spec err_subscription_required(binary(), binary()) -> error().
 err_subscription_required(Text, Lang) ->
     err(auth, 'subscription-required', 407, Text, Lang).
 
@@ -574,7 +565,7 @@ err_undefined_condition(Type) ->
     err(Type, 'undefined-condition', 500).
 
 -spec err_undefined_condition('auth' | 'cancel' | 'continue' | 'modify' | 'wait',
-			      binary(), binary() | undefined) -> error().
+			      binary(), binary()) -> error().
 err_undefined_condition(Type, Text, Lang) ->
     err(Type, 'undefined-condition', 500, Text, Lang).
 
@@ -584,7 +575,7 @@ err_undefined_condition(Type, Text, Lang) ->
 err_unexpected_request() ->
     err(wait, 'unexpected-request', 400).
 
--spec err_unexpected_request(binary(), binary() | undefined) -> error().
+-spec err_unexpected_request(binary(), binary()) -> error().
 err_unexpected_request(Text, Lang) ->
     err(wait, 'unexpected-request', 400, Text, Lang).
 
@@ -595,7 +586,7 @@ err_unexpected_request(Text, Lang) ->
 serr_bad_format() ->
     serr('bad-format').
 
--spec serr_bad_format(binary(), binary() | undefined) -> stream_error().
+-spec serr_bad_format(binary(), binary()) -> stream_error().
 serr_bad_format(Text, Lang) ->
     serr('bad-format', Text, Lang).
 
@@ -603,7 +594,7 @@ serr_bad_format(Text, Lang) ->
 serr_bad_namespace_prefix() ->
     serr('bad-namespace-prefix').
 
--spec serr_bad_namespace_prefix(binary(), binary() | undefined) -> stream_error().
+-spec serr_bad_namespace_prefix(binary(), binary()) -> stream_error().
 serr_bad_namespace_prefix(Text, Lang) ->
     serr('bad-namespace-prefix', Text, Lang).
 
@@ -611,7 +602,7 @@ serr_bad_namespace_prefix(Text, Lang) ->
 serr_conflict() ->
     serr('conflict').
 
--spec serr_conflict(binary(), binary() | undefined) -> stream_error().
+-spec serr_conflict(binary(), binary()) -> stream_error().
 serr_conflict(Text, Lang) ->
     serr('conflict', Text, Lang).
 
@@ -619,7 +610,7 @@ serr_conflict(Text, Lang) ->
 serr_connection_timeout() ->
     serr('connection-timeout').
 
--spec serr_connection_timeout(binary(), binary() | undefined) -> stream_error().
+-spec serr_connection_timeout(binary(), binary()) -> stream_error().
 serr_connection_timeout(Text, Lang) ->
     serr('connection-timeout', Text, Lang).
 
@@ -627,7 +618,7 @@ serr_connection_timeout(Text, Lang) ->
 serr_host_gone() ->
     serr('host-gone').
 
--spec serr_host_gone(binary(), binary() | undefined) -> stream_error().
+-spec serr_host_gone(binary(), binary()) -> stream_error().
 serr_host_gone(Text, Lang) ->
     serr('host-gone', Text, Lang).
 
@@ -635,7 +626,7 @@ serr_host_gone(Text, Lang) ->
 serr_host_unknown() ->
     serr('host-unknown').
 
--spec serr_host_unknown(binary(), binary() | undefined) -> stream_error().
+-spec serr_host_unknown(binary(), binary()) -> stream_error().
 serr_host_unknown(Text, Lang) ->
     serr('host-unknown', Text, Lang).
 
@@ -643,7 +634,7 @@ serr_host_unknown(Text, Lang) ->
 serr_improper_addressing() ->
     serr('improper-addressing').
 
--spec serr_improper_addressing(binary(), binary() | undefined) -> stream_error().
+-spec serr_improper_addressing(binary(), binary()) -> stream_error().
 serr_improper_addressing(Text, Lang) ->
     serr('improper-addressing', Text, Lang).
 
@@ -651,7 +642,7 @@ serr_improper_addressing(Text, Lang) ->
 serr_internal_server_error() ->
     serr('internal-server-error').
 
--spec serr_internal_server_error(binary(), binary() | undefined) -> stream_error().
+-spec serr_internal_server_error(binary(), binary()) -> stream_error().
 serr_internal_server_error(Text, Lang) ->
     serr('internal-server-error', Text, Lang).
 
@@ -659,7 +650,7 @@ serr_internal_server_error(Text, Lang) ->
 serr_invalid_from() ->
     serr('invalid-from').
 
--spec serr_invalid_from(binary(), binary() | undefined) -> stream_error().
+-spec serr_invalid_from(binary(), binary()) -> stream_error().
 serr_invalid_from(Text, Lang) ->
     serr('invalid-from', Text, Lang).
 
@@ -667,7 +658,7 @@ serr_invalid_from(Text, Lang) ->
 serr_invalid_id() ->
     serr('invalid-id').
 
--spec serr_invalid_id(binary(), binary() | undefined) -> stream_error().
+-spec serr_invalid_id(binary(), binary()) -> stream_error().
 serr_invalid_id(Text, Lang) ->
     serr('invalid-id', Text, Lang).
 
@@ -675,7 +666,7 @@ serr_invalid_id(Text, Lang) ->
 serr_invalid_namespace() ->
     serr('invalid-namespace').
 
--spec serr_invalid_namespace(binary(), binary() | undefined) -> stream_error().
+-spec serr_invalid_namespace(binary(), binary()) -> stream_error().
 serr_invalid_namespace(Text, Lang) ->
     serr('invalid-namespace', Text, Lang).
 
@@ -683,7 +674,7 @@ serr_invalid_namespace(Text, Lang) ->
 serr_invalid_xml() ->
     serr('invalid-xml').
 
--spec serr_invalid_xml(binary(), binary() | undefined) -> stream_error().
+-spec serr_invalid_xml(binary(), binary()) -> stream_error().
 serr_invalid_xml(Text, Lang) ->
     serr('invalid-xml', Text, Lang).
 
@@ -691,7 +682,7 @@ serr_invalid_xml(Text, Lang) ->
 serr_not_authorized() ->
     serr('not-authorized').
 
--spec serr_not_authorized(binary(), binary() | undefined) -> stream_error().
+-spec serr_not_authorized(binary(), binary()) -> stream_error().
 serr_not_authorized(Text, Lang) ->
     serr('not-authorized', Text, Lang).
 
@@ -699,7 +690,7 @@ serr_not_authorized(Text, Lang) ->
 serr_not_well_formed() ->
     serr('not-well-formed').
 
--spec serr_not_well_formed(binary(), binary() | undefined) -> stream_error().
+-spec serr_not_well_formed(binary(), binary()) -> stream_error().
 serr_not_well_formed(Text, Lang) ->
     serr('not-well-formed', Text, Lang).
 
@@ -707,7 +698,7 @@ serr_not_well_formed(Text, Lang) ->
 serr_policy_violation() ->
     serr('policy-violation').
 
--spec serr_policy_violation(binary(), binary() | undefined) -> stream_error().
+-spec serr_policy_violation(binary(), binary()) -> stream_error().
 serr_policy_violation(Text, Lang) ->
     serr('policy-violation', Text, Lang).
 
@@ -715,7 +706,7 @@ serr_policy_violation(Text, Lang) ->
 serr_remote_connection_failed() ->
     serr('remote-connection-failed').
 
--spec serr_remote_connection_failed(binary(), binary() | undefined) -> stream_error().
+-spec serr_remote_connection_failed(binary(), binary()) -> stream_error().
 serr_remote_connection_failed(Text, Lang) ->
     serr('remote-connection-failed', Text, Lang).
 
@@ -723,7 +714,7 @@ serr_remote_connection_failed(Text, Lang) ->
 serr_reset() ->
     serr('reset').
 
--spec serr_reset(binary(), binary() | undefined) -> stream_error().
+-spec serr_reset(binary(), binary()) -> stream_error().
 serr_reset(Text, Lang) ->
     serr('reset', Text, Lang).
 
@@ -731,7 +722,7 @@ serr_reset(Text, Lang) ->
 serr_resource_constraint() ->
     serr('resource-constraint').
 
--spec serr_resource_constraint(binary(), binary() | undefined) -> stream_error().
+-spec serr_resource_constraint(binary(), binary()) -> stream_error().
 serr_resource_constraint(Text, Lang) ->
     serr('resource-constraint', Text, Lang).
 
@@ -739,7 +730,7 @@ serr_resource_constraint(Text, Lang) ->
 serr_restricted_xml() ->
     serr('restricted-xml').
 
--spec serr_restricted_xml(binary(), binary() | undefined) -> stream_error().
+-spec serr_restricted_xml(binary(), binary()) -> stream_error().
 serr_restricted_xml(Text, Lang) ->
     serr('restricted-xml', Text, Lang).
 
@@ -747,7 +738,7 @@ serr_restricted_xml(Text, Lang) ->
 serr_see_other_host() ->
     serr('see-other-host').
 
--spec serr_see_other_host(binary(), binary() | undefined) -> stream_error().
+-spec serr_see_other_host(binary(), binary()) -> stream_error().
 serr_see_other_host(Text, Lang) ->
     serr('see-other-host', Text, Lang).
 
@@ -755,7 +746,7 @@ serr_see_other_host(Text, Lang) ->
 serr_system_shutdown() ->
     serr('system-shutdown').
 
--spec serr_system_shutdown(binary(), binary() | undefined) -> stream_error().
+-spec serr_system_shutdown(binary(), binary()) -> stream_error().
 serr_system_shutdown(Text, Lang) ->
     serr('system-shutdown', Text, Lang).
 
@@ -763,7 +754,7 @@ serr_system_shutdown(Text, Lang) ->
 serr_undefined_condition() ->
     serr('undefined-condition').
 
--spec serr_undefined_condition(binary(), binary() | undefined) -> stream_error().
+-spec serr_undefined_condition(binary(), binary()) -> stream_error().
 serr_undefined_condition(Text, Lang) ->
     serr('undefined-condition', Text, Lang).
 
@@ -771,7 +762,7 @@ serr_undefined_condition(Text, Lang) ->
 serr_unsupported_encoding() ->
     serr('unsupported-encoding').
 
--spec serr_unsupported_encoding(binary(), binary() | undefined) -> stream_error().
+-spec serr_unsupported_encoding(binary(), binary()) -> stream_error().
 serr_unsupported_encoding(Text, Lang) ->
     serr('unsupported-encoding', Text, Lang).
 
@@ -779,7 +770,7 @@ serr_unsupported_encoding(Text, Lang) ->
 serr_unsupported_stanza_type() ->
     serr('unsupported-stanza-type').
 
--spec serr_unsupported_stanza_type(binary(), binary() | undefined) -> stream_error().
+-spec serr_unsupported_stanza_type(binary(), binary()) -> stream_error().
 serr_unsupported_stanza_type(Text, Lang) ->
     serr('unsupported-stanza-type', Text, Lang).
 
@@ -787,7 +778,7 @@ serr_unsupported_stanza_type(Text, Lang) ->
 serr_unsupported_version() ->
     serr('unsupported-version').
 
--spec serr_unsupported_version(binary(), binary() | undefined) -> stream_error().
+-spec serr_unsupported_version(binary(), binary()) -> stream_error().
 serr_unsupported_version(Text, Lang) ->
     serr('unsupported-version', Text, Lang).
 
@@ -801,7 +792,7 @@ err(Type, Reason, Code) ->
 
 -spec err('auth' | 'cancel' | 'continue' | 'modify' | 'wait',
 	  atom() | gone() | redirect(), non_neg_integer(),
-	  binary(), binary() | undefined) -> error().
+	  binary(), binary()) -> error().
 err(Type, Reason, Code, Text, Lang) ->
     #error{type = Type, reason = Reason, code = Code,
 	   text = #text{lang = Lang,
@@ -812,7 +803,7 @@ serr(Reason) ->
     #stream_error{reason = Reason}.
 
 -spec serr(atom() | 'see-other-host'(), binary(),
-	   binary() | undefined) -> stream_error().
+	   binary()) -> stream_error().
 serr(Reason, Text, Lang) ->
     #stream_error{reason = Reason,
 		  text = #text{lang = Lang,
diff --git a/src/xmpp_codec.erl b/src/xmpp_codec.erl
index e0a5d47c9..905e48f3c 100644
--- a/src/xmpp_codec.erl
+++ b/src/xmpp_codec.erl
@@ -2399,7 +2399,7 @@ encode({vcard_temp, _, _, _, _, _, _, _, _, _, _, _, _,
 	   Vcard) ->
     encode_vcard_temp(Vcard,
 		      [{<<"xmlns">>, <<"vcard-temp">>}]);
-encode({vcard_xupdate, undefined, _} = X) ->
+encode({vcard_xupdate, _, _} = X) ->
     encode_vcard_xupdate(X,
 			 [{<<"xmlns">>, <<"vcard-temp:x:update">>}]);
 encode({xdata_option, _, _} = Option) ->
@@ -2801,7 +2801,7 @@ get_name({vcard_temp, _, _, _, _, _, _, _, _, _, _, _,
 	  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
 	  _}) ->
     <<"vCard">>;
-get_name({vcard_xupdate, undefined, _}) -> <<"x">>;
+get_name({vcard_xupdate, _, _}) -> <<"x">>;
 get_name({xdata_option, _, _}) -> <<"option">>;
 get_name({xdata_field, _, _, _, _, _, _, _, _}) ->
     <<"field">>;
@@ -3033,7 +3033,7 @@ get_ns({vcard_key, _, _}) -> <<"vcard-temp">>;
 get_ns({vcard_temp, _, _, _, _, _, _, _, _, _, _, _, _,
 	_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _}) ->
     <<"vcard-temp">>;
-get_ns({vcard_xupdate, undefined, _}) ->
+get_ns({vcard_xupdate, _, _}) ->
     <<"vcard-temp:x:update">>;
 get_ns({xdata_option, _, _}) -> <<"jabber:x:data">>;
 get_ns({xdata_field, _, _, _, _, _, _, _, _}) ->
@@ -3331,7 +3331,6 @@ pp(vcard_temp, 29) ->
      email, jabberid, mailer, tz, geo, title, role, logo,
      org, categories, note, prodid, rev, sort_string, sound,
      uid, url, class, key, desc];
-pp(vcard_xupdate, 2) -> [us, hash];
 pp(xdata_option, 2) -> [label, value];
 pp(xdata_field, 8) ->
     [label, type, var, required, desc, values, options,
@@ -3355,7 +3354,6 @@ pp(pubsub, 8) ->
     [subscriptions, affiliations, publish, subscribe,
      unsubscribe, options, items, retract];
 pp(shim, 1) -> [headers];
-pp(chatstate, 1) -> [type];
 pp(delay, 3) -> [stamp, from, desc];
 pp(streamhost, 3) -> [jid, host, port];
 pp(bytestreams, 6) ->
@@ -3396,7 +3394,6 @@ pp(carbons_private, 0) -> [];
 pp(carbons_received, 1) -> [forwarded];
 pp(carbons_sent, 1) -> [forwarded];
 pp(feature_csi, 1) -> [xmlns];
-pp(csi, 1) -> [type];
 pp(feature_sm, 1) -> [xmlns];
 pp(sm_enable, 3) -> [max, resume, xmlns];
 pp(sm_enabled, 5) -> [id, location, max, resume, xmlns];
@@ -3410,7 +3407,6 @@ pp(offline, 3) -> [items, purge, fetch];
 pp(mix_join, 2) -> [jid, subscribe];
 pp(mix_leave, 0) -> [];
 pp(mix_participant, 2) -> [jid, nick];
-pp(hint, 1) -> [type];
 pp(search_item, 5) -> [jid, first, last, nick, email];
 pp(search, 7) ->
     [instructions, first, last, nick, email, items, xdata];
@@ -3445,6 +3441,27 @@ pp(upload_slot, 3) -> [get, put, xmlns];
 pp(thumbnail, 4) -> [uri, 'media-type', width, height];
 pp(_, _) -> no.
 
+enc_host_port(Host) when is_binary(Host) -> Host;
+enc_host_port({{_, _, _, _, _, _, _, _} = IPv6,
+	       Port}) ->
+    enc_host_port({<<$[, (enc_ip(IPv6))/binary, $]>>,
+		   Port});
+enc_host_port({{_, _, _, _} = IPv4, Port}) ->
+    enc_host_port({enc_ip(IPv4), Port});
+enc_host_port({Host, Port}) ->
+    <>;
+enc_host_port(Addr) -> enc_ip(Addr).
+
+dec_host_port(<<$[, T/binary>>) ->
+    [IP, <<$:, Port/binary>>] = binary:split(T, <<$]>>),
+    {dec_ip(IP), dec_int(Port, 0, 65535)};
+dec_host_port(S) ->
+    case binary:split(S, <<$:>>) of
+      [S] -> try dec_ip(S) catch _:_ -> S end;
+      [S, P] ->
+	  {try dec_ip(S) catch _:_ -> S end, dec_int(P, 0, 65535)}
+    end.
+
 enc_ip({0, 0, 0, 0, 0, 65535, A, B}) ->
     enc_ip({(A bsr 8) band 255, A band 255,
 	    (B bsr 8) band 255, B band 255});
@@ -3693,10 +3710,10 @@ encode_upload_slot({upload_slot, Get, Put, Xmlns},
     [encode_upload_get(Get, []) | _acc].
 
 decode_upload_slot_attr_xmlns(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_upload_slot_attr_xmlns(__TopXMLNS, _val) -> _val.
 
-encode_upload_slot_attr_xmlns(undefined, _acc) -> _acc;
+encode_upload_slot_attr_xmlns(<<>>, _acc) -> _acc;
 encode_upload_slot_attr_xmlns(_val, _acc) ->
     [{<<"xmlns">>, _val} | _acc].
 
@@ -3916,12 +3933,11 @@ encode_upload_request({upload_request, Filename, Size,
 
 decode_upload_request_attr_xmlns(__TopXMLNS,
 				 undefined) ->
-    undefined;
+    <<>>;
 decode_upload_request_attr_xmlns(__TopXMLNS, _val) ->
     _val.
 
-encode_upload_request_attr_xmlns(undefined, _acc) ->
-    _acc;
+encode_upload_request_attr_xmlns(<<>>, _acc) -> _acc;
 encode_upload_request_attr_xmlns(_val, _acc) ->
     [{<<"xmlns">>, _val} | _acc].
 
@@ -4094,11 +4110,10 @@ encode_sic({sic, Ip, Port, Xmlns}, _xmlns_attrs) ->
 'encode_sic_$port'(Port, _acc) ->
     [encode_sip_port(Port, []) | _acc].
 
-decode_sic_attr_xmlns(__TopXMLNS, undefined) ->
-    undefined;
+decode_sic_attr_xmlns(__TopXMLNS, undefined) -> <<>>;
 decode_sic_attr_xmlns(__TopXMLNS, _val) -> _val.
 
-encode_sic_attr_xmlns(undefined, _acc) -> _acc;
+encode_sic_attr_xmlns(<<>>, _acc) -> _acc;
 encode_sic_attr_xmlns(_val, _acc) ->
     [{<<"xmlns">>, _val} | _acc].
 
@@ -4571,10 +4586,10 @@ encode_bob_data_attr_cid(_val, _acc) ->
     [{<<"max-age">>, enc_int(_val)} | _acc].
 
 decode_bob_data_attr_type(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_bob_data_attr_type(__TopXMLNS, _val) -> _val.
 
-encode_bob_data_attr_type(undefined, _acc) -> _acc;
+encode_bob_data_attr_type(<<>>, _acc) -> _acc;
 encode_bob_data_attr_type(_val, _acc) ->
     [{<<"type">>, _val} | _acc].
 
@@ -4707,11 +4722,11 @@ encode_stream_start_attr_to(_val, _acc) ->
     [{<<"to">>, enc_jid(_val)} | _acc].
 
 decode_stream_start_attr_xmlns(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_stream_start_attr_xmlns(__TopXMLNS, _val) ->
     _val.
 
-encode_stream_start_attr_xmlns(undefined, _acc) -> _acc;
+encode_stream_start_attr_xmlns(<<>>, _acc) -> _acc;
 encode_stream_start_attr_xmlns(_val, _acc) ->
     [{<<"xmlns">>, _val} | _acc].
 
@@ -5207,24 +5222,23 @@ encode_adhoc_command_attr_node(_val, _acc) ->
 
 'decode_adhoc_command_attr_xml:lang'(__TopXMLNS,
 				     undefined) ->
-    undefined;
+    <<>>;
 'decode_adhoc_command_attr_xml:lang'(__TopXMLNS,
 				     _val) ->
     _val.
 
-'encode_adhoc_command_attr_xml:lang'(undefined, _acc) ->
+'encode_adhoc_command_attr_xml:lang'(<<>>, _acc) ->
     _acc;
 'encode_adhoc_command_attr_xml:lang'(_val, _acc) ->
     [{<<"xml:lang">>, _val} | _acc].
 
 decode_adhoc_command_attr_sessionid(__TopXMLNS,
 				    undefined) ->
-    undefined;
+    <<>>;
 decode_adhoc_command_attr_sessionid(__TopXMLNS, _val) ->
     _val.
 
-encode_adhoc_command_attr_sessionid(undefined, _acc) ->
-    _acc;
+encode_adhoc_command_attr_sessionid(<<>>, _acc) -> _acc;
 encode_adhoc_command_attr_sessionid(_val, _acc) ->
     [{<<"sessionid">>, _val} | _acc].
 
@@ -5723,19 +5737,17 @@ encode_address_attr_jid(undefined, _acc) -> _acc;
 encode_address_attr_jid(_val, _acc) ->
     [{<<"jid">>, enc_jid(_val)} | _acc].
 
-decode_address_attr_desc(__TopXMLNS, undefined) ->
-    undefined;
+decode_address_attr_desc(__TopXMLNS, undefined) -> <<>>;
 decode_address_attr_desc(__TopXMLNS, _val) -> _val.
 
-encode_address_attr_desc(undefined, _acc) -> _acc;
+encode_address_attr_desc(<<>>, _acc) -> _acc;
 encode_address_attr_desc(_val, _acc) ->
     [{<<"desc">>, _val} | _acc].
 
-decode_address_attr_node(__TopXMLNS, undefined) ->
-    undefined;
+decode_address_attr_node(__TopXMLNS, undefined) -> <<>>;
 decode_address_attr_node(__TopXMLNS, _val) -> _val.
 
-encode_address_attr_node(undefined, _acc) -> _acc;
+encode_address_attr_node(<<>>, _acc) -> _acc;
 encode_address_attr_node(_val, _acc) ->
     [{<<"node">>, _val} | _acc].
 
@@ -6001,10 +6013,10 @@ encode_xevent_id(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"id">>, _attrs, _els}.
 
-decode_xevent_id_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_xevent_id_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_xevent_id_cdata(__TopXMLNS, _val) -> _val.
 
-encode_xevent_id_cdata(undefined, _acc) -> _acc;
+encode_xevent_id_cdata(<<>>, _acc) -> _acc;
 encode_xevent_id_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -6519,12 +6531,11 @@ encode_search_instructions(Cdata, _xmlns_attrs) ->
     {xmlel, <<"instructions">>, _attrs, _els}.
 
 decode_search_instructions_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+    <<>>;
 decode_search_instructions_cdata(__TopXMLNS, _val) ->
     _val.
 
-encode_search_instructions_cdata(undefined, _acc) ->
-    _acc;
+encode_search_instructions_cdata(<<>>, _acc) -> _acc;
 encode_search_instructions_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -6641,12 +6652,11 @@ encode_mix_participant_attr_jid(_val, _acc) ->
 
 decode_mix_participant_attr_nick(__TopXMLNS,
 				 undefined) ->
-    undefined;
+    <<>>;
 decode_mix_participant_attr_nick(__TopXMLNS, _val) ->
     _val.
 
-encode_mix_participant_attr_nick(undefined, _acc) ->
-    _acc;
+encode_mix_participant_attr_nick(<<>>, _acc) -> _acc;
 encode_mix_participant_attr_nick(_val, _acc) ->
     [{<<"nick">>, _val} | _acc].
 
@@ -6889,10 +6899,10 @@ encode_offline_item({offline_item, Node, Action},
     {xmlel, <<"item">>, _attrs, _els}.
 
 decode_offline_item_attr_node(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_offline_item_attr_node(__TopXMLNS, _val) -> _val.
 
-encode_offline_item_attr_node(undefined, _acc) -> _acc;
+encode_offline_item_attr_node(<<>>, _acc) -> _acc;
 encode_offline_item_attr_node(_val, _acc) ->
     [{<<"node">>, _val} | _acc].
 
@@ -7413,10 +7423,10 @@ encode_sm_failed_attr_h(_val, _acc) ->
     [{<<"h">>, enc_int(_val)} | _acc].
 
 decode_sm_failed_attr_xmlns(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_sm_failed_attr_xmlns(__TopXMLNS, _val) -> _val.
 
-encode_sm_failed_attr_xmlns(undefined, _acc) -> _acc;
+encode_sm_failed_attr_xmlns(<<>>, _acc) -> _acc;
 encode_sm_failed_attr_xmlns(_val, _acc) ->
     [{<<"xmlns">>, _val} | _acc].
 
@@ -7458,11 +7468,10 @@ decode_sm_a_attr_h(__TopXMLNS, _val) ->
 encode_sm_a_attr_h(_val, _acc) ->
     [{<<"h">>, enc_int(_val)} | _acc].
 
-decode_sm_a_attr_xmlns(__TopXMLNS, undefined) ->
-    undefined;
+decode_sm_a_attr_xmlns(__TopXMLNS, undefined) -> <<>>;
 decode_sm_a_attr_xmlns(__TopXMLNS, _val) -> _val.
 
-encode_sm_a_attr_xmlns(undefined, _acc) -> _acc;
+encode_sm_a_attr_xmlns(<<>>, _acc) -> _acc;
 encode_sm_a_attr_xmlns(_val, _acc) ->
     [{<<"xmlns">>, _val} | _acc].
 
@@ -7485,11 +7494,10 @@ encode_sm_r({sm_r, Xmlns}, _xmlns_attrs) ->
     _attrs = encode_sm_r_attr_xmlns(Xmlns, _xmlns_attrs),
     {xmlel, <<"r">>, _attrs, _els}.
 
-decode_sm_r_attr_xmlns(__TopXMLNS, undefined) ->
-    undefined;
+decode_sm_r_attr_xmlns(__TopXMLNS, undefined) -> <<>>;
 decode_sm_r_attr_xmlns(__TopXMLNS, _val) -> _val.
 
-encode_sm_r_attr_xmlns(undefined, _acc) -> _acc;
+encode_sm_r_attr_xmlns(<<>>, _acc) -> _acc;
 encode_sm_r_attr_xmlns(_val, _acc) ->
     [{<<"xmlns">>, _val} | _acc].
 
@@ -7546,10 +7554,10 @@ encode_sm_resumed_attr_h(_val, _acc) ->
     [{<<"h">>, enc_int(_val)} | _acc].
 
 decode_sm_resumed_attr_xmlns(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_sm_resumed_attr_xmlns(__TopXMLNS, _val) -> _val.
 
-encode_sm_resumed_attr_xmlns(undefined, _acc) -> _acc;
+encode_sm_resumed_attr_xmlns(<<>>, _acc) -> _acc;
 encode_sm_resumed_attr_xmlns(_val, _acc) ->
     [{<<"xmlns">>, _val} | _acc].
 
@@ -7615,10 +7623,10 @@ encode_sm_resume_attr_h(_val, _acc) ->
     [{<<"h">>, enc_int(_val)} | _acc].
 
 decode_sm_resume_attr_xmlns(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_sm_resume_attr_xmlns(__TopXMLNS, _val) -> _val.
 
-encode_sm_resume_attr_xmlns(undefined, _acc) -> _acc;
+encode_sm_resume_attr_xmlns(<<>>, _acc) -> _acc;
 encode_sm_resume_attr_xmlns(_val, _acc) ->
     [{<<"xmlns">>, _val} | _acc].
 
@@ -7688,29 +7696,28 @@ encode_sm_enabled({sm_enabled, Id, Location, Max,
     {xmlel, <<"enabled">>, _attrs, _els}.
 
 decode_sm_enabled_attr_id(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_sm_enabled_attr_id(__TopXMLNS, _val) -> _val.
 
-encode_sm_enabled_attr_id(undefined, _acc) -> _acc;
+encode_sm_enabled_attr_id(<<>>, _acc) -> _acc;
 encode_sm_enabled_attr_id(_val, _acc) ->
     [{<<"id">>, _val} | _acc].
 
 decode_sm_enabled_attr_location(__TopXMLNS,
 				undefined) ->
-    undefined;
+    <<>>;
 decode_sm_enabled_attr_location(__TopXMLNS, _val) ->
     _val.
 
-encode_sm_enabled_attr_location(undefined, _acc) ->
-    _acc;
+encode_sm_enabled_attr_location(<<>>, _acc) -> _acc;
 encode_sm_enabled_attr_location(_val, _acc) ->
     [{<<"location">>, _val} | _acc].
 
 decode_sm_enabled_attr_xmlns(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_sm_enabled_attr_xmlns(__TopXMLNS, _val) -> _val.
 
-encode_sm_enabled_attr_xmlns(undefined, _acc) -> _acc;
+encode_sm_enabled_attr_xmlns(<<>>, _acc) -> _acc;
 encode_sm_enabled_attr_xmlns(_val, _acc) ->
     [{<<"xmlns">>, _val} | _acc].
 
@@ -7797,10 +7804,10 @@ encode_sm_enable_attr_max(_val, _acc) ->
     [{<<"max">>, enc_int(_val)} | _acc].
 
 decode_sm_enable_attr_xmlns(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_sm_enable_attr_xmlns(__TopXMLNS, _val) -> _val.
 
-encode_sm_enable_attr_xmlns(undefined, _acc) -> _acc;
+encode_sm_enable_attr_xmlns(<<>>, _acc) -> _acc;
 encode_sm_enable_attr_xmlns(_val, _acc) ->
     [{<<"xmlns">>, _val} | _acc].
 
@@ -7841,10 +7848,10 @@ encode_feature_sm({feature_sm, Xmlns}, _xmlns_attrs) ->
     {xmlel, <<"sm">>, _attrs, _els}.
 
 decode_feature_sm_attr_xmlns(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_feature_sm_attr_xmlns(__TopXMLNS, _val) -> _val.
 
-encode_feature_sm_attr_xmlns(undefined, _acc) -> _acc;
+encode_feature_sm_attr_xmlns(<<>>, _acc) -> _acc;
 encode_feature_sm_attr_xmlns(_val, _acc) ->
     [{<<"xmlns">>, _val} | _acc].
 
@@ -7889,10 +7896,10 @@ encode_feature_csi({feature_csi, Xmlns},
     {xmlel, <<"csi">>, _attrs, _els}.
 
 decode_feature_csi_attr_xmlns(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_feature_csi_attr_xmlns(__TopXMLNS, _val) -> _val.
 
-encode_feature_csi_attr_xmlns(undefined, _acc) -> _acc;
+encode_feature_csi_attr_xmlns(<<>>, _acc) -> _acc;
 encode_feature_csi_attr_xmlns(_val, _acc) ->
     [{<<"xmlns">>, _val} | _acc].
 
@@ -8137,10 +8144,10 @@ encode_mam_fin({mam_fin, Id, Rsm, Stable, Complete},
      | _acc].
 
 decode_mam_fin_attr_queryid(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_mam_fin_attr_queryid(__TopXMLNS, _val) -> _val.
 
-encode_mam_fin_attr_queryid(undefined, _acc) -> _acc;
+encode_mam_fin_attr_queryid(<<>>, _acc) -> _acc;
 encode_mam_fin_attr_queryid(_val, _acc) ->
     [{<<"queryid">>, _val} | _acc].
 
@@ -8301,10 +8308,10 @@ encode_mam_prefs_attr_default(_val, _acc) ->
     [{<<"default">>, enc_enum(_val)} | _acc].
 
 decode_mam_prefs_attr_xmlns(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_mam_prefs_attr_xmlns(__TopXMLNS, _val) -> _val.
 
-encode_mam_prefs_attr_xmlns(undefined, _acc) -> _acc;
+encode_mam_prefs_attr_xmlns(<<>>, _acc) -> _acc;
 encode_mam_prefs_attr_xmlns(_val, _acc) ->
     [{<<"xmlns">>, _val} | _acc].
 
@@ -8325,36 +8332,23 @@ decode_mam_always_els(__TopXMLNS, __IgnoreEls,
 	       __TopXMLNS == <<"urn:xmpp:mam:0">>;
 	       __TopXMLNS == <<"urn:xmpp:mam:tmp">> ->
 	  decode_mam_always_els(__TopXMLNS, __IgnoreEls, _els,
-				case decode_mam_jid(__TopXMLNS, __IgnoreEls,
-						    _el)
-				    of
-				  undefined -> Jids;
-				  _new_el -> [_new_el | Jids]
-				end);
+				[decode_mam_jid(__TopXMLNS, __IgnoreEls, _el)
+				 | Jids]);
       <<"urn:xmpp:mam:0">> ->
 	  decode_mam_always_els(__TopXMLNS, __IgnoreEls, _els,
-				case decode_mam_jid(<<"urn:xmpp:mam:0">>,
-						    __IgnoreEls, _el)
-				    of
-				  undefined -> Jids;
-				  _new_el -> [_new_el | Jids]
-				end);
+				[decode_mam_jid(<<"urn:xmpp:mam:0">>,
+						__IgnoreEls, _el)
+				 | Jids]);
       <<"urn:xmpp:mam:1">> ->
 	  decode_mam_always_els(__TopXMLNS, __IgnoreEls, _els,
-				case decode_mam_jid(<<"urn:xmpp:mam:1">>,
-						    __IgnoreEls, _el)
-				    of
-				  undefined -> Jids;
-				  _new_el -> [_new_el | Jids]
-				end);
+				[decode_mam_jid(<<"urn:xmpp:mam:1">>,
+						__IgnoreEls, _el)
+				 | Jids]);
       <<"urn:xmpp:mam:tmp">> ->
 	  decode_mam_always_els(__TopXMLNS, __IgnoreEls, _els,
-				case decode_mam_jid(<<"urn:xmpp:mam:tmp">>,
-						    __IgnoreEls, _el)
-				    of
-				  undefined -> Jids;
-				  _new_el -> [_new_el | Jids]
-				end);
+				[decode_mam_jid(<<"urn:xmpp:mam:tmp">>,
+						__IgnoreEls, _el)
+				 | Jids]);
       _ ->
 	  decode_mam_always_els(__TopXMLNS, __IgnoreEls, _els,
 				Jids)
@@ -8392,35 +8386,23 @@ decode_mam_never_els(__TopXMLNS, __IgnoreEls,
 	       __TopXMLNS == <<"urn:xmpp:mam:0">>;
 	       __TopXMLNS == <<"urn:xmpp:mam:tmp">> ->
 	  decode_mam_never_els(__TopXMLNS, __IgnoreEls, _els,
-			       case decode_mam_jid(__TopXMLNS, __IgnoreEls, _el)
-				   of
-				 undefined -> Jids;
-				 _new_el -> [_new_el | Jids]
-			       end);
+			       [decode_mam_jid(__TopXMLNS, __IgnoreEls, _el)
+				| Jids]);
       <<"urn:xmpp:mam:0">> ->
 	  decode_mam_never_els(__TopXMLNS, __IgnoreEls, _els,
-			       case decode_mam_jid(<<"urn:xmpp:mam:0">>,
-						   __IgnoreEls, _el)
-				   of
-				 undefined -> Jids;
-				 _new_el -> [_new_el | Jids]
-			       end);
+			       [decode_mam_jid(<<"urn:xmpp:mam:0">>,
+					       __IgnoreEls, _el)
+				| Jids]);
       <<"urn:xmpp:mam:1">> ->
 	  decode_mam_never_els(__TopXMLNS, __IgnoreEls, _els,
-			       case decode_mam_jid(<<"urn:xmpp:mam:1">>,
-						   __IgnoreEls, _el)
-				   of
-				 undefined -> Jids;
-				 _new_el -> [_new_el | Jids]
-			       end);
+			       [decode_mam_jid(<<"urn:xmpp:mam:1">>,
+					       __IgnoreEls, _el)
+				| Jids]);
       <<"urn:xmpp:mam:tmp">> ->
 	  decode_mam_never_els(__TopXMLNS, __IgnoreEls, _els,
-			       case decode_mam_jid(<<"urn:xmpp:mam:tmp">>,
-						   __IgnoreEls, _el)
-				   of
-				 undefined -> Jids;
-				 _new_el -> [_new_el | Jids]
-			       end);
+			       [decode_mam_jid(<<"urn:xmpp:mam:tmp">>,
+					       __IgnoreEls, _el)
+				| Jids]);
       _ ->
 	  decode_mam_never_els(__TopXMLNS, __IgnoreEls, _els,
 			       Jids)
@@ -8544,27 +8526,27 @@ encode_mam_result({mam_result, Xmlns, Queryid, Id,
     {xmlel, <<"result">>, _attrs, _els}.
 
 decode_mam_result_attr_queryid(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_mam_result_attr_queryid(__TopXMLNS, _val) ->
     _val.
 
-encode_mam_result_attr_queryid(undefined, _acc) -> _acc;
+encode_mam_result_attr_queryid(<<>>, _acc) -> _acc;
 encode_mam_result_attr_queryid(_val, _acc) ->
     [{<<"queryid">>, _val} | _acc].
 
 decode_mam_result_attr_xmlns(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_mam_result_attr_xmlns(__TopXMLNS, _val) -> _val.
 
-encode_mam_result_attr_xmlns(undefined, _acc) -> _acc;
+encode_mam_result_attr_xmlns(<<>>, _acc) -> _acc;
 encode_mam_result_attr_xmlns(_val, _acc) ->
     [{<<"xmlns">>, _val} | _acc].
 
 decode_mam_result_attr_id(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_mam_result_attr_id(__TopXMLNS, _val) -> _val.
 
-encode_mam_result_attr_id(undefined, _acc) -> _acc;
+encode_mam_result_attr_id(<<>>, _acc) -> _acc;
 encode_mam_result_attr_id(_val, _acc) ->
     [{<<"id">>, _val} | _acc].
 
@@ -8596,10 +8578,10 @@ encode_mam_archived({mam_archived, By, Id},
     {xmlel, <<"archived">>, _attrs, _els}.
 
 decode_mam_archived_attr_id(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_mam_archived_attr_id(__TopXMLNS, _val) -> _val.
 
-encode_mam_archived_attr_id(undefined, _acc) -> _acc;
+encode_mam_archived_attr_id(<<>>, _acc) -> _acc;
 encode_mam_archived_attr_id(_val, _acc) ->
     [{<<"id">>, _val} | _acc].
 
@@ -8797,18 +8779,18 @@ encode_mam_query({mam_query, Xmlns, Id, Start, End,
      | _acc].
 
 decode_mam_query_attr_queryid(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_mam_query_attr_queryid(__TopXMLNS, _val) -> _val.
 
-encode_mam_query_attr_queryid(undefined, _acc) -> _acc;
+encode_mam_query_attr_queryid(<<>>, _acc) -> _acc;
 encode_mam_query_attr_queryid(_val, _acc) ->
     [{<<"queryid">>, _val} | _acc].
 
 decode_mam_query_attr_xmlns(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_mam_query_attr_xmlns(__TopXMLNS, _val) -> _val.
 
-encode_mam_query_attr_xmlns(undefined, _acc) -> _acc;
+encode_mam_query_attr_xmlns(<<>>, _acc) -> _acc;
 encode_mam_query_attr_xmlns(_val, _acc) ->
     [{<<"xmlns">>, _val} | _acc].
 
@@ -9205,10 +9187,10 @@ encode_rsm_first_attr_index(undefined, _acc) -> _acc;
 encode_rsm_first_attr_index(_val, _acc) ->
     [{<<"index">>, enc_int(_val)} | _acc].
 
-decode_rsm_first_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_rsm_first_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_rsm_first_cdata(__TopXMLNS, _val) -> _val.
 
-encode_rsm_first_cdata(undefined, _acc) -> _acc;
+encode_rsm_first_cdata(<<>>, _acc) -> _acc;
 encode_rsm_first_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -9343,10 +9325,10 @@ encode_rsm_last(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"last">>, _attrs, _els}.
 
-decode_rsm_last_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_rsm_last_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_rsm_last_cdata(__TopXMLNS, _val) -> _val.
 
-encode_rsm_last_cdata(undefined, _acc) -> _acc;
+encode_rsm_last_cdata(<<>>, _acc) -> _acc;
 encode_rsm_last_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -9403,10 +9385,10 @@ encode_rsm_after(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"after">>, _attrs, _els}.
 
-decode_rsm_after_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_rsm_after_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_rsm_after_cdata(__TopXMLNS, _val) -> _val.
 
-encode_rsm_after_cdata(undefined, _acc) -> _acc;
+encode_rsm_after_cdata(<<>>, _acc) -> _acc;
 encode_rsm_after_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -9540,24 +9522,17 @@ decode_muc_subscriptions_els(__TopXMLNS, __IgnoreEls,
       <<"">> when __TopXMLNS == <<"urn:xmpp:mucsub:0">> ->
 	  decode_muc_subscriptions_els(__TopXMLNS, __IgnoreEls,
 				       _els,
-				       case decode_muc_subscription(__TopXMLNS,
-								    __IgnoreEls,
-								    _el)
-					   of
-					 undefined -> List;
-					 _new_el -> [_new_el | List]
-				       end);
+				       [decode_muc_subscription(__TopXMLNS,
+								__IgnoreEls,
+								_el)
+					| List]);
       <<"urn:xmpp:mucsub:0">> ->
 	  decode_muc_subscriptions_els(__TopXMLNS, __IgnoreEls,
 				       _els,
-				       case
-					 decode_muc_subscription(<<"urn:xmpp:mucsub:0">>,
-								 __IgnoreEls,
-								 _el)
-					   of
-					 undefined -> List;
-					 _new_el -> [_new_el | List]
-				       end);
+				       [decode_muc_subscription(<<"urn:xmpp:mucsub:0">>,
+								__IgnoreEls,
+								_el)
+					| List]);
       _ ->
 	  decode_muc_subscriptions_els(__TopXMLNS, __IgnoreEls,
 				       _els, List)
@@ -9913,13 +9888,12 @@ encode_muc_admin_continue(Thread, _xmlns_attrs) ->
 
 decode_muc_admin_continue_attr_thread(__TopXMLNS,
 				      undefined) ->
-    undefined;
+    <<>>;
 decode_muc_admin_continue_attr_thread(__TopXMLNS,
 				      _val) ->
     _val.
 
-encode_muc_admin_continue_attr_thread(undefined,
-				      _acc) ->
+encode_muc_admin_continue_attr_thread(<<>>, _acc) ->
     _acc;
 encode_muc_admin_continue_attr_thread(_val, _acc) ->
     [{<<"thread">>, _val} | _acc].
@@ -9973,12 +9947,11 @@ encode_muc_admin_actor_attr_jid(_val, _acc) ->
 
 decode_muc_admin_actor_attr_nick(__TopXMLNS,
 				 undefined) ->
-    undefined;
+    <<>>;
 decode_muc_admin_actor_attr_nick(__TopXMLNS, _val) ->
     _val.
 
-encode_muc_admin_actor_attr_nick(undefined, _acc) ->
-    _acc;
+encode_muc_admin_actor_attr_nick(<<>>, _acc) -> _acc;
 encode_muc_admin_actor_attr_nick(_val, _acc) ->
     [{<<"nick">>, _val} | _acc].
 
@@ -10188,12 +10161,11 @@ encode_muc_admin_item_attr_jid(_val, _acc) ->
 
 decode_muc_admin_item_attr_nick(__TopXMLNS,
 				undefined) ->
-    undefined;
+    <<>>;
 decode_muc_admin_item_attr_nick(__TopXMLNS, _val) ->
     _val.
 
-encode_muc_admin_item_attr_nick(undefined, _acc) ->
-    _acc;
+encode_muc_admin_item_attr_nick(<<>>, _acc) -> _acc;
 encode_muc_admin_item_attr_nick(_val, _acc) ->
     [{<<"nick">>, _val} | _acc].
 
@@ -10394,12 +10366,11 @@ encode_muc_owner_item_attr_jid(_val, _acc) ->
 
 decode_muc_owner_item_attr_nick(__TopXMLNS,
 				undefined) ->
-    undefined;
+    <<>>;
 decode_muc_owner_item_attr_nick(__TopXMLNS, _val) ->
     _val.
 
-encode_muc_owner_item_attr_nick(undefined, _acc) ->
-    _acc;
+encode_muc_owner_item_attr_nick(<<>>, _acc) -> _acc;
 encode_muc_owner_item_attr_nick(_val, _acc) ->
     [{<<"nick">>, _val} | _acc].
 
@@ -10526,11 +10497,10 @@ encode_muc_password(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"password">>, _attrs, _els}.
 
-decode_muc_password_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_muc_password_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_muc_password_cdata(__TopXMLNS, _val) -> _val.
 
-encode_muc_password_cdata(undefined, _acc) -> _acc;
+encode_muc_password_cdata(<<>>, _acc) -> _acc;
 encode_muc_password_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -10969,11 +10939,11 @@ encode_muc_user_item_attr_jid(_val, _acc) ->
     [{<<"jid">>, enc_jid(_val)} | _acc].
 
 decode_muc_user_item_attr_nick(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_muc_user_item_attr_nick(__TopXMLNS, _val) ->
     _val.
 
-encode_muc_user_item_attr_nick(undefined, _acc) -> _acc;
+encode_muc_user_item_attr_nick(<<>>, _acc) -> _acc;
 encode_muc_user_item_attr_nick(_val, _acc) ->
     [{<<"nick">>, _val} | _acc].
 
@@ -11042,12 +11012,12 @@ encode_muc_user_continue(Thread, _xmlns_attrs) ->
 
 decode_muc_user_continue_attr_thread(__TopXMLNS,
 				     undefined) ->
-    undefined;
+    <<>>;
 decode_muc_user_continue_attr_thread(__TopXMLNS,
 				     _val) ->
     _val.
 
-encode_muc_user_continue_attr_thread(undefined, _acc) ->
+encode_muc_user_continue_attr_thread(<<>>, _acc) ->
     _acc;
 encode_muc_user_continue_attr_thread(_val, _acc) ->
     [{<<"thread">>, _val} | _acc].
@@ -11099,12 +11069,11 @@ encode_muc_user_actor_attr_jid(_val, _acc) ->
 
 decode_muc_user_actor_attr_nick(__TopXMLNS,
 				undefined) ->
-    undefined;
+    <<>>;
 decode_muc_user_actor_attr_nick(__TopXMLNS, _val) ->
     _val.
 
-encode_muc_user_actor_attr_nick(undefined, _acc) ->
-    _acc;
+encode_muc_user_actor_attr_nick(<<>>, _acc) -> _acc;
 encode_muc_user_actor_attr_nick(_val, _acc) ->
     [{<<"nick">>, _val} | _acc].
 
@@ -11378,10 +11347,10 @@ encode_muc_destroy_attr_jid(_val, _acc) ->
     [{<<"jid">>, enc_jid(_val)} | _acc].
 
 decode_muc_destroy_attr_xmlns(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_muc_destroy_attr_xmlns(__TopXMLNS, _val) -> _val.
 
-encode_muc_destroy_attr_xmlns(undefined, _acc) -> _acc;
+encode_muc_destroy_attr_xmlns(<<>>, _acc) -> _acc;
 encode_muc_destroy_attr_xmlns(_val, _acc) ->
     [{<<"xmlns">>, _val} | _acc].
 
@@ -11518,10 +11487,10 @@ encode_muc_reason(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"reason">>, _attrs, _els}.
 
-decode_muc_reason_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_muc_reason_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_muc_reason_cdata(__TopXMLNS, _val) -> _val.
 
-encode_muc_reason_cdata(undefined, _acc) -> _acc;
+encode_muc_reason_cdata(<<>>, _acc) -> _acc;
 encode_muc_reason_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -11781,20 +11750,19 @@ encode_bytestreams({bytestreams, Hosts, Used, Activate,
 
 decode_bytestreams_attr_dstaddr(__TopXMLNS,
 				undefined) ->
-    undefined;
+    <<>>;
 decode_bytestreams_attr_dstaddr(__TopXMLNS, _val) ->
     _val.
 
-encode_bytestreams_attr_dstaddr(undefined, _acc) ->
-    _acc;
+encode_bytestreams_attr_dstaddr(<<>>, _acc) -> _acc;
 encode_bytestreams_attr_dstaddr(_val, _acc) ->
     [{<<"dstaddr">>, _val} | _acc].
 
 decode_bytestreams_attr_sid(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_bytestreams_attr_sid(__TopXMLNS, _val) -> _val.
 
-encode_bytestreams_attr_sid(undefined, _acc) -> _acc;
+encode_bytestreams_attr_sid(<<>>, _acc) -> _acc;
 encode_bytestreams_attr_sid(_val, _acc) ->
     [{<<"sid">>, _val} | _acc].
 
@@ -12206,10 +12174,10 @@ decode_shim_header_attr_name(__TopXMLNS, _val) -> _val.
 encode_shim_header_attr_name(_val, _acc) ->
     [{<<"name">>, _val} | _acc].
 
-decode_shim_header_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_shim_header_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_shim_header_cdata(__TopXMLNS, _val) -> _val.
 
-encode_shim_header_cdata(undefined, _acc) -> _acc;
+encode_shim_header_cdata(<<>>, _acc) -> _acc;
 encode_shim_header_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -12642,23 +12610,21 @@ encode_pubsub_options({pubsub_options, Node, Jid, Subid,
 
 decode_pubsub_options_attr_node(__TopXMLNS,
 				undefined) ->
-    undefined;
+    <<>>;
 decode_pubsub_options_attr_node(__TopXMLNS, _val) ->
     _val.
 
-encode_pubsub_options_attr_node(undefined, _acc) ->
-    _acc;
+encode_pubsub_options_attr_node(<<>>, _acc) -> _acc;
 encode_pubsub_options_attr_node(_val, _acc) ->
     [{<<"node">>, _val} | _acc].
 
 decode_pubsub_options_attr_subid(__TopXMLNS,
 				 undefined) ->
-    undefined;
+    <<>>;
 decode_pubsub_options_attr_subid(__TopXMLNS, _val) ->
     _val.
 
-encode_pubsub_options_attr_subid(undefined, _acc) ->
-    _acc;
+encode_pubsub_options_attr_subid(<<>>, _acc) -> _acc;
 encode_pubsub_options_attr_subid(_val, _acc) ->
     [{<<"subid">>, _val} | _acc].
 
@@ -12790,23 +12756,22 @@ encode_pubsub_unsubscribe({pubsub_unsubscribe, Node,
 
 decode_pubsub_unsubscribe_attr_node(__TopXMLNS,
 				    undefined) ->
-    undefined;
+    <<>>;
 decode_pubsub_unsubscribe_attr_node(__TopXMLNS, _val) ->
     _val.
 
-encode_pubsub_unsubscribe_attr_node(undefined, _acc) ->
-    _acc;
+encode_pubsub_unsubscribe_attr_node(<<>>, _acc) -> _acc;
 encode_pubsub_unsubscribe_attr_node(_val, _acc) ->
     [{<<"node">>, _val} | _acc].
 
 decode_pubsub_unsubscribe_attr_subid(__TopXMLNS,
 				     undefined) ->
-    undefined;
+    <<>>;
 decode_pubsub_unsubscribe_attr_subid(__TopXMLNS,
 				     _val) ->
     _val.
 
-encode_pubsub_unsubscribe_attr_subid(undefined, _acc) ->
+encode_pubsub_unsubscribe_attr_subid(<<>>, _acc) ->
     _acc;
 encode_pubsub_unsubscribe_attr_subid(_val, _acc) ->
     [{<<"subid">>, _val} | _acc].
@@ -12861,12 +12826,11 @@ encode_pubsub_subscribe({pubsub_subscribe, Node, Jid},
 
 decode_pubsub_subscribe_attr_node(__TopXMLNS,
 				  undefined) ->
-    undefined;
+    <<>>;
 decode_pubsub_subscribe_attr_node(__TopXMLNS, _val) ->
     _val.
 
-encode_pubsub_subscribe_attr_node(undefined, _acc) ->
-    _acc;
+encode_pubsub_subscribe_attr_node(<<>>, _acc) -> _acc;
 encode_pubsub_subscribe_attr_node(_val, _acc) ->
     [{<<"node">>, _val} | _acc].
 
@@ -13021,12 +12985,12 @@ encode_pubsub_subscriptions({Node, Subscriptions},
 
 decode_pubsub_subscriptions_attr_node(__TopXMLNS,
 				      undefined) ->
-    none;
+    <<>>;
 decode_pubsub_subscriptions_attr_node(__TopXMLNS,
 				      _val) ->
     _val.
 
-encode_pubsub_subscriptions_attr_node(none, _acc) ->
+encode_pubsub_subscriptions_attr_node(<<>>, _acc) ->
     _acc;
 encode_pubsub_subscriptions_attr_node(_val, _acc) ->
     [{<<"node">>, _val} | _acc].
@@ -13251,35 +13215,32 @@ encode_pubsub_event_item({pubsub_event_item, Id, Node,
 
 decode_pubsub_event_item_attr_id(__TopXMLNS,
 				 undefined) ->
-    undefined;
+    <<>>;
 decode_pubsub_event_item_attr_id(__TopXMLNS, _val) ->
     _val.
 
-encode_pubsub_event_item_attr_id(undefined, _acc) ->
-    _acc;
+encode_pubsub_event_item_attr_id(<<>>, _acc) -> _acc;
 encode_pubsub_event_item_attr_id(_val, _acc) ->
     [{<<"id">>, _val} | _acc].
 
 decode_pubsub_event_item_attr_node(__TopXMLNS,
 				   undefined) ->
-    undefined;
+    <<>>;
 decode_pubsub_event_item_attr_node(__TopXMLNS, _val) ->
     _val.
 
-encode_pubsub_event_item_attr_node(undefined, _acc) ->
-    _acc;
+encode_pubsub_event_item_attr_node(<<>>, _acc) -> _acc;
 encode_pubsub_event_item_attr_node(_val, _acc) ->
     [{<<"node">>, _val} | _acc].
 
 decode_pubsub_event_item_attr_publisher(__TopXMLNS,
 					undefined) ->
-    undefined;
+    <<>>;
 decode_pubsub_event_item_attr_publisher(__TopXMLNS,
 					_val) ->
     _val.
 
-encode_pubsub_event_item_attr_publisher(undefined,
-					_acc) ->
+encode_pubsub_event_item_attr_publisher(<<>>, _acc) ->
     _acc;
 encode_pubsub_event_item_attr_publisher(_val, _acc) ->
     [{<<"publisher">>, _val} | _acc].
@@ -13421,11 +13382,11 @@ encode_pubsub_items_attr_node(_val, _acc) ->
     [{<<"node">>, _val} | _acc].
 
 decode_pubsub_items_attr_subid(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_pubsub_items_attr_subid(__TopXMLNS, _val) ->
     _val.
 
-encode_pubsub_items_attr_subid(undefined, _acc) -> _acc;
+encode_pubsub_items_attr_subid(<<>>, _acc) -> _acc;
 encode_pubsub_items_attr_subid(_val, _acc) ->
     [{<<"subid">>, _val} | _acc].
 
@@ -13465,10 +13426,10 @@ encode_pubsub_item({pubsub_item, Id, __Xmls},
     {xmlel, <<"item">>, _attrs, _els}.
 
 decode_pubsub_item_attr_id(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_pubsub_item_attr_id(__TopXMLNS, _val) -> _val.
 
-encode_pubsub_item_attr_id(undefined, _acc) -> _acc;
+encode_pubsub_item_attr_id(<<>>, _acc) -> _acc;
 encode_pubsub_item_attr_id(_val, _acc) ->
     [{<<"id">>, _val} | _acc].
 
@@ -13613,25 +13574,24 @@ encode_pubsub_subscription_attr_jid(_val, _acc) ->
 
 decode_pubsub_subscription_attr_node(__TopXMLNS,
 				     undefined) ->
-    undefined;
+    <<>>;
 decode_pubsub_subscription_attr_node(__TopXMLNS,
 				     _val) ->
     _val.
 
-encode_pubsub_subscription_attr_node(undefined, _acc) ->
+encode_pubsub_subscription_attr_node(<<>>, _acc) ->
     _acc;
 encode_pubsub_subscription_attr_node(_val, _acc) ->
     [{<<"node">>, _val} | _acc].
 
 decode_pubsub_subscription_attr_subid(__TopXMLNS,
 				      undefined) ->
-    undefined;
+    <<>>;
 decode_pubsub_subscription_attr_subid(__TopXMLNS,
 				      _val) ->
     _val.
 
-encode_pubsub_subscription_attr_subid(undefined,
-				      _acc) ->
+encode_pubsub_subscription_attr_subid(<<>>, _acc) ->
     _acc;
 encode_pubsub_subscription_attr_subid(_val, _acc) ->
     [{<<"subid">>, _val} | _acc].
@@ -13679,22 +13639,16 @@ decode_xdata_els(__TopXMLNS, __IgnoreEls,
       <<"">> when __TopXMLNS == <<"jabber:x:data">> ->
 	  decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields,
 			   Items,
-			   case decode_xdata_instructions(__TopXMLNS,
-							  __IgnoreEls, _el)
-			       of
-			     undefined -> Instructions;
-			     _new_el -> [_new_el | Instructions]
-			   end,
+			   [decode_xdata_instructions(__TopXMLNS, __IgnoreEls,
+						      _el)
+			    | Instructions],
 			   Reported, Title);
       <<"jabber:x:data">> ->
 	  decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields,
 			   Items,
-			   case decode_xdata_instructions(<<"jabber:x:data">>,
-							  __IgnoreEls, _el)
-			       of
-			     undefined -> Instructions;
-			     _new_el -> [_new_el | Instructions]
-			   end,
+			   [decode_xdata_instructions(<<"jabber:x:data">>,
+						      __IgnoreEls, _el)
+			    | Instructions],
 			   Reported, Title);
       _ ->
 	  decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields,
@@ -13951,10 +13905,10 @@ encode_xdata_title(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"title">>, _attrs, _els}.
 
-decode_xdata_title_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_xdata_title_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_xdata_title_cdata(__TopXMLNS, _val) -> _val.
 
-encode_xdata_title_cdata(undefined, _acc) -> _acc;
+encode_xdata_title_cdata(<<>>, _acc) -> _acc;
 encode_xdata_title_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -13982,12 +13936,11 @@ encode_xdata_instructions(Cdata, _xmlns_attrs) ->
     {xmlel, <<"instructions">>, _attrs, _els}.
 
 decode_xdata_instructions_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+    <<>>;
 decode_xdata_instructions_cdata(__TopXMLNS, _val) ->
     _val.
 
-encode_xdata_instructions_cdata(undefined, _acc) ->
-    _acc;
+encode_xdata_instructions_cdata(<<>>, _acc) -> _acc;
 encode_xdata_instructions_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -14053,23 +14006,16 @@ decode_xdata_field_els(__TopXMLNS, __IgnoreEls,
       <<"">> when __TopXMLNS == <<"jabber:x:data">> ->
 	  decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els,
 				 Options,
-				 case decode_xdata_field_value(__TopXMLNS,
-							       __IgnoreEls, _el)
-				     of
-				   undefined -> Values;
-				   _new_el -> [_new_el | Values]
-				 end,
+				 [decode_xdata_field_value(__TopXMLNS,
+							   __IgnoreEls, _el)
+				  | Values],
 				 Desc, Required, __Els);
       <<"jabber:x:data">> ->
 	  decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els,
 				 Options,
-				 case
-				   decode_xdata_field_value(<<"jabber:x:data">>,
-							    __IgnoreEls, _el)
-				     of
-				   undefined -> Values;
-				   _new_el -> [_new_el | Values]
-				 end,
+				 [decode_xdata_field_value(<<"jabber:x:data">>,
+							   __IgnoreEls, _el)
+				  | Values],
 				 Desc, Required, __Els);
       _ ->
 	  decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els,
@@ -14175,10 +14121,10 @@ encode_xdata_field({xdata_field, Label, Type, Var,
     [encode_xdata_field_required(Required, []) | _acc].
 
 decode_xdata_field_attr_label(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_xdata_field_attr_label(__TopXMLNS, _val) -> _val.
 
-encode_xdata_field_attr_label(undefined, _acc) -> _acc;
+encode_xdata_field_attr_label(<<>>, _acc) -> _acc;
 encode_xdata_field_attr_label(_val, _acc) ->
     [{<<"label">>, _val} | _acc].
 
@@ -14201,10 +14147,10 @@ encode_xdata_field_attr_type(_val, _acc) ->
     [{<<"type">>, enc_enum(_val)} | _acc].
 
 decode_xdata_field_attr_var(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_xdata_field_attr_var(__TopXMLNS, _val) -> _val.
 
-encode_xdata_field_attr_var(undefined, _acc) -> _acc;
+encode_xdata_field_attr_var(<<>>, _acc) -> _acc;
 encode_xdata_field_attr_var(_val, _acc) ->
     [{<<"var">>, _val} | _acc].
 
@@ -14277,12 +14223,12 @@ encode_xdata_field_option({xdata_option, Label, Value},
 
 decode_xdata_field_option_attr_label(__TopXMLNS,
 				     undefined) ->
-    undefined;
+    <<>>;
 decode_xdata_field_option_attr_label(__TopXMLNS,
 				     _val) ->
     _val.
 
-encode_xdata_field_option_attr_label(undefined, _acc) ->
+encode_xdata_field_option_attr_label(<<>>, _acc) ->
     _acc;
 encode_xdata_field_option_attr_label(_val, _acc) ->
     [{<<"label">>, _val} | _acc].
@@ -14311,11 +14257,11 @@ encode_xdata_field_value(Cdata, _xmlns_attrs) ->
     {xmlel, <<"value">>, _attrs, _els}.
 
 decode_xdata_field_value_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+    <<>>;
 decode_xdata_field_value_cdata(__TopXMLNS, _val) ->
     _val.
 
-encode_xdata_field_value_cdata(undefined, _acc) -> _acc;
+encode_xdata_field_value_cdata(<<>>, _acc) -> _acc;
 encode_xdata_field_value_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -14342,11 +14288,10 @@ encode_xdata_field_desc(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"desc">>, _attrs, _els}.
 
-decode_xdata_field_desc_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_xdata_field_desc_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_xdata_field_desc_cdata(__TopXMLNS, _val) -> _val.
 
-encode_xdata_field_desc_cdata(undefined, _acc) -> _acc;
+encode_xdata_field_desc_cdata(<<>>, _acc) -> _acc;
 encode_xdata_field_desc_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -14363,7 +14308,7 @@ decode_vcard_xupdate(__TopXMLNS, __IgnoreEls,
 		     {xmlel, <<"x">>, _attrs, _els}) ->
     Hash = decode_vcard_xupdate_els(__TopXMLNS, __IgnoreEls,
 				    _els, undefined),
-    {vcard_xupdate, undefined, Hash}.
+    {vcard_xupdate, {<<>>, <<>>}, Hash}.
 
 decode_vcard_xupdate_els(__TopXMLNS, __IgnoreEls, [],
 			 Hash) ->
@@ -14391,7 +14336,7 @@ decode_vcard_xupdate_els(__TopXMLNS, __IgnoreEls,
     decode_vcard_xupdate_els(__TopXMLNS, __IgnoreEls, _els,
 			     Hash).
 
-encode_vcard_xupdate({vcard_xupdate, undefined, Hash},
+encode_vcard_xupdate({vcard_xupdate, _, Hash},
 		     _xmlns_attrs) ->
     _els = lists:reverse('encode_vcard_xupdate_$hash'(Hash,
 						      [])),
@@ -14426,12 +14371,11 @@ encode_vcard_xupdate_photo(Cdata, _xmlns_attrs) ->
     {xmlel, <<"photo">>, _attrs, _els}.
 
 decode_vcard_xupdate_photo_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+    <<>>;
 decode_vcard_xupdate_photo_cdata(__TopXMLNS, _val) ->
     _val.
 
-encode_vcard_xupdate_photo_cdata(undefined, _acc) ->
-    _acc;
+encode_vcard_xupdate_photo_cdata(<<>>, _acc) -> _acc;
 encode_vcard_xupdate_photo_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -15677,23 +15621,15 @@ decode_vcard_CATEGORIES_els(__TopXMLNS, __IgnoreEls,
       <<"">> when __TopXMLNS == <<"vcard-temp">> ->
 	  decode_vcard_CATEGORIES_els(__TopXMLNS, __IgnoreEls,
 				      _els,
-				      case decode_vcard_KEYWORD(__TopXMLNS,
-								__IgnoreEls,
-								_el)
-					  of
-					undefined -> Keywords;
-					_new_el -> [_new_el | Keywords]
-				      end);
+				      [decode_vcard_KEYWORD(__TopXMLNS,
+							    __IgnoreEls, _el)
+				       | Keywords]);
       <<"vcard-temp">> ->
 	  decode_vcard_CATEGORIES_els(__TopXMLNS, __IgnoreEls,
 				      _els,
-				      case
-					decode_vcard_KEYWORD(<<"vcard-temp">>,
-							     __IgnoreEls, _el)
-					  of
-					undefined -> Keywords;
-					_new_el -> [_new_el | Keywords]
-				      end);
+				      [decode_vcard_KEYWORD(<<"vcard-temp">>,
+							    __IgnoreEls, _el)
+				       | Keywords]);
       _ ->
 	  decode_vcard_CATEGORIES_els(__TopXMLNS, __IgnoreEls,
 				      _els, Keywords)
@@ -15909,21 +15845,15 @@ decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls,
     case get_attr(<<"xmlns">>, _attrs) of
       <<"">> when __TopXMLNS == <<"vcard-temp">> ->
 	  decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, _els,
-			       case decode_vcard_ORGUNIT(__TopXMLNS,
-							 __IgnoreEls, _el)
-				   of
-				 undefined -> Units;
-				 _new_el -> [_new_el | Units]
-			       end,
+			       [decode_vcard_ORGUNIT(__TopXMLNS, __IgnoreEls,
+						     _el)
+				| Units],
 			       Name);
       <<"vcard-temp">> ->
 	  decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, _els,
-			       case decode_vcard_ORGUNIT(<<"vcard-temp">>,
-							 __IgnoreEls, _el)
-				   of
-				 undefined -> Units;
-				 _new_el -> [_new_el | Units]
-			       end,
+			       [decode_vcard_ORGUNIT(<<"vcard-temp">>,
+						     __IgnoreEls, _el)
+				| Units],
 			       Name);
       _ ->
 	  decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, _els,
@@ -16157,8 +16087,7 @@ encode_vcard_BINVAL(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"BINVAL">>, _attrs, _els}.
 
-decode_vcard_BINVAL_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_vcard_BINVAL_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_BINVAL_cdata(__TopXMLNS, _val) ->
     case catch base64:decode(_val) of
       {'EXIT', _} ->
@@ -16167,7 +16096,7 @@ decode_vcard_BINVAL_cdata(__TopXMLNS, _val) ->
       _res -> _res
     end.
 
-encode_vcard_BINVAL_cdata(undefined, _acc) -> _acc;
+encode_vcard_BINVAL_cdata(<<>>, _acc) -> _acc;
 encode_vcard_BINVAL_cdata(_val, _acc) ->
     [{xmlcdata, base64:encode(_val)} | _acc].
 
@@ -16977,21 +16906,15 @@ decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls,
     case get_attr(<<"xmlns">>, _attrs) of
       <<"">> when __TopXMLNS == <<"vcard-temp">> ->
 	  decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els,
-				 case decode_vcard_LINE(__TopXMLNS, __IgnoreEls,
-							_el)
-				     of
-				   undefined -> Line;
-				   _new_el -> [_new_el | Line]
-				 end,
+				 [decode_vcard_LINE(__TopXMLNS, __IgnoreEls,
+						    _el)
+				  | Line],
 				 Home, Pref, Work, Intl, Parcel, Postal, Dom);
       <<"vcard-temp">> ->
 	  decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els,
-				 case decode_vcard_LINE(<<"vcard-temp">>,
-							__IgnoreEls, _el)
-				     of
-				   undefined -> Line;
-				   _new_el -> [_new_el | Line]
-				 end,
+				 [decode_vcard_LINE(<<"vcard-temp">>,
+						    __IgnoreEls, _el)
+				  | Line],
 				 Home, Pref, Work, Intl, Parcel, Postal, Dom);
       _ ->
 	  decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els,
@@ -17679,11 +17602,10 @@ encode_vcard_EXTVAL(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"EXTVAL">>, _attrs, _els}.
 
-decode_vcard_EXTVAL_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_vcard_EXTVAL_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_EXTVAL_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_EXTVAL_cdata(undefined, _acc) -> _acc;
+encode_vcard_EXTVAL_cdata(<<>>, _acc) -> _acc;
 encode_vcard_EXTVAL_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -17710,10 +17632,10 @@ encode_vcard_TYPE(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"TYPE">>, _attrs, _els}.
 
-decode_vcard_TYPE_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_vcard_TYPE_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_TYPE_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_TYPE_cdata(undefined, _acc) -> _acc;
+encode_vcard_TYPE_cdata(<<>>, _acc) -> _acc;
 encode_vcard_TYPE_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -17740,10 +17662,10 @@ encode_vcard_DESC(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"DESC">>, _attrs, _els}.
 
-decode_vcard_DESC_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_vcard_DESC_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_DESC_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_DESC_cdata(undefined, _acc) -> _acc;
+encode_vcard_DESC_cdata(<<>>, _acc) -> _acc;
 encode_vcard_DESC_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -17770,10 +17692,10 @@ encode_vcard_URL(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"URL">>, _attrs, _els}.
 
-decode_vcard_URL_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_vcard_URL_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_URL_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_URL_cdata(undefined, _acc) -> _acc;
+encode_vcard_URL_cdata(<<>>, _acc) -> _acc;
 encode_vcard_URL_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -17800,10 +17722,10 @@ encode_vcard_UID(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"UID">>, _attrs, _els}.
 
-decode_vcard_UID_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_vcard_UID_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_UID_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_UID_cdata(undefined, _acc) -> _acc;
+encode_vcard_UID_cdata(<<>>, _acc) -> _acc;
 encode_vcard_UID_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -17831,11 +17753,11 @@ encode_vcard_SORT_STRING(Cdata, _xmlns_attrs) ->
     {xmlel, <<"SORT-STRING">>, _attrs, _els}.
 
 decode_vcard_SORT_STRING_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+    <<>>;
 decode_vcard_SORT_STRING_cdata(__TopXMLNS, _val) ->
     _val.
 
-encode_vcard_SORT_STRING_cdata(undefined, _acc) -> _acc;
+encode_vcard_SORT_STRING_cdata(<<>>, _acc) -> _acc;
 encode_vcard_SORT_STRING_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -17862,10 +17784,10 @@ encode_vcard_REV(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"REV">>, _attrs, _els}.
 
-decode_vcard_REV_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_vcard_REV_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_REV_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_REV_cdata(undefined, _acc) -> _acc;
+encode_vcard_REV_cdata(<<>>, _acc) -> _acc;
 encode_vcard_REV_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -17892,11 +17814,10 @@ encode_vcard_PRODID(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"PRODID">>, _attrs, _els}.
 
-decode_vcard_PRODID_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_vcard_PRODID_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_PRODID_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_PRODID_cdata(undefined, _acc) -> _acc;
+encode_vcard_PRODID_cdata(<<>>, _acc) -> _acc;
 encode_vcard_PRODID_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -17923,10 +17844,10 @@ encode_vcard_NOTE(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"NOTE">>, _attrs, _els}.
 
-decode_vcard_NOTE_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_vcard_NOTE_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_NOTE_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_NOTE_cdata(undefined, _acc) -> _acc;
+encode_vcard_NOTE_cdata(<<>>, _acc) -> _acc;
 encode_vcard_NOTE_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -17953,11 +17874,10 @@ encode_vcard_KEYWORD(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"KEYWORD">>, _attrs, _els}.
 
-decode_vcard_KEYWORD_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_vcard_KEYWORD_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_KEYWORD_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_KEYWORD_cdata(undefined, _acc) -> _acc;
+encode_vcard_KEYWORD_cdata(<<>>, _acc) -> _acc;
 encode_vcard_KEYWORD_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -17984,10 +17904,10 @@ encode_vcard_ROLE(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"ROLE">>, _attrs, _els}.
 
-decode_vcard_ROLE_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_vcard_ROLE_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_ROLE_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_ROLE_cdata(undefined, _acc) -> _acc;
+encode_vcard_ROLE_cdata(<<>>, _acc) -> _acc;
 encode_vcard_ROLE_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18014,10 +17934,10 @@ encode_vcard_TITLE(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"TITLE">>, _attrs, _els}.
 
-decode_vcard_TITLE_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_vcard_TITLE_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_TITLE_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_TITLE_cdata(undefined, _acc) -> _acc;
+encode_vcard_TITLE_cdata(<<>>, _acc) -> _acc;
 encode_vcard_TITLE_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18044,10 +17964,10 @@ encode_vcard_TZ(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"TZ">>, _attrs, _els}.
 
-decode_vcard_TZ_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_vcard_TZ_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_TZ_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_TZ_cdata(undefined, _acc) -> _acc;
+encode_vcard_TZ_cdata(<<>>, _acc) -> _acc;
 encode_vcard_TZ_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18074,11 +17994,10 @@ encode_vcard_MAILER(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"MAILER">>, _attrs, _els}.
 
-decode_vcard_MAILER_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_vcard_MAILER_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_MAILER_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_MAILER_cdata(undefined, _acc) -> _acc;
+encode_vcard_MAILER_cdata(<<>>, _acc) -> _acc;
 encode_vcard_MAILER_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18105,11 +18024,10 @@ encode_vcard_JABBERID(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"JABBERID">>, _attrs, _els}.
 
-decode_vcard_JABBERID_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_vcard_JABBERID_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_JABBERID_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_JABBERID_cdata(undefined, _acc) -> _acc;
+encode_vcard_JABBERID_cdata(<<>>, _acc) -> _acc;
 encode_vcard_JABBERID_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18136,10 +18054,10 @@ encode_vcard_BDAY(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"BDAY">>, _attrs, _els}.
 
-decode_vcard_BDAY_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_vcard_BDAY_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_BDAY_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_BDAY_cdata(undefined, _acc) -> _acc;
+encode_vcard_BDAY_cdata(<<>>, _acc) -> _acc;
 encode_vcard_BDAY_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18166,11 +18084,10 @@ encode_vcard_NICKNAME(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"NICKNAME">>, _attrs, _els}.
 
-decode_vcard_NICKNAME_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_vcard_NICKNAME_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_NICKNAME_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_NICKNAME_cdata(undefined, _acc) -> _acc;
+encode_vcard_NICKNAME_cdata(<<>>, _acc) -> _acc;
 encode_vcard_NICKNAME_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18197,10 +18114,10 @@ encode_vcard_FN(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"FN">>, _attrs, _els}.
 
-decode_vcard_FN_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_vcard_FN_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_FN_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_FN_cdata(undefined, _acc) -> _acc;
+encode_vcard_FN_cdata(<<>>, _acc) -> _acc;
 encode_vcard_FN_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18227,11 +18144,10 @@ encode_vcard_VERSION(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"VERSION">>, _attrs, _els}.
 
-decode_vcard_VERSION_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_vcard_VERSION_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_VERSION_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_VERSION_cdata(undefined, _acc) -> _acc;
+encode_vcard_VERSION_cdata(<<>>, _acc) -> _acc;
 encode_vcard_VERSION_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18258,10 +18174,10 @@ encode_vcard_CRED(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"CRED">>, _attrs, _els}.
 
-decode_vcard_CRED_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_vcard_CRED_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_CRED_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_CRED_cdata(undefined, _acc) -> _acc;
+encode_vcard_CRED_cdata(<<>>, _acc) -> _acc;
 encode_vcard_CRED_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18288,11 +18204,10 @@ encode_vcard_PHONETIC(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"PHONETIC">>, _attrs, _els}.
 
-decode_vcard_PHONETIC_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_vcard_PHONETIC_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_PHONETIC_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_PHONETIC_cdata(undefined, _acc) -> _acc;
+encode_vcard_PHONETIC_cdata(<<>>, _acc) -> _acc;
 encode_vcard_PHONETIC_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18319,11 +18234,10 @@ encode_vcard_ORGUNIT(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"ORGUNIT">>, _attrs, _els}.
 
-decode_vcard_ORGUNIT_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_vcard_ORGUNIT_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_ORGUNIT_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_ORGUNIT_cdata(undefined, _acc) -> _acc;
+encode_vcard_ORGUNIT_cdata(<<>>, _acc) -> _acc;
 encode_vcard_ORGUNIT_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18350,11 +18264,10 @@ encode_vcard_ORGNAME(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"ORGNAME">>, _attrs, _els}.
 
-decode_vcard_ORGNAME_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_vcard_ORGNAME_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_ORGNAME_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_ORGNAME_cdata(undefined, _acc) -> _acc;
+encode_vcard_ORGNAME_cdata(<<>>, _acc) -> _acc;
 encode_vcard_ORGNAME_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18381,10 +18294,10 @@ encode_vcard_LON(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"LON">>, _attrs, _els}.
 
-decode_vcard_LON_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_vcard_LON_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_LON_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_LON_cdata(undefined, _acc) -> _acc;
+encode_vcard_LON_cdata(<<>>, _acc) -> _acc;
 encode_vcard_LON_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18411,10 +18324,10 @@ encode_vcard_LAT(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"LAT">>, _attrs, _els}.
 
-decode_vcard_LAT_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_vcard_LAT_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_LAT_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_LAT_cdata(undefined, _acc) -> _acc;
+encode_vcard_LAT_cdata(<<>>, _acc) -> _acc;
 encode_vcard_LAT_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18441,11 +18354,10 @@ encode_vcard_USERID(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"USERID">>, _attrs, _els}.
 
-decode_vcard_USERID_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_vcard_USERID_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_USERID_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_USERID_cdata(undefined, _acc) -> _acc;
+encode_vcard_USERID_cdata(<<>>, _acc) -> _acc;
 encode_vcard_USERID_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18472,11 +18384,10 @@ encode_vcard_NUMBER(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"NUMBER">>, _attrs, _els}.
 
-decode_vcard_NUMBER_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_vcard_NUMBER_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_NUMBER_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_NUMBER_cdata(undefined, _acc) -> _acc;
+encode_vcard_NUMBER_cdata(<<>>, _acc) -> _acc;
 encode_vcard_NUMBER_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18503,10 +18414,10 @@ encode_vcard_LINE(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"LINE">>, _attrs, _els}.
 
-decode_vcard_LINE_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_vcard_LINE_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_LINE_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_LINE_cdata(undefined, _acc) -> _acc;
+encode_vcard_LINE_cdata(<<>>, _acc) -> _acc;
 encode_vcard_LINE_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18533,10 +18444,10 @@ encode_vcard_CTRY(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"CTRY">>, _attrs, _els}.
 
-decode_vcard_CTRY_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_vcard_CTRY_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_CTRY_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_CTRY_cdata(undefined, _acc) -> _acc;
+encode_vcard_CTRY_cdata(<<>>, _acc) -> _acc;
 encode_vcard_CTRY_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18563,10 +18474,10 @@ encode_vcard_PCODE(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"PCODE">>, _attrs, _els}.
 
-decode_vcard_PCODE_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_vcard_PCODE_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_PCODE_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_PCODE_cdata(undefined, _acc) -> _acc;
+encode_vcard_PCODE_cdata(<<>>, _acc) -> _acc;
 encode_vcard_PCODE_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18593,11 +18504,10 @@ encode_vcard_REGION(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"REGION">>, _attrs, _els}.
 
-decode_vcard_REGION_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_vcard_REGION_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_REGION_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_REGION_cdata(undefined, _acc) -> _acc;
+encode_vcard_REGION_cdata(<<>>, _acc) -> _acc;
 encode_vcard_REGION_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18624,11 +18534,10 @@ encode_vcard_LOCALITY(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"LOCALITY">>, _attrs, _els}.
 
-decode_vcard_LOCALITY_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_vcard_LOCALITY_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_LOCALITY_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_LOCALITY_cdata(undefined, _acc) -> _acc;
+encode_vcard_LOCALITY_cdata(<<>>, _acc) -> _acc;
 encode_vcard_LOCALITY_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18655,11 +18564,10 @@ encode_vcard_STREET(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"STREET">>, _attrs, _els}.
 
-decode_vcard_STREET_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_vcard_STREET_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_STREET_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_STREET_cdata(undefined, _acc) -> _acc;
+encode_vcard_STREET_cdata(<<>>, _acc) -> _acc;
 encode_vcard_STREET_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18686,11 +18594,10 @@ encode_vcard_EXTADD(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"EXTADD">>, _attrs, _els}.
 
-decode_vcard_EXTADD_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_vcard_EXTADD_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_EXTADD_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_EXTADD_cdata(undefined, _acc) -> _acc;
+encode_vcard_EXTADD_cdata(<<>>, _acc) -> _acc;
 encode_vcard_EXTADD_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18717,10 +18624,10 @@ encode_vcard_POBOX(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"POBOX">>, _attrs, _els}.
 
-decode_vcard_POBOX_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_vcard_POBOX_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_POBOX_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_POBOX_cdata(undefined, _acc) -> _acc;
+encode_vcard_POBOX_cdata(<<>>, _acc) -> _acc;
 encode_vcard_POBOX_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18747,11 +18654,10 @@ encode_vcard_SUFFIX(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"SUFFIX">>, _attrs, _els}.
 
-decode_vcard_SUFFIX_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_vcard_SUFFIX_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_SUFFIX_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_SUFFIX_cdata(undefined, _acc) -> _acc;
+encode_vcard_SUFFIX_cdata(<<>>, _acc) -> _acc;
 encode_vcard_SUFFIX_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18778,11 +18684,10 @@ encode_vcard_PREFIX(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"PREFIX">>, _attrs, _els}.
 
-decode_vcard_PREFIX_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_vcard_PREFIX_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_PREFIX_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_PREFIX_cdata(undefined, _acc) -> _acc;
+encode_vcard_PREFIX_cdata(<<>>, _acc) -> _acc;
 encode_vcard_PREFIX_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18809,11 +18714,10 @@ encode_vcard_MIDDLE(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"MIDDLE">>, _attrs, _els}.
 
-decode_vcard_MIDDLE_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_vcard_MIDDLE_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_MIDDLE_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_MIDDLE_cdata(undefined, _acc) -> _acc;
+encode_vcard_MIDDLE_cdata(<<>>, _acc) -> _acc;
 encode_vcard_MIDDLE_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18840,10 +18744,10 @@ encode_vcard_GIVEN(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"GIVEN">>, _attrs, _els}.
 
-decode_vcard_GIVEN_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_vcard_GIVEN_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_GIVEN_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_GIVEN_cdata(undefined, _acc) -> _acc;
+encode_vcard_GIVEN_cdata(<<>>, _acc) -> _acc;
 encode_vcard_GIVEN_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -18870,11 +18774,10 @@ encode_vcard_FAMILY(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"FAMILY">>, _attrs, _els}.
 
-decode_vcard_FAMILY_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_vcard_FAMILY_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_vcard_FAMILY_cdata(__TopXMLNS, _val) -> _val.
 
-encode_vcard_FAMILY_cdata(undefined, _acc) -> _acc;
+encode_vcard_FAMILY_cdata(<<>>, _acc) -> _acc;
 encode_vcard_FAMILY_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -19722,10 +19625,16 @@ decode_stream_error_see_other_host_cdata(__TopXMLNS,
 		   __TopXMLNS}});
 decode_stream_error_see_other_host_cdata(__TopXMLNS,
 					 _val) ->
-    _val.
+    case catch dec_host_port(_val) of
+      {'EXIT', _} ->
+	  erlang:error({xmpp_codec,
+			{bad_cdata_value, <<>>, <<"see-other-host">>,
+			 __TopXMLNS}});
+      _res -> _res
+    end.
 
 encode_stream_error_see_other_host_cdata(_val, _acc) ->
-    [{xmlcdata, _val} | _acc].
+    [{xmlcdata, enc_host_port(_val)} | _acc].
 
 decode_stream_error_restricted_xml(__TopXMLNS,
 				   __IgnoreEls,
@@ -19981,23 +19890,22 @@ encode_stream_error_text({text, Lang, Data},
 
 'decode_stream_error_text_attr_xml:lang'(__TopXMLNS,
 					 undefined) ->
-    undefined;
+    <<>>;
 'decode_stream_error_text_attr_xml:lang'(__TopXMLNS,
 					 _val) ->
     _val.
 
-'encode_stream_error_text_attr_xml:lang'(undefined,
-					 _acc) ->
+'encode_stream_error_text_attr_xml:lang'(<<>>, _acc) ->
     _acc;
 'encode_stream_error_text_attr_xml:lang'(_val, _acc) ->
     [{<<"xml:lang">>, _val} | _acc].
 
 decode_stream_error_text_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+    <<>>;
 decode_stream_error_text_cdata(__TopXMLNS, _val) ->
     _val.
 
-encode_stream_error_text_cdata(undefined, _acc) -> _acc;
+encode_stream_error_text_cdata(<<>>, _acc) -> _acc;
 encode_stream_error_text_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -20993,10 +20901,10 @@ encode_register_key(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"key">>, _attrs, _els}.
 
-decode_register_key_cdata(__TopXMLNS, <<>>) -> none;
+decode_register_key_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_register_key_cdata(__TopXMLNS, _val) -> _val.
 
-encode_register_key_cdata(none, _acc) -> _acc;
+encode_register_key_cdata(<<>>, _acc) -> _acc;
 encode_register_key_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -21023,10 +20931,10 @@ encode_register_text(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"text">>, _attrs, _els}.
 
-decode_register_text_cdata(__TopXMLNS, <<>>) -> none;
+decode_register_text_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_register_text_cdata(__TopXMLNS, _val) -> _val.
 
-encode_register_text_cdata(none, _acc) -> _acc;
+encode_register_text_cdata(<<>>, _acc) -> _acc;
 encode_register_text_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -21053,10 +20961,10 @@ encode_register_misc(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"misc">>, _attrs, _els}.
 
-decode_register_misc_cdata(__TopXMLNS, <<>>) -> none;
+decode_register_misc_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_register_misc_cdata(__TopXMLNS, _val) -> _val.
 
-encode_register_misc_cdata(none, _acc) -> _acc;
+encode_register_misc_cdata(<<>>, _acc) -> _acc;
 encode_register_misc_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -21083,10 +20991,10 @@ encode_register_date(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"date">>, _attrs, _els}.
 
-decode_register_date_cdata(__TopXMLNS, <<>>) -> none;
+decode_register_date_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_register_date_cdata(__TopXMLNS, _val) -> _val.
 
-encode_register_date_cdata(none, _acc) -> _acc;
+encode_register_date_cdata(<<>>, _acc) -> _acc;
 encode_register_date_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -21113,10 +21021,10 @@ encode_register_url(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"url">>, _attrs, _els}.
 
-decode_register_url_cdata(__TopXMLNS, <<>>) -> none;
+decode_register_url_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_register_url_cdata(__TopXMLNS, _val) -> _val.
 
-encode_register_url_cdata(none, _acc) -> _acc;
+encode_register_url_cdata(<<>>, _acc) -> _acc;
 encode_register_url_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -21143,10 +21051,10 @@ encode_register_phone(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"phone">>, _attrs, _els}.
 
-decode_register_phone_cdata(__TopXMLNS, <<>>) -> none;
+decode_register_phone_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_register_phone_cdata(__TopXMLNS, _val) -> _val.
 
-encode_register_phone_cdata(none, _acc) -> _acc;
+encode_register_phone_cdata(<<>>, _acc) -> _acc;
 encode_register_phone_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -21173,10 +21081,10 @@ encode_register_zip(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"zip">>, _attrs, _els}.
 
-decode_register_zip_cdata(__TopXMLNS, <<>>) -> none;
+decode_register_zip_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_register_zip_cdata(__TopXMLNS, _val) -> _val.
 
-encode_register_zip_cdata(none, _acc) -> _acc;
+encode_register_zip_cdata(<<>>, _acc) -> _acc;
 encode_register_zip_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -21203,10 +21111,10 @@ encode_register_state(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"state">>, _attrs, _els}.
 
-decode_register_state_cdata(__TopXMLNS, <<>>) -> none;
+decode_register_state_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_register_state_cdata(__TopXMLNS, _val) -> _val.
 
-encode_register_state_cdata(none, _acc) -> _acc;
+encode_register_state_cdata(<<>>, _acc) -> _acc;
 encode_register_state_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -21233,10 +21141,10 @@ encode_register_city(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"city">>, _attrs, _els}.
 
-decode_register_city_cdata(__TopXMLNS, <<>>) -> none;
+decode_register_city_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_register_city_cdata(__TopXMLNS, _val) -> _val.
 
-encode_register_city_cdata(none, _acc) -> _acc;
+encode_register_city_cdata(<<>>, _acc) -> _acc;
 encode_register_city_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -21263,10 +21171,10 @@ encode_register_address(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"address">>, _attrs, _els}.
 
-decode_register_address_cdata(__TopXMLNS, <<>>) -> none;
+decode_register_address_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_register_address_cdata(__TopXMLNS, _val) -> _val.
 
-encode_register_address_cdata(none, _acc) -> _acc;
+encode_register_address_cdata(<<>>, _acc) -> _acc;
 encode_register_address_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -21293,10 +21201,10 @@ encode_register_email(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"email">>, _attrs, _els}.
 
-decode_register_email_cdata(__TopXMLNS, <<>>) -> none;
+decode_register_email_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_register_email_cdata(__TopXMLNS, _val) -> _val.
 
-encode_register_email_cdata(none, _acc) -> _acc;
+encode_register_email_cdata(<<>>, _acc) -> _acc;
 encode_register_email_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -21323,10 +21231,10 @@ encode_register_last(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"last">>, _attrs, _els}.
 
-decode_register_last_cdata(__TopXMLNS, <<>>) -> none;
+decode_register_last_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_register_last_cdata(__TopXMLNS, _val) -> _val.
 
-encode_register_last_cdata(none, _acc) -> _acc;
+encode_register_last_cdata(<<>>, _acc) -> _acc;
 encode_register_last_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -21353,10 +21261,10 @@ encode_register_first(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"first">>, _attrs, _els}.
 
-decode_register_first_cdata(__TopXMLNS, <<>>) -> none;
+decode_register_first_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_register_first_cdata(__TopXMLNS, _val) -> _val.
 
-encode_register_first_cdata(none, _acc) -> _acc;
+encode_register_first_cdata(<<>>, _acc) -> _acc;
 encode_register_first_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -21383,10 +21291,10 @@ encode_register_name(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"name">>, _attrs, _els}.
 
-decode_register_name_cdata(__TopXMLNS, <<>>) -> none;
+decode_register_name_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_register_name_cdata(__TopXMLNS, _val) -> _val.
 
-encode_register_name_cdata(none, _acc) -> _acc;
+encode_register_name_cdata(<<>>, _acc) -> _acc;
 encode_register_name_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -21414,11 +21322,11 @@ encode_register_password(Cdata, _xmlns_attrs) ->
     {xmlel, <<"password">>, _attrs, _els}.
 
 decode_register_password_cdata(__TopXMLNS, <<>>) ->
-    none;
+    <<>>;
 decode_register_password_cdata(__TopXMLNS, _val) ->
     _val.
 
-encode_register_password_cdata(none, _acc) -> _acc;
+encode_register_password_cdata(<<>>, _acc) -> _acc;
 encode_register_password_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -21445,10 +21353,10 @@ encode_register_nick(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"nick">>, _attrs, _els}.
 
-decode_register_nick_cdata(__TopXMLNS, <<>>) -> none;
+decode_register_nick_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_register_nick_cdata(__TopXMLNS, _val) -> _val.
 
-encode_register_nick_cdata(none, _acc) -> _acc;
+encode_register_nick_cdata(<<>>, _acc) -> _acc;
 encode_register_nick_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -21476,11 +21384,11 @@ encode_register_username(Cdata, _xmlns_attrs) ->
     {xmlel, <<"username">>, _attrs, _els}.
 
 decode_register_username_cdata(__TopXMLNS, <<>>) ->
-    none;
+    <<>>;
 decode_register_username_cdata(__TopXMLNS, _val) ->
     _val.
 
-encode_register_username_cdata(none, _acc) -> _acc;
+encode_register_username_cdata(<<>>, _acc) -> _acc;
 encode_register_username_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -21510,12 +21418,11 @@ encode_register_instructions(Cdata, _xmlns_attrs) ->
     {xmlel, <<"instructions">>, _attrs, _els}.
 
 decode_register_instructions_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+    <<>>;
 decode_register_instructions_cdata(__TopXMLNS, _val) ->
     _val.
 
-encode_register_instructions_cdata(undefined, _acc) ->
-    _acc;
+encode_register_instructions_cdata(<<>>, _acc) -> _acc;
 encode_register_instructions_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -21595,19 +21502,17 @@ encode_caps({caps, Node, Version, Hash, Exts},
 												   _xmlns_attrs)))),
     {xmlel, <<"c">>, _attrs, _els}.
 
-decode_caps_attr_hash(__TopXMLNS, undefined) ->
-    undefined;
+decode_caps_attr_hash(__TopXMLNS, undefined) -> <<>>;
 decode_caps_attr_hash(__TopXMLNS, _val) -> _val.
 
-encode_caps_attr_hash(undefined, _acc) -> _acc;
+encode_caps_attr_hash(<<>>, _acc) -> _acc;
 encode_caps_attr_hash(_val, _acc) ->
     [{<<"hash">>, _val} | _acc].
 
-decode_caps_attr_node(__TopXMLNS, undefined) ->
-    undefined;
+decode_caps_attr_node(__TopXMLNS, undefined) -> <<>>;
 decode_caps_attr_node(__TopXMLNS, _val) -> _val.
 
-encode_caps_attr_node(undefined, _acc) -> _acc;
+encode_caps_attr_node(<<>>, _acc) -> _acc;
 encode_caps_attr_node(_val, _acc) ->
     [{<<"node">>, _val} | _acc].
 
@@ -21624,11 +21529,10 @@ encode_caps_attr_ext([], _acc) -> _acc;
 encode_caps_attr_ext(_val, _acc) ->
     [{<<"ext">>, join(_val, 32)} | _acc].
 
-decode_caps_attr_ver(__TopXMLNS, undefined) ->
-    undefined;
+decode_caps_attr_ver(__TopXMLNS, undefined) -> <<>>;
 decode_caps_attr_ver(__TopXMLNS, _val) -> _val.
 
-encode_caps_attr_ver(undefined, _acc) -> _acc;
+encode_caps_attr_ver(<<>>, _acc) -> _acc;
 encode_caps_attr_ver(_val, _acc) ->
     [{<<"ver">>, _val} | _acc].
 
@@ -21711,22 +21615,14 @@ decode_compression_els(__TopXMLNS, __IgnoreEls,
 	  when __TopXMLNS ==
 		 <<"http://jabber.org/features/compress">> ->
 	  decode_compression_els(__TopXMLNS, __IgnoreEls, _els,
-				 case decode_compression_method(__TopXMLNS,
-								__IgnoreEls,
-								_el)
-				     of
-				   undefined -> Methods;
-				   _new_el -> [_new_el | Methods]
-				 end);
+				 [decode_compression_method(__TopXMLNS,
+							    __IgnoreEls, _el)
+				  | Methods]);
       <<"http://jabber.org/features/compress">> ->
 	  decode_compression_els(__TopXMLNS, __IgnoreEls, _els,
-				 case
-				   decode_compression_method(<<"http://jabber.org/features/compress">>,
-							     __IgnoreEls, _el)
-				     of
-				   undefined -> Methods;
-				   _new_el -> [_new_el | Methods]
-				 end);
+				 [decode_compression_method(<<"http://jabber.org/features/compress">>,
+							    __IgnoreEls, _el)
+				  | Methods]);
       _ ->
 	  decode_compression_els(__TopXMLNS, __IgnoreEls, _els,
 				 Methods)
@@ -21774,12 +21670,11 @@ encode_compression_method(Cdata, _xmlns_attrs) ->
     {xmlel, <<"method">>, _attrs, _els}.
 
 decode_compression_method_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+    <<>>;
 decode_compression_method_cdata(__TopXMLNS, _val) ->
     _val.
 
-encode_compression_method_cdata(undefined, _acc) ->
-    _acc;
+encode_compression_method_cdata(<<>>, _acc) -> _acc;
 encode_compression_method_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -21809,21 +21704,14 @@ decode_compress_els(__TopXMLNS, __IgnoreEls,
 	  when __TopXMLNS ==
 		 <<"http://jabber.org/protocol/compress">> ->
 	  decode_compress_els(__TopXMLNS, __IgnoreEls, _els,
-			      case decode_compress_method(__TopXMLNS,
-							  __IgnoreEls, _el)
-				  of
-				undefined -> Methods;
-				_new_el -> [_new_el | Methods]
-			      end);
+			      [decode_compress_method(__TopXMLNS, __IgnoreEls,
+						      _el)
+			       | Methods]);
       <<"http://jabber.org/protocol/compress">> ->
 	  decode_compress_els(__TopXMLNS, __IgnoreEls, _els,
-			      case
-				decode_compress_method(<<"http://jabber.org/protocol/compress">>,
-						       __IgnoreEls, _el)
-				  of
-				undefined -> Methods;
-				_new_el -> [_new_el | Methods]
-			      end);
+			      [decode_compress_method(<<"http://jabber.org/protocol/compress">>,
+						      __IgnoreEls, _el)
+			       | Methods]);
       _ ->
 	  decode_compress_els(__TopXMLNS, __IgnoreEls, _els,
 			      Methods)
@@ -21867,11 +21755,10 @@ encode_compress_method(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"method">>, _attrs, _els}.
 
-decode_compress_method_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_compress_method_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_compress_method_cdata(__TopXMLNS, _val) -> _val.
 
-encode_compress_method_cdata(undefined, _acc) -> _acc;
+encode_compress_method_cdata(<<>>, _acc) -> _acc;
 encode_compress_method_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -22110,23 +21997,15 @@ decode_sasl_mechanisms_els(__TopXMLNS, __IgnoreEls,
 		 <<"urn:ietf:params:xml:ns:xmpp-sasl">> ->
 	  decode_sasl_mechanisms_els(__TopXMLNS, __IgnoreEls,
 				     _els,
-				     case decode_sasl_mechanism(__TopXMLNS,
-								__IgnoreEls,
-								_el)
-					 of
-				       undefined -> List;
-				       _new_el -> [_new_el | List]
-				     end);
+				     [decode_sasl_mechanism(__TopXMLNS,
+							    __IgnoreEls, _el)
+				      | List]);
       <<"urn:ietf:params:xml:ns:xmpp-sasl">> ->
 	  decode_sasl_mechanisms_els(__TopXMLNS, __IgnoreEls,
 				     _els,
-				     case
-				       decode_sasl_mechanism(<<"urn:ietf:params:xml:ns:xmpp-sasl">>,
-							     __IgnoreEls, _el)
-					 of
-				       undefined -> List;
-				       _new_el -> [_new_el | List]
-				     end);
+				     [decode_sasl_mechanism(<<"urn:ietf:params:xml:ns:xmpp-sasl">>,
+							    __IgnoreEls, _el)
+				      | List]);
       _ ->
 	  decode_sasl_mechanisms_els(__TopXMLNS, __IgnoreEls,
 				     _els, List)
@@ -22171,11 +22050,10 @@ encode_sasl_mechanism(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"mechanism">>, _attrs, _els}.
 
-decode_sasl_mechanism_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_sasl_mechanism_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_sasl_mechanism_cdata(__TopXMLNS, _val) -> _val.
 
-encode_sasl_mechanism_cdata(undefined, _acc) -> _acc;
+encode_sasl_mechanism_cdata(<<>>, _acc) -> _acc;
 encode_sasl_mechanism_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -22737,23 +22615,22 @@ encode_sasl_failure_text({text, Lang, Data},
 
 'decode_sasl_failure_text_attr_xml:lang'(__TopXMLNS,
 					 undefined) ->
-    undefined;
+    <<>>;
 'decode_sasl_failure_text_attr_xml:lang'(__TopXMLNS,
 					 _val) ->
     _val.
 
-'encode_sasl_failure_text_attr_xml:lang'(undefined,
-					 _acc) ->
+'encode_sasl_failure_text_attr_xml:lang'(<<>>, _acc) ->
     _acc;
 'encode_sasl_failure_text_attr_xml:lang'(_val, _acc) ->
     [{<<"xml:lang">>, _val} | _acc].
 
 decode_sasl_failure_text_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+    <<>>;
 decode_sasl_failure_text_cdata(__TopXMLNS, _val) ->
     _val.
 
-encode_sasl_failure_text_cdata(undefined, _acc) -> _acc;
+encode_sasl_failure_text_cdata(<<>>, _acc) -> _acc;
 encode_sasl_failure_text_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -22781,8 +22658,7 @@ encode_sasl_success({sasl_success, Text},
     _attrs = _xmlns_attrs,
     {xmlel, <<"success">>, _attrs, _els}.
 
-decode_sasl_success_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_sasl_success_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_sasl_success_cdata(__TopXMLNS, _val) ->
     case catch base64:decode(_val) of
       {'EXIT', _} ->
@@ -22791,7 +22667,7 @@ decode_sasl_success_cdata(__TopXMLNS, _val) ->
       _res -> _res
     end.
 
-encode_sasl_success_cdata(undefined, _acc) -> _acc;
+encode_sasl_success_cdata(<<>>, _acc) -> _acc;
 encode_sasl_success_cdata(_val, _acc) ->
     [{xmlcdata, base64:encode(_val)} | _acc].
 
@@ -22819,8 +22695,7 @@ encode_sasl_response({sasl_response, Text},
     _attrs = _xmlns_attrs,
     {xmlel, <<"response">>, _attrs, _els}.
 
-decode_sasl_response_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_sasl_response_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_sasl_response_cdata(__TopXMLNS, _val) ->
     case catch base64:decode(_val) of
       {'EXIT', _} ->
@@ -22829,7 +22704,7 @@ decode_sasl_response_cdata(__TopXMLNS, _val) ->
       _res -> _res
     end.
 
-encode_sasl_response_cdata(undefined, _acc) -> _acc;
+encode_sasl_response_cdata(<<>>, _acc) -> _acc;
 encode_sasl_response_cdata(_val, _acc) ->
     [{xmlcdata, base64:encode(_val)} | _acc].
 
@@ -22857,8 +22732,7 @@ encode_sasl_challenge({sasl_challenge, Text},
     _attrs = _xmlns_attrs,
     {xmlel, <<"challenge">>, _attrs, _els}.
 
-decode_sasl_challenge_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_sasl_challenge_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_sasl_challenge_cdata(__TopXMLNS, _val) ->
     case catch base64:decode(_val) of
       {'EXIT', _} ->
@@ -22867,7 +22741,7 @@ decode_sasl_challenge_cdata(__TopXMLNS, _val) ->
       _res -> _res
     end.
 
-encode_sasl_challenge_cdata(undefined, _acc) -> _acc;
+encode_sasl_challenge_cdata(<<>>, _acc) -> _acc;
 encode_sasl_challenge_cdata(_val, _acc) ->
     [{xmlcdata, base64:encode(_val)} | _acc].
 
@@ -22927,7 +22801,7 @@ decode_sasl_auth_attr_mechanism(__TopXMLNS, _val) ->
 encode_sasl_auth_attr_mechanism(_val, _acc) ->
     [{<<"mechanism">>, _val} | _acc].
 
-decode_sasl_auth_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_sasl_auth_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_sasl_auth_cdata(__TopXMLNS, _val) ->
     case catch base64:decode(_val) of
       {'EXIT', _} ->
@@ -22936,7 +22810,7 @@ decode_sasl_auth_cdata(__TopXMLNS, _val) ->
       _res -> _res
     end.
 
-encode_sasl_auth_cdata(undefined, _acc) -> _acc;
+encode_sasl_auth_cdata(<<>>, _acc) -> _acc;
 encode_sasl_auth_cdata(_val, _acc) ->
     [{xmlcdata, base64:encode(_val)} | _acc].
 
@@ -23083,11 +22957,11 @@ encode_legacy_auth_resource(Cdata, _xmlns_attrs) ->
     {xmlel, <<"resource">>, _attrs, _els}.
 
 decode_legacy_auth_resource_cdata(__TopXMLNS, <<>>) ->
-    none;
+    <<>>;
 decode_legacy_auth_resource_cdata(__TopXMLNS, _val) ->
     _val.
 
-encode_legacy_auth_resource_cdata(none, _acc) -> _acc;
+encode_legacy_auth_resource_cdata(<<>>, _acc) -> _acc;
 encode_legacy_auth_resource_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -23115,11 +22989,11 @@ encode_legacy_auth_digest(Cdata, _xmlns_attrs) ->
     {xmlel, <<"digest">>, _attrs, _els}.
 
 decode_legacy_auth_digest_cdata(__TopXMLNS, <<>>) ->
-    none;
+    <<>>;
 decode_legacy_auth_digest_cdata(__TopXMLNS, _val) ->
     _val.
 
-encode_legacy_auth_digest_cdata(none, _acc) -> _acc;
+encode_legacy_auth_digest_cdata(<<>>, _acc) -> _acc;
 encode_legacy_auth_digest_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -23147,11 +23021,11 @@ encode_legacy_auth_password(Cdata, _xmlns_attrs) ->
     {xmlel, <<"password">>, _attrs, _els}.
 
 decode_legacy_auth_password_cdata(__TopXMLNS, <<>>) ->
-    none;
+    <<>>;
 decode_legacy_auth_password_cdata(__TopXMLNS, _val) ->
     _val.
 
-encode_legacy_auth_password_cdata(none, _acc) -> _acc;
+encode_legacy_auth_password_cdata(<<>>, _acc) -> _acc;
 encode_legacy_auth_password_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -23179,11 +23053,11 @@ encode_legacy_auth_username(Cdata, _xmlns_attrs) ->
     {xmlel, <<"username">>, _attrs, _els}.
 
 decode_legacy_auth_username_cdata(__TopXMLNS, <<>>) ->
-    none;
+    <<>>;
 decode_legacy_auth_username_cdata(__TopXMLNS, _val) ->
     _val.
 
-encode_legacy_auth_username_cdata(none, _acc) -> _acc;
+encode_legacy_auth_username_cdata(<<>>, _acc) -> _acc;
 encode_legacy_auth_username_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -23275,8 +23149,7 @@ encode_bind_resource(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"resource">>, _attrs, _els}.
 
-decode_bind_resource_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_bind_resource_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_bind_resource_cdata(__TopXMLNS, _val) ->
     case catch resourceprep(_val) of
       {'EXIT', _} ->
@@ -23285,7 +23158,7 @@ decode_bind_resource_cdata(__TopXMLNS, _val) ->
       _res -> _res
     end.
 
-encode_bind_resource_cdata(undefined, _acc) -> _acc;
+encode_bind_resource_cdata(<<>>, _acc) -> _acc;
 encode_bind_resource_cdata(_val, _acc) ->
     [{xmlcdata, resourceprep(_val)} | _acc].
 
@@ -23889,11 +23762,10 @@ encode_error_attr_code(undefined, _acc) -> _acc;
 encode_error_attr_code(_val, _acc) ->
     [{<<"code">>, enc_int(_val)} | _acc].
 
-decode_error_attr_by(__TopXMLNS, undefined) ->
-    undefined;
+decode_error_attr_by(__TopXMLNS, undefined) -> <<>>;
 decode_error_attr_by(__TopXMLNS, _val) -> _val.
 
-encode_error_attr_by(undefined, _acc) -> _acc;
+encode_error_attr_by(<<>>, _acc) -> _acc;
 encode_error_attr_by(_val, _acc) ->
     [{<<"by">>, _val} | _acc].
 
@@ -23934,19 +23806,18 @@ encode_error_text({text, Lang, Data}, _xmlns_attrs) ->
 
 'decode_error_text_attr_xml:lang'(__TopXMLNS,
 				  undefined) ->
-    undefined;
+    <<>>;
 'decode_error_text_attr_xml:lang'(__TopXMLNS, _val) ->
     _val.
 
-'encode_error_text_attr_xml:lang'(undefined, _acc) ->
-    _acc;
+'encode_error_text_attr_xml:lang'(<<>>, _acc) -> _acc;
 'encode_error_text_attr_xml:lang'(_val, _acc) ->
     [{<<"xml:lang">>, _val} | _acc].
 
-decode_error_text_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_error_text_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_error_text_cdata(__TopXMLNS, _val) -> _val.
 
-encode_error_text_cdata(undefined, _acc) -> _acc;
+encode_error_text_cdata(<<>>, _acc) -> _acc;
 encode_error_text_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -24068,11 +23939,10 @@ encode_error_redirect({redirect, Uri}, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"redirect">>, _attrs, _els}.
 
-decode_error_redirect_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_error_redirect_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_error_redirect_cdata(__TopXMLNS, _val) -> _val.
 
-encode_error_redirect_cdata(undefined, _acc) -> _acc;
+encode_error_redirect_cdata(<<>>, _acc) -> _acc;
 encode_error_redirect_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -24192,10 +24062,10 @@ encode_error_gone({gone, Uri}, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"gone">>, _attrs, _els}.
 
-decode_error_gone_cdata(__TopXMLNS, <<>>) -> undefined;
+decode_error_gone_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_error_gone_cdata(__TopXMLNS, _val) -> _val.
 
-encode_error_gone_cdata(undefined, _acc) -> _acc;
+encode_error_gone_cdata(<<>>, _acc) -> _acc;
 encode_error_gone_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -24401,11 +24271,10 @@ encode_presence({presence, Id, Type, Lang, From, To,
 'encode_presence_$priority'(Priority, _acc) ->
     [encode_presence_priority(Priority, []) | _acc].
 
-decode_presence_attr_id(__TopXMLNS, undefined) ->
-    undefined;
+decode_presence_attr_id(__TopXMLNS, undefined) -> <<>>;
 decode_presence_attr_id(__TopXMLNS, _val) -> _val.
 
-encode_presence_attr_id(undefined, _acc) -> _acc;
+encode_presence_attr_id(<<>>, _acc) -> _acc;
 encode_presence_attr_id(_val, _acc) ->
     [{<<"id">>, _val} | _acc].
 
@@ -24459,12 +24328,11 @@ encode_presence_attr_to(_val, _acc) ->
 
 'decode_presence_attr_xml:lang'(__TopXMLNS,
 				undefined) ->
-    undefined;
+    <<>>;
 'decode_presence_attr_xml:lang'(__TopXMLNS, _val) ->
     _val.
 
-'encode_presence_attr_xml:lang'(undefined, _acc) ->
-    _acc;
+'encode_presence_attr_xml:lang'(<<>>, _acc) -> _acc;
 'encode_presence_attr_xml:lang'(_val, _acc) ->
     [{<<"xml:lang">>, _val} | _acc].
 
@@ -24544,22 +24412,20 @@ encode_presence_status({text, Lang, Data},
 
 'decode_presence_status_attr_xml:lang'(__TopXMLNS,
 				       undefined) ->
-    undefined;
+    <<>>;
 'decode_presence_status_attr_xml:lang'(__TopXMLNS,
 				       _val) ->
     _val.
 
-'encode_presence_status_attr_xml:lang'(undefined,
-				       _acc) ->
+'encode_presence_status_attr_xml:lang'(<<>>, _acc) ->
     _acc;
 'encode_presence_status_attr_xml:lang'(_val, _acc) ->
     [{<<"xml:lang">>, _val} | _acc].
 
-decode_presence_status_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_presence_status_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_presence_status_cdata(__TopXMLNS, _val) -> _val.
 
-encode_presence_status_cdata(undefined, _acc) -> _acc;
+encode_presence_status_cdata(<<>>, _acc) -> _acc;
 encode_presence_status_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -24765,11 +24631,10 @@ encode_message({message, Id, Type, Lang, From, To,
     'encode_message_$body'(_els,
 			   [encode_message_body(Body, []) | _acc]).
 
-decode_message_attr_id(__TopXMLNS, undefined) ->
-    undefined;
+decode_message_attr_id(__TopXMLNS, undefined) -> <<>>;
 decode_message_attr_id(__TopXMLNS, _val) -> _val.
 
-encode_message_attr_id(undefined, _acc) -> _acc;
+encode_message_attr_id(<<>>, _acc) -> _acc;
 encode_message_attr_id(_val, _acc) ->
     [{<<"id">>, _val} | _acc].
 
@@ -24820,11 +24685,11 @@ encode_message_attr_to(_val, _acc) ->
     [{<<"to">>, enc_jid(_val)} | _acc].
 
 'decode_message_attr_xml:lang'(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 'decode_message_attr_xml:lang'(__TopXMLNS, _val) ->
     _val.
 
-'encode_message_attr_xml:lang'(undefined, _acc) -> _acc;
+'encode_message_attr_xml:lang'(<<>>, _acc) -> _acc;
 'encode_message_attr_xml:lang'(_val, _acc) ->
     [{<<"xml:lang">>, _val} | _acc].
 
@@ -24851,11 +24716,10 @@ encode_message_thread(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"thread">>, _attrs, _els}.
 
-decode_message_thread_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_message_thread_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_message_thread_cdata(__TopXMLNS, _val) -> _val.
 
-encode_message_thread_cdata(undefined, _acc) -> _acc;
+encode_message_thread_cdata(<<>>, _acc) -> _acc;
 encode_message_thread_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -24896,20 +24760,18 @@ encode_message_body({text, Lang, Data}, _xmlns_attrs) ->
 
 'decode_message_body_attr_xml:lang'(__TopXMLNS,
 				    undefined) ->
-    undefined;
+    <<>>;
 'decode_message_body_attr_xml:lang'(__TopXMLNS, _val) ->
     _val.
 
-'encode_message_body_attr_xml:lang'(undefined, _acc) ->
-    _acc;
+'encode_message_body_attr_xml:lang'(<<>>, _acc) -> _acc;
 'encode_message_body_attr_xml:lang'(_val, _acc) ->
     [{<<"xml:lang">>, _val} | _acc].
 
-decode_message_body_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_message_body_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_message_body_cdata(__TopXMLNS, _val) -> _val.
 
-encode_message_body_cdata(undefined, _acc) -> _acc;
+encode_message_body_cdata(<<>>, _acc) -> _acc;
 encode_message_body_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -24952,22 +24814,20 @@ encode_message_subject({text, Lang, Data},
 
 'decode_message_subject_attr_xml:lang'(__TopXMLNS,
 				       undefined) ->
-    undefined;
+    <<>>;
 'decode_message_subject_attr_xml:lang'(__TopXMLNS,
 				       _val) ->
     _val.
 
-'encode_message_subject_attr_xml:lang'(undefined,
-				       _acc) ->
+'encode_message_subject_attr_xml:lang'(<<>>, _acc) ->
     _acc;
 'encode_message_subject_attr_xml:lang'(_val, _acc) ->
     [{<<"xml:lang">>, _val} | _acc].
 
-decode_message_subject_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_message_subject_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_message_subject_cdata(__TopXMLNS, _val) -> _val.
 
-encode_message_subject_cdata(undefined, _acc) -> _acc;
+encode_message_subject_cdata(<<>>, _acc) -> _acc;
 encode_message_subject_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -25096,10 +24956,10 @@ encode_iq_attr_to(_val, _acc) ->
     [{<<"to">>, enc_jid(_val)} | _acc].
 
 'decode_iq_attr_xml:lang'(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 'decode_iq_attr_xml:lang'(__TopXMLNS, _val) -> _val.
 
-'encode_iq_attr_xml:lang'(undefined, _acc) -> _acc;
+'encode_iq_attr_xml:lang'(<<>>, _acc) -> _acc;
 'encode_iq_attr_xml:lang'(_val, _acc) ->
     [{<<"xml:lang">>, _val} | _acc].
 
@@ -25618,12 +25478,11 @@ encode_conference_password(Cdata, _xmlns_attrs) ->
     {xmlel, <<"password">>, _attrs, _els}.
 
 decode_conference_password_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+    <<>>;
 decode_conference_password_cdata(__TopXMLNS, _val) ->
     _val.
 
-encode_conference_password_cdata(undefined, _acc) ->
-    _acc;
+encode_conference_password_cdata(<<>>, _acc) -> _acc;
 encode_conference_password_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -25650,11 +25509,10 @@ encode_conference_nick(Cdata, _xmlns_attrs) ->
     _attrs = _xmlns_attrs,
     {xmlel, <<"nick">>, _attrs, _els}.
 
-decode_conference_nick_cdata(__TopXMLNS, <<>>) ->
-    undefined;
+decode_conference_nick_cdata(__TopXMLNS, <<>>) -> <<>>;
 decode_conference_nick_cdata(__TopXMLNS, _val) -> _val.
 
-encode_conference_nick_cdata(undefined, _acc) -> _acc;
+encode_conference_nick_cdata(<<>>, _acc) -> _acc;
 encode_conference_nick_cdata(_val, _acc) ->
     [{xmlcdata, _val} | _acc].
 
@@ -25762,10 +25620,10 @@ encode_disco_items({disco_items, Node, Items, Rsm},
      | _acc].
 
 decode_disco_items_attr_node(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_disco_items_attr_node(__TopXMLNS, _val) -> _val.
 
-encode_disco_items_attr_node(undefined, _acc) -> _acc;
+encode_disco_items_attr_node(<<>>, _acc) -> _acc;
 encode_disco_items_attr_node(_val, _acc) ->
     [{<<"node">>, _val} | _acc].
 
@@ -25822,18 +25680,18 @@ encode_disco_item_attr_jid(_val, _acc) ->
     [{<<"jid">>, enc_jid(_val)} | _acc].
 
 decode_disco_item_attr_name(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_disco_item_attr_name(__TopXMLNS, _val) -> _val.
 
-encode_disco_item_attr_name(undefined, _acc) -> _acc;
+encode_disco_item_attr_name(<<>>, _acc) -> _acc;
 encode_disco_item_attr_name(_val, _acc) ->
     [{<<"name">>, _val} | _acc].
 
 decode_disco_item_attr_node(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_disco_item_attr_node(__TopXMLNS, _val) -> _val.
 
-encode_disco_item_attr_node(undefined, _acc) -> _acc;
+encode_disco_item_attr_node(<<>>, _acc) -> _acc;
 encode_disco_item_attr_node(_val, _acc) ->
     [{<<"node">>, _val} | _acc].
 
@@ -25957,10 +25815,10 @@ encode_disco_info({disco_info, Node, Identities,
 				     | _acc]).
 
 decode_disco_info_attr_node(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_disco_info_attr_node(__TopXMLNS, _val) -> _val.
 
-encode_disco_info_attr_node(undefined, _acc) -> _acc;
+encode_disco_info_attr_node(<<>>, _acc) -> _acc;
 encode_disco_info_attr_node(_val, _acc) ->
     [{<<"node">>, _val} | _acc].
 
@@ -26067,25 +25925,23 @@ encode_disco_identity_attr_type(_val, _acc) ->
 
 'decode_disco_identity_attr_xml:lang'(__TopXMLNS,
 				      undefined) ->
-    undefined;
+    <<>>;
 'decode_disco_identity_attr_xml:lang'(__TopXMLNS,
 				      _val) ->
     _val.
 
-'encode_disco_identity_attr_xml:lang'(undefined,
-				      _acc) ->
+'encode_disco_identity_attr_xml:lang'(<<>>, _acc) ->
     _acc;
 'encode_disco_identity_attr_xml:lang'(_val, _acc) ->
     [{<<"xml:lang">>, _val} | _acc].
 
 decode_disco_identity_attr_name(__TopXMLNS,
 				undefined) ->
-    undefined;
+    <<>>;
 decode_disco_identity_attr_name(__TopXMLNS, _val) ->
     _val.
 
-encode_disco_identity_attr_name(undefined, _acc) ->
-    _acc;
+encode_disco_identity_attr_name(<<>>, _acc) -> _acc;
 encode_disco_identity_attr_name(_val, _acc) ->
     [{<<"name">>, _val} | _acc].
 
@@ -26103,20 +25959,13 @@ decode_block_list_els(__TopXMLNS, __IgnoreEls,
     case get_attr(<<"xmlns">>, _attrs) of
       <<"">> when __TopXMLNS == <<"urn:xmpp:blocking">> ->
 	  decode_block_list_els(__TopXMLNS, __IgnoreEls, _els,
-				case decode_block_item(__TopXMLNS, __IgnoreEls,
-						       _el)
-				    of
-				  undefined -> Items;
-				  _new_el -> [_new_el | Items]
-				end);
+				[decode_block_item(__TopXMLNS, __IgnoreEls, _el)
+				 | Items]);
       <<"urn:xmpp:blocking">> ->
 	  decode_block_list_els(__TopXMLNS, __IgnoreEls, _els,
-				case decode_block_item(<<"urn:xmpp:blocking">>,
-						       __IgnoreEls, _el)
-				    of
-				  undefined -> Items;
-				  _new_el -> [_new_el | Items]
-				end);
+				[decode_block_item(<<"urn:xmpp:blocking">>,
+						   __IgnoreEls, _el)
+				 | Items]);
       _ ->
 	  decode_block_list_els(__TopXMLNS, __IgnoreEls, _els,
 				Items)
@@ -26151,20 +26000,13 @@ decode_unblock_els(__TopXMLNS, __IgnoreEls,
     case get_attr(<<"xmlns">>, _attrs) of
       <<"">> when __TopXMLNS == <<"urn:xmpp:blocking">> ->
 	  decode_unblock_els(__TopXMLNS, __IgnoreEls, _els,
-			     case decode_block_item(__TopXMLNS, __IgnoreEls,
-						    _el)
-				 of
-			       undefined -> Items;
-			       _new_el -> [_new_el | Items]
-			     end);
+			     [decode_block_item(__TopXMLNS, __IgnoreEls, _el)
+			      | Items]);
       <<"urn:xmpp:blocking">> ->
 	  decode_unblock_els(__TopXMLNS, __IgnoreEls, _els,
-			     case decode_block_item(<<"urn:xmpp:blocking">>,
-						    __IgnoreEls, _el)
-				 of
-			       undefined -> Items;
-			       _new_el -> [_new_el | Items]
-			     end);
+			     [decode_block_item(<<"urn:xmpp:blocking">>,
+						__IgnoreEls, _el)
+			      | Items]);
       _ ->
 	  decode_unblock_els(__TopXMLNS, __IgnoreEls, _els, Items)
     end;
@@ -26197,19 +26039,13 @@ decode_block_els(__TopXMLNS, __IgnoreEls,
     case get_attr(<<"xmlns">>, _attrs) of
       <<"">> when __TopXMLNS == <<"urn:xmpp:blocking">> ->
 	  decode_block_els(__TopXMLNS, __IgnoreEls, _els,
-			   case decode_block_item(__TopXMLNS, __IgnoreEls, _el)
-			       of
-			     undefined -> Items;
-			     _new_el -> [_new_el | Items]
-			   end);
+			   [decode_block_item(__TopXMLNS, __IgnoreEls, _el)
+			    | Items]);
       <<"urn:xmpp:blocking">> ->
 	  decode_block_els(__TopXMLNS, __IgnoreEls, _els,
-			   case decode_block_item(<<"urn:xmpp:blocking">>,
-						  __IgnoreEls, _el)
-			       of
-			     undefined -> Items;
-			     _new_el -> [_new_el | Items]
-			   end);
+			   [decode_block_item(<<"urn:xmpp:blocking">>,
+					      __IgnoreEls, _el)
+			    | Items]);
       _ ->
 	  decode_block_els(__TopXMLNS, __IgnoreEls, _els, Items)
     end;
@@ -26692,11 +26528,11 @@ encode_privacy_item_attr_type(_val, _acc) ->
     [{<<"type">>, enc_enum(_val)} | _acc].
 
 decode_privacy_item_attr_value(__TopXMLNS, undefined) ->
-    undefined;
+    <<>>;
 decode_privacy_item_attr_value(__TopXMLNS, _val) ->
     _val.
 
-encode_privacy_item_attr_value(undefined, _acc) -> _acc;
+encode_privacy_item_attr_value(<<>>, _acc) -> _acc;
 encode_privacy_item_attr_value(_val, _acc) ->
     [{<<"value">>, _val} | _acc].
 
diff --git a/src/xmpp_util.erl b/src/xmpp_util.erl
index a4f37c926..20231fffa 100644
--- a/src/xmpp_util.erl
+++ b/src/xmpp_util.erl
@@ -94,7 +94,7 @@ make_adhoc_response(#adhoc_command{lang = Lang, node = Node, sid = SID},
     Command#adhoc_command{lang = Lang, node = Node, sid = SID}.
 
 -spec make_adhoc_response(adhoc_command()) -> adhoc_command().
-make_adhoc_response(#adhoc_command{sid = undefined} = Command) ->
+make_adhoc_response(#adhoc_command{sid = <<"">>} = Command) ->
     SID = jlib:now_to_utc_string(p1_time_compat:timestamp()),
     Command#adhoc_command{sid = SID};
 make_adhoc_response(Command) ->
diff --git a/tools/xmpp_codec.spec b/tools/xmpp_codec.spec
index a50b58b59..0b8f3b668 100644
--- a/tools/xmpp_codec.spec
+++ b/tools/xmpp_codec.spec
@@ -69,7 +69,7 @@
      #elem{name = <<"query">>,
            xmlns = <<"jabber:iq:roster">>,
            result = {roster_query, '$items', '$ver'},
-           attrs = [#attr{name = <<"ver">>}],
+           attrs = [#attr{name = <<"ver">>, default = undefined}],
            refs = [#ref{name = roster_item, label = '$items'}]}).
 
 -xml(rosterver_feature,
@@ -616,22 +616,18 @@
 -xml(legacy_auth_username,
      #elem{name = <<"username">>,
 	   xmlns = <<"jabber:iq:auth">>,
-	   cdata = #cdata{default = none},
 	   result = '$cdata'}).
 -xml(legacy_auth_password,
      #elem{name = <<"password">>,
 	   xmlns = <<"jabber:iq:auth">>,
-	   cdata = #cdata{default = none},
 	   result = '$cdata'}).
 -xml(legacy_auth_digest,
      #elem{name = <<"digest">>,
 	   xmlns = <<"jabber:iq:auth">>,
-	   cdata = #cdata{default = none},
 	   result = '$cdata'}).
 -xml(legacy_auth_resource,
      #elem{name = <<"resource">>,
 	   xmlns = <<"jabber:iq:auth">>,
-	   cdata = #cdata{default = none},
 	   result = '$cdata'}).
 
 -xml(legacy_auth,
@@ -917,87 +913,70 @@
 -xml(register_username,
      #elem{name = <<"username">>,
            xmlns = <<"jabber:iq:register">>,
-           cdata = #cdata{default = none},
            result = '$cdata'}).
 -xml(register_nick,
      #elem{name = <<"nick">>,
            xmlns = <<"jabber:iq:register">>,
-           cdata = #cdata{default = none},
            result = '$cdata'}).
 -xml(register_password,
      #elem{name = <<"password">>,
            xmlns = <<"jabber:iq:register">>,
-           cdata = #cdata{default = none},
            result = '$cdata'}).
 -xml(register_name,
      #elem{name = <<"name">>,
            xmlns = <<"jabber:iq:register">>,
-           cdata = #cdata{default = none},
            result = '$cdata'}).
 -xml(register_first,
      #elem{name = <<"first">>,
            xmlns = <<"jabber:iq:register">>,
-           cdata = #cdata{default = none},
            result = '$cdata'}).
 -xml(register_last,
      #elem{name = <<"last">>,
            xmlns = <<"jabber:iq:register">>,
-           cdata = #cdata{default = none},
            result = '$cdata'}).
 -xml(register_email,
      #elem{name = <<"email">>,
            xmlns = <<"jabber:iq:register">>,
-           cdata = #cdata{default = none},
            result = '$cdata'}).
 -xml(register_address,
      #elem{name = <<"address">>,
            xmlns = <<"jabber:iq:register">>,
-           cdata = #cdata{default = none},
            result = '$cdata'}).
 -xml(register_city,
      #elem{name = <<"city">>,
            xmlns = <<"jabber:iq:register">>,
-           cdata = #cdata{default = none},
            result = '$cdata'}).
 -xml(register_state,
      #elem{name = <<"state">>,
            xmlns = <<"jabber:iq:register">>,
-           cdata = #cdata{default = none},
            result = '$cdata'}).
 -xml(register_zip,
      #elem{name = <<"zip">>,
            xmlns = <<"jabber:iq:register">>,
-           cdata = #cdata{default = none},
            result = '$cdata'}).
 -xml(register_phone,
      #elem{name = <<"phone">>,
            xmlns = <<"jabber:iq:register">>,
-           cdata = #cdata{default = none},
            result = '$cdata'}).
 -xml(register_url,
      #elem{name = <<"url">>,
            xmlns = <<"jabber:iq:register">>,
-           cdata = #cdata{default = none},
            result = '$cdata'}).
 -xml(register_date,
      #elem{name = <<"date">>,
            xmlns = <<"jabber:iq:register">>,
-           cdata = #cdata{default = none},
            result = '$cdata'}).
 -xml(register_misc,
      #elem{name = <<"misc">>,
            xmlns = <<"jabber:iq:register">>,
-           cdata = #cdata{default = none},
            result = '$cdata'}).
 -xml(register_text,
      #elem{name = <<"text">>,
            xmlns = <<"jabber:iq:register">>,
-           cdata = #cdata{default = none},
            result = '$cdata'}).
 -xml(register_key,
      #elem{name = <<"key">>,
            xmlns = <<"jabber:iq:register">>,
-           cdata = #cdata{default = none},
            result = '$cdata'}).
 
 -xml(register,
@@ -1180,7 +1159,9 @@
            xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}).
 -xml(stream_error_see_other_host,
      #elem{name = <<"see-other-host">>,
-           cdata = #cdata{required = true, label = '$host'},
+           cdata = #cdata{required = true, label = '$host',
+			  dec = {dec_host_port, []},
+			  enc = {enc_host_port, []}},
            result = {'see-other-host', '$host'},
            xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}).
 -xml(stream_error_system_shutdown,
@@ -1562,14 +1543,14 @@
 	   xmlns = <<"vcard-temp:x:update">>,
 	   result = '$cdata'}).
 
--record(vcard_xupdate, {us :: {binary(), binary()},
+-record(vcard_xupdate, {us = {<<>>, <<>>} :: {binary(), binary()},
 			hash :: binary()}).
 -type vcard_xupdate() :: #vcard_xupdate{}.
 
 -xml(vcard_xupdate,
      #elem{name = <<"x">>,
 	   xmlns = <<"vcard-temp:x:update">>,
-	   result = {vcard_xupdate, undefined, '$hash'},
+	   result = {vcard_xupdate, '$_', '$hash'},
 	   refs = [#ref{name = vcard_xupdate_photo, min = 0, max = 1,
 			label = '$hash'}]}).
 
@@ -1745,8 +1726,7 @@
      #elem{name = <<"subscriptions">>,
            xmlns = <<"http://jabber.org/protocol/pubsub">>,
            result = {'$node', '$subscriptions'},
-           attrs = [#attr{name = <<"node">>,
-                          default = none}],
+           attrs = [#attr{name = <<"node">>}],
            refs = [#ref{name = pubsub_subscription, label = '$subscriptions'}]}).
 
 -xml(pubsub_affiliations,
@@ -3088,6 +3068,7 @@
 			  dec = {dec_int, [0, infinity]},
 			  enc = {enc_int, []}}]}).
 
+-spec dec_tzo(_) -> {integer(), integer()}.
 dec_tzo(Val) ->
     [H1, M1] = str:tokens(Val, <<":">>),
     H = jlib:binary_to_integer(H1),
@@ -3104,12 +3085,14 @@ enc_tzo({H, M}) ->
            end,
     list_to_binary([Sign, io_lib:format("~2..0w:~2..0w", [H, M])]).
 
+-spec dec_utc(_) -> erlang:timestamp().
 dec_utc(Val) ->
     {_, _, _} = jlib:datetime_string_to_timestamp(Val).
 
 enc_utc(Val) ->
     jlib:now_to_utc_string(Val).
 
+-spec dec_jid(_) -> jid:jid().
 dec_jid(Val) ->
     case jid:from_string(Val) of
         error ->
@@ -3121,6 +3104,7 @@ dec_jid(Val) ->
 enc_jid(J) ->            
     jid:to_string(J).
 
+-spec resourceprep(_) -> binary().
 resourceprep(R) ->
     case jid:resourceprep(R) of
         error ->
@@ -3129,6 +3113,7 @@ resourceprep(R) ->
             R1
     end.
 
+-spec dec_bool(_) -> boolean().
 dec_bool(<<"false">>) -> false;
 dec_bool(<<"0">>) -> false;
 dec_bool(<<"true">>) -> true;
@@ -3141,6 +3126,7 @@ join([], _Sep) -> <<>>;
 join([H | T], Sep) ->
     <> || X <- T >>)/binary>>.
 
+-spec dec_ip(_) -> inet:ip_address().
 dec_ip(S) ->
     {ok, Addr} = inet_parse:address(binary_to_list(S)),
     Addr.
@@ -3151,6 +3137,33 @@ enc_ip({0,0,0,0,0,16#ffff,A,B}) ->
 enc_ip(Addr) ->
     list_to_binary(inet_parse:ntoa(Addr)).
 
+-spec re:split(_, _) -> binary().
+-spec base64:decode(_) -> binary().
+
+-spec dec_host_port(_) -> binary() | inet:ip_address() |
+			  {binary() | inet:ip_address(), non_neg_integer()}.
+dec_host_port(<<$[, T/binary>>) ->
+    [IP, <<$:, Port/binary>>] = binary:split(T, <<$]>>),
+    {dec_ip(IP), dec_int(Port, 0, 65535)};
+dec_host_port(S) ->
+    case binary:split(S, <<$:>>) of
+	[S] ->
+	    try dec_ip(S) catch _:_ -> S end;
+	[S, P] ->
+	    {try dec_ip(S) catch _:_ -> S end, dec_int(P, 0, 65535)}
+    end.
+
+enc_host_port(Host) when is_binary(Host) ->
+    Host;
+enc_host_port({{_,_,_,_,_,_,_,_} = IPv6, Port}) ->
+    enc_host_port({<<$[, (enc_ip(IPv6))/binary, $]>>, Port});
+enc_host_port({{_,_,_,_} = IPv4, Port}) ->
+    enc_host_port({enc_ip(IPv4), Port});
+enc_host_port({Host, Port}) ->
+    <>;
+enc_host_port(Addr) ->
+    enc_ip(Addr).
+
 %% Local Variables:
 %% mode: erlang
 %% End:

From 522a186a3822a3fdb04a423b2238aab2fcfb4b1c Mon Sep 17 00:00:00 2001
From: Evgeniy Khramtsov 
Date: Tue, 9 Aug 2016 10:56:32 +0300
Subject: [PATCH 034/151] Improve some type specs

---
 include/ejabberd.hrl              |   2 +-
 include/xmpp_codec.hrl            |  10 +--
 src/ejabberd_auth_anonymous.erl   |   2 +
 src/ejabberd_c2s.erl              |  98 ++++++++++++++++------
 src/ejabberd_config.erl           |   2 +-
 src/ejabberd_local.erl            |   5 +-
 src/ejabberd_router_multicast.erl |   2 +-
 src/ejabberd_s2s_in.erl           |  31 +++----
 src/ejabberd_s2s_out.erl          |   8 +-
 src/ejabberd_service.erl          |   2 +-
 src/ejabberd_sm.erl               |   8 +-
 src/ejabberd_socket.erl           |   2 +-
 src/ejabberd_system_monitor.erl   |   3 +-
 src/ejabberd_web_admin.erl        |  35 ++++----
 src/gen_iq_handler.erl            |   1 +
 src/gen_mod.erl                   |   2 +-
 src/mod_adhoc.erl                 |  24 ++++--
 src/mod_announce.erl              |  43 +++++-----
 src/mod_blocking.erl              |   7 +-
 src/mod_caps.erl                  |  28 +++++--
 src/mod_carboncopy.erl            |   2 +-
 src/mod_client_state.erl          |  26 +++---
 src/mod_configure.erl             |  16 +++-
 src/mod_disco.erl                 |   5 +-
 src/mod_fail2ban.erl              |   8 +-
 src/mod_http_upload.erl           |   9 +-
 src/mod_ip_blacklist.erl          |   4 +
 src/mod_irc.erl                   |   6 +-
 src/mod_irc_connection.erl        |  18 ++--
 src/mod_mam.erl                   |  12 +--
 src/mod_metrics.erl               |  41 +++++++---
 src/mod_mix.erl                   |   4 +
 src/mod_muc_room.erl              | 132 ++++++++++++++++--------------
 src/mod_offline.erl               |   7 +-
 src/mod_ping.erl                  |   4 +-
 src/mod_privacy.erl               |   1 +
 src/mod_private.erl               |   1 +
 src/mod_pubsub.erl                |  16 +++-
 src/mod_register.erl              |   4 +
 src/mod_roster.erl                |   7 +-
 src/mod_shared_roster.erl         |  10 ++-
 src/mod_shared_roster_ldap.erl    |   3 +
 src/mod_vcard_xupdate.erl         |   3 +-
 src/node_online.erl               |   1 +
 src/xmpp.erl                      |   2 +-
 src/xmpp_codec.erl                |  22 +++--
 tools/xmpp_codec.spec             |  19 +++--
 47 files changed, 437 insertions(+), 261 deletions(-)

diff --git a/include/ejabberd.hrl b/include/ejabberd.hrl
index a97474d2b..7a6df5644 100644
--- a/include/ejabberd.hrl
+++ b/include/ejabberd.hrl
@@ -64,7 +64,7 @@
 
 -define(TDICT, dict:dict()).
 -define(TGB_TREE, gb_trees:tree()).
--define(TGB_SET, gb_set:set()).
+-define(TGB_SET, gb_sets:set()).
 -define(TQUEUE, queue:queue()).
 
 -endif.
diff --git a/include/xmpp_codec.hrl b/include/xmpp_codec.hrl
index 935607de9..3424ec3b9 100644
--- a/include/xmpp_codec.hrl
+++ b/include/xmpp_codec.hrl
@@ -178,8 +178,8 @@
 -record(private, {xml_els = [] :: [fxml:xmlel()]}).
 -type private() :: #private{}.
 
--record(db_verify, {from :: jid:jid(),
-                    to :: jid:jid(),
+-record(db_verify, {from = <<>> :: binary(),
+                    to = <<>> :: binary(),
                     id = <<>> :: binary(),
                     type :: 'error' | 'invalid' | 'valid',
                     key = <<>> :: binary(),
@@ -361,7 +361,7 @@
 -record(caps, {node = <<>> :: binary(),
                version = <<>> :: binary(),
                hash = <<>> :: binary(),
-               exts = [] :: binary() | []}).
+               exts = [] :: [binary()]}).
 -type caps() :: #caps{}.
 
 -record(muc, {history :: #muc_history{},
@@ -428,8 +428,8 @@
                       userid :: binary()}).
 -type vcard_email() :: #vcard_email{}.
 
--record(db_result, {from :: jid:jid(),
-                    to :: jid:jid(),
+-record(db_result, {from = <<>> :: binary(),
+                    to = <<>> :: binary(),
                     type :: 'error' | 'invalid' | 'valid',
                     key = <<>> :: binary(),
                     sub_els = [] :: [xmpp_element() | fxml:xmlel()]}).
diff --git a/src/ejabberd_auth_anonymous.erl b/src/ejabberd_auth_anonymous.erl
index c0ad1fb21..c84321ad9 100644
--- a/src/ejabberd_auth_anonymous.erl
+++ b/src/ejabberd_auth_anonymous.erl
@@ -139,6 +139,7 @@ remove_connection(SID, LUser, LServer) ->
     mnesia:transaction(F).
 
 %% Register connection
+-spec register_connection(ejabberd_sm:sid(), jid(), ejabberd_sm:info()) -> ok.
 register_connection(SID,
 		    #jid{luser = LUser, lserver = LServer}, Info) ->
     AuthModule = proplists:get_value(auth_module, Info, undefined),
@@ -155,6 +156,7 @@ register_connection(SID,
     end.
 
 %% Remove an anonymous user from the anonymous users table
+-spec unregister_connection(ejabberd_sm:sid(), jid(), ejabberd_sm:info()) -> any().
 unregister_connection(SID,
 		      #jid{luser = LUser, lserver = LServer}, _) ->
     purge_hook(anonymous_user_exist(LUser, LServer), LUser,
diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl
index b13e7fe00..9c1d99091 100644
--- a/src/ejabberd_c2s.erl
+++ b/src/ejabberd_c2s.erl
@@ -125,6 +125,7 @@
 -type state() :: #state{}.
 -type fsm_stop() :: {stop, normal, state()}.
 -type fsm_next() :: {next_state, state_name(), state(), non_neg_integer()}.
+-type fsm_reply() :: {reply, any(), state_name(), state(), non_neg_integer()}.
 -type fsm_transition() :: fsm_stop() | fsm_next().
 -export_type([state/0]).
 
@@ -184,9 +185,9 @@ get_presence(FsmRef) ->
 
 -spec get_aux_field(any(), state()) -> {ok, any()} | error.
 get_aux_field(Key, #state{aux_fields = Opts}) ->
-    case lists:keysearch(Key, 1, Opts) of
-      {value, {_, Val}} -> {ok, Val};
-      _ -> error
+    case lists:keyfind(Key, 1, Opts) of
+	{_, Val} -> {ok, Val};
+	false -> error
     end.
 
 -spec set_aux_field(any(), any(), state()) -> state().
@@ -525,7 +526,7 @@ wait_for_auth(#iq{type = get,
     Auth = #legacy_auth{username = Username, password = <<>>, resource = <<>>},
     Res = case ejabberd_auth:plain_password_required(StateData#state.server) of
 	      false ->
-		  xmpp:make_iq_result(IQ, Auth#legacy_auth{digest = none});
+		  xmpp:make_iq_result(IQ, Auth#legacy_auth{digest = <<>>});
 	      true ->
 		  xmpp:make_iq_result(IQ, Auth)
 	  end,
@@ -1067,7 +1068,6 @@ session_established2(Pkt, StateData) ->
 		J -> J
 	    end,
     Lang = case xmpp:get_lang(Pkt) of
-	       undefined -> StateData#state.lang;
 	       <<"">> -> StateData#state.lang;
 	       L -> L
 	   end,
@@ -1252,7 +1252,7 @@ handle_info({route, From, To, Packet}, StateName, StateData) when ?is_stanza(Pac
 			process_presence_probe(From, To, NewStateData),
 			{false, NewStateData};
 		    error ->
-			NewA = remove_element(jid:tolower(From), State#state.pres_a),
+			NewA = ?SETS:del_element(jid:tolower(From), State#state.pres_a),
 			{true, State#state{pres_a = NewA}};
 		    subscribe ->
 			SRes = is_privacy_allow(State, From, To, Packet, in),
@@ -1666,6 +1666,7 @@ get_conn_type(StateData) ->
 	websocket -> websocket
     end.
 
+-spec process_presence_probe(jid(), jid(), state()) -> ok.
 process_presence_probe(From, To, StateData) ->
     LFrom = jid:tolower(From),
     LBFrom = setelement(3, LFrom, <<"">>),
@@ -1702,6 +1703,7 @@ process_presence_probe(From, To, StateData) ->
     end.
 
 %% User updates his presence (non-directed presence packet)
+-spec presence_update(jid(), presence(), state()) -> state().
 presence_update(From, Packet, StateData) ->
     #presence{type = Type} = Packet,
     case Type of
@@ -1761,6 +1763,7 @@ presence_update(From, Packet, StateData) ->
     end.
 
 %% User sends a directed presence packet
+-spec presence_track(jid(), jid(), presence(), state()) -> state().
 presence_track(From, To, Packet, StateData) ->
     #presence{type = Type} = Packet,
     LTo = jid:tolower(To),
@@ -1768,7 +1771,7 @@ presence_track(From, To, Packet, StateData) ->
     Server = StateData#state.server,
     case Type of
       unavailable ->
-	  A = remove_element(LTo, StateData#state.pres_a),
+	  A = ?SETS:del_element(LTo, StateData#state.pres_a),
 	  check_privacy_route(From, StateData#state{pres_a = A}, From, To, Packet);
       subscribe ->
 	  try_roster_subscribe(subscribe, User, Server, From, To, Packet, StateData);
@@ -1793,6 +1796,7 @@ presence_track(From, To, Packet, StateData) ->
 	  check_privacy_route(From, StateData#state{pres_a = A}, From, To, Packet)
     end.
 
+-spec check_privacy_route(jid(), state(), jid(), jid(), stanza()) -> state().
 check_privacy_route(From, StateData, FromRoute, To,
 		    Packet) ->
     case privacy_check_packet(StateData, From, To, Packet,
@@ -1812,6 +1816,7 @@ check_privacy_route(From, StateData, FromRoute, To,
     end.
 
 %% Check if privacy rules allow this delivery
+-spec privacy_check_packet(state(), jid(), jid(), stanza(), in | out) -> allow | deny.
 privacy_check_packet(StateData, From, To, Packet,
 		     Dir) ->
     ejabberd_hooks:run_fold(privacy_check_packet,
@@ -1820,11 +1825,14 @@ privacy_check_packet(StateData, From, To, Packet,
 			     StateData#state.privacy_list, {From, To, Packet},
 			     Dir]).
 
+-spec is_privacy_allow(state(), jid(), jid(), stanza(), in | out) -> boolean().
 is_privacy_allow(StateData, From, To, Packet, Dir) ->
     allow ==
       privacy_check_packet(StateData, From, To, Packet, Dir).
 
 %%% Check ACL before allowing to send a subscription stanza
+-spec try_roster_subscribe(subscribe | unsubscribe, binary(), binary(),
+			   jid(), jid(), presence(), state()) -> state().
 try_roster_subscribe(Type, User, Server, From, To, Packet, StateData) ->
     JID1 = jid:make(User, Server, <<"">>),
     Access = gen_mod:get_module_opt(Server, mod_roster, access, fun(A) when is_atom(A) -> A end, all),
@@ -1841,21 +1849,24 @@ try_roster_subscribe(Type, User, Server, From, To, Packet, StateData) ->
     end.
 
 %% Send presence when disconnecting
+-spec presence_broadcast(state(), jid(), ?SETS:set(), presence()) -> ok.
 presence_broadcast(StateData, From, JIDSet, Packet) ->
     JIDs = ?SETS:to_list(JIDSet),
     JIDs2 = format_and_check_privacy(From, StateData, Packet, JIDs, out),
     Server = StateData#state.server,
     send_multiple(From, Server, JIDs2, Packet).
 
+-spec presence_broadcast_to_trusted(
+	state(), jid(), ?SETS:set(), ?SETS:set(), presence()) -> ok.
 %% Send presence when updating presence
 presence_broadcast_to_trusted(StateData, From, Trusted, JIDSet, Packet) ->
-    JIDs = ?SETS:to_list(JIDSet),
-    JIDs_trusted = [JID || JID <- JIDs, ?SETS:is_element(JID, Trusted)],
-    JIDs2 = format_and_check_privacy(From, StateData, Packet, JIDs_trusted, out),
+    JIDs = ?SETS:to_list(?SETS:intersection(Trusted, JIDSet)),
+    JIDs2 = format_and_check_privacy(From, StateData, Packet, JIDs, out),
     Server = StateData#state.server,
     send_multiple(From, Server, JIDs2, Packet).
 
 %% Send presence when connecting
+-spec presence_broadcast_first(jid(), state(), presence()) -> state().
 presence_broadcast_first(From, StateData, Packet) ->
     JIDsProbe =
 	?SETS:fold(
@@ -1877,6 +1888,8 @@ presence_broadcast_first(From, StateData, Packet) ->
     send_multiple(From, Server, JIDs2, Packet),
     StateData#state{pres_a = As}.
 
+-spec format_and_check_privacy(
+	jid(), state(), stanza(), [ljid()], in | out) -> [jid()].
 format_and_check_privacy(From, StateData, Packet, JIDs, Dir) ->
     FJIDs = [jid:make(JID) || JID <- JIDs],
     lists:filter(
@@ -1895,15 +1908,11 @@ format_and_check_privacy(From, StateData, Packet, JIDs, Dir) ->
       end,
       FJIDs).
 
+-spec send_multiple(jid(), binary(), [jid()], stanza()) -> ok.
 send_multiple(From, Server, JIDs, Packet) ->
     ejabberd_router_multicast:route_multicast(From, Server, JIDs, Packet).
 
-remove_element(E, Set) ->
-    case (?SETS):is_element(E, Set) of
-      true -> (?SETS):del_element(E, Set);
-      _ -> Set
-    end.
-
+-spec roster_change(jid(), both | from | none | remove | to, state()) -> state().
 roster_change(IJID, ISubscription, StateData) ->
     LIJID = jid:tolower(IJID),
     IsFrom = (ISubscription == both) or (ISubscription == from),
@@ -1911,11 +1920,11 @@ roster_change(IJID, ISubscription, StateData) ->
     OldIsFrom = (?SETS):is_element(LIJID, StateData#state.pres_f),
     FSet = if
 	       IsFrom -> (?SETS):add_element(LIJID, StateData#state.pres_f);
-	       true -> remove_element(LIJID, StateData#state.pres_f)
+	       true -> ?SETS:del_element(LIJID, StateData#state.pres_f)
 	   end,
     TSet = if
 	       IsTo -> (?SETS):add_element(LIJID, StateData#state.pres_t);
-	       true -> remove_element(LIJID, StateData#state.pres_t)
+	       true -> ?SETS:del_element(LIJID, StateData#state.pres_t)
 	   end,
     case StateData#state.pres_last of
       undefined ->
@@ -1946,13 +1955,14 @@ roster_change(IJID, ISubscription, StateData) ->
 		   deny -> ok;
 		   allow -> ejabberd_router:route(From, To, PU)
 		 end,
-		 A = remove_element(LIJID, StateData#state.pres_a),
+		 A = ?SETS:del_element(LIJID, StateData#state.pres_a),
 		 StateData#state{pres_a = A, pres_f = FSet,
 				 pres_t = TSet};
 	     true -> StateData#state{pres_f = FSet, pres_t = TSet}
 	  end
     end.
 
+-spec update_priority(integer(), presence(), state()) -> ok.
 update_priority(Priority, Packet, StateData) ->
     Info = [{ip, StateData#state.ip}, {conn, StateData#state.conn},
 	    {auth_module, StateData#state.auth_module}],
@@ -1960,12 +1970,14 @@ update_priority(Priority, Packet, StateData) ->
 			     StateData#state.user, StateData#state.server,
 			     StateData#state.resource, Priority, Packet, Info).
 
+-spec get_priority_from_presence(presence()) -> integer().
 get_priority_from_presence(#presence{priority = Prio}) ->
     case Prio of
 	undefined -> 0;
 	_ -> Prio
     end.
 
+-spec process_privacy_iq(iq(), state()) -> state().
 process_privacy_iq(#iq{from = From, to = To,
 		       type = Type, lang = Lang} = IQ, StateData) ->
     Txt = <<"No module is handling this query">>,
@@ -2001,6 +2013,7 @@ process_privacy_iq(#iq{from = From, to = To,
     ejabberd_router:route(To, From, IQRes),
     NewStateData.
 
+-spec resend_offline_messages(state()) -> ok.
 resend_offline_messages(#state{ask_offline = true} = StateData) ->
     case ejabberd_hooks:run_fold(resend_offline_messages_hook,
 				 StateData#state.server, [],
@@ -2025,6 +2038,7 @@ resend_offline_messages(#state{ask_offline = true} = StateData) ->
 resend_offline_messages(_StateData) ->
     ok.
 
+-spec resend_subscription_requests(state()) -> state().
 resend_subscription_requests(#state{user = User,
 				    server = Server} = StateData) ->
     PendingSubscriptions =
@@ -2036,13 +2050,16 @@ resend_subscription_requests(#state{user = User,
 		StateData,
 		PendingSubscriptions).
 
+-spec get_showtag(undefined | presence()) -> binary().
 get_showtag(undefined) -> <<"unavailable">>;
 get_showtag(#presence{show = undefined}) -> <<"available">>;
 get_showtag(#presence{show = Show}) -> atom_to_binary(Show, utf8).
 
-get_statustag(#presence{status = [#text{data = Status}|_]}) -> Status;
-get_statustag(_) -> <<"">>.
+-spec get_statustag(undefined | presence()) -> binary().
+get_statustag(#presence{status = Status}) -> xmpp:get_text(Status);
+get_statustag(undefined) -> <<"">>.
 
+-spec process_unauthenticated_stanza(state(), iq()) -> ok | {error, any()}.
 process_unauthenticated_stanza(StateData, #iq{type = T, lang = L} = IQ)
   when T == set; T == get ->
     Lang = if L == undefined; L == <<"">> -> StateData#state.lang;
@@ -2067,6 +2084,9 @@ process_unauthenticated_stanza(_StateData, _) ->
     %% Drop any stanza, which isn't IQ stanza
     ok.
 
+-spec peerip(ejabberd_socket:sockmod(),
+	     ejabberd_socket:socket()) ->
+		    {inet:ip_address(), non_neg_integer()} | undefined.
 peerip(SockMod, Socket) ->
     IP = case SockMod of
 	   gen_tcp -> inet:peername(Socket);
@@ -2124,6 +2144,7 @@ fsm_next_state(StateName, StateData) ->
 
 %% fsm_reply: Generate the reply FSM tuple with different timeout,
 %% depending on the future state
+-spec fsm_reply(_, state_name(), state()) -> fsm_reply().
 fsm_reply(Reply, session_established, StateData) ->
     {reply, Reply, session_established, StateData,
      ?C2S_HIBERNATE_TIMEOUT};
@@ -2135,6 +2156,8 @@ fsm_reply(Reply, StateName, StateData) ->
     {reply, Reply, StateName, StateData, ?C2S_OPEN_TIMEOUT}.
 
 %% Used by c2s blacklist plugins
+-spec is_ip_blacklisted(undefined | {inet:ip_address(), non_neg_integer()},
+			binary()) -> false | {true, binary(), binary()}.
 is_ip_blacklisted(undefined, _Lang) -> false;
 is_ip_blacklisted({IP, _Port}, Lang) ->
     ejabberd_hooks:run_fold(check_bl_c2s, false, [IP, Lang]).
@@ -2174,6 +2197,7 @@ fsm_limit_opts(Opts) ->
 	  end
     end.
 
+-spec bounce_messages() -> ok.
 bounce_messages() ->
     receive
       {route, From, To, El} ->
@@ -2181,6 +2205,7 @@ bounce_messages() ->
       after 0 -> ok
     end.
 
+-spec process_compression_request(compress(), state_name(), state()) -> fsm_next().
 process_compression_request(#compress{methods = []}, StateName, StateData) ->
     send_element(StateData, #compress_failure{reason = 'setup-failed'}),
     fsm_next_state(StateName, StateData);
@@ -2203,6 +2228,8 @@ process_compression_request(#compress{methods = Ms}, StateName, StateData) ->
 %%% XEP-0191
 %%%----------------------------------------------------------------------
 
+-spec route_blocking(
+	{block, [jid()]} | {unblock, [jid()]} | unblock_all, state()) -> state().
 route_blocking(What, StateData) ->
     SubEl = case What of
 		{block, JIDs} ->
@@ -2223,12 +2250,13 @@ route_blocking(What, StateData) ->
 %%%----------------------------------------------------------------------
 %%% XEP-0198
 %%%----------------------------------------------------------------------
-
+-spec stream_mgmt_enabled(state()) -> boolean().
 stream_mgmt_enabled(#state{mgmt_state = disabled}) ->
     false;
 stream_mgmt_enabled(_StateData) ->
     true.
 
+-spec dispatch_stream_mgmt(xmpp_element(), state()) -> state().
 dispatch_stream_mgmt(El, #state{mgmt_state = MgmtState} = StateData)
     when MgmtState == active;
 	 MgmtState == pending ->
@@ -2236,6 +2264,7 @@ dispatch_stream_mgmt(El, #state{mgmt_state = MgmtState} = StateData)
 dispatch_stream_mgmt(El, StateData) ->
     negotiate_stream_mgmt(El, StateData).
 
+-spec negotiate_stream_mgmt(xmpp_element(), state()) -> state().
 negotiate_stream_mgmt(_El, #state{resource = <<"">>} = StateData) ->
     %% XEP-0198 says: "For client-to-server connections, the client MUST NOT
     %% attempt to enable stream management until after it has completed Resource
@@ -2272,6 +2301,7 @@ negotiate_stream_mgmt(Pkt, StateData) ->
 	    StateData
     end.
 
+-spec perform_stream_mgmt(xmpp_element(), state()) -> state().
 perform_stream_mgmt(Pkt, StateData) ->
     case xmpp:get_ns(Pkt) of
 	Xmlns when Xmlns == StateData#state.mgmt_xmlns ->
@@ -2298,6 +2328,7 @@ perform_stream_mgmt(Pkt, StateData) ->
 				    xmlns = StateData#state.mgmt_xmlns})
     end.
 
+-spec handle_enable(state(), sm_enable()) -> state().
 handle_enable(#state{mgmt_timeout = DefaultTimeout,
 		     mgmt_max_timeout = MaxTimeout} = StateData,
 	      #sm_enable{resume = Resume, max = Max}) ->
@@ -2325,15 +2356,18 @@ handle_enable(#state{mgmt_timeout = DefaultTimeout,
 		    mgmt_queue = queue:new(),
 		    mgmt_timeout = Timeout * 1000}.
 
+-spec handle_r(state()) -> state().
 handle_r(StateData) ->
     Res = #sm_a{xmlns = StateData#state.mgmt_xmlns,
 		h = StateData#state.mgmt_stanzas_in},
     send_element(StateData, Res),
     StateData.
 
+-spec handle_a(state(), sm_a()) -> state().
 handle_a(StateData, #sm_a{h = H}) ->
     check_h_attribute(StateData, H).
 
+-spec handle_resume(state(), sm_resume()) -> {ok, state()} | error.
 handle_resume(StateData, #sm_resume{h = H, previd = PrevID, xmlns = Xmlns}) ->
     R = case stream_mgmt_enabled(StateData) of
 	    true ->
@@ -2379,6 +2413,7 @@ handle_resume(StateData, #sm_resume{h = H, previd = PrevID, xmlns = Xmlns}) ->
 	  error
     end.
 
+-spec check_h_attribute(state(), non_neg_integer()) -> state().
 check_h_attribute(#state{mgmt_stanzas_out = NumStanzasOut} = StateData, H)
     when H > NumStanzasOut ->
     ?DEBUG("~s acknowledged ~B stanzas, but only ~B were sent",
@@ -2389,6 +2424,7 @@ check_h_attribute(#state{mgmt_stanzas_out = NumStanzasOut} = StateData, H) ->
 	   [jid:to_string(StateData#state.jid), H, NumStanzasOut]),
     mgmt_queue_drop(StateData, H).
 
+-spec update_num_stanzas_in(state(), xmpp_element()) -> state().
 update_num_stanzas_in(#state{mgmt_state = MgmtState} = StateData, El)
     when MgmtState == active;
 	 MgmtState == pending ->
@@ -2404,6 +2440,7 @@ update_num_stanzas_in(#state{mgmt_state = MgmtState} = StateData, El)
 update_num_stanzas_in(StateData, _El) ->
     StateData.
 
+-spec send_stanza_and_ack_req(state(), stanza()) -> state().
 send_stanza_and_ack_req(StateData, Stanza) ->
     AckReq = #sm_r{xmlns = StateData#state.mgmt_xmlns},
     case send_element(StateData, Stanza) == ok andalso
@@ -2414,6 +2451,7 @@ send_stanza_and_ack_req(StateData, Stanza) ->
 	  StateData#state{mgmt_state = pending}
     end.
 
+-spec mgmt_queue_add(state(), xmpp_element()) -> state().
 mgmt_queue_add(StateData, El) ->
     NewNum = case StateData#state.mgmt_stanzas_out of
 	       4294967295 ->
@@ -2426,11 +2464,13 @@ mgmt_queue_add(StateData, El) ->
 			       mgmt_stanzas_out = NewNum},
     check_queue_length(NewState).
 
+-spec mgmt_queue_drop(state(), non_neg_integer()) -> state().
 mgmt_queue_drop(StateData, NumHandled) ->
     NewQueue = jlib:queue_drop_while(fun({N, _T, _E}) -> N =< NumHandled end,
 				     StateData#state.mgmt_queue),
     StateData#state{mgmt_queue = NewQueue}.
 
+-spec check_queue_length(state()) -> state().
 check_queue_length(#state{mgmt_max_queue = Limit} = StateData)
     when Limit == infinity;
 	 Limit == exceeded ->
@@ -2444,6 +2484,7 @@ check_queue_length(#state{mgmt_queue = Queue,
 	  StateData
     end.
 
+-spec handle_unacked_stanzas(state(), fun((_, _, _, _) -> _)) -> ok.
 handle_unacked_stanzas(#state{mgmt_state = MgmtState} = StateData, F)
     when MgmtState == active;
 	 MgmtState == pending;
@@ -2465,6 +2506,7 @@ handle_unacked_stanzas(#state{mgmt_state = MgmtState} = StateData, F)
 handle_unacked_stanzas(_StateData, _F) ->
     ok.
 
+-spec handle_unacked_stanzas(state()) -> ok.
 handle_unacked_stanzas(#state{mgmt_state = MgmtState} = StateData)
     when MgmtState == active;
 	 MgmtState == pending;
@@ -2537,6 +2579,7 @@ handle_unacked_stanzas(#state{mgmt_state = MgmtState} = StateData)
 handle_unacked_stanzas(_StateData) ->
     ok.
 
+-spec is_encapsulated_forward(stanza()) -> boolean().
 is_encapsulated_forward(#message{} = Msg) ->
     xmpp:has_subtag(Msg, #forwarded{}) orelse
 	xmpp:has_subtag(Msg, #carbons_sent{}) orelse
@@ -2544,6 +2587,9 @@ is_encapsulated_forward(#message{} = Msg) ->
 is_encapsulated_forward(_El) ->
     false.
 
+-spec inherit_session_state(state(), binary()) -> {ok, state()} |
+						  {error, binary()} |
+						  {error, binary(), non_neg_integer()}.
 inherit_session_state(#state{user = U, server = S} = StateData, ResumeID) ->
     case jlib:base64_to_term(ResumeID) of
       {term, {R, Time}} ->
@@ -2604,13 +2650,16 @@ inherit_session_state(#state{user = U, server = S} = StateData, ResumeID) ->
 	  {error, <<"Invalid 'previd' value">>}
     end.
 
+-spec resume_session({integer(), pid()}) -> any().
 resume_session({Time, PID}) ->
     (?GEN_FSM):sync_send_all_state_event(PID, {resume_session, Time}, 5000).
 
+-spec make_resume_id(state()) -> binary().
 make_resume_id(StateData) ->
     {Time, _} = StateData#state.sid,
     jlib:term_to_base64({StateData#state.resource, Time}).
 
+-spec add_resent_delay_info(state(), stanza(), erlang:timestamp()) -> stanza().
 add_resent_delay_info(_State, #iq{} = El, _Time) ->
     El;
 add_resent_delay_info(#state{server = From}, El, Time) ->
@@ -2619,7 +2668,7 @@ add_resent_delay_info(#state{server = From}, El, Time) ->
 %%%----------------------------------------------------------------------
 %%% XEP-0352
 %%%----------------------------------------------------------------------
-
+-spec csi_filter_stanza(state(), stanza()) -> state().
 csi_filter_stanza(#state{csi_state = CsiState, server = Server} = StateData,
 		  Stanza) ->
     {StateData1, Stanzas} = ejabberd_hooks:run_fold(csi_filter_stanza, Server,
@@ -2631,6 +2680,7 @@ csi_filter_stanza(#state{csi_state = CsiState, server = Server} = StateData,
 			     Stanzas),
     StateData2#state{csi_state = CsiState}.
 
+-spec csi_flush_queue(state()) -> state().
 csi_flush_queue(#state{csi_state = CsiState, server = Server} = StateData) ->
     {StateData1, Stanzas} = ejabberd_hooks:run_fold(csi_flush_queue, Server,
 						    {StateData, []}, [Server]),
@@ -2646,6 +2696,7 @@ csi_flush_queue(#state{csi_state = CsiState, server = Server} = StateData) ->
 
 %% Try to reduce the heap footprint of the four presence sets
 %% by ensuring that we re-use strings and Jids wherever possible.
+-spec pack(state()) -> state().
 pack(S = #state{pres_a = A, pres_f = F,
 		pres_t = T}) ->
     {NewA, Pack2} = pack_jid_set(A, gb_trees:empty()),
@@ -2682,6 +2733,7 @@ pack_string(String, Pack) ->
 transform_listen_option(Opt, Opts) ->
     [Opt|Opts].
 
+-spec identity([{atom(), binary()}]) -> binary().
 identity(Props) ->
     case proplists:get_value(authzid, Props, <<>>) of
 	<<>> -> proplists:get_value(username, Props, <<>>);
diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl
index 5a39df043..d82e32b9a 100644
--- a/src/ejabberd_config.erl
+++ b/src/ejabberd_config.erl
@@ -877,7 +877,7 @@ v_db(Mod, Type) ->
 	[] -> erlang:error(badarg)
     end.
 
--spec default_db(binary(), module()) -> atom().
+-spec default_db(global | binary(), module()) -> atom().
 
 default_db(Host, Module) ->
     case ejabberd_config:get_option(
diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl
index dca456427..c2bf453a5 100644
--- a/src/ejabberd_local.erl
+++ b/src/ejabberd_local.erl
@@ -183,14 +183,13 @@ unregister_iq_handler(Host, XMLNS) ->
 refresh_iq_handlers() ->
     ejabberd_local ! refresh_iq_handlers.
 
--spec bounce_resource_packet(jid(), jid(), stanza()) -> stop.
+-spec bounce_resource_packet(jid(), jid(), stanza()) -> ok.
 bounce_resource_packet(From, To, Packet) ->
     Lang = xmpp:get_lang(Packet),
     Txt = <<"No available resource found">>,
     Err = xmpp:make_error(Packet,
 			  xmpp:err_item_not_found(Txt, Lang)),
-    ejabberd_router:route(To, From, Err),
-    stop.
+    ejabberd_router:route(To, From, Err).
 
 %%====================================================================
 %% gen_server callbacks
diff --git a/src/ejabberd_router_multicast.erl b/src/ejabberd_router_multicast.erl
index 967699007..283bcac25 100644
--- a/src/ejabberd_router_multicast.erl
+++ b/src/ejabberd_router_multicast.erl
@@ -45,7 +45,7 @@
 -include("logger.hrl").
 -include("xmpp.hrl").
 
--record(route_multicast, {domain = <<"">> :: binary(),
+-record(route_multicast, {domain = <<"">> :: binary() | '_',
 			  pid = self() :: pid()}).
 -record(state, {}).
 
diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl
index 04b961b3d..7be4906fb 100644
--- a/src/ejabberd_s2s_in.erl
+++ b/src/ejabberd_s2s_in.erl
@@ -62,7 +62,7 @@
 	 connections = (?DICT):new() :: ?TDICT,
          timer = make_ref()          :: reference()}).
 
--type state_name() :: wait_for_stream | wait_for_features | stream_established.
+-type state_name() :: wait_for_stream | wait_for_feature_request | stream_established.
 -type state() :: #state{}.
 -type fsm_next() :: {next_state, state_name(), state()}.
 -type fsm_stop() :: {stop, normal, state()}.
@@ -287,7 +287,8 @@ wait_for_feature_request(#starttls{},
 		      end,
 	    TLSSocket = (StateData#state.sockmod):starttls(
 			  Socket, TLSOpts,
-			  fxml:element_to_binary(#starttls_proceed{})),
+			  fxml:element_to_binary(
+			    xmpp:encode(#starttls_proceed{}))),
 	    {next_state, wait_for_stream,
 	     StateData#state{socket = TLSSocket, streamid = new_id(),
 			     tls_enabled = true, tls_options = TLSOpts}};
@@ -342,19 +343,17 @@ stream_established({xmlstreamelement, El}, StateData) ->
 stream_established(#db_result{to = To, from = From, key = Key},
 		   StateData) ->
     ?DEBUG("GET KEY: ~p", [{To, From, Key}]),
-    LTo = To#jid.lserver,
-    LFrom = From#jid.lserver,
-    case {ejabberd_s2s:allow_host(LTo, LFrom),
-	  lists:member(LTo, ejabberd_router:dirty_get_all_domains())} of
+    case {ejabberd_s2s:allow_host(To, From),
+	  lists:member(To, ejabberd_router:dirty_get_all_domains())} of
 	{true, true} ->
-	    ejabberd_s2s_out:terminate_if_waiting_delay(LTo, LFrom),
-	    ejabberd_s2s_out:start(LTo, LFrom,
+	    ejabberd_s2s_out:terminate_if_waiting_delay(To, From),
+	    ejabberd_s2s_out:start(To, From,
 				   {verify, self(), Key,
 				    StateData#state.streamid}),
-	    Conns = (?DICT):store({LFrom, LTo},
+	    Conns = (?DICT):store({From, To},
 				  wait_for_verification,
 				  StateData#state.connections),
-	    change_shaper(StateData, LTo, jid:make(LFrom)),
+	    change_shaper(StateData, To, jid:make(From)),
 	    {next_state, stream_established,
 	     StateData#state{connections = Conns}};
 	{_, false} ->
@@ -367,9 +366,7 @@ stream_established(#db_result{to = To, from = From, key = Key},
 stream_established(#db_verify{to = To, from = From, id = Id, key = Key},
 		   StateData) ->
     ?DEBUG("VERIFY KEY: ~p", [{To, From, Id, Key}]),
-    LTo = jid:nameprep(To),
-    LFrom = jid:nameprep(From),
-    Type = case ejabberd_s2s:make_key({LTo, LFrom}, Id) of
+    Type = case ejabberd_s2s:make_key({To, From}, Id) of
 	       Key -> valid;
 	       _ -> invalid
 	   end,
@@ -412,19 +409,15 @@ stream_established({valid, From, To}, StateData) ->
 		 #db_result{from = To, to = From, type = valid}),
     ?INFO_MSG("Accepted s2s dialback authentication for ~s (TLS=~p)",
 	      [From, StateData#state.tls_enabled]),
-    LFrom = jid:nameprep(From),
-    LTo = jid:nameprep(To),
     NSD = StateData#state{connections =
-			      (?DICT):store({LFrom, LTo}, established,
+			      (?DICT):store({From, To}, established,
 					    StateData#state.connections)},
     {next_state, stream_established, NSD};
 stream_established({invalid, From, To}, StateData) ->
     send_element(StateData,
 		 #db_result{from = To, to = From, type = invalid}),
-    LFrom = jid:nameprep(From),
-    LTo = jid:nameprep(To),
     NSD = StateData#state{connections =
-			      (?DICT):erase({LFrom, LTo},
+			      (?DICT):erase({From, To},
 					    StateData#state.connections)},
     {next_state, stream_established, NSD};
 stream_established({xmlstreamend, _Name}, StateData) ->
diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl
index 024e51e7a..4284f7f7b 100644
--- a/src/ejabberd_s2s_out.erl
+++ b/src/ejabberd_s2s_out.erl
@@ -832,15 +832,15 @@ send_db_request(StateData) ->
 		       {StateData#state.myname, Server},
 		       StateData#state.remote_streamid),
 	      send_element(StateData,
-			   #db_result{from = jid:make(StateData#state.myname),
-				      to = jid:make(Server),
+			   #db_result{from = StateData#state.myname,
+				      to = Server,
 				      key = Key1})
 	end,
 	case StateData#state.verify of
 	  false -> ok;
 	  {_Pid, Key2, SID} ->
 	      send_element(StateData,
-			   #db_verify{from = jid:make(StateData#state.myname),
+			   #db_verify{from = StateData#state.myname,
 				      to = StateData#state.server,
 				      id = SID,
 				      key = Key2})
@@ -1067,7 +1067,7 @@ get_max_retry_delay() ->
     end.
 
 %% Terminate s2s_out connections that are in state wait_before_retry
--spec terminate_if_waiting_delay(ljid(), ljid()) -> ok.
+-spec terminate_if_waiting_delay(binary(), binary()) -> ok.
 terminate_if_waiting_delay(From, To) ->
     FromTo = {From, To},
     Pids = ejabberd_s2s:get_connections_pids(FromTo),
diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl
index 432253e09..3df39438a 100644
--- a/src/ejabberd_service.erl
+++ b/src/ejabberd_service.erl
@@ -127,7 +127,7 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) ->
     try xmpp:decode(#xmlel{name = Name, attrs = Attrs}) of
 	#stream_start{xmlns = ?NS_COMPONENT, to = To} when is_record(To, jid) ->
 	    Host = To#jid.lserver,
-	    send_header(StateData, To),
+	    send_header(StateData, Host),
 	    HostOpts = case dict:is_key(Host, StateData#state.host_opts) of
 			   true ->
 			       StateData#state.host_opts;
diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl
index bc550ef44..3ff9f2908 100644
--- a/src/ejabberd_sm.erl
+++ b/src/ejabberd_sm.erl
@@ -110,7 +110,7 @@
 %%====================================================================
 %% API
 %%====================================================================
--export_type([sid/0]).
+-export_type([sid/0, info/0]).
 
 start() ->
     ChildSpec = {?MODULE, {?MODULE, start_link, []},
@@ -168,7 +168,7 @@ check_in_subscription(Acc, User, Server, _JID, _Type, _Reason) ->
       false -> {stop, false}
     end.
 
--spec bounce_offline_message(jid(), jid(), xmlel()) -> stop.
+-spec bounce_offline_message(jid(), jid(), message()) -> stop.
 
 bounce_offline_message(From, To, Packet) ->
     Lang = xmpp:get_lang(Packet),
@@ -234,7 +234,7 @@ get_user_info(User, Server, Resource) ->
     end.
 
 -spec set_presence(sid(), binary(), binary(), binary(),
-                   prio(), xmlel(), info()) -> ok.
+                   prio(), presence(), info()) -> ok.
 
 set_presence(SID, User, Server, Resource, Priority,
 	     Presence, Info) ->
@@ -750,7 +750,7 @@ process_iq(From, To, #iq{type = T} = Packet) when T == get; T == set ->
 process_iq(_From, _To, #iq{}) ->
     ok.
 
--spec force_update_presence({binary(), binary()}) -> any().
+-spec force_update_presence({binary(), binary()}) -> ok.
 
 force_update_presence({LUser, LServer}) ->
     Mod = get_sm_backend(LServer),
diff --git a/src/ejabberd_socket.erl b/src/ejabberd_socket.erl
index 7160025e7..f8dc84630 100644
--- a/src/ejabberd_socket.erl
+++ b/src/ejabberd_socket.erl
@@ -65,7 +65,7 @@
 
 -type socket_state() :: #socket_state{}.
 
--export_type([socket_state/0, sockmod/0]).
+-export_type([socket/0, socket_state/0, sockmod/0]).
 
 
 %%====================================================================
diff --git a/src/ejabberd_system_monitor.erl b/src/ejabberd_system_monitor.erl
index ae7cb2d88..7f815a57e 100644
--- a/src/ejabberd_system_monitor.erl
+++ b/src/ejabberd_system_monitor.erl
@@ -61,6 +61,7 @@ start_link() ->
     gen_server:start_link({local, ?MODULE}, ?MODULE, Opts,
 			  []).
 
+-spec process_command(jid(), jid(), stanza()) -> ok.
 process_command(From, To, Packet) ->
     case To of
       #jid{luser = <<"">>, lresource = <<"watchdog">>} ->
@@ -75,7 +76,7 @@ process_command(From, To, Packet) ->
 				    process_flag(priority, high),
 				    process_command1(From, To, BodyText)
 			    end),
-		      stop;
+		      ok;
 		  false -> ok
 		end;
 	    _ -> ok
diff --git a/src/ejabberd_web_admin.erl b/src/ejabberd_web_admin.erl
index e62b4d257..2740e2879 100644
--- a/src/ejabberd_web_admin.erl
+++ b/src/ejabberd_web_admin.erl
@@ -1045,17 +1045,21 @@ process_admin(Host,
 process_admin(Host,
 	      #request{lang = Lang, auth = {_, _Auth, AJID}} =
 		  Request) ->
-    {Hook, Opts} = case Host of
-		     global -> {webadmin_page_main, [Request]};
-		     Host -> {webadmin_page_host, [Host, Request]}
-		   end,
-    case ejabberd_hooks:run_fold(Hook, Host, [], Opts) of
+    Res = case Host of
+	      global ->
+		  ejabberd_hooks:run_fold(
+		    webadmin_page_main, Host, [], [Request]);
+	      _ ->
+		  ejabberd_hooks:run_fold(
+		    webadmin_page_host, Host, [], [Host, Request])
+	  end,
+    case Res of
       [] ->
 	  setelement(1,
 		     make_xhtml([?XC(<<"h1">>, <<"Not Found">>)], Host, Lang,
 				AJID),
 		     404);
-      Res -> make_xhtml(Res, Host, Lang, AJID)
+      _ -> make_xhtml(Res, Host, Lang, AJID)
     end.
 
 %%%==================================
@@ -2269,16 +2273,17 @@ get_node(global, Node, [<<"update">>], Query, Lang) ->
 	       ?BR,
 	       ?INPUTT(<<"submit">>, <<"update">>, <<"Update">>)])];
 get_node(Host, Node, NPath, Query, Lang) ->
-    {Hook, Opts} = case Host of
-		     global ->
-			 {webadmin_page_node, [Node, NPath, Query, Lang]};
-		     Host ->
-			 {webadmin_page_hostnode,
-			  [Host, Node, NPath, Query, Lang]}
-		   end,
-    case ejabberd_hooks:run_fold(Hook, Host, [], Opts) of
+    Res = case Host of
+	      global ->
+		  ejabberd_hooks:run_fold(webadmin_page_node, Host, [],
+					  [Node, NPath, Query, Lang]);
+	      _ ->
+		  ejabberd_hooks:run_fold(webadmin_page_hostnode, Host, [],
+					  [Host, Node, NPath, Query, Lang])
+	  end,
+    case Res of
       [] -> [?XC(<<"h1">>, <<"Not Found">>)];
-      Res -> Res
+      _ -> Res
     end.
 
 %%%==================================
diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl
index f78ba7e40..fcfe9f3a7 100644
--- a/src/gen_iq_handler.erl
+++ b/src/gen_iq_handler.erl
@@ -47,6 +47,7 @@
 -type component() :: ejabberd_sm | ejabberd_local.
 -type type() :: no_queue | one_queue | pos_integer() | parallel.
 -type opts() :: no_queue | {one_queue, pid()} | {queues, [pid()]} | parallel.
+-export_type([opts/0]).
 
 %%====================================================================
 %% API
diff --git a/src/gen_mod.erl b/src/gen_mod.erl
index e5b504897..476e19e9d 100644
--- a/src/gen_mod.erl
+++ b/src/gen_mod.erl
@@ -378,7 +378,7 @@ db_type(Host, Module) when is_atom(Module) ->
 	    undefined
     end.
 
--spec db_type(binary(), opts(), module()) -> db_type().
+-spec db_type(global | binary(), opts(), module()) -> db_type().
 
 db_type(Host, Opts, Module) ->
     case catch Module:mod_opt_type(db_type) of
diff --git a/src/mod_adhoc.erl b/src/mod_adhoc.erl
index 22bde2586..e6d94e40a 100644
--- a/src/mod_adhoc.erl
+++ b/src/mod_adhoc.erl
@@ -173,7 +173,9 @@ get_sm_identity(Acc, _From, _To, ?NS_COMMANDS, Lang) ->
 get_sm_identity(Acc, _From, _To, _Node, _Lang) -> Acc.
 
 %-------------------------------------------------------------------------
-
+-spec get_local_features({error, error()} | {result, [binary()]} | empty,
+			 jid(), jid(), binary(), binary()) ->
+				{error, error()} | {result, [binary()]} | empty.
 get_local_features(Acc, _From, _To, <<"">>, _Lang) ->
     Feats = case Acc of
 	      {result, I} -> I;
@@ -205,16 +207,24 @@ get_sm_features(Acc, _From, _To, _Node, _Lang) -> Acc.
 %-------------------------------------------------------------------------
 
 process_local_iq(IQ) ->
-    process_adhoc_request(IQ, adhoc_local_commands).
+    process_adhoc_request(IQ, local).
 
 process_sm_iq(IQ) ->
-    process_adhoc_request(IQ, adhoc_sm_commands).
+    process_adhoc_request(IQ, sm).
 
 process_adhoc_request(#iq{from = From, to = To,
 			  type = set, lang = Lang,
-			  sub_els = [#adhoc_command{} = SubEl]} = IQ, Hook) ->
+			  sub_els = [#adhoc_command{} = SubEl]} = IQ, Type) ->
     Host = To#jid.lserver,
-    case ejabberd_hooks:run_fold(Hook, Host, empty, [From, To, SubEl]) of
+    Res = case Type of
+	      local ->
+		  ejabberd_hooks:run_fold(adhoc_local_commands, Host, empty,
+					  [From, To, SubEl]);
+	      sm ->
+		  ejabberd_hooks:run_fold(adhoc_sm_commands, Host, empty,
+					  [From, To, SubEl])
+	  end,
+    case Res of
 	ignore ->
 	    ignore;
 	empty ->
@@ -228,6 +238,8 @@ process_adhoc_request(#iq{from = From, to = To,
 process_adhoc_request(#iq{} = IQ, _Hooks) ->
     xmpp:make_error(IQ, xmpp:err_bad_request()).
 
+-spec ping_item(empty | {error, error()} | {result, [disco_item()]},
+		jid(), jid(), binary()) -> {result, [disco_item()]}.
 ping_item(Acc, _From, #jid{server = Server} = _To,
 	  Lang) ->
     Items = case Acc of
@@ -239,6 +251,8 @@ ping_item(Acc, _From, #jid{server = Server} = _To,
 			 name = translate:translate(Lang, <<"Ping">>)}],
     {result, Items ++ Nodes}.
 
+-spec ping_command(adhoc_command(), jid(), jid(), adhoc_command()) ->
+			  adhoc_command() | {error, error()}.
 ping_command(_Acc, _From, _To,
 	     #adhoc_command{lang = Lang, node = <<"ping">>,
 			    action = Action} = Request) ->
diff --git a/src/mod_announce.erl b/src/mod_announce.erl
index 1a42a460b..eb201fc88 100644
--- a/src/mod_announce.erl
+++ b/src/mod_announce.erl
@@ -130,42 +130,34 @@ stop(Host) ->
     {wait, Proc}.
 
 %% Announcing via messages to a custom resource
+-spec announce(jid(), jid(), stanza()) -> ok.
 announce(From, #jid{luser = <<>>} = To, #message{} = Packet) ->
     Proc = gen_mod:get_module_proc(To#jid.lserver, ?PROCNAME),
     case To#jid.lresource of
         <<"announce/all">> ->
-            Proc ! {announce_all, From, To, Packet},
-            stop;
+            Proc ! {announce_all, From, To, Packet};
         <<"announce/all-hosts/all">> ->
-            Proc ! {announce_all_hosts_all, From, To, Packet},
-            stop;
+            Proc ! {announce_all_hosts_all, From, To, Packet};
         <<"announce/online">> ->
-            Proc ! {announce_online, From, To, Packet},
-            stop;
+            Proc ! {announce_online, From, To, Packet};
         <<"announce/all-hosts/online">> ->
-            Proc ! {announce_all_hosts_online, From, To, Packet},
-            stop;
+            Proc ! {announce_all_hosts_online, From, To, Packet};
         <<"announce/motd">> ->
-            Proc ! {announce_motd, From, To, Packet},
-            stop;
+            Proc ! {announce_motd, From, To, Packet};
         <<"announce/all-hosts/motd">> ->
-            Proc ! {announce_all_hosts_motd, From, To, Packet},
-            stop;
+            Proc ! {announce_all_hosts_motd, From, To, Packet};
         <<"announce/motd/update">> ->
-            Proc ! {announce_motd_update, From, To, Packet},
-            stop;
+            Proc ! {announce_motd_update, From, To, Packet};
         <<"announce/all-hosts/motd/update">> ->
-            Proc ! {announce_all_hosts_motd_update, From, To, Packet},
-            stop;
+            Proc ! {announce_all_hosts_motd_update, From, To, Packet};
         <<"announce/motd/delete">> ->
-            Proc ! {announce_motd_delete, From, To, Packet},
-            stop;
+            Proc ! {announce_motd_delete, From, To, Packet};
         <<"announce/all-hosts/motd/delete">> ->
-            Proc ! {announce_all_hosts_motd_delete, From, To, Packet},
-            stop;
+            Proc ! {announce_all_hosts_motd_delete, From, To, Packet};
         _ ->
             ok
-    end;
+    end,
+    ok;
 announce(_From, _To, _Packet) ->
     ok.
 
@@ -344,7 +336,10 @@ disco_items(Acc, From, #jid{lserver = LServer} = _To, Node, Lang) ->
     end.
 
 %%-------------------------------------------------------------------------
-
+-spec announce_items(empty | {error, error()} | {result, [disco_item()]},
+			jid(), jid(), binary()) -> {error, error()} |
+						   {result, [disco_item()]} |
+						   empty.
 announce_items(Acc, From, #jid{lserver = LServer, server = Server} = _To, Lang) ->
     Access1 = get_access(LServer),
     Nodes1 = case acl:match_rule(LServer, Access1, From) of
@@ -390,7 +385,8 @@ commands_result(Allow, From, To, Request) ->
 	    announce_commands(From, To, Request)
     end.
 
-
+-spec announce_commands(adhoc_command(), jid(), jid(), adhoc_command()) ->
+			       adhoc_command() | {error, error()}.
 announce_commands(Acc, From, #jid{lserver = LServer} = To,
 		  #adhoc_command{node = Node} = Request) ->
     LNode = tokenize(Node),
@@ -764,6 +760,7 @@ announce_motd_delete(LServer) ->
     Mod = gen_mod:db_mod(LServer, ?MODULE),
     Mod:delete_motd(LServer).
 
+-spec send_motd(jid()) -> ok | {atomic, any()}.
 send_motd(#jid{luser = LUser, lserver = LServer} = JID) when LUser /= <<>> ->
     Mod = gen_mod:db_mod(LServer, ?MODULE),
     case Mod:get_motd(LServer) of
diff --git a/src/mod_blocking.erl b/src/mod_blocking.erl
index bc3080871..98fb1e441 100644
--- a/src/mod_blocking.erl
+++ b/src/mod_blocking.erl
@@ -227,16 +227,13 @@ make_userlist(Name, List) ->
     NeedDb = mod_privacy:is_list_needdb(List),
     #userlist{name = Name, list = List, needdb = NeedDb}.
 
--spec broadcast_list_update(binary(), binary(), binary(), userlist()) ->
-				   {broadcast,
-				    {privacy_list, userlist(), binary() | none}}.
+-spec broadcast_list_update(binary(), binary(), binary(), userlist()) -> ok.
 broadcast_list_update(LUser, LServer, Name, UserList) ->
     ejabberd_sm:route(jid:make(LUser, LServer, <<"">>),
                       jid:make(LUser, LServer, <<"">>),
                       {broadcast, {privacy_list, UserList, Name}}).
 
--spec broadcast_blocklist_event(binary(), binary(), block_event()) ->
-				       {broadcast, {blocking, block_event()}}.
+-spec broadcast_blocklist_event(binary(), binary(), block_event()) -> ok.
 broadcast_blocklist_event(LUser, LServer, Event) ->
     JID = jid:make(LUser, LServer, <<"">>),
     ejabberd_sm:route(JID, JID,
diff --git a/src/mod_caps.erl b/src/mod_caps.erl
index d5033ffd8..e57bc7928 100644
--- a/src/mod_caps.erl
+++ b/src/mod_caps.erl
@@ -161,7 +161,7 @@ caps_stream_features(Acc, MyHost) ->
 -spec disco_features({error, error()} | {result, [binary()]} | empty,
 		     jid(), jid(),
 		     binary(), binary()) ->
-			    {error, error()} | {result, [binary()]}.
+			    {error, error()} | {result, [binary()]} | empty.
 disco_features(Acc, From, To, Node, Lang) ->
     case is_valid_node(Node) of
         true ->
@@ -185,16 +185,18 @@ disco_identity(Acc, From, To, Node, Lang) ->
             Acc
     end.
 
--spec disco_info([xdata()], binary(), module(),
-		 binary(), binary()) -> [xdata()].
-disco_info(Acc, Host, Module, Node, Lang) ->
+-spec disco_info([xdata()], binary(), module(), binary(), binary()) -> [xdata()];
+		([xdata()], jid(), jid(), binary(), binary()) -> [xdata()].
+disco_info(Acc, Host, Module, Node, Lang) when is_atom(Module) ->
     case is_valid_node(Node) of
         true ->
             ejabberd_hooks:run_fold(disco_info, Host, [],
                                     [Host, Module, <<"">>, Lang]);
         false ->
             Acc
-    end.
+    end;
+disco_info(Acc, _, _, _Node, _Lang) ->
+    Acc.
 
 -spec c2s_presence_in(ejabberd_c2s:state(), {jid(), jid(), presence()}) ->
 			     ejabberd_c2s:state().
@@ -277,6 +279,7 @@ c2s_broadcast_recipients(InAcc, Host, C2SState,
     end;
 c2s_broadcast_recipients(Acc, _, _, _, _, _) -> Acc.
 
+-spec depends(binary(), gen_mod:opts()) -> [{module(), hard | soft}].
 depends(_Host, _Opts) ->
     [].
 
@@ -403,13 +406,13 @@ feature_response(_IQResult, Host, From, Caps,
 		 [_SubNode | SubNodes]) ->
     feature_request(Host, From, Caps, SubNodes).
 
--spec caps_read_fun(binary(), binary()) -> function().
+-spec caps_read_fun(binary(), {binary(), binary()}) -> function().
 caps_read_fun(Host, Node) ->
     LServer = jid:nameprep(Host),
     Mod = gen_mod:db_mod(LServer, ?MODULE),
     fun() -> Mod:caps_read(LServer, Node) end.
 
--spec caps_write_fun(binary(), binary(), [binary()]) -> function().
+-spec caps_write_fun(binary(), {binary(), binary()}, [binary()]) -> function().
 caps_write_fun(Host, Node, Features) ->
     LServer = jid:nameprep(Host),
     Mod = gen_mod:db_mod(LServer, ?MODULE),
@@ -437,8 +440,8 @@ make_my_disco_hash(Host) ->
       _Err -> <<"">>
     end.
 
--spec make_disco_hash(disco_info(), crypto:digest_type()) -> binary().
-
+-type digest_type() :: md5 | sha | sha224 | sha256 | sha384 | sha512.
+-spec make_disco_hash(disco_info(), digest_type()) -> binary().
 make_disco_hash(DiscoInfo, Algo) ->
     Concat = list_to_binary([concat_identities(DiscoInfo),
                              concat_features(DiscoInfo), concat_info(DiscoInfo)]),
@@ -469,19 +472,23 @@ check_hash(Caps, DiscoInfo) ->
       _ -> true
     end.
 
+-spec concat_features(disco_info()) -> iolist().
 concat_features(#disco_info{features = Features}) ->
     lists:usort([[Feat, $<] || Feat <- Features]).
 
+-spec concat_identities(disco_info()) -> iolist().
 concat_identities(#disco_info{identities = Identities}) ->
     lists:sort(
       [[Cat, $/, T, $/, Lang, $/, Name, $<] ||
 	  #identity{category = Cat, type = T,
 		    lang = Lang, name = Name} <- Identities]).
 
+-spec concat_info(disco_info()) -> iolist().
 concat_info(#disco_info{xdata = Xs}) ->
     lists:sort(
       [concat_xdata_fields(Fs) || #xdata{type = result, fields = Fs} <- Xs]).
 
+-spec concat_xdata_fields([xdata_field()]) -> iolist().
 concat_xdata_fields(Fields) ->
     Form = case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var, Fields) of
 	       #xdata_field{values = Values} -> Values;
@@ -492,10 +499,12 @@ concat_xdata_fields(Fields) ->
 	      is_binary(Var), Var /= <<"FORM_TYPE">>],
     [Form, $<, lists:sort(Res)].
 
+-spec gb_trees_fold(fun((_, _, T) -> T), T, gb_trees:tree()) -> T.
 gb_trees_fold(F, Acc, Tree) ->
     Iter = gb_trees:iterator(Tree),
     gb_trees_fold_iter(F, Acc, Iter).
 
+-spec gb_trees_fold_iter(fun((_, _, T) -> T), T, gb_trees:iter()) -> T.
 gb_trees_fold_iter(F, Acc, Iter) ->
     case gb_trees:next(Iter) of
       {Key, Val, NewIter} ->
@@ -504,6 +513,7 @@ gb_trees_fold_iter(F, Acc, Iter) ->
       _ -> Acc
     end.
 
+-spec now_ts() -> integer().
 now_ts() ->
     p1_time_compat:system_time(seconds).
 
diff --git a/src/mod_carboncopy.erl b/src/mod_carboncopy.erl
index b70ccbc2a..e35caa1c7 100644
--- a/src/mod_carboncopy.erl
+++ b/src/mod_carboncopy.erl
@@ -197,7 +197,7 @@ send_copies(JID, To, Packet, Direction)->
 
 -spec build_forward_packet(jid(), message(), jid(), jid(), direction()) -> message().
 build_forward_packet(JID, #message{type = T} = Msg, Sender, Dest, Direction) ->
-    Forwarded = #forwarded{sub_els = complete_packet(JID, Msg, Direction)},
+    Forwarded = #forwarded{sub_els = [complete_packet(JID, Msg, Direction)]},
     Carbon = case Direction of
 		 sent -> #carbons_sent{forwarded = Forwarded};
 		 received -> #carbons_received{forwarded = Forwarded}
diff --git a/src/mod_client_state.erl b/src/mod_client_state.erl
index a6a6ddc20..042c59702 100644
--- a/src/mod_client_state.erl
+++ b/src/mod_client_state.erl
@@ -151,12 +151,13 @@ depends(_Host, _Opts) ->
 %% ejabberd_hooks callbacks.
 %%--------------------------------------------------------------------
 
--spec filter_presence({term(), [stanza()]}, binary(), stanza())
-      -> {term(), [stanza()]} | {stop, {term(), [stanza()]}}.
+-spec filter_presence({ejabberd_c2s:state(), [stanza()]}, binary(), stanza())
+      -> {ejabberd_c2s:state(), [stanza()]} |
+	 {stop, {ejabberd_c2s:state(), [stanza()]}}.
 
 filter_presence({C2SState, _OutStanzas} = Acc, Host,
 		#presence{type = Type} = Stanza) ->
-    if Type == available, Type == unavailable ->
+    if Type == available; Type == unavailable ->
 	    ?DEBUG("Got availability presence stanza", []),
 	    queue_add(presence, Stanza, Host, C2SState);
        true ->
@@ -164,8 +165,9 @@ filter_presence({C2SState, _OutStanzas} = Acc, Host,
     end;
 filter_presence(Acc, _Host, _Stanza) -> Acc.
 
--spec filter_chat_states({term(), [stanza()]}, binary(), stanza())
-      -> {term(), [stanza()]} | {stop, {term(), [stanza()]}}.
+-spec filter_chat_states({ejabberd_c2s:state(), [stanza()]}, binary(), stanza())
+      -> {ejabberd_c2s:state(), [stanza()]} |
+	 {stop, {ejabberd_c2s:state(), [stanza()]}}.
 
 filter_chat_states({C2SState, _OutStanzas} = Acc, Host,
 		   #message{from = From, to = To} = Stanza) ->
@@ -186,8 +188,9 @@ filter_chat_states({C2SState, _OutStanzas} = Acc, Host,
     end;
 filter_chat_states(Acc, _Host, _Stanza) -> Acc.
 
--spec filter_pep({term(), [stanza()]}, binary(), stanza())
-      -> {term(), [stanza()]} | {stop, {term(), [stanza()]}}.
+-spec filter_pep({ejabberd_c2s:state(), [stanza()]}, binary(), stanza())
+      -> {ejabberd_c2s:state(), [stanza()]} |
+	 {stop, {ejabberd_c2s:state(), [stanza()]}}.
 
 filter_pep({C2SState, _OutStanzas} = Acc, Host, #message{} = Stanza) ->
     case get_pep_node(Stanza) of
@@ -199,14 +202,15 @@ filter_pep({C2SState, _OutStanzas} = Acc, Host, #message{} = Stanza) ->
     end;
 filter_pep(Acc, _Host, _Stanza) -> Acc.
 
--spec filter_other({term(), [stanza()]}, binary(), stanza())
-      -> {stop, {term(), [stanza()]}}.
+-spec filter_other({ejabberd_c2s:state(), [stanza()]}, binary(), stanza())
+      -> {stop, {ejabberd_c2s:state(), [stanza()]}}.
 
 filter_other({C2SState, _OutStanzas}, Host, Stanza) ->
     ?DEBUG("Won't add stanza to CSI queue", []),
     queue_take(Stanza, Host, C2SState).
 
--spec flush_queue({term(), [stanza()]}, binary()) -> {term(), [stanza()]}.
+-spec flush_queue({ejabberd_c2s:state(), [stanza()]}, binary())
+      -> {ejabberd_c2s:state(), [stanza()]}.
 
 flush_queue({C2SState, _OutStanzas}, Host) ->
     ?DEBUG("Going to flush CSI queue", []),
@@ -284,7 +288,7 @@ get_pep_node(#message{from = #jid{luser = <<>>}}) ->
     undefined;
 get_pep_node(#message{} = Msg) ->
     case xmpp:get_subtag(Msg, #pubsub_event{}) of
-	#pubsub_event{items = [#pubsub_event_item{node = Node}]} ->
+	#pubsub_event{items = [#pubsub_event_items{node = Node}]} ->
 	    Node;
 	_ ->
 	    undefined
diff --git a/src/mod_configure.erl b/src/mod_configure.erl
index 07a1c7333..a798d010f 100644
--- a/src/mod_configure.erl
+++ b/src/mod_configure.erl
@@ -270,7 +270,10 @@ get_local_features(Acc, From,
     end.
 
 %%%-----------------------------------------------------------------------
-
+-spec adhoc_sm_items(empty | {error, error()} | {result, [disco_item()]},
+		     jid(), jid(), binary()) -> {error, error()} |
+						{result, [disco_item()]} |
+						empty.
 adhoc_sm_items(Acc, From, #jid{lserver = LServer} = To,
 	       Lang) ->
     case acl:match_rule(LServer, configure, From) of
@@ -322,6 +325,10 @@ get_user_resources(User, Server) ->
 
 %%%-----------------------------------------------------------------------
 
+-spec adhoc_local_items(empty | {error, error()} | {result, [disco_item()]},
+			jid(), jid(), binary()) -> {error, error()} |
+						   {result, [disco_item()]} |
+						   empty.
 adhoc_local_items(Acc, From,
 		  #jid{lserver = LServer, server = Server} = To, Lang) ->
     case acl:match_rule(LServer, configure, From) of
@@ -765,6 +772,8 @@ get_stopped_nodes(_Lang) ->
 	  allow -> adhoc_local_commands(From, To, Request)
 	end).
 
+-spec adhoc_local_commands(adhoc_command(), jid(), jid(), adhoc_command()) ->
+				  adhoc_command() | {error, error()}.
 adhoc_local_commands(Acc, From,
 		     #jid{lserver = LServer} = To,
 		     #adhoc_command{node = Node, lang = Lang} = Request) ->
@@ -1672,8 +1681,7 @@ set_form(_From, _Host, _, _Lang, _XData) ->
 get_value(Field, XData) -> hd(get_values(Field, XData)).
 
 get_values(Field, XData) ->
-    [_|_] = Values = xmpp_util:get_xdata_values(Field, XData),
-    Values.
+    xmpp_util:get_xdata_values(Field, XData).
 
 search_running_node(SNode) ->
     search_running_node(SNode,
@@ -1723,7 +1731,7 @@ get_last_info(User, Server) ->
     end.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
+-spec adhoc_sm_commands(adhoc_command(), jid(), jid(), adhoc_command()) -> adhoc_command().
 adhoc_sm_commands(_Acc, From,
 		  #jid{user = User, server = Server, lserver = LServer},
 		  #adhoc_command{lang = Lang, node = <<"config">>,
diff --git a/src/mod_disco.erl b/src/mod_disco.erl
index e78b8f72f..e33241928 100644
--- a/src/mod_disco.erl
+++ b/src/mod_disco.erl
@@ -424,8 +424,9 @@ transform_module_options(Opts) ->
 
 %%% Support for: XEP-0157 Contact Addresses for XMPP Services
 
--spec get_info([xdata()], binary(), module(), binary(), binary()) -> [xdata()].
-get_info(_A, Host, Mod, Node, _Lang) when Node == <<"">> ->
+-spec get_info([xdata()], binary(), module(), binary(), binary()) -> [xdata()];
+	      ([xdata()], jid(), jid(), binary(), binary()) -> [xdata()].
+get_info(_A, Host, Mod, Node, _Lang) when is_atom(Mod), Node == <<"">> ->
     Module = case Mod of
 	       undefined -> ?MODULE;
 	       _ -> Mod
diff --git a/src/mod_fail2ban.erl b/src/mod_fail2ban.erl
index c57ac21b0..cc3b4bf7f 100644
--- a/src/mod_fail2ban.erl
+++ b/src/mod_fail2ban.erl
@@ -52,6 +52,8 @@ start_link(Host, Opts) ->
     Proc = gen_mod:get_module_proc(Host, ?MODULE),
     gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []).
 
+-spec c2s_auth_result(boolean(), binary(), binary(),
+		      {inet:ip_address(), non_neg_integer()}) -> ok.
 c2s_auth_result(false, _User, LServer, {Addr, _Port}) ->
     case is_whitelisted(LServer, Addr) of
 	true ->
@@ -71,11 +73,15 @@ c2s_auth_result(false, _User, LServer, {Addr, _Port}) ->
 		    ets:insert(failed_auth, {Addr, N+1, UnbanTS, MaxFailures});
 		[] ->
 		    ets:insert(failed_auth, {Addr, 1, UnbanTS, MaxFailures})
-	    end
+	    end,
+	    ok
     end;
 c2s_auth_result(true, _User, _Server, _AddrPort) ->
     ok.
 
+-spec check_bl_c2s({true, binary(), binary()} | false,
+		   {inet:ip_address(), non_neg_integer()},
+		   binary()) -> {stop, {true, binary(), binary()}} | false.
 check_bl_c2s(_Acc, Addr, Lang) ->
     case ets:lookup(failed_auth, Addr) of
 	[{Addr, N, TS, MaxFailures}] when N >= MaxFailures ->
diff --git a/src/mod_http_upload.erl b/src/mod_http_upload.erl
index 63dc2dfe2..babdbb7b6 100644
--- a/src/mod_http_upload.erl
+++ b/src/mod_http_upload.erl
@@ -553,8 +553,8 @@ process_iq(From, #iq{type = get, lang = Lang,
 						   {slot_timed_out,
 						    Slot}),
 		    NewState = add_slot(Slot, Size, Timer, State),
-		    Slot = mk_slot(Slot, State, XMLNS),
-		    {xmpp:make_iq_result(IQ, Slot), NewState};
+		    NewSlot = mk_slot(Slot, State, XMLNS),
+		    {xmpp:make_iq_result(IQ, NewSlot), NewState};
 		{ok, PutURL, GetURL} ->
 		    Slot = mk_slot(PutURL, GetURL, XMLNS),
 		    xmpp:make_iq_result(IQ, Slot);
@@ -668,11 +668,14 @@ del_slot(Slot, #state{slots = Slots} = State) ->
     NewSlots = maps:remove(Slot, Slots),
     State#state{slots = NewSlots}.
 
--spec mk_slot(slot() | binary(), state() | binary(), binary()) -> xmlel().
+-spec mk_slot(slot(), state(), binary()) -> upload_slot();
+	     (binary(), binary(), binary()) -> upload_slot().
 
 mk_slot(Slot, #state{put_url = PutPrefix, get_url = GetPrefix}, XMLNS) ->
     PutURL = str:join([PutPrefix | Slot], <<$/>>),
     GetURL = str:join([GetPrefix | Slot], <<$/>>),
+    mk_slot(PutURL, GetURL, XMLNS);
+mk_slot(PutURL, GetURL, XMLNS) ->
     #upload_slot{get = GetURL, put = PutURL, xmlns = XMLNS}.
 
 -spec make_user_string(jid(), sha1 | node) -> binary().
diff --git a/src/mod_ip_blacklist.erl b/src/mod_ip_blacklist.erl
index 4f54ecd79..897810927 100644
--- a/src/mod_ip_blacklist.erl
+++ b/src/mod_ip_blacklist.erl
@@ -109,6 +109,10 @@ update_bl_c2s() ->
 %% Return: false: IP not blacklisted
 %%         true: IP is blacklisted
 %% IPV4 IP tuple:
+-spec is_ip_in_c2s_blacklist(
+	{true, binary(), binary()} | false,
+	{inet:ip_address(), non_neg_integer()},
+	binary()) -> {stop, {true, binary(), binary()}} | false.
 is_ip_in_c2s_blacklist(_Val, IP, Lang) when is_tuple(IP) ->
     BinaryIP = jlib:ip_to_list(IP),
     case ets:lookup(bl_c2s, BinaryIP) of
diff --git a/src/mod_irc.erl b/src/mod_irc.erl
index 3c094ef9c..a833287c8 100644
--- a/src/mod_irc.erl
+++ b/src/mod_irc.erl
@@ -66,10 +66,8 @@
 
 -callback init(binary(), gen_mod:opts()) -> any().
 -callback import(binary(), #irc_custom{}) -> ok | pass.
--callback get_data(binary(), binary(), {binary(), binary()}) ->
-    error | empty | irc_data().
--callback set_data(binary(), binary(), {binary(), binary()}, irc_data()) ->
-    {atomic, any()}.
+-callback get_data(binary(), binary(), jid()) -> error | empty | irc_data().
+-callback set_data(binary(), binary(), jid(), irc_data()) -> {atomic, any()}.
 
 %%====================================================================
 %% API
diff --git a/src/mod_irc_connection.erl b/src/mod_irc_connection.erl
index 694accf45..c9b460ad0 100644
--- a/src/mod_irc_connection.erl
+++ b/src/mod_irc_connection.erl
@@ -584,12 +584,12 @@ handle_info({ircstring, <<$:, String/binary>>},
 		     [From, <<"MODE">>, <<$#, Chan/binary>>, <<"+o">>, Nick
 		      | _] ->
 			 process_mode_o(StateData, Chan, From, Nick,
-					<<"admin">>, <<"moderator">>),
+					admin, moderator),
 			 StateData;
 		     [From, <<"MODE">>, <<$#, Chan/binary>>, <<"-o">>, Nick
 		      | _] ->
 			 process_mode_o(StateData, Chan, From, Nick,
-					<<"member">>, <<"participant">>),
+					member, participant),
 			 StateData;
 		     [From, <<"KICK">>, <<$#, Chan/binary>>, Nick | _] ->
 			 process_kick(StateData, Chan, From, Nick, String),
@@ -756,16 +756,16 @@ process_channel_list_user(StateData, Chan, User) ->
 	    end,
     {User2, Affiliation, Role} = case User1 of
 				   <<$@, U2/binary>> ->
-				       {U2, <<"admin">>, <<"moderator">>};
+				       {U2, admin, moderator};
 				   <<$+, U2/binary>> ->
-				       {U2, <<"member">>, <<"participant">>};
+				       {U2, member, participant};
 				   <<$%, U2/binary>> ->
-				       {U2, <<"admin">>, <<"moderator">>};
+				       {U2, admin, moderator};
 				   <<$&, U2/binary>> ->
-				       {U2, <<"admin">>, <<"moderator">>};
+				       {U2, admin, moderator};
 				   <<$~, U2/binary>> ->
-				       {U2, <<"admin">>, <<"moderator">>};
-				   _ -> {User1, <<"member">>, <<"participant">>}
+				       {U2, admin, moderator};
+				   _ -> {User1, member, participant}
 				 end,
     ejabberd_router:route(
       jid:make(iolist_to_binary([Chan, <<"%">>, StateData#state.server]),
@@ -1157,8 +1157,6 @@ remove_element(E, Set) ->
 iq_admin(StateData, Channel, From, To,
 	 #iq{type = Type, sub_els = [SubEl]} = IQ) ->
     try process_iq_admin(StateData, Channel, Type, SubEl) of
-	ignore ->
-	    ignore;
 	{result, Result} ->
 	    ejabberd_router:route(To, From, xmpp:make_iq_result(IQ, Result));
 	{error, Error} ->
diff --git a/src/mod_mam.erl b/src/mod_mam.erl
index b83c423c7..7e93a3166 100644
--- a/src/mod_mam.erl
+++ b/src/mod_mam.erl
@@ -175,17 +175,21 @@ stop(Host) ->
 depends(_Host, _Opts) ->
     [].
 
+-spec remove_user(binary(), binary()) -> ok.
 remove_user(User, Server) ->
     LUser = jid:nodeprep(User),
     LServer = jid:nameprep(Server),
     Mod = gen_mod:db_mod(LServer, ?MODULE),
-    Mod:remove_user(LUser, LServer).
+    Mod:remove_user(LUser, LServer),
+    ok.
 
+-spec remove_room(binary(), binary(), binary()) -> ok.
 remove_room(LServer, Name, Host) ->
     LName = jid:nodeprep(Name),
     LHost = jid:nameprep(Host),
     Mod = gen_mod:db_mod(LServer, ?MODULE),
-    Mod:remove_room(LServer, LName, LHost).
+    Mod:remove_room(LServer, LName, LHost),
+    ok.
 
 get_room_config(X, RoomState, _From, Lang) ->
     Config = RoomState#state.config,
@@ -621,9 +625,7 @@ should_archive_muc(#message{type = groupchat,
 		    end;
 		_ ->
 		    true
-	    end;
-	_ ->
-	    false
+	    end
     end;
 should_archive_muc(_) ->
     false.
diff --git a/src/mod_metrics.erl b/src/mod_metrics.erl
index cb7946a28..605fe3d6b 100644
--- a/src/mod_metrics.erl
+++ b/src/mod_metrics.erl
@@ -31,13 +31,7 @@
 
 -include("ejabberd.hrl").
 -include("logger.hrl").
--include("jid.hrl").
-
--define(HOOKS, [offline_message_hook,
-                sm_register_connection_hook, sm_remove_connection_hook,
-                user_send_packet, user_receive_packet,
-                s2s_send_packet, s2s_receive_packet,
-                remove_user, register_user]).
+-include("xmpp.hrl").
 
 -export([start/2, stop/1, send_metrics/4, opt_type/1, mod_opt_type/1,
 	 depends/2]).
@@ -53,12 +47,26 @@
 %%====================================================================
 
 start(Host, _Opts) ->
-    [ejabberd_hooks:add(Hook, Host, ?MODULE, Hook, 20)
-     || Hook <- ?HOOKS].
+    ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, offline_message_hook, 20),
+    ejabberd_hooks:add(sm_register_connection_hook, Host, ?MODULE, sm_register_connection_hook, 20),
+    ejabberd_hooks:add(sm_remove_connection_hook, Host, ?MODULE, sm_remove_connection_hook, 20),
+    ejabberd_hooks:add(user_send_packet, Host, ?MODULE, user_send_packet, 20),
+    ejabberd_hooks:add(user_receive_packet, Host, ?MODULE, user_receive_packet, 20),
+    ejabberd_hooks:add(s2s_send_packet, Host, ?MODULE, s2s_send_packet, 20),
+    ejabberd_hooks:add(s2s_receive_packet, Host, ?MODULE, s2s_receive_packet, 20),
+    ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 20),
+    ejabberd_hooks:add(register_user, Host, ?MODULE, register_user, 20).
 
 stop(Host) ->
-    [ejabberd_hooks:delete(Hook, Host, ?MODULE, Hook, 20)
-     || Hook <- ?HOOKS].
+    ejabberd_hooks:delete(offline_message_hook, Host, ?MODULE, offline_message_hook, 20),
+    ejabberd_hooks:delete(sm_register_connection_hook, Host, ?MODULE, sm_register_connection_hook, 20),
+    ejabberd_hooks:delete(sm_remove_connection_hook, Host, ?MODULE, sm_remove_connection_hook, 20),
+    ejabberd_hooks:delete(user_send_packet, Host, ?MODULE, user_send_packet, 20),
+    ejabberd_hooks:delete(user_receive_packet, Host, ?MODULE, user_receive_packet, 20),
+    ejabberd_hooks:delete(s2s_send_packet, Host, ?MODULE, s2s_send_packet, 20),
+    ejabberd_hooks:delete(s2s_receive_packet, Host, ?MODULE, s2s_receive_packet, 20),
+    ejabberd_hooks:delete(remove_user, Host, ?MODULE, remove_user, 20),
+    ejabberd_hooks:delete(register_user, Host, ?MODULE, register_user, 20).
 
 depends(_Host, _Opts) ->
     [].
@@ -66,12 +74,15 @@ depends(_Host, _Opts) ->
 %%====================================================================
 %% Hooks handlers
 %%====================================================================
-
+-spec offline_message_hook(jid(), jid(), message()) -> any().
 offline_message_hook(_From, #jid{lserver=LServer}, _Packet) ->
     push(LServer, offline_message).
 
+-spec sm_register_connection_hook(ejabberd_sm:sid(), jid(), ejabberd_sm:info()) -> any().
 sm_register_connection_hook(_SID, #jid{lserver=LServer}, _Info) ->
     push(LServer, sm_register_connection).
+
+-spec sm_remove_connection_hook(ejabberd_sm:sid(), jid(), ejabberd_sm:info()) -> any().
 sm_remove_connection_hook(_SID, #jid{lserver=LServer}, _Info) ->
     push(LServer, sm_remove_connection).
 
@@ -82,13 +93,19 @@ user_receive_packet(Packet, _C2SState, _JID, _From, #jid{lserver=LServer}) ->
     push(LServer, user_receive_packet),
     Packet.
 
+-spec s2s_send_packet(jid(), jid(), stanza()) -> any().
 s2s_send_packet(#jid{lserver=LServer}, _To, _Packet) ->
     push(LServer, s2s_send_packet).
+
+-spec s2s_receive_packet(jid(), jid(), stanza()) -> any().
 s2s_receive_packet(_From, #jid{lserver=LServer}, _Packet) ->
     push(LServer, s2s_receive_packet).
 
+-spec remove_user(binary(), binary()) -> any().
 remove_user(_User, Server) ->
     push(jid:nameprep(Server), remove_user).
+
+-spec register_user(binary(), binary()) -> any().
 register_user(_User, Server) ->
     push(jid:nameprep(Server), register_user).
 
diff --git a/src/mod_mix.erl b/src/mod_mix.erl
index 3ba173b9f..52a3c8ed8 100644
--- a/src/mod_mix.erl
+++ b/src/mod_mix.erl
@@ -52,6 +52,8 @@ stop(Host) ->
     supervisor:delete_child(ejabberd_sup, Proc),
     ok.
 
+-spec disco_features({error, error()} | {result, [binary()]} | empty,
+		     jid(), jid(), binary(), binary()) -> {result, [binary()]}.
 disco_features(_Acc, _From, _To, _Node, _Lang) ->
     {result, [?NS_MIX_0]}.
 
@@ -69,6 +71,8 @@ disco_identity(Acc, _From, _To, _Node, _Lang) ->
     Acc ++ [#identity{category = <<"conference">>,
 		      type = <<"mix">>}].
 
+-spec disco_info([xdata()], binary(), module(), binary(), binary()) -> [xdata()];
+		([xdata()], jid(), jid(), binary(), binary()) -> [xdata()].
 disco_info(_Acc, _From, To, _Node, _Lang) when is_atom(To) ->
     [#xdata{type = result,
 	    fields = [#xdata_field{var = <<"FORM_TYPE">>,
diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl
index 5814ca832..b470c093e 100644
--- a/src/mod_muc_room.erl
+++ b/src/mod_muc_room.erl
@@ -3317,28 +3317,34 @@ set_config(#xdata{fields = Fields}, StateData, Lang) ->
 	Err -> Err
     end.
 
+get_config_opt_name(Pos) ->
+    Fs = [config|record_info(fields, config)],
+    lists:nth(Pos, Fs).
+
 -define(SET_BOOL_XOPT(Opt, Val),
 	case Val of
 	  <<"0">> ->
-	      set_xoption(Opts, Config#config{Opt = false}, ServerHost, Lang);
+	      set_xoption(Opts, setelement(Opt, Config, false), ServerHost, Lang);
 	  <<"false">> ->
-	      set_xoption(Opts, Config#config{Opt = false}, ServerHost, Lang);
-	  <<"1">> -> set_xoption(Opts, Config#config{Opt = true}, ServerHost, Lang);
+	      set_xoption(Opts, setelement(Opt, Config, false), ServerHost, Lang);
+	  <<"1">> -> set_xoption(Opts, setelement(Opt, Config, true), ServerHost, Lang);
 	  <<"true">> ->
-	      set_xoption(Opts, Config#config{Opt = true}, ServerHost, Lang);
+	      set_xoption(Opts, setelement(Opt, Config, true), ServerHost, Lang);
 	  _ ->
 	      Txt = <<"Value of '~s' should be boolean">>,
-	      ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])),
+	      OptName = get_config_opt_name(Opt),
+	      ErrTxt = iolist_to_binary(io_lib:format(Txt, [OptName])),
 	      {error, xmpp:err_bad_request(ErrTxt, Lang)}
 	end).
 
 -define(SET_NAT_XOPT(Opt, Val),
 	case catch binary_to_integer(Val) of
 	  I when is_integer(I), I > 0 ->
-	      set_xoption(Opts, Config#config{Opt = I}, ServerHost, Lang);
+	      set_xoption(Opts, setelement(Opt, Config, I), ServerHost, Lang);
 	  _ ->
 	      Txt = <<"Value of '~s' should be integer">>,
-	      ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])),
+	      OptName = get_config_opt_name(Opt),
+	      ErrTxt = iolist_to_binary(io_lib:format(Txt, [OptName])),
 	      {error, xmpp:err_bad_request(ErrTxt, Lang)}
 	end).
 
@@ -3349,10 +3355,11 @@ set_config(#xdata{fields = Fields}, StateData, Lang) ->
 		    [Val] -> Val;
 		    _ when is_atom(Vals) -> Vals
 		end,
-	    set_xoption(Opts, Config#config{Opt = V}, ServerHost, Lang)
+	    set_xoption(Opts, setelement(Opt, Config, V), ServerHost, Lang)
 	catch _:_ ->
 		Txt = <<"Incorrect value of option '~s'">>,
-		ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])),
+		OptName = get_config_opt_name(Opt),
+		ErrTxt = iolist_to_binary(io_lib:format(Txt, [OptName])),
 		{error, xmpp:err_bad_request(ErrTxt, Lang)}
 	end).
 
@@ -3366,7 +3373,7 @@ set_config(#xdata{fields = Fields}, StateData, Lang) ->
 				(_, Set1) -> Set1
 			    end,
 			    (?SETS):empty(), Vals),
-	  set_xoption(Opts, Config#config{Opt = Set}, ServerHost, Lang)
+	  set_xoption(Opts, setelement(Opt, Config, Set), ServerHost, Lang)
 	end).
 
 -spec set_xoption([{binary(), [binary()]}], #config{},
@@ -3375,35 +3382,35 @@ set_xoption([], Config, _ServerHost, _Lang) -> Config;
 set_xoption([{<<"muc#roomconfig_roomname">>, Vals}
 	     | Opts],
 	    Config, ServerHost, Lang) ->
-    ?SET_STRING_XOPT(title, Vals);
+    ?SET_STRING_XOPT(#config.title, Vals);
 set_xoption([{<<"muc#roomconfig_roomdesc">>, Vals}
 	     | Opts],
 	    Config, ServerHost, Lang) ->
-    ?SET_STRING_XOPT(description, Vals);
+    ?SET_STRING_XOPT(#config.description, Vals);
 set_xoption([{<<"muc#roomconfig_changesubject">>, [Val]}
 	     | Opts],
 	    Config, ServerHost, Lang) ->
-    ?SET_BOOL_XOPT(allow_change_subj, Val);
+    ?SET_BOOL_XOPT(#config.allow_change_subj, Val);
 set_xoption([{<<"allow_query_users">>, [Val]} | Opts],
 	    Config, ServerHost, Lang) ->
-    ?SET_BOOL_XOPT(allow_query_users, Val);
+    ?SET_BOOL_XOPT(#config.allow_query_users, Val);
 set_xoption([{<<"allow_private_messages">>, [Val]}
 	     | Opts],
 	    Config, ServerHost, Lang) ->
-    ?SET_BOOL_XOPT(allow_private_messages, Val);
+    ?SET_BOOL_XOPT(#config.allow_private_messages, Val);
 set_xoption([{<<"allow_private_messages_from_visitors">>,
 	      [Val]}
 	     | Opts],
 	    Config, ServerHost, Lang) ->
     case Val of
       <<"anyone">> ->
-	  ?SET_STRING_XOPT(allow_private_messages_from_visitors,
+	  ?SET_STRING_XOPT(#config.allow_private_messages_from_visitors,
 			   anyone);
       <<"moderators">> ->
-	  ?SET_STRING_XOPT(allow_private_messages_from_visitors,
+	  ?SET_STRING_XOPT(#config.allow_private_messages_from_visitors,
 			   moderators);
       <<"nobody">> ->
-	  ?SET_STRING_XOPT(allow_private_messages_from_visitors,
+	  ?SET_STRING_XOPT(#config.allow_private_messages_from_visitors,
 			   nobody);
       _ ->
 	  Txt = <<"Value of 'allow_private_messages_from_visitors' "
@@ -3414,58 +3421,58 @@ set_xoption([{<<"muc#roomconfig_allowvisitorstatus">>,
 	      [Val]}
 	     | Opts],
 	    Config, ServerHost, Lang) ->
-    ?SET_BOOL_XOPT(allow_visitor_status, Val);
+    ?SET_BOOL_XOPT(#config.allow_visitor_status, Val);
 set_xoption([{<<"muc#roomconfig_allowvisitornickchange">>,
 	      [Val]}
 	     | Opts],
 	    Config, ServerHost, Lang) ->
-    ?SET_BOOL_XOPT(allow_visitor_nickchange, Val);
+    ?SET_BOOL_XOPT(#config.allow_visitor_nickchange, Val);
 set_xoption([{<<"muc#roomconfig_publicroom">>, [Val]}
 	     | Opts],
 	    Config, ServerHost, Lang) ->
-    ?SET_BOOL_XOPT(public, Val);
+    ?SET_BOOL_XOPT(#config.public, Val);
 set_xoption([{<<"public_list">>, [Val]} | Opts],
 	    Config, ServerHost, Lang) ->
-    ?SET_BOOL_XOPT(public_list, Val);
+    ?SET_BOOL_XOPT(#config.public_list, Val);
 set_xoption([{<<"muc#roomconfig_persistentroom">>,
 	      [Val]}
 	     | Opts],
 	    Config, ServerHost, Lang) ->
-    ?SET_BOOL_XOPT(persistent, Val);
+    ?SET_BOOL_XOPT(#config.persistent, Val);
 set_xoption([{<<"muc#roomconfig_moderatedroom">>, [Val]}
 	     | Opts],
 	    Config, ServerHost, Lang) ->
-    ?SET_BOOL_XOPT(moderated, Val);
+    ?SET_BOOL_XOPT(#config.moderated, Val);
 set_xoption([{<<"members_by_default">>, [Val]} | Opts],
 	    Config, ServerHost, Lang) ->
-    ?SET_BOOL_XOPT(members_by_default, Val);
+    ?SET_BOOL_XOPT(#config.members_by_default, Val);
 set_xoption([{<<"muc#roomconfig_membersonly">>, [Val]}
 	     | Opts],
 	    Config, ServerHost, Lang) ->
-    ?SET_BOOL_XOPT(members_only, Val);
+    ?SET_BOOL_XOPT(#config.members_only, Val);
 set_xoption([{<<"captcha_protected">>, [Val]} | Opts],
 	    Config, ServerHost, Lang) ->
-    ?SET_BOOL_XOPT(captcha_protected, Val);
+    ?SET_BOOL_XOPT(#config.captcha_protected, Val);
 set_xoption([{<<"muc#roomconfig_allowinvites">>, [Val]}
 	     | Opts],
 	    Config, ServerHost, Lang) ->
-    ?SET_BOOL_XOPT(allow_user_invites, Val);
+    ?SET_BOOL_XOPT(#config.allow_user_invites, Val);
 set_xoption([{<<"muc#roomconfig_allow_subscription">>, [Val]}
 	     | Opts],
 	    Config, ServerHost, Lang) ->
-    ?SET_BOOL_XOPT(allow_subscription, Val);
+    ?SET_BOOL_XOPT(#config.allow_subscription, Val);
 set_xoption([{<<"muc#roomconfig_passwordprotectedroom">>,
 	      [Val]}
 	     | Opts],
 	    Config, ServerHost, Lang) ->
-    ?SET_BOOL_XOPT(password_protected, Val);
+    ?SET_BOOL_XOPT(#config.password_protected, Val);
 set_xoption([{<<"muc#roomconfig_roomsecret">>, Vals}
 	     | Opts],
 	    Config, ServerHost, Lang) ->
-    ?SET_STRING_XOPT(password, Vals);
+    ?SET_STRING_XOPT(#config.password, Vals);
 set_xoption([{<<"anonymous">>, [Val]} | Opts],
 	    Config, ServerHost, Lang) ->
-    ?SET_BOOL_XOPT(anonymous, Val);
+    ?SET_BOOL_XOPT(#config.anonymous, Val);
 set_xoption([{<<"muc#roomconfig_presencebroadcast">>, Vals} | Opts],
 	    Config, ServerHost, Lang) ->
     Roles =
@@ -3496,21 +3503,21 @@ set_xoption([{<<"muc#roomconfig_allowvoicerequests">>,
 	      [Val]}
 	     | Opts],
 	    Config, ServerHost, Lang) ->
-    ?SET_BOOL_XOPT(allow_voice_requests, Val);
+    ?SET_BOOL_XOPT(#config.allow_voice_requests, Val);
 set_xoption([{<<"muc#roomconfig_voicerequestmininterval">>,
 	      [Val]}
 	     | Opts],
 	    Config, ServerHost, Lang) ->
-    ?SET_NAT_XOPT(voice_request_min_interval, Val);
+    ?SET_NAT_XOPT(#config.voice_request_min_interval, Val);
 set_xoption([{<<"muc#roomconfig_whois">>, [Val]}
 	     | Opts],
 	    Config, ServerHost, Lang) ->
     case Val of
       <<"moderators">> ->
-	  ?SET_BOOL_XOPT(anonymous,
+	  ?SET_BOOL_XOPT(#config.anonymous,
 			 (iolist_to_binary(integer_to_list(1))));
       <<"anyone">> ->
-	  ?SET_BOOL_XOPT(anonymous,
+	  ?SET_BOOL_XOPT(#config.anonymous,
 			 (iolist_to_binary(integer_to_list(0))));
       _ ->
 	  Txt = <<"Value of 'muc#roomconfig_whois' should be "
@@ -3521,19 +3528,19 @@ set_xoption([{<<"muc#roomconfig_maxusers">>, [Val]}
 	     | Opts],
 	    Config, ServerHost, Lang) ->
     case Val of
-      <<"none">> -> ?SET_STRING_XOPT(max_users, none);
-      _ -> ?SET_NAT_XOPT(max_users, Val)
+      <<"none">> -> ?SET_STRING_XOPT(#config.max_users, none);
+      _ -> ?SET_NAT_XOPT(#config.max_users, Val)
     end;
 set_xoption([{<<"muc#roomconfig_enablelogging">>, [Val]}
 	     | Opts],
 	    Config, ServerHost, Lang) ->
-    ?SET_BOOL_XOPT(logging, Val);
+    ?SET_BOOL_XOPT(#config.logging, Val);
 set_xoption([{<<"muc#roomconfig_captcha_whitelist">>,
 	      Vals}
 	     | Opts],
 	    Config, ServerHost, Lang) ->
     JIDs = [jid:from_string(Val) || Val <- Vals],
-    ?SET_JIDMULTI_XOPT(captcha_whitelist, JIDs);
+    ?SET_JIDMULTI_XOPT(#config.captcha_whitelist, JIDs);
 set_xoption([{<<"FORM_TYPE">>, _} | Opts], Config, ServerHost, Lang) ->
     set_xoption(Opts, Config, ServerHost, Lang);
 set_xoption([{Opt, Vals} | Opts], Config, ServerHost, Lang) ->
@@ -3752,7 +3759,8 @@ set_opts([{Opt, Val} | Opts], StateData) ->
 	  end,
     set_opts(Opts, NSD).
 
--define(MAKE_CONFIG_OPT(Opt), {Opt, Config#config.Opt}).
+-define(MAKE_CONFIG_OPT(Opt),
+	{get_config_opt_name(Opt), element(Opt, Config)}).
 
 -spec make_opts(state()) -> [{atom(), any()}].
 make_opts(StateData) ->
@@ -3764,27 +3772,27 @@ make_opts(StateData) ->
 		       (_, _, Acc) ->
 			    Acc
 		    end, [], StateData#state.users),
-    [?MAKE_CONFIG_OPT(title), ?MAKE_CONFIG_OPT(description),
-     ?MAKE_CONFIG_OPT(allow_change_subj),
-     ?MAKE_CONFIG_OPT(allow_query_users),
-     ?MAKE_CONFIG_OPT(allow_private_messages),
-     ?MAKE_CONFIG_OPT(allow_private_messages_from_visitors),
-     ?MAKE_CONFIG_OPT(allow_visitor_status),
-     ?MAKE_CONFIG_OPT(allow_visitor_nickchange),
-     ?MAKE_CONFIG_OPT(public), ?MAKE_CONFIG_OPT(public_list),
-     ?MAKE_CONFIG_OPT(persistent),
-     ?MAKE_CONFIG_OPT(moderated),
-     ?MAKE_CONFIG_OPT(members_by_default),
-     ?MAKE_CONFIG_OPT(members_only),
-     ?MAKE_CONFIG_OPT(allow_user_invites),
-     ?MAKE_CONFIG_OPT(password_protected),
-     ?MAKE_CONFIG_OPT(captcha_protected),
-     ?MAKE_CONFIG_OPT(password), ?MAKE_CONFIG_OPT(anonymous),
-     ?MAKE_CONFIG_OPT(logging), ?MAKE_CONFIG_OPT(max_users),
-     ?MAKE_CONFIG_OPT(allow_voice_requests),
-     ?MAKE_CONFIG_OPT(mam),
-     ?MAKE_CONFIG_OPT(voice_request_min_interval),
-     ?MAKE_CONFIG_OPT(vcard),
+    [?MAKE_CONFIG_OPT(#config.title), ?MAKE_CONFIG_OPT(#config.description),
+     ?MAKE_CONFIG_OPT(#config.allow_change_subj),
+     ?MAKE_CONFIG_OPT(#config.allow_query_users),
+     ?MAKE_CONFIG_OPT(#config.allow_private_messages),
+     ?MAKE_CONFIG_OPT(#config.allow_private_messages_from_visitors),
+     ?MAKE_CONFIG_OPT(#config.allow_visitor_status),
+     ?MAKE_CONFIG_OPT(#config.allow_visitor_nickchange),
+     ?MAKE_CONFIG_OPT(#config.public), ?MAKE_CONFIG_OPT(#config.public_list),
+     ?MAKE_CONFIG_OPT(#config.persistent),
+     ?MAKE_CONFIG_OPT(#config.moderated),
+     ?MAKE_CONFIG_OPT(#config.members_by_default),
+     ?MAKE_CONFIG_OPT(#config.members_only),
+     ?MAKE_CONFIG_OPT(#config.allow_user_invites),
+     ?MAKE_CONFIG_OPT(#config.password_protected),
+     ?MAKE_CONFIG_OPT(#config.captcha_protected),
+     ?MAKE_CONFIG_OPT(#config.password), ?MAKE_CONFIG_OPT(#config.anonymous),
+     ?MAKE_CONFIG_OPT(#config.logging), ?MAKE_CONFIG_OPT(#config.max_users),
+     ?MAKE_CONFIG_OPT(#config.allow_voice_requests),
+     ?MAKE_CONFIG_OPT(#config.mam),
+     ?MAKE_CONFIG_OPT(#config.voice_request_min_interval),
+     ?MAKE_CONFIG_OPT(#config.vcard),
      {captcha_whitelist,
       (?SETS):to_list((StateData#state.config)#config.captcha_whitelist)},
      {affiliations,
diff --git a/src/mod_offline.erl b/src/mod_offline.erl
index 4d597a52c..03eb3c59a 100644
--- a/src/mod_offline.erl
+++ b/src/mod_offline.erl
@@ -297,7 +297,8 @@ get_sm_items(_Acc, #jid{luser = U, lserver = S, lresource = R} = JID,
 get_sm_items(Acc, _From, _To, _Node, _Lang) ->
     Acc.
 
--spec get_info([xdata()], jid(), jid(), binary(), binary()) -> [xdata()].
+-spec get_info([xdata()], binary(), module(), binary(), binary()) -> [xdata()];
+	      ([xdata()], jid(), jid(), binary(), binary()) -> [xdata()].
 get_info(_Acc, #jid{luser = U, lserver = S, lresource = R},
 	 #jid{luser = U, lserver = S}, ?NS_FLEX_OFFLINE, _Lang) ->
     N = jlib:integer_to_binary(count_offline_messages(U, S)),
@@ -570,11 +571,13 @@ remove_old_messages(Days, Server) ->
     Mod = gen_mod:db_mod(LServer, ?MODULE),
     Mod:remove_old_messages(Days, LServer).
 
+-spec remove_user(binary(), binary()) -> ok.
 remove_user(User, Server) ->
     LUser = jid:nodeprep(User),
     LServer = jid:nameprep(Server),
     Mod = gen_mod:db_mod(LServer, ?MODULE),
-    Mod:remove_user(LUser, LServer).
+    Mod:remove_user(LUser, LServer),
+    ok.
 
 %% Helper functions:
 
diff --git a/src/mod_ping.erl b/src/mod_ping.erl
index b09ca9ab2..5e861b7f7 100644
--- a/src/mod_ping.erl
+++ b/src/mod_ping.erl
@@ -207,11 +207,11 @@ iq_ping(#iq{lang = Lang} = IQ) ->
     Txt = <<"Ping query is incorrect">>,
     xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)).
 
--spec user_online(ejabberd_sm:sid(), jid(), any()) -> ok.
+-spec user_online(ejabberd_sm:sid(), jid(), ejabberd_sm:info()) -> ok.
 user_online(_SID, JID, _Info) ->
     start_ping(JID#jid.lserver, JID).
 
--spec user_offline(ejabberd_sm:sid(), jid(), any()) -> ok.
+-spec user_offline(ejabberd_sm:sid(), jid(), ejabberd_sm:info()) -> ok.
 user_offline(_SID, JID, _Info) ->
     stop_ping(JID#jid.lserver, JID).
 
diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl
index 1da040d43..f94c422b3 100644
--- a/src/mod_privacy.erl
+++ b/src/mod_privacy.erl
@@ -515,6 +515,7 @@ is_type_match(Type, Value, JID, Subscription, Groups) ->
       group -> lists:member(Value, Groups)
     end.
 
+-spec remove_user(binary(), binary()) -> any().
 remove_user(User, Server) ->
     LUser = jid:nodeprep(User),
     LServer = jid:nameprep(Server),
diff --git a/src/mod_private.erl b/src/mod_private.erl
index 6236b1012..565500d4a 100644
--- a/src/mod_private.erl
+++ b/src/mod_private.erl
@@ -117,6 +117,7 @@ get_data(LUser, LServer) ->
     Mod = gen_mod:db_mod(LServer, ?MODULE),
     Mod:get_all_data(LUser, LServer).
 
+-spec remove_user(binary(), binary()) -> any().
 remove_user(User, Server) ->
     LUser = jid:nodeprep(User),
     LServer = jid:nameprep(Server),
diff --git a/src/mod_pubsub.erl b/src/mod_pubsub.erl
index 81afc9a06..0796a20bb 100644
--- a/src/mod_pubsub.erl
+++ b/src/mod_pubsub.erl
@@ -660,6 +660,7 @@ disco_items(Host, Node, From) ->
 %% presence hooks handling functions
 %%
 
+-spec caps_add(jid(), jid(), [binary()]) -> ok.
 caps_add(#jid{luser = U, lserver = S, lresource = R}, #jid{lserver = Host} = JID, _Features)
 	when Host =/= S ->
     %% When a remote contact goes online while the local user is offline, the
@@ -675,9 +676,11 @@ caps_add(#jid{luser = U, lserver = S, lresource = R}, #jid{lserver = Host} = JID
 caps_add(_From, _To, _Feature) ->
     ok.
 
+-spec caps_update(jid(), jid(), [binary()]) -> ok.
 caps_update(#jid{luser = U, lserver = S, lresource = R}, #jid{lserver = Host} = JID, _Features) ->
     presence(Host, {presence, U, S, [R], JID}).
 
+-spec presence_probe(jid(), jid(), pid()) -> ok.
 presence_probe(#jid{luser = U, lserver = S, lresource = R} = JID, JID, Pid) ->
     presence(S, {presence, JID, Pid}),
     presence(S, {presence, U, S, [R], JID});
@@ -697,12 +700,16 @@ presence(ServerHost, Presence) ->
 	undefined -> init_send_loop(ServerHost);
 	Pid -> {Pid, undefined}
     end,
-    SendLoop ! Presence.
+    SendLoop ! Presence,
+    ok.
 
 %% -------
 %% subscription hooks handling functions
 %%
 
+-spec out_subscription(
+	binary(), binary(), jid(),
+	subscribed | unsubscribed | subscribe | unsubscribe) -> boolean().
 out_subscription(User, Server, JID, subscribed) ->
     Owner = jid:make(User, Server, <<>>),
     {PUser, PServer, PResource} = jid:tolower(JID),
@@ -763,6 +770,7 @@ unsubscribe_user(Host, Entity, Owner) ->
 %% user remove hook handling function
 %%
 
+-spec remove_user(binary(), binary()) -> ok.
 remove_user(User, Server) ->
     LUser = jid:nodeprep(User),
     LServer = jid:nameprep(Server),
@@ -802,7 +810,8 @@ remove_user(User, Server) ->
 				Affs)
 		    end,
 		    plugins(Host))
-	end).
+	  end),
+    ok.
 
 handle_call(server_host, _From, State) ->
     {reply, State#state.server_host, State};
@@ -4224,11 +4233,12 @@ extended_headers(Jids) ->
 	    attrs = [{<<"type">>, <<"replyto">>}, {<<"jid">>, Jid}]}
 	|| Jid <- Jids].
 
+-spec on_user_offline(ejabberd_sm:sid(), jid(), ejabberd_sm:info()) -> ok.
 on_user_offline(_, JID, _) ->
     {User, Server, Resource} = jid:tolower(JID),
     case user_resources(User, Server) of
 	[] -> purge_offline({User, Server, Resource});
-	_ -> true
+	_ -> ok
     end.
 
 purge_offline(LJID) ->
diff --git a/src/mod_register.erl b/src/mod_register.erl
index 1ed266d47..334af4514 100644
--- a/src/mod_register.erl
+++ b/src/mod_register.erl
@@ -74,6 +74,7 @@ stop(Host) ->
 depends(_Host, _Opts) ->
     [].
 
+-spec stream_feature_register([xmpp_element()], binary()) -> [xmpp_element()].
 stream_feature_register(Acc, Host) ->
     AF = gen_mod:get_module_opt(Host, ?MODULE, access_from,
                                           fun(A) -> A end,
@@ -85,6 +86,9 @@ stream_feature_register(Acc, Host) ->
 	    Acc
     end.
 
+-spec unauthenticated_iq_register(empty | iq(), binary(), iq(),
+				  {inet:ip_address(), non_neg_integer()}) ->
+					 empty | iq().
 unauthenticated_iq_register(_Acc, Server,
 			    #iq{sub_els = [#register{}]} = IQ, IP) ->
     Address = case IP of
diff --git a/src/mod_roster.erl b/src/mod_roster.erl
index 51fe08ba5..c118a61ff 100644
--- a/src/mod_roster.erl
+++ b/src/mod_roster.erl
@@ -452,6 +452,9 @@ in_subscription(_, User, Server, JID, Type, Reason) ->
     process_subscription(in, User, Server, JID, Type,
 			 Reason).
 
+-spec out_subscription(
+	binary(), binary(), jid(),
+	subscribed | unsubscribed | subscribe | unsubscribe) -> boolean().
 out_subscription(User, Server, JID, Type) ->
     process_subscription(out, User, Server, JID, Type, <<"">>).
 
@@ -643,12 +646,14 @@ in_auto_reply(from, out, unsubscribe) -> unsubscribed;
 in_auto_reply(both, none, unsubscribe) -> unsubscribed;
 in_auto_reply(_, _, _) -> none.
 
+-spec remove_user(binary(), binary()) -> ok.
 remove_user(User, Server) ->
     LUser = jid:nodeprep(User),
     LServer = jid:nameprep(Server),
     send_unsubscription_to_rosteritems(LUser, LServer),
     Mod = gen_mod:db_mod(LServer, ?MODULE),
-    Mod:remove_user(LUser, LServer).
+    Mod:remove_user(LUser, LServer),
+    ok.
 
 %% For each contact with Subscription:
 %% Both or From, send a "unsubscribed" presence stanza;
diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl
index 079a2f44c..ac3717bd3 100644
--- a/src/mod_shared_roster.erl
+++ b/src/mod_shared_roster.erl
@@ -336,6 +336,9 @@ in_subscription(Acc, User, Server, JID, Type,
 		_Reason) ->
     process_subscription(in, User, Server, JID, Type, Acc).
 
+-spec out_subscription(
+	binary(), binary(), jid(),
+	subscribed | unsubscribed | subscribe | unsubscribe) -> boolean().
 out_subscription(UserFrom, ServerFrom, JIDTo,
 		 unsubscribed) ->
     #jid{luser = UserTo, lserver = ServerTo} = JIDTo,
@@ -629,12 +632,15 @@ broadcast_members_to_user(LUser, LServer, Group, Host, Subscription) ->
 	      broadcast_subscription(U, S, {LUser, LServer, <<"">>}, Subscription)
       end, Members).
 
+-spec register_user(binary(), binary()) -> ok.
 register_user(User, Server) ->
     Groups = get_user_groups({User, Server}),
     [push_user_to_displayed(User, Server, Group, Server,
 			    both, displayed_to_groups(Group, Server))
-     || Group <- Groups].
+     || Group <- Groups],
+    ok.
 
+-spec remove_user(binary(), binary()) -> ok.
 remove_user(User, Server) ->
     push_user_to_members(User, Server, remove).
 
@@ -724,6 +730,7 @@ push_roster_item(User, Server, ContactU, ContactS,
 		   groups = [GroupName]},
     push_item(User, Server, Item).
 
+-spec user_available(jid()) -> ok.
 user_available(New) ->
     LUser = New#jid.luser,
     LServer = New#jid.lserver,
@@ -747,6 +754,7 @@ user_available(New) ->
       _ -> ok
     end.
 
+-spec unset_presence(binary(), binary(), binary(), binary()) -> ok.
 unset_presence(LUser, LServer, Resource, Status) ->
     Resources = ejabberd_sm:get_user_resources(LUser,
 					       LServer),
diff --git a/src/mod_shared_roster_ldap.erl b/src/mod_shared_roster_ldap.erl
index 06dd0e3a9..809887237 100644
--- a/src/mod_shared_roster_ldap.erl
+++ b/src/mod_shared_roster_ldap.erl
@@ -191,6 +191,9 @@ in_subscription(Acc, User, Server, JID, Type,
 		_Reason) ->
     process_subscription(in, User, Server, JID, Type, Acc).
 
+-spec out_subscription(
+	binary(), binary(), jid(),
+	subscribed | unsubscribed | subscribe | unsubscribe) -> boolean().
 out_subscription(User, Server, JID, Type) ->
     process_subscription(out, User, Server, JID, Type,
 			 false).
diff --git a/src/mod_vcard_xupdate.erl b/src/mod_vcard_xupdate.erl
index 27ea8461a..5cc87056e 100644
--- a/src/mod_vcard_xupdate.erl
+++ b/src/mod_vcard_xupdate.erl
@@ -51,11 +51,12 @@ depends(_Host, _Opts) ->
 %%====================================================================
 %% Hooks
 %%====================================================================
-
+-spec update_presence(presence(), binary(), binary()) -> presence().
 update_presence(#presence{type = undefined} = Packet, User, Host) ->
     presence_with_xupdate(Packet, User, Host);
 update_presence(Packet, _User, _Host) -> Packet.
 
+-spec vcard_set(binary(), binary(), xmlel()) -> ok.
 vcard_set(LUser, LServer, VCARD) ->
     US = {LUser, LServer},
     case fxml:get_path_s(VCARD,
diff --git a/src/node_online.erl b/src/node_online.erl
index 4b01d2a2c..2620e6a49 100644
--- a/src/node_online.erl
+++ b/src/node_online.erl
@@ -57,6 +57,7 @@ terminate(Host, ServerHost) ->
 			  ?MODULE, user_offline, 75),
     ok.
 
+-spec user_offline(ejabberd_sm:sid(), jid(), ejabberd_sm:info()) -> _.
 user_offline(_SID, #jid{luser=LUser,lserver=LServer}, _Info) ->
     mod_pubsub:remove_user(LUser, LServer).
 
diff --git a/src/xmpp.erl b/src/xmpp.erl
index c81474f10..8dbc49532 100644
--- a/src/xmpp.erl
+++ b/src/xmpp.erl
@@ -134,7 +134,7 @@ get_type(#message{type = T}) -> T;
 get_type(#presence{type = T}) -> T;
 get_type(#xmlel{attrs = Attrs}) -> fxml:get_attr_s(<<"type">>, Attrs).
 
--spec get_lang(iq() | message() | presence()) -> binary().
+-spec get_lang(iq() | message() | presence() | xmlel()) -> binary().
 get_lang(#iq{lang = L}) -> L;
 get_lang(#message{lang = L}) -> L;
 get_lang(#presence{lang = L}) -> L;
diff --git a/src/xmpp_codec.erl b/src/xmpp_codec.erl
index 905e48f3c..afe6ff1ad 100644
--- a/src/xmpp_codec.erl
+++ b/src/xmpp_codec.erl
@@ -3483,6 +3483,12 @@ dec_bool(<<"0">>) -> false;
 dec_bool(<<"true">>) -> true;
 dec_bool(<<"1">>) -> true.
 
+nameprep(S) ->
+    case jid:nameprep(S) of
+      error -> erlang:error(badarg);
+      S1 -> S1
+    end.
+
 resourceprep(R) ->
     case jid:resourceprep(R) of
       error -> erlang:error(badarg);
@@ -4887,7 +4893,7 @@ decode_db_verify_attr_from(__TopXMLNS, undefined) ->
 		  {missing_attr, <<"from">>, <<"db:verify">>,
 		   __TopXMLNS}});
 decode_db_verify_attr_from(__TopXMLNS, _val) ->
-    case catch dec_jid(_val) of
+    case catch nameprep(_val) of
       {'EXIT', _} ->
 	  erlang:error({xmpp_codec,
 			{bad_attr_value, <<"from">>, <<"db:verify">>,
@@ -4896,13 +4902,13 @@ decode_db_verify_attr_from(__TopXMLNS, _val) ->
     end.
 
 encode_db_verify_attr_from(_val, _acc) ->
-    [{<<"from">>, enc_jid(_val)} | _acc].
+    [{<<"from">>, nameprep(_val)} | _acc].
 
 decode_db_verify_attr_to(__TopXMLNS, undefined) ->
     erlang:error({xmpp_codec,
 		  {missing_attr, <<"to">>, <<"db:verify">>, __TopXMLNS}});
 decode_db_verify_attr_to(__TopXMLNS, _val) ->
-    case catch dec_jid(_val) of
+    case catch nameprep(_val) of
       {'EXIT', _} ->
 	  erlang:error({xmpp_codec,
 			{bad_attr_value, <<"to">>, <<"db:verify">>,
@@ -4911,7 +4917,7 @@ decode_db_verify_attr_to(__TopXMLNS, _val) ->
     end.
 
 encode_db_verify_attr_to(_val, _acc) ->
-    [{<<"to">>, enc_jid(_val)} | _acc].
+    [{<<"to">>, nameprep(_val)} | _acc].
 
 decode_db_verify_attr_id(__TopXMLNS, undefined) ->
     erlang:error({xmpp_codec,
@@ -5014,7 +5020,7 @@ decode_db_result_attr_from(__TopXMLNS, undefined) ->
 		  {missing_attr, <<"from">>, <<"db:result">>,
 		   __TopXMLNS}});
 decode_db_result_attr_from(__TopXMLNS, _val) ->
-    case catch dec_jid(_val) of
+    case catch nameprep(_val) of
       {'EXIT', _} ->
 	  erlang:error({xmpp_codec,
 			{bad_attr_value, <<"from">>, <<"db:result">>,
@@ -5023,13 +5029,13 @@ decode_db_result_attr_from(__TopXMLNS, _val) ->
     end.
 
 encode_db_result_attr_from(_val, _acc) ->
-    [{<<"from">>, enc_jid(_val)} | _acc].
+    [{<<"from">>, nameprep(_val)} | _acc].
 
 decode_db_result_attr_to(__TopXMLNS, undefined) ->
     erlang:error({xmpp_codec,
 		  {missing_attr, <<"to">>, <<"db:result">>, __TopXMLNS}});
 decode_db_result_attr_to(__TopXMLNS, _val) ->
-    case catch dec_jid(_val) of
+    case catch nameprep(_val) of
       {'EXIT', _} ->
 	  erlang:error({xmpp_codec,
 			{bad_attr_value, <<"to">>, <<"db:result">>,
@@ -5038,7 +5044,7 @@ decode_db_result_attr_to(__TopXMLNS, _val) ->
     end.
 
 encode_db_result_attr_to(_val, _acc) ->
-    [{<<"to">>, enc_jid(_val)} | _acc].
+    [{<<"to">>, nameprep(_val)} | _acc].
 
 decode_db_result_attr_type(__TopXMLNS, undefined) ->
     undefined;
diff --git a/tools/xmpp_codec.spec b/tools/xmpp_codec.spec
index 0b8f3b668..d410a7613 100644
--- a/tools/xmpp_codec.spec
+++ b/tools/xmpp_codec.spec
@@ -2860,9 +2860,9 @@
 	   result = {db_result, '$from', '$to', '$type', '$key', '$_els'},
 	   cdata = #cdata{default = <<"">>, label = '$key'},
 	   attrs = [#attr{name = <<"from">>, required = true,
-			  dec = {dec_jid, []}, enc = {enc_jid, []}},
+			  dec = {nameprep, []}, enc = {nameprep, []}},
 		    #attr{name = <<"to">>, required = true,
-			  dec = {dec_jid, []}, enc = {enc_jid, []}},
+			  dec = {nameprep, []}, enc = {nameprep, []}},
 		    #attr{name = <<"type">>,
 			  dec = {dec_enum, [[valid, invalid, error]]},
 			  enc = {enc_enum, []}}]}).
@@ -2873,9 +2873,9 @@
 	   result = {db_verify, '$from', '$to', '$id', '$type', '$key', '$_els'},
 	   cdata = #cdata{default = <<"">>, label = '$key'},
 	   attrs = [#attr{name = <<"from">>, required = true,
-			  dec = {dec_jid, []}, enc = {enc_jid, []}},
+			  dec = {nameprep, []}, enc = {nameprep, []}},
 		    #attr{name = <<"to">>, required = true,
-			  dec = {dec_jid, []}, enc = {enc_jid, []}},
+			  dec = {nameprep, []}, enc = {nameprep, []}},
 		    #attr{name = <<"id">>, required = true},
 		    #attr{name = <<"type">>,
 			  dec = {dec_enum, [[valid, invalid, error]]},
@@ -3113,6 +3113,15 @@ resourceprep(R) ->
             R1
     end.
 
+-spec nameprep(_) -> binary().
+nameprep(S) ->
+    case jid:nameprep(S) of
+	error ->
+	    erlang:error(badarg);
+	S1 ->
+	    S1
+    end.
+
 -spec dec_bool(_) -> boolean().
 dec_bool(<<"false">>) -> false;
 dec_bool(<<"0">>) -> false;
@@ -3137,7 +3146,7 @@ enc_ip({0,0,0,0,0,16#ffff,A,B}) ->
 enc_ip(Addr) ->
     list_to_binary(inet_parse:ntoa(Addr)).
 
--spec re:split(_, _) -> binary().
+-spec re:split(_, _) -> [binary()].
 -spec base64:decode(_) -> binary().
 
 -spec dec_host_port(_) -> binary() | inet:ip_address() |

From 31faa4eb9ad881c7884cd24f5d374d8b20e4b6c5 Mon Sep 17 00:00:00 2001
From: Evgeniy Khramtsov 
Date: Fri, 12 Aug 2016 13:17:42 +0300
Subject: [PATCH 035/151] Add more type specs

---
 src/ejabberd_sm.erl            |  6 +++---
 src/mod_http_upload_quota.erl  |  4 ++--
 src/mod_last.erl               |  1 +
 src/mod_mam.erl                | 17 +++++++++++++++--
 src/mod_metrics.erl            |  3 +++
 src/mod_offline.erl            |  3 +++
 src/mod_pres_counter.erl       |  2 ++
 src/mod_pubsub.erl             |  3 +++
 src/mod_roster.erl             | 10 ++++++++++
 src/mod_service_log.erl        |  3 +++
 src/mod_shared_roster.erl      |  9 +++++++++
 src/mod_shared_roster_ldap.erl |  9 +++++++++
 src/mod_vcard.erl              |  1 +
 13 files changed, 64 insertions(+), 7 deletions(-)

diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl
index 3ff9f2908..f6d0e765d 100644
--- a/src/ejabberd_sm.erl
+++ b/src/ejabberd_sm.erl
@@ -159,9 +159,9 @@ close_session(SID, User, Server, Resource) ->
     ejabberd_hooks:run(sm_remove_connection_hook,
 		       JID#jid.lserver, [SID, JID, Info]).
 
--spec check_in_subscription(any(), binary(), binary(),
-                            any(), any(), any()) -> any().
-
+-spec check_in_subscription(boolean(), binary(), binary(), jid(),
+			    subscribe | subscribed | unsubscribe | unsubscribed,
+			    binary()) -> boolean() | {stop, false}.
 check_in_subscription(Acc, User, Server, _JID, _Type, _Reason) ->
     case ejabberd_auth:is_user_exists(User, Server) of
       true -> Acc;
diff --git a/src/mod_http_upload_quota.erl b/src/mod_http_upload_quota.erl
index 056edbedb..fa37b801f 100644
--- a/src/mod_http_upload_quota.erl
+++ b/src/mod_http_upload_quota.erl
@@ -263,8 +263,8 @@ code_change(_OldVsn, #state{server_host = ServerHost} = State, _Extra) ->
 %% ejabberd_hooks callback.
 %%--------------------------------------------------------------------
 
--spec handle_slot_request(term(), jid(), binary(), non_neg_integer(), binary())
-      -> term().
+-spec handle_slot_request(allow | deny, jid(), binary(),
+			  non_neg_integer(), binary()) -> allow | deny.
 
 handle_slot_request(allow, #jid{lserver = ServerHost} = JID, Path, Size,
 		    _Lang) ->
diff --git a/src/mod_last.erl b/src/mod_last.erl
index 6d0edebf0..56e3b1c5e 100644
--- a/src/mod_last.erl
+++ b/src/mod_last.erl
@@ -200,6 +200,7 @@ get_last_info(LUser, LServer) ->
       Res -> Res
     end.
 
+-spec remove_user(binary(), binary()) -> any().
 remove_user(User, Server) ->
     LUser = jid:nodeprep(User),
     LServer = jid:nameprep(Server),
diff --git a/src/mod_mam.erl b/src/mod_mam.erl
index 7e93a3166..2529b7389 100644
--- a/src/mod_mam.erl
+++ b/src/mod_mam.erl
@@ -191,7 +191,9 @@ remove_room(LServer, Name, Host) ->
     Mod:remove_room(LServer, LName, LHost),
     ok.
 
-get_room_config(X, RoomState, _From, Lang) ->
+-spec get_room_config([xdata_field()], mod_muc_room:state(), jid(), binary())
+      -> [xdata_field()].			     
+get_room_config(XFields, RoomState, _From, Lang) ->
     Config = RoomState#state.config,
     Label = <<"Enable message archiving">>,
     Var = <<"muc#roomconfig_mam">>,
@@ -203,8 +205,10 @@ get_room_config(X, RoomState, _From, Lang) ->
 			  label = translate:translate(Lang, Label),
 			  var = Var,
 			  values = [Val]},
-    X ++ [XField].
+    XFields ++ [XField].
 
+-spec set_room_option({pos_integer(), _}, binary(), [binary()], binary())
+      -> {pos_integer(), _}.
 set_room_option(_Acc, <<"muc#roomconfig_mam">> = Opt, Vals, Lang) ->
     try
 	Val = case Vals of
@@ -222,6 +226,7 @@ set_room_option(_Acc, <<"muc#roomconfig_mam">> = Opt, Vals, Lang) ->
 set_room_option(Acc, _Opt, _Vals, _Lang) ->
     Acc.
 
+-spec user_receive_packet(stanza(), ejabberd_c2s:state(), jid(), jid(), jid()) -> stanza().
 user_receive_packet(Pkt, C2SState, JID, Peer, To) ->
     LUser = JID#jid.luser,
     LServer = JID#jid.lserver,
@@ -239,6 +244,7 @@ user_receive_packet(Pkt, C2SState, JID, Peer, To) ->
 	    Pkt
     end.
 
+-spec user_send_packet(stanza(), ejabberd_c2s:state(), jid(), jid()) -> stanza().
 user_send_packet(Pkt, C2SState, JID, Peer) ->
     LUser = JID#jid.luser,
     LServer = JID#jid.lserver,
@@ -256,10 +262,14 @@ user_send_packet(Pkt, C2SState, JID, Peer) ->
 	    Pkt
     end.
 
+-spec user_send_packet_strip_tag(stanza(), ejabberd_c2s:state(),
+				 jid(), jid()) -> stanza().
 user_send_packet_strip_tag(Pkt, _C2SState, JID, _Peer) ->
     LServer = JID#jid.lserver,
     strip_my_archived_tag(Pkt, LServer).
 
+-spec muc_filter_message(message(), mod_muc_room:state(),
+			 jid(), jid(), binary()) -> message().
 muc_filter_message(Pkt, #state{config = Config} = MUCState,
 		   RoomJID, From, FromNick) ->
     if Config#config.mam ->
@@ -302,6 +312,7 @@ process_iq_v0_3(#iq{from = #jid{lserver = LServer},
 process_iq_v0_3(IQ) ->
     process_iq(IQ).
 
+-spec muc_process_iq(ignore | iq(), mod_muc_room:state()) -> ignore | iq().
 muc_process_iq(#iq{type = T, lang = Lang,
 		   from = From,
 		   sub_els = [#mam_query{xmlns = NS}]} = IQ,
@@ -372,6 +383,8 @@ disco_sm_features({result, OtherFeatures},
 disco_sm_features(Acc, _From, _To, _Node, _Lang) ->
     Acc.
 
+-spec message_is_archived(boolean(), ejabberd_c2s:state(),
+			  jid(), jid(), message()) -> boolean().
 message_is_archived(true, _C2SState, _Peer, _JID, _Pkt) ->
     true;
 message_is_archived(false, C2SState, Peer,
diff --git a/src/mod_metrics.erl b/src/mod_metrics.erl
index 605fe3d6b..7861542c5 100644
--- a/src/mod_metrics.erl
+++ b/src/mod_metrics.erl
@@ -86,9 +86,12 @@ sm_register_connection_hook(_SID, #jid{lserver=LServer}, _Info) ->
 sm_remove_connection_hook(_SID, #jid{lserver=LServer}, _Info) ->
     push(LServer, sm_remove_connection).
 
+-spec user_send_packet(stanza(), ejabberd_c2s:state(), jid(), jid()) -> stanza().
 user_send_packet(Packet, _C2SState, #jid{lserver=LServer}, _To) ->
     push(LServer, user_send_packet),
     Packet.
+
+-spec user_receive_packet(stanza(), ejabberd_c2s:state(), jid(), jid(), jid()) -> stanza().
 user_receive_packet(Packet, _C2SState, _JID, _From, #jid{lserver=LServer}) ->
     push(LServer, user_receive_packet),
     Packet.
diff --git a/src/mod_offline.erl b/src/mod_offline.erl
index 03eb3c59a..509406aa4 100644
--- a/src/mod_offline.erl
+++ b/src/mod_offline.erl
@@ -533,6 +533,9 @@ resend_offline_messages(User, Server) ->
       _ -> ok
     end.
 
+-spec pop_offline_messages([{route, jid(), jid(), message()}],
+			   binary(), binary()) ->
+      [{route, jid(), jid(), message()}].
 pop_offline_messages(Ls, User, Server) ->
     LUser = jid:nodeprep(User),
     LServer = jid:nameprep(Server),
diff --git a/src/mod_pres_counter.erl b/src/mod_pres_counter.erl
index 786ba97f2..955e53f6f 100644
--- a/src/mod_pres_counter.erl
+++ b/src/mod_pres_counter.erl
@@ -51,6 +51,8 @@ stop(Host) ->
 depends(_Host, _Opts) ->
     [].
 
+-spec check_packet(allow | deny, binary(), binary(), _,
+		   {jid(), jid(), stanza()}, in | out) -> allow | deny.
 check_packet(_, _User, Server, _PrivacyList,
 	     {From, To, #presence{type = Type}}, Dir) ->
     IsSubscription = case Type of
diff --git a/src/mod_pubsub.erl b/src/mod_pubsub.erl
index 0796a20bb..fadc7720c 100644
--- a/src/mod_pubsub.erl
+++ b/src/mod_pubsub.erl
@@ -722,6 +722,9 @@ out_subscription(User, Server, JID, subscribed) ->
 out_subscription(_, _, _, _) ->
     true.
 
+-spec in_subscription(boolean(), binary(), binary(), jid(),
+		      subscribe | subscribed | unsubscribe | unsubscribed,
+		      binary()) -> true.
 in_subscription(_, User, Server, Owner, unsubscribed, _) ->
     unsubscribe_user(jid:make(User, Server, <<>>), Owner),
     true;
diff --git a/src/mod_roster.erl b/src/mod_roster.erl
index c118a61ff..2a41907a4 100644
--- a/src/mod_roster.erl
+++ b/src/mod_roster.erl
@@ -175,6 +175,7 @@ roster_version_on_db(Host) ->
 			   false).
 
 %% Returns a list that may contain an xmlelement with the XEP-237 feature if it's enabled.
+-spec get_versioning_feature([xmpp_element()], binary()) -> [xmpp_element()].
 get_versioning_feature(Acc, Host) ->
     case roster_versioning_enabled(Host) of
       true ->
@@ -274,6 +275,7 @@ process_iq_get(#iq{from = From, to = To, lang = Lang,
 	    xmpp:make_error(IQ, xmpp:err_internal_server_error(Txt, Lang))
     end.
 
+-spec get_user_roster([#roster{}], {binary(), binary()}) -> [#roster{}].
 get_user_roster(Acc, {LUser, LServer}) ->
     Items = get_roster(LUser, LServer),
     lists:filter(fun (#roster{subscription = none,
@@ -416,6 +418,8 @@ push_item_version(Server, User, From, Item,
 		  end,
 		  ejabberd_sm:get_user_resources(User, Server)).
 
+-spec get_subscription_lists({[ljid()], [ljid()]}, binary(), binary())
+      -> {[ljid()], [ljid()]}.
 get_subscription_lists(_Acc, User, Server) ->
     LUser = jid:nodeprep(User),
     LServer = jid:nameprep(Server),
@@ -448,6 +452,9 @@ transaction(LServer, F) ->
     Mod = gen_mod:db_mod(LServer, ?MODULE),
     Mod:transaction(LServer, F).
 
+-spec in_subscription(boolean(), binary(), binary(), jid(),
+		      subscribe | subscribed | unsubscribe | unsubscribed,
+		      binary()) -> boolean().
 in_subscription(_, User, Server, JID, Type, Reason) ->
     process_subscription(in, User, Server, JID, Type,
 			 Reason).
@@ -726,6 +733,7 @@ process_item_set_t(LUser, LServer, #roster_item{jid = JID1} = QueryItem) ->
     end;
 process_item_set_t(_LUser, _LServer, _) -> ok.
 
+-spec get_in_pending_subscriptions([presence()], binary(), binary()) -> [presence()].
 get_in_pending_subscriptions(Ls, User, Server) ->
     LServer = jid:nameprep(Server),
     Mod = gen_mod:db_mod(LServer, ?MODULE),
@@ -755,6 +763,8 @@ read_subscription_and_groups(User, Server, LJID) ->
     Mod = gen_mod:db_mod(LServer, ?MODULE),
     Mod:read_subscription_and_groups(LUser, LServer, LJID).
 
+-spec get_jid_info({subscription(), [binary()]}, binary(), binary(), jid())
+      -> {subscription(), [binary()]}.
 get_jid_info(_, User, Server, JID) ->
     LJID = jid:tolower(JID),
     case read_subscription_and_groups(User, Server, LJID) of
diff --git a/src/mod_service_log.erl b/src/mod_service_log.erl
index a88b04b58..ea7768bca 100644
--- a/src/mod_service_log.erl
+++ b/src/mod_service_log.erl
@@ -54,14 +54,17 @@ stop(Host) ->
 depends(_Host, _Opts) ->
     [].
 
+-spec log_user_send(stanza(), ejabberd_c2s:state(), jid(), jid()) -> stanza().
 log_user_send(Packet, _C2SState, From, To) ->
     log_packet(From, To, Packet, From#jid.lserver),
     Packet.
 
+-spec log_user_receive(stanza(), ejabberd_c2s:state(), jid(), jid(), jid()) -> stanza().
 log_user_receive(Packet, _C2SState, _JID, From, To) ->
     log_packet(From, To, Packet, To#jid.lserver),
     Packet.
 
+-spec log_packet(jid(), jid(), stanza(), binary()) -> ok.
 log_packet(From, To, Packet, Host) ->
     Loggers = gen_mod:get_module_opt(Host, ?MODULE, loggers,
                                      fun(L) ->
diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl
index ac3717bd3..8b620514b 100644
--- a/src/mod_shared_roster.erl
+++ b/src/mod_shared_roster.erl
@@ -135,6 +135,7 @@ stop(Host) ->
 depends(_Host, _Opts) ->
     [].
 
+-spec get_user_roster([#roster{}], {binary(), binary()}) -> [#roster{}].
 get_user_roster(Items, US) ->
     {U, S} = US,
     DisplayedGroups = get_user_displayed_groups(US),
@@ -202,6 +203,7 @@ get_rosteritem_name_vcard(_) ->
 
 %% This function rewrites the roster entries when moving or renaming
 %% them in the user contact list.
+-spec process_item(#roster{}, binary()) -> #roster{}.
 process_item(RosterItem, Host) ->
     USFrom = {UserFrom, ServerFrom} = RosterItem#roster.us,
     {UserTo, ServerTo, ResourceTo} = RosterItem#roster.jid,
@@ -292,6 +294,8 @@ set_item(User, Server, Resource, Item) ->
 			  jid:make(Server),
 			  ResIQ).
 
+-spec get_subscription_lists({[ljid()], [ljid()]}, binary(), binary())
+      -> {[ljid()], [ljid()]}.
 get_subscription_lists({F, T}, User, Server) ->
     LUser = jid:nodeprep(User),
     LServer = jid:nameprep(Server),
@@ -304,6 +308,8 @@ get_subscription_lists({F, T}, User, Server) ->
     SRJIDs = [{U1, S1, <<"">>} || {U1, S1} <- SRUsers],
     {lists:usort(SRJIDs ++ F), lists:usort(SRJIDs ++ T)}.
 
+-spec get_jid_info({subscription(), [binary()]}, binary(), binary(), jid())
+      -> {subscription(), [binary()]}.
 get_jid_info({Subscription, Groups}, User, Server,
 	     JID) ->
     LUser = jid:nodeprep(User),
@@ -332,6 +338,9 @@ get_jid_info({Subscription, Groups}, User, Server,
       error -> {Subscription, Groups}
     end.
 
+-spec in_subscription(boolean(), binary(), binary(), jid(),
+		      subscribe | subscribed | unsubscribe | unsubscribed,
+		      binary()) -> boolean().
 in_subscription(Acc, User, Server, JID, Type,
 		_Reason) ->
     process_subscription(in, User, Server, JID, Type, Acc).
diff --git a/src/mod_shared_roster_ldap.erl b/src/mod_shared_roster_ldap.erl
index 809887237..97ead9f3d 100644
--- a/src/mod_shared_roster_ldap.erl
+++ b/src/mod_shared_roster_ldap.erl
@@ -111,6 +111,7 @@ depends(_Host, _Opts) ->
 %%--------------------------------------------------------------------
 %% Hooks
 %%--------------------------------------------------------------------
+-spec get_user_roster([#roster{}], {binary(), binary()}) -> [#roster{}].
 get_user_roster(Items, {U, S} = US) ->
     SRUsers = get_user_to_groups_map(US, true),
     {NewItems1, SRUsersRest} = lists:mapfoldl(fun (Item,
@@ -143,6 +144,7 @@ get_user_roster(Items, {U, S} = US) ->
 
 %% This function in use to rewrite the roster entries when moving or renaming
 %% them in the user contact list.
+-spec process_item(#roster{}, binary()) -> #roster{}.
 process_item(RosterItem, _Host) ->
     USFrom = RosterItem#roster.us,
     {User, Server, _Resource} = RosterItem#roster.jid,
@@ -158,6 +160,8 @@ process_item(RosterItem, _Host) ->
       _ -> RosterItem#roster{subscription = both, ask = none}
     end.
 
+-spec get_subscription_lists({[ljid()], [ljid()]}, binary(), binary())
+      -> {[ljid()], [ljid()]}.
 get_subscription_lists({F, T}, User, Server) ->
     LUser = jid:nodeprep(User),
     LServer = jid:nameprep(Server),
@@ -170,6 +174,8 @@ get_subscription_lists({F, T}, User, Server) ->
     SRJIDs = [{U1, S1, <<"">>} || {U1, S1} <- SRUsers],
     {lists:usort(SRJIDs ++ F), lists:usort(SRJIDs ++ T)}.
 
+-spec get_jid_info({subscription(), [binary()]}, binary(), binary(), jid())
+      -> {subscription(), [binary()]}.
 get_jid_info({Subscription, Groups}, User, Server,
 	     JID) ->
     LUser = jid:nodeprep(User),
@@ -187,6 +193,9 @@ get_jid_info({Subscription, Groups}, User, Server,
       error -> {Subscription, Groups}
     end.
 
+-spec in_subscription(boolean(), binary(), binary(), jid(),
+		      subscribe | subscribed | unsubscribe | unsubscribed,
+		      binary()) -> boolean().
 in_subscription(Acc, User, Server, JID, Type,
 		_Reason) ->
     process_subscription(in, User, Server, JID, Type, Acc).
diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl
index 4653d6e2c..f0fb556ba 100644
--- a/src/mod_vcard.erl
+++ b/src/mod_vcard.erl
@@ -423,6 +423,7 @@ search(LServer, XFields) ->
     Mod:search(LServer, Data, AllowReturnAll, MaxMatch).
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-spec remove_user(binary(), binary()) -> any().
 remove_user(User, Server) ->
     LUser = jid:nodeprep(User),
     LServer = jid:nameprep(Server),

From 45eb49125ba46cd692a9fb430c567c0c2cf4a84d Mon Sep 17 00:00:00 2001
From: Evgeniy Khramtsov 
Date: Tue, 30 Aug 2016 09:48:08 +0300
Subject: [PATCH 036/151] Rewrite mod_pubsub to use XML codec

---
 include/xmpp_codec.hrl   |  224 +-
 src/gen_pubsub_node.erl  |   21 +-
 src/mod_caps.erl         |    6 +-
 src/mod_client_state.erl |    4 +-
 src/mod_muc_room.erl     |   12 +-
 src/mod_pubsub.erl       | 2907 ++++++++++++-------------
 src/node_flat_sql.erl    |  533 +++--
 src/xmpp.erl             |   10 +-
 src/xmpp_codec.erl       | 4325 +++++++++++++++++++++++++++++---------
 tools/xmpp_codec.spec    |  403 +++-
 10 files changed, 5450 insertions(+), 2995 deletions(-)

diff --git a/include/xmpp_codec.hrl b/include/xmpp_codec.hrl
index 3424ec3b9..7eabdab8f 100644
--- a/include/xmpp_codec.hrl
+++ b/include/xmpp_codec.hrl
@@ -5,6 +5,47 @@
 			hash :: binary()}).
 -type vcard_xupdate() :: #vcard_xupdate{}.
 
+-record(ps_affiliation, {xmlns = <<>> :: binary(),
+			 node = <<>> :: binary(),
+			 type :: member | none | outcast |
+				 owner | publisher | 'publish-only',
+			 jid :: jid:jid()}).
+-type ps_affiliation() :: #ps_affiliation{}.
+
+-type ps_error_type() :: 'closed-node' | 'configuration-required' |
+			 'invalid-jid' | 'invalid-options' |
+			 'invalid-payload' | 'invalid-subid' |
+			 'item-forbidden' | 'item-required' | 'jid-required' |
+			 'max-items-exceeded' | 'max-nodes-exceeded' |
+			 'nodeid-required' | 'not-in-roster-group' |
+			 'not-subscribed' | 'payload-too-big' |
+			 'payload-required' | 'pending-subscription' |
+			 'presence-subscription-required' | 'subid-required' |
+			 'too-many-subscriptions' | 'unsupported' |
+			 'unsupported-access-model'.
+-type ps_error_feature() :: 'access-authorize' | 'access-open' |
+			    'access-presence' | 'access-roster' |
+			    'access-whitelist' | 'auto-create' |
+			    'auto-subscribe' | 'collections' | 'config-node' |
+			    'create-and-configure' | 'create-nodes' |
+			    'delete-items' | 'delete-nodes' |
+			    'filtered-notifications' | 'get-pending' |
+			    'instant-nodes' | 'item-ids' | 'last-published' |
+			    'leased-subscription' | 'manage-subscriptions' |
+			    'member-affiliation' | 'meta-data' |
+			    'modify-affiliations' | 'multi-collection' |
+			    'multi-subscribe' | 'outcast-affiliation' |
+			    'persistent-items' | 'presence-notifications' |
+			    'presence-subscribe' | 'publish' |
+			    'publish-options' | 'publish-only-affiliation' |
+			    'publisher-affiliation' | 'purge-nodes' |
+			    'retract-items' | 'retrieve-affiliations' |
+			    'retrieve-default' | 'retrieve-items' |
+			    'retrieve-subscriptions' | 'subscribe' |
+			    'subscription-options' | 'subscription-notifications'.
+-record(ps_error, {type :: ps_error_type(), feature :: ps_error_feature()}).
+-type ps_error() :: #ps_error{}.
+
 -record(chatstate, {type :: active | composing | gone | inactive | paused}).
 -type chatstate() :: #chatstate{}.
 
@@ -77,10 +118,10 @@
 -record(muc_unsubscribe, {}).
 -type muc_unsubscribe() :: #muc_unsubscribe{}.
 
--record(pubsub_unsubscribe, {node = <<>> :: binary(),
-                             jid :: jid:jid(),
-                             subid = <<>> :: binary()}).
--type pubsub_unsubscribe() :: #pubsub_unsubscribe{}.
+-record(ps_unsubscribe, {node = <<>> :: binary(),
+                         jid :: jid:jid(),
+                         subid = <<>> :: binary()}).
+-type ps_unsubscribe() :: #ps_unsubscribe{}.
 
 -record(mix_leave, {}).
 -type mix_leave() :: #mix_leave{}.
@@ -105,10 +146,6 @@
                     height :: non_neg_integer()}).
 -type thumbnail() :: #thumbnail{}.
 
--record(pubsub_affiliation, {node = <<>> :: binary(),
-                             type :: 'member' | 'none' | 'outcast' | 'owner' | 'publish-only' | 'publisher'}).
--type pubsub_affiliation() :: #pubsub_affiliation{}.
-
 -record(muc_decline, {reason = <<>> :: binary(),
                       from :: jid:jid(),
                       to :: jid:jid()}).
@@ -195,13 +232,16 @@
 -record(feature_sm, {xmlns = <<>> :: binary()}).
 -type feature_sm() :: #feature_sm{}.
 
--record(pubsub_item, {id = <<>> :: binary(),
-                      xml_els = [] :: [fxml:xmlel()]}).
--type pubsub_item() :: #pubsub_item{}.
+-record(ps_item, {xmlns = <<>> :: binary(),
+                  id = <<>> :: binary(),
+                  xml_els = [] :: [fxml:xmlel()],
+                  node = <<>> :: binary(),
+                  publisher = <<>> :: binary()}).
+-type ps_item() :: #ps_item{}.
 
--record(pubsub_publish, {node = <<>> :: binary(),
-                         items = [] :: [#pubsub_item{}]}).
--type pubsub_publish() :: #pubsub_publish{}.
+-record(ps_publish, {node = <<>> :: binary(),
+                     items = [] :: [#ps_item{}]}).
+-type ps_publish() :: #ps_publish{}.
 
 -record(roster_item, {jid :: jid:jid(),
                       name = <<>> :: binary(),
@@ -214,12 +254,6 @@
                        ver :: binary()}).
 -type roster_query() :: #roster_query{}.
 
--record(pubsub_event_item, {id = <<>> :: binary(),
-                            node = <<>> :: binary(),
-                            publisher = <<>> :: binary(),
-                            xml_els = [] :: [fxml:xmlel()]}).
--type pubsub_event_item() :: #pubsub_event_item{}.
-
 -record(sm_r, {xmlns = <<>> :: binary()}).
 -type sm_r() :: #sm_r{}.
 
@@ -263,14 +297,6 @@
                      xmlns = <<>> :: binary()}).
 -type sm_enabled() :: #sm_enabled{}.
 
--record(pubsub_event_items, {node = <<>> :: binary(),
-                             retract = [] :: [binary()],
-                             items = [] :: [#pubsub_event_item{}]}).
--type pubsub_event_items() :: #pubsub_event_items{}.
-
--record(pubsub_event, {items = [] :: [#pubsub_event_items{}]}).
--type pubsub_event() :: #pubsub_event{}.
-
 -record(muc_unique, {name = <<>> :: binary()}).
 -type muc_unique() :: #muc_unique{}.
 
@@ -283,9 +309,9 @@
                       resource :: binary()}).
 -type legacy_auth() :: #legacy_auth{}.
 
--record(pubsub_subscribe, {node = <<>> :: binary(),
-                           jid :: jid:jid()}).
--type pubsub_subscribe() :: #pubsub_subscribe{}.
+-record(ps_subscribe, {node = <<>> :: binary(),
+                       jid :: jid:jid()}).
+-type ps_subscribe() :: #ps_subscribe{}.
 
 -record(message, {id = <<>> :: binary(),
                   type = normal :: 'chat' | 'error' | 'groupchat' | 'headline' | 'normal',
@@ -325,11 +351,13 @@
 -record(muc_subscriptions, {list = [] :: [jid:jid()]}).
 -type muc_subscriptions() :: #muc_subscriptions{}.
 
--record(pubsub_subscription, {jid :: jid:jid(),
-                              node = <<>> :: binary(),
-                              subid = <<>> :: binary(),
-                              type :: 'none' | 'pending' | 'subscribed' | 'unconfigured'}).
--type pubsub_subscription() :: #pubsub_subscription{}.
+-record(ps_subscription, {xmlns = <<>> :: binary(),
+                          jid :: jid:jid(),
+                          type :: 'none' | 'pending' | 'subscribed' | 'unconfigured',
+                          node = <<>> :: binary(),
+                          subid = <<>> :: binary(),
+                          expiry :: erlang:timestamp()}).
+-type ps_subscription() :: #ps_subscription{}.
 
 -record(bob_data, {cid = <<>> :: binary(),
                    'max-age' :: non_neg_integer(),
@@ -375,11 +403,13 @@
                 node = <<>> :: binary()}).
 -type stats() :: #stats{}.
 
--record(pubsub_items, {node = <<>> :: binary(),
-                       max_items :: non_neg_integer(),
-                       subid = <<>> :: binary(),
-                       items = [] :: [#pubsub_item{}]}).
--type pubsub_items() :: #pubsub_items{}.
+-record(ps_items, {xmlns = <<>> :: binary(),
+                   node = <<>> :: binary(),
+                   items = [] :: [#ps_item{}],
+                   max_items :: non_neg_integer(),
+                   subid = <<>> :: binary(),
+                   retract :: binary()}).
+-type ps_items() :: #ps_items{}.
 
 -record(presence, {id = <<>> :: binary(),
                    type = available :: 'available' | 'error' | 'probe' | 'subscribe' | 'subscribed' | 'unavailable' | 'unsubscribe' | 'unsubscribed',
@@ -438,10 +468,10 @@
 -record(carbons_received, {forwarded :: #forwarded{}}).
 -type carbons_received() :: #carbons_received{}.
 
--record(pubsub_retract, {node = <<>> :: binary(),
-                         notify = false :: boolean(),
-                         items = [] :: [#pubsub_item{}]}).
--type pubsub_retract() :: #pubsub_retract{}.
+-record(ps_retract, {node = <<>> :: binary(),
+                     notify = false :: boolean(),
+                     items = [] :: [#ps_item{}]}).
+-type ps_retract() :: #ps_retract{}.
 
 -record(upload_slot, {get :: binary(),
                       put :: binary(),
@@ -707,22 +737,46 @@
                     xdata :: #xdata{}}).
 -type mam_query() :: #mam_query{}.
 
--record(pubsub_options, {node = <<>> :: binary(),
-                         jid :: jid:jid(),
-                         subid = <<>> :: binary(),
-                         xdata :: #xdata{}}).
--type pubsub_options() :: #pubsub_options{}.
+-record(pubsub_owner, {affiliations :: {binary(),[#ps_affiliation{}]},
+                       configure :: {binary(),'undefined' | #xdata{}},
+                       default :: {binary(),'undefined' | #xdata{}},
+                       delete :: {binary(),binary()},
+                       purge :: binary(),
+                       subscriptions :: {binary(),[#ps_subscription{}]}}).
+-type pubsub_owner() :: #pubsub_owner{}.
 
--record(pubsub, {subscriptions :: {binary(),[#pubsub_subscription{}]},
-                 affiliations :: [#pubsub_affiliation{}],
-                 publish :: #pubsub_publish{},
-                 subscribe :: #pubsub_subscribe{},
-                 unsubscribe :: #pubsub_unsubscribe{},
-                 options :: #pubsub_options{},
-                 items :: #pubsub_items{},
-                 retract :: #pubsub_retract{}}).
+-record(ps_options, {node = <<>> :: binary(),
+                     jid :: jid:jid(),
+                     subid = <<>> :: binary(),
+                     xdata :: #xdata{}}).
+-type ps_options() :: #ps_options{}.
+
+-record(pubsub, {subscriptions :: {binary(),[#ps_subscription{}]},
+                 subscription :: #ps_subscription{},
+                 affiliations :: {binary(),[#ps_affiliation{}]},
+                 publish :: #ps_publish{},
+                 publish_options :: #xdata{},
+                 subscribe :: #ps_subscribe{},
+                 unsubscribe :: #ps_unsubscribe{},
+                 options :: #ps_options{},
+                 items :: #ps_items{},
+                 retract :: #ps_retract{},
+                 create :: binary(),
+                 configure :: {binary(),'undefined' | #xdata{}},
+                 default :: {binary(),'undefined' | #xdata{}},
+                 delete :: {binary(),binary()},
+                 purge :: binary(),
+                 rsm :: #rsm_set{}}).
 -type pubsub() :: #pubsub{}.
 
+-record(ps_event, {items :: #ps_items{},
+                   purge :: binary(),
+                   subscription :: #ps_subscription{},
+                   delete :: {binary(),binary()},
+                   create :: binary(),
+                   configuration :: {binary(),'undefined' | #xdata{}}}).
+-type ps_event() :: #ps_event{}.
+
 -record(register, {registered = false :: boolean(),
                    remove = false :: boolean(),
                    instructions :: binary(),
@@ -852,21 +906,27 @@
 
 -type xmpp_element() :: muc_admin() |
                         compression() |
-                        pubsub_subscription() |
+                        ps_subscription() |
                         xdata_option() |
                         version() |
-                        pubsub_affiliation() |
+                        ps_affiliation() |
                         mam_fin() |
                         sm_a() |
                         bob_data() |
                         media() |
+                        stanza_id() |
+                        starttls_proceed() |
+                        client_id() |
+                        sm_resumed() |
+                        forwarded() |
+                        xevent() |
+                        privacy_list() |
                         carbons_sent() |
                         mam_archived() |
                         p1_rebind() |
                         sasl_abort() |
                         db_result() |
                         carbons_received() |
-                        pubsub_retract() |
                         upload_slot() |
                         mix_participant() |
                         compressed() |
@@ -875,31 +935,20 @@
                         'see-other-host'() |
                         hint() |
                         stream_start() |
-                        stanza_id() |
-                        starttls_proceed() |
-                        client_id() |
-                        sm_resumed() |
-                        forwarded() |
-                        xevent() |
-                        privacy_list() |
                         text() |
                         vcard_org() |
                         shim() |
                         search_item() |
                         offline_item() |
                         feature_sm() |
-                        pubsub_item() |
                         roster_item() |
-                        pubsub_event_item() |
                         muc_item() |
                         vcard_temp() |
                         address() |
                         sasl_success() |
                         addresses() |
-                        pubsub_event_items() |
                         muc_subscriptions() |
                         disco_items() |
-                        pubsub_options() |
                         compress() |
                         bytestreams() |
                         adhoc_actions() |
@@ -912,9 +961,16 @@
                         vcard_tel() |
                         vcard_geo() |
                         vcard_photo() |
+                        pubsub_owner() |
                         pubsub() |
                         muc_owner() |
                         muc_actor() |
+                        ps_error() |
+                        starttls_failure() |
+                        sasl_challenge() |
+                        x_conference() |
+                        private() |
+                        sasl_failure() |
                         vcard_name() |
                         adhoc_note() |
                         rosterver_feature() |
@@ -924,18 +980,15 @@
                         bookmark_conference() |
                         offline() |
                         time() |
+                        ps_subscribe() |
                         sm_enable() |
-                        starttls_failure() |
-                        sasl_challenge() |
                         handshake() |
-                        x_conference() |
-                        private() |
                         compress_failure() |
-                        sasl_failure() |
                         bookmark_storage() |
                         muc_decline() |
                         legacy_auth() |
                         search() |
+                        ps_publish() |
                         nick() |
                         p1_ack() |
                         block() |
@@ -946,11 +999,12 @@
                         xcaptcha() |
                         streamhost() |
                         bind() |
+                        ps_retract() |
                         last() |
                         redirect() |
                         sm_enabled() |
-                        pubsub_event() |
                         vcard_sound() |
+                        ps_event() |
                         mam_result() |
                         rsm_first() |
                         stat() |
@@ -961,15 +1015,17 @@
                         ping() |
                         privacy_item() |
                         disco_item() |
+                        ps_item() |
+                        mam_prefs() |
+                        sasl_mechanisms() |
                         caps() |
                         muc() |
                         stream_features() |
                         stats() |
-                        pubsub_items() |
+                        ps_items() |
                         sic() |
+                        ps_options() |
                         starttls() |
-                        mam_prefs() |
-                        sasl_mechanisms() |
                         media_uri() |
                         muc_destroy() |
                         vcard_key() |
@@ -990,23 +1046,21 @@
                         stream_error() |
                         muc_user() |
                         vcard_adr() |
+                        gone() |
                         carbons_private() |
                         mix_leave() |
                         muc_subscribe() |
                         muc_unique() |
                         sasl_response() |
-                        pubsub_subscribe() |
                         message() |
                         presence() |
-                        gone() |
                         sm_resume() |
                         carbons_enable() |
                         expire() |
                         muc_unsubscribe() |
-                        pubsub_unsubscribe() |
+                        ps_unsubscribe() |
                         chatstate() |
                         sasl_auth() |
                         p1_push() |
                         oob_x() |
-                        pubsub_publish() |
                         unblock().
diff --git a/src/gen_pubsub_node.erl b/src/gen_pubsub_node.erl
index 27cb032bd..cc94ea147 100644
--- a/src/gen_pubsub_node.erl
+++ b/src/gen_pubsub_node.erl
@@ -25,7 +25,7 @@
 
 -module(gen_pubsub_node).
 
--include("jlib.hrl").
+-include("xmpp.hrl").
 
 -type(host() :: mod_pubsub:host()).
 -type(nodeId() :: mod_pubsub:nodeId()).
@@ -175,20 +175,13 @@
     ok |
     {error, xmlel()}.
 
--callback get_items(NodeIdx :: nodeIdx(),
-	JID :: jid(),
-	AccessModel :: accessModel(),
-	Presence_Subscription :: boolean(),
-	RosterGroup :: boolean(),
-	SubId :: subId(),
-	RSM :: none | rsm_in()) ->
-    {result, {[pubsubItem()], none | rsm_out()}} |
-    {error, xmlel()}.
+-callback get_items(nodeIdx(), jid(), accessModel(),
+		    boolean(), boolean(), binary(),
+		    undefined | rsm_set()) ->
+    {result, {[pubsubItem()], undefined | rsm_set()}} | {error, error()}.
 
--callback get_items(NodeIdx :: nodeIdx(),
-	From :: jid(),
-	RSM :: none | rsm_in()) ->
-    {result, {[pubsubItem()], none | rsm_out()}}.
+-callback get_items(nodeIdx(), jid(), undefined | rsm_set()) ->
+    {result, {[pubsubItem()], undefined | rsm_set()}}.
 
 -callback get_item(NodeIdx :: nodeIdx(),
 	ItemId :: itemId(),
diff --git a/src/mod_caps.erl b/src/mod_caps.erl
index e57bc7928..a388b085f 100644
--- a/src/mod_caps.erl
+++ b/src/mod_caps.erl
@@ -406,13 +406,15 @@ feature_response(_IQResult, Host, From, Caps,
 		 [_SubNode | SubNodes]) ->
     feature_request(Host, From, Caps, SubNodes).
 
--spec caps_read_fun(binary(), {binary(), binary()}) -> function().
+-spec caps_read_fun(binary(), {binary(), binary()})
+      -> fun(() -> {ok, [binary()] | non_neg_integer()} | error).
 caps_read_fun(Host, Node) ->
     LServer = jid:nameprep(Host),
     Mod = gen_mod:db_mod(LServer, ?MODULE),
     fun() -> Mod:caps_read(LServer, Node) end.
 
--spec caps_write_fun(binary(), {binary(), binary()}, [binary()]) -> function().
+-spec caps_write_fun(binary(), {binary(), binary()},
+		     [binary()] | non_neg_integer()) -> fun().
 caps_write_fun(Host, Node, Features) ->
     LServer = jid:nameprep(Host),
     Mod = gen_mod:db_mod(LServer, ?MODULE),
diff --git a/src/mod_client_state.erl b/src/mod_client_state.erl
index 042c59702..f72f334f3 100644
--- a/src/mod_client_state.erl
+++ b/src/mod_client_state.erl
@@ -287,8 +287,8 @@ get_pep_node(#message{from = #jid{luser = <<>>}}) ->
     %% It's not PEP.
     undefined;
 get_pep_node(#message{} = Msg) ->
-    case xmpp:get_subtag(Msg, #pubsub_event{}) of
-	#pubsub_event{items = [#pubsub_event_items{node = Node}]} ->
+    case xmpp:get_subtag(Msg, #ps_event{}) of
+	#ps_event{items = #ps_items{node = Node}} ->
 	    Node;
 	_ ->
 	    undefined
diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl
index b470c093e..2f2962b97 100644
--- a/src/mod_muc_room.erl
+++ b/src/mod_muc_room.erl
@@ -4377,12 +4377,12 @@ send_wrapped(From, To, Packet, Node, State) ->
 wrap(From, To, Packet, Node) ->
     El = xmpp:encode(xmpp:set_from_to(Packet, From, To)),
     #message{
-       sub_els = [#pubsub_event{
-		     items = [#pubsub_event_items{
-				 node = Node,
-				 items = [#pubsub_event_item{
-					     id = randoms:get_string(),
-					     xml_els = [El]}]}]}]}.
+       sub_els = [#ps_event{
+		     items = #ps_items{
+				node = Node,
+				items = [#ps_item{
+					    id = randoms:get_string(),
+					    xml_els = [El]}]}}]}.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %% Multicast
diff --git a/src/mod_pubsub.erl b/src/mod_pubsub.erl
index fadc7720c..c84fb5fe8 100644
--- a/src/mod_pubsub.erl
+++ b/src/mod_pubsub.erl
@@ -41,8 +41,9 @@
 
 -include("ejabberd.hrl").
 -include("logger.hrl").
--include("adhoc.hrl").
--include("jlib.hrl").
+%%-include("adhoc.hrl").
+%%-include("jlib.hrl").
+-include("xmpp.hrl").
 -include("pubsub.hrl").
 
 -define(STDTREE, <<"tree">>).
@@ -58,7 +59,9 @@
     disco_sm_features/5, disco_sm_items/5]).
 
 %% exported iq handlers
--export([iq_sm/3]).
+-export([iq_sm/1, process_disco_info/1, process_disco_items/1,
+	 process_pubsub/1, process_pubsub_owner/1, process_vcard/1,
+	 process_commands/1]).
 
 %% exports for console debug manual use
 -export([create_node/5, create_node/7, delete_node/3,
@@ -70,10 +73,21 @@
 %% general helpers for plugins
 -export([subscription_to_string/1, affiliation_to_string/1,
     string_to_subscription/1, string_to_affiliation/1,
-    extended_error/2, extended_error/3, service_jid/1,
+    extended_error/2, service_jid/1,
     tree/1, tree/2, plugin/2, plugins/1, config/3,
     host/1, serverhost/1]).
 
+%% pubsub#errors
+-export([err_closed_node/0, err_configuration_required/0,
+	 err_invalid_jid/0, err_invalid_options/0, err_invalid_payload/0,
+	 err_invalid_subid/0, err_item_forbidden/0, err_item_required/0,
+	 err_jid_required/0, err_max_items_exceeded/0, err_max_nodes_exceeded/0,
+	 err_nodeid_required/0, err_not_in_roster_group/0, err_not_subscribed/0,
+	 err_payload_too_big/0, err_payload_required/0,
+	 err_pending_subscription/0, err_presence_subscription_required/0,
+	 err_subid_required/0, err_too_many_subscriptions/0, err_unsupported/1,
+	 err_unsupported_access_model/0]).
+
 %% API and gen_server callbacks
 -export([start_link/2, start/2, stop/1, init/1,
     handle_call/3, handle_cast/2, handle_info/2,
@@ -295,6 +309,18 @@ init([ServerHost, Opts]) ->
 	?MODULE, remove_user, 50),
     ejabberd_hooks:add(anonymous_purge_hook, ServerHost,
 	?MODULE, remove_user, 50),
+    gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO,
+				  ?MODULE, process_disco_info, IQDisc),
+    gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS,
+				  ?MODULE, process_disco_items, IQDisc),
+    gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_PUBSUB,
+				  ?MODULE, process_pubsub, IQDisc),
+    gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_PUBSUB_OWNER,
+				  ?MODULE, process_pubsub_owner, IQDisc),
+    gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_VCARD,
+				  ?MODULE, process_vcard, IQDisc),
+    gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_COMMANDS,
+				  ?MODULE, process_commands, IQDisc),
     case lists:member(?PEPNODE, Plugins) of
 	true ->
 	    ejabberd_hooks:add(caps_add, ServerHost,
@@ -489,27 +515,21 @@ send_loop(State) ->
 %% disco hooks handling functions
 %%
 
--spec disco_local_identity(Acc :: [xmlel()], _From :: jid(),
-			   To :: jid(), Node :: <<>> | mod_pubsub:nodeId(),
-			   Lang :: binary()) -> [xmlel()].
-
+-spec disco_local_identity([identity()], jid(), jid(),
+			   binary(), binary()) -> [identity()].
 disco_local_identity(Acc, _From, To, <<>>, _Lang) ->
     case lists:member(?PEPNODE, plugins(host(To#jid.lserver))) of
 	true ->
-	    [#xmlel{name = <<"identity">>,
-		    attrs = [{<<"category">>, <<"pubsub">>},
-			{<<"type">>, <<"pep">>}]}
-		| Acc];
+	    [#identity{category = <<"pubsub">>, type = <<"pep">>} | Acc];
 	false ->
 	    Acc
     end;
 disco_local_identity(Acc, _From, _To, _Node, _Lang) ->
     Acc.
 
--spec disco_local_features(Acc :: [xmlel()], _From :: jid(),
-			   To :: jid(), Node :: <<>> | mod_pubsub:nodeId(),
-			   Lang :: binary()) -> [binary(),...].
-
+-spec disco_local_features({error, error()} | {result, [binary()]} | empty,
+			   jid(), jid(), binary(), binary()) ->
+				  {error, error()} | {result, [binary()]} | empty.
 disco_local_features(Acc, _From, To, <<>>, _Lang) ->
     Host = host(To#jid.lserver),
     Feats = case Acc of
@@ -520,88 +540,83 @@ disco_local_features(Acc, _From, To, <<>>, _Lang) ->
 disco_local_features(Acc, _From, _To, _Node, _Lang) ->
     Acc.
 
+-spec disco_local_items({error, error()} | {result, [disco_item()]} | empty,
+			jid(), jid(), binary(), binary()) ->
+			       {error, error()} | {result, [disco_item()]} | empty.
 disco_local_items(Acc, _From, _To, <<>>, _Lang) -> Acc;
 disco_local_items(Acc, _From, _To, _Node, _Lang) -> Acc.
 
-%disco_sm_identity(Acc, From, To, Node, Lang)
-%    when is_binary(Node) ->
-%    disco_sm_identity(Acc, From, To, iolist_to_binary(Node),
-%                      Lang);
--spec disco_sm_identity(Acc :: empty | [xmlel()], From :: jid(),
-			To :: jid(), Node :: mod_pubsub:nodeId(),
-			Lang :: binary()) -> [xmlel()].
-
-disco_sm_identity(empty, From, To, Node, Lang) ->
-    disco_sm_identity([], From, To, Node, Lang);
+-spec disco_sm_identity([identity()], jid(), jid(),
+			binary(), binary()) -> [identity()].
 disco_sm_identity(Acc, From, To, Node, _Lang) ->
     disco_identity(jid:tolower(jid:remove_resource(To)), Node, From)
     ++ Acc.
 
+-spec disco_identity(binary(), binary(), jid()) -> [identity()].
 disco_identity(_Host, <<>>, _From) ->
-    [#xmlel{name = <<"identity">>,
-	    attrs = [{<<"category">>, <<"pubsub">>},
-		{<<"type">>, <<"pep">>}]}];
+    [#identity{category = <<"pubsub">>, type = <<"pep">>}];
 disco_identity(Host, Node, From) ->
-    Action = fun (#pubsub_node{id = Nidx, type = Type, options = Options, owners = O}) ->
-	    Owners = node_owners_call(Host, Type, Nidx, O),
-	    case get_allowed_items_call(Host, Nidx, From, Type, Options, Owners) of
-		{result, _} ->
-		    {result, [#xmlel{name = <<"identity">>,
-				attrs = [{<<"category">>, <<"pubsub">>},
-				    {<<"type">>, <<"pep">>}]},
-			    #xmlel{name = <<"identity">>,
-				attrs = [{<<"category">>, <<"pubsub">>},
-				    {<<"type">>, <<"leaf">>}
-				    | case get_option(Options, title) of
-					false -> [];
-					[Title] -> [{<<"name">>, Title}]
-				    end]}]};
-		_ ->
-		    {result, []}
-	    end
-    end,
+    Action =
+	fun(#pubsub_node{id = Nidx, type = Type,
+			 options = Options, owners = O}) ->
+		Owners = node_owners_call(Host, Type, Nidx, O),
+		case get_allowed_items_call(Host, Nidx, From, Type,
+					    Options, Owners) of
+		    {result, _} ->
+			{result, [#identity{category = <<"pubsub">>,
+					    type = <<"pep">>},
+				  #identity{category = <<"pubsub">>,
+					    type = <<"leaf">>,
+					    name = case get_option(Options, title) of
+						       false -> <<>>;
+						       [Title] -> Title
+						   end}]};
+		    _ ->
+			{result, []}
+		end
+	end,
     case transaction(Host, Node, Action, sync_dirty) of
 	{result, {_, Result}} -> Result;
 	_ -> []
     end.
 
--spec disco_sm_features(Acc :: empty | {result, Features::[Feature::binary()]},
-			From :: jid(), To :: jid(), Node :: mod_pubsub:nodeId(),
-			Lang :: binary()) -> {result, Features::[Feature::binary()]}.
-%disco_sm_features(Acc, From, To, Node, Lang)
-%    when is_binary(Node) ->
-%    disco_sm_features(Acc, From, To, iolist_to_binary(Node),
-%                      Lang);
+-spec disco_sm_features({error, error()} | {result, [binary()]} | empty,
+			jid(), jid(), binary(), binary()) ->
+			       {error, error()} | {result, [binary()]}.
 disco_sm_features(empty, From, To, Node, Lang) ->
     disco_sm_features({result, []}, From, To, Node, Lang);
 disco_sm_features({result, OtherFeatures} = _Acc, From, To, Node, _Lang) ->
     {result,
-	OtherFeatures ++
-	disco_features(jid:tolower(jid:remove_resource(To)), Node, From)};
+     OtherFeatures ++
+	 disco_features(jid:tolower(jid:remove_resource(To)), Node, From)};
 disco_sm_features(Acc, _From, _To, _Node, _Lang) -> Acc.
 
+-spec disco_features(ljid(), binary(), jid()) -> [binary()].
 disco_features(Host, <<>>, _From) ->
     [?NS_PUBSUB | [feature(F) || F <- plugin_features(Host, <<"pep">>)]];
 disco_features(Host, Node, From) ->
-    Action = fun (#pubsub_node{id = Nidx, type = Type, options = Options, owners = O}) ->
-	    Owners = node_owners_call(Host, Type, Nidx, O),
-	    case get_allowed_items_call(Host, Nidx, From, Type, Options, Owners) of
-		{result, _} -> {result, [?NS_PUBSUB | [feature(F) || F <- plugin_features(Host, <<"pep">>)]]};
-		_ -> {result, []}
-	    end
-    end,
+    Action =
+	fun(#pubsub_node{id = Nidx, type = Type,
+			 options = Options, owners = O}) ->
+		Owners = node_owners_call(Host, Type, Nidx, O),
+		case get_allowed_items_call(Host, Nidx, From,
+					    Type, Options, Owners) of
+		    {result, _} ->
+			{result,
+			 [?NS_PUBSUB |
+			  [feature(F) || F <- plugin_features(Host, <<"pep">>)]]};
+		    _ ->
+			{result, []}
+		end
+	end,
     case transaction(Host, Node, Action, sync_dirty) of
 	{result, {_, Result}} -> Result;
 	_ -> []
     end.
 
--spec disco_sm_items(Acc :: empty | {result, [xmlel()]}, From :: jid(),
-		     To :: jid(), Node :: mod_pubsub:nodeId(),
-		     Lang :: binary()) -> {result, [xmlel()]}.
-%disco_sm_items(Acc, From, To, Node, Lang)
-%    when is_binary(Node) ->
-%    disco_sm_items(Acc, From, To, iolist_to_binary(Node),
-%                   Lang);
+-spec disco_sm_items({error, error()} | {result, [disco_item()]} | empty,
+		     jid(), jid(), binary(), binary()) ->
+			    {error, error()} | {result, [disco_item()]}.
 disco_sm_items(empty, From, To, Node, Lang) ->
     disco_sm_items({result, []}, From, To, Node, Lang);
 disco_sm_items({result, OtherItems}, From, To, Node, _Lang) ->
@@ -609,48 +624,48 @@ disco_sm_items({result, OtherItems}, From, To, Node, _Lang) ->
 	    disco_items(jid:tolower(jid:remove_resource(To)), Node, From))};
 disco_sm_items(Acc, _From, _To, _Node, _Lang) -> Acc.
 
--spec disco_items(Host :: mod_pubsub:host(), Node :: mod_pubsub:nodeId(),
-		  From :: jid()) -> [xmlel()].
+-spec disco_items(ljid(), binary(), jid()) -> [disco_item()].
 disco_items(Host, <<>>, From) ->
-    Action = fun (#pubsub_node{nodeid = {_, Node},
-			options = Options, type = Type, id = Nidx, owners = O},
-		    Acc) ->
-	    Owners = node_owners_call(Host, Type, Nidx, O),
-	    case get_allowed_items_call(Host, Nidx, From, Type, Options, Owners) of
-		{result, _} ->
-		    [#xmlel{name = <<"item">>,
-			    attrs = [{<<"node">>, (Node)},
-				{<<"jid">>, jid:to_string(Host)}
-				| case get_option(Options, title) of
-				    false -> [];
-				    [Title] -> [{<<"name">>, Title}]
-				end]}
-			| Acc];
-		_ ->
-		    Acc
-	    end
-    end,
+    Action =
+	fun(#pubsub_node{nodeid = {_, Node}, options = Options,
+			 type = Type, id = Nidx, owners = O}, Acc) ->
+		Owners = node_owners_call(Host, Type, Nidx, O),
+		case get_allowed_items_call(Host, Nidx, From,
+					    Type, Options, Owners) of
+		    {result, _} ->
+			[#disco_item{node = Node,
+				     jid = jid:make(Host),
+				     name = case get_option(Options, title) of
+						false -> <<>>;
+						[Title] -> Title
+					    end} | Acc];
+		    _ ->
+			Acc
+		end
+	end,
     NodeBloc = fun() ->
-	    {result,
-		lists:foldl(Action, [], tree_call(Host, get_nodes, [Host]))}
-    end,
+		       {result,
+			lists:foldl(Action, [], tree_call(Host, get_nodes, [Host]))}
+	       end,
     case transaction(Host, NodeBloc, sync_dirty) of
 	{result, Items} -> Items;
 	_ -> []
     end;
 disco_items(Host, Node, From) ->
-    Action = fun (#pubsub_node{id = Nidx, type = Type, options = Options, owners = O}) ->
-	    Owners = node_owners_call(Host, Type, Nidx, O),
-	    case get_allowed_items_call(Host, Nidx, From, Type, Options, Owners) of
-		{result, Items} ->
-		    {result, [#xmlel{name = <<"item">>,
-				attrs = [{<<"jid">>, jid:to_string(Host)},
-				    {<<"name">>, ItemId}]}
-			    || #pubsub_item{itemid = {ItemId, _}} <- Items]};
-		_ ->
-		    {result, []}
-	    end
-    end,
+    Action =
+	fun(#pubsub_node{id = Nidx, type = Type,
+			 options = Options, owners = O}) ->
+		Owners = node_owners_call(Host, Type, Nidx, O),
+		case get_allowed_items_call(Host, Nidx, From,
+					    Type, Options, Owners) of
+		    {result, Items} ->
+			{result, [#disco_item{jid = jid:make(Host),
+					      name = ItemId}
+				  || #pubsub_item{itemid = {ItemId, _}} <- Items]};
+		    _ ->
+			{result, []}
+		end
+	end,
     case transaction(Host, Node, Action, sync_dirty) of
 	{result, {_, Result}} -> Result;
 	_ -> []
@@ -836,9 +851,6 @@ handle_call(stop, _From, State) ->
 %% @private
 handle_cast(_Msg, State) -> {noreply, State}.
 
--spec handle_info(_ :: {route, From::jid(), To::jid(), Packet::xmlel()},
-		  State :: state()) -> {noreply, state()}.
-
 %%--------------------------------------------------------------------
 %% Function: handle_info(Info, State) -> {noreply, State} |
 %%                                       {noreply, State, Timeout} |
@@ -846,9 +858,12 @@ handle_cast(_Msg, State) -> {noreply, State}.
 %% Description: Handling all non call/cast messages
 %%--------------------------------------------------------------------
 %% @private
-handle_info({route, From, To, Packet},
-	    #state{server_host = ServerHost, access = Access, plugins = Plugins} = State) ->
-    case catch do_route(ServerHost, Access, Plugins, To#jid.lserver, From, To, Packet) of
+handle_info({route, From, To, #iq{} = IQ},
+	    State) when To#jid.lresource == <<"">> ->
+    ejabberd_router:process_iq(From, To, IQ),
+    {noreply, State};
+handle_info({route, From, To, Packet}, State) ->
+    case catch do_route(To#jid.lserver, From, To, Packet) of
 	{'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]);
 	_ -> ok
     end,
@@ -903,6 +918,12 @@ terminate(_Reason,
 	?MODULE, remove_user, 50),
     ejabberd_hooks:delete(anonymous_purge_hook, ServerHost,
 	?MODULE, remove_user, 50),
+    gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO),
+    gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS),
+    gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_PUBSUB),
+    gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_PUBSUB_OWNER),
+    gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VCARD),
+    gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_COMMANDS),
     mod_disco:unregister_feature(ServerHost, ?NS_PUBSUB),
     case whereis(gen_mod:get_module_proc(ServerHost, ?LOOPNAME)) of
 	undefined ->
@@ -920,187 +941,163 @@ terminate(_Reason,
 %% @private
 code_change(_OldVsn, State, _Extra) -> {ok, State}.
 
--spec do_route(ServerHost :: binary(), Access :: atom(),
-	       Plugins :: [binary(),...], Host :: mod_pubsub:hostPubsub(),
-	       From :: jid(), To :: jid(), Packet :: xmlel()) -> ok.
-
 %%--------------------------------------------------------------------
 %%% Internal functions
 %%--------------------------------------------------------------------
-do_route(ServerHost, Access, Plugins, Host, From, To, Packet) ->
-    #xmlel{name = Name, attrs = Attrs} = Packet,
-    case To of
-	#jid{luser = <<>>, lresource = <<>>} ->
-	    case Name of
-		<<"iq">> ->
-		    case jlib:iq_query_info(Packet) of
-			#iq{type = get, xmlns = ?NS_DISCO_INFO, sub_el = SubEl, lang = Lang} = IQ ->
-			    #xmlel{attrs = QAttrs} = SubEl,
-			    Node = fxml:get_attr_s(<<"node">>, QAttrs),
-			    Info = ejabberd_hooks:run_fold(disco_info, ServerHost,
-				    [],
-				    [ServerHost, ?MODULE, <<>>, <<>>]),
-			    Res = case iq_disco_info(Host, Node, From, Lang) of
-				{result, IQRes} ->
-				    jlib:iq_to_xml(IQ#iq{type = result,
-					    sub_el =
-					    [#xmlel{name = <<"query">>,
-						    attrs = QAttrs,
-						    children = IQRes ++ Info}]});
-				{error, Error} ->
-				    jlib:make_error_reply(Packet, Error)
-			    end,
-			    ejabberd_router:route(To, From, Res);
-			#iq{type = get, xmlns = ?NS_DISCO_ITEMS, sub_el = SubEl} = IQ ->
-			    #xmlel{attrs = QAttrs} = SubEl,
-			    Node = fxml:get_attr_s(<<"node">>, QAttrs),
-			    Res = case iq_disco_items(Host, Node, From, jlib:rsm_decode(IQ)) of
-				{result, IQRes} ->
-				    jlib:iq_to_xml(IQ#iq{type = result,
-					    sub_el =
-					    [#xmlel{name = <<"query">>,
-						    attrs = QAttrs,
-						    children = IQRes}]})
-				    %{error, Error} ->
-				    %     jlib:make_error_reply(Packet, Error)
-			    end,
-			    ejabberd_router:route(To, From, Res);
-			#iq{type = IQType, xmlns = ?NS_PUBSUB, lang = Lang, sub_el = SubEl} = IQ ->
-			    Res = case iq_pubsub(Host, ServerHost, From, IQType,
-				    SubEl, Lang, Access, Plugins)
-			    of
-				{result, IQRes} ->
-				    jlib:iq_to_xml(IQ#iq{type = result, sub_el = IQRes});
-				{error, Error} ->
-				    jlib:make_error_reply(Packet, Error)
-			    end,
-			    ejabberd_router:route(To, From, Res);
-			#iq{type = IQType, xmlns = ?NS_PUBSUB_OWNER, lang = Lang, sub_el = SubEl} = IQ ->
-			    Res = case iq_pubsub_owner(Host, ServerHost, From,
-				    IQType, SubEl, Lang)
-			    of
-				{result, IQRes} ->
-				    jlib:iq_to_xml(IQ#iq{type = result, sub_el = IQRes});
-				{error, Error} ->
-				    jlib:make_error_reply(Packet, Error)
-			    end,
-			    ejabberd_router:route(To, From, Res);
-			#iq{type = get, xmlns = (?NS_VCARD) = XMLNS, lang = Lang, sub_el = _SubEl} = IQ ->
-			    Res = IQ#iq{type = result,
-				    sub_el =
-				    [#xmlel{name = <<"vCard">>,
-					    attrs = [{<<"xmlns">>, XMLNS}],
-					    children = iq_get_vcard(Lang)}]},
-			    ejabberd_router:route(To, From, jlib:iq_to_xml(Res));
-			#iq{type = set, xmlns = ?NS_COMMANDS} = IQ ->
-			    Res = case iq_command(Host, ServerHost, From, IQ, Access, Plugins) of
-				{error, Error} ->
-				    jlib:make_error_reply(Packet, Error);
-				{result, IQRes} ->
-				    jlib:iq_to_xml(IQ#iq{type = result, sub_el = IQRes})
-			    end,
-			    ejabberd_router:route(To, From, Res);
-			#iq{} ->
-			    Err = jlib:make_error_reply(Packet, ?ERR_FEATURE_NOT_IMPLEMENTED),
-			    ejabberd_router:route(To, From, Err);
-			_ ->
-			    ok
-		    end;
-		<<"message">> ->
-		    case fxml:get_attr_s(<<"type">>, Attrs) of
-			<<"error">> ->
-			    ok;
-			_ ->
-			    case find_authorization_response(Packet) of
-				none ->
-				    ok;
-				invalid ->
-				    Lang = fxml:get_attr_s(<<"xml:lang">>, Attrs),
-				    Txt = <<"Incorrect authorization response">>,
-				    Err = jlib:make_error_reply(
-					    Packet, ?ERRT_BAD_REQUEST(Lang, Txt)),
-				    ejabberd_router:route(To, From, Err);
-				XFields ->
-				    handle_authorization_response(Host, From, To, Packet, XFields)
-			    end
-		    end;
-		_ ->
-		    ok
-	    end;
-	_ ->
-	    case fxml:get_attr_s(<<"type">>, Attrs) of
-		<<"error">> ->
-		    ok;
-		<<"result">> ->
-		    ok;
-		_ ->
-		    Err = jlib:make_error_reply(Packet, ?ERR_ITEM_NOT_FOUND),
-		    ejabberd_router:route(To, From, Err)
-	    end
+-spec process_disco_info(iq()) -> iq().
+process_disco_info(#iq{type = set, lang = Lang} = IQ) ->
+    Txt = <<"Value 'set' of 'type' attribute is not allowed">>,
+    xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang));
+process_disco_info(#iq{from = From, to = To, lang = Lang, type = get,
+		       sub_els = [#disco_info{node = Node}]} = IQ) ->
+    Host = To#jid.lserver,
+    ServerHost = ejabberd_router:host_of_route(Host),
+    Info = ejabberd_hooks:run_fold(disco_info, ServerHost,
+				   [],
+				   [ServerHost, ?MODULE, <<>>, <<>>]),
+    case iq_disco_info(Host, Node, From, Lang) of
+	{result, IQRes} ->
+	    xmpp:make_iq_result(IQ, IQRes#disco_info{node = Node, xdata = Info});
+	{error, Error} ->
+	    xmpp:make_error(IQ, Error)
     end.
 
-command_disco_info(_Host, ?NS_COMMANDS, _From) ->
-    IdentityEl = #xmlel{name = <<"identity">>,
-	    attrs = [{<<"category">>, <<"automation">>},
-		{<<"type">>, <<"command-list">>}]},
-    {result, [IdentityEl]};
-command_disco_info(_Host, ?NS_PUBSUB_GET_PENDING, _From) ->
-    IdentityEl = #xmlel{name = <<"identity">>,
-	    attrs = [{<<"category">>, <<"automation">>},
-		{<<"type">>, <<"command-node">>}]},
-    FeaturesEl = #xmlel{name = <<"feature">>,
-	    attrs = [{<<"var">>, ?NS_COMMANDS}]},
-    {result, [IdentityEl, FeaturesEl]}.
+-spec process_disco_items(iq()) -> iq().
+process_disco_items(#iq{type = set, lang = Lang} = IQ) ->
+    Txt = <<"Value 'set' of 'type' attribute is not allowed">>,
+    xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang));
+process_disco_items(#iq{type = get, from = From, to = To,
+                        sub_els = [#disco_items{node = Node} = SubEl]} = IQ) ->
+    Host = To#jid.lserver,
+    case iq_disco_items(Host, Node, From, SubEl#disco_items.rsm) of
+	{result, IQRes} ->
+	    xmpp:make_iq_result(IQ, IQRes#disco_items{node = Node});
+	{error, Error} ->
+	    xmpp:make_error(IQ, Error)
+    end.
 
+-spec process_pubsub(iq()) -> iq().
+process_pubsub(#iq{to = To} = IQ) ->
+    Host = To#jid.lserver,
+    ServerHost = ejabberd_router:host_of_route(Host),
+    Access = config(ServerHost, access),
+    case iq_pubsub(Host, Access, IQ) of
+	{result, IQRes} ->
+	    xmpp:make_iq_result(IQ, IQRes);
+	{error, Error} ->
+	    xmpp:make_error(IQ, Error)
+    end.
+
+-spec process_pubsub_owner(iq()) -> iq().
+process_pubsub_owner(#iq{to = To} = IQ) ->
+    Host = To#jid.lserver,
+    case iq_pubsub_owner(Host, IQ) of
+	{result, IQRes} ->
+	    xmpp:make_iq_result(IQ, IQRes);
+	{error, Error} ->
+	    xmpp:make_error(IQ, Error)
+    end.
+
+-spec process_vcard(iq()) -> iq().
+process_vcard(#iq{type = get, lang = Lang} = IQ) ->
+    xmpp:make_iq_result(IQ, iq_get_vcard(Lang));
+process_vcard(#iq{type = set, lang = Lang} = IQ) ->
+    Txt = <<"Value 'set' of 'type' attribute is not allowed">>,
+    xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)).
+
+-spec process_commands(iq()) -> iq().
+process_commands(#iq{type = set, to = To, from = From,
+		     sub_els = [#adhoc_command{} = Request]} = IQ) ->
+    Host = To#jid.lserver,
+    ServerHost = ejabberd_router:host_of_route(Host),
+    Plugins = config(ServerHost, plugins),
+    Access = config(ServerHost, access),
+    case adhoc_request(Host, ServerHost, From, Request, Access, Plugins) of
+	{error, Error} ->
+	    xmpp:make_error(IQ, Error);
+	Response ->
+	    xmpp:make_iq_result(
+	      IQ, xmpp_util:make_adhoc_response(Request, Response))
+    end;
+process_commands(#iq{type = get, lang = Lang} = IQ) ->
+    Txt = <<"Value 'get' of 'type' attribute is not allowed">>,
+    xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)).
+
+-spec do_route(binary(), jid(), jid(), stanza()) -> ok.
+do_route(Host, From, To, Packet) ->
+    case To of
+	#jid{luser = <<>>, lresource = <<>>} ->
+	    case Packet of
+		#message{type = T} when T /= error ->
+		    case find_authorization_response(Packet) of
+			undefined ->
+			    ok;
+			XData ->
+			    handle_authorization_response(Host, From, To, Packet, XData)
+		    end;
+		_ ->
+		    Err = xmpp:err_service_unavailable(),
+		    ejabberd_router:route_error(To, From, Packet, Err)
+	    end;
+	_ ->
+	    Err = xmpp:err_item_not_found(),
+	    ejabberd_router:route_error(To, From, Packet, Err)
+    end.
+
+-spec command_disco_info(binary(), binary(), jid()) -> {result, disco_info()}.
+command_disco_info(_Host, ?NS_COMMANDS, _From) ->
+    {result, #disco_info{identities = [#identity{category = <<"automation">>,
+						 type = <<"command-list">>}]}};
+command_disco_info(_Host, ?NS_PUBSUB_GET_PENDING, _From) ->
+    {result, #disco_info{identities = [#identity{category = <<"automation">>,
+						 type = <<"command-node">>}],
+			 features = [?NS_COMMANDS]}}.
+
+-spec node_disco_info(binary(), binary(), jid()) -> {result, disco_info()} |
+						    {error, error()}.
 node_disco_info(Host, Node, From) ->
     node_disco_info(Host, Node, From, true, true).
 
+-spec node_disco_info(binary(), binary(), jid(), boolean(), boolean()) ->
+			     {result, disco_info()} | {error, error()}.
 node_disco_info(Host, Node, _From, _Identity, _Features) ->
-    Action = fun (#pubsub_node{type = Type, options = Options}) ->
-	    NodeType = case get_option(Options, node_type) of
-		collection -> <<"collection">>;
-		_ -> <<"leaf">>
-	    end,
-	    I = #xmlel{name = <<"identity">>,
-			attrs = [{<<"category">>, <<"pubsub">>},
-				 {<<"type">>, NodeType}]},
-	    F = [#xmlel{name = <<"feature">>,
-			attrs = [{<<"var">>, ?NS_PUBSUB}]}
-		    | [#xmlel{name = <<"feature">>,
-			    attrs = [{<<"var">>, feature(F)}]}
-			|| F <- plugin_features(Host, Type)]],
-	    {result, [I | F]}
-    end,
+    Action =
+	fun(#pubsub_node{type = Type, options = Options}) ->
+		NodeType = case get_option(Options, node_type) of
+			       collection -> <<"collection">>;
+			       _ -> <<"leaf">>
+			   end,
+		Is = [#identity{category = <<"pubsub">>, type = NodeType}],
+		Fs = [?NS_PUBSUB | [feature(F) || F <- plugin_features(Host, Type)]],
+		{result, #disco_info{identities = Is, features = Fs}}
+	end,
     case transaction(Host, Node, Action, sync_dirty) of
 	{result, {_, Result}} -> {result, Result};
 	Other -> Other
     end.
 
+-spec iq_disco_info(binary(), binary(), jid(), binary())
+		   -> {result, disco_info()} | {error, error()}.
 iq_disco_info(Host, SNode, From, Lang) ->
     [Node | _] = case SNode of
-	<<>> -> [<<>>];
-	_ -> str:tokens(SNode, <<"!">>)
-    end,
-    %   Node = string_to_node(RealSNode),
+		     <<>> -> [<<>>];
+		     _ -> str:tokens(SNode, <<"!">>)
+		 end,
     case Node of
 	<<>> ->
-	    {result, [#xmlel{name = <<"identity">>,
-			attrs = [{<<"category">>, <<"pubsub">>},
-			    {<<"type">>, <<"service">>},
-			    {<<"name">>, translate:translate(Lang, <<"Publish-Subscribe">>)}]},
-		    #xmlel{name = <<"feature">>,
-			attrs = [{<<"var">>, ?NS_DISCO_INFO}]},
-		    #xmlel{name = <<"feature">>,
-			attrs = [{<<"var">>, ?NS_DISCO_ITEMS}]},
-		    #xmlel{name = <<"feature">>,
-			attrs = [{<<"var">>, ?NS_PUBSUB}]},
-		    #xmlel{name = <<"feature">>,
-			attrs = [{<<"var">>, ?NS_COMMANDS}]},
-		    #xmlel{name = <<"feature">>,
-			attrs = [{<<"var">>, ?NS_VCARD}]}]
-		++ [#xmlel{name = <<"feature">>,
-			attrs = [{<<"var">>, feature(F)}]}
-		    || F <- features(Host, Node)]};
+	    {result,
+	     #disco_info{
+		identities = [#identity{
+				 category = <<"pubsub">>,
+				 type = <<"service">>,
+				 name = translate:translate(
+					  Lang, <<"Publish-Subscribe">>)}],
+		features = [?NS_DISCO_INFO,
+			    ?NS_DISCO_ITEMS,
+			    ?NS_PUBSUB,
+			    ?NS_COMMANDS,
+			    ?NS_VCARD |
+			    [feature(F) || F <- features(Host, Node)]]}};
 	?NS_COMMANDS ->
 	    command_disco_info(Host, Node, From);
 	?NS_PUBSUB_GET_PENDING ->
@@ -1109,34 +1106,34 @@ iq_disco_info(Host, SNode, From, Lang) ->
 	    node_disco_info(Host, Node, From)
     end.
 
--spec iq_disco_items(Host :: mod_pubsub:host(), Node :: <<>> | mod_pubsub:nodeId(),
-		     From :: jid(), Rsm :: none | rsm_in()) -> {result, [xmlel()]}.
+-spec iq_disco_items(host(), binary(), jid(), undefined | rsm_set()) ->
+			    {result, disco_items()} | {error, error()}.
 iq_disco_items(Host, <<>>, From, _RSM) ->
-    {result,
-	lists:map(fun (#pubsub_node{nodeid = {_, SubNode}, options = Options}) ->
-		    Attrs = case get_option(Options, title) of
-			false ->
-			    [{<<"jid">>, Host}
-				| nodeAttr(SubNode)];
-			Title ->
-			    [{<<"jid">>, Host},
-				{<<"name">>, Title}
-				| nodeAttr(SubNode)]
-		    end,
-		    #xmlel{name = <<"item">>, attrs = Attrs}
-	    end,
-	    tree_action(Host, get_subnodes, [Host, <<>>, From]))};
+    Items = 
+	lists:map(
+	  fun(#pubsub_node{nodeid = {_, SubNode}, options = Options}) ->
+		  case get_option(Options, title) of
+		      false ->
+			  #disco_item{jid = jid:make(Host),
+				      node = SubNode};
+		      Title ->
+			  #disco_item{jid = jid:make(Host),
+				      name = Title,
+				      node = SubNode}
+		  end
+	  end, tree_action(Host, get_subnodes, [Host, <<>>, From])),
+    {result, #disco_items{items = Items}};
 iq_disco_items(Host, ?NS_COMMANDS, _From, _RSM) ->
-    {result, [#xmlel{name = <<"item">>,
-		attrs = [{<<"jid">>, Host},
-		    {<<"node">>, ?NS_PUBSUB_GET_PENDING},
-		    {<<"name">>, <<"Get Pending">>}]}]};
+    {result,
+     #disco_items{items = [#disco_item{jid = jid:make(Host),
+				       node = ?NS_PUBSUB_GET_PENDING,
+				       name = <<"Get Pending">>}]}};
 iq_disco_items(_Host, ?NS_PUBSUB_GET_PENDING, _From, _RSM) ->
-    {result, []};
+    {result, #disco_items{}};
 iq_disco_items(Host, Item, From, RSM) ->
     case str:tokens(Item, <<"!">>) of
 	[_Node, _ItemId] ->
-	    {result, []};
+	    {result, #disco_items{}};
 	[Node] ->
 	    Action = fun (#pubsub_node{id = Nidx, type = Type, options = Options, owners = O}) ->
 		    Owners = node_owners_call(Host, Type, Nidx, O),
@@ -1144,28 +1141,28 @@ iq_disco_items(Host, Item, From, RSM) ->
 			    From, Type, Options, Owners, RSM)
 		    of
 			{result, R} -> R;
-			_ -> {[], none}
+			_ -> {[], undefined}
 		    end,
-		    Nodes = lists:map(fun (#pubsub_node{nodeid = {_, SubNode}, options = SubOptions}) ->
-				    Attrs = case get_option(SubOptions, title) of
-					false ->
-					    [{<<"jid">>, Host}
-						| nodeAttr(SubNode)];
-					Title ->
-					    [{<<"jid">>, Host},
-						{<<"name">>, Title}
-						| nodeAttr(SubNode)]
-				    end,
-				    #xmlel{name = <<"item">>, attrs = Attrs}
-			    end,
-			    tree_call(Host, get_subnodes, [Host, Node, From])),
-		    Items = lists:map(fun (#pubsub_item{itemid = {RN, _}}) ->
-				    {result, Name} = node_call(Host, Type, get_item_name, [Host, Node, RN]),
-				    #xmlel{name = <<"item">>,
-					attrs = [{<<"jid">>, Host}, {<<"name">>, Name}]}
-			    end,
-			    NodeItems),
-		    {result, Nodes ++ Items ++ jlib:rsm_encode(RsmOut)}
+		    Nodes = lists:map(
+			      fun(#pubsub_node{nodeid = {_, SubNode}, options = SubOptions}) ->
+				      case get_option(SubOptions, title) of
+					  false ->
+					      #disco_item{jid = jid:make(Host),
+							  node = SubNode};
+					  Title ->
+					      #disco_item{jid = jid:make(Host),
+							  name = Title,
+							  node = SubNode}
+				      end
+			      end, tree_call(Host, get_subnodes, [Host, Node, From])),
+		    Items = lists:map(
+			      fun(#pubsub_item{itemid = {RN, _}}) ->
+				      {result, Name} = node_call(Host, Type, get_item_name, [Host, Node, RN]),
+				      #disco_item{jid = jid:make(Host), name = Name}
+			      end, NodeItems),
+		    {result,
+		     #disco_items{items = Nodes ++ Items,
+				  rsm = RsmOut}}
 	    end,
 	    case transaction(Host, Node, Action, sync_dirty) of
 		{result, {_, Result}} -> {result, Result};
@@ -1173,477 +1170,348 @@ iq_disco_items(Host, Item, From, RSM) ->
 	    end
     end.
 
--spec iq_sm(From :: jid(), To :: jid(), IQ :: iq_request()) -> iq_result() | iq_error().
-iq_sm(From, To, #iq{type = Type, sub_el = SubEl, xmlns = XMLNS, lang = Lang} = IQ) ->
-    ServerHost = To#jid.lserver,
+-spec iq_sm(iq()) -> iq().
+iq_sm(#iq{to = To, sub_els = [SubEl]} = IQ) ->
     LOwner = jid:tolower(jid:remove_resource(To)),
-    Res = case XMLNS of
-	?NS_PUBSUB ->
-	    iq_pubsub(LOwner, ServerHost, From, Type, SubEl, Lang);
-	?NS_PUBSUB_OWNER ->
-	    iq_pubsub_owner(LOwner, ServerHost, From, Type, SubEl, Lang)
-    end,
+    Res = case xmpp:get_ns(SubEl) of
+	      ?NS_PUBSUB ->
+		  iq_pubsub(LOwner, all, IQ);
+	      ?NS_PUBSUB_OWNER ->
+		  iq_pubsub_owner(LOwner, IQ)
+	  end,
     case Res of
-	{result, IQRes} -> IQ#iq{type = result, sub_el = IQRes};
-	{error, Error} -> IQ#iq{type = error, sub_el = [Error, SubEl]}
+	{result, IQRes} ->
+	    xmpp:make_iq_result(IQ, IQRes);
+	{error, Error} ->
+	    xmpp:make_error(IQ, Error)
     end.
 
+-spec iq_get_vcard(binary()) -> vcard_temp().
 iq_get_vcard(Lang) ->
-    [#xmlel{name = <<"FN">>, attrs = [],
-	    children = [{xmlcdata, <<"ejabberd/mod_pubsub">>}]},
-	#xmlel{name = <<"URL">>, attrs = [],
-	    children = [{xmlcdata, ?EJABBERD_URI}]},
-	#xmlel{name = <<"DESC">>, attrs = [],
-	    children = [{xmlcdata,
-		    <<(translate:translate(Lang, <<"ejabberd Publish-Subscribe module">>))/binary,
-			"\nCopyright (c) 2004-2016 ProcessOne">>}]}].
+    Desc = translate:translate(Lang, <<"ejabberd Publish-Subscribe module">>),
+    Copyright = <<"Copyright (c) 2004-2016 ProcessOne">>,
+    #vcard_temp{fn = <<"ejabberd/mod_pubsub">>,
+		url = ?EJABBERD_URI,
+		desc = <>}.
 
--spec iq_pubsub(Host :: mod_pubsub:host(), ServerHost :: binary(), From :: jid(),
-		IQType :: 'get' | 'set', SubEl :: xmlel(), Lang :: binary()) ->
-		       {result, [xmlel()]} | {error, xmlel()}.
-
-iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang) ->
-    iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, all, plugins(Host)).
-
--spec iq_pubsub(Host :: mod_pubsub:host(), ServerHost :: binary(), From :: jid(),
-		IQType :: 'get' | 'set', SubEl :: xmlel(), Lang :: binary(),
-		Access :: atom(), Plugins :: [binary(),...]) ->
-		       {result, [xmlel()]} | {error, xmlel()}.
-
-iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, Access, Plugins) ->
-    #xmlel{children = SubEls} = SubEl,
-    case fxml:remove_cdata(SubEls) of
-	[#xmlel{name = Name, attrs = Attrs, children = Els} | Rest] ->
-	    Node = fxml:get_attr_s(<<"node">>, Attrs),
-	    case {IQType, Name} of
-		{set, <<"create">>} ->
-		    Config = case Rest of
-			[#xmlel{name = <<"configure">>, children = C}] -> C;
-			_ -> []
-		    end,
-		    Type = case fxml:get_attr_s(<<"type">>, Attrs) of
-			<<>> -> hd(Plugins);
-			T -> T
-		    end,
-		    case lists:member(Type, Plugins) of
-			false ->
-			    {error,
-				extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, <<"create-nodes">>)};
-			true ->
-			    create_node(Host, ServerHost, Node, From, Type, Access, Config)
-		    end;
-		{set, <<"publish">>} ->
-		    case fxml:remove_cdata(Els) of
-			[#xmlel{name = <<"item">>, attrs = ItemAttrs,
-					children = Payload}] ->
-			    ItemId = fxml:get_attr_s(<<"id">>, ItemAttrs),
-			    PubOpts = case [C || #xmlel{name = <<"publish-options">>,
-							children = [C]} <- Rest] of
-				[XEl] ->
-				    case jlib:parse_xdata_submit(XEl) of
-				      invalid -> [];
-				      Form -> Form
-				    end;
-				_ -> []
-			    end,
-			    publish_item(Host, ServerHost, Node, From, ItemId, Payload, PubOpts, Access);
-			[] ->
-			    {error,
-				extended_error(?ERR_BAD_REQUEST, <<"item-required">>)};
-			_ ->
-			    {error,
-				extended_error(?ERR_BAD_REQUEST, <<"invalid-payload">>)}
-		    end;
-		{set, <<"retract">>} ->
-		    ForceNotify = case fxml:get_attr_s(<<"notify">>, Attrs) of
-			<<"1">> -> true;
-			<<"true">> -> true;
-			_ -> false
-		    end,
-		    case fxml:remove_cdata(Els) of
-			[#xmlel{name = <<"item">>, attrs = ItemAttrs}] ->
-			    ItemId = fxml:get_attr_s(<<"id">>, ItemAttrs),
-			    delete_item(Host, Node, From, ItemId, ForceNotify);
-			_ ->
-			    {error,
-				extended_error(?ERR_BAD_REQUEST, <<"item-required">>)}
-		    end;
-		{set, <<"subscribe">>} ->
-		    Config = case Rest of
-			[#xmlel{name = <<"options">>, children = C}] -> C;
-			_ -> []
-		    end,
-		    JID = fxml:get_attr_s(<<"jid">>, Attrs),
-		    subscribe_node(Host, Node, From, JID, Config);
-		{set, <<"unsubscribe">>} ->
-		    JID = fxml:get_attr_s(<<"jid">>, Attrs),
-		    SubId = fxml:get_attr_s(<<"subid">>, Attrs),
-		    unsubscribe_node(Host, Node, From, JID, SubId);
-		{get, <<"items">>} ->
-		    MaxItems = fxml:get_attr_s(<<"max_items">>, Attrs),
-		    SubId = fxml:get_attr_s(<<"subid">>, Attrs),
-		    ItemIds = lists:foldl(fun
-				(#xmlel{name = <<"item">>, attrs = ItemAttrs}, Acc) ->
-				    case fxml:get_attr_s(<<"id">>, ItemAttrs) of
-					<<>> -> Acc;
-					ItemId -> [ItemId | Acc]
-				    end;
-				(_, Acc) ->
-				    Acc
-			    end,
-			    [], fxml:remove_cdata(Els)),
-		    get_items(Host, Node, From, SubId, MaxItems, ItemIds, jlib:rsm_decode(SubEl));
-		{get, <<"subscriptions">>} ->
-		    get_subscriptions(Host, Node, From, Plugins);
-		{get, <<"affiliations">>} ->
-		    get_affiliations(Host, Node, From, Plugins);
-		{get, <<"options">>} ->
-		    SubId = fxml:get_attr_s(<<"subid">>, Attrs),
-		    JID = fxml:get_attr_s(<<"jid">>, Attrs),
-		    get_options(Host, Node, JID, SubId, Lang);
-		{set, <<"options">>} ->
-		    SubId = fxml:get_attr_s(<<"subid">>, Attrs),
-		    JID = fxml:get_attr_s(<<"jid">>, Attrs),
-		    set_options(Host, Node, JID, SubId, Els);
+-spec iq_pubsub(binary() | ljid(), atom(), iq()) ->
+		       {result, pubsub()} | {error, error()}.
+iq_pubsub(Host, Access, #iq{from = From, type = IQType, lang = Lang,
+			    sub_els = [SubEl]}) ->
+    case {IQType, SubEl} of
+	{set, #pubsub{create = Node, configure = {_, XData},
+		      _ = undefined}} when is_binary(Node) ->
+	    ServerHost = serverhost(Host),
+	    Plugins = config(ServerHost, plugins),
+	    Config = get_xdata_fields(XData),
+	    Type = hd(Plugins),
+	    create_node(Host, ServerHost, Node, From, Type, Access, Config);
+	{set, #pubsub{publish = #ps_publish{node = Node, items = Items},
+		      publish_options = XData, _ = undefined}} ->
+	    ServerHost = serverhost(Host),
+	    case Items of
+		[#ps_item{id = ItemId, xml_els = Payload}] ->
+		    PubOpts = get_xdata_fields(XData),
+		    publish_item(Host, ServerHost, Node, From, ItemId,
+				 Payload, PubOpts, Access);
+		[] ->
+		    {error, extended_error(xmpp:err_bad_request(), err_item_required())};
 		_ ->
-		    {error, ?ERR_FEATURE_NOT_IMPLEMENTED}
+		    {error, extended_error(xmpp:err_bad_request(), err_invalid_payload())}
 	    end;
-	Other ->
-	    ?INFO_MSG("Too many actions: ~p", [Other]),
-	    {error, ?ERR_BAD_REQUEST}
-    end.
-
-
--spec iq_pubsub_owner(Host :: mod_pubsub:host(), ServerHost :: binary(), From :: jid(),
-		      IQType :: 'get' | 'set', SubEl :: xmlel(), Lang :: binary()) ->
-			     {result, [xmlel()]} | {error, xmlel()}.
-
-iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) ->
-    #xmlel{children = SubEls} = SubEl,
-    Action = fxml:remove_cdata(SubEls),
-    case Action of
-	[#xmlel{name = Name, attrs = Attrs, children = Els}] ->
-	    Node = fxml:get_attr_s(<<"node">>, Attrs),
-	    case {IQType, Name} of
-		{get, <<"configure">>} ->
-		    get_configure(Host, ServerHost, Node, From, Lang);
-		{set, <<"configure">>} ->
-		    set_configure(Host, Node, From, Els, Lang);
-		{get, <<"default">>} ->
-		    get_default(Host, Node, From, Lang);
-		{set, <<"delete">>} ->
-		    delete_node(Host, Node, From);
-		{set, <<"purge">>} ->
-		    purge_node(Host, Node, From);
-		{get, <<"subscriptions">>} ->
-		    get_subscriptions(Host, Node, From);
-		{set, <<"subscriptions">>} ->
-		    set_subscriptions(Host, Node, From, fxml:remove_cdata(Els));
-		{get, <<"affiliations">>} ->
-		    get_affiliations(Host, Node, From);
-		{set, <<"affiliations">>} ->
-		    set_affiliations(Host, Node, From, fxml:remove_cdata(Els));
+	{set, #pubsub{retract = #ps_retract{node = Node, notify = Notify, items = Items},
+		      _ = undefined}} ->
+	    case Items of
+		[#ps_item{id = ItemId}] ->
+		    delete_item(Host, Node, From, ItemId, Notify);
+		[] ->
+		    {error, extended_error(xmpp:err_bad_request(), err_item_required())};
 		_ ->
-		    {error, ?ERR_FEATURE_NOT_IMPLEMENTED}
+		    {error, extended_error(xmpp:err_bad_request(), err_invalid_payload())}
 	    end;
+	{set, #pubsub{subscribe = #ps_subscribe{node = Node, jid = JID},
+		      options = Options, _ = undefined}} ->
+	    Config = case Options of
+			 #ps_options{xdata = XData} -> get_xdata_fields(XData);
+			 _ -> []
+		     end,
+	    subscribe_node(Host, Node, From, JID, Config);
+	{set, #pubsub{unsubscribe = #ps_unsubscribe{node = Node, jid = JID, subid = SubId},
+		      _ = undefined}} ->
+	    unsubscribe_node(Host, Node, From, JID, SubId);
+	{get, #pubsub{items = #ps_items{node = Node,
+					max_items = MaxItems,
+					subid = SubId,
+					items = Items},
+		      rsm = RSM, _ = undefined}} ->
+	    ItemIds = [ItemId || #ps_item{id = ItemId} <- Items, ItemId /= <<>>],
+	    get_items(Host, Node, From, SubId, MaxItems, ItemIds, RSM);
+	{get, #pubsub{subscriptions = {Node, _}, _ = undefined}} ->
+	    Plugins = config(serverhost(Host), plugins),
+	    get_subscriptions(Host, Node, From, Plugins);
+	{get, #pubsub{affiliations = {Node, _}, _ = undefined}} ->
+	    Plugins = config(serverhost(Host), plugins),
+	    get_affiliations(Host, Node, From, Plugins);
+	{get, #pubsub{options = #ps_options{node = Node, subid = SubId, jid = JID},
+		      _ = undefined}} ->
+	    get_options(Host, Node, JID, SubId, Lang);
+	{set, #pubsub{options = #ps_options{node = Node, subid = SubId,
+					    jid = JID, xdata = XData},
+		      _ = undefined}} ->
+	    set_options(Host, Node, JID, SubId, get_xdata_fields(XData));
 	_ ->
-	    ?INFO_MSG("Too many actions: ~p", [Action]),
-	    {error, ?ERR_BAD_REQUEST}
+	    {error, xmpp:err_feature_not_implemented()}
     end.
 
-iq_command(Host, ServerHost, From, IQ, Access, Plugins) ->
-    case adhoc:parse_request(IQ) of
-	Req when is_record(Req, adhoc_request) ->
-	    case adhoc_request(Host, ServerHost, From, Req, Access, Plugins) of
-		Resp when is_record(Resp, adhoc_response) ->
-		    {result, [adhoc:produce_response(Req, Resp)]};
-		Error ->
-		    Error
+-spec iq_pubsub_owner(binary() | ljid(), iq()) -> {result, pubsub()} | {error, error()}.
+iq_pubsub_owner(Host, #iq{type = IQType, from = From,
+			  lang = Lang, sub_els = [SubEl]}) ->
+    case {IQType, SubEl} of
+	{get, #pubsub_owner{configure = {Node, undefined}, _ = undefined}} ->
+	    ServerHost = serverhost(Host),
+	    get_configure(Host, ServerHost, Node, From, Lang);
+	{set, #pubsub_owner{configure = {Node, XData}, _ = undefined}} ->
+	    case XData of
+		undefined ->
+		    {error, xmpp:err_bad_request(<<"No data form found">>, Lang)};
+		#xdata{type = cancel} ->
+		    {result, #pubsub{}};
+		#xdata{type = submit} ->
+		    Config = get_xdata_fields(XData),
+		    set_configure(Host, Node, From, Config, Lang);
+		#xdata{} ->
+		    {error, xmpp:err_bad_request(<<"Incorrect data form">>, Lang)}
 	    end;
-	Err -> Err
+	{get, #pubsub_owner{default = {Node, undefined}, _ = undefined}} ->
+	    get_default(Host, Node, From, Lang);
+	{set, #pubsub_owner{delete = {Node, _}, _ = undefined}} ->
+	    delete_node(Host, Node, From);
+	{set, #pubsub_owner{purge = Node, _ = undefined}} when Node /= undefined ->
+	    purge_node(Host, Node, From);
+	{get, #pubsub_owner{subscriptions = {Node, []}, _ = undefined}} ->
+	    get_subscriptions(Host, Node, From);
+	{set, #pubsub_owner{subscriptions = {Node, Subs}, _ = undefined}} ->
+	    set_subscriptions(Host, Node, From, Subs);
+	{get, #pubsub_owner{affiliations = {Node, []}, _ = undefined}} ->
+	    get_affiliations(Host, Node, From);
+	{set, #pubsub_owner{affiliations = {Node, Affs}, _ = undefined}} ->
+	    set_affiliations(Host, Node, From, Affs);
+	{_, #pubsub_owner{}} ->
+	    {error, xmpp:err_bad_request()};
+	_ ->
+	    {error, xmpp:err_feature_not_implemented()}
     end.
 
-%% @doc 

Processes an Ad Hoc Command.

+-spec adhoc_request(binary(), binary(), jid(), adhoc_command(), + atom(), [binary()]) -> adhoc_command() | {error, error()}. adhoc_request(Host, _ServerHost, Owner, - #adhoc_request{node = ?NS_PUBSUB_GET_PENDING, - lang = Lang, action = <<"execute">>, - xdata = false}, - _Access, Plugins) -> + #adhoc_command{node = ?NS_PUBSUB_GET_PENDING, lang = Lang, + action = execute, xdata = undefined}, + _Access, Plugins) -> send_pending_node_form(Host, Owner, Lang, Plugins); adhoc_request(Host, _ServerHost, Owner, - #adhoc_request{node = ?NS_PUBSUB_GET_PENDING, - action = <<"execute">>, xdata = XData, lang = Lang}, - _Access, _Plugins) -> - ParseOptions = case XData of - #xmlel{name = <<"x">>} = XEl -> - case jlib:parse_xdata_submit(XEl) of - invalid -> - Txt = <<"Incorrect data form">>, - {error, ?ERRT_BAD_REQUEST(Lang, Txt)}; - XData2 -> - case set_xoption(Host, XData2, []) of - NewOpts when is_list(NewOpts) -> {result, NewOpts}; - Err -> Err - end - end; - _ -> - Txt = <<"No data form found">>, - {error, ?ERRT_BAD_REQUEST(Lang, Txt)} - end, - case ParseOptions of - {result, XForm} -> + #adhoc_command{node = ?NS_PUBSUB_GET_PENDING, lang = Lang, + action = execute, xdata = #xdata{} = XData}, + _Access, _Plugins) -> + Config = get_xdata_fields(XData), + case set_xoption(Host, Config, []) of + XForm when is_list(XForm) -> case lists:keysearch(node, 1, XForm) of - {value, {_, Node}} -> send_pending_auth_events(Host, Node, Owner); - false -> {error, extended_error(?ERR_BAD_REQUEST, <<"bad-payload">>)} + {value, {_, Node}} -> + send_pending_auth_events(Host, Node, Owner, Lang); + false -> + {error, extended_error(xmpp:err_bad_request(), err_invalid_payload())} end; - Error -> Error + Err -> + Err end; adhoc_request(_Host, _ServerHost, _Owner, - #adhoc_request{action = <<"cancel">>}, _Access, - _Plugins) -> - #adhoc_response{status = canceled}; -adhoc_request(Host, ServerHost, Owner, - #adhoc_request{action = <<>>} = R, Access, Plugins) -> - adhoc_request(Host, ServerHost, Owner, - R#adhoc_request{action = <<"execute">>}, Access, - Plugins); + #adhoc_command{action = cancel}, _Access, _Plugins) -> + #adhoc_command{status = canceled}; adhoc_request(_Host, _ServerHost, _Owner, Other, _Access, _Plugins) -> ?DEBUG("Couldn't process ad hoc command:~n~p", [Other]), - {error, ?ERR_ITEM_NOT_FOUND}. + {error, xmpp:err_item_not_found()}. -%% @doc

Sends the process pending subscriptions XForm for Host to Owner.

+-spec send_pending_node_form(binary(), jid(), binary(), + [binary()]) -> adhoc_command() | {error, error()}. send_pending_node_form(Host, Owner, _Lang, Plugins) -> Filter = fun (Type) -> lists:member(<<"get-pending">>, plugin_features(Host, Type)) end, case lists:filter(Filter, Plugins) of [] -> - Err = extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, - unsupported, <<"get-pending">>), + Err = extended_error(xmpp:err_feature_not_implemented(), + err_unsupported('get-pending')), {error, Err}; Ps -> - XOpts = [#xmlel{name = <<"option">>, attrs = [], - children = [#xmlel{name = <<"value">>, - attrs = [], - children = [{xmlcdata, Node}]}]} - || Node <- get_pending_nodes(Host, Owner, Ps)], - XForm = #xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_XDATA}, - {<<"type">>, <<"form">>}], - children = [#xmlel{name = <<"field">>, - attrs = [{<<"type">>, <<"list-single">>}, - {<<"var">>, <<"pubsub#node">>}], - children = lists:usort(XOpts)}]}, - #adhoc_response{status = executing, - defaultaction = <<"execute">>, elements = [XForm]} + case get_pending_nodes(Host, Owner, Ps) of + {ok, Nodes} -> + XOpts = [#xdata_option{value = Node} || Node <- Nodes], + XForm = #xdata{type = form, + fields = [#xdata_field{ + type = 'list-single', + var = <<"pubsub#node">>, + options = lists:usort(XOpts)}]}, + #adhoc_command{status = executing, action = execute, + xdata = XForm}; + Err -> + Err + end end. +-spec get_pending_nodes(binary(), jid(), [binary()]) -> {ok, [binary()]} | + {error, error()}. get_pending_nodes(Host, Owner, Plugins) -> Tr = fun (Type) -> case node_call(Host, Type, get_pending_nodes, [Host, Owner]) of {result, Nodes} -> Nodes; _ -> [] end - end, + end, Action = fun() -> {result, lists:flatmap(Tr, Plugins)} end, case transaction(Host, Action, sync_dirty) of - {result, Res} -> Res; + {result, Res} -> {ok, Res}; Err -> Err end. %% @doc

Send a subscription approval form to Owner for all pending %% subscriptions on Host and Node.

-send_pending_auth_events(Host, Node, Owner) -> +-spec send_pending_auth_events(binary(), binary(), jid(), + binary()) -> adhoc_command() | {error, error()}. +send_pending_auth_events(Host, Node, Owner, Lang) -> ?DEBUG("Sending pending auth events for ~s on ~s:~s", - [jid:to_string(Owner), Host, Node]), - Action = fun (#pubsub_node{id = Nidx, type = Type}) -> - case lists:member(<<"get-pending">>, plugin_features(Host, Type)) of - true -> - case node_call(Host, Type, get_affiliation, [Nidx, Owner]) of - {result, owner} -> node_call(Host, Type, get_node_subscriptions, [Nidx]); - _ -> {error, ?ERRT_FORBIDDEN(?MYLANG, <<"You're not an owner">>)} - end; - false -> - {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, - unsupported, <<"get-pending">>)} - end - end, + [jid:to_string(Owner), Host, Node]), + Action = + fun(#pubsub_node{id = Nidx, type = Type}) -> + case lists:member(<<"get-pending">>, plugin_features(Host, Type)) of + true -> + case node_call(Host, Type, get_affiliation, [Nidx, Owner]) of + {result, owner} -> + node_call(Host, Type, get_node_subscriptions, [Nidx]); + _ -> + {error, xmpp:err_forbidden( + <<"Owner privileges required">>, Lang)} + end; + false -> + {error, extended_error(xmpp:err_feature_not_implemented(), + err_unsupported('get-pending'))} + end + end, case transaction(Host, Node, Action, sync_dirty) of {result, {N, Subs}} -> - lists:foreach(fun - ({J, pending, _SubId}) -> send_authorization_request(N, jid:make(J)); - ({J, pending}) -> send_authorization_request(N, jid:make(J)); - (_) -> ok - end, - Subs), - #adhoc_response{}; + lists:foreach( + fun({J, pending, _SubId}) -> send_authorization_request(N, jid:make(J)); + ({J, pending}) -> send_authorization_request(N, jid:make(J)); + (_) -> ok + end, Subs), + #adhoc_command{}; Err -> Err end. %%% authorization handling - -send_authorization_request(#pubsub_node{nodeid = {Host, Node}, type = Type, id = Nidx, owners = O}, - Subscriber) -> +-spec send_authorization_request(#pubsub_node{}, jid()) -> ok. +send_authorization_request(#pubsub_node{nodeid = {Host, Node}, + type = Type, id = Nidx, owners = O}, + Subscriber) -> + %% TODO: pass lang to this function Lang = <<"en">>, - Stanza = #xmlel{name = <<"message">>, attrs = [], - children = - [#xmlel{name = <<"x">>, - attrs = - [{<<"xmlns">>, ?NS_XDATA}, - {<<"type">>, <<"form">>}], - children = - [#xmlel{name = <<"title">>, attrs = [], - children = - [{xmlcdata, - translate:translate(Lang, <<"PubSub subscriber request">>)}]}, - #xmlel{name = <<"instructions">>, - attrs = [], - children = - [{xmlcdata, - translate:translate(Lang, - <<"Choose whether to approve this entity's " - "subscription.">>)}]}, - #xmlel{name = <<"field">>, - attrs = - [{<<"var">>, <<"FORM_TYPE">>}, - {<<"type">>, <<"hidden">>}], - children = - [#xmlel{name = <<"value">>, - attrs = [], - children = - [{xmlcdata, ?NS_PUBSUB_SUB_AUTH}]}]}, - #xmlel{name = <<"field">>, - attrs = - [{<<"var">>, <<"pubsub#node">>}, - {<<"type">>, - <<"text-single">>}, - {<<"label">>, translate:translate(Lang, <<"Node ID">>)}], - children = - [#xmlel{name = <<"value">>, - attrs = [], - children = - [{xmlcdata, Node}]}]}, - #xmlel{name = <<"field">>, - attrs = - [{<<"var">>, - <<"pubsub#subscriber_jid">>}, - {<<"type">>, <<"jid-single">>}, - {<<"label">>, - translate:translate(Lang, <<"Subscriber Address">>)}], - children = - [#xmlel{name = <<"value">>, - attrs = [], - children = - [{xmlcdata, jid:to_string(Subscriber)}]}]}, - #xmlel{name = <<"field">>, - attrs = - [{<<"var">>, - <<"pubsub#allow">>}, - {<<"type">>, <<"boolean">>}, - {<<"label">>, - translate:translate(Lang, - <<"Allow this Jabber ID to subscribe to " - "this pubsub node?">>)}], - children = - [#xmlel{name = <<"value">>, - attrs = [], - children = - [{xmlcdata, <<"false">>}]}]}]}]}, - lists:foreach(fun (Owner) -> - ejabberd_router:route(service_jid(Host), jid:make(Owner), Stanza) - end, - node_owners_action(Host, Type, Nidx, O)). + Fs = [#xdata_field{var = <<"FORM_TYPE">>, + type = hidden, + values = [?NS_PUBSUB_SUB_AUTH]}, + #xdata_field{var = <<"pubsub#node">>, + type = 'text-single', + label = translate:translate(Lang, <<"Node ID">>), + values = [Node]}, + #xdata_field{var = <<"pubsub#subscriber_jid">>, + type = 'jid-single', + label = translate:translate(Lang, <<"Subscriber Address">>), + values = [jid:to_string(Subscriber)]}, + #xdata_field{var = <<"pubsub#allow">>, + type = boolean, + label = translate:translate( + Lang, + <<"Allow this Jabber ID to subscribe to " + "this pubsub node?">>), + values = [<<"false">>]}], + X = #xdata{type = form, + title = translate:translate( + Lang, <<"PubSub subscriber request">>), + instructions = [translate:translate( + Lang, + <<"Choose whether to approve this entity's " + "subscription.">>)], + fields = Fs}, + Stanza = #message{sub_els = [X]}, + lists:foreach( + fun (Owner) -> + ejabberd_router:route(service_jid(Host), jid:make(Owner), Stanza) + end, node_owners_action(Host, Type, Nidx, O)). +-spec find_authorization_response(message()) -> undefined | xdata(). find_authorization_response(Packet) -> - #xmlel{children = Els} = Packet, - XData1 = lists:map(fun - (#xmlel{name = <<"x">>, attrs = XAttrs} = XEl) -> - case fxml:get_attr_s(<<"xmlns">>, XAttrs) of - ?NS_XDATA -> - case fxml:get_attr_s(<<"type">>, XAttrs) of - <<"cancel">> -> none; - _ -> jlib:parse_xdata_submit(XEl) - end; - _ -> - none - end; - (_) -> - none - end, - fxml:remove_cdata(Els)), - XData = lists:filter(fun (E) -> E /= none end, XData1), - case XData of - [invalid] -> - invalid; - [] -> - none; - [XFields] when is_list(XFields) -> - ?DEBUG("XFields: ~p", [XFields]), - case lists:keysearch(<<"FORM_TYPE">>, 1, XFields) of - {value, {_, [?NS_PUBSUB_SUB_AUTH]}} -> XFields; - _ -> invalid - end + case xmpp:get_subtag(Packet, #xdata{}) of + #xdata{type = submit} = X -> + case xmpp_util:get_xdata_values(<<"FORM_TYPE">>, X) of + [?NS_PUBSUB_SUB_AUTH] -> X; + _ -> undefined + end; + _ -> + undefined end. %% @doc Send a message to JID with the supplied Subscription +-spec send_authorization_approval(binary(), jid(), binary(), subscribed | none) -> ok. send_authorization_approval(Host, JID, SNode, Subscription) -> - SubAttrs = case Subscription of - %{S, SID} -> - % [{<<"subscription">>, subscription_to_string(S)}, - % {<<"subid">>, SID}]; - S -> - [{<<"subscription">>, subscription_to_string(S)}] - end, - Stanza = event_stanza(<<"subscription">>, - [{<<"jid">>, jid:to_string(JID)} - | nodeAttr(SNode)] - ++ SubAttrs), + Event = #ps_event{subscription = + #ps_subscription{jid = JID, + node = SNode, + type = Subscription}}, + Stanza = #message{sub_els = [Event]}, ejabberd_router:route(service_jid(Host), JID, Stanza). -handle_authorization_response(Host, From, To, Packet, XFields) -> - Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), - case {lists:keysearch(<<"pubsub#node">>, 1, XFields), - lists:keysearch(<<"pubsub#subscriber_jid">>, 1, XFields), - lists:keysearch(<<"pubsub#allow">>, 1, XFields)} - of - {{value, {_, [Node]}}, - {value, {_, [SSubscriber]}}, - {value, {_, [SAllow]}}} -> +-spec handle_authorization_response(binary(), jid(), jid(), message(), xdata()) -> ok. +handle_authorization_response(Host, From, To, Packet, X) -> + Lang = xmpp:get_lang(Packet), + case {xmpp_util:get_xdata_values(<<"pubsub#node">>, X), + xmpp_util:get_xdata_values(<<"pubsub#subscriber_jid">>, X), + xmpp_util:get_xdata_values(<<"pubsub#allow">>, X)} of + {[Node], [SSubscriber], [SAllow]} -> FromLJID = jid:tolower(jid:remove_resource(From)), Subscriber = jid:from_string(SSubscriber), Allow = case SAllow of - <<"1">> -> true; - <<"true">> -> true; - _ -> false - end, - Action = fun (#pubsub_node{type = Type, id = Nidx, owners = O}) -> - Owners = node_owners_call(Host, Type, Nidx, O), - case lists:member(FromLJID, Owners) of - true -> - {result, Subs} = node_call(Host, Type, get_subscriptions, [Nidx, Subscriber]), - update_auth(Host, Node, Type, Nidx, Subscriber, Allow, Subs); - false -> - {error, ?ERRT_FORBIDDEN(Lang, <<"You're not an owner">>)} - end - end, + <<"1">> -> true; + <<"true">> -> true; + _ -> false + end, + Action = + fun(#pubsub_node{type = Type, id = Nidx, owners = O}) -> + Owners = node_owners_call(Host, Type, Nidx, O), + case lists:member(FromLJID, Owners) of + true -> + {result, Subs} = node_call(Host, Type, get_subscriptions, [Nidx, Subscriber]), + update_auth(Host, Node, Type, Nidx, Subscriber, Allow, Subs); + false -> + {error, xmpp:err_forbidden(<<"Owner privileges required">>, Lang)} + end + end, case transaction(Host, Node, Action, sync_dirty) of {error, Error} -> - Err = jlib:make_error_reply(Packet, Error), - ejabberd_router:route(To, From, Err); + ejabberd_router:route_error(To, From, Packet, Error); {result, {_, _NewSubscription}} -> %% XXX: notify about subscription state change, section 12.11 ok; _ -> - Err = jlib:make_error_reply(Packet, ?ERR_INTERNAL_SERVER_ERROR), - ejabberd_router:route(To, From, Err) + Err = xmpp:err_internal_server_error(), + ejabberd_router:route_error(To, From, Packet, Err) end; _ -> - Txt = <<"Incorrect data form">>, - Err = jlib:make_error_reply(Packet, ?ERRT_NOT_ACCEPTABLE(Lang, Txt)), - ejabberd_router:route(To, From, Err) + Err = xmpp:err_not_acceptable(<<"Incorrect data form">>, Lang), + ejabberd_router:route_error(To, From, Packet, Err) end. +-spec update_auth(binary(), binary(), _, _, jid() | error, boolean(), _) -> + {result, ok} | {error, error()}. update_auth(Host, Node, Type, Nidx, Subscriber, Allow, Subs) -> Sub= lists:filter(fun ({pending, _}) -> true; @@ -1661,67 +1529,47 @@ update_auth(Host, Node, Type, Nidx, Subscriber, Allow, Subs) -> {result, ok}; _ -> Txt = <<"No pending subscriptions found">>, - {error, ?ERRT_UNEXPECTED_REQUEST(?MYLANG, Txt)} + {error, xmpp:err_unexpected_request(Txt, ?MYLANG)} end. -define(XFIELD(Type, Label, Var, Val), - #xmlel{name = <<"field">>, - attrs = [{<<"type">>, Type}, - {<<"label">>, translate:translate(Lang, Label)}, - {<<"var">>, Var}], - children = [#xmlel{name = <<"value">>, attrs = [], - children = [{xmlcdata, Val}]}]}). + #xdata_field{type = Type, + label = translate:translate(Lang, Label), + var = Var, + values = [Val]}). -define(BOOLXFIELD(Label, Var, Val), - ?XFIELD(<<"boolean">>, Label, Var, - case Val of - true -> <<"1">>; - _ -> <<"0">> - end)). + ?XFIELD(boolean, Label, Var, + case Val of + true -> <<"1">>; + _ -> <<"0">> + end)). -define(STRINGXFIELD(Label, Var, Val), - ?XFIELD(<<"text-single">>, Label, Var, Val)). + ?XFIELD('text-single', Label, Var, Val)). -define(STRINGMXFIELD(Label, Var, Vals), - #xmlel{name = <<"field">>, - attrs = [{<<"type">>, <<"text-multi">>}, - {<<"label">>, translate:translate(Lang, Label)}, - {<<"var">>, Var}], - children = [#xmlel{name = <<"value">>, attrs = [], - children = [{xmlcdata, V}]} - || V <- Vals]}). + #xdata_field{type = 'text-multi', + label = translate:translate(Lang, Label), + var = Var, + values = Vals}). -define(XFIELDOPT(Type, Label, Var, Val, Opts), - #xmlel{name = <<"field">>, - attrs = [{<<"type">>, Type}, - {<<"label">>, translate:translate(Lang, Label)}, - {<<"var">>, Var}], - children = [#xmlel{name = <<"option">>, attrs = [], - children = [#xmlel{name = <<"value">>, - attrs = [], - children = [{xmlcdata, Opt}]}]} - || Opt <- Opts] - ++ - [#xmlel{name = <<"value">>, attrs = [], - children = [{xmlcdata, Val}]}]}). + #xdata_field{type = Type, + label = translate:translate(Lang, Label), + var = Var, + options = [#xdata_option{value = Opt} || Opt <- Opts], + values = [Val]}). -define(LISTXFIELD(Label, Var, Val, Opts), - ?XFIELDOPT(<<"list-single">>, Label, Var, Val, Opts)). + ?XFIELDOPT('list-single', Label, Var, Val, Opts)). -define(LISTMXFIELD(Label, Var, Vals, Opts), - #xmlel{name = <<"field">>, - attrs = [{<<"type">>, <<"list-multi">>}, - {<<"label">>, translate:translate(Lang, Label)}, - {<<"var">>, Var}], - children = [#xmlel{name = <<"option">>, attrs = [], - children = [#xmlel{name = <<"value">>, - attrs = [], - children = [{xmlcdata, Opt}]}]} - || Opt <- Opts] - ++ - [#xmlel{name = <<"value">>, attrs = [], - children = [{xmlcdata, Val}]} - || Val <- Vals]}). + #xdata_field{type = 'list-multi', + label = translate:translate(Lang, Label), + var = Var, + options = [#xdata_option{value = Opt} || Opt <- Opts], + values = Vals}). %% @doc

Create new pubsub nodes

%%

In addition to method-specific error conditions, there are several general reasons why the node creation request might fail:

@@ -1740,97 +1588,69 @@ update_auth(Host, Node, Type, Nidx, Subscriber, Allow, Subs) -> %%
  • nodetree create_node checks if nodeid already exists
  • %%
  • node plugin create_node just sets default affiliation/subscription
  • %% --spec create_node(Host :: mod_pubsub:host(), ServerHost :: binary(), - Node :: <<>> | mod_pubsub:nodeId(), Owner :: jid(), - Type :: binary()) -> {result, [xmlel(),...]} | {error, xmlel()}. +-spec create_node(host(), binary(), binary(), jid(), + binary()) -> {result, pubsub()} | {error, error()}. create_node(Host, ServerHost, Node, Owner, Type) -> create_node(Host, ServerHost, Node, Owner, Type, all, []). --spec create_node(Host :: mod_pubsub:host(), ServerHost :: binary(), - Node :: <<>> | mod_pubsub:nodeId(), Owner :: jid(), - Type :: binary(), Access :: atom(), Configuration :: [xmlel()]) -> - {result, [xmlel(),...]} | {error, xmlel()}. - +-spec create_node(host(), binary(), binary(), jid(), binary(), + atom(), [{binary(), [binary()]}]) -> {result, pubsub()} | {error, error()}. create_node(Host, ServerHost, <<>>, Owner, Type, Access, Configuration) -> case lists:member(<<"instant-nodes">>, plugin_features(Host, Type)) of true -> Node = randoms:get_string(), case create_node(Host, ServerHost, Node, Owner, Type, Access, Configuration) of {result, _} -> - {result, [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB}], - children = [#xmlel{name = <<"create">>, - attrs = nodeAttr(Node)}]}]}; + {result, #pubsub{create = Node}}; Error -> Error end; false -> - {error, extended_error(?ERR_NOT_ACCEPTABLE, <<"nodeid-required">>)} + {error, extended_error(xmpp:err_not_acceptable(), err_nodeid_required())} end; create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> Type = select_type(ServerHost, Host, Node, GivenType), - ParseOptions = case fxml:remove_cdata(Configuration) of - [] -> - {result, node_options(Host, Type)}; - [#xmlel{name = <<"x">>} = XEl] -> - case jlib:parse_xdata_submit(XEl) of - invalid -> - Txt = <<"Incorrect data form">>, - {error, ?ERRT_BAD_REQUEST(?MYLANG, Txt)}; - XData -> - case set_xoption(Host, XData, node_options(Host, Type)) of - NewOpts when is_list(NewOpts) -> {result, NewOpts}; - Err -> Err - end - end; - _ -> - ?INFO_MSG("Node ~p; bad configuration: ~p", [Node, Configuration]), - Txt = <<"No data form found">>, - {error, ?ERRT_BAD_REQUEST(?MYLANG, Txt)} - end, - case ParseOptions of - {result, NodeOptions} -> - CreateNode = fun () -> - Parent = case node_call(Host, Type, node_to_path, [Node]) of - {result, [Node]} -> - <<>>; - {result, Path} -> - element(2, node_call(Host, Type, path_to_node, [lists:sublist(Path, length(Path)-1)])) - end, - Parents = case Parent of - <<>> -> []; - _ -> [Parent] - end, - case node_call(Host, Type, create_node_permission, - [Host, ServerHost, Node, Parent, Owner, Access]) - of - {result, true} -> - case tree_call(Host, create_node, - [Host, Node, Type, Owner, NodeOptions, Parents]) - of - {ok, Nidx} -> - SubsByDepth = get_node_subs_by_depth(Host, Node, Owner), - case node_call(Host, Type, create_node, [Nidx, Owner]) of - {result, Result} -> {result, {Nidx, SubsByDepth, Result}}; - Error -> Error - end; - {error, {virtual, Nidx}} -> - case node_call(Host, Type, create_node, [Nidx, Owner]) of - {result, Result} -> {result, {Nidx, [], Result}}; - Error -> Error - end; - Error -> - Error - end; - _ -> - Txt1 = <<"You're not allowed to create nodes">>, - {error, ?ERRT_FORBIDDEN(?MYLANG, Txt1)} - end - end, - Reply = [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB}], - children = [#xmlel{name = <<"create">>, - attrs = nodeAttr(Node)}]}], + case set_xoption(Host, Configuration, node_options(Host, Type)) of + NodeOptions when is_list(NodeOptions) -> + CreateNode = + fun() -> + Parent = case node_call(Host, Type, node_to_path, [Node]) of + {result, [Node]} -> + <<>>; + {result, Path} -> + element(2, node_call(Host, Type, path_to_node, + [lists:sublist(Path, length(Path)-1)])) + end, + Parents = case Parent of + <<>> -> []; + _ -> [Parent] + end, + case node_call(Host, Type, create_node_permission, + [Host, ServerHost, Node, Parent, Owner, Access]) of + {result, true} -> + case tree_call(Host, create_node, + [Host, Node, Type, Owner, NodeOptions, Parents]) + of + {ok, Nidx} -> + SubsByDepth = get_node_subs_by_depth(Host, Node, Owner), + case node_call(Host, Type, create_node, [Nidx, Owner]) of + {result, Result} -> {result, {Nidx, SubsByDepth, Result}}; + Error -> Error + end; + {error, {virtual, Nidx}} -> + case node_call(Host, Type, create_node, [Nidx, Owner]) of + {result, Result} -> {result, {Nidx, [], Result}}; + Error -> Error + end; + Error -> + Error + end; + _ -> + Txt = <<"You're not allowed to create nodes">>, + {error, xmpp:err_forbidden(Txt, ?MYLANG)} + end + end, + Reply = #pubsub{create = Node}, case transaction(Host, CreateNode, transaction) of {result, {Nidx, SubsByDepth, {Result, broadcast}}} -> broadcast_created_node(Host, Node, Nidx, Type, NodeOptions, SubsByDepth), @@ -1864,10 +1684,9 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> %%
  • The node is the root collection node, which cannot be deleted.
  • %%
  • The specified node does not exist.
  • %% --spec delete_node(Host :: mod_pubsub:host(), Node :: mod_pubsub:nodeId(), - Owner :: jid()) -> {result, [xmlel(),...]} | {error, xmlel()}. +-spec delete_node(host(), binary(), jid()) -> {result, pubsub()} | {error, error()}. delete_node(_Host, <<>>, _Owner) -> - {error, ?ERRT_NOT_ALLOWED(?MYLANG, <<"No node specified">>)}; + {error, xmpp:err_not_allowed(<<"No node specified">>, ?MYLANG)}; delete_node(Host, Node, Owner) -> Action = fun (#pubsub_node{type = Type, id = Nidx}) -> case node_call(Host, Type, get_affiliation, [Nidx, Owner]) of @@ -1879,7 +1698,7 @@ delete_node(Host, Node, Owner) -> Error -> Error end; _ -> - {error, ?ERRT_FORBIDDEN(?MYLANG, <<"You're not an owner">>)} + {error, xmpp:err_forbidden(<<"Owner privileges required">>, ?MYLANG)} end end, Reply = [], @@ -1941,16 +1760,15 @@ delete_node(Host, Node, Owner) -> %%
  • The node does not support subscriptions.
  • %%
  • The node does not exist.
  • %% --spec subscribe_node(Host :: mod_pubsub:host(), Node :: mod_pubsub:nodeId(), - From :: jid(), JID :: binary(), Configuration :: [xmlel()]) -> - {result, [xmlel(),...]} | {error, xmlel()}. +-spec subscribe_node(host(), binary(), jid(), binary(), [{binary(), [binary()]}]) -> + {result, pubsub()} | {error, error()}. subscribe_node(Host, Node, From, JID, Configuration) -> SubModule = subscription_plugin(Host), SubOpts = case SubModule:parse_options_xform(Configuration) of {result, GoodSubOpts} -> GoodSubOpts; _ -> invalid end, - Subscriber = string_to_ljid(JID), + Subscriber = jid:tolower(JID), Action = fun (#pubsub_node{options = Options, type = Type, id = Nidx, owners = O}) -> Features = plugin_features(Host, Type), SubscribeFeature = lists:member(<<"subscribe">>, Features), @@ -1976,21 +1794,21 @@ subscribe_node(Host, Node, From, JID, Configuration) -> true end, if not SubscribeFeature -> - {error, - extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, <<"subscribe">>)}; + {error, extended_error(xmpp:err_feature_not_implemented(), + err_unsupported('subscribe'))}; not SubscribeConfig -> - {error, - extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, <<"subscribe">>)}; + {error, extended_error(xmpp:err_feature_not_implemented(), + err_unsupported('subscribe'))}; HasOptions andalso not OptionsFeature -> - {error, - extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, <<"subscription-options">>)}; + {error, extended_error(xmpp:err_feature_not_implemented(), + err_unsupported('subscription-options'))}; SubOpts == invalid -> - {error, - extended_error(?ERR_BAD_REQUEST, <<"invalid-options">>)}; + {error, extended_error(xmpp:err_bad_request(), + err_invalid_options())}; not CanSubscribe -> %% fallback to closest XEP compatible result, assume we are not allowed to subscribe - {error, - extended_error(?ERR_NOT_ALLOWED, <<"closed-node">>)}; + {error, extended_error(xmpp:err_not_allowed(), + err_closed_node())}; true -> Owners = node_owners_call(Host, Type, Nidx, O), {PS, RG} = get_presence_and_roster_permissions(Host, Subscriber, @@ -2001,19 +1819,13 @@ subscribe_node(Host, Node, From, JID, Configuration) -> end end, Reply = fun (Subscription) -> - SubAttrs = case Subscription of - {subscribed, SubId} -> - [{<<"subscription">>, subscription_to_string(subscribed)}, - {<<"subid">>, SubId}, {<<"node">>, Node}]; - Other -> - [{<<"subscription">>, subscription_to_string(Other)}, - {<<"node">>, Node}] - end, - [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB}], - children = [#xmlel{name = <<"subscription">>, - attrs = [{<<"jid">>, jid:to_string(Subscriber)} - | SubAttrs]}]}] + Sub = case Subscription of + {subscribed, SubId} -> + #ps_subscription{type = subscribed, subid = SubId}; + Other -> + #ps_subscription{type = Other} + end, + #pubsub{subscription = Sub#ps_subscription{jid = Subscriber, node = Node}} end, case transaction(Host, Node, Action, sync_dirty) of {result, {TNode, {Result, subscribed, SubId, send_last}}} -> @@ -2052,14 +1864,10 @@ subscribe_node(Host, Node, From, JID, Configuration) -> %%
  • The node does not exist.
  • %%
  • The request specifies a subscription ID that is not valid or current.
  • %% --spec unsubscribe_node(Host :: mod_pubsub:host(), Node :: mod_pubsub:nodeId(), - From :: jid(), JID :: binary() | ljid(), - SubId :: mod_pubsub:subId()) -> - {result, []} | {error, xmlel()}. - -unsubscribe_node(Host, Node, From, JID, SubId) when is_binary(JID) -> - unsubscribe_node(Host, Node, From, string_to_ljid(JID), SubId); -unsubscribe_node(Host, Node, From, Subscriber, SubId) -> +-spec unsubscribe_node(host(), binary(), jid(), jid(), binary()) -> + {result, undefined} | {error, error()}. +unsubscribe_node(Host, Node, From, JID, SubId) -> + Subscriber = jid:tolower(JID), Action = fun (#pubsub_node{type = Type, id = Nidx}) -> node_call(Host, Type, unsubscribe_node, [Nidx, From, Subscriber, SubId]) end, @@ -2067,9 +1875,8 @@ unsubscribe_node(Host, Node, From, Subscriber, SubId) -> {result, {_, default}} -> ServerHost = serverhost(Host), ejabberd_hooks:run(pubsub_unsubscribe_node, ServerHost, - [ServerHost, Host, Node, Subscriber, SubId]), - {result, []}; - % {result, {_, Result}} -> {result, Result}; + [ServerHost, Host, Node, Subscriber, SubId]), + {result, undefined}; Error -> Error end. @@ -2084,12 +1891,8 @@ unsubscribe_node(Host, Node, From, Subscriber, SubId) -> %%
  • The item contains more than one payload element or the namespace of the root payload element does not match the configured namespace for the node.
  • %%
  • The request does not match the node configuration.
  • %% --spec publish_item(Host :: mod_pubsub:host(), ServerHost :: binary(), - Node :: mod_pubsub:nodeId(), Publisher :: jid(), - ItemId :: <<>> | mod_pubsub:itemId(), - Payload :: mod_pubsub:payload()) -> - {result, [xmlel(),...]} | {error, xmlel()}. - +-spec publish_item(host(), binary(), binary(), jid(), binary(), + [xmlel()]) -> {result, pubsub()} | {error, error()}. publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload, [], all). publish_item(Host, ServerHost, Node, Publisher, <<>>, Payload, PubOpts, Access) -> @@ -2106,34 +1909,31 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload, PubOpts, Access PayloadSize = byte_size(term_to_binary(Payload)) - 2, PayloadMaxSize = get_option(Options, max_payload_size), if not PublishFeature -> - {error, - extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, <<"publish">>)}; + {error, extended_error(xmpp:err_feature_not_implemented(), + err_unsupported(publish))}; PayloadSize > PayloadMaxSize -> - {error, - extended_error(?ERR_NOT_ACCEPTABLE, <<"payload-too-big">>)}; + {error, extended_error(xmpp:err_not_acceptable(), + err_payload_too_big())}; (PayloadCount == 0) and (Payload == []) -> - {error, - extended_error(?ERR_BAD_REQUEST, <<"payload-required">>)}; + {error, extended_error(xmpp:err_bad_request(), + err_payload_required())}; (PayloadCount > 1) or (PayloadCount == 0) -> - {error, - extended_error(?ERR_BAD_REQUEST, <<"invalid-payload">>)}; + {error, extended_error(xmpp:err_bad_request(), + err_invalid_payload())}; (DeliverPayloads == false) and (PersistItems == false) and (PayloadSize > 0) -> - {error, - extended_error(?ERR_BAD_REQUEST, <<"item-forbidden">>)}; + {error, extended_error(xmpp:err_bad_request(), + err_item_forbidden())}; ((DeliverPayloads == true) or (PersistItems == true)) and (PayloadSize == 0) -> - {error, - extended_error(?ERR_BAD_REQUEST, <<"item-required">>)}; + {error, extended_error(xmpp:err_bad_request(), + err_item_required())}; true -> node_call(Host, Type, publish_item, [Nidx, Publisher, PublishModel, MaxItems, ItemId, Payload, PubOpts]) end end, - Reply = [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB}], - children = [#xmlel{name = <<"publish">>, attrs = nodeAttr(Node), - children = [#xmlel{name = <<"item">>, - attrs = itemAttr(ItemId)}]}]}], + Reply = #pubsub{publish = #ps_publish{node = Node, + items = [#ps_item{id = ItemId}]}}, case transaction(Host, Node, Action, sync_dirty) of {result, {TNode, {Result, Broadcast, Removed}}} -> Nidx = TNode#pubsub_node.id, @@ -2175,29 +1975,20 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload, PubOpts, Access {result, Reply}; {result, {_, Result}} -> {result, Result}; - {error, _} = Error -> - case is_item_not_found(Error) of + {error, #error{reason = 'item-not-found'}} -> + Type = select_type(ServerHost, Host, Node), + case lists:member(<<"auto-create">>, plugin_features(Host, Type)) of true -> - Type = select_type(ServerHost, Host, Node), - case lists:member(<<"auto-create">>, plugin_features(Host, Type)) of - true -> - case create_node(Host, ServerHost, Node, Publisher, Type, Access, []) of - {result, - [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB}], - children = [#xmlel{name = <<"create">>, - attrs = [{<<"node">>, NewNode}]}]}]} -> + case create_node(Host, ServerHost, Node, Publisher, Type, Access, []) of + {result, #pubsub{create = NewNode}} -> publish_item(Host, ServerHost, NewNode, Publisher, ItemId, - Payload, PubOpts, Access); - _ -> - {error, ?ERR_ITEM_NOT_FOUND} - end; - false -> - Txt = <<"Automatic node creation is not enabled">>, - {error, ?ERRT_ITEM_NOT_FOUND(?MYLANG, Txt)} + Payload, PubOpts, Access); + _ -> + {error, xmpp:err_item_not_found()} end; false -> - Error + Txt = <<"Automatic node creation is not enabled">>, + {error, xmpp:err_item_not_found(Txt, ?MYLANG)} end; Error -> Error @@ -2214,14 +2005,12 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload, PubOpts, Access %%
  • The node does not support persistent items.
  • %%
  • The service does not support the deletion of items.
  • %% --spec delete_item(Host :: mod_pubsub:host(), Node :: mod_pubsub:nodeId(), - Publisher :: jid(), ItemId :: mod_pubsub:itemId()) -> - {result, []} | {error, xmlel()}. - +-spec delete_item(host(), binary(), jid(), binary()) -> {result, undefined} | + {error, error()}. delete_item(Host, Node, Publisher, ItemId) -> delete_item(Host, Node, Publisher, ItemId, false). delete_item(_, <<>>, _, _, _) -> - {error, extended_error(?ERR_BAD_REQUEST, <<"node-required">>)}; + {error, extended_error(xmpp:err_bad_request(), err_nodeid_required())}; delete_item(Host, Node, Publisher, ItemId, ForceNotify) -> Action = fun (#pubsub_node{options = Options, type = Type, id = Nidx}) -> Features = plugin_features(Host, Type), @@ -2232,16 +2021,16 @@ delete_item(Host, Node, Publisher, ItemId, ForceNotify) -> %% %% Request does not specify an item %% {error, extended_error(?ERR_BAD_REQUEST, "item-required")}; not PersistentFeature -> - {error, - extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, <<"persistent-items">>)}; + {error, extended_error(xmpp:err_feature_not_implemented(), + err_unsupported('persistent-items'))}; not DeleteFeature -> - {error, - extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, <<"delete-items">>)}; + {error, extended_error(xmpp:err_feature_not_implemented(), + err_unsupported('delete-items'))}; true -> node_call(Host, Type, delete_item, [Nidx, Publisher, PublishModel, ItemId]) end end, - Reply = [], + Reply = undefined, case transaction(Host, Node, Action, sync_dirty) of {result, {TNode, {Result, broadcast}}} -> Nidx = TNode#pubsub_node.id, @@ -2272,10 +2061,8 @@ delete_item(Host, Node, Publisher, ItemId, ForceNotify) -> %%
  • The node is not configured to persist items.
  • %%
  • The specified node does not exist.
  • %% --spec purge_node(Host :: mod_pubsub:host(), Node :: mod_pubsub:nodeId(), - Owner :: jid()) -> - {result, []} | {error, xmlel()}. - +-spec purge_node(mod_pubsub:host(), binary(), jid()) -> {result, undefined} | + {error, error()}. purge_node(Host, Node, Owner) -> Action = fun (#pubsub_node{options = Options, type = Type, id = Nidx}) -> Features = plugin_features(Host, Type), @@ -2283,18 +2070,18 @@ purge_node(Host, Node, Owner) -> PersistentFeature = lists:member(<<"persistent-items">>, Features), PersistentConfig = get_option(Options, persist_items), if not PurgeFeature -> - {error, - extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, <<"purge-nodes">>)}; + {error, extended_error(xmpp:err_feature_not_implemented(), + err_unsupported('purge-nodes'))}; not PersistentFeature -> - {error, - extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, <<"persistent-items">>)}; + {error, extended_error(xmpp:err_feature_not_implemented(), + err_unsupported('persistent-items'))}; not PersistentConfig -> - {error, - extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, <<"persistent-items">>)}; + {error, extended_error(xmpp:err_feature_not_implemented(), + err_unsupported('persistent-items'))}; true -> node_call(Host, Type, purge_node, [Nidx, Owner]) end end, - Reply = [], + Reply = undefined, case transaction(Host, Node, Action, sync_dirty) of {result, {TNode, {Result, broadcast}}} -> Nidx = TNode#pubsub_node.id, @@ -2319,71 +2106,57 @@ purge_node(Host, Node, Owner) -> %%

    The permission are not checked in this function.

    %% @todo We probably need to check that the user doing the query has the right %% to read the items. --spec get_items(Host :: mod_pubsub:host(), Node :: mod_pubsub:nodeId(), - From :: jid(), SubId :: mod_pubsub:subId(), - SMaxItems :: binary(), ItemIds :: [mod_pubsub:itemId()], - Rsm :: none | rsm_in()) -> - {result, [xmlel(),...]} | {error, xmlel()}. - +-spec get_items(host(), binary(), jid(), binary(), + binary(), [binary()], undefined | rsm_set()) -> + {result, pubsub()} | {error, error()}. get_items(Host, Node, From, SubId, SMaxItems, ItemIds, RSM) -> - MaxItems = if SMaxItems == <<>> -> - case get_max_items_node(Host) of - undefined -> ?MAXITEMS; - Max -> Max - end; - true -> - case catch jlib:binary_to_integer(SMaxItems) of - {'EXIT', _} -> - Txt = <<"Value of 'max_items' should be integer">>, - {error, ?ERRT_BAD_REQUEST(?MYLANG, Txt)}; - Val -> Val - end - end, - case MaxItems of - {error, Error} -> - {error, Error}; - _ -> - Action = fun (#pubsub_node{options = Options, type = Type, id = Nidx, owners = O}) -> - Features = plugin_features(Host, Type), - RetreiveFeature = lists:member(<<"retrieve-items">>, Features), - PersistentFeature = lists:member(<<"persistent-items">>, Features), - AccessModel = get_option(Options, access_model), - AllowedGroups = get_option(Options, roster_groups_allowed, []), - if not RetreiveFeature -> - {error, - extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, <<"retrieve-items">>)}; - not PersistentFeature -> - {error, - extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, <<"persistent-items">>)}; - true -> - Owners = node_owners_call(Host, Type, Nidx, O), - {PS, RG} = get_presence_and_roster_permissions(Host, From, Owners, - AccessModel, AllowedGroups), - node_call(Host, Type, get_items, - [Nidx, From, AccessModel, PS, RG, SubId, RSM]) - end - end, - case transaction(Host, Node, Action, sync_dirty) of - {result, {_, {Items, RsmOut}}} -> - SendItems = case ItemIds of - [] -> - Items; - _ -> - lists:filter(fun (#pubsub_item{itemid = {ItemId, _}}) -> - lists:member(ItemId, ItemIds) - end, - Items) - end, - {result, - [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB}], - children = - [#xmlel{name = <<"items">>, attrs = nodeAttr(Node), - children = itemsEls(lists:sublist(SendItems, MaxItems))} - | jlib:rsm_encode(RsmOut)]}]}; - Error -> - Error - end + MaxItems = if SMaxItems == undefined -> + case get_max_items_node(Host) of + undefined -> ?MAXITEMS; + Max -> Max + end; + true -> + SMaxItems + end, + Action = + fun(#pubsub_node{options = Options, type = Type, + id = Nidx, owners = O}) -> + Features = plugin_features(Host, Type), + RetreiveFeature = lists:member(<<"retrieve-items">>, Features), + PersistentFeature = lists:member(<<"persistent-items">>, Features), + AccessModel = get_option(Options, access_model), + AllowedGroups = get_option(Options, roster_groups_allowed, []), + if not RetreiveFeature -> + {error, extended_error(xmpp:err_feature_not_implemented(), + err_unsupported('retrieve-items'))}; + not PersistentFeature -> + {error, extended_error(xmpp:err_feature_not_implemented(), + err_unsupported('persistent-items'))}; + true -> + Owners = node_owners_call(Host, Type, Nidx, O), + {PS, RG} = get_presence_and_roster_permissions( + Host, From, Owners, AccessModel, AllowedGroups), + node_call(Host, Type, get_items, + [Nidx, From, AccessModel, PS, RG, SubId, RSM]) + end + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, {Items, RsmOut}}} -> + SendItems = case ItemIds of + [] -> + Items; + _ -> + lists:filter( + fun(#pubsub_item{itemid = {ItemId, _}}) -> + lists:member(ItemId, ItemIds) + end, Items) + end, + {result, + #pubsub{items = #ps_items{node = Node, + items = itemsEls(lists:sublist(SendItems, MaxItems))}, + rsm = RsmOut}}; + Error -> + Error end. get_items(Host, Node) -> @@ -2487,227 +2260,200 @@ dispatch_items(From, To, _Node, Stanza) -> ejabberd_router:route(service_jid(From), jid:make(To), Stanza). %% @doc

    Return the list of affiliations as an XMPP response.

    --spec get_affiliations(Host :: mod_pubsub:host(), Node :: mod_pubsub:nodeId(), - JID :: jid(), Plugins :: [binary()]) -> - {result, [xmlel(),...]} | {error, xmlel()}. - +-spec get_affiliations(host(), binary(), jid(), [binary()]) -> + {result, pubsub()} | {error, error()}. get_affiliations(Host, Node, JID, Plugins) when is_list(Plugins) -> - Result = lists:foldl( fun (Type, {Status, Acc}) -> - Features = plugin_features(Host, Type), - RetrieveFeature = lists:member(<<"retrieve-affiliations">>, Features), - if not RetrieveFeature -> - {{error, - extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, - unsupported, <<"retrieve-affiliations">>)}, - Acc}; - true -> - {result, Affs} = node_action(Host, Type, - get_entity_affiliations, - [Host, JID]), - {Status, [Affs | Acc]} - end - end, - {ok, []}, Plugins), + Result = + lists:foldl( + fun(Type, {Status, Acc}) -> + Features = plugin_features(Host, Type), + RetrieveFeature = lists:member(<<"retrieve-affiliations">>, Features), + if not RetrieveFeature -> + {{error, extended_error(xmpp:err_feature_not_implemented(), + err_unsupported('retrieve-affiliations'))}, + Acc}; + true -> + {result, Affs} = node_action(Host, Type, + get_entity_affiliations, + [Host, JID]), + {Status, [Affs | Acc]} + end + end, + {ok, []}, Plugins), case Result of {ok, Affs} -> - Entities = lists:flatmap(fun - ({_, none}) -> - []; - ({#pubsub_node{nodeid = {_, NodeId}}, Aff}) -> - if (Node == <<>>) or (Node == NodeId) -> - [#xmlel{name = <<"affiliation">>, - attrs = [{<<"affiliation">>, affiliation_to_string(Aff)} - | nodeAttr(NodeId)]}]; - true -> - [] - end; - (_) -> - [] - end, - lists:usort(lists:flatten(Affs))), - {result, - [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB}], - children = [#xmlel{name = <<"affiliations">>, attrs = [], - children = Entities}]}]}; + Entities = lists:flatmap( + fun({_, none}) -> + []; + ({#pubsub_node{nodeid = {_, NodeId}}, Aff}) -> + if (Node == <<>>) or (Node == NodeId) -> + [#ps_affiliation{node = NodeId, + type = Aff}]; + true -> + [] + end; + (_) -> + [] + end, lists:usort(lists:flatten(Affs))), + {result, #pubsub{affiliations = {<<>>, Entities}}}; {Error, _} -> Error end. --spec get_affiliations(Host :: mod_pubsub:host(), Node :: mod_pubsub:nodeId(), - JID :: jid()) -> - {result, [xmlel(),...]} | {error, xmlel()}. - +-spec get_affiliations(host(), binary(), jid()) -> + {result, pubsub_owner()} | {error, error()}. get_affiliations(Host, Node, JID) -> - Action = fun (#pubsub_node{type = Type, id = Nidx}) -> - Features = plugin_features(Host, Type), - RetrieveFeature = lists:member(<<"modify-affiliations">>, Features), - {result, Affiliation} = node_call(Host, Type, get_affiliation, [Nidx, JID]), - if not RetrieveFeature -> - {error, - extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, <<"modify-affiliations">>)}; - Affiliation /= owner -> - {error, ?ERRT_FORBIDDEN(?MYLANG, <<"You're not an owner">>)}; - true -> - node_call(Host, Type, get_node_affiliations, [Nidx]) - end - end, + Action = + fun(#pubsub_node{type = Type, id = Nidx}) -> + Features = plugin_features(Host, Type), + RetrieveFeature = lists:member(<<"modify-affiliations">>, Features), + {result, Affiliation} = node_call(Host, Type, get_affiliation, [Nidx, JID]), + if not RetrieveFeature -> + {error, extended_error(xmpp:err_feature_not_implemented(), + err_unsupported('modify-affiliations'))}; + Affiliation /= owner -> + {error, xmpp:err_forbidden(<<"Owner privileges required">>, ?MYLANG)}; + true -> + node_call(Host, Type, get_node_affiliations, [Nidx]) + end + end, case transaction(Host, Node, Action, sync_dirty) of {result, {_, []}} -> - {error, ?ERR_ITEM_NOT_FOUND}; + {error, xmpp:err_item_not_found()}; {result, {_, Affs}} -> - Entities = lists:flatmap(fun - ({_, none}) -> - []; - ({AJID, Aff}) -> - [#xmlel{name = <<"affiliation">>, - attrs = [{<<"jid">>, jid:to_string(AJID)}, - {<<"affiliation">>, affiliation_to_string(Aff)}]}] - end, - Affs), - {result, - [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB_OWNER}], - children = [#xmlel{name = <<"affiliations">>, - attrs = nodeAttr(Node), children = Entities}]}]}; + Entities = lists:flatmap( + fun({_, none}) -> + []; + ({AJID, Aff}) -> + [#ps_affiliation{jid = AJID, type = Aff}] + end, Affs), + {result, #pubsub_owner{affiliations = {Node, Entities}}}; Error -> Error end. --spec set_affiliations(Host :: mod_pubsub:host(), Node :: mod_pubsub:nodeId(), - From :: jid(), EntitiesEls :: [xmlel()]) -> - {result, []} | {error, xmlel()}. - -set_affiliations(Host, Node, From, EntitiesEls) -> +-spec set_affiliations(host(), binary(), jid(), [ps_affiliation()]) -> + {result, undefined} | {error, error()}. +set_affiliations(Host, Node, From, Affs) -> Owner = jid:tolower(jid:remove_resource(From)), - Entities = lists:foldl(fun - (_, error) -> - error; - (El, Acc) -> - case El of - #xmlel{name = <<"affiliation">>, attrs = Attrs} -> - JID = jid:from_string(fxml:get_attr_s(<<"jid">>, Attrs)), - Affiliation = string_to_affiliation(fxml:get_attr_s(<<"affiliation">>, Attrs)), - if (JID == error) or (Affiliation == false) -> error; - true -> [{jid:tolower(JID), Affiliation} | Acc] - end - end - end, - [], EntitiesEls), - case Entities of - error -> - {error, ?ERR_BAD_REQUEST}; - _ -> - Action = fun (#pubsub_node{type = Type, id = Nidx, owners = O} = N) -> - Owners = node_owners_call(Host, Type, Nidx, O), - case lists:member(Owner, Owners) of - true -> - OwnerJID = jid:make(Owner), - FilteredEntities = case Owners of - [Owner] -> [E || E <- Entities, element(1, E) =/= OwnerJID]; - _ -> Entities + Action = + fun(#pubsub_node{type = Type, id = Nidx, owners = O} = N) -> + Owners = node_owners_call(Host, Type, Nidx, O), + case lists:member(Owner, Owners) of + true -> + OwnerJID = jid:make(Owner), + FilteredAffs = + case Owners of + [Owner] -> + [Aff || Aff <- Affs, + Aff#ps_affiliation.jid /= OwnerJID]; + _ -> + Affs end, - lists:foreach(fun ({JID, Affiliation}) -> - node_call(Host, Type, set_affiliation, [Nidx, JID, Affiliation]), - case Affiliation of - owner -> - NewOwner = jid:tolower(jid:remove_resource(JID)), - NewOwners = [NewOwner | Owners], - tree_call(Host, + lists:foreach( + fun(#ps_affiliation{jid = JID, type = Affiliation}) -> + node_call(Host, Type, set_affiliation, [Nidx, JID, Affiliation]), + case Affiliation of + owner -> + NewOwner = jid:tolower(jid:remove_resource(JID)), + NewOwners = [NewOwner | Owners], + tree_call(Host, set_node, [N#pubsub_node{owners = NewOwners}]); - none -> - OldOwner = jid:tolower(jid:remove_resource(JID)), - case lists:member(OldOwner, Owners) of - true -> - NewOwners = Owners -- [OldOwner], - tree_call(Host, + none -> + OldOwner = jid:tolower(jid:remove_resource(JID)), + case lists:member(OldOwner, Owners) of + true -> + NewOwners = Owners -- [OldOwner], + tree_call(Host, set_node, [N#pubsub_node{owners = NewOwners}]); - _ -> - ok - end; - _ -> - ok - end - end, - FilteredEntities), - {result, []}; - _ -> - {error, ?ERRT_FORBIDDEN(?MYLANG, <<"You're not an owner">>)} - end - end, - case transaction(Host, Node, Action, sync_dirty) of - {result, {_, Result}} -> {result, Result}; - Other -> Other - end + _ -> + ok + end; + _ -> + ok + end + end, FilteredAffs), + {result, undefined}; + _ -> + {error, xmpp:err_forbidden( + <<"Owner privileges required">>, ?MYLANG)} + end + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, Result}} -> {result, Result}; + Other -> Other end. +-spec get_options(binary(), binary(), jid(), binary(), binary()) -> + {result, xdata()} | {error, error()}. get_options(Host, Node, JID, SubId, Lang) -> Action = fun (#pubsub_node{type = Type, id = Nidx}) -> case lists:member(<<"subscription-options">>, plugin_features(Host, Type)) of true -> get_options_helper(Host, JID, Lang, Node, Nidx, SubId, Type); false -> - {error, - extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, <<"subscription-options">>)} + {error, extended_error(xmpp:err_feature_not_implemented(), + err_unsupported('subscription-options'))} end end, case transaction(Host, Node, Action, sync_dirty) of - {result, {_Node, XForm}} -> {result, [XForm]}; + {result, {_Node, XForm}} -> {result, XForm}; Error -> Error end. +-spec get_options_helper(binary(), jid(), binary(), binary(), _, binary(), + binary()) -> {result, pubsub()} | {error, error()}. get_options_helper(Host, JID, Lang, Node, Nidx, SubId, Type) -> - Subscriber = string_to_ljid(JID), + Subscriber = jid:tolower(JID), {result, Subs} = node_call(Host, Type, get_subscriptions, [Nidx, Subscriber]), SubIds = [Id || {Sub, Id} <- Subs, Sub == subscribed], case {SubId, SubIds} of {_, []} -> - {error, - extended_error(?ERR_NOT_ACCEPTABLE, <<"not-subscribed">>)}; + {error, extended_error(xmpp:err_not_acceptable(), + err_not_subscribed())}; {<<>>, [SID]} -> read_sub(Host, Node, Nidx, Subscriber, SID, Lang); {<<>>, _} -> - {error, - extended_error(?ERR_NOT_ACCEPTABLE, <<"subid-required">>)}; + {error, extended_error(xmpp:err_not_acceptable(), + err_subid_required())}; {_, _} -> ValidSubId = lists:member(SubId, SubIds), if ValidSubId -> read_sub(Host, Node, Nidx, Subscriber, SubId, Lang); true -> - {error, - extended_error(?ERR_NOT_ACCEPTABLE, <<"invalid-subid">>)} + {error, extended_error(xmpp:err_not_acceptable(), + err_invalid_subid())} end end. +-spec read_sub(binary(), binary(), nodeIdx(), ljid(), binary(), binary()) -> {result, pubsub()}. read_sub(Host, Node, Nidx, Subscriber, SubId, Lang) -> SubModule = subscription_plugin(Host), - Children = case SubModule:get_subscription(Subscriber, Nidx, SubId) of - {error, notfound} -> - []; - {result, #pubsub_subscription{options = Options}} -> - {result, XdataEl} = SubModule:get_options_xform(Lang, Options), - [XdataEl] - end, - OptionsEl = #xmlel{name = <<"options">>, - attrs = [{<<"jid">>, jid:to_string(Subscriber)}, - {<<"subid">>, SubId} - | nodeAttr(Node)], - children = Children}, - PubsubEl = #xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB}], - children = [OptionsEl]}, - {result, PubsubEl}. + XData = case SubModule:get_subscription(Subscriber, Nidx, SubId) of + {error, notfound} -> + undefined; + {result, #pubsub_subscription{options = Options}} -> + {result, X} = SubModule:get_options_xform(Lang, Options), + X + end, + {result, #pubsub{options = #ps_options{jid = jid:make(Subscriber), + subid = SubId, + node = Node, + xdata = XData}}}. +-spec set_options(binary(), binary(), jid(), binary(), + [{binary(), [binary()]}]) -> + {result, undefined} | {error, error()}. set_options(Host, Node, JID, SubId, Configuration) -> Action = fun (#pubsub_node{type = Type, id = Nidx}) -> case lists:member(<<"subscription-options">>, plugin_features(Host, Type)) of true -> set_options_helper(Host, Configuration, JID, Nidx, SubId, Type); false -> - {error, - extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, <<"subscription-options">>)} + {error, extended_error(xmpp:err_feature_not_implemented(), + err_unsupported('subscription-options'))} end end, case transaction(Host, Node, Action, sync_dirty) of @@ -2715,56 +2461,53 @@ set_options(Host, Node, JID, SubId, Configuration) -> Error -> Error end. +-spec set_options_helper(binary(), [{binary(), [binary()]}], jid(), + nodeIdx(), binary(), binary()) -> + {result, undefined} | {error, error()}. set_options_helper(Host, Configuration, JID, Nidx, SubId, Type) -> SubModule = subscription_plugin(Host), SubOpts = case SubModule:parse_options_xform(Configuration) of {result, GoodSubOpts} -> GoodSubOpts; _ -> invalid end, - Subscriber = string_to_ljid(JID), + Subscriber = jid:tolower(JID), {result, Subs} = node_call(Host, Type, get_subscriptions, [Nidx, Subscriber]), SubIds = [Id || {Sub, Id} <- Subs, Sub == subscribed], case {SubId, SubIds} of {_, []} -> - {error, - extended_error(?ERR_NOT_ACCEPTABLE, <<"not-subscribed">>)}; + {error, extended_error(xmpp:err_not_acceptable(), err_not_subscribed())}; {<<>>, [SID]} -> write_sub(Host, Nidx, Subscriber, SID, SubOpts); {<<>>, _} -> - {error, - extended_error(?ERR_NOT_ACCEPTABLE, <<"subid-required">>)}; + {error, extended_error(xmpp:err_not_acceptable(), err_subid_required())}; {_, _} -> write_sub(Host, Nidx, Subscriber, SubId, SubOpts) end. +-spec write_sub(binary(), nodeIdx(), ljid(), binary(), _) -> {result, undefined} | + {error, error()}. write_sub(_Host, _Nidx, _Subscriber, _SubId, invalid) -> - {error, - extended_error(?ERR_BAD_REQUEST, <<"invalid-options">>)}; + {error, extended_error(xmpp:err_bad_request(), err_invalid_options())}; write_sub(_Host, _Nidx, _Subscriber, _SubId, []) -> - {result, []}; + {result, undefined}; write_sub(Host, Nidx, Subscriber, SubId, Options) -> SubModule = subscription_plugin(Host), case SubModule:set_subscription(Subscriber, Nidx, SubId, Options) of - {result, _} -> {result, []}; - {error, _} -> {error, extended_error(?ERR_NOT_ACCEPTABLE, <<"invalid-subid">>)} + {result, _} -> {result, undefined}; + {error, _} -> {error, extended_error(xmpp:err_not_acceptable(), + err_invalid_subid())} end. -%% @spec (Host, Node, JID, Plugins) -> {error, Reason} | {result, Response} -%% Host = host() -%% Node = pubsubNode() -%% JID = jid() -%% Plugins = [Plugin::string()] -%% Reason = stanzaError() -%% Response = [pubsubIQResponse()] %% @doc

    Return the list of subscriptions as an XMPP response.

    +-spec get_subscriptions(host(), binary(), jid(), [binary()]) -> + {result, pubsub()} | {error, error()}. get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> Result = lists:foldl(fun (Type, {Status, Acc}) -> Features = plugin_features(Host, Type), RetrieveFeature = lists:member(<<"retrieve-subscriptions">>, Features), if not RetrieveFeature -> - {{error, - extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, - unsupported, <<"retrieve-subscriptions">>)}, + {{error, extended_error(xmpp:err_feature_not_implemented(), + err_unsupported('retrieve-subscriptions'))}, Acc}; true -> Subscriber = jid:remove_resource(JID), @@ -2783,14 +2526,9 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> ({#pubsub_node{nodeid = {_, SubsNode}}, Sub}) -> case Node of <<>> -> - [#xmlel{name = <<"subscription">>, - attrs = - [{<<"subscription">>, subscription_to_string(Sub)} - | nodeAttr(SubsNode)]}]; + [#ps_subscription{node = SubsNode, type = Sub}]; SubsNode -> - [#xmlel{name = <<"subscription">>, - attrs = - [{<<"subscription">>, subscription_to_string(Sub)}]}]; + [#ps_subscription{type = Sub}]; _ -> [] end; @@ -2799,88 +2537,65 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> ({#pubsub_node{nodeid = {_, SubsNode}}, Sub, SubId, SubJID}) -> case Node of <<>> -> - [#xmlel{name = <<"subscription">>, - attrs = - [{<<"jid">>, jid:to_string(SubJID)}, - {<<"subid">>, SubId}, - {<<"subscription">>, subscription_to_string(Sub)} - | nodeAttr(SubsNode)]}]; + [#ps_subscription{jid = SubJID, + subid = SubId, + type = Sub, + node = SubsNode}]; SubsNode -> - [#xmlel{name = <<"subscription">>, - attrs = - [{<<"jid">>, jid:to_string(SubJID)}, - {<<"subid">>, SubId}, - {<<"subscription">>, subscription_to_string(Sub)}]}]; + [#ps_subscription{jid = SubJID, + subid = SubId, + type = Sub}]; _ -> [] end; ({#pubsub_node{nodeid = {_, SubsNode}}, Sub, SubJID}) -> case Node of <<>> -> - [#xmlel{name = <<"subscription">>, - attrs = - [{<<"jid">>, jid:to_string(SubJID)}, - {<<"subscription">>, subscription_to_string(Sub)} - | nodeAttr(SubsNode)]}]; + [#ps_subscription{jid = SubJID, + type = Sub, + node = SubsNode}]; SubsNode -> - [#xmlel{name = <<"subscription">>, - attrs = - [{<<"jid">>, jid:to_string(SubJID)}, - {<<"subscription">>, subscription_to_string(Sub)}]}]; + [#ps_subscription{jid = SubJID, type = Sub}]; _ -> [] end end, lists:usort(lists:flatten(Subs))), - {result, - [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB}], - children = [#xmlel{name = <<"subscriptions">>, attrs = [], - children = Entities}]}]}; + {result, #pubsub{subscriptions = {<<>>, Entities}}}; {Error, _} -> Error end. +-spec get_subscriptions(binary(), binary(), jid()) -> {result, pubsub()} | + {error, error()}. get_subscriptions(Host, Node, JID) -> Action = fun (#pubsub_node{type = Type, id = Nidx}) -> Features = plugin_features(Host, Type), RetrieveFeature = lists:member(<<"manage-subscriptions">>, Features), {result, Affiliation} = node_call(Host, Type, get_affiliation, [Nidx, JID]), if not RetrieveFeature -> - {error, - extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, <<"manage-subscriptions">>)}; + {error, extended_error(xmpp:err_feature_not_implemented(), + err_unsupported('manage-subscriptions'))}; Affiliation /= owner -> - {error, ?ERRT_FORBIDDEN(?MYLANG, <<"You're not an owner">>)}; + {error, xmpp:err_forbidden(<<"Owner privileges required">>, ?MYLANG)}; true -> node_call(Host, Type, get_node_subscriptions, [Nidx]) end end, case transaction(Host, Node, Action, sync_dirty) of {result, {_, Subs}} -> - Entities = lists:flatmap(fun - ({_, none}) -> - []; - ({_, pending, _}) -> - []; - ({AJID, Sub}) -> - [#xmlel{name = <<"subscription">>, - attrs = - [{<<"jid">>, jid:to_string(AJID)}, - {<<"subscription">>, subscription_to_string(Sub)}]}]; + Entities = + lists:flatmap( + fun({_, none}) -> + []; + ({_, pending, _}) -> + []; + ({AJID, Sub}) -> + [#ps_subscription{jid = AJID, type = Sub}]; ({AJID, Sub, SubId}) -> - [#xmlel{name = <<"subscription">>, - attrs = - [{<<"jid">>, jid:to_string(AJID)}, - {<<"subscription">>, subscription_to_string(Sub)}, - {<<"subid">>, SubId}]}] - end, - Subs), - {result, - [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB_OWNER}], - children = [#xmlel{name = <<"subscriptions">>, - attrs = nodeAttr(Node), - children = Entities}]}]}; + [#ps_subscription{jid = AJID, type = Sub, subid = SubId}] + end, Subs), + {result, #pubsub{subscriptions = {Node, Entities}}}; Error -> Error end. @@ -2908,78 +2623,55 @@ get_subscriptions_for_send_last(Host, PType, sql, JID, LJID, BJID) -> get_subscriptions_for_send_last(_Host, _PType, _, _JID, _LJID, _BJID) -> []. -set_subscriptions(Host, Node, From, EntitiesEls) -> +set_subscriptions(Host, Node, From, Entities) -> Owner = jid:tolower(jid:remove_resource(From)), - Entities = lists:foldl(fun - (_, error) -> - error; - (El, Acc) -> - case El of - #xmlel{name = <<"subscription">>, attrs = Attrs} -> - JID = jid:from_string(fxml:get_attr_s(<<"jid">>, Attrs)), - Sub = string_to_subscription(fxml:get_attr_s(<<"subscription">>, Attrs)), - SubId = fxml:get_attr_s(<<"subid">>, Attrs), - if (JID == error) or (Sub == false) -> error; - true -> [{jid:tolower(JID), Sub, SubId} | Acc] - end - end - end, - [], EntitiesEls), - case Entities of - error -> - {error, ?ERR_BAD_REQUEST}; - _ -> - Notify = fun (JID, Sub, _SubId) -> - Stanza = #xmlel{name = <<"message">>, attrs = [], - children = - [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB}], - children = - [#xmlel{name = <<"subscription">>, - attrs = [{<<"jid">>, jid:to_string(JID)}, - {<<"subscription">>, subscription_to_string(Sub)} - | nodeAttr(Node)]}]}]}, - ejabberd_router:route(service_jid(Host), jid:make(JID), Stanza) - end, - Action = fun (#pubsub_node{type = Type, id = Nidx, owners = O}) -> - Owners = node_owners_call(Host, Type, Nidx, O), - case lists:member(Owner, Owners) of - true -> - Result = lists:foldl(fun ({JID, Sub, SubId}, Acc) -> - case - node_call(Host, Type, - set_subscriptions, - [Nidx, JID, Sub, SubId]) - of - {error, Err} -> - [{error, Err} | Acc]; - _ -> - Notify(JID, Sub, SubId), - Acc - end - end, - [], Entities), - case Result of - [] -> {result, []}; - [{error, E}|_] -> {error, E} - end; - _ -> - {error, ?ERRT_FORBIDDEN(?MYLANG, <<"You're not an owner">>)} - end - end, - case transaction(Host, Node, Action, sync_dirty) of - {result, {_, Result}} -> {result, Result}; - Other -> Other - end + Notify = fun(#ps_subscription{jid = JID, type = Sub}) -> + Stanza = #message{ + sub_els = [#pubsub{ + subscription = #ps_subscription{ + jid = JID, + type = Sub, + node = Node}}]}, + ejabberd_router:route(service_jid(Host), JID, Stanza) + end, + Action = + fun(#pubsub_node{type = Type, id = Nidx, owners = O}) -> + Owners = node_owners_call(Host, Type, Nidx, O), + case lists:member(Owner, Owners) of + true -> + Result = + lists:foldl( + fun(_, {error, _} = Err) -> + Err; + (#ps_subscription{jid = JID, type = Sub, + subid = SubId} = Entity, _) -> + case node_call(Host, Type, + set_subscriptions, + [Nidx, JID, Sub, SubId]) of + {error, _} = Err -> + Err; + _ -> + Notify(Entity) + end + end, ok, Entities), + case Result of + ok -> {result, undefined}; + {error, _} = Err -> Err + end; + _ -> + {error, xmpp:err_forbidden( + <<"Owner privileges required">>, ?MYLANG)} + + end + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, Result}} -> {result, Result}; + Other -> Other end. --spec get_presence_and_roster_permissions(Host :: mod_pubsub:host(), - From :: ljid(), Owners :: [ljid(),...], - AccessModel :: mod_pubsub:accessModel(), - AllowedGroups :: [binary()]) -> - {PresenceSubscription::boolean(), - RosterGroup::boolean()}. - +-spec get_presence_and_roster_permissions( + host(), ljid(), [ljid()], accessModel(), + [binary()]) -> {boolean(), boolean()}. get_presence_and_roster_permissions(Host, From, Owners, AccessModel, AllowedGroups) -> if (AccessModel == presence) or (AccessModel == roster) -> case Host of @@ -3037,10 +2729,10 @@ subscription_to_string(pending) -> <<"pending">>; subscription_to_string(unconfigured) -> <<"unconfigured">>; subscription_to_string(_) -> <<"none">>. --spec service_jid(Host :: mod_pubsub:host()) -> jid(). +-spec service_jid(jid() | ljid() | binary()) -> jid(). service_jid(#jid{} = Jid) -> Jid; service_jid({U, S, R}) -> jid:make(U, S, R); -service_jid(Host) -> jid:make(<<>>, Host, <<>>). +service_jid(Host) -> jid:make(Host). %% @spec (LJID, NotifyType, Depth, NodeOptions, SubOptions) -> boolean() %% LJID = jid() @@ -3071,7 +2763,7 @@ sub_option_can_deliver(_, _, {deliver, false}) -> false; sub_option_can_deliver(_, _, {expire, When}) -> p1_time_compat:timestamp() < When; sub_option_can_deliver(_, _, _) -> true. --spec presence_can_deliver(Entity :: ljid(), _ :: boolean()) -> boolean(). +-spec presence_can_deliver(ljid(), boolean()) -> boolean(). presence_can_deliver(_, false) -> true; presence_can_deliver({User, Server, Resource}, true) -> @@ -3092,10 +2784,7 @@ presence_can_deliver({User, Server, Resource}, true) -> false, Ss) end. --spec state_can_deliver(Entity::ljid(), - SubOptions :: mod_pubsub:subOptions() | []) -> - [ljid()]. - +-spec state_can_deliver(ljid(), subOptions() | []) -> [ljid()]. state_can_deliver({U, S, R}, []) -> [{U, S, R}]; state_can_deliver({U, S, R}, SubOptions) -> case lists:keysearch(show_values, 1, SubOptions) of @@ -3115,10 +2804,7 @@ state_can_deliver({U, S, R}, SubOptions) -> [], Resources) end. --spec get_resource_state(Entity :: ljid(), ShowValues :: [binary()], - JIDs :: [ljid()]) -> - [ljid()]. - +-spec get_resource_state(ljid(), [binary()], [ljid()]) -> [ljid()]. get_resource_state({U, S, R}, ShowValues, JIDs) -> case ejabberd_sm:get_session_pid(U, S, R) of none -> @@ -3137,8 +2823,7 @@ get_resource_state({U, S, R}, ShowValues, JIDs) -> end end. --spec payload_xmlelements(Payload :: mod_pubsub:payload()) -> - Count :: non_neg_integer(). +-spec payload_xmlelements([xmlel()]) -> non_neg_integer(). payload_xmlelements(Payload) -> payload_xmlelements(Payload, 0). @@ -3152,63 +2837,55 @@ items_event_stanza(Node, Options, Items) -> MoreEls = case Items of [LastItem] -> {ModifNow, ModifUSR} = LastItem#pubsub_item.modification, - DateTime = calendar:now_to_datetime(ModifNow), - {T_string, Tz_string} = jlib:timestamp_to_iso(DateTime, utc), - [#xmlel{name = <<"delay">>, attrs = [{<<"xmlns">>, ?NS_DELAY}, - {<<"from">>, jid:to_string(ModifUSR)}, - {<<"stamp">>, <>}], - children = [{xmlcdata, <<>>}]}]; + [#delay{stamp = ModifNow, from = jid:make(ModifUSR)}]; _ -> [] end, - BaseStanza = event_stanza_with_els([#xmlel{name = <<"items">>, - attrs = nodeAttr(Node), - children = itemsEls(Items)}], - MoreEls), + BaseStanza = #message{ + sub_els = [#ps_event{items = #ps_items{ + node = Node, + items = itemsEls(Items)}} + | MoreEls]}, NotificationType = get_option(Options, notification_type, headline), add_message_type(BaseStanza, NotificationType). -event_stanza(Els) -> - event_stanza_with_els(Els, []). -event_stanza_with_els(Els, MoreEls) -> - #xmlel{name = <<"message">>, attrs = [], - children = [#xmlel{name = <<"event">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB_EVENT}], - children = Els} - | MoreEls]}. - -event_stanza(Event, EvAttr) -> - event_stanza_with_els([#xmlel{name = Event, attrs = EvAttr}], []). - %%%%%% broadcast functions broadcast_publish_item(Host, Node, Nidx, Type, NodeOptions, ItemId, From, Payload, Removed) -> case get_collection_subscriptions(Host, Node) of SubsByDepth when is_list(SubsByDepth) -> - Content = case get_option(NodeOptions, deliver_payloads) of - true -> Payload; - false -> [] - end, - Attrs = case get_option(NodeOptions, itemreply, none) of - owner -> itemAttr(ItemId); %% owner not supported - publisher -> itemAttr(ItemId, {<<"publisher">>, jid:to_string(From)}); - none -> itemAttr(ItemId) - end, - Stanza = event_stanza( - [#xmlel{name = <<"items">>, attrs = nodeAttr(Node), - children = [#xmlel{name = <<"item">>, attrs = Attrs, - children = Content}]}]), + EventItem0 = case get_option(NodeOptions, deliver_payloads) of + true -> #ps_item{xml_els = Payload, id = ItemId}; + false -> #ps_item{id = ItemId} + end, + EventItem = case get_option(NodeOptions, itemreply, none) of + owner -> %% owner not supported + EventItem0; + publisher -> + EventItem0#ps_item{ + publisher = jid:to_string(From)}; + none -> + EventItem0 + end, + Stanza = #message{ + sub_els = + [#ps_event{items = + #ps_items{node = Node, + items = [EventItem]}}]}, broadcast_stanza(Host, From, Node, Nidx, Type, - NodeOptions, SubsByDepth, items, Stanza, true), + NodeOptions, SubsByDepth, items, Stanza, true), case Removed of [] -> ok; _ -> case get_option(NodeOptions, notify_retract) of true -> - RetractStanza = event_stanza( - [#xmlel{name = <<"items">>, attrs = nodeAttr(Node), - children = [#xmlel{name = <<"retract">>, attrs = itemAttr(RId)} || RId <- Removed]}]), + RetractStanza = #message{ + sub_els = + [#ps_event{ + items = #ps_items{ + node = Node, + retract = Removed}}]}, broadcast_stanza(Host, Node, Nidx, Type, NodeOptions, SubsByDepth, items, RetractStanza, true); @@ -3230,9 +2907,12 @@ broadcast_retract_items(Host, Node, Nidx, Type, NodeOptions, ItemIds, ForceNotif true -> case get_collection_subscriptions(Host, Node) of SubsByDepth when is_list(SubsByDepth) -> - Stanza = event_stanza( - [#xmlel{name = <<"items">>, attrs = nodeAttr(Node), - children = [#xmlel{name = <<"retract">>, attrs = itemAttr(ItemId)} || ItemId <- ItemIds]}]), + Stanza = #message{ + sub_els = + [#ps_event{ + items = #ps_items{ + node = Node, + retract = ItemIds}}]}, broadcast_stanza(Host, Node, Nidx, Type, NodeOptions, SubsByDepth, items, Stanza, true), {result, true}; @@ -3248,8 +2928,7 @@ broadcast_purge_node(Host, Node, Nidx, Type, NodeOptions) -> true -> case get_collection_subscriptions(Host, Node) of SubsByDepth when is_list(SubsByDepth) -> - Stanza = event_stanza( - [#xmlel{name = <<"purge">>, attrs = nodeAttr(Node)}]), + Stanza = #message{sub_els = [#ps_event{purge = Node}]}, broadcast_stanza(Host, Node, Nidx, Type, NodeOptions, SubsByDepth, nodes, Stanza, false), {result, true}; @@ -3267,8 +2946,7 @@ broadcast_removed_node(Host, Node, Nidx, Type, NodeOptions, SubsByDepth) -> [] -> {result, false}; _ -> - Stanza = event_stanza( - [#xmlel{name = <<"delete">>, attrs = nodeAttr(Node)}]), + Stanza = #message{sub_els = [#ps_event{delete = {Node, <<>>}}]}, broadcast_stanza(Host, Node, Nidx, Type, NodeOptions, SubsByDepth, nodes, Stanza, false), {result, true} @@ -3280,7 +2958,7 @@ broadcast_removed_node(Host, Node, Nidx, Type, NodeOptions, SubsByDepth) -> broadcast_created_node(_, _, _, _, _, []) -> {result, false}; broadcast_created_node(Host, Node, Nidx, Type, NodeOptions, SubsByDepth) -> - Stanza = event_stanza([#xmlel{name = <<"create">>, attrs = nodeAttr(Node)}]), + Stanza = #message{sub_els = [#ps_event{create = Node}]}, broadcast_stanza(Host, Node, Nidx, Type, NodeOptions, SubsByDepth, nodes, Stanza, true), {result, true}. @@ -3291,13 +2969,15 @@ broadcast_config_notification(Host, Node, Nidx, Type, NodeOptions, Lang) -> SubsByDepth when is_list(SubsByDepth) -> Content = case get_option(NodeOptions, deliver_payloads) of true -> - [#xmlel{name = <<"x">>, attrs = [{<<"xmlns">>, ?NS_XDATA}, {<<"type">>, <<"result">>}], - children = get_configure_xfields(Type, NodeOptions, Lang, [])}]; + #xdata{type = result, + fields = get_configure_xfields( + Type, NodeOptions, Lang, [])}; false -> - [] + undefined end, - Stanza = event_stanza( - [#xmlel{name = <<"configuration">>, attrs = nodeAttr(Node), children = Content}]), + Stanza = #message{ + sub_els = [#ps_event{ + configuration = {Node, Content}}]}, broadcast_stanza(Host, Node, Nidx, Type, NodeOptions, SubsByDepth, nodes, Stanza, false), {result, true}; @@ -3389,8 +3069,9 @@ broadcast_stanza({LUser, LServer, LResource}, Publisher, Node, Nidx, Type, NodeO ejabberd_c2s:broadcast(C2SPid, {pep_message, <<((Node))/binary, "+notify">>}, _Sender = jid:make(LUser, LServer, <<"">>), - _StanzaToSend = add_extended_headers(Stanza, - _ReplyTo = extended_headers([jid:to_string(Publisher)]))); + _StanzaToSend = add_extended_headers( + Stanza, + _ReplyTo = extended_headers([Publisher]))); _ -> ?DEBUG("~p@~p has no session; can't deliver ~p to contacts", [LUser, LServer, BaseStanza]) end; @@ -3456,9 +3137,11 @@ subscribed_nodes_by_jid(NotifyType, SubsByDepth) -> {_, JIDSubs} = lists:foldl(DepthsToDeliver, {[], []}, SubsByDepth), JIDSubs. +-spec user_resources(binary(), binary()) -> [binary()]. user_resources(User, Server) -> ejabberd_sm:get_user_resources(User, Server). +-spec user_resource(binary(), binary(), binary()) -> binary(). user_resource(User, Server, <<>>) -> case user_resources(User, Server) of [R | _] -> R; @@ -3468,26 +3151,19 @@ user_resource(_, _, Resource) -> Resource. %%%%%%% Configuration handling - +-spec get_configure(host(), binary(), binary(), jid(), + binary()) -> {error, error()} | {result, pubsub()}. get_configure(Host, ServerHost, Node, From, Lang) -> Action = fun (#pubsub_node{options = Options, type = Type, id = Nidx}) -> case node_call(Host, Type, get_affiliation, [Nidx, From]) of {result, owner} -> Groups = ejabberd_hooks:run_fold(roster_groups, ServerHost, [], [ServerHost]), - {result, - [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB_OWNER}], - children = - [#xmlel{name = <<"configure">>, - attrs = nodeAttr(Node), - children = - [#xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_XDATA}, - {<<"type">>, <<"form">>}], - children = - get_configure_xfields(Type, Options, Lang, Groups)}]}]}]}; + Fs = get_configure_xfields(Type, Options, Lang, Groups), + {result, #pubsub_owner{ + configure = + {Node, #xdata{type = form, fields = Fs}}}}; _ -> - {error, ?ERRT_FORBIDDEN(Lang, <<"You're not an owner">>)} + {error, xmpp:err_forbidden(<<"Owner privileges required">>, Lang)} end end, case transaction(Host, Node, Action, sync_dirty) of @@ -3495,20 +3171,14 @@ get_configure(Host, ServerHost, Node, From, Lang) -> Other -> Other end. +-spec get_default(host(), binary(), jid(), binary()) -> {result, pubsub()}. get_default(Host, Node, _From, Lang) -> Type = select_type(Host, Host, Node), Options = node_options(Host, Type), - {result, - [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB_OWNER}], - children = - [#xmlel{name = <<"default">>, attrs = [], - children = - [#xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_XDATA}, - {<<"type">>, <<"form">>}], - children = get_configure_xfields(Type, Options, Lang, [])}]}]}]}. + Fs = get_configure_xfields(Type, Options, Lang, []), + {result, #pubsub_owner{default = {<<>>, #xdata{type = form, fields = Fs}}}}. +-spec match_option(#pubsub_node{} | [{atom(), any()}], atom(), any()) -> boolean(). match_option(Node, Var, Val) when is_record(Node, pubsub_node) -> match_option(Node#pubsub_node.options, Var, Val); match_option(Options, Var, Val) when is_list(Options) -> @@ -3516,21 +3186,26 @@ match_option(Options, Var, Val) when is_list(Options) -> match_option(_, _, _) -> false. +-spec get_option([{atom(), any()}], atom()) -> any(). get_option([], _) -> false; get_option(Options, Var) -> get_option(Options, Var, false). +-spec get_option([{atom(), any()}], atom(), any()) -> any(). get_option(Options, Var, Def) -> case lists:keysearch(Var, 1, Options) of {value, {_Val, Ret}} -> Ret; _ -> Def end. +-spec node_options(host(), binary()) -> [{atom(), any()}]. node_options(Host, Type) -> case config(Host, default_node_config) of undefined -> node_plugin_options(Host, Type); [] -> node_plugin_options(Host, Type); Config -> Config end. + +-spec node_plugin_options(host(), binary()) -> [{atom(), any()}]. node_plugin_options(Host, Type) -> Module = plugin(Host, Type), case catch Module:options() of @@ -3540,12 +3215,15 @@ node_plugin_options(Host, Type) -> Result -> Result end. + +-spec filter_node_options([{atom(), any()}], [{atom(), any()}]) -> [{atom(), any()}]. filter_node_options(Options, BaseOptions) -> lists:foldl(fun({Key, Val}, Acc) -> DefaultValue = proplists:get_value(Key, Options, Val), [{Key, DefaultValue}|Acc] end, [], BaseOptions). +-spec node_owners_action(host(), binary(), nodeIdx(), [ljid()]) -> [ljid()]. node_owners_action(Host, Type, Nidx, []) -> case gen_mod:db_type(serverhost(Host), ?MODULE) of sql -> @@ -3559,6 +3237,7 @@ node_owners_action(Host, Type, Nidx, []) -> node_owners_action(_Host, _Type, _Nidx, Owners) -> Owners. +-spec node_owners_call(host(), binary(), nodeIdx(), [ljid()]) -> [ljid()]. node_owners_call(Host, Type, Nidx, []) -> case gen_mod:db_type(serverhost(Host), ?MODULE) of sql -> @@ -3583,6 +3262,7 @@ node_owners_call(_Host, _Type, _Nidx, Owners) -> %% @todo In practice, the current data structure means that we cannot manage %% millions of items on a given node. This should be addressed in a new %% version. +-spec max_items(host(), [{atom(), any()}]) -> non_neg_integer(). max_items(Host, Options) -> case get_option(Options, persist_items) of true -> @@ -3625,10 +3305,10 @@ max_items(Host, Options) -> [jid:to_string(O) || O <- Opts])). -define(ALIST_CONFIG_FIELD(Label, Var, Opts), - ?LISTXFIELD(Label, - <<"pubsub#", (atom_to_binary(Var, latin1))/binary>>, - (atom_to_binary(get_option(Options, Var), latin1)), - [atom_to_binary(O, latin1) || O <- Opts])). + ?LISTXFIELD(Label, + <<"pubsub#", (atom_to_binary(Var, latin1))/binary>>, + (atom_to_binary(get_option(Options, Var), latin1)), + [atom_to_binary(O, latin1) || O <- Opts])). -define(LISTM_CONFIG_FIELD(Label, Var, Opts), ?LISTMXFIELD(Label, @@ -3641,45 +3321,45 @@ max_items(Host, Options) -> get_option(Options, Var, []))). get_configure_xfields(_Type, Options, Lang, Groups) -> - [?XFIELD(<<"hidden">>, <<>>, <<"FORM_TYPE">>, (?NS_PUBSUB_NODE_CONFIG)), - ?BOOL_CONFIG_FIELD(<<"Deliver payloads with event notifications">>, - deliver_payloads), - ?BOOL_CONFIG_FIELD(<<"Deliver event notifications">>, - deliver_notifications), - ?BOOL_CONFIG_FIELD(<<"Notify subscribers when the node configuration changes">>, - notify_config), - ?BOOL_CONFIG_FIELD(<<"Notify subscribers when the node is deleted">>, - notify_delete), - ?BOOL_CONFIG_FIELD(<<"Notify subscribers when items are removed from the node">>, - notify_retract), - ?BOOL_CONFIG_FIELD(<<"Persist items to storage">>, - persist_items), - ?STRING_CONFIG_FIELD(<<"A friendly name for the node">>, - title), - ?INTEGER_CONFIG_FIELD(<<"Max # of items to persist">>, - max_items), - ?BOOL_CONFIG_FIELD(<<"Whether to allow subscriptions">>, - subscribe), - ?ALIST_CONFIG_FIELD(<<"Specify the access model">>, - access_model, [open, authorize, presence, roster, whitelist]), - ?LISTM_CONFIG_FIELD(<<"Roster groups allowed to subscribe">>, - roster_groups_allowed, Groups), - ?ALIST_CONFIG_FIELD(<<"Specify the publisher model">>, - publish_model, [publishers, subscribers, open]), - ?BOOL_CONFIG_FIELD(<<"Purge all items when the relevant publisher goes offline">>, - purge_offline), - ?ALIST_CONFIG_FIELD(<<"Specify the event message type">>, - notification_type, [headline, normal]), - ?INTEGER_CONFIG_FIELD(<<"Max payload size in bytes">>, - max_payload_size), - ?ALIST_CONFIG_FIELD(<<"When to send the last published item">>, - send_last_published_item, [never, on_sub, on_sub_and_presence]), - ?BOOL_CONFIG_FIELD(<<"Only deliver notifications to available users">>, - presence_based_delivery), - ?NLIST_CONFIG_FIELD(<<"The collections with which a node is affiliated">>, - collection), - ?ALIST_CONFIG_FIELD(<<"Whether owners or publisher should receive replies to items">>, - itemreply, [none, owner, publisher])]. + [?XFIELD(hidden, <<>>, <<"FORM_TYPE">>, ?NS_PUBSUB_NODE_CONFIG), + ?BOOL_CONFIG_FIELD(<<"Deliver payloads with event notifications">>, + deliver_payloads), + ?BOOL_CONFIG_FIELD(<<"Deliver event notifications">>, + deliver_notifications), + ?BOOL_CONFIG_FIELD(<<"Notify subscribers when the node configuration changes">>, + notify_config), + ?BOOL_CONFIG_FIELD(<<"Notify subscribers when the node is deleted">>, + notify_delete), + ?BOOL_CONFIG_FIELD(<<"Notify subscribers when items are removed from the node">>, + notify_retract), + ?BOOL_CONFIG_FIELD(<<"Persist items to storage">>, + persist_items), + ?STRING_CONFIG_FIELD(<<"A friendly name for the node">>, + title), + ?INTEGER_CONFIG_FIELD(<<"Max # of items to persist">>, + max_items), + ?BOOL_CONFIG_FIELD(<<"Whether to allow subscriptions">>, + subscribe), + ?ALIST_CONFIG_FIELD(<<"Specify the access model">>, + access_model, [open, authorize, presence, roster, whitelist]), + ?LISTM_CONFIG_FIELD(<<"Roster groups allowed to subscribe">>, + roster_groups_allowed, Groups), + ?ALIST_CONFIG_FIELD(<<"Specify the publisher model">>, + publish_model, [publishers, subscribers, open]), + ?BOOL_CONFIG_FIELD(<<"Purge all items when the relevant publisher goes offline">>, + purge_offline), + ?ALIST_CONFIG_FIELD(<<"Specify the event message type">>, + notification_type, [headline, normal]), + ?INTEGER_CONFIG_FIELD(<<"Max payload size in bytes">>, + max_payload_size), + ?ALIST_CONFIG_FIELD(<<"When to send the last published item">>, + send_last_published_item, [never, on_sub, on_sub_and_presence]), + ?BOOL_CONFIG_FIELD(<<"Only deliver notifications to available users">>, + presence_based_delivery), + ?NLIST_CONFIG_FIELD(<<"The collections with which a node is affiliated">>, + collection), + ?ALIST_CONFIG_FIELD(<<"Whether owners or publisher should receive replies to items">>, + itemreply, [none, owner, publisher])]. %%

    There are several reasons why the node configuration request might fail:

    %%
      @@ -3689,65 +3369,49 @@ get_configure_xfields(_Type, Options, Lang, Groups) -> %%
    • The node has no configuration options.
    • %%
    • The specified node does not exist.
    • %%
    -set_configure(Host, Node, From, Els, Lang) -> - case fxml:remove_cdata(Els) of - [#xmlel{name = <<"x">>} = XEl] -> - case {fxml:get_tag_attr_s(<<"xmlns">>, XEl), fxml:get_tag_attr_s(<<"type">>, XEl)} of - {?NS_XDATA, <<"cancel">>} -> - {result, []}; - {?NS_XDATA, <<"submit">>} -> - Action = fun (#pubsub_node{options = Options, type = Type, id = Nidx} = N) -> - case node_call(Host, Type, get_affiliation, [Nidx, From]) of - {result, owner} -> - case jlib:parse_xdata_submit(XEl) of - invalid -> - Txt = <<"Incorrect data form">>, - {error, ?ERRT_BAD_REQUEST(Lang, Txt)}; - XData -> - OldOpts = case Options of - [] -> node_options(Host, Type); - _ -> Options - end, - case set_xoption(Host, XData, OldOpts) of - NewOpts when is_list(NewOpts) -> - case tree_call(Host, - set_node, - [N#pubsub_node{options = NewOpts}]) - of - {result, Nidx} -> {result, ok}; - ok -> {result, ok}; - Err -> Err - end; - Error -> - Error - end - end; - _ -> - Txt = <<"You're not an owner">>, - {error, ?ERRT_FORBIDDEN(Lang, Txt)} - end - end, - case transaction(Host, Node, Action, transaction) of - {result, {TNode, ok}} -> - Nidx = TNode#pubsub_node.id, - Type = TNode#pubsub_node.type, - Options = TNode#pubsub_node.options, - broadcast_config_notification(Host, Node, Nidx, Type, Options, Lang), - {result, []}; - Other -> - Other - end; - _ -> - Txt = <<"Incorrect data form">>, - {error, ?ERRT_BAD_REQUEST(Lang, Txt)} - end; - _ -> - Txt = <<"No data form found">>, - {error, ?ERRT_BAD_REQUEST(Lang, Txt)} +-spec set_configure(host(), binary(), jid(), [{binary(), [binary()]}], + binary()) -> {result, undefined} | {error, error()}. +set_configure(Host, Node, From, Config, Lang) -> + Action = + fun(#pubsub_node{options = Options, type = Type, id = Nidx} = N) -> + case node_call(Host, Type, get_affiliation, [Nidx, From]) of + {result, owner} -> + OldOpts = case Options of + [] -> node_options(Host, Type); + _ -> Options + end, + case set_xoption(Host, Config, OldOpts) of + NewOpts when is_list(NewOpts) -> + case tree_call(Host, + set_node, + [N#pubsub_node{options = NewOpts}]) + of + {result, Nidx} -> {result, ok}; + ok -> {result, ok}; + Err -> Err + end; + Error -> + Error + end; + _ -> + {error, xmpp:err_forbidden( + <<"Owner privileges required">>, Lang)} + end + end, + case transaction(Host, Node, Action, transaction) of + {result, {TNode, ok}} -> + Nidx = TNode#pubsub_node.id, + Type = TNode#pubsub_node.type, + Options = TNode#pubsub_node.options, + broadcast_config_notification(Host, Node, Nidx, Type, Options, Lang), + {result, undefined}; + Other -> + Other end. +-spec add_opt(atom(), any(), [{atom(), any()}]) -> [{atom(), any()}]. add_opt(Key, Value, Opts) -> - [{Key, Value} | lists:keydelete(Key, 1, Opts)]. + lists:keystore(Key, 1, Opts, {Key, Value}). -define(SET_BOOL_XOPT(Opt, Val), BoolVal = case Val of @@ -3761,7 +3425,7 @@ add_opt(Key, Value, Opts) -> error -> Txt = <<"Value of '~s' should be boolean">>, ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), - {error, ?ERRT_NOT_ACCEPTABLE(?MYLANG, ErrTxt)}; + {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)}; _ -> set_xoption(Host, Opts, add_opt(Opt, BoolVal, NewOpts)) end). @@ -3769,20 +3433,20 @@ add_opt(Key, Value, Opts) -> set_xoption(Host, Opts, add_opt(Opt, Val, NewOpts))). -define(SET_INTEGER_XOPT(Opt, Val, Min, Max), - case catch jlib:binary_to_integer(Val) of - IVal when is_integer(IVal), IVal >= Min -> - if (Max =:= undefined) orelse (IVal =< Max) -> - set_xoption(Host, Opts, add_opt(Opt, IVal, NewOpts)); - true -> - Txt = <<"Incorrect value of '~s'">>, + case catch jlib:binary_to_integer(Val) of + IVal when is_integer(IVal), IVal >= Min -> + if (Max =:= undefined) orelse (IVal =< Max) -> + set_xoption(Host, Opts, add_opt(Opt, IVal, NewOpts)); + true -> + Txt = <<"Incorrect value of '~s'">>, + ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), + {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} + end; + _ -> + Txt = <<"Value of '~s' should be integer">>, ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), - {error, ?ERRT_NOT_ACCEPTABLE(?MYLANG, ErrTxt)} - end; - _ -> - Txt = <<"Value of '~s' should be integer">>, - ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), - {error, ?ERRT_NOT_ACCEPTABLE(?MYLANG, ErrTxt)} - end). + {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} + end). -define(SET_ALIST_XOPT(Opt, Val, Vals), case lists:member(Val, [atom_to_binary(V, latin1) || V <- Vals]) of @@ -3791,12 +3455,13 @@ add_opt(Key, Value, Opts) -> false -> Txt = <<"Incorrect value of '~s'">>, ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), - {error, ?ERRT_NOT_ACCEPTABLE(?MYLANG, ErrTxt)} + {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} end). -define(SET_LIST_XOPT(Opt, Val), - set_xoption(Host, Opts, add_opt(Opt, Val, NewOpts))). + set_xoption(Host, Opts, add_opt(Opt, Val, NewOpts))). +-spec set_xoption(host(), [{binary(), [binary()]}], [{atom(), any()}]) -> [{atom(), any()}]. set_xoption(_Host, [], NewOpts) -> NewOpts; set_xoption(Host, [{<<"FORM_TYPE">>, _} | Opts], NewOpts) -> set_xoption(Host, Opts, NewOpts); @@ -3852,17 +3517,26 @@ set_xoption(Host, [{<<"pubsub#itemreply">>, [Val]} | Opts], NewOpts) -> set_xoption(Host, [_ | Opts], NewOpts) -> set_xoption(Host, Opts, NewOpts). +-spec get_xdata_fields(undefined | xdata()) -> [{binary(), [binary()]}]. +get_xdata_fields(undefined) -> + []; +get_xdata_fields(#xdata{fields = Fs}) -> + [{Var, Vals} || #xdata_field{var = Var, values = Vals} <- Fs]. + +-spec get_max_items_node(host()) -> undefined | non_neg_integer(). get_max_items_node(Host) -> config(Host, max_items_node, undefined). +-spec get_max_subscriptions_node(host()) -> undefined | non_neg_integer(). get_max_subscriptions_node(Host) -> config(Host, max_subscriptions_node, undefined). %%%% last item cache handling - +-spec is_last_item_cache_enabled(host()) -> boolean(). is_last_item_cache_enabled(Host) -> config(Host, last_item_cache, false). +-spec set_cached_item(host(), nodeIdx(), binary(), binary(), [xmlel()]) -> ok. set_cached_item({_, ServerHost, _}, Nidx, ItemId, Publisher, Payload) -> set_cached_item(ServerHost, Nidx, ItemId, Publisher, Payload); set_cached_item(Host, Nidx, ItemId, Publisher, Payload) -> @@ -3873,6 +3547,7 @@ set_cached_item(Host, Nidx, ItemId, Publisher, Payload) -> _ -> ok end. +-spec unset_cached_item(host(), nodeIdx()) -> ok. unset_cached_item({_, ServerHost, _}, Nidx) -> unset_cached_item(ServerHost, Nidx); unset_cached_item(Host, Nidx) -> @@ -3881,9 +3556,7 @@ unset_cached_item(Host, Nidx) -> _ -> ok end. --spec get_cached_item(Host :: mod_pubsub:host(), Nidx :: mod_pubsub:nodeIdx()) -> - undefined | mod_pubsub:pubsubItem(). - +-spec get_cached_item(host(), nodeIdx()) -> undefined | pubsubItem(). get_cached_item({_, ServerHost, _}, Nidx) -> get_cached_item(ServerHost, Nidx); get_cached_item(Host, Nidx) -> @@ -3904,21 +3577,24 @@ get_cached_item(Host, Nidx) -> end. %%%% plugin handling - +-spec host(binary()) -> binary(). host(ServerHost) -> config(ServerHost, host, <<"pubsub.", ServerHost/binary>>). +-spec serverhost(host()) -> binary(). serverhost({_U, ServerHost, _R})-> serverhost(ServerHost); serverhost(Host) -> ejabberd_router:host_of_route(Host). +-spec tree(host()) -> atom(). tree(Host) -> case config(Host, nodetree) of undefined -> tree(Host, ?STDTREE); Tree -> Tree end. +-spec tree(host(), binary() | atom()) -> atom(). tree(_Host, <<"virtual">>) -> nodetree_virtual; % special case, virtual does not use any backend tree(Host, Name) -> @@ -3928,6 +3604,7 @@ tree(Host, Name) -> _ -> Name end. +-spec plugin(host(), binary() | atom()) -> atom(). plugin(Host, Name) -> case gen_mod:db_type(serverhost(Host), ?MODULE) of mnesia -> jlib:binary_to_atom(<<"node_", Name/binary>>); @@ -3935,6 +3612,7 @@ plugin(Host, Name) -> _ -> Name end. +-spec plugins(host()) -> [binary()]. plugins(Host) -> case config(Host, plugins) of undefined -> [?STDNODE]; @@ -3942,6 +3620,9 @@ plugins(Host) -> Plugins -> Plugins end. +-spec subscription_plugin(host()) -> pubsub_subscription | + pubsub_subscription_sql | + none. subscription_plugin(Host) -> case gen_mod:db_type(serverhost(Host), ?MODULE) of mnesia -> pubsub_subscription; @@ -3949,9 +3630,11 @@ subscription_plugin(Host) -> _ -> none end. +-spec config(binary(), any()) -> any(). config(ServerHost, Key) -> config(ServerHost, Key, undefined). +-spec config(host(), any(), any()) -> any(). config({_User, Host, _Resource}, Key, Default) -> config(Host, Key, Default); config(ServerHost, Key, Default) -> @@ -3960,6 +3643,7 @@ config(ServerHost, Key, Default) -> _ -> Default end. +-spec select_type(binary(), host(), binary(), binary()) -> binary(). select_type(ServerHost, Host, Node, Type) -> SelectedType = case Host of {_User, _Server, _Resource} -> @@ -3976,6 +3660,7 @@ select_type(ServerHost, Host, Node, Type) -> false -> hd(ConfiguredTypes) end. +-spec select_type(binary(), host(), binary()) -> binary(). select_type(ServerHost, Host, Node) -> select_type(ServerHost, Host, Node, hd(plugins(Host))). @@ -4005,7 +3690,7 @@ features() -> % see plugin "subscribe", % REQUIRED % see plugin "subscription-options", % OPTIONAL % see plugin "subscription-notifications" % OPTIONAL - +-spec plugin_features(binary(), binary()) -> [binary()]. plugin_features(Host, Type) -> Module = plugin(Host, Type), case catch Module:features() of @@ -4013,6 +3698,7 @@ plugin_features(Host, Type) -> Result -> Result end. +-spec features(binary(), binary()) -> [binary()]. features(Host, <<>>) -> lists:usort(lists:foldl(fun (Plugin, Acc) -> Acc ++ plugin_features(Host, Plugin) @@ -4048,11 +3734,13 @@ tree_action(Host, Function, Args) -> Result; {aborted, Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]), - {error, ?ERR_INTERNAL_SERVER_ERROR} + ErrTxt = <<"Database failure">>, + {error, xmpp:err_internal_server_error(ErrTxt, ?MYLANG)} end; Other -> ?ERROR_MSG("unsupported backend: ~p~n", [Other]), - {error, ?ERR_INTERNAL_SERVER_ERROR} + ErrTxt = <<"Database failure">>, + {error, xmpp:err_internal_server_error(ErrTxt, ?MYLANG)} end. %% @doc

    node plugin call.

    @@ -4108,7 +3796,7 @@ transaction(Host, Fun, Trans) -> transaction_retry(Host, ServerHost, Fun, Trans, DBType, Retry). transaction_retry(_Host, _ServerHost, _Fun, _Trans, _DBType, 0) -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; + {error, xmpp:err_internal_server_error(<<"Database failure">>, ?MYLANG)}; transaction_retry(Host, ServerHost, Fun, Trans, DBType, Count) -> Res = case DBType of mnesia -> @@ -4133,75 +3821,126 @@ transaction_retry(Host, ServerHost, Fun, Trans, DBType, Count) -> {error, Error}; {aborted, Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]), - {error, ?ERR_INTERNAL_SERVER_ERROR}; + {error, xmpp:err_internal_server_error(<<"Database failure">>, ?MYLANG)}; {'EXIT', {timeout, _} = Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [Reason]), transaction_retry(Host, ServerHost, Fun, Trans, DBType, Count - 1); {'EXIT', Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]), - {error, ?ERR_INTERNAL_SERVER_ERROR}; + {error, xmpp:err_internal_server_error(<<"Database failure">>, ?MYLANG)}; Other -> ?ERROR_MSG("transaction return internal error: ~p~n", [Other]), - {error, ?ERR_INTERNAL_SERVER_ERROR} + {error, xmpp:err_internal_server_error(<<"Database failure">>, ?MYLANG)} end. %%%% helpers %% Add pubsub-specific error element -extended_error(Error, Ext) -> - extended_error(Error, Ext, [{<<"xmlns">>, ?NS_PUBSUB_ERRORS}]). +-spec extended_error(error(), ps_error()) -> error(). +extended_error(StanzaErr, PubSubErr) -> + StanzaErr#error{sub_els = [PubSubErr]}. -extended_error(Error, unsupported, Feature) -> - %% Give a uniq identifier - extended_error(Error, <<"unsupported">>, - [{<<"xmlns">>, ?NS_PUBSUB_ERRORS}, - {<<"feature">>, Feature}]); -extended_error(#xmlel{name = Error, attrs = Attrs, children = SubEls}, Ext, ExtAttrs) -> - #xmlel{name = Error, attrs = Attrs, - children = lists:reverse([#xmlel{name = Ext, attrs = ExtAttrs} | SubEls])}. +-spec err_closed_node() -> ps_error(). +err_closed_node() -> + #ps_error{type = 'closed-node'}. -is_item_not_found({error, ErrEl}) -> - case fxml:get_subtag_with_xmlns( - ErrEl, <<"item-not-found">>, ?NS_STANZAS) of - #xmlel{} -> true; - _ -> false - end. +-spec err_configuration_required() -> ps_error(). +err_configuration_required() -> + #ps_error{type = 'configuration-required'}. -string_to_ljid(JID) -> - case jid:from_string(JID) of - error -> - {<<>>, <<>>, <<>>}; - J -> - case jid:tolower(J) of - error -> {<<>>, <<>>, <<>>}; - J1 -> J1 - end - end. +-spec err_invalid_jid() -> ps_error(). +err_invalid_jid() -> + #ps_error{type = 'invalid-jid'}. + +-spec err_invalid_options() -> ps_error(). +err_invalid_options() -> + #ps_error{type = 'invalid-options'}. + +-spec err_invalid_payload() -> ps_error(). +err_invalid_payload() -> + #ps_error{type = 'invalid-payload'}. + +-spec err_invalid_subid() -> ps_error(). +err_invalid_subid() -> + #ps_error{type = 'invalid-subid'}. + +-spec err_item_forbidden() -> ps_error(). +err_item_forbidden() -> + #ps_error{type = 'item-forbidden'}. + +-spec err_item_required() -> ps_error(). +err_item_required() -> + #ps_error{type = 'item-required'}. + +-spec err_jid_required() -> ps_error(). +err_jid_required() -> + #ps_error{type = 'jid-required'}. + +-spec err_max_items_exceeded() -> ps_error(). +err_max_items_exceeded() -> + #ps_error{type = 'max-items-exceeded'}. + +-spec err_max_nodes_exceeded() -> ps_error(). +err_max_nodes_exceeded() -> + #ps_error{type = 'max-nodes-exceeded'}. + +-spec err_nodeid_required() -> ps_error(). +err_nodeid_required() -> + #ps_error{type = 'nodeid-required'}. + +-spec err_not_in_roster_group() -> ps_error(). +err_not_in_roster_group() -> + #ps_error{type = 'not-in-roster-group'}. + +-spec err_not_subscribed() -> ps_error(). +err_not_subscribed() -> + #ps_error{type = 'not-subscribed'}. + +-spec err_payload_too_big() -> ps_error(). +err_payload_too_big() -> + #ps_error{type = 'payload-too-big'}. + +-spec err_payload_required() -> ps_error(). +err_payload_required() -> + #ps_error{type = 'payload-required'}. + +-spec err_pending_subscription() -> ps_error(). +err_pending_subscription() -> + #ps_error{type = 'pending-subscription'}. + +-spec err_presence_subscription_required() -> ps_error(). +err_presence_subscription_required() -> + #ps_error{type = 'presence-subscription-required'}. + +-spec err_subid_required() -> ps_error(). +err_subid_required() -> + #ps_error{type = 'subid-required'}. + +-spec err_too_many_subscriptions() -> ps_error(). +err_too_many_subscriptions() -> + #ps_error{type = 'too-many-subscriptions'}. + +-spec err_unsupported(ps_error_feature()) -> ps_error(). +err_unsupported(Feature) -> + #ps_error{type = 'unsupported', feature = Feature}. + +-spec err_unsupported_access_model() -> ps_error(). +err_unsupported_access_model() -> + #ps_error{type = 'unsupported-access-model'}. -spec uniqid() -> mod_pubsub:itemId(). uniqid() -> {T1, T2, T3} = p1_time_compat:timestamp(), iolist_to_binary(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3])). -nodeAttr(Node) -> [{<<"node">>, Node}]. - -itemAttr([]) -> []; -itemAttr(ItemId) -> [{<<"id">>, ItemId}]. -itemAttr(ItemId, From) -> [{<<"id">>, ItemId}, From]. - +-spec itemsEls([#pubsub_item{}]) -> [ps_item()]. itemsEls(Items) -> - [#xmlel{name = <<"item">>, attrs = itemAttr(ItemId), children = Payload} - || #pubsub_item{itemid = {ItemId, _}, payload = Payload} <- Items]. + [#ps_item{id = ItemId, xml_els = Payload} + || #pubsub_item{itemid = {ItemId, _}, payload = Payload} <- Items]. --spec add_message_type(Message :: xmlel(), Type :: atom()) -> xmlel(). - -add_message_type(Message, normal) -> Message; -add_message_type(#xmlel{name = <<"message">>, attrs = Attrs, children = Els}, Type) -> - #xmlel{name = <<"message">>, - attrs = [{<<"type">>, jlib:atom_to_binary(Type)} | Attrs], - children = Els}; -add_message_type(XmlEl, _Type) -> - XmlEl. +-spec add_message_type(message(), message_type()) -> message(). +add_message_type(#message{} = Message, Type) -> + Message#message{type = Type}. %% Place of changed at the bottom of the stanza %% cf. http://xmpp.org/extensions/xep-0060.html#publisher-publish-success-subid @@ -4209,32 +3948,24 @@ add_message_type(XmlEl, _Type) -> %% "[SHIM Headers] SHOULD be included after the event notification information %% (i.e., as the last child of the stanza)". -add_shim_headers(Stanza, HeaderEls) -> - add_headers(Stanza, <<"headers">>, ?NS_SHIM, HeaderEls). +-spec add_shim_headers(stanza(), [{binary(), binary()}]) -> stanza(). +add_shim_headers(Stanza, Headers) -> + xmpp:set_subtag(Stanza, #shim{headers = Headers}). -add_extended_headers(Stanza, HeaderEls) -> - add_headers(Stanza, <<"addresses">>, ?NS_ADDRESS, HeaderEls). - -add_headers(#xmlel{name = Name, attrs = Attrs, children = Els}, HeaderName, HeaderNS, HeaderEls) -> - HeaderEl = #xmlel{name = HeaderName, - attrs = [{<<"xmlns">>, HeaderNS}], - children = HeaderEls}, - #xmlel{name = Name, attrs = Attrs, - children = lists:append(Els, [HeaderEl])}. +-spec add_extended_headers(stanza(), [address()]) -> stanza(). +add_extended_headers(Stanza, Addrs) -> + xmpp:set_subtag(Stanza, #addresses{list = Addrs}). +-spec subid_shim([binary()]) -> [{binary(), binary()}]. subid_shim(SubIds) -> - [#xmlel{name = <<"header">>, - attrs = [{<<"name">>, <<"SubId">>}], - children = [{xmlcdata, SubId}]} - || SubId <- SubIds]. + [{<<"SubId">>, SubId} || SubId <- SubIds]. %% The argument is a list of Jids because this function could be used %% with the 'pubsub#replyto' (type=jid-multi) node configuration. +-spec extended_headers([jid()]) -> [address()]. extended_headers(Jids) -> - [#xmlel{name = <<"address">>, - attrs = [{<<"type">>, <<"replyto">>}, {<<"jid">>, Jid}]} - || Jid <- Jids]. + [#address{type = replyto, jid = Jid} || Jid <- Jids]. -spec on_user_offline(ejabberd_sm:sid(), jid(), ejabberd_sm:info()) -> ok. on_user_offline(_, JID, _) -> @@ -4244,6 +3975,7 @@ on_user_offline(_, JID, _) -> _ -> ok end. +-spec purge_offline(ljid()) -> ok. purge_offline(LJID) -> Host = host(element(2, LJID)), Plugins = plugins(Host), @@ -4251,8 +3983,8 @@ purge_offline(LJID) -> Features = plugin_features(Host, Type), case lists:member(<<"retrieve-affiliations">>, plugin_features(Host, Type)) of false -> - {{error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, - unsupported, <<"retrieve-affiliations">>)}, + {{error, extended_error(xmpp:err_feature_not_implemented(), + err_unsupported('retrieve-affiliations'))}, Acc}; true -> Items = lists:member(<<"retract-items">>, Features) @@ -4286,6 +4018,7 @@ purge_offline(LJID) -> ?DEBUG("on_user_offline ~p", [Error]) end. +-spec purge_offline(host(), ljid(), binary()) -> ok | {error, error()}. purge_offline(Host, LJID, Node) -> Nidx = Node#pubsub_node.id, Type = Node#pubsub_node.type, diff --git a/src/node_flat_sql.erl b/src/node_flat_sql.erl index fa4af4d57..2a468c69a 100644 --- a/src/node_flat_sql.erl +++ b/src/node_flat_sql.erl @@ -36,7 +36,7 @@ -compile([{parse_transform, ejabberd_sql_pt}]). -include("pubsub.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("ejabberd_sql_pt.hrl"). -export([init/3, terminate/2, options/0, features/0, @@ -81,27 +81,27 @@ create_node(Nidx, Owner) -> J = encode_jid(OwnerKey), A = encode_affiliation(owner), S = encode_subscriptions([]), - catch ejabberd_sql:sql_query_t( - ?SQL("insert into pubsub_state(" - "nodeid, jid, affiliation, subscriptions) " - "values (%(Nidx)d, %(J)s, %(A)s, %(S)s)")), + ejabberd_sql:sql_query_t( + ?SQL("insert into pubsub_state(" + "nodeid, jid, affiliation, subscriptions) " + "values (%(Nidx)d, %(J)s, %(A)s, %(S)s)")), {result, {default, broadcast}}. delete_node(Nodes) -> - Reply = lists:map(fun (#pubsub_node{id = Nidx} = PubsubNode) -> - Subscriptions = case catch - ejabberd_sql:sql_query_t( - ?SQL("select @(jid)s, @(subscriptions)s " - "from pubsub_state where nodeid=%(Nidx)d")) - of - {selected, RItems} -> - [{decode_jid(SJID), decode_subscriptions(Subs)} || - {SJID, Subs} <- RItems]; - _ -> - [] - end, - {PubsubNode, Subscriptions} - end, Nodes), + Reply = lists:map( + fun(#pubsub_node{id = Nidx} = PubsubNode) -> + Subscriptions = + case ejabberd_sql:sql_query_t( + ?SQL("select @(jid)s, @(subscriptions)s " + "from pubsub_state where nodeid=%(Nidx)d")) of + {selected, RItems} -> + [{decode_jid(SJID), decode_subscriptions(Subs)} + || {SJID, Subs} <- RItems]; + _ -> + [] + end, + {PubsubNode, Subscriptions} + end, Nodes), {result, {default, broadcast, Reply}}. subscribe_node(Nidx, Sender, Subscriber, AccessModel, @@ -118,22 +118,25 @@ subscribe_node(Nidx, Sender, Subscriber, AccessModel, Subscriptions), Owner = Affiliation == owner, if not Authorized -> - {error, - ?ERR_EXTENDED((?ERR_BAD_REQUEST), <<"invalid-jid">>)}; + {error, mod_pubsub:extended_error( + xmpp:err_bad_request(), mod_pubsub:err_invalid_jid())}; (Affiliation == outcast) or (Affiliation == publish_only) -> - {error, ?ERR_FORBIDDEN}; + {error, xmpp:err_forbidden()}; PendingSubscription -> - {error, - ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"pending-subscription">>)}; + {error, mod_pubsub:extended_error( + xmpp:err_not_authorized(), + mod_pubsub:err_pending_subscription())}; (AccessModel == presence) and (not PresenceSubscription) and (not Owner) -> - {error, - ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"presence-subscription-required">>)}; + {error, mod_pubsub:extended_error( + xmpp:err_not_authorized(), + mod_pubsub:err_presence_subscription_required())}; (AccessModel == roster) and (not RosterGroup) and (not Owner) -> - {error, - ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"not-in-roster-group">>)}; + {error, mod_pubsub:extended_error( + xmpp:err_not_authorized(), + mod_pubsub:err_not_in_roster_group())}; (AccessModel == whitelist) and (not Whitelisted) and (not Owner) -> - {error, - ?ERR_EXTENDED((?ERR_NOT_ALLOWED), <<"closed-node">>)}; + {error, mod_pubsub:extended_error( + xmpp:err_not_allowed(), mod_pubsub:err_closed_node())}; %%MustPay -> %% % Payment is required for a subscription %% {error, ?ERR_PAYMENT_REQUIRED}; @@ -177,7 +180,7 @@ unsubscribe_node(Nidx, Sender, Subscriber, SubId) -> if %% Requesting entity is prohibited from unsubscribing entity not Authorized -> - {error, ?ERR_FORBIDDEN}; + {error, xmpp:err_forbidden()}; %% Entity did not specify SubId %%SubId == "", ?? -> %% {error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")}; @@ -186,8 +189,9 @@ unsubscribe_node(Nidx, Sender, Subscriber, SubId) -> %% {error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")}; %% Requesting entity is not a subscriber Subscriptions == [] -> - {error, - ?ERR_EXTENDED((?ERR_UNEXPECTED_REQUEST_CANCEL), <<"not-subscribed">>)}; + {error, mod_pubsub:extended_error( + xmpp:err_unexpected_request(), + mod_pubsub:err_not_subscribed())}; %% Subid supplied, so use that. SubIdExists -> Sub = first_in_list(fun @@ -200,8 +204,9 @@ unsubscribe_node(Nidx, Sender, Subscriber, SubId) -> delete_subscription(SubKey, Nidx, S, Affiliation, Subscriptions), {result, default}; false -> - {error, - ?ERR_EXTENDED((?ERR_UNEXPECTED_REQUEST_CANCEL), <<"not-subscribed">>)} + {error, mod_pubsub:extended_error( + xmpp:err_unexpected_request(), + mod_pubsub:err_not_subscribed())} end; %% Asking to remove all subscriptions to the given node SubId == all -> @@ -214,8 +219,8 @@ unsubscribe_node(Nidx, Sender, Subscriber, SubId) -> {result, default}; %% No subid and more than one possible subscription match. true -> - {error, - ?ERR_EXTENDED((?ERR_BAD_REQUEST), <<"subid-required">>)} + {error, mod_pubsub:extended_error( + xmpp:err_bad_request(), mod_pubsub:err_subid_required())} end. delete_subscription(SubKey, Nidx, {Subscription, SubId}, Affiliation, Subscriptions) -> @@ -241,7 +246,7 @@ publish_item(Nidx, Publisher, PublishModel, MaxItems, ItemId, Payload, or (Affiliation == publisher) or (Affiliation == publish_only)) or (Subscribed == true)) -> - {error, ?ERR_FORBIDDEN}; + {error, xmpp:err_forbidden()}; true -> if MaxItems > 0 -> PubId = {p1_time_compat:timestamp(), SubKey}, @@ -277,11 +282,11 @@ delete_item(Nidx, Publisher, PublishModel, ItemId) -> _ -> false end, if not Allowed -> - {error, ?ERR_FORBIDDEN}; + {error, xmpp:err_forbidden()}; true -> case del_item(Nidx, ItemId) of {updated, 1} -> {result, {default, broadcast}}; - _ -> {error, ?ERR_ITEM_NOT_FOUND} + _ -> {error, xmpp:err_item_not_found()} end end. @@ -299,7 +304,7 @@ purge_node(Nidx, Owner) -> States), {result, {default, broadcast}}; _ -> - {error, ?ERR_FORBIDDEN} + {error, xmpp:err_forbidden()} end. get_entity_affiliations(Host, Owner) -> @@ -307,48 +312,42 @@ get_entity_affiliations(Host, Owner) -> GenKey = jid:remove_resource(SubKey), H = encode_host(Host), J = encode_jid(GenKey), - Reply = case catch - ejabberd_sql:sql_query_t( - ?SQL("select @(node)s, @(type)s, @(i.nodeid)d, @(affiliation)s " - "from pubsub_state i, pubsub_node n where " - "i.nodeid = n.nodeid and jid=%(J)s and host=%(H)s")) - of - {selected, RItems} -> - [{nodetree_tree_sql:raw_to_node(Host, {N, <<"">>, T, I}), decode_affiliation(A)} - || {N, T, I, A} <- RItems]; - _ -> - [] - end, - {result, Reply}. + {result, + case ejabberd_sql:sql_query_t( + ?SQL("select @(node)s, @(type)s, @(i.nodeid)d, @(affiliation)s " + "from pubsub_state i, pubsub_node n where " + "i.nodeid = n.nodeid and jid=%(J)s and host=%(H)s")) of + {selected, RItems} -> + [{nodetree_tree_sql:raw_to_node(Host, {N, <<"">>, T, I}), + decode_affiliation(A)} || {N, T, I, A} <- RItems]; + _ -> + [] + end}. get_node_affiliations(Nidx) -> - Reply = case catch - ejabberd_sql:sql_query_t( - ?SQL("select @(jid)s, @(affiliation)s from pubsub_state " - "where nodeid=%(Nidx)d")) - of - {selected, RItems} -> - [{decode_jid(J), decode_affiliation(A)} || {J, A} <- RItems]; - _ -> - [] - end, - {result, Reply}. + {result, + case ejabberd_sql:sql_query_t( + ?SQL("select @(jid)s, @(affiliation)s from pubsub_state " + "where nodeid=%(Nidx)d")) of + {selected, RItems} -> + [{decode_jid(J), decode_affiliation(A)} || {J, A} <- RItems]; + _ -> + [] + end}. get_affiliation(Nidx, Owner) -> SubKey = jid:tolower(Owner), GenKey = jid:remove_resource(SubKey), J = encode_jid(GenKey), - Reply = case catch - ejabberd_sql:sql_query_t( - ?SQL("select @(affiliation)s from pubsub_state " - "where nodeid=%(Nidx)d and jid=%(J)s")) - of - {selected, [{A}]} -> - decode_affiliation(A); - _ -> - none - end, - {result, Reply}. + {result, + case ejabberd_sql:sql_query_t( + ?SQL("select @(affiliation)s from pubsub_state " + "where nodeid=%(Nidx)d and jid=%(J)s")) of + {selected, [{A}]} -> + decode_affiliation(A); + _ -> + none + end}. set_affiliation(Nidx, Owner, Affiliation) -> SubKey = jid:tolower(Owner), @@ -382,26 +381,26 @@ get_entity_subscriptions(Host, Owner) -> "where i.nodeid = n.nodeid and" " jid in (%(SJ)s, %(GJ)s) and host=%(H)s") end, - Reply = case catch ejabberd_sql:sql_query_t(Query) of - {selected, RItems} -> - lists:foldl(fun ({N, T, I, J, S}, Acc) -> - Node = nodetree_tree_sql:raw_to_node(Host, {N, <<"">>, T, I}), - Jid = decode_jid(J), - case decode_subscriptions(S) of - [] -> - [{Node, none, Jid} | Acc]; - Subs -> - lists:foldl(fun ({Sub, SubId}, Acc2) -> - [{Node, Sub, SubId, Jid} | Acc2] - end, - Acc, Subs) - end - end, - [], RItems); - _ -> - [] - end, - {result, Reply}. + {result, + case ejabberd_sql:sql_query_t(Query) of + {selected, RItems} -> + lists:foldl( + fun({N, T, I, J, S}, Acc) -> + Node = nodetree_tree_sql:raw_to_node(Host, {N, <<"">>, T, I}), + Jid = decode_jid(J), + case decode_subscriptions(S) of + [] -> + [{Node, none, Jid} | Acc]; + Subs -> + lists:foldl( + fun({Sub, SubId}, Acc2) -> + [{Node, Sub, SubId, Jid} | Acc2] + end, Acc, Subs) + end + end, [], RItems); + _ -> + [] + end}. -spec get_entity_subscriptions_for_send_last(Host :: mod_pubsub:hostPubsub(), Owner :: jid()) -> @@ -435,66 +434,62 @@ get_entity_subscriptions_for_send_last(Host, Owner) -> "and val='on_sub_and_presence' and" " jid in (%(SJ)s, %(GJ)s) and host=%(H)s") end, - Reply = case catch ejabberd_sql:sql_query_t(Query) of - {selected, RItems} -> - lists:foldl(fun ({N, T, I, J, S}, Acc) -> - Node = nodetree_tree_sql:raw_to_node(Host, {N, <<"">>, T, I}), - Jid = decode_jid(J), - case decode_subscriptions(S) of - [] -> - [{Node, none, Jid} | Acc]; - Subs -> - lists:foldl(fun ({Sub, SubId}, Acc2) -> - [{Node, Sub, SubId, Jid}| Acc2] - end, - Acc, Subs) - end - end, - [], RItems); - _ -> - [] - end, - {result, Reply}. + {result, + case ejabberd_sql:sql_query_t(Query) of + {selected, RItems} -> + lists:foldl( + fun ({N, T, I, J, S}, Acc) -> + Node = nodetree_tree_sql:raw_to_node(Host, {N, <<"">>, T, I}), + Jid = decode_jid(J), + case decode_subscriptions(S) of + [] -> + [{Node, none, Jid} | Acc]; + Subs -> + lists:foldl( + fun ({Sub, SubId}, Acc2) -> + [{Node, Sub, SubId, Jid}| Acc2] + end, Acc, Subs) + end + end, [], RItems); + _ -> + [] + end}. get_node_subscriptions(Nidx) -> - Reply = case catch - ejabberd_sql:sql_query_t( - ?SQL("select @(jid)s, @(subscriptions)s from pubsub_state " - "where nodeid=%(Nidx)d")) - of - {selected, RItems} -> - lists:foldl(fun ({J, S}, Acc) -> - Jid = decode_jid(J), - case decode_subscriptions(S) of - [] -> - [{Jid, none} | Acc]; - Subs -> - lists:foldl(fun ({Sub, SubId}, Acc2) -> - [{Jid, Sub, SubId} | Acc2] - end, - Acc, Subs) - end - end, - [], RItems); - _ -> - [] - end, - {result, Reply}. + {result, + case ejabberd_sql:sql_query_t( + ?SQL("select @(jid)s, @(subscriptions)s from pubsub_state " + "where nodeid=%(Nidx)d")) of + {selected, RItems} -> + lists:foldl( + fun ({J, S}, Acc) -> + Jid = decode_jid(J), + case decode_subscriptions(S) of + [] -> + [{Jid, none} | Acc]; + Subs -> + lists:foldl( + fun ({Sub, SubId}, Acc2) -> + [{Jid, Sub, SubId} | Acc2] + end, Acc, Subs) + end + end, [], RItems); + _ -> + [] + end}. get_subscriptions(Nidx, Owner) -> SubKey = jid:tolower(Owner), J = encode_jid(SubKey), - Reply = case catch - ejabberd_sql:sql_query_t( - ?SQL("select @(subscriptions)s from pubsub_state" - " where nodeid=%(Nidx)d and jid=%(J)s")) - of - {selected, [{S}]} -> - decode_subscriptions(S); - _ -> - [] - end, - {result, Reply}. + {result, + case ejabberd_sql:sql_query_t( + ?SQL("select @(subscriptions)s from pubsub_state" + " where nodeid=%(Nidx)d and jid=%(J)s")) of + {selected, [{S}]} -> + decode_subscriptions(S); + _ -> + [] + end}. set_subscriptions(Nidx, Owner, Subscription, SubId) -> SubKey = jid:tolower(Owner), @@ -503,8 +498,9 @@ set_subscriptions(Nidx, Owner, Subscription, SubId) -> {_, []} -> case Subscription of none -> - {error, - ?ERR_EXTENDED((?ERR_BAD_REQUEST), <<"not-subscribed">>)}; + {error, mod_pubsub:extended_error( + xmpp:err_bad_request(), + mod_pubsub:err_not_subscribed())}; _ -> new_subscription(Nidx, Owner, Subscription, SubState) end; @@ -514,8 +510,9 @@ set_subscriptions(Nidx, Owner, Subscription, SubId) -> _ -> replace_subscription({Subscription, SID}, SubState) end; {<<>>, [_ | _]} -> - {error, - ?ERR_EXTENDED((?ERR_BAD_REQUEST), <<"subid-required">>)}; + {error, mod_pubsub:extended_error( + xmpp:err_bad_request(), + mod_pubsub:err_subid_required())}; _ -> case Subscription of none -> unsub_with_subid(Nidx, SubId, SubState); @@ -585,21 +582,19 @@ get_nodes_helper(NodeTree, #pubsub_state{stateid = {_, N}, subscriptions = Subs} end. get_states(Nidx) -> - case catch - ejabberd_sql:sql_query_t( - ?SQL("select @(jid)s, @(affiliation)s, @(subscriptions)s " - "from pubsub_state where nodeid=%(Nidx)d")) - of + case ejabberd_sql:sql_query_t( + ?SQL("select @(jid)s, @(affiliation)s, @(subscriptions)s " + "from pubsub_state where nodeid=%(Nidx)d")) of {selected, RItems} -> {result, - lists:map(fun ({SJID, Aff, Subs}) -> - JID = decode_jid(SJID), - #pubsub_state{stateid = {JID, Nidx}, - items = itemids(Nidx, JID), - affiliation = decode_affiliation(Aff), - subscriptions = decode_subscriptions(Subs)} - end, - RItems)}; + lists:map( + fun({SJID, Aff, Subs}) -> + JID = decode_jid(SJID), + #pubsub_state{stateid = {JID, Nidx}, + items = itemids(Nidx, JID), + affiliation = decode_affiliation(Aff), + subscriptions = decode_subscriptions(Subs)} + end, RItems)}; _ -> {result, []} end. @@ -614,16 +609,14 @@ get_state(Nidx, JID) -> get_state_without_itemids(Nidx, JID) -> J = encode_jid(JID), - case catch - ejabberd_sql:sql_query_t( - ?SQL("select @(jid)s, @(affiliation)s, @(subscriptions)s " - "from pubsub_state " - "where nodeid=%(Nidx)d and jid=%(J)s")) - of + case ejabberd_sql:sql_query_t( + ?SQL("select @(jid)s, @(affiliation)s, @(subscriptions)s " + "from pubsub_state " + "where nodeid=%(Nidx)d and jid=%(J)s")) of {selected, [{SJID, Aff, Subs}]} -> #pubsub_state{stateid = {decode_jid(SJID), Nidx}, - affiliation = decode_affiliation(Aff), - subscriptions = decode_subscriptions(Subs)}; + affiliation = decode_affiliation(Aff), + subscriptions = decode_subscriptions(Subs)}; _ -> #pubsub_state{stateid = {JID, Nidx}} end. @@ -653,73 +646,60 @@ del_state(Nidx, JID) -> " where jid=%(J)s and nodeid=%(Nidx)d")), ok. -%get_items(Nidx, _From) -> -% case catch -% ejabberd_sql:sql_query_t([<<"select itemid, publisher, creation, modification, payload " -% "from pubsub_item where nodeid='">>, Nidx, -% <<"' order by modification desc;">>]) -% of -% {selected, -% [<<"itemid">>, <<"publisher">>, <<"creation">>, <<"modification">>, <<"payload">>], RItems} -> -% {result, [raw_to_item(Nidx, RItem) || RItem <- RItems]}; -% _ -> -% {result, []} -% end. - -get_items(Nidx, From, none) -> - MaxItems = case catch - ejabberd_sql:sql_query_t( - ?SQL("select @(val)s from pubsub_node_option " - "where nodeid=%(Nidx)d and name='max_items'")) - of - {selected, [{Value}]} -> - jlib:expr_to_term(Value); - _ -> - ?MAXITEMS - end, - get_items(Nidx, From, #rsm_in{max = MaxItems}); -get_items(Nidx, _From, - #rsm_in{max = M, direction = Direction, id = I, index = IncIndex}) -> - Max = ejabberd_sql:escape(jlib:i2l(M)), - {Way, Order} = case Direction of - aft when I == <<>> -> {<<"is not">>, <<"desc">>}; - aft -> {<<"<">>, <<"desc">>}; - before when I == <<>> -> {<<"is not">>, <<"asc">>}; - before -> {<<">">>, <<"asc">>}; - _ -> {<<"is not">>, <<"desc">>} - end, +get_items(Nidx, From, undefined) -> + MaxItems = case ejabberd_sql:sql_query_t( + ?SQL("select @(val)s from pubsub_node_option " + "where nodeid=%(Nidx)d and name='max_items'")) of + {selected, [{Value}]} -> + jlib:expr_to_term(Value); + _ -> + ?MAXITEMS + end, + get_items(Nidx, From, #rsm_set{max = MaxItems}); +get_items(Nidx, _From, #rsm_set{max = Max, index = IncIndex, + 'after' = After, before = Before}) -> + {Way, Order} = if After == <<>> -> {<<"is not">>, <<"desc">>}; + After /= undefined -> {<<"<">>, <<"desc">>}; + Before == <<>> -> {<<"is not">>, <<"asc">>}; + Before /= undefined -> {<<">">>, <<"asc">>}; + true -> {<<"is not">>, <<"desc">>} + end, SNidx = integer_to_binary(Nidx), - [AttrName, Id] = case I of - undefined when IncIndex =/= undefined -> - case catch - ejabberd_sql:sql_query_t([<<"select modification from pubsub_item pi " - "where exists ( select count(*) as count1 " - "from pubsub_item where nodeid='">>, SNidx, + I = if After /= undefined -> After; + Before /= undefined -> Before; + true -> undefined + end, + [AttrName, Id] = + case I of + undefined when IncIndex =/= undefined -> + case ejabberd_sql:sql_query_t( + [<<"select modification from pubsub_item pi " + "where exists ( select count(*) as count1 " + "from pubsub_item where nodeid='">>, SNidx, <<"' and modification > pi.modification having count1 = ">>, - ejabberd_sql:escape(jlib:i2l(IncIndex)), <<" );">>]) - of - {selected, [_], [[O]]} -> - [<<"modification">>, <<"'", O/binary, "'">>]; - _ -> - [<<"modification">>, <<"null">>] - end; - undefined -> - [<<"modification">>, <<"null">>]; - <<>> -> - [<<"modification">>, <<"null">>]; - I -> - [A, B] = str:tokens(ejabberd_sql:escape(jlib:i2l(I)), <<"@">>), - [A, <<"'", B/binary, "'">>] - end, - Count = case catch - ejabberd_sql:sql_query_t([<<"select count(*) from pubsub_item where nodeid='">>, SNidx, <<"';">>]) - of - {selected, [_], [[C]]} -> C; - _ -> <<"0">> - end, + IncIndex, <<" );">>]) of + {selected, [_], [[O]]} -> + [<<"modification">>, <<"'", O/binary, "'">>]; + _ -> + [<<"modification">>, <<"null">>] + end; + undefined -> + [<<"modification">>, <<"null">>]; + <<>> -> + [<<"modification">>, <<"null">>]; + I -> + [A, B] = str:tokens(ejabberd_sql:escape(I), <<"@">>), + [A, <<"'", B/binary, "'">>] + end, + Count = case ejabberd_sql:sql_query_t( + [<<"select count(*) from pubsub_item where nodeid='">>, + SNidx, <<"';">>]) of + {selected, [_], [[C]]} -> binary_to_integer(C); + _ -> 0 + end, Query = fun(mssql, _) -> ejabberd_sql:sql_query_t( - [<<"select top ">>, jlib:i2l(Max), + [<<"select top ">>, Max, <<" itemid, publisher, creation, modification, payload " "from pubsub_item where nodeid='">>, SNidx, <<"' and ">>, AttrName, <<" ">>, Way, <<" ">>, Id, <<" order by ">>, @@ -729,32 +709,33 @@ get_items(Nidx, _From, [<<"select itemid, publisher, creation, modification, payload " "from pubsub_item where nodeid='">>, SNidx, <<"' and ">>, AttrName, <<" ">>, Way, <<" ">>, Id, <<" order by ">>, - AttrName, <<" ">>, Order, <<" limit ">>, jlib:i2l(Max), <<" ;">>]) + AttrName, <<" ">>, Order, <<" limit ">>, Max, <<" ;">>]) end, - case catch ejabberd_sql:sql_query_t(Query) of - {selected, - [<<"itemid">>, <<"publisher">>, <<"creation">>, <<"modification">>, <<"payload">>], RItems} -> + case ejabberd_sql:sql_query_t(Query) of + {selected, [<<"itemid">>, <<"publisher">>, <<"creation">>, + <<"modification">>, <<"payload">>], RItems} -> case RItems of [[_, _, _, F, _]|_] -> - Index = case catch - ejabberd_sql:sql_query_t([<<"select count(*) from pubsub_item " - "where nodeid='">>, SNidx, <<"' and ">>, - AttrName, <<" > '">>, F, <<"';">>]) - of - %{selected, [_], [{C}, {In}]} -> [string:strip(C, both, $"), string:strip(In, both, $")]; - {selected, [_], [[In]]} -> In; - _ -> <<"0">> - end, + Index = case catch ejabberd_sql:sql_query_t( + [<<"select count(*) from pubsub_item " + "where nodeid='">>, SNidx, <<"' and ">>, + AttrName, <<" > '">>, F, <<"';">>]) of + {selected, [_], [[In]]} -> binary_to_integer(In); + _ -> 0 + end, [_, _, _, L, _] = lists:last(RItems), - RsmOut = #rsm_out{count = Count, index = Index, - first = <<"modification@", F/binary>>, - last = <<"modification@", (jlib:i2l(L))/binary>>}, + RsmOut = #rsm_set{count = Count, + index = Index, + first = #rsm_first{ + index = Index, + data = <<"modification@", F/binary>>}, + last = <<"modification@", L/binary>>}, {result, {[raw_to_item(Nidx, RItem) || RItem <- RItems], RsmOut}}; [] -> - {result, {[], #rsm_out{count = Count}}} + {result, {[], #rsm_set{count = Count}}} end; _ -> - {result, {[], none}} + {result, {[], undefined}} end. get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId, RSM) -> @@ -769,18 +750,20 @@ get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId, RSM %% Entity is subscribed but specifies an invalid subscription ID %{error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")}; (Affiliation == outcast) or (Affiliation == publish_only) -> - {error, ?ERR_FORBIDDEN}; + {error, xmpp:err_forbidden()}; (AccessModel == presence) and not PresenceSubscription -> - {error, - ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"presence-subscription-required">>)}; + {error, mod_pubsub:extended_error( + xmpp:err_not_authorized(), + mod_pubsub:err_presence_subscription_required())}; (AccessModel == roster) and not RosterGroup -> - {error, - ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"not-in-roster-group">>)}; + {error, mod_pubsub:extended_error( + xmpp:err_not_authorized(), + mod_pubsub:err_not_in_roster_group())}; (AccessModel == whitelist) and not Whitelisted -> - {error, - ?ERR_EXTENDED((?ERR_NOT_ALLOWED), <<"closed-node">>)}; + {error, mod_pubsub:extended_error( + xmpp:err_not_allowed(), mod_pubsub:err_closed_node())}; (AccessModel == authorize) and not Whitelisted -> - {error, ?ERR_FORBIDDEN}; + {error, xmpp:err_forbidden()}; %%MustPay -> %% % Payment is required for a subscription %% {error, ?ERR_PAYMENT_REQUIRED}; @@ -820,9 +803,9 @@ get_item(Nidx, ItemId) -> {selected, [RItem]} -> {result, raw_to_item(Nidx, RItem)}; {selected, []} -> - {error, ?ERR_ITEM_NOT_FOUND}; + {error, xmpp:err_item_not_found()}; {'EXIT', _} -> - {error, ?ERRT_INTERNAL_SERVER_ERROR(?MYLANG, <<"Database failure">>)} + {error, xmpp:err_internal_server_error(<<"Database failure">>, ?MYLANG)} end. get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) -> @@ -837,18 +820,20 @@ get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _Sub %% Entity is subscribed but specifies an invalid subscription ID %{error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")}; (Affiliation == outcast) or (Affiliation == publish_only) -> - {error, ?ERR_FORBIDDEN}; + {error, xmpp:err_forbidden()}; (AccessModel == presence) and not PresenceSubscription -> - {error, - ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"presence-subscription-required">>)}; + {error, mod_pubsub:extended_error( + xmpp:err_not_authorized(), + mod_pubsub:err_presence_subscription_required())}; (AccessModel == roster) and not RosterGroup -> - {error, - ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"not-in-roster-group">>)}; + {error, mod_pubsub:extended_error( + xmpp:err_not_authorized(), + mod_pubsub:err_not_in_roster_group())}; (AccessModel == whitelist) and not Whitelisted -> - {error, - ?ERR_EXTENDED((?ERR_NOT_ALLOWED), <<"closed-node">>)}; + {error, mod_pubsub:extended_error( + xmpp:err_not_allowed(), mod_pubsub:err_closed_node())}; (AccessModel == authorize) and not Whitelisted -> - {error, ?ERR_FORBIDDEN}; + {error, xmpp:err_forbidden()}; %%MustPay -> %% % Payment is required for a subscription %% {error, ?ERR_PAYMENT_REQUIRED}; diff --git a/src/xmpp.erl b/src/xmpp.erl index 8dbc49532..10872b341 100644 --- a/src/xmpp.erl +++ b/src/xmpp.erl @@ -10,7 +10,7 @@ %% API -export([make_iq_result/1, make_iq_result/2, make_error/2, - decode/1, decode/2, decode_tags_by_ns/2, encode/1, + decode/1, decode/2, encode/1, get_type/1, get_to/1, get_from/1, get_id/1, get_lang/1, get_error/1, get_els/1, get_ns/1, set_type/2, set_to/2, set_from/2, set_id/2, @@ -252,6 +252,10 @@ decode(Pkt, _Opts) -> decode_els(Stanza) -> decode_els(Stanza, fun xmpp_codec:is_known_tag/1). +-type match_fun() :: fun((xmlel()) -> boolean()). +-spec decode_els(iq(), match_fun()) -> iq(); + (message(), match_fun()) -> message(); + (presence(), match_fun()) -> presence(). decode_els(Stanza, MatchFun) -> Els = lists:map( fun(#xmlel{} = El) -> @@ -268,10 +272,6 @@ decode_els(Stanza, MatchFun) -> encode(Pkt) -> xmpp_codec:encode(Pkt). --spec decode_tags_by_ns([xmpp_element() | xmlel()], [binary()]) -> [xmpp_element()]. -decode_tags_by_ns(Els, NSList) -> - [xmpp_codec:decode(El) || El <- Els, lists:member(get_ns(El), NSList)]. - format_error(Reason) -> xmpp_codec:format_error(Reason). diff --git a/src/xmpp_codec.erl b/src/xmpp_codec.erl index afe6ff1ad..135a2acbb 100644 --- a/src/xmpp_codec.erl +++ b/src/xmpp_codec.erl @@ -520,10 +520,166 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> {<<"header">>, <<"http://jabber.org/protocol/shim">>} -> decode_shim_header(<<"http://jabber.org/protocol/shim">>, IgnoreEls, _el); + {<<"unsupported-access-model">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + decode_pubsub_error_unsupported_access_model(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"unsupported">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + decode_pubsub_error_unsupported(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"too-many-subscriptions">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + decode_pubsub_error_too_many_subscriptions(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"subid-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + decode_pubsub_error_subid_required(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"presence-subscription-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + decode_pubsub_error_presence_subscription_required(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"pending-subscription">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + decode_pubsub_error_pending_subscription(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"payload-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + decode_pubsub_error_payload_required(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"payload-too-big">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + decode_pubsub_error_payload_too_big(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"not-subscribed">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + decode_pubsub_error_not_subscribed(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"not-in-roster-group">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + decode_pubsub_error_not_in_roster_group(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"nodeid-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + decode_pubsub_error_nodeid_required(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"max-nodes-exceeded">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + decode_pubsub_error_max_nodes_exceeded(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"max-items-exceeded">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + decode_pubsub_error_max_items_exceeded(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"jid-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + decode_pubsub_error_jid_required(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"item-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + decode_pubsub_error_item_required(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"item-forbidden">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + decode_pubsub_error_item_forbidden(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"invalid-subid">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + decode_pubsub_error_invalid_subid(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"invalid-payload">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + decode_pubsub_error_invalid_payload(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"invalid-options">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + decode_pubsub_error_invalid_options(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"invalid-jid">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + decode_pubsub_error_invalid_jid(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"configuration-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + decode_pubsub_error_configuration_required(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"closed-node">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + decode_pubsub_error_closed_node(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"pubsub">>, + <<"http://jabber.org/protocol/pubsub#owner">>} -> + decode_pubsub_owner(<<"http://jabber.org/protocol/pubsub#owner">>, + IgnoreEls, _el); {<<"pubsub">>, <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub(<<"http://jabber.org/protocol/pubsub">>, IgnoreEls, _el); + {<<"purge">>, + <<"http://jabber.org/protocol/pubsub">>} -> + decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"purge">>, + <<"http://jabber.org/protocol/pubsub#owner">>} -> + decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub#owner">>, + IgnoreEls, _el); + {<<"purge">>, + <<"http://jabber.org/protocol/pubsub#event">>} -> + decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub#event">>, + IgnoreEls, _el); + {<<"delete">>, + <<"http://jabber.org/protocol/pubsub">>} -> + decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"delete">>, + <<"http://jabber.org/protocol/pubsub#owner">>} -> + decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub#owner">>, + IgnoreEls, _el); + {<<"delete">>, + <<"http://jabber.org/protocol/pubsub#event">>} -> + decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub#event">>, + IgnoreEls, _el); + {<<"redirect">>, + <<"http://jabber.org/protocol/pubsub">>} -> + decode_pubsub_redirect(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"redirect">>, + <<"http://jabber.org/protocol/pubsub#owner">>} -> + decode_pubsub_redirect(<<"http://jabber.org/protocol/pubsub#owner">>, + IgnoreEls, _el); + {<<"redirect">>, + <<"http://jabber.org/protocol/pubsub#event">>} -> + decode_pubsub_redirect(<<"http://jabber.org/protocol/pubsub#event">>, + IgnoreEls, _el); + {<<"default">>, + <<"http://jabber.org/protocol/pubsub">>} -> + decode_pubsub_default(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"default">>, + <<"http://jabber.org/protocol/pubsub#owner">>} -> + decode_pubsub_default(<<"http://jabber.org/protocol/pubsub#owner">>, + IgnoreEls, _el); + {<<"publish-options">>, + <<"http://jabber.org/protocol/pubsub">>} -> + decode_pubsub_publish_options(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"configure">>, + <<"http://jabber.org/protocol/pubsub">>} -> + decode_pubsub_configure(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"configure">>, + <<"http://jabber.org/protocol/pubsub#owner">>} -> + decode_pubsub_configure(<<"http://jabber.org/protocol/pubsub#owner">>, + IgnoreEls, _el); + {<<"create">>, + <<"http://jabber.org/protocol/pubsub">>} -> + decode_pubsub_create(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"create">>, + <<"http://jabber.org/protocol/pubsub#event">>} -> + decode_pubsub_create(<<"http://jabber.org/protocol/pubsub#event">>, + IgnoreEls, _el); {<<"retract">>, <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_retract(<<"http://jabber.org/protocol/pubsub">>, @@ -544,6 +700,10 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_subscribe(<<"http://jabber.org/protocol/pubsub">>, IgnoreEls, _el); + {<<"affiliations">>, + <<"http://jabber.org/protocol/pubsub#owner">>} -> + decode_pubsub_owner_affiliations(<<"http://jabber.org/protocol/pubsub#owner">>, + IgnoreEls, _el); {<<"affiliations">>, <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_affiliations(<<"http://jabber.org/protocol/pubsub">>, @@ -552,29 +712,41 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_subscriptions(<<"http://jabber.org/protocol/pubsub">>, IgnoreEls, _el); + {<<"subscriptions">>, + <<"http://jabber.org/protocol/pubsub#owner">>} -> + decode_pubsub_subscriptions(<<"http://jabber.org/protocol/pubsub#owner">>, + IgnoreEls, _el); {<<"event">>, <<"http://jabber.org/protocol/pubsub#event">>} -> decode_pubsub_event(<<"http://jabber.org/protocol/pubsub#event">>, IgnoreEls, _el); - {<<"items">>, - <<"http://jabber.org/protocol/pubsub#event">>} -> - decode_pubsub_event_items(<<"http://jabber.org/protocol/pubsub#event">>, - IgnoreEls, _el); - {<<"item">>, - <<"http://jabber.org/protocol/pubsub#event">>} -> - decode_pubsub_event_item(<<"http://jabber.org/protocol/pubsub#event">>, - IgnoreEls, _el); - {<<"retract">>, - <<"http://jabber.org/protocol/pubsub#event">>} -> - decode_pubsub_event_retract(<<"http://jabber.org/protocol/pubsub#event">>, - IgnoreEls, _el); {<<"items">>, <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_items(<<"http://jabber.org/protocol/pubsub">>, IgnoreEls, _el); + {<<"items">>, + <<"http://jabber.org/protocol/pubsub#event">>} -> + decode_pubsub_items(<<"http://jabber.org/protocol/pubsub#event">>, + IgnoreEls, _el); {<<"item">>, <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_item(<<"http://jabber.org/protocol/pubsub">>, IgnoreEls, _el); + {<<"item">>, + <<"http://jabber.org/protocol/pubsub#event">>} -> + decode_pubsub_item(<<"http://jabber.org/protocol/pubsub#event">>, + IgnoreEls, _el); + {<<"retract">>, + <<"http://jabber.org/protocol/pubsub#event">>} -> + decode_pubsub_event_retract(<<"http://jabber.org/protocol/pubsub#event">>, + IgnoreEls, _el); + {<<"configuration">>, + <<"http://jabber.org/protocol/pubsub#event">>} -> + decode_pubsub_event_configuration(<<"http://jabber.org/protocol/pubsub#event">>, + IgnoreEls, _el); + {<<"affiliation">>, + <<"http://jabber.org/protocol/pubsub#owner">>} -> + decode_pubsub_owner_affiliation(<<"http://jabber.org/protocol/pubsub#owner">>, + IgnoreEls, _el); {<<"affiliation">>, <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_affiliation(<<"http://jabber.org/protocol/pubsub">>, @@ -583,6 +755,14 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub">>, IgnoreEls, _el); + {<<"subscription">>, + <<"http://jabber.org/protocol/pubsub#owner">>} -> + decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub#owner">>, + IgnoreEls, _el); + {<<"subscription">>, + <<"http://jabber.org/protocol/pubsub#event">>} -> + decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub#event">>, + IgnoreEls, _el); {<<"x">>, <<"jabber:x:data">>} -> decode_xdata(<<"jabber:x:data">>, IgnoreEls, _el); {<<"item">>, <<"jabber:x:data">>} -> @@ -1654,9 +1834,126 @@ is_known_tag({xmlel, _name, _attrs, _} = _el) -> true; {<<"header">>, <<"http://jabber.org/protocol/shim">>} -> true; + {<<"unsupported-access-model">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + true; + {<<"unsupported">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + true; + {<<"too-many-subscriptions">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + true; + {<<"subid-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + true; + {<<"presence-subscription-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + true; + {<<"pending-subscription">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + true; + {<<"payload-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + true; + {<<"payload-too-big">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + true; + {<<"not-subscribed">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + true; + {<<"not-in-roster-group">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + true; + {<<"nodeid-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + true; + {<<"max-nodes-exceeded">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + true; + {<<"max-items-exceeded">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + true; + {<<"jid-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + true; + {<<"item-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + true; + {<<"item-forbidden">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + true; + {<<"invalid-subid">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + true; + {<<"invalid-payload">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + true; + {<<"invalid-options">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + true; + {<<"invalid-jid">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + true; + {<<"configuration-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + true; + {<<"closed-node">>, + <<"http://jabber.org/protocol/pubsub#errors">>} -> + true; + {<<"pubsub">>, + <<"http://jabber.org/protocol/pubsub#owner">>} -> + true; {<<"pubsub">>, <<"http://jabber.org/protocol/pubsub">>} -> true; + {<<"purge">>, + <<"http://jabber.org/protocol/pubsub">>} -> + true; + {<<"purge">>, + <<"http://jabber.org/protocol/pubsub#owner">>} -> + true; + {<<"purge">>, + <<"http://jabber.org/protocol/pubsub#event">>} -> + true; + {<<"delete">>, + <<"http://jabber.org/protocol/pubsub">>} -> + true; + {<<"delete">>, + <<"http://jabber.org/protocol/pubsub#owner">>} -> + true; + {<<"delete">>, + <<"http://jabber.org/protocol/pubsub#event">>} -> + true; + {<<"redirect">>, + <<"http://jabber.org/protocol/pubsub">>} -> + true; + {<<"redirect">>, + <<"http://jabber.org/protocol/pubsub#owner">>} -> + true; + {<<"redirect">>, + <<"http://jabber.org/protocol/pubsub#event">>} -> + true; + {<<"default">>, + <<"http://jabber.org/protocol/pubsub">>} -> + true; + {<<"default">>, + <<"http://jabber.org/protocol/pubsub#owner">>} -> + true; + {<<"publish-options">>, + <<"http://jabber.org/protocol/pubsub">>} -> + true; + {<<"configure">>, + <<"http://jabber.org/protocol/pubsub">>} -> + true; + {<<"configure">>, + <<"http://jabber.org/protocol/pubsub#owner">>} -> + true; + {<<"create">>, + <<"http://jabber.org/protocol/pubsub">>} -> + true; + {<<"create">>, + <<"http://jabber.org/protocol/pubsub#event">>} -> + true; {<<"retract">>, <<"http://jabber.org/protocol/pubsub">>} -> true; @@ -1672,28 +1969,40 @@ is_known_tag({xmlel, _name, _attrs, _} = _el) -> {<<"subscribe">>, <<"http://jabber.org/protocol/pubsub">>} -> true; + {<<"affiliations">>, + <<"http://jabber.org/protocol/pubsub#owner">>} -> + true; {<<"affiliations">>, <<"http://jabber.org/protocol/pubsub">>} -> true; {<<"subscriptions">>, <<"http://jabber.org/protocol/pubsub">>} -> true; + {<<"subscriptions">>, + <<"http://jabber.org/protocol/pubsub#owner">>} -> + true; {<<"event">>, <<"http://jabber.org/protocol/pubsub#event">>} -> true; + {<<"items">>, + <<"http://jabber.org/protocol/pubsub">>} -> + true; {<<"items">>, <<"http://jabber.org/protocol/pubsub#event">>} -> true; + {<<"item">>, <<"http://jabber.org/protocol/pubsub">>} -> + true; {<<"item">>, <<"http://jabber.org/protocol/pubsub#event">>} -> true; {<<"retract">>, <<"http://jabber.org/protocol/pubsub#event">>} -> true; - {<<"items">>, - <<"http://jabber.org/protocol/pubsub">>} -> + {<<"configuration">>, + <<"http://jabber.org/protocol/pubsub#event">>} -> true; - {<<"item">>, <<"http://jabber.org/protocol/pubsub">>} -> + {<<"affiliation">>, + <<"http://jabber.org/protocol/pubsub#owner">>} -> true; {<<"affiliation">>, <<"http://jabber.org/protocol/pubsub">>} -> @@ -1701,6 +2010,12 @@ is_known_tag({xmlel, _name, _attrs, _} = _el) -> {<<"subscription">>, <<"http://jabber.org/protocol/pubsub">>} -> true; + {<<"subscription">>, + <<"http://jabber.org/protocol/pubsub#owner">>} -> + true; + {<<"subscription">>, + <<"http://jabber.org/protocol/pubsub#event">>} -> + true; {<<"x">>, <<"jabber:x:data">>} -> true; {<<"item">>, <<"jabber:x:data">>} -> true; {<<"reported">>, <<"jabber:x:data">>} -> true; @@ -2410,59 +2725,162 @@ encode({xdata_field, _, _, _, _, _, _, _, _} = Field) -> [{<<"xmlns">>, <<"jabber:x:data">>}]); encode({xdata, _, _, _, _, _, _} = X) -> encode_xdata(X, [{<<"xmlns">>, <<"jabber:x:data">>}]); -encode({pubsub_subscription, _, _, _, _} = +encode({ps_subscription, _, _, _, _, _, _} = Subscription) -> - encode_pubsub_subscription(Subscription, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub">>}]); -encode({pubsub_affiliation, _, _} = Affiliation) -> - encode_pubsub_affiliation(Affiliation, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub">>}]); -encode({pubsub_item, _, _} = Item) -> - encode_pubsub_item(Item, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub">>}]); -encode({pubsub_items, _, _, _, _} = Items) -> - encode_pubsub_items(Items, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub">>}]); -encode({pubsub_event_item, _, _, _, _} = Item) -> - encode_pubsub_event_item(Item, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#event">>}]); -encode({pubsub_event_items, _, _, _} = Items) -> - encode_pubsub_event_items(Items, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#event">>}]); -encode({pubsub_event, _} = Event) -> + encode_pubsub_subscription(Subscription, []); +encode({ps_affiliation, + <<"http://jabber.org/protocol/pubsub">>, _, _, _} = + Affiliation) -> + encode_pubsub_affiliation(Affiliation, []); +encode({ps_affiliation, + <<"http://jabber.org/protocol/pubsub#owner">>, _, _, + _} = + Affiliation) -> + encode_pubsub_owner_affiliation(Affiliation, []); +encode({ps_item, _, _, _, _, _} = Item) -> + encode_pubsub_item(Item, []); +encode({ps_items, _, _, _, _, _, _} = Items) -> + encode_pubsub_items(Items, []); +encode({ps_event, _, _, _, _, _, _} = Event) -> encode_pubsub_event(Event, [{<<"xmlns">>, <<"http://jabber.org/protocol/pubsub#event">>}]); -encode({pubsub_subscribe, _, _} = Subscribe) -> +encode({ps_subscribe, _, _} = Subscribe) -> encode_pubsub_subscribe(Subscribe, [{<<"xmlns">>, <<"http://jabber.org/protocol/pubsub">>}]); -encode({pubsub_unsubscribe, _, _, _} = Unsubscribe) -> +encode({ps_unsubscribe, _, _, _} = Unsubscribe) -> encode_pubsub_unsubscribe(Unsubscribe, [{<<"xmlns">>, <<"http://jabber.org/protocol/pubsub">>}]); -encode({pubsub_publish, _, _} = Publish) -> +encode({ps_publish, _, _} = Publish) -> encode_pubsub_publish(Publish, [{<<"xmlns">>, <<"http://jabber.org/protocol/pubsub">>}]); -encode({pubsub_options, _, _, _, _} = Options) -> +encode({ps_options, _, _, _, _} = Options) -> encode_pubsub_options(Options, [{<<"xmlns">>, <<"http://jabber.org/protocol/pubsub">>}]); -encode({pubsub_retract, _, _, _} = Retract) -> +encode({ps_retract, _, _, _} = Retract) -> encode_pubsub_retract(Retract, [{<<"xmlns">>, <<"http://jabber.org/protocol/pubsub">>}]); -encode({pubsub, _, _, _, _, _, _, _, _} = Pubsub) -> +encode({pubsub, _, _, _, _, _, _, _, _, _, _, _, _, _, + _, _, _} = + Pubsub) -> encode_pubsub(Pubsub, [{<<"xmlns">>, <<"http://jabber.org/protocol/pubsub">>}]); +encode({pubsub_owner, _, _, _, _, _, _} = Pubsub) -> + encode_pubsub_owner(Pubsub, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/pubsub#owner">>}]); +encode({ps_error, 'closed-node', _} = Closed_node) -> + encode_pubsub_error_closed_node(Closed_node, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/pubsub#errors">>}]); +encode({ps_error, 'configuration-required', _} = + Configuration_required) -> + encode_pubsub_error_configuration_required(Configuration_required, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/pubsub#errors">>}]); +encode({ps_error, 'invalid-jid', _} = Invalid_jid) -> + encode_pubsub_error_invalid_jid(Invalid_jid, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/pubsub#errors">>}]); +encode({ps_error, 'invalid-options', _} = + Invalid_options) -> + encode_pubsub_error_invalid_options(Invalid_options, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/pubsub#errors">>}]); +encode({ps_error, 'invalid-payload', _} = + Invalid_payload) -> + encode_pubsub_error_invalid_payload(Invalid_payload, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/pubsub#errors">>}]); +encode({ps_error, 'invalid-subid', _} = + Invalid_subid) -> + encode_pubsub_error_invalid_subid(Invalid_subid, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/pubsub#errors">>}]); +encode({ps_error, 'item-forbidden', _} = + Item_forbidden) -> + encode_pubsub_error_item_forbidden(Item_forbidden, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/pubsub#errors">>}]); +encode({ps_error, 'item-required', _} = + Item_required) -> + encode_pubsub_error_item_required(Item_required, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/pubsub#errors">>}]); +encode({ps_error, 'jid-required', _} = Jid_required) -> + encode_pubsub_error_jid_required(Jid_required, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/pubsub#errors">>}]); +encode({ps_error, 'max-items-exceeded', _} = + Max_items_exceeded) -> + encode_pubsub_error_max_items_exceeded(Max_items_exceeded, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/pubsub#errors">>}]); +encode({ps_error, 'max-nodes-exceeded', _} = + Max_nodes_exceeded) -> + encode_pubsub_error_max_nodes_exceeded(Max_nodes_exceeded, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/pubsub#errors">>}]); +encode({ps_error, 'nodeid-required', _} = + Nodeid_required) -> + encode_pubsub_error_nodeid_required(Nodeid_required, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/pubsub#errors">>}]); +encode({ps_error, 'not-in-roster-group', _} = + Not_in_roster_group) -> + encode_pubsub_error_not_in_roster_group(Not_in_roster_group, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/pubsub#errors">>}]); +encode({ps_error, 'not-subscribed', _} = + Not_subscribed) -> + encode_pubsub_error_not_subscribed(Not_subscribed, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/pubsub#errors">>}]); +encode({ps_error, 'payload-too-big', _} = + Payload_too_big) -> + encode_pubsub_error_payload_too_big(Payload_too_big, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/pubsub#errors">>}]); +encode({ps_error, 'payload-required', _} = + Payload_required) -> + encode_pubsub_error_payload_required(Payload_required, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/pubsub#errors">>}]); +encode({ps_error, 'pending-subscription', _} = + Pending_subscription) -> + encode_pubsub_error_pending_subscription(Pending_subscription, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/pubsub#errors">>}]); +encode({ps_error, 'presence-subscription-required', _} = + Presence_subscription_required) -> + encode_pubsub_error_presence_subscription_required(Presence_subscription_required, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/pubsub#errors">>}]); +encode({ps_error, 'subid-required', _} = + Subid_required) -> + encode_pubsub_error_subid_required(Subid_required, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/pubsub#errors">>}]); +encode({ps_error, 'too-many-subscriptions', _} = + Too_many_subscriptions) -> + encode_pubsub_error_too_many_subscriptions(Too_many_subscriptions, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/pubsub#errors">>}]); +encode({ps_error, unsupported, _} = Unsupported) -> + encode_pubsub_error_unsupported(Unsupported, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/pubsub#errors">>}]); +encode({ps_error, 'unsupported-access-model', _} = + Unsupported_access_model) -> + encode_pubsub_error_unsupported_access_model(Unsupported_access_model, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/pubsub#errors">>}]); encode({shim, _} = Headers) -> encode_shim_headers(Headers, [{<<"xmlns">>, <<"http://jabber.org/protocol/shim">>}]); @@ -2581,7 +2999,7 @@ encode({carbons_received, _} = Received) -> encode({carbons_sent, _} = Sent) -> encode_carbons_sent(Sent, [{<<"xmlns">>, <<"urn:xmpp:carbons:2">>}]); -encode({feature_csi, _} = Csi) -> +encode({feature_csi, <<"urn:xmpp:csi:0">>} = Csi) -> encode_feature_csi(Csi, []); encode({csi, active} = Active) -> encode_csi_active(Active, @@ -2717,357 +3135,280 @@ encode({thumbnail, _, _, _, _} = Thumbnail) -> encode_thumbnail(Thumbnail, [{<<"xmlns">>, <<"urn:xmpp:thumbs:1">>}]). -get_name({last, _, _}) -> <<"query">>; -get_name({version, _, _, _}) -> <<"query">>; -get_name({roster_item, _, _, _, _, _}) -> <<"item">>; -get_name({roster_query, _, _}) -> <<"query">>; -get_name({rosterver_feature}) -> <<"ver">>; -get_name({privacy_item, _, _, _, _, _, _, _, _}) -> - <<"item">>; -get_name({privacy_list, _, _}) -> <<"list">>; -get_name({privacy_query, _, _, _}) -> <<"query">>; +get_name({address, _, _, _, _, _}) -> <<"address">>; +get_name({addresses, _}) -> <<"addresses">>; +get_name({adhoc_actions, _, _, _, _}) -> <<"actions">>; +get_name({adhoc_command, _, _, _, _, _, _, _, _}) -> + <<"command">>; +get_name({adhoc_note, _, _}) -> <<"note">>; +get_name({bind, _, _}) -> <<"bind">>; get_name({block, _}) -> <<"block">>; -get_name({unblock, _}) -> <<"unblock">>; get_name({block_list, _}) -> <<"blocklist">>; -get_name({identity, _, _, _, _}) -> <<"identity">>; -get_name({disco_info, _, _, _, _}) -> <<"query">>; -get_name({disco_item, _, _, _}) -> <<"item">>; -get_name({disco_items, _, _, _}) -> <<"query">>; -get_name({private, _}) -> <<"query">>; +get_name({bob_data, _, _, _, _}) -> <<"data">>; get_name({bookmark_conference, _, _, _, _, _}) -> <<"conference">>; -get_name({bookmark_url, _, _}) -> <<"url">>; get_name({bookmark_storage, _, _}) -> <<"storage">>; -get_name({stat_error, _, _}) -> <<"error">>; -get_name({stat, _, _, _, _}) -> <<"stat">>; -get_name({stats, _, _}) -> <<"query">>; -get_name({iq, _, _, _, _, _, _}) -> <<"iq">>; -get_name({message, _, _, _, _, _, _, _, _, _}) -> - <<"message">>; -get_name({presence, _, _, _, _, _, _, _, _, _}) -> - <<"presence">>; -get_name({gone, _}) -> <<"gone">>; -get_name({redirect, _}) -> <<"redirect">>; -get_name({error, _, _, _, _, _, _}) -> <<"error">>; -get_name({bind, _, _}) -> <<"bind">>; -get_name({legacy_auth, _, _, _, _}) -> <<"query">>; -get_name({sasl_auth, _, _}) -> <<"auth">>; -get_name({sasl_abort}) -> <<"abort">>; -get_name({sasl_challenge, _}) -> <<"challenge">>; -get_name({sasl_response, _}) -> <<"response">>; -get_name({sasl_success, _}) -> <<"success">>; -get_name({sasl_failure, _, _}) -> <<"failure">>; -get_name({sasl_mechanisms, _}) -> <<"mechanisms">>; -get_name({starttls, _}) -> <<"starttls">>; -get_name({starttls_proceed}) -> <<"proceed">>; -get_name({starttls_failure}) -> <<"failure">>; -get_name({compress_failure, _}) -> <<"failure">>; -get_name({compress, _}) -> <<"compress">>; -get_name({compressed}) -> <<"compressed">>; -get_name({compression, _}) -> <<"compression">>; -get_name({stream_features, _}) -> <<"stream:features">>; -get_name({p1_push}) -> <<"push">>; -get_name({p1_rebind}) -> <<"rebind">>; -get_name({p1_ack}) -> <<"ack">>; -get_name({caps, _, _, _, _}) -> <<"c">>; -get_name({feature_register}) -> <<"register">>; -get_name({register, _, _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, _, _}) -> - <<"query">>; -get_name({xmpp_session, _}) -> <<"session">>; -get_name({ping}) -> <<"ping">>; -get_name({time, _, _}) -> <<"time">>; -get_name({text, _, _}) -> <<"text">>; -get_name({'see-other-host', _}) -> <<"see-other-host">>; -get_name({stream_error, _, _}) -> <<"stream:error">>; -get_name({vcard_name, _, _, _, _, _}) -> <<"N">>; -get_name({vcard_adr, _, _, _, _, _, _, _, _, _, _, _, _, - _, _}) -> - <<"ADR">>; -get_name({vcard_label, _, _, _, _, _, _, _, _}) -> - <<"LABEL">>; -get_name({vcard_tel, _, _, _, _, _, _, _, _, _, _, _, _, - _, _}) -> - <<"TEL">>; -get_name({vcard_email, _, _, _, _, _, _}) -> - <<"EMAIL">>; -get_name({vcard_geo, _, _}) -> <<"GEO">>; -get_name({vcard_logo, _, _, _}) -> <<"LOGO">>; -get_name({vcard_photo, _, _, _}) -> <<"PHOTO">>; -get_name({vcard_org, _, _}) -> <<"ORG">>; -get_name({vcard_sound, _, _, _}) -> <<"SOUND">>; -get_name({vcard_key, _, _}) -> <<"KEY">>; -get_name({vcard_temp, _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, - _}) -> - <<"vCard">>; -get_name({vcard_xupdate, _, _}) -> <<"x">>; -get_name({xdata_option, _, _}) -> <<"option">>; -get_name({xdata_field, _, _, _, _, _, _, _, _}) -> - <<"field">>; -get_name({xdata, _, _, _, _, _, _}) -> <<"x">>; -get_name({pubsub_subscription, _, _, _, _}) -> - <<"subscription">>; -get_name({pubsub_affiliation, _, _}) -> - <<"affiliation">>; -get_name({pubsub_item, _, _}) -> <<"item">>; -get_name({pubsub_items, _, _, _, _}) -> <<"items">>; -get_name({pubsub_event_item, _, _, _, _}) -> <<"item">>; -get_name({pubsub_event_items, _, _, _}) -> <<"items">>; -get_name({pubsub_event, _}) -> <<"event">>; -get_name({pubsub_subscribe, _, _}) -> <<"subscribe">>; -get_name({pubsub_unsubscribe, _, _, _}) -> - <<"unsubscribe">>; -get_name({pubsub_publish, _, _}) -> <<"publish">>; -get_name({pubsub_options, _, _, _, _}) -> <<"options">>; -get_name({pubsub_retract, _, _, _}) -> <<"retract">>; -get_name({pubsub, _, _, _, _, _, _, _, _}) -> - <<"pubsub">>; -get_name({shim, _}) -> <<"headers">>; -get_name({chatstate, active}) -> <<"active">>; -get_name({chatstate, composing}) -> <<"composing">>; -get_name({chatstate, gone}) -> <<"gone">>; -get_name({chatstate, inactive}) -> <<"inactive">>; -get_name({chatstate, paused}) -> <<"paused">>; -get_name({delay, _, _, _}) -> <<"delay">>; -get_name({streamhost, _, _, _}) -> <<"streamhost">>; +get_name({bookmark_url, _, _}) -> <<"url">>; get_name({bytestreams, _, _, _, _, _, _}) -> <<"query">>; -get_name({muc_history, _, _, _, _}) -> <<"history">>; -get_name({muc_decline, _, _, _}) -> <<"decline">>; -get_name({muc_destroy, _, _, _, _}) -> <<"destroy">>; -get_name({muc_invite, _, _, _, _}) -> <<"invite">>; -get_name({muc_user, _, _, _, _, _, _}) -> <<"x">>; -get_name({muc_owner, _, _, _}) -> <<"query">>; -get_name({muc_item, _, _, _, _, _, _, _}) -> <<"item">>; -get_name({muc_actor, _, _}) -> <<"actor">>; -get_name({muc_admin, _}) -> <<"query">>; -get_name({muc, _, _}) -> <<"x">>; -get_name({muc_unique, _}) -> <<"unique">>; -get_name({x_conference, _, _, _, _, _}) -> <<"x">>; -get_name({muc_subscriptions, _}) -> <<"subscriptions">>; -get_name({muc_subscribe, _, _}) -> <<"subscribe">>; -get_name({muc_unsubscribe}) -> <<"unsubscribe">>; -get_name({rsm_first, _, _}) -> <<"first">>; -get_name({rsm_set, _, _, _, _, _, _, _}) -> <<"set">>; -get_name({mam_query, _, _, _, _, _, _, _, _}) -> - <<"query">>; -get_name({mam_archived, _, _}) -> <<"archived">>; -get_name({mam_result, _, _, _, _}) -> <<"result">>; -get_name({mam_prefs, _, _, _, _}) -> <<"prefs">>; -get_name({mam_fin, _, _, _, _}) -> <<"fin">>; -get_name({forwarded, _, _}) -> <<"forwarded">>; +get_name({caps, _, _, _, _}) -> <<"c">>; get_name({carbons_disable}) -> <<"disable">>; get_name({carbons_enable}) -> <<"enable">>; get_name({carbons_private}) -> <<"private">>; get_name({carbons_received, _}) -> <<"received">>; get_name({carbons_sent, _}) -> <<"sent">>; -get_name({feature_csi, _}) -> <<"csi">>; +get_name({chatstate, active}) -> <<"active">>; +get_name({chatstate, composing}) -> <<"composing">>; +get_name({chatstate, gone}) -> <<"gone">>; +get_name({chatstate, inactive}) -> <<"inactive">>; +get_name({chatstate, paused}) -> <<"paused">>; +get_name({client_id, _}) -> <<"client-id">>; +get_name({compress, _}) -> <<"compress">>; +get_name({compress_failure, _}) -> <<"failure">>; +get_name({compressed}) -> <<"compressed">>; +get_name({compression, _}) -> <<"compression">>; get_name({csi, active}) -> <<"active">>; get_name({csi, inactive}) -> <<"inactive">>; -get_name({feature_sm, _}) -> <<"sm">>; -get_name({sm_enable, _, _, _}) -> <<"enable">>; -get_name({sm_enabled, _, _, _, _, _}) -> <<"enabled">>; -get_name({sm_resume, _, _, _}) -> <<"resume">>; -get_name({sm_resumed, _, _, _}) -> <<"resumed">>; -get_name({sm_r, _}) -> <<"r">>; -get_name({sm_a, _, _}) -> <<"a">>; -get_name({sm_failed, _, _, _}) -> <<"failed">>; -get_name({offline_item, _, _}) -> <<"item">>; -get_name({offline, _, _, _}) -> <<"offline">>; -get_name({mix_join, _, _}) -> <<"join">>; -get_name({mix_leave}) -> <<"leave">>; -get_name({mix_participant, _, _}) -> <<"participant">>; -get_name({hint, 'no-copy'}) -> <<"no-copy">>; -get_name({hint, 'no-store'}) -> <<"no-store">>; -get_name({hint, 'no-storage'}) -> <<"no-storage">>; -get_name({hint, store}) -> <<"store">>; -get_name({hint, 'no-permanent-store'}) -> - <<"no-permanent-store">>; -get_name({hint, 'no-permanent-storage'}) -> - <<"no-permanent-storage">>; -get_name({search_item, _, _, _, _, _}) -> <<"item">>; -get_name({search, _, _, _, _, _, _, _}) -> <<"query">>; -get_name({xevent, _, _, _, _, _}) -> <<"x">>; -get_name({expire, _, _}) -> <<"x">>; -get_name({nick, _}) -> <<"nick">>; -get_name({address, _, _, _, _, _}) -> <<"address">>; -get_name({addresses, _}) -> <<"addresses">>; -get_name({stanza_id, _, _}) -> <<"stanza-id">>; -get_name({client_id, _}) -> <<"client-id">>; -get_name({adhoc_actions, _, _, _, _}) -> <<"actions">>; -get_name({adhoc_note, _, _}) -> <<"note">>; -get_name({adhoc_command, _, _, _, _, _, _, _, _}) -> - <<"command">>; get_name({db_result, _, _, _, _, _}) -> <<"db:result">>; get_name({db_verify, _, _, _, _, _, _}) -> <<"db:verify">>; +get_name({delay, _, _, _}) -> <<"delay">>; +get_name({disco_info, _, _, _, _}) -> <<"query">>; +get_name({disco_item, _, _, _}) -> <<"item">>; +get_name({disco_items, _, _, _}) -> <<"query">>; +get_name({error, _, _, _, _, _, _}) -> <<"error">>; +get_name({expire, _, _}) -> <<"x">>; +get_name({feature_csi, _}) -> <<"csi">>; +get_name({feature_register}) -> <<"register">>; +get_name({feature_sm, _}) -> <<"sm">>; +get_name({forwarded, _, _}) -> <<"forwarded">>; +get_name({gone, _}) -> <<"gone">>; get_name({handshake, _}) -> <<"handshake">>; +get_name({hint, 'no-copy'}) -> <<"no-copy">>; +get_name({hint, 'no-permanent-storage'}) -> + <<"no-permanent-storage">>; +get_name({hint, 'no-permanent-store'}) -> + <<"no-permanent-store">>; +get_name({hint, 'no-storage'}) -> <<"no-storage">>; +get_name({hint, 'no-store'}) -> <<"no-store">>; +get_name({hint, store}) -> <<"store">>; +get_name({identity, _, _, _, _}) -> <<"identity">>; +get_name({iq, _, _, _, _, _, _}) -> <<"iq">>; +get_name({last, _, _}) -> <<"query">>; +get_name({legacy_auth, _, _, _, _}) -> <<"query">>; +get_name({mam_archived, _, _}) -> <<"archived">>; +get_name({mam_fin, _, _, _, _}) -> <<"fin">>; +get_name({mam_prefs, _, _, _, _}) -> <<"prefs">>; +get_name({mam_query, _, _, _, _, _, _, _, _}) -> + <<"query">>; +get_name({mam_result, _, _, _, _}) -> <<"result">>; +get_name({media, _, _, _}) -> <<"media">>; +get_name({media_uri, _, _}) -> <<"uri">>; +get_name({message, _, _, _, _, _, _, _, _, _}) -> + <<"message">>; +get_name({mix_join, _, _}) -> <<"join">>; +get_name({mix_leave}) -> <<"leave">>; +get_name({mix_participant, _, _}) -> <<"participant">>; +get_name({muc, _, _}) -> <<"x">>; +get_name({muc_actor, _, _}) -> <<"actor">>; +get_name({muc_admin, _}) -> <<"query">>; +get_name({muc_decline, _, _, _}) -> <<"decline">>; +get_name({muc_destroy, _, _, _, _}) -> <<"destroy">>; +get_name({muc_history, _, _, _, _}) -> <<"history">>; +get_name({muc_invite, _, _, _, _}) -> <<"invite">>; +get_name({muc_item, _, _, _, _, _, _, _}) -> <<"item">>; +get_name({muc_owner, _, _, _}) -> <<"query">>; +get_name({muc_subscribe, _, _}) -> <<"subscribe">>; +get_name({muc_subscriptions, _}) -> <<"subscriptions">>; +get_name({muc_unique, _}) -> <<"unique">>; +get_name({muc_unsubscribe}) -> <<"unsubscribe">>; +get_name({muc_user, _, _, _, _, _, _}) -> <<"x">>; +get_name({nick, _}) -> <<"nick">>; +get_name({offline, _, _, _}) -> <<"offline">>; +get_name({offline_item, _, _}) -> <<"item">>; +get_name({oob_x, _, _, _}) -> <<"x">>; +get_name({p1_ack}) -> <<"ack">>; +get_name({p1_push}) -> <<"push">>; +get_name({p1_rebind}) -> <<"rebind">>; +get_name({ping}) -> <<"ping">>; +get_name({presence, _, _, _, _, _, _, _, _, _}) -> + <<"presence">>; +get_name({privacy_item, _, _, _, _, _, _, _, _}) -> + <<"item">>; +get_name({privacy_list, _, _}) -> <<"list">>; +get_name({privacy_query, _, _, _}) -> <<"query">>; +get_name({private, _}) -> <<"query">>; +get_name({ps_affiliation, _, _, _, _}) -> + <<"affiliation">>; +get_name({ps_error, 'closed-node', _}) -> + <<"closed-node">>; +get_name({ps_error, 'configuration-required', _}) -> + <<"configuration-required">>; +get_name({ps_error, 'invalid-jid', _}) -> + <<"invalid-jid">>; +get_name({ps_error, 'invalid-options', _}) -> + <<"invalid-options">>; +get_name({ps_error, 'invalid-payload', _}) -> + <<"invalid-payload">>; +get_name({ps_error, 'invalid-subid', _}) -> + <<"invalid-subid">>; +get_name({ps_error, 'item-forbidden', _}) -> + <<"item-forbidden">>; +get_name({ps_error, 'item-required', _}) -> + <<"item-required">>; +get_name({ps_error, 'jid-required', _}) -> + <<"jid-required">>; +get_name({ps_error, 'max-items-exceeded', _}) -> + <<"max-items-exceeded">>; +get_name({ps_error, 'max-nodes-exceeded', _}) -> + <<"max-nodes-exceeded">>; +get_name({ps_error, 'nodeid-required', _}) -> + <<"nodeid-required">>; +get_name({ps_error, 'not-in-roster-group', _}) -> + <<"not-in-roster-group">>; +get_name({ps_error, 'not-subscribed', _}) -> + <<"not-subscribed">>; +get_name({ps_error, 'payload-required', _}) -> + <<"payload-required">>; +get_name({ps_error, 'payload-too-big', _}) -> + <<"payload-too-big">>; +get_name({ps_error, 'pending-subscription', _}) -> + <<"pending-subscription">>; +get_name({ps_error, 'presence-subscription-required', + _}) -> + <<"presence-subscription-required">>; +get_name({ps_error, 'subid-required', _}) -> + <<"subid-required">>; +get_name({ps_error, 'too-many-subscriptions', _}) -> + <<"too-many-subscriptions">>; +get_name({ps_error, unsupported, _}) -> + <<"unsupported">>; +get_name({ps_error, 'unsupported-access-model', _}) -> + <<"unsupported-access-model">>; +get_name({ps_event, _, _, _, _, _, _}) -> <<"event">>; +get_name({ps_item, _, _, _, _, _}) -> <<"item">>; +get_name({ps_items, _, _, _, _, _, _}) -> <<"items">>; +get_name({ps_options, _, _, _, _}) -> <<"options">>; +get_name({ps_publish, _, _}) -> <<"publish">>; +get_name({ps_retract, _, _, _}) -> <<"retract">>; +get_name({ps_subscribe, _, _}) -> <<"subscribe">>; +get_name({ps_subscription, _, _, _, _, _, _}) -> + <<"subscription">>; +get_name({ps_unsubscribe, _, _, _}) -> + <<"unsubscribe">>; +get_name({pubsub, _, _, _, _, _, _, _, _, _, _, _, _, _, + _, _, _}) -> + <<"pubsub">>; +get_name({pubsub_owner, _, _, _, _, _, _}) -> + <<"pubsub">>; +get_name({redirect, _}) -> <<"redirect">>; +get_name({register, _, _, _, _, _, _, _, _, _, _, _, _, + _, _, _, _, _, _, _, _, _, _}) -> + <<"query">>; +get_name({roster_item, _, _, _, _, _}) -> <<"item">>; +get_name({roster_query, _, _}) -> <<"query">>; +get_name({rosterver_feature}) -> <<"ver">>; +get_name({rsm_first, _, _}) -> <<"first">>; +get_name({rsm_set, _, _, _, _, _, _, _}) -> <<"set">>; +get_name({sasl_abort}) -> <<"abort">>; +get_name({sasl_auth, _, _}) -> <<"auth">>; +get_name({sasl_challenge, _}) -> <<"challenge">>; +get_name({sasl_failure, _, _}) -> <<"failure">>; +get_name({sasl_mechanisms, _}) -> <<"mechanisms">>; +get_name({sasl_response, _}) -> <<"response">>; +get_name({sasl_success, _}) -> <<"success">>; +get_name({search, _, _, _, _, _, _, _}) -> <<"query">>; +get_name({search_item, _, _, _, _, _}) -> <<"item">>; +get_name({'see-other-host', _}) -> <<"see-other-host">>; +get_name({shim, _}) -> <<"headers">>; +get_name({sic, _, _, _}) -> <<"address">>; +get_name({sm_a, _, _}) -> <<"a">>; +get_name({sm_enable, _, _, _}) -> <<"enable">>; +get_name({sm_enabled, _, _, _, _, _}) -> <<"enabled">>; +get_name({sm_failed, _, _, _}) -> <<"failed">>; +get_name({sm_r, _}) -> <<"r">>; +get_name({sm_resume, _, _, _}) -> <<"resume">>; +get_name({sm_resumed, _, _, _}) -> <<"resumed">>; +get_name({stanza_id, _, _}) -> <<"stanza-id">>; +get_name({starttls, _}) -> <<"starttls">>; +get_name({starttls_failure}) -> <<"failure">>; +get_name({starttls_proceed}) -> <<"proceed">>; +get_name({stat, _, _, _, _}) -> <<"stat">>; +get_name({stat_error, _, _}) -> <<"error">>; +get_name({stats, _, _}) -> <<"query">>; +get_name({stream_error, _, _}) -> <<"stream:error">>; +get_name({stream_features, _}) -> <<"stream:features">>; get_name({stream_start, _, _, _, _, _, _, _, _}) -> <<"stream:stream">>; -get_name({bob_data, _, _, _, _}) -> <<"data">>; -get_name({xcaptcha, _}) -> <<"captcha">>; -get_name({media_uri, _, _}) -> <<"uri">>; -get_name({media, _, _, _}) -> <<"media">>; -get_name({oob_x, _, _, _}) -> <<"x">>; -get_name({sic, _, _, _}) -> <<"address">>; +get_name({streamhost, _, _, _}) -> <<"streamhost">>; +get_name({text, _, _}) -> <<"text">>; +get_name({thumbnail, _, _, _, _}) -> <<"thumbnail">>; +get_name({time, _, _}) -> <<"time">>; +get_name({unblock, _}) -> <<"unblock">>; get_name({upload_request, _, _, _, _}) -> <<"request">>; get_name({upload_slot, _, _, _}) -> <<"slot">>; -get_name({thumbnail, _, _, _, _}) -> <<"thumbnail">>. +get_name({vcard_adr, _, _, _, _, _, _, _, _, _, _, _, _, + _, _}) -> + <<"ADR">>; +get_name({vcard_email, _, _, _, _, _, _}) -> + <<"EMAIL">>; +get_name({vcard_geo, _, _}) -> <<"GEO">>; +get_name({vcard_key, _, _}) -> <<"KEY">>; +get_name({vcard_label, _, _, _, _, _, _, _, _}) -> + <<"LABEL">>; +get_name({vcard_logo, _, _, _}) -> <<"LOGO">>; +get_name({vcard_name, _, _, _, _, _}) -> <<"N">>; +get_name({vcard_org, _, _}) -> <<"ORG">>; +get_name({vcard_photo, _, _, _}) -> <<"PHOTO">>; +get_name({vcard_sound, _, _, _}) -> <<"SOUND">>; +get_name({vcard_tel, _, _, _, _, _, _, _, _, _, _, _, _, + _, _}) -> + <<"TEL">>; +get_name({vcard_temp, _, _, _, _, _, _, _, _, _, _, _, + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, + _}) -> + <<"vCard">>; +get_name({vcard_xupdate, _, _}) -> <<"x">>; +get_name({version, _, _, _}) -> <<"query">>; +get_name({x_conference, _, _, _, _, _}) -> <<"x">>; +get_name({xcaptcha, _}) -> <<"captcha">>; +get_name({xdata, _, _, _, _, _, _}) -> <<"x">>; +get_name({xdata_field, _, _, _, _, _, _, _, _}) -> + <<"field">>; +get_name({xdata_option, _, _}) -> <<"option">>; +get_name({xevent, _, _, _, _, _}) -> <<"x">>; +get_name({xmpp_session, _}) -> <<"session">>. -get_ns({last, _, _}) -> <<"jabber:iq:last">>; -get_ns({version, _, _, _}) -> <<"jabber:iq:version">>; -get_ns({roster_item, _, _, _, _, _}) -> - <<"jabber:iq:roster">>; -get_ns({roster_query, _, _}) -> <<"jabber:iq:roster">>; -get_ns({rosterver_feature}) -> - <<"urn:xmpp:features:rosterver">>; -get_ns({privacy_item, _, _, _, _, _, _, _, _}) -> - <<"jabber:iq:privacy">>; -get_ns({privacy_list, _, _}) -> <<"jabber:iq:privacy">>; -get_ns({privacy_query, _, _, _}) -> - <<"jabber:iq:privacy">>; -get_ns({block, _}) -> <<"urn:xmpp:blocking">>; -get_ns({unblock, _}) -> <<"urn:xmpp:blocking">>; -get_ns({block_list, _}) -> <<"urn:xmpp:blocking">>; -get_ns({identity, _, _, _, _}) -> - <<"http://jabber.org/protocol/disco#info">>; -get_ns({disco_info, _, _, _, _}) -> - <<"http://jabber.org/protocol/disco#info">>; -get_ns({disco_item, _, _, _}) -> - <<"http://jabber.org/protocol/disco#items">>; -get_ns({disco_items, _, _, _}) -> - <<"http://jabber.org/protocol/disco#items">>; -get_ns({private, _}) -> <<"jabber:iq:private">>; -get_ns({bookmark_conference, _, _, _, _, _}) -> - <<"storage:bookmarks">>; -get_ns({bookmark_url, _, _}) -> <<"storage:bookmarks">>; -get_ns({bookmark_storage, _, _}) -> - <<"storage:bookmarks">>; -get_ns({stat_error, _, _}) -> - <<"http://jabber.org/protocol/stats">>; -get_ns({stat, _, _, _, _}) -> - <<"http://jabber.org/protocol/stats">>; -get_ns({stats, _, _}) -> - <<"http://jabber.org/protocol/stats">>; -get_ns({iq, _, _, _, _, _, _}) -> <<"jabber:client">>; -get_ns({message, _, _, _, _, _, _, _, _, _}) -> - <<"jabber:client">>; -get_ns({presence, _, _, _, _, _, _, _, _, _}) -> - <<"jabber:client">>; -get_ns({gone, _}) -> - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>; -get_ns({redirect, _}) -> - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>; -get_ns({error, _, _, _, _, _, _}) -> - <<"jabber:client">>; +get_ns({address, _, _, _, _, _}) -> + <<"http://jabber.org/protocol/address">>; +get_ns({addresses, _}) -> + <<"http://jabber.org/protocol/address">>; +get_ns({adhoc_actions, _, _, _, _}) -> + <<"http://jabber.org/protocol/commands">>; +get_ns({adhoc_command, _, _, _, _, _, _, _, _}) -> + <<"http://jabber.org/protocol/commands">>; +get_ns({adhoc_note, _, _}) -> + <<"http://jabber.org/protocol/commands">>; get_ns({bind, _, _}) -> <<"urn:ietf:params:xml:ns:xmpp-bind">>; -get_ns({legacy_auth, _, _, _, _}) -> - <<"jabber:iq:auth">>; -get_ns({sasl_auth, _, _}) -> - <<"urn:ietf:params:xml:ns:xmpp-sasl">>; -get_ns({sasl_abort}) -> - <<"urn:ietf:params:xml:ns:xmpp-sasl">>; -get_ns({sasl_challenge, _}) -> - <<"urn:ietf:params:xml:ns:xmpp-sasl">>; -get_ns({sasl_response, _}) -> - <<"urn:ietf:params:xml:ns:xmpp-sasl">>; -get_ns({sasl_success, _}) -> - <<"urn:ietf:params:xml:ns:xmpp-sasl">>; -get_ns({sasl_failure, _, _}) -> - <<"urn:ietf:params:xml:ns:xmpp-sasl">>; -get_ns({sasl_mechanisms, _}) -> - <<"urn:ietf:params:xml:ns:xmpp-sasl">>; -get_ns({starttls, _}) -> - <<"urn:ietf:params:xml:ns:xmpp-tls">>; -get_ns({starttls_proceed}) -> - <<"urn:ietf:params:xml:ns:xmpp-tls">>; -get_ns({starttls_failure}) -> - <<"urn:ietf:params:xml:ns:xmpp-tls">>; -get_ns({compress_failure, _}) -> - <<"http://jabber.org/protocol/compress">>; -get_ns({compress, _}) -> - <<"http://jabber.org/protocol/compress">>; -get_ns({compressed}) -> - <<"http://jabber.org/protocol/compress">>; -get_ns({compression, _}) -> - <<"http://jabber.org/features/compress">>; -get_ns({stream_features, _}) -> - <<"http://etherx.jabber.org/streams">>; -get_ns({p1_push}) -> <<"p1:push">>; -get_ns({p1_rebind}) -> <<"p1:rebind">>; -get_ns({p1_ack}) -> <<"p1:ack">>; +get_ns({block, _}) -> <<"urn:xmpp:blocking">>; +get_ns({block_list, _}) -> <<"urn:xmpp:blocking">>; +get_ns({bob_data, _, _, _, _}) -> <<"urn:xmpp:bob">>; +get_ns({bookmark_conference, _, _, _, _, _}) -> + <<"storage:bookmarks">>; +get_ns({bookmark_storage, _, _}) -> + <<"storage:bookmarks">>; +get_ns({bookmark_url, _, _}) -> <<"storage:bookmarks">>; +get_ns({bytestreams, _, _, _, _, _, _}) -> + <<"http://jabber.org/protocol/bytestreams">>; get_ns({caps, _, _, _, _}) -> <<"http://jabber.org/protocol/caps">>; -get_ns({feature_register}) -> - <<"http://jabber.org/features/iq-register">>; -get_ns({register, _, _, _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, _}) -> - <<"jabber:iq:register">>; -get_ns({xmpp_session, _}) -> - <<"urn:ietf:params:xml:ns:xmpp-session">>; -get_ns({ping}) -> <<"urn:xmpp:ping">>; -get_ns({time, _, _}) -> <<"urn:xmpp:time">>; -get_ns({'see-other-host', _}) -> - <<"urn:ietf:params:xml:ns:xmpp-streams">>; -get_ns({stream_error, _, _}) -> - <<"http://etherx.jabber.org/streams">>; -get_ns({vcard_name, _, _, _, _, _}) -> <<"vcard-temp">>; -get_ns({vcard_adr, _, _, _, _, _, _, _, _, _, _, _, _, - _, _}) -> - <<"vcard-temp">>; -get_ns({vcard_label, _, _, _, _, _, _, _, _}) -> - <<"vcard-temp">>; -get_ns({vcard_tel, _, _, _, _, _, _, _, _, _, _, _, _, - _, _}) -> - <<"vcard-temp">>; -get_ns({vcard_email, _, _, _, _, _, _}) -> - <<"vcard-temp">>; -get_ns({vcard_geo, _, _}) -> <<"vcard-temp">>; -get_ns({vcard_logo, _, _, _}) -> <<"vcard-temp">>; -get_ns({vcard_photo, _, _, _}) -> <<"vcard-temp">>; -get_ns({vcard_org, _, _}) -> <<"vcard-temp">>; -get_ns({vcard_sound, _, _, _}) -> <<"vcard-temp">>; -get_ns({vcard_key, _, _}) -> <<"vcard-temp">>; -get_ns({vcard_temp, _, _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _}) -> - <<"vcard-temp">>; -get_ns({vcard_xupdate, _, _}) -> - <<"vcard-temp:x:update">>; -get_ns({xdata_option, _, _}) -> <<"jabber:x:data">>; -get_ns({xdata_field, _, _, _, _, _, _, _, _}) -> - <<"jabber:x:data">>; -get_ns({xdata, _, _, _, _, _, _}) -> - <<"jabber:x:data">>; -get_ns({pubsub_subscription, _, _, _, _}) -> - <<"http://jabber.org/protocol/pubsub">>; -get_ns({pubsub_affiliation, _, _}) -> - <<"http://jabber.org/protocol/pubsub">>; -get_ns({pubsub_item, _, _}) -> - <<"http://jabber.org/protocol/pubsub">>; -get_ns({pubsub_items, _, _, _, _}) -> - <<"http://jabber.org/protocol/pubsub">>; -get_ns({pubsub_event_item, _, _, _, _}) -> - <<"http://jabber.org/protocol/pubsub#event">>; -get_ns({pubsub_event_items, _, _, _}) -> - <<"http://jabber.org/protocol/pubsub#event">>; -get_ns({pubsub_event, _}) -> - <<"http://jabber.org/protocol/pubsub#event">>; -get_ns({pubsub_subscribe, _, _}) -> - <<"http://jabber.org/protocol/pubsub">>; -get_ns({pubsub_unsubscribe, _, _, _}) -> - <<"http://jabber.org/protocol/pubsub">>; -get_ns({pubsub_publish, _, _}) -> - <<"http://jabber.org/protocol/pubsub">>; -get_ns({pubsub_options, _, _, _, _}) -> - <<"http://jabber.org/protocol/pubsub">>; -get_ns({pubsub_retract, _, _, _}) -> - <<"http://jabber.org/protocol/pubsub">>; -get_ns({pubsub, _, _, _, _, _, _, _, _}) -> - <<"http://jabber.org/protocol/pubsub">>; -get_ns({shim, _}) -> - <<"http://jabber.org/protocol/shim">>; +get_ns({carbons_disable}) -> <<"urn:xmpp:carbons:2">>; +get_ns({carbons_enable}) -> <<"urn:xmpp:carbons:2">>; +get_ns({carbons_private}) -> <<"urn:xmpp:carbons:2">>; +get_ns({carbons_received, _}) -> + <<"urn:xmpp:carbons:2">>; +get_ns({carbons_sent, _}) -> <<"urn:xmpp:carbons:2">>; get_ns({chatstate, active}) -> <<"http://jabber.org/protocol/chatstates">>; get_ns({chatstate, composing}) -> @@ -3078,117 +3419,281 @@ get_ns({chatstate, inactive}) -> <<"http://jabber.org/protocol/chatstates">>; get_ns({chatstate, paused}) -> <<"http://jabber.org/protocol/chatstates">>; -get_ns({delay, _, _, _}) -> <<"urn:xmpp:delay">>; -get_ns({streamhost, _, _, _}) -> - <<"http://jabber.org/protocol/bytestreams">>; -get_ns({bytestreams, _, _, _, _, _, _}) -> - <<"http://jabber.org/protocol/bytestreams">>; -get_ns({muc_history, _, _, _, _}) -> - <<"http://jabber.org/protocol/muc">>; -get_ns({muc_decline, _, _, _}) -> - <<"http://jabber.org/protocol/muc#user">>; -get_ns({muc_destroy, Xmlns, _, _, _}) -> Xmlns; -get_ns({muc_invite, _, _, _, _}) -> - <<"http://jabber.org/protocol/muc#user">>; -get_ns({muc_user, _, _, _, _, _, _}) -> - <<"http://jabber.org/protocol/muc#user">>; -get_ns({muc_owner, _, _, _}) -> - <<"http://jabber.org/protocol/muc#owner">>; -get_ns({muc_admin, _}) -> - <<"http://jabber.org/protocol/muc#admin">>; -get_ns({muc, _, _}) -> - <<"http://jabber.org/protocol/muc">>; -get_ns({muc_unique, _}) -> - <<"http://jabber.org/protocol/muc#unique">>; -get_ns({x_conference, _, _, _, _, _}) -> - <<"jabber:x:conference">>; -get_ns({muc_subscriptions, _}) -> - <<"urn:xmpp:mucsub:0">>; -get_ns({muc_subscribe, _, _}) -> - <<"urn:xmpp:mucsub:0">>; -get_ns({muc_unsubscribe}) -> <<"urn:xmpp:mucsub:0">>; -get_ns({rsm_first, _, _}) -> - <<"http://jabber.org/protocol/rsm">>; -get_ns({rsm_set, _, _, _, _, _, _, _}) -> - <<"http://jabber.org/protocol/rsm">>; -get_ns({mam_query, Xmlns, _, _, _, _, _, _, _}) -> - Xmlns; -get_ns({mam_archived, _, _}) -> <<"urn:xmpp:mam:tmp">>; -get_ns({mam_result, Xmlns, _, _, _}) -> Xmlns; -get_ns({mam_prefs, Xmlns, _, _, _}) -> Xmlns; -get_ns({mam_fin, _, _, _, _}) -> <<"urn:xmpp:mam:0">>; -get_ns({forwarded, _, _}) -> <<"urn:xmpp:forward:0">>; -get_ns({carbons_disable}) -> <<"urn:xmpp:carbons:2">>; -get_ns({carbons_enable}) -> <<"urn:xmpp:carbons:2">>; -get_ns({carbons_private}) -> <<"urn:xmpp:carbons:2">>; -get_ns({carbons_received, _}) -> - <<"urn:xmpp:carbons:2">>; -get_ns({carbons_sent, _}) -> <<"urn:xmpp:carbons:2">>; -get_ns({feature_csi, Xmlns}) -> Xmlns; +get_ns({client_id, _}) -> <<"urn:xmpp:sid:0">>; +get_ns({compress, _}) -> + <<"http://jabber.org/protocol/compress">>; +get_ns({compress_failure, _}) -> + <<"http://jabber.org/protocol/compress">>; +get_ns({compressed}) -> + <<"http://jabber.org/protocol/compress">>; +get_ns({compression, _}) -> + <<"http://jabber.org/features/compress">>; get_ns({csi, active}) -> <<"urn:xmpp:csi:0">>; get_ns({csi, inactive}) -> <<"urn:xmpp:csi:0">>; -get_ns({feature_sm, Xmlns}) -> Xmlns; -get_ns({sm_enable, _, _, Xmlns}) -> Xmlns; -get_ns({sm_enabled, _, _, _, _, Xmlns}) -> Xmlns; -get_ns({sm_resume, _, _, Xmlns}) -> Xmlns; -get_ns({sm_resumed, _, _, Xmlns}) -> Xmlns; -get_ns({sm_r, Xmlns}) -> Xmlns; -get_ns({sm_a, _, Xmlns}) -> Xmlns; -get_ns({sm_failed, _, _, Xmlns}) -> Xmlns; -get_ns({offline_item, _, _}) -> - <<"http://jabber.org/protocol/offline">>; -get_ns({offline, _, _, _}) -> - <<"http://jabber.org/protocol/offline">>; -get_ns({mix_join, _, _}) -> <<"urn:xmpp:mix:0">>; -get_ns({mix_leave}) -> <<"urn:xmpp:mix:0">>; -get_ns({mix_participant, _, _}) -> <<"urn:xmpp:mix:0">>; -get_ns({hint, 'no-copy'}) -> <<"urn:xmpp:hints">>; -get_ns({hint, 'no-store'}) -> <<"urn:xmpp:hints">>; -get_ns({hint, 'no-storage'}) -> <<"urn:xmpp:hints">>; -get_ns({hint, store}) -> <<"urn:xmpp:hints">>; -get_ns({hint, 'no-permanent-store'}) -> - <<"urn:xmpp:hints">>; -get_ns({hint, 'no-permanent-storage'}) -> - <<"urn:xmpp:hints">>; -get_ns({search_item, _, _, _, _, _}) -> - <<"jabber:iq:search">>; -get_ns({search, _, _, _, _, _, _, _}) -> - <<"jabber:iq:search">>; -get_ns({xevent, _, _, _, _, _}) -> <<"jabber:x:event">>; -get_ns({expire, _, _}) -> <<"jabber:x:expire">>; -get_ns({nick, _}) -> - <<"http://jabber.org/protocol/nick">>; -get_ns({address, _, _, _, _, _}) -> - <<"http://jabber.org/protocol/address">>; -get_ns({addresses, _}) -> - <<"http://jabber.org/protocol/address">>; -get_ns({stanza_id, _, _}) -> <<"urn:xmpp:sid:0">>; -get_ns({client_id, _}) -> <<"urn:xmpp:sid:0">>; -get_ns({adhoc_actions, _, _, _, _}) -> - <<"http://jabber.org/protocol/commands">>; -get_ns({adhoc_note, _, _}) -> - <<"http://jabber.org/protocol/commands">>; -get_ns({adhoc_command, _, _, _, _, _, _, _, _}) -> - <<"http://jabber.org/protocol/commands">>; get_ns({db_result, _, _, _, _, _}) -> <<"jabber:client">>; get_ns({db_verify, _, _, _, _, _, _}) -> <<"jabber:client">>; +get_ns({delay, _, _, _}) -> <<"urn:xmpp:delay">>; +get_ns({disco_info, _, _, _, _}) -> + <<"http://jabber.org/protocol/disco#info">>; +get_ns({disco_item, _, _, _}) -> + <<"http://jabber.org/protocol/disco#items">>; +get_ns({disco_items, _, _, _}) -> + <<"http://jabber.org/protocol/disco#items">>; +get_ns({error, _, _, _, _, _, _}) -> + <<"jabber:client">>; +get_ns({expire, _, _}) -> <<"jabber:x:expire">>; +get_ns({feature_csi, Xmlns}) -> Xmlns; +get_ns({feature_register}) -> + <<"http://jabber.org/features/iq-register">>; +get_ns({feature_sm, Xmlns}) -> Xmlns; +get_ns({forwarded, _, _}) -> <<"urn:xmpp:forward:0">>; +get_ns({gone, _}) -> + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>; get_ns({handshake, _}) -> <<"jabber:client">>; -get_ns({stream_start, _, _, _, _, Xmlns, _, _, _}) -> +get_ns({hint, 'no-copy'}) -> <<"urn:xmpp:hints">>; +get_ns({hint, 'no-permanent-storage'}) -> + <<"urn:xmpp:hints">>; +get_ns({hint, 'no-permanent-store'}) -> + <<"urn:xmpp:hints">>; +get_ns({hint, 'no-storage'}) -> <<"urn:xmpp:hints">>; +get_ns({hint, 'no-store'}) -> <<"urn:xmpp:hints">>; +get_ns({hint, store}) -> <<"urn:xmpp:hints">>; +get_ns({identity, _, _, _, _}) -> + <<"http://jabber.org/protocol/disco#info">>; +get_ns({iq, _, _, _, _, _, _}) -> <<"jabber:client">>; +get_ns({last, _, _}) -> <<"jabber:iq:last">>; +get_ns({legacy_auth, _, _, _, _}) -> + <<"jabber:iq:auth">>; +get_ns({mam_archived, _, _}) -> <<"urn:xmpp:mam:tmp">>; +get_ns({mam_fin, _, _, _, _}) -> <<"urn:xmpp:mam:0">>; +get_ns({mam_prefs, Xmlns, _, _, _}) -> Xmlns; +get_ns({mam_query, Xmlns, _, _, _, _, _, _, _}) -> Xmlns; -get_ns({bob_data, _, _, _, _}) -> <<"urn:xmpp:bob">>; -get_ns({xcaptcha, _}) -> <<"urn:xmpp:captcha">>; -get_ns({media_uri, _, _}) -> - <<"urn:xmpp:media-element">>; +get_ns({mam_result, Xmlns, _, _, _}) -> Xmlns; get_ns({media, _, _, _}) -> <<"urn:xmpp:media-element">>; +get_ns({media_uri, _, _}) -> + <<"urn:xmpp:media-element">>; +get_ns({message, _, _, _, _, _, _, _, _, _}) -> + <<"jabber:client">>; +get_ns({mix_join, _, _}) -> <<"urn:xmpp:mix:0">>; +get_ns({mix_leave}) -> <<"urn:xmpp:mix:0">>; +get_ns({mix_participant, _, _}) -> <<"urn:xmpp:mix:0">>; +get_ns({muc, _, _}) -> + <<"http://jabber.org/protocol/muc">>; +get_ns({muc_admin, _}) -> + <<"http://jabber.org/protocol/muc#admin">>; +get_ns({muc_decline, _, _, _}) -> + <<"http://jabber.org/protocol/muc#user">>; +get_ns({muc_destroy, Xmlns, _, _, _}) -> Xmlns; +get_ns({muc_history, _, _, _, _}) -> + <<"http://jabber.org/protocol/muc">>; +get_ns({muc_invite, _, _, _, _}) -> + <<"http://jabber.org/protocol/muc#user">>; +get_ns({muc_owner, _, _, _}) -> + <<"http://jabber.org/protocol/muc#owner">>; +get_ns({muc_subscribe, _, _}) -> + <<"urn:xmpp:mucsub:0">>; +get_ns({muc_subscriptions, _}) -> + <<"urn:xmpp:mucsub:0">>; +get_ns({muc_unique, _}) -> + <<"http://jabber.org/protocol/muc#unique">>; +get_ns({muc_unsubscribe}) -> <<"urn:xmpp:mucsub:0">>; +get_ns({muc_user, _, _, _, _, _, _}) -> + <<"http://jabber.org/protocol/muc#user">>; +get_ns({nick, _}) -> + <<"http://jabber.org/protocol/nick">>; +get_ns({offline, _, _, _}) -> + <<"http://jabber.org/protocol/offline">>; +get_ns({offline_item, _, _}) -> + <<"http://jabber.org/protocol/offline">>; get_ns({oob_x, _, _, _}) -> <<"jabber:x:oob">>; +get_ns({p1_ack}) -> <<"p1:ack">>; +get_ns({p1_push}) -> <<"p1:push">>; +get_ns({p1_rebind}) -> <<"p1:rebind">>; +get_ns({ping}) -> <<"urn:xmpp:ping">>; +get_ns({presence, _, _, _, _, _, _, _, _, _}) -> + <<"jabber:client">>; +get_ns({privacy_item, _, _, _, _, _, _, _, _}) -> + <<"jabber:iq:privacy">>; +get_ns({privacy_list, _, _}) -> <<"jabber:iq:privacy">>; +get_ns({privacy_query, _, _, _}) -> + <<"jabber:iq:privacy">>; +get_ns({private, _}) -> <<"jabber:iq:private">>; +get_ns({ps_affiliation, Xmlns, _, _, _}) -> Xmlns; +get_ns({ps_error, 'closed-node', _}) -> + <<"http://jabber.org/protocol/pubsub#errors">>; +get_ns({ps_error, 'configuration-required', _}) -> + <<"http://jabber.org/protocol/pubsub#errors">>; +get_ns({ps_error, 'invalid-jid', _}) -> + <<"http://jabber.org/protocol/pubsub#errors">>; +get_ns({ps_error, 'invalid-options', _}) -> + <<"http://jabber.org/protocol/pubsub#errors">>; +get_ns({ps_error, 'invalid-payload', _}) -> + <<"http://jabber.org/protocol/pubsub#errors">>; +get_ns({ps_error, 'invalid-subid', _}) -> + <<"http://jabber.org/protocol/pubsub#errors">>; +get_ns({ps_error, 'item-forbidden', _}) -> + <<"http://jabber.org/protocol/pubsub#errors">>; +get_ns({ps_error, 'item-required', _}) -> + <<"http://jabber.org/protocol/pubsub#errors">>; +get_ns({ps_error, 'jid-required', _}) -> + <<"http://jabber.org/protocol/pubsub#errors">>; +get_ns({ps_error, 'max-items-exceeded', _}) -> + <<"http://jabber.org/protocol/pubsub#errors">>; +get_ns({ps_error, 'max-nodes-exceeded', _}) -> + <<"http://jabber.org/protocol/pubsub#errors">>; +get_ns({ps_error, 'nodeid-required', _}) -> + <<"http://jabber.org/protocol/pubsub#errors">>; +get_ns({ps_error, 'not-in-roster-group', _}) -> + <<"http://jabber.org/protocol/pubsub#errors">>; +get_ns({ps_error, 'not-subscribed', _}) -> + <<"http://jabber.org/protocol/pubsub#errors">>; +get_ns({ps_error, 'payload-required', _}) -> + <<"http://jabber.org/protocol/pubsub#errors">>; +get_ns({ps_error, 'payload-too-big', _}) -> + <<"http://jabber.org/protocol/pubsub#errors">>; +get_ns({ps_error, 'pending-subscription', _}) -> + <<"http://jabber.org/protocol/pubsub#errors">>; +get_ns({ps_error, 'presence-subscription-required', + _}) -> + <<"http://jabber.org/protocol/pubsub#errors">>; +get_ns({ps_error, 'subid-required', _}) -> + <<"http://jabber.org/protocol/pubsub#errors">>; +get_ns({ps_error, 'too-many-subscriptions', _}) -> + <<"http://jabber.org/protocol/pubsub#errors">>; +get_ns({ps_error, unsupported, _}) -> + <<"http://jabber.org/protocol/pubsub#errors">>; +get_ns({ps_error, 'unsupported-access-model', _}) -> + <<"http://jabber.org/protocol/pubsub#errors">>; +get_ns({ps_event, _, _, _, _, _, _}) -> + <<"http://jabber.org/protocol/pubsub#event">>; +get_ns({ps_item, Xmlns, _, _, _, _}) -> Xmlns; +get_ns({ps_items, Xmlns, _, _, _, _, _}) -> Xmlns; +get_ns({ps_options, _, _, _, _}) -> + <<"http://jabber.org/protocol/pubsub">>; +get_ns({ps_publish, _, _}) -> + <<"http://jabber.org/protocol/pubsub">>; +get_ns({ps_retract, _, _, _}) -> + <<"http://jabber.org/protocol/pubsub">>; +get_ns({ps_subscribe, _, _}) -> + <<"http://jabber.org/protocol/pubsub">>; +get_ns({ps_subscription, Xmlns, _, _, _, _, _}) -> + Xmlns; +get_ns({ps_unsubscribe, _, _, _}) -> + <<"http://jabber.org/protocol/pubsub">>; +get_ns({pubsub, _, _, _, _, _, _, _, _, _, _, _, _, _, + _, _, _}) -> + <<"http://jabber.org/protocol/pubsub">>; +get_ns({pubsub_owner, _, _, _, _, _, _}) -> + <<"http://jabber.org/protocol/pubsub#owner">>; +get_ns({redirect, _}) -> + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>; +get_ns({register, _, _, _, _, _, _, _, _, _, _, _, _, _, + _, _, _, _, _, _, _, _, _}) -> + <<"jabber:iq:register">>; +get_ns({roster_item, _, _, _, _, _}) -> + <<"jabber:iq:roster">>; +get_ns({roster_query, _, _}) -> <<"jabber:iq:roster">>; +get_ns({rosterver_feature}) -> + <<"urn:xmpp:features:rosterver">>; +get_ns({rsm_first, _, _}) -> + <<"http://jabber.org/protocol/rsm">>; +get_ns({rsm_set, _, _, _, _, _, _, _}) -> + <<"http://jabber.org/protocol/rsm">>; +get_ns({sasl_abort}) -> + <<"urn:ietf:params:xml:ns:xmpp-sasl">>; +get_ns({sasl_auth, _, _}) -> + <<"urn:ietf:params:xml:ns:xmpp-sasl">>; +get_ns({sasl_challenge, _}) -> + <<"urn:ietf:params:xml:ns:xmpp-sasl">>; +get_ns({sasl_failure, _, _}) -> + <<"urn:ietf:params:xml:ns:xmpp-sasl">>; +get_ns({sasl_mechanisms, _}) -> + <<"urn:ietf:params:xml:ns:xmpp-sasl">>; +get_ns({sasl_response, _}) -> + <<"urn:ietf:params:xml:ns:xmpp-sasl">>; +get_ns({sasl_success, _}) -> + <<"urn:ietf:params:xml:ns:xmpp-sasl">>; +get_ns({search, _, _, _, _, _, _, _}) -> + <<"jabber:iq:search">>; +get_ns({search_item, _, _, _, _, _}) -> + <<"jabber:iq:search">>; +get_ns({'see-other-host', _}) -> + <<"urn:ietf:params:xml:ns:xmpp-streams">>; +get_ns({shim, _}) -> + <<"http://jabber.org/protocol/shim">>; get_ns({sic, _, _, Xmlns}) -> Xmlns; +get_ns({sm_a, _, Xmlns}) -> Xmlns; +get_ns({sm_enable, _, _, Xmlns}) -> Xmlns; +get_ns({sm_enabled, _, _, _, _, Xmlns}) -> Xmlns; +get_ns({sm_failed, _, _, Xmlns}) -> Xmlns; +get_ns({sm_r, Xmlns}) -> Xmlns; +get_ns({sm_resume, _, _, Xmlns}) -> Xmlns; +get_ns({sm_resumed, _, _, Xmlns}) -> Xmlns; +get_ns({stanza_id, _, _}) -> <<"urn:xmpp:sid:0">>; +get_ns({starttls, _}) -> + <<"urn:ietf:params:xml:ns:xmpp-tls">>; +get_ns({starttls_failure}) -> + <<"urn:ietf:params:xml:ns:xmpp-tls">>; +get_ns({starttls_proceed}) -> + <<"urn:ietf:params:xml:ns:xmpp-tls">>; +get_ns({stat, _, _, _, _}) -> + <<"http://jabber.org/protocol/stats">>; +get_ns({stat_error, _, _}) -> + <<"http://jabber.org/protocol/stats">>; +get_ns({stats, _, _}) -> + <<"http://jabber.org/protocol/stats">>; +get_ns({stream_error, _, _}) -> + <<"http://etherx.jabber.org/streams">>; +get_ns({stream_features, _}) -> + <<"http://etherx.jabber.org/streams">>; +get_ns({stream_start, _, _, _, _, Xmlns, _, _, _}) -> + Xmlns; +get_ns({streamhost, _, _, _}) -> + <<"http://jabber.org/protocol/bytestreams">>; +get_ns({thumbnail, _, _, _, _}) -> + <<"urn:xmpp:thumbs:1">>; +get_ns({time, _, _}) -> <<"urn:xmpp:time">>; +get_ns({unblock, _}) -> <<"urn:xmpp:blocking">>; get_ns({upload_request, _, _, _, Xmlns}) -> Xmlns; get_ns({upload_slot, _, _, Xmlns}) -> Xmlns; -get_ns({thumbnail, _, _, _, _}) -> - <<"urn:xmpp:thumbs:1">>. +get_ns({vcard_adr, _, _, _, _, _, _, _, _, _, _, _, _, + _, _}) -> + <<"vcard-temp">>; +get_ns({vcard_email, _, _, _, _, _, _}) -> + <<"vcard-temp">>; +get_ns({vcard_geo, _, _}) -> <<"vcard-temp">>; +get_ns({vcard_key, _, _}) -> <<"vcard-temp">>; +get_ns({vcard_label, _, _, _, _, _, _, _, _}) -> + <<"vcard-temp">>; +get_ns({vcard_logo, _, _, _}) -> <<"vcard-temp">>; +get_ns({vcard_name, _, _, _, _, _}) -> <<"vcard-temp">>; +get_ns({vcard_org, _, _}) -> <<"vcard-temp">>; +get_ns({vcard_photo, _, _, _}) -> <<"vcard-temp">>; +get_ns({vcard_sound, _, _, _}) -> <<"vcard-temp">>; +get_ns({vcard_tel, _, _, _, _, _, _, _, _, _, _, _, _, + _, _}) -> + <<"vcard-temp">>; +get_ns({vcard_temp, _, _, _, _, _, _, _, _, _, _, _, _, + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _}) -> + <<"vcard-temp">>; +get_ns({vcard_xupdate, _, _}) -> + <<"vcard-temp:x:update">>; +get_ns({version, _, _, _}) -> <<"jabber:iq:version">>; +get_ns({x_conference, _, _, _, _, _}) -> + <<"jabber:x:conference">>; +get_ns({xcaptcha, _}) -> <<"urn:xmpp:captcha">>; +get_ns({xdata, _, _, _, _, _, _}) -> + <<"jabber:x:data">>; +get_ns({xdata_field, _, _, _, _, _, _, _, _}) -> + <<"jabber:x:data">>; +get_ns({xdata_option, _, _}) -> <<"jabber:x:data">>; +get_ns({xevent, _, _, _, _, _}) -> <<"jabber:x:event">>; +get_ns({xmpp_session, _}) -> + <<"urn:ietf:params:xml:ns:xmpp-session">>. dec_int(Val) -> dec_int(Val, infinity, infinity). @@ -3337,22 +3842,27 @@ pp(xdata_field, 8) -> sub_els]; pp(xdata, 6) -> [type, instructions, title, reported, items, fields]; -pp(pubsub_subscription, 4) -> [jid, node, subid, type]; -pp(pubsub_affiliation, 2) -> [node, type]; -pp(pubsub_item, 2) -> [id, xml_els]; -pp(pubsub_items, 4) -> [node, max_items, subid, items]; -pp(pubsub_event_item, 4) -> - [id, node, publisher, xml_els]; -pp(pubsub_event_items, 3) -> [node, retract, items]; -pp(pubsub_event, 1) -> [items]; -pp(pubsub_subscribe, 2) -> [node, jid]; -pp(pubsub_unsubscribe, 3) -> [node, jid, subid]; -pp(pubsub_publish, 2) -> [node, items]; -pp(pubsub_options, 4) -> [node, jid, subid, xdata]; -pp(pubsub_retract, 3) -> [node, notify, items]; -pp(pubsub, 8) -> - [subscriptions, affiliations, publish, subscribe, - unsubscribe, options, items, retract]; +pp(ps_subscription, 6) -> + [xmlns, jid, type, node, subid, expiry]; +pp(ps_item, 5) -> [xmlns, id, xml_els, node, publisher]; +pp(ps_items, 6) -> + [xmlns, node, items, max_items, subid, retract]; +pp(ps_event, 6) -> + [items, purge, subscription, delete, create, + configuration]; +pp(ps_subscribe, 2) -> [node, jid]; +pp(ps_unsubscribe, 3) -> [node, jid, subid]; +pp(ps_publish, 2) -> [node, items]; +pp(ps_options, 4) -> [node, jid, subid, xdata]; +pp(ps_retract, 3) -> [node, notify, items]; +pp(pubsub, 16) -> + [subscriptions, subscription, affiliations, publish, + publish_options, subscribe, unsubscribe, options, items, + retract, create, configure, default, delete, purge, + rsm]; +pp(pubsub_owner, 6) -> + [affiliations, configure, default, delete, purge, + subscriptions]; pp(shim, 1) -> [headers]; pp(delay, 3) -> [stamp, from, desc]; pp(streamhost, 3) -> [jid, host, port]; @@ -12187,237 +12697,1244 @@ encode_shim_header_cdata(<<>>, _acc) -> _acc; encode_shim_header_cdata(_val, _acc) -> [{xmlcdata, _val} | _acc]. +decode_pubsub_error_unsupported_access_model(__TopXMLNS, + __IgnoreEls, + {xmlel, + <<"unsupported-access-model">>, + _attrs, _els}) -> + {ps_error, 'unsupported-access-model', undefined}. + +encode_pubsub_error_unsupported_access_model({ps_error, + 'unsupported-access-model', _}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"unsupported-access-model">>, _attrs, _els}. + +decode_pubsub_error_unsupported(__TopXMLNS, __IgnoreEls, + {xmlel, <<"unsupported">>, _attrs, _els}) -> + Feature = + decode_pubsub_error_unsupported_attrs(__TopXMLNS, + _attrs, undefined), + {ps_error, unsupported, Feature}. + +decode_pubsub_error_unsupported_attrs(__TopXMLNS, + [{<<"feature">>, _val} | _attrs], + _Feature) -> + decode_pubsub_error_unsupported_attrs(__TopXMLNS, + _attrs, _val); +decode_pubsub_error_unsupported_attrs(__TopXMLNS, + [_ | _attrs], Feature) -> + decode_pubsub_error_unsupported_attrs(__TopXMLNS, + _attrs, Feature); +decode_pubsub_error_unsupported_attrs(__TopXMLNS, [], + Feature) -> + decode_pubsub_error_unsupported_attr_feature(__TopXMLNS, + Feature). + +encode_pubsub_error_unsupported({ps_error, unsupported, + Feature}, + _xmlns_attrs) -> + _els = [], + _attrs = + encode_pubsub_error_unsupported_attr_feature(Feature, + _xmlns_attrs), + {xmlel, <<"unsupported">>, _attrs, _els}. + +decode_pubsub_error_unsupported_attr_feature(__TopXMLNS, + undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"feature">>, <<"unsupported">>, + __TopXMLNS}}); +decode_pubsub_error_unsupported_attr_feature(__TopXMLNS, + _val) -> + case catch dec_enum(_val, + ['access-authorize', 'access-open', 'access-presence', + 'access-roster', 'access-whitelist', 'auto-create', + 'auto-subscribe', collections, 'config-node', + 'create-and-configure', 'create-nodes', 'delete-items', + 'delete-nodes', 'filtered-notifications', + 'get-pending', 'instant-nodes', 'item-ids', + 'last-published', 'leased-subscription', + 'manage-subscriptions', 'member-affiliation', + 'meta-data', 'modify-affiliations', 'multi-collection', + 'multi-subscribe', 'outcast-affiliation', + 'persistent-items', 'presence-notifications', + 'presence-subscribe', publish, 'publish-options', + 'publish-only-affiliation', 'publisher-affiliation', + 'purge-nodes', 'retract-items', + 'retrieve-affiliations', 'retrieve-default', + 'retrieve-items', 'retrieve-subscriptions', subscribe, + 'subscription-options', 'subscription-notifications']) + of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"feature">>, <<"unsupported">>, + __TopXMLNS}}); + _res -> _res + end. + +encode_pubsub_error_unsupported_attr_feature(_val, + _acc) -> + [{<<"feature">>, enc_enum(_val)} | _acc]. + +decode_pubsub_error_too_many_subscriptions(__TopXMLNS, + __IgnoreEls, + {xmlel, <<"too-many-subscriptions">>, + _attrs, _els}) -> + {ps_error, 'too-many-subscriptions', undefined}. + +encode_pubsub_error_too_many_subscriptions({ps_error, + 'too-many-subscriptions', _}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"too-many-subscriptions">>, _attrs, _els}. + +decode_pubsub_error_subid_required(__TopXMLNS, + __IgnoreEls, + {xmlel, <<"subid-required">>, _attrs, + _els}) -> + {ps_error, 'subid-required', undefined}. + +encode_pubsub_error_subid_required({ps_error, + 'subid-required', _}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"subid-required">>, _attrs, _els}. + +decode_pubsub_error_presence_subscription_required(__TopXMLNS, + __IgnoreEls, + {xmlel, + <<"presence-subscription-required">>, + _attrs, _els}) -> + {ps_error, 'presence-subscription-required', undefined}. + +encode_pubsub_error_presence_subscription_required({ps_error, + 'presence-subscription-required', + _}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"presence-subscription-required">>, _attrs, + _els}. + +decode_pubsub_error_pending_subscription(__TopXMLNS, + __IgnoreEls, + {xmlel, <<"pending-subscription">>, + _attrs, _els}) -> + {ps_error, 'pending-subscription', undefined}. + +encode_pubsub_error_pending_subscription({ps_error, + 'pending-subscription', _}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"pending-subscription">>, _attrs, _els}. + +decode_pubsub_error_payload_required(__TopXMLNS, + __IgnoreEls, + {xmlel, <<"payload-required">>, _attrs, + _els}) -> + {ps_error, 'payload-required', undefined}. + +encode_pubsub_error_payload_required({ps_error, + 'payload-required', _}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"payload-required">>, _attrs, _els}. + +decode_pubsub_error_payload_too_big(__TopXMLNS, + __IgnoreEls, + {xmlel, <<"payload-too-big">>, _attrs, + _els}) -> + {ps_error, 'payload-too-big', undefined}. + +encode_pubsub_error_payload_too_big({ps_error, + 'payload-too-big', _}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"payload-too-big">>, _attrs, _els}. + +decode_pubsub_error_not_subscribed(__TopXMLNS, + __IgnoreEls, + {xmlel, <<"not-subscribed">>, _attrs, + _els}) -> + {ps_error, 'not-subscribed', undefined}. + +encode_pubsub_error_not_subscribed({ps_error, + 'not-subscribed', _}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"not-subscribed">>, _attrs, _els}. + +decode_pubsub_error_not_in_roster_group(__TopXMLNS, + __IgnoreEls, + {xmlel, <<"not-in-roster-group">>, + _attrs, _els}) -> + {ps_error, 'not-in-roster-group', undefined}. + +encode_pubsub_error_not_in_roster_group({ps_error, + 'not-in-roster-group', _}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"not-in-roster-group">>, _attrs, _els}. + +decode_pubsub_error_nodeid_required(__TopXMLNS, + __IgnoreEls, + {xmlel, <<"nodeid-required">>, _attrs, + _els}) -> + {ps_error, 'nodeid-required', undefined}. + +encode_pubsub_error_nodeid_required({ps_error, + 'nodeid-required', _}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"nodeid-required">>, _attrs, _els}. + +decode_pubsub_error_max_nodes_exceeded(__TopXMLNS, + __IgnoreEls, + {xmlel, <<"max-nodes-exceeded">>, _attrs, + _els}) -> + {ps_error, 'max-nodes-exceeded', undefined}. + +encode_pubsub_error_max_nodes_exceeded({ps_error, + 'max-nodes-exceeded', _}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"max-nodes-exceeded">>, _attrs, _els}. + +decode_pubsub_error_max_items_exceeded(__TopXMLNS, + __IgnoreEls, + {xmlel, <<"max-items-exceeded">>, _attrs, + _els}) -> + {ps_error, 'max-items-exceeded', undefined}. + +encode_pubsub_error_max_items_exceeded({ps_error, + 'max-items-exceeded', _}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"max-items-exceeded">>, _attrs, _els}. + +decode_pubsub_error_jid_required(__TopXMLNS, + __IgnoreEls, + {xmlel, <<"jid-required">>, _attrs, _els}) -> + {ps_error, 'jid-required', undefined}. + +encode_pubsub_error_jid_required({ps_error, + 'jid-required', _}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"jid-required">>, _attrs, _els}. + +decode_pubsub_error_item_required(__TopXMLNS, + __IgnoreEls, + {xmlel, <<"item-required">>, _attrs, _els}) -> + {ps_error, 'item-required', undefined}. + +encode_pubsub_error_item_required({ps_error, + 'item-required', _}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"item-required">>, _attrs, _els}. + +decode_pubsub_error_item_forbidden(__TopXMLNS, + __IgnoreEls, + {xmlel, <<"item-forbidden">>, _attrs, + _els}) -> + {ps_error, 'item-forbidden', undefined}. + +encode_pubsub_error_item_forbidden({ps_error, + 'item-forbidden', _}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"item-forbidden">>, _attrs, _els}. + +decode_pubsub_error_invalid_subid(__TopXMLNS, + __IgnoreEls, + {xmlel, <<"invalid-subid">>, _attrs, _els}) -> + {ps_error, 'invalid-subid', undefined}. + +encode_pubsub_error_invalid_subid({ps_error, + 'invalid-subid', _}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"invalid-subid">>, _attrs, _els}. + +decode_pubsub_error_invalid_payload(__TopXMLNS, + __IgnoreEls, + {xmlel, <<"invalid-payload">>, _attrs, + _els}) -> + {ps_error, 'invalid-payload', undefined}. + +encode_pubsub_error_invalid_payload({ps_error, + 'invalid-payload', _}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"invalid-payload">>, _attrs, _els}. + +decode_pubsub_error_invalid_options(__TopXMLNS, + __IgnoreEls, + {xmlel, <<"invalid-options">>, _attrs, + _els}) -> + {ps_error, 'invalid-options', undefined}. + +encode_pubsub_error_invalid_options({ps_error, + 'invalid-options', _}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"invalid-options">>, _attrs, _els}. + +decode_pubsub_error_invalid_jid(__TopXMLNS, __IgnoreEls, + {xmlel, <<"invalid-jid">>, _attrs, _els}) -> + {ps_error, 'invalid-jid', undefined}. + +encode_pubsub_error_invalid_jid({ps_error, + 'invalid-jid', _}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"invalid-jid">>, _attrs, _els}. + +decode_pubsub_error_configuration_required(__TopXMLNS, + __IgnoreEls, + {xmlel, <<"configuration-required">>, + _attrs, _els}) -> + {ps_error, 'configuration-required', undefined}. + +encode_pubsub_error_configuration_required({ps_error, + 'configuration-required', _}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"configuration-required">>, _attrs, _els}. + +decode_pubsub_error_closed_node(__TopXMLNS, __IgnoreEls, + {xmlel, <<"closed-node">>, _attrs, _els}) -> + {ps_error, 'closed-node', undefined}. + +encode_pubsub_error_closed_node({ps_error, + 'closed-node', _}, + _xmlns_attrs) -> + _els = [], + _attrs = _xmlns_attrs, + {xmlel, <<"closed-node">>, _attrs, _els}. + +decode_pubsub_owner(__TopXMLNS, __IgnoreEls, + {xmlel, <<"pubsub">>, _attrs, _els}) -> + {Subscriptions, Affiliations, Default, Purge, Delete, + Configure} = + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + undefined, undefined, undefined, undefined, + undefined, undefined), + {pubsub_owner, Affiliations, Configure, Default, Delete, + Purge, Subscriptions}. + +decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, [], + Subscriptions, Affiliations, Default, Purge, Delete, + Configure) -> + {Subscriptions, Affiliations, Default, Purge, Delete, + Configure}; +decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"affiliations">>, _attrs, _} = _el | _els], + Subscriptions, Affiliations, Default, Purge, Delete, + Configure) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub#owner">> -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + Subscriptions, + decode_pubsub_owner_affiliations(__TopXMLNS, + __IgnoreEls, + _el), + Default, Purge, Delete, Configure); + <<"http://jabber.org/protocol/pubsub#owner">> -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + Subscriptions, + decode_pubsub_owner_affiliations(<<"http://jabber.org/protocol/pubsub#owner">>, + __IgnoreEls, + _el), + Default, Purge, Delete, Configure); + _ -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + Subscriptions, Affiliations, Default, Purge, + Delete, Configure) + end; +decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"configure">>, _attrs, _} = _el | _els], + Subscriptions, Affiliations, Default, Purge, Delete, + Configure) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub#owner">> -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + Subscriptions, Affiliations, Default, Purge, + Delete, + decode_pubsub_configure(__TopXMLNS, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + Subscriptions, Affiliations, Default, Purge, + Delete, + decode_pubsub_configure(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/pubsub#owner">> -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + Subscriptions, Affiliations, Default, Purge, + Delete, + decode_pubsub_configure(<<"http://jabber.org/protocol/pubsub#owner">>, + __IgnoreEls, _el)); + _ -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + Subscriptions, Affiliations, Default, Purge, + Delete, Configure) + end; +decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"default">>, _attrs, _} = _el | _els], + Subscriptions, Affiliations, Default, Purge, Delete, + Configure) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub#owner">> -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + Subscriptions, Affiliations, + decode_pubsub_default(__TopXMLNS, __IgnoreEls, + _el), + Purge, Delete, Configure); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + Subscriptions, Affiliations, + decode_pubsub_default(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el), + Purge, Delete, Configure); + <<"http://jabber.org/protocol/pubsub#owner">> -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + Subscriptions, Affiliations, + decode_pubsub_default(<<"http://jabber.org/protocol/pubsub#owner">>, + __IgnoreEls, _el), + Purge, Delete, Configure); + _ -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + Subscriptions, Affiliations, Default, Purge, + Delete, Configure) + end; +decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"delete">>, _attrs, _} = _el | _els], + Subscriptions, Affiliations, Default, Purge, Delete, + Configure) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub#owner">> -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + Subscriptions, Affiliations, Default, Purge, + decode_pubsub_delete(__TopXMLNS, __IgnoreEls, + _el), + Configure); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + Subscriptions, Affiliations, Default, Purge, + decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el), + Configure); + <<"http://jabber.org/protocol/pubsub#owner">> -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + Subscriptions, Affiliations, Default, Purge, + decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub#owner">>, + __IgnoreEls, _el), + Configure); + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + Subscriptions, Affiliations, Default, Purge, + decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub#event">>, + __IgnoreEls, _el), + Configure); + _ -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + Subscriptions, Affiliations, Default, Purge, + Delete, Configure) + end; +decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"purge">>, _attrs, _} = _el | _els], + Subscriptions, Affiliations, Default, Purge, Delete, + Configure) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub#owner">> -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + Subscriptions, Affiliations, Default, + decode_pubsub_purge(__TopXMLNS, __IgnoreEls, + _el), + Delete, Configure); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + Subscriptions, Affiliations, Default, + decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el), + Delete, Configure); + <<"http://jabber.org/protocol/pubsub#owner">> -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + Subscriptions, Affiliations, Default, + decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub#owner">>, + __IgnoreEls, _el), + Delete, Configure); + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + Subscriptions, Affiliations, Default, + decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub#event">>, + __IgnoreEls, _el), + Delete, Configure); + _ -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + Subscriptions, Affiliations, Default, Purge, + Delete, Configure) + end; +decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"subscriptions">>, _attrs, _} = _el | _els], + Subscriptions, Affiliations, Default, Purge, Delete, + Configure) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub#owner">> -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + decode_pubsub_subscriptions(__TopXMLNS, + __IgnoreEls, _el), + Affiliations, Default, Purge, Delete, + Configure); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + decode_pubsub_subscriptions(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el), + Affiliations, Default, Purge, Delete, + Configure); + <<"http://jabber.org/protocol/pubsub#owner">> -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + decode_pubsub_subscriptions(<<"http://jabber.org/protocol/pubsub#owner">>, + __IgnoreEls, _el), + Affiliations, Default, Purge, Delete, + Configure); + _ -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + Subscriptions, Affiliations, Default, Purge, + Delete, Configure) + end; +decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Subscriptions, Affiliations, Default, Purge, + Delete, Configure) -> + decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, + Subscriptions, Affiliations, Default, Purge, Delete, + Configure). + +encode_pubsub_owner({pubsub_owner, Affiliations, + Configure, Default, Delete, Purge, Subscriptions}, + _xmlns_attrs) -> + _els = + lists:reverse('encode_pubsub_owner_$subscriptions'(Subscriptions, + 'encode_pubsub_owner_$affiliations'(Affiliations, + 'encode_pubsub_owner_$default'(Default, + 'encode_pubsub_owner_$purge'(Purge, + 'encode_pubsub_owner_$delete'(Delete, + 'encode_pubsub_owner_$configure'(Configure, + []))))))), + _attrs = _xmlns_attrs, + {xmlel, <<"pubsub">>, _attrs, _els}. + +'encode_pubsub_owner_$subscriptions'(undefined, _acc) -> + _acc; +'encode_pubsub_owner_$subscriptions'(Subscriptions, + _acc) -> + [encode_pubsub_subscriptions(Subscriptions, []) | _acc]. + +'encode_pubsub_owner_$affiliations'(undefined, _acc) -> + _acc; +'encode_pubsub_owner_$affiliations'(Affiliations, + _acc) -> + [encode_pubsub_owner_affiliations(Affiliations, []) + | _acc]. + +'encode_pubsub_owner_$default'(undefined, _acc) -> _acc; +'encode_pubsub_owner_$default'(Default, _acc) -> + [encode_pubsub_default(Default, []) | _acc]. + +'encode_pubsub_owner_$purge'(undefined, _acc) -> _acc; +'encode_pubsub_owner_$purge'(Purge, _acc) -> + [encode_pubsub_purge(Purge, []) | _acc]. + +'encode_pubsub_owner_$delete'(undefined, _acc) -> _acc; +'encode_pubsub_owner_$delete'(Delete, _acc) -> + [encode_pubsub_delete(Delete, []) | _acc]. + +'encode_pubsub_owner_$configure'(undefined, _acc) -> + _acc; +'encode_pubsub_owner_$configure'(Configure, _acc) -> + [encode_pubsub_configure(Configure, []) | _acc]. + decode_pubsub(__TopXMLNS, __IgnoreEls, {xmlel, <<"pubsub">>, _attrs, _els}) -> - {Items, Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish} = + {Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, + Subscription} = decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, undefined, undefined, undefined, undefined, undefined, - undefined, undefined, undefined), - {pubsub, Subscriptions, Affiliations, Publish, - Subscribe, Unsubscribe, Options, Items, Retract}. + undefined, undefined, undefined, undefined, undefined, + undefined, undefined, undefined, undefined, undefined, + undefined), + {pubsub, Subscriptions, Subscription, Affiliations, + Publish, Publish_options, Subscribe, Unsubscribe, + Options, Items, Retract, Create, Configure, Default, + Delete, Purge, Rsm}. -decode_pubsub_els(__TopXMLNS, __IgnoreEls, [], Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) -> - {Items, Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish}; +decode_pubsub_els(__TopXMLNS, __IgnoreEls, [], + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, + Subscription) -> + {Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, + Subscription}; decode_pubsub_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"subscriptions">>, _attrs, _} = _el | _els], - Items, Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) -> + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, + Subscription) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, decode_pubsub_subscriptions(__TopXMLNS, __IgnoreEls, _el), - Retract, Unsubscribe, Subscribe, Publish); + Default, Retract, Purge, Delete, Configure, Create, + Unsubscribe, Subscribe, Publish, Rsm, Subscription); <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, decode_pubsub_subscriptions(<<"http://jabber.org/protocol/pubsub">>, __IgnoreEls, _el), - Retract, Unsubscribe, Subscribe, Publish); + Default, Retract, Purge, Delete, Configure, Create, + Unsubscribe, Subscribe, Publish, Rsm, Subscription); + <<"http://jabber.org/protocol/pubsub#owner">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + decode_pubsub_subscriptions(<<"http://jabber.org/protocol/pubsub#owner">>, + __IgnoreEls, _el), + Default, Retract, Purge, Delete, Configure, Create, + Unsubscribe, Subscribe, Publish, Rsm, Subscription); _ -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, Subscription) end; decode_pubsub_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"affiliations">>, _attrs, _} = _el | _els], - Items, Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) -> + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, + Subscription) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, decode_pubsub_affiliations(__TopXMLNS, __IgnoreEls, _el), - Subscriptions, Retract, Unsubscribe, Subscribe, - Publish); + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, Subscription); <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, decode_pubsub_affiliations(<<"http://jabber.org/protocol/pubsub">>, __IgnoreEls, _el), - Subscriptions, Retract, Unsubscribe, Subscribe, - Publish); + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, Subscription); _ -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, Subscription) end; decode_pubsub_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"subscribe">>, _attrs, _} = _el | _els], - Items, Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) -> + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, + Subscription) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, decode_pubsub_subscribe(__TopXMLNS, __IgnoreEls, _el), - Publish); + Publish, Rsm, Subscription); <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, decode_pubsub_subscribe(<<"http://jabber.org/protocol/pubsub">>, __IgnoreEls, _el), - Publish); + Publish, Rsm, Subscription); _ -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, Subscription) end; decode_pubsub_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"unsubscribe">>, _attrs, _} = _el | _els], - Items, Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) -> + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, + Subscription) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, decode_pubsub_unsubscribe(__TopXMLNS, __IgnoreEls, _el), - Subscribe, Publish); + Subscribe, Publish, Rsm, Subscription); <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, decode_pubsub_unsubscribe(<<"http://jabber.org/protocol/pubsub">>, __IgnoreEls, _el), - Subscribe, Publish); + Subscribe, Publish, Rsm, Subscription); _ -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, Subscription) end; decode_pubsub_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"options">>, _attrs, _} = _el | _els], Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) -> + [{xmlel, <<"options">>, _attrs, _} = _el | _els], + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, + Subscription) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, decode_pubsub_options(__TopXMLNS, __IgnoreEls, _el), - Affiliations, Subscriptions, Retract, Unsubscribe, - Subscribe, Publish); + Affiliations, Subscriptions, Default, Retract, + Purge, Delete, Configure, Create, Unsubscribe, + Subscribe, Publish, Rsm, Subscription); <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, decode_pubsub_options(<<"http://jabber.org/protocol/pubsub">>, __IgnoreEls, _el), - Affiliations, Subscriptions, Retract, Unsubscribe, - Subscribe, Publish); + Affiliations, Subscriptions, Default, Retract, + Purge, Delete, Configure, Create, Unsubscribe, + Subscribe, Publish, Rsm, Subscription); _ -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, Subscription) end; decode_pubsub_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"items">>, _attrs, _} = _el | _els], Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) -> + [{xmlel, <<"items">>, _attrs, _} = _el | _els], + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, + Subscription) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"http://jabber.org/protocol/pubsub">> -> decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, decode_pubsub_items(__TopXMLNS, __IgnoreEls, _el), - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish); + Options, Affiliations, Subscriptions, Default, + Retract, Purge, Delete, Configure, Create, + Unsubscribe, Subscribe, Publish, Rsm, Subscription); <<"http://jabber.org/protocol/pubsub">> -> decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, decode_pubsub_items(<<"http://jabber.org/protocol/pubsub">>, __IgnoreEls, _el), - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish); + Options, Affiliations, Subscriptions, Default, + Retract, Purge, Delete, Configure, Create, + Unsubscribe, Subscribe, Publish, Rsm, Subscription); + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, + decode_pubsub_items(<<"http://jabber.org/protocol/pubsub#event">>, + __IgnoreEls, _el), + Options, Affiliations, Subscriptions, Default, + Retract, Purge, Delete, Configure, Create, + Unsubscribe, Subscribe, Publish, Rsm, Subscription); _ -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, Subscription) end; decode_pubsub_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"retract">>, _attrs, _} = _el | _els], Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) -> + [{xmlel, <<"retract">>, _attrs, _} = _el | _els], + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, + Subscription) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, decode_pubsub_retract(__TopXMLNS, __IgnoreEls, _el), - Unsubscribe, Subscribe, Publish); + Purge, Delete, Configure, Create, Unsubscribe, + Subscribe, Publish, Rsm, Subscription); <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, decode_pubsub_retract(<<"http://jabber.org/protocol/pubsub">>, __IgnoreEls, _el), - Unsubscribe, Subscribe, Publish); + Purge, Delete, Configure, Create, Unsubscribe, + Subscribe, Publish, Rsm, Subscription); _ -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, Subscription) end; decode_pubsub_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"publish">>, _attrs, _} = _el | _els], Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) -> + [{xmlel, <<"create">>, _attrs, _} = _el | _els], + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, + Subscription) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, - decode_pubsub_publish(__TopXMLNS, __IgnoreEls, - _el)); + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, + decode_pubsub_create(__TopXMLNS, __IgnoreEls, _el), + Unsubscribe, Subscribe, Publish, Rsm, Subscription); <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, - decode_pubsub_publish(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el)); + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, + decode_pubsub_create(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el), + Unsubscribe, Subscribe, Publish, Rsm, Subscription); + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, + decode_pubsub_create(<<"http://jabber.org/protocol/pubsub#event">>, + __IgnoreEls, _el), + Unsubscribe, Subscribe, Publish, Rsm, Subscription); _ -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, Subscription) + end; +decode_pubsub_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"configure">>, _attrs, _} = _el | _els], + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, + Subscription) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + decode_pubsub_configure(__TopXMLNS, __IgnoreEls, + _el), + Create, Unsubscribe, Subscribe, Publish, Rsm, + Subscription); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + decode_pubsub_configure(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el), + Create, Unsubscribe, Subscribe, Publish, Rsm, + Subscription); + <<"http://jabber.org/protocol/pubsub#owner">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + decode_pubsub_configure(<<"http://jabber.org/protocol/pubsub#owner">>, + __IgnoreEls, _el), + Create, Unsubscribe, Subscribe, Publish, Rsm, + Subscription); + _ -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, Subscription) + end; +decode_pubsub_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"publish-options">>, _attrs, _} = _el + | _els], + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, + Subscription) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + decode_pubsub_publish_options(__TopXMLNS, + __IgnoreEls, _el), + Items, Options, Affiliations, Subscriptions, + Default, Retract, Purge, Delete, Configure, Create, + Unsubscribe, Subscribe, Publish, Rsm, Subscription); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + decode_pubsub_publish_options(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el), + Items, Options, Affiliations, Subscriptions, + Default, Retract, Purge, Delete, Configure, Create, + Unsubscribe, Subscribe, Publish, Rsm, Subscription); + _ -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, Subscription) + end; +decode_pubsub_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"default">>, _attrs, _} = _el | _els], + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, + Subscription) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, + decode_pubsub_default(__TopXMLNS, __IgnoreEls, _el), + Retract, Purge, Delete, Configure, Create, + Unsubscribe, Subscribe, Publish, Rsm, Subscription); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, + decode_pubsub_default(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el), + Retract, Purge, Delete, Configure, Create, + Unsubscribe, Subscribe, Publish, Rsm, Subscription); + <<"http://jabber.org/protocol/pubsub#owner">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, + decode_pubsub_default(<<"http://jabber.org/protocol/pubsub#owner">>, + __IgnoreEls, _el), + Retract, Purge, Delete, Configure, Create, + Unsubscribe, Subscribe, Publish, Rsm, Subscription); + _ -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, Subscription) + end; +decode_pubsub_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"delete">>, _attrs, _} = _el | _els], + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, + Subscription) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, + decode_pubsub_delete(__TopXMLNS, __IgnoreEls, _el), + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, Subscription); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, + decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el), + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, Subscription); + <<"http://jabber.org/protocol/pubsub#owner">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, + decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub#owner">>, + __IgnoreEls, _el), + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, Subscription); + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, + decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub#event">>, + __IgnoreEls, _el), + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, Subscription); + _ -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, Subscription) + end; +decode_pubsub_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"purge">>, _attrs, _} = _el | _els], + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, + Subscription) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, + decode_pubsub_purge(__TopXMLNS, __IgnoreEls, _el), + Delete, Configure, Create, Unsubscribe, Subscribe, + Publish, Rsm, Subscription); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, + decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el), + Delete, Configure, Create, Unsubscribe, Subscribe, + Publish, Rsm, Subscription); + <<"http://jabber.org/protocol/pubsub#owner">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, + decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub#owner">>, + __IgnoreEls, _el), + Delete, Configure, Create, Unsubscribe, Subscribe, + Publish, Rsm, Subscription); + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, + decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub#event">>, + __IgnoreEls, _el), + Delete, Configure, Create, Unsubscribe, Subscribe, + Publish, Rsm, Subscription); + _ -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, Subscription) + end; +decode_pubsub_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"subscription">>, _attrs, _} = _el | _els], + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, + Subscription) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, + decode_pubsub_subscription(__TopXMLNS, __IgnoreEls, + _el)); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, + decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/pubsub#owner">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, + decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub#owner">>, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, + decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub#event">>, + __IgnoreEls, _el)); + _ -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, Subscription) + end; +decode_pubsub_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"set">>, _attrs, _} = _el | _els], + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, + Subscription) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"http://jabber.org/protocol/rsm">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, + decode_rsm_set(<<"http://jabber.org/protocol/rsm">>, + __IgnoreEls, _el), + Subscription); + _ -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, Subscription) + end; +decode_pubsub_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"publish">>, _attrs, _} = _el | _els], + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, + Subscription) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, + decode_pubsub_publish(__TopXMLNS, __IgnoreEls, _el), + Rsm, Subscription); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, + decode_pubsub_publish(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el), + Rsm, Subscription); + _ -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, + Rsm, Subscription) end; decode_pubsub_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Items, Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish) -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, Items, - Options, Affiliations, Subscriptions, Retract, - Unsubscribe, Subscribe, Publish). + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, + Subscription) -> + decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, + Publish_options, Items, Options, Affiliations, + Subscriptions, Default, Retract, Purge, Delete, + Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, + Subscription). -encode_pubsub({pubsub, Subscriptions, Affiliations, - Publish, Subscribe, Unsubscribe, Options, Items, - Retract}, +encode_pubsub({pubsub, Subscriptions, Subscription, + Affiliations, Publish, Publish_options, Subscribe, + Unsubscribe, Options, Items, Retract, Create, Configure, + Default, Delete, Purge, Rsm}, _xmlns_attrs) -> - _els = lists:reverse('encode_pubsub_$items'(Items, - 'encode_pubsub_$options'(Options, - 'encode_pubsub_$affiliations'(Affiliations, - 'encode_pubsub_$subscriptions'(Subscriptions, - 'encode_pubsub_$retract'(Retract, - 'encode_pubsub_$unsubscribe'(Unsubscribe, - 'encode_pubsub_$subscribe'(Subscribe, - 'encode_pubsub_$publish'(Publish, - []))))))))), + _els = + lists:reverse('encode_pubsub_$publish_options'(Publish_options, + 'encode_pubsub_$items'(Items, + 'encode_pubsub_$options'(Options, + 'encode_pubsub_$affiliations'(Affiliations, + 'encode_pubsub_$subscriptions'(Subscriptions, + 'encode_pubsub_$default'(Default, + 'encode_pubsub_$retract'(Retract, + 'encode_pubsub_$purge'(Purge, + 'encode_pubsub_$delete'(Delete, + 'encode_pubsub_$configure'(Configure, + 'encode_pubsub_$create'(Create, + 'encode_pubsub_$unsubscribe'(Unsubscribe, + 'encode_pubsub_$subscribe'(Subscribe, + 'encode_pubsub_$publish'(Publish, + 'encode_pubsub_$rsm'(Rsm, + 'encode_pubsub_$subscription'(Subscription, + []))))))))))))))))), _attrs = _xmlns_attrs, {xmlel, <<"pubsub">>, _attrs, _els}. +'encode_pubsub_$publish_options'(undefined, _acc) -> + _acc; +'encode_pubsub_$publish_options'(Publish_options, + _acc) -> + [encode_pubsub_publish_options(Publish_options, []) + | _acc]. + 'encode_pubsub_$items'(undefined, _acc) -> _acc; 'encode_pubsub_$items'(Items, _acc) -> [encode_pubsub_items(Items, []) | _acc]. @@ -12434,10 +13951,30 @@ encode_pubsub({pubsub, Subscriptions, Affiliations, 'encode_pubsub_$subscriptions'(Subscriptions, _acc) -> [encode_pubsub_subscriptions(Subscriptions, []) | _acc]. +'encode_pubsub_$default'(undefined, _acc) -> _acc; +'encode_pubsub_$default'(Default, _acc) -> + [encode_pubsub_default(Default, []) | _acc]. + 'encode_pubsub_$retract'(undefined, _acc) -> _acc; 'encode_pubsub_$retract'(Retract, _acc) -> [encode_pubsub_retract(Retract, []) | _acc]. +'encode_pubsub_$purge'(undefined, _acc) -> _acc; +'encode_pubsub_$purge'(Purge, _acc) -> + [encode_pubsub_purge(Purge, []) | _acc]. + +'encode_pubsub_$delete'(undefined, _acc) -> _acc; +'encode_pubsub_$delete'(Delete, _acc) -> + [encode_pubsub_delete(Delete, []) | _acc]. + +'encode_pubsub_$configure'(undefined, _acc) -> _acc; +'encode_pubsub_$configure'(Configure, _acc) -> + [encode_pubsub_configure(Configure, []) | _acc]. + +'encode_pubsub_$create'(undefined, _acc) -> _acc; +'encode_pubsub_$create'(Create, _acc) -> + [encode_pubsub_create(Create, []) | _acc]. + 'encode_pubsub_$unsubscribe'(undefined, _acc) -> _acc; 'encode_pubsub_$unsubscribe'(Unsubscribe, _acc) -> [encode_pubsub_unsubscribe(Unsubscribe, []) | _acc]. @@ -12450,13 +13987,354 @@ encode_pubsub({pubsub, Subscriptions, Affiliations, 'encode_pubsub_$publish'(Publish, _acc) -> [encode_pubsub_publish(Publish, []) | _acc]. +'encode_pubsub_$rsm'(undefined, _acc) -> _acc; +'encode_pubsub_$rsm'(Rsm, _acc) -> + [encode_rsm_set(Rsm, + [{<<"xmlns">>, <<"http://jabber.org/protocol/rsm">>}]) + | _acc]. + +'encode_pubsub_$subscription'(undefined, _acc) -> _acc; +'encode_pubsub_$subscription'(Subscription, _acc) -> + [encode_pubsub_subscription(Subscription, []) | _acc]. + +decode_pubsub_purge(__TopXMLNS, __IgnoreEls, + {xmlel, <<"purge">>, _attrs, _els}) -> + Node = decode_pubsub_purge_attrs(__TopXMLNS, _attrs, + undefined), + Node. + +decode_pubsub_purge_attrs(__TopXMLNS, + [{<<"node">>, _val} | _attrs], _Node) -> + decode_pubsub_purge_attrs(__TopXMLNS, _attrs, _val); +decode_pubsub_purge_attrs(__TopXMLNS, [_ | _attrs], + Node) -> + decode_pubsub_purge_attrs(__TopXMLNS, _attrs, Node); +decode_pubsub_purge_attrs(__TopXMLNS, [], Node) -> + decode_pubsub_purge_attr_node(__TopXMLNS, Node). + +encode_pubsub_purge(Node, _xmlns_attrs) -> + _els = [], + _attrs = encode_pubsub_purge_attr_node(Node, + _xmlns_attrs), + {xmlel, <<"purge">>, _attrs, _els}. + +decode_pubsub_purge_attr_node(__TopXMLNS, undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"node">>, <<"purge">>, __TopXMLNS}}); +decode_pubsub_purge_attr_node(__TopXMLNS, _val) -> _val. + +encode_pubsub_purge_attr_node(_val, _acc) -> + [{<<"node">>, _val} | _acc]. + +decode_pubsub_delete(__TopXMLNS, __IgnoreEls, + {xmlel, <<"delete">>, _attrs, _els}) -> + Uri = decode_pubsub_delete_els(__TopXMLNS, __IgnoreEls, + _els, <<>>), + Node = decode_pubsub_delete_attrs(__TopXMLNS, _attrs, + undefined), + {Node, Uri}. + +decode_pubsub_delete_els(__TopXMLNS, __IgnoreEls, [], + Uri) -> + Uri; +decode_pubsub_delete_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"redirect">>, _attrs, _} = _el | _els], + Uri) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub">>; + __TopXMLNS == + <<"http://jabber.org/protocol/pubsub#owner">>; + __TopXMLNS == + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_delete_els(__TopXMLNS, __IgnoreEls, _els, + decode_pubsub_redirect(__TopXMLNS, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_delete_els(__TopXMLNS, __IgnoreEls, _els, + decode_pubsub_redirect(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/pubsub#owner">> -> + decode_pubsub_delete_els(__TopXMLNS, __IgnoreEls, _els, + decode_pubsub_redirect(<<"http://jabber.org/protocol/pubsub#owner">>, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_delete_els(__TopXMLNS, __IgnoreEls, _els, + decode_pubsub_redirect(<<"http://jabber.org/protocol/pubsub#event">>, + __IgnoreEls, _el)); + _ -> + decode_pubsub_delete_els(__TopXMLNS, __IgnoreEls, _els, + Uri) + end; +decode_pubsub_delete_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Uri) -> + decode_pubsub_delete_els(__TopXMLNS, __IgnoreEls, _els, + Uri). + +decode_pubsub_delete_attrs(__TopXMLNS, + [{<<"node">>, _val} | _attrs], _Node) -> + decode_pubsub_delete_attrs(__TopXMLNS, _attrs, _val); +decode_pubsub_delete_attrs(__TopXMLNS, [_ | _attrs], + Node) -> + decode_pubsub_delete_attrs(__TopXMLNS, _attrs, Node); +decode_pubsub_delete_attrs(__TopXMLNS, [], Node) -> + decode_pubsub_delete_attr_node(__TopXMLNS, Node). + +encode_pubsub_delete({Node, Uri}, _xmlns_attrs) -> + _els = lists:reverse('encode_pubsub_delete_$uri'(Uri, + [])), + _attrs = encode_pubsub_delete_attr_node(Node, + _xmlns_attrs), + {xmlel, <<"delete">>, _attrs, _els}. + +'encode_pubsub_delete_$uri'(<<>>, _acc) -> _acc; +'encode_pubsub_delete_$uri'(Uri, _acc) -> + [encode_pubsub_redirect(Uri, []) | _acc]. + +decode_pubsub_delete_attr_node(__TopXMLNS, undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"node">>, <<"delete">>, __TopXMLNS}}); +decode_pubsub_delete_attr_node(__TopXMLNS, _val) -> + _val. + +encode_pubsub_delete_attr_node(_val, _acc) -> + [{<<"node">>, _val} | _acc]. + +decode_pubsub_redirect(__TopXMLNS, __IgnoreEls, + {xmlel, <<"redirect">>, _attrs, _els}) -> + Uri = decode_pubsub_redirect_attrs(__TopXMLNS, _attrs, + undefined), + Uri. + +decode_pubsub_redirect_attrs(__TopXMLNS, + [{<<"uri">>, _val} | _attrs], _Uri) -> + decode_pubsub_redirect_attrs(__TopXMLNS, _attrs, _val); +decode_pubsub_redirect_attrs(__TopXMLNS, [_ | _attrs], + Uri) -> + decode_pubsub_redirect_attrs(__TopXMLNS, _attrs, Uri); +decode_pubsub_redirect_attrs(__TopXMLNS, [], Uri) -> + decode_pubsub_redirect_attr_uri(__TopXMLNS, Uri). + +encode_pubsub_redirect(Uri, _xmlns_attrs) -> + _els = [], + _attrs = encode_pubsub_redirect_attr_uri(Uri, + _xmlns_attrs), + {xmlel, <<"redirect">>, _attrs, _els}. + +decode_pubsub_redirect_attr_uri(__TopXMLNS, + undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"uri">>, <<"redirect">>, __TopXMLNS}}); +decode_pubsub_redirect_attr_uri(__TopXMLNS, _val) -> + _val. + +encode_pubsub_redirect_attr_uri(_val, _acc) -> + [{<<"uri">>, _val} | _acc]. + +decode_pubsub_default(__TopXMLNS, __IgnoreEls, + {xmlel, <<"default">>, _attrs, _els}) -> + Xdata = decode_pubsub_default_els(__TopXMLNS, + __IgnoreEls, _els, undefined), + Node = decode_pubsub_default_attrs(__TopXMLNS, _attrs, + undefined), + {Node, Xdata}. + +decode_pubsub_default_els(__TopXMLNS, __IgnoreEls, [], + Xdata) -> + Xdata; +decode_pubsub_default_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"x">>, _attrs, _} = _el | _els], Xdata) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"jabber:x:data">> -> + decode_pubsub_default_els(__TopXMLNS, __IgnoreEls, _els, + decode_xdata(<<"jabber:x:data">>, + __IgnoreEls, _el)); + _ -> + decode_pubsub_default_els(__TopXMLNS, __IgnoreEls, _els, + Xdata) + end; +decode_pubsub_default_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Xdata) -> + decode_pubsub_default_els(__TopXMLNS, __IgnoreEls, _els, + Xdata). + +decode_pubsub_default_attrs(__TopXMLNS, + [{<<"node">>, _val} | _attrs], _Node) -> + decode_pubsub_default_attrs(__TopXMLNS, _attrs, _val); +decode_pubsub_default_attrs(__TopXMLNS, [_ | _attrs], + Node) -> + decode_pubsub_default_attrs(__TopXMLNS, _attrs, Node); +decode_pubsub_default_attrs(__TopXMLNS, [], Node) -> + decode_pubsub_default_attr_node(__TopXMLNS, Node). + +encode_pubsub_default({Node, Xdata}, _xmlns_attrs) -> + _els = + lists:reverse('encode_pubsub_default_$xdata'(Xdata, + [])), + _attrs = encode_pubsub_default_attr_node(Node, + _xmlns_attrs), + {xmlel, <<"default">>, _attrs, _els}. + +'encode_pubsub_default_$xdata'(undefined, _acc) -> _acc; +'encode_pubsub_default_$xdata'(Xdata, _acc) -> + [encode_xdata(Xdata, + [{<<"xmlns">>, <<"jabber:x:data">>}]) + | _acc]. + +decode_pubsub_default_attr_node(__TopXMLNS, + undefined) -> + <<>>; +decode_pubsub_default_attr_node(__TopXMLNS, _val) -> + _val. + +encode_pubsub_default_attr_node(<<>>, _acc) -> _acc; +encode_pubsub_default_attr_node(_val, _acc) -> + [{<<"node">>, _val} | _acc]. + +decode_pubsub_publish_options(__TopXMLNS, __IgnoreEls, + {xmlel, <<"publish-options">>, _attrs, _els}) -> + Xdata = decode_pubsub_publish_options_els(__TopXMLNS, + __IgnoreEls, _els, undefined), + Xdata. + +decode_pubsub_publish_options_els(__TopXMLNS, + __IgnoreEls, [], Xdata) -> + Xdata; +decode_pubsub_publish_options_els(__TopXMLNS, + __IgnoreEls, + [{xmlel, <<"x">>, _attrs, _} = _el | _els], + Xdata) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"jabber:x:data">> -> + decode_pubsub_publish_options_els(__TopXMLNS, + __IgnoreEls, _els, + decode_xdata(<<"jabber:x:data">>, + __IgnoreEls, _el)); + _ -> + decode_pubsub_publish_options_els(__TopXMLNS, + __IgnoreEls, _els, Xdata) + end; +decode_pubsub_publish_options_els(__TopXMLNS, + __IgnoreEls, [_ | _els], Xdata) -> + decode_pubsub_publish_options_els(__TopXMLNS, + __IgnoreEls, _els, Xdata). + +encode_pubsub_publish_options(Xdata, _xmlns_attrs) -> + _els = + lists:reverse('encode_pubsub_publish_options_$xdata'(Xdata, + [])), + _attrs = _xmlns_attrs, + {xmlel, <<"publish-options">>, _attrs, _els}. + +'encode_pubsub_publish_options_$xdata'(undefined, + _acc) -> + _acc; +'encode_pubsub_publish_options_$xdata'(Xdata, _acc) -> + [encode_xdata(Xdata, + [{<<"xmlns">>, <<"jabber:x:data">>}]) + | _acc]. + +decode_pubsub_configure(__TopXMLNS, __IgnoreEls, + {xmlel, <<"configure">>, _attrs, _els}) -> + Xdata = decode_pubsub_configure_els(__TopXMLNS, + __IgnoreEls, _els, undefined), + Node = decode_pubsub_configure_attrs(__TopXMLNS, _attrs, + undefined), + {Node, Xdata}. + +decode_pubsub_configure_els(__TopXMLNS, __IgnoreEls, [], + Xdata) -> + Xdata; +decode_pubsub_configure_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"x">>, _attrs, _} = _el | _els], + Xdata) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"jabber:x:data">> -> + decode_pubsub_configure_els(__TopXMLNS, __IgnoreEls, + _els, + decode_xdata(<<"jabber:x:data">>, + __IgnoreEls, _el)); + _ -> + decode_pubsub_configure_els(__TopXMLNS, __IgnoreEls, + _els, Xdata) + end; +decode_pubsub_configure_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Xdata) -> + decode_pubsub_configure_els(__TopXMLNS, __IgnoreEls, + _els, Xdata). + +decode_pubsub_configure_attrs(__TopXMLNS, + [{<<"node">>, _val} | _attrs], _Node) -> + decode_pubsub_configure_attrs(__TopXMLNS, _attrs, _val); +decode_pubsub_configure_attrs(__TopXMLNS, [_ | _attrs], + Node) -> + decode_pubsub_configure_attrs(__TopXMLNS, _attrs, Node); +decode_pubsub_configure_attrs(__TopXMLNS, [], Node) -> + decode_pubsub_configure_attr_node(__TopXMLNS, Node). + +encode_pubsub_configure({Node, Xdata}, _xmlns_attrs) -> + _els = + lists:reverse('encode_pubsub_configure_$xdata'(Xdata, + [])), + _attrs = encode_pubsub_configure_attr_node(Node, + _xmlns_attrs), + {xmlel, <<"configure">>, _attrs, _els}. + +'encode_pubsub_configure_$xdata'(undefined, _acc) -> + _acc; +'encode_pubsub_configure_$xdata'(Xdata, _acc) -> + [encode_xdata(Xdata, + [{<<"xmlns">>, <<"jabber:x:data">>}]) + | _acc]. + +decode_pubsub_configure_attr_node(__TopXMLNS, + undefined) -> + <<>>; +decode_pubsub_configure_attr_node(__TopXMLNS, _val) -> + _val. + +encode_pubsub_configure_attr_node(<<>>, _acc) -> _acc; +encode_pubsub_configure_attr_node(_val, _acc) -> + [{<<"node">>, _val} | _acc]. + +decode_pubsub_create(__TopXMLNS, __IgnoreEls, + {xmlel, <<"create">>, _attrs, _els}) -> + Node = decode_pubsub_create_attrs(__TopXMLNS, _attrs, + undefined), + Node. + +decode_pubsub_create_attrs(__TopXMLNS, + [{<<"node">>, _val} | _attrs], _Node) -> + decode_pubsub_create_attrs(__TopXMLNS, _attrs, _val); +decode_pubsub_create_attrs(__TopXMLNS, [_ | _attrs], + Node) -> + decode_pubsub_create_attrs(__TopXMLNS, _attrs, Node); +decode_pubsub_create_attrs(__TopXMLNS, [], Node) -> + decode_pubsub_create_attr_node(__TopXMLNS, Node). + +encode_pubsub_create(Node, _xmlns_attrs) -> + _els = [], + _attrs = encode_pubsub_create_attr_node(Node, + _xmlns_attrs), + {xmlel, <<"create">>, _attrs, _els}. + +decode_pubsub_create_attr_node(__TopXMLNS, undefined) -> + <<>>; +decode_pubsub_create_attr_node(__TopXMLNS, _val) -> + _val. + +encode_pubsub_create_attr_node(<<>>, _acc) -> _acc; +encode_pubsub_create_attr_node(_val, _acc) -> + [{<<"node">>, _val} | _acc]. + decode_pubsub_retract(__TopXMLNS, __IgnoreEls, {xmlel, <<"retract">>, _attrs, _els}) -> Items = decode_pubsub_retract_els(__TopXMLNS, __IgnoreEls, _els, []), {Node, Notify} = decode_pubsub_retract_attrs(__TopXMLNS, _attrs, undefined, undefined), - {pubsub_retract, Node, Notify, Items}. + {ps_retract, Node, Notify, Items}. decode_pubsub_retract_els(__TopXMLNS, __IgnoreEls, [], Items) -> @@ -12477,6 +14355,11 @@ decode_pubsub_retract_els(__TopXMLNS, __IgnoreEls, [decode_pubsub_item(<<"http://jabber.org/protocol/pubsub">>, __IgnoreEls, _el) | Items]); + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_retract_els(__TopXMLNS, __IgnoreEls, _els, + [decode_pubsub_item(<<"http://jabber.org/protocol/pubsub#event">>, + __IgnoreEls, _el) + | Items]); _ -> decode_pubsub_retract_els(__TopXMLNS, __IgnoreEls, _els, Items) @@ -12503,8 +14386,7 @@ decode_pubsub_retract_attrs(__TopXMLNS, [], Node, {decode_pubsub_retract_attr_node(__TopXMLNS, Node), decode_pubsub_retract_attr_notify(__TopXMLNS, Notify)}. -encode_pubsub_retract({pubsub_retract, Node, Notify, - Items}, +encode_pubsub_retract({ps_retract, Node, Notify, Items}, _xmlns_attrs) -> _els = lists:reverse('encode_pubsub_retract_$items'(Items, @@ -12552,7 +14434,7 @@ decode_pubsub_options(__TopXMLNS, __IgnoreEls, {Node, Subid, Jid} = decode_pubsub_options_attrs(__TopXMLNS, _attrs, undefined, undefined, undefined), - {pubsub_options, Node, Jid, Subid, Xdata}. + {ps_options, Node, Jid, Subid, Xdata}. decode_pubsub_options_els(__TopXMLNS, __IgnoreEls, [], Xdata) -> @@ -12596,7 +14478,7 @@ decode_pubsub_options_attrs(__TopXMLNS, [], Node, Subid, decode_pubsub_options_attr_subid(__TopXMLNS, Subid), decode_pubsub_options_attr_jid(__TopXMLNS, Jid)}. -encode_pubsub_options({pubsub_options, Node, Jid, Subid, +encode_pubsub_options({ps_options, Node, Jid, Subid, Xdata}, _xmlns_attrs) -> _els = @@ -12655,7 +14537,7 @@ decode_pubsub_publish(__TopXMLNS, __IgnoreEls, __IgnoreEls, _els, []), Node = decode_pubsub_publish_attrs(__TopXMLNS, _attrs, undefined), - {pubsub_publish, Node, Items}. + {ps_publish, Node, Items}. decode_pubsub_publish_els(__TopXMLNS, __IgnoreEls, [], Items) -> @@ -12676,6 +14558,11 @@ decode_pubsub_publish_els(__TopXMLNS, __IgnoreEls, [decode_pubsub_item(<<"http://jabber.org/protocol/pubsub">>, __IgnoreEls, _el) | Items]); + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_publish_els(__TopXMLNS, __IgnoreEls, _els, + [decode_pubsub_item(<<"http://jabber.org/protocol/pubsub#event">>, + __IgnoreEls, _el) + | Items]); _ -> decode_pubsub_publish_els(__TopXMLNS, __IgnoreEls, _els, Items) @@ -12694,7 +14581,7 @@ decode_pubsub_publish_attrs(__TopXMLNS, [_ | _attrs], decode_pubsub_publish_attrs(__TopXMLNS, [], Node) -> decode_pubsub_publish_attr_node(__TopXMLNS, Node). -encode_pubsub_publish({pubsub_publish, Node, Items}, +encode_pubsub_publish({ps_publish, Node, Items}, _xmlns_attrs) -> _els = lists:reverse('encode_pubsub_publish_$items'(Items, @@ -12723,7 +14610,7 @@ decode_pubsub_unsubscribe(__TopXMLNS, __IgnoreEls, {Node, Subid, Jid} = decode_pubsub_unsubscribe_attrs(__TopXMLNS, _attrs, undefined, undefined, undefined), - {pubsub_unsubscribe, Node, Jid, Subid}. + {ps_unsubscribe, Node, Jid, Subid}. decode_pubsub_unsubscribe_attrs(__TopXMLNS, [{<<"node">>, _val} | _attrs], _Node, Subid, @@ -12750,8 +14637,8 @@ decode_pubsub_unsubscribe_attrs(__TopXMLNS, [], Node, decode_pubsub_unsubscribe_attr_subid(__TopXMLNS, Subid), decode_pubsub_unsubscribe_attr_jid(__TopXMLNS, Jid)}. -encode_pubsub_unsubscribe({pubsub_unsubscribe, Node, - Jid, Subid}, +encode_pubsub_unsubscribe({ps_unsubscribe, Node, Jid, + Subid}, _xmlns_attrs) -> _els = [], _attrs = encode_pubsub_unsubscribe_attr_jid(Jid, @@ -12803,7 +14690,7 @@ decode_pubsub_subscribe(__TopXMLNS, __IgnoreEls, {xmlel, <<"subscribe">>, _attrs, _els}) -> {Node, Jid} = decode_pubsub_subscribe_attrs(__TopXMLNS, _attrs, undefined, undefined), - {pubsub_subscribe, Node, Jid}. + {ps_subscribe, Node, Jid}. decode_pubsub_subscribe_attrs(__TopXMLNS, [{<<"node">>, _val} | _attrs], _Node, Jid) -> @@ -12822,7 +14709,7 @@ decode_pubsub_subscribe_attrs(__TopXMLNS, [], Node, {decode_pubsub_subscribe_attr_node(__TopXMLNS, Node), decode_pubsub_subscribe_attr_jid(__TopXMLNS, Jid)}. -encode_pubsub_subscribe({pubsub_subscribe, Node, Jid}, +encode_pubsub_subscribe({ps_subscribe, Node, Jid}, _xmlns_attrs) -> _els = [], _attrs = encode_pubsub_subscribe_attr_jid(Jid, @@ -12857,12 +14744,108 @@ decode_pubsub_subscribe_attr_jid(__TopXMLNS, _val) -> encode_pubsub_subscribe_attr_jid(_val, _acc) -> [{<<"jid">>, enc_jid(_val)} | _acc]. +decode_pubsub_owner_affiliations(__TopXMLNS, + __IgnoreEls, + {xmlel, <<"affiliations">>, _attrs, _els}) -> + Affiliations = + decode_pubsub_owner_affiliations_els(__TopXMLNS, + __IgnoreEls, _els, []), + Node = + decode_pubsub_owner_affiliations_attrs(__TopXMLNS, + _attrs, undefined), + {Node, Affiliations}. + +decode_pubsub_owner_affiliations_els(__TopXMLNS, + __IgnoreEls, [], Affiliations) -> + lists:reverse(Affiliations); +decode_pubsub_owner_affiliations_els(__TopXMLNS, + __IgnoreEls, + [{xmlel, <<"affiliation">>, _attrs, _} = + _el + | _els], + Affiliations) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub#owner">> -> + decode_pubsub_owner_affiliations_els(__TopXMLNS, + __IgnoreEls, _els, + [decode_pubsub_owner_affiliation(__TopXMLNS, + __IgnoreEls, + _el) + | Affiliations]); + <<"http://jabber.org/protocol/pubsub#owner">> -> + decode_pubsub_owner_affiliations_els(__TopXMLNS, + __IgnoreEls, _els, + [decode_pubsub_owner_affiliation(<<"http://jabber.org/protocol/pubsub#owner">>, + __IgnoreEls, + _el) + | Affiliations]); + _ -> + decode_pubsub_owner_affiliations_els(__TopXMLNS, + __IgnoreEls, _els, Affiliations) + end; +decode_pubsub_owner_affiliations_els(__TopXMLNS, + __IgnoreEls, [_ | _els], Affiliations) -> + decode_pubsub_owner_affiliations_els(__TopXMLNS, + __IgnoreEls, _els, Affiliations). + +decode_pubsub_owner_affiliations_attrs(__TopXMLNS, + [{<<"node">>, _val} | _attrs], _Node) -> + decode_pubsub_owner_affiliations_attrs(__TopXMLNS, + _attrs, _val); +decode_pubsub_owner_affiliations_attrs(__TopXMLNS, + [_ | _attrs], Node) -> + decode_pubsub_owner_affiliations_attrs(__TopXMLNS, + _attrs, Node); +decode_pubsub_owner_affiliations_attrs(__TopXMLNS, [], + Node) -> + decode_pubsub_owner_affiliations_attr_node(__TopXMLNS, + Node). + +encode_pubsub_owner_affiliations({Node, Affiliations}, + _xmlns_attrs) -> + _els = + lists:reverse('encode_pubsub_owner_affiliations_$affiliations'(Affiliations, + [])), + _attrs = + encode_pubsub_owner_affiliations_attr_node(Node, + _xmlns_attrs), + {xmlel, <<"affiliations">>, _attrs, _els}. + +'encode_pubsub_owner_affiliations_$affiliations'([], + _acc) -> + _acc; +'encode_pubsub_owner_affiliations_$affiliations'([Affiliations + | _els], + _acc) -> + 'encode_pubsub_owner_affiliations_$affiliations'(_els, + [encode_pubsub_owner_affiliation(Affiliations, + []) + | _acc]). + +decode_pubsub_owner_affiliations_attr_node(__TopXMLNS, + undefined) -> + <<>>; +decode_pubsub_owner_affiliations_attr_node(__TopXMLNS, + _val) -> + _val. + +encode_pubsub_owner_affiliations_attr_node(<<>>, + _acc) -> + _acc; +encode_pubsub_owner_affiliations_attr_node(_val, + _acc) -> + [{<<"node">>, _val} | _acc]. + decode_pubsub_affiliations(__TopXMLNS, __IgnoreEls, {xmlel, <<"affiliations">>, _attrs, _els}) -> Affiliations = decode_pubsub_affiliations_els(__TopXMLNS, __IgnoreEls, _els, []), - Affiliations. + Node = decode_pubsub_affiliations_attrs(__TopXMLNS, + _attrs, undefined), + {Node, Affiliations}. decode_pubsub_affiliations_els(__TopXMLNS, __IgnoreEls, [], Affiliations) -> @@ -12897,12 +14880,25 @@ decode_pubsub_affiliations_els(__TopXMLNS, __IgnoreEls, decode_pubsub_affiliations_els(__TopXMLNS, __IgnoreEls, _els, Affiliations). -encode_pubsub_affiliations(Affiliations, +decode_pubsub_affiliations_attrs(__TopXMLNS, + [{<<"node">>, _val} | _attrs], _Node) -> + decode_pubsub_affiliations_attrs(__TopXMLNS, _attrs, + _val); +decode_pubsub_affiliations_attrs(__TopXMLNS, + [_ | _attrs], Node) -> + decode_pubsub_affiliations_attrs(__TopXMLNS, _attrs, + Node); +decode_pubsub_affiliations_attrs(__TopXMLNS, [], + Node) -> + decode_pubsub_affiliations_attr_node(__TopXMLNS, Node). + +encode_pubsub_affiliations({Node, Affiliations}, _xmlns_attrs) -> _els = lists:reverse('encode_pubsub_affiliations_$affiliations'(Affiliations, [])), - _attrs = _xmlns_attrs, + _attrs = encode_pubsub_affiliations_attr_node(Node, + _xmlns_attrs), {xmlel, <<"affiliations">>, _attrs, _els}. 'encode_pubsub_affiliations_$affiliations'([], _acc) -> @@ -12915,6 +14911,18 @@ encode_pubsub_affiliations(Affiliations, []) | _acc]). +decode_pubsub_affiliations_attr_node(__TopXMLNS, + undefined) -> + <<>>; +decode_pubsub_affiliations_attr_node(__TopXMLNS, + _val) -> + _val. + +encode_pubsub_affiliations_attr_node(<<>>, _acc) -> + _acc; +encode_pubsub_affiliations_attr_node(_val, _acc) -> + [{<<"node">>, _val} | _acc]. + decode_pubsub_subscriptions(__TopXMLNS, __IgnoreEls, {xmlel, <<"subscriptions">>, _attrs, _els}) -> Subscriptions = @@ -12934,7 +14942,9 @@ decode_pubsub_subscriptions_els(__TopXMLNS, __IgnoreEls, case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub">> -> + <<"http://jabber.org/protocol/pubsub">>; + __TopXMLNS == + <<"http://jabber.org/protocol/pubsub#owner">> -> decode_pubsub_subscriptions_els(__TopXMLNS, __IgnoreEls, _els, [decode_pubsub_subscription(__TopXMLNS, @@ -12948,6 +14958,20 @@ decode_pubsub_subscriptions_els(__TopXMLNS, __IgnoreEls, __IgnoreEls, _el) | Subscriptions]); + <<"http://jabber.org/protocol/pubsub#owner">> -> + decode_pubsub_subscriptions_els(__TopXMLNS, __IgnoreEls, + _els, + [decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub#owner">>, + __IgnoreEls, + _el) + | Subscriptions]); + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_subscriptions_els(__TopXMLNS, __IgnoreEls, + _els, + [decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub#event">>, + __IgnoreEls, + _el) + | Subscriptions]); _ -> decode_pubsub_subscriptions_els(__TopXMLNS, __IgnoreEls, _els, Subscriptions) @@ -13003,358 +15027,368 @@ encode_pubsub_subscriptions_attr_node(_val, _acc) -> decode_pubsub_event(__TopXMLNS, __IgnoreEls, {xmlel, <<"event">>, _attrs, _els}) -> - Items = decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, - _els, []), - {pubsub_event, Items}. + {Items, Create, Delete, Purge, Configuration, + Subscription} = + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + undefined, undefined, undefined, undefined, + undefined, undefined), + {ps_event, Items, Purge, Subscription, Delete, Create, + Configuration}. decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, [], - Items) -> - lists:reverse(Items); + Items, Create, Delete, Purge, Configuration, + Subscription) -> + {Items, Create, Delete, Purge, Configuration, + Subscription}; decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"items">>, _attrs, _} = _el | _els], - Items) -> + [{xmlel, <<"items">>, _attrs, _} = _el | _els], Items, + Create, Delete, Purge, Configuration, Subscription) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == <<"http://jabber.org/protocol/pubsub#event">> -> decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - [decode_pubsub_event_items(__TopXMLNS, - __IgnoreEls, _el) - | Items]); + decode_pubsub_items(__TopXMLNS, __IgnoreEls, + _el), + Create, Delete, Purge, Configuration, + Subscription); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + decode_pubsub_items(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el), + Create, Delete, Purge, Configuration, + Subscription); <<"http://jabber.org/protocol/pubsub#event">> -> decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - [decode_pubsub_event_items(<<"http://jabber.org/protocol/pubsub#event">>, - __IgnoreEls, _el) - | Items]); + decode_pubsub_items(<<"http://jabber.org/protocol/pubsub#event">>, + __IgnoreEls, _el), + Create, Delete, Purge, Configuration, + Subscription); _ -> decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items) + Items, Create, Delete, Purge, Configuration, + Subscription) end; decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Items) -> + [{xmlel, <<"subscription">>, _attrs, _} = _el | _els], + Items, Create, Delete, Purge, Configuration, + Subscription) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + Items, Create, Delete, Purge, Configuration, + decode_pubsub_subscription(__TopXMLNS, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + Items, Create, Delete, Purge, Configuration, + decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/pubsub#owner">> -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + Items, Create, Delete, Purge, Configuration, + decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub#owner">>, + __IgnoreEls, _el)); + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + Items, Create, Delete, Purge, Configuration, + decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub#event">>, + __IgnoreEls, _el)); + _ -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + Items, Create, Delete, Purge, Configuration, + Subscription) + end; +decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"purge">>, _attrs, _} = _el | _els], Items, + Create, Delete, Purge, Configuration, Subscription) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + Items, Create, Delete, + decode_pubsub_purge(__TopXMLNS, __IgnoreEls, + _el), + Configuration, Subscription); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + Items, Create, Delete, + decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el), + Configuration, Subscription); + <<"http://jabber.org/protocol/pubsub#owner">> -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + Items, Create, Delete, + decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub#owner">>, + __IgnoreEls, _el), + Configuration, Subscription); + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + Items, Create, Delete, + decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub#event">>, + __IgnoreEls, _el), + Configuration, Subscription); + _ -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + Items, Create, Delete, Purge, Configuration, + Subscription) + end; +decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"delete">>, _attrs, _} = _el | _els], Items, + Create, Delete, Purge, Configuration, Subscription) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + Items, Create, + decode_pubsub_delete(__TopXMLNS, __IgnoreEls, + _el), + Purge, Configuration, Subscription); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + Items, Create, + decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el), + Purge, Configuration, Subscription); + <<"http://jabber.org/protocol/pubsub#owner">> -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + Items, Create, + decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub#owner">>, + __IgnoreEls, _el), + Purge, Configuration, Subscription); + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + Items, Create, + decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub#event">>, + __IgnoreEls, _el), + Purge, Configuration, Subscription); + _ -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + Items, Create, Delete, Purge, Configuration, + Subscription) + end; +decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"create">>, _attrs, _} = _el | _els], Items, + Create, Delete, Purge, Configuration, Subscription) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + Items, + decode_pubsub_create(__TopXMLNS, __IgnoreEls, + _el), + Delete, Purge, Configuration, Subscription); + <<"http://jabber.org/protocol/pubsub">> -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + Items, + decode_pubsub_create(<<"http://jabber.org/protocol/pubsub">>, + __IgnoreEls, _el), + Delete, Purge, Configuration, Subscription); + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + Items, + decode_pubsub_create(<<"http://jabber.org/protocol/pubsub#event">>, + __IgnoreEls, _el), + Delete, Purge, Configuration, Subscription); + _ -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + Items, Create, Delete, Purge, Configuration, + Subscription) + end; +decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"configuration">>, _attrs, _} = _el | _els], + Items, Create, Delete, Purge, Configuration, + Subscription) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + Items, Create, Delete, Purge, + decode_pubsub_event_configuration(__TopXMLNS, + __IgnoreEls, + _el), + Subscription); + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + Items, Create, Delete, Purge, + decode_pubsub_event_configuration(<<"http://jabber.org/protocol/pubsub#event">>, + __IgnoreEls, + _el), + Subscription); + _ -> + decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, + Items, Create, Delete, Purge, Configuration, + Subscription) + end; +decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Items, Create, Delete, Purge, Configuration, + Subscription) -> decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items). + Items, Create, Delete, Purge, Configuration, + Subscription). -encode_pubsub_event({pubsub_event, Items}, +encode_pubsub_event({ps_event, Items, Purge, + Subscription, Delete, Create, Configuration}, _xmlns_attrs) -> _els = lists:reverse('encode_pubsub_event_$items'(Items, - [])), + 'encode_pubsub_event_$create'(Create, + 'encode_pubsub_event_$delete'(Delete, + 'encode_pubsub_event_$purge'(Purge, + 'encode_pubsub_event_$configuration'(Configuration, + 'encode_pubsub_event_$subscription'(Subscription, + []))))))), _attrs = _xmlns_attrs, {xmlel, <<"event">>, _attrs, _els}. -'encode_pubsub_event_$items'([], _acc) -> _acc; -'encode_pubsub_event_$items'([Items | _els], _acc) -> - 'encode_pubsub_event_$items'(_els, - [encode_pubsub_event_items(Items, []) | _acc]). +'encode_pubsub_event_$items'(undefined, _acc) -> _acc; +'encode_pubsub_event_$items'(Items, _acc) -> + [encode_pubsub_items(Items, []) | _acc]. -decode_pubsub_event_items(__TopXMLNS, __IgnoreEls, - {xmlel, <<"items">>, _attrs, _els}) -> - {Items, Retract} = - decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, - _els, [], []), - Node = decode_pubsub_event_items_attrs(__TopXMLNS, - _attrs, undefined), - {pubsub_event_items, Node, Retract, Items}. +'encode_pubsub_event_$create'(undefined, _acc) -> _acc; +'encode_pubsub_event_$create'(Create, _acc) -> + [encode_pubsub_create(Create, []) | _acc]. -decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, - [], Items, Retract) -> - {lists:reverse(Items), lists:reverse(Retract)}; -decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"retract">>, _attrs, _} = _el | _els], - Items, Retract) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, - _els, Items, - [decode_pubsub_event_retract(__TopXMLNS, - __IgnoreEls, - _el) - | Retract]); - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, - _els, Items, - [decode_pubsub_event_retract(<<"http://jabber.org/protocol/pubsub#event">>, - __IgnoreEls, - _el) - | Retract]); - _ -> - decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, - _els, Items, Retract) - end; -decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"item">>, _attrs, _} = _el | _els], - Items, Retract) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, - _els, - [decode_pubsub_event_item(__TopXMLNS, - __IgnoreEls, - _el) - | Items], - Retract); - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, - _els, - [decode_pubsub_event_item(<<"http://jabber.org/protocol/pubsub#event">>, - __IgnoreEls, - _el) - | Items], - Retract); - _ -> - decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, - _els, Items, Retract) - end; -decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Items, Retract) -> - decode_pubsub_event_items_els(__TopXMLNS, __IgnoreEls, - _els, Items, Retract). +'encode_pubsub_event_$delete'(undefined, _acc) -> _acc; +'encode_pubsub_event_$delete'(Delete, _acc) -> + [encode_pubsub_delete(Delete, []) | _acc]. -decode_pubsub_event_items_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], _Node) -> - decode_pubsub_event_items_attrs(__TopXMLNS, _attrs, - _val); -decode_pubsub_event_items_attrs(__TopXMLNS, - [_ | _attrs], Node) -> - decode_pubsub_event_items_attrs(__TopXMLNS, _attrs, - Node); -decode_pubsub_event_items_attrs(__TopXMLNS, [], Node) -> - decode_pubsub_event_items_attr_node(__TopXMLNS, Node). +'encode_pubsub_event_$purge'(undefined, _acc) -> _acc; +'encode_pubsub_event_$purge'(Purge, _acc) -> + [encode_pubsub_purge(Purge, []) | _acc]. -encode_pubsub_event_items({pubsub_event_items, Node, - Retract, Items}, - _xmlns_attrs) -> - _els = - lists:reverse('encode_pubsub_event_items_$items'(Items, - 'encode_pubsub_event_items_$retract'(Retract, - []))), - _attrs = encode_pubsub_event_items_attr_node(Node, - _xmlns_attrs), - {xmlel, <<"items">>, _attrs, _els}. - -'encode_pubsub_event_items_$items'([], _acc) -> _acc; -'encode_pubsub_event_items_$items'([Items | _els], - _acc) -> - 'encode_pubsub_event_items_$items'(_els, - [encode_pubsub_event_item(Items, []) - | _acc]). - -'encode_pubsub_event_items_$retract'([], _acc) -> _acc; -'encode_pubsub_event_items_$retract'([Retract | _els], - _acc) -> - 'encode_pubsub_event_items_$retract'(_els, - [encode_pubsub_event_retract(Retract, - []) - | _acc]). - -decode_pubsub_event_items_attr_node(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"node">>, <<"items">>, __TopXMLNS}}); -decode_pubsub_event_items_attr_node(__TopXMLNS, _val) -> - _val. - -encode_pubsub_event_items_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_pubsub_event_item(__TopXMLNS, __IgnoreEls, - {xmlel, <<"item">>, _attrs, _els}) -> - __Xmls = decode_pubsub_event_item_els(__TopXMLNS, - __IgnoreEls, _els, []), - {Id, Node, Publisher} = - decode_pubsub_event_item_attrs(__TopXMLNS, _attrs, - undefined, undefined, undefined), - {pubsub_event_item, Id, Node, Publisher, __Xmls}. - -decode_pubsub_event_item_els(__TopXMLNS, __IgnoreEls, - [], __Xmls) -> - lists:reverse(__Xmls); -decode_pubsub_event_item_els(__TopXMLNS, __IgnoreEls, - [{xmlel, _, _, _} = _el | _els], __Xmls) -> - decode_pubsub_event_item_els(__TopXMLNS, __IgnoreEls, - _els, [_el | __Xmls]); -decode_pubsub_event_item_els(__TopXMLNS, __IgnoreEls, - [_ | _els], __Xmls) -> - decode_pubsub_event_item_els(__TopXMLNS, __IgnoreEls, - _els, __Xmls). - -decode_pubsub_event_item_attrs(__TopXMLNS, - [{<<"id">>, _val} | _attrs], _Id, Node, - Publisher) -> - decode_pubsub_event_item_attrs(__TopXMLNS, _attrs, _val, - Node, Publisher); -decode_pubsub_event_item_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], Id, _Node, - Publisher) -> - decode_pubsub_event_item_attrs(__TopXMLNS, _attrs, Id, - _val, Publisher); -decode_pubsub_event_item_attrs(__TopXMLNS, - [{<<"publisher">>, _val} | _attrs], Id, Node, - _Publisher) -> - decode_pubsub_event_item_attrs(__TopXMLNS, _attrs, Id, - Node, _val); -decode_pubsub_event_item_attrs(__TopXMLNS, [_ | _attrs], - Id, Node, Publisher) -> - decode_pubsub_event_item_attrs(__TopXMLNS, _attrs, Id, - Node, Publisher); -decode_pubsub_event_item_attrs(__TopXMLNS, [], Id, Node, - Publisher) -> - {decode_pubsub_event_item_attr_id(__TopXMLNS, Id), - decode_pubsub_event_item_attr_node(__TopXMLNS, Node), - decode_pubsub_event_item_attr_publisher(__TopXMLNS, - Publisher)}. - -encode_pubsub_event_item({pubsub_event_item, Id, Node, - Publisher, __Xmls}, - _xmlns_attrs) -> - _els = __Xmls, - _attrs = - encode_pubsub_event_item_attr_publisher(Publisher, - encode_pubsub_event_item_attr_node(Node, - encode_pubsub_event_item_attr_id(Id, - _xmlns_attrs))), - {xmlel, <<"item">>, _attrs, _els}. - -decode_pubsub_event_item_attr_id(__TopXMLNS, - undefined) -> - <<>>; -decode_pubsub_event_item_attr_id(__TopXMLNS, _val) -> - _val. - -encode_pubsub_event_item_attr_id(<<>>, _acc) -> _acc; -encode_pubsub_event_item_attr_id(_val, _acc) -> - [{<<"id">>, _val} | _acc]. - -decode_pubsub_event_item_attr_node(__TopXMLNS, - undefined) -> - <<>>; -decode_pubsub_event_item_attr_node(__TopXMLNS, _val) -> - _val. - -encode_pubsub_event_item_attr_node(<<>>, _acc) -> _acc; -encode_pubsub_event_item_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_pubsub_event_item_attr_publisher(__TopXMLNS, - undefined) -> - <<>>; -decode_pubsub_event_item_attr_publisher(__TopXMLNS, - _val) -> - _val. - -encode_pubsub_event_item_attr_publisher(<<>>, _acc) -> +'encode_pubsub_event_$configuration'(undefined, _acc) -> _acc; -encode_pubsub_event_item_attr_publisher(_val, _acc) -> - [{<<"publisher">>, _val} | _acc]. +'encode_pubsub_event_$configuration'(Configuration, + _acc) -> + [encode_pubsub_event_configuration(Configuration, []) + | _acc]. -decode_pubsub_event_retract(__TopXMLNS, __IgnoreEls, - {xmlel, <<"retract">>, _attrs, _els}) -> - Id = decode_pubsub_event_retract_attrs(__TopXMLNS, - _attrs, undefined), - Id. - -decode_pubsub_event_retract_attrs(__TopXMLNS, - [{<<"id">>, _val} | _attrs], _Id) -> - decode_pubsub_event_retract_attrs(__TopXMLNS, _attrs, - _val); -decode_pubsub_event_retract_attrs(__TopXMLNS, - [_ | _attrs], Id) -> - decode_pubsub_event_retract_attrs(__TopXMLNS, _attrs, - Id); -decode_pubsub_event_retract_attrs(__TopXMLNS, [], Id) -> - decode_pubsub_event_retract_attr_id(__TopXMLNS, Id). - -encode_pubsub_event_retract(Id, _xmlns_attrs) -> - _els = [], - _attrs = encode_pubsub_event_retract_attr_id(Id, - _xmlns_attrs), - {xmlel, <<"retract">>, _attrs, _els}. - -decode_pubsub_event_retract_attr_id(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"id">>, <<"retract">>, __TopXMLNS}}); -decode_pubsub_event_retract_attr_id(__TopXMLNS, _val) -> - _val. - -encode_pubsub_event_retract_attr_id(_val, _acc) -> - [{<<"id">>, _val} | _acc]. +'encode_pubsub_event_$subscription'(undefined, _acc) -> + _acc; +'encode_pubsub_event_$subscription'(Subscription, + _acc) -> + [encode_pubsub_subscription(Subscription, []) | _acc]. decode_pubsub_items(__TopXMLNS, __IgnoreEls, {xmlel, <<"items">>, _attrs, _els}) -> - Items = decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, - _els, []), - {Max_items, Node, Subid} = + {Items, Retract} = decode_pubsub_items_els(__TopXMLNS, + __IgnoreEls, _els, [], + undefined), + {Xmlns, Max_items, Node, Subid} = decode_pubsub_items_attrs(__TopXMLNS, _attrs, undefined, - undefined, undefined), - {pubsub_items, Node, Max_items, Subid, Items}. + undefined, undefined, undefined), + {ps_items, Xmlns, Node, Items, Max_items, Subid, + Retract}. decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, [], - Items) -> - lists:reverse(Items); + Items, Retract) -> + {lists:reverse(Items), Retract}; decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items) -> + [{xmlel, <<"retract">>, _attrs, _} = _el | _els], Items, + Retract) -> case get_attr(<<"xmlns">>, _attrs) of <<"">> when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub">> -> + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, _els, + Items, + decode_pubsub_event_retract(__TopXMLNS, + __IgnoreEls, + _el)); + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, _els, + Items, + decode_pubsub_event_retract(<<"http://jabber.org/protocol/pubsub#event">>, + __IgnoreEls, + _el)); + _ -> + decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, _els, + Items, Retract) + end; +decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, + [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items, + Retract) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"">> + when __TopXMLNS == + <<"http://jabber.org/protocol/pubsub">>; + __TopXMLNS == + <<"http://jabber.org/protocol/pubsub#event">> -> decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, _els, [decode_pubsub_item(__TopXMLNS, __IgnoreEls, _el) - | Items]); + | Items], + Retract); <<"http://jabber.org/protocol/pubsub">> -> decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, _els, [decode_pubsub_item(<<"http://jabber.org/protocol/pubsub">>, __IgnoreEls, _el) - | Items]); + | Items], + Retract); + <<"http://jabber.org/protocol/pubsub#event">> -> + decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, _els, + [decode_pubsub_item(<<"http://jabber.org/protocol/pubsub#event">>, + __IgnoreEls, _el) + | Items], + Retract); _ -> decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, _els, - Items) + Items, Retract) end; decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Items) -> + [_ | _els], Items, Retract) -> decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, _els, - Items). + Items, Retract). decode_pubsub_items_attrs(__TopXMLNS, - [{<<"max_items">>, _val} | _attrs], _Max_items, Node, - Subid) -> - decode_pubsub_items_attrs(__TopXMLNS, _attrs, _val, - Node, Subid); -decode_pubsub_items_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], Max_items, _Node, - Subid) -> - decode_pubsub_items_attrs(__TopXMLNS, _attrs, Max_items, - _val, Subid); -decode_pubsub_items_attrs(__TopXMLNS, - [{<<"subid">>, _val} | _attrs], Max_items, Node, - _Subid) -> - decode_pubsub_items_attrs(__TopXMLNS, _attrs, Max_items, - Node, _val); -decode_pubsub_items_attrs(__TopXMLNS, [_ | _attrs], - Max_items, Node, Subid) -> - decode_pubsub_items_attrs(__TopXMLNS, _attrs, Max_items, - Node, Subid); -decode_pubsub_items_attrs(__TopXMLNS, [], Max_items, + [{<<"xmlns">>, _val} | _attrs], _Xmlns, Max_items, Node, Subid) -> - {decode_pubsub_items_attr_max_items(__TopXMLNS, + decode_pubsub_items_attrs(__TopXMLNS, _attrs, _val, + Max_items, Node, Subid); +decode_pubsub_items_attrs(__TopXMLNS, + [{<<"max_items">>, _val} | _attrs], Xmlns, _Max_items, + Node, Subid) -> + decode_pubsub_items_attrs(__TopXMLNS, _attrs, Xmlns, + _val, Node, Subid); +decode_pubsub_items_attrs(__TopXMLNS, + [{<<"node">>, _val} | _attrs], Xmlns, Max_items, + _Node, Subid) -> + decode_pubsub_items_attrs(__TopXMLNS, _attrs, Xmlns, + Max_items, _val, Subid); +decode_pubsub_items_attrs(__TopXMLNS, + [{<<"subid">>, _val} | _attrs], Xmlns, Max_items, + Node, _Subid) -> + decode_pubsub_items_attrs(__TopXMLNS, _attrs, Xmlns, + Max_items, Node, _val); +decode_pubsub_items_attrs(__TopXMLNS, [_ | _attrs], + Xmlns, Max_items, Node, Subid) -> + decode_pubsub_items_attrs(__TopXMLNS, _attrs, Xmlns, + Max_items, Node, Subid); +decode_pubsub_items_attrs(__TopXMLNS, [], Xmlns, + Max_items, Node, Subid) -> + {decode_pubsub_items_attr_xmlns(__TopXMLNS, Xmlns), + decode_pubsub_items_attr_max_items(__TopXMLNS, Max_items), decode_pubsub_items_attr_node(__TopXMLNS, Node), decode_pubsub_items_attr_subid(__TopXMLNS, Subid)}. -encode_pubsub_items({pubsub_items, Node, Max_items, - Subid, Items}, +encode_pubsub_items({ps_items, Xmlns, Node, Items, + Max_items, Subid, Retract}, _xmlns_attrs) -> _els = lists:reverse('encode_pubsub_items_$items'(Items, - [])), + 'encode_pubsub_items_$retract'(Retract, + []))), _attrs = encode_pubsub_items_attr_subid(Subid, encode_pubsub_items_attr_node(Node, encode_pubsub_items_attr_max_items(Max_items, - _xmlns_attrs))), + encode_pubsub_items_attr_xmlns(Xmlns, + _xmlns_attrs)))), {xmlel, <<"items">>, _attrs, _els}. 'encode_pubsub_items_$items'([], _acc) -> _acc; @@ -13362,6 +15396,19 @@ encode_pubsub_items({pubsub_items, Node, Max_items, 'encode_pubsub_items_$items'(_els, [encode_pubsub_item(Items, []) | _acc]). +'encode_pubsub_items_$retract'(undefined, _acc) -> _acc; +'encode_pubsub_items_$retract'(Retract, _acc) -> + [encode_pubsub_event_retract(Retract, []) | _acc]. + +decode_pubsub_items_attr_xmlns(__TopXMLNS, undefined) -> + <<>>; +decode_pubsub_items_attr_xmlns(__TopXMLNS, _val) -> + _val. + +encode_pubsub_items_attr_xmlns(<<>>, _acc) -> _acc; +encode_pubsub_items_attr_xmlns(_val, _acc) -> + [{<<"xmlns">>, _val} | _acc]. + decode_pubsub_items_attr_max_items(__TopXMLNS, undefined) -> undefined; @@ -13400,9 +15447,10 @@ decode_pubsub_item(__TopXMLNS, __IgnoreEls, {xmlel, <<"item">>, _attrs, _els}) -> __Xmls = decode_pubsub_item_els(__TopXMLNS, __IgnoreEls, _els, []), - Id = decode_pubsub_item_attrs(__TopXMLNS, _attrs, - undefined), - {pubsub_item, Id, __Xmls}. + {Id, Xmlns, Node, Publisher} = + decode_pubsub_item_attrs(__TopXMLNS, _attrs, undefined, + undefined, undefined, undefined), + {ps_item, Xmlns, Id, __Xmls, Node, Publisher}. decode_pubsub_item_els(__TopXMLNS, __IgnoreEls, [], __Xmls) -> @@ -13417,18 +15465,46 @@ decode_pubsub_item_els(__TopXMLNS, __IgnoreEls, __Xmls). decode_pubsub_item_attrs(__TopXMLNS, - [{<<"id">>, _val} | _attrs], _Id) -> - decode_pubsub_item_attrs(__TopXMLNS, _attrs, _val); -decode_pubsub_item_attrs(__TopXMLNS, [_ | _attrs], - Id) -> - decode_pubsub_item_attrs(__TopXMLNS, _attrs, Id); -decode_pubsub_item_attrs(__TopXMLNS, [], Id) -> - decode_pubsub_item_attr_id(__TopXMLNS, Id). + [{<<"id">>, _val} | _attrs], _Id, Xmlns, Node, + Publisher) -> + decode_pubsub_item_attrs(__TopXMLNS, _attrs, _val, + Xmlns, Node, Publisher); +decode_pubsub_item_attrs(__TopXMLNS, + [{<<"xmlns">>, _val} | _attrs], Id, _Xmlns, Node, + Publisher) -> + decode_pubsub_item_attrs(__TopXMLNS, _attrs, Id, _val, + Node, Publisher); +decode_pubsub_item_attrs(__TopXMLNS, + [{<<"node">>, _val} | _attrs], Id, Xmlns, _Node, + Publisher) -> + decode_pubsub_item_attrs(__TopXMLNS, _attrs, Id, Xmlns, + _val, Publisher); +decode_pubsub_item_attrs(__TopXMLNS, + [{<<"publisher">>, _val} | _attrs], Id, Xmlns, Node, + _Publisher) -> + decode_pubsub_item_attrs(__TopXMLNS, _attrs, Id, Xmlns, + Node, _val); +decode_pubsub_item_attrs(__TopXMLNS, [_ | _attrs], Id, + Xmlns, Node, Publisher) -> + decode_pubsub_item_attrs(__TopXMLNS, _attrs, Id, Xmlns, + Node, Publisher); +decode_pubsub_item_attrs(__TopXMLNS, [], Id, Xmlns, + Node, Publisher) -> + {decode_pubsub_item_attr_id(__TopXMLNS, Id), + decode_pubsub_item_attr_xmlns(__TopXMLNS, Xmlns), + decode_pubsub_item_attr_node(__TopXMLNS, Node), + decode_pubsub_item_attr_publisher(__TopXMLNS, + Publisher)}. -encode_pubsub_item({pubsub_item, Id, __Xmls}, +encode_pubsub_item({ps_item, Xmlns, Id, __Xmls, Node, + Publisher}, _xmlns_attrs) -> _els = __Xmls, - _attrs = encode_pubsub_item_attr_id(Id, _xmlns_attrs), + _attrs = encode_pubsub_item_attr_publisher(Publisher, + encode_pubsub_item_attr_node(Node, + encode_pubsub_item_attr_xmlns(Xmlns, + encode_pubsub_item_attr_id(Id, + _xmlns_attrs)))), {xmlel, <<"item">>, _attrs, _els}. decode_pubsub_item_attr_id(__TopXMLNS, undefined) -> @@ -13439,40 +15515,287 @@ encode_pubsub_item_attr_id(<<>>, _acc) -> _acc; encode_pubsub_item_attr_id(_val, _acc) -> [{<<"id">>, _val} | _acc]. +decode_pubsub_item_attr_xmlns(__TopXMLNS, undefined) -> + <<>>; +decode_pubsub_item_attr_xmlns(__TopXMLNS, _val) -> _val. + +encode_pubsub_item_attr_xmlns(<<>>, _acc) -> _acc; +encode_pubsub_item_attr_xmlns(_val, _acc) -> + [{<<"xmlns">>, _val} | _acc]. + +decode_pubsub_item_attr_node(__TopXMLNS, undefined) -> + <<>>; +decode_pubsub_item_attr_node(__TopXMLNS, _val) -> _val. + +encode_pubsub_item_attr_node(<<>>, _acc) -> _acc; +encode_pubsub_item_attr_node(_val, _acc) -> + [{<<"node">>, _val} | _acc]. + +decode_pubsub_item_attr_publisher(__TopXMLNS, + undefined) -> + <<>>; +decode_pubsub_item_attr_publisher(__TopXMLNS, _val) -> + _val. + +encode_pubsub_item_attr_publisher(<<>>, _acc) -> _acc; +encode_pubsub_item_attr_publisher(_val, _acc) -> + [{<<"publisher">>, _val} | _acc]. + +decode_pubsub_event_retract(__TopXMLNS, __IgnoreEls, + {xmlel, <<"retract">>, _attrs, _els}) -> + Id = decode_pubsub_event_retract_attrs(__TopXMLNS, + _attrs, undefined), + Id. + +decode_pubsub_event_retract_attrs(__TopXMLNS, + [{<<"id">>, _val} | _attrs], _Id) -> + decode_pubsub_event_retract_attrs(__TopXMLNS, _attrs, + _val); +decode_pubsub_event_retract_attrs(__TopXMLNS, + [_ | _attrs], Id) -> + decode_pubsub_event_retract_attrs(__TopXMLNS, _attrs, + Id); +decode_pubsub_event_retract_attrs(__TopXMLNS, [], Id) -> + decode_pubsub_event_retract_attr_id(__TopXMLNS, Id). + +encode_pubsub_event_retract(Id, _xmlns_attrs) -> + _els = [], + _attrs = encode_pubsub_event_retract_attr_id(Id, + _xmlns_attrs), + {xmlel, <<"retract">>, _attrs, _els}. + +decode_pubsub_event_retract_attr_id(__TopXMLNS, + undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"id">>, <<"retract">>, __TopXMLNS}}); +decode_pubsub_event_retract_attr_id(__TopXMLNS, _val) -> + _val. + +encode_pubsub_event_retract_attr_id(_val, _acc) -> + [{<<"id">>, _val} | _acc]. + +decode_pubsub_event_configuration(__TopXMLNS, + __IgnoreEls, + {xmlel, <<"configuration">>, _attrs, _els}) -> + Xdata = + decode_pubsub_event_configuration_els(__TopXMLNS, + __IgnoreEls, _els, undefined), + Node = + decode_pubsub_event_configuration_attrs(__TopXMLNS, + _attrs, undefined), + {Node, Xdata}. + +decode_pubsub_event_configuration_els(__TopXMLNS, + __IgnoreEls, [], Xdata) -> + Xdata; +decode_pubsub_event_configuration_els(__TopXMLNS, + __IgnoreEls, + [{xmlel, <<"x">>, _attrs, _} = _el + | _els], + Xdata) -> + case get_attr(<<"xmlns">>, _attrs) of + <<"jabber:x:data">> -> + decode_pubsub_event_configuration_els(__TopXMLNS, + __IgnoreEls, _els, + decode_xdata(<<"jabber:x:data">>, + __IgnoreEls, _el)); + _ -> + decode_pubsub_event_configuration_els(__TopXMLNS, + __IgnoreEls, _els, Xdata) + end; +decode_pubsub_event_configuration_els(__TopXMLNS, + __IgnoreEls, [_ | _els], Xdata) -> + decode_pubsub_event_configuration_els(__TopXMLNS, + __IgnoreEls, _els, Xdata). + +decode_pubsub_event_configuration_attrs(__TopXMLNS, + [{<<"node">>, _val} | _attrs], _Node) -> + decode_pubsub_event_configuration_attrs(__TopXMLNS, + _attrs, _val); +decode_pubsub_event_configuration_attrs(__TopXMLNS, + [_ | _attrs], Node) -> + decode_pubsub_event_configuration_attrs(__TopXMLNS, + _attrs, Node); +decode_pubsub_event_configuration_attrs(__TopXMLNS, [], + Node) -> + decode_pubsub_event_configuration_attr_node(__TopXMLNS, + Node). + +encode_pubsub_event_configuration({Node, Xdata}, + _xmlns_attrs) -> + _els = + lists:reverse('encode_pubsub_event_configuration_$xdata'(Xdata, + [])), + _attrs = + encode_pubsub_event_configuration_attr_node(Node, + _xmlns_attrs), + {xmlel, <<"configuration">>, _attrs, _els}. + +'encode_pubsub_event_configuration_$xdata'(undefined, + _acc) -> + _acc; +'encode_pubsub_event_configuration_$xdata'(Xdata, + _acc) -> + [encode_xdata(Xdata, + [{<<"xmlns">>, <<"jabber:x:data">>}]) + | _acc]. + +decode_pubsub_event_configuration_attr_node(__TopXMLNS, + undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"node">>, <<"configuration">>, + __TopXMLNS}}); +decode_pubsub_event_configuration_attr_node(__TopXMLNS, + _val) -> + _val. + +encode_pubsub_event_configuration_attr_node(_val, + _acc) -> + [{<<"node">>, _val} | _acc]. + +decode_pubsub_owner_affiliation(__TopXMLNS, __IgnoreEls, + {xmlel, <<"affiliation">>, _attrs, _els}) -> + {Jid, Xmlns, Type} = + decode_pubsub_owner_affiliation_attrs(__TopXMLNS, + _attrs, undefined, undefined, + undefined), + {ps_affiliation, Xmlns, <<>>, Type, Jid}. + +decode_pubsub_owner_affiliation_attrs(__TopXMLNS, + [{<<"jid">>, _val} | _attrs], _Jid, Xmlns, + Type) -> + decode_pubsub_owner_affiliation_attrs(__TopXMLNS, + _attrs, _val, Xmlns, Type); +decode_pubsub_owner_affiliation_attrs(__TopXMLNS, + [{<<"xmlns">>, _val} | _attrs], Jid, + _Xmlns, Type) -> + decode_pubsub_owner_affiliation_attrs(__TopXMLNS, + _attrs, Jid, _val, Type); +decode_pubsub_owner_affiliation_attrs(__TopXMLNS, + [{<<"affiliation">>, _val} | _attrs], Jid, + Xmlns, _Type) -> + decode_pubsub_owner_affiliation_attrs(__TopXMLNS, + _attrs, Jid, Xmlns, _val); +decode_pubsub_owner_affiliation_attrs(__TopXMLNS, + [_ | _attrs], Jid, Xmlns, Type) -> + decode_pubsub_owner_affiliation_attrs(__TopXMLNS, + _attrs, Jid, Xmlns, Type); +decode_pubsub_owner_affiliation_attrs(__TopXMLNS, [], + Jid, Xmlns, Type) -> + {decode_pubsub_owner_affiliation_attr_jid(__TopXMLNS, + Jid), + decode_pubsub_owner_affiliation_attr_xmlns(__TopXMLNS, + Xmlns), + decode_pubsub_owner_affiliation_attr_affiliation(__TopXMLNS, + Type)}. + +encode_pubsub_owner_affiliation({ps_affiliation, Xmlns, + _, Type, Jid}, + _xmlns_attrs) -> + _els = [], + _attrs = + encode_pubsub_owner_affiliation_attr_affiliation(Type, + encode_pubsub_owner_affiliation_attr_xmlns(Xmlns, + encode_pubsub_owner_affiliation_attr_jid(Jid, + _xmlns_attrs))), + {xmlel, <<"affiliation">>, _attrs, _els}. + +decode_pubsub_owner_affiliation_attr_jid(__TopXMLNS, + undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"jid">>, <<"affiliation">>, + __TopXMLNS}}); +decode_pubsub_owner_affiliation_attr_jid(__TopXMLNS, + _val) -> + case catch dec_jid(_val) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"jid">>, <<"affiliation">>, + __TopXMLNS}}); + _res -> _res + end. + +encode_pubsub_owner_affiliation_attr_jid(_val, _acc) -> + [{<<"jid">>, enc_jid(_val)} | _acc]. + +decode_pubsub_owner_affiliation_attr_xmlns(__TopXMLNS, + undefined) -> + <<>>; +decode_pubsub_owner_affiliation_attr_xmlns(__TopXMLNS, + _val) -> + _val. + +encode_pubsub_owner_affiliation_attr_xmlns(<<>>, + _acc) -> + _acc; +encode_pubsub_owner_affiliation_attr_xmlns(_val, + _acc) -> + [{<<"xmlns">>, _val} | _acc]. + +decode_pubsub_owner_affiliation_attr_affiliation(__TopXMLNS, + undefined) -> + erlang:error({xmpp_codec, + {missing_attr, <<"affiliation">>, <<"affiliation">>, + __TopXMLNS}}); +decode_pubsub_owner_affiliation_attr_affiliation(__TopXMLNS, + _val) -> + case catch dec_enum(_val, + [member, none, outcast, owner, publisher, + 'publish-only']) + of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"affiliation">>, <<"affiliation">>, + __TopXMLNS}}); + _res -> _res + end. + +encode_pubsub_owner_affiliation_attr_affiliation(_val, + _acc) -> + [{<<"affiliation">>, enc_enum(_val)} | _acc]. + decode_pubsub_affiliation(__TopXMLNS, __IgnoreEls, {xmlel, <<"affiliation">>, _attrs, _els}) -> - {Node, Type} = + {Node, Xmlns, Type} = decode_pubsub_affiliation_attrs(__TopXMLNS, _attrs, - undefined, undefined), - {pubsub_affiliation, Node, Type}. + undefined, undefined, undefined), + {ps_affiliation, Xmlns, Node, Type, undefined}. decode_pubsub_affiliation_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], _Node, Type) -> + [{<<"node">>, _val} | _attrs], _Node, Xmlns, + Type) -> decode_pubsub_affiliation_attrs(__TopXMLNS, _attrs, - _val, Type); + _val, Xmlns, Type); +decode_pubsub_affiliation_attrs(__TopXMLNS, + [{<<"xmlns">>, _val} | _attrs], Node, _Xmlns, + Type) -> + decode_pubsub_affiliation_attrs(__TopXMLNS, _attrs, + Node, _val, Type); decode_pubsub_affiliation_attrs(__TopXMLNS, [{<<"affiliation">>, _val} | _attrs], Node, - _Type) -> + Xmlns, _Type) -> decode_pubsub_affiliation_attrs(__TopXMLNS, _attrs, - Node, _val); + Node, Xmlns, _val); decode_pubsub_affiliation_attrs(__TopXMLNS, - [_ | _attrs], Node, Type) -> + [_ | _attrs], Node, Xmlns, Type) -> decode_pubsub_affiliation_attrs(__TopXMLNS, _attrs, - Node, Type); + Node, Xmlns, Type); decode_pubsub_affiliation_attrs(__TopXMLNS, [], Node, - Type) -> + Xmlns, Type) -> {decode_pubsub_affiliation_attr_node(__TopXMLNS, Node), + decode_pubsub_affiliation_attr_xmlns(__TopXMLNS, Xmlns), decode_pubsub_affiliation_attr_affiliation(__TopXMLNS, Type)}. -encode_pubsub_affiliation({pubsub_affiliation, Node, - Type}, +encode_pubsub_affiliation({ps_affiliation, Xmlns, Node, + Type, _}, _xmlns_attrs) -> _els = [], _attrs = encode_pubsub_affiliation_attr_affiliation(Type, - encode_pubsub_affiliation_attr_node(Node, - _xmlns_attrs)), + encode_pubsub_affiliation_attr_xmlns(Xmlns, + encode_pubsub_affiliation_attr_node(Node, + _xmlns_attrs))), {xmlel, <<"affiliation">>, _attrs, _els}. decode_pubsub_affiliation_attr_node(__TopXMLNS, @@ -13486,6 +15809,18 @@ decode_pubsub_affiliation_attr_node(__TopXMLNS, _val) -> encode_pubsub_affiliation_attr_node(_val, _acc) -> [{<<"node">>, _val} | _acc]. +decode_pubsub_affiliation_attr_xmlns(__TopXMLNS, + undefined) -> + <<>>; +decode_pubsub_affiliation_attr_xmlns(__TopXMLNS, + _val) -> + _val. + +encode_pubsub_affiliation_attr_xmlns(<<>>, _acc) -> + _acc; +encode_pubsub_affiliation_attr_xmlns(_val, _acc) -> + [{<<"xmlns">>, _val} | _acc]. + decode_pubsub_affiliation_attr_affiliation(__TopXMLNS, undefined) -> erlang:error({xmpp_codec, @@ -13510,57 +15845,86 @@ encode_pubsub_affiliation_attr_affiliation(_val, decode_pubsub_subscription(__TopXMLNS, __IgnoreEls, {xmlel, <<"subscription">>, _attrs, _els}) -> - {Jid, Node, Subid, Type} = + {Xmlns, Jid, Node, Subid, Type, Expiry} = decode_pubsub_subscription_attrs(__TopXMLNS, _attrs, undefined, undefined, undefined, - undefined), - {pubsub_subscription, Jid, Node, Subid, Type}. + undefined, undefined, undefined), + {ps_subscription, Xmlns, Jid, Type, Node, Subid, + Expiry}. decode_pubsub_subscription_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], _Jid, Node, - Subid, Type) -> + [{<<"xmlns">>, _val} | _attrs], _Xmlns, Jid, + Node, Subid, Type, Expiry) -> decode_pubsub_subscription_attrs(__TopXMLNS, _attrs, - _val, Node, Subid, Type); + _val, Jid, Node, Subid, Type, Expiry); decode_pubsub_subscription_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], Jid, _Node, - Subid, Type) -> + [{<<"jid">>, _val} | _attrs], Xmlns, _Jid, + Node, Subid, Type, Expiry) -> decode_pubsub_subscription_attrs(__TopXMLNS, _attrs, - Jid, _val, Subid, Type); + Xmlns, _val, Node, Subid, Type, Expiry); decode_pubsub_subscription_attrs(__TopXMLNS, - [{<<"subid">>, _val} | _attrs], Jid, Node, - _Subid, Type) -> + [{<<"node">>, _val} | _attrs], Xmlns, Jid, + _Node, Subid, Type, Expiry) -> decode_pubsub_subscription_attrs(__TopXMLNS, _attrs, - Jid, Node, _val, Type); + Xmlns, Jid, _val, Subid, Type, Expiry); decode_pubsub_subscription_attrs(__TopXMLNS, - [{<<"subscription">>, _val} | _attrs], Jid, - Node, Subid, _Type) -> + [{<<"subid">>, _val} | _attrs], Xmlns, Jid, + Node, _Subid, Type, Expiry) -> decode_pubsub_subscription_attrs(__TopXMLNS, _attrs, - Jid, Node, Subid, _val); + Xmlns, Jid, Node, _val, Type, Expiry); decode_pubsub_subscription_attrs(__TopXMLNS, - [_ | _attrs], Jid, Node, Subid, Type) -> + [{<<"subscription">>, _val} | _attrs], Xmlns, + Jid, Node, Subid, _Type, Expiry) -> decode_pubsub_subscription_attrs(__TopXMLNS, _attrs, - Jid, Node, Subid, Type); -decode_pubsub_subscription_attrs(__TopXMLNS, [], Jid, - Node, Subid, Type) -> - {decode_pubsub_subscription_attr_jid(__TopXMLNS, Jid), + Xmlns, Jid, Node, Subid, _val, Expiry); +decode_pubsub_subscription_attrs(__TopXMLNS, + [{<<"expiry">>, _val} | _attrs], Xmlns, Jid, + Node, Subid, Type, _Expiry) -> + decode_pubsub_subscription_attrs(__TopXMLNS, _attrs, + Xmlns, Jid, Node, Subid, Type, _val); +decode_pubsub_subscription_attrs(__TopXMLNS, + [_ | _attrs], Xmlns, Jid, Node, Subid, Type, + Expiry) -> + decode_pubsub_subscription_attrs(__TopXMLNS, _attrs, + Xmlns, Jid, Node, Subid, Type, Expiry); +decode_pubsub_subscription_attrs(__TopXMLNS, [], Xmlns, + Jid, Node, Subid, Type, Expiry) -> + {decode_pubsub_subscription_attr_xmlns(__TopXMLNS, + Xmlns), + decode_pubsub_subscription_attr_jid(__TopXMLNS, Jid), decode_pubsub_subscription_attr_node(__TopXMLNS, Node), decode_pubsub_subscription_attr_subid(__TopXMLNS, Subid), decode_pubsub_subscription_attr_subscription(__TopXMLNS, - Type)}. + Type), + decode_pubsub_subscription_attr_expiry(__TopXMLNS, + Expiry)}. -encode_pubsub_subscription({pubsub_subscription, Jid, - Node, Subid, Type}, +encode_pubsub_subscription({ps_subscription, Xmlns, Jid, + Type, Node, Subid, Expiry}, _xmlns_attrs) -> _els = [], - _attrs = - encode_pubsub_subscription_attr_subscription(Type, - encode_pubsub_subscription_attr_subid(Subid, - encode_pubsub_subscription_attr_node(Node, - encode_pubsub_subscription_attr_jid(Jid, - _xmlns_attrs)))), + _attrs = encode_pubsub_subscription_attr_expiry(Expiry, + encode_pubsub_subscription_attr_subscription(Type, + encode_pubsub_subscription_attr_subid(Subid, + encode_pubsub_subscription_attr_node(Node, + encode_pubsub_subscription_attr_jid(Jid, + encode_pubsub_subscription_attr_xmlns(Xmlns, + _xmlns_attrs)))))), {xmlel, <<"subscription">>, _attrs, _els}. +decode_pubsub_subscription_attr_xmlns(__TopXMLNS, + undefined) -> + <<>>; +decode_pubsub_subscription_attr_xmlns(__TopXMLNS, + _val) -> + _val. + +encode_pubsub_subscription_attr_xmlns(<<>>, _acc) -> + _acc; +encode_pubsub_subscription_attr_xmlns(_val, _acc) -> + [{<<"xmlns">>, _val} | _acc]. + decode_pubsub_subscription_attr_jid(__TopXMLNS, undefined) -> erlang:error({xmpp_codec, @@ -13624,6 +15988,25 @@ encode_pubsub_subscription_attr_subscription(_val, _acc) -> [{<<"subscription">>, enc_enum(_val)} | _acc]. +decode_pubsub_subscription_attr_expiry(__TopXMLNS, + undefined) -> + undefined; +decode_pubsub_subscription_attr_expiry(__TopXMLNS, + _val) -> + case catch dec_utc(_val) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"expiry">>, <<"subscription">>, + __TopXMLNS}}); + _res -> _res + end. + +encode_pubsub_subscription_attr_expiry(undefined, + _acc) -> + _acc; +encode_pubsub_subscription_attr_expiry(_val, _acc) -> + [{<<"expiry">>, enc_utc(_val)} | _acc]. + decode_xdata(__TopXMLNS, __IgnoreEls, {xmlel, <<"x">>, _attrs, _els}) -> {Fields, Items, Instructions, Reported, Title} = diff --git a/tools/xmpp_codec.spec b/tools/xmpp_codec.spec index d410a7613..445d9a716 100644 --- a/tools/xmpp_codec.spec +++ b/tools/xmpp_codec.spec @@ -1646,27 +1646,40 @@ -xml(pubsub_subscription, #elem{name = <<"subscription">>, - xmlns = <<"http://jabber.org/protocol/pubsub">>, - result = {pubsub_subscription, '$jid', '$node', '$subid', - '$type'}, - attrs = [#attr{name = <<"jid">>, - required = true, + xmlns = [<<"http://jabber.org/protocol/pubsub">>, + <<"http://jabber.org/protocol/pubsub#owner">>, + <<"http://jabber.org/protocol/pubsub#event">>], + result = {ps_subscription, '$xmlns', '$jid', '$type', + '$node', '$subid', '$expiry'}, + attrs = [#attr{name = <<"xmlns">>}, + #attr{name = <<"jid">>, + required = true, dec = {dec_jid, []}, enc = {enc_jid, []}}, - #attr{name = <<"node">>}, + #attr{name = <<"node">>}, #attr{name = <<"subid">>}, #attr{name = <<"subscription">>, label = '$type', dec = {dec_enum, [[none, pending, subscribed, unconfigured]]}, - enc = {enc_enum, []}}]}). + enc = {enc_enum, []}}, + #attr{name = <<"expiry">>, + dec = {dec_utc, []}, + enc = {enc_utc, []}}]}). + +-record(ps_affiliation, {xmlns = <<>> :: binary(), + node = <<>> :: binary(), + type :: member | none | outcast | + owner | publisher | 'publish-only', + jid :: jid:jid()}). +-type ps_affiliation() :: #ps_affiliation{}. -xml(pubsub_affiliation, #elem{name = <<"affiliation">>, xmlns = <<"http://jabber.org/protocol/pubsub">>, - result = {pubsub_affiliation, '$node', '$type'}, - attrs = [#attr{name = <<"node">>, - required = true}, + result = {ps_affiliation, '$xmlns', '$node', '$type', '$_'}, + attrs = [#attr{name = <<"node">>, required = true}, + #attr{name = <<"xmlns">>}, #attr{name = <<"affiliation">>, label = '$type', required = true, @@ -1674,24 +1687,28 @@ publisher, 'publish-only']]}, enc = {enc_enum, []}}]}). --xml(pubsub_item, - #elem{name = <<"item">>, - xmlns = <<"http://jabber.org/protocol/pubsub">>, - result = {pubsub_item, '$id', '$_xmls'}, - attrs = [#attr{name = <<"id">>}]}). +-xml(pubsub_owner_affiliation, + #elem{name = <<"affiliation">>, + xmlns = <<"http://jabber.org/protocol/pubsub#owner">>, + result = {ps_affiliation, '$xmlns', '$_', '$type', '$jid'}, + attrs = [#attr{name = <<"jid">>, + required = true, + dec = {dec_jid, []}, + enc = {enc_jid, []}}, + #attr{name = <<"xmlns">>}, + #attr{name = <<"affiliation">>, + label = '$type', + required = true, + dec = {dec_enum, [[member, none, outcast, owner, + publisher, 'publish-only']]}, + enc = {enc_enum, []}}]}). --xml(pubsub_items, - #elem{name = <<"items">>, - xmlns = <<"http://jabber.org/protocol/pubsub">>, - result = {pubsub_items, '$node', '$max_items', - '$subid', '$items'}, - attrs = [#attr{name = <<"max_items">>, - dec = {dec_int, [0, infinity]}, - enc = {enc_int, []}}, - #attr{name = <<"node">>, - required = true}, - #attr{name = <<"subid">>}], - refs = [#ref{name = pubsub_item, label = '$items'}]}). +-xml(pubsub_event_configuration, + #elem{name = <<"configuration">>, + xmlns = <<"http://jabber.org/protocol/pubsub#event">>, + result = {'$node', '$xdata'}, + attrs = [#attr{name = <<"node">>, required = true}], + refs = [#ref{name = xdata, min = 0, max = 1}]}). -xml(pubsub_event_retract, #elem{name = <<"retract">>, @@ -1699,32 +1716,55 @@ result = '$id', attrs = [#attr{name = <<"id">>, required = true}]}). --xml(pubsub_event_item, +-xml(pubsub_item, #elem{name = <<"item">>, - xmlns = <<"http://jabber.org/protocol/pubsub#event">>, - result = {pubsub_event_item, '$id', '$node', '$publisher', '$_xmls'}, + xmlns = [<<"http://jabber.org/protocol/pubsub">>, + <<"http://jabber.org/protocol/pubsub#event">>], + result = {ps_item, '$xmlns', '$id', '$_xmls', '$node', '$publisher'}, attrs = [#attr{name = <<"id">>}, + #attr{name = <<"xmlns">>}, #attr{name = <<"node">>}, #attr{name = <<"publisher">>}]}). --xml(pubsub_event_items, +-xml(pubsub_items, #elem{name = <<"items">>, - xmlns = <<"http://jabber.org/protocol/pubsub#event">>, - result = {pubsub_event_items, '$node', '$retract', '$items'}, - attrs = [#attr{name = <<"node">>, - required = true}], - refs = [#ref{name = pubsub_event_retract, label = '$retract'}, - #ref{name = pubsub_event_item, label = '$items'}]}). + xmlns = [<<"http://jabber.org/protocol/pubsub">>, + <<"http://jabber.org/protocol/pubsub#event">>], + result = {ps_items, '$xmlns', '$node', '$items', '$max_items', + '$subid', '$retract'}, + attrs = [#attr{name = <<"xmlns">>}, + #attr{name = <<"max_items">>, + dec = {dec_int, [0, infinity]}, + enc = {enc_int, []}}, + #attr{name = <<"node">>, + required = true}, + #attr{name = <<"subid">>}], + refs = [#ref{name = pubsub_event_retract, label = '$retract', + min = 0, max = 1}, + #ref{name = pubsub_item, label = '$items'}]}). -xml(pubsub_event, #elem{name = <<"event">>, xmlns = <<"http://jabber.org/protocol/pubsub#event">>, - result = {pubsub_event, '$items'}, - refs = [#ref{name = pubsub_event_items, label = '$items'}]}). + result = {ps_event, '$items', '$purge', '$subscription', '$delete', + '$create', '$configuration'}, + refs = [#ref{name = pubsub_items, label = '$items', + min = 0, max = 1}, + #ref{name = pubsub_subscription, min = 0, max = 1, + label = '$subscription'}, + #ref{name = pubsub_purge, min = 0, max = 1, + label = '$purge'}, + #ref{name = pubsub_delete, min = 0, max = 1, + label = '$delete'}, + #ref{name = pubsub_create, min = 0, max = 1, + label = '$create'}, + #ref{name = pubsub_event_configuration, min = 0, max = 1, + label = '$configuration'}]}). -xml(pubsub_subscriptions, #elem{name = <<"subscriptions">>, - xmlns = <<"http://jabber.org/protocol/pubsub">>, + xmlns = [<<"http://jabber.org/protocol/pubsub">>, + <<"http://jabber.org/protocol/pubsub#owner">>], result = {'$node', '$subscriptions'}, attrs = [#attr{name = <<"node">>}], refs = [#ref{name = pubsub_subscription, label = '$subscriptions'}]}). @@ -1732,13 +1772,21 @@ -xml(pubsub_affiliations, #elem{name = <<"affiliations">>, xmlns = <<"http://jabber.org/protocol/pubsub">>, - result = '$affiliations', + result = {'$node', '$affiliations'}, + attrs = [#attr{name = <<"node">>}], refs = [#ref{name = pubsub_affiliation, label = '$affiliations'}]}). +-xml(pubsub_owner_affiliations, + #elem{name = <<"affiliations">>, + xmlns = <<"http://jabber.org/protocol/pubsub#owner">>, + result = {'$node', '$affiliations'}, + attrs = [#attr{name = <<"node">>}], + refs = [#ref{name = pubsub_owner_affiliation, label = '$affiliations'}]}). + -xml(pubsub_subscribe, #elem{name = <<"subscribe">>, xmlns = <<"http://jabber.org/protocol/pubsub">>, - result = {pubsub_subscribe, '$node', '$jid'}, + result = {ps_subscribe, '$node', '$jid'}, attrs = [#attr{name = <<"node">>}, #attr{name = <<"jid">>, required = true, @@ -1748,7 +1796,7 @@ -xml(pubsub_unsubscribe, #elem{name = <<"unsubscribe">>, xmlns = <<"http://jabber.org/protocol/pubsub">>, - result = {pubsub_unsubscribe, '$node', '$jid', '$subid'}, + result = {ps_unsubscribe, '$node', '$jid', '$subid'}, attrs = [#attr{name = <<"node">>}, #attr{name = <<"subid">>}, #attr{name = <<"jid">>, @@ -1759,7 +1807,7 @@ -xml(pubsub_publish, #elem{name = <<"publish">>, xmlns = <<"http://jabber.org/protocol/pubsub">>, - result = {pubsub_publish, '$node', '$items'}, + result = {ps_publish, '$node', '$items'}, attrs = [#attr{name = <<"node">>, required = true}], refs = [#ref{name = pubsub_item, label = '$items'}]}). @@ -1767,7 +1815,7 @@ -xml(pubsub_options, #elem{name = <<"options">>, xmlns = <<"http://jabber.org/protocol/pubsub">>, - result = {pubsub_options, '$node', '$jid', '$subid', '$xdata'}, + result = {ps_options, '$node', '$jid', '$subid', '$xdata'}, attrs = [#attr{name = <<"node">>}, #attr{name = <<"subid">>}, #attr{name = <<"jid">>, @@ -1780,7 +1828,7 @@ -xml(pubsub_retract, #elem{name = <<"retract">>, xmlns = <<"http://jabber.org/protocol/pubsub">>, - result = {pubsub_retract, '$node', '$notify', '$items'}, + result = {ps_retract, '$node', '$notify', '$items'}, attrs = [#attr{name = <<"node">>, required = true}, #attr{name = <<"notify">>, @@ -1789,12 +1837,69 @@ enc = {enc_bool, []}}], refs = [#ref{name = pubsub_item, label = '$items'}]}). +-xml(pubsub_create, + #elem{name = <<"create">>, + xmlns = [<<"http://jabber.org/protocol/pubsub">>, + <<"http://jabber.org/protocol/pubsub#event">>], + result = '$node', + attrs = [#attr{name = <<"node">>}]}). + +-xml(pubsub_configure, + #elem{name = <<"configure">>, + xmlns = [<<"http://jabber.org/protocol/pubsub">>, + <<"http://jabber.org/protocol/pubsub#owner">>], + result = {'$node', '$xdata'}, + attrs = [#attr{name = <<"node">>}], + refs = [#ref{name = xdata, min = 0, max = 1}]}). + +-xml(pubsub_publish_options, + #elem{name = <<"publish-options">>, + xmlns = <<"http://jabber.org/protocol/pubsub">>, + result = '$xdata', + refs = [#ref{name = xdata, min = 0, max = 1}]}). + +-xml(pubsub_default, + #elem{name = <<"default">>, + xmlns = [<<"http://jabber.org/protocol/pubsub">>, + <<"http://jabber.org/protocol/pubsub#owner">>], + result = {'$node', '$xdata'}, + attrs = [#attr{name = <<"node">>}], + refs = [#ref{name = xdata, min = 0, max = 1}]}). + +-xml(pubsub_redirect, + #elem{name = <<"redirect">>, + xmlns = [<<"http://jabber.org/protocol/pubsub">>, + <<"http://jabber.org/protocol/pubsub#owner">>, + <<"http://jabber.org/protocol/pubsub#event">>], + result = '$uri', + attrs = [#attr{name = <<"uri">>, required = true}]}). + +-xml(pubsub_delete, + #elem{name = <<"delete">>, + xmlns = [<<"http://jabber.org/protocol/pubsub">>, + <<"http://jabber.org/protocol/pubsub#owner">>, + <<"http://jabber.org/protocol/pubsub#event">>], + result = {'$node', '$uri'}, + attrs = [#attr{name = <<"node">>, required = true}], + refs = [#ref{name = pubsub_redirect, min = 0, max = 1, + label = '$uri', default = <<>>}]}). + +-xml(pubsub_purge, + #elem{name = <<"purge">>, + xmlns = [<<"http://jabber.org/protocol/pubsub">>, + <<"http://jabber.org/protocol/pubsub#owner">>, + <<"http://jabber.org/protocol/pubsub#event">>], + result = '$node', + attrs = [#attr{name = <<"node">>, required = true}]}). + -xml(pubsub, #elem{name = <<"pubsub">>, xmlns = <<"http://jabber.org/protocol/pubsub">>, - result = {pubsub, '$subscriptions', '$affiliations', '$publish', - '$subscribe', '$unsubscribe', '$options', '$items', - '$retract'}, + result = {pubsub, '$subscriptions', '$subscription', + '$affiliations', '$publish', '$publish_options', + '$subscribe', '$unsubscribe', '$options', '$items', + '$retract', '$create', '$configure', '$default', '$delete', + '$purge', '$rsm'}, refs = [#ref{name = pubsub_subscriptions, label = '$subscriptions', min = 0, max = 1}, #ref{name = pubsub_affiliations, label = '$affiliations', @@ -1809,9 +1914,209 @@ min = 0, max = 1}, #ref{name = pubsub_retract, label = '$retract', min = 0, max = 1}, + #ref{name = pubsub_create, label = '$create', + min = 0, max = 1}, + #ref{name = pubsub_configure, label = '$configure', + min = 0, max = 1}, + #ref{name = pubsub_publish_options, min = 0, max = 1, + label = '$publish_options'}, + #ref{name = pubsub_default, label = '$default', + min = 0, max = 1}, + #ref{name = pubsub_delete, label = '$delete', + min = 0, max = 1}, + #ref{name = pubsub_purge, label = '$purge', + min = 0, max = 1}, + #ref{name = pubsub_subscription, label = '$subscription', + min = 0, max = 1}, + #ref{name = rsm_set, min = 0, max = 1, label = '$rsm'}, #ref{name = pubsub_publish, label = '$publish', min = 0, max = 1}]}). +-xml(pubsub_owner, + #elem{name = <<"pubsub">>, + xmlns = <<"http://jabber.org/protocol/pubsub#owner">>, + result = {pubsub_owner, '$affiliations', '$configure', '$default', + '$delete', '$purge', '$subscriptions'}, + refs = [#ref{name = pubsub_owner_affiliations, + label = '$affiliations', min = 0, max = 1}, + #ref{name = pubsub_configure, label = '$configure', + min = 0, max = 1}, + #ref{name = pubsub_default, label = '$default', + min = 0, max = 1}, + #ref{name = pubsub_delete, label = '$delete', + min = 0, max = 1}, + #ref{name = pubsub_purge, label = '$purge', + min = 0, max = 1}, + #ref{name = pubsub_subscriptions, + label = '$subscriptions', min = 0, max = 1}]}). + +-type ps_error_type() :: 'closed-node' | 'configuration-required' | + 'invalid-jid' | 'invalid-options' | + 'invalid-payload' | 'invalid-subid' | + 'item-forbidden' | 'item-required' | 'jid-required' | + 'max-items-exceeded' | 'max-nodes-exceeded' | + 'nodeid-required' | 'not-in-roster-group' | + 'not-subscribed' | 'payload-too-big' | + 'payload-required' | 'pending-subscription' | + 'presence-subscription-required' | 'subid-required' | + 'too-many-subscriptions' | 'unsupported' | + 'unsupported-access-model'. +-type ps_error_feature() :: 'access-authorize' | 'access-open' | + 'access-presence' | 'access-roster' | + 'access-whitelist' | 'auto-create' | + 'auto-subscribe' | 'collections' | 'config-node' | + 'create-and-configure' | 'create-nodes' | + 'delete-items' | 'delete-nodes' | + 'filtered-notifications' | 'get-pending' | + 'instant-nodes' | 'item-ids' | 'last-published' | + 'leased-subscription' | 'manage-subscriptions' | + 'member-affiliation' | 'meta-data' | + 'modify-affiliations' | 'multi-collection' | + 'multi-subscribe' | 'outcast-affiliation' | + 'persistent-items' | 'presence-notifications' | + 'presence-subscribe' | 'publish' | + 'publish-options' | 'publish-only-affiliation' | + 'publisher-affiliation' | 'purge-nodes' | + 'retract-items' | 'retrieve-affiliations' | + 'retrieve-default' | 'retrieve-items' | + 'retrieve-subscriptions' | 'subscribe' | + 'subscription-options' | 'subscription-notifications'. +-record(ps_error, {type :: ps_error_type(), feature :: ps_error_feature()}). +-type ps_error() :: #ps_error{}. + +-xml(pubsub_error_closed_node, + #elem{name = <<"closed-node">>, + xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, + result = {ps_error, 'closed-node', '$_'}}). +-xml(pubsub_error_configuration_required, + #elem{name = <<"configuration-required">>, + xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, + result = {ps_error, 'configuration-required', '$_'}}). +-xml(pubsub_error_invalid_jid, + #elem{name = <<"invalid-jid">>, + xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, + result = {ps_error, 'invalid-jid', '$_'}}). +-xml(pubsub_error_invalid_options, + #elem{name = <<"invalid-options">>, + xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, + result = {ps_error, 'invalid-options', '$_'}}). +-xml(pubsub_error_invalid_payload, + #elem{name = <<"invalid-payload">>, + xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, + result = {ps_error, 'invalid-payload', '$_'}}). +-xml(pubsub_error_invalid_subid, + #elem{name = <<"invalid-subid">>, + xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, + result = {ps_error, 'invalid-subid', '$_'}}). +-xml(pubsub_error_item_forbidden, + #elem{name = <<"item-forbidden">>, + xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, + result = {ps_error, 'item-forbidden', '$_'}}). +-xml(pubsub_error_item_required, + #elem{name = <<"item-required">>, + xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, + result = {ps_error, 'item-required', '$_'}}). +-xml(pubsub_error_jid_required, + #elem{name = <<"jid-required">>, + xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, + result = {ps_error, 'jid-required', '$_'}}). +-xml(pubsub_error_max_items_exceeded, + #elem{name = <<"max-items-exceeded">>, + xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, + result = {ps_error, 'max-items-exceeded', '$_'}}). +-xml(pubsub_error_max_nodes_exceeded, + #elem{name = <<"max-nodes-exceeded">>, + xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, + result = {ps_error, 'max-nodes-exceeded', '$_'}}). +-xml(pubsub_error_nodeid_required, + #elem{name = <<"nodeid-required">>, + xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, + result = {ps_error, 'nodeid-required', '$_'}}). +-xml(pubsub_error_not_in_roster_group, + #elem{name = <<"not-in-roster-group">>, + xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, + result = {ps_error, 'not-in-roster-group', '$_'}}). +-xml(pubsub_error_not_subscribed, + #elem{name = <<"not-subscribed">>, + xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, + result = {ps_error, 'not-subscribed', '$_'}}). +-xml(pubsub_error_payload_too_big, + #elem{name = <<"payload-too-big">>, + xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, + result = {ps_error, 'payload-too-big', '$_'}}). +-xml(pubsub_error_payload_required, + #elem{name = <<"payload-required">>, + xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, + result = {ps_error, 'payload-required', '$_'}}). +-xml(pubsub_error_pending_subscription, + #elem{name = <<"pending-subscription">>, + xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, + result = {ps_error, 'pending-subscription', '$_'}}). +-xml(pubsub_error_presence_subscription_required, + #elem{name = <<"presence-subscription-required">>, + xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, + result = {ps_error, 'presence-subscription-required', '$_'}}). +-xml(pubsub_error_subid_required, + #elem{name = <<"subid-required">>, + xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, + result = {ps_error, 'subid-required', '$_'}}). +-xml(pubsub_error_too_many_subscriptions, + #elem{name = <<"too-many-subscriptions">>, + xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, + result = {ps_error, 'too-many-subscriptions', '$_'}}). +-xml(pubsub_error_unsupported, + #elem{name = <<"unsupported">>, + xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, + result = {ps_error, 'unsupported', '$feature'}, + attrs = [#attr{name = <<"feature">>, required = true, + dec = {dec_enum, [['access-authorize', + 'access-open', + 'access-presence', + 'access-roster', + 'access-whitelist', + 'auto-create', + 'auto-subscribe', + 'collections', + 'config-node', + 'create-and-configure', + 'create-nodes', + 'delete-items', + 'delete-nodes', + 'filtered-notifications', + 'get-pending', + 'instant-nodes', + 'item-ids', + 'last-published', + 'leased-subscription', + 'manage-subscriptions', + 'member-affiliation', + 'meta-data', + 'modify-affiliations', + 'multi-collection', + 'multi-subscribe', + 'outcast-affiliation', + 'persistent-items', + 'presence-notifications', + 'presence-subscribe', + 'publish', + 'publish-options', + 'publish-only-affiliation', + 'publisher-affiliation', + 'purge-nodes', + 'retract-items', + 'retrieve-affiliations', + 'retrieve-default', + 'retrieve-items', + 'retrieve-subscriptions', + 'subscribe', + 'subscription-options', + 'subscription-notifications']]}, + enc = {enc_enum, []}}]}). +-xml(pubsub_error_unsupported_access_model, + #elem{name = <<"unsupported-access-model">>, + xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, + result = {ps_error, 'unsupported-access-model', '$_'}}). + -xml(shim_header, #elem{name = <<"header">>, xmlns = <<"http://jabber.org/protocol/shim">>, From 5ec972b00f2f140594eebfe1569e203cfb4f741c Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Thu, 8 Sep 2016 15:49:27 +0300 Subject: [PATCH 037/151] Improve pubsub code --- include/xmpp_codec.hrl | 42 ++++----- src/adhoc.erl | 149 -------------------------------- src/mod_pubsub.erl | 75 +++++++++------- src/node_dag.erl | 7 +- src/node_dispatch.erl | 14 +-- src/node_flat.erl | 74 ++++++++-------- src/node_flat_sql.erl | 7 +- src/nodetree_dag.erl | 18 ++-- src/nodetree_tree.erl | 10 +-- src/nodetree_tree_sql.erl | 18 ++-- src/pubsub_db_sql.erl | 16 ++-- src/pubsub_subscription.erl | 95 ++++++++------------ src/pubsub_subscription_sql.erl | 114 ++++++++++-------------- tools/xmpp_codec.spec | 42 ++++----- 14 files changed, 257 insertions(+), 424 deletions(-) delete mode 100644 src/adhoc.erl diff --git a/include/xmpp_codec.hrl b/include/xmpp_codec.hrl index 7eabdab8f..d2acf316c 100644 --- a/include/xmpp_codec.hrl +++ b/include/xmpp_codec.hrl @@ -23,27 +23,27 @@ 'presence-subscription-required' | 'subid-required' | 'too-many-subscriptions' | 'unsupported' | 'unsupported-access-model'. --type ps_error_feature() :: 'access-authorize' | 'access-open' | - 'access-presence' | 'access-roster' | - 'access-whitelist' | 'auto-create' | - 'auto-subscribe' | 'collections' | 'config-node' | - 'create-and-configure' | 'create-nodes' | - 'delete-items' | 'delete-nodes' | - 'filtered-notifications' | 'get-pending' | - 'instant-nodes' | 'item-ids' | 'last-published' | - 'leased-subscription' | 'manage-subscriptions' | - 'member-affiliation' | 'meta-data' | - 'modify-affiliations' | 'multi-collection' | - 'multi-subscribe' | 'outcast-affiliation' | - 'persistent-items' | 'presence-notifications' | - 'presence-subscribe' | 'publish' | - 'publish-options' | 'publish-only-affiliation' | - 'publisher-affiliation' | 'purge-nodes' | - 'retract-items' | 'retrieve-affiliations' | - 'retrieve-default' | 'retrieve-items' | - 'retrieve-subscriptions' | 'subscribe' | - 'subscription-options' | 'subscription-notifications'. --record(ps_error, {type :: ps_error_type(), feature :: ps_error_feature()}). +-type ps_feature() :: 'access-authorize' | 'access-open' | + 'access-presence' | 'access-roster' | + 'access-whitelist' | 'auto-create' | + 'auto-subscribe' | 'collections' | 'config-node' | + 'create-and-configure' | 'create-nodes' | + 'delete-items' | 'delete-nodes' | + 'filtered-notifications' | 'get-pending' | + 'instant-nodes' | 'item-ids' | 'last-published' | + 'leased-subscription' | 'manage-subscriptions' | + 'member-affiliation' | 'meta-data' | + 'modify-affiliations' | 'multi-collection' | + 'multi-subscribe' | 'outcast-affiliation' | + 'persistent-items' | 'presence-notifications' | + 'presence-subscribe' | 'publish' | + 'publish-options' | 'publish-only-affiliation' | + 'publisher-affiliation' | 'purge-nodes' | + 'retract-items' | 'retrieve-affiliations' | + 'retrieve-default' | 'retrieve-items' | + 'retrieve-subscriptions' | 'subscribe' | + 'subscription-options' | 'subscription-notifications'. +-record(ps_error, {type :: ps_error_type(), feature :: ps_feature()}). -type ps_error() :: #ps_error{}. -record(chatstate, {type :: active | composing | gone | inactive | paused}). diff --git a/src/adhoc.erl b/src/adhoc.erl deleted file mode 100644 index 6970584f9..000000000 --- a/src/adhoc.erl +++ /dev/null @@ -1,149 +0,0 @@ -%%%---------------------------------------------------------------------- -%%% File : adhoc.erl -%%% Author : Magnus Henoch -%%% Purpose : Provide helper functions for ad-hoc commands (XEP-0050) -%%% Created : 31 Oct 2005 by Magnus Henoch -%%% -%%% -%%% ejabberd, Copyright (C) 2002-2016 ProcessOne -%%% -%%% This program is free software; you can redistribute it and/or -%%% modify it under the terms of the GNU General Public License as -%%% published by the Free Software Foundation; either version 2 of the -%%% License, or (at your option) any later version. -%%% -%%% This program is distributed in the hope that it will be useful, -%%% but WITHOUT ANY WARRANTY; without even the implied warranty of -%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -%%% General Public License for more details. -%%% -%%% You should have received a copy of the GNU General Public License along -%%% with this program; if not, write to the Free Software Foundation, Inc., -%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -%%% -%%%---------------------------------------------------------------------- - --module(adhoc). - --author('henoch@dtek.chalmers.se'). - --export([ - parse_request/1, - produce_response/2, - produce_response/1 -]). - --include("ejabberd.hrl"). --include("logger.hrl"). --include("jlib.hrl"). --include("adhoc.hrl"). - -%% Parse an ad-hoc request. Return either an adhoc_request record or -%% an {error, ErrorType} tuple. -%% --spec parse_request(IQ :: iq_request()) -> adhoc_response() | {error, _}. - -parse_request(#iq{type = set, lang = Lang, sub_el = SubEl, xmlns = ?NS_COMMANDS}) -> - ?DEBUG("entering parse_request...", []), - Node = fxml:get_tag_attr_s(<<"node">>, SubEl), - SessionID = fxml:get_tag_attr_s(<<"sessionid">>, SubEl), - Action = fxml:get_tag_attr_s(<<"action">>, SubEl), - XData = find_xdata_el(SubEl), - #xmlel{children = AllEls} = SubEl, - Others = case XData of - false -> AllEls; - _ -> lists:delete(XData, AllEls) - end, - #adhoc_request{ - lang = Lang, - node = Node, - sessionid = SessionID, - action = Action, - xdata = XData, - others = Others - }; -parse_request(#iq{lang = Lang}) -> - Text = <<"Failed to parse ad-hoc command request">>, - {error, ?ERRT_BAD_REQUEST(Lang, Text)}. - -%% Borrowed from mod_vcard.erl -find_xdata_el(#xmlel{children = SubEls}) -> - find_xdata_el1(SubEls). - -find_xdata_el1([]) -> false; -find_xdata_el1([El | Els]) when is_record(El, xmlel) -> - case fxml:get_tag_attr_s(<<"xmlns">>, El) of - ?NS_XDATA -> El; - _ -> find_xdata_el1(Els) - end; -find_xdata_el1([_ | Els]) -> find_xdata_el1(Els). - -%% Produce a node to use as response from an adhoc_response -%% record, filling in values for language, node and session id from -%% the request. -%% --spec produce_response(Adhoc_Request :: adhoc_request(), - Adhoc_Response :: adhoc_response()) -> - Xmlel::xmlel(). - -%% Produce a node to use as response from an adhoc_response -%% record. -produce_response(#adhoc_request{lang = Lang, node = Node, sessionid = SessionID}, - Adhoc_Response) -> - produce_response(Adhoc_Response#adhoc_response{ - lang = Lang, node = Node, sessionid = SessionID - }). - -%% --spec produce_response(Adhoc_Response::adhoc_response()) -> Xmlel::xmlel(). - -produce_response( - #adhoc_response{ - %lang = _Lang, - node = Node, - sessionid = ProvidedSessionID, - status = Status, - defaultaction = DefaultAction, - actions = Actions, - notes = Notes, - elements = Elements - }) -> - SessionID = if is_binary(ProvidedSessionID), - ProvidedSessionID /= <<"">> -> ProvidedSessionID; - true -> jlib:now_to_utc_string(p1_time_compat:timestamp()) - end, - case Actions of - [] -> - ActionsEls = []; - _ -> - case DefaultAction of - <<"">> -> ActionsElAttrs = []; - _ -> ActionsElAttrs = [{<<"execute">>, DefaultAction}] - end, - ActionsEls = [ - #xmlel{ - name = <<"actions">>, - attrs = ActionsElAttrs, - children = [ - #xmlel{name = Action, attrs = [], children = []} - || Action <- Actions] - } - ] - end, - NotesEls = lists:map(fun({Type, Text}) -> - #xmlel{ - name = <<"note">>, - attrs = [{<<"type">>, Type}], - children = [{xmlcdata, Text}] - } - end, Notes), - #xmlel{ - name = <<"command">>, - attrs = [ - {<<"xmlns">>, ?NS_COMMANDS}, - {<<"sessionid">>, SessionID}, - {<<"node">>, Node}, - {<<"status">>, iolist_to_binary(atom_to_list(Status))} - ], - children = ActionsEls ++ NotesEls ++ Elements - }. diff --git a/src/mod_pubsub.erl b/src/mod_pubsub.erl index c84fb5fe8..a7a0e2d88 100644 --- a/src/mod_pubsub.erl +++ b/src/mod_pubsub.erl @@ -41,8 +41,6 @@ -include("ejabberd.hrl"). -include("logger.hrl"). -%%-include("adhoc.hrl"). -%%-include("jlib.hrl"). -include("xmpp.hrl"). -include("pubsub.hrl"). @@ -1199,11 +1197,14 @@ iq_get_vcard(Lang) -> iq_pubsub(Host, Access, #iq{from = From, type = IQType, lang = Lang, sub_els = [SubEl]}) -> case {IQType, SubEl} of - {set, #pubsub{create = Node, configure = {_, XData}, + {set, #pubsub{create = Node, configure = Configure, _ = undefined}} when is_binary(Node) -> ServerHost = serverhost(Host), Plugins = config(ServerHost, plugins), - Config = get_xdata_fields(XData), + Config = case Configure of + {_, XData} -> get_xdata_fields(XData); + undefined -> [] + end, Type = hd(Plugins), create_node(Host, ServerHost, Node, From, Type, Access, Config); {set, #pubsub{publish = #ps_publish{node = Node, items = Items}, @@ -1223,7 +1224,12 @@ iq_pubsub(Host, Access, #iq{from = From, type = IQType, lang = Lang, _ = undefined}} -> case Items of [#ps_item{id = ItemId}] -> - delete_item(Host, Node, From, ItemId, Notify); + if ItemId /= <<>> -> + delete_item(Host, Node, From, ItemId, Notify); + true -> + {error, extended_error(xmpp:err_bad_request(), + err_item_required())} + end; [] -> {error, extended_error(xmpp:err_bad_request(), err_item_required())}; _ -> @@ -1259,11 +1265,14 @@ iq_pubsub(Host, Access, #iq{from = From, type = IQType, lang = Lang, jid = JID, xdata = XData}, _ = undefined}} -> set_options(Host, Node, JID, SubId, get_xdata_fields(XData)); + {set, #pubsub{}} -> + {error, xmpp:err_bad_request()}; _ -> {error, xmpp:err_feature_not_implemented()} end. --spec iq_pubsub_owner(binary() | ljid(), iq()) -> {result, pubsub()} | {error, error()}. +-spec iq_pubsub_owner(binary() | ljid(), iq()) -> {result, pubsub_owner() | undefined} | + {error, error()}. iq_pubsub_owner(Host, #iq{type = IQType, from = From, lang = Lang, sub_els = [SubEl]}) -> case {IQType, SubEl} of @@ -1275,7 +1284,7 @@ iq_pubsub_owner(Host, #iq{type = IQType, from = From, undefined -> {error, xmpp:err_bad_request(<<"No data form found">>, Lang)}; #xdata{type = cancel} -> - {result, #pubsub{}}; + {result, #pubsub_owner{}}; #xdata{type = submit} -> Config = get_xdata_fields(XData), set_configure(Host, Node, From, Config, Lang); @@ -1684,7 +1693,7 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> %%
  • The node is the root collection node, which cannot be deleted.
  • %%
  • The specified node does not exist.
  • %% --spec delete_node(host(), binary(), jid()) -> {result, pubsub()} | {error, error()}. +-spec delete_node(host(), binary(), jid()) -> {result, pubsub_owner()} | {error, error()}. delete_node(_Host, <<>>, _Owner) -> {error, xmpp:err_not_allowed(<<"No node specified">>, ?MYLANG)}; delete_node(Host, Node, Owner) -> @@ -1701,7 +1710,7 @@ delete_node(Host, Node, Owner) -> {error, xmpp:err_forbidden(<<"Owner privileges required">>, ?MYLANG)} end end, - Reply = [], + Reply = undefined, ServerHost = serverhost(Host), case transaction(Host, Node, Action, transaction) of {result, {_, {SubsByDepth, {Result, broadcast, Removed}}}} -> @@ -2566,8 +2575,8 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> Error end. --spec get_subscriptions(binary(), binary(), jid()) -> {result, pubsub()} | - {error, error()}. +-spec get_subscriptions(host(), binary(), jid()) -> {result, pubsub_owner()} | + {error, error()}. get_subscriptions(Host, Node, JID) -> Action = fun (#pubsub_node{type = Type, id = Nidx}) -> Features = plugin_features(Host, Type), @@ -2595,7 +2604,7 @@ get_subscriptions(Host, Node, JID) -> ({AJID, Sub, SubId}) -> [#ps_subscription{jid = AJID, type = Sub, subid = SubId}] end, Subs), - {result, #pubsub{subscriptions = {Node, Entities}}}; + {result, #pubsub_owner{subscriptions = {Node, Entities}}}; Error -> Error end. @@ -2623,6 +2632,8 @@ get_subscriptions_for_send_last(Host, PType, sql, JID, LJID, BJID) -> get_subscriptions_for_send_last(_Host, _PType, _, _JID, _LJID, _BJID) -> []. +-spec set_subscriptions(host(), binary(), jid(), [ps_subscription()]) -> + {result, undefined} | {error, error()}. set_subscriptions(Host, Node, From, Entities) -> Owner = jid:tolower(jid:remove_resource(From)), Notify = fun(#ps_subscription{jid = JID, type = Sub}) -> @@ -3152,7 +3163,7 @@ user_resource(_, _, Resource) -> %%%%%%% Configuration handling -spec get_configure(host(), binary(), binary(), jid(), - binary()) -> {error, error()} | {result, pubsub()}. + binary()) -> {error, error()} | {result, pubsub_owner()}. get_configure(Host, ServerHost, Node, From, Lang) -> Action = fun (#pubsub_node{options = Options, type = Type, id = Nidx}) -> case node_call(Host, Type, get_affiliation, [Nidx, From]) of @@ -3171,7 +3182,7 @@ get_configure(Host, ServerHost, Node, From, Lang) -> Other -> Other end. --spec get_default(host(), binary(), jid(), binary()) -> {result, pubsub()}. +-spec get_default(host(), binary(), jid(), binary()) -> {result, pubsub_owner()}. get_default(Host, Node, _From, Lang) -> Type = select_type(Host, Host, Node), Options = node_options(Host, Type), @@ -3371,6 +3382,8 @@ get_configure_xfields(_Type, Options, Lang, Groups) -> %% -spec set_configure(host(), binary(), jid(), [{binary(), [binary()]}], binary()) -> {result, undefined} | {error, error()}. +set_configure(_Host, <<>>, _From, _Config, _Lang) -> + {error, extended_error(xmpp:err_bad_request(), err_nodeid_required())}; set_configure(Host, Node, From, Config, Lang) -> Action = fun(#pubsub_node{options = Options, type = Type, id = Nidx} = N) -> @@ -3664,26 +3677,28 @@ select_type(ServerHost, Host, Node, Type) -> select_type(ServerHost, Host, Node) -> select_type(ServerHost, Host, Node, hd(plugins(Host))). +-spec feature(binary()) -> binary(). feature(<<"rsm">>) -> ?NS_RSM; feature(Feature) -> <<(?NS_PUBSUB)/binary, "#", Feature/binary>>. +-spec features() -> [binary()]. features() -> [% see plugin "access-authorize", % OPTIONAL - <<"access-open">>, % OPTIONAL this relates to access_model option in node_hometree - <<"access-presence">>, % OPTIONAL this relates to access_model option in node_pep - <<"access-whitelist">>, % OPTIONAL - <<"collections">>, % RECOMMENDED - <<"config-node">>, % RECOMMENDED - <<"create-and-configure">>, % RECOMMENDED - <<"item-ids">>, % RECOMMENDED - <<"last-published">>, % RECOMMENDED - <<"member-affiliation">>, % RECOMMENDED - <<"presence-notifications">>, % OPTIONAL - <<"presence-subscribe">>, % RECOMMENDED - <<"publisher-affiliation">>, % RECOMMENDED - <<"publish-only-affiliation">>, % OPTIONAL - <<"retrieve-default">>, - <<"shim">>]. % RECOMMENDED + <<"access-open">>, % OPTIONAL this relates to access_model option in node_hometree + <<"access-presence">>, % OPTIONAL this relates to access_model option in node_pep + <<"access-whitelist">>, % OPTIONAL + <<"collections">>, % RECOMMENDED + <<"config-node">>, % RECOMMENDED + <<"create-and-configure">>, % RECOMMENDED + <<"item-ids">>, % RECOMMENDED + <<"last-published">>, % RECOMMENDED + <<"member-affiliation">>, % RECOMMENDED + <<"presence-notifications">>, % OPTIONAL + <<"presence-subscribe">>, % RECOMMENDED + <<"publisher-affiliation">>, % RECOMMENDED + <<"publish-only-affiliation">>, % OPTIONAL + <<"retrieve-default">>, + <<"shim">>]. % RECOMMENDED % see plugin "retrieve-items", % RECOMMENDED % see plugin "retrieve-subscriptions", % RECOMMENDED @@ -3920,7 +3935,7 @@ err_subid_required() -> err_too_many_subscriptions() -> #ps_error{type = 'too-many-subscriptions'}. --spec err_unsupported(ps_error_feature()) -> ps_error(). +-spec err_unsupported(ps_feature()) -> ps_error(). err_unsupported(Feature) -> #ps_error{type = 'unsupported', feature = Feature}. diff --git a/src/node_dag.erl b/src/node_dag.erl index afb610ca7..45f8ade63 100644 --- a/src/node_dag.erl +++ b/src/node_dag.erl @@ -28,7 +28,7 @@ -author('bjc@kublai.com'). -include("pubsub.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -export([init/3, terminate/2, options/0, features/0, create_node_permission/6, create_node/2, delete_node/1, @@ -78,8 +78,9 @@ publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload, PubOpts) -> case find_opt(node_type, Options) of collection -> Txt = <<"Publishing items to collection node is not allowed">>, - {error, - ?ERR_EXTENDED(?ERRT_NOT_ALLOWED(?MYLANG, Txt), <<"publish">>)}; + {error, mod_pubsub:extended_error( + xmpp:err_not_allowed(Txt, ?MYLANG), + mod_pubsub:err_unsupported('publish'))}; _ -> node_hometree:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload, PubOpts) diff --git a/src/node_dispatch.erl b/src/node_dispatch.erl index b3af69cd1..0a72b18d5 100644 --- a/src/node_dispatch.erl +++ b/src/node_dispatch.erl @@ -34,7 +34,7 @@ -author('christophe.romain@process-one.net'). -include("pubsub.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -export([init/3, terminate/2, options/0, features/0, create_node_permission/6, create_node/2, delete_node/1, @@ -94,10 +94,12 @@ delete_node(Nodes) -> subscribe_node(_Nidx, _Sender, _Subscriber, _AccessModel, _SendLast, _PresenceSubscription, _RosterGroup, _Options) -> - {error, ?ERR_FORBIDDEN}. + {error, mod_pubsub:extended_error(xmpp:err_feature_not_implemented(), + mod_pubsub:err_unsupported('subscribe'))}. unsubscribe_node(_Nidx, _Sender, _Subscriber, _SubId) -> - {error, ?ERR_FORBIDDEN}. + {error, mod_pubsub:extended_error(xmpp:err_feature_not_implemented(), + mod_pubsub:err_unsupported('subscribe'))}. publish_item(Nidx, Publisher, PublishModel, MaxItems, ItemId, Payload, PubOpts) -> @@ -118,10 +120,12 @@ remove_extra_items(_Nidx, _MaxItems, ItemIds) -> {result, {ItemIds, []}}. delete_item(_Nidx, _Publisher, _PublishModel, _ItemId) -> - {error, ?ERR_ITEM_NOT_FOUND}. + {error, mod_pubsub:extended_error(xmpp:err_feature_not_implemented(), + mod_pubsub:err_unsupported('delete-items'))}. purge_node(_Nidx, _Owner) -> - {error, ?ERR_FORBIDDEN}. + {error, mod_pubsub:extended_error(xmpp:err_feature_not_implemented(), + mod_pubsub:err_unsupported('purge-nodes'))}. get_entity_affiliations(_Host, _Owner) -> {result, []}. diff --git a/src/node_flat.erl b/src/node_flat.erl index 2fb24ee69..2ec9afe54 100644 --- a/src/node_flat.erl +++ b/src/node_flat.erl @@ -34,7 +34,7 @@ -author('christophe.romain@process-one.net'). -include("pubsub.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -export([init/3, terminate/2, options/0, features/0, create_node_permission/6, create_node/2, delete_node/1, @@ -107,8 +107,8 @@ features() -> <<"retrieve-items">>, <<"retrieve-subscriptions">>, <<"subscribe">>, + %%<<"subscription-options">>, <<"subscription-notifications">>]. -%%<<"subscription-options">> %% @doc Checks if the current user has the permission to create the requested node %%

    In flat node, any unused node name is allowed. The access parameter is also @@ -196,27 +196,27 @@ subscribe_node(Nidx, Sender, Subscriber, AccessModel, Owner = Affiliation == owner, if not Authorized -> {error, - ?ERR_EXTENDED((?ERR_BAD_REQUEST), <<"invalid-jid">>)}; + mod_pubsub:extended_error((xmpp:err_bad_request()), mod_pubsub:err_invalid_jid())}; (Affiliation == outcast) or (Affiliation == publish_only) -> - {error, ?ERR_FORBIDDEN}; + {error, xmpp:err_forbidden()}; PendingSubscription -> {error, - ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"pending-subscription">>)}; + mod_pubsub:extended_error((xmpp:err_not_authorized()), mod_pubsub:err_pending_subscription())}; (AccessModel == presence) and (not PresenceSubscription) and (not Owner) -> {error, - ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"presence-subscription-required">>)}; + mod_pubsub:extended_error((xmpp:err_not_authorized()), mod_pubsub:err_presence_subscription_required())}; (AccessModel == roster) and (not RosterGroup) and (not Owner) -> {error, - ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"not-in-roster-group">>)}; + mod_pubsub:extended_error((xmpp:err_not_authorized()), mod_pubsub:err_not_in_roster_group())}; (AccessModel == whitelist) and (not Whitelisted) and (not Owner) -> {error, - ?ERR_EXTENDED((?ERR_NOT_ALLOWED), <<"closed-node">>)}; + mod_pubsub:extended_error((xmpp:err_not_allowed()), mod_pubsub:err_closed_node())}; %%MustPay -> %% % Payment is required for a subscription %% {error, ?ERR_PAYMENT_REQUIRED}; %%ForbiddenAnonymous -> %% % Requesting entity is anonymous - %% {error, ?ERR_FORBIDDEN}; + %% {error, xmpp:err_forbidden()}; true -> %%SubId = pubsub_subscription:add_subscription(Subscriber, Nidx, Options), {NewSub, SubId} = case Subscriptions of @@ -265,17 +265,17 @@ unsubscribe_node(Nidx, Sender, Subscriber, SubId) -> if %% Requesting entity is prohibited from unsubscribing entity not Authorized -> - {error, ?ERR_FORBIDDEN}; + {error, xmpp:err_forbidden()}; %% Entity did not specify SubId %%SubId == "", ?? -> - %% {error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")}; + %% {error, mod_pubsub:extended_error(xmpp:err_bad_request(), "subid-required")}; %% Invalid subscription identifier %%InvalidSubId -> - %% {error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")}; + %% {error, mod_pubsub:extended_error(?ERR_NOT_ACCEPTABLE, "invalid-subid")}; %% Requesting entity is not a subscriber Subscriptions == [] -> {error, - ?ERR_EXTENDED((?ERR_UNEXPECTED_REQUEST_CANCEL), <<"not-subscribed">>)}; + mod_pubsub:extended_error(xmpp:err_unexpected_request(), mod_pubsub:err_not_subscribed())}; %% Subid supplied, so use that. SubIdExists -> Sub = first_in_list(fun @@ -289,7 +289,7 @@ unsubscribe_node(Nidx, Sender, Subscriber, SubId) -> {result, default}; false -> {error, - ?ERR_EXTENDED((?ERR_UNEXPECTED_REQUEST_CANCEL), <<"not-subscribed">>)} + mod_pubsub:extended_error(xmpp:err_unexpected_request(), mod_pubsub:err_not_subscribed())} end; %% Asking to remove all subscriptions to the given node SubId == all -> @@ -302,7 +302,7 @@ unsubscribe_node(Nidx, Sender, Subscriber, SubId) -> %% No subid and more than one possible subscription match. true -> {error, - ?ERR_EXTENDED((?ERR_BAD_REQUEST), <<"subid-required">>)} + mod_pubsub:extended_error((xmpp:err_bad_request()), mod_pubsub:err_subid_required())} end. delete_subscriptions(SubKey, Nidx, Subscriptions, SubState) -> @@ -366,7 +366,7 @@ publish_item(Nidx, Publisher, PublishModel, MaxItems, ItemId, Payload, or (Affiliation == publisher) or (Affiliation == publish_only)) or (Subscribed == true)) -> - {error, ?ERR_FORBIDDEN}; + {error, xmpp:err_forbidden()}; true -> if MaxItems > 0 -> Now = p1_time_compat:timestamp(), @@ -425,7 +425,7 @@ delete_item(Nidx, Publisher, PublishModel, ItemId) -> _ -> false end, if not Allowed -> - {error, ?ERR_FORBIDDEN}; + {error, xmpp:err_forbidden()}; true -> case lists:member(ItemId, Items) of true -> @@ -450,9 +450,9 @@ delete_item(Nidx, Publisher, PublishModel, ItemId) -> (_, Res) -> Res end, - {error, ?ERR_ITEM_NOT_FOUND}, States); + {error, xmpp:err_item_not_found()}, States); _ -> - {error, ?ERR_ITEM_NOT_FOUND} + {error, xmpp:err_item_not_found()} end end end. @@ -474,7 +474,7 @@ purge_node(Nidx, Owner) -> States), {result, {default, broadcast}}; _ -> - {error, ?ERR_FORBIDDEN} + {error, xmpp:err_forbidden()} end. %% @doc

    Return the current affiliations for the given user

    @@ -581,7 +581,7 @@ set_subscriptions(Nidx, Owner, Subscription, SubId) -> case Subscription of none -> {error, - ?ERR_EXTENDED((?ERR_BAD_REQUEST), <<"not-subscribed">>)}; + mod_pubsub:extended_error((xmpp:err_bad_request()), mod_pubsub:err_not_subscribed())}; _ -> new_subscription(Nidx, Owner, Subscription, SubState) end; @@ -592,7 +592,7 @@ set_subscriptions(Nidx, Owner, Subscription, SubId) -> end; {<<>>, [_ | _]} -> {error, - ?ERR_EXTENDED((?ERR_BAD_REQUEST), <<"subid-required">>)}; + mod_pubsub:extended_error((xmpp:err_bad_request()), mod_pubsub:err_subid_required())}; _ -> case Subscription of none -> unsub_with_subid(Nidx, SubId, SubState); @@ -721,23 +721,23 @@ get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId, RSM can_fetch_item(Affiliation, FullSubscriptions), if %%SubId == "", ?? -> %% Entity has multiple subscriptions to the node but does not specify a subscription ID - %{error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")}; + %{error, mod_pubsub:extended_error(xmpp:err_bad_request(), "subid-required")}; %%InvalidSubId -> %% Entity is subscribed but specifies an invalid subscription ID - %{error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")}; + %{error, mod_pubsub:extended_error(?ERR_NOT_ACCEPTABLE, "invalid-subid")}; (Affiliation == outcast) or (Affiliation == publish_only) -> - {error, ?ERR_FORBIDDEN}; + {error, xmpp:err_forbidden()}; (AccessModel == presence) and not PresenceSubscription -> {error, - ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"presence-subscription-required">>)}; + mod_pubsub:extended_error((xmpp:err_not_authorized()), mod_pubsub:err_presence_subscription_required())}; (AccessModel == roster) and not RosterGroup -> {error, - ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"not-in-roster-group">>)}; + mod_pubsub:extended_error((xmpp:err_not_authorized()), mod_pubsub:err_not_in_roster_group())}; (AccessModel == whitelist) and not Whitelisted -> {error, - ?ERR_EXTENDED((?ERR_NOT_ALLOWED), <<"closed-node">>)}; + mod_pubsub:extended_error((xmpp:err_not_allowed()), mod_pubsub:err_closed_node())}; (AccessModel == authorize) and not Whitelisted -> - {error, ?ERR_FORBIDDEN}; + {error, xmpp:err_forbidden()}; %%MustPay -> %% % Payment is required for a subscription %% {error, ?ERR_PAYMENT_REQUIRED}; @@ -750,7 +750,7 @@ get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId, RSM get_item(Nidx, ItemId) -> case mnesia:read({pubsub_item, {ItemId, Nidx}}) of [Item] when is_record(Item, pubsub_item) -> {result, Item}; - _ -> {error, ?ERR_ITEM_NOT_FOUND} + _ -> {error, xmpp:err_item_not_found()} end. get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) -> @@ -762,23 +762,23 @@ get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _Sub Whitelisted = can_fetch_item(Affiliation, Subscriptions), if %%SubId == "", ?? -> %% Entity has multiple subscriptions to the node but does not specify a subscription ID - %{error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")}; + %{error, mod_pubsub:extended_error(xmpp:err_bad_request(), "subid-required")}; %%InvalidSubId -> %% Entity is subscribed but specifies an invalid subscription ID - %{error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")}; + %{error, mod_pubsub:extended_error(?ERR_NOT_ACCEPTABLE, "invalid-subid")}; (Affiliation == outcast) or (Affiliation == publish_only) -> - {error, ?ERR_FORBIDDEN}; + {error, xmpp:err_forbidden()}; (AccessModel == presence) and not PresenceSubscription -> {error, - ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"presence-subscription-required">>)}; + mod_pubsub:extended_error((xmpp:err_not_authorized()), mod_pubsub:err_presence_subscription_required())}; (AccessModel == roster) and not RosterGroup -> {error, - ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"not-in-roster-group">>)}; + mod_pubsub:extended_error((xmpp:err_not_authorized()), mod_pubsub:err_not_in_roster_group())}; (AccessModel == whitelist) and not Whitelisted -> {error, - ?ERR_EXTENDED((?ERR_NOT_ALLOWED), <<"closed-node">>)}; + mod_pubsub:extended_error((xmpp:err_not_allowed()), mod_pubsub:err_closed_node())}; (AccessModel == authorize) and not Whitelisted -> - {error, ?ERR_FORBIDDEN}; + {error, xmpp:err_forbidden()}; %%MustPay -> %% % Payment is required for a subscription %% {error, ?ERR_PAYMENT_REQUIRED}; diff --git a/src/node_flat_sql.erl b/src/node_flat_sql.erl index 2a468c69a..025f6caa8 100644 --- a/src/node_flat_sql.erl +++ b/src/node_flat_sql.erl @@ -677,7 +677,7 @@ get_items(Nidx, _From, #rsm_set{max = Max, index = IncIndex, "where exists ( select count(*) as count1 " "from pubsub_item where nodeid='">>, SNidx, <<"' and modification > pi.modification having count1 = ">>, - IncIndex, <<" );">>]) of + integer_to_binary(IncIndex), <<" );">>]) of {selected, [_], [[O]]} -> [<<"modification">>, <<"'", O/binary, "'">>]; _ -> @@ -699,7 +699,7 @@ get_items(Nidx, _From, #rsm_set{max = Max, index = IncIndex, end, Query = fun(mssql, _) -> ejabberd_sql:sql_query_t( - [<<"select top ">>, Max, + [<<"select top ">>, integer_to_binary(Max), <<" itemid, publisher, creation, modification, payload " "from pubsub_item where nodeid='">>, SNidx, <<"' and ">>, AttrName, <<" ">>, Way, <<" ">>, Id, <<" order by ">>, @@ -709,7 +709,8 @@ get_items(Nidx, _From, #rsm_set{max = Max, index = IncIndex, [<<"select itemid, publisher, creation, modification, payload " "from pubsub_item where nodeid='">>, SNidx, <<"' and ">>, AttrName, <<" ">>, Way, <<" ">>, Id, <<" order by ">>, - AttrName, <<" ">>, Order, <<" limit ">>, Max, <<" ;">>]) + AttrName, <<" ">>, Order, <<" limit ">>, + integer_to_binary(Max), <<" ;">>]) end, case ejabberd_sql:sql_query_t(Query) of {selected, [<<"itemid">>, <<"publisher">>, <<"creation">>, diff --git a/src/nodetree_dag.erl b/src/nodetree_dag.erl index 387d98413..f17f2846d 100644 --- a/src/nodetree_dag.erl +++ b/src/nodetree_dag.erl @@ -30,7 +30,7 @@ -include_lib("stdlib/include/qlc.hrl"). -include("pubsub.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -export([init/3, terminate/2, options/0, set_node/1, get_node/3, get_node/2, get_node/1, get_nodes/2, @@ -69,13 +69,13 @@ create_node(Key, Node, Type, Owner, Options, Parents) -> Other -> Other end; _ -> - {error, ?ERRT_CONFLICT(?MYLANG, <<"Node already exists">>)} + {error, xmpp:err_conflict(<<"Node already exists">>, ?MYLANG)} end. delete_node(Key, Node) -> case find_node(Key, Node) of false -> - {error, ?ERRT_ITEM_NOT_FOUND(?MYLANG, <<"Node not found">>)}; + {error, xmpp:err_item_not_found(<<"Node not found">>, ?MYLANG)}; Record -> lists:foreach(fun (#pubsub_node{options = Opts} = Child) -> NewOpts = remove_config_parent(Node, Opts), @@ -99,7 +99,7 @@ get_node(Host, Node, _From) -> get_node(Host, Node) -> case find_node(Host, Node) of - false -> {error, ?ERRT_ITEM_NOT_FOUND(?MYLANG, <<"Node not found">>)}; + false -> {error, xmpp:err_item_not_found(<<"Node not found">>, ?MYLANG)}; Record -> Record end. @@ -115,7 +115,7 @@ get_nodes(Key) -> get_parentnodes(Host, Node, _From) -> case find_node(Host, Node) of false -> - {error, ?ERRT_ITEM_NOT_FOUND(?MYLANG, <<"Node not found">>)}; + {error, xmpp:err_item_not_found(<<"Node not found">>, ?MYLANG)}; #pubsub_node{parents = Parents} -> Q = qlc:q([N || #pubsub_node{nodeid = {NHost, NNode}} = N @@ -139,7 +139,7 @@ get_subnodes(Host, <<>>) -> get_subnodes_helper(Host, <<>>); get_subnodes(Host, Node) -> case find_node(Host, Node) of - false -> {error, ?ERRT_ITEM_NOT_FOUND(?MYLANG, <<"Node not found">>)}; + false -> {error, xmpp:err_item_not_found(<<"Node not found">>, ?MYLANG)}; _ -> get_subnodes_helper(Host, Node) end. @@ -226,13 +226,13 @@ validate_parentage(Key, Owners, [<<>> | T]) -> validate_parentage(Key, Owners, [ParentID | T]) -> case find_node(Key, ParentID) of false -> - {error, ?ERRT_ITEM_NOT_FOUND(?MYLANG, <<"Node not found">>)}; + {error, xmpp:err_item_not_found(<<"Node not found">>, ?MYLANG)}; #pubsub_node{owners = POwners, options = POptions} -> NodeType = find_opt(node_type, ?DEFAULT_NODETYPE, POptions), MutualOwners = [O || O <- Owners, PO <- POwners, O == PO], case {MutualOwners, NodeType} of - {[], _} -> {error, ?ERR_FORBIDDEN}; + {[], _} -> {error, xmpp:err_forbidden()}; {_, collection} -> validate_parentage(Key, Owners, T); - {_, _} -> {error, ?ERR_NOT_ALLOWED} + {_, _} -> {error, xmpp:err_not_allowed()} end end. diff --git a/src/nodetree_tree.erl b/src/nodetree_tree.erl index 69b50ff9f..81972ca3c 100644 --- a/src/nodetree_tree.erl +++ b/src/nodetree_tree.erl @@ -40,7 +40,7 @@ -include_lib("stdlib/include/qlc.hrl"). -include("pubsub.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -export([init/3, terminate/2, options/0, set_node/1, get_node/3, get_node/2, get_node/1, get_nodes/2, @@ -76,13 +76,13 @@ get_node(Host, Node, _From) -> get_node(Host, Node) -> case mnesia:read({pubsub_node, {Host, Node}}) of [Record] when is_record(Record, pubsub_node) -> Record; - _ -> {error, ?ERRT_ITEM_NOT_FOUND(?MYLANG, <<"Node not found">>)} + _ -> {error, xmpp:err_item_not_found(<<"Node not found">>, ?MYLANG)} end. get_node(Nidx) -> case mnesia:index_read(pubsub_node, Nidx, #pubsub_node.id) of [Record] when is_record(Record, pubsub_node) -> Record; - _ -> {error, ?ERRT_ITEM_NOT_FOUND(?MYLANG, <<"Node not found">>)} + _ -> {error, xmpp:err_item_not_found(<<"Node not found">>, ?MYLANG)} end. get_nodes(Host, _From) -> @@ -180,10 +180,10 @@ create_node(Host, Node, Type, Owner, Options, Parents) -> options = Options}), {ok, Nidx}; false -> - {error, ?ERR_FORBIDDEN} + {error, xmpp:err_forbidden()} end; _ -> - {error, ?ERRT_CONFLICT(?MYLANG, <<"Node already exists">>)} + {error, xmpp:err_conflict(<<"Node already exists">>, ?MYLANG)} end. delete_node(Host, Node) -> diff --git a/src/nodetree_tree_sql.erl b/src/nodetree_tree_sql.erl index edfdbc1d5..c292c7755 100644 --- a/src/nodetree_tree_sql.erl +++ b/src/nodetree_tree_sql.erl @@ -40,7 +40,7 @@ -compile([{parse_transform, ejabberd_sql_pt}]). -include("pubsub.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("ejabberd_sql_pt.hrl"). -export([init/3, terminate/2, options/0, set_node/1, @@ -97,7 +97,7 @@ set_node(Record) when is_record(Record, pubsub_node) -> case Nidx of none -> Txt = <<"Node index not found">>, - {error, ?ERRT_INTERNAL_SERVER_ERROR(?MYLANG, Txt)}; + {error, xmpp:err_internal_server_error(Txt, ?MYLANG)}; _ -> lists:foreach(fun ({Key, Value}) -> SKey = iolist_to_binary(atom_to_list(Key)), @@ -125,9 +125,9 @@ get_node(Host, Node) -> {selected, [RItem]} -> raw_to_node(Host, RItem); {'EXIT', _Reason} -> - {error, ?ERRT_INTERNAL_SERVER_ERROR(?MYLANG, <<"Database failure">>)}; + {error, xmpp:err_internal_server_error(<<"Database failure">>, ?MYLANG)}; _ -> - {error, ?ERRT_ITEM_NOT_FOUND(?MYLANG, <<"Node not found">>)} + {error, xmpp:err_item_not_found(<<"Node not found">>, ?MYLANG)} end. get_node(Nidx) -> @@ -139,9 +139,9 @@ get_node(Nidx) -> {selected, [{Host, Node, Parent, Type}]} -> raw_to_node(Host, {Node, Parent, Type, Nidx}); {'EXIT', _Reason} -> - {error, ?ERRT_INTERNAL_SERVER_ERROR(?MYLANG, <<"Database failure">>)}; + {error, xmpp:err_internal_server_error(<<"Database failure">>, ?MYLANG)}; _ -> - {error, ?ERRT_ITEM_NOT_FOUND(?MYLANG, <<"Node not found">>)} + {error, xmpp:err_item_not_found(<<"Node not found">>, ?MYLANG)} end. get_nodes(Host, _From) -> @@ -249,12 +249,12 @@ create_node(Host, Node, Type, Owner, Options, Parents) -> Other -> Other end; false -> - {error, ?ERR_FORBIDDEN} + {error, xmpp:err_forbidden()} end; {result, _} -> - {error, ?ERRT_CONFLICT(?MYLANG, <<"Node already exists">>)}; + {error, xmpp:err_conflict(<<"Node already exists">>, ?MYLANG)}; {error, db_fail} -> - {error, ?ERRT_INTERNAL_SERVER_ERROR(?MYLANG, <<"Database failure">>)} + {error, xmpp:err_internal_server_error(<<"Database failure">>, ?MYLANG)} end. delete_node(Host, Node) -> diff --git a/src/pubsub_db_sql.erl b/src/pubsub_db_sql.erl index b910a5e7d..a6f8888a9 100644 --- a/src/pubsub_db_sql.erl +++ b/src/pubsub_db_sql.erl @@ -75,27 +75,27 @@ add_subscription(#pubsub_subscription{subid = SubId, options = Opts}) -> Opts), ok. -subscription_opt_from_sql({<<"DELIVER">>, Value}) -> +subscription_opt_from_sql([<<"DELIVER">>, Value]) -> {deliver, sql_to_boolean(Value)}; -subscription_opt_from_sql({<<"DIGEST">>, Value}) -> +subscription_opt_from_sql([<<"DIGEST">>, Value]) -> {digest, sql_to_boolean(Value)}; -subscription_opt_from_sql({<<"DIGEST_FREQUENCY">>, Value}) -> +subscription_opt_from_sql([<<"DIGEST_FREQUENCY">>, Value]) -> {digest_frequency, sql_to_integer(Value)}; -subscription_opt_from_sql({<<"EXPIRE">>, Value}) -> +subscription_opt_from_sql([<<"EXPIRE">>, Value]) -> {expire, sql_to_timestamp(Value)}; -subscription_opt_from_sql({<<"INCLUDE_BODY">>, Value}) -> +subscription_opt_from_sql([<<"INCLUDE_BODY">>, Value]) -> {include_body, sql_to_boolean(Value)}; %%TODO: might be > than 1 show_values value??. %% need to use compact all in only 1 opt. -subscription_opt_from_sql({<<"SHOW_VALUES">>, Value}) -> +subscription_opt_from_sql([<<"SHOW_VALUES">>, Value]) -> {show_values, Value}; -subscription_opt_from_sql({<<"SUBSCRIPTION_TYPE">>, Value}) -> +subscription_opt_from_sql([<<"SUBSCRIPTION_TYPE">>, Value]) -> {subscription_type, case Value of <<"items">> -> items; <<"nodes">> -> nodes end}; -subscription_opt_from_sql({<<"SUBSCRIPTION_DEPTH">>, Value}) -> +subscription_opt_from_sql([<<"SUBSCRIPTION_DEPTH">>, Value]) -> {subscription_depth, case Value of <<"all">> -> all; diff --git a/src/pubsub_subscription.erl b/src/pubsub_subscription.erl index 3ab502184..33c884afb 100644 --- a/src/pubsub_subscription.erl +++ b/src/pubsub_subscription.erl @@ -39,7 +39,7 @@ -include("pubsub.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -define(PUBSUB_DELIVER, <<"pubsub#deliver">>). -define(PUBSUB_DIGEST, <<"pubsub#digest">>). @@ -112,30 +112,15 @@ get_options_xform(Lang, Options) -> Keys = [deliver, show_values, subscription_type, subscription_depth], XFields = [get_option_xfield(Lang, Key, Options) || Key <- Keys], {result, - #xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_XDATA}], - children = - [#xmlel{name = <<"field">>, - attrs = - [{<<"var">>, <<"FORM_TYPE">>}, - {<<"type">>, <<"hidden">>}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = - [{xmlcdata, ?NS_PUBSUB_SUB_OPTIONS}]}]}] - ++ XFields}}. + #xdata{type = form, + fields = [#xdata_field{type = hidden, + var = <<"FORM_TYPE">>, + values = [?NS_PUBSUB_SUB_OPTIONS]}| + XFields]}}. parse_options_xform(XFields) -> - case fxml:remove_cdata(XFields) of - [#xmlel{name = <<"x">>} = XEl] -> - case jlib:parse_xdata_submit(XEl) of - XData when is_list(XData) -> - Opts = set_xoption(XData, []), - {result, Opts}; - Other -> Other - end; - _ -> {result, []} - end. + Opts = set_xoption(XFields, []), + {result, Opts}. %%==================================================================== %% Internal functions @@ -223,9 +208,17 @@ val_xfield(digest_frequency = Opt, [Val]) -> _ -> Txt = <<"Value of '~s' should be integer">>, ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), - {error, ?ERRT_NOT_ACCEPTABLE(?MYLANG, ErrTxt)} + {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} + end; +val_xfield(expire = Opt, [Val]) -> + case jlib:datetime_string_to_timestamp(Val) of + undefined -> + Txt = <<"Value of '~s' should be datetime string">>, + ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), + {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)}; + Timestamp -> + Timestamp end; -val_xfield(expire, [Val]) -> jlib:datetime_string_to_timestamp(Val); val_xfield(include_body = Opt, [Val]) -> xopt_to_bool(Opt, Val); val_xfield(show_values, Vals) -> Vals; val_xfield(subscription_type, [<<"items">>]) -> items; @@ -237,7 +230,7 @@ val_xfield(subscription_depth = Opt, [Depth]) -> _ -> Txt = <<"Value of '~s' should be integer">>, ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), - {error, ?ERRT_NOT_ACCEPTABLE(?MYLANG, ErrTxt)} + {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} end. %% Convert XForm booleans to Erlang booleans. @@ -248,10 +241,7 @@ xopt_to_bool(_, <<"true">>) -> true; xopt_to_bool(Option, _) -> Txt = <<"Value of '~s' should be boolean">>, ErrTxt = iolist_to_binary(io_lib:format(Txt, [Option])), - {error, ?ERRT_NOT_ACCEPTABLE(?MYLANG, ErrTxt)}. - --spec get_option_xfield(Lang :: binary(), Key :: atom(), - Options :: mod_pubsub:subOptions()) -> xmlel(). + {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)}. %% Return a field for an XForm for Key, with data filled in, if %% applicable, from Options. @@ -261,33 +251,22 @@ get_option_xfield(Lang, Key, Options) -> {Type, OptEls} = type_and_options(xfield_type(Key), Lang), Vals = case lists:keysearch(Key, 1, Options) of {value, {_, Val}} -> - [tr_xfield_values(Vals) - || Vals <- xfield_val(Key, Val)]; - false -> [] + [xfield_val(Key, Val)]; + false -> + [] end, - #xmlel{name = <<"field">>, - attrs = - [{<<"var">>, Var}, {<<"type">>, Type}, - {<<"label">>, translate:translate(Lang, Label)}], - children = OptEls ++ Vals}. + #xdata_field{type = Type, var = Var, + label = translate:translate(Lang, Label), + values = Vals, + options = OptEls}. type_and_options({Type, Options}, Lang) -> {Type, [tr_xfield_options(O, Lang) || O <- Options]}; type_and_options(Type, _Lang) -> {Type, []}. tr_xfield_options({Value, Label}, Lang) -> - #xmlel{name = <<"option">>, - attrs = - [{<<"label">>, translate:translate(Lang, Label)}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = [{xmlcdata, Value}]}]}. - -tr_xfield_values(Value) -> - %% Return the XForm variable name for a subscription option key. - %% Return the XForm variable type for a subscription option key. - #xmlel{name = <<"value">>, attrs = [], - children = [{xmlcdata, Value}]}. + #xdata_option{label = translate:translate(Lang, Label), + value = Value}. xfield_var(deliver) -> ?PUBSUB_DELIVER; %xfield_var(digest) -> ?PUBSUB_DIGEST; @@ -298,24 +277,24 @@ xfield_var(show_values) -> ?PUBSUB_SHOW_VALUES; xfield_var(subscription_type) -> ?PUBSUB_SUBSCRIPTION_TYPE; xfield_var(subscription_depth) -> ?PUBSUB_SUBSCRIPTION_DEPTH. -xfield_type(deliver) -> <<"boolean">>; -%xfield_type(digest) -> <<"boolean">>; -%xfield_type(digest_frequency) -> <<"text-single">>; -%xfield_type(expire) -> <<"text-single">>; -%xfield_type(include_body) -> <<"boolean">>; +xfield_type(deliver) -> boolean; +%xfield_type(digest) -> boolean; +%xfield_type(digest_frequency) -> 'text-single'; +%xfield_type(expire) -> 'text-single'; +%xfield_type(include_body) -> boolean; xfield_type(show_values) -> - {<<"list-multi">>, + {'list-multi', [{<<"away">>, ?SHOW_VALUE_AWAY_LABEL}, {<<"chat">>, ?SHOW_VALUE_CHAT_LABEL}, {<<"dnd">>, ?SHOW_VALUE_DND_LABEL}, {<<"online">>, ?SHOW_VALUE_ONLINE_LABEL}, {<<"xa">>, ?SHOW_VALUE_XA_LABEL}]}; xfield_type(subscription_type) -> - {<<"list-single">>, + {'list-single', [{<<"items">>, ?SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL}, {<<"nodes">>, ?SUBSCRIPTION_TYPE_VALUE_NODES_LABEL}]}; xfield_type(subscription_depth) -> - {<<"list-single">>, + {'list-single', [{<<"1">>, ?SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL}, {<<"all">>, ?SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL}]}. diff --git a/src/pubsub_subscription_sql.erl b/src/pubsub_subscription_sql.erl index 6e598320c..7c0670957 100644 --- a/src/pubsub_subscription_sql.erl +++ b/src/pubsub_subscription_sql.erl @@ -35,7 +35,7 @@ -include("pubsub.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -define(PUBSUB_DELIVER, <<"pubsub#deliver">>). -define(PUBSUB_DIGEST, <<"pubsub#digest">>). @@ -117,30 +117,15 @@ get_options_xform(Lang, Options) -> Keys = [deliver, show_values, subscription_type, subscription_depth], XFields = [get_option_xfield(Lang, Key, Options) || Key <- Keys], {result, - #xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_XDATA}], - children = - [#xmlel{name = <<"field">>, - attrs = - [{<<"var">>, <<"FORM_TYPE">>}, - {<<"type">>, <<"hidden">>}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = - [{xmlcdata, ?NS_PUBSUB_SUB_OPTIONS}]}]}] - ++ XFields}}. + #xdata{type = form, + fields = [#xdata_field{type = hidden, + var = <<"FORM_TYPE">>, + values = [?NS_PUBSUB_SUB_OPTIONS]}| + XFields]}}. parse_options_xform(XFields) -> - case fxml:remove_cdata(XFields) of - [#xmlel{name = <<"x">>} = XEl] -> - case jlib:parse_xdata_submit(XEl) of - XData when is_list(XData) -> - Opts = set_xoption(XData, []), - {result, Opts}; - Other -> Other - end; - _ -> {result, []} - end. + Opts = set_xoption(XFields, []), + {result, Opts}. %%==================================================================== %% Internal functions @@ -188,9 +173,17 @@ val_xfield(digest_frequency = Opt, [Val]) -> _ -> Txt = <<"Value of '~s' should be integer">>, ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), - {error, ?ERRT_NOT_ACCEPTABLE(?MYLANG, ErrTxt)} + {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} + end; +val_xfield(expire = Opt, [Val]) -> + case jlib:datetime_string_to_timestamp(Val) of + undefined -> + Txt = <<"Value of '~s' should be datetime string">>, + ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), + {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)}; + Timestamp -> + Timestamp end; -val_xfield(expire, [Val]) -> jlib:datetime_string_to_timestamp(Val); val_xfield(include_body = Opt, [Val]) -> xopt_to_bool(Opt, Val); val_xfield(show_values, Vals) -> Vals; val_xfield(subscription_type, [<<"items">>]) -> items; @@ -202,7 +195,7 @@ val_xfield(subscription_depth = Opt, [Depth]) -> _ -> Txt = <<"Value of '~s' should be integer">>, ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), - {error, ?ERRT_NOT_ACCEPTABLE(?MYLANG, ErrTxt)} + {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} end. %% Convert XForm booleans to Erlang booleans. @@ -213,7 +206,7 @@ xopt_to_bool(_, <<"true">>) -> true; xopt_to_bool(Option, _) -> Txt = <<"Value of '~s' should be boolean">>, ErrTxt = iolist_to_binary(io_lib:format(Txt, [Option])), - {error, ?ERRT_NOT_ACCEPTABLE(?MYLANG, ErrTxt)}. + {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)}. %% Return a field for an XForm for Key, with data filled in, if %% applicable, from Options. @@ -222,34 +215,23 @@ get_option_xfield(Lang, Key, Options) -> Label = xfield_label(Key), {Type, OptEls} = type_and_options(xfield_type(Key), Lang), Vals = case lists:keysearch(Key, 1, Options) of - {value, {_, Val}} -> - [tr_xfield_values(Vals) - || Vals <- xfield_val(Key, Val)]; - false -> [] - end, - #xmlel{name = <<"field">>, - attrs = - [{<<"var">>, Var}, {<<"type">>, Type}, - {<<"label">>, translate:translate(Lang, Label)}], - children = OptEls ++ Vals}. + {value, {_, Val}} -> + [xfield_val(Key, Val)]; + false -> + [] + end, + #xdata_field{type = Type, var = Var, + label = translate:translate(Lang, Label), + values = Vals, + options = OptEls}. type_and_options({Type, Options}, Lang) -> {Type, [tr_xfield_options(O, Lang) || O <- Options]}; type_and_options(Type, _Lang) -> {Type, []}. tr_xfield_options({Value, Label}, Lang) -> - #xmlel{name = <<"option">>, - attrs = - [{<<"label">>, translate:translate(Lang, Label)}], - children = - [#xmlel{name = <<"value">>, attrs = [], - children = [{xmlcdata, Value}]}]}. - -tr_xfield_values(Value) -> - %% Return the XForm variable name for a subscription option key. - %% Return the XForm variable type for a subscription option key. - #xmlel{name = <<"value">>, attrs = [], - children = [{xmlcdata, Value}]}. + #xdata_option{label = translate:translate(Lang, Label), + value = Value}. xfield_var(deliver) -> ?PUBSUB_DELIVER; %xfield_var(digest) -> ?PUBSUB_DIGEST; @@ -260,26 +242,26 @@ xfield_var(show_values) -> ?PUBSUB_SHOW_VALUES; xfield_var(subscription_type) -> ?PUBSUB_SUBSCRIPTION_TYPE; xfield_var(subscription_depth) -> ?PUBSUB_SUBSCRIPTION_DEPTH. -xfield_type(deliver) -> <<"boolean">>; -%xfield_type(digest) -> <<"boolean">>; -%xfield_type(digest_frequency) -> <<"text-single">>; -%xfield_type(expire) -> <<"text-single">>; -%xfield_type(include_body) -> <<"boolean">>; +xfield_type(deliver) -> boolean; +%xfield_type(digest) -> boolean; +%xfield_type(digest_frequency) -> 'text-single'; +%xfield_type(expire) -> 'text-single'; +%xfield_type(include_body) -> boolean; xfield_type(show_values) -> - {<<"list-multi">>, - [{<<"away">>, ?SHOW_VALUE_AWAY_LABEL}, - {<<"chat">>, ?SHOW_VALUE_CHAT_LABEL}, - {<<"dnd">>, ?SHOW_VALUE_DND_LABEL}, - {<<"online">>, ?SHOW_VALUE_ONLINE_LABEL}, - {<<"xa">>, ?SHOW_VALUE_XA_LABEL}]}; + {'list-multi', + [{<<"away">>, ?SHOW_VALUE_AWAY_LABEL}, + {<<"chat">>, ?SHOW_VALUE_CHAT_LABEL}, + {<<"dnd">>, ?SHOW_VALUE_DND_LABEL}, + {<<"online">>, ?SHOW_VALUE_ONLINE_LABEL}, + {<<"xa">>, ?SHOW_VALUE_XA_LABEL}]}; xfield_type(subscription_type) -> - {<<"list-single">>, - [{<<"items">>, ?SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL}, - {<<"nodes">>, ?SUBSCRIPTION_TYPE_VALUE_NODES_LABEL}]}; + {'list-single', + [{<<"items">>, ?SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL}, + {<<"nodes">>, ?SUBSCRIPTION_TYPE_VALUE_NODES_LABEL}]}; xfield_type(subscription_depth) -> - {<<"list-single">>, - [{<<"1">>, ?SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL}, - {<<"all">>, ?SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL}]}. + {'list-single', + [{<<"1">>, ?SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL}, + {<<"all">>, ?SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL}]}. %% Return the XForm variable label for a subscription option key. xfield_label(deliver) -> ?DELIVER_LABEL; diff --git a/tools/xmpp_codec.spec b/tools/xmpp_codec.spec index 445d9a716..a11c8dd76 100644 --- a/tools/xmpp_codec.spec +++ b/tools/xmpp_codec.spec @@ -1961,27 +1961,27 @@ 'presence-subscription-required' | 'subid-required' | 'too-many-subscriptions' | 'unsupported' | 'unsupported-access-model'. --type ps_error_feature() :: 'access-authorize' | 'access-open' | - 'access-presence' | 'access-roster' | - 'access-whitelist' | 'auto-create' | - 'auto-subscribe' | 'collections' | 'config-node' | - 'create-and-configure' | 'create-nodes' | - 'delete-items' | 'delete-nodes' | - 'filtered-notifications' | 'get-pending' | - 'instant-nodes' | 'item-ids' | 'last-published' | - 'leased-subscription' | 'manage-subscriptions' | - 'member-affiliation' | 'meta-data' | - 'modify-affiliations' | 'multi-collection' | - 'multi-subscribe' | 'outcast-affiliation' | - 'persistent-items' | 'presence-notifications' | - 'presence-subscribe' | 'publish' | - 'publish-options' | 'publish-only-affiliation' | - 'publisher-affiliation' | 'purge-nodes' | - 'retract-items' | 'retrieve-affiliations' | - 'retrieve-default' | 'retrieve-items' | - 'retrieve-subscriptions' | 'subscribe' | - 'subscription-options' | 'subscription-notifications'. --record(ps_error, {type :: ps_error_type(), feature :: ps_error_feature()}). +-type ps_feature() :: 'access-authorize' | 'access-open' | + 'access-presence' | 'access-roster' | + 'access-whitelist' | 'auto-create' | + 'auto-subscribe' | 'collections' | 'config-node' | + 'create-and-configure' | 'create-nodes' | + 'delete-items' | 'delete-nodes' | + 'filtered-notifications' | 'get-pending' | + 'instant-nodes' | 'item-ids' | 'last-published' | + 'leased-subscription' | 'manage-subscriptions' | + 'member-affiliation' | 'meta-data' | + 'modify-affiliations' | 'multi-collection' | + 'multi-subscribe' | 'outcast-affiliation' | + 'persistent-items' | 'presence-notifications' | + 'presence-subscribe' | 'publish' | + 'publish-options' | 'publish-only-affiliation' | + 'publisher-affiliation' | 'purge-nodes' | + 'retract-items' | 'retrieve-affiliations' | + 'retrieve-default' | 'retrieve-items' | + 'retrieve-subscriptions' | 'subscribe' | + 'subscription-options' | 'subscription-notifications'. +-record(ps_error, {type :: ps_error_type(), feature :: ps_feature()}). -type ps_error() :: #ps_error{}. -xml(pubsub_error_closed_node, From c29a48695d3d46e556aea2ea3c5fb8b558d43f7c Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Thu, 8 Sep 2016 17:08:48 +0300 Subject: [PATCH 038/151] Rename #error{} record to #stanza_error{} --- include/xmpp_codec.hrl | 16 ++--- src/ejabberd_c2s.erl | 4 +- src/ejabberd_piefxis.erl | 2 +- src/ejabberd_router.erl | 4 +- src/ejabberd_s2s_in.erl | 2 +- src/ejabberd_s2s_out.erl | 6 +- src/ejabberd_service.erl | 2 +- src/gen_pubsub_node.erl | 2 +- src/mod_adhoc.erl | 8 +-- src/mod_announce.erl | 6 +- src/mod_blocking.erl | 16 ++--- src/mod_caps.erl | 4 +- src/mod_configure.erl | 10 ++-- src/mod_disco.erl | 16 ++--- src/mod_http_upload.erl | 2 +- src/mod_irc.erl | 2 +- src/mod_mix.erl | 2 +- src/mod_muc_room.erl | 32 +++++----- src/mod_multicast.erl | 2 +- src/mod_privacy.erl | 18 +++--- src/mod_pubsub.erl | 90 ++++++++++++++--------------- src/mod_vcard.erl | 12 ++-- src/xmpp.erl | 122 +++++++++++++++++++-------------------- src/xmpp_codec.erl | 18 +++--- tools/xmpp_codec.spec | 2 +- 25 files changed, 201 insertions(+), 199 deletions(-) diff --git a/include/xmpp_codec.hrl b/include/xmpp_codec.hrl index d2acf316c..635fcf3cb 100644 --- a/include/xmpp_codec.hrl +++ b/include/xmpp_codec.hrl @@ -829,13 +829,13 @@ xmlns = <<>> :: binary()}). -type sm_failed() :: #sm_failed{}. --record(error, {type :: 'auth' | 'cancel' | 'continue' | 'modify' | 'wait', - code :: non_neg_integer(), - by = <<>> :: binary(), - reason :: atom() | #gone{} | #redirect{}, - text :: #text{}, - sub_els = [] :: [xmpp_element() | fxml:xmlel()]}). --type error() :: #error{}. +-record(stanza_error, {type :: 'auth' | 'cancel' | 'continue' | 'modify' | 'wait', + code :: non_neg_integer(), + by = <<>> :: binary(), + reason :: atom() | #gone{} | #redirect{}, + text :: #text{}, + sub_els = [] :: [xmpp_element() | fxml:xmlel()]}). +-type stanza_error() :: #stanza_error{}. -record(mix_join, {jid :: jid:jid(), subscribe = [] :: [binary()]}). @@ -1042,7 +1042,7 @@ register() | sm_r() | stat_error() | - error() | + stanza_error() | stream_error() | muc_user() | vcard_adr() | diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 9c1d99091..e658536ab 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -961,7 +961,7 @@ wait_for_bind(Pkt, StateData) -> end, fsm_next_state(wait_for_bind, StateData). --spec open_session(state()) -> {ok, state()} | {error, error()}. +-spec open_session(state()) -> {ok, state()} | {error, stanza_error()}. open_session(StateData) -> U = StateData#state.user, R = StateData#state.resource, @@ -1568,7 +1568,7 @@ send_element(StateData, #xmlel{} = El) -> send_element(StateData, Pkt) -> send_element(StateData, xmpp:encode(Pkt)). --spec send_error(state(), xmlel() | stanza(), error()) -> ok. +-spec send_error(state(), xmlel() | stanza(), stanza_error()) -> ok. send_error(StateData, Stanza, Error) -> Type = xmpp:get_type(Stanza), if Type == error; Type == result; diff --git a/src/ejabberd_piefxis.erl b/src/ejabberd_piefxis.erl index 6a2b5e644..7d7d01060 100644 --- a/src/ejabberd_piefxis.erl +++ b/src/ejabberd_piefxis.erl @@ -487,7 +487,7 @@ process_privacy(#privacy_query{lists = Lists, Txt = <<"No module is handling this query">>, Error = {error, xmpp:err_feature_not_implemented(Txt, ?MYLANG)}, case mod_privacy:process_iq_set(Error, IQ) of - {error, #error{reason = Reason}} = Err -> + {error, #stanza_error{reason = Reason}} = Err -> if Reason == 'item-not-found', Lists == [], Active == undefined, Default /= undefined -> %% Failed to set default list because there is no diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl index d65edc6e3..db82f67ea 100644 --- a/src/ejabberd_router.erl +++ b/src/ejabberd_router.erl @@ -86,7 +86,7 @@ route(From, To, Packet) -> %% Route the error packet only if the originating packet is not an error itself. %% RFC3920 9.3.1 -spec route_error(jid(), jid(), xmlel(), xmlel()) -> ok; - (jid(), jid(), stanza(), error()) -> ok. + (jid(), jid(), stanza(), stanza_error()) -> ok. route_error(From, To, #xmlel{} = ErrPacket, #xmlel{} = OrigPacket) -> #xmlel{attrs = Attrs} = OrigPacket, @@ -94,7 +94,7 @@ route_error(From, To, #xmlel{} = ErrPacket, #xmlel{} = OrigPacket) -> false -> route(From, To, ErrPacket); true -> ok end; -route_error(From, To, Packet, #error{} = Err) -> +route_error(From, To, Packet, #stanza_error{} = Err) -> Type = xmpp:get_type(Packet), if Type == error; Type == result -> ok; diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 7be4906fb..fd560a451 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -541,7 +541,7 @@ send_element(StateData, El) -> El1 = fix_ns(xmpp:encode(El)), send_text(StateData, fxml:element_to_binary(El1)). --spec send_error(state(), xmlel() | stanza(), error()) -> ok. +-spec send_error(state(), xmlel() | stanza(), stanza_error()) -> ok. send_error(StateData, Stanza, Error) -> Type = xmpp:get_type(Stanza), if Type == error; Type == result; diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index 4284f7f7b..dd37445d7 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -785,13 +785,13 @@ fix_ns(El) -> El. %% Bounce a single message (xmlelement) --spec bounce_element(stanza(), error()) -> ok. +-spec bounce_element(stanza(), stanza_error()) -> ok. bounce_element(El, Error) -> From = xmpp:get_from(El), To = xmpp:get_to(El), ejabberd_router:route_error(To, From, El, Error). --spec bounce_queue(queue:queue(), error()) -> ok. +-spec bounce_queue(queue:queue(), stanza_error()) -> ok. bounce_queue(Q, Error) -> case queue:out(Q) of {{value, El}, Q1} -> @@ -807,7 +807,7 @@ cancel_timer(Timer) -> erlang:cancel_timer(Timer), receive {timeout, Timer, _} -> ok after 0 -> ok end. --spec bounce_messages(error()) -> ok. +-spec bounce_messages(stanza_error()) -> ok. bounce_messages(Error) -> receive {send_element, El} -> diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index 3df39438a..002d74949 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -308,7 +308,7 @@ send_element(StateData, El) -> El1 = fix_ns(xmpp:encode(El)), send_text(StateData, fxml:element_to_binary(El1)). --spec send_error(state(), xmlel() | stanza(), error()) -> ok. +-spec send_error(state(), xmlel() | stanza(), stanza_error()) -> ok. send_error(StateData, Stanza, Error) -> Type = xmpp:get_type(Stanza), if Type == error; Type == result; diff --git a/src/gen_pubsub_node.erl b/src/gen_pubsub_node.erl index cc94ea147..5690c8a1d 100644 --- a/src/gen_pubsub_node.erl +++ b/src/gen_pubsub_node.erl @@ -178,7 +178,7 @@ -callback get_items(nodeIdx(), jid(), accessModel(), boolean(), boolean(), binary(), undefined | rsm_set()) -> - {result, {[pubsubItem()], undefined | rsm_set()}} | {error, error()}. + {result, {[pubsubItem()], undefined | rsm_set()}} | {error, stanza_error()}. -callback get_items(nodeIdx(), jid(), undefined | rsm_set()) -> {result, {[pubsubItem()], undefined | rsm_set()}}. diff --git a/src/mod_adhoc.erl b/src/mod_adhoc.erl index e6d94e40a..5b582d82b 100644 --- a/src/mod_adhoc.erl +++ b/src/mod_adhoc.erl @@ -173,9 +173,9 @@ get_sm_identity(Acc, _From, _To, ?NS_COMMANDS, Lang) -> get_sm_identity(Acc, _From, _To, _Node, _Lang) -> Acc. %------------------------------------------------------------------------- --spec get_local_features({error, error()} | {result, [binary()]} | empty, +-spec get_local_features({error, stanza_error()} | {result, [binary()]} | empty, jid(), jid(), binary(), binary()) -> - {error, error()} | {result, [binary()]} | empty. + {error, stanza_error()} | {result, [binary()]} | empty. get_local_features(Acc, _From, _To, <<"">>, _Lang) -> Feats = case Acc of {result, I} -> I; @@ -238,7 +238,7 @@ process_adhoc_request(#iq{from = From, to = To, process_adhoc_request(#iq{} = IQ, _Hooks) -> xmpp:make_error(IQ, xmpp:err_bad_request()). --spec ping_item(empty | {error, error()} | {result, [disco_item()]}, +-spec ping_item(empty | {error, stanza_error()} | {result, [disco_item()]}, jid(), jid(), binary()) -> {result, [disco_item()]}. ping_item(Acc, _From, #jid{server = Server} = _To, Lang) -> @@ -252,7 +252,7 @@ ping_item(Acc, _From, #jid{server = Server} = _To, {result, Items ++ Nodes}. -spec ping_command(adhoc_command(), jid(), jid(), adhoc_command()) -> - adhoc_command() | {error, error()}. + adhoc_command() | {error, stanza_error()}. ping_command(_Acc, _From, _To, #adhoc_command{lang = Lang, node = <<"ping">>, action = Action} = Request) -> diff --git a/src/mod_announce.erl b/src/mod_announce.erl index eb201fc88..d9209f418 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -336,8 +336,8 @@ disco_items(Acc, From, #jid{lserver = LServer} = _To, Node, Lang) -> end. %%------------------------------------------------------------------------- --spec announce_items(empty | {error, error()} | {result, [disco_item()]}, - jid(), jid(), binary()) -> {error, error()} | +-spec announce_items(empty | {error, stanza_error()} | {result, [disco_item()]}, + jid(), jid(), binary()) -> {error, stanza_error()} | {result, [disco_item()]} | empty. announce_items(Acc, From, #jid{lserver = LServer, server = Server} = _To, Lang) -> @@ -386,7 +386,7 @@ commands_result(Allow, From, To, Request) -> end. -spec announce_commands(adhoc_command(), jid(), jid(), adhoc_command()) -> - adhoc_command() | {error, error()}. + adhoc_command() | {error, stanza_error()}. announce_commands(Acc, From, #jid{lserver = LServer} = To, #adhoc_command{node = Node} = Request) -> LNode = tokenize(Node), diff --git a/src/mod_blocking.erl b/src/mod_blocking.erl index 98fb1e441..55e3ca151 100644 --- a/src/mod_blocking.erl +++ b/src/mod_blocking.erl @@ -72,19 +72,19 @@ depends(_Host, _Opts) -> process_iq(IQ) -> xmpp:make_error(IQ, xmpp:err_not_allowed()). --spec process_iq_get({error, error()} | {result, xmpp_element() | undefined}, +-spec process_iq_get({error, stanza_error()} | {result, xmpp_element() | undefined}, iq(), userlist()) -> - {error, error()} | {result, block_list()}. + {error, stanza_error()} | {result, block_list()}. process_iq_get(_, #iq{lang = Lang, from = From, sub_els = [#block_list{}]}, _) -> #jid{luser = LUser, lserver = LServer} = From, {stop, process_blocklist_get(LUser, LServer, Lang)}; process_iq_get(Acc, _, _) -> Acc. --spec process_iq_set({error, error()} | +-spec process_iq_set({error, stanza_error()} | {result, xmpp_element() | undefined} | {result, xmpp_element() | undefined, userlist()}, - iq()) -> {error, error()} | + iq()) -> {error, stanza_error()} | {result, undefined} | {result, undefined, userlist()}. process_iq_set(_, #iq{from = From, lang = Lang, sub_els = [SubEl]}) -> @@ -136,7 +136,7 @@ list_to_blocklist_jids([_ | Items], JIDs) -> -spec process_blocklist_block(binary(), binary(), [ljid()], binary()) -> - {error, error()} | + {error, stanza_error()} | {result, undefined, userlist()}. process_blocklist_block(LUser, LServer, JIDs, Lang) -> Filter = fun (List) -> @@ -171,7 +171,7 @@ process_blocklist_block(LUser, LServer, JIDs, Lang) -> end. -spec process_blocklist_unblock_all(binary(), binary(), binary()) -> - {error, error()} | + {error, stanza_error()} | {result, undefined} | {result, undefined, userlist()}. process_blocklist_unblock_all(LUser, LServer, Lang) -> @@ -195,7 +195,7 @@ process_blocklist_unblock_all(LUser, LServer, Lang) -> end. -spec process_blocklist_unblock(binary(), binary(), [ljid()], binary()) -> - {error, error()} | + {error, stanza_error()} | {result, undefined} | {result, undefined, userlist()}. process_blocklist_unblock(LUser, LServer, JIDs, Lang) -> @@ -240,7 +240,7 @@ broadcast_blocklist_event(LUser, LServer, Event) -> {broadcast, {blocking, Event}}). -spec process_blocklist_get(binary(), binary(), binary()) -> - {error, error()} | {result, block_list()}. + {error, stanza_error()} | {result, block_list()}. process_blocklist_get(LUser, LServer, Lang) -> Mod = db_mod(LServer), case Mod:process_blocklist_get(LUser, LServer) of diff --git a/src/mod_caps.erl b/src/mod_caps.erl index a388b085f..ae11ab651 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -158,10 +158,10 @@ caps_stream_features(Acc, MyHost) -> [#caps{hash = <<"sha-1">>, node = ?EJABBERD_URI, version = Hash}|Acc] end. --spec disco_features({error, error()} | {result, [binary()]} | empty, +-spec disco_features({error, stanza_error()} | {result, [binary()]} | empty, jid(), jid(), binary(), binary()) -> - {error, error()} | {result, [binary()]} | empty. + {error, stanza_error()} | {result, [binary()]} | empty. disco_features(Acc, From, To, Node, Lang) -> case is_valid_node(Node) of true -> diff --git a/src/mod_configure.erl b/src/mod_configure.erl index a798d010f..dd361028b 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -270,8 +270,8 @@ get_local_features(Acc, From, end. %%%----------------------------------------------------------------------- --spec adhoc_sm_items(empty | {error, error()} | {result, [disco_item()]}, - jid(), jid(), binary()) -> {error, error()} | +-spec adhoc_sm_items(empty | {error, stanza_error()} | {result, [disco_item()]}, + jid(), jid(), binary()) -> {error, stanza_error()} | {result, [disco_item()]} | empty. adhoc_sm_items(Acc, From, #jid{lserver = LServer} = To, @@ -325,8 +325,8 @@ get_user_resources(User, Server) -> %%%----------------------------------------------------------------------- --spec adhoc_local_items(empty | {error, error()} | {result, [disco_item()]}, - jid(), jid(), binary()) -> {error, error()} | +-spec adhoc_local_items(empty | {error, stanza_error()} | {result, [disco_item()]}, + jid(), jid(), binary()) -> {error, stanza_error()} | {result, [disco_item()]} | empty. adhoc_local_items(Acc, From, @@ -773,7 +773,7 @@ get_stopped_nodes(_Lang) -> end). -spec adhoc_local_commands(adhoc_command(), jid(), jid(), adhoc_command()) -> - adhoc_command() | {error, error()}. + adhoc_command() | {error, stanza_error()}. adhoc_local_commands(Acc, From, #jid{lserver = LServer} = To, #adhoc_command{node = Node, lang = Lang} = Request) -> diff --git a/src/mod_disco.erl b/src/mod_disco.erl index e33241928..953d1da10 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -198,9 +198,9 @@ get_local_identity(Acc, _From, _To, <<"">>, _Lang) -> get_local_identity(Acc, _From, _To, _Node, _Lang) -> Acc. --spec get_local_features({error, error()} | {result, [binary()]} | empty, +-spec get_local_features({error, stanza_error()} | {result, [binary()]} | empty, jid(), jid(), binary(), binary()) -> - {error, error()} | {result, [binary()]}. + {error, stanza_error()} | {result, [binary()]}. get_local_features({error, _Error} = Acc, _From, _To, _Node, _Lang) -> Acc; @@ -222,10 +222,10 @@ get_local_features(Acc, _From, _To, _Node, Lang) -> {error, xmpp:err_item_not_found(Txt, Lang)} end. --spec get_local_services({error, error()} | {result, [disco_item()]} | empty, +-spec get_local_services({error, stanza_error()} | {result, [disco_item()]} | empty, jid(), jid(), binary(), binary()) -> - {error, error()} | {result, [disco_item()]}. + {error, stanza_error()} | {result, [disco_item()]}. get_local_services({error, _Error} = Acc, _From, _To, _Node, _Lang) -> Acc; @@ -296,10 +296,10 @@ process_sm_iq_items(#iq{type = get, lang = Lang, xmpp:make_error(IQ, xmpp:err_subscription_required(Txt, Lang)) end. --spec get_sm_items({error, error()} | {result, [disco_item()]} | empty, +-spec get_sm_items({error, stanza_error()} | {result, [disco_item()]} | empty, jid(), jid(), binary(), binary()) -> - {error, error()} | {result, [disco_item()]}. + {error, stanza_error()} | {result, [disco_item()]}. get_sm_items({error, _Error} = Acc, _From, _To, _Node, _Lang) -> Acc; @@ -383,9 +383,9 @@ get_sm_identity(Acc, _From, _ -> [] end. --spec get_sm_features({error, error()} | {result, [binary()]} | empty, +-spec get_sm_features({error, stanza_error()} | {result, [binary()]} | empty, jid(), jid(), binary(), binary()) -> - {error, error()} | {result, [binary()]}. + {error, stanza_error()} | {result, [binary()]}. get_sm_features(empty, From, To, _Node, Lang) -> #jid{luser = LFrom, lserver = LSFrom} = From, #jid{luser = LTo, lserver = LSTo} = To, diff --git a/src/mod_http_upload.erl b/src/mod_http_upload.erl index babdbb7b6..f1f5d8173 100644 --- a/src/mod_http_upload.erl +++ b/src/mod_http_upload.erl @@ -601,7 +601,7 @@ create_slot(#state{service_url = undefined, {ok, [UserStr, RandStr, FileStr]}; deny -> {error, xmpp:err_service_unavailable()}; - #error{} = Error -> + #stanza_error{} = Error -> {error, Error} end; create_slot(#state{service_url = ServiceURL}, diff --git a/src/mod_irc.erl b/src/mod_irc.erl index a833287c8..fefebcfa3 100644 --- a/src/mod_irc.erl +++ b/src/mod_irc.erl @@ -679,7 +679,7 @@ adhoc_join(From, To, #adhoc_command{lang = Lang, xdata = X} = Request) -> end. -spec adhoc_register(binary(), jid(), jid(), adhoc_command()) -> - adhoc_command() | {error, error()}. + adhoc_command() | {error, stanza_error()}. adhoc_register(_ServerHost, _From, _To, #adhoc_command{action = cancel} = Request) -> xmpp_util:make_adhoc_response(Request, #adhoc_command{status = canceled}); diff --git a/src/mod_mix.erl b/src/mod_mix.erl index 52a3c8ed8..f39408210 100644 --- a/src/mod_mix.erl +++ b/src/mod_mix.erl @@ -52,7 +52,7 @@ stop(Host) -> supervisor:delete_child(ejabberd_sup, Proc), ok. --spec disco_features({error, error()} | {result, [binary()]} | empty, +-spec disco_features({error, stanza_error()} | {result, [binary()]} | empty, jid(), jid(), binary(), binary()) -> {result, [binary()]}. disco_features(_Acc, _From, _To, _Node, _Lang) -> {result, [?NS_MIX_0]}. diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl index 2f2962b97..c32551091 100644 --- a/src/mod_muc_room.erl +++ b/src/mod_muc_room.erl @@ -1136,8 +1136,8 @@ decide_fate_message(_, _, _) -> continue_delivery. %% Check if the elements of this error stanza indicate %% that the sender is a dead participant. %% If so, return true to kick the participant. --spec check_error_kick(error()) -> boolean(). -check_error_kick(#error{reason = Reason}) -> +-spec check_error_kick(stanza_error()) -> boolean(). +check_error_kick(#stanza_error{reason = Reason}) -> case Reason of #gone{} -> true; 'internal-server-error' -> true; @@ -1153,8 +1153,8 @@ check_error_kick(#error{reason = Reason}) -> check_error_kick(undefined) -> false. --spec get_error_condition(error()) -> string(). -get_error_condition(#error{reason = Reason}) -> +-spec get_error_condition(stanza_error()) -> string(). +get_error_condition(#stanza_error{reason = Reason}) -> case Reason of #gone{} -> "gone"; #redirect{} -> "redirect"; @@ -1673,7 +1673,7 @@ nick_collision(User, Nick, StateData) -> -spec add_new_user(jid(), binary(), presence() | iq(), state()) -> state() | - {error, error()} | + {error, stanza_error()} | {ignore, state()} | {result, xmpp_element(), state()}. add_new_user(From, Nick, Packet, StateData) -> @@ -2467,7 +2467,7 @@ can_change_subject(Role, StateData) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Admin stuff --spec process_iq_admin(jid(), iq(), #state{}) -> {error, error()} | +-spec process_iq_admin(jid(), iq(), #state{}) -> {error, stanza_error()} | {result, undefined, #state{}} | {result, muc_admin()}. process_iq_admin(_From, #iq{lang = Lang, sub_els = [#muc_admin{items = []}]}, @@ -2557,7 +2557,7 @@ search_affiliation(Affiliation, StateData) -> -spec process_admin_items_set(jid(), [muc_item()], binary(), #state{}) -> {result, undefined, #state{}} | - {error, error()}. + {error, stanza_error()}. process_admin_items_set(UJID, Items, Lang, StateData) -> UAffiliation = get_affiliation(UJID, StateData), URole = get_role(UJID, StateData), @@ -2939,7 +2939,7 @@ get_actor_nick(MJID, StateData) -> -spec process_iq_owner(jid(), iq(), state()) -> {result, undefined | muc_owner()} | {result, undefined | muc_owner(), state() | stop} | - {error, error()}. + {error, stanza_error()}. process_iq_owner(From, #iq{type = set, lang = Lang, sub_els = [#muc_owner{destroy = Destroy, config = Config, @@ -3294,7 +3294,7 @@ get_config(Lang, StateData, From) -> [StateData, From, Lang]), #xdata{type = form, title = Title, fields = Fields}. --spec set_config(xdata(), state(), binary()) -> {error, error()} | +-spec set_config(xdata(), state(), binary()) -> {error, stanza_error()} | {result, undefined, state()}. set_config(#xdata{fields = Fields}, StateData, Lang) -> Options = [{Var, Vals} || #xdata_field{var = Var, values = Vals} <- Fields], @@ -3377,7 +3377,7 @@ get_config_opt_name(Pos) -> end). -spec set_xoption([{binary(), [binary()]}], #config{}, - binary(), binary()) -> #config{} | {error, error()}. + binary(), binary()) -> #config{} | {error, stanza_error()}. set_xoption([], Config, _ServerHost, _Lang) -> Config; set_xoption([{<<"muc#roomconfig_roomname">>, Vals} | Opts], @@ -3836,7 +3836,7 @@ destroy_room(DEl, StateData) -> end). -spec process_iq_disco_info(jid(), iq(), state()) -> - {result, disco_info()} | {error, error()}. + {result, disco_info()} | {error, stanza_error()}. process_iq_disco_info(_From, #iq{type = set, lang = Lang}, _StateData) -> Txt = <<"Value 'set' of 'type' attribute is not allowed">>, {error, xmpp:err_not_allowed(Txt, Lang)}; @@ -3901,7 +3901,7 @@ iq_disco_info_extras(Lang, StateData) -> integer_to_binary(Len), Lang)]}. -spec process_iq_disco_items(jid(), iq(), state()) -> - {error, error()} | {result, disco_items()}. + {error, stanza_error()} | {result, disco_items()}. process_iq_disco_items(_From, #iq{type = set, lang = Lang}, _StateData) -> Txt = <<"Value 'set' of 'type' attribute is not allowed">>, {error, xmpp:err_not_allowed(Txt, Lang)}; @@ -3919,7 +3919,7 @@ process_iq_disco_items(From, #iq{type = get, lang = Lang}, StateData) -> end end. --spec process_iq_captcha(jid(), iq(), state()) -> {error, error()} | +-spec process_iq_captcha(jid(), iq(), state()) -> {error, stanza_error()} | {result, undefined}. process_iq_captcha(_From, #iq{type = get, lang = Lang}, _StateData) -> Txt = <<"Value 'get' of 'type' attribute is not allowed">>, @@ -3939,7 +3939,7 @@ process_iq_captcha(_From, #iq{type = set, lang = Lang, sub_els = [SubEl]}, -spec process_iq_vcard(jid(), iq(), state()) -> {result, vcard_temp() | xmlel()} | {result, undefined, state()} | - {error, error()}. + {error, stanza_error()}. process_iq_vcard(_From, #iq{type = get}, StateData) -> #state{config = #config{vcard = VCardRaw}} = StateData, case fxml_stream:parse_element(VCardRaw) of @@ -3962,7 +3962,7 @@ process_iq_vcard(From, #iq{type = set, lang = Lang, sub_els = [SubEl]}, end. -spec process_iq_mucsub(jid(), iq(), state()) -> - {error, error()} | + {error, stanza_error()} | {result, undefined | muc_subscribe(), state()} | {ignore, state()}. process_iq_mucsub(_From, #iq{type = set, lang = Lang, @@ -4205,7 +4205,7 @@ is_invitation(Packet) -> (_) -> false end, Els). --spec check_invitation(jid(), message(), state()) -> {error, error()} | jid(). +-spec check_invitation(jid(), message(), state()) -> {error, stanza_error()} | jid(). check_invitation(From, Packet, StateData) -> Lang = xmpp:get_lang(Packet), FAffiliation = get_affiliation(From, StateData), diff --git a/src/mod_multicast.erl b/src/mod_multicast.erl index f1c090ae4..72046491f 100644 --- a/src/mod_multicast.erl +++ b/src/mod_multicast.erl @@ -243,7 +243,7 @@ handle_iq(From, To, Packet, State) -> end. -spec process_iq(jid(), iq(), state()) -> {result, xmpp_element()} | - {error, error()} | reply. + {error, stanza_error()} | reply. process_iq(From, #iq{type = get, lang = Lang, sub_els = [#disco_info{}]}, State) -> {result, iq_disco_info(From, Lang, State)}; diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index f94c422b3..3be3f2d3b 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -100,8 +100,8 @@ stop(Host) -> process_iq(IQ) -> xmpp:make_error(IQ, xmpp:err_not_allowed()). --spec process_iq_get({error, error()} | {result, xmpp_element() | undefined}, - iq(), userlist()) -> {error, error()} | {result, privacy_query()}. +-spec process_iq_get({error, stanza_error()} | {result, xmpp_element() | undefined}, + iq(), userlist()) -> {error, stanza_error()} | {result, privacy_query()}. process_iq_get(_, #iq{from = From, lang = Lang, sub_els = [#privacy_query{lists = Lists}]}, #userlist{name = Active}) -> @@ -117,7 +117,7 @@ process_iq_get(_, #iq{from = From, lang = Lang, end. -spec process_lists_get(binary(), binary(), binary(), binary()) -> - {error, error()} | {result, privacy_query()}. + {error, stanza_error()} | {result, privacy_query()}. process_lists_get(LUser, LServer, Active, Lang) -> Mod = gen_mod:db_mod(LServer, ?MODULE), case Mod:process_lists_get(LUser, LServer) of @@ -135,7 +135,7 @@ process_lists_get(LUser, LServer, Active, Lang) -> end. -spec process_list_get(binary(), binary(), binary(), binary()) -> - {error, error()} | {result, privacy_query()}. + {error, stanza_error()} | {result, privacy_query()}. process_list_get(LUser, LServer, Name, Lang) -> Mod = gen_mod:db_mod(LServer, ?MODULE), case Mod:process_list_get(LUser, LServer, Name) of @@ -214,10 +214,10 @@ decode_value(Type, Value) -> undefined -> none end. --spec process_iq_set({error, error()} | +-spec process_iq_set({error, stanza_error()} | {result, xmpp_element() | undefined} | {result, xmpp_element() | undefined, userlist()}, - iq()) -> {error, error()} | + iq()) -> {error, stanza_error()} | {result, undefined, userlist()}. process_iq_set(_, #iq{from = From, lang = Lang, sub_els = [#privacy_query{default = Default, @@ -239,7 +239,7 @@ process_iq_set(_, #iq{from = From, lang = Lang, end. -spec process_default_set(binary(), binary(), none | binary(), - binary()) -> {error, error()} | {result, undefined}. + binary()) -> {error, stanza_error()} | {result, undefined}. process_default_set(LUser, LServer, Value, Lang) -> Mod = gen_mod:db_mod(LServer, ?MODULE), case Mod:process_default_set(LUser, LServer, Value) of @@ -258,7 +258,7 @@ process_default_set(LUser, LServer, Value, Lang) -> end. -spec process_active_set(binary(), binary(), none | binary(), binary()) -> - {error, error()} | + {error, stanza_error()} | {result, undefined, userlist()}. process_active_set(_LUser, _LServer, none, _Lang) -> {result, undefined, #userlist{}}; @@ -280,7 +280,7 @@ set_privacy_list(#privacy{us = {_, LServer}} = Privacy) -> Mod:set_privacy_list(Privacy). -spec process_lists_set(binary(), binary(), binary(), [privacy_item()], - binary()) -> {error, error()} | {result, undefined}. + binary()) -> {error, stanza_error()} | {result, undefined}. process_lists_set(LUser, LServer, Name, [], Lang) -> Mod = gen_mod:db_mod(LServer, ?MODULE), case Mod:remove_privacy_list(LUser, LServer, Name) of diff --git a/src/mod_pubsub.erl b/src/mod_pubsub.erl index a7a0e2d88..b470d83d9 100644 --- a/src/mod_pubsub.erl +++ b/src/mod_pubsub.erl @@ -525,9 +525,9 @@ disco_local_identity(Acc, _From, To, <<>>, _Lang) -> disco_local_identity(Acc, _From, _To, _Node, _Lang) -> Acc. --spec disco_local_features({error, error()} | {result, [binary()]} | empty, +-spec disco_local_features({error, stanza_error()} | {result, [binary()]} | empty, jid(), jid(), binary(), binary()) -> - {error, error()} | {result, [binary()]} | empty. + {error, stanza_error()} | {result, [binary()]} | empty. disco_local_features(Acc, _From, To, <<>>, _Lang) -> Host = host(To#jid.lserver), Feats = case Acc of @@ -538,9 +538,9 @@ disco_local_features(Acc, _From, To, <<>>, _Lang) -> disco_local_features(Acc, _From, _To, _Node, _Lang) -> Acc. --spec disco_local_items({error, error()} | {result, [disco_item()]} | empty, +-spec disco_local_items({error, stanza_error()} | {result, [disco_item()]} | empty, jid(), jid(), binary(), binary()) -> - {error, error()} | {result, [disco_item()]} | empty. + {error, stanza_error()} | {result, [disco_item()]} | empty. disco_local_items(Acc, _From, _To, <<>>, _Lang) -> Acc; disco_local_items(Acc, _From, _To, _Node, _Lang) -> Acc. @@ -578,9 +578,9 @@ disco_identity(Host, Node, From) -> _ -> [] end. --spec disco_sm_features({error, error()} | {result, [binary()]} | empty, +-spec disco_sm_features({error, stanza_error()} | {result, [binary()]} | empty, jid(), jid(), binary(), binary()) -> - {error, error()} | {result, [binary()]}. + {error, stanza_error()} | {result, [binary()]}. disco_sm_features(empty, From, To, Node, Lang) -> disco_sm_features({result, []}, From, To, Node, Lang); disco_sm_features({result, OtherFeatures} = _Acc, From, To, Node, _Lang) -> @@ -612,9 +612,9 @@ disco_features(Host, Node, From) -> _ -> [] end. --spec disco_sm_items({error, error()} | {result, [disco_item()]} | empty, +-spec disco_sm_items({error, stanza_error()} | {result, [disco_item()]} | empty, jid(), jid(), binary(), binary()) -> - {error, error()} | {result, [disco_item()]}. + {error, stanza_error()} | {result, [disco_item()]}. disco_sm_items(empty, From, To, Node, Lang) -> disco_sm_items({result, []}, From, To, Node, Lang); disco_sm_items({result, OtherItems}, From, To, Node, _Lang) -> @@ -1052,12 +1052,12 @@ command_disco_info(_Host, ?NS_PUBSUB_GET_PENDING, _From) -> features = [?NS_COMMANDS]}}. -spec node_disco_info(binary(), binary(), jid()) -> {result, disco_info()} | - {error, error()}. + {error, stanza_error()}. node_disco_info(Host, Node, From) -> node_disco_info(Host, Node, From, true, true). -spec node_disco_info(binary(), binary(), jid(), boolean(), boolean()) -> - {result, disco_info()} | {error, error()}. + {result, disco_info()} | {error, stanza_error()}. node_disco_info(Host, Node, _From, _Identity, _Features) -> Action = fun(#pubsub_node{type = Type, options = Options}) -> @@ -1075,7 +1075,7 @@ node_disco_info(Host, Node, _From, _Identity, _Features) -> end. -spec iq_disco_info(binary(), binary(), jid(), binary()) - -> {result, disco_info()} | {error, error()}. + -> {result, disco_info()} | {error, stanza_error()}. iq_disco_info(Host, SNode, From, Lang) -> [Node | _] = case SNode of <<>> -> [<<>>]; @@ -1105,7 +1105,7 @@ iq_disco_info(Host, SNode, From, Lang) -> end. -spec iq_disco_items(host(), binary(), jid(), undefined | rsm_set()) -> - {result, disco_items()} | {error, error()}. + {result, disco_items()} | {error, stanza_error()}. iq_disco_items(Host, <<>>, From, _RSM) -> Items = lists:map( @@ -1193,7 +1193,7 @@ iq_get_vcard(Lang) -> desc = <>}. -spec iq_pubsub(binary() | ljid(), atom(), iq()) -> - {result, pubsub()} | {error, error()}. + {result, pubsub()} | {error, stanza_error()}. iq_pubsub(Host, Access, #iq{from = From, type = IQType, lang = Lang, sub_els = [SubEl]}) -> case {IQType, SubEl} of @@ -1272,7 +1272,7 @@ iq_pubsub(Host, Access, #iq{from = From, type = IQType, lang = Lang, end. -spec iq_pubsub_owner(binary() | ljid(), iq()) -> {result, pubsub_owner() | undefined} | - {error, error()}. + {error, stanza_error()}. iq_pubsub_owner(Host, #iq{type = IQType, from = From, lang = Lang, sub_els = [SubEl]}) -> case {IQType, SubEl} of @@ -1312,7 +1312,7 @@ iq_pubsub_owner(Host, #iq{type = IQType, from = From, end. -spec adhoc_request(binary(), binary(), jid(), adhoc_command(), - atom(), [binary()]) -> adhoc_command() | {error, error()}. + atom(), [binary()]) -> adhoc_command() | {error, stanza_error()}. adhoc_request(Host, _ServerHost, Owner, #adhoc_command{node = ?NS_PUBSUB_GET_PENDING, lang = Lang, action = execute, xdata = undefined}, @@ -1342,7 +1342,7 @@ adhoc_request(_Host, _ServerHost, _Owner, Other, _Access, _Plugins) -> {error, xmpp:err_item_not_found()}. -spec send_pending_node_form(binary(), jid(), binary(), - [binary()]) -> adhoc_command() | {error, error()}. + [binary()]) -> adhoc_command() | {error, stanza_error()}. send_pending_node_form(Host, Owner, _Lang, Plugins) -> Filter = fun (Type) -> lists:member(<<"get-pending">>, plugin_features(Host, Type)) @@ -1369,7 +1369,7 @@ send_pending_node_form(Host, Owner, _Lang, Plugins) -> end. -spec get_pending_nodes(binary(), jid(), [binary()]) -> {ok, [binary()]} | - {error, error()}. + {error, stanza_error()}. get_pending_nodes(Host, Owner, Plugins) -> Tr = fun (Type) -> case node_call(Host, Type, get_pending_nodes, [Host, Owner]) of @@ -1386,7 +1386,7 @@ get_pending_nodes(Host, Owner, Plugins) -> %% @doc

    Send a subscription approval form to Owner for all pending %% subscriptions on Host and Node.

    -spec send_pending_auth_events(binary(), binary(), jid(), - binary()) -> adhoc_command() | {error, error()}. + binary()) -> adhoc_command() | {error, stanza_error()}. send_pending_auth_events(Host, Node, Owner, Lang) -> ?DEBUG("Sending pending auth events for ~s on ~s:~s", [jid:to_string(Owner), Host, Node]), @@ -1520,7 +1520,7 @@ handle_authorization_response(Host, From, To, Packet, X) -> end. -spec update_auth(binary(), binary(), _, _, jid() | error, boolean(), _) -> - {result, ok} | {error, error()}. + {result, ok} | {error, stanza_error()}. update_auth(Host, Node, Type, Nidx, Subscriber, Allow, Subs) -> Sub= lists:filter(fun ({pending, _}) -> true; @@ -1598,12 +1598,12 @@ update_auth(Host, Node, Type, Nidx, Subscriber, Allow, Subs) -> %%
  • node plugin create_node just sets default affiliation/subscription
  • %% -spec create_node(host(), binary(), binary(), jid(), - binary()) -> {result, pubsub()} | {error, error()}. + binary()) -> {result, pubsub()} | {error, stanza_error()}. create_node(Host, ServerHost, Node, Owner, Type) -> create_node(Host, ServerHost, Node, Owner, Type, all, []). -spec create_node(host(), binary(), binary(), jid(), binary(), - atom(), [{binary(), [binary()]}]) -> {result, pubsub()} | {error, error()}. + atom(), [{binary(), [binary()]}]) -> {result, pubsub()} | {error, stanza_error()}. create_node(Host, ServerHost, <<>>, Owner, Type, Access, Configuration) -> case lists:member(<<"instant-nodes">>, plugin_features(Host, Type)) of true -> @@ -1693,7 +1693,7 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> %%
  • The node is the root collection node, which cannot be deleted.
  • %%
  • The specified node does not exist.
  • %% --spec delete_node(host(), binary(), jid()) -> {result, pubsub_owner()} | {error, error()}. +-spec delete_node(host(), binary(), jid()) -> {result, pubsub_owner()} | {error, stanza_error()}. delete_node(_Host, <<>>, _Owner) -> {error, xmpp:err_not_allowed(<<"No node specified">>, ?MYLANG)}; delete_node(Host, Node, Owner) -> @@ -1770,7 +1770,7 @@ delete_node(Host, Node, Owner) -> %%
  • The node does not exist.
  • %% -spec subscribe_node(host(), binary(), jid(), binary(), [{binary(), [binary()]}]) -> - {result, pubsub()} | {error, error()}. + {result, pubsub()} | {error, stanza_error()}. subscribe_node(Host, Node, From, JID, Configuration) -> SubModule = subscription_plugin(Host), SubOpts = case SubModule:parse_options_xform(Configuration) of @@ -1874,7 +1874,7 @@ subscribe_node(Host, Node, From, JID, Configuration) -> %%
  • The request specifies a subscription ID that is not valid or current.
  • %% -spec unsubscribe_node(host(), binary(), jid(), jid(), binary()) -> - {result, undefined} | {error, error()}. + {result, undefined} | {error, stanza_error()}. unsubscribe_node(Host, Node, From, JID, SubId) -> Subscriber = jid:tolower(JID), Action = fun (#pubsub_node{type = Type, id = Nidx}) -> @@ -1901,7 +1901,7 @@ unsubscribe_node(Host, Node, From, JID, SubId) -> %%
  • The request does not match the node configuration.
  • %% -spec publish_item(host(), binary(), binary(), jid(), binary(), - [xmlel()]) -> {result, pubsub()} | {error, error()}. + [xmlel()]) -> {result, pubsub()} | {error, stanza_error()}. publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload, [], all). publish_item(Host, ServerHost, Node, Publisher, <<>>, Payload, PubOpts, Access) -> @@ -1984,7 +1984,7 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload, PubOpts, Access {result, Reply}; {result, {_, Result}} -> {result, Result}; - {error, #error{reason = 'item-not-found'}} -> + {error, #stanza_error{reason = 'item-not-found'}} -> Type = select_type(ServerHost, Host, Node), case lists:member(<<"auto-create">>, plugin_features(Host, Type)) of true -> @@ -2015,7 +2015,7 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload, PubOpts, Access %%
  • The service does not support the deletion of items.
  • %% -spec delete_item(host(), binary(), jid(), binary()) -> {result, undefined} | - {error, error()}. + {error, stanza_error()}. delete_item(Host, Node, Publisher, ItemId) -> delete_item(Host, Node, Publisher, ItemId, false). delete_item(_, <<>>, _, _, _) -> @@ -2071,7 +2071,7 @@ delete_item(Host, Node, Publisher, ItemId, ForceNotify) -> %%
  • The specified node does not exist.
  • %% -spec purge_node(mod_pubsub:host(), binary(), jid()) -> {result, undefined} | - {error, error()}. + {error, stanza_error()}. purge_node(Host, Node, Owner) -> Action = fun (#pubsub_node{options = Options, type = Type, id = Nidx}) -> Features = plugin_features(Host, Type), @@ -2117,7 +2117,7 @@ purge_node(Host, Node, Owner) -> %% to read the items. -spec get_items(host(), binary(), jid(), binary(), binary(), [binary()], undefined | rsm_set()) -> - {result, pubsub()} | {error, error()}. + {result, pubsub()} | {error, stanza_error()}. get_items(Host, Node, From, SubId, SMaxItems, ItemIds, RSM) -> MaxItems = if SMaxItems == undefined -> case get_max_items_node(Host) of @@ -2270,7 +2270,7 @@ dispatch_items(From, To, _Node, Stanza) -> %% @doc

    Return the list of affiliations as an XMPP response.

    -spec get_affiliations(host(), binary(), jid(), [binary()]) -> - {result, pubsub()} | {error, error()}. + {result, pubsub()} | {error, stanza_error()}. get_affiliations(Host, Node, JID, Plugins) when is_list(Plugins) -> Result = lists:foldl( @@ -2310,7 +2310,7 @@ get_affiliations(Host, Node, JID, Plugins) when is_list(Plugins) -> end. -spec get_affiliations(host(), binary(), jid()) -> - {result, pubsub_owner()} | {error, error()}. + {result, pubsub_owner()} | {error, stanza_error()}. get_affiliations(Host, Node, JID) -> Action = fun(#pubsub_node{type = Type, id = Nidx}) -> @@ -2342,7 +2342,7 @@ get_affiliations(Host, Node, JID) -> end. -spec set_affiliations(host(), binary(), jid(), [ps_affiliation()]) -> - {result, undefined} | {error, error()}. + {result, undefined} | {error, stanza_error()}. set_affiliations(Host, Node, From, Affs) -> Owner = jid:tolower(jid:remove_resource(From)), Action = @@ -2396,7 +2396,7 @@ set_affiliations(Host, Node, From, Affs) -> end. -spec get_options(binary(), binary(), jid(), binary(), binary()) -> - {result, xdata()} | {error, error()}. + {result, xdata()} | {error, stanza_error()}. get_options(Host, Node, JID, SubId, Lang) -> Action = fun (#pubsub_node{type = Type, id = Nidx}) -> case lists:member(<<"subscription-options">>, plugin_features(Host, Type)) of @@ -2413,7 +2413,7 @@ get_options(Host, Node, JID, SubId, Lang) -> end. -spec get_options_helper(binary(), jid(), binary(), binary(), _, binary(), - binary()) -> {result, pubsub()} | {error, error()}. + binary()) -> {result, pubsub()} | {error, stanza_error()}. get_options_helper(Host, JID, Lang, Node, Nidx, SubId, Type) -> Subscriber = jid:tolower(JID), {result, Subs} = node_call(Host, Type, get_subscriptions, [Nidx, Subscriber]), @@ -2454,7 +2454,7 @@ read_sub(Host, Node, Nidx, Subscriber, SubId, Lang) -> -spec set_options(binary(), binary(), jid(), binary(), [{binary(), [binary()]}]) -> - {result, undefined} | {error, error()}. + {result, undefined} | {error, stanza_error()}. set_options(Host, Node, JID, SubId, Configuration) -> Action = fun (#pubsub_node{type = Type, id = Nidx}) -> case lists:member(<<"subscription-options">>, plugin_features(Host, Type)) of @@ -2472,7 +2472,7 @@ set_options(Host, Node, JID, SubId, Configuration) -> -spec set_options_helper(binary(), [{binary(), [binary()]}], jid(), nodeIdx(), binary(), binary()) -> - {result, undefined} | {error, error()}. + {result, undefined} | {error, stanza_error()}. set_options_helper(Host, Configuration, JID, Nidx, SubId, Type) -> SubModule = subscription_plugin(Host), SubOpts = case SubModule:parse_options_xform(Configuration) of @@ -2494,7 +2494,7 @@ set_options_helper(Host, Configuration, JID, Nidx, SubId, Type) -> end. -spec write_sub(binary(), nodeIdx(), ljid(), binary(), _) -> {result, undefined} | - {error, error()}. + {error, stanza_error()}. write_sub(_Host, _Nidx, _Subscriber, _SubId, invalid) -> {error, extended_error(xmpp:err_bad_request(), err_invalid_options())}; write_sub(_Host, _Nidx, _Subscriber, _SubId, []) -> @@ -2509,7 +2509,7 @@ write_sub(Host, Nidx, Subscriber, SubId, Options) -> %% @doc

    Return the list of subscriptions as an XMPP response.

    -spec get_subscriptions(host(), binary(), jid(), [binary()]) -> - {result, pubsub()} | {error, error()}. + {result, pubsub()} | {error, stanza_error()}. get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> Result = lists:foldl(fun (Type, {Status, Acc}) -> Features = plugin_features(Host, Type), @@ -2576,7 +2576,7 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> end. -spec get_subscriptions(host(), binary(), jid()) -> {result, pubsub_owner()} | - {error, error()}. + {error, stanza_error()}. get_subscriptions(Host, Node, JID) -> Action = fun (#pubsub_node{type = Type, id = Nidx}) -> Features = plugin_features(Host, Type), @@ -2633,7 +2633,7 @@ get_subscriptions_for_send_last(_Host, _PType, _, _JID, _LJID, _BJID) -> []. -spec set_subscriptions(host(), binary(), jid(), [ps_subscription()]) -> - {result, undefined} | {error, error()}. + {result, undefined} | {error, stanza_error()}. set_subscriptions(Host, Node, From, Entities) -> Owner = jid:tolower(jid:remove_resource(From)), Notify = fun(#ps_subscription{jid = JID, type = Sub}) -> @@ -3163,7 +3163,7 @@ user_resource(_, _, Resource) -> %%%%%%% Configuration handling -spec get_configure(host(), binary(), binary(), jid(), - binary()) -> {error, error()} | {result, pubsub_owner()}. + binary()) -> {error, stanza_error()} | {result, pubsub_owner()}. get_configure(Host, ServerHost, Node, From, Lang) -> Action = fun (#pubsub_node{options = Options, type = Type, id = Nidx}) -> case node_call(Host, Type, get_affiliation, [Nidx, From]) of @@ -3381,7 +3381,7 @@ get_configure_xfields(_Type, Options, Lang, Groups) -> %%
  • The specified node does not exist.
  • %% -spec set_configure(host(), binary(), jid(), [{binary(), [binary()]}], - binary()) -> {result, undefined} | {error, error()}. + binary()) -> {result, undefined} | {error, stanza_error()}. set_configure(_Host, <<>>, _From, _Config, _Lang) -> {error, extended_error(xmpp:err_bad_request(), err_nodeid_required())}; set_configure(Host, Node, From, Config, Lang) -> @@ -3851,9 +3851,9 @@ transaction_retry(Host, ServerHost, Fun, Trans, DBType, Count) -> %%%% helpers %% Add pubsub-specific error element --spec extended_error(error(), ps_error()) -> error(). +-spec extended_error(stanza_error(), ps_error()) -> stanza_error(). extended_error(StanzaErr, PubSubErr) -> - StanzaErr#error{sub_els = [PubSubErr]}. + StanzaErr#stanza_error{sub_els = [PubSubErr]}. -spec err_closed_node() -> ps_error(). err_closed_node() -> @@ -4033,7 +4033,7 @@ purge_offline(LJID) -> ?DEBUG("on_user_offline ~p", [Error]) end. --spec purge_offline(host(), ljid(), binary()) -> ok | {error, error()}. +-spec purge_offline(host(), ljid(), binary()) -> ok | {error, stanza_error()}. purge_offline(Host, LJID, Node) -> Nidx = Node#pubsub_node.id, Type = Node#pubsub_node.type, diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index f0fb556ba..1f6edb460 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -150,9 +150,9 @@ do_route(From, To, #iq{} = IQ) -> do_route(_, _, _) -> ok. --spec get_sm_features({error, error()} | empty | {result, [binary()]}, +-spec get_sm_features({error, stanza_error()} | empty | {result, [binary()]}, jid(), jid(), binary(), binary()) -> - {error, error()} | empty | {result, [binary()]}. + {error, stanza_error()} | empty | {result, [binary()]}. get_sm_features({error, _Error} = Acc, _From, _To, _Node, _Lang) -> Acc; @@ -230,9 +230,9 @@ process_search(#iq{type = set, lang = Lang} = IQ) -> Txt = <<"Incorrect data form">>, xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)). --spec disco_items({error, error()} | {result, [disco_item()]} | empty, +-spec disco_items({error, stanza_error()} | {result, [disco_item()]} | empty, jid(), jid(), binary(), binary()) -> - {error, error()} | {result, [disco_item()]}. + {error, stanza_error()} | {result, [disco_item()]}. disco_items(empty, _From, _To, <<"">>, _Lang) -> {result, []}; disco_items(empty, _From, _To, _Node, Lang) -> @@ -240,9 +240,9 @@ disco_items(empty, _From, _To, _Node, Lang) -> disco_items(Acc, _From, _To, _Node, _Lang) -> Acc. --spec disco_features({error, error()} | {result, [binary()]} | empty, +-spec disco_features({error, stanza_error()} | {result, [binary()]} | empty, jid(), jid(), binary(), binary()) -> - {error, error()} | {result, [binary()]}. + {error, stanza_error()} | {result, [binary()]}. disco_features({error, _Error} = Acc, _From, _To, _Node, _Lang) -> Acc; disco_features(Acc, _From, _To, <<"">>, _Lang) -> diff --git a/src/xmpp.erl b/src/xmpp.erl index 10872b341..49d824af2 100644 --- a/src/xmpp.erl +++ b/src/xmpp.erl @@ -88,10 +88,10 @@ make_iq_result(#iq{type = Type, from = From, to = To} = IQ, El) end, IQ#iq{type = result, to = From, from = To, sub_els = SubEls}. --spec make_error(message(), error() | xmlel()) -> message(); - (presence(), error() | xmlel()) -> presence(); - (iq(), error() | xmlel()) -> iq(); - (xmlel(), error() | xmlel()) -> xmlel(). +-spec make_error(message(), stanza_error() | xmlel()) -> message(); + (presence(), stanza_error() | xmlel()) -> presence(); + (iq(), stanza_error() | xmlel()) -> iq(); + (xmlel(), stanza_error() | xmlel()) -> xmlel(). make_error(#message{type = Type, from = From, to = To, sub_els = Els} = Msg, Err) when Type /= error -> Msg#message{type = error, from = To, to = From, sub_els = Els ++ [Err]}; @@ -150,9 +150,9 @@ get_to(#iq{to = J}) -> J; get_to(#message{to = J}) -> J; get_to(#presence{to = J}) -> J. --spec get_error(iq() | message() | presence()) -> undefined | error(). +-spec get_error(iq() | message() | presence()) -> undefined | stanza_error(). get_error(Stanza) -> - case get_subtag(Stanza, #error{}) of + case get_subtag(Stanza, #stanza_error{}) of false -> undefined; Error -> Error end. @@ -206,9 +206,9 @@ set_from_to(#iq{} = IQ, F, T) -> IQ#iq{from = F, to = T}; set_from_to(#message{} = Msg, F, T) -> Msg#message{from = F, to = T}; set_from_to(#presence{} = Pres, F, T) -> Pres#presence{from = F, to = T}. --spec set_error(iq(), error()) -> iq(); - (message(), error()) -> message(); - (presence(), error()) -> presence(). +-spec set_error(iq(), stanza_error()) -> iq(); + (message(), stanza_error()) -> message(); + (presence(), stanza_error()) -> presence(). set_error(Stanza, E) -> set_subtag(Stanza, E). -spec set_els(iq(), [xmpp_element() | xmlel()]) -> iq(); @@ -383,199 +383,199 @@ pp(Term) -> %%%=================================================================== %%% Functions to construct general XMPP errors %%%=================================================================== --spec err_bad_request() -> error(). +-spec err_bad_request() -> stanza_error(). err_bad_request() -> err(modify, 'bad-request', 400). --spec err_bad_request(binary(), binary()) -> error(). +-spec err_bad_request(binary(), binary()) -> stanza_error(). err_bad_request(Text, Lang) -> err(modify, 'bad-request', 400, Text, Lang). --spec err_conflict() -> error(). +-spec err_conflict() -> stanza_error(). err_conflict() -> err(cancel, 'conflict', 409). --spec err_conflict(binary(), binary()) -> error(). +-spec err_conflict(binary(), binary()) -> stanza_error(). err_conflict(Text, Lang) -> err(cancel, 'conflict', 409, Text, Lang). --spec err_feature_not_implemented() -> error(). +-spec err_feature_not_implemented() -> stanza_error(). err_feature_not_implemented() -> err(cancel, 'feature-not-implemented', 501). --spec err_feature_not_implemented(binary(), binary()) -> error(). +-spec err_feature_not_implemented(binary(), binary()) -> stanza_error(). err_feature_not_implemented(Text, Lang) -> err(cancel, 'feature-not-implemented', 501, Text, Lang). --spec err_forbidden() -> error(). +-spec err_forbidden() -> stanza_error(). err_forbidden() -> err(auth, 'forbidden', 403). --spec err_forbidden(binary(), binary()) -> error(). +-spec err_forbidden(binary(), binary()) -> stanza_error(). err_forbidden(Text, Lang) -> err(auth, 'forbidden', 403, Text, Lang). %% RFC 6120 says error type SHOULD be "cancel". %% RFC 3920 and XEP-0082 says it SHOULD be "modify". --spec err_gone() -> error(). +-spec err_gone() -> stanza_error(). err_gone() -> err(modify, 'gone', 302). --spec err_gone(binary(), binary()) -> error(). +-spec err_gone(binary(), binary()) -> stanza_error(). err_gone(Text, Lang) -> err(modify, 'gone', 302, Text, Lang). %% RFC 6120 sasy error type SHOULD be "cancel". %% RFC 3920 and XEP-0082 says it SHOULD be "wait". --spec err_internal_server_error() -> error(). +-spec err_internal_server_error() -> stanza_error(). err_internal_server_error() -> err(wait, 'internal-server-error', 500). --spec err_internal_server_error(binary(), binary()) -> error(). +-spec err_internal_server_error(binary(), binary()) -> stanza_error(). err_internal_server_error(Text, Lang) -> err(wait, 'internal-server-error', 500, Text, Lang). --spec err_item_not_found() -> error(). +-spec err_item_not_found() -> stanza_error(). err_item_not_found() -> err(cancel, 'item-not-found', 404). --spec err_item_not_found(binary(), binary()) -> error(). +-spec err_item_not_found(binary(), binary()) -> stanza_error(). err_item_not_found(Text, Lang) -> err(cancel, 'item-not-found', 404, Text, Lang). --spec err_jid_malformed() -> error(). +-spec err_jid_malformed() -> stanza_error(). err_jid_malformed() -> err(modify, 'jid-malformed', 400). --spec err_jid_malformed(binary(), binary()) -> error(). +-spec err_jid_malformed(binary(), binary()) -> stanza_error(). err_jid_malformed(Text, Lang) -> err(modify, 'jid-malformed', 400, Text, Lang). --spec err_not_acceptable() -> error(). +-spec err_not_acceptable() -> stanza_error(). err_not_acceptable() -> err(modify, 'not-acceptable', 406). --spec err_not_acceptable(binary(), binary()) -> error(). +-spec err_not_acceptable(binary(), binary()) -> stanza_error(). err_not_acceptable(Text, Lang) -> err(modify, 'not-acceptable', 406, Text, Lang). --spec err_not_allowed() -> error(). +-spec err_not_allowed() -> stanza_error(). err_not_allowed() -> err(cancel, 'not-allowed', 405). --spec err_not_allowed(binary(), binary()) -> error(). +-spec err_not_allowed(binary(), binary()) -> stanza_error(). err_not_allowed(Text, Lang) -> err(cancel, 'not-allowed', 405, Text, Lang). --spec err_not_authorized() -> error(). +-spec err_not_authorized() -> stanza_error(). err_not_authorized() -> err(auth, 'not-authorized', 401). --spec err_not_authorized(binary(), binary()) -> error(). +-spec err_not_authorized(binary(), binary()) -> stanza_error(). err_not_authorized(Text, Lang) -> err(auth, 'not-authorized', 401, Text, Lang). --spec err_payment_required() -> error(). +-spec err_payment_required() -> stanza_error(). err_payment_required() -> err(auth, 'not-authorized', 402). --spec err_payment_required(binary(), binary()) -> error(). +-spec err_payment_required(binary(), binary()) -> stanza_error(). err_payment_required(Text, Lang) -> err(auth, 'not-authorized', 402, Text, Lang). %% is defined in neither RFC 3920 nor XEP-0086. %% We choose '403' error code (as in ). --spec err_policy_violation() -> error(). +-spec err_policy_violation() -> stanza_error(). err_policy_violation() -> err(modify, 'policy-violation', 403). --spec err_policy_violation(binary(), binary()) -> error(). +-spec err_policy_violation(binary(), binary()) -> stanza_error(). err_policy_violation(Text, Lang) -> err(modify, 'policy-violation', 403, Text, Lang). --spec err_recipient_unavailable() -> error(). +-spec err_recipient_unavailable() -> stanza_error(). err_recipient_unavailable() -> err(wait, 'recipient-unavailable', 404). --spec err_recipient_unavailable(binary(), binary()) -> error(). +-spec err_recipient_unavailable(binary(), binary()) -> stanza_error(). err_recipient_unavailable(Text, Lang) -> err(wait, 'recipient-unavailable', 404, Text, Lang). --spec err_redirect() -> error(). +-spec err_redirect() -> stanza_error(). err_redirect() -> err(modify, 'redirect', 302). --spec err_redirect(binary(), binary()) -> error(). +-spec err_redirect(binary(), binary()) -> stanza_error(). err_redirect(Text, Lang) -> err(modify, 'redirect', 302, Text, Lang). --spec err_registration_required() -> error(). +-spec err_registration_required() -> stanza_error(). err_registration_required() -> err(auth, 'registration-required', 407). --spec err_registration_required(binary(), binary()) -> error(). +-spec err_registration_required(binary(), binary()) -> stanza_error(). err_registration_required(Text, Lang) -> err(auth, 'registration-required', 407, Text, Lang). --spec err_remote_server_not_found() -> error(). +-spec err_remote_server_not_found() -> stanza_error(). err_remote_server_not_found() -> err(cancel, 'remote-server-not-found', 404). --spec err_remote_server_not_found(binary(), binary()) -> error(). +-spec err_remote_server_not_found(binary(), binary()) -> stanza_error(). err_remote_server_not_found(Text, Lang) -> err(cancel, 'remote-server-not-found', 404, Text, Lang). --spec err_remote_server_timeout() -> error(). +-spec err_remote_server_timeout() -> stanza_error(). err_remote_server_timeout() -> err(wait, 'remote-server-timeout', 504). --spec err_remote_server_timeout(binary(), binary()) -> error(). +-spec err_remote_server_timeout(binary(), binary()) -> stanza_error(). err_remote_server_timeout(Text, Lang) -> err(wait, 'remote-server-timeout', 504, Text, Lang). --spec err_resource_constraint() -> error(). +-spec err_resource_constraint() -> stanza_error(). err_resource_constraint() -> err(wait, 'resource-constraint', 500). --spec err_resource_constraint(binary(), binary()) -> error(). +-spec err_resource_constraint(binary(), binary()) -> stanza_error(). err_resource_constraint(Text, Lang) -> err(wait, 'resource-constraint', 500, Text, Lang). --spec err_service_unavailable() -> error(). +-spec err_service_unavailable() -> stanza_error(). err_service_unavailable() -> err(cancel, 'service-unavailable', 503). --spec err_service_unavailable(binary(), binary()) -> error(). +-spec err_service_unavailable(binary(), binary()) -> stanza_error(). err_service_unavailable(Text, Lang) -> err(cancel, 'service-unavailable', 503, Text, Lang). --spec err_subscription_required() -> error(). +-spec err_subscription_required() -> stanza_error(). err_subscription_required() -> err(auth, 'subscription-required', 407). --spec err_subscription_required(binary(), binary()) -> error(). +-spec err_subscription_required(binary(), binary()) -> stanza_error(). err_subscription_required(Text, Lang) -> err(auth, 'subscription-required', 407, Text, Lang). %% No error type is defined for . %% Let user provide the type. -spec err_undefined_condition('auth' | 'cancel' | 'continue' | - 'modify' | 'wait') -> error(). + 'modify' | 'wait') -> stanza_error(). err_undefined_condition(Type) -> err(Type, 'undefined-condition', 500). -spec err_undefined_condition('auth' | 'cancel' | 'continue' | 'modify' | 'wait', - binary(), binary()) -> error(). + binary(), binary()) -> stanza_error(). err_undefined_condition(Type, Text, Lang) -> err(Type, 'undefined-condition', 500, Text, Lang). %% RFC 6120 says error type SHOULD be "wait" or "modify". %% RFC 3920 and XEP-0082 says it SHOULD be "wait". --spec err_unexpected_request() -> error(). +-spec err_unexpected_request() -> stanza_error(). err_unexpected_request() -> err(wait, 'unexpected-request', 400). --spec err_unexpected_request(binary(), binary()) -> error(). +-spec err_unexpected_request(binary(), binary()) -> stanza_error(). err_unexpected_request(Text, Lang) -> err(wait, 'unexpected-request', 400, Text, Lang). @@ -786,17 +786,17 @@ serr_unsupported_version(Text, Lang) -> %%% Internal functions %%%=================================================================== -spec err('auth' | 'cancel' | 'continue' | 'modify' | 'wait', - atom() | gone() | redirect(), non_neg_integer()) -> error(). + atom() | gone() | redirect(), non_neg_integer()) -> stanza_error(). err(Type, Reason, Code) -> - #error{type = Type, reason = Reason, code = Code}. + #stanza_error{type = Type, reason = Reason, code = Code}. -spec err('auth' | 'cancel' | 'continue' | 'modify' | 'wait', atom() | gone() | redirect(), non_neg_integer(), - binary(), binary()) -> error(). + binary(), binary()) -> stanza_error(). err(Type, Reason, Code, Text, Lang) -> - #error{type = Type, reason = Reason, code = Code, - text = #text{lang = Lang, - data = translate:translate(Lang, Text)}}. + #stanza_error{type = Type, reason = Reason, code = Code, + text = #text{lang = Lang, + data = translate:translate(Lang, Text)}}. -spec serr(atom() | 'see-other-host'()) -> stream_error(). serr(Reason) -> diff --git a/src/xmpp_codec.erl b/src/xmpp_codec.erl index 135a2acbb..8653d591c 100644 --- a/src/xmpp_codec.erl +++ b/src/xmpp_codec.erl @@ -2567,7 +2567,7 @@ encode({redirect, _} = Redirect) -> encode_error_redirect(Redirect, [{<<"xmlns">>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]); -encode({error, _, _, _, _, _, _} = Error) -> +encode({stanza_error, _, _, _, _, _, _} = Error) -> encode_error(Error, [{<<"xmlns">>, <<"jabber:client">>}]); encode({bind, _, _} = Bind) -> @@ -3176,7 +3176,6 @@ get_name({delay, _, _, _}) -> <<"delay">>; get_name({disco_info, _, _, _, _}) -> <<"query">>; get_name({disco_item, _, _, _}) -> <<"item">>; get_name({disco_items, _, _, _}) -> <<"query">>; -get_name({error, _, _, _, _, _, _}) -> <<"error">>; get_name({expire, _, _}) -> <<"x">>; get_name({feature_csi, _}) -> <<"csi">>; get_name({feature_register}) -> <<"register">>; @@ -3329,6 +3328,8 @@ get_name({sm_failed, _, _, _}) -> <<"failed">>; get_name({sm_r, _}) -> <<"r">>; get_name({sm_resume, _, _, _}) -> <<"resume">>; get_name({sm_resumed, _, _, _}) -> <<"resumed">>; +get_name({stanza_error, _, _, _, _, _, _}) -> + <<"error">>; get_name({stanza_id, _, _}) -> <<"stanza-id">>; get_name({starttls, _}) -> <<"starttls">>; get_name({starttls_failure}) -> <<"failure">>; @@ -3441,8 +3442,6 @@ get_ns({disco_item, _, _, _}) -> <<"http://jabber.org/protocol/disco#items">>; get_ns({disco_items, _, _, _}) -> <<"http://jabber.org/protocol/disco#items">>; -get_ns({error, _, _, _, _, _, _}) -> - <<"jabber:client">>; get_ns({expire, _, _}) -> <<"jabber:x:expire">>; get_ns({feature_csi, Xmlns}) -> Xmlns; get_ns({feature_register}) -> @@ -3633,6 +3632,8 @@ get_ns({sm_failed, _, _, Xmlns}) -> Xmlns; get_ns({sm_r, Xmlns}) -> Xmlns; get_ns({sm_resume, _, _, Xmlns}) -> Xmlns; get_ns({sm_resumed, _, _, Xmlns}) -> Xmlns; +get_ns({stanza_error, _, _, _, _, _, _}) -> + <<"jabber:client">>; get_ns({stanza_id, _, _}) -> <<"urn:xmpp:sid:0">>; get_ns({starttls, _}) -> <<"urn:ietf:params:xml:ns:xmpp-tls">>; @@ -3778,7 +3779,8 @@ pp(presence, 9) -> sub_els]; pp(gone, 1) -> [uri]; pp(redirect, 1) -> [uri]; -pp(error, 6) -> [type, code, by, reason, text, sub_els]; +pp(stanza_error, 6) -> + [type, code, by, reason, text, sub_els]; pp(bind, 2) -> [jid, resource]; pp(legacy_auth, 4) -> [username, password, digest, resource]; @@ -25595,7 +25597,7 @@ decode_error(__TopXMLNS, __IgnoreEls, {Type, Code, By} = decode_error_attrs(__TopXMLNS, _attrs, undefined, undefined, undefined), - {error, Type, Code, By, Reason, Text, __Els}. + {stanza_error, Type, Code, By, Reason, Text, __Els}. decode_error_els(__TopXMLNS, __IgnoreEls, [], Text, Reason, __Els) -> @@ -25965,8 +25967,8 @@ decode_error_attrs(__TopXMLNS, [], Type, Code, By) -> decode_error_attr_code(__TopXMLNS, Code), decode_error_attr_by(__TopXMLNS, By)}. -encode_error({error, Type, Code, By, Reason, Text, - __Els}, +encode_error({stanza_error, Type, Code, By, Reason, + Text, __Els}, _xmlns_attrs) -> _els = [encode(_el) || _el <- __Els] ++ lists:reverse('encode_error_$text'(Text, diff --git a/tools/xmpp_codec.spec b/tools/xmpp_codec.spec index a11c8dd76..265bd6de9 100644 --- a/tools/xmpp_codec.spec +++ b/tools/xmpp_codec.spec @@ -528,7 +528,7 @@ -xml(error, #elem{name = <<"error">>, xmlns = <<"jabber:client">>, - result = {error, '$type', '$code', '$by', '$reason', '$text', '$_els'}, + result = {stanza_error, '$type', '$code', '$by', '$reason', '$text', '$_els'}, attrs = [#attr{name = <<"type">>, label = '$type', required = true, From e987b888481e3e68f6259e96e7c54af84d168c3c Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Tue, 13 Sep 2016 12:30:05 +0300 Subject: [PATCH 039/151] Make common tests working again --- include/xmpp_codec.hrl | 3 +- src/ejabberd_c2s.erl | 2 +- src/mod_announce.erl | 55 ++-- src/mod_blocking.erl | 44 ++- src/mod_client_state.erl | 2 +- src/mod_mam.erl | 9 +- src/mod_mam_mnesia.erl | 8 +- src/mod_mix.erl | 31 +- src/mod_muc.erl | 10 +- src/mod_offline.erl | 2 +- src/mod_privacy.erl | 14 +- src/mod_pubsub.erl | 38 +-- src/mod_register.erl | 8 +- src/mod_roster.erl | 73 ++--- src/mod_vcard.erl | 2 +- src/mod_vcard_ldap.erl | 8 +- src/mod_vcard_xupdate.erl | 2 +- src/node_flat.erl | 2 +- src/xmpp_codec.erl | 66 ++-- src/xmpp_util.erl | 2 +- test/ejabberd_SUITE.erl | 413 +++++++++++++------------- test/ejabberd_SUITE_data/ejabberd.yml | 3 +- test/suite.erl | 19 +- tools/xmpp_codec.spec | 5 +- 24 files changed, 410 insertions(+), 411 deletions(-) diff --git a/include/xmpp_codec.hrl b/include/xmpp_codec.hrl index 635fcf3cb..845861948 100644 --- a/include/xmpp_codec.hrl +++ b/include/xmpp_codec.hrl @@ -564,7 +564,8 @@ max :: non_neg_integer()}). -type rsm_set() :: #rsm_set{}. --record(mam_fin, {id = <<>> :: binary(), +-record(mam_fin, {xmlns = <<>> :: binary(), + id = <<>> :: binary(), rsm :: #rsm_set{}, stable :: boolean(), complete :: boolean()}). diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index e658536ab..186f7e9a5 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -2663,7 +2663,7 @@ make_resume_id(StateData) -> add_resent_delay_info(_State, #iq{} = El, _Time) -> El; add_resent_delay_info(#state{server = From}, El, Time) -> - xmpp_util:add_delay_info(El, From, Time, <<"Resent">>). + xmpp_util:add_delay_info(El, jid:make(From), Time, <<"Resent">>). %%%---------------------------------------------------------------------- %%% XEP-0352 diff --git a/src/mod_announce.erl b/src/mod_announce.erl index d9209f418..8d2fbebff 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -130,34 +130,37 @@ stop(Host) -> {wait, Proc}. %% Announcing via messages to a custom resource --spec announce(jid(), jid(), stanza()) -> ok. +-spec announce(jid(), jid(), stanza()) -> ok | stop. announce(From, #jid{luser = <<>>} = To, #message{} = Packet) -> Proc = gen_mod:get_module_proc(To#jid.lserver, ?PROCNAME), - case To#jid.lresource of - <<"announce/all">> -> - Proc ! {announce_all, From, To, Packet}; - <<"announce/all-hosts/all">> -> - Proc ! {announce_all_hosts_all, From, To, Packet}; - <<"announce/online">> -> - Proc ! {announce_online, From, To, Packet}; - <<"announce/all-hosts/online">> -> - Proc ! {announce_all_hosts_online, From, To, Packet}; - <<"announce/motd">> -> - Proc ! {announce_motd, From, To, Packet}; - <<"announce/all-hosts/motd">> -> - Proc ! {announce_all_hosts_motd, From, To, Packet}; - <<"announce/motd/update">> -> - Proc ! {announce_motd_update, From, To, Packet}; - <<"announce/all-hosts/motd/update">> -> - Proc ! {announce_all_hosts_motd_update, From, To, Packet}; - <<"announce/motd/delete">> -> - Proc ! {announce_motd_delete, From, To, Packet}; - <<"announce/all-hosts/motd/delete">> -> - Proc ! {announce_all_hosts_motd_delete, From, To, Packet}; - _ -> - ok - end, - ok; + Res = case To#jid.lresource of + <<"announce/all">> -> + Proc ! {announce_all, From, To, Packet}; + <<"announce/all-hosts/all">> -> + Proc ! {announce_all_hosts_all, From, To, Packet}; + <<"announce/online">> -> + Proc ! {announce_online, From, To, Packet}; + <<"announce/all-hosts/online">> -> + Proc ! {announce_all_hosts_online, From, To, Packet}; + <<"announce/motd">> -> + Proc ! {announce_motd, From, To, Packet}; + <<"announce/all-hosts/motd">> -> + Proc ! {announce_all_hosts_motd, From, To, Packet}; + <<"announce/motd/update">> -> + Proc ! {announce_motd_update, From, To, Packet}; + <<"announce/all-hosts/motd/update">> -> + Proc ! {announce_all_hosts_motd_update, From, To, Packet}; + <<"announce/motd/delete">> -> + Proc ! {announce_motd_delete, From, To, Packet}; + <<"announce/all-hosts/motd/delete">> -> + Proc ! {announce_all_hosts_motd_delete, From, To, Packet}; + _ -> + ok + end, + case Res of + ok -> ok; + _ -> stop + end; announce(_From, _To, _Packet) -> ok. diff --git a/src/mod_blocking.erl b/src/mod_blocking.erl index 55e3ca151..b3bbff96e 100644 --- a/src/mod_blocking.erl +++ b/src/mod_blocking.erl @@ -74,39 +74,37 @@ process_iq(IQ) -> -spec process_iq_get({error, stanza_error()} | {result, xmpp_element() | undefined}, iq(), userlist()) -> - {error, stanza_error()} | {result, block_list()}. + {error, stanza_error()} | + {result, xmpp_element() | undefined}. process_iq_get(_, #iq{lang = Lang, from = From, sub_els = [#block_list{}]}, _) -> #jid{luser = LUser, lserver = LServer} = From, - {stop, process_blocklist_get(LUser, LServer, Lang)}; + process_blocklist_get(LUser, LServer, Lang); process_iq_get(Acc, _, _) -> Acc. -spec process_iq_set({error, stanza_error()} | {result, xmpp_element() | undefined} | {result, xmpp_element() | undefined, userlist()}, iq()) -> {error, stanza_error()} | - {result, undefined} | - {result, undefined, userlist()}. -process_iq_set(_, #iq{from = From, lang = Lang, sub_els = [SubEl]}) -> + {result, xmpp_element() | undefined} | + {result, xmpp_element() | undefined, userlist()}. +process_iq_set(Acc, #iq{from = From, lang = Lang, sub_els = [SubEl]}) -> #jid{luser = LUser, lserver = LServer} = From, - Res = case SubEl of - #block{items = []} -> - Txt = <<"No items found in this query">>, - {error, xmpp:err_bad_request(Txt, Lang)}; - #block{items = Items} -> - JIDs = [jid:tolower(Item) || Item <- Items], - process_blocklist_block(LUser, LServer, JIDs, Lang); - #unblock{items = []} -> - process_blocklist_unblock_all(LUser, LServer, Lang); - #unblock{items = Items} -> - JIDs = [jid:tolower(Item) || Item <- Items], - process_blocklist_unblock(LUser, LServer, JIDs, Lang); - _ -> - Txt = <<"Only and are allowed " - "in this request">>, - {error, xmpp:err_bad_request(Txt, Lang)} - end, - {stop, Res}; + case SubEl of + #block{items = []} -> + Txt = <<"No items found in this query">>, + {error, xmpp:err_bad_request(Txt, Lang)}; + #block{items = Items} -> + JIDs = [jid:tolower(Item) || Item <- Items], + process_blocklist_block(LUser, LServer, JIDs, Lang); + #unblock{items = []} -> + process_blocklist_unblock_all(LUser, LServer, Lang); + #unblock{items = Items} -> + JIDs = [jid:tolower(Item) || Item <- Items], + process_blocklist_unblock(LUser, LServer, JIDs, Lang); + _ -> + Acc + end; process_iq_set(Acc, _) -> Acc. -spec list_to_blocklist_jids([listitem()], [ljid()]) -> [ljid()]. diff --git a/src/mod_client_state.erl b/src/mod_client_state.erl index f72f334f3..7f0658eff 100644 --- a/src/mod_client_state.erl +++ b/src/mod_client_state.erl @@ -277,7 +277,7 @@ get_queue(C2SState) -> get_stanzas(Queue, Host) -> lists:map(fun({_Key, Time, Stanza}) -> - xmpp_util:add_delay_info(Stanza, Host, Time, + xmpp_util:add_delay_info(Stanza, jid:make(Host), Time, <<"Client Inactive">>) end, Queue). diff --git a/src/mod_mam.erl b/src/mod_mam.erl index 2529b7389..ea267c1c0 100644 --- a/src/mod_mam.erl +++ b/src/mod_mam.erl @@ -834,6 +834,10 @@ msg_to_el(#archive_msg{timestamp = TS, packet = Pkt1, nick = Nick, peer = Peer}, #forwarded{sub_els = [Pkt2], delay = #delay{stamp = TS, from = jid:make(LServer)}}. +maybe_update_from_to(#xmlel{} = El, JidRequestor, JidArchive, Peer, + {groupchat, _, _} = MsgType, Nick) -> + Pkt = xmpp:decode(El, [ignore_els]), + maybe_update_from_to(Pkt, JidRequestor, JidArchive, Peer, MsgType, Nick); maybe_update_from_to(#message{sub_els = Els} = Pkt, JidRequestor, JidArchive, Peer, {groupchat, Role, #state{config = #config{anonymous = Anon}}}, @@ -908,7 +912,8 @@ send(Msgs, Count, IsComplete, Result = if NS == ?NS_MAM_TMP -> #mam_query{xmlns = NS, id = QID, rsm = RSMOut}; true -> - #mam_fin{id = QID, rsm = RSMOut, complete = IsComplete} + #mam_fin{xmlns = NS, id = QID, rsm = RSMOut, + complete = IsComplete} end, if NS == ?NS_MAM_TMP; NS == ?NS_MAM_1 -> lists:foreach( @@ -950,6 +955,8 @@ limit_max(#rsm_set{max = Max} = RSM, _NS) when Max > ?MAX_PAGE_SIZE -> limit_max(RSM, _NS) -> RSM. +match_interval(Now, Start, undefined) -> + Now >= Start; match_interval(Now, Start, End) -> (Now >= Start) and (Now =< End). diff --git a/src/mod_mam_mnesia.erl b/src/mod_mam_mnesia.erl index cbe7c336c..ecaa4d053 100644 --- a/src/mod_mam_mnesia.erl +++ b/src/mod_mam_mnesia.erl @@ -134,7 +134,10 @@ select(_LServer, JidRequestor, #jid{luser = LUser, lserver = LServer} = JidArchive, #mam_query{start = Start, 'end' = End, with = With, rsm = RSM}, MsgType) -> - MS = make_matchspec(LUser, LServer, Start, End, With), + LWith = if With /= undefined -> jid:tolower(With); + true -> undefined + end, + MS = make_matchspec(LUser, LServer, Start, End, LWith), Msgs = mnesia:dirty_select(archive_msg, MS), SortedMsgs = lists:keysort(#archive_msg.timestamp, Msgs), {FilteredMsgs, IsComplete} = filter_by_rsm(SortedMsgs, RSM), @@ -155,6 +158,9 @@ select(_LServer, JidRequestor, now_to_usec({MSec, Sec, USec}) -> (MSec*1000000 + Sec)*1000000 + USec. +make_matchspec(LUser, LServer, Start, undefined, With) -> + %% List is always greater than a tuple + make_matchspec(LUser, LServer, Start, [], With); make_matchspec(LUser, LServer, Start, End, {_, _, <<>>} = With) -> ets:fun2ms( fun(#archive_msg{timestamp = TS, diff --git a/src/mod_mix.erl b/src/mod_mix.erl index f39408210..7ca09f4db 100644 --- a/src/mod_mix.erl +++ b/src/mod_mix.erl @@ -209,19 +209,18 @@ do_route(_State, _From, _To, _Packet) -> subscribe_nodes(From, To, Nodes) -> LTo = jid:tolower(jid:remove_resource(To)), LFrom = jid:tolower(jid:remove_resource(From)), - From_s = jid:to_string(LFrom), lists:foldl( fun(_Node, {error, _} = Err) -> Err; (Node, {result, _}) -> - case mod_pubsub:subscribe_node(LTo, Node, From, From_s, []) of + case mod_pubsub:subscribe_node(LTo, Node, From, From, []) of {error, _} = Err -> case is_item_not_found(Err) of true -> case mod_pubsub:create_node( LTo, To#jid.lserver, Node, LFrom, <<"mix">>) of {result, _} -> - mod_pubsub:subscribe_node(LTo, Node, From, From_s, []); + mod_pubsub:subscribe_node(LTo, Node, From, From, []); Error -> Error end; @@ -235,13 +234,12 @@ subscribe_nodes(From, To, Nodes) -> unsubscribe_nodes(From, To, Nodes) -> LTo = jid:tolower(jid:remove_resource(To)), - LFrom = jid:tolower(jid:remove_resource(From)), - From_s = jid:to_string(LFrom), + BareFrom = jid:remove_resource(From), lists:foldl( fun(_Node, {error, _} = Err) -> Err; (Node, {result, _} = Result) -> - case mod_pubsub:unsubscribe_node(LTo, Node, From, From_s, <<"">>) of + case mod_pubsub:unsubscribe_node(LTo, Node, From, BareFrom, <<"">>) of {error, _} = Err -> case is_not_subscribed(Err) of true -> Result; @@ -297,19 +295,16 @@ delete_item(From, To, Node, ItemID) -> end end. -is_item_not_found({error, ErrEl}) -> - case fxml:get_subtag_with_xmlns( - ErrEl, <<"item-not-found">>, ?NS_STANZAS) of - #xmlel{} -> true; - _ -> false - end. +-spec is_item_not_found({error, stanza_error()}) -> boolean(). +is_item_not_found({error, #stanza_error{reason = 'item-not-found'}}) -> true; +is_item_not_found({error, _}) -> false. -is_not_subscribed({error, ErrEl}) -> - case fxml:get_subtag_with_xmlns( - ErrEl, <<"not-subscribed">>, ?NS_PUBSUB_ERRORS) of - #xmlel{} -> true; - _ -> false - end. +-spec is_not_subscribed({error, stanza_error()}) -> boolean(). +is_not_subscribed({error, #stanza_error{sub_els = Els}}) -> + %% TODO: make xmpp:get_els function working for any XMPP element + %% with sub_els field + xmpp:has_subtag(#message{sub_els = Els}, + #ps_error{type = 'not-subscribed'}). depends(_Host, _Opts) -> [{mod_pubsub, hard}]. diff --git a/src/mod_muc.erl b/src/mod_muc.erl index 3eca79fec..66604394b 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -668,17 +668,17 @@ get_nick(ServerHost, Host, From) -> Mod:get_nick(LServer, Host, From). iq_get_register_info(ServerHost, Host, From, Lang) -> - {Nick, Registered} = case get_nick(ServerHost, Host, From) of - error -> {<<"">>, false}; - N -> {N, true} - end, + {Nick, NickVals, Registered} = case get_nick(ServerHost, Host, From) of + error -> {<<"">>, [], false}; + N -> {N, [N], true} + end, Title = <<(translate:translate( Lang, <<"Nickname Registration at ">>))/binary, Host/binary>>, Inst = translate:translate(Lang, <<"Enter nickname you want to register">>), Field = #xdata_field{type = 'text-single', label = translate:translate(Lang, <<"Nickname">>), var = <<"nick">>, - values = [Nick]}, + values = NickVals}, X = #xdata{type = form, title = Title, instructions = [Inst], fields = [Field]}, #register{nick = Nick, diff --git a/src/mod_offline.erl b/src/mod_offline.erl index 509406aa4..a2bcec894 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -616,7 +616,7 @@ offline_msg_to_route(LServer, #offline_msg{} = R) -> undefined -> Pkt; TS -> - xmpp_util:add_delay_info(Pkt, LServer, TS, + xmpp_util:add_delay_info(Pkt, jid:make(LServer), TS, <<"Offline Storage">>) end, {route, R#offline_msg.from, R#offline_msg.to, Pkt1}. diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index 3be3f2d3b..2f318deec 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -101,7 +101,8 @@ process_iq(IQ) -> xmpp:make_error(IQ, xmpp:err_not_allowed()). -spec process_iq_get({error, stanza_error()} | {result, xmpp_element() | undefined}, - iq(), userlist()) -> {error, stanza_error()} | {result, privacy_query()}. + iq(), userlist()) -> {error, stanza_error()} | + {result, xmpp_element() | undefined}. process_iq_get(_, #iq{from = From, lang = Lang, sub_els = [#privacy_query{lists = Lists}]}, #userlist{name = Active}) -> @@ -114,7 +115,9 @@ process_iq_get(_, #iq{from = From, lang = Lang, _ -> Txt = <<"Too many elements">>, {error, xmpp:err_bad_request(Txt, Lang)} - end. + end; +process_iq_get(Acc, _, _) -> + Acc. -spec process_lists_get(binary(), binary(), binary(), binary()) -> {error, stanza_error()} | {result, privacy_query()}. @@ -218,7 +221,8 @@ decode_value(Type, Value) -> {result, xmpp_element() | undefined} | {result, xmpp_element() | undefined, userlist()}, iq()) -> {error, stanza_error()} | - {result, undefined, userlist()}. + {result, xmpp_element() | undefined} | + {result, xmpp_element() | undefined, userlist()}. process_iq_set(_, #iq{from = From, lang = Lang, sub_els = [#privacy_query{default = Default, active = Active, @@ -236,7 +240,9 @@ process_iq_set(_, #iq{from = From, lang = Lang, Txt = <<"There should be exactly one element in this query: " ", or ">>, {error, xmpp:err_bad_request(Txt, Lang)} - end. + end; +process_iq_set(Acc, _) -> + Acc. -spec process_default_set(binary(), binary(), none | binary(), binary()) -> {error, stanza_error()} | {result, undefined}. diff --git a/src/mod_pubsub.erl b/src/mod_pubsub.erl index b470d83d9..f7e1a9834 100644 --- a/src/mod_pubsub.erl +++ b/src/mod_pubsub.erl @@ -69,9 +69,7 @@ tree_action/3, node_action/4, node_call/4]). %% general helpers for plugins --export([subscription_to_string/1, affiliation_to_string/1, - string_to_subscription/1, string_to_affiliation/1, - extended_error/2, service_jid/1, +-export([extended_error/2, service_jid/1, tree/1, tree/2, plugin/2, plugins/1, config/3, host/1, serverhost/1]). @@ -2170,7 +2168,7 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIds, RSM) -> get_items(Host, Node) -> Action = fun (#pubsub_node{type = Type, id = Nidx}) -> - node_call(Host, Type, get_items, [Nidx, service_jid(Host), none]) + node_call(Host, Type, get_items, [Nidx, service_jid(Host), undefined]) end, case transaction(Host, Node, Action, sync_dirty) of {result, {_, {Items, _}}} -> Items; @@ -2187,7 +2185,7 @@ get_item(Host, Node, ItemId) -> end. get_allowed_items_call(Host, Nidx, From, Type, Options, Owners) -> - case get_allowed_items_call(Host, Nidx, From, Type, Options, Owners, none) of + case get_allowed_items_call(Host, Nidx, From, Type, Options, Owners, undefined) of {result, {Items, _RSM}} -> {result, Items}; Error -> Error end. @@ -2203,7 +2201,7 @@ get_last_item(Host, Type, Nidx, LJID) -> LastItem -> LastItem end. get_last_item(Host, Type, Nidx, LJID, mnesia) -> - case node_action(Host, Type, get_items, [Nidx, LJID, none]) of + case node_action(Host, Type, get_items, [Nidx, LJID, undefined]) of {result, {[LastItem|_], _}} -> LastItem; _ -> undefined end; @@ -2218,7 +2216,7 @@ get_last_item(_Host, _Type, _Nidx, _LJID, _) -> get_last_items(Host, Type, Nidx, LJID, Number) -> get_last_items(Host, Type, Nidx, LJID, Number, gen_mod:db_type(serverhost(Host), ?MODULE)). get_last_items(Host, Type, Nidx, LJID, Number, mnesia) -> - case node_action(Host, Type, get_items, [Nidx, LJID, none]) of + case node_action(Host, Type, get_items, [Nidx, LJID, undefined]) of {result, {Items, _}} -> lists:sublist(Items, Number); _ -> [] end; @@ -2714,32 +2712,6 @@ get_roster_info(OwnerUser, OwnerServer, {SubscriberUser, SubscriberServer, _}, A get_roster_info(OwnerUser, OwnerServer, JID, AllowedGroups) -> get_roster_info(OwnerUser, OwnerServer, jid:tolower(JID), AllowedGroups). -string_to_affiliation(<<"owner">>) -> owner; -string_to_affiliation(<<"publisher">>) -> publisher; -string_to_affiliation(<<"publish-only">>) -> publish_only; -string_to_affiliation(<<"member">>) -> member; -string_to_affiliation(<<"outcast">>) -> outcast; -string_to_affiliation(<<"none">>) -> none; -string_to_affiliation(_) -> false. - -string_to_subscription(<<"subscribed">>) -> subscribed; -string_to_subscription(<<"pending">>) -> pending; -string_to_subscription(<<"unconfigured">>) -> unconfigured; -string_to_subscription(<<"none">>) -> none; -string_to_subscription(_) -> false. - -affiliation_to_string(owner) -> <<"owner">>; -affiliation_to_string(publisher) -> <<"publisher">>; -affiliation_to_string(publish_only) -> <<"publish-only">>; -affiliation_to_string(member) -> <<"member">>; -affiliation_to_string(outcast) -> <<"outcast">>; -affiliation_to_string(_) -> <<"none">>. - -subscription_to_string(subscribed) -> <<"subscribed">>; -subscription_to_string(pending) -> <<"pending">>; -subscription_to_string(unconfigured) -> <<"unconfigured">>; -subscription_to_string(_) -> <<"none">>. - -spec service_jid(jid() | ljid() | binary()) -> jid(). service_jid(#jid{} = Jid) -> Jid; service_jid({U, S, R}) -> jid:make(U, S, R); diff --git a/src/mod_register.erl b/src/mod_register.erl index 334af4514..44a64539e 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -146,12 +146,10 @@ process_iq(#iq{type = set, lang = Lang, to = To, from = From, end; true -> case From of - #jid{user = User, lserver = Server, resource = Resource} -> + #jid{luser = LUser, lserver = Server} -> ResIQ = xmpp:make_iq_result(IQ), - ejabberd_router:route(jid:make(User, Server, Resource), - jid:make(User, Server, Resource), - ResIQ), - ejabberd_auth:remove_user(User, Server), + ejabberd_router:route(From, From, ResIQ), + ejabberd_auth:remove_user(LUser, Server), ignore; _ -> Txt = <<"The query is only allowed from local users">>, diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 2a41907a4..feebd3945 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -308,13 +308,13 @@ encode_item(Item) -> end, groups = Item#roster.groups}. -decode_item(#roster_item{} = Item, R, Managed) -> +decode_item(Item, R, Managed) -> R#roster{jid = jid:tolower(Item#roster_item.jid), name = Item#roster_item.name, subscription = case Item#roster_item.subscription of remove -> remove; Sub when Managed -> Sub; - _ -> undefined + _ -> R#roster.subscription end, groups = Item#roster_item.groups}. @@ -334,45 +334,48 @@ try_process_iq_set(#iq{from = From, lang = Lang} = IQ) -> end. process_iq_set(#iq{from = From, to = To, id = Id, - sub_els = [#roster_query{items = Items}]} = IQ) -> + sub_els = [#roster_query{items = QueryItems}]} = IQ) -> Managed = is_managed_from_id(Id), - lists:foreach(fun (Item) -> process_item_set(From, To, Item, Managed) - end, - Items), - xmpp:make_iq_result(IQ). - -process_item_set(From, To, #roster_item{jid = JID1} = QueryItem, Managed) -> #jid{user = User, luser = LUser, lserver = LServer} = From, - LJID = jid:tolower(JID1), F = fun () -> - Item = get_roster_by_jid_t(LUser, LServer, LJID), - Item2 = decode_item(QueryItem, Item, Managed), - Item3 = ejabberd_hooks:run_fold(roster_process_item, - LServer, Item2, - [LServer]), - case Item3#roster.subscription of - remove -> del_roster_t(LUser, LServer, LJID); - _ -> update_roster_t(LUser, LServer, LJID, Item3) - end, - send_itemset_to_managers(From, Item3, Managed), - case roster_version_on_db(LServer) of - true -> write_roster_version_t(LUser, LServer); - false -> ok - end, - {Item, Item3} + lists:map( + fun(#roster_item{jid = JID1} = QueryItem) -> + LJID = jid:tolower(JID1), + Item = get_roster_by_jid_t(LUser, LServer, LJID), + Item2 = decode_item(QueryItem, Item, Managed), + Item3 = ejabberd_hooks:run_fold(roster_process_item, + LServer, Item2, + [LServer]), + case Item3#roster.subscription of + remove -> del_roster_t(LUser, LServer, LJID); + _ -> update_roster_t(LUser, LServer, LJID, Item3) + end, + case roster_version_on_db(LServer) of + true -> write_roster_version_t(LUser, LServer); + false -> ok + end, + {Item, Item3} + end, QueryItems) end, case transaction(LServer, F) of - {atomic, {OldItem, Item}} -> - push_item(User, LServer, To, Item), - case Item#roster.subscription of - remove -> - send_unsubscribing_presence(From, OldItem), ok; - _ -> ok - end; + {atomic, ItemPairs} -> + lists:foreach( + fun({OldItem, Item}) -> + send_itemset_to_managers(From, Item, Managed), + push_item(User, LServer, To, Item), + case Item#roster.subscription of + remove -> + send_unsubscribing_presence(From, OldItem); + _ -> + ok + end + end, ItemPairs), + xmpp:make_iq_result(IQ); E -> - ?DEBUG("ROSTER: roster item set error: ~p~n", [E]), ok - end; -process_item_set(_From, _To, _, _Managed) -> ok. + ?ERROR_MSG("roster set failed:~nIQ = ~s~nError = ~p", + [xmpp:pp(IQ), E]), + xmpp:make_error(IQ, xmpp:err_internal_server_error()) + end. push_item(User, Server, From, Item) -> ejabberd_sm:route(jid:make(<<"">>, <<"">>, <<"">>), diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index 1f6edb460..8333d32cf 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -137,7 +137,7 @@ stop(Host) -> ?NS_VCARD), ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 50), - Mod = gen_mod:db_type(Host, ?MODULE), + Mod = gen_mod:db_mod(Host, ?MODULE), Mod:stop(Host), Proc = gen_mod:get_module_proc(Host, ?PROCNAME), Proc ! stop, diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl index 191676224..d8efe30f5 100644 --- a/src/mod_vcard_ldap.erl +++ b/src/mod_vcard_ldap.erl @@ -248,10 +248,10 @@ ldap_attribute_to_vcard({Attr, Value}, V) -> <<"tel">> -> V#vcard_temp{tel = [#vcard_tel{number = Value}|Ts]}; <<"email">> -> V#vcard_temp{email = [#vcard_email{userid = Value}|Es]}; <<"photo">> -> V#vcard_temp{photo = #vcard_photo{binval = Value}}; - <<"family">> -> V#vcard_temp{n = N#vcard_name{family = V}}; - <<"given">> -> V#vcard_temp{n = N#vcard_name{given = V}}; - <<"middle">> -> V#vcard_temp{n = N#vcard_name{middle = V}}; - <<"orgname">> -> V#vcard_temp{org = O#vcard_org{name = V}}; + <<"family">> -> V#vcard_temp{n = N#vcard_name{family = Value}}; + <<"given">> -> V#vcard_temp{n = N#vcard_name{given = Value}}; + <<"middle">> -> V#vcard_temp{n = N#vcard_name{middle = Value}}; + <<"orgname">> -> V#vcard_temp{org = O#vcard_org{name = Value}}; <<"orgunit">> -> V#vcard_temp{org = O#vcard_org{units = [Value]}}; <<"locality">> -> V#vcard_temp{adr = [A#vcard_adr{locality = Value}]}; <<"street">> -> V#vcard_temp{adr = [A#vcard_adr{street = Value}]}; diff --git a/src/mod_vcard_xupdate.erl b/src/mod_vcard_xupdate.erl index 5cc87056e..27688e8fb 100644 --- a/src/mod_vcard_xupdate.erl +++ b/src/mod_vcard_xupdate.erl @@ -52,7 +52,7 @@ depends(_Host, _Opts) -> %% Hooks %%==================================================================== -spec update_presence(presence(), binary(), binary()) -> presence(). -update_presence(#presence{type = undefined} = Packet, User, Host) -> +update_presence(#presence{type = available} = Packet, User, Host) -> presence_with_xupdate(Packet, User, Host); update_presence(Packet, _User, _Host) -> Packet. diff --git a/src/node_flat.erl b/src/node_flat.erl index 2ec9afe54..e80aaad34 100644 --- a/src/node_flat.erl +++ b/src/node_flat.erl @@ -707,7 +707,7 @@ del_state(Nidx, Key) -> %% relational database), or they can even decide not to persist any items.

    get_items(Nidx, _From, _RSM) -> Items = mnesia:match_object(#pubsub_item{itemid = {'_', Nidx}, _ = '_'}), - {result, {lists:reverse(lists:keysort(#pubsub_item.modification, Items)), none}}. + {result, {lists:reverse(lists:keysort(#pubsub_item.modification, Items)), undefined}}. get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId, RSM) -> SubKey = jid:tolower(JID), diff --git a/src/xmpp_codec.erl b/src/xmpp_codec.erl index 8653d591c..00ee53aaf 100644 --- a/src/xmpp_codec.erl +++ b/src/xmpp_codec.erl @@ -286,6 +286,8 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> _el); {<<"fin">>, <<"urn:xmpp:mam:0">>} -> decode_mam_fin(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); + {<<"fin">>, <<"urn:xmpp:mam:1">>} -> + decode_mam_fin(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); {<<"prefs">>, <<"urn:xmpp:mam:0">>} -> decode_mam_prefs(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); {<<"prefs">>, <<"urn:xmpp:mam:1">>} -> @@ -1688,6 +1690,7 @@ is_known_tag({xmlel, _name, _attrs, _} = _el) -> {<<"disable">>, <<"urn:xmpp:carbons:2">>} -> true; {<<"forwarded">>, <<"urn:xmpp:forward:0">>} -> true; {<<"fin">>, <<"urn:xmpp:mam:0">>} -> true; + {<<"fin">>, <<"urn:xmpp:mam:1">>} -> true; {<<"prefs">>, <<"urn:xmpp:mam:0">>} -> true; {<<"prefs">>, <<"urn:xmpp:mam:1">>} -> true; {<<"prefs">>, <<"urn:xmpp:mam:tmp">>} -> true; @@ -2978,9 +2981,8 @@ encode({mam_result, _, _, _, _} = Result) -> encode_mam_result(Result, []); encode({mam_prefs, _, _, _, _} = Prefs) -> encode_mam_prefs(Prefs, []); -encode({mam_fin, _, _, _, _} = Fin) -> - encode_mam_fin(Fin, - [{<<"xmlns">>, <<"urn:xmpp:mam:0">>}]); +encode({mam_fin, _, _, _, _, _} = Fin) -> + encode_mam_fin(Fin, []); encode({forwarded, _, _} = Forwarded) -> encode_forwarded(Forwarded, [{<<"xmlns">>, <<"urn:xmpp:forward:0">>}]); @@ -3196,7 +3198,7 @@ get_name({iq, _, _, _, _, _, _}) -> <<"iq">>; get_name({last, _, _}) -> <<"query">>; get_name({legacy_auth, _, _, _, _}) -> <<"query">>; get_name({mam_archived, _, _}) -> <<"archived">>; -get_name({mam_fin, _, _, _, _}) -> <<"fin">>; +get_name({mam_fin, _, _, _, _, _}) -> <<"fin">>; get_name({mam_prefs, _, _, _, _}) -> <<"prefs">>; get_name({mam_query, _, _, _, _, _, _, _, _}) -> <<"query">>; @@ -3466,7 +3468,7 @@ get_ns({last, _, _}) -> <<"jabber:iq:last">>; get_ns({legacy_auth, _, _, _, _}) -> <<"jabber:iq:auth">>; get_ns({mam_archived, _, _}) -> <<"urn:xmpp:mam:tmp">>; -get_ns({mam_fin, _, _, _, _}) -> <<"urn:xmpp:mam:0">>; +get_ns({mam_fin, Xmlns, _, _, _, _}) -> Xmlns; get_ns({mam_prefs, Xmlns, _, _, _}) -> Xmlns; get_ns({mam_query, Xmlns, _, _, _, _, _, _, _}) -> Xmlns; @@ -3898,7 +3900,7 @@ pp(mam_query, 8) -> pp(mam_archived, 2) -> [by, id]; pp(mam_result, 4) -> [xmlns, queryid, id, sub_els]; pp(mam_prefs, 4) -> [xmlns, default, always, never]; -pp(mam_fin, 4) -> [id, rsm, stable, complete]; +pp(mam_fin, 5) -> [xmlns, id, rsm, stable, complete]; pp(forwarded, 2) -> [delay, sub_els]; pp(carbons_disable, 0) -> []; pp(carbons_enable, 0) -> []; @@ -8600,10 +8602,10 @@ decode_mam_fin(__TopXMLNS, __IgnoreEls, {xmlel, <<"fin">>, _attrs, _els}) -> Rsm = decode_mam_fin_els(__TopXMLNS, __IgnoreEls, _els, undefined), - {Id, Stable, Complete} = + {Id, Xmlns, Stable, Complete} = decode_mam_fin_attrs(__TopXMLNS, _attrs, undefined, - undefined, undefined), - {mam_fin, Id, Rsm, Stable, Complete}. + undefined, undefined, undefined), + {mam_fin, Xmlns, Id, Rsm, Stable, Complete}. decode_mam_fin_els(__TopXMLNS, __IgnoreEls, [], Rsm) -> Rsm; @@ -8622,37 +8624,45 @@ decode_mam_fin_els(__TopXMLNS, __IgnoreEls, [_ | _els], decode_mam_fin_els(__TopXMLNS, __IgnoreEls, _els, Rsm). decode_mam_fin_attrs(__TopXMLNS, - [{<<"queryid">>, _val} | _attrs], _Id, Stable, + [{<<"queryid">>, _val} | _attrs], _Id, Xmlns, Stable, Complete) -> - decode_mam_fin_attrs(__TopXMLNS, _attrs, _val, Stable, - Complete); + decode_mam_fin_attrs(__TopXMLNS, _attrs, _val, Xmlns, + Stable, Complete); decode_mam_fin_attrs(__TopXMLNS, - [{<<"stable">>, _val} | _attrs], Id, _Stable, + [{<<"xmlns">>, _val} | _attrs], Id, _Xmlns, Stable, Complete) -> decode_mam_fin_attrs(__TopXMLNS, _attrs, Id, _val, - Complete); + Stable, Complete); decode_mam_fin_attrs(__TopXMLNS, - [{<<"complete">>, _val} | _attrs], Id, Stable, + [{<<"stable">>, _val} | _attrs], Id, Xmlns, _Stable, + Complete) -> + decode_mam_fin_attrs(__TopXMLNS, _attrs, Id, Xmlns, + _val, Complete); +decode_mam_fin_attrs(__TopXMLNS, + [{<<"complete">>, _val} | _attrs], Id, Xmlns, Stable, _Complete) -> - decode_mam_fin_attrs(__TopXMLNS, _attrs, Id, Stable, - _val); + decode_mam_fin_attrs(__TopXMLNS, _attrs, Id, Xmlns, + Stable, _val); decode_mam_fin_attrs(__TopXMLNS, [_ | _attrs], Id, - Stable, Complete) -> - decode_mam_fin_attrs(__TopXMLNS, _attrs, Id, Stable, - Complete); -decode_mam_fin_attrs(__TopXMLNS, [], Id, Stable, + Xmlns, Stable, Complete) -> + decode_mam_fin_attrs(__TopXMLNS, _attrs, Id, Xmlns, + Stable, Complete); +decode_mam_fin_attrs(__TopXMLNS, [], Id, Xmlns, Stable, Complete) -> {decode_mam_fin_attr_queryid(__TopXMLNS, Id), + decode_mam_fin_attr_xmlns(__TopXMLNS, Xmlns), decode_mam_fin_attr_stable(__TopXMLNS, Stable), decode_mam_fin_attr_complete(__TopXMLNS, Complete)}. -encode_mam_fin({mam_fin, Id, Rsm, Stable, Complete}, +encode_mam_fin({mam_fin, Xmlns, Id, Rsm, Stable, + Complete}, _xmlns_attrs) -> _els = lists:reverse('encode_mam_fin_$rsm'(Rsm, [])), _attrs = encode_mam_fin_attr_complete(Complete, encode_mam_fin_attr_stable(Stable, - encode_mam_fin_attr_queryid(Id, - _xmlns_attrs))), + encode_mam_fin_attr_xmlns(Xmlns, + encode_mam_fin_attr_queryid(Id, + _xmlns_attrs)))), {xmlel, <<"fin">>, _attrs, _els}. 'encode_mam_fin_$rsm'(undefined, _acc) -> _acc; @@ -8669,6 +8679,14 @@ encode_mam_fin_attr_queryid(<<>>, _acc) -> _acc; encode_mam_fin_attr_queryid(_val, _acc) -> [{<<"queryid">>, _val} | _acc]. +decode_mam_fin_attr_xmlns(__TopXMLNS, undefined) -> + <<>>; +decode_mam_fin_attr_xmlns(__TopXMLNS, _val) -> _val. + +encode_mam_fin_attr_xmlns(<<>>, _acc) -> _acc; +encode_mam_fin_attr_xmlns(_val, _acc) -> + [{<<"xmlns">>, _val} | _acc]. + decode_mam_fin_attr_stable(__TopXMLNS, undefined) -> undefined; decode_mam_fin_attr_stable(__TopXMLNS, _val) -> diff --git a/src/xmpp_util.erl b/src/xmpp_util.erl index 20231fffa..43178e86f 100644 --- a/src/xmpp_util.erl +++ b/src/xmpp_util.erl @@ -68,7 +68,7 @@ unwrap_carbon(Stanza) -> Stanza. -spec is_standalone_chat_state(stanza()) -> boolean(). is_standalone_chat_state(Stanza) -> case unwrap_carbon(Stanza) of - #message{sub_els = Els} -> + #message{body = [], subject = [], sub_els = Els} -> IgnoreNS = [?NS_CHATSTATES, ?NS_DELAY], Stripped = [El || El <- Els, not lists:member(xmpp:get_ns(El), IgnoreNS)], diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index d3e7ec668..fbaee781f 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -25,7 +25,7 @@ -include("suite.hrl"). suite() -> - [{timetrap, {seconds,120}}]. + [{timetrap, {seconds,10}}]. init_per_suite(Config) -> NewConfig = init_config(Config), @@ -432,8 +432,8 @@ test_register(Config) -> register(Config) -> #iq{type = result, - sub_els = [#register{username = none, - password = none}]} = + sub_els = [#register{username = <<>>, + password = <<>>}]} = send_recv(Config, #iq{type = get, to = server_jid(Config), sub_els = [#register{}]}), #iq{type = result, sub_els = []} = @@ -492,31 +492,31 @@ test_open_session(Config) -> disconnect(open_session(Config)). roster_get(Config) -> - #iq{type = result, sub_els = [#roster{items = []}]} = - send_recv(Config, #iq{type = get, sub_els = [#roster{}]}), + #iq{type = result, sub_els = [#roster_query{items = []}]} = + send_recv(Config, #iq{type = get, sub_els = [#roster_query{}]}), disconnect(Config). roster_ver(Config) -> %% Get initial "ver" - #iq{type = result, sub_els = [#roster{ver = Ver1, items = []}]} = + #iq{type = result, sub_els = [#roster_query{ver = Ver1, items = []}]} = send_recv(Config, #iq{type = get, - sub_els = [#roster{ver = <<"">>}]}), + sub_els = [#roster_query{ver = <<"">>}]}), %% Should receive empty IQ-result #iq{type = result, sub_els = []} = send_recv(Config, #iq{type = get, - sub_els = [#roster{ver = Ver1}]}), + sub_els = [#roster_query{ver = Ver1}]}), %% Attempting to subscribe to server's JID send(Config, #presence{type = subscribe, to = server_jid(Config)}), %% Receive a single roster push with the new "ver" - ?recv1(#iq{type = set, sub_els = [#roster{ver = Ver2}]}), + ?recv1(#iq{type = set, sub_els = [#roster_query{ver = Ver2}]}), %% Requesting roster with the previous "ver". Should receive Ver2 again - #iq{type = result, sub_els = [#roster{ver = Ver2}]} = + #iq{type = result, sub_els = [#roster_query{ver = Ver2}]} = send_recv(Config, #iq{type = get, - sub_els = [#roster{ver = Ver1}]}), + sub_els = [#roster_query{ver = Ver1}]}), %% Now requesting roster with the newest "ver". Should receive empty IQ. #iq{type = result, sub_els = []} = send_recv(Config, #iq{type = get, - sub_els = [#roster{ver = Ver2}]}), + sub_els = [#roster_query{ver = Ver2}]}), disconnect(Config). presence(Config) -> @@ -539,7 +539,7 @@ presence_broadcast(Config) -> lang = <<"en">>, name = <<"ejabberd_ct">>}], node = Node, features = [Feature]}, - Caps = #caps{hash = <<"sha-1">>, node = ?EJABBERD_CT_URI, ver = Ver}, + Caps = #caps{hash = <<"sha-1">>, node = ?EJABBERD_CT_URI, version = B64Ver}, send(Config, #presence{sub_els = [Caps]}), JID = my_jid(Config), %% We receive: @@ -559,10 +559,7 @@ presence_broadcast(Config) -> lists:foldl( fun(Time, []) -> timer:sleep(Time), - mod_caps:get_features( - Server, - mod_caps:read_caps( - [xmpp_codec:encode(Caps)])); + mod_caps:get_features(Server, Caps); (_, Acc) -> Acc end, [], [0, 100, 200, 2000, 5000, 10000]), @@ -692,12 +689,12 @@ last(Config) -> privacy(Config) -> true = is_feature_advertised(Config, ?NS_PRIVACY), - #iq{type = result, sub_els = [#privacy{}]} = - send_recv(Config, #iq{type = get, sub_els = [#privacy{}]}), + #iq{type = result, sub_els = [#privacy_query{}]} = + send_recv(Config, #iq{type = get, sub_els = [#privacy_query{}]}), JID = <<"tybalt@example.com">>, I1 = send(Config, #iq{type = set, - sub_els = [#privacy{ + sub_els = [#privacy_query{ lists = [#privacy_list{ name = <<"public">>, items = @@ -705,41 +702,41 @@ privacy(Config) -> type = jid, order = 3, action = deny, - kinds = ['presence-in'], + presence_in = true, value = JID}]}]}]}), {Push1, _} = ?recv2( #iq{type = set, - sub_els = [#privacy{ + sub_els = [#privacy_query{ lists = [#privacy_list{ name = <<"public">>}]}]}, #iq{type = result, id = I1, sub_els = []}), send(Config, make_iq_result(Push1)), #iq{type = result, sub_els = []} = send_recv(Config, #iq{type = set, - sub_els = [#privacy{active = <<"public">>}]}), + sub_els = [#privacy_query{active = <<"public">>}]}), #iq{type = result, sub_els = []} = send_recv(Config, #iq{type = set, - sub_els = [#privacy{default = <<"public">>}]}), + sub_els = [#privacy_query{default = <<"public">>}]}), #iq{type = result, - sub_els = [#privacy{default = <<"public">>, + sub_els = [#privacy_query{default = <<"public">>, active = <<"public">>, lists = [#privacy_list{name = <<"public">>}]}]} = - send_recv(Config, #iq{type = get, sub_els = [#privacy{}]}), + send_recv(Config, #iq{type = get, sub_els = [#privacy_query{}]}), #iq{type = result, sub_els = []} = send_recv(Config, - #iq{type = set, sub_els = [#privacy{default = none}]}), + #iq{type = set, sub_els = [#privacy_query{default = none}]}), #iq{type = result, sub_els = []} = - send_recv(Config, #iq{type = set, sub_els = [#privacy{active = none}]}), + send_recv(Config, #iq{type = set, sub_els = [#privacy_query{active = none}]}), I2 = send(Config, #iq{type = set, - sub_els = [#privacy{ + sub_els = [#privacy_query{ lists = [#privacy_list{ name = <<"public">>}]}]}), {Push2, _} = ?recv2( #iq{type = set, - sub_els = [#privacy{ + sub_els = [#privacy_query{ lists = [#privacy_list{ name = <<"public">>}]}]}, #iq{type = result, id = I2, sub_els = []}), @@ -756,7 +753,7 @@ blocking(Config) -> {Push1, Push2, _} = ?recv3( #iq{type = set, - sub_els = [#privacy{lists = [#privacy_list{}]}]}, + sub_els = [#privacy_query{lists = [#privacy_list{}]}]}, #iq{type = set, sub_els = [#block{items = [JID]}]}, #iq{type = result, id = I1, sub_els = []}), @@ -767,7 +764,7 @@ blocking(Config) -> {Push3, Push4, _} = ?recv3( #iq{type = set, - sub_els = [#privacy{lists = [#privacy_list{}]}]}, + sub_els = [#privacy_query{lists = [#privacy_list{}]}]}, #iq{type = set, sub_els = [#unblock{items = [JID]}]}, #iq{type = result, id = I2, sub_els = []}), @@ -778,7 +775,7 @@ blocking(Config) -> vcard(Config) -> true = is_feature_advertised(Config, ?NS_VCARD), VCard = - #vcard{fn = <<"Peter Saint-Andre">>, + #vcard_temp{fn = <<"Peter Saint-Andre">>, n = #vcard_name{family = <<"Saint-Andre">>, given = <<"Peter">>}, nickname = <<"stpeter">>, @@ -811,21 +808,21 @@ vcard(Config) -> send_recv(Config, #iq{type = set, sub_els = [VCard]}), %% TODO: check if VCard == VCard1. #iq{type = result, sub_els = [_VCard1]} = - send_recv(Config, #iq{type = get, sub_els = [#vcard{}]}), + send_recv(Config, #iq{type = get, sub_els = [#vcard_temp{}]}), disconnect(Config). vcard_get(Config) -> true = is_feature_advertised(Config, ?NS_VCARD), %% TODO: check if VCard corresponds to LDIF data from ejabberd.ldif #iq{type = result, sub_els = [_VCard]} = - send_recv(Config, #iq{type = get, sub_els = [#vcard{}]}), + send_recv(Config, #iq{type = get, sub_els = [#vcard_temp{}]}), disconnect(Config). ldap_shared_roster_get(Config) -> Item = #roster_item{jid = jid:from_string(<<"user2@ldap.localhost">>), name = <<"Test User 2">>, groups = [<<"group1">>], subscription = both}, - #iq{type = result, sub_els = [#roster{items = [Item]}]} = - send_recv(Config, #iq{type = get, sub_els = [#roster{}]}), + #iq{type = result, sub_els = [#roster_query{items = [Item]}]} = + send_recv(Config, #iq{type = get, sub_els = [#roster_query{}]}), disconnect(Config). vcard_xupdate_master(Config) -> @@ -835,17 +832,17 @@ vcard_xupdate_master(Config) -> Peer = ?config(slave, Config), wait_for_slave(Config), send(Config, #presence{}), - ?recv2(#presence{from = MyJID, type = undefined}, - #presence{from = Peer, type = undefined}), - VCard = #vcard{photo = #vcard_photo{type = <<"image/png">>, binval = Img}}, + ?recv2(#presence{from = MyJID, type = available}, + #presence{from = Peer, type = available}), + VCard = #vcard_temp{photo = #vcard_photo{type = <<"image/png">>, binval = Img}}, I1 = send(Config, #iq{type = set, sub_els = [VCard]}), ?recv2(#iq{type = result, sub_els = [], id = I1}, - #presence{from = MyJID, type = undefined, - sub_els = [#vcard_xupdate{photo = ImgHash}]}), - I2 = send(Config, #iq{type = set, sub_els = [#vcard{}]}), + #presence{from = MyJID, type = available, + sub_els = [#vcard_xupdate{hash = ImgHash}]}), + I2 = send(Config, #iq{type = set, sub_els = [#vcard_temp{}]}), ?recv3(#iq{type = result, sub_els = [], id = I2}, - #presence{from = MyJID, type = undefined, - sub_els = [#vcard_xupdate{photo = undefined}]}, + #presence{from = MyJID, type = available, + sub_els = [#vcard_xupdate{hash = undefined}]}, #presence{from = Peer, type = unavailable}), disconnect(Config). @@ -855,24 +852,24 @@ vcard_xupdate_slave(Config) -> MyJID = my_jid(Config), Peer = ?config(master, Config), send(Config, #presence{}), - ?recv1(#presence{from = MyJID, type = undefined}), + ?recv1(#presence{from = MyJID, type = available}), wait_for_master(Config), - ?recv1(#presence{from = Peer, type = undefined}), - ?recv1(#presence{from = Peer, type = undefined, - sub_els = [#vcard_xupdate{photo = ImgHash}]}), - ?recv1(#presence{from = Peer, type = undefined, - sub_els = [#vcard_xupdate{photo = undefined}]}), + ?recv1(#presence{from = Peer, type = available}), + ?recv1(#presence{from = Peer, type = available, + sub_els = [#vcard_xupdate{hash = ImgHash}]}), + ?recv1(#presence{from = Peer, type = available, + sub_els = [#vcard_xupdate{hash = undefined}]}), disconnect(Config). stats(Config) -> - #iq{type = result, sub_els = [#stats{stat = Stats}]} = + #iq{type = result, sub_els = [#stats{list = Stats}]} = send_recv(Config, #iq{type = get, sub_els = [#stats{}], to = server_jid(Config)}), lists:foreach( fun(#stat{} = Stat) -> #iq{type = result, sub_els = [_|_]} = send_recv(Config, #iq{type = get, - sub_els = [#stats{stat = [Stat]}], + sub_els = [#stats{list = [Stat]}], to = server_jid(Config)}) end, Stats), disconnect(Config). @@ -883,68 +880,68 @@ pubsub(Config) -> %% Publish element within node "presence" ItemID = randoms:get_string(), Node = <<"presence!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>, - Item = #pubsub_item{id = ItemID, + Item = #ps_item{id = ItemID, xml_els = [xmpp_codec:encode(#presence{})]}, #iq{type = result, - sub_els = [#pubsub{publish = #pubsub_publish{ + sub_els = [#pubsub{publish = #ps_publish{ node = Node, - items = [#pubsub_item{id = ItemID}]}}]} = + items = [#ps_item{id = ItemID}]}}]} = send_recv(Config, #iq{type = set, to = pubsub_jid(Config), - sub_els = [#pubsub{publish = #pubsub_publish{ + sub_els = [#pubsub{publish = #ps_publish{ node = Node, items = [Item]}}]}), %% Subscribe to node "presence" I1 = send(Config, #iq{type = set, to = pubsub_jid(Config), - sub_els = [#pubsub{subscribe = #pubsub_subscribe{ + sub_els = [#pubsub{subscribe = #ps_subscribe{ node = Node, jid = my_jid(Config)}}]}), ?recv2( - #message{sub_els = [#pubsub_event{}, #delay{}]}, + #message{sub_els = [#ps_event{}, #delay{}]}, #iq{type = result, id = I1}), %% Get subscriptions true = lists:member(?PUBSUB("retrieve-subscriptions"), Features), #iq{type = result, sub_els = [#pubsub{subscriptions = - {none, [#pubsub_subscription{node = Node}]}}]} = + {<<>>, [#ps_subscription{node = Node}]}}]} = send_recv(Config, #iq{type = get, to = pubsub_jid(Config), - sub_els = [#pubsub{subscriptions = {none, []}}]}), + sub_els = [#pubsub{subscriptions = {<<>>, []}}]}), %% Get affiliations true = lists:member(?PUBSUB("retrieve-affiliations"), Features), #iq{type = result, sub_els = [#pubsub{ affiliations = - [#pubsub_affiliation{node = Node, type = owner}]}]} = + {<<>>, [#ps_affiliation{node = Node, type = owner}]}}]} = send_recv(Config, #iq{type = get, to = pubsub_jid(Config), - sub_els = [#pubsub{affiliations = []}]}), + sub_els = [#pubsub{affiliations = {<<>>, []}}]}), %% Fetching published items from node "presence" #iq{type = result, - sub_els = [#pubsub{items = #pubsub_items{ + sub_els = [#pubsub{items = #ps_items{ node = Node, items = [Item]}}]} = send_recv(Config, #iq{type = get, to = pubsub_jid(Config), - sub_els = [#pubsub{items = #pubsub_items{node = Node}}]}), + sub_els = [#pubsub{items = #ps_items{node = Node}}]}), %% Deleting the item from the node true = lists:member(?PUBSUB("delete-items"), Features), I2 = send(Config, #iq{type = set, to = pubsub_jid(Config), - sub_els = [#pubsub{retract = #pubsub_retract{ + sub_els = [#pubsub{retract = #ps_retract{ node = Node, - items = [#pubsub_item{id = ItemID}]}}]}), + items = [#ps_item{id = ItemID}]}}]}), ?recv2( #iq{type = result, id = I2, sub_els = []}, - #message{sub_els = [#pubsub_event{ - items = [#pubsub_event_items{ - node = Node, - retract = [ItemID]}]}]}), + #message{sub_els = [#ps_event{ + items = #ps_items{ + node = Node, + retract = ItemID}}]}), %% Unsubscribe from node "presence" #iq{type = result, sub_els = []} = send_recv(Config, #iq{type = set, to = pubsub_jid(Config), - sub_els = [#pubsub{unsubscribe = #pubsub_unsubscribe{ + sub_els = [#pubsub{unsubscribe = #ps_unsubscribe{ node = Node, jid = my_jid(Config)}}]}), disconnect(Config). @@ -974,12 +971,12 @@ mix_master(Config) -> I0 = send(Config, #iq{type = set, to = Room, sub_els = [#mix_join{subscribe = Nodes}]}), {_, #message{sub_els = - [#pubsub_event{ - items = [#pubsub_event_items{ - node = ?NS_MIX_NODES_PARTICIPANTS, - items = [#pubsub_event_item{ - id = ParticipantID, - xml_els = [PXML]}]}]}]}} = + [#ps_event{ + items = #ps_items{ + node = ?NS_MIX_NODES_PARTICIPANTS, + items = [#ps_item{ + id = ParticipantID, + xml_els = [PXML]}]}}]}} = ?recv2(#iq{type = result, id = I0, sub_els = [#mix_join{subscribe = Nodes, jid = MyBareJID}]}, #message{from = Room}), @@ -992,42 +989,42 @@ mix_master(Config) -> #iq{type = set, to = Room, sub_els = [#pubsub{ - publish = #pubsub_publish{ + publish = #ps_publish{ node = ?NS_MIX_NODES_PRESENCE, - items = [#pubsub_item{ + items = [#ps_item{ id = PresenceID, xml_els = [Presence]}]}}]}), ?recv2(#iq{type = result, id = I1, sub_els = [#pubsub{ - publish = #pubsub_publish{ + publish = #ps_publish{ node = ?NS_MIX_NODES_PRESENCE, - items = [#pubsub_item{id = PresenceID}]}}]}, + items = [#ps_item{id = PresenceID}]}}]}, #message{from = Room, sub_els = - [#pubsub_event{ - items = [#pubsub_event_items{ - node = ?NS_MIX_NODES_PRESENCE, - items = [#pubsub_event_item{ + [#ps_event{ + items = #ps_items{ + node = ?NS_MIX_NODES_PRESENCE, + items = [#ps_item{ id = PresenceID, - xml_els = [Presence]}]}]}]}), + xml_els = [Presence]}]}}]}), %% Coming offline send(Config, #presence{type = unavailable, to = Room}), %% Receiving presence retract event #message{from = Room, - sub_els = [#pubsub_event{ - items = [#pubsub_event_items{ - node = ?NS_MIX_NODES_PRESENCE, - retract = [PresenceID]}]}]} = recv(), + sub_els = [#ps_event{ + items = #ps_items{ + node = ?NS_MIX_NODES_PRESENCE, + retract = PresenceID}}]} = recv(), %% Leaving I2 = send(Config, #iq{type = set, to = Room, sub_els = [#mix_leave{}]}), ?recv2(#iq{type = result, id = I2, sub_els = []}, #message{from = Room, sub_els = - [#pubsub_event{ - items = [#pubsub_event_items{ - node = ?NS_MIX_NODES_PARTICIPANTS, - retract = [ParticipantID]}]}]}), + [#ps_event{ + items = #ps_items{ + node = ?NS_MIX_NODES_PARTICIPANTS, + retract = ParticipantID}}]}), disconnect(Config). mix_slave(Config) -> @@ -1041,45 +1038,45 @@ roster_subscribe_master(Config) -> LPeer = jid:remove_resource(Peer), send(Config, #presence{type = subscribe, to = LPeer}), Push1 = ?recv1(#iq{type = set, - sub_els = [#roster{items = [#roster_item{ + sub_els = [#roster_query{items = [#roster_item{ ask = subscribe, subscription = none, jid = LPeer}]}]}), send(Config, make_iq_result(Push1)), {Push2, _} = ?recv2( #iq{type = set, - sub_els = [#roster{items = [#roster_item{ + sub_els = [#roster_query{items = [#roster_item{ subscription = to, jid = LPeer}]}]}, #presence{type = subscribed, from = LPeer}), send(Config, make_iq_result(Push2)), - ?recv1(#presence{type = undefined, from = Peer}), + ?recv1(#presence{type = available, from = Peer}), %% BUG: ejabberd sends previous push again. Is it ok? Push3 = ?recv1(#iq{type = set, - sub_els = [#roster{items = [#roster_item{ + sub_els = [#roster_query{items = [#roster_item{ subscription = to, jid = LPeer}]}]}), send(Config, make_iq_result(Push3)), ?recv1(#presence{type = subscribe, from = LPeer}), send(Config, #presence{type = subscribed, to = LPeer}), Push4 = ?recv1(#iq{type = set, - sub_els = [#roster{items = [#roster_item{ + sub_els = [#roster_query{items = [#roster_item{ subscription = both, jid = LPeer}]}]}), send(Config, make_iq_result(Push4)), %% Move into a group Groups = [<<"A">>, <<"B">>], Item = #roster_item{jid = LPeer, groups = Groups}, - I1 = send(Config, #iq{type = set, sub_els = [#roster{items = [Item]}]}), + I1 = send(Config, #iq{type = set, sub_els = [#roster_query{items = [Item]}]}), {Push5, _} = ?recv2( #iq{type = set, sub_els = - [#roster{items = [#roster_item{ + [#roster_query{items = [#roster_item{ jid = LPeer, subscription = both}]}]}, #iq{type = result, id = I1, sub_els = []}), send(Config, make_iq_result(Push5)), - #iq{sub_els = [#roster{items = [#roster_item{groups = G1}]}]} = Push5, + #iq{sub_els = [#roster_query{items = [#roster_item{groups = G1}]}]} = Push5, Groups = lists:sort(G1), wait_for_slave(Config), ?recv1(#presence{type = unavailable, from = Peer}), @@ -1094,25 +1091,25 @@ roster_subscribe_slave(Config) -> ?recv1(#presence{type = subscribe, from = LPeer}), send(Config, #presence{type = subscribed, to = LPeer}), Push1 = ?recv1(#iq{type = set, - sub_els = [#roster{items = [#roster_item{ + sub_els = [#roster_query{items = [#roster_item{ subscription = from, jid = LPeer}]}]}), send(Config, make_iq_result(Push1)), send(Config, #presence{type = subscribe, to = LPeer}), Push2 = ?recv1(#iq{type = set, - sub_els = [#roster{items = [#roster_item{ + sub_els = [#roster_query{items = [#roster_item{ ask = subscribe, subscription = from, jid = LPeer}]}]}), send(Config, make_iq_result(Push2)), {Push3, _} = ?recv2( #iq{type = set, - sub_els = [#roster{items = [#roster_item{ + sub_els = [#roster_query{items = [#roster_item{ subscription = both, jid = LPeer}]}]}, #presence{type = subscribed, from = LPeer}), send(Config, make_iq_result(Push3)), - ?recv1(#presence{type = undefined, from = Peer}), + ?recv1(#presence{type = available, from = Peer}), wait_for_master(Config), disconnect(Config). @@ -1123,8 +1120,8 @@ roster_remove_master(Config) -> Groups = [<<"A">>, <<"B">>], wait_for_slave(Config), send(Config, #presence{}), - ?recv2(#presence{from = MyJID, type = undefined}, - #presence{from = Peer, type = undefined}), + ?recv2(#presence{from = MyJID, type = available}, + #presence{from = Peer, type = available}), %% The peer removed us from its roster. {Push1, Push2, _, _, _} = ?recv5( @@ -1132,12 +1129,12 @@ roster_remove_master(Config) -> %% to send transient roster push with subscription = 'to'. #iq{type = set, sub_els = - [#roster{items = [#roster_item{ + [#roster_query{items = [#roster_item{ jid = LPeer, subscription = to}]}]}, #iq{type = set, sub_els = - [#roster{items = [#roster_item{ + [#roster_query{items = [#roster_item{ jid = LPeer, subscription = none}]}]}, #presence{type = unsubscribe, from = LPeer}, @@ -1145,8 +1142,8 @@ roster_remove_master(Config) -> #presence{type = unavailable, from = Peer}), send(Config, make_iq_result(Push1)), send(Config, make_iq_result(Push2)), - #iq{sub_els = [#roster{items = [#roster_item{groups = G1}]}]} = Push1, - #iq{sub_els = [#roster{items = [#roster_item{groups = G2}]}]} = Push2, + #iq{sub_els = [#roster_query{items = [#roster_item{groups = G1}]}]} = Push1, + #iq{sub_els = [#roster_query{items = [#roster_item{groups = G2}]}]} = Push2, Groups = lists:sort(G1), Groups = lists:sort(G2), disconnect(Config). @@ -1155,16 +1152,16 @@ roster_remove_slave(Config) -> Peer = ?config(master, Config), LPeer = jid:remove_resource(Peer), send(Config, #presence{}), - ?recv1(#presence{from = MyJID, type = undefined}), + ?recv1(#presence{from = MyJID, type = available}), wait_for_master(Config), - ?recv1(#presence{from = Peer, type = undefined}), + ?recv1(#presence{from = Peer, type = available}), %% Remove the peer from roster. Item = #roster_item{jid = LPeer, subscription = remove}, - I = send(Config, #iq{type = set, sub_els = [#roster{items = [Item]}]}), + I = send(Config, #iq{type = set, sub_els = [#roster_query{items = [Item]}]}), {Push, _, _} = ?recv3( #iq{type = set, sub_els = - [#roster{items = [#roster_item{ + [#roster_query{items = [#roster_item{ jid = LPeer, subscription = remove}]}]}, #iq{type = result, id = I, sub_els = []}, @@ -1178,7 +1175,7 @@ proxy65_master(Config) -> Peer = ?config(slave, Config), wait_for_slave(Config), send(Config, #presence{}), - ?recv1(#presence{from = MyJID, type = undefined}), + ?recv1(#presence{from = MyJID, type = available}), true = is_feature_advertised(Config, ?NS_BYTESTREAMS, Proxy), #iq{type = result, sub_els = [#bytestreams{hosts = [StreamHost]}]} = send_recv( @@ -1201,7 +1198,7 @@ proxy65_slave(Config) -> MyJID = my_jid(Config), Peer = ?config(master, Config), send(Config, #presence{}), - ?recv1(#presence{from = MyJID, type = undefined}), + ?recv1(#presence{from = MyJID, type = available}), wait_for_master(Config), {StreamHost, SID, Data} = get_event(Config), Socks5 = socks5_connect(StreamHost, {SID, Peer, MyJID}), @@ -1228,6 +1225,7 @@ retrieve_messages_from_room_via_mam(Config, Range) -> Room = muc_room_jid(Config), MyNickJID = jid:replace_resource(Room, MyNick), QID = randoms:get_string(), + Count = length(Range), I = send(Config, #iq{type = set, to = Room, sub_els = [#mam_query{xmlns = ?NS_MAM_1, id = QID}]}), lists:foreach( @@ -1247,7 +1245,11 @@ retrieve_messages_from_room_via_mam(Config, Range) -> type = groupchat, body = [Text]}]}]}]}) end, Range), - ?recv1(#iq{from = Room, id = I, type = result, sub_els = []}). + ?recv1(#iq{from = Room, id = I, type = result, + sub_els = [#mam_fin{xmlns = ?NS_MAM_1, + id = QID, + rsm = #rsm_set{count = Count}, + complete = true}]}). muc_mam_master(Config) -> MyJID = my_jid(Config), @@ -1318,14 +1320,12 @@ muc_master(Config) -> %% 4. The room subject %% 5. Live messages, presence updates, new user joins, etc. %% As this is the newly created room, we receive only the 2nd stanza. - ?recv1(#presence{ - from = MyNickJID, - sub_els = [#vcard_xupdate{}, - #muc_user{ - status_codes = Codes, - items = [#muc_item{role = moderator, - jid = MyJID, - affiliation = owner}]}]}), + #muc_user{ + status_codes = Codes, + items = [#muc_item{role = moderator, + jid = MyJID, + affiliation = owner}]} = + xmpp:get_subtag(?recv1(#presence{from = MyNickJID}), #muc_user{}), %% 110 -> Inform user that presence refers to itself %% 201 -> Inform user that a new room has been created [110, 201] = lists:sort(Codes), @@ -1389,13 +1389,11 @@ muc_master(Config) -> [#muc_user{ invites = [#muc_invite{to = PeerJID}]}]}), - %% Peer is joining - ?recv1(#presence{from = PeerNickJID, - sub_els = [#vcard_xupdate{}, - #muc_user{ - items = [#muc_item{role = visitor, - jid = PeerJID, - affiliation = none}]}]}), + #muc_user{ + items = [#muc_item{role = visitor, + jid = PeerJID, + affiliation = none}]} = + xmpp:get_subtag(?recv1(#presence{from = PeerNickJID}), #muc_user{}), %% Receiving a voice request ?recv1(#message{from = Room, sub_els = [#xdata{type = form, @@ -1424,12 +1422,10 @@ muc_master(Config) -> sub_els = [#xdata{type = submit, fields = ReplyVoiceReqFs}]}), %% Peer is becoming a participant - ?recv1(#presence{from = PeerNickJID, - sub_els = [#vcard_xupdate{}, - #muc_user{ - items = [#muc_item{role = participant, - jid = PeerJID, - affiliation = none}]}]}), + #muc_user{items = [#muc_item{role = participant, + jid = PeerJID, + affiliation = none}]} = + xmpp:get_subtag(?recv1(#presence{from = PeerNickJID}), #muc_user{}), %% Receive private message from the peer ?recv1(#message{from = PeerNickJID, body = [#text{data = Subject}]}), %% Granting membership to the peer and localhost server @@ -1443,19 +1439,16 @@ muc_master(Config) -> jid = PeerBareJID, affiliation = member}]}]}), %% Peer became a member - ?recv1(#presence{from = PeerNickJID, - sub_els = [#vcard_xupdate{}, - #muc_user{ - items = [#muc_item{affiliation = member, - jid = PeerJID, - role = participant}]}]}), + #muc_user{items = [#muc_item{affiliation = member, + jid = PeerJID, + role = participant}]} = + xmpp:get_subtag(?recv1(#presence{from = PeerNickJID}), #muc_user{}), ?recv1(#message{from = Room, sub_els = [#muc_user{ items = [#muc_item{affiliation = member, jid = Localhost, role = none}]}]}), - %% BUG: We should not receive any sub_els! - ?recv1(#iq{type = result, id = I1, sub_els = [_|_]}), + ?recv1(#iq{type = result, id = I1, sub_els = []}), %% Receive groupchat message from the peer ?recv1(#message{type = groupchat, from = PeerNickJID, body = [#text{data = Subject}]}), @@ -1483,22 +1476,20 @@ muc_master(Config) -> items = [#muc_item{affiliation = member, jid = PeerJID, role = none}]}]}), - %% BUG: We should not receive any sub_els! - ?recv1(#iq{type = result, id = I2, sub_els = [_|_]}), + ?recv1(#iq{type = result, id = I2, sub_els = []}), %% Destroying the room I3 = send(Config, #iq{type = set, to = Room, sub_els = [#muc_owner{ - destroy = #muc_owner_destroy{ + destroy = #muc_destroy{ reason = Subject}}]}), %% Kicked off ?recv1(#presence{from = MyNickJID, type = unavailable, sub_els = [#muc_user{items = [#muc_item{role = none, affiliation = none}], - destroy = #muc_user_destroy{ + destroy = #muc_destroy{ reason = Subject}}]}), - %% BUG: We should not receive any sub_els! - ?recv1(#iq{type = result, id = I3, sub_els = [_|_]}), + ?recv1(#iq{type = result, id = I3, sub_els = []}), disconnect(Config). muc_slave(Config) -> @@ -1514,10 +1505,9 @@ muc_slave(Config) -> Subject = ?config(room_subject, Config), Localhost = jid:make(<<"">>, <<"localhost">>, <<"">>), %% Receive an invite from the peer - ?recv1(#message{from = Room, type = normal, - sub_els = - [#muc_user{invites = - [#muc_invite{from = PeerJID}]}]}), + #muc_user{invites = [#muc_invite{from = PeerJID}]} = + xmpp:get_subtag(?recv1(#message{from = Room, type = normal}), + #muc_user{}), %% But before joining we discover the MUC service first %% to check if the room is in the disco list #iq{type = result, @@ -1533,21 +1523,16 @@ muc_slave(Config) -> %% Now joining send(Config, #presence{to = MyNickJID, sub_els = [#muc{}]}), %% First presence is from the participant, i.e. from the peer - ?recv1(#presence{ - from = PeerNickJID, - sub_els = [#vcard_xupdate{}, - #muc_user{ - status_codes = [], - items = [#muc_item{role = moderator, - affiliation = owner}]}]}), + #muc_user{ + status_codes = [], + items = [#muc_item{role = moderator, + affiliation = owner}]} = + xmpp:get_subtag(?recv1(#presence{from = PeerNickJID}), #muc_user{}), %% The next is the self-presence (code 110 means it) - ?recv1(#presence{ - from = MyNickJID, - sub_els = [#vcard_xupdate{}, - #muc_user{ - status_codes = [110], - items = [#muc_item{role = visitor, - affiliation = none}]}]}), + #muc_user{status_codes = [110], + items = [#muc_item{role = visitor, + affiliation = none}]} = + xmpp:get_subtag(?recv1(#presence{from = MyNickJID}), #muc_user{}), %% Receive the room subject ?recv1(#message{from = PeerNickJID, type = groupchat, body = [#text{data = Subject}], @@ -1574,20 +1559,16 @@ muc_slave(Config) -> values = [<<"participant">>]}]}, send(Config, #message{to = Room, sub_els = [VoiceReq]}), %% Becoming a participant - ?recv1(#presence{from = MyNickJID, - sub_els = [#vcard_xupdate{}, - #muc_user{ - items = [#muc_item{role = participant, - affiliation = none}]}]}), + #muc_user{items = [#muc_item{role = participant, + affiliation = none}]} = + xmpp:get_subtag(?recv1(#presence{from = MyNickJID}), #muc_user{}), %% Sending private message to the peer send(Config, #message{to = PeerNickJID, body = [#text{data = Subject}]}), %% Becoming a member - ?recv1(#presence{from = MyNickJID, - sub_els = [#vcard_xupdate{}, - #muc_user{ - items = [#muc_item{role = participant, - affiliation = member}]}]}), + #muc_user{items = [#muc_item{role = participant, + affiliation = member}]} = + xmpp:get_subtag(?recv1(#presence{from = MyNickJID}), #muc_user{}), %% Sending groupchat message send(Config, #message{to = Room, type = groupchat, body = [#text{data = Subject}]}), @@ -1624,7 +1605,7 @@ muc_register_nick(Config, MUC, PrevNick, Nick) -> X = #xdata{type = submit, fields = [#xdata_field{var = <<"nick">>, values = [Nick]}]}, %% Submitting form - #iq{type = result, sub_els = [_|_]} = + #iq{type = result, sub_els = []} = send_recv(Config, #iq{type = set, to = MUC, sub_els = [#register{xdata = X}]}), %% Check if the nick was registered @@ -1643,7 +1624,7 @@ muc_register_master(Config) -> %% Register nick "master1" muc_register_nick(Config, MUC, <<"">>, <<"master1">>), %% Unregister nick "master1" via jabber:register - #iq{type = result, sub_els = [_|_]} = + #iq{type = result, sub_els = []} = send_recv(Config, #iq{type = set, to = MUC, sub_els = [#register{remove = true}]}), %% Register nick "master2" @@ -1690,6 +1671,7 @@ announce_slave(Config) -> flex_offline_master(Config) -> Peer = ?config(slave, Config), + ct:log("hooks = ~p", [ets:tab2list(hooks)]), LPeer = jid:remove_resource(Peer), lists:foreach( fun(I) -> @@ -2026,8 +2008,11 @@ mam_slave(Config, NS) -> lists:foreach( fun(N) -> Text = #text{data = integer_to_binary(N)}, - ?recv1(#message{from = Peer, body = [Text], - sub_els = [#mam_archived{by = ServerJID}]}) + Msg = ?recv1(#message{from = Peer, body = [Text]}), + #mam_archived{by = ServerJID} = + xmpp:get_subtag(Msg, #mam_archived{}), + #stanza_id{by = ServerJID} = + xmpp:get_subtag(Msg, #stanza_id{}) end, lists:seq(1, 5)), #iq{type = result, sub_els = [#mam_prefs{xmlns = NS, default = never}]} = send_recv(Config, #iq{type = set, @@ -2241,7 +2226,7 @@ mam_query_rsm(Config, NS) -> #iq{type = Type, sub_els = [#mam_query{xmlns = NS, rsm = #rsm_set{max = 2, - before = none}}]}), + before = <<"">>}}]}), maybe_recv_iq_result(NS, I5), lists:foreach( fun(N) -> @@ -2278,25 +2263,25 @@ client_state_master(Config) -> PepOne = #message{ to = Peer, sub_els = - [#pubsub_event{ + [#ps_event{ items = - [#pubsub_event_items{ - node = <<"foo-1">>, - items = - [#pubsub_event_item{ - id = <<"pep-1">>, - xml_els = [PepPayload]}]}]}]}, + #ps_items{ + node = <<"foo-1">>, + items = + [#ps_item{ + id = <<"pep-1">>, + xml_els = [PepPayload]}]}}]}, PepTwo = #message{ to = Peer, sub_els = - [#pubsub_event{ + [#ps_event{ items = - [#pubsub_event_items{ - node = <<"foo-2">>, - items = - [#pubsub_event_item{ - id = <<"pep-2">>, - xml_els = [PepPayload]}]}]}]}, + #ps_items{ + node = <<"foo-2">>, + items = + [#ps_item{ + id = <<"pep-2">>, + xml_els = [PepPayload]}]}}]}, %% Wait for the slave to become inactive. wait_for_slave(Config), %% Should be queued (but see below): @@ -2330,24 +2315,24 @@ client_state_slave(Config) -> #message{ from = Peer, sub_els = - [#pubsub_event{ + [#ps_event{ items = - [#pubsub_event_items{ - node = <<"foo-1">>, - items = - [#pubsub_event_item{ - id = <<"pep-1">>}]}]}, + #ps_items{ + node = <<"foo-1">>, + items = + [#ps_item{ + id = <<"pep-1">>}]}}, #delay{}]} = recv(), #message{ from = Peer, sub_els = - [#pubsub_event{ + [#ps_event{ items = - [#pubsub_event_items{ - node = <<"foo-2">>, - items = - [#pubsub_event_item{ - id = <<"pep-2">>}]}]}, + #ps_items{ + node = <<"foo-2">>, + items = + [#ps_item{ + id = <<"pep-2">>}]}}, #delay{}]} = recv(), ?recv1(#message{from = Peer, thread = <<"1">>, sub_els = [#chatstate{type = composing}, diff --git a/test/ejabberd_SUITE_data/ejabberd.yml b/test/ejabberd_SUITE_data/ejabberd.yml index aca547d99..b2a0cd5ac 100644 --- a/test/ejabberd_SUITE_data/ejabberd.yml +++ b/test/ejabberd_SUITE_data/ejabberd.yml @@ -337,7 +337,8 @@ Welcome to this XMPP server." ldap_base: "ou=users,dc=localhost" auth_method: ldap modules: - mod_vcard_ldap: [] + mod_vcard: + db_type: ldap mod_roster: [] # mod_roster is required by mod_shared_roster mod_shared_roster_ldap: ldap_auth_check: off diff --git a/test/suite.erl b/test/suite.erl index c5593c4cf..d89a49ef8 100644 --- a/test/suite.erl +++ b/test/suite.erl @@ -199,7 +199,7 @@ bind(Config) -> open_session(Config) -> #iq{type = result, sub_els = []} = - send_recv(Config, #iq{type = set, sub_els = [#session{}]}), + send_recv(Config, #iq{type = set, sub_els = [#xmpp_session{}]}), Config. auth_SASL(Mech, Config) -> @@ -252,10 +252,15 @@ match_failure(Received, Matches) -> recv() -> receive {'$gen_event', {xmlstreamelement, El}} -> - Pkt = xmpp_codec:decode(fix_ns(El)), - ct:pal("recv: ~p ->~n~s", [El, xmpp_codec:pp(Pkt)]), - Pkt; - {'$gen_event', Event} -> + try + Pkt = xmpp:decode(El), + ct:pal("recv: ~p ->~n~s", [El, xmpp_codec:pp(Pkt)]), + Pkt + catch _:{xmpp_codec, Why} -> + ct:fail("recv failed: ~p->~n~s", + [El, xmpp:format_error(Why)]) + end; + {'$gen_event', Event} -> Event end. @@ -404,9 +409,9 @@ mix_room_jid(Config) -> jid:make(<<"test">>, <<"mix.", Server/binary>>, <<>>). id() -> - id(undefined). + id(<<>>). -id(undefined) -> +id(<<>>) -> randoms:get_string(); id(ID) -> ID. diff --git a/tools/xmpp_codec.spec b/tools/xmpp_codec.spec index 265bd6de9..aa18899c9 100644 --- a/tools/xmpp_codec.spec +++ b/tools/xmpp_codec.spec @@ -2653,9 +2653,10 @@ -xml(mam_fin, #elem{name = <<"fin">>, - xmlns = <<"urn:xmpp:mam:0">>, - result = {mam_fin, '$id', '$rsm', '$stable', '$complete'}, + xmlns = [<<"urn:xmpp:mam:0">>, <<"urn:xmpp:mam:1">>], + result = {mam_fin, '$xmlns', '$id', '$rsm', '$stable', '$complete'}, attrs = [#attr{name = <<"queryid">>, label = '$id'}, + #attr{name = <<"xmlns">>}, #attr{name = <<"stable">>, label = '$stable', dec = {dec_bool, []}, enc = {enc_bool, []}}, From 151668ac10613c7c47d62db6c3d102b536f7a3e4 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Tue, 13 Sep 2016 16:56:34 +0300 Subject: [PATCH 040/151] Fix dialyzer warnings for mod_mam --- include/mod_mam.hrl | 2 +- src/mod_mam.erl | 2 +- src/mod_mam_sql.erl | 9 +++------ 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/include/mod_mam.hrl b/include/mod_mam.hrl index 463db4cff..a2b92fca5 100644 --- a/include/mod_mam.hrl +++ b/include/mod_mam.hrl @@ -4,7 +4,7 @@ timestamp = p1_time_compat:timestamp() :: erlang:timestamp() | '_' | '$1', peer = {<<"">>, <<"">>, <<"">>} :: ljid() | '_' | '$3' | undefined, bare_peer = {<<"">>, <<"">>, <<"">>} :: ljid() | '_' | '$3', - packet = #xmlel{} :: xmlel() | '_', + packet = #xmlel{} :: xmlel() | message() | '_', nick = <<"">> :: binary(), type = chat :: chat | groupchat}). diff --git a/src/mod_mam.erl b/src/mod_mam.erl index ea267c1c0..5e4bebb75 100644 --- a/src/mod_mam.erl +++ b/src/mod_mam.erl @@ -945,7 +945,7 @@ filter_by_max(Msgs, Len) when is_integer(Len), Len >= 0 -> filter_by_max(_Msgs, _Junk) -> {[], true}. --spec limit_max(rsm_set(), binary()) -> rsm_set(). +-spec limit_max(rsm_set(), binary()) -> rsm_set() | undefined. limit_max(RSM, ?NS_MAM_TMP) -> RSM; % XEP-0313 v0.2 doesn't require clients to support RSM. limit_max(#rsm_set{max = Max} = RSM, _NS) when not is_integer(Max) -> diff --git a/src/mod_mam_sql.erl b/src/mod_mam_sql.erl index 6e5231989..2a0dcce95 100644 --- a/src/mod_mam_sql.erl +++ b/src/mod_mam_sql.erl @@ -217,13 +217,10 @@ make_sql_query(User, LServer, true -> [] end, - WithTextClause = case WithText of - {text, <<>>} -> - []; - {text, Txt} -> + WithTextClause = if is_binary(WithText), WithText /= <<>> -> [<<" and match (txt) against ('">>, - Escape(Txt), <<"')">>]; - undefined -> + Escape(WithText), <<"')">>]; + true -> [] end, WithClause = case catch jid:tolower(With) of From a4ec06445593728af35149a2a111527f8515e43c Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Tue, 20 Sep 2016 14:04:07 +0300 Subject: [PATCH 041/151] Add more tests for C2S --- src/ejabberd_c2s.erl | 26 ++--- test/ejabberd_SUITE.erl | 228 ++++++++++++++++++++++++++++++++++------ test/suite.erl | 150 ++++++++++++++++++++------ test/suite.hrl | 6 -- 4 files changed, 326 insertions(+), 84 deletions(-) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 186f7e9a5..e98a9eb8f 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -323,24 +323,25 @@ get_subscribed(FsmRef) -> wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) -> try xmpp:decode(#xmlel{name = Name, attrs = Attrs}) of - #stream_start{xmlns = NS_CLIENT, stream_xmlns = NS_STREAM, lang = Lang} + #stream_start{xmlns = NS_CLIENT, stream_xmlns = NS_STREAM, + version = Version, lang = Lang} when NS_CLIENT /= ?NS_CLIENT; NS_STREAM /= ?NS_STREAM -> - send_header(StateData, ?MYNAME, <<"">>, Lang), + send_header(StateData, ?MYNAME, Version, Lang), send_element(StateData, xmpp:serr_invalid_namespace()), {stop, normal, StateData}; - #stream_start{lang = Lang} when byte_size(Lang) > 35 -> + #stream_start{lang = Lang, version = Version} when byte_size(Lang) > 35 -> %% As stated in BCP47, 4.4.1: %% Protocols or specifications that specify limited buffer sizes for %% language tags MUST allow for language tags of at least 35 characters. %% Do not store long language tag to avoid possible DoS/flood attacks - send_header(StateData, ?MYNAME, <<"">>, ?MYLANG), + send_header(StateData, ?MYNAME, Version, ?MYLANG), Txt = <<"Too long value of 'xml:lang' attribute">>, send_element(StateData, xmpp:serr_policy_violation(Txt, ?MYLANG)), {stop, normal, StateData}; - #stream_start{to = undefined, lang = Lang} -> + #stream_start{to = undefined, lang = Lang, version = Version} -> Txt = <<"Missing 'to' attribute">>, - send_header(StateData, ?MYNAME, <<"">>, Lang), + send_header(StateData, ?MYNAME, Version, Lang), send_element(StateData, xmpp:serr_improper_addressing(Txt, Lang)), {stop, normal, StateData}; @@ -463,7 +464,7 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) -> end end; _ -> - send_header(StateData, Server, <<"">>, ?MYLANG), + send_header(StateData, Server, StreamVersion, ?MYLANG), if not StateData#state.tls_enabled and StateData#state.tls_required -> send_element( @@ -492,7 +493,7 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) -> end catch _:{xmpp_codec, Why} -> Txt = xmpp:format_error(Why), - send_header(StateData, ?MYNAME, <<"">>, ?MYLANG), + send_header(StateData, ?MYNAME, <<"1.0">>, ?MYLANG), send_element(StateData, xmpp:serr_not_well_formed(Txt, ?MYLANG)), {stop, normal, StateData} end; @@ -517,13 +518,8 @@ wait_for_auth({xmlstreamelement, #xmlel{} = El}, StateData) -> decode_element(El, wait_for_auth, StateData); wait_for_auth(Pkt, StateData) when ?IS_STREAM_MGMT_PACKET(Pkt) -> fsm_next_state(wait_for_auth, dispatch_stream_mgmt(Pkt, StateData)); -wait_for_auth(#iq{type = get, - sub_els = [#legacy_auth{username = U}]} = IQ, StateData) -> - Username = case U of - undefined -> <<"">>; - _ -> U - end, - Auth = #legacy_auth{username = Username, password = <<>>, resource = <<>>}, +wait_for_auth(#iq{type = get, sub_els = [#legacy_auth{}]} = IQ, StateData) -> + Auth = #legacy_auth{username = <<>>, password = <<>>, resource = <<>>}, Res = case ejabberd_auth:plain_password_required(StateData#state.server) of false -> xmpp:make_iq_result(IQ, Auth#legacy_auth{digest = <<>>}); diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index fbaee781f..0af81dd33 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -19,8 +19,9 @@ wait_for_master/1, wait_for_slave/1, make_iq_result/1, start_event_relay/0, stop_event_relay/1, put_event/2, get_event/1, - bind/1, auth/1, open_session/1, zlib/1, starttls/1, - close_socket/1]). + bind/1, auth/1, auth/2, open_session/1, open_session/2, + zlib/1, starttls/1, close_socket/1, init_stream/1, + auth_legacy/2, auth_legacy/3]). -include("suite.hrl"). @@ -154,15 +155,26 @@ init_per_testcase(stop_ejabberd, Config) -> open_session(bind(auth(connect(Config)))); init_per_testcase(TestCase, OrigConfig) -> subscribe_to_events(OrigConfig), + TestGroup = proplists:get_value( + name, ?config(tc_group_properties, OrigConfig)), Server = ?config(server, OrigConfig), - Resource = ?config(resource, OrigConfig), + Resource = case TestGroup of + generic -> + randoms:get_string(); + legacy_auth -> + randoms:get_string(); + _ -> + ?config(resource, OrigConfig) + end, MasterResource = ?config(master_resource, OrigConfig), SlaveResource = ?config(slave_resource, OrigConfig), Test = atom_to_list(TestCase), IsMaster = lists:suffix("_master", Test), IsSlave = lists:suffix("_slave", Test), IsCarbons = lists:prefix("carbons_", Test), - User = if IsMaster or IsCarbons -> <<"test_master!#$%^*()`~+-;_=[]{}|\\">>; + IsReplaced = lists:prefix("replaced_", Test), + User = if IsReplaced -> <<"test_single!#$%^*()`~+-;_=[]{}|\\">>; + IsMaster or IsCarbons -> <<"test_master!#$%^*()`~+-;_=[]{}|\\">>; IsSlave -> <<"test_slave!#$%^*()`~+-;_=[]{}|\\">>; true -> <<"test_single!#$%^*()`~+-;_=[]{}|\\">> end, @@ -172,11 +184,15 @@ init_per_testcase(TestCase, OrigConfig) -> end, Slave = if IsCarbons -> jid:make(<<"test_master!#$%^*()`~+-;_=[]{}|\\">>, Server, SlaveResource); + IsReplaced -> + jid:make(User, Server, Resource); true -> jid:make(<<"test_slave!#$%^*()`~+-;_=[]{}|\\">>, Server, Resource) end, Master = if IsCarbons -> jid:make(<<"test_master!#$%^*()`~+-;_=[]{}|\\">>, Server, MasterResource); + IsReplaced -> + jid:make(User, Server, Resource); true -> jid:make(<<"test_master!#$%^*()`~+-;_=[]{}|\\">>, Server, Resource) end, @@ -184,29 +200,35 @@ init_per_testcase(TestCase, OrigConfig) -> set_opt(slave, Slave, set_opt(master, Master, set_opt(resource, MyResource, OrigConfig)))), - case TestCase of - test_connect -> + case Test of + "test_connect" ++ _ -> Config; - test_auth -> + "test_legacy_auth" ++ _ -> + init_stream(set_opt(stream_version, <<"">>, Config)); + "test_auth" ++ _ -> connect(Config); - test_starttls -> + "test_starttls" ++ _ -> connect(Config); - test_zlib -> + "test_zlib" -> connect(Config); - test_register -> + "test_register" -> connect(Config); - auth_md5 -> + "auth_md5" -> connect(Config); - auth_plain -> + "auth_plain" -> connect(Config); - test_bind -> + "unauthenticated_" ++ _ -> + connect(Config); + "test_bind" -> auth(connect(Config)); - sm_resume -> + "sm_resume" -> auth(connect(Config)); - sm_resume_failed -> + "sm_resume_failed" -> auth(connect(Config)); - test_open_session -> + "test_open_session" -> bind(auth(connect(Config))); + "replaced" ++ _ -> + auth(connect(Config)); _ when IsMaster or IsSlave -> Password = ?config(password, Config), ejabberd_auth:try_register(User, Server, Password), @@ -218,30 +240,56 @@ init_per_testcase(TestCase, OrigConfig) -> end_per_testcase(_TestCase, _Config) -> ok. +legacy_auth_tests() -> + {legacy_auth, [parallel], + [test_legacy_auth, + test_legacy_auth_digest, + test_legacy_auth_no_resource, + test_legacy_auth_bad_jid, + test_legacy_auth_fail]}. + no_db_tests() -> - [{generic, [sequence], - [test_connect, + [{generic, [parallel], + [test_connect_bad_xml, + test_connect_unknown_ns, + test_connect_bad_ns_client, + test_connect_bad_ns_stream, + test_connect_bad_lang, + test_connect_bad_to, + test_connect_missing_to, + test_connect, + unauthenticated_iq, + unauthenticated_stanza, test_starttls, test_zlib, test_auth, + test_auth_fail, test_bind, test_open_session, - presence, + codec_failure, + unsupported_query, + bad_nonza, + invalid_from, ping, version, time, stats, - sm, - sm_resume, - sm_resume_failed, disco]}, + {presence, [sequence], [presence]}, + {sm, [sequence], + [sm, + sm_resume, + sm_resume_failed]}, {test_proxy65, [parallel], - [proxy65_master, proxy65_slave]}]. + [proxy65_master, proxy65_slave]}, + {replaced, [parallel], + [replaced_master, replaced_slave]}]. db_tests(riak) -> %% No support for mod_pubsub [{single_user, [sequence], [test_register, + legacy_auth_tests(), auth_plain, auth_md5, presence_broadcast, @@ -273,6 +321,7 @@ db_tests(riak) -> db_tests(DB) when DB == mnesia; DB == redis -> [{single_user, [sequence], [test_register, + legacy_auth_tests(), auth_plain, auth_md5, presence_broadcast, @@ -319,6 +368,7 @@ db_tests(_) -> %% No support for carboncopy [{single_user, [sequence], [test_register, + legacy_auth_tests(), auth_plain, auth_md5, presence_broadcast, @@ -361,12 +411,14 @@ db_tests(_) -> ldap_tests() -> [{ldap_tests, [sequence], [test_auth, + test_auth_fail, vcard_get, ldap_shared_roster_get]}]. extauth_tests() -> [{extauth_tests, [sequence], [test_auth, + test_auth_fail, test_unregister]}]. groups() -> @@ -381,15 +433,15 @@ groups() -> {riak, [sequence], db_tests(riak)}]. all() -> - [{group, ldap}, + [%%{group, ldap}, {group, no_db}, {group, mnesia}, - {group, redis}, - {group, mysql}, - {group, pgsql}, - {group, sqlite}, - {group, extauth}, - {group, riak}, + %%{group, redis}, + %%{group, mysql}, + %%{group, pgsql}, + %%{group, sqlite}, + %%{group, extauth}, + %%{group, riak}, stop_ejabberd]. stop_ejabberd(Config) -> @@ -398,6 +450,48 @@ stop_ejabberd(Config) -> ?recv1({xmlstreamend, <<"stream:stream">>}), Config. +test_connect_bad_xml(Config) -> + Config0 = init_stream(set_opt(ns_client, <<"'">>, Config)), + ?recv1(#stream_error{reason = 'not-well-formed'}), + ?recv1({xmlstreamend, <<"stream:stream">>}), + close_socket(Config0). + +test_connect_unknown_ns(Config) -> + Config0 = init_stream(set_opt(ns_client, <<"wrong">>, Config)), + ?recv1(#stream_error{reason = 'not-well-formed'}), + ?recv1({xmlstreamend, <<"stream:stream">>}), + close_socket(Config0). + +test_connect_bad_ns_client(Config) -> + Config0 = init_stream(set_opt(ns_client, ?NS_SERVER, Config)), + ?recv1(#stream_error{reason = 'invalid-namespace'}), + ?recv1({xmlstreamend, <<"stream:stream">>}), + close_socket(Config0). + +test_connect_bad_ns_stream(Config) -> + Config0 = init_stream(set_opt(ns_stream, <<"wrong">>, Config)), + ?recv1(#stream_error{reason = 'invalid-namespace'}), + ?recv1({xmlstreamend, <<"stream:stream">>}), + close_socket(Config0). + +test_connect_bad_lang(Config) -> + Config0 = init_stream(set_opt(lang, lists:duplicate(36, $x), Config)), + ?recv1(#stream_error{reason = 'policy-violation'}), + ?recv1({xmlstreamend, <<"stream:stream">>}), + close_socket(Config0). + +test_connect_bad_to(Config) -> + Config0 = init_stream(set_opt(server, <<"wrong.com">>, Config)), + ?recv1(#stream_error{reason = 'host-unknown'}), + ?recv1({xmlstreamend, <<"stream:stream">>}), + close_socket(Config0). + +test_connect_missing_to(Config) -> + Config0 = init_stream(set_opt(server, <<"">>, Config)), + ?recv1(#stream_error{reason = 'improper-addressing'}), + ?recv1({xmlstreamend, <<"stream:stream">>}), + close_socket(Config0). + test_connect(Config) -> disconnect(connect(Config)). @@ -462,6 +556,28 @@ try_unregister(Config) -> ?recv1(#stream_error{reason = conflict}), Config. +unauthenticated_stanza(Config) -> + %% Unauthenticated stanza should be silently dropped. + send(Config, #message{to = server_jid(Config)}), + disconnect(Config). + +unauthenticated_iq(Config) -> + #iq{type = error} = + send_recv(Config, #iq{type = get, sub_els = [#disco_info{}]}), + disconnect(Config). + +bad_nonza(Config) -> + %% Unsupported and invalid nonza should be silently dropped. + send(Config, #caps{}), + send(Config, #stanza_error{type = wrong}), + disconnect(Config). + +invalid_from(Config) -> + send(Config, #message{from = jid:make(randoms:get_string())}), + ?recv1(#stream_error{reason = 'invalid-from'}), + ?recv1({xmlstreamend, <<"stream:stream">>}), + close_socket(Config). + auth_md5(Config) -> Mechs = ?config(mechs, Config), case lists:member(<<"DIGEST-MD5">>, Mechs) of @@ -482,14 +598,37 @@ auth_plain(Config) -> {skipped, 'PLAIN_not_available'} end. +test_legacy_auth(Config) -> + disconnect(auth_legacy(Config, _Digest = false)). + +test_legacy_auth_digest(Config) -> + ServerJID = server_jid(Config), + disconnect(auth_legacy(Config, _Digest = true)). + +test_legacy_auth_no_resource(Config0) -> + Config = set_opt(resource, <<"">>, Config0), + disconnect(auth_legacy(Config, _Digest = false, _ShouldFail = true)). + +test_legacy_auth_bad_jid(Config0) -> + Config = set_opt(user, <<"@">>, Config0), + disconnect(auth_legacy(Config, _Digest = false, _ShouldFail = true)). + +test_legacy_auth_fail(Config0) -> + Config = set_opt(user, <<"wrong">>, Config0), + disconnect(auth_legacy(Config, _Digest = false, _ShouldFail = true)). + test_auth(Config) -> disconnect(auth(Config)). +test_auth_fail(Config0) -> + Config = set_opt(user, <<"wrong">>, Config0), + disconnect(auth(Config, _ShouldFail = true)). + test_bind(Config) -> disconnect(bind(Config)). test_open_session(Config) -> - disconnect(open_session(Config)). + disconnect(open_session(Config, true)). roster_get(Config) -> #iq{type = result, sub_els = [#roster_query{items = []}]} = @@ -519,6 +658,21 @@ roster_ver(Config) -> sub_els = [#roster_query{ver = Ver2}]}), disconnect(Config). +codec_failure(Config) -> + #iq{type = error} = send_recv(Config, #iq{type = wrong}), + disconnect(Config). + +unsupported_query(Config) -> + ServerJID = server_jid(Config), + #iq{type = error} = send_recv(Config, #iq{type = get, to = ServerJID}), + #iq{type = error} = send_recv(Config, #iq{type = get, to = ServerJID, + sub_els = [#caps{}]}), + #iq{type = error} = send_recv(Config, #iq{type = get, to = ServerJID, + sub_els = [#roster_query{}, + #disco_info{}, + #privacy_query{}]}), + disconnect(Config). + presence(Config) -> send(Config, #presence{}), JID = my_jid(Config), @@ -604,6 +758,18 @@ disco(Config) -> end, Items), disconnect(Config). +replaced_master(Config0) -> + Config = bind(Config0), + wait_for_slave(Config), + ?recv1(#stream_error{reason = conflict}), + ?recv1({xmlstreamend, <<"stream:stream">>}), + close_socket(Config). + +replaced_slave(Config0) -> + wait_for_master(Config0), + Config = bind(Config0), + disconnect(Config). + sm(Config) -> Server = ?config(server, Config), ServerJID = jid:make(<<"">>, Server, <<"">>), diff --git a/test/suite.erl b/test/suite.erl index d89a49ef8..93141d846 100644 --- a/test/suite.erl +++ b/test/suite.erl @@ -32,7 +32,7 @@ init_config(Config) -> {ok, CfgContentTpl} = file:read_file(ConfigPathTpl), CfgContent = process_config_tpl(CfgContentTpl, [ {c2s_port, 5222}, - {loglevel, 4}, + {loglevel, 5}, {s2s_port, 5269}, {web_port, 5280}, {mysql_server, <<"localhost">>}, @@ -64,6 +64,12 @@ init_config(Config) -> {slave_nick, <<"slave_nick!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, {room_subject, <<"hello, world!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, {certfile, CertFile}, + {ns_client, ?NS_CLIENT}, + {ns_stream, ?NS_STREAM}, + {stream_version, <<"1.0">>}, + {stream_id, <<"">>}, + {mechs, []}, + {lang, <<"en">>}, {base_dir, BaseDir}, {resource, <<"resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, {master_resource, <<"master_resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, @@ -118,20 +124,36 @@ process_config_tpl(Content, [{Name, DefaultValue} | Rest]) -> NewContent = binary:replace(Content, <<"@@",(atom_to_binary(Name, latin1))/binary, "@@">>, Val), process_config_tpl(NewContent, Rest). +stream_header(Config) -> + NSStream = ?config(ns_stream, Config), + NSClient = ?config(ns_client, Config), + Lang = ?config(lang, Config), + To = case ?config(server, Config) of + <<"">> -> <<"">>; + Server -> <<"to='", Server/binary, "'">> + end, + Version = ?config(stream_version, Config), + io_lib:format("", + [NSStream, NSClient, To, Version, Lang]). connect(Config) -> + process_stream_features(init_stream(Config)). + +init_stream(Config) -> + Version = ?config(stream_version, Config), {ok, Sock} = ejabberd_socket:connect( ?config(server_host, Config), ?config(server_port, Config), [binary, {packet, 0}, {active, false}]), - init_stream(set_opt(socket, Sock, Config)). + NewConfig = set_opt(socket, Sock, Config), + ok = send_text(NewConfig, stream_header(NewConfig)), + #stream_start{id = ID, xmlns = ?NS_CLIENT, + version = Version} = recv(), + set_opt(stream_id, ID, NewConfig). -init_stream(Config) -> - ok = send_text(Config, io_lib:format(?STREAM_HEADER, - [?config(server, Config)])), - {xmlstreamstart, <<"stream:stream">>, Attrs} = recv(), - <<"jabber:client">> = fxml:get_attr_s(<<"xmlns">>, Attrs), - <<"1.0">> = fxml:get_attr_s(<<"version">>, Attrs), +process_stream_features(Config) -> #stream_features{sub_els = Fs} = recv(), Mechs = lists:flatmap( fun(#sasl_mechanisms{list = Ms}) -> @@ -169,24 +191,27 @@ starttls(Config) -> ?config(socket, Config), [{certfile, ?config(certfile, Config)}, connect]), - init_stream(set_opt(socket, TLSSocket, Config)). + process_stream_features(init_stream(set_opt(socket, TLSSocket, Config))). zlib(Config) -> send(Config, #compress{methods = [<<"zlib">>]}), #compressed{} = recv(), ZlibSocket = ejabberd_socket:compress(?config(socket, Config)), - init_stream(set_opt(socket, ZlibSocket, Config)). + process_stream_features(init_stream(set_opt(socket, ZlibSocket, Config))). auth(Config) -> + auth(Config, false). + +auth(Config, ShouldFail) -> Mechs = ?config(mechs, Config), HaveMD5 = lists:member(<<"DIGEST-MD5">>, Mechs), HavePLAIN = lists:member(<<"PLAIN">>, Mechs), if HavePLAIN -> - auth_SASL(<<"PLAIN">>, Config); + auth_SASL(<<"PLAIN">>, Config, ShouldFail); HaveMD5 -> - auth_SASL(<<"DIGEST-MD5">>, Config); + auth_SASL(<<"DIGEST-MD5">>, Config, ShouldFail); true -> - ct:fail(no_sasl_mechanisms_available) + auth_legacy(Config, false, ShouldFail) end. bind(Config) -> @@ -198,29 +223,83 @@ bind(Config) -> Config. open_session(Config) -> - #iq{type = result, sub_els = []} = - send_recv(Config, #iq{type = set, sub_els = [#xmpp_session{}]}), + open_session(Config, false). + +open_session(Config, Force) -> + if Force -> + #iq{type = result, sub_els = []} = + send_recv(Config, #iq{type = set, sub_els = [#xmpp_session{}]}); + true -> + ok + end, Config. +auth_legacy(Config, IsDigest) -> + auth_legacy(Config, IsDigest, false). + +auth_legacy(Config, IsDigest, ShouldFail) -> + ServerJID = server_jid(Config), + U = ?config(user, Config), + R = ?config(resource, Config), + P = ?config(password, Config), + #iq{type = result, + from = ServerJID, + sub_els = [#legacy_auth{username = <<"">>, + password = <<"">>, + resource = <<"">>} = Auth]} = + send_recv(Config, + #iq{to = ServerJID, type = get, + sub_els = [#legacy_auth{}]}), + Res = case Auth#legacy_auth.digest of + <<"">> when IsDigest -> + StreamID = ?config(stream_id, Config), + D = p1_sha:sha(<>), + send_recv(Config, #iq{to = ServerJID, type = set, + sub_els = [#legacy_auth{username = U, + resource = R, + digest = D}]}); + _ when not IsDigest -> + send_recv(Config, #iq{to = ServerJID, type = set, + sub_els = [#legacy_auth{username = U, + resource = R, + password = P}]}) + end, + case Res of + #iq{from = ServerJID, type = result, sub_els = []} -> + if ShouldFail -> + ct:fail(legacy_auth_should_have_failed); + true -> + Config + end; + #iq{from = ServerJID, type = error} -> + if ShouldFail -> + Config; + true -> + ct:fail(legacy_auth_failed) + end + end. + auth_SASL(Mech, Config) -> + auth_SASL(Mech, Config, false). + +auth_SASL(Mech, Config, ShouldFail) -> {Response, SASL} = sasl_new(Mech, ?config(user, Config), ?config(server, Config), ?config(password, Config)), send(Config, #sasl_auth{mechanism = Mech, text = Response}), - wait_auth_SASL_result(set_opt(sasl, SASL, Config)). + wait_auth_SASL_result(set_opt(sasl, SASL, Config), ShouldFail). -wait_auth_SASL_result(Config) -> +wait_auth_SASL_result(Config, ShouldFail) -> case recv() of + #sasl_success{} when ShouldFail -> + ct:fail(sasl_auth_should_have_failed); #sasl_success{} -> ejabberd_socket:reset_stream(?config(socket, Config)), - send_text(Config, - io_lib:format(?STREAM_HEADER, - [?config(server, Config)])), - {xmlstreamstart, <<"stream:stream">>, Attrs} = recv(), - <<"jabber:client">> = fxml:get_attr_s(<<"xmlns">>, Attrs), - <<"1.0">> = fxml:get_attr_s(<<"version">>, Attrs), + send_text(Config, stream_header(Config)), + #stream_start{xmlns = ?NS_CLIENT, version = <<"1.0">>} = recv(), #stream_features{sub_els = Fs} = recv(), + #xmpp_session{optional = true} = lists:keyfind(xmpp_session, 1, Fs), lists:foldl( fun(#feature_sm{}, ConfigAcc) -> set_opt(sm, true, ConfigAcc); @@ -232,7 +311,9 @@ wait_auth_SASL_result(Config) -> #sasl_challenge{text = ClientIn} -> {Response, SASL} = (?config(sasl, Config))(ClientIn), send(Config, #sasl_response{text = Response}), - wait_auth_SASL_result(set_opt(sasl, SASL, Config)); + wait_auth_SASL_result(set_opt(sasl, SASL, Config), ShouldFail); + #sasl_failure{} when ShouldFail -> + Config; #sasl_failure{} -> ct:fail(sasl_auth_failed) end. @@ -252,18 +333,23 @@ match_failure(Received, Matches) -> recv() -> receive {'$gen_event', {xmlstreamelement, El}} -> - try - Pkt = xmpp:decode(El), - ct:pal("recv: ~p ->~n~s", [El, xmpp_codec:pp(Pkt)]), - Pkt - catch _:{xmpp_codec, Why} -> - ct:fail("recv failed: ~p->~n~s", - [El, xmpp:format_error(Why)]) - end; + decode(El); + {'$gen_event', {xmlstreamstart, Name, Attrs}} -> + decode(#xmlel{name = Name, attrs = Attrs}); {'$gen_event', Event} -> Event end. +decode(El) -> + try + Pkt = xmpp:decode(El), + ct:pal("recv: ~p ->~n~s", [El, xmpp_codec:pp(Pkt)]), + Pkt + catch _:{xmpp_codec, Why} -> + ct:fail("recv failed: ~p->~n~s", + [El, xmpp:format_error(Why)]) + end. + fix_ns(#xmlel{name = Tag, attrs = Attrs} = El) when Tag == <<"stream:features">>; Tag == <<"stream:error">> -> NewAttrs = [{<<"xmlns">>, <<"http://etherx.jabber.org/streams">>} diff --git a/test/suite.hrl b/test/suite.hrl index fb6b4f3ac..3095e1bb5 100644 --- a/test/suite.hrl +++ b/test/suite.hrl @@ -5,12 +5,6 @@ -include("mod_proxy65.hrl"). -include("xmpp_codec.hrl"). --define(STREAM_HEADER, - <<"">>). - -define(STREAM_TRAILER, <<"">>). -define(PUBSUB(Node), <<(?NS_PUBSUB)/binary, "#", Node>>). From ceda0737666760e5fa93bed0a9ab160778d29358 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Wed, 21 Sep 2016 10:45:11 +0300 Subject: [PATCH 042/151] Add tests for external component --- src/ejabberd_c2s.erl | 2 +- src/ejabberd_service.erl | 29 +++++----- test/ejabberd_SUITE.erl | 82 ++++++++++++++++++++++---- test/ejabberd_SUITE_data/ejabberd.yml | 5 ++ test/suite.erl | 83 +++++++++++++++++++++------ 5 files changed, 154 insertions(+), 47 deletions(-) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index e98a9eb8f..7dc9960e6 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -494,7 +494,7 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) -> catch _:{xmpp_codec, Why} -> Txt = xmpp:format_error(Why), send_header(StateData, ?MYNAME, <<"1.0">>, ?MYLANG), - send_element(StateData, xmpp:serr_not_well_formed(Txt, ?MYLANG)), + send_element(StateData, xmpp:serr_invalid_xml(Txt, ?MYLANG)), {stop, normal, StateData} end; wait_for_stream(timeout, StateData) -> diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index 002d74949..f4338593d 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -125,7 +125,12 @@ init([{SockMod, Socket}, Opts]) -> wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) -> try xmpp:decode(#xmlel{name = Name, attrs = Attrs}) of - #stream_start{xmlns = ?NS_COMPONENT, to = To} when is_record(To, jid) -> + #stream_start{xmlns = NS_COMPONENT, stream_xmlns = NS_STREAM} + when NS_COMPONENT /= ?NS_COMPONENT; NS_STREAM /= ?NS_STREAM -> + send_header(StateData, ?MYNAME), + send_element(StateData, xmpp:serr_invalid_namespace()), + {stop, normal, StateData}; + #stream_start{to = To} when is_record(To, jid) -> Host = To#jid.lserver, send_header(StateData, Host), HostOpts = case dict:is_key(Host, StateData#state.host_opts) of @@ -141,13 +146,9 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) -> end, {next_state, wait_for_handshake, StateData#state{host = Host, host_opts = HostOpts}}; - #stream_start{xmlns = ?NS_COMPONENT} -> - send_header(StateData, ?MYNAME), - send_element(StateData, xmpp:serr_improper_addressing()), - {stop, normal, StateData}; #stream_start{} -> send_header(StateData, ?MYNAME), - send_element(StateData, xmpp:serr_invalid_namespace()), + send_element(StateData, xmpp:serr_improper_addressing()), {stop, normal, StateData} catch _:{xmpp_codec, Why} -> Txt = xmpp:format_error(Why), @@ -203,7 +204,8 @@ stream_established(El, StateData) when ?is_stanza(El) -> To = xmpp:get_to(El), Lang = xmpp:get_lang(El), if From == undefined orelse To == undefined -> - send_error(StateData, El, xmpp:err_jid_malformed()); + Txt = <<"Missing 'from' or 'to' attribute">>, + send_error(StateData, El, xmpp:err_jid_malformed(Txt, Lang)); true -> FromJID = case StateData#state.check_from of false -> @@ -214,19 +216,16 @@ stream_established(El, StateData) when ?is_stanza(El) -> From; _ -> %% The default is the standard behaviour in XEP-0114 - case From of - #jid{lserver = Server} -> - case dict:is_key(Server, StateData#state.host_opts) of - true -> From; - false -> error - end; - _ -> error + Server = From#jid.lserver, + case dict:is_key(Server, StateData#state.host_opts) of + true -> From; + false -> error end end, if FromJID /= error -> ejabberd_router:route(FromJID, To, El); true -> - Txt = <<"Incorrect value of 'from' or 'to' attribute">>, + Txt = <<"Improper domain part of 'from' attribute">>, send_error(StateData, El, xmpp:err_not_allowed(Txt, Lang)) end end, diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index 0af81dd33..dbcd9a905 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -125,6 +125,15 @@ do_init_per_group(riak, Config) -> Err -> {skip, {riak_not_available, Err}} end; +do_init_per_group(component, Config) -> + Server = ?config(server, Config), + Port = ?config(component_port, Config), + set_opt(xmlns, ?NS_COMPONENT, + set_opt(server, <<"component.", Server/binary>>, + set_opt(type, component, + set_opt(server_port, Port, + set_opt(stream_version, <<"">>, + set_opt(lang, <<"">>, Config)))))); do_init_per_group(_GroupName, Config) -> Pid = start_event_relay(), set_opt(event_relay, Pid, Config). @@ -147,6 +156,8 @@ end_per_group(extauth, _Config) -> ok; end_per_group(riak, _Config) -> ok; +end_per_group(component, _Config) -> + ok; end_per_group(_GroupName, Config) -> stop_event_relay(Config), ok. @@ -252,7 +263,7 @@ no_db_tests() -> [{generic, [parallel], [test_connect_bad_xml, test_connect_unknown_ns, - test_connect_bad_ns_client, + test_connect_bad_xmlns, test_connect_bad_ns_stream, test_connect_bad_lang, test_connect_bad_to, @@ -421,10 +432,27 @@ extauth_tests() -> test_auth_fail, test_unregister]}]. +component_tests() -> + [{component_tests, [sequence], + [test_connect_bad_xml, + test_connect_unknown_ns, + test_connect_bad_xmlns, + test_connect_bad_ns_stream, + test_connect_missing_to, + test_connect, + test_auth, + test_auth_fail, + component_missing_address, + component_invalid_from, + component_send, + bad_nonza, + codec_failure]}]. + groups() -> [{ldap, [sequence], ldap_tests()}, {extauth, [sequence], extauth_tests()}, {no_db, [sequence], no_db_tests()}, + {component, [sequence], component_tests()}, {mnesia, [sequence], db_tests(mnesia)}, {redis, [sequence], db_tests(redis)}, {mysql, [sequence], db_tests(mysql)}, @@ -433,7 +461,8 @@ groups() -> {riak, [sequence], db_tests(riak)}]. all() -> - [%%{group, ldap}, + [{group, component}, + %%{group, ldap}, {group, no_db}, {group, mnesia}, %%{group, redis}, @@ -451,19 +480,19 @@ stop_ejabberd(Config) -> Config. test_connect_bad_xml(Config) -> - Config0 = init_stream(set_opt(ns_client, <<"'">>, Config)), + Config0 = init_stream(set_opt(xmlns, <<"'">>, Config)), ?recv1(#stream_error{reason = 'not-well-formed'}), ?recv1({xmlstreamend, <<"stream:stream">>}), close_socket(Config0). test_connect_unknown_ns(Config) -> - Config0 = init_stream(set_opt(ns_client, <<"wrong">>, Config)), - ?recv1(#stream_error{reason = 'not-well-formed'}), + Config0 = init_stream(set_opt(xmlns, <<"wrong">>, Config)), + ?recv1(#stream_error{reason = 'invalid-xml'}), ?recv1({xmlstreamend, <<"stream:stream">>}), close_socket(Config0). -test_connect_bad_ns_client(Config) -> - Config0 = init_stream(set_opt(ns_client, ?NS_SERVER, Config)), +test_connect_bad_xmlns(Config) -> + Config0 = init_stream(set_opt(xmlns, ?NS_SERVER, Config)), ?recv1(#stream_error{reason = 'invalid-namespace'}), ?recv1({xmlstreamend, <<"stream:stream">>}), close_socket(Config0). @@ -495,6 +524,12 @@ test_connect_missing_to(Config) -> test_connect(Config) -> disconnect(connect(Config)). +test_component_connect(Config) -> + disconnect(component_connect(Config)). + +component_connect(Config) -> + init_stream(Config). + test_starttls(Config) -> case ?config(starttls, Config) of true -> @@ -578,6 +613,25 @@ invalid_from(Config) -> ?recv1({xmlstreamend, <<"stream:stream">>}), close_socket(Config). +component_missing_address(Config) -> + Server = server_jid(Config), + #iq{type = error} = send_recv(Config, #iq{type = get, from = Server}), + #iq{type = error} = send_recv(Config, #iq{type = get, to = Server}), + disconnect(Config). + +component_invalid_from(Config) -> + From = jid:make(randoms:get_string()), + To = jid:make(randoms:get_string()), + #iq{type = error} = + send_recv(Config, #iq{type = get, from = From, to = To}), + disconnect(Config). + +component_send(Config) -> + JID = my_jid(Config), + send(Config, #message{from = JID, to = JID}), + #message{from = JID, to = JID} = recv(), + disconnect(Config). + auth_md5(Config) -> Mechs = ?config(mechs, Config), case lists:member(<<"DIGEST-MD5">>, Mechs) of @@ -621,7 +675,8 @@ test_auth(Config) -> disconnect(auth(Config)). test_auth_fail(Config0) -> - Config = set_opt(user, <<"wrong">>, Config0), + Config = set_opt(user, <<"wrong">>, + set_opt(password, <<"wrong">>, Config0)), disconnect(auth(Config, _ShouldFail = true)). test_bind(Config) -> @@ -659,7 +714,9 @@ roster_ver(Config) -> disconnect(Config). codec_failure(Config) -> - #iq{type = error} = send_recv(Config, #iq{type = wrong}), + JID = my_jid(Config), + #iq{type = error} = + send_recv(Config, #iq{type = wrong, from = JID, to = JID}), disconnect(Config). unsupported_query(Config) -> @@ -829,13 +886,14 @@ private(Config) -> <<>>)}, Storage = #bookmark_storage{conference = [Conference]}, StorageXMLOut = xmpp_codec:encode(Storage), + WrongEl = #xmlel{name = <<"wrong">>}, #iq{type = error} = - send_recv(Config, #iq{type = get, sub_els = [#private{}], - to = server_jid(Config)}), + send_recv(Config, #iq{type = get, + sub_els = [#private{xml_els = [WrongEl]}]}), #iq{type = result, sub_els = []} = send_recv( Config, #iq{type = set, - sub_els = [#private{xml_els = [StorageXMLOut]}]}), + sub_els = [#private{xml_els = [WrongEl, StorageXMLOut]}]}), #iq{type = result, sub_els = [#private{xml_els = [StorageXMLIn]}]} = send_recv( diff --git a/test/ejabberd_SUITE_data/ejabberd.yml b/test/ejabberd_SUITE_data/ejabberd.yml index b2a0cd5ac..99af18bbf 100644 --- a/test/ejabberd_SUITE_data/ejabberd.yml +++ b/test/ejabberd_SUITE_data/ejabberd.yml @@ -428,6 +428,11 @@ listen: port: @@web_port@@ module: ejabberd_http captcha: true + - + port: @@component_port@@ + module: ejabberd_service + password: >- + @@password@@ loglevel: @@loglevel@@ max_fsm_queue: 1000 modules: diff --git a/test/suite.erl b/test/suite.erl index 93141d846..f78b7bd1a 100644 --- a/test/suite.erl +++ b/test/suite.erl @@ -30,11 +30,14 @@ init_config(Config) -> {ok, CWD} = file:get_cwd(), {ok, _} = file:copy(CertFile, filename:join([CWD, "cert.pem"])), {ok, CfgContentTpl} = file:read_file(ConfigPathTpl), + Password = <<"password!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>, CfgContent = process_config_tpl(CfgContentTpl, [ {c2s_port, 5222}, {loglevel, 5}, {s2s_port, 5269}, + {component_port, 5270}, {web_port, 5280}, + {password, Password}, {mysql_server, <<"localhost">>}, {mysql_port, 3306}, {mysql_db, <<"ejabberd_test">>}, @@ -58,13 +61,15 @@ init_config(Config) -> application:set_env(mnesia, dir, MnesiaDir), [{server_port, ct:get_config(c2s_port, 5222)}, {server_host, "localhost"}, + {component_port, ct:get_config(component_port, 5270)}, {server, ?COMMON_VHOST}, {user, <<"test_single!#$%^*()`~+-;_=[]{}|\\">>}, {master_nick, <<"master_nick!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, {slave_nick, <<"slave_nick!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, {room_subject, <<"hello, world!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, {certfile, CertFile}, - {ns_client, ?NS_CLIENT}, + {type, client}, + {xmlns, ?NS_CLIENT}, {ns_stream, ?NS_STREAM}, {stream_version, <<"1.0">>}, {stream_id, <<"">>}, @@ -74,7 +79,7 @@ init_config(Config) -> {resource, <<"resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, {master_resource, <<"master_resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, {slave_resource, <<"slave_resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, - {password, <<"password!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, + {password, Password}, {backends, get_config_backends()} |Config]. @@ -126,20 +131,29 @@ process_config_tpl(Content, [{Name, DefaultValue} | Rest]) -> stream_header(Config) -> NSStream = ?config(ns_stream, Config), - NSClient = ?config(ns_client, Config), - Lang = ?config(lang, Config), + XMLNS = ?config(xmlns, Config), + Lang = case ?config(lang, Config) of + <<"">> -> <<"">>; + L -> iolist_to_binary(["xml:lang='", L, "'"]) + end, To = case ?config(server, Config) of <<"">> -> <<"">>; Server -> <<"to='", Server/binary, "'">> end, - Version = ?config(stream_version, Config), + Version = case ?config(stream_version, Config) of + <<"">> -> <<"">>; + V -> <<"version='", V/binary, "'">> + end, io_lib:format("", - [NSStream, NSClient, To, Version, Lang]). + "xmlns:stream='~s' xmlns='~s' ~s ~s ~s>", + [NSStream, XMLNS, To, Version, Lang]). connect(Config) -> - process_stream_features(init_stream(Config)). + NewConfig = init_stream(Config), + case ?config(type, NewConfig) of + client -> process_stream_features(NewConfig); + component -> NewConfig + end. init_stream(Config) -> Version = ?config(stream_version, Config), @@ -149,8 +163,11 @@ init_stream(Config) -> [binary, {packet, 0}, {active, false}]), NewConfig = set_opt(socket, Sock, Config), ok = send_text(NewConfig, stream_header(NewConfig)), - #stream_start{id = ID, xmlns = ?NS_CLIENT, - version = Version} = recv(), + XMLNS = case ?config(type, Config) of + client -> ?NS_CLIENT; + component -> ?NS_COMPONENT + end, + #stream_start{id = ID, xmlns = XMLNS, version = Version} = recv(), set_opt(stream_id, ID, NewConfig). process_stream_features(Config) -> @@ -174,7 +191,11 @@ process_stream_features(Config) -> disconnect(Config) -> Socket = ?config(socket, Config), - ok = ejabberd_socket:send(Socket, ?STREAM_TRAILER), + try + ok = send_text(Config, ?STREAM_TRAILER) + catch exit:normal -> + ok + end, {xmlstreamend, <<"stream:stream">>} = recv(), ejabberd_socket:close(Socket), Config. @@ -203,6 +224,7 @@ auth(Config) -> auth(Config, false). auth(Config, ShouldFail) -> + Type = ?config(type, Config), Mechs = ?config(mechs, Config), HaveMD5 = lists:member(<<"DIGEST-MD5">>, Mechs), HavePLAIN = lists:member(<<"PLAIN">>, Mechs), @@ -210,16 +232,23 @@ auth(Config, ShouldFail) -> auth_SASL(<<"PLAIN">>, Config, ShouldFail); HaveMD5 -> auth_SASL(<<"DIGEST-MD5">>, Config, ShouldFail); - true -> - auth_legacy(Config, false, ShouldFail) + Type == client -> + auth_legacy(Config, false, ShouldFail); + Type == component -> + auth_component(Config, ShouldFail) end. bind(Config) -> - #iq{type = result, sub_els = [#bind{}]} = - send_recv( - Config, - #iq{type = set, - sub_els = [#bind{resource = ?config(resource, Config)}]}), + case ?config(type, Config) of + client -> + #iq{type = result, sub_els = [#bind{}]} = + send_recv( + Config, + #iq{type = set, + sub_els = [#bind{resource = ?config(resource, Config)}]}); + component -> + ok + end, Config. open_session(Config) -> @@ -279,6 +308,22 @@ auth_legacy(Config, IsDigest, ShouldFail) -> end end. +auth_component(Config, ShouldFail) -> + StreamID = ?config(stream_id, Config), + Password = ?config(password, Config), + Digest = p1_sha:sha(<>), + send(Config, #handshake{data = Digest}), + case recv() of + #handshake{} when ShouldFail -> + ct:fail(component_auth_should_have_failed); + #handshake{} -> + Config; + #stream_error{reason = 'not-authorized'} when ShouldFail -> + Config; + #stream_error{reason = 'not-authorized'} -> + ct:fail(component_auth_failed) + end. + auth_SASL(Mech, Config) -> auth_SASL(Mech, Config, false). From 53209b9ab1c154334eafacd3ca9aebe965380d50 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Fri, 23 Sep 2016 12:30:33 +0300 Subject: [PATCH 043/151] Add tests for s2s code --- include/xmpp_codec.hrl | 2 +- src/ejabberd_c2s.erl | 65 ++-- src/ejabberd_s2s.erl | 18 +- src/ejabberd_s2s_in.erl | 101 ++++-- src/ejabberd_s2s_out.erl | 48 ++- src/ejabberd_service.erl | 17 +- src/xmpp_codec.erl | 23 +- test/ejabberd_SUITE.erl | 183 ++++++++-- test/ejabberd_SUITE_data/ca.key | 27 ++ test/ejabberd_SUITE_data/ca.pem | 22 ++ test/ejabberd_SUITE_data/cert.pem | 94 ++--- test/ejabberd_SUITE_data/ejabberd.yml | 5 + test/ejabberd_SUITE_data/extauth.py | 5 +- test/ejabberd_SUITE_data/gencerts.sh | 18 + test/ejabberd_SUITE_data/openssl.cnf | 323 ++++++++++++++++++ test/ejabberd_SUITE_data/self-signed-cert.pem | 46 +++ test/suite.erl | 143 +++++--- test/suite.hrl | 1 + tools/xmpp_codec.spec | 12 +- 19 files changed, 917 insertions(+), 236 deletions(-) create mode 100644 test/ejabberd_SUITE_data/ca.key create mode 100644 test/ejabberd_SUITE_data/ca.pem create mode 100755 test/ejabberd_SUITE_data/gencerts.sh create mode 100644 test/ejabberd_SUITE_data/openssl.cnf create mode 100644 test/ejabberd_SUITE_data/self-signed-cert.pem diff --git a/include/xmpp_codec.hrl b/include/xmpp_codec.hrl index 845861948..5428aad11 100644 --- a/include/xmpp_codec.hrl +++ b/include/xmpp_codec.hrl @@ -158,7 +158,7 @@ -record(stream_start, {from :: jid:jid(), to :: jid:jid(), id = <<>> :: binary(), - version = <<>> :: binary(), + version :: {non_neg_integer(),non_neg_integer()}, xmlns = <<>> :: binary(), stream_xmlns = <<>> :: binary(), db_xmlns = <<>> :: binary(), diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 7dc9960e6..858e285a6 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -352,16 +352,16 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) -> S -> S end, StreamVersion = case Version of - <<"1.0">> -> <<"1.0">>; - _ -> <<"">> + {1,0} -> {1,0}; + _ -> undefined end, IsBlacklistedIP = is_ip_blacklisted(StateData#state.ip, Lang), case lists:member(Server, ?MYHOSTS) of true when IsBlacklistedIP == false -> change_shaper(StateData, jid:make(<<"">>, Server, <<"">>)), case StreamVersion of - <<"1.0">> -> - send_header(StateData, Server, <<"1.0">>, ?MYLANG), + {1,0} -> + send_header(StateData, Server, {1,0}, ?MYLANG), case StateData#state.authenticated of false -> TLS = StateData#state.tls, @@ -490,10 +490,14 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) -> send_header(StateData, ?MYNAME, StreamVersion, ?MYLANG), send_element(StateData, xmpp:serr_host_unknown()), {stop, normal, StateData} - end + end; + _ -> + send_header(StateData, ?MYNAME, {1,0}, ?MYLANG), + send_element(StateData, xmpp:serr_invalid_xml()), + {stop, normal, StateData} catch _:{xmpp_codec, Why} -> Txt = xmpp:format_error(Why), - send_header(StateData, ?MYNAME, <<"1.0">>, ?MYLANG), + send_header(StateData, ?MYNAME, {1,0}, ?MYLANG), send_element(StateData, xmpp:serr_invalid_xml(Txt, ?MYLANG)), {stop, normal, StateData} end; @@ -506,7 +510,7 @@ wait_for_stream({xmlstreamend, _}, StateData) -> send_element(StateData, xmpp:serr_not_well_formed()), {stop, normal, StateData}; wait_for_stream({xmlstreamerror, _}, StateData) -> - send_header(StateData, ?MYNAME, <<"1.0">>, <<"">>), + send_header(StateData, ?MYNAME, {1,0}, <<"">>), send_element(StateData, xmpp:serr_not_well_formed()), {stop, normal, StateData}; wait_for_stream(closed, StateData) -> @@ -1374,7 +1378,7 @@ handle_info({'DOWN', Monitor, _Type, _Object, _Info}, handle_info(system_shutdown, StateName, StateData) -> case StateName of wait_for_stream -> - send_header(StateData, ?MYNAME, <<"1.0">>, <<"en">>), + send_header(StateData, ?MYNAME, {1,0}, <<"en">>), send_element(StateData, xmpp:serr_system_shutdown()), ok; _ -> @@ -1597,39 +1601,20 @@ send_packet(StateData, Packet) -> end. -spec send_header(state(), binary(), binary(), binary()) -> ok | {error, any()}. -send_header(StateData, Server, Version, Lang) - when StateData#state.xml_socket -> - VersionAttr = case Version of - <<"">> -> []; - _ -> [{<<"version">>, Version}] - end, - LangAttr = case Lang of - <<"">> -> []; - _ -> [{<<"xml:lang">>, Lang}] - end, - Header = {xmlstreamstart, <<"stream:stream">>, - VersionAttr ++ - LangAttr ++ - [{<<"xmlns">>, <<"jabber:client">>}, - {<<"xmlns:stream">>, - <<"http://etherx.jabber.org/streams">>}, - {<<"id">>, StateData#state.streamid}, - {<<"from">>, Server}]}, - (StateData#state.sockmod):send_xml(StateData#state.socket, - Header); send_header(StateData, Server, Version, Lang) -> - VersionStr = case Version of - <<"">> -> <<"">>; - _ -> [<<" version='">>, Version, <<"'">>] - end, - LangStr = case Lang of - <<"">> -> <<"">>; - _ -> [<<" xml:lang='">>, Lang, <<"'">>] - end, - Header = io_lib:format(?STREAM_HEADER, - [StateData#state.streamid, Server, VersionStr, - LangStr]), - send_text(StateData, iolist_to_binary(Header)). + Header = #xmlel{name = Name, attrs = Attrs} = + xmpp:encode(#stream_start{version = Version, + lang = Lang, + xmlns = ?NS_CLIENT, + stream_xmlns = ?NS_STREAM, + id = StateData#state.streamid, + from = jid:make(Server)}), + if StateData#state.xml_socket -> + (StateData#state.sockmod):send_xml(StateData#state.socket, + {xmlstreamstart, Name, Attrs}); + true -> + send_text(StateData, fxml:element_to_header(Header)) + end. -spec send_trailer(state()) -> ok | {error, any()}. send_trailer(StateData) diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl index e585257e8..3c3e698ad 100644 --- a/src/ejabberd_s2s.erl +++ b/src/ejabberd_s2s.erl @@ -39,6 +39,7 @@ remove_connection/2, find_connection/2, dirty_get_connections/0, allow_host/2, incoming_s2s_number/0, outgoing_s2s_number/0, + stop_all_connections/0, clean_temporarily_blocked_table/0, list_temporarily_blocked_hosts/0, external_host_overloaded/1, is_temporarly_blocked/1, @@ -480,7 +481,13 @@ get_commands_spec() -> "the node", policy = admin, module = ?MODULE, function = outgoing_s2s_number, - args = [], result = {s2s_outgoing, integer}}]. + args = [], result = {s2s_outgoing, integer}}, + #ejabberd_commands{name = stop_all_connections, + tags = [s2s], + desc = "Stop all outgoing and incoming connections", + policy = admin, + module = ?MODULE, function = stop_all_connections, + args = [], result = {res, rescode}}]. incoming_s2s_number() -> length(supervisor:which_children(ejabberd_s2s_in_sup)). @@ -488,6 +495,15 @@ incoming_s2s_number() -> outgoing_s2s_number() -> length(supervisor:which_children(ejabberd_s2s_out_sup)). +stop_all_connections() -> + lists:foreach( + fun({_Id, Pid, _Type, _Module}) -> + exit(Pid, kill) + end, + supervisor:which_children(ejabberd_s2s_in_sup) ++ + supervisor:which_children(ejabberd_s2s_out_sup)), + mnesia:clear_table(s2s). + %%%---------------------------------------------------------------------- %%% Update Mnesia tables diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index fd560a451..6d1791d0b 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -168,21 +168,26 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) -> try xmpp:decode(#xmlel{name = Name, attrs = Attrs}) of #stream_start{xmlns = NS_SERVER, stream_xmlns = NS_STREAM} when NS_SERVER /= ?NS_SERVER; NS_STREAM /= ?NS_STREAM -> - send_header(StateData, <<" version='1.0'">>), + send_header(StateData, {1,0}), send_element(StateData, xmpp:serr_invalid_namespace()), {stop, normal, StateData}; #stream_start{to = #jid{lserver = Server}, - from = #jid{lserver = From}, - version = <<"1.0">>} + from = From, version = {1,0}} when StateData#state.tls and not StateData#state.authenticated -> - send_header(StateData, <<" version='1.0'">>), + send_header(StateData, {1,0}), Auth = if StateData#state.tls_enabled -> - {Result, Message} = - ejabberd_s2s:check_peer_certificate( - StateData#state.sockmod, - StateData#state.socket, - From), - {Result, From, Message}; + case From of + #jid{} -> + {Result, Message} = + ejabberd_s2s:check_peer_certificate( + StateData#state.sockmod, + StateData#state.socket, + From#jid.lserver), + {Result, From#jid.lserver, Message}; + undefined -> + {error, <<"(unknown)">>, + <<"Got no valid 'from' attribute">>} + end; true -> {no_verify, <<"(unknown)">>, <<"TLS not (yet) enabled">>} end, @@ -225,8 +230,8 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) -> NewStateData#state{server = Server}} end; #stream_start{to = #jid{lserver = Server}, - version = <<"1.0">>} when StateData#state.authenticated -> - send_header(StateData, <<" version='1.0'">>), + version = {1,0}} when StateData#state.authenticated -> + send_header(StateData, {1,0}), send_element(StateData, #stream_features{ sub_els = ejabberd_hooks:run_fold( @@ -236,24 +241,28 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) -> #stream_start{db_xmlns = ?NS_SERVER_DIALBACK} when (StateData#state.tls_required and StateData#state.tls_enabled) or (not StateData#state.tls_required) -> - send_header(StateData, <<"">>), + send_header(StateData, undefined), {next_state, stream_established, StateData}; #stream_start{} -> - send_header(StateData, <<" version='1.0'">>), + send_header(StateData, {1,0}), send_element(StateData, xmpp:serr_undefined_condition()), - {stop, normal, StateData} + {stop, normal, StateData}; + _ -> + send_header(StateData, {1,0}), + send_element(StateData, xmpp:serr_invalid_xml()), + {stop, normal, StateData} catch _:{xmpp_codec, Why} -> Txt = xmpp:format_error(Why), - send_header(StateData, <<" version='1.0'">>), - send_element(StateData, xmpp:serr_not_well_formed(Txt, ?MYLANG)), + send_header(StateData, {1,0}), + send_element(StateData, xmpp:serr_invalid_xml(Txt, ?MYLANG)), {stop, normal, StateData} end; wait_for_stream({xmlstreamerror, _}, StateData) -> - send_header(StateData, <<"">>), + send_header(StateData, {1,0}), send_element(StateData, xmpp:serr_not_well_formed()), {stop, normal, StateData}; wait_for_stream(timeout, StateData) -> - send_header(StateData, <<"">>), + send_header(StateData, {1,0}), send_element(StateData, xmpp:serr_connection_timeout()), {stop, normal, StateData}; wait_for_stream(closed, StateData) -> @@ -277,13 +286,21 @@ wait_for_feature_request(#starttls{}, StateData#state.tls_options, {certfile, CertFile}) end, + TLSOpts2 = case ejabberd_config:get_option( + {s2s_cafile, StateData#state.server}, + fun iolist_to_binary/1) of + undefined -> TLSOpts1; + CAFile -> + lists:keystore(cafile, 1, TLSOpts1, + {cafile, CAFile}) + end, TLSOpts = case ejabberd_config:get_option( {s2s_tls_compression, StateData#state.server}, fun(true) -> true; (false) -> false end, false) of - true -> lists:delete(compression_none, TLSOpts1); - false -> [compression_none | TLSOpts1] + true -> lists:delete(compression_none, TLSOpts2); + false -> [compression_none | TLSOpts2] end, TLSSocket = (StateData#state.sockmod):starttls( Socket, TLSOpts, @@ -293,8 +310,7 @@ wait_for_feature_request(#starttls{}, StateData#state{socket = TLSSocket, streamid = new_id(), tls_enabled = true, tls_options = TLSOpts}}; _ -> - Txt = <<"Unsupported TLS transport">>, - send_element(StateData, xmpp:serr_policy_violation(Txt, ?MYLANG)), + send_element(StateData, #starttls_failure{}), {stop, normal, StateData} end; wait_for_feature_request(#sasl_auth{mechanism = Mech}, @@ -313,7 +329,10 @@ wait_for_feature_request(#sasl_auth{mechanism = Mech}, StateData#state{streamid = new_id(), authenticated = true}}; true -> - send_element(StateData, #sasl_failure{}), + Txt = xmpp:mk_text(<<"Denied by ACL">>, ?MYLANG), + send_element(StateData, + #sasl_failure{reason = 'not-authorized', + text = Txt}), {stop, normal, StateData} end; _ -> @@ -495,7 +514,7 @@ handle_info({send_text, Text}, StateName, StateData) -> handle_info({timeout, Timer, _}, StateName, #state{timer = Timer} = StateData) -> if StateName == wait_for_stream -> - send_header(StateData, <<"">>); + send_header(StateData, undefined); true -> ok end, @@ -555,15 +574,15 @@ send_error(StateData, Stanza, Error) -> send_trailer(StateData) -> send_text(StateData, <<"">>). --spec send_header(state(), binary()) -> ok. +-spec send_header(state(), undefined | {integer(), integer()}) -> ok. send_header(StateData, Version) -> - send_text(StateData, - <<"">>). + Header = xmpp:encode( + #stream_start{xmlns = ?NS_SERVER, + stream_xmlns = ?NS_STREAM, + db_xmlns = ?NS_SERVER_DIALBACK, + id = StateData#state.streamid, + version = Version}), + send_text(StateData, fxml:element_to_header(Header)). -spec change_shaper(state(), binary(), jid()) -> ok. change_shaper(StateData, Host, JID) -> @@ -606,9 +625,14 @@ fsm_limit_opts(Opts) -> end end. --spec decode_element(xmlel(), state_name(), state()) -> fsm_transition(). +-spec decode_element(xmlel() | xmpp_element(), state_name(), state()) -> fsm_transition(). decode_element(#xmlel{} = El, StateName, StateData) -> - try xmpp:decode(El) of + Opts = if StateName == stream_established -> + [ignore_els]; + true -> + [] + end, + try xmpp:decode(El, Opts) of Pkt -> ?MODULE:StateName(Pkt, StateData) catch error:{xmpp_codec, Why} -> case xmpp:is_stanza(El) of @@ -620,12 +644,15 @@ decode_element(#xmlel{} = El, StateName, StateData) -> ok end, {next_state, StateName, StateData} - end. + end; +decode_element(Pkt, StateName, StateData) -> + ?MODULE:StateName(Pkt, StateData). opt_type(domain_certfile) -> fun iolist_to_binary/1; opt_type(max_fsm_queue) -> fun (I) when is_integer(I), I > 0 -> I end; opt_type(s2s_certfile) -> fun iolist_to_binary/1; +opt_type(s2s_cafile) -> fun iolist_to_binary/1; opt_type(s2s_ciphers) -> fun iolist_to_binary/1; opt_type(s2s_dhfile) -> fun iolist_to_binary/1; opt_type(s2s_protocol_options) -> @@ -647,6 +674,6 @@ opt_type(s2s_use_starttls) -> (required_trusted) -> required_trusted end; opt_type(_) -> - [domain_certfile, max_fsm_queue, s2s_certfile, + [domain_certfile, max_fsm_queue, s2s_certfile, s2s_cafile, s2s_ciphers, s2s_dhfile, s2s_protocol_options, s2s_tls_compression, s2s_use_starttls]. diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index dd37445d7..06ba16863 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -106,12 +106,6 @@ %% Specified in miliseconds. Default value is 5 minutes. -define(MAX_RETRY_DELAY, 300000). --define(STREAM_HEADER, - <<"">>). - -define(SOCKET_DEFAULT_RESULT, {error, badarg}). %%%---------------------------------------------------------------------- @@ -228,9 +222,8 @@ open_socket(init, StateData) -> ?SOCKET_DEFAULT_RESULT, AddrList) of {ok, Socket} -> - Version = if StateData#state.use_v10 -> - <<" version='1.0'">>; - true -> <<"">> + Version = if StateData#state.use_v10 -> {1,0}; + true -> undefined end, NewStateData = StateData#state{socket = Socket, tls_enabled = false, @@ -318,11 +311,10 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData0) -> {stop, normal, StateData}; #stream_start{xmlns = NS_SERVER, stream_xmlns = NS_STREAM} when NS_SERVER /= ?NS_SERVER; NS_STREAM /= ?NS_STREAM -> - send_header(StateData, <<" version='1.0'">>), send_element(StateData, xmpp:serr_invalid_namespace()), {stop, normal, StateData}; #stream_start{db_xmlns = ?NS_SERVER_DIALBACK, id = ID, - version = V} when V /= <<"1.0">> -> + version = V} when V /= {1,0} -> send_db_request(StateData#state{remote_streamid = ID}); #stream_start{db_xmlns = ?NS_SERVER_DIALBACK, id = ID} when StateData#state.use_v10 -> @@ -337,13 +329,14 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData0) -> StateData#state{db_enabled = false, remote_streamid = ID}, ?FSMTIMEOUT}; #stream_start{} -> - send_header(StateData, <<"">>), send_element(StateData, xmpp:serr_invalid_namespace()), - {stop, normal, StateData} + {stop, normal, StateData}; + _ -> + send_element(StateData, xmpp:serr_invalid_xml()), + {stop, normal, StateData} catch _:{xmpp_codec, Why} -> Txt = xmpp:format_error(Why), - send_header(StateData, <<" version='1.0'">>), - send_element(StateData, xmpp:serr_not_well_formed(Txt, ?MYLANG)), + send_element(StateData, xmpp:serr_invalid_xml(Txt, ?MYLANG)), {stop, normal, StateData} end; wait_for_stream(Event, StateData) -> @@ -469,7 +462,7 @@ wait_for_auth_result({xmlstreamelement, El}, StateData) -> wait_for_auth_result(#sasl_success{}, StateData) -> ?DEBUG("auth: ~p", [{StateData#state.myname, StateData#state.server}]), ejabberd_socket:reset_stream(StateData#state.socket), - send_header(StateData, <<" version='1.0'">>), + send_header(StateData, {1,0}), {next_state, wait_for_stream, StateData#state{streamid = new_id(), authenticated = true}, ?FSMTIMEOUT}; @@ -500,7 +493,7 @@ wait_for_starttls_proceed(#starttls_proceed{}, StateData) -> streamid = new_id(), tls_enabled = true, tls_options = TLSOpts}, - send_header(NewStateData, <<" version='1.0'">>), + send_header(NewStateData, {1,0}), {next_state, wait_for_stream, NewStateData, ?FSMTIMEOUT}; wait_for_starttls_proceed(Event, StateData) -> handle_unexpected_event(Event, wait_for_starttls_proceed, StateData). @@ -567,7 +560,8 @@ handle_unexpected_event(Event, StateName, StateData) -> {xmlstreamend, _} -> ?INFO_MSG("Closing s2s connection ~s -> ~s in state ~s: " "XML stream closed by peer", - [StateData#state.myname, StateData#state.server]), + [StateData#state.myname, StateData#state.server, + StateName]), {stop, normal, StateData}; timeout -> send_element(StateData, xmpp:serr_connection_timeout()), @@ -741,6 +735,7 @@ print_state(State) -> State. -spec send_text(state(), iodata()) -> ok. send_text(StateData, Text) -> + ?DEBUG("Send Text on stream = ~s", [Text]), ejabberd_socket:send(StateData#state.socket, Text). -spec send_element(state(), xmpp_element()) -> ok. @@ -748,15 +743,16 @@ send_element(StateData, El) -> El1 = fix_ns(xmpp:encode(El)), send_text(StateData, fxml:element_to_binary(El1)). --spec send_header(state(), binary()) -> ok. +-spec send_header(state(), undefined | {integer(), integer()}) -> ok. send_header(StateData, Version) -> - Txt = io_lib:format( - "", - [StateData#state.myname, StateData#state.server, Version]), - send_text(StateData, Txt). + Header = xmpp:encode( + #stream_start{xmlns = ?NS_SERVER, + stream_xmlns = ?NS_STREAM, + db_xmlns = ?NS_SERVER_DIALBACK, + from = jid:make(StateData#state.myname), + to = jid:make(StateData#state.server), + version = Version}), + send_text(StateData, fxml:element_to_header(Header)). -spec send_trailer(state()) -> ok. send_trailer(StateData) -> diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index f4338593d..46d32e4fd 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -149,6 +149,10 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) -> #stream_start{} -> send_header(StateData, ?MYNAME), send_element(StateData, xmpp:serr_improper_addressing()), + {stop, normal, StateData}; + _ -> + send_header(StateData, ?MYNAME), + send_element(StateData, xmpp:serr_invalid_xml()), {stop, normal, StateData} catch _:{xmpp_codec, Why} -> Txt = xmpp:format_error(Why), @@ -319,13 +323,12 @@ send_error(StateData, Stanza, Error) -> -spec send_header(state(), binary()) -> ok. send_header(StateData, Host) -> - send_text(StateData, - io_lib:format( - <<"">>, - [StateData#state.streamid, fxml:crypt(Host)])). + Header = xmpp:encode( + #stream_start{xmlns = ?NS_COMPONENT, + stream_xmlns = ?NS_STREAM, + from = jid:make(Host), + id = StateData#state.streamid}), + send_text(StateData, fxml:element_to_header(Header)). -spec send_trailer(state()) -> ok. send_trailer(StateData) -> diff --git a/src/xmpp_codec.erl b/src/xmpp_codec.erl index 00ee53aaf..0a9258195 100644 --- a/src/xmpp_codec.erl +++ b/src/xmpp_codec.erl @@ -3955,6 +3955,14 @@ pp(upload_slot, 3) -> [get, put, xmlns]; pp(thumbnail, 4) -> [uri, 'media-type', width, height]; pp(_, _) -> no. +enc_version({Maj, Min}) -> + <<(integer_to_binary(Maj))/binary, $., + (integer_to_binary(Min))/binary>>. + +dec_version(S) -> + [Major, Minor] = binary:split(S, <<$.>>), + {binary_to_integer(Major), binary_to_integer(Minor)}. + enc_host_port(Host) when is_binary(Host) -> Host; enc_host_port({{_, _, _, _, _, _, _, _} = IPv6, Port}) -> @@ -5284,13 +5292,20 @@ encode_stream_start_attr_xmlns(_val, _acc) -> decode_stream_start_attr_version(__TopXMLNS, undefined) -> - <<>>; + undefined; decode_stream_start_attr_version(__TopXMLNS, _val) -> - _val. + case catch dec_version(_val) of + {'EXIT', _} -> + erlang:error({xmpp_codec, + {bad_attr_value, <<"version">>, <<"stream:stream">>, + __TopXMLNS}}); + _res -> _res + end. -encode_stream_start_attr_version(<<>>, _acc) -> _acc; +encode_stream_start_attr_version(undefined, _acc) -> + _acc; encode_stream_start_attr_version(_val, _acc) -> - [{<<"version">>, _val} | _acc]. + [{<<"version">>, enc_version(_val)} | _acc]. decode_stream_start_attr_id(__TopXMLNS, undefined) -> <<>>; diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index dbcd9a905..063f51bd1 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -20,13 +20,13 @@ make_iq_result/1, start_event_relay/0, stop_event_relay/1, put_event/2, get_event/1, bind/1, auth/1, auth/2, open_session/1, open_session/2, - zlib/1, starttls/1, close_socket/1, init_stream/1, - auth_legacy/2, auth_legacy/3]). + zlib/1, starttls/1, starttls/2, close_socket/1, init_stream/1, + auth_legacy/2, auth_legacy/3, tcp_connect/1, send_text/2]). -include("suite.hrl"). suite() -> - [{timetrap, {seconds,10}}]. + [{timetrap, {seconds,30}}]. init_per_suite(Config) -> NewConfig = init_config(Config), @@ -36,6 +36,10 @@ init_per_suite(Config) -> LDIFFile = filename:join([DataDir, "ejabberd.ldif"]), {ok, _} = file:copy(ExtAuthScript, filename:join([CWD, "extauth.py"])), {ok, _} = ldap_srv:start(LDIFFile), + inet_db:add_host({127,0,0,1}, [binary_to_list(?S2S_VHOST), + binary_to_list(?MNESIA_VHOST)]), + inet_db:set_domain(binary_to_list(randoms:get_string())), + inet_db:set_lookup([file, native]), start_ejabberd(NewConfig), NewConfig. @@ -125,6 +129,16 @@ do_init_per_group(riak, Config) -> Err -> {skip, {riak_not_available, Err}} end; +do_init_per_group(s2s, Config) -> + ejabberd_config:add_option(s2s_use_starttls, required_trusted), + ejabberd_config:add_option(domain_certfile, "cert.pem"), + Port = ?config(s2s_port, Config), + set_opt(server, ?COMMON_VHOST, + set_opt(xmlns, ?NS_SERVER, + set_opt(type, server, + set_opt(server_port, Port, + set_opt(stream_from, ?S2S_VHOST, + set_opt(lang, <<"">>, Config)))))); do_init_per_group(component, Config) -> Server = ?config(server, Config), Port = ?config(component_port, Config), @@ -132,7 +146,7 @@ do_init_per_group(component, Config) -> set_opt(server, <<"component.", Server/binary>>, set_opt(type, component, set_opt(server_port, Port, - set_opt(stream_version, <<"">>, + set_opt(stream_version, undefined, set_opt(lang, <<"">>, Config)))))); do_init_per_group(_GroupName, Config) -> Pid = start_event_relay(), @@ -158,6 +172,8 @@ end_per_group(riak, _Config) -> ok; end_per_group(component, _Config) -> ok; +end_per_group(s2s, _Config) -> + ejabberd_config:add_option(s2s_use_starttls, false); end_per_group(_GroupName, Config) -> stop_event_relay(Config), ok. @@ -215,7 +231,7 @@ init_per_testcase(TestCase, OrigConfig) -> "test_connect" ++ _ -> Config; "test_legacy_auth" ++ _ -> - init_stream(set_opt(stream_version, <<"">>, Config)); + init_stream(set_opt(stream_version, undefined, Config)); "test_auth" ++ _ -> connect(Config); "test_starttls" ++ _ -> @@ -244,6 +260,8 @@ init_per_testcase(TestCase, OrigConfig) -> Password = ?config(password, Config), ejabberd_auth:try_register(User, Server, Password), open_session(bind(auth(connect(Config)))); + _ when TestGroup == s2s_tests -> + auth(connect(starttls(connect(Config)))); _ -> open_session(bind(auth(connect(Config)))) end. @@ -262,6 +280,7 @@ legacy_auth_tests() -> no_db_tests() -> [{generic, [parallel], [test_connect_bad_xml, + test_connect_unexpected_xml, test_connect_unknown_ns, test_connect_bad_xmlns, test_connect_bad_ns_stream, @@ -286,7 +305,12 @@ no_db_tests() -> time, stats, disco]}, - {presence, [sequence], [presence]}, + {presence_and_s2s, [sequence], + [presence, + s2s_dialback, + s2s_optional, + s2s_required, + s2s_required_trusted]}, {sm, [sequence], [sm, sm_resume, @@ -433,18 +457,39 @@ extauth_tests() -> test_unregister]}]. component_tests() -> - [{component_tests, [sequence], + [{component_connect, [parallel], [test_connect_bad_xml, + test_connect_unexpected_xml, test_connect_unknown_ns, test_connect_bad_xmlns, test_connect_bad_ns_stream, test_connect_missing_to, test_connect, test_auth, - test_auth_fail, - component_missing_address, - component_invalid_from, - component_send, + test_auth_fail]}, + {component_tests, [sequence], + [test_missing_address, + test_invalid_from, + test_component_send, + bad_nonza, + codec_failure]}]. + +s2s_tests() -> + [{s2s_connect, [parallel], + [test_connect_bad_xml, + test_connect_unexpected_xml, + test_connect_unknown_ns, + test_connect_bad_xmlns, + test_connect_bad_ns_stream, + test_connect, + test_connect_s2s_starttls_required, + test_starttls, + test_connect_missing_from, + test_connect_s2s_unauthenticated_iq, + test_auth_starttls]}, + {s2s_tests, [sequence], + [test_missing_address, + test_invalid_from, bad_nonza, codec_failure]}]. @@ -453,6 +498,7 @@ groups() -> {extauth, [sequence], extauth_tests()}, {no_db, [sequence], no_db_tests()}, {component, [sequence], component_tests()}, + {s2s, [sequence], s2s_tests()}, {mnesia, [sequence], db_tests(mnesia)}, {redis, [sequence], db_tests(redis)}, {mysql, [sequence], db_tests(mysql)}, @@ -461,16 +507,17 @@ groups() -> {riak, [sequence], db_tests(riak)}]. all() -> - [{group, component}, - %%{group, ldap}, + [{group, ldap}, {group, no_db}, {group, mnesia}, - %%{group, redis}, - %%{group, mysql}, - %%{group, pgsql}, - %%{group, sqlite}, - %%{group, extauth}, - %%{group, riak}, + {group, redis}, + {group, mysql}, + {group, pgsql}, + {group, sqlite}, + {group, extauth}, + {group, riak}, + {group, component}, + {group, s2s}, stop_ejabberd]. stop_ejabberd(Config) -> @@ -480,11 +527,23 @@ stop_ejabberd(Config) -> Config. test_connect_bad_xml(Config) -> - Config0 = init_stream(set_opt(xmlns, <<"'">>, Config)), + Config0 = tcp_connect(Config), + send_text(Config0, <<"<'/>">>), + Version = ?config(stream_version, Config0), + ?recv1(#stream_start{version = Version}), ?recv1(#stream_error{reason = 'not-well-formed'}), ?recv1({xmlstreamend, <<"stream:stream">>}), close_socket(Config0). +test_connect_unexpected_xml(Config) -> + Config0 = tcp_connect(Config), + send(Config0, #caps{}), + Version = ?config(stream_version, Config0), + ?recv1(#stream_start{version = Version}), + ?recv1(#stream_error{reason = 'invalid-xml'}), + ?recv1({xmlstreamend, <<"stream:stream">>}), + close_socket(Config0). + test_connect_unknown_ns(Config) -> Config0 = init_stream(set_opt(xmlns, <<"wrong">>, Config)), ?recv1(#stream_error{reason = 'invalid-xml'}), @@ -492,7 +551,11 @@ test_connect_unknown_ns(Config) -> close_socket(Config0). test_connect_bad_xmlns(Config) -> - Config0 = init_stream(set_opt(xmlns, ?NS_SERVER, Config)), + NS = case ?config(type, Config) of + client -> ?NS_SERVER; + _ -> ?NS_CLIENT + end, + Config0 = init_stream(set_opt(xmlns, NS, Config)), ?recv1(#stream_error{reason = 'invalid-namespace'}), ?recv1({xmlstreamend, <<"stream:stream">>}), close_socket(Config0). @@ -521,19 +584,32 @@ test_connect_missing_to(Config) -> ?recv1({xmlstreamend, <<"stream:stream">>}), close_socket(Config0). +test_connect_missing_from(Config) -> + Config1 = starttls(connect(Config)), + Config2 = set_opt(stream_from, <<"">>, Config1), + Config3 = init_stream(Config2), + ?recv1(#stream_error{reason = 'policy-violation'}), + ?recv1({xmlstreamend, <<"stream:stream">>}), + close_socket(Config3). + test_connect(Config) -> disconnect(connect(Config)). -test_component_connect(Config) -> - disconnect(component_connect(Config)). +test_connect_s2s_starttls_required(Config) -> + Config1 = connect(Config), + send(Config1, #caps{}), + ?recv1(#stream_error{reason = 'policy-violation'}), + ?recv1({xmlstreamend, <<"stream:stream">>}), + close_socket(Config1). -component_connect(Config) -> - init_stream(Config). +test_connect_s2s_unauthenticated_iq(Config) -> + Config1 = connect(starttls(connect(Config))), + unauthenticated_iq(Config1). test_starttls(Config) -> case ?config(starttls, Config) of true -> - disconnect(starttls(Config)); + disconnect(connect(starttls(Config))); _ -> {skipped, 'starttls_not_available'} end. @@ -597,8 +673,11 @@ unauthenticated_stanza(Config) -> disconnect(Config). unauthenticated_iq(Config) -> + From = my_jid(Config), + To = server_jid(Config), #iq{type = error} = - send_recv(Config, #iq{type = get, sub_els = [#disco_info{}]}), + send_recv(Config, #iq{type = get, from = From, to = To, + sub_els = [#disco_info{}]}), disconnect(Config). bad_nonza(Config) -> @@ -613,23 +692,57 @@ invalid_from(Config) -> ?recv1({xmlstreamend, <<"stream:stream">>}), close_socket(Config). -component_missing_address(Config) -> +test_missing_address(Config) -> Server = server_jid(Config), #iq{type = error} = send_recv(Config, #iq{type = get, from = Server}), #iq{type = error} = send_recv(Config, #iq{type = get, to = Server}), disconnect(Config). -component_invalid_from(Config) -> +test_invalid_from(Config) -> From = jid:make(randoms:get_string()), To = jid:make(randoms:get_string()), #iq{type = error} = send_recv(Config, #iq{type = get, from = From, to = To}), disconnect(Config). -component_send(Config) -> - JID = my_jid(Config), - send(Config, #message{from = JID, to = JID}), - #message{from = JID, to = JID} = recv(), +test_component_send(Config) -> + To = jid:make(?COMMON_VHOST), + From = server_jid(Config), + #iq{type = result, from = To, to = From} = + send_recv(Config, #iq{type = get, to = To, from = From, + sub_els = [#ping{}]}), + disconnect(Config). + +s2s_dialback(Config) -> + ejabberd_s2s:stop_all_connections(), + ejabberd_config:add_option(s2s_use_starttls, false), + ejabberd_config:add_option(domain_certfile, "self-signed-cert.pem"), + s2s_ping(Config). + +s2s_optional(Config) -> + ejabberd_s2s:stop_all_connections(), + ejabberd_config:add_option(s2s_use_starttls, optional), + ejabberd_config:add_option(domain_certfile, "self-signed-cert.pem"), + s2s_ping(Config). + +s2s_required(Config) -> + ejabberd_s2s:stop_all_connections(), + ejabberd_config:add_option(s2s_use_starttls, required), + ejabberd_config:add_option(domain_certfile, "self-signed-cert.pem"), + s2s_ping(Config). + +s2s_required_trusted(Config) -> + ejabberd_s2s:stop_all_connections(), + ejabberd_config:add_option(s2s_use_starttls, required), + ejabberd_config:add_option(domain_certfile, "cert.pem"), + s2s_ping(Config). + +s2s_ping(Config) -> + From = my_jid(Config), + To = jid:make(?MNESIA_VHOST), + ID = randoms:get_string(), + ejabberd_s2s:route(From, To, #iq{id = ID, type = get, sub_els = [#ping{}]}), + ?recv1(#iq{type = result, id = ID, sub_els = []}), disconnect(Config). auth_md5(Config) -> @@ -674,6 +787,9 @@ test_legacy_auth_fail(Config0) -> test_auth(Config) -> disconnect(auth(Config)). +test_auth_starttls(Config) -> + disconnect(auth(connect(starttls(Config)))). + test_auth_fail(Config0) -> Config = set_opt(user, <<"wrong">>, set_opt(password, <<"wrong">>, Config0)), @@ -1895,7 +2011,6 @@ announce_slave(Config) -> flex_offline_master(Config) -> Peer = ?config(slave, Config), - ct:log("hooks = ~p", [ets:tab2list(hooks)]), LPeer = jid:remove_resource(Peer), lists:foreach( fun(I) -> diff --git a/test/ejabberd_SUITE_data/ca.key b/test/ejabberd_SUITE_data/ca.key new file mode 100644 index 000000000..858100686 --- /dev/null +++ b/test/ejabberd_SUITE_data/ca.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAxGSSFSDTbBTk2GwkORLCXoBdYq5YxwPfen8bK+8WjxRb9Thp +FsHYfImtDQV0qvcZyWnjUFxRh7Dyw7A2X690nplCdzZ9Gl+5yzzlRefHborMSnNY +rnTqx3vs9qiac0A5bzdjMY7XN3VuVwz0XWY6rAiL/7OxunCNUnQz+oswDx7cj1W4 +bb9pFzBvW5TjaAiziyzS3IxvTc7kYQYJEa99vIlDZ+Ov9rHtiF/5CZ8kHc457B3s +uc9hHxO2t0EzmBiqg7wpksJjoJeXaJvT9sKSgW6LXkjBCm/7jm1ElPq+7FCph0qp +uIsxMtu15exLKQaSRLcc+tyNkWIZGQ371D2+7wIDAQABAoIBACzcNCozV1fm5ecx +vIx05oUjmTFDVfAPyGp4wkIk2OhR5Dd9bTPPj53S7P5+coni67cAQvZGQDFYj/t3 +MtRkhaT8qRwGDEmL+CqefFidewabGdMfye//sOlkO1qUZMNStkvbQQM+95Ypcszb +nq3+/gPx59i+uSg3MXDWLlFand217d8oU4JxmCxHc9ezhkpWsdReiAukWTud+q/5 +DzyPetaP09z8Ua/YNXuI6IdsvObYxOSCI1hPPuMSQGM4hQiqkHPqPNBIJDwfM9wk +WzGom5M7nGitrKynJHdS2VRzsZwFL3Hg0yBXnSY1o8er5A6i5//dS2ISSEN9xHjz +9PRRCbECgYEA+yVmv8i5uBLuz/Oeu/iOcX9ZNHfNowuIpInWVyfVhURIc1OwP1Sy +uj5Qst2IY+Hm4IVq0sNg3cZdEk+K6RMyc/Qgd7GoYeJNKH1v0RbA6E1zEzqm8Xv+ +jA3dd7RLb5NTwFv11Qh0BDZfw2e8pCmN4oDp+n8fo7RE3NQGaLb77QsCgYEAyDBE +FoYVwXhGaKnhDT1AqM3hkOGBqheJJIxkNUnyMhlU/AxmWtfvTtw7MCP+311bz4Ma +h6yUfaEiHQJs2wkPyIaZ8CbbVyP7bXWMZzA/Rnk4dQWZ/VjRYvEzIvmz9di3w5j6 +P1fWX0QODqcY2CvHyMmPLIysbC0cjVDA4ZpDvC0CgYEAlqvrpuevtCV3rL7F3pPS +MXlrdTTi5AyJX91qAEPfr+I1bSsqM/SGfYHhPE34A6SFtPGWEvgwZx0YvWGHPynL +PRGbYPPuxzrTe5U1vkVeWoAMp96qRXpUToYK9kPudfP3bRI+vB4kLFrKvRrBa+Oa +QeeBeE1IGBiQr8NsTOpq3d0CgYB9R+d0iRlYaKL3oUjcdjbe7Wl6uAXjorMLEmks +CEjwHXZX/pKXy4dSPPU1nXFF7DEm3o9d1R1gudSVfw0MztD313TDHC4sjLIuwF/L +vB/9RKOWaJkEOe9gEj7EZqy+8I+gcz45IglguUBq3xvnPQ7ck3dsk+TcFidGMQFk +rpwxSQKBgQDbdzOJagPep0HVJPkOmF1X4idb1rnQUuMi59I3k6lFTXAaypy6nU69 +aAUgv7UY4i3XglEhbztk/o51W4/fJ1N8UzbXlBur/pJD8GN2h52ea77CbpOAmDSm +Bjjoj92wmYGfBRf7DwJQDgqxvpa0s1cwtYjNf0RmbDPzBsfzrKLKbQ== +-----END RSA PRIVATE KEY----- diff --git a/test/ejabberd_SUITE_data/ca.pem b/test/ejabberd_SUITE_data/ca.pem new file mode 100644 index 000000000..3daa7f5d6 --- /dev/null +++ b/test/ejabberd_SUITE_data/ca.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIJAKI8WTrCnPXzMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTUwNDE1MTQxNTI0WhcNNDIwODMxMTQxNTI0WjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAxGSSFSDTbBTk2GwkORLCXoBdYq5YxwPfen8bK+8WjxRb9ThpFsHYfImt +DQV0qvcZyWnjUFxRh7Dyw7A2X690nplCdzZ9Gl+5yzzlRefHborMSnNYrnTqx3vs +9qiac0A5bzdjMY7XN3VuVwz0XWY6rAiL/7OxunCNUnQz+oswDx7cj1W4bb9pFzBv +W5TjaAiziyzS3IxvTc7kYQYJEa99vIlDZ+Ov9rHtiF/5CZ8kHc457B3suc9hHxO2 +t0EzmBiqg7wpksJjoJeXaJvT9sKSgW6LXkjBCm/7jm1ElPq+7FCph0qpuIsxMtu1 +5exLKQaSRLcc+tyNkWIZGQ371D2+7wIDAQABo4GnMIGkMB0GA1UdDgQWBBTQ9mbL +xyIyE3pDyrNMsC36DRHp+TB1BgNVHSMEbjBsgBTQ9mbLxyIyE3pDyrNMsC36DRHp ++aFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV +BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAKI8WTrCnPXzMAwGA1UdEwQF +MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAGyAi//UQaUhy8RLGc33T36Ni6TnRgpz +1xu2aahMe0YfPUZsZwwCP6dK+6fSw7OsRqyXZNZJntlur30yMMDlvjXmV6UDzeS4 +/HGd/hr0LqruYpmvOKmvT/y8VkmBqsGlcaRNhSJGDzMHAVEQ0hzAJe3Emw5R753p +iVRbxPqiOVt4U/gjwtrVumSt1v9O4buWo1lTp0jxK1L6K8YWmETLuxyS3IG+i9Ij +DDNyU/UxyocP/mcscUAoV9MJX56exwPC93rPxOlwJT5e5ZMRGnwwUt017dPUrKbA +u+24S8uJCKN2w0OzsrqzC6lvxOf0JRfNxxxGr1KZYyEGT7ps1jhTebA= +-----END CERTIFICATE----- diff --git a/test/ejabberd_SUITE_data/cert.pem b/test/ejabberd_SUITE_data/cert.pem index 11e18491f..ee9cf1641 100644 --- a/test/ejabberd_SUITE_data/cert.pem +++ b/test/ejabberd_SUITE_data/cert.pem @@ -1,52 +1,54 @@ -----BEGIN CERTIFICATE----- -MIIGbDCCBVSgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJBVTET +MIIEmTCCA4GgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJBVTET MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ -dHkgTHRkMB4XDTE2MDUyNDE3NDIyNVoXDTQzMTAxMDE3NDIyNVowVjELMAkGA1UE +dHkgTHRkMB4XDTE2MDkyMzA3MDMyNFoXDTQ0MDIwOTA3MDMyNFowVjELMAkGA1UE BhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp -ZGdpdHMgUHR5IEx0ZDEPMA0GA1UEAxMGYWN0aXZlMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQC+GTA1D1+yiXgLqUhJXkSj3hj5FiqlBAfJT/8OSXYifY4M4HYv -VQrqER2Fs7jdCaeoGWDvwfK/UOV0b1ROnf+T/2bXFs8EOeqjOz4xG2oexNKVrYj9 -ICYAgmSh6Hf2cZJM/YCAISje93Xl2J2w/N7oFC1ZXasPoBIZv3Fgg7hTtQIDAQAB -o4ID2DCCA9QwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5l -cmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFEynWiCoZK4tLDk3KM1wMsbrz9Ug -MB8GA1UdIwQYMBaAFND2ZsvHIjITekPKs0ywLfoNEen5MDMGA1UdHwQsMCowKKAm -oCSGImh0dHA6Ly9sb2NhbGhvc3Q6NTI4MC9kYXRhL2NybC5kZXIwNgYIKwYBBQUH -AQEEKjAoMCYGCCsGAQUFBzABhhpodHRwOi8vbG9jYWxob3N0OjUyODAvb2NzcDAL -BgNVHQ8EBAMCBeAwEwYDVR0lBAwwCgYIKwYBBQUHAwkwggLIBgNVHREEggK/MIIC -u6A4BggrBgEFBQcIBaAsDCp0ZXN0X3NpbmdsZSEjJCVeKigpYH4rLTtfPVtde318 -XEBsb2NhbGhvc3SgPwYIKwYBBQUHCAWgMwwxdGVzdF9zaW5nbGUhIyQlXiooKWB+ -Ky07Xz1bXXt9fFxAbW5lc2lhLmxvY2FsaG9zdKA+BggrBgEFBQcIBaAyDDB0ZXN0 -X3NpbmdsZSEjJCVeKigpYH4rLTtfPVtde318XEBteXNxbC5sb2NhbGhvc3SgPgYI -KwYBBQUHCAWgMgwwdGVzdF9zaW5nbGUhIyQlXiooKWB+Ky07Xz1bXXt9fFxAcGdz -cWwubG9jYWxob3N0oD8GCCsGAQUFBwgFoDMMMXRlc3Rfc2luZ2xlISMkJV4qKClg -fistO189W117fXxcQHNxbGl0ZS5sb2NhbGhvc3SgQAYIKwYBBQUHCAWgNAwydGVz -dF9zaW5nbGUhIyQlXiooKWB+Ky07Xz1bXXt9fFxAZXh0YXV0aC5sb2NhbGhvc3Sg -PQYIKwYBBQUHCAWgMQwvdGVzdF9zaW5nbGUhIyQlXiooKWB+Ky07Xz1bXXt9fFxA -bGRhcC5sb2NhbGhvc3SgPQYIKwYBBQUHCAWgMQwvdGVzdF9zaW5nbGUhIyQlXioo -KWB+Ky07Xz1bXXt9fFxAcDFkYi5sb2NhbGhvc3SgPQYIKwYBBQUHCAWgMQwvdGVz -dF9zaW5nbGUhIyQlXiooKWB+Ky07Xz1bXXt9fFxAcmlhay5sb2NhbGhvc3SgPgYI -KwYBBQUHCAWgMgwwdGVzdF9zaW5nbGUhIyQlXiooKWB+Ky07Xz1bXXt9fFxAcmVk -aXMubG9jYWxob3N0oD4GCCsGAQUFBwgFoDIMMHRlc3Rfc2luZ2xlISMkJV4qKClg -fistO189W117fXxcQG1zc3FsLmxvY2FsaG9zdDANBgkqhkiG9w0BAQUFAAOCAQEA -et4jpmpwlE+2bw+/iqCt7sfU/5nPmQ8YtgMB+32wf7DINNJgkwOdkYJpzhlMXKrh -/bn8+Ybmq6MbK0r2R91Uu858xQf8VKExQm44qaGSyL5Ug3jsAWb3GLZSaWQo37e9 -QdDeP8XijCEyr3rum19tRIdiImsRAxJqwfaE4pUSgfCEQMkvb+6//8HSf9RRPToD -o6eAg8QerEtTfxerEdW/0K1ozOrzSrQembWOu+JjvANRl+p59j+1YOWHzS/yQeZl -K3sjFoCvXPvocRnUznvT+TSdy3ORJSjwfEcP5Crim70amZZ6NeMAxfby9wwmmX0x -zkwPCSUXliXke6T88Olj7Q== +ZGdpdHMgUHR5IEx0ZDEPMA0GA1UEAxMGYWN0aXZlMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAselBnOh089g/VN7gH1m43Vo67kSqh8QRnXZxfjpzt3oP +Dl5nd04eNey4ezoSBo7o1hKhj/m5KLxmy1kN+xssyutgzto1FZu8GC2jDyLvByNL +h0Z3XLmzdzBzBjosCtllJtzHlVL08SPuuOId5hToiiT8h3ElgNI4L6w+eLzhZIk5 +Rj1WojGa+pnaTEgoOaZPcNrkOj81o1tgnbLXN7HY3hJKnRp78DmPySq82cRhvfNr +ePCs6BJr3y7yYJk0nG+EOaj5BK95YSJondZ8fOZuCigJPMogEaSw0SGsSUiQrPsd ++3vZQ+3ctOimnhW7cF3fAM79g+zDdv9N9E3D+inhyQIDAQABo4IBgTCCAX0wCQYD +VR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlm +aWNhdGUwHQYDVR0OBBYEFJgip1fThIyZu9J+YNz3XKDkOcMKMB8GA1UdIwQYMBaA +FND2ZsvHIjITekPKs0ywLfoNEen5MDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly9s +b2NhbGhvc3Q6NTI4MC9kYXRhL2NybC5kZXIwNgYIKwYBBQUHAQEEKjAoMCYGCCsG +AQUFBzABhhpodHRwOi8vbG9jYWxob3N0OjUyODAvb2NzcDALBgNVHQ8EBAMCBeAw +JwYDVR0lBCAwHgYIKwYBBQUHAwkGCCsGAQUFBwMBBggrBgEFBQcDAjBfBgNVHREE +WDBWoBcGCCsGAQUFBwgFoAsMCWxvY2FsaG9zdKAbBggrBgEFBQcIBaAPDA1zMnMu +bG9jYWxob3N0oB4GCCsGAQUFBwgFoBIMEG1uZXNpYS5sb2NhbGhvc3QwDQYJKoZI +hvcNAQEFBQADggEBAEwHeECqeEJIz0VFA0OZ0w9+3rfZPX9K59rbJNNnKVATPhk5 +g5NFpXy1mFTV/3MWjDS1QRbgoXzOYR64S87oez4l3jyDz3YxklyjbbiN3QKaUq5h +284Ze6CiRqxIi6V2bhjjp3voMSP8BQ72bX9uAWjqQl7Z16wYuCzV4QzVZRD5p0c1 +y45WZ6J+sU1GTwEGh0vXZBlDMeTb+53smjEoCxET1ecJmStAvJi+UHiLn63Z3Yzz +CTfdAZ/mj+ytaNLVsgrULXrmZAeo064HVqeyLWL8ZBoM0zLs6u14OQOeDCCB62cj +UXb9npKmIdfsWvdii6emCVQqKBQmHnlUMCh56tE= -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQC+GTA1D1+yiXgLqUhJXkSj3hj5FiqlBAfJT/8OSXYifY4M4HYv -VQrqER2Fs7jdCaeoGWDvwfK/UOV0b1ROnf+T/2bXFs8EOeqjOz4xG2oexNKVrYj9 -ICYAgmSh6Hf2cZJM/YCAISje93Xl2J2w/N7oFC1ZXasPoBIZv3Fgg7hTtQIDAQAB -AoGALddtJJ58eVVlOYqs/+RXsRyR8R9DUV/TcNx1qUBV2KNmafyHA4sCgsd10xQv -9D2rzIGyOp8OpswfSSC/t+WqB9+ezSruzMuX6IURdHZbX6aWWX6maICtPKEEkCmI -gaLxE/ojuOXnTEBTkVuVWtuFL9PsK/WGi/FIDzJbwqTWJ4ECQQDy9DrBAQM96B6u -G4XpFzBsfgJZoS+NaMdCwK+/jgcEpI6oxobK8tuGB6drp5jNSuQ905W9n8XjA6Xq -x8/GH9I5AkEAyE5g05HhMlxBWCq+P70pBDIamdHJcPQVL8+6NXkT+mTqqZxxkUy4 -nMfTh5zE6WfmqYNtrmNBDxXUyaoRSBydXQJACnFnCR7DBekxUGiMc/10LmWoMjQU -eC6Vyg/APiqbsJ5mJ2kJKDYSK4uurZjxn3lloCa1HAZ/GgfxHMtj6e86OQJAetq3 -wIwE12KGIZF1xpo6gfxJHHbzWngaVozN5OYyPq2O0CDH9xpbUK2vK8oXbCDx9J5L -s13lFV+Kd3X7y4LhcQJBAKSFg7ht33l8Sa0TdUkY6Tl1NBMCCLf+np+HYrAbQZux -2NtR6nj2YqeOpEe1ibWZm8tj3dzlTm1FCOIpa+pm114= +MIIEpAIBAAKCAQEAselBnOh089g/VN7gH1m43Vo67kSqh8QRnXZxfjpzt3oPDl5n +d04eNey4ezoSBo7o1hKhj/m5KLxmy1kN+xssyutgzto1FZu8GC2jDyLvByNLh0Z3 +XLmzdzBzBjosCtllJtzHlVL08SPuuOId5hToiiT8h3ElgNI4L6w+eLzhZIk5Rj1W +ojGa+pnaTEgoOaZPcNrkOj81o1tgnbLXN7HY3hJKnRp78DmPySq82cRhvfNrePCs +6BJr3y7yYJk0nG+EOaj5BK95YSJondZ8fOZuCigJPMogEaSw0SGsSUiQrPsd+3vZ +Q+3ctOimnhW7cF3fAM79g+zDdv9N9E3D+inhyQIDAQABAoIBAQCWIyxVx+36YgGA +E927VzIkyqJ0tMncbOAYq/228oj4yy6th4l1Kx1fkHdWtnjDxBJFpc9l+u4ArI1r +Cao8wIAadmxp48dshtJC7TBv86EXuvdgH11XiPcknGRVWv4T4cX099gN8cX3QcWR +jHCC3B4phnD9s8RcZAs6X/cQWQU0mxiHodYJefSXDyRIx9wimXmmW83ZqcsFftXS +MI0+jflmRTf07M4gALVL0LlaBkg2FMoNiaKYPTbubcrEMUgTDsoDsjX3Fi43qLdF +QTq+lF7HrHQ1EQlngCJupka9JxwZc3Fae6XYlDQvSDPcRxzWJoOuVBPtheGeoU3c +PAry9KihAoGBAN8HCb0k4bMN06WZjSzClKhb6eFw4GMbVpDAOwPDl2N+9+pwrGxE +ztekrM+VdXVScIj23g6wKd6fPqK6EYuEEu3Hre82e9ApqjJ34p1UcOs9Vs4N3VDy +HJnWhEytsc9c03O5nhsK1YAXoGHEPmCYGsg2UA171LDcarnO1WDmpKkNAoGBAMw2 +sTCC/LBwgsuPZL5fR10wQ1sr1fIheSL+VK10jSRDwNXT2Y4wdCpQXQ6XNi+n98n5 +VvKaE6PxFqjnKCrUUty8X5+fzVcTKpBYVICceEzpVY9FrKbeY1shMnOBRTCkaQwz +8CoEbbQz6SH5s4qW7M8iJdUJ0RulaFDfpmangTStAoGBALMkMxVjZ4rsI0GT2grG +7KNi2LTFducEUX8JeR2n4JUBql78S/LXPhGGa2x9z5ACPPQ23tyLccYowSXyMR+Q +YafuyO4pJEBrBxNsqnDXH7BEX9I43rkjEAgdf70bk4RNOmdtA+sSw7UUxTVibPwn +kPOadKiv+4JoOa2vzkL8X+yNAoGAbU85OUZkC+2tlViEDILjqDYVV8/3DUxtkxWg +LdidVDQQHGTxpvK4u42Ywh6empPGRw54RBPFP5PlFTPmhEZytEUAymi3eUyBFBKz +6MPYgRLFAZPB/vA7LqRuZPVlG8xljmqeu17zeenveIg4Wo6+44Dbz1UZ4TqAxAlz +AK/YsWECgYAPuZnIo9fWJtUAIe5IA2LIqcN0rj3PsZ/tL6eaMXqKZgCYwTvVUGbT +XD4O352t+yLM8v2hJGHrIPuHooN2dCadYuzoBvVFsRTZjGpBlAZ+EJ5WfDYFL0qf +68O2KZNXaSS8ZARlp9g3C8AFiakm/uWhtSfwx09uSBHJgld1V3GAoA== -----END RSA PRIVATE KEY----- diff --git a/test/ejabberd_SUITE_data/ejabberd.yml b/test/ejabberd_SUITE_data/ejabberd.yml index 99af18bbf..128be2aed 100644 --- a/test/ejabberd_SUITE_data/ejabberd.yml +++ b/test/ejabberd_SUITE_data/ejabberd.yml @@ -409,6 +409,7 @@ acl: user_regexp: "" define_macro: CERTFILE: "cert.pem" + CAFILE: "ca.pem" language: "en" listen: - @@ -450,6 +451,10 @@ Welcome to this XMPP server." mod_time: [] mod_version: [] registration_timeout: infinity +route_subdomains: s2s +domain_certfile: CERTFILE +s2s_use_starttls: false +s2s_cafile: CAFILE shaper: fast: 50000 normal: 1000 diff --git a/test/ejabberd_SUITE_data/extauth.py b/test/ejabberd_SUITE_data/extauth.py index 84c000144..fa2c9efd0 100755 --- a/test/ejabberd_SUITE_data/extauth.py +++ b/test/ejabberd_SUITE_data/extauth.py @@ -7,7 +7,10 @@ def read(): cmd = pkt[0] args_num = len(pkt) - 1 if cmd == 'auth' and args_num >= 3: - write(True) + if pkt[1] == "wrong": + write(False) + else: + write(True) elif cmd == 'isuser' and args_num == 2: write(True) elif cmd == 'setpass' and args_num >= 3: diff --git a/test/ejabberd_SUITE_data/gencerts.sh b/test/ejabberd_SUITE_data/gencerts.sh new file mode 100755 index 000000000..d0acd4b0c --- /dev/null +++ b/test/ejabberd_SUITE_data/gencerts.sh @@ -0,0 +1,18 @@ +#!/bin/sh +# Update openssl.cnf if needed (in particular section [alt_names]) + +rm -rf ssl +mkdir -p ssl/newcerts +touch ssl/index.txt +echo 01 > ssl/serial +echo 1000 > ssl/crlnumber +openssl genrsa -out ssl/client.key +openssl req -new -key ssl/client.key -out ssl/client.csr -config openssl.cnf -batch -subj /C=AU/ST=Some-State/O=Internet\ Widgits\ Pty\ Ltd/CN=active +openssl ca -keyfile ca.key -cert ca.pem -in ssl/client.csr -out ssl/client.crt -config openssl.cnf -days 10000 -batch -notext +openssl req -new -key ssl/client.key -out ssl/self-signed-client.csr -batch -subj /C=AU/ST=Some-State/O=Internet\ Widgits\ Pty\ Ltd/CN=active +openssl x509 -req -in ssl/self-signed-client.csr -signkey ssl/client.key -out ssl/self-signed-client.crt -days 10000 +cat ssl/client.crt > cert.pem +cat ssl/self-signed-client.crt > self-signed-cert.pem +cat ssl/client.key >> cert.pem +cat ssl/client.key >> self-signed-cert.pem +rm -rf ssl diff --git a/test/ejabberd_SUITE_data/openssl.cnf b/test/ejabberd_SUITE_data/openssl.cnf new file mode 100644 index 000000000..ff11d1460 --- /dev/null +++ b/test/ejabberd_SUITE_data/openssl.cnf @@ -0,0 +1,323 @@ +# +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +extensions = v3_req +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] +# We can add new OIDs in here for use by 'ca' and 'req'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +#dir = ./demoCA # Where everything is kept +dir = ssl +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several ctificates with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem# The private key +RANDFILE = $dir/private/.rand # private random number file + +x509_extensions = usr_cert # The extentions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +# crl_extensions = crl_ext + +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = sha1 # which md to use. +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = optional +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = optional +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 1024 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString. +# utf8only: only UTF8Strings. +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings +# so use this option with caution! +string_mask = nombstr + +req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = AU +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Some-State + +localityName = Locality Name (eg, city) + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Internet Widgits Pty Ltd + +# we can do this but it is not needed normally :-) +#1.organizationName = Second Organization Name (eg, company) +#1.organizationName_default = World Wide Web Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) +#organizationalUnitName_default = + +commonName = Common Name (eg, YOUR name) +commonName_max = 64 + +emailAddress = Email Address +emailAddress_max = 64 + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +crlDistributionPoints = URI:http://localhost:5280/data/crl.der +authorityInfoAccess = OCSP;URI:http://localhost:5280/ocsp + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +extendedKeyUsage = OCSPSigning,serverAuth,clientAuth +subjectAltName = @alt_names + +[alt_names] +otherName.1 = 1.3.6.1.5.5.7.8.5;UTF8:"localhost" +otherName.2 = 1.3.6.1.5.5.7.8.5;UTF8:"s2s.localhost" +otherName.3 = 1.3.6.1.5.5.7.8.5;UTF8:"mnesia.localhost" + +[ v3_ca ] +crlDistributionPoints = URI:http://localhost:5280/data/crl.der + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer:always + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +# keyUsage = cRLSign, keyCertSign + +# Some might want this also +# nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always,issuer:always + +[ proxy_cert_ext ] +# These extensions should be added when creating a proxy certificate + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer:always + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This really needs to be in place for it to be a proxy certificate. +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo diff --git a/test/ejabberd_SUITE_data/self-signed-cert.pem b/test/ejabberd_SUITE_data/self-signed-cert.pem new file mode 100644 index 000000000..d6b34f50e --- /dev/null +++ b/test/ejabberd_SUITE_data/self-signed-cert.pem @@ -0,0 +1,46 @@ +-----BEGIN CERTIFICATE----- +MIIDKDCCAhACCQCsLYnJDV1wHDANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJB +VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMQ8wDQYDVQQDEwZhY3RpdmUwHhcNMTYwOTIzMDcwMzI0WhcNNDQw +MjA5MDcwMzI0WjBWMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEh +MB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMQ8wDQYDVQQDEwZhY3Rp +dmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx6UGc6HTz2D9U3uAf +WbjdWjruRKqHxBGddnF+OnO3eg8OXmd3Th417Lh7OhIGjujWEqGP+bkovGbLWQ37 +GyzK62DO2jUVm7wYLaMPIu8HI0uHRndcubN3MHMGOiwK2WUm3MeVUvTxI+644h3m +FOiKJPyHcSWA0jgvrD54vOFkiTlGPVaiMZr6mdpMSCg5pk9w2uQ6PzWjW2Cdstc3 +sdjeEkqdGnvwOY/JKrzZxGG982t48KzoEmvfLvJgmTScb4Q5qPkEr3lhImid1nx8 +5m4KKAk8yiARpLDRIaxJSJCs+x37e9lD7dy06KaeFbtwXd8Azv2D7MN2/030TcP6 +KeHJAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAEAIFwHpNCVUiivAcfkxcUPKp0nn +mhGqkMDRrPA7fOCm0ir1Puz4GQ/G4i+tWejzzFoS6kKQl+sUZAUYJdziftJFFoZ7 +br3q3Xafc2dWa8SHNcHH6lA1OEk8tXlhkNl+EgSLnRGMhIf0iZL2wGjE8Hlig6cu +3h+OpbUijXUmq0XdH+ui3wNgXb7+Tosg/Od+lr0fNjkopsk3t1oiVXD4OQBZdUyq +V5XValiZjMFDUUBdxBA+l6/Qj3bFmluz+FXI8UwfbinukqADTJzkMeUjEkvmKZWO +tb+EU77NIuvg/k7b1yp4lEmATpdUfcGEuhWNtgeh5AqgMxOhAsJ7zUTA80I= +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAselBnOh089g/VN7gH1m43Vo67kSqh8QRnXZxfjpzt3oPDl5n +d04eNey4ezoSBo7o1hKhj/m5KLxmy1kN+xssyutgzto1FZu8GC2jDyLvByNLh0Z3 +XLmzdzBzBjosCtllJtzHlVL08SPuuOId5hToiiT8h3ElgNI4L6w+eLzhZIk5Rj1W +ojGa+pnaTEgoOaZPcNrkOj81o1tgnbLXN7HY3hJKnRp78DmPySq82cRhvfNrePCs +6BJr3y7yYJk0nG+EOaj5BK95YSJondZ8fOZuCigJPMogEaSw0SGsSUiQrPsd+3vZ +Q+3ctOimnhW7cF3fAM79g+zDdv9N9E3D+inhyQIDAQABAoIBAQCWIyxVx+36YgGA +E927VzIkyqJ0tMncbOAYq/228oj4yy6th4l1Kx1fkHdWtnjDxBJFpc9l+u4ArI1r +Cao8wIAadmxp48dshtJC7TBv86EXuvdgH11XiPcknGRVWv4T4cX099gN8cX3QcWR +jHCC3B4phnD9s8RcZAs6X/cQWQU0mxiHodYJefSXDyRIx9wimXmmW83ZqcsFftXS +MI0+jflmRTf07M4gALVL0LlaBkg2FMoNiaKYPTbubcrEMUgTDsoDsjX3Fi43qLdF +QTq+lF7HrHQ1EQlngCJupka9JxwZc3Fae6XYlDQvSDPcRxzWJoOuVBPtheGeoU3c +PAry9KihAoGBAN8HCb0k4bMN06WZjSzClKhb6eFw4GMbVpDAOwPDl2N+9+pwrGxE +ztekrM+VdXVScIj23g6wKd6fPqK6EYuEEu3Hre82e9ApqjJ34p1UcOs9Vs4N3VDy +HJnWhEytsc9c03O5nhsK1YAXoGHEPmCYGsg2UA171LDcarnO1WDmpKkNAoGBAMw2 +sTCC/LBwgsuPZL5fR10wQ1sr1fIheSL+VK10jSRDwNXT2Y4wdCpQXQ6XNi+n98n5 +VvKaE6PxFqjnKCrUUty8X5+fzVcTKpBYVICceEzpVY9FrKbeY1shMnOBRTCkaQwz +8CoEbbQz6SH5s4qW7M8iJdUJ0RulaFDfpmangTStAoGBALMkMxVjZ4rsI0GT2grG +7KNi2LTFducEUX8JeR2n4JUBql78S/LXPhGGa2x9z5ACPPQ23tyLccYowSXyMR+Q +YafuyO4pJEBrBxNsqnDXH7BEX9I43rkjEAgdf70bk4RNOmdtA+sSw7UUxTVibPwn +kPOadKiv+4JoOa2vzkL8X+yNAoGAbU85OUZkC+2tlViEDILjqDYVV8/3DUxtkxWg +LdidVDQQHGTxpvK4u42Ywh6empPGRw54RBPFP5PlFTPmhEZytEUAymi3eUyBFBKz +6MPYgRLFAZPB/vA7LqRuZPVlG8xljmqeu17zeenveIg4Wo6+44Dbz1UZ4TqAxAlz +AK/YsWECgYAPuZnIo9fWJtUAIe5IA2LIqcN0rj3PsZ/tL6eaMXqKZgCYwTvVUGbT +XD4O352t+yLM8v2hJGHrIPuHooN2dCadYuzoBvVFsRTZjGpBlAZ+EJ5WfDYFL0qf +68O2KZNXaSS8ZARlp9g3C8AFiakm/uWhtSfwx09uSBHJgld1V3GAoA== +-----END RSA PRIVATE KEY----- diff --git a/test/suite.erl b/test/suite.erl index f78b7bd1a..e4be0054f 100644 --- a/test/suite.erl +++ b/test/suite.erl @@ -27,13 +27,18 @@ init_config(Config) -> SASLPath = filename:join([PrivDir, "sasl.log"]), MnesiaDir = filename:join([PrivDir, "mnesia"]), CertFile = filename:join([DataDir, "cert.pem"]), + SelfSignedCertFile = filename:join([DataDir, "self-signed-cert.pem"]), + CAFile = filename:join([DataDir, "ca.pem"]), {ok, CWD} = file:get_cwd(), {ok, _} = file:copy(CertFile, filename:join([CWD, "cert.pem"])), + {ok, _} = file:copy(SelfSignedCertFile, + filename:join([CWD, "self-signed-cert.pem"])), + {ok, _} = file:copy(CAFile, filename:join([CWD, "ca.pem"])), {ok, CfgContentTpl} = file:read_file(ConfigPathTpl), Password = <<"password!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>, CfgContent = process_config_tpl(CfgContentTpl, [ {c2s_port, 5222}, - {loglevel, 5}, + {loglevel, 4}, {s2s_port, 5269}, {component_port, 5270}, {web_port, 5280}, @@ -62,6 +67,7 @@ init_config(Config) -> [{server_port, ct:get_config(c2s_port, 5222)}, {server_host, "localhost"}, {component_port, ct:get_config(component_port, 5270)}, + {s2s_port, ct:get_config(s2s_port, 5269)}, {server, ?COMMON_VHOST}, {user, <<"test_single!#$%^*()`~+-;_=[]{}|\\">>}, {master_nick, <<"master_nick!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, @@ -71,11 +77,14 @@ init_config(Config) -> {type, client}, {xmlns, ?NS_CLIENT}, {ns_stream, ?NS_STREAM}, - {stream_version, <<"1.0">>}, + {stream_version, {1, 0}}, {stream_id, <<"">>}, + {stream_from, <<"">>}, + {db_xmlns, <<"">>}, {mechs, []}, {lang, <<"en">>}, {base_dir, BaseDir}, + {socket, undefined}, {resource, <<"resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, {master_resource, <<"master_resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, {slave_resource, <<"slave_resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, @@ -130,42 +139,50 @@ process_config_tpl(Content, [{Name, DefaultValue} | Rest]) -> process_config_tpl(NewContent, Rest). stream_header(Config) -> - NSStream = ?config(ns_stream, Config), - XMLNS = ?config(xmlns, Config), - Lang = case ?config(lang, Config) of - <<"">> -> <<"">>; - L -> iolist_to_binary(["xml:lang='", L, "'"]) - end, To = case ?config(server, Config) of - <<"">> -> <<"">>; - Server -> <<"to='", Server/binary, "'">> + <<"">> -> undefined; + Server -> jid:make(Server) end, - Version = case ?config(stream_version, Config) of - <<"">> -> <<"">>; - V -> <<"version='", V/binary, "'">> - end, - io_lib:format("", - [NSStream, XMLNS, To, Version, Lang]). + From = case ?config(stream_from, Config) of + <<"">> -> undefined; + Frm -> jid:make(Frm) + end, + #stream_start{to = To, + from = From, + lang = ?config(lang, Config), + version = ?config(stream_version, Config), + xmlns = ?config(xmlns, Config), + db_xmlns = ?config(db_xmlns, Config), + stream_xmlns = ?config(ns_stream, Config)}. connect(Config) -> NewConfig = init_stream(Config), case ?config(type, NewConfig) of client -> process_stream_features(NewConfig); + server -> process_stream_features(NewConfig); component -> NewConfig end. +tcp_connect(Config) -> + case ?config(socket, Config) of + undefined -> + {ok, Sock} = ejabberd_socket:connect( + ?config(server_host, Config), + ?config(server_port, Config), + [binary, {packet, 0}, {active, false}]), + set_opt(socket, Sock, Config); + _ -> + Config + end. + init_stream(Config) -> Version = ?config(stream_version, Config), - {ok, Sock} = ejabberd_socket:connect( - ?config(server_host, Config), - ?config(server_port, Config), - [binary, {packet, 0}, {active, false}]), - NewConfig = set_opt(socket, Sock, Config), - ok = send_text(NewConfig, stream_header(NewConfig)), + NewConfig = tcp_connect(Config), + send(NewConfig, stream_header(NewConfig)), XMLNS = case ?config(type, Config) of client -> ?NS_CLIENT; - component -> ?NS_COMPONENT + component -> ?NS_COMPONENT; + server -> ?NS_SERVER end, #stream_start{id = ID, xmlns = XMLNS, version = Version} = recv(), set_opt(stream_id, ID, NewConfig). @@ -206,13 +223,24 @@ close_socket(Config) -> Config. starttls(Config) -> + starttls(Config, false). + +starttls(Config, ShouldFail) -> send(Config, #starttls{}), - #starttls_proceed{} = recv(), - TLSSocket = ejabberd_socket:starttls( - ?config(socket, Config), - [{certfile, ?config(certfile, Config)}, - connect]), - process_stream_features(init_stream(set_opt(socket, TLSSocket, Config))). + case recv() of + #starttls_proceed{} when ShouldFail -> + ct:fail(starttls_should_have_failed); + #starttls_failure{} when ShouldFail -> + Config; + #starttls_failure{} -> + ct:fail(starttls_failed); + #starttls_proceed{} -> + TLSSocket = ejabberd_socket:starttls( + ?config(socket, Config), + [{certfile, ?config(certfile, Config)}, + connect]), + set_opt(socket, TLSSocket, Config) + end. zlib(Config) -> send(Config, #compress{methods = [<<"zlib">>]}), @@ -228,14 +256,19 @@ auth(Config, ShouldFail) -> Mechs = ?config(mechs, Config), HaveMD5 = lists:member(<<"DIGEST-MD5">>, Mechs), HavePLAIN = lists:member(<<"PLAIN">>, Mechs), + HaveExternal = lists:member(<<"EXTERNAL">>, Mechs), if HavePLAIN -> auth_SASL(<<"PLAIN">>, Config, ShouldFail); HaveMD5 -> auth_SASL(<<"DIGEST-MD5">>, Config, ShouldFail); + HaveExternal andalso Type == server -> + auth_SASL(<<"EXTERNAL">>, Config, ShouldFail); Type == client -> auth_legacy(Config, false, ShouldFail); Type == component -> - auth_component(Config, ShouldFail) + auth_component(Config, ShouldFail); + true -> + ct:fail(no_known_sasl_mechanism_available) end. bind(Config) -> @@ -341,10 +374,19 @@ wait_auth_SASL_result(Config, ShouldFail) -> ct:fail(sasl_auth_should_have_failed); #sasl_success{} -> ejabberd_socket:reset_stream(?config(socket, Config)), - send_text(Config, stream_header(Config)), - #stream_start{xmlns = ?NS_CLIENT, version = <<"1.0">>} = recv(), + send(Config, stream_header(Config)), + Type = ?config(type, Config), + NS = if Type == client -> ?NS_CLIENT; + Type == server -> ?NS_SERVER + end, + #stream_start{xmlns = NS, version = {1,0}} = recv(), #stream_features{sub_els = Fs} = recv(), - #xmpp_session{optional = true} = lists:keyfind(xmpp_session, 1, Fs), + if Type == client -> + #xmpp_session{optional = true} = + lists:keyfind(xmpp_session, 1, Fs); + true -> + ok + end, lists:foldl( fun(#feature_sm{}, ConfigAcc) -> set_opt(sm, true, ConfigAcc); @@ -427,7 +469,11 @@ send(State, Pkt) -> end, El = xmpp_codec:encode(NewPkt), ct:pal("sent: ~p <-~n~s", [El, xmpp_codec:pp(NewPkt)]), - ok = send_text(State, fxml:element_to_binary(El)), + Data = case NewPkt of + #stream_start{} -> fxml:element_to_header(El); + _ -> fxml:element_to_binary(El) + end, + ok = send_text(State, Data), NewID. send_recv(State, IQ) -> @@ -437,6 +483,9 @@ send_recv(State, IQ) -> sasl_new(<<"PLAIN">>, User, Server, Password) -> {<>, fun (_) -> {error, <<"Invalid SASL challenge">>} end}; +sasl_new(<<"EXTERNAL">>, _User, _Server, _Password) -> + {<<"">>, + fun(_) -> ct:fail(sasl_challenge_is_not_expected) end}; sasl_new(<<"DIGEST-MD5">>, User, Server, Password) -> {<<"">>, fun (ServerIn) -> @@ -567,11 +616,21 @@ set_opt(Opt, Val, Config) -> wait_for_master(Config) -> put_event(Config, slave_ready), - master_ready = get_event(Config). + case get_event(Config) of + master_ready -> + ok; + Other -> + suite:match_failure([Other], [master_ready]) + end. wait_for_slave(Config) -> put_event(Config, master_ready), - slave_ready = get_event(Config). + case get_event(Config) of + slave_ready -> + ok; + Other -> + suite:match_failure([Other], [slave_ready]) + end. make_iq_result(#iq{from = From} = IQ) -> IQ#iq{type = result, to = From, from = undefined, sub_els = []}. @@ -592,6 +651,7 @@ event_relay() -> event_relay(Events, Subscribers) -> receive {subscribe, From} -> + erlang:monitor(process, From), From ! {ok, self()}, lists:foreach( fun(Event) -> From ! {event, Event, self()} @@ -605,7 +665,14 @@ event_relay(Events, Subscribers) -> (_) -> ok end, Subscribers), - event_relay([Event|Events], Subscribers) + event_relay([Event|Events], Subscribers); + {'DOWN', _MRef, process, Pid, _Info} -> + NewSubscribers = lists:delete(Pid, Subscribers), + lists:foreach( + fun(Subscriber) -> + Subscriber ! {event, peer_down, self()} + end, NewSubscribers), + event_relay(Events, NewSubscribers) end. subscribe_to_events(Config) -> diff --git a/test/suite.hrl b/test/suite.hrl index 3095e1bb5..cbeedff53 100644 --- a/test/suite.hrl +++ b/test/suite.hrl @@ -75,6 +75,7 @@ -define(LDAP_VHOST, <<"ldap.localhost">>). -define(EXTAUTH_VHOST, <<"extauth.localhost">>). -define(RIAK_VHOST, <<"riak.localhost">>). +-define(S2S_VHOST, <<"s2s.localhost">>). insert(Val, N, Tuple) -> L = tuple_to_list(Tuple), diff --git a/tools/xmpp_codec.spec b/tools/xmpp_codec.spec index aa18899c9..7b5ca5e66 100644 --- a/tools/xmpp_codec.spec +++ b/tools/xmpp_codec.spec @@ -3215,7 +3215,9 @@ default = <<"">>}, #attr{name = <<"xml:lang">>, label = '$lang', default = <<"">>}, - #attr{name = <<"version">>, default = <<"">>}, + #attr{name = <<"version">>, + dec = {dec_version, []}, + enc = {enc_version, []}}, #attr{name = <<"id">>, default = <<"">>}]}). -xml(bob_data, @@ -3479,6 +3481,14 @@ enc_host_port({Host, Port}) -> enc_host_port(Addr) -> enc_ip(Addr). +-spec dec_version(_) -> {non_neg_integer(), non_neg_integer()}. +dec_version(S) -> + [Major, Minor] = binary:split(S, <<$.>>), + {binary_to_integer(Major), binary_to_integer(Minor)}. + +enc_version({Maj, Min}) -> + <<(integer_to_binary(Maj))/binary, $., (integer_to_binary(Min))/binary>>. + %% Local Variables: %% mode: erlang %% End: From 58969fb854207637e8c3548c1b2a6a0c865dfe7e Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sat, 24 Sep 2016 14:17:21 +0300 Subject: [PATCH 044/151] Improve namespace handling --- src/ejabberd_c2s.erl | 8 +- src/ejabberd_piefxis.erl | 8 +- src/ejabberd_router.erl | 6 +- src/ejabberd_s2s_in.erl | 18 +- src/ejabberd_s2s_out.erl | 23 +- src/ejabberd_service.erl | 16 +- src/gen_iq_handler.erl | 4 +- src/jd2ejd.erl | 2 +- src/mod_admin_extra.erl | 2 +- src/mod_announce.erl | 4 +- src/mod_mam.erl | 51 +- src/mod_muc_room.erl | 2 +- src/mod_offline.erl | 4 +- src/xmpp.erl | 60 +- src/xmpp_codec.erl | 12218 +++++++++++++++++++++++++------------ test/ejabberd_SUITE.erl | 42 +- test/suite.erl | 54 +- test/suite.hrl | 10 +- tools/xmpp_codec.spec | 41 +- 19 files changed, 8588 insertions(+), 3985 deletions(-) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 858e285a6..d89290d47 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -862,10 +862,10 @@ resource_conflict_action(U, S, R) -> -spec decode_element(xmlel(), state_name(), state()) -> fsm_transition(). decode_element(#xmlel{} = El, StateName, StateData) -> - try case xmpp:decode(El, [ignore_els]) of + try case xmpp:decode(El, ?NS_CLIENT, [ignore_els]) of #iq{sub_els = [_], type = T} = Pkt when T == set; T == get -> NewPkt = xmpp:decode_els( - Pkt, + Pkt, ?NS_CLIENT, fun(SubEl) when StateName == session_established -> case xmpp:get_ns(SubEl) of ?NS_PRIVACY -> true; @@ -873,7 +873,7 @@ decode_element(#xmlel{} = El, StateName, StateData) -> _ -> false end; (SubEl) -> - xmpp_codec:is_known_tag(SubEl) + xmpp:is_known_tag(SubEl) end), ?MODULE:StateName(NewPkt, StateData); Pkt -> @@ -1566,7 +1566,7 @@ send_element(StateData, #xmlel{} = El) when StateData#state.xml_socket -> send_element(StateData, #xmlel{} = El) -> send_text(StateData, fxml:element_to_binary(El)); send_element(StateData, Pkt) -> - send_element(StateData, xmpp:encode(Pkt)). + send_element(StateData, xmpp:encode(Pkt, ?NS_CLIENT)). -spec send_error(state(), xmlel() | stanza(), stanza_error()) -> ok. send_error(StateData, Stanza, Error) -> diff --git a/src/ejabberd_piefxis.erl b/src/ejabberd_piefxis.erl index 7d7d01060..5e6e1bf58 100644 --- a/src/ejabberd_piefxis.erl +++ b/src/ejabberd_piefxis.erl @@ -440,11 +440,11 @@ process_user_el(#xmlel{name = Name, attrs = Attrs, children = Els} = El, process_private(xmpp:decode(El), State); {<<"vCard">>, ?NS_VCARD} -> process_vcard(El, State); - {<<"offline-messages">>, _} -> - Msgs = [xmpp:decode(E, [ignore_els]) || E <- Els], + {<<"offline-messages">>, NS} -> + Msgs = [xmpp:decode(E, NS, [ignore_els]) || E <- Els], process_offline_msgs(Msgs, State); - {<<"presence">>, <<"jabber:client">>} -> - process_presence(xmpp:decode(El, [ignore_els]), State); + {<<"presence">>, ?NS_CLIENT} -> + process_presence(xmpp:decode(El, ?NS_CLIENT, [ignore_els]), State); _ -> {ok, State} end diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl index db82f67ea..c6d919097 100644 --- a/src/ejabberd_router.erl +++ b/src/ejabberd_router.erl @@ -253,7 +253,7 @@ process_iq(From, To, #iq{} = IQ) -> ejabberd_sm:process_iq(From, To, IQ) end; process_iq(From, To, El) -> - try xmpp:decode(El, [ignore_els]) of + try xmpp:decode(El, ?NS_CLIENT, [ignore_els]) of IQ -> process_iq(From, To, IQ) catch _:{xmpp_codec, Why} -> Type = xmpp:get_type(El), @@ -390,7 +390,7 @@ do_route(OrigFrom, OrigTo, OrigPacket) -> LDstDomain = To#jid.lserver, case mnesia:dirty_read(route, LDstDomain) of [] -> - try xmpp:decode(Packet, [ignore_els]) of + try xmpp:decode(Packet, ?NS_CLIENT, [ignore_els]) of Pkt -> ejabberd_s2s:route(From, To, Pkt) catch _:{xmpp_codec, Why} -> @@ -422,7 +422,7 @@ do_route(OrigFrom, OrigTo, OrigPacket) -> -spec do_route(jid(), jid(), xmlel() | xmpp_element(), #route{}) -> any(). do_route(From, To, Packet, #route{local_hint = LocalHint, pid = Pid}) when is_pid(Pid) -> - try xmpp:decode(Packet, [ignore_els]) of + try xmpp:decode(Packet, ?NS_CLIENT, [ignore_els]) of Pkt -> case LocalHint of {apply, Module, Function} when node(Pid) == node() -> diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 6d1791d0b..395a0fce7 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -557,7 +557,7 @@ send_text(StateData, Text) -> -spec send_element(state(), xmpp_element()) -> ok. send_element(StateData, El) -> - El1 = fix_ns(xmpp:encode(El)), + El1 = xmpp:encode(El, ?NS_SERVER), send_text(StateData, fxml:element_to_binary(El1)). -spec send_error(state(), xmlel() | stanza(), stanza_error()) -> ok. @@ -591,20 +591,6 @@ change_shaper(StateData, Host, JID) -> (StateData#state.sockmod):change_shaper(StateData#state.socket, Shaper). --spec fix_ns(xmlel()) -> xmlel(). -fix_ns(#xmlel{name = Name} = El) when Name == <<"message">>; - Name == <<"iq">>; - Name == <<"presence">>; - Name == <<"db:verify">>, - Name == <<"db:result">> -> - Attrs = lists:filter( - fun({<<"xmlns">>, _}) -> false; - (_) -> true - end, El#xmlel.attrs), - El#xmlel{attrs = Attrs}; -fix_ns(El) -> - El. - -spec new_id() -> binary(). new_id() -> randoms:get_string(). @@ -632,7 +618,7 @@ decode_element(#xmlel{} = El, StateName, StateData) -> true -> [] end, - try xmpp:decode(El, Opts) of + try xmpp:decode(El, ?NS_SERVER, Opts) of Pkt -> ?MODULE:StateName(Pkt, StateData) catch error:{xmpp_codec, Why} -> case xmpp:is_stanza(El) of diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index 06ba16863..62c07b068 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -740,7 +740,7 @@ send_text(StateData, Text) -> -spec send_element(state(), xmpp_element()) -> ok. send_element(StateData, El) -> - El1 = fix_ns(xmpp:encode(El)), + El1 = xmpp:encode(El, ?NS_SERVER), send_text(StateData, fxml:element_to_binary(El1)). -spec send_header(state(), undefined | {integer(), integer()}) -> ok. @@ -766,20 +766,6 @@ send_queue(StateData, Q) -> {empty, _Q1} -> ok end. --spec fix_ns(xmlel()) -> xmlel(). -fix_ns(#xmlel{name = Name} = El) when Name == <<"message">>; - Name == <<"iq">>; - Name == <<"presence">>; - Name == <<"db:verify">>, - Name == <<"db:result">> -> - Attrs = lists:filter( - fun({<<"xmlns">>, _}) -> false; - (_) -> true - end, El#xmlel.attrs), - El#xmlel{attrs = Attrs}; -fix_ns(El) -> - El. - %% Bounce a single message (xmlelement) -spec bounce_element(stanza(), stanza_error()) -> ok. bounce_element(El, Error) -> @@ -1083,7 +1069,12 @@ fsm_limit_opts() -> -spec decode_element(xmlel(), state_name(), state()) -> fsm_next(). decode_element(#xmlel{} = El, StateName, StateData) -> - try xmpp:decode(El) of + Opts = if StateName == stream_established -> + [ignore_els]; + true -> + [] + end, + try xmpp:decode(El, ?NS_SERVER, Opts) of Pkt -> ?MODULE:StateName(Pkt, StateData) catch error:{xmpp_codec, Why} -> Type = xmpp:get_type(El), diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index 46d32e4fd..b1a4b433e 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -308,7 +308,7 @@ send_text(StateData, Text) -> -spec send_element(state(), xmpp_element()) -> ok. send_element(StateData, El) -> - El1 = fix_ns(xmpp:encode(El)), + El1 = xmpp:encode(El, ?NS_COMPONENT), send_text(StateData, fxml:element_to_binary(El1)). -spec send_error(state(), xmlel() | stanza(), stanza_error()) -> ok. @@ -334,21 +334,9 @@ send_header(StateData, Host) -> send_trailer(StateData) -> send_text(StateData, <<"">>). --spec fix_ns(xmlel()) -> xmlel(). -fix_ns(#xmlel{name = Name} = El) when Name == <<"message">>; - Name == <<"iq">>; - Name == <<"presence">> -> - Attrs = lists:filter( - fun({<<"xmlns">>, _}) -> false; - (_) -> true - end, El#xmlel.attrs), - El#xmlel{attrs = Attrs}; -fix_ns(El) -> - El. - -spec decode_element(xmlel(), state_name(), state()) -> fsm_transition(). decode_element(#xmlel{} = El, StateName, StateData) -> - try xmpp:decode(El, [ignore_els]) of + try xmpp:decode(El, ?NS_COMPONENT, [ignore_els]) of Pkt -> ?MODULE:StateName(Pkt, StateData) catch error:{xmpp_codec, Why} -> case xmpp:is_stanza(El) of diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl index fcfe9f3a7..b8a44c96c 100644 --- a/src/gen_iq_handler.erl +++ b/src/gen_iq_handler.erl @@ -144,7 +144,7 @@ process_iq(_Host, Module, Function, From, To, IQ0) -> end catch E:R -> ?ERROR_MSG("failed to process iq:~n~s~nReason = ~p", - [xmpp_codec:pp(IQ), {E, {R, erlang:get_stacktrace()}}]), + [xmpp:pp(IQ), {E, {R, erlang:get_stacktrace()}}]), Txt = <<"Module failed to handle the query">>, Err = xmpp:err_internal_server_error(Txt, IQ#iq.lang), ejabberd_router:route(To, From, xmpp:make_error(IQ, Err)) @@ -169,7 +169,7 @@ process_iq(Module, Function, #iq{lang = Lang, sub_els = [El]} = IQ) -> process_iq(Module, Function, From, To, IQ) -> case Module:Function(From, To, IQ) of ignore -> ignore; - ResIQ -> xmpp:decode(jlib:iq_to_xml(ResIQ), [ignore_els]) + ResIQ -> xmpp:decode(jlib:iq_to_xml(ResIQ), ?NS_CLIENT, [ignore_els]) end. -spec check_type(type()) -> type(). diff --git a/src/jd2ejd.erl b/src/jd2ejd.erl index 81732547b..037d6d63a 100644 --- a/src/jd2ejd.erl +++ b/src/jd2ejd.erl @@ -155,7 +155,7 @@ process_offline(Server, To, #xmlel{children = Els}) -> LServer = jid:nameprep(Server), lists:foreach( fun(#xmlel{} = El) -> - try xmpp:decode(El, [ignore_els]) of + try xmpp:decode(El, ?NS_CLIENT, [ignore_els]) of #message{from = JID} -> From = case JID of undefined -> jid:make(Server); diff --git a/src/mod_admin_extra.erl b/src/mod_admin_extra.erl index a147a5881..627b5b58f 100644 --- a/src/mod_admin_extra.erl +++ b/src/mod_admin_extra.erl @@ -1351,7 +1351,7 @@ send_stanza(FromString, ToString, Stanza) -> #xmlel{} = El = fxml_stream:parse_element(Stanza), #jid{} = From = jid:from_string(FromString), #jid{} = To = jid:to_string(ToString), - Pkt = xmpp:decode(El, [ignore_els]), + Pkt = xmpp:decode(El, ?NS_CLIENT, [ignore_els]), ejabberd_router:route(From, To, Pkt) catch _:{xmpp_codec, Why} -> io:format("incorrect stanza: ~s~n", [xmpp:format_error(Why)]), diff --git a/src/mod_announce.erl b/src/mod_announce.erl index 8d2fbebff..495cbf946 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -768,7 +768,7 @@ send_motd(#jid{luser = LUser, lserver = LServer} = JID) when LUser /= <<>> -> Mod = gen_mod:db_mod(LServer, ?MODULE), case Mod:get_motd(LServer) of {ok, Packet} -> - try xmpp:decode(Packet, [ignore_els]) of + try xmpp:decode(Packet, ?NS_CLIENT, [ignore_els]) of Msg -> case Mod:is_motd_user(LUser, LServer) of false -> @@ -792,7 +792,7 @@ get_stored_motd(LServer) -> Mod = gen_mod:db_mod(LServer, ?MODULE), case Mod:get_motd(LServer) of {ok, Packet} -> - try xmpp:decode(Packet, [ignore_els]) of + try xmpp:decode(Packet, ?NS_CLIENT, [ignore_els]) of #message{body = Body, subject = Subject} -> {xmpp:get_text(Subject), xmpp:get_text(Body)} catch _:{xmpp_codec, Why} -> diff --git a/src/mod_mam.erl b/src/mod_mam.erl index 5e4bebb75..8569ee020 100644 --- a/src/mod_mam.erl +++ b/src/mod_mam.erl @@ -540,18 +540,20 @@ should_archive(#message{body = Body} = Pkt, LServer) -> should_archive(_, _LServer) -> false. +-spec strip_my_archived_tag(stanza(), binary()) -> stanza(). strip_my_archived_tag(Pkt, LServer) -> NewPkt = xmpp:decode_els( - Pkt, fun(El) -> - case xmpp:get_name(El) of - <<"archived">> -> - xmpp:get_ns(El) == ?NS_MAM_TMP; - <<"stanza-id">> -> - xmpp:get_ns(El) == ?NS_SID_0; - _ -> - false - end - end), + Pkt, ?NS_CLIENT, + fun(El) -> + case xmpp:get_name(El) of + <<"archived">> -> + xmpp:get_ns(El) == ?NS_MAM_TMP; + <<"stanza-id">> -> + xmpp:get_ns(El) == ?NS_SID_0; + _ -> + false + end + end), NewEls = lists:filter( fun(#mam_archived{by = #jid{luser = <<>>} = By}) -> By#jid.lserver /= LServer; @@ -564,19 +566,20 @@ strip_my_archived_tag(Pkt, LServer) -> strip_x_jid_tags(Pkt) -> NewPkt = xmpp:decode_els( - Pkt, fun(El) -> - case xmpp:get_name(El) of - <<"x">> -> - case xmpp:get_ns(El) of - ?NS_MUC_USER -> true; - ?NS_MUC_ADMIN -> true; - ?NS_MUC_OWNER -> true; - _ -> false - end; - _ -> - false - end - end), + Pkt, ?NS_CLIENT, + fun(El) -> + case xmpp:get_name(El) of + <<"x">> -> + case xmpp:get_ns(El) of + ?NS_MUC_USER -> true; + ?NS_MUC_ADMIN -> true; + ?NS_MUC_OWNER -> true; + _ -> false + end; + _ -> + false + end + end), NewEls = lists:filter( fun(El) -> Items = case El of @@ -836,7 +839,7 @@ msg_to_el(#archive_msg{timestamp = TS, packet = Pkt1, nick = Nick, peer = Peer}, maybe_update_from_to(#xmlel{} = El, JidRequestor, JidArchive, Peer, {groupchat, _, _} = MsgType, Nick) -> - Pkt = xmpp:decode(El, [ignore_els]), + Pkt = xmpp:decode(El, ?NS_CLIENT, [ignore_els]), maybe_update_from_to(Pkt, JidRequestor, JidArchive, Peer, MsgType, Nick); maybe_update_from_to(#message{sub_els = Els} = Pkt, JidRequestor, JidArchive, Peer, {groupchat, Role, diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl index c32551091..339b85ecb 100644 --- a/src/mod_muc_room.erl +++ b/src/mod_muc_room.erl @@ -4343,7 +4343,7 @@ tab_count_user(JID) -> -spec element_size(stanza()) -> non_neg_integer(). element_size(El) -> - byte_size(fxml:element_to_binary(xmpp:encode(El))). + byte_size(fxml:element_to_binary(xmpp:encode(El, ?NS_CLIENT))). -spec store_room(state()) -> ok. store_room(StateData) -> diff --git a/src/mod_offline.erl b/src/mod_offline.erl index a2bcec894..9c062065d 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -611,7 +611,7 @@ get_offline_els(LUser, LServer) -> end, Hdrs). offline_msg_to_route(LServer, #offline_msg{} = R) -> - Pkt = xmpp:decode(R#offline_msg.packet, [ignore_els]), + Pkt = xmpp:decode(R#offline_msg.packet, ?NS_CLIENT, [ignore_els]), Pkt1 = case R#offline_msg.timestamp of undefined -> Pkt; @@ -626,7 +626,7 @@ read_message_headers(LUser, LServer) -> lists:map( fun({Seq, From, To, El}) -> Node = integer_to_binary(Seq), - Packet = xmpp:decode(El, [ignore_els]), + Packet = xmpp:decode(El, ?NS_CLIENT, [ignore_els]), {Node, From, To, Packet} end, Mod:read_message_headers(LUser, LServer)). diff --git a/src/xmpp.erl b/src/xmpp.erl index 49d824af2..0abcda7ee 100644 --- a/src/xmpp.erl +++ b/src/xmpp.erl @@ -10,14 +10,15 @@ %% API -export([make_iq_result/1, make_iq_result/2, make_error/2, - decode/1, decode/2, encode/1, + decode/1, decode/3, encode/1, encode/2, get_type/1, get_to/1, get_from/1, get_id/1, get_lang/1, get_error/1, get_els/1, get_ns/1, set_type/2, set_to/2, set_from/2, set_id/2, set_lang/2, set_error/2, set_els/2, set_from_to/3, format_error/1, is_stanza/1, set_subtag/2, get_subtag/2, - remove_subtag/2, has_subtag/2, decode_els/1, decode_els/2, - pp/1, get_name/1, get_text/1, mk_text/1, mk_text/2]). + remove_subtag/2, has_subtag/2, decode_els/1, decode_els/3, + pp/1, get_name/1, get_text/1, mk_text/1, mk_text/2, + is_known_tag/1, is_known_tag/2]). %% XMPP errors -export([err_bad_request/0, err_bad_request/2, @@ -117,7 +118,7 @@ make_error(#xmlel{attrs = Attrs, children = Els} = El, Err) -> Attrs end, Attrs3 = lists:keystore(<<"type">>, 1, Attrs2, {<<"type">>, <<"error">>}), - El#xmlel{attrs = Attrs3, children = Els ++ [encode(Err)]}. + El#xmlel{attrs = Attrs3, children = Els ++ [encode(Err, ?NS_CLIENT)]}. -spec get_id(iq() | message() | presence() | xmlel()) -> binary(). get_id(#iq{id = ID}) -> ID; @@ -232,35 +233,30 @@ get_name(Pkt) -> -spec decode(xmlel() | xmpp_element()) -> {ok, xmpp_element()} | {error, any()}. decode(El) -> - decode(El, []). + decode(El, ?NS_CLIENT, []). --spec decode(xmlel() | xmpp_element(), - [proplists:property()] | - fun((xmlel() | xmpp_element()) -> boolean())) -> +-spec decode(xmlel() | xmpp_element(), binary(), [proplists:property()]) -> {ok, xmpp_element()} | {error, any()}. -decode(#xmlel{} = El, MatchFun) when is_function(MatchFun) -> - Pkt = xmpp_codec:decode(add_ns(El), [ignore_els]), - decode_els(Pkt, MatchFun); -decode(#xmlel{} = El, Opts) when is_list(Opts) -> - xmpp_codec:decode(add_ns(El), Opts); -decode(Pkt, _Opts) -> +decode(#xmlel{} = El, TopXMLNS, Opts) -> + xmpp_codec:decode(El, TopXMLNS, Opts); +decode(Pkt, _, _) -> Pkt. -spec decode_els(iq()) -> iq(); (message()) -> message(); (presence()) -> presence(). decode_els(Stanza) -> - decode_els(Stanza, fun xmpp_codec:is_known_tag/1). + decode_els(Stanza, ?NS_CLIENT, fun is_known_tag/1). -type match_fun() :: fun((xmlel()) -> boolean()). --spec decode_els(iq(), match_fun()) -> iq(); - (message(), match_fun()) -> message(); - (presence(), match_fun()) -> presence(). -decode_els(Stanza, MatchFun) -> +-spec decode_els(iq(), binary(), match_fun()) -> iq(); + (message(), binary(), match_fun()) -> message(); + (presence(), binary(), match_fun()) -> presence(). +decode_els(Stanza, TopXMLNS, MatchFun) -> Els = lists:map( fun(#xmlel{} = El) -> case MatchFun(El) of - true -> decode(El); + true -> decode(El, TopXMLNS, []); false -> El end; (Pkt) -> @@ -270,7 +266,19 @@ decode_els(Stanza, MatchFun) -> -spec encode(xmpp_element() | xmlel()) -> xmlel(). encode(Pkt) -> - xmpp_codec:encode(Pkt). + encode(Pkt, <<>>). + +-spec encode(xmpp_element() | xmlel(), binary()) -> xmlel(). +encode(Pkt, TopXMLNS) -> + xmpp_codec:encode(Pkt, TopXMLNS). + +-spec is_known_tag(xmlel()) -> boolean(). +is_known_tag(El) -> + is_known_tag(El, ?NS_CLIENT). + +-spec is_known_tag(xmlel(), binary()) -> boolean(). +is_known_tag(El, TopXMLNS) -> + xmpp_codec:is_known_tag(El, TopXMLNS). format_error(Reason) -> xmpp_codec:format_error(Reason). @@ -809,16 +817,6 @@ serr(Reason, Text, Lang) -> text = #text{lang = Lang, data = translate:translate(Lang, Text)}}. --spec add_ns(xmlel()) -> xmlel(). -add_ns(#xmlel{name = Name} = El) when Name == <<"message">>; - Name == <<"presence">>; - Name == <<"iq">> -> - Attrs = lists:keystore(<<"xmlns">>, 1, El#xmlel.attrs, - {<<"xmlns">>, ?NS_CLIENT}), - El#xmlel{attrs = Attrs}; -add_ns(El) -> - El. - -spec match_tag(xmlel() | xmpp_element(), binary(), binary()) -> boolean(). match_tag(El, TagName, XMLNS) -> get_name(El) == TagName andalso get_ns(El) == XMLNS. diff --git a/src/xmpp_codec.erl b/src/xmpp_codec.erl index 0a9258195..bffe2f1ad 100644 --- a/src/xmpp_codec.erl +++ b/src/xmpp_codec.erl @@ -5,3137 +5,5774 @@ -compile({nowarn_unused_function, [{dec_int, 3}, {dec_int, 1}, {dec_enum, 2}, - {enc_int, 1}, {get_attr, 2}, {enc_enum, 1}]}). + {enc_int, 1}, {get_attr, 2}, {enc_enum, 1}, + {choose_top_xmlns, 3}, {enc_xmlns_attrs, 2}]}). -export([pp/1, format_error/1, decode/1, decode/2, - is_known_tag/1, encode/1, get_name/1, get_ns/1]). + decode/3, is_known_tag/2, encode/1, encode/2, + get_name/1, get_ns/1]). -decode(_el) -> decode(_el, []). +decode(_el) -> decode(_el, <<>>, []). -decode({xmlel, _name, _attrs, _} = _el, Opts) -> +decode(_el, Opts) -> decode(_el, <<>>, Opts). + +decode({xmlel, _name, _attrs, _} = _el, TopXMLNS, + Opts) -> IgnoreEls = proplists:get_bool(ignore_els, Opts), - case {_name, get_attr(<<"xmlns">>, _attrs)} of - {<<"thumbnail">>, <<"urn:xmpp:thumbs:1">>} -> + case {_name, get_attr(<<"xmlns">>, _attrs), TopXMLNS} of + {<<"thumbnail">>, <<"urn:xmpp:thumbs:1">>, _} -> decode_thumbnail(<<"urn:xmpp:thumbs:1">>, IgnoreEls, _el); - {<<"slot">>, <<"urn:xmpp:http:upload">>} -> + {<<"thumbnail">>, <<>>, <<"urn:xmpp:thumbs:1">>} -> + decode_thumbnail(<<"urn:xmpp:thumbs:1">>, IgnoreEls, + _el); + {<<"slot">>, <<"urn:xmpp:http:upload">>, _} -> decode_upload_slot(<<"urn:xmpp:http:upload">>, IgnoreEls, _el); - {<<"slot">>, + {<<"slot">>, <<>>, <<"urn:xmpp:http:upload">>} -> + decode_upload_slot(<<"urn:xmpp:http:upload">>, + IgnoreEls, _el); + {<<"slot">>, <<"eu:siacs:conversations:http:upload">>, + _} -> + decode_upload_slot(<<"eu:siacs:conversations:http:upload">>, + IgnoreEls, _el); + {<<"slot">>, <<>>, <<"eu:siacs:conversations:http:upload">>} -> decode_upload_slot(<<"eu:siacs:conversations:http:upload">>, IgnoreEls, _el); - {<<"put">>, <<"urn:xmpp:http:upload">>} -> + {<<"put">>, <<"urn:xmpp:http:upload">>, _} -> decode_upload_put(<<"urn:xmpp:http:upload">>, IgnoreEls, _el); - {<<"put">>, <<"eu:siacs:conversations:http:upload">>} -> + {<<"put">>, <<>>, <<"urn:xmpp:http:upload">>} -> + decode_upload_put(<<"urn:xmpp:http:upload">>, IgnoreEls, + _el); + {<<"put">>, <<"eu:siacs:conversations:http:upload">>, + _} -> decode_upload_put(<<"eu:siacs:conversations:http:upload">>, IgnoreEls, _el); - {<<"get">>, <<"urn:xmpp:http:upload">>} -> + {<<"put">>, <<>>, + <<"eu:siacs:conversations:http:upload">>} -> + decode_upload_put(<<"eu:siacs:conversations:http:upload">>, + IgnoreEls, _el); + {<<"get">>, <<"urn:xmpp:http:upload">>, _} -> decode_upload_get(<<"urn:xmpp:http:upload">>, IgnoreEls, _el); - {<<"get">>, <<"eu:siacs:conversations:http:upload">>} -> + {<<"get">>, <<>>, <<"urn:xmpp:http:upload">>} -> + decode_upload_get(<<"urn:xmpp:http:upload">>, IgnoreEls, + _el); + {<<"get">>, <<"eu:siacs:conversations:http:upload">>, + _} -> decode_upload_get(<<"eu:siacs:conversations:http:upload">>, IgnoreEls, _el); - {<<"request">>, <<"urn:xmpp:http:upload">>} -> + {<<"get">>, <<>>, + <<"eu:siacs:conversations:http:upload">>} -> + decode_upload_get(<<"eu:siacs:conversations:http:upload">>, + IgnoreEls, _el); + {<<"request">>, <<"urn:xmpp:http:upload">>, _} -> + decode_upload_request(<<"urn:xmpp:http:upload">>, + IgnoreEls, _el); + {<<"request">>, <<>>, <<"urn:xmpp:http:upload">>} -> decode_upload_request(<<"urn:xmpp:http:upload">>, IgnoreEls, _el); {<<"request">>, + <<"eu:siacs:conversations:http:upload">>, _} -> + decode_upload_request(<<"eu:siacs:conversations:http:upload">>, + IgnoreEls, _el); + {<<"request">>, <<>>, <<"eu:siacs:conversations:http:upload">>} -> decode_upload_request(<<"eu:siacs:conversations:http:upload">>, IgnoreEls, _el); - {<<"content-type">>, <<"urn:xmpp:http:upload">>} -> + {<<"content-type">>, <<"urn:xmpp:http:upload">>, _} -> + decode_upload_content_type(<<"urn:xmpp:http:upload">>, + IgnoreEls, _el); + {<<"content-type">>, <<>>, + <<"urn:xmpp:http:upload">>} -> decode_upload_content_type(<<"urn:xmpp:http:upload">>, IgnoreEls, _el); {<<"content-type">>, + <<"eu:siacs:conversations:http:upload">>, _} -> + decode_upload_content_type(<<"eu:siacs:conversations:http:upload">>, + IgnoreEls, _el); + {<<"content-type">>, <<>>, <<"eu:siacs:conversations:http:upload">>} -> decode_upload_content_type(<<"eu:siacs:conversations:http:upload">>, IgnoreEls, _el); - {<<"size">>, <<"urn:xmpp:http:upload">>} -> + {<<"size">>, <<"urn:xmpp:http:upload">>, _} -> decode_upload_size(<<"urn:xmpp:http:upload">>, IgnoreEls, _el); - {<<"size">>, + {<<"size">>, <<>>, <<"urn:xmpp:http:upload">>} -> + decode_upload_size(<<"urn:xmpp:http:upload">>, + IgnoreEls, _el); + {<<"size">>, <<"eu:siacs:conversations:http:upload">>, + _} -> + decode_upload_size(<<"eu:siacs:conversations:http:upload">>, + IgnoreEls, _el); + {<<"size">>, <<>>, <<"eu:siacs:conversations:http:upload">>} -> decode_upload_size(<<"eu:siacs:conversations:http:upload">>, IgnoreEls, _el); - {<<"filename">>, <<"urn:xmpp:http:upload">>} -> + {<<"filename">>, <<"urn:xmpp:http:upload">>, _} -> + decode_upload_filename(<<"urn:xmpp:http:upload">>, + IgnoreEls, _el); + {<<"filename">>, <<>>, <<"urn:xmpp:http:upload">>} -> decode_upload_filename(<<"urn:xmpp:http:upload">>, IgnoreEls, _el); {<<"filename">>, + <<"eu:siacs:conversations:http:upload">>, _} -> + decode_upload_filename(<<"eu:siacs:conversations:http:upload">>, + IgnoreEls, _el); + {<<"filename">>, <<>>, <<"eu:siacs:conversations:http:upload">>} -> decode_upload_filename(<<"eu:siacs:conversations:http:upload">>, IgnoreEls, _el); - {<<"address">>, <<"urn:xmpp:sic:0">>} -> + {<<"address">>, <<"urn:xmpp:sic:0">>, _} -> decode_sic(<<"urn:xmpp:sic:0">>, IgnoreEls, _el); - {<<"address">>, <<"urn:xmpp:sic:1">>} -> + {<<"address">>, <<>>, <<"urn:xmpp:sic:0">>} -> + decode_sic(<<"urn:xmpp:sic:0">>, IgnoreEls, _el); + {<<"address">>, <<"urn:xmpp:sic:1">>, _} -> decode_sic(<<"urn:xmpp:sic:1">>, IgnoreEls, _el); - {<<"port">>, <<"urn:xmpp:sic:1">>} -> + {<<"address">>, <<>>, <<"urn:xmpp:sic:1">>} -> + decode_sic(<<"urn:xmpp:sic:1">>, IgnoreEls, _el); + {<<"port">>, <<"urn:xmpp:sic:1">>, _} -> decode_sip_port(<<"urn:xmpp:sic:1">>, IgnoreEls, _el); - {<<"ip">>, <<"urn:xmpp:sic:0">>} -> + {<<"port">>, <<>>, <<"urn:xmpp:sic:1">>} -> + decode_sip_port(<<"urn:xmpp:sic:1">>, IgnoreEls, _el); + {<<"ip">>, <<"urn:xmpp:sic:0">>, _} -> decode_sic_ip(<<"urn:xmpp:sic:0">>, IgnoreEls, _el); - {<<"ip">>, <<"urn:xmpp:sic:1">>} -> + {<<"ip">>, <<>>, <<"urn:xmpp:sic:0">>} -> + decode_sic_ip(<<"urn:xmpp:sic:0">>, IgnoreEls, _el); + {<<"ip">>, <<"urn:xmpp:sic:1">>, _} -> decode_sic_ip(<<"urn:xmpp:sic:1">>, IgnoreEls, _el); - {<<"x">>, <<"jabber:x:oob">>} -> + {<<"ip">>, <<>>, <<"urn:xmpp:sic:1">>} -> + decode_sic_ip(<<"urn:xmpp:sic:1">>, IgnoreEls, _el); + {<<"x">>, <<"jabber:x:oob">>, _} -> decode_oob_x(<<"jabber:x:oob">>, IgnoreEls, _el); - {<<"desc">>, <<"jabber:x:oob">>} -> + {<<"x">>, <<>>, <<"jabber:x:oob">>} -> + decode_oob_x(<<"jabber:x:oob">>, IgnoreEls, _el); + {<<"desc">>, <<"jabber:x:oob">>, _} -> decode_oob_desc(<<"jabber:x:oob">>, IgnoreEls, _el); - {<<"url">>, <<"jabber:x:oob">>} -> + {<<"desc">>, <<>>, <<"jabber:x:oob">>} -> + decode_oob_desc(<<"jabber:x:oob">>, IgnoreEls, _el); + {<<"url">>, <<"jabber:x:oob">>, _} -> decode_oob_url(<<"jabber:x:oob">>, IgnoreEls, _el); - {<<"media">>, <<"urn:xmpp:media-element">>} -> + {<<"url">>, <<>>, <<"jabber:x:oob">>} -> + decode_oob_url(<<"jabber:x:oob">>, IgnoreEls, _el); + {<<"media">>, <<"urn:xmpp:media-element">>, _} -> decode_media(<<"urn:xmpp:media-element">>, IgnoreEls, _el); - {<<"uri">>, <<"urn:xmpp:media-element">>} -> + {<<"media">>, <<>>, <<"urn:xmpp:media-element">>} -> + decode_media(<<"urn:xmpp:media-element">>, IgnoreEls, + _el); + {<<"uri">>, <<"urn:xmpp:media-element">>, _} -> decode_media_uri(<<"urn:xmpp:media-element">>, IgnoreEls, _el); - {<<"captcha">>, <<"urn:xmpp:captcha">>} -> + {<<"uri">>, <<>>, <<"urn:xmpp:media-element">>} -> + decode_media_uri(<<"urn:xmpp:media-element">>, + IgnoreEls, _el); + {<<"captcha">>, <<"urn:xmpp:captcha">>, _} -> decode_captcha(<<"urn:xmpp:captcha">>, IgnoreEls, _el); - {<<"data">>, <<"urn:xmpp:bob">>} -> + {<<"captcha">>, <<>>, <<"urn:xmpp:captcha">>} -> + decode_captcha(<<"urn:xmpp:captcha">>, IgnoreEls, _el); + {<<"data">>, <<"urn:xmpp:bob">>, _} -> decode_bob_data(<<"urn:xmpp:bob">>, IgnoreEls, _el); - {<<"stream:stream">>, <<"jabber:client">>} -> + {<<"data">>, <<>>, <<"urn:xmpp:bob">>} -> + decode_bob_data(<<"urn:xmpp:bob">>, IgnoreEls, _el); + {<<"stream:stream">>, <<"jabber:client">>, _} -> decode_stream_start(<<"jabber:client">>, IgnoreEls, _el); - {<<"stream:stream">>, <<"jabber:server">>} -> + {<<"stream:stream">>, <<>>, <<"jabber:client">>} -> + decode_stream_start(<<"jabber:client">>, IgnoreEls, + _el); + {<<"stream:stream">>, <<"jabber:server">>, _} -> decode_stream_start(<<"jabber:server">>, IgnoreEls, _el); - {<<"stream:stream">>, <<"jabber:component:accept">>} -> + {<<"stream:stream">>, <<>>, <<"jabber:server">>} -> + decode_stream_start(<<"jabber:server">>, IgnoreEls, + _el); + {<<"stream:stream">>, <<"jabber:component:accept">>, + _} -> decode_stream_start(<<"jabber:component:accept">>, IgnoreEls, _el); - {<<"handshake">>, <<"jabber:client">>} -> - decode_handshake(<<"jabber:client">>, IgnoreEls, _el); - {<<"db:verify">>, <<"jabber:client">>} -> - decode_db_verify(<<"jabber:client">>, IgnoreEls, _el); - {<<"db:result">>, <<"jabber:client">>} -> - decode_db_result(<<"jabber:client">>, IgnoreEls, _el); + {<<"stream:stream">>, <<>>, + <<"jabber:component:accept">>} -> + decode_stream_start(<<"jabber:component:accept">>, + IgnoreEls, _el); + {<<"handshake">>, <<"jabber:component:accept">>, _} -> + decode_handshake(<<"jabber:component:accept">>, + IgnoreEls, _el); + {<<"handshake">>, <<>>, + <<"jabber:component:accept">>} -> + decode_handshake(<<"jabber:component:accept">>, + IgnoreEls, _el); + {<<"db:verify">>, <<"jabber:server">>, _} -> + decode_db_verify(<<"jabber:server">>, IgnoreEls, _el); + {<<"db:verify">>, <<>>, <<"jabber:server">>} -> + decode_db_verify(<<"jabber:server">>, IgnoreEls, _el); + {<<"db:result">>, <<"jabber:server">>, _} -> + decode_db_result(<<"jabber:server">>, IgnoreEls, _el); + {<<"db:result">>, <<>>, <<"jabber:server">>} -> + decode_db_result(<<"jabber:server">>, IgnoreEls, _el); {<<"command">>, + <<"http://jabber.org/protocol/commands">>, _} -> + decode_adhoc_command(<<"http://jabber.org/protocol/commands">>, + IgnoreEls, _el); + {<<"command">>, <<>>, <<"http://jabber.org/protocol/commands">>} -> decode_adhoc_command(<<"http://jabber.org/protocol/commands">>, IgnoreEls, _el); - {<<"note">>, + {<<"note">>, <<"http://jabber.org/protocol/commands">>, + _} -> + decode_adhoc_command_notes(<<"http://jabber.org/protocol/commands">>, + IgnoreEls, _el); + {<<"note">>, <<>>, <<"http://jabber.org/protocol/commands">>} -> decode_adhoc_command_notes(<<"http://jabber.org/protocol/commands">>, IgnoreEls, _el); {<<"actions">>, + <<"http://jabber.org/protocol/commands">>, _} -> + decode_adhoc_command_actions(<<"http://jabber.org/protocol/commands">>, + IgnoreEls, _el); + {<<"actions">>, <<>>, <<"http://jabber.org/protocol/commands">>} -> decode_adhoc_command_actions(<<"http://jabber.org/protocol/commands">>, IgnoreEls, _el); {<<"complete">>, + <<"http://jabber.org/protocol/commands">>, _} -> + decode_adhoc_command_complete(<<"http://jabber.org/protocol/commands">>, + IgnoreEls, _el); + {<<"complete">>, <<>>, <<"http://jabber.org/protocol/commands">>} -> decode_adhoc_command_complete(<<"http://jabber.org/protocol/commands">>, IgnoreEls, _el); - {<<"next">>, + {<<"next">>, <<"http://jabber.org/protocol/commands">>, + _} -> + decode_adhoc_command_next(<<"http://jabber.org/protocol/commands">>, + IgnoreEls, _el); + {<<"next">>, <<>>, <<"http://jabber.org/protocol/commands">>} -> decode_adhoc_command_next(<<"http://jabber.org/protocol/commands">>, IgnoreEls, _el); - {<<"prev">>, + {<<"prev">>, <<"http://jabber.org/protocol/commands">>, + _} -> + decode_adhoc_command_prev(<<"http://jabber.org/protocol/commands">>, + IgnoreEls, _el); + {<<"prev">>, <<>>, <<"http://jabber.org/protocol/commands">>} -> decode_adhoc_command_prev(<<"http://jabber.org/protocol/commands">>, IgnoreEls, _el); - {<<"client-id">>, <<"urn:xmpp:sid:0">>} -> + {<<"client-id">>, <<"urn:xmpp:sid:0">>, _} -> decode_client_id(<<"urn:xmpp:sid:0">>, IgnoreEls, _el); - {<<"stanza-id">>, <<"urn:xmpp:sid:0">>} -> + {<<"client-id">>, <<>>, <<"urn:xmpp:sid:0">>} -> + decode_client_id(<<"urn:xmpp:sid:0">>, IgnoreEls, _el); + {<<"stanza-id">>, <<"urn:xmpp:sid:0">>, _} -> + decode_stanza_id(<<"urn:xmpp:sid:0">>, IgnoreEls, _el); + {<<"stanza-id">>, <<>>, <<"urn:xmpp:sid:0">>} -> decode_stanza_id(<<"urn:xmpp:sid:0">>, IgnoreEls, _el); {<<"addresses">>, + <<"http://jabber.org/protocol/address">>, _} -> + decode_addresses(<<"http://jabber.org/protocol/address">>, + IgnoreEls, _el); + {<<"addresses">>, <<>>, <<"http://jabber.org/protocol/address">>} -> decode_addresses(<<"http://jabber.org/protocol/address">>, IgnoreEls, _el); {<<"address">>, + <<"http://jabber.org/protocol/address">>, _} -> + decode_address(<<"http://jabber.org/protocol/address">>, + IgnoreEls, _el); + {<<"address">>, <<>>, <<"http://jabber.org/protocol/address">>} -> decode_address(<<"http://jabber.org/protocol/address">>, IgnoreEls, _el); - {<<"nick">>, <<"http://jabber.org/protocol/nick">>} -> + {<<"nick">>, <<"http://jabber.org/protocol/nick">>, + _} -> decode_nick(<<"http://jabber.org/protocol/nick">>, IgnoreEls, _el); - {<<"x">>, <<"jabber:x:expire">>} -> + {<<"nick">>, <<>>, + <<"http://jabber.org/protocol/nick">>} -> + decode_nick(<<"http://jabber.org/protocol/nick">>, + IgnoreEls, _el); + {<<"x">>, <<"jabber:x:expire">>, _} -> decode_expire(<<"jabber:x:expire">>, IgnoreEls, _el); - {<<"x">>, <<"jabber:x:event">>} -> + {<<"x">>, <<>>, <<"jabber:x:expire">>} -> + decode_expire(<<"jabber:x:expire">>, IgnoreEls, _el); + {<<"x">>, <<"jabber:x:event">>, _} -> decode_xevent(<<"jabber:x:event">>, IgnoreEls, _el); - {<<"id">>, <<"jabber:x:event">>} -> + {<<"x">>, <<>>, <<"jabber:x:event">>} -> + decode_xevent(<<"jabber:x:event">>, IgnoreEls, _el); + {<<"id">>, <<"jabber:x:event">>, _} -> decode_xevent_id(<<"jabber:x:event">>, IgnoreEls, _el); - {<<"composing">>, <<"jabber:x:event">>} -> + {<<"id">>, <<>>, <<"jabber:x:event">>} -> + decode_xevent_id(<<"jabber:x:event">>, IgnoreEls, _el); + {<<"composing">>, <<"jabber:x:event">>, _} -> decode_xevent_composing(<<"jabber:x:event">>, IgnoreEls, _el); - {<<"displayed">>, <<"jabber:x:event">>} -> + {<<"composing">>, <<>>, <<"jabber:x:event">>} -> + decode_xevent_composing(<<"jabber:x:event">>, IgnoreEls, + _el); + {<<"displayed">>, <<"jabber:x:event">>, _} -> decode_xevent_displayed(<<"jabber:x:event">>, IgnoreEls, _el); - {<<"delivered">>, <<"jabber:x:event">>} -> + {<<"displayed">>, <<>>, <<"jabber:x:event">>} -> + decode_xevent_displayed(<<"jabber:x:event">>, IgnoreEls, + _el); + {<<"delivered">>, <<"jabber:x:event">>, _} -> decode_xevent_delivered(<<"jabber:x:event">>, IgnoreEls, _el); - {<<"offline">>, <<"jabber:x:event">>} -> + {<<"delivered">>, <<>>, <<"jabber:x:event">>} -> + decode_xevent_delivered(<<"jabber:x:event">>, IgnoreEls, + _el); + {<<"offline">>, <<"jabber:x:event">>, _} -> decode_xevent_offline(<<"jabber:x:event">>, IgnoreEls, _el); - {<<"query">>, <<"jabber:iq:search">>} -> + {<<"offline">>, <<>>, <<"jabber:x:event">>} -> + decode_xevent_offline(<<"jabber:x:event">>, IgnoreEls, + _el); + {<<"query">>, <<"jabber:iq:search">>, _} -> decode_search(<<"jabber:iq:search">>, IgnoreEls, _el); - {<<"item">>, <<"jabber:iq:search">>} -> + {<<"query">>, <<>>, <<"jabber:iq:search">>} -> + decode_search(<<"jabber:iq:search">>, IgnoreEls, _el); + {<<"item">>, <<"jabber:iq:search">>, _} -> decode_search_item(<<"jabber:iq:search">>, IgnoreEls, _el); - {<<"email">>, <<"jabber:iq:search">>} -> + {<<"item">>, <<>>, <<"jabber:iq:search">>} -> + decode_search_item(<<"jabber:iq:search">>, IgnoreEls, + _el); + {<<"email">>, <<"jabber:iq:search">>, _} -> decode_search_email(<<"jabber:iq:search">>, IgnoreEls, _el); - {<<"nick">>, <<"jabber:iq:search">>} -> + {<<"email">>, <<>>, <<"jabber:iq:search">>} -> + decode_search_email(<<"jabber:iq:search">>, IgnoreEls, + _el); + {<<"nick">>, <<"jabber:iq:search">>, _} -> decode_search_nick(<<"jabber:iq:search">>, IgnoreEls, _el); - {<<"last">>, <<"jabber:iq:search">>} -> + {<<"nick">>, <<>>, <<"jabber:iq:search">>} -> + decode_search_nick(<<"jabber:iq:search">>, IgnoreEls, + _el); + {<<"last">>, <<"jabber:iq:search">>, _} -> decode_search_last(<<"jabber:iq:search">>, IgnoreEls, _el); - {<<"first">>, <<"jabber:iq:search">>} -> + {<<"last">>, <<>>, <<"jabber:iq:search">>} -> + decode_search_last(<<"jabber:iq:search">>, IgnoreEls, + _el); + {<<"first">>, <<"jabber:iq:search">>, _} -> decode_search_first(<<"jabber:iq:search">>, IgnoreEls, _el); - {<<"instructions">>, <<"jabber:iq:search">>} -> + {<<"first">>, <<>>, <<"jabber:iq:search">>} -> + decode_search_first(<<"jabber:iq:search">>, IgnoreEls, + _el); + {<<"instructions">>, <<"jabber:iq:search">>, _} -> decode_search_instructions(<<"jabber:iq:search">>, IgnoreEls, _el); - {<<"no-permanent-storage">>, <<"urn:xmpp:hints">>} -> + {<<"instructions">>, <<>>, <<"jabber:iq:search">>} -> + decode_search_instructions(<<"jabber:iq:search">>, + IgnoreEls, _el); + {<<"no-permanent-storage">>, <<"urn:xmpp:hints">>, _} -> decode_hint_no_permanent_storage(<<"urn:xmpp:hints">>, IgnoreEls, _el); - {<<"no-permanent-store">>, <<"urn:xmpp:hints">>} -> + {<<"no-permanent-storage">>, <<>>, + <<"urn:xmpp:hints">>} -> + decode_hint_no_permanent_storage(<<"urn:xmpp:hints">>, + IgnoreEls, _el); + {<<"no-permanent-store">>, <<"urn:xmpp:hints">>, _} -> decode_hint_no_permanent_store(<<"urn:xmpp:hints">>, IgnoreEls, _el); - {<<"store">>, <<"urn:xmpp:hints">>} -> + {<<"no-permanent-store">>, <<>>, + <<"urn:xmpp:hints">>} -> + decode_hint_no_permanent_store(<<"urn:xmpp:hints">>, + IgnoreEls, _el); + {<<"store">>, <<"urn:xmpp:hints">>, _} -> decode_hint_store(<<"urn:xmpp:hints">>, IgnoreEls, _el); - {<<"no-storage">>, <<"urn:xmpp:hints">>} -> + {<<"store">>, <<>>, <<"urn:xmpp:hints">>} -> + decode_hint_store(<<"urn:xmpp:hints">>, IgnoreEls, _el); + {<<"no-storage">>, <<"urn:xmpp:hints">>, _} -> decode_hint_no_storage(<<"urn:xmpp:hints">>, IgnoreEls, _el); - {<<"no-store">>, <<"urn:xmpp:hints">>} -> + {<<"no-storage">>, <<>>, <<"urn:xmpp:hints">>} -> + decode_hint_no_storage(<<"urn:xmpp:hints">>, IgnoreEls, + _el); + {<<"no-store">>, <<"urn:xmpp:hints">>, _} -> decode_hint_no_store(<<"urn:xmpp:hints">>, IgnoreEls, _el); - {<<"no-copy">>, <<"urn:xmpp:hints">>} -> + {<<"no-store">>, <<>>, <<"urn:xmpp:hints">>} -> + decode_hint_no_store(<<"urn:xmpp:hints">>, IgnoreEls, + _el); + {<<"no-copy">>, <<"urn:xmpp:hints">>, _} -> decode_hint_no_copy(<<"urn:xmpp:hints">>, IgnoreEls, _el); - {<<"participant">>, <<"urn:xmpp:mix:0">>} -> + {<<"no-copy">>, <<>>, <<"urn:xmpp:hints">>} -> + decode_hint_no_copy(<<"urn:xmpp:hints">>, IgnoreEls, + _el); + {<<"participant">>, <<"urn:xmpp:mix:0">>, _} -> decode_mix_participant(<<"urn:xmpp:mix:0">>, IgnoreEls, _el); - {<<"leave">>, <<"urn:xmpp:mix:0">>} -> + {<<"participant">>, <<>>, <<"urn:xmpp:mix:0">>} -> + decode_mix_participant(<<"urn:xmpp:mix:0">>, IgnoreEls, + _el); + {<<"leave">>, <<"urn:xmpp:mix:0">>, _} -> decode_mix_leave(<<"urn:xmpp:mix:0">>, IgnoreEls, _el); - {<<"join">>, <<"urn:xmpp:mix:0">>} -> + {<<"leave">>, <<>>, <<"urn:xmpp:mix:0">>} -> + decode_mix_leave(<<"urn:xmpp:mix:0">>, IgnoreEls, _el); + {<<"join">>, <<"urn:xmpp:mix:0">>, _} -> decode_mix_join(<<"urn:xmpp:mix:0">>, IgnoreEls, _el); - {<<"subscribe">>, <<"urn:xmpp:mix:0">>} -> + {<<"join">>, <<>>, <<"urn:xmpp:mix:0">>} -> + decode_mix_join(<<"urn:xmpp:mix:0">>, IgnoreEls, _el); + {<<"subscribe">>, <<"urn:xmpp:mix:0">>, _} -> + decode_mix_subscribe(<<"urn:xmpp:mix:0">>, IgnoreEls, + _el); + {<<"subscribe">>, <<>>, <<"urn:xmpp:mix:0">>} -> decode_mix_subscribe(<<"urn:xmpp:mix:0">>, IgnoreEls, _el); {<<"offline">>, + <<"http://jabber.org/protocol/offline">>, _} -> + decode_offline(<<"http://jabber.org/protocol/offline">>, + IgnoreEls, _el); + {<<"offline">>, <<>>, <<"http://jabber.org/protocol/offline">>} -> decode_offline(<<"http://jabber.org/protocol/offline">>, IgnoreEls, _el); - {<<"item">>, + {<<"item">>, <<"http://jabber.org/protocol/offline">>, + _} -> + decode_offline_item(<<"http://jabber.org/protocol/offline">>, + IgnoreEls, _el); + {<<"item">>, <<>>, <<"http://jabber.org/protocol/offline">>} -> decode_offline_item(<<"http://jabber.org/protocol/offline">>, IgnoreEls, _el); - {<<"fetch">>, + {<<"fetch">>, <<"http://jabber.org/protocol/offline">>, + _} -> + decode_offline_fetch(<<"http://jabber.org/protocol/offline">>, + IgnoreEls, _el); + {<<"fetch">>, <<>>, <<"http://jabber.org/protocol/offline">>} -> decode_offline_fetch(<<"http://jabber.org/protocol/offline">>, IgnoreEls, _el); - {<<"purge">>, + {<<"purge">>, <<"http://jabber.org/protocol/offline">>, + _} -> + decode_offline_purge(<<"http://jabber.org/protocol/offline">>, + IgnoreEls, _el); + {<<"purge">>, <<>>, <<"http://jabber.org/protocol/offline">>} -> decode_offline_purge(<<"http://jabber.org/protocol/offline">>, IgnoreEls, _el); - {<<"failed">>, <<"urn:xmpp:sm:2">>} -> + {<<"failed">>, <<"urn:xmpp:sm:2">>, _} -> decode_sm_failed(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); - {<<"failed">>, <<"urn:xmpp:sm:3">>} -> + {<<"failed">>, <<>>, <<"urn:xmpp:sm:2">>} -> + decode_sm_failed(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); + {<<"failed">>, <<"urn:xmpp:sm:3">>, _} -> decode_sm_failed(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); - {<<"a">>, <<"urn:xmpp:sm:2">>} -> + {<<"failed">>, <<>>, <<"urn:xmpp:sm:3">>} -> + decode_sm_failed(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); + {<<"a">>, <<"urn:xmpp:sm:2">>, _} -> decode_sm_a(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); - {<<"a">>, <<"urn:xmpp:sm:3">>} -> + {<<"a">>, <<>>, <<"urn:xmpp:sm:2">>} -> + decode_sm_a(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); + {<<"a">>, <<"urn:xmpp:sm:3">>, _} -> decode_sm_a(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); - {<<"r">>, <<"urn:xmpp:sm:2">>} -> + {<<"a">>, <<>>, <<"urn:xmpp:sm:3">>} -> + decode_sm_a(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); + {<<"r">>, <<"urn:xmpp:sm:2">>, _} -> decode_sm_r(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); - {<<"r">>, <<"urn:xmpp:sm:3">>} -> + {<<"r">>, <<>>, <<"urn:xmpp:sm:2">>} -> + decode_sm_r(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); + {<<"r">>, <<"urn:xmpp:sm:3">>, _} -> decode_sm_r(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); - {<<"resumed">>, <<"urn:xmpp:sm:2">>} -> + {<<"r">>, <<>>, <<"urn:xmpp:sm:3">>} -> + decode_sm_r(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); + {<<"resumed">>, <<"urn:xmpp:sm:2">>, _} -> decode_sm_resumed(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); - {<<"resumed">>, <<"urn:xmpp:sm:3">>} -> + {<<"resumed">>, <<>>, <<"urn:xmpp:sm:2">>} -> + decode_sm_resumed(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); + {<<"resumed">>, <<"urn:xmpp:sm:3">>, _} -> decode_sm_resumed(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); - {<<"resume">>, <<"urn:xmpp:sm:2">>} -> + {<<"resumed">>, <<>>, <<"urn:xmpp:sm:3">>} -> + decode_sm_resumed(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); + {<<"resume">>, <<"urn:xmpp:sm:2">>, _} -> decode_sm_resume(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); - {<<"resume">>, <<"urn:xmpp:sm:3">>} -> + {<<"resume">>, <<>>, <<"urn:xmpp:sm:2">>} -> + decode_sm_resume(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); + {<<"resume">>, <<"urn:xmpp:sm:3">>, _} -> decode_sm_resume(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); - {<<"enabled">>, <<"urn:xmpp:sm:2">>} -> + {<<"resume">>, <<>>, <<"urn:xmpp:sm:3">>} -> + decode_sm_resume(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); + {<<"enabled">>, <<"urn:xmpp:sm:2">>, _} -> decode_sm_enabled(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); - {<<"enabled">>, <<"urn:xmpp:sm:3">>} -> + {<<"enabled">>, <<>>, <<"urn:xmpp:sm:2">>} -> + decode_sm_enabled(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); + {<<"enabled">>, <<"urn:xmpp:sm:3">>, _} -> decode_sm_enabled(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); - {<<"enable">>, <<"urn:xmpp:sm:2">>} -> + {<<"enabled">>, <<>>, <<"urn:xmpp:sm:3">>} -> + decode_sm_enabled(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); + {<<"enable">>, <<"urn:xmpp:sm:2">>, _} -> decode_sm_enable(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); - {<<"enable">>, <<"urn:xmpp:sm:3">>} -> + {<<"enable">>, <<>>, <<"urn:xmpp:sm:2">>} -> + decode_sm_enable(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); + {<<"enable">>, <<"urn:xmpp:sm:3">>, _} -> decode_sm_enable(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); - {<<"sm">>, <<"urn:xmpp:sm:2">>} -> + {<<"enable">>, <<>>, <<"urn:xmpp:sm:3">>} -> + decode_sm_enable(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); + {<<"sm">>, <<"urn:xmpp:sm:2">>, _} -> decode_feature_sm(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); - {<<"sm">>, <<"urn:xmpp:sm:3">>} -> + {<<"sm">>, <<>>, <<"urn:xmpp:sm:2">>} -> + decode_feature_sm(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); + {<<"sm">>, <<"urn:xmpp:sm:3">>, _} -> decode_feature_sm(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); - {<<"inactive">>, <<"urn:xmpp:csi:0">>} -> + {<<"sm">>, <<>>, <<"urn:xmpp:sm:3">>} -> + decode_feature_sm(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); + {<<"inactive">>, <<"urn:xmpp:csi:0">>, _} -> decode_csi_inactive(<<"urn:xmpp:csi:0">>, IgnoreEls, _el); - {<<"active">>, <<"urn:xmpp:csi:0">>} -> + {<<"inactive">>, <<>>, <<"urn:xmpp:csi:0">>} -> + decode_csi_inactive(<<"urn:xmpp:csi:0">>, IgnoreEls, + _el); + {<<"active">>, <<"urn:xmpp:csi:0">>, _} -> decode_csi_active(<<"urn:xmpp:csi:0">>, IgnoreEls, _el); - {<<"csi">>, <<"urn:xmpp:csi:0">>} -> + {<<"active">>, <<>>, <<"urn:xmpp:csi:0">>} -> + decode_csi_active(<<"urn:xmpp:csi:0">>, IgnoreEls, _el); + {<<"csi">>, <<"urn:xmpp:csi:0">>, _} -> decode_feature_csi(<<"urn:xmpp:csi:0">>, IgnoreEls, _el); - {<<"sent">>, <<"urn:xmpp:carbons:2">>} -> + {<<"csi">>, <<>>, <<"urn:xmpp:csi:0">>} -> + decode_feature_csi(<<"urn:xmpp:csi:0">>, IgnoreEls, + _el); + {<<"sent">>, <<"urn:xmpp:carbons:2">>, _} -> decode_carbons_sent(<<"urn:xmpp:carbons:2">>, IgnoreEls, _el); - {<<"received">>, <<"urn:xmpp:carbons:2">>} -> + {<<"sent">>, <<>>, <<"urn:xmpp:carbons:2">>} -> + decode_carbons_sent(<<"urn:xmpp:carbons:2">>, IgnoreEls, + _el); + {<<"received">>, <<"urn:xmpp:carbons:2">>, _} -> decode_carbons_received(<<"urn:xmpp:carbons:2">>, IgnoreEls, _el); - {<<"private">>, <<"urn:xmpp:carbons:2">>} -> + {<<"received">>, <<>>, <<"urn:xmpp:carbons:2">>} -> + decode_carbons_received(<<"urn:xmpp:carbons:2">>, + IgnoreEls, _el); + {<<"private">>, <<"urn:xmpp:carbons:2">>, _} -> decode_carbons_private(<<"urn:xmpp:carbons:2">>, IgnoreEls, _el); - {<<"enable">>, <<"urn:xmpp:carbons:2">>} -> + {<<"private">>, <<>>, <<"urn:xmpp:carbons:2">>} -> + decode_carbons_private(<<"urn:xmpp:carbons:2">>, + IgnoreEls, _el); + {<<"enable">>, <<"urn:xmpp:carbons:2">>, _} -> decode_carbons_enable(<<"urn:xmpp:carbons:2">>, IgnoreEls, _el); - {<<"disable">>, <<"urn:xmpp:carbons:2">>} -> + {<<"enable">>, <<>>, <<"urn:xmpp:carbons:2">>} -> + decode_carbons_enable(<<"urn:xmpp:carbons:2">>, + IgnoreEls, _el); + {<<"disable">>, <<"urn:xmpp:carbons:2">>, _} -> decode_carbons_disable(<<"urn:xmpp:carbons:2">>, IgnoreEls, _el); - {<<"forwarded">>, <<"urn:xmpp:forward:0">>} -> + {<<"disable">>, <<>>, <<"urn:xmpp:carbons:2">>} -> + decode_carbons_disable(<<"urn:xmpp:carbons:2">>, + IgnoreEls, _el); + {<<"forwarded">>, <<"urn:xmpp:forward:0">>, _} -> decode_forwarded(<<"urn:xmpp:forward:0">>, IgnoreEls, _el); - {<<"fin">>, <<"urn:xmpp:mam:0">>} -> + {<<"forwarded">>, <<>>, <<"urn:xmpp:forward:0">>} -> + decode_forwarded(<<"urn:xmpp:forward:0">>, IgnoreEls, + _el); + {<<"fin">>, <<"urn:xmpp:mam:0">>, _} -> decode_mam_fin(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); - {<<"fin">>, <<"urn:xmpp:mam:1">>} -> + {<<"fin">>, <<>>, <<"urn:xmpp:mam:0">>} -> + decode_mam_fin(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); + {<<"fin">>, <<"urn:xmpp:mam:1">>, _} -> decode_mam_fin(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); - {<<"prefs">>, <<"urn:xmpp:mam:0">>} -> + {<<"fin">>, <<>>, <<"urn:xmpp:mam:1">>} -> + decode_mam_fin(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); + {<<"prefs">>, <<"urn:xmpp:mam:0">>, _} -> decode_mam_prefs(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); - {<<"prefs">>, <<"urn:xmpp:mam:1">>} -> + {<<"prefs">>, <<>>, <<"urn:xmpp:mam:0">>} -> + decode_mam_prefs(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); + {<<"prefs">>, <<"urn:xmpp:mam:1">>, _} -> decode_mam_prefs(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); - {<<"prefs">>, <<"urn:xmpp:mam:tmp">>} -> + {<<"prefs">>, <<>>, <<"urn:xmpp:mam:1">>} -> + decode_mam_prefs(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); + {<<"prefs">>, <<"urn:xmpp:mam:tmp">>, _} -> decode_mam_prefs(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); - {<<"always">>, <<"urn:xmpp:mam:0">>} -> + {<<"prefs">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> + decode_mam_prefs(<<"urn:xmpp:mam:tmp">>, IgnoreEls, + _el); + {<<"always">>, <<"urn:xmpp:mam:0">>, _} -> decode_mam_always(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); - {<<"always">>, <<"urn:xmpp:mam:1">>} -> + {<<"always">>, <<>>, <<"urn:xmpp:mam:0">>} -> + decode_mam_always(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); + {<<"always">>, <<"urn:xmpp:mam:1">>, _} -> decode_mam_always(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); - {<<"always">>, <<"urn:xmpp:mam:tmp">>} -> + {<<"always">>, <<>>, <<"urn:xmpp:mam:1">>} -> + decode_mam_always(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); + {<<"always">>, <<"urn:xmpp:mam:tmp">>, _} -> decode_mam_always(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); - {<<"never">>, <<"urn:xmpp:mam:0">>} -> + {<<"always">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> + decode_mam_always(<<"urn:xmpp:mam:tmp">>, IgnoreEls, + _el); + {<<"never">>, <<"urn:xmpp:mam:0">>, _} -> decode_mam_never(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); - {<<"never">>, <<"urn:xmpp:mam:1">>} -> + {<<"never">>, <<>>, <<"urn:xmpp:mam:0">>} -> + decode_mam_never(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); + {<<"never">>, <<"urn:xmpp:mam:1">>, _} -> decode_mam_never(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); - {<<"never">>, <<"urn:xmpp:mam:tmp">>} -> + {<<"never">>, <<>>, <<"urn:xmpp:mam:1">>} -> + decode_mam_never(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); + {<<"never">>, <<"urn:xmpp:mam:tmp">>, _} -> decode_mam_never(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); - {<<"jid">>, <<"urn:xmpp:mam:0">>} -> + {<<"never">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> + decode_mam_never(<<"urn:xmpp:mam:tmp">>, IgnoreEls, + _el); + {<<"jid">>, <<"urn:xmpp:mam:0">>, _} -> decode_mam_jid(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); - {<<"jid">>, <<"urn:xmpp:mam:1">>} -> + {<<"jid">>, <<>>, <<"urn:xmpp:mam:0">>} -> + decode_mam_jid(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); + {<<"jid">>, <<"urn:xmpp:mam:1">>, _} -> decode_mam_jid(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); - {<<"jid">>, <<"urn:xmpp:mam:tmp">>} -> + {<<"jid">>, <<>>, <<"urn:xmpp:mam:1">>} -> + decode_mam_jid(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); + {<<"jid">>, <<"urn:xmpp:mam:tmp">>, _} -> decode_mam_jid(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); - {<<"result">>, <<"urn:xmpp:mam:0">>} -> + {<<"jid">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> + decode_mam_jid(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); + {<<"result">>, <<"urn:xmpp:mam:0">>, _} -> decode_mam_result(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); - {<<"result">>, <<"urn:xmpp:mam:1">>} -> + {<<"result">>, <<>>, <<"urn:xmpp:mam:0">>} -> + decode_mam_result(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); + {<<"result">>, <<"urn:xmpp:mam:1">>, _} -> decode_mam_result(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); - {<<"result">>, <<"urn:xmpp:mam:tmp">>} -> + {<<"result">>, <<>>, <<"urn:xmpp:mam:1">>} -> + decode_mam_result(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); + {<<"result">>, <<"urn:xmpp:mam:tmp">>, _} -> decode_mam_result(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); - {<<"archived">>, <<"urn:xmpp:mam:tmp">>} -> + {<<"result">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> + decode_mam_result(<<"urn:xmpp:mam:tmp">>, IgnoreEls, + _el); + {<<"archived">>, <<"urn:xmpp:mam:tmp">>, _} -> decode_mam_archived(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); - {<<"query">>, <<"urn:xmpp:mam:0">>} -> + {<<"archived">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> + decode_mam_archived(<<"urn:xmpp:mam:tmp">>, IgnoreEls, + _el); + {<<"query">>, <<"urn:xmpp:mam:0">>, _} -> decode_mam_query(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); - {<<"query">>, <<"urn:xmpp:mam:1">>} -> + {<<"query">>, <<>>, <<"urn:xmpp:mam:0">>} -> + decode_mam_query(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); + {<<"query">>, <<"urn:xmpp:mam:1">>, _} -> decode_mam_query(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); - {<<"query">>, <<"urn:xmpp:mam:tmp">>} -> + {<<"query">>, <<>>, <<"urn:xmpp:mam:1">>} -> + decode_mam_query(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); + {<<"query">>, <<"urn:xmpp:mam:tmp">>, _} -> decode_mam_query(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); - {<<"withtext">>, <<"urn:xmpp:mam:tmp">>} -> + {<<"query">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> + decode_mam_query(<<"urn:xmpp:mam:tmp">>, IgnoreEls, + _el); + {<<"withtext">>, <<"urn:xmpp:mam:tmp">>, _} -> decode_mam_withtext(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); - {<<"with">>, <<"urn:xmpp:mam:tmp">>} -> + {<<"withtext">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> + decode_mam_withtext(<<"urn:xmpp:mam:tmp">>, IgnoreEls, + _el); + {<<"with">>, <<"urn:xmpp:mam:tmp">>, _} -> decode_mam_with(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); - {<<"end">>, <<"urn:xmpp:mam:tmp">>} -> + {<<"with">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> + decode_mam_with(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); + {<<"end">>, <<"urn:xmpp:mam:tmp">>, _} -> decode_mam_end(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); - {<<"start">>, <<"urn:xmpp:mam:tmp">>} -> + {<<"end">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> + decode_mam_end(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); + {<<"start">>, <<"urn:xmpp:mam:tmp">>, _} -> decode_mam_start(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); - {<<"set">>, <<"http://jabber.org/protocol/rsm">>} -> + {<<"start">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> + decode_mam_start(<<"urn:xmpp:mam:tmp">>, IgnoreEls, + _el); + {<<"set">>, <<"http://jabber.org/protocol/rsm">>, _} -> decode_rsm_set(<<"http://jabber.org/protocol/rsm">>, IgnoreEls, _el); - {<<"first">>, <<"http://jabber.org/protocol/rsm">>} -> + {<<"set">>, <<>>, + <<"http://jabber.org/protocol/rsm">>} -> + decode_rsm_set(<<"http://jabber.org/protocol/rsm">>, + IgnoreEls, _el); + {<<"first">>, <<"http://jabber.org/protocol/rsm">>, + _} -> decode_rsm_first(<<"http://jabber.org/protocol/rsm">>, IgnoreEls, _el); - {<<"max">>, <<"http://jabber.org/protocol/rsm">>} -> + {<<"first">>, <<>>, + <<"http://jabber.org/protocol/rsm">>} -> + decode_rsm_first(<<"http://jabber.org/protocol/rsm">>, + IgnoreEls, _el); + {<<"max">>, <<"http://jabber.org/protocol/rsm">>, _} -> decode_rsm_max(<<"http://jabber.org/protocol/rsm">>, IgnoreEls, _el); - {<<"index">>, <<"http://jabber.org/protocol/rsm">>} -> + {<<"max">>, <<>>, + <<"http://jabber.org/protocol/rsm">>} -> + decode_rsm_max(<<"http://jabber.org/protocol/rsm">>, + IgnoreEls, _el); + {<<"index">>, <<"http://jabber.org/protocol/rsm">>, + _} -> decode_rsm_index(<<"http://jabber.org/protocol/rsm">>, IgnoreEls, _el); - {<<"count">>, <<"http://jabber.org/protocol/rsm">>} -> + {<<"index">>, <<>>, + <<"http://jabber.org/protocol/rsm">>} -> + decode_rsm_index(<<"http://jabber.org/protocol/rsm">>, + IgnoreEls, _el); + {<<"count">>, <<"http://jabber.org/protocol/rsm">>, + _} -> decode_rsm_count(<<"http://jabber.org/protocol/rsm">>, IgnoreEls, _el); - {<<"last">>, <<"http://jabber.org/protocol/rsm">>} -> + {<<"count">>, <<>>, + <<"http://jabber.org/protocol/rsm">>} -> + decode_rsm_count(<<"http://jabber.org/protocol/rsm">>, + IgnoreEls, _el); + {<<"last">>, <<"http://jabber.org/protocol/rsm">>, _} -> decode_rsm_last(<<"http://jabber.org/protocol/rsm">>, IgnoreEls, _el); - {<<"before">>, <<"http://jabber.org/protocol/rsm">>} -> + {<<"last">>, <<>>, + <<"http://jabber.org/protocol/rsm">>} -> + decode_rsm_last(<<"http://jabber.org/protocol/rsm">>, + IgnoreEls, _el); + {<<"before">>, <<"http://jabber.org/protocol/rsm">>, + _} -> decode_rsm_before(<<"http://jabber.org/protocol/rsm">>, IgnoreEls, _el); - {<<"after">>, <<"http://jabber.org/protocol/rsm">>} -> + {<<"before">>, <<>>, + <<"http://jabber.org/protocol/rsm">>} -> + decode_rsm_before(<<"http://jabber.org/protocol/rsm">>, + IgnoreEls, _el); + {<<"after">>, <<"http://jabber.org/protocol/rsm">>, + _} -> decode_rsm_after(<<"http://jabber.org/protocol/rsm">>, IgnoreEls, _el); - {<<"unsubscribe">>, <<"urn:xmpp:mucsub:0">>} -> + {<<"after">>, <<>>, + <<"http://jabber.org/protocol/rsm">>} -> + decode_rsm_after(<<"http://jabber.org/protocol/rsm">>, + IgnoreEls, _el); + {<<"unsubscribe">>, <<"urn:xmpp:mucsub:0">>, _} -> decode_muc_unsubscribe(<<"urn:xmpp:mucsub:0">>, IgnoreEls, _el); - {<<"subscribe">>, <<"urn:xmpp:mucsub:0">>} -> + {<<"unsubscribe">>, <<>>, <<"urn:xmpp:mucsub:0">>} -> + decode_muc_unsubscribe(<<"urn:xmpp:mucsub:0">>, + IgnoreEls, _el); + {<<"subscribe">>, <<"urn:xmpp:mucsub:0">>, _} -> decode_muc_subscribe(<<"urn:xmpp:mucsub:0">>, IgnoreEls, _el); - {<<"event">>, <<"urn:xmpp:mucsub:0">>} -> + {<<"subscribe">>, <<>>, <<"urn:xmpp:mucsub:0">>} -> + decode_muc_subscribe(<<"urn:xmpp:mucsub:0">>, IgnoreEls, + _el); + {<<"event">>, <<"urn:xmpp:mucsub:0">>, _} -> decode_muc_subscribe_event(<<"urn:xmpp:mucsub:0">>, IgnoreEls, _el); - {<<"subscriptions">>, <<"urn:xmpp:mucsub:0">>} -> + {<<"event">>, <<>>, <<"urn:xmpp:mucsub:0">>} -> + decode_muc_subscribe_event(<<"urn:xmpp:mucsub:0">>, + IgnoreEls, _el); + {<<"subscriptions">>, <<"urn:xmpp:mucsub:0">>, _} -> decode_muc_subscriptions(<<"urn:xmpp:mucsub:0">>, IgnoreEls, _el); - {<<"subscription">>, <<"urn:xmpp:mucsub:0">>} -> + {<<"subscriptions">>, <<>>, <<"urn:xmpp:mucsub:0">>} -> + decode_muc_subscriptions(<<"urn:xmpp:mucsub:0">>, + IgnoreEls, _el); + {<<"subscription">>, <<"urn:xmpp:mucsub:0">>, _} -> decode_muc_subscription(<<"urn:xmpp:mucsub:0">>, IgnoreEls, _el); - {<<"x">>, <<"jabber:x:conference">>} -> + {<<"subscription">>, <<>>, <<"urn:xmpp:mucsub:0">>} -> + decode_muc_subscription(<<"urn:xmpp:mucsub:0">>, + IgnoreEls, _el); + {<<"x">>, <<"jabber:x:conference">>, _} -> + decode_x_conference(<<"jabber:x:conference">>, + IgnoreEls, _el); + {<<"x">>, <<>>, <<"jabber:x:conference">>} -> decode_x_conference(<<"jabber:x:conference">>, IgnoreEls, _el); {<<"unique">>, + <<"http://jabber.org/protocol/muc#unique">>, _} -> + decode_muc_unique(<<"http://jabber.org/protocol/muc#unique">>, + IgnoreEls, _el); + {<<"unique">>, <<>>, <<"http://jabber.org/protocol/muc#unique">>} -> decode_muc_unique(<<"http://jabber.org/protocol/muc#unique">>, IgnoreEls, _el); - {<<"x">>, <<"http://jabber.org/protocol/muc">>} -> + {<<"x">>, <<"http://jabber.org/protocol/muc">>, _} -> + decode_muc(<<"http://jabber.org/protocol/muc">>, + IgnoreEls, _el); + {<<"x">>, <<>>, <<"http://jabber.org/protocol/muc">>} -> decode_muc(<<"http://jabber.org/protocol/muc">>, IgnoreEls, _el); {<<"query">>, + <<"http://jabber.org/protocol/muc#admin">>, _} -> + decode_muc_admin(<<"http://jabber.org/protocol/muc#admin">>, + IgnoreEls, _el); + {<<"query">>, <<>>, <<"http://jabber.org/protocol/muc#admin">>} -> decode_muc_admin(<<"http://jabber.org/protocol/muc#admin">>, IgnoreEls, _el); {<<"continue">>, + <<"http://jabber.org/protocol/muc#admin">>, _} -> + decode_muc_admin_continue(<<"http://jabber.org/protocol/muc#admin">>, + IgnoreEls, _el); + {<<"continue">>, <<>>, <<"http://jabber.org/protocol/muc#admin">>} -> decode_muc_admin_continue(<<"http://jabber.org/protocol/muc#admin">>, IgnoreEls, _el); {<<"actor">>, + <<"http://jabber.org/protocol/muc#admin">>, _} -> + decode_muc_admin_actor(<<"http://jabber.org/protocol/muc#admin">>, + IgnoreEls, _el); + {<<"actor">>, <<>>, <<"http://jabber.org/protocol/muc#admin">>} -> decode_muc_admin_actor(<<"http://jabber.org/protocol/muc#admin">>, IgnoreEls, _el); - {<<"item">>, + {<<"item">>, <<"http://jabber.org/protocol/muc#admin">>, + _} -> + decode_muc_admin_item(<<"http://jabber.org/protocol/muc#admin">>, + IgnoreEls, _el); + {<<"item">>, <<>>, <<"http://jabber.org/protocol/muc#admin">>} -> decode_muc_admin_item(<<"http://jabber.org/protocol/muc#admin">>, IgnoreEls, _el); - {<<"item">>, + {<<"item">>, <<"http://jabber.org/protocol/muc#owner">>, + _} -> + decode_muc_owner_item(<<"http://jabber.org/protocol/muc#owner">>, + IgnoreEls, _el); + {<<"item">>, <<>>, <<"http://jabber.org/protocol/muc#owner">>} -> decode_muc_owner_item(<<"http://jabber.org/protocol/muc#owner">>, IgnoreEls, _el); {<<"query">>, + <<"http://jabber.org/protocol/muc#owner">>, _} -> + decode_muc_owner(<<"http://jabber.org/protocol/muc#owner">>, + IgnoreEls, _el); + {<<"query">>, <<>>, <<"http://jabber.org/protocol/muc#owner">>} -> decode_muc_owner(<<"http://jabber.org/protocol/muc#owner">>, IgnoreEls, _el); {<<"password">>, + <<"http://jabber.org/protocol/muc#owner">>, _} -> + decode_muc_password(<<"http://jabber.org/protocol/muc#owner">>, + IgnoreEls, _el); + {<<"password">>, <<>>, <<"http://jabber.org/protocol/muc#owner">>} -> decode_muc_password(<<"http://jabber.org/protocol/muc#owner">>, IgnoreEls, _el); {<<"password">>, + <<"http://jabber.org/protocol/muc#user">>, _} -> + decode_muc_password(<<"http://jabber.org/protocol/muc#user">>, + IgnoreEls, _el); + {<<"password">>, <<>>, <<"http://jabber.org/protocol/muc#user">>} -> decode_muc_password(<<"http://jabber.org/protocol/muc#user">>, IgnoreEls, _el); - {<<"password">>, + {<<"password">>, <<"http://jabber.org/protocol/muc">>, + _} -> + decode_muc_password(<<"http://jabber.org/protocol/muc">>, + IgnoreEls, _el); + {<<"password">>, <<>>, <<"http://jabber.org/protocol/muc">>} -> decode_muc_password(<<"http://jabber.org/protocol/muc">>, IgnoreEls, _el); - {<<"x">>, <<"http://jabber.org/protocol/muc#user">>} -> + {<<"x">>, <<"http://jabber.org/protocol/muc#user">>, + _} -> decode_muc_user(<<"http://jabber.org/protocol/muc#user">>, IgnoreEls, _el); - {<<"item">>, + {<<"x">>, <<>>, + <<"http://jabber.org/protocol/muc#user">>} -> + decode_muc_user(<<"http://jabber.org/protocol/muc#user">>, + IgnoreEls, _el); + {<<"item">>, <<"http://jabber.org/protocol/muc#user">>, + _} -> + decode_muc_user_item(<<"http://jabber.org/protocol/muc#user">>, + IgnoreEls, _el); + {<<"item">>, <<>>, <<"http://jabber.org/protocol/muc#user">>} -> decode_muc_user_item(<<"http://jabber.org/protocol/muc#user">>, IgnoreEls, _el); {<<"status">>, + <<"http://jabber.org/protocol/muc#user">>, _} -> + decode_muc_user_status(<<"http://jabber.org/protocol/muc#user">>, + IgnoreEls, _el); + {<<"status">>, <<>>, <<"http://jabber.org/protocol/muc#user">>} -> decode_muc_user_status(<<"http://jabber.org/protocol/muc#user">>, IgnoreEls, _el); {<<"continue">>, + <<"http://jabber.org/protocol/muc#user">>, _} -> + decode_muc_user_continue(<<"http://jabber.org/protocol/muc#user">>, + IgnoreEls, _el); + {<<"continue">>, <<>>, <<"http://jabber.org/protocol/muc#user">>} -> decode_muc_user_continue(<<"http://jabber.org/protocol/muc#user">>, IgnoreEls, _el); - {<<"actor">>, + {<<"actor">>, <<"http://jabber.org/protocol/muc#user">>, + _} -> + decode_muc_user_actor(<<"http://jabber.org/protocol/muc#user">>, + IgnoreEls, _el); + {<<"actor">>, <<>>, <<"http://jabber.org/protocol/muc#user">>} -> decode_muc_user_actor(<<"http://jabber.org/protocol/muc#user">>, IgnoreEls, _el); {<<"invite">>, + <<"http://jabber.org/protocol/muc#user">>, _} -> + decode_muc_user_invite(<<"http://jabber.org/protocol/muc#user">>, + IgnoreEls, _el); + {<<"invite">>, <<>>, <<"http://jabber.org/protocol/muc#user">>} -> decode_muc_user_invite(<<"http://jabber.org/protocol/muc#user">>, IgnoreEls, _el); {<<"destroy">>, + <<"http://jabber.org/protocol/muc#user">>, _} -> + decode_muc_destroy(<<"http://jabber.org/protocol/muc#user">>, + IgnoreEls, _el); + {<<"destroy">>, <<>>, <<"http://jabber.org/protocol/muc#user">>} -> decode_muc_destroy(<<"http://jabber.org/protocol/muc#user">>, IgnoreEls, _el); {<<"destroy">>, + <<"http://jabber.org/protocol/muc#owner">>, _} -> + decode_muc_destroy(<<"http://jabber.org/protocol/muc#owner">>, + IgnoreEls, _el); + {<<"destroy">>, <<>>, <<"http://jabber.org/protocol/muc#owner">>} -> decode_muc_destroy(<<"http://jabber.org/protocol/muc#owner">>, IgnoreEls, _el); {<<"decline">>, + <<"http://jabber.org/protocol/muc#user">>, _} -> + decode_muc_user_decline(<<"http://jabber.org/protocol/muc#user">>, + IgnoreEls, _el); + {<<"decline">>, <<>>, <<"http://jabber.org/protocol/muc#user">>} -> decode_muc_user_decline(<<"http://jabber.org/protocol/muc#user">>, IgnoreEls, _el); {<<"reason">>, + <<"http://jabber.org/protocol/muc#user">>, _} -> + decode_muc_reason(<<"http://jabber.org/protocol/muc#user">>, + IgnoreEls, _el); + {<<"reason">>, <<>>, <<"http://jabber.org/protocol/muc#user">>} -> decode_muc_reason(<<"http://jabber.org/protocol/muc#user">>, IgnoreEls, _el); {<<"reason">>, + <<"http://jabber.org/protocol/muc#admin">>, _} -> + decode_muc_reason(<<"http://jabber.org/protocol/muc#admin">>, + IgnoreEls, _el); + {<<"reason">>, <<>>, <<"http://jabber.org/protocol/muc#admin">>} -> decode_muc_reason(<<"http://jabber.org/protocol/muc#admin">>, IgnoreEls, _el); {<<"reason">>, + <<"http://jabber.org/protocol/muc#owner">>, _} -> + decode_muc_reason(<<"http://jabber.org/protocol/muc#owner">>, + IgnoreEls, _el); + {<<"reason">>, <<>>, <<"http://jabber.org/protocol/muc#owner">>} -> decode_muc_reason(<<"http://jabber.org/protocol/muc#owner">>, IgnoreEls, _el); - {<<"history">>, <<"http://jabber.org/protocol/muc">>} -> + {<<"history">>, <<"http://jabber.org/protocol/muc">>, + _} -> + decode_muc_history(<<"http://jabber.org/protocol/muc">>, + IgnoreEls, _el); + {<<"history">>, <<>>, + <<"http://jabber.org/protocol/muc">>} -> decode_muc_history(<<"http://jabber.org/protocol/muc">>, IgnoreEls, _el); {<<"query">>, + <<"http://jabber.org/protocol/bytestreams">>, _} -> + decode_bytestreams(<<"http://jabber.org/protocol/bytestreams">>, + IgnoreEls, _el); + {<<"query">>, <<>>, <<"http://jabber.org/protocol/bytestreams">>} -> decode_bytestreams(<<"http://jabber.org/protocol/bytestreams">>, IgnoreEls, _el); {<<"activate">>, + <<"http://jabber.org/protocol/bytestreams">>, _} -> + decode_bytestreams_activate(<<"http://jabber.org/protocol/bytestreams">>, + IgnoreEls, _el); + {<<"activate">>, <<>>, <<"http://jabber.org/protocol/bytestreams">>} -> decode_bytestreams_activate(<<"http://jabber.org/protocol/bytestreams">>, IgnoreEls, _el); {<<"streamhost-used">>, + <<"http://jabber.org/protocol/bytestreams">>, _} -> + decode_bytestreams_streamhost_used(<<"http://jabber.org/protocol/bytestreams">>, + IgnoreEls, _el); + {<<"streamhost-used">>, <<>>, <<"http://jabber.org/protocol/bytestreams">>} -> decode_bytestreams_streamhost_used(<<"http://jabber.org/protocol/bytestreams">>, IgnoreEls, _el); {<<"streamhost">>, + <<"http://jabber.org/protocol/bytestreams">>, _} -> + decode_bytestreams_streamhost(<<"http://jabber.org/protocol/bytestreams">>, + IgnoreEls, _el); + {<<"streamhost">>, <<>>, <<"http://jabber.org/protocol/bytestreams">>} -> decode_bytestreams_streamhost(<<"http://jabber.org/protocol/bytestreams">>, IgnoreEls, _el); - {<<"delay">>, <<"urn:xmpp:delay">>} -> + {<<"delay">>, <<"urn:xmpp:delay">>, _} -> + decode_delay(<<"urn:xmpp:delay">>, IgnoreEls, _el); + {<<"delay">>, <<>>, <<"urn:xmpp:delay">>} -> decode_delay(<<"urn:xmpp:delay">>, IgnoreEls, _el); {<<"paused">>, + <<"http://jabber.org/protocol/chatstates">>, _} -> + decode_chatstate_paused(<<"http://jabber.org/protocol/chatstates">>, + IgnoreEls, _el); + {<<"paused">>, <<>>, <<"http://jabber.org/protocol/chatstates">>} -> decode_chatstate_paused(<<"http://jabber.org/protocol/chatstates">>, IgnoreEls, _el); {<<"inactive">>, + <<"http://jabber.org/protocol/chatstates">>, _} -> + decode_chatstate_inactive(<<"http://jabber.org/protocol/chatstates">>, + IgnoreEls, _el); + {<<"inactive">>, <<>>, <<"http://jabber.org/protocol/chatstates">>} -> decode_chatstate_inactive(<<"http://jabber.org/protocol/chatstates">>, IgnoreEls, _el); {<<"gone">>, + <<"http://jabber.org/protocol/chatstates">>, _} -> + decode_chatstate_gone(<<"http://jabber.org/protocol/chatstates">>, + IgnoreEls, _el); + {<<"gone">>, <<>>, <<"http://jabber.org/protocol/chatstates">>} -> decode_chatstate_gone(<<"http://jabber.org/protocol/chatstates">>, IgnoreEls, _el); {<<"composing">>, + <<"http://jabber.org/protocol/chatstates">>, _} -> + decode_chatstate_composing(<<"http://jabber.org/protocol/chatstates">>, + IgnoreEls, _el); + {<<"composing">>, <<>>, <<"http://jabber.org/protocol/chatstates">>} -> decode_chatstate_composing(<<"http://jabber.org/protocol/chatstates">>, IgnoreEls, _el); {<<"active">>, + <<"http://jabber.org/protocol/chatstates">>, _} -> + decode_chatstate_active(<<"http://jabber.org/protocol/chatstates">>, + IgnoreEls, _el); + {<<"active">>, <<>>, <<"http://jabber.org/protocol/chatstates">>} -> decode_chatstate_active(<<"http://jabber.org/protocol/chatstates">>, IgnoreEls, _el); - {<<"headers">>, + {<<"headers">>, <<"http://jabber.org/protocol/shim">>, + _} -> + decode_shim_headers(<<"http://jabber.org/protocol/shim">>, + IgnoreEls, _el); + {<<"headers">>, <<>>, <<"http://jabber.org/protocol/shim">>} -> decode_shim_headers(<<"http://jabber.org/protocol/shim">>, IgnoreEls, _el); - {<<"header">>, <<"http://jabber.org/protocol/shim">>} -> + {<<"header">>, <<"http://jabber.org/protocol/shim">>, + _} -> + decode_shim_header(<<"http://jabber.org/protocol/shim">>, + IgnoreEls, _el); + {<<"header">>, <<>>, + <<"http://jabber.org/protocol/shim">>} -> decode_shim_header(<<"http://jabber.org/protocol/shim">>, IgnoreEls, _el); {<<"unsupported-access-model">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + decode_pubsub_error_unsupported_access_model(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"unsupported-access-model">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> decode_pubsub_error_unsupported_access_model(<<"http://jabber.org/protocol/pubsub#errors">>, IgnoreEls, _el); {<<"unsupported">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + decode_pubsub_error_unsupported(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"unsupported">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> decode_pubsub_error_unsupported(<<"http://jabber.org/protocol/pubsub#errors">>, IgnoreEls, _el); {<<"too-many-subscriptions">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + decode_pubsub_error_too_many_subscriptions(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"too-many-subscriptions">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> decode_pubsub_error_too_many_subscriptions(<<"http://jabber.org/protocol/pubsub#errors">>, IgnoreEls, _el); {<<"subid-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + decode_pubsub_error_subid_required(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"subid-required">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> decode_pubsub_error_subid_required(<<"http://jabber.org/protocol/pubsub#errors">>, IgnoreEls, _el); {<<"presence-subscription-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + decode_pubsub_error_presence_subscription_required(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"presence-subscription-required">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> decode_pubsub_error_presence_subscription_required(<<"http://jabber.org/protocol/pubsub#errors">>, IgnoreEls, _el); {<<"pending-subscription">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + decode_pubsub_error_pending_subscription(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"pending-subscription">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> decode_pubsub_error_pending_subscription(<<"http://jabber.org/protocol/pubsub#errors">>, IgnoreEls, _el); {<<"payload-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + decode_pubsub_error_payload_required(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"payload-required">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> decode_pubsub_error_payload_required(<<"http://jabber.org/protocol/pubsub#errors">>, IgnoreEls, _el); {<<"payload-too-big">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + decode_pubsub_error_payload_too_big(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"payload-too-big">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> decode_pubsub_error_payload_too_big(<<"http://jabber.org/protocol/pubsub#errors">>, IgnoreEls, _el); {<<"not-subscribed">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + decode_pubsub_error_not_subscribed(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"not-subscribed">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> decode_pubsub_error_not_subscribed(<<"http://jabber.org/protocol/pubsub#errors">>, IgnoreEls, _el); {<<"not-in-roster-group">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + decode_pubsub_error_not_in_roster_group(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"not-in-roster-group">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> decode_pubsub_error_not_in_roster_group(<<"http://jabber.org/protocol/pubsub#errors">>, IgnoreEls, _el); {<<"nodeid-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + decode_pubsub_error_nodeid_required(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"nodeid-required">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> decode_pubsub_error_nodeid_required(<<"http://jabber.org/protocol/pubsub#errors">>, IgnoreEls, _el); {<<"max-nodes-exceeded">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + decode_pubsub_error_max_nodes_exceeded(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"max-nodes-exceeded">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> decode_pubsub_error_max_nodes_exceeded(<<"http://jabber.org/protocol/pubsub#errors">>, IgnoreEls, _el); {<<"max-items-exceeded">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + decode_pubsub_error_max_items_exceeded(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"max-items-exceeded">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> decode_pubsub_error_max_items_exceeded(<<"http://jabber.org/protocol/pubsub#errors">>, IgnoreEls, _el); {<<"jid-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + decode_pubsub_error_jid_required(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"jid-required">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> decode_pubsub_error_jid_required(<<"http://jabber.org/protocol/pubsub#errors">>, IgnoreEls, _el); {<<"item-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + decode_pubsub_error_item_required(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"item-required">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> decode_pubsub_error_item_required(<<"http://jabber.org/protocol/pubsub#errors">>, IgnoreEls, _el); {<<"item-forbidden">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + decode_pubsub_error_item_forbidden(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"item-forbidden">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> decode_pubsub_error_item_forbidden(<<"http://jabber.org/protocol/pubsub#errors">>, IgnoreEls, _el); {<<"invalid-subid">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + decode_pubsub_error_invalid_subid(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"invalid-subid">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> decode_pubsub_error_invalid_subid(<<"http://jabber.org/protocol/pubsub#errors">>, IgnoreEls, _el); {<<"invalid-payload">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + decode_pubsub_error_invalid_payload(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"invalid-payload">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> decode_pubsub_error_invalid_payload(<<"http://jabber.org/protocol/pubsub#errors">>, IgnoreEls, _el); {<<"invalid-options">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + decode_pubsub_error_invalid_options(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"invalid-options">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> decode_pubsub_error_invalid_options(<<"http://jabber.org/protocol/pubsub#errors">>, IgnoreEls, _el); {<<"invalid-jid">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + decode_pubsub_error_invalid_jid(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"invalid-jid">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> decode_pubsub_error_invalid_jid(<<"http://jabber.org/protocol/pubsub#errors">>, IgnoreEls, _el); {<<"configuration-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + decode_pubsub_error_configuration_required(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"configuration-required">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> decode_pubsub_error_configuration_required(<<"http://jabber.org/protocol/pubsub#errors">>, IgnoreEls, _el); {<<"closed-node">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + decode_pubsub_error_closed_node(<<"http://jabber.org/protocol/pubsub#errors">>, + IgnoreEls, _el); + {<<"closed-node">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> decode_pubsub_error_closed_node(<<"http://jabber.org/protocol/pubsub#errors">>, IgnoreEls, _el); {<<"pubsub">>, + <<"http://jabber.org/protocol/pubsub#owner">>, _} -> + decode_pubsub_owner(<<"http://jabber.org/protocol/pubsub#owner">>, + IgnoreEls, _el); + {<<"pubsub">>, <<>>, <<"http://jabber.org/protocol/pubsub#owner">>} -> decode_pubsub_owner(<<"http://jabber.org/protocol/pubsub#owner">>, IgnoreEls, _el); - {<<"pubsub">>, + {<<"pubsub">>, <<"http://jabber.org/protocol/pubsub">>, + _} -> + decode_pubsub(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"pubsub">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub(<<"http://jabber.org/protocol/pubsub">>, IgnoreEls, _el); - {<<"purge">>, + {<<"purge">>, <<"http://jabber.org/protocol/pubsub">>, + _} -> + decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"purge">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub">>, IgnoreEls, _el); {<<"purge">>, + <<"http://jabber.org/protocol/pubsub#owner">>, _} -> + decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub#owner">>, + IgnoreEls, _el); + {<<"purge">>, <<>>, <<"http://jabber.org/protocol/pubsub#owner">>} -> decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub#owner">>, IgnoreEls, _el); {<<"purge">>, + <<"http://jabber.org/protocol/pubsub#event">>, _} -> + decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub#event">>, + IgnoreEls, _el); + {<<"purge">>, <<>>, <<"http://jabber.org/protocol/pubsub#event">>} -> decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub#event">>, IgnoreEls, _el); - {<<"delete">>, + {<<"delete">>, <<"http://jabber.org/protocol/pubsub">>, + _} -> + decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"delete">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub">>, IgnoreEls, _el); {<<"delete">>, + <<"http://jabber.org/protocol/pubsub#owner">>, _} -> + decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub#owner">>, + IgnoreEls, _el); + {<<"delete">>, <<>>, <<"http://jabber.org/protocol/pubsub#owner">>} -> decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub#owner">>, IgnoreEls, _el); {<<"delete">>, + <<"http://jabber.org/protocol/pubsub#event">>, _} -> + decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub#event">>, + IgnoreEls, _el); + {<<"delete">>, <<>>, <<"http://jabber.org/protocol/pubsub#event">>} -> decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub#event">>, IgnoreEls, _el); {<<"redirect">>, + <<"http://jabber.org/protocol/pubsub">>, _} -> + decode_pubsub_redirect(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"redirect">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_redirect(<<"http://jabber.org/protocol/pubsub">>, IgnoreEls, _el); {<<"redirect">>, + <<"http://jabber.org/protocol/pubsub#owner">>, _} -> + decode_pubsub_redirect(<<"http://jabber.org/protocol/pubsub#owner">>, + IgnoreEls, _el); + {<<"redirect">>, <<>>, <<"http://jabber.org/protocol/pubsub#owner">>} -> decode_pubsub_redirect(<<"http://jabber.org/protocol/pubsub#owner">>, IgnoreEls, _el); {<<"redirect">>, + <<"http://jabber.org/protocol/pubsub#event">>, _} -> + decode_pubsub_redirect(<<"http://jabber.org/protocol/pubsub#event">>, + IgnoreEls, _el); + {<<"redirect">>, <<>>, <<"http://jabber.org/protocol/pubsub#event">>} -> decode_pubsub_redirect(<<"http://jabber.org/protocol/pubsub#event">>, IgnoreEls, _el); - {<<"default">>, + {<<"default">>, <<"http://jabber.org/protocol/pubsub">>, + _} -> + decode_pubsub_default(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"default">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_default(<<"http://jabber.org/protocol/pubsub">>, IgnoreEls, _el); {<<"default">>, + <<"http://jabber.org/protocol/pubsub#owner">>, _} -> + decode_pubsub_default(<<"http://jabber.org/protocol/pubsub#owner">>, + IgnoreEls, _el); + {<<"default">>, <<>>, <<"http://jabber.org/protocol/pubsub#owner">>} -> decode_pubsub_default(<<"http://jabber.org/protocol/pubsub#owner">>, IgnoreEls, _el); {<<"publish-options">>, + <<"http://jabber.org/protocol/pubsub">>, _} -> + decode_pubsub_publish_options(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"publish-options">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_publish_options(<<"http://jabber.org/protocol/pubsub">>, IgnoreEls, _el); {<<"configure">>, + <<"http://jabber.org/protocol/pubsub">>, _} -> + decode_pubsub_configure(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"configure">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_configure(<<"http://jabber.org/protocol/pubsub">>, IgnoreEls, _el); {<<"configure">>, + <<"http://jabber.org/protocol/pubsub#owner">>, _} -> + decode_pubsub_configure(<<"http://jabber.org/protocol/pubsub#owner">>, + IgnoreEls, _el); + {<<"configure">>, <<>>, <<"http://jabber.org/protocol/pubsub#owner">>} -> decode_pubsub_configure(<<"http://jabber.org/protocol/pubsub#owner">>, IgnoreEls, _el); - {<<"create">>, + {<<"create">>, <<"http://jabber.org/protocol/pubsub">>, + _} -> + decode_pubsub_create(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"create">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_create(<<"http://jabber.org/protocol/pubsub">>, IgnoreEls, _el); {<<"create">>, + <<"http://jabber.org/protocol/pubsub#event">>, _} -> + decode_pubsub_create(<<"http://jabber.org/protocol/pubsub#event">>, + IgnoreEls, _el); + {<<"create">>, <<>>, <<"http://jabber.org/protocol/pubsub#event">>} -> decode_pubsub_create(<<"http://jabber.org/protocol/pubsub#event">>, IgnoreEls, _el); - {<<"retract">>, + {<<"retract">>, <<"http://jabber.org/protocol/pubsub">>, + _} -> + decode_pubsub_retract(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"retract">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_retract(<<"http://jabber.org/protocol/pubsub">>, IgnoreEls, _el); - {<<"options">>, + {<<"options">>, <<"http://jabber.org/protocol/pubsub">>, + _} -> + decode_pubsub_options(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"options">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_options(<<"http://jabber.org/protocol/pubsub">>, IgnoreEls, _el); - {<<"publish">>, + {<<"publish">>, <<"http://jabber.org/protocol/pubsub">>, + _} -> + decode_pubsub_publish(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"publish">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_publish(<<"http://jabber.org/protocol/pubsub">>, IgnoreEls, _el); {<<"unsubscribe">>, + <<"http://jabber.org/protocol/pubsub">>, _} -> + decode_pubsub_unsubscribe(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"unsubscribe">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_unsubscribe(<<"http://jabber.org/protocol/pubsub">>, IgnoreEls, _el); {<<"subscribe">>, + <<"http://jabber.org/protocol/pubsub">>, _} -> + decode_pubsub_subscribe(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"subscribe">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_subscribe(<<"http://jabber.org/protocol/pubsub">>, IgnoreEls, _el); {<<"affiliations">>, + <<"http://jabber.org/protocol/pubsub#owner">>, _} -> + decode_pubsub_owner_affiliations(<<"http://jabber.org/protocol/pubsub#owner">>, + IgnoreEls, _el); + {<<"affiliations">>, <<>>, <<"http://jabber.org/protocol/pubsub#owner">>} -> decode_pubsub_owner_affiliations(<<"http://jabber.org/protocol/pubsub#owner">>, IgnoreEls, _el); {<<"affiliations">>, + <<"http://jabber.org/protocol/pubsub">>, _} -> + decode_pubsub_affiliations(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"affiliations">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_affiliations(<<"http://jabber.org/protocol/pubsub">>, IgnoreEls, _el); {<<"subscriptions">>, + <<"http://jabber.org/protocol/pubsub">>, _} -> + decode_pubsub_subscriptions(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"subscriptions">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_subscriptions(<<"http://jabber.org/protocol/pubsub">>, IgnoreEls, _el); {<<"subscriptions">>, + <<"http://jabber.org/protocol/pubsub#owner">>, _} -> + decode_pubsub_subscriptions(<<"http://jabber.org/protocol/pubsub#owner">>, + IgnoreEls, _el); + {<<"subscriptions">>, <<>>, <<"http://jabber.org/protocol/pubsub#owner">>} -> decode_pubsub_subscriptions(<<"http://jabber.org/protocol/pubsub#owner">>, IgnoreEls, _el); {<<"event">>, + <<"http://jabber.org/protocol/pubsub#event">>, _} -> + decode_pubsub_event(<<"http://jabber.org/protocol/pubsub#event">>, + IgnoreEls, _el); + {<<"event">>, <<>>, <<"http://jabber.org/protocol/pubsub#event">>} -> decode_pubsub_event(<<"http://jabber.org/protocol/pubsub#event">>, IgnoreEls, _el); - {<<"items">>, + {<<"items">>, <<"http://jabber.org/protocol/pubsub">>, + _} -> + decode_pubsub_items(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"items">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_items(<<"http://jabber.org/protocol/pubsub">>, IgnoreEls, _el); {<<"items">>, + <<"http://jabber.org/protocol/pubsub#event">>, _} -> + decode_pubsub_items(<<"http://jabber.org/protocol/pubsub#event">>, + IgnoreEls, _el); + {<<"items">>, <<>>, <<"http://jabber.org/protocol/pubsub#event">>} -> decode_pubsub_items(<<"http://jabber.org/protocol/pubsub#event">>, IgnoreEls, _el); - {<<"item">>, <<"http://jabber.org/protocol/pubsub">>} -> + {<<"item">>, <<"http://jabber.org/protocol/pubsub">>, + _} -> + decode_pubsub_item(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"item">>, <<>>, + <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_item(<<"http://jabber.org/protocol/pubsub">>, IgnoreEls, _el); {<<"item">>, + <<"http://jabber.org/protocol/pubsub#event">>, _} -> + decode_pubsub_item(<<"http://jabber.org/protocol/pubsub#event">>, + IgnoreEls, _el); + {<<"item">>, <<>>, <<"http://jabber.org/protocol/pubsub#event">>} -> decode_pubsub_item(<<"http://jabber.org/protocol/pubsub#event">>, IgnoreEls, _el); {<<"retract">>, + <<"http://jabber.org/protocol/pubsub#event">>, _} -> + decode_pubsub_event_retract(<<"http://jabber.org/protocol/pubsub#event">>, + IgnoreEls, _el); + {<<"retract">>, <<>>, <<"http://jabber.org/protocol/pubsub#event">>} -> decode_pubsub_event_retract(<<"http://jabber.org/protocol/pubsub#event">>, IgnoreEls, _el); {<<"configuration">>, + <<"http://jabber.org/protocol/pubsub#event">>, _} -> + decode_pubsub_event_configuration(<<"http://jabber.org/protocol/pubsub#event">>, + IgnoreEls, _el); + {<<"configuration">>, <<>>, <<"http://jabber.org/protocol/pubsub#event">>} -> decode_pubsub_event_configuration(<<"http://jabber.org/protocol/pubsub#event">>, IgnoreEls, _el); {<<"affiliation">>, + <<"http://jabber.org/protocol/pubsub#owner">>, _} -> + decode_pubsub_owner_affiliation(<<"http://jabber.org/protocol/pubsub#owner">>, + IgnoreEls, _el); + {<<"affiliation">>, <<>>, <<"http://jabber.org/protocol/pubsub#owner">>} -> decode_pubsub_owner_affiliation(<<"http://jabber.org/protocol/pubsub#owner">>, IgnoreEls, _el); {<<"affiliation">>, + <<"http://jabber.org/protocol/pubsub">>, _} -> + decode_pubsub_affiliation(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"affiliation">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_affiliation(<<"http://jabber.org/protocol/pubsub">>, IgnoreEls, _el); {<<"subscription">>, + <<"http://jabber.org/protocol/pubsub">>, _} -> + decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub">>, + IgnoreEls, _el); + {<<"subscription">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub">>, IgnoreEls, _el); {<<"subscription">>, + <<"http://jabber.org/protocol/pubsub#owner">>, _} -> + decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub#owner">>, + IgnoreEls, _el); + {<<"subscription">>, <<>>, <<"http://jabber.org/protocol/pubsub#owner">>} -> decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub#owner">>, IgnoreEls, _el); {<<"subscription">>, + <<"http://jabber.org/protocol/pubsub#event">>, _} -> + decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub#event">>, + IgnoreEls, _el); + {<<"subscription">>, <<>>, <<"http://jabber.org/protocol/pubsub#event">>} -> decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub#event">>, IgnoreEls, _el); - {<<"x">>, <<"jabber:x:data">>} -> + {<<"x">>, <<"jabber:x:data">>, _} -> decode_xdata(<<"jabber:x:data">>, IgnoreEls, _el); - {<<"item">>, <<"jabber:x:data">>} -> + {<<"x">>, <<>>, <<"jabber:x:data">>} -> + decode_xdata(<<"jabber:x:data">>, IgnoreEls, _el); + {<<"item">>, <<"jabber:x:data">>, _} -> decode_xdata_item(<<"jabber:x:data">>, IgnoreEls, _el); - {<<"reported">>, <<"jabber:x:data">>} -> + {<<"item">>, <<>>, <<"jabber:x:data">>} -> + decode_xdata_item(<<"jabber:x:data">>, IgnoreEls, _el); + {<<"reported">>, <<"jabber:x:data">>, _} -> decode_xdata_reported(<<"jabber:x:data">>, IgnoreEls, _el); - {<<"title">>, <<"jabber:x:data">>} -> + {<<"reported">>, <<>>, <<"jabber:x:data">>} -> + decode_xdata_reported(<<"jabber:x:data">>, IgnoreEls, + _el); + {<<"title">>, <<"jabber:x:data">>, _} -> decode_xdata_title(<<"jabber:x:data">>, IgnoreEls, _el); - {<<"instructions">>, <<"jabber:x:data">>} -> + {<<"title">>, <<>>, <<"jabber:x:data">>} -> + decode_xdata_title(<<"jabber:x:data">>, IgnoreEls, _el); + {<<"instructions">>, <<"jabber:x:data">>, _} -> decode_xdata_instructions(<<"jabber:x:data">>, IgnoreEls, _el); - {<<"field">>, <<"jabber:x:data">>} -> + {<<"instructions">>, <<>>, <<"jabber:x:data">>} -> + decode_xdata_instructions(<<"jabber:x:data">>, + IgnoreEls, _el); + {<<"field">>, <<"jabber:x:data">>, _} -> decode_xdata_field(<<"jabber:x:data">>, IgnoreEls, _el); - {<<"option">>, <<"jabber:x:data">>} -> + {<<"field">>, <<>>, <<"jabber:x:data">>} -> + decode_xdata_field(<<"jabber:x:data">>, IgnoreEls, _el); + {<<"option">>, <<"jabber:x:data">>, _} -> decode_xdata_field_option(<<"jabber:x:data">>, IgnoreEls, _el); - {<<"value">>, <<"jabber:x:data">>} -> + {<<"option">>, <<>>, <<"jabber:x:data">>} -> + decode_xdata_field_option(<<"jabber:x:data">>, + IgnoreEls, _el); + {<<"value">>, <<"jabber:x:data">>, _} -> decode_xdata_field_value(<<"jabber:x:data">>, IgnoreEls, _el); - {<<"desc">>, <<"jabber:x:data">>} -> + {<<"value">>, <<>>, <<"jabber:x:data">>} -> + decode_xdata_field_value(<<"jabber:x:data">>, IgnoreEls, + _el); + {<<"desc">>, <<"jabber:x:data">>, _} -> decode_xdata_field_desc(<<"jabber:x:data">>, IgnoreEls, _el); - {<<"required">>, <<"jabber:x:data">>} -> + {<<"desc">>, <<>>, <<"jabber:x:data">>} -> + decode_xdata_field_desc(<<"jabber:x:data">>, IgnoreEls, + _el); + {<<"required">>, <<"jabber:x:data">>, _} -> decode_xdata_field_required(<<"jabber:x:data">>, IgnoreEls, _el); - {<<"x">>, <<"vcard-temp:x:update">>} -> + {<<"required">>, <<>>, <<"jabber:x:data">>} -> + decode_xdata_field_required(<<"jabber:x:data">>, + IgnoreEls, _el); + {<<"x">>, <<"vcard-temp:x:update">>, _} -> decode_vcard_xupdate(<<"vcard-temp:x:update">>, IgnoreEls, _el); - {<<"photo">>, <<"vcard-temp:x:update">>} -> + {<<"x">>, <<>>, <<"vcard-temp:x:update">>} -> + decode_vcard_xupdate(<<"vcard-temp:x:update">>, + IgnoreEls, _el); + {<<"photo">>, <<"vcard-temp:x:update">>, _} -> decode_vcard_xupdate_photo(<<"vcard-temp:x:update">>, IgnoreEls, _el); - {<<"vCard">>, <<"vcard-temp">>} -> + {<<"photo">>, <<>>, <<"vcard-temp:x:update">>} -> + decode_vcard_xupdate_photo(<<"vcard-temp:x:update">>, + IgnoreEls, _el); + {<<"vCard">>, <<"vcard-temp">>, _} -> decode_vcard_temp(<<"vcard-temp">>, IgnoreEls, _el); - {<<"CLASS">>, <<"vcard-temp">>} -> + {<<"vCard">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_temp(<<"vcard-temp">>, IgnoreEls, _el); + {<<"CLASS">>, <<"vcard-temp">>, _} -> decode_vcard_CLASS(<<"vcard-temp">>, IgnoreEls, _el); - {<<"CATEGORIES">>, <<"vcard-temp">>} -> + {<<"CLASS">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_CLASS(<<"vcard-temp">>, IgnoreEls, _el); + {<<"CATEGORIES">>, <<"vcard-temp">>, _} -> decode_vcard_CATEGORIES(<<"vcard-temp">>, IgnoreEls, _el); - {<<"KEY">>, <<"vcard-temp">>} -> + {<<"CATEGORIES">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_CATEGORIES(<<"vcard-temp">>, IgnoreEls, + _el); + {<<"KEY">>, <<"vcard-temp">>, _} -> decode_vcard_KEY(<<"vcard-temp">>, IgnoreEls, _el); - {<<"SOUND">>, <<"vcard-temp">>} -> + {<<"KEY">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_KEY(<<"vcard-temp">>, IgnoreEls, _el); + {<<"SOUND">>, <<"vcard-temp">>, _} -> decode_vcard_SOUND(<<"vcard-temp">>, IgnoreEls, _el); - {<<"ORG">>, <<"vcard-temp">>} -> + {<<"SOUND">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_SOUND(<<"vcard-temp">>, IgnoreEls, _el); + {<<"ORG">>, <<"vcard-temp">>, _} -> decode_vcard_ORG(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PHOTO">>, <<"vcard-temp">>} -> + {<<"ORG">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_ORG(<<"vcard-temp">>, IgnoreEls, _el); + {<<"PHOTO">>, <<"vcard-temp">>, _} -> decode_vcard_PHOTO(<<"vcard-temp">>, IgnoreEls, _el); - {<<"LOGO">>, <<"vcard-temp">>} -> + {<<"PHOTO">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_PHOTO(<<"vcard-temp">>, IgnoreEls, _el); + {<<"LOGO">>, <<"vcard-temp">>, _} -> decode_vcard_LOGO(<<"vcard-temp">>, IgnoreEls, _el); - {<<"BINVAL">>, <<"vcard-temp">>} -> + {<<"LOGO">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_LOGO(<<"vcard-temp">>, IgnoreEls, _el); + {<<"BINVAL">>, <<"vcard-temp">>, _} -> decode_vcard_BINVAL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"GEO">>, <<"vcard-temp">>} -> + {<<"BINVAL">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_BINVAL(<<"vcard-temp">>, IgnoreEls, _el); + {<<"GEO">>, <<"vcard-temp">>, _} -> decode_vcard_GEO(<<"vcard-temp">>, IgnoreEls, _el); - {<<"EMAIL">>, <<"vcard-temp">>} -> + {<<"GEO">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_GEO(<<"vcard-temp">>, IgnoreEls, _el); + {<<"EMAIL">>, <<"vcard-temp">>, _} -> decode_vcard_EMAIL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"TEL">>, <<"vcard-temp">>} -> + {<<"EMAIL">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_EMAIL(<<"vcard-temp">>, IgnoreEls, _el); + {<<"TEL">>, <<"vcard-temp">>, _} -> decode_vcard_TEL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"LABEL">>, <<"vcard-temp">>} -> + {<<"TEL">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_TEL(<<"vcard-temp">>, IgnoreEls, _el); + {<<"LABEL">>, <<"vcard-temp">>, _} -> decode_vcard_LABEL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"ADR">>, <<"vcard-temp">>} -> + {<<"LABEL">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_LABEL(<<"vcard-temp">>, IgnoreEls, _el); + {<<"ADR">>, <<"vcard-temp">>, _} -> decode_vcard_ADR(<<"vcard-temp">>, IgnoreEls, _el); - {<<"N">>, <<"vcard-temp">>} -> + {<<"ADR">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_ADR(<<"vcard-temp">>, IgnoreEls, _el); + {<<"N">>, <<"vcard-temp">>, _} -> decode_vcard_N(<<"vcard-temp">>, IgnoreEls, _el); - {<<"CONFIDENTIAL">>, <<"vcard-temp">>} -> + {<<"N">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_N(<<"vcard-temp">>, IgnoreEls, _el); + {<<"CONFIDENTIAL">>, <<"vcard-temp">>, _} -> decode_vcard_CONFIDENTIAL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PRIVATE">>, <<"vcard-temp">>} -> + {<<"CONFIDENTIAL">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_CONFIDENTIAL(<<"vcard-temp">>, IgnoreEls, + _el); + {<<"PRIVATE">>, <<"vcard-temp">>, _} -> decode_vcard_PRIVATE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PUBLIC">>, <<"vcard-temp">>} -> + {<<"PRIVATE">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_PRIVATE(<<"vcard-temp">>, IgnoreEls, _el); + {<<"PUBLIC">>, <<"vcard-temp">>, _} -> decode_vcard_PUBLIC(<<"vcard-temp">>, IgnoreEls, _el); - {<<"EXTVAL">>, <<"vcard-temp">>} -> + {<<"PUBLIC">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_PUBLIC(<<"vcard-temp">>, IgnoreEls, _el); + {<<"EXTVAL">>, <<"vcard-temp">>, _} -> decode_vcard_EXTVAL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"TYPE">>, <<"vcard-temp">>} -> + {<<"EXTVAL">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_EXTVAL(<<"vcard-temp">>, IgnoreEls, _el); + {<<"TYPE">>, <<"vcard-temp">>, _} -> decode_vcard_TYPE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"DESC">>, <<"vcard-temp">>} -> + {<<"TYPE">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_TYPE(<<"vcard-temp">>, IgnoreEls, _el); + {<<"DESC">>, <<"vcard-temp">>, _} -> decode_vcard_DESC(<<"vcard-temp">>, IgnoreEls, _el); - {<<"URL">>, <<"vcard-temp">>} -> + {<<"DESC">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_DESC(<<"vcard-temp">>, IgnoreEls, _el); + {<<"URL">>, <<"vcard-temp">>, _} -> decode_vcard_URL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"UID">>, <<"vcard-temp">>} -> + {<<"URL">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_URL(<<"vcard-temp">>, IgnoreEls, _el); + {<<"UID">>, <<"vcard-temp">>, _} -> decode_vcard_UID(<<"vcard-temp">>, IgnoreEls, _el); - {<<"SORT-STRING">>, <<"vcard-temp">>} -> + {<<"UID">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_UID(<<"vcard-temp">>, IgnoreEls, _el); + {<<"SORT-STRING">>, <<"vcard-temp">>, _} -> decode_vcard_SORT_STRING(<<"vcard-temp">>, IgnoreEls, _el); - {<<"REV">>, <<"vcard-temp">>} -> + {<<"SORT-STRING">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_SORT_STRING(<<"vcard-temp">>, IgnoreEls, + _el); + {<<"REV">>, <<"vcard-temp">>, _} -> decode_vcard_REV(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PRODID">>, <<"vcard-temp">>} -> + {<<"REV">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_REV(<<"vcard-temp">>, IgnoreEls, _el); + {<<"PRODID">>, <<"vcard-temp">>, _} -> decode_vcard_PRODID(<<"vcard-temp">>, IgnoreEls, _el); - {<<"NOTE">>, <<"vcard-temp">>} -> + {<<"PRODID">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_PRODID(<<"vcard-temp">>, IgnoreEls, _el); + {<<"NOTE">>, <<"vcard-temp">>, _} -> decode_vcard_NOTE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"KEYWORD">>, <<"vcard-temp">>} -> + {<<"NOTE">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_NOTE(<<"vcard-temp">>, IgnoreEls, _el); + {<<"KEYWORD">>, <<"vcard-temp">>, _} -> decode_vcard_KEYWORD(<<"vcard-temp">>, IgnoreEls, _el); - {<<"ROLE">>, <<"vcard-temp">>} -> + {<<"KEYWORD">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_KEYWORD(<<"vcard-temp">>, IgnoreEls, _el); + {<<"ROLE">>, <<"vcard-temp">>, _} -> decode_vcard_ROLE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"TITLE">>, <<"vcard-temp">>} -> + {<<"ROLE">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_ROLE(<<"vcard-temp">>, IgnoreEls, _el); + {<<"TITLE">>, <<"vcard-temp">>, _} -> decode_vcard_TITLE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"TZ">>, <<"vcard-temp">>} -> + {<<"TITLE">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_TITLE(<<"vcard-temp">>, IgnoreEls, _el); + {<<"TZ">>, <<"vcard-temp">>, _} -> decode_vcard_TZ(<<"vcard-temp">>, IgnoreEls, _el); - {<<"MAILER">>, <<"vcard-temp">>} -> + {<<"TZ">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_TZ(<<"vcard-temp">>, IgnoreEls, _el); + {<<"MAILER">>, <<"vcard-temp">>, _} -> decode_vcard_MAILER(<<"vcard-temp">>, IgnoreEls, _el); - {<<"JABBERID">>, <<"vcard-temp">>} -> + {<<"MAILER">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_MAILER(<<"vcard-temp">>, IgnoreEls, _el); + {<<"JABBERID">>, <<"vcard-temp">>, _} -> decode_vcard_JABBERID(<<"vcard-temp">>, IgnoreEls, _el); - {<<"BDAY">>, <<"vcard-temp">>} -> + {<<"JABBERID">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_JABBERID(<<"vcard-temp">>, IgnoreEls, _el); + {<<"BDAY">>, <<"vcard-temp">>, _} -> decode_vcard_BDAY(<<"vcard-temp">>, IgnoreEls, _el); - {<<"NICKNAME">>, <<"vcard-temp">>} -> + {<<"BDAY">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_BDAY(<<"vcard-temp">>, IgnoreEls, _el); + {<<"NICKNAME">>, <<"vcard-temp">>, _} -> decode_vcard_NICKNAME(<<"vcard-temp">>, IgnoreEls, _el); - {<<"FN">>, <<"vcard-temp">>} -> + {<<"NICKNAME">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_NICKNAME(<<"vcard-temp">>, IgnoreEls, _el); + {<<"FN">>, <<"vcard-temp">>, _} -> decode_vcard_FN(<<"vcard-temp">>, IgnoreEls, _el); - {<<"VERSION">>, <<"vcard-temp">>} -> + {<<"FN">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_FN(<<"vcard-temp">>, IgnoreEls, _el); + {<<"VERSION">>, <<"vcard-temp">>, _} -> decode_vcard_VERSION(<<"vcard-temp">>, IgnoreEls, _el); - {<<"CRED">>, <<"vcard-temp">>} -> + {<<"VERSION">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_VERSION(<<"vcard-temp">>, IgnoreEls, _el); + {<<"CRED">>, <<"vcard-temp">>, _} -> decode_vcard_CRED(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PHONETIC">>, <<"vcard-temp">>} -> + {<<"CRED">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_CRED(<<"vcard-temp">>, IgnoreEls, _el); + {<<"PHONETIC">>, <<"vcard-temp">>, _} -> decode_vcard_PHONETIC(<<"vcard-temp">>, IgnoreEls, _el); - {<<"ORGUNIT">>, <<"vcard-temp">>} -> + {<<"PHONETIC">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_PHONETIC(<<"vcard-temp">>, IgnoreEls, _el); + {<<"ORGUNIT">>, <<"vcard-temp">>, _} -> decode_vcard_ORGUNIT(<<"vcard-temp">>, IgnoreEls, _el); - {<<"ORGNAME">>, <<"vcard-temp">>} -> + {<<"ORGUNIT">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_ORGUNIT(<<"vcard-temp">>, IgnoreEls, _el); + {<<"ORGNAME">>, <<"vcard-temp">>, _} -> decode_vcard_ORGNAME(<<"vcard-temp">>, IgnoreEls, _el); - {<<"LON">>, <<"vcard-temp">>} -> + {<<"ORGNAME">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_ORGNAME(<<"vcard-temp">>, IgnoreEls, _el); + {<<"LON">>, <<"vcard-temp">>, _} -> decode_vcard_LON(<<"vcard-temp">>, IgnoreEls, _el); - {<<"LAT">>, <<"vcard-temp">>} -> + {<<"LON">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_LON(<<"vcard-temp">>, IgnoreEls, _el); + {<<"LAT">>, <<"vcard-temp">>, _} -> decode_vcard_LAT(<<"vcard-temp">>, IgnoreEls, _el); - {<<"USERID">>, <<"vcard-temp">>} -> + {<<"LAT">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_LAT(<<"vcard-temp">>, IgnoreEls, _el); + {<<"USERID">>, <<"vcard-temp">>, _} -> decode_vcard_USERID(<<"vcard-temp">>, IgnoreEls, _el); - {<<"NUMBER">>, <<"vcard-temp">>} -> + {<<"USERID">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_USERID(<<"vcard-temp">>, IgnoreEls, _el); + {<<"NUMBER">>, <<"vcard-temp">>, _} -> decode_vcard_NUMBER(<<"vcard-temp">>, IgnoreEls, _el); - {<<"LINE">>, <<"vcard-temp">>} -> + {<<"NUMBER">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_NUMBER(<<"vcard-temp">>, IgnoreEls, _el); + {<<"LINE">>, <<"vcard-temp">>, _} -> decode_vcard_LINE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"CTRY">>, <<"vcard-temp">>} -> + {<<"LINE">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_LINE(<<"vcard-temp">>, IgnoreEls, _el); + {<<"CTRY">>, <<"vcard-temp">>, _} -> decode_vcard_CTRY(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PCODE">>, <<"vcard-temp">>} -> + {<<"CTRY">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_CTRY(<<"vcard-temp">>, IgnoreEls, _el); + {<<"PCODE">>, <<"vcard-temp">>, _} -> decode_vcard_PCODE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"REGION">>, <<"vcard-temp">>} -> + {<<"PCODE">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_PCODE(<<"vcard-temp">>, IgnoreEls, _el); + {<<"REGION">>, <<"vcard-temp">>, _} -> decode_vcard_REGION(<<"vcard-temp">>, IgnoreEls, _el); - {<<"LOCALITY">>, <<"vcard-temp">>} -> + {<<"REGION">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_REGION(<<"vcard-temp">>, IgnoreEls, _el); + {<<"LOCALITY">>, <<"vcard-temp">>, _} -> decode_vcard_LOCALITY(<<"vcard-temp">>, IgnoreEls, _el); - {<<"STREET">>, <<"vcard-temp">>} -> + {<<"LOCALITY">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_LOCALITY(<<"vcard-temp">>, IgnoreEls, _el); + {<<"STREET">>, <<"vcard-temp">>, _} -> decode_vcard_STREET(<<"vcard-temp">>, IgnoreEls, _el); - {<<"EXTADD">>, <<"vcard-temp">>} -> + {<<"STREET">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_STREET(<<"vcard-temp">>, IgnoreEls, _el); + {<<"EXTADD">>, <<"vcard-temp">>, _} -> decode_vcard_EXTADD(<<"vcard-temp">>, IgnoreEls, _el); - {<<"POBOX">>, <<"vcard-temp">>} -> + {<<"EXTADD">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_EXTADD(<<"vcard-temp">>, IgnoreEls, _el); + {<<"POBOX">>, <<"vcard-temp">>, _} -> decode_vcard_POBOX(<<"vcard-temp">>, IgnoreEls, _el); - {<<"SUFFIX">>, <<"vcard-temp">>} -> + {<<"POBOX">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_POBOX(<<"vcard-temp">>, IgnoreEls, _el); + {<<"SUFFIX">>, <<"vcard-temp">>, _} -> decode_vcard_SUFFIX(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PREFIX">>, <<"vcard-temp">>} -> + {<<"SUFFIX">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_SUFFIX(<<"vcard-temp">>, IgnoreEls, _el); + {<<"PREFIX">>, <<"vcard-temp">>, _} -> decode_vcard_PREFIX(<<"vcard-temp">>, IgnoreEls, _el); - {<<"MIDDLE">>, <<"vcard-temp">>} -> + {<<"PREFIX">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_PREFIX(<<"vcard-temp">>, IgnoreEls, _el); + {<<"MIDDLE">>, <<"vcard-temp">>, _} -> decode_vcard_MIDDLE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"GIVEN">>, <<"vcard-temp">>} -> + {<<"MIDDLE">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_MIDDLE(<<"vcard-temp">>, IgnoreEls, _el); + {<<"GIVEN">>, <<"vcard-temp">>, _} -> decode_vcard_GIVEN(<<"vcard-temp">>, IgnoreEls, _el); - {<<"FAMILY">>, <<"vcard-temp">>} -> + {<<"GIVEN">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_GIVEN(<<"vcard-temp">>, IgnoreEls, _el); + {<<"FAMILY">>, <<"vcard-temp">>, _} -> decode_vcard_FAMILY(<<"vcard-temp">>, IgnoreEls, _el); - {<<"X400">>, <<"vcard-temp">>} -> + {<<"FAMILY">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_FAMILY(<<"vcard-temp">>, IgnoreEls, _el); + {<<"X400">>, <<"vcard-temp">>, _} -> decode_vcard_X400(<<"vcard-temp">>, IgnoreEls, _el); - {<<"INTERNET">>, <<"vcard-temp">>} -> + {<<"X400">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_X400(<<"vcard-temp">>, IgnoreEls, _el); + {<<"INTERNET">>, <<"vcard-temp">>, _} -> decode_vcard_INTERNET(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PREF">>, <<"vcard-temp">>} -> + {<<"INTERNET">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_INTERNET(<<"vcard-temp">>, IgnoreEls, _el); + {<<"PREF">>, <<"vcard-temp">>, _} -> decode_vcard_PREF(<<"vcard-temp">>, IgnoreEls, _el); - {<<"INTL">>, <<"vcard-temp">>} -> + {<<"PREF">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_PREF(<<"vcard-temp">>, IgnoreEls, _el); + {<<"INTL">>, <<"vcard-temp">>, _} -> decode_vcard_INTL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"DOM">>, <<"vcard-temp">>} -> + {<<"INTL">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_INTL(<<"vcard-temp">>, IgnoreEls, _el); + {<<"DOM">>, <<"vcard-temp">>, _} -> decode_vcard_DOM(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PARCEL">>, <<"vcard-temp">>} -> + {<<"DOM">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_DOM(<<"vcard-temp">>, IgnoreEls, _el); + {<<"PARCEL">>, <<"vcard-temp">>, _} -> decode_vcard_PARCEL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"POSTAL">>, <<"vcard-temp">>} -> + {<<"PARCEL">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_PARCEL(<<"vcard-temp">>, IgnoreEls, _el); + {<<"POSTAL">>, <<"vcard-temp">>, _} -> decode_vcard_POSTAL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PCS">>, <<"vcard-temp">>} -> + {<<"POSTAL">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_POSTAL(<<"vcard-temp">>, IgnoreEls, _el); + {<<"PCS">>, <<"vcard-temp">>, _} -> decode_vcard_PCS(<<"vcard-temp">>, IgnoreEls, _el); - {<<"ISDN">>, <<"vcard-temp">>} -> + {<<"PCS">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_PCS(<<"vcard-temp">>, IgnoreEls, _el); + {<<"ISDN">>, <<"vcard-temp">>, _} -> decode_vcard_ISDN(<<"vcard-temp">>, IgnoreEls, _el); - {<<"MODEM">>, <<"vcard-temp">>} -> + {<<"ISDN">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_ISDN(<<"vcard-temp">>, IgnoreEls, _el); + {<<"MODEM">>, <<"vcard-temp">>, _} -> decode_vcard_MODEM(<<"vcard-temp">>, IgnoreEls, _el); - {<<"BBS">>, <<"vcard-temp">>} -> + {<<"MODEM">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_MODEM(<<"vcard-temp">>, IgnoreEls, _el); + {<<"BBS">>, <<"vcard-temp">>, _} -> decode_vcard_BBS(<<"vcard-temp">>, IgnoreEls, _el); - {<<"VIDEO">>, <<"vcard-temp">>} -> + {<<"BBS">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_BBS(<<"vcard-temp">>, IgnoreEls, _el); + {<<"VIDEO">>, <<"vcard-temp">>, _} -> decode_vcard_VIDEO(<<"vcard-temp">>, IgnoreEls, _el); - {<<"CELL">>, <<"vcard-temp">>} -> + {<<"VIDEO">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_VIDEO(<<"vcard-temp">>, IgnoreEls, _el); + {<<"CELL">>, <<"vcard-temp">>, _} -> decode_vcard_CELL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"MSG">>, <<"vcard-temp">>} -> + {<<"CELL">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_CELL(<<"vcard-temp">>, IgnoreEls, _el); + {<<"MSG">>, <<"vcard-temp">>, _} -> decode_vcard_MSG(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PAGER">>, <<"vcard-temp">>} -> + {<<"MSG">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_MSG(<<"vcard-temp">>, IgnoreEls, _el); + {<<"PAGER">>, <<"vcard-temp">>, _} -> decode_vcard_PAGER(<<"vcard-temp">>, IgnoreEls, _el); - {<<"FAX">>, <<"vcard-temp">>} -> + {<<"PAGER">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_PAGER(<<"vcard-temp">>, IgnoreEls, _el); + {<<"FAX">>, <<"vcard-temp">>, _} -> decode_vcard_FAX(<<"vcard-temp">>, IgnoreEls, _el); - {<<"VOICE">>, <<"vcard-temp">>} -> + {<<"FAX">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_FAX(<<"vcard-temp">>, IgnoreEls, _el); + {<<"VOICE">>, <<"vcard-temp">>, _} -> decode_vcard_VOICE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"WORK">>, <<"vcard-temp">>} -> + {<<"VOICE">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_VOICE(<<"vcard-temp">>, IgnoreEls, _el); + {<<"WORK">>, <<"vcard-temp">>, _} -> decode_vcard_WORK(<<"vcard-temp">>, IgnoreEls, _el); - {<<"HOME">>, <<"vcard-temp">>} -> + {<<"WORK">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_WORK(<<"vcard-temp">>, IgnoreEls, _el); + {<<"HOME">>, <<"vcard-temp">>, _} -> decode_vcard_HOME(<<"vcard-temp">>, IgnoreEls, _el); - {<<"stream:error">>, - <<"http://etherx.jabber.org/streams">>} -> - decode_stream_error(<<"http://etherx.jabber.org/streams">>, + {<<"HOME">>, <<>>, <<"vcard-temp">>} -> + decode_vcard_HOME(<<"vcard-temp">>, IgnoreEls, _el); + {<<"stream:error">>, <<"jabber:client">>, _} -> + decode_stream_error(<<"jabber:client">>, IgnoreEls, + _el); + {<<"stream:error">>, <<>>, <<"jabber:client">>} -> + decode_stream_error(<<"jabber:client">>, IgnoreEls, + _el); + {<<"stream:error">>, <<"jabber:server">>, _} -> + decode_stream_error(<<"jabber:server">>, IgnoreEls, + _el); + {<<"stream:error">>, <<>>, <<"jabber:server">>} -> + decode_stream_error(<<"jabber:server">>, IgnoreEls, + _el); + {<<"stream:error">>, <<"jabber:component:accept">>, + _} -> + decode_stream_error(<<"jabber:component:accept">>, + IgnoreEls, _el); + {<<"stream:error">>, <<>>, + <<"jabber:component:accept">>} -> + decode_stream_error(<<"jabber:component:accept">>, IgnoreEls, _el); {<<"unsupported-version">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + decode_stream_error_unsupported_version(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"unsupported-version">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_unsupported_version(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); {<<"unsupported-stanza-type">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + decode_stream_error_unsupported_stanza_type(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"unsupported-stanza-type">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_unsupported_stanza_type(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); {<<"unsupported-encoding">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + decode_stream_error_unsupported_encoding(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"unsupported-encoding">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_unsupported_encoding(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); {<<"undefined-condition">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + decode_stream_error_undefined_condition(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"undefined-condition">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_undefined_condition(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); {<<"system-shutdown">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + decode_stream_error_system_shutdown(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"system-shutdown">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_system_shutdown(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); {<<"see-other-host">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + decode_stream_error_see_other_host(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"see-other-host">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_see_other_host(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); {<<"restricted-xml">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + decode_stream_error_restricted_xml(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"restricted-xml">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_restricted_xml(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); {<<"resource-constraint">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + decode_stream_error_resource_constraint(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"resource-constraint">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_resource_constraint(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); - {<<"reset">>, + {<<"reset">>, <<"urn:ietf:params:xml:ns:xmpp-streams">>, + _} -> + decode_stream_error_reset(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"reset">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_reset(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); {<<"remote-connection-failed">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + decode_stream_error_remote_connection_failed(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"remote-connection-failed">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_remote_connection_failed(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); {<<"policy-violation">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + decode_stream_error_policy_violation(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"policy-violation">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_policy_violation(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); {<<"not-well-formed">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + decode_stream_error_not_well_formed(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"not-well-formed">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_not_well_formed(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); {<<"not-authorized">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + decode_stream_error_not_authorized(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"not-authorized">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_not_authorized(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); {<<"invalid-xml">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + decode_stream_error_invalid_xml(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"invalid-xml">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_invalid_xml(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); {<<"invalid-namespace">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + decode_stream_error_invalid_namespace(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"invalid-namespace">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_invalid_namespace(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); {<<"invalid-id">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + decode_stream_error_invalid_id(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"invalid-id">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_invalid_id(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); {<<"invalid-from">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + decode_stream_error_invalid_from(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"invalid-from">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_invalid_from(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); {<<"internal-server-error">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + decode_stream_error_internal_server_error(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"internal-server-error">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_internal_server_error(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); {<<"improper-addressing">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + decode_stream_error_improper_addressing(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"improper-addressing">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_improper_addressing(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); {<<"host-unknown">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + decode_stream_error_host_unknown(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"host-unknown">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_host_unknown(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); {<<"host-gone">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + decode_stream_error_host_gone(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"host-gone">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_host_gone(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); {<<"connection-timeout">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + decode_stream_error_connection_timeout(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"connection-timeout">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_connection_timeout(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); {<<"conflict">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + decode_stream_error_conflict(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"conflict">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_conflict(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); {<<"bad-namespace-prefix">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + decode_stream_error_bad_namespace_prefix(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"bad-namespace-prefix">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_bad_namespace_prefix(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); {<<"bad-format">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + decode_stream_error_bad_format(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"bad-format">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_bad_format(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); - {<<"text">>, + {<<"text">>, <<"urn:ietf:params:xml:ns:xmpp-streams">>, + _} -> + decode_stream_error_text(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + IgnoreEls, _el); + {<<"text">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> decode_stream_error_text(<<"urn:ietf:params:xml:ns:xmpp-streams">>, IgnoreEls, _el); - {<<"time">>, <<"urn:xmpp:time">>} -> + {<<"time">>, <<"urn:xmpp:time">>, _} -> decode_time(<<"urn:xmpp:time">>, IgnoreEls, _el); - {<<"tzo">>, <<"urn:xmpp:time">>} -> + {<<"time">>, <<>>, <<"urn:xmpp:time">>} -> + decode_time(<<"urn:xmpp:time">>, IgnoreEls, _el); + {<<"tzo">>, <<"urn:xmpp:time">>, _} -> decode_time_tzo(<<"urn:xmpp:time">>, IgnoreEls, _el); - {<<"utc">>, <<"urn:xmpp:time">>} -> + {<<"tzo">>, <<>>, <<"urn:xmpp:time">>} -> + decode_time_tzo(<<"urn:xmpp:time">>, IgnoreEls, _el); + {<<"utc">>, <<"urn:xmpp:time">>, _} -> decode_time_utc(<<"urn:xmpp:time">>, IgnoreEls, _el); - {<<"ping">>, <<"urn:xmpp:ping">>} -> + {<<"utc">>, <<>>, <<"urn:xmpp:time">>} -> + decode_time_utc(<<"urn:xmpp:time">>, IgnoreEls, _el); + {<<"ping">>, <<"urn:xmpp:ping">>, _} -> + decode_ping(<<"urn:xmpp:ping">>, IgnoreEls, _el); + {<<"ping">>, <<>>, <<"urn:xmpp:ping">>} -> decode_ping(<<"urn:xmpp:ping">>, IgnoreEls, _el); {<<"session">>, + <<"urn:ietf:params:xml:ns:xmpp-session">>, _} -> + decode_session(<<"urn:ietf:params:xml:ns:xmpp-session">>, + IgnoreEls, _el); + {<<"session">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-session">>} -> decode_session(<<"urn:ietf:params:xml:ns:xmpp-session">>, IgnoreEls, _el); {<<"optional">>, + <<"urn:ietf:params:xml:ns:xmpp-session">>, _} -> + decode_session_optional(<<"urn:ietf:params:xml:ns:xmpp-session">>, + IgnoreEls, _el); + {<<"optional">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-session">>} -> decode_session_optional(<<"urn:ietf:params:xml:ns:xmpp-session">>, IgnoreEls, _el); - {<<"query">>, <<"jabber:iq:register">>} -> + {<<"query">>, <<"jabber:iq:register">>, _} -> decode_register(<<"jabber:iq:register">>, IgnoreEls, _el); - {<<"key">>, <<"jabber:iq:register">>} -> + {<<"query">>, <<>>, <<"jabber:iq:register">>} -> + decode_register(<<"jabber:iq:register">>, IgnoreEls, + _el); + {<<"key">>, <<"jabber:iq:register">>, _} -> decode_register_key(<<"jabber:iq:register">>, IgnoreEls, _el); - {<<"text">>, <<"jabber:iq:register">>} -> + {<<"key">>, <<>>, <<"jabber:iq:register">>} -> + decode_register_key(<<"jabber:iq:register">>, IgnoreEls, + _el); + {<<"text">>, <<"jabber:iq:register">>, _} -> decode_register_text(<<"jabber:iq:register">>, IgnoreEls, _el); - {<<"misc">>, <<"jabber:iq:register">>} -> + {<<"text">>, <<>>, <<"jabber:iq:register">>} -> + decode_register_text(<<"jabber:iq:register">>, + IgnoreEls, _el); + {<<"misc">>, <<"jabber:iq:register">>, _} -> decode_register_misc(<<"jabber:iq:register">>, IgnoreEls, _el); - {<<"date">>, <<"jabber:iq:register">>} -> + {<<"misc">>, <<>>, <<"jabber:iq:register">>} -> + decode_register_misc(<<"jabber:iq:register">>, + IgnoreEls, _el); + {<<"date">>, <<"jabber:iq:register">>, _} -> decode_register_date(<<"jabber:iq:register">>, IgnoreEls, _el); - {<<"url">>, <<"jabber:iq:register">>} -> + {<<"date">>, <<>>, <<"jabber:iq:register">>} -> + decode_register_date(<<"jabber:iq:register">>, + IgnoreEls, _el); + {<<"url">>, <<"jabber:iq:register">>, _} -> decode_register_url(<<"jabber:iq:register">>, IgnoreEls, _el); - {<<"phone">>, <<"jabber:iq:register">>} -> + {<<"url">>, <<>>, <<"jabber:iq:register">>} -> + decode_register_url(<<"jabber:iq:register">>, IgnoreEls, + _el); + {<<"phone">>, <<"jabber:iq:register">>, _} -> decode_register_phone(<<"jabber:iq:register">>, IgnoreEls, _el); - {<<"zip">>, <<"jabber:iq:register">>} -> + {<<"phone">>, <<>>, <<"jabber:iq:register">>} -> + decode_register_phone(<<"jabber:iq:register">>, + IgnoreEls, _el); + {<<"zip">>, <<"jabber:iq:register">>, _} -> decode_register_zip(<<"jabber:iq:register">>, IgnoreEls, _el); - {<<"state">>, <<"jabber:iq:register">>} -> + {<<"zip">>, <<>>, <<"jabber:iq:register">>} -> + decode_register_zip(<<"jabber:iq:register">>, IgnoreEls, + _el); + {<<"state">>, <<"jabber:iq:register">>, _} -> decode_register_state(<<"jabber:iq:register">>, IgnoreEls, _el); - {<<"city">>, <<"jabber:iq:register">>} -> + {<<"state">>, <<>>, <<"jabber:iq:register">>} -> + decode_register_state(<<"jabber:iq:register">>, + IgnoreEls, _el); + {<<"city">>, <<"jabber:iq:register">>, _} -> decode_register_city(<<"jabber:iq:register">>, IgnoreEls, _el); - {<<"address">>, <<"jabber:iq:register">>} -> + {<<"city">>, <<>>, <<"jabber:iq:register">>} -> + decode_register_city(<<"jabber:iq:register">>, + IgnoreEls, _el); + {<<"address">>, <<"jabber:iq:register">>, _} -> decode_register_address(<<"jabber:iq:register">>, IgnoreEls, _el); - {<<"email">>, <<"jabber:iq:register">>} -> + {<<"address">>, <<>>, <<"jabber:iq:register">>} -> + decode_register_address(<<"jabber:iq:register">>, + IgnoreEls, _el); + {<<"email">>, <<"jabber:iq:register">>, _} -> decode_register_email(<<"jabber:iq:register">>, IgnoreEls, _el); - {<<"last">>, <<"jabber:iq:register">>} -> + {<<"email">>, <<>>, <<"jabber:iq:register">>} -> + decode_register_email(<<"jabber:iq:register">>, + IgnoreEls, _el); + {<<"last">>, <<"jabber:iq:register">>, _} -> decode_register_last(<<"jabber:iq:register">>, IgnoreEls, _el); - {<<"first">>, <<"jabber:iq:register">>} -> + {<<"last">>, <<>>, <<"jabber:iq:register">>} -> + decode_register_last(<<"jabber:iq:register">>, + IgnoreEls, _el); + {<<"first">>, <<"jabber:iq:register">>, _} -> decode_register_first(<<"jabber:iq:register">>, IgnoreEls, _el); - {<<"name">>, <<"jabber:iq:register">>} -> + {<<"first">>, <<>>, <<"jabber:iq:register">>} -> + decode_register_first(<<"jabber:iq:register">>, + IgnoreEls, _el); + {<<"name">>, <<"jabber:iq:register">>, _} -> decode_register_name(<<"jabber:iq:register">>, IgnoreEls, _el); - {<<"password">>, <<"jabber:iq:register">>} -> + {<<"name">>, <<>>, <<"jabber:iq:register">>} -> + decode_register_name(<<"jabber:iq:register">>, + IgnoreEls, _el); + {<<"password">>, <<"jabber:iq:register">>, _} -> decode_register_password(<<"jabber:iq:register">>, IgnoreEls, _el); - {<<"nick">>, <<"jabber:iq:register">>} -> + {<<"password">>, <<>>, <<"jabber:iq:register">>} -> + decode_register_password(<<"jabber:iq:register">>, + IgnoreEls, _el); + {<<"nick">>, <<"jabber:iq:register">>, _} -> decode_register_nick(<<"jabber:iq:register">>, IgnoreEls, _el); - {<<"username">>, <<"jabber:iq:register">>} -> + {<<"nick">>, <<>>, <<"jabber:iq:register">>} -> + decode_register_nick(<<"jabber:iq:register">>, + IgnoreEls, _el); + {<<"username">>, <<"jabber:iq:register">>, _} -> decode_register_username(<<"jabber:iq:register">>, IgnoreEls, _el); - {<<"instructions">>, <<"jabber:iq:register">>} -> + {<<"username">>, <<>>, <<"jabber:iq:register">>} -> + decode_register_username(<<"jabber:iq:register">>, + IgnoreEls, _el); + {<<"instructions">>, <<"jabber:iq:register">>, _} -> decode_register_instructions(<<"jabber:iq:register">>, IgnoreEls, _el); - {<<"remove">>, <<"jabber:iq:register">>} -> + {<<"instructions">>, <<>>, <<"jabber:iq:register">>} -> + decode_register_instructions(<<"jabber:iq:register">>, + IgnoreEls, _el); + {<<"remove">>, <<"jabber:iq:register">>, _} -> decode_register_remove(<<"jabber:iq:register">>, IgnoreEls, _el); - {<<"registered">>, <<"jabber:iq:register">>} -> + {<<"remove">>, <<>>, <<"jabber:iq:register">>} -> + decode_register_remove(<<"jabber:iq:register">>, + IgnoreEls, _el); + {<<"registered">>, <<"jabber:iq:register">>, _} -> + decode_register_registered(<<"jabber:iq:register">>, + IgnoreEls, _el); + {<<"registered">>, <<>>, <<"jabber:iq:register">>} -> decode_register_registered(<<"jabber:iq:register">>, IgnoreEls, _el); {<<"register">>, + <<"http://jabber.org/features/iq-register">>, _} -> + decode_feature_register(<<"http://jabber.org/features/iq-register">>, + IgnoreEls, _el); + {<<"register">>, <<>>, <<"http://jabber.org/features/iq-register">>} -> decode_feature_register(<<"http://jabber.org/features/iq-register">>, IgnoreEls, _el); - {<<"c">>, <<"http://jabber.org/protocol/caps">>} -> + {<<"c">>, <<"http://jabber.org/protocol/caps">>, _} -> decode_caps(<<"http://jabber.org/protocol/caps">>, IgnoreEls, _el); - {<<"ack">>, <<"p1:ack">>} -> + {<<"c">>, <<>>, + <<"http://jabber.org/protocol/caps">>} -> + decode_caps(<<"http://jabber.org/protocol/caps">>, + IgnoreEls, _el); + {<<"ack">>, <<"p1:ack">>, _} -> decode_p1_ack(<<"p1:ack">>, IgnoreEls, _el); - {<<"rebind">>, <<"p1:rebind">>} -> + {<<"ack">>, <<>>, <<"p1:ack">>} -> + decode_p1_ack(<<"p1:ack">>, IgnoreEls, _el); + {<<"rebind">>, <<"p1:rebind">>, _} -> decode_p1_rebind(<<"p1:rebind">>, IgnoreEls, _el); - {<<"push">>, <<"p1:push">>} -> + {<<"rebind">>, <<>>, <<"p1:rebind">>} -> + decode_p1_rebind(<<"p1:rebind">>, IgnoreEls, _el); + {<<"push">>, <<"p1:push">>, _} -> decode_p1_push(<<"p1:push">>, IgnoreEls, _el); - {<<"stream:features">>, - <<"http://etherx.jabber.org/streams">>} -> - decode_stream_features(<<"http://etherx.jabber.org/streams">>, - IgnoreEls, _el); + {<<"push">>, <<>>, <<"p1:push">>} -> + decode_p1_push(<<"p1:push">>, IgnoreEls, _el); + {<<"stream:features">>, <<"jabber:client">>, _} -> + decode_stream_features(<<"jabber:client">>, IgnoreEls, + _el); + {<<"stream:features">>, <<>>, <<"jabber:client">>} -> + decode_stream_features(<<"jabber:client">>, IgnoreEls, + _el); + {<<"stream:features">>, <<"jabber:server">>, _} -> + decode_stream_features(<<"jabber:server">>, IgnoreEls, + _el); + {<<"stream:features">>, <<>>, <<"jabber:server">>} -> + decode_stream_features(<<"jabber:server">>, IgnoreEls, + _el); {<<"compression">>, + <<"http://jabber.org/features/compress">>, _} -> + decode_compression(<<"http://jabber.org/features/compress">>, + IgnoreEls, _el); + {<<"compression">>, <<>>, <<"http://jabber.org/features/compress">>} -> decode_compression(<<"http://jabber.org/features/compress">>, IgnoreEls, _el); {<<"method">>, + <<"http://jabber.org/features/compress">>, _} -> + decode_compression_method(<<"http://jabber.org/features/compress">>, + IgnoreEls, _el); + {<<"method">>, <<>>, <<"http://jabber.org/features/compress">>} -> decode_compression_method(<<"http://jabber.org/features/compress">>, IgnoreEls, _el); {<<"compressed">>, + <<"http://jabber.org/protocol/compress">>, _} -> + decode_compressed(<<"http://jabber.org/protocol/compress">>, + IgnoreEls, _el); + {<<"compressed">>, <<>>, <<"http://jabber.org/protocol/compress">>} -> decode_compressed(<<"http://jabber.org/protocol/compress">>, IgnoreEls, _el); {<<"compress">>, + <<"http://jabber.org/protocol/compress">>, _} -> + decode_compress(<<"http://jabber.org/protocol/compress">>, + IgnoreEls, _el); + {<<"compress">>, <<>>, <<"http://jabber.org/protocol/compress">>} -> decode_compress(<<"http://jabber.org/protocol/compress">>, IgnoreEls, _el); {<<"method">>, + <<"http://jabber.org/protocol/compress">>, _} -> + decode_compress_method(<<"http://jabber.org/protocol/compress">>, + IgnoreEls, _el); + {<<"method">>, <<>>, <<"http://jabber.org/protocol/compress">>} -> decode_compress_method(<<"http://jabber.org/protocol/compress">>, IgnoreEls, _el); {<<"failure">>, + <<"http://jabber.org/protocol/compress">>, _} -> + decode_compress_failure(<<"http://jabber.org/protocol/compress">>, + IgnoreEls, _el); + {<<"failure">>, <<>>, <<"http://jabber.org/protocol/compress">>} -> decode_compress_failure(<<"http://jabber.org/protocol/compress">>, IgnoreEls, _el); {<<"unsupported-method">>, + <<"http://jabber.org/protocol/compress">>, _} -> + decode_compress_failure_unsupported_method(<<"http://jabber.org/protocol/compress">>, + IgnoreEls, _el); + {<<"unsupported-method">>, <<>>, <<"http://jabber.org/protocol/compress">>} -> decode_compress_failure_unsupported_method(<<"http://jabber.org/protocol/compress">>, IgnoreEls, _el); {<<"processing-failed">>, + <<"http://jabber.org/protocol/compress">>, _} -> + decode_compress_failure_processing_failed(<<"http://jabber.org/protocol/compress">>, + IgnoreEls, _el); + {<<"processing-failed">>, <<>>, <<"http://jabber.org/protocol/compress">>} -> decode_compress_failure_processing_failed(<<"http://jabber.org/protocol/compress">>, IgnoreEls, _el); {<<"setup-failed">>, + <<"http://jabber.org/protocol/compress">>, _} -> + decode_compress_failure_setup_failed(<<"http://jabber.org/protocol/compress">>, + IgnoreEls, _el); + {<<"setup-failed">>, <<>>, <<"http://jabber.org/protocol/compress">>} -> decode_compress_failure_setup_failed(<<"http://jabber.org/protocol/compress">>, IgnoreEls, _el); - {<<"failure">>, + {<<"failure">>, <<"urn:ietf:params:xml:ns:xmpp-tls">>, + _} -> + decode_starttls_failure(<<"urn:ietf:params:xml:ns:xmpp-tls">>, + IgnoreEls, _el); + {<<"failure">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-tls">>} -> decode_starttls_failure(<<"urn:ietf:params:xml:ns:xmpp-tls">>, IgnoreEls, _el); - {<<"proceed">>, + {<<"proceed">>, <<"urn:ietf:params:xml:ns:xmpp-tls">>, + _} -> + decode_starttls_proceed(<<"urn:ietf:params:xml:ns:xmpp-tls">>, + IgnoreEls, _el); + {<<"proceed">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-tls">>} -> decode_starttls_proceed(<<"urn:ietf:params:xml:ns:xmpp-tls">>, IgnoreEls, _el); - {<<"starttls">>, + {<<"starttls">>, <<"urn:ietf:params:xml:ns:xmpp-tls">>, + _} -> + decode_starttls(<<"urn:ietf:params:xml:ns:xmpp-tls">>, + IgnoreEls, _el); + {<<"starttls">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-tls">>} -> decode_starttls(<<"urn:ietf:params:xml:ns:xmpp-tls">>, IgnoreEls, _el); - {<<"required">>, + {<<"required">>, <<"urn:ietf:params:xml:ns:xmpp-tls">>, + _} -> + decode_starttls_required(<<"urn:ietf:params:xml:ns:xmpp-tls">>, + IgnoreEls, _el); + {<<"required">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-tls">>} -> decode_starttls_required(<<"urn:ietf:params:xml:ns:xmpp-tls">>, IgnoreEls, _el); {<<"mechanisms">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + decode_sasl_mechanisms(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + IgnoreEls, _el); + {<<"mechanisms">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> decode_sasl_mechanisms(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, IgnoreEls, _el); {<<"mechanism">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + decode_sasl_mechanism(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + IgnoreEls, _el); + {<<"mechanism">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> decode_sasl_mechanism(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, IgnoreEls, _el); - {<<"failure">>, + {<<"failure">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, + _} -> + decode_sasl_failure(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + IgnoreEls, _el); + {<<"failure">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> decode_sasl_failure(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, IgnoreEls, _el); {<<"temporary-auth-failure">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + decode_sasl_failure_temporary_auth_failure(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + IgnoreEls, _el); + {<<"temporary-auth-failure">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> decode_sasl_failure_temporary_auth_failure(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, IgnoreEls, _el); {<<"bad-protocol">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + decode_sasl_failure_bad_protocol(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + IgnoreEls, _el); + {<<"bad-protocol">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> decode_sasl_failure_bad_protocol(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, IgnoreEls, _el); {<<"not-authorized">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + decode_sasl_failure_not_authorized(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + IgnoreEls, _el); + {<<"not-authorized">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> decode_sasl_failure_not_authorized(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, IgnoreEls, _el); {<<"mechanism-too-weak">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + decode_sasl_failure_mechanism_too_weak(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + IgnoreEls, _el); + {<<"mechanism-too-weak">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> decode_sasl_failure_mechanism_too_weak(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, IgnoreEls, _el); {<<"malformed-request">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + decode_sasl_failure_malformed_request(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + IgnoreEls, _el); + {<<"malformed-request">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> decode_sasl_failure_malformed_request(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, IgnoreEls, _el); {<<"invalid-mechanism">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + decode_sasl_failure_invalid_mechanism(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + IgnoreEls, _el); + {<<"invalid-mechanism">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> decode_sasl_failure_invalid_mechanism(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, IgnoreEls, _el); {<<"invalid-authzid">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + decode_sasl_failure_invalid_authzid(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + IgnoreEls, _el); + {<<"invalid-authzid">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> decode_sasl_failure_invalid_authzid(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, IgnoreEls, _el); {<<"incorrect-encoding">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + decode_sasl_failure_incorrect_encoding(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + IgnoreEls, _el); + {<<"incorrect-encoding">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> decode_sasl_failure_incorrect_encoding(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, IgnoreEls, _el); {<<"encryption-required">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + decode_sasl_failure_encryption_required(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + IgnoreEls, _el); + {<<"encryption-required">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> decode_sasl_failure_encryption_required(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, IgnoreEls, _el); {<<"credentials-expired">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + decode_sasl_failure_credentials_expired(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + IgnoreEls, _el); + {<<"credentials-expired">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> decode_sasl_failure_credentials_expired(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, IgnoreEls, _el); {<<"account-disabled">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + decode_sasl_failure_account_disabled(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + IgnoreEls, _el); + {<<"account-disabled">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> decode_sasl_failure_account_disabled(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, IgnoreEls, _el); - {<<"aborted">>, + {<<"aborted">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, + _} -> + decode_sasl_failure_aborted(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + IgnoreEls, _el); + {<<"aborted">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> decode_sasl_failure_aborted(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, IgnoreEls, _el); - {<<"text">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> + {<<"text">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, + _} -> decode_sasl_failure_text(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, IgnoreEls, _el); - {<<"success">>, + {<<"text">>, <<>>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> + decode_sasl_failure_text(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + IgnoreEls, _el); + {<<"success">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, + _} -> + decode_sasl_success(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + IgnoreEls, _el); + {<<"success">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> decode_sasl_success(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, IgnoreEls, _el); - {<<"response">>, + {<<"response">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, + _} -> + decode_sasl_response(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + IgnoreEls, _el); + {<<"response">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> decode_sasl_response(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, IgnoreEls, _el); {<<"challenge">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + decode_sasl_challenge(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + IgnoreEls, _el); + {<<"challenge">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> decode_sasl_challenge(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, IgnoreEls, _el); - {<<"abort">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> + {<<"abort">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, + _} -> decode_sasl_abort(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, IgnoreEls, _el); - {<<"auth">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> + {<<"abort">>, <<>>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> + decode_sasl_abort(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + IgnoreEls, _el); + {<<"auth">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, + _} -> decode_sasl_auth(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, IgnoreEls, _el); - {<<"query">>, <<"jabber:iq:auth">>} -> + {<<"auth">>, <<>>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> + decode_sasl_auth(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + IgnoreEls, _el); + {<<"query">>, <<"jabber:iq:auth">>, _} -> decode_legacy_auth(<<"jabber:iq:auth">>, IgnoreEls, _el); - {<<"resource">>, <<"jabber:iq:auth">>} -> + {<<"query">>, <<>>, <<"jabber:iq:auth">>} -> + decode_legacy_auth(<<"jabber:iq:auth">>, IgnoreEls, + _el); + {<<"resource">>, <<"jabber:iq:auth">>, _} -> decode_legacy_auth_resource(<<"jabber:iq:auth">>, IgnoreEls, _el); - {<<"digest">>, <<"jabber:iq:auth">>} -> + {<<"resource">>, <<>>, <<"jabber:iq:auth">>} -> + decode_legacy_auth_resource(<<"jabber:iq:auth">>, + IgnoreEls, _el); + {<<"digest">>, <<"jabber:iq:auth">>, _} -> decode_legacy_auth_digest(<<"jabber:iq:auth">>, IgnoreEls, _el); - {<<"password">>, <<"jabber:iq:auth">>} -> + {<<"digest">>, <<>>, <<"jabber:iq:auth">>} -> + decode_legacy_auth_digest(<<"jabber:iq:auth">>, + IgnoreEls, _el); + {<<"password">>, <<"jabber:iq:auth">>, _} -> decode_legacy_auth_password(<<"jabber:iq:auth">>, IgnoreEls, _el); - {<<"username">>, <<"jabber:iq:auth">>} -> + {<<"password">>, <<>>, <<"jabber:iq:auth">>} -> + decode_legacy_auth_password(<<"jabber:iq:auth">>, + IgnoreEls, _el); + {<<"username">>, <<"jabber:iq:auth">>, _} -> decode_legacy_auth_username(<<"jabber:iq:auth">>, IgnoreEls, _el); - {<<"bind">>, <<"urn:ietf:params:xml:ns:xmpp-bind">>} -> + {<<"username">>, <<>>, <<"jabber:iq:auth">>} -> + decode_legacy_auth_username(<<"jabber:iq:auth">>, + IgnoreEls, _el); + {<<"bind">>, <<"urn:ietf:params:xml:ns:xmpp-bind">>, + _} -> decode_bind(<<"urn:ietf:params:xml:ns:xmpp-bind">>, IgnoreEls, _el); - {<<"resource">>, + {<<"bind">>, <<>>, + <<"urn:ietf:params:xml:ns:xmpp-bind">>} -> + decode_bind(<<"urn:ietf:params:xml:ns:xmpp-bind">>, + IgnoreEls, _el); + {<<"resource">>, <<"urn:ietf:params:xml:ns:xmpp-bind">>, + _} -> + decode_bind_resource(<<"urn:ietf:params:xml:ns:xmpp-bind">>, + IgnoreEls, _el); + {<<"resource">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-bind">>} -> decode_bind_resource(<<"urn:ietf:params:xml:ns:xmpp-bind">>, IgnoreEls, _el); - {<<"jid">>, <<"urn:ietf:params:xml:ns:xmpp-bind">>} -> + {<<"jid">>, <<"urn:ietf:params:xml:ns:xmpp-bind">>, + _} -> decode_bind_jid(<<"urn:ietf:params:xml:ns:xmpp-bind">>, IgnoreEls, _el); - {<<"error">>, <<"jabber:client">>} -> + {<<"jid">>, <<>>, + <<"urn:ietf:params:xml:ns:xmpp-bind">>} -> + decode_bind_jid(<<"urn:ietf:params:xml:ns:xmpp-bind">>, + IgnoreEls, _el); + {<<"error">>, <<"jabber:client">>, _} -> decode_error(<<"jabber:client">>, IgnoreEls, _el); - {<<"text">>, + {<<"error">>, <<>>, <<"jabber:client">>} -> + decode_error(<<"jabber:client">>, IgnoreEls, _el); + {<<"error">>, <<"jabber:server">>, _} -> + decode_error(<<"jabber:server">>, IgnoreEls, _el); + {<<"error">>, <<>>, <<"jabber:server">>} -> + decode_error(<<"jabber:server">>, IgnoreEls, _el); + {<<"error">>, <<"jabber:component:accept">>, _} -> + decode_error(<<"jabber:component:accept">>, IgnoreEls, + _el); + {<<"error">>, <<>>, <<"jabber:component:accept">>} -> + decode_error(<<"jabber:component:accept">>, IgnoreEls, + _el); + {<<"text">>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + _} -> + decode_error_text(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + IgnoreEls, _el); + {<<"text">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_text(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, IgnoreEls, _el); {<<"unexpected-request">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + decode_error_unexpected_request(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + IgnoreEls, _el); + {<<"unexpected-request">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_unexpected_request(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, IgnoreEls, _el); {<<"undefined-condition">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + decode_error_undefined_condition(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + IgnoreEls, _el); + {<<"undefined-condition">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_undefined_condition(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, IgnoreEls, _el); {<<"subscription-required">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + decode_error_subscription_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + IgnoreEls, _el); + {<<"subscription-required">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_subscription_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, IgnoreEls, _el); {<<"service-unavailable">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + decode_error_service_unavailable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + IgnoreEls, _el); + {<<"service-unavailable">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_service_unavailable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, IgnoreEls, _el); {<<"resource-constraint">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + decode_error_resource_constraint(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + IgnoreEls, _el); + {<<"resource-constraint">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_resource_constraint(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, IgnoreEls, _el); {<<"remote-server-timeout">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + decode_error_remote_server_timeout(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + IgnoreEls, _el); + {<<"remote-server-timeout">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_remote_server_timeout(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, IgnoreEls, _el); {<<"remote-server-not-found">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + decode_error_remote_server_not_found(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + IgnoreEls, _el); + {<<"remote-server-not-found">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_remote_server_not_found(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, IgnoreEls, _el); {<<"registration-required">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + decode_error_registration_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + IgnoreEls, _el); + {<<"registration-required">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_registration_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, IgnoreEls, _el); {<<"redirect">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + decode_error_redirect(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + IgnoreEls, _el); + {<<"redirect">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_redirect(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, IgnoreEls, _el); {<<"recipient-unavailable">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + decode_error_recipient_unavailable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + IgnoreEls, _el); + {<<"recipient-unavailable">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_recipient_unavailable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, IgnoreEls, _el); {<<"policy-violation">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + decode_error_policy_violation(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + IgnoreEls, _el); + {<<"policy-violation">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_policy_violation(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, IgnoreEls, _el); {<<"payment-required">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + decode_error_payment_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + IgnoreEls, _el); + {<<"payment-required">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_payment_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, IgnoreEls, _el); {<<"not-authorized">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + decode_error_not_authorized(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + IgnoreEls, _el); + {<<"not-authorized">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_not_authorized(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, IgnoreEls, _el); {<<"not-allowed">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + decode_error_not_allowed(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + IgnoreEls, _el); + {<<"not-allowed">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_not_allowed(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, IgnoreEls, _el); {<<"not-acceptable">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + decode_error_not_acceptable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + IgnoreEls, _el); + {<<"not-acceptable">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_not_acceptable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, IgnoreEls, _el); {<<"jid-malformed">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + decode_error_jid_malformed(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + IgnoreEls, _el); + {<<"jid-malformed">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_jid_malformed(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, IgnoreEls, _el); {<<"item-not-found">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + decode_error_item_not_found(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + IgnoreEls, _el); + {<<"item-not-found">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_item_not_found(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, IgnoreEls, _el); {<<"internal-server-error">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + decode_error_internal_server_error(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + IgnoreEls, _el); + {<<"internal-server-error">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_internal_server_error(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, IgnoreEls, _el); - {<<"gone">>, + {<<"gone">>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + _} -> + decode_error_gone(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + IgnoreEls, _el); + {<<"gone">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_gone(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, IgnoreEls, _el); {<<"forbidden">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + decode_error_forbidden(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + IgnoreEls, _el); + {<<"forbidden">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_forbidden(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, IgnoreEls, _el); {<<"feature-not-implemented">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + decode_error_feature_not_implemented(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + IgnoreEls, _el); + {<<"feature-not-implemented">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_feature_not_implemented(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, IgnoreEls, _el); {<<"conflict">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + decode_error_conflict(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + IgnoreEls, _el); + {<<"conflict">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_conflict(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, IgnoreEls, _el); {<<"bad-request">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + decode_error_bad_request(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + IgnoreEls, _el); + {<<"bad-request">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> decode_error_bad_request(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, IgnoreEls, _el); - {<<"presence">>, <<"jabber:client">>} -> + {<<"presence">>, <<"jabber:client">>, _} -> decode_presence(<<"jabber:client">>, IgnoreEls, _el); - {<<"priority">>, <<"jabber:client">>} -> + {<<"presence">>, <<>>, <<"jabber:client">>} -> + decode_presence(<<"jabber:client">>, IgnoreEls, _el); + {<<"presence">>, <<"jabber:server">>, _} -> + decode_presence(<<"jabber:server">>, IgnoreEls, _el); + {<<"presence">>, <<>>, <<"jabber:server">>} -> + decode_presence(<<"jabber:server">>, IgnoreEls, _el); + {<<"presence">>, <<"jabber:component:accept">>, _} -> + decode_presence(<<"jabber:component:accept">>, + IgnoreEls, _el); + {<<"presence">>, <<>>, <<"jabber:component:accept">>} -> + decode_presence(<<"jabber:component:accept">>, + IgnoreEls, _el); + {<<"priority">>, <<"jabber:client">>, _} -> decode_presence_priority(<<"jabber:client">>, IgnoreEls, _el); - {<<"status">>, <<"jabber:client">>} -> + {<<"priority">>, <<>>, <<"jabber:client">>} -> + decode_presence_priority(<<"jabber:client">>, IgnoreEls, + _el); + {<<"priority">>, <<"jabber:server">>, _} -> + decode_presence_priority(<<"jabber:server">>, IgnoreEls, + _el); + {<<"priority">>, <<>>, <<"jabber:server">>} -> + decode_presence_priority(<<"jabber:server">>, IgnoreEls, + _el); + {<<"priority">>, <<"jabber:component:accept">>, _} -> + decode_presence_priority(<<"jabber:component:accept">>, + IgnoreEls, _el); + {<<"priority">>, <<>>, <<"jabber:component:accept">>} -> + decode_presence_priority(<<"jabber:component:accept">>, + IgnoreEls, _el); + {<<"status">>, <<"jabber:client">>, _} -> decode_presence_status(<<"jabber:client">>, IgnoreEls, _el); - {<<"show">>, <<"jabber:client">>} -> + {<<"status">>, <<>>, <<"jabber:client">>} -> + decode_presence_status(<<"jabber:client">>, IgnoreEls, + _el); + {<<"status">>, <<"jabber:server">>, _} -> + decode_presence_status(<<"jabber:server">>, IgnoreEls, + _el); + {<<"status">>, <<>>, <<"jabber:server">>} -> + decode_presence_status(<<"jabber:server">>, IgnoreEls, + _el); + {<<"status">>, <<"jabber:component:accept">>, _} -> + decode_presence_status(<<"jabber:component:accept">>, + IgnoreEls, _el); + {<<"status">>, <<>>, <<"jabber:component:accept">>} -> + decode_presence_status(<<"jabber:component:accept">>, + IgnoreEls, _el); + {<<"show">>, <<"jabber:client">>, _} -> decode_presence_show(<<"jabber:client">>, IgnoreEls, _el); - {<<"message">>, <<"jabber:client">>} -> + {<<"show">>, <<>>, <<"jabber:client">>} -> + decode_presence_show(<<"jabber:client">>, IgnoreEls, + _el); + {<<"show">>, <<"jabber:server">>, _} -> + decode_presence_show(<<"jabber:server">>, IgnoreEls, + _el); + {<<"show">>, <<>>, <<"jabber:server">>} -> + decode_presence_show(<<"jabber:server">>, IgnoreEls, + _el); + {<<"show">>, <<"jabber:component:accept">>, _} -> + decode_presence_show(<<"jabber:component:accept">>, + IgnoreEls, _el); + {<<"show">>, <<>>, <<"jabber:component:accept">>} -> + decode_presence_show(<<"jabber:component:accept">>, + IgnoreEls, _el); + {<<"message">>, <<"jabber:client">>, _} -> decode_message(<<"jabber:client">>, IgnoreEls, _el); - {<<"thread">>, <<"jabber:client">>} -> + {<<"message">>, <<>>, <<"jabber:client">>} -> + decode_message(<<"jabber:client">>, IgnoreEls, _el); + {<<"message">>, <<"jabber:server">>, _} -> + decode_message(<<"jabber:server">>, IgnoreEls, _el); + {<<"message">>, <<>>, <<"jabber:server">>} -> + decode_message(<<"jabber:server">>, IgnoreEls, _el); + {<<"message">>, <<"jabber:component:accept">>, _} -> + decode_message(<<"jabber:component:accept">>, IgnoreEls, + _el); + {<<"message">>, <<>>, <<"jabber:component:accept">>} -> + decode_message(<<"jabber:component:accept">>, IgnoreEls, + _el); + {<<"thread">>, <<"jabber:client">>, _} -> decode_message_thread(<<"jabber:client">>, IgnoreEls, _el); - {<<"body">>, <<"jabber:client">>} -> + {<<"thread">>, <<>>, <<"jabber:client">>} -> + decode_message_thread(<<"jabber:client">>, IgnoreEls, + _el); + {<<"thread">>, <<"jabber:server">>, _} -> + decode_message_thread(<<"jabber:server">>, IgnoreEls, + _el); + {<<"thread">>, <<>>, <<"jabber:server">>} -> + decode_message_thread(<<"jabber:server">>, IgnoreEls, + _el); + {<<"thread">>, <<"jabber:component:accept">>, _} -> + decode_message_thread(<<"jabber:component:accept">>, + IgnoreEls, _el); + {<<"thread">>, <<>>, <<"jabber:component:accept">>} -> + decode_message_thread(<<"jabber:component:accept">>, + IgnoreEls, _el); + {<<"body">>, <<"jabber:client">>, _} -> decode_message_body(<<"jabber:client">>, IgnoreEls, _el); - {<<"subject">>, <<"jabber:client">>} -> + {<<"body">>, <<>>, <<"jabber:client">>} -> + decode_message_body(<<"jabber:client">>, IgnoreEls, + _el); + {<<"body">>, <<"jabber:server">>, _} -> + decode_message_body(<<"jabber:server">>, IgnoreEls, + _el); + {<<"body">>, <<>>, <<"jabber:server">>} -> + decode_message_body(<<"jabber:server">>, IgnoreEls, + _el); + {<<"body">>, <<"jabber:component:accept">>, _} -> + decode_message_body(<<"jabber:component:accept">>, + IgnoreEls, _el); + {<<"body">>, <<>>, <<"jabber:component:accept">>} -> + decode_message_body(<<"jabber:component:accept">>, + IgnoreEls, _el); + {<<"subject">>, <<"jabber:client">>, _} -> decode_message_subject(<<"jabber:client">>, IgnoreEls, _el); - {<<"iq">>, <<"jabber:client">>} -> + {<<"subject">>, <<>>, <<"jabber:client">>} -> + decode_message_subject(<<"jabber:client">>, IgnoreEls, + _el); + {<<"subject">>, <<"jabber:server">>, _} -> + decode_message_subject(<<"jabber:server">>, IgnoreEls, + _el); + {<<"subject">>, <<>>, <<"jabber:server">>} -> + decode_message_subject(<<"jabber:server">>, IgnoreEls, + _el); + {<<"subject">>, <<"jabber:component:accept">>, _} -> + decode_message_subject(<<"jabber:component:accept">>, + IgnoreEls, _el); + {<<"subject">>, <<>>, <<"jabber:component:accept">>} -> + decode_message_subject(<<"jabber:component:accept">>, + IgnoreEls, _el); + {<<"iq">>, <<"jabber:client">>, _} -> decode_iq(<<"jabber:client">>, IgnoreEls, _el); - {<<"query">>, <<"http://jabber.org/protocol/stats">>} -> + {<<"iq">>, <<>>, <<"jabber:client">>} -> + decode_iq(<<"jabber:client">>, IgnoreEls, _el); + {<<"iq">>, <<"jabber:server">>, _} -> + decode_iq(<<"jabber:server">>, IgnoreEls, _el); + {<<"iq">>, <<>>, <<"jabber:server">>} -> + decode_iq(<<"jabber:server">>, IgnoreEls, _el); + {<<"iq">>, <<"jabber:component:accept">>, _} -> + decode_iq(<<"jabber:component:accept">>, IgnoreEls, + _el); + {<<"iq">>, <<>>, <<"jabber:component:accept">>} -> + decode_iq(<<"jabber:component:accept">>, IgnoreEls, + _el); + {<<"query">>, <<"http://jabber.org/protocol/stats">>, + _} -> decode_stats(<<"http://jabber.org/protocol/stats">>, IgnoreEls, _el); - {<<"stat">>, <<"http://jabber.org/protocol/stats">>} -> + {<<"query">>, <<>>, + <<"http://jabber.org/protocol/stats">>} -> + decode_stats(<<"http://jabber.org/protocol/stats">>, + IgnoreEls, _el); + {<<"stat">>, <<"http://jabber.org/protocol/stats">>, + _} -> decode_stat(<<"http://jabber.org/protocol/stats">>, IgnoreEls, _el); - {<<"error">>, <<"http://jabber.org/protocol/stats">>} -> + {<<"stat">>, <<>>, + <<"http://jabber.org/protocol/stats">>} -> + decode_stat(<<"http://jabber.org/protocol/stats">>, + IgnoreEls, _el); + {<<"error">>, <<"http://jabber.org/protocol/stats">>, + _} -> decode_stat_error(<<"http://jabber.org/protocol/stats">>, IgnoreEls, _el); - {<<"storage">>, <<"storage:bookmarks">>} -> + {<<"error">>, <<>>, + <<"http://jabber.org/protocol/stats">>} -> + decode_stat_error(<<"http://jabber.org/protocol/stats">>, + IgnoreEls, _el); + {<<"storage">>, <<"storage:bookmarks">>, _} -> decode_bookmarks_storage(<<"storage:bookmarks">>, IgnoreEls, _el); - {<<"url">>, <<"storage:bookmarks">>} -> + {<<"storage">>, <<>>, <<"storage:bookmarks">>} -> + decode_bookmarks_storage(<<"storage:bookmarks">>, + IgnoreEls, _el); + {<<"url">>, <<"storage:bookmarks">>, _} -> decode_bookmark_url(<<"storage:bookmarks">>, IgnoreEls, _el); - {<<"conference">>, <<"storage:bookmarks">>} -> + {<<"url">>, <<>>, <<"storage:bookmarks">>} -> + decode_bookmark_url(<<"storage:bookmarks">>, IgnoreEls, + _el); + {<<"conference">>, <<"storage:bookmarks">>, _} -> decode_bookmark_conference(<<"storage:bookmarks">>, IgnoreEls, _el); - {<<"password">>, <<"storage:bookmarks">>} -> + {<<"conference">>, <<>>, <<"storage:bookmarks">>} -> + decode_bookmark_conference(<<"storage:bookmarks">>, + IgnoreEls, _el); + {<<"password">>, <<"storage:bookmarks">>, _} -> decode_conference_password(<<"storage:bookmarks">>, IgnoreEls, _el); - {<<"nick">>, <<"storage:bookmarks">>} -> + {<<"password">>, <<>>, <<"storage:bookmarks">>} -> + decode_conference_password(<<"storage:bookmarks">>, + IgnoreEls, _el); + {<<"nick">>, <<"storage:bookmarks">>, _} -> decode_conference_nick(<<"storage:bookmarks">>, IgnoreEls, _el); - {<<"query">>, <<"jabber:iq:private">>} -> + {<<"nick">>, <<>>, <<"storage:bookmarks">>} -> + decode_conference_nick(<<"storage:bookmarks">>, + IgnoreEls, _el); + {<<"query">>, <<"jabber:iq:private">>, _} -> + decode_private(<<"jabber:iq:private">>, IgnoreEls, _el); + {<<"query">>, <<>>, <<"jabber:iq:private">>} -> decode_private(<<"jabber:iq:private">>, IgnoreEls, _el); {<<"query">>, + <<"http://jabber.org/protocol/disco#items">>, _} -> + decode_disco_items(<<"http://jabber.org/protocol/disco#items">>, + IgnoreEls, _el); + {<<"query">>, <<>>, <<"http://jabber.org/protocol/disco#items">>} -> decode_disco_items(<<"http://jabber.org/protocol/disco#items">>, IgnoreEls, _el); {<<"item">>, + <<"http://jabber.org/protocol/disco#items">>, _} -> + decode_disco_item(<<"http://jabber.org/protocol/disco#items">>, + IgnoreEls, _el); + {<<"item">>, <<>>, <<"http://jabber.org/protocol/disco#items">>} -> decode_disco_item(<<"http://jabber.org/protocol/disco#items">>, IgnoreEls, _el); {<<"query">>, + <<"http://jabber.org/protocol/disco#info">>, _} -> + decode_disco_info(<<"http://jabber.org/protocol/disco#info">>, + IgnoreEls, _el); + {<<"query">>, <<>>, <<"http://jabber.org/protocol/disco#info">>} -> decode_disco_info(<<"http://jabber.org/protocol/disco#info">>, IgnoreEls, _el); {<<"feature">>, + <<"http://jabber.org/protocol/disco#info">>, _} -> + decode_disco_feature(<<"http://jabber.org/protocol/disco#info">>, + IgnoreEls, _el); + {<<"feature">>, <<>>, <<"http://jabber.org/protocol/disco#info">>} -> decode_disco_feature(<<"http://jabber.org/protocol/disco#info">>, IgnoreEls, _el); {<<"identity">>, + <<"http://jabber.org/protocol/disco#info">>, _} -> + decode_disco_identity(<<"http://jabber.org/protocol/disco#info">>, + IgnoreEls, _el); + {<<"identity">>, <<>>, <<"http://jabber.org/protocol/disco#info">>} -> decode_disco_identity(<<"http://jabber.org/protocol/disco#info">>, IgnoreEls, _el); - {<<"blocklist">>, <<"urn:xmpp:blocking">>} -> + {<<"blocklist">>, <<"urn:xmpp:blocking">>, _} -> decode_block_list(<<"urn:xmpp:blocking">>, IgnoreEls, _el); - {<<"unblock">>, <<"urn:xmpp:blocking">>} -> + {<<"blocklist">>, <<>>, <<"urn:xmpp:blocking">>} -> + decode_block_list(<<"urn:xmpp:blocking">>, IgnoreEls, + _el); + {<<"unblock">>, <<"urn:xmpp:blocking">>, _} -> decode_unblock(<<"urn:xmpp:blocking">>, IgnoreEls, _el); - {<<"block">>, <<"urn:xmpp:blocking">>} -> + {<<"unblock">>, <<>>, <<"urn:xmpp:blocking">>} -> + decode_unblock(<<"urn:xmpp:blocking">>, IgnoreEls, _el); + {<<"block">>, <<"urn:xmpp:blocking">>, _} -> decode_block(<<"urn:xmpp:blocking">>, IgnoreEls, _el); - {<<"item">>, <<"urn:xmpp:blocking">>} -> + {<<"block">>, <<>>, <<"urn:xmpp:blocking">>} -> + decode_block(<<"urn:xmpp:blocking">>, IgnoreEls, _el); + {<<"item">>, <<"urn:xmpp:blocking">>, _} -> decode_block_item(<<"urn:xmpp:blocking">>, IgnoreEls, _el); - {<<"query">>, <<"jabber:iq:privacy">>} -> + {<<"item">>, <<>>, <<"urn:xmpp:blocking">>} -> + decode_block_item(<<"urn:xmpp:blocking">>, IgnoreEls, + _el); + {<<"query">>, <<"jabber:iq:privacy">>, _} -> decode_privacy(<<"jabber:iq:privacy">>, IgnoreEls, _el); - {<<"active">>, <<"jabber:iq:privacy">>} -> + {<<"query">>, <<>>, <<"jabber:iq:privacy">>} -> + decode_privacy(<<"jabber:iq:privacy">>, IgnoreEls, _el); + {<<"active">>, <<"jabber:iq:privacy">>, _} -> decode_privacy_active_list(<<"jabber:iq:privacy">>, IgnoreEls, _el); - {<<"default">>, <<"jabber:iq:privacy">>} -> + {<<"active">>, <<>>, <<"jabber:iq:privacy">>} -> + decode_privacy_active_list(<<"jabber:iq:privacy">>, + IgnoreEls, _el); + {<<"default">>, <<"jabber:iq:privacy">>, _} -> decode_privacy_default_list(<<"jabber:iq:privacy">>, IgnoreEls, _el); - {<<"list">>, <<"jabber:iq:privacy">>} -> + {<<"default">>, <<>>, <<"jabber:iq:privacy">>} -> + decode_privacy_default_list(<<"jabber:iq:privacy">>, + IgnoreEls, _el); + {<<"list">>, <<"jabber:iq:privacy">>, _} -> decode_privacy_list(<<"jabber:iq:privacy">>, IgnoreEls, _el); - {<<"item">>, <<"jabber:iq:privacy">>} -> + {<<"list">>, <<>>, <<"jabber:iq:privacy">>} -> + decode_privacy_list(<<"jabber:iq:privacy">>, IgnoreEls, + _el); + {<<"item">>, <<"jabber:iq:privacy">>, _} -> decode_privacy_item(<<"jabber:iq:privacy">>, IgnoreEls, _el); - {<<"presence-out">>, <<"jabber:iq:privacy">>} -> + {<<"item">>, <<>>, <<"jabber:iq:privacy">>} -> + decode_privacy_item(<<"jabber:iq:privacy">>, IgnoreEls, + _el); + {<<"presence-out">>, <<"jabber:iq:privacy">>, _} -> decode_privacy_presence_out(<<"jabber:iq:privacy">>, IgnoreEls, _el); - {<<"presence-in">>, <<"jabber:iq:privacy">>} -> + {<<"presence-out">>, <<>>, <<"jabber:iq:privacy">>} -> + decode_privacy_presence_out(<<"jabber:iq:privacy">>, + IgnoreEls, _el); + {<<"presence-in">>, <<"jabber:iq:privacy">>, _} -> decode_privacy_presence_in(<<"jabber:iq:privacy">>, IgnoreEls, _el); - {<<"iq">>, <<"jabber:iq:privacy">>} -> + {<<"presence-in">>, <<>>, <<"jabber:iq:privacy">>} -> + decode_privacy_presence_in(<<"jabber:iq:privacy">>, + IgnoreEls, _el); + {<<"iq">>, <<"jabber:iq:privacy">>, _} -> decode_privacy_iq(<<"jabber:iq:privacy">>, IgnoreEls, _el); - {<<"message">>, <<"jabber:iq:privacy">>} -> + {<<"iq">>, <<>>, <<"jabber:iq:privacy">>} -> + decode_privacy_iq(<<"jabber:iq:privacy">>, IgnoreEls, + _el); + {<<"message">>, <<"jabber:iq:privacy">>, _} -> decode_privacy_message(<<"jabber:iq:privacy">>, IgnoreEls, _el); - {<<"ver">>, <<"urn:xmpp:features:rosterver">>} -> + {<<"message">>, <<>>, <<"jabber:iq:privacy">>} -> + decode_privacy_message(<<"jabber:iq:privacy">>, + IgnoreEls, _el); + {<<"ver">>, <<"urn:xmpp:features:rosterver">>, _} -> decode_rosterver_feature(<<"urn:xmpp:features:rosterver">>, IgnoreEls, _el); - {<<"query">>, <<"jabber:iq:roster">>} -> + {<<"ver">>, <<>>, <<"urn:xmpp:features:rosterver">>} -> + decode_rosterver_feature(<<"urn:xmpp:features:rosterver">>, + IgnoreEls, _el); + {<<"query">>, <<"jabber:iq:roster">>, _} -> decode_roster_query(<<"jabber:iq:roster">>, IgnoreEls, _el); - {<<"item">>, <<"jabber:iq:roster">>} -> + {<<"query">>, <<>>, <<"jabber:iq:roster">>} -> + decode_roster_query(<<"jabber:iq:roster">>, IgnoreEls, + _el); + {<<"item">>, <<"jabber:iq:roster">>, _} -> decode_roster_item(<<"jabber:iq:roster">>, IgnoreEls, _el); - {<<"group">>, <<"jabber:iq:roster">>} -> + {<<"item">>, <<>>, <<"jabber:iq:roster">>} -> + decode_roster_item(<<"jabber:iq:roster">>, IgnoreEls, + _el); + {<<"group">>, <<"jabber:iq:roster">>, _} -> decode_roster_group(<<"jabber:iq:roster">>, IgnoreEls, _el); - {<<"query">>, <<"jabber:iq:version">>} -> + {<<"group">>, <<>>, <<"jabber:iq:roster">>} -> + decode_roster_group(<<"jabber:iq:roster">>, IgnoreEls, + _el); + {<<"query">>, <<"jabber:iq:version">>, _} -> decode_version(<<"jabber:iq:version">>, IgnoreEls, _el); - {<<"os">>, <<"jabber:iq:version">>} -> + {<<"query">>, <<>>, <<"jabber:iq:version">>} -> + decode_version(<<"jabber:iq:version">>, IgnoreEls, _el); + {<<"os">>, <<"jabber:iq:version">>, _} -> decode_version_os(<<"jabber:iq:version">>, IgnoreEls, _el); - {<<"version">>, <<"jabber:iq:version">>} -> + {<<"os">>, <<>>, <<"jabber:iq:version">>} -> + decode_version_os(<<"jabber:iq:version">>, IgnoreEls, + _el); + {<<"version">>, <<"jabber:iq:version">>, _} -> decode_version_ver(<<"jabber:iq:version">>, IgnoreEls, _el); - {<<"name">>, <<"jabber:iq:version">>} -> + {<<"version">>, <<>>, <<"jabber:iq:version">>} -> + decode_version_ver(<<"jabber:iq:version">>, IgnoreEls, + _el); + {<<"name">>, <<"jabber:iq:version">>, _} -> decode_version_name(<<"jabber:iq:version">>, IgnoreEls, _el); - {<<"query">>, <<"jabber:iq:last">>} -> + {<<"name">>, <<>>, <<"jabber:iq:version">>} -> + decode_version_name(<<"jabber:iq:version">>, IgnoreEls, + _el); + {<<"query">>, <<"jabber:iq:last">>, _} -> decode_last(<<"jabber:iq:last">>, IgnoreEls, _el); - {_name, _xmlns} -> + {<<"query">>, <<>>, <<"jabber:iq:last">>} -> + decode_last(<<"jabber:iq:last">>, IgnoreEls, _el); + {_name, <<>>, <<>>} -> + erlang:error({xmpp_codec, {missing_tag_xmlns, _name}}); + {_name, <<>>, _} -> + erlang:error({xmpp_codec, + {unknown_tag, _name, TopXMLNS}}); + {_name, _xmlns, _} -> erlang:error({xmpp_codec, {unknown_tag, _name, _xmlns}}) end. -is_known_tag({xmlel, _name, _attrs, _} = _el) -> - case {_name, get_attr(<<"xmlns">>, _attrs)} of - {<<"thumbnail">>, <<"urn:xmpp:thumbs:1">>} -> true; - {<<"slot">>, <<"urn:xmpp:http:upload">>} -> true; - {<<"slot">>, +is_known_tag({xmlel, _name, _attrs, _} = _el, + TopXMLNS) -> + case {_name, get_attr(<<"xmlns">>, _attrs), TopXMLNS} of + {<<"thumbnail">>, <<"urn:xmpp:thumbs:1">>, _} -> true; + {<<"thumbnail">>, <<>>, <<"urn:xmpp:thumbs:1">>} -> + true; + {<<"slot">>, <<"urn:xmpp:http:upload">>, _} -> true; + {<<"slot">>, <<>>, <<"urn:xmpp:http:upload">>} -> true; + {<<"slot">>, <<"eu:siacs:conversations:http:upload">>, + _} -> + true; + {<<"slot">>, <<>>, <<"eu:siacs:conversations:http:upload">>} -> true; - {<<"put">>, <<"urn:xmpp:http:upload">>} -> true; - {<<"put">>, <<"eu:siacs:conversations:http:upload">>} -> + {<<"put">>, <<"urn:xmpp:http:upload">>, _} -> true; + {<<"put">>, <<>>, <<"urn:xmpp:http:upload">>} -> true; + {<<"put">>, <<"eu:siacs:conversations:http:upload">>, + _} -> true; - {<<"get">>, <<"urn:xmpp:http:upload">>} -> true; - {<<"get">>, <<"eu:siacs:conversations:http:upload">>} -> + {<<"put">>, <<>>, + <<"eu:siacs:conversations:http:upload">>} -> + true; + {<<"get">>, <<"urn:xmpp:http:upload">>, _} -> true; + {<<"get">>, <<>>, <<"urn:xmpp:http:upload">>} -> true; + {<<"get">>, <<"eu:siacs:conversations:http:upload">>, + _} -> + true; + {<<"get">>, <<>>, + <<"eu:siacs:conversations:http:upload">>} -> + true; + {<<"request">>, <<"urn:xmpp:http:upload">>, _} -> true; + {<<"request">>, <<>>, <<"urn:xmpp:http:upload">>} -> true; - {<<"request">>, <<"urn:xmpp:http:upload">>} -> true; {<<"request">>, + <<"eu:siacs:conversations:http:upload">>, _} -> + true; + {<<"request">>, <<>>, <<"eu:siacs:conversations:http:upload">>} -> true; - {<<"content-type">>, <<"urn:xmpp:http:upload">>} -> + {<<"content-type">>, <<"urn:xmpp:http:upload">>, _} -> + true; + {<<"content-type">>, <<>>, + <<"urn:xmpp:http:upload">>} -> true; {<<"content-type">>, + <<"eu:siacs:conversations:http:upload">>, _} -> + true; + {<<"content-type">>, <<>>, <<"eu:siacs:conversations:http:upload">>} -> true; - {<<"size">>, <<"urn:xmpp:http:upload">>} -> true; - {<<"size">>, + {<<"size">>, <<"urn:xmpp:http:upload">>, _} -> true; + {<<"size">>, <<>>, <<"urn:xmpp:http:upload">>} -> true; + {<<"size">>, <<"eu:siacs:conversations:http:upload">>, + _} -> + true; + {<<"size">>, <<>>, <<"eu:siacs:conversations:http:upload">>} -> true; - {<<"filename">>, <<"urn:xmpp:http:upload">>} -> true; + {<<"filename">>, <<"urn:xmpp:http:upload">>, _} -> true; + {<<"filename">>, <<>>, <<"urn:xmpp:http:upload">>} -> + true; {<<"filename">>, + <<"eu:siacs:conversations:http:upload">>, _} -> + true; + {<<"filename">>, <<>>, <<"eu:siacs:conversations:http:upload">>} -> true; - {<<"address">>, <<"urn:xmpp:sic:0">>} -> true; - {<<"address">>, <<"urn:xmpp:sic:1">>} -> true; - {<<"port">>, <<"urn:xmpp:sic:1">>} -> true; - {<<"ip">>, <<"urn:xmpp:sic:0">>} -> true; - {<<"ip">>, <<"urn:xmpp:sic:1">>} -> true; - {<<"x">>, <<"jabber:x:oob">>} -> true; - {<<"desc">>, <<"jabber:x:oob">>} -> true; - {<<"url">>, <<"jabber:x:oob">>} -> true; - {<<"media">>, <<"urn:xmpp:media-element">>} -> true; - {<<"uri">>, <<"urn:xmpp:media-element">>} -> true; - {<<"captcha">>, <<"urn:xmpp:captcha">>} -> true; - {<<"data">>, <<"urn:xmpp:bob">>} -> true; - {<<"stream:stream">>, <<"jabber:client">>} -> true; - {<<"stream:stream">>, <<"jabber:server">>} -> true; - {<<"stream:stream">>, <<"jabber:component:accept">>} -> + {<<"address">>, <<"urn:xmpp:sic:0">>, _} -> true; + {<<"address">>, <<>>, <<"urn:xmpp:sic:0">>} -> true; + {<<"address">>, <<"urn:xmpp:sic:1">>, _} -> true; + {<<"address">>, <<>>, <<"urn:xmpp:sic:1">>} -> true; + {<<"port">>, <<"urn:xmpp:sic:1">>, _} -> true; + {<<"port">>, <<>>, <<"urn:xmpp:sic:1">>} -> true; + {<<"ip">>, <<"urn:xmpp:sic:0">>, _} -> true; + {<<"ip">>, <<>>, <<"urn:xmpp:sic:0">>} -> true; + {<<"ip">>, <<"urn:xmpp:sic:1">>, _} -> true; + {<<"ip">>, <<>>, <<"urn:xmpp:sic:1">>} -> true; + {<<"x">>, <<"jabber:x:oob">>, _} -> true; + {<<"x">>, <<>>, <<"jabber:x:oob">>} -> true; + {<<"desc">>, <<"jabber:x:oob">>, _} -> true; + {<<"desc">>, <<>>, <<"jabber:x:oob">>} -> true; + {<<"url">>, <<"jabber:x:oob">>, _} -> true; + {<<"url">>, <<>>, <<"jabber:x:oob">>} -> true; + {<<"media">>, <<"urn:xmpp:media-element">>, _} -> true; + {<<"media">>, <<>>, <<"urn:xmpp:media-element">>} -> true; - {<<"handshake">>, <<"jabber:client">>} -> true; - {<<"db:verify">>, <<"jabber:client">>} -> true; - {<<"db:result">>, <<"jabber:client">>} -> true; + {<<"uri">>, <<"urn:xmpp:media-element">>, _} -> true; + {<<"uri">>, <<>>, <<"urn:xmpp:media-element">>} -> true; + {<<"captcha">>, <<"urn:xmpp:captcha">>, _} -> true; + {<<"captcha">>, <<>>, <<"urn:xmpp:captcha">>} -> true; + {<<"data">>, <<"urn:xmpp:bob">>, _} -> true; + {<<"data">>, <<>>, <<"urn:xmpp:bob">>} -> true; + {<<"stream:stream">>, <<"jabber:client">>, _} -> true; + {<<"stream:stream">>, <<>>, <<"jabber:client">>} -> + true; + {<<"stream:stream">>, <<"jabber:server">>, _} -> true; + {<<"stream:stream">>, <<>>, <<"jabber:server">>} -> + true; + {<<"stream:stream">>, <<"jabber:component:accept">>, + _} -> + true; + {<<"stream:stream">>, <<>>, + <<"jabber:component:accept">>} -> + true; + {<<"handshake">>, <<"jabber:component:accept">>, _} -> + true; + {<<"handshake">>, <<>>, + <<"jabber:component:accept">>} -> + true; + {<<"db:verify">>, <<"jabber:server">>, _} -> true; + {<<"db:verify">>, <<>>, <<"jabber:server">>} -> true; + {<<"db:result">>, <<"jabber:server">>, _} -> true; + {<<"db:result">>, <<>>, <<"jabber:server">>} -> true; {<<"command">>, + <<"http://jabber.org/protocol/commands">>, _} -> + true; + {<<"command">>, <<>>, <<"http://jabber.org/protocol/commands">>} -> true; - {<<"note">>, + {<<"note">>, <<"http://jabber.org/protocol/commands">>, + _} -> + true; + {<<"note">>, <<>>, <<"http://jabber.org/protocol/commands">>} -> true; {<<"actions">>, + <<"http://jabber.org/protocol/commands">>, _} -> + true; + {<<"actions">>, <<>>, <<"http://jabber.org/protocol/commands">>} -> true; {<<"complete">>, + <<"http://jabber.org/protocol/commands">>, _} -> + true; + {<<"complete">>, <<>>, <<"http://jabber.org/protocol/commands">>} -> true; - {<<"next">>, + {<<"next">>, <<"http://jabber.org/protocol/commands">>, + _} -> + true; + {<<"next">>, <<>>, <<"http://jabber.org/protocol/commands">>} -> true; - {<<"prev">>, + {<<"prev">>, <<"http://jabber.org/protocol/commands">>, + _} -> + true; + {<<"prev">>, <<>>, <<"http://jabber.org/protocol/commands">>} -> true; - {<<"client-id">>, <<"urn:xmpp:sid:0">>} -> true; - {<<"stanza-id">>, <<"urn:xmpp:sid:0">>} -> true; + {<<"client-id">>, <<"urn:xmpp:sid:0">>, _} -> true; + {<<"client-id">>, <<>>, <<"urn:xmpp:sid:0">>} -> true; + {<<"stanza-id">>, <<"urn:xmpp:sid:0">>, _} -> true; + {<<"stanza-id">>, <<>>, <<"urn:xmpp:sid:0">>} -> true; {<<"addresses">>, + <<"http://jabber.org/protocol/address">>, _} -> + true; + {<<"addresses">>, <<>>, <<"http://jabber.org/protocol/address">>} -> true; {<<"address">>, + <<"http://jabber.org/protocol/address">>, _} -> + true; + {<<"address">>, <<>>, <<"http://jabber.org/protocol/address">>} -> true; - {<<"nick">>, <<"http://jabber.org/protocol/nick">>} -> + {<<"nick">>, <<"http://jabber.org/protocol/nick">>, + _} -> true; - {<<"x">>, <<"jabber:x:expire">>} -> true; - {<<"x">>, <<"jabber:x:event">>} -> true; - {<<"id">>, <<"jabber:x:event">>} -> true; - {<<"composing">>, <<"jabber:x:event">>} -> true; - {<<"displayed">>, <<"jabber:x:event">>} -> true; - {<<"delivered">>, <<"jabber:x:event">>} -> true; - {<<"offline">>, <<"jabber:x:event">>} -> true; - {<<"query">>, <<"jabber:iq:search">>} -> true; - {<<"item">>, <<"jabber:iq:search">>} -> true; - {<<"email">>, <<"jabber:iq:search">>} -> true; - {<<"nick">>, <<"jabber:iq:search">>} -> true; - {<<"last">>, <<"jabber:iq:search">>} -> true; - {<<"first">>, <<"jabber:iq:search">>} -> true; - {<<"instructions">>, <<"jabber:iq:search">>} -> true; - {<<"no-permanent-storage">>, <<"urn:xmpp:hints">>} -> + {<<"nick">>, <<>>, + <<"http://jabber.org/protocol/nick">>} -> true; - {<<"no-permanent-store">>, <<"urn:xmpp:hints">>} -> + {<<"x">>, <<"jabber:x:expire">>, _} -> true; + {<<"x">>, <<>>, <<"jabber:x:expire">>} -> true; + {<<"x">>, <<"jabber:x:event">>, _} -> true; + {<<"x">>, <<>>, <<"jabber:x:event">>} -> true; + {<<"id">>, <<"jabber:x:event">>, _} -> true; + {<<"id">>, <<>>, <<"jabber:x:event">>} -> true; + {<<"composing">>, <<"jabber:x:event">>, _} -> true; + {<<"composing">>, <<>>, <<"jabber:x:event">>} -> true; + {<<"displayed">>, <<"jabber:x:event">>, _} -> true; + {<<"displayed">>, <<>>, <<"jabber:x:event">>} -> true; + {<<"delivered">>, <<"jabber:x:event">>, _} -> true; + {<<"delivered">>, <<>>, <<"jabber:x:event">>} -> true; + {<<"offline">>, <<"jabber:x:event">>, _} -> true; + {<<"offline">>, <<>>, <<"jabber:x:event">>} -> true; + {<<"query">>, <<"jabber:iq:search">>, _} -> true; + {<<"query">>, <<>>, <<"jabber:iq:search">>} -> true; + {<<"item">>, <<"jabber:iq:search">>, _} -> true; + {<<"item">>, <<>>, <<"jabber:iq:search">>} -> true; + {<<"email">>, <<"jabber:iq:search">>, _} -> true; + {<<"email">>, <<>>, <<"jabber:iq:search">>} -> true; + {<<"nick">>, <<"jabber:iq:search">>, _} -> true; + {<<"nick">>, <<>>, <<"jabber:iq:search">>} -> true; + {<<"last">>, <<"jabber:iq:search">>, _} -> true; + {<<"last">>, <<>>, <<"jabber:iq:search">>} -> true; + {<<"first">>, <<"jabber:iq:search">>, _} -> true; + {<<"first">>, <<>>, <<"jabber:iq:search">>} -> true; + {<<"instructions">>, <<"jabber:iq:search">>, _} -> true; + {<<"instructions">>, <<>>, <<"jabber:iq:search">>} -> true; - {<<"store">>, <<"urn:xmpp:hints">>} -> true; - {<<"no-storage">>, <<"urn:xmpp:hints">>} -> true; - {<<"no-store">>, <<"urn:xmpp:hints">>} -> true; - {<<"no-copy">>, <<"urn:xmpp:hints">>} -> true; - {<<"participant">>, <<"urn:xmpp:mix:0">>} -> true; - {<<"leave">>, <<"urn:xmpp:mix:0">>} -> true; - {<<"join">>, <<"urn:xmpp:mix:0">>} -> true; - {<<"subscribe">>, <<"urn:xmpp:mix:0">>} -> true; + {<<"no-permanent-storage">>, <<"urn:xmpp:hints">>, _} -> + true; + {<<"no-permanent-storage">>, <<>>, + <<"urn:xmpp:hints">>} -> + true; + {<<"no-permanent-store">>, <<"urn:xmpp:hints">>, _} -> + true; + {<<"no-permanent-store">>, <<>>, + <<"urn:xmpp:hints">>} -> + true; + {<<"store">>, <<"urn:xmpp:hints">>, _} -> true; + {<<"store">>, <<>>, <<"urn:xmpp:hints">>} -> true; + {<<"no-storage">>, <<"urn:xmpp:hints">>, _} -> true; + {<<"no-storage">>, <<>>, <<"urn:xmpp:hints">>} -> true; + {<<"no-store">>, <<"urn:xmpp:hints">>, _} -> true; + {<<"no-store">>, <<>>, <<"urn:xmpp:hints">>} -> true; + {<<"no-copy">>, <<"urn:xmpp:hints">>, _} -> true; + {<<"no-copy">>, <<>>, <<"urn:xmpp:hints">>} -> true; + {<<"participant">>, <<"urn:xmpp:mix:0">>, _} -> true; + {<<"participant">>, <<>>, <<"urn:xmpp:mix:0">>} -> true; + {<<"leave">>, <<"urn:xmpp:mix:0">>, _} -> true; + {<<"leave">>, <<>>, <<"urn:xmpp:mix:0">>} -> true; + {<<"join">>, <<"urn:xmpp:mix:0">>, _} -> true; + {<<"join">>, <<>>, <<"urn:xmpp:mix:0">>} -> true; + {<<"subscribe">>, <<"urn:xmpp:mix:0">>, _} -> true; + {<<"subscribe">>, <<>>, <<"urn:xmpp:mix:0">>} -> true; {<<"offline">>, + <<"http://jabber.org/protocol/offline">>, _} -> + true; + {<<"offline">>, <<>>, <<"http://jabber.org/protocol/offline">>} -> true; - {<<"item">>, + {<<"item">>, <<"http://jabber.org/protocol/offline">>, + _} -> + true; + {<<"item">>, <<>>, <<"http://jabber.org/protocol/offline">>} -> true; - {<<"fetch">>, + {<<"fetch">>, <<"http://jabber.org/protocol/offline">>, + _} -> + true; + {<<"fetch">>, <<>>, <<"http://jabber.org/protocol/offline">>} -> true; - {<<"purge">>, + {<<"purge">>, <<"http://jabber.org/protocol/offline">>, + _} -> + true; + {<<"purge">>, <<>>, <<"http://jabber.org/protocol/offline">>} -> true; - {<<"failed">>, <<"urn:xmpp:sm:2">>} -> true; - {<<"failed">>, <<"urn:xmpp:sm:3">>} -> true; - {<<"a">>, <<"urn:xmpp:sm:2">>} -> true; - {<<"a">>, <<"urn:xmpp:sm:3">>} -> true; - {<<"r">>, <<"urn:xmpp:sm:2">>} -> true; - {<<"r">>, <<"urn:xmpp:sm:3">>} -> true; - {<<"resumed">>, <<"urn:xmpp:sm:2">>} -> true; - {<<"resumed">>, <<"urn:xmpp:sm:3">>} -> true; - {<<"resume">>, <<"urn:xmpp:sm:2">>} -> true; - {<<"resume">>, <<"urn:xmpp:sm:3">>} -> true; - {<<"enabled">>, <<"urn:xmpp:sm:2">>} -> true; - {<<"enabled">>, <<"urn:xmpp:sm:3">>} -> true; - {<<"enable">>, <<"urn:xmpp:sm:2">>} -> true; - {<<"enable">>, <<"urn:xmpp:sm:3">>} -> true; - {<<"sm">>, <<"urn:xmpp:sm:2">>} -> true; - {<<"sm">>, <<"urn:xmpp:sm:3">>} -> true; - {<<"inactive">>, <<"urn:xmpp:csi:0">>} -> true; - {<<"active">>, <<"urn:xmpp:csi:0">>} -> true; - {<<"csi">>, <<"urn:xmpp:csi:0">>} -> true; - {<<"sent">>, <<"urn:xmpp:carbons:2">>} -> true; - {<<"received">>, <<"urn:xmpp:carbons:2">>} -> true; - {<<"private">>, <<"urn:xmpp:carbons:2">>} -> true; - {<<"enable">>, <<"urn:xmpp:carbons:2">>} -> true; - {<<"disable">>, <<"urn:xmpp:carbons:2">>} -> true; - {<<"forwarded">>, <<"urn:xmpp:forward:0">>} -> true; - {<<"fin">>, <<"urn:xmpp:mam:0">>} -> true; - {<<"fin">>, <<"urn:xmpp:mam:1">>} -> true; - {<<"prefs">>, <<"urn:xmpp:mam:0">>} -> true; - {<<"prefs">>, <<"urn:xmpp:mam:1">>} -> true; - {<<"prefs">>, <<"urn:xmpp:mam:tmp">>} -> true; - {<<"always">>, <<"urn:xmpp:mam:0">>} -> true; - {<<"always">>, <<"urn:xmpp:mam:1">>} -> true; - {<<"always">>, <<"urn:xmpp:mam:tmp">>} -> true; - {<<"never">>, <<"urn:xmpp:mam:0">>} -> true; - {<<"never">>, <<"urn:xmpp:mam:1">>} -> true; - {<<"never">>, <<"urn:xmpp:mam:tmp">>} -> true; - {<<"jid">>, <<"urn:xmpp:mam:0">>} -> true; - {<<"jid">>, <<"urn:xmpp:mam:1">>} -> true; - {<<"jid">>, <<"urn:xmpp:mam:tmp">>} -> true; - {<<"result">>, <<"urn:xmpp:mam:0">>} -> true; - {<<"result">>, <<"urn:xmpp:mam:1">>} -> true; - {<<"result">>, <<"urn:xmpp:mam:tmp">>} -> true; - {<<"archived">>, <<"urn:xmpp:mam:tmp">>} -> true; - {<<"query">>, <<"urn:xmpp:mam:0">>} -> true; - {<<"query">>, <<"urn:xmpp:mam:1">>} -> true; - {<<"query">>, <<"urn:xmpp:mam:tmp">>} -> true; - {<<"withtext">>, <<"urn:xmpp:mam:tmp">>} -> true; - {<<"with">>, <<"urn:xmpp:mam:tmp">>} -> true; - {<<"end">>, <<"urn:xmpp:mam:tmp">>} -> true; - {<<"start">>, <<"urn:xmpp:mam:tmp">>} -> true; - {<<"set">>, <<"http://jabber.org/protocol/rsm">>} -> + {<<"failed">>, <<"urn:xmpp:sm:2">>, _} -> true; + {<<"failed">>, <<>>, <<"urn:xmpp:sm:2">>} -> true; + {<<"failed">>, <<"urn:xmpp:sm:3">>, _} -> true; + {<<"failed">>, <<>>, <<"urn:xmpp:sm:3">>} -> true; + {<<"a">>, <<"urn:xmpp:sm:2">>, _} -> true; + {<<"a">>, <<>>, <<"urn:xmpp:sm:2">>} -> true; + {<<"a">>, <<"urn:xmpp:sm:3">>, _} -> true; + {<<"a">>, <<>>, <<"urn:xmpp:sm:3">>} -> true; + {<<"r">>, <<"urn:xmpp:sm:2">>, _} -> true; + {<<"r">>, <<>>, <<"urn:xmpp:sm:2">>} -> true; + {<<"r">>, <<"urn:xmpp:sm:3">>, _} -> true; + {<<"r">>, <<>>, <<"urn:xmpp:sm:3">>} -> true; + {<<"resumed">>, <<"urn:xmpp:sm:2">>, _} -> true; + {<<"resumed">>, <<>>, <<"urn:xmpp:sm:2">>} -> true; + {<<"resumed">>, <<"urn:xmpp:sm:3">>, _} -> true; + {<<"resumed">>, <<>>, <<"urn:xmpp:sm:3">>} -> true; + {<<"resume">>, <<"urn:xmpp:sm:2">>, _} -> true; + {<<"resume">>, <<>>, <<"urn:xmpp:sm:2">>} -> true; + {<<"resume">>, <<"urn:xmpp:sm:3">>, _} -> true; + {<<"resume">>, <<>>, <<"urn:xmpp:sm:3">>} -> true; + {<<"enabled">>, <<"urn:xmpp:sm:2">>, _} -> true; + {<<"enabled">>, <<>>, <<"urn:xmpp:sm:2">>} -> true; + {<<"enabled">>, <<"urn:xmpp:sm:3">>, _} -> true; + {<<"enabled">>, <<>>, <<"urn:xmpp:sm:3">>} -> true; + {<<"enable">>, <<"urn:xmpp:sm:2">>, _} -> true; + {<<"enable">>, <<>>, <<"urn:xmpp:sm:2">>} -> true; + {<<"enable">>, <<"urn:xmpp:sm:3">>, _} -> true; + {<<"enable">>, <<>>, <<"urn:xmpp:sm:3">>} -> true; + {<<"sm">>, <<"urn:xmpp:sm:2">>, _} -> true; + {<<"sm">>, <<>>, <<"urn:xmpp:sm:2">>} -> true; + {<<"sm">>, <<"urn:xmpp:sm:3">>, _} -> true; + {<<"sm">>, <<>>, <<"urn:xmpp:sm:3">>} -> true; + {<<"inactive">>, <<"urn:xmpp:csi:0">>, _} -> true; + {<<"inactive">>, <<>>, <<"urn:xmpp:csi:0">>} -> true; + {<<"active">>, <<"urn:xmpp:csi:0">>, _} -> true; + {<<"active">>, <<>>, <<"urn:xmpp:csi:0">>} -> true; + {<<"csi">>, <<"urn:xmpp:csi:0">>, _} -> true; + {<<"csi">>, <<>>, <<"urn:xmpp:csi:0">>} -> true; + {<<"sent">>, <<"urn:xmpp:carbons:2">>, _} -> true; + {<<"sent">>, <<>>, <<"urn:xmpp:carbons:2">>} -> true; + {<<"received">>, <<"urn:xmpp:carbons:2">>, _} -> true; + {<<"received">>, <<>>, <<"urn:xmpp:carbons:2">>} -> true; - {<<"first">>, <<"http://jabber.org/protocol/rsm">>} -> + {<<"private">>, <<"urn:xmpp:carbons:2">>, _} -> true; + {<<"private">>, <<>>, <<"urn:xmpp:carbons:2">>} -> true; + {<<"enable">>, <<"urn:xmpp:carbons:2">>, _} -> true; + {<<"enable">>, <<>>, <<"urn:xmpp:carbons:2">>} -> true; + {<<"disable">>, <<"urn:xmpp:carbons:2">>, _} -> true; + {<<"disable">>, <<>>, <<"urn:xmpp:carbons:2">>} -> true; + {<<"forwarded">>, <<"urn:xmpp:forward:0">>, _} -> true; + {<<"forwarded">>, <<>>, <<"urn:xmpp:forward:0">>} -> true; - {<<"max">>, <<"http://jabber.org/protocol/rsm">>} -> + {<<"fin">>, <<"urn:xmpp:mam:0">>, _} -> true; + {<<"fin">>, <<>>, <<"urn:xmpp:mam:0">>} -> true; + {<<"fin">>, <<"urn:xmpp:mam:1">>, _} -> true; + {<<"fin">>, <<>>, <<"urn:xmpp:mam:1">>} -> true; + {<<"prefs">>, <<"urn:xmpp:mam:0">>, _} -> true; + {<<"prefs">>, <<>>, <<"urn:xmpp:mam:0">>} -> true; + {<<"prefs">>, <<"urn:xmpp:mam:1">>, _} -> true; + {<<"prefs">>, <<>>, <<"urn:xmpp:mam:1">>} -> true; + {<<"prefs">>, <<"urn:xmpp:mam:tmp">>, _} -> true; + {<<"prefs">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> true; + {<<"always">>, <<"urn:xmpp:mam:0">>, _} -> true; + {<<"always">>, <<>>, <<"urn:xmpp:mam:0">>} -> true; + {<<"always">>, <<"urn:xmpp:mam:1">>, _} -> true; + {<<"always">>, <<>>, <<"urn:xmpp:mam:1">>} -> true; + {<<"always">>, <<"urn:xmpp:mam:tmp">>, _} -> true; + {<<"always">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> true; + {<<"never">>, <<"urn:xmpp:mam:0">>, _} -> true; + {<<"never">>, <<>>, <<"urn:xmpp:mam:0">>} -> true; + {<<"never">>, <<"urn:xmpp:mam:1">>, _} -> true; + {<<"never">>, <<>>, <<"urn:xmpp:mam:1">>} -> true; + {<<"never">>, <<"urn:xmpp:mam:tmp">>, _} -> true; + {<<"never">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> true; + {<<"jid">>, <<"urn:xmpp:mam:0">>, _} -> true; + {<<"jid">>, <<>>, <<"urn:xmpp:mam:0">>} -> true; + {<<"jid">>, <<"urn:xmpp:mam:1">>, _} -> true; + {<<"jid">>, <<>>, <<"urn:xmpp:mam:1">>} -> true; + {<<"jid">>, <<"urn:xmpp:mam:tmp">>, _} -> true; + {<<"jid">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> true; + {<<"result">>, <<"urn:xmpp:mam:0">>, _} -> true; + {<<"result">>, <<>>, <<"urn:xmpp:mam:0">>} -> true; + {<<"result">>, <<"urn:xmpp:mam:1">>, _} -> true; + {<<"result">>, <<>>, <<"urn:xmpp:mam:1">>} -> true; + {<<"result">>, <<"urn:xmpp:mam:tmp">>, _} -> true; + {<<"result">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> true; + {<<"archived">>, <<"urn:xmpp:mam:tmp">>, _} -> true; + {<<"archived">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> true; + {<<"query">>, <<"urn:xmpp:mam:0">>, _} -> true; + {<<"query">>, <<>>, <<"urn:xmpp:mam:0">>} -> true; + {<<"query">>, <<"urn:xmpp:mam:1">>, _} -> true; + {<<"query">>, <<>>, <<"urn:xmpp:mam:1">>} -> true; + {<<"query">>, <<"urn:xmpp:mam:tmp">>, _} -> true; + {<<"query">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> true; + {<<"withtext">>, <<"urn:xmpp:mam:tmp">>, _} -> true; + {<<"withtext">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> true; + {<<"with">>, <<"urn:xmpp:mam:tmp">>, _} -> true; + {<<"with">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> true; + {<<"end">>, <<"urn:xmpp:mam:tmp">>, _} -> true; + {<<"end">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> true; + {<<"start">>, <<"urn:xmpp:mam:tmp">>, _} -> true; + {<<"start">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> true; + {<<"set">>, <<"http://jabber.org/protocol/rsm">>, _} -> true; - {<<"index">>, <<"http://jabber.org/protocol/rsm">>} -> + {<<"set">>, <<>>, + <<"http://jabber.org/protocol/rsm">>} -> true; - {<<"count">>, <<"http://jabber.org/protocol/rsm">>} -> + {<<"first">>, <<"http://jabber.org/protocol/rsm">>, + _} -> true; - {<<"last">>, <<"http://jabber.org/protocol/rsm">>} -> + {<<"first">>, <<>>, + <<"http://jabber.org/protocol/rsm">>} -> true; - {<<"before">>, <<"http://jabber.org/protocol/rsm">>} -> + {<<"max">>, <<"http://jabber.org/protocol/rsm">>, _} -> true; - {<<"after">>, <<"http://jabber.org/protocol/rsm">>} -> + {<<"max">>, <<>>, + <<"http://jabber.org/protocol/rsm">>} -> true; - {<<"unsubscribe">>, <<"urn:xmpp:mucsub:0">>} -> true; - {<<"subscribe">>, <<"urn:xmpp:mucsub:0">>} -> true; - {<<"event">>, <<"urn:xmpp:mucsub:0">>} -> true; - {<<"subscriptions">>, <<"urn:xmpp:mucsub:0">>} -> true; - {<<"subscription">>, <<"urn:xmpp:mucsub:0">>} -> true; - {<<"x">>, <<"jabber:x:conference">>} -> true; + {<<"index">>, <<"http://jabber.org/protocol/rsm">>, + _} -> + true; + {<<"index">>, <<>>, + <<"http://jabber.org/protocol/rsm">>} -> + true; + {<<"count">>, <<"http://jabber.org/protocol/rsm">>, + _} -> + true; + {<<"count">>, <<>>, + <<"http://jabber.org/protocol/rsm">>} -> + true; + {<<"last">>, <<"http://jabber.org/protocol/rsm">>, _} -> + true; + {<<"last">>, <<>>, + <<"http://jabber.org/protocol/rsm">>} -> + true; + {<<"before">>, <<"http://jabber.org/protocol/rsm">>, + _} -> + true; + {<<"before">>, <<>>, + <<"http://jabber.org/protocol/rsm">>} -> + true; + {<<"after">>, <<"http://jabber.org/protocol/rsm">>, + _} -> + true; + {<<"after">>, <<>>, + <<"http://jabber.org/protocol/rsm">>} -> + true; + {<<"unsubscribe">>, <<"urn:xmpp:mucsub:0">>, _} -> true; + {<<"unsubscribe">>, <<>>, <<"urn:xmpp:mucsub:0">>} -> + true; + {<<"subscribe">>, <<"urn:xmpp:mucsub:0">>, _} -> true; + {<<"subscribe">>, <<>>, <<"urn:xmpp:mucsub:0">>} -> + true; + {<<"event">>, <<"urn:xmpp:mucsub:0">>, _} -> true; + {<<"event">>, <<>>, <<"urn:xmpp:mucsub:0">>} -> true; + {<<"subscriptions">>, <<"urn:xmpp:mucsub:0">>, _} -> + true; + {<<"subscriptions">>, <<>>, <<"urn:xmpp:mucsub:0">>} -> + true; + {<<"subscription">>, <<"urn:xmpp:mucsub:0">>, _} -> + true; + {<<"subscription">>, <<>>, <<"urn:xmpp:mucsub:0">>} -> + true; + {<<"x">>, <<"jabber:x:conference">>, _} -> true; + {<<"x">>, <<>>, <<"jabber:x:conference">>} -> true; {<<"unique">>, + <<"http://jabber.org/protocol/muc#unique">>, _} -> + true; + {<<"unique">>, <<>>, <<"http://jabber.org/protocol/muc#unique">>} -> true; - {<<"x">>, <<"http://jabber.org/protocol/muc">>} -> true; + {<<"x">>, <<"http://jabber.org/protocol/muc">>, _} -> + true; + {<<"x">>, <<>>, <<"http://jabber.org/protocol/muc">>} -> + true; {<<"query">>, + <<"http://jabber.org/protocol/muc#admin">>, _} -> + true; + {<<"query">>, <<>>, <<"http://jabber.org/protocol/muc#admin">>} -> true; {<<"continue">>, + <<"http://jabber.org/protocol/muc#admin">>, _} -> + true; + {<<"continue">>, <<>>, <<"http://jabber.org/protocol/muc#admin">>} -> true; {<<"actor">>, + <<"http://jabber.org/protocol/muc#admin">>, _} -> + true; + {<<"actor">>, <<>>, <<"http://jabber.org/protocol/muc#admin">>} -> true; - {<<"item">>, + {<<"item">>, <<"http://jabber.org/protocol/muc#admin">>, + _} -> + true; + {<<"item">>, <<>>, <<"http://jabber.org/protocol/muc#admin">>} -> true; - {<<"item">>, + {<<"item">>, <<"http://jabber.org/protocol/muc#owner">>, + _} -> + true; + {<<"item">>, <<>>, <<"http://jabber.org/protocol/muc#owner">>} -> true; {<<"query">>, + <<"http://jabber.org/protocol/muc#owner">>, _} -> + true; + {<<"query">>, <<>>, <<"http://jabber.org/protocol/muc#owner">>} -> true; {<<"password">>, + <<"http://jabber.org/protocol/muc#owner">>, _} -> + true; + {<<"password">>, <<>>, <<"http://jabber.org/protocol/muc#owner">>} -> true; {<<"password">>, + <<"http://jabber.org/protocol/muc#user">>, _} -> + true; + {<<"password">>, <<>>, <<"http://jabber.org/protocol/muc#user">>} -> true; - {<<"password">>, + {<<"password">>, <<"http://jabber.org/protocol/muc">>, + _} -> + true; + {<<"password">>, <<>>, <<"http://jabber.org/protocol/muc">>} -> true; - {<<"x">>, <<"http://jabber.org/protocol/muc#user">>} -> + {<<"x">>, <<"http://jabber.org/protocol/muc#user">>, + _} -> true; - {<<"item">>, + {<<"x">>, <<>>, + <<"http://jabber.org/protocol/muc#user">>} -> + true; + {<<"item">>, <<"http://jabber.org/protocol/muc#user">>, + _} -> + true; + {<<"item">>, <<>>, <<"http://jabber.org/protocol/muc#user">>} -> true; {<<"status">>, + <<"http://jabber.org/protocol/muc#user">>, _} -> + true; + {<<"status">>, <<>>, <<"http://jabber.org/protocol/muc#user">>} -> true; {<<"continue">>, + <<"http://jabber.org/protocol/muc#user">>, _} -> + true; + {<<"continue">>, <<>>, <<"http://jabber.org/protocol/muc#user">>} -> true; - {<<"actor">>, + {<<"actor">>, <<"http://jabber.org/protocol/muc#user">>, + _} -> + true; + {<<"actor">>, <<>>, <<"http://jabber.org/protocol/muc#user">>} -> true; {<<"invite">>, + <<"http://jabber.org/protocol/muc#user">>, _} -> + true; + {<<"invite">>, <<>>, <<"http://jabber.org/protocol/muc#user">>} -> true; {<<"destroy">>, + <<"http://jabber.org/protocol/muc#user">>, _} -> + true; + {<<"destroy">>, <<>>, <<"http://jabber.org/protocol/muc#user">>} -> true; {<<"destroy">>, + <<"http://jabber.org/protocol/muc#owner">>, _} -> + true; + {<<"destroy">>, <<>>, <<"http://jabber.org/protocol/muc#owner">>} -> true; {<<"decline">>, + <<"http://jabber.org/protocol/muc#user">>, _} -> + true; + {<<"decline">>, <<>>, <<"http://jabber.org/protocol/muc#user">>} -> true; {<<"reason">>, + <<"http://jabber.org/protocol/muc#user">>, _} -> + true; + {<<"reason">>, <<>>, <<"http://jabber.org/protocol/muc#user">>} -> true; {<<"reason">>, + <<"http://jabber.org/protocol/muc#admin">>, _} -> + true; + {<<"reason">>, <<>>, <<"http://jabber.org/protocol/muc#admin">>} -> true; {<<"reason">>, + <<"http://jabber.org/protocol/muc#owner">>, _} -> + true; + {<<"reason">>, <<>>, <<"http://jabber.org/protocol/muc#owner">>} -> true; - {<<"history">>, <<"http://jabber.org/protocol/muc">>} -> + {<<"history">>, <<"http://jabber.org/protocol/muc">>, + _} -> + true; + {<<"history">>, <<>>, + <<"http://jabber.org/protocol/muc">>} -> true; {<<"query">>, + <<"http://jabber.org/protocol/bytestreams">>, _} -> + true; + {<<"query">>, <<>>, <<"http://jabber.org/protocol/bytestreams">>} -> true; {<<"activate">>, + <<"http://jabber.org/protocol/bytestreams">>, _} -> + true; + {<<"activate">>, <<>>, <<"http://jabber.org/protocol/bytestreams">>} -> true; {<<"streamhost-used">>, + <<"http://jabber.org/protocol/bytestreams">>, _} -> + true; + {<<"streamhost-used">>, <<>>, <<"http://jabber.org/protocol/bytestreams">>} -> true; {<<"streamhost">>, + <<"http://jabber.org/protocol/bytestreams">>, _} -> + true; + {<<"streamhost">>, <<>>, <<"http://jabber.org/protocol/bytestreams">>} -> true; - {<<"delay">>, <<"urn:xmpp:delay">>} -> true; + {<<"delay">>, <<"urn:xmpp:delay">>, _} -> true; + {<<"delay">>, <<>>, <<"urn:xmpp:delay">>} -> true; {<<"paused">>, + <<"http://jabber.org/protocol/chatstates">>, _} -> + true; + {<<"paused">>, <<>>, <<"http://jabber.org/protocol/chatstates">>} -> true; {<<"inactive">>, + <<"http://jabber.org/protocol/chatstates">>, _} -> + true; + {<<"inactive">>, <<>>, <<"http://jabber.org/protocol/chatstates">>} -> true; {<<"gone">>, + <<"http://jabber.org/protocol/chatstates">>, _} -> + true; + {<<"gone">>, <<>>, <<"http://jabber.org/protocol/chatstates">>} -> true; {<<"composing">>, + <<"http://jabber.org/protocol/chatstates">>, _} -> + true; + {<<"composing">>, <<>>, <<"http://jabber.org/protocol/chatstates">>} -> true; {<<"active">>, + <<"http://jabber.org/protocol/chatstates">>, _} -> + true; + {<<"active">>, <<>>, <<"http://jabber.org/protocol/chatstates">>} -> true; - {<<"headers">>, + {<<"headers">>, <<"http://jabber.org/protocol/shim">>, + _} -> + true; + {<<"headers">>, <<>>, <<"http://jabber.org/protocol/shim">>} -> true; - {<<"header">>, <<"http://jabber.org/protocol/shim">>} -> + {<<"header">>, <<"http://jabber.org/protocol/shim">>, + _} -> + true; + {<<"header">>, <<>>, + <<"http://jabber.org/protocol/shim">>} -> true; {<<"unsupported-access-model">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + true; + {<<"unsupported-access-model">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> true; {<<"unsupported">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + true; + {<<"unsupported">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> true; {<<"too-many-subscriptions">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + true; + {<<"too-many-subscriptions">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> true; {<<"subid-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + true; + {<<"subid-required">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> true; {<<"presence-subscription-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + true; + {<<"presence-subscription-required">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> true; {<<"pending-subscription">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + true; + {<<"pending-subscription">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> true; {<<"payload-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + true; + {<<"payload-required">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> true; {<<"payload-too-big">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + true; + {<<"payload-too-big">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> true; {<<"not-subscribed">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + true; + {<<"not-subscribed">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> true; {<<"not-in-roster-group">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + true; + {<<"not-in-roster-group">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> true; {<<"nodeid-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + true; + {<<"nodeid-required">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> true; {<<"max-nodes-exceeded">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + true; + {<<"max-nodes-exceeded">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> true; {<<"max-items-exceeded">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + true; + {<<"max-items-exceeded">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> true; {<<"jid-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + true; + {<<"jid-required">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> true; {<<"item-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + true; + {<<"item-required">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> true; {<<"item-forbidden">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + true; + {<<"item-forbidden">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> true; {<<"invalid-subid">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + true; + {<<"invalid-subid">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> true; {<<"invalid-payload">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + true; + {<<"invalid-payload">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> true; {<<"invalid-options">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + true; + {<<"invalid-options">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> true; {<<"invalid-jid">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + true; + {<<"invalid-jid">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> true; {<<"configuration-required">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + true; + {<<"configuration-required">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> true; {<<"closed-node">>, + <<"http://jabber.org/protocol/pubsub#errors">>, _} -> + true; + {<<"closed-node">>, <<>>, <<"http://jabber.org/protocol/pubsub#errors">>} -> true; {<<"pubsub">>, + <<"http://jabber.org/protocol/pubsub#owner">>, _} -> + true; + {<<"pubsub">>, <<>>, <<"http://jabber.org/protocol/pubsub#owner">>} -> true; - {<<"pubsub">>, + {<<"pubsub">>, <<"http://jabber.org/protocol/pubsub">>, + _} -> + true; + {<<"pubsub">>, <<>>, + <<"http://jabber.org/protocol/pubsub">>} -> + true; + {<<"purge">>, <<"http://jabber.org/protocol/pubsub">>, + _} -> + true; + {<<"purge">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> true; {<<"purge">>, - <<"http://jabber.org/protocol/pubsub">>} -> + <<"http://jabber.org/protocol/pubsub#owner">>, _} -> true; - {<<"purge">>, + {<<"purge">>, <<>>, <<"http://jabber.org/protocol/pubsub#owner">>} -> true; {<<"purge">>, + <<"http://jabber.org/protocol/pubsub#event">>, _} -> + true; + {<<"purge">>, <<>>, <<"http://jabber.org/protocol/pubsub#event">>} -> true; - {<<"delete">>, + {<<"delete">>, <<"http://jabber.org/protocol/pubsub">>, + _} -> + true; + {<<"delete">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> true; {<<"delete">>, + <<"http://jabber.org/protocol/pubsub#owner">>, _} -> + true; + {<<"delete">>, <<>>, <<"http://jabber.org/protocol/pubsub#owner">>} -> true; {<<"delete">>, + <<"http://jabber.org/protocol/pubsub#event">>, _} -> + true; + {<<"delete">>, <<>>, <<"http://jabber.org/protocol/pubsub#event">>} -> true; {<<"redirect">>, + <<"http://jabber.org/protocol/pubsub">>, _} -> + true; + {<<"redirect">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> true; {<<"redirect">>, + <<"http://jabber.org/protocol/pubsub#owner">>, _} -> + true; + {<<"redirect">>, <<>>, <<"http://jabber.org/protocol/pubsub#owner">>} -> true; {<<"redirect">>, + <<"http://jabber.org/protocol/pubsub#event">>, _} -> + true; + {<<"redirect">>, <<>>, <<"http://jabber.org/protocol/pubsub#event">>} -> true; - {<<"default">>, + {<<"default">>, <<"http://jabber.org/protocol/pubsub">>, + _} -> + true; + {<<"default">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> true; {<<"default">>, + <<"http://jabber.org/protocol/pubsub#owner">>, _} -> + true; + {<<"default">>, <<>>, <<"http://jabber.org/protocol/pubsub#owner">>} -> true; {<<"publish-options">>, + <<"http://jabber.org/protocol/pubsub">>, _} -> + true; + {<<"publish-options">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> true; {<<"configure">>, + <<"http://jabber.org/protocol/pubsub">>, _} -> + true; + {<<"configure">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> true; {<<"configure">>, + <<"http://jabber.org/protocol/pubsub#owner">>, _} -> + true; + {<<"configure">>, <<>>, <<"http://jabber.org/protocol/pubsub#owner">>} -> true; - {<<"create">>, + {<<"create">>, <<"http://jabber.org/protocol/pubsub">>, + _} -> + true; + {<<"create">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> true; {<<"create">>, + <<"http://jabber.org/protocol/pubsub#event">>, _} -> + true; + {<<"create">>, <<>>, <<"http://jabber.org/protocol/pubsub#event">>} -> true; - {<<"retract">>, + {<<"retract">>, <<"http://jabber.org/protocol/pubsub">>, + _} -> + true; + {<<"retract">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> true; - {<<"options">>, + {<<"options">>, <<"http://jabber.org/protocol/pubsub">>, + _} -> + true; + {<<"options">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> true; - {<<"publish">>, + {<<"publish">>, <<"http://jabber.org/protocol/pubsub">>, + _} -> + true; + {<<"publish">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> true; {<<"unsubscribe">>, + <<"http://jabber.org/protocol/pubsub">>, _} -> + true; + {<<"unsubscribe">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> true; {<<"subscribe">>, + <<"http://jabber.org/protocol/pubsub">>, _} -> + true; + {<<"subscribe">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> true; {<<"affiliations">>, + <<"http://jabber.org/protocol/pubsub#owner">>, _} -> + true; + {<<"affiliations">>, <<>>, <<"http://jabber.org/protocol/pubsub#owner">>} -> true; {<<"affiliations">>, + <<"http://jabber.org/protocol/pubsub">>, _} -> + true; + {<<"affiliations">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> true; {<<"subscriptions">>, + <<"http://jabber.org/protocol/pubsub">>, _} -> + true; + {<<"subscriptions">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> true; {<<"subscriptions">>, + <<"http://jabber.org/protocol/pubsub#owner">>, _} -> + true; + {<<"subscriptions">>, <<>>, <<"http://jabber.org/protocol/pubsub#owner">>} -> true; {<<"event">>, + <<"http://jabber.org/protocol/pubsub#event">>, _} -> + true; + {<<"event">>, <<>>, <<"http://jabber.org/protocol/pubsub#event">>} -> true; - {<<"items">>, + {<<"items">>, <<"http://jabber.org/protocol/pubsub">>, + _} -> + true; + {<<"items">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> true; {<<"items">>, + <<"http://jabber.org/protocol/pubsub#event">>, _} -> + true; + {<<"items">>, <<>>, <<"http://jabber.org/protocol/pubsub#event">>} -> true; - {<<"item">>, <<"http://jabber.org/protocol/pubsub">>} -> + {<<"item">>, <<"http://jabber.org/protocol/pubsub">>, + _} -> + true; + {<<"item">>, <<>>, + <<"http://jabber.org/protocol/pubsub">>} -> true; {<<"item">>, + <<"http://jabber.org/protocol/pubsub#event">>, _} -> + true; + {<<"item">>, <<>>, <<"http://jabber.org/protocol/pubsub#event">>} -> true; {<<"retract">>, + <<"http://jabber.org/protocol/pubsub#event">>, _} -> + true; + {<<"retract">>, <<>>, <<"http://jabber.org/protocol/pubsub#event">>} -> true; {<<"configuration">>, + <<"http://jabber.org/protocol/pubsub#event">>, _} -> + true; + {<<"configuration">>, <<>>, <<"http://jabber.org/protocol/pubsub#event">>} -> true; {<<"affiliation">>, + <<"http://jabber.org/protocol/pubsub#owner">>, _} -> + true; + {<<"affiliation">>, <<>>, <<"http://jabber.org/protocol/pubsub#owner">>} -> true; {<<"affiliation">>, + <<"http://jabber.org/protocol/pubsub">>, _} -> + true; + {<<"affiliation">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> true; {<<"subscription">>, + <<"http://jabber.org/protocol/pubsub">>, _} -> + true; + {<<"subscription">>, <<>>, <<"http://jabber.org/protocol/pubsub">>} -> true; {<<"subscription">>, + <<"http://jabber.org/protocol/pubsub#owner">>, _} -> + true; + {<<"subscription">>, <<>>, <<"http://jabber.org/protocol/pubsub#owner">>} -> true; {<<"subscription">>, + <<"http://jabber.org/protocol/pubsub#event">>, _} -> + true; + {<<"subscription">>, <<>>, <<"http://jabber.org/protocol/pubsub#event">>} -> true; - {<<"x">>, <<"jabber:x:data">>} -> true; - {<<"item">>, <<"jabber:x:data">>} -> true; - {<<"reported">>, <<"jabber:x:data">>} -> true; - {<<"title">>, <<"jabber:x:data">>} -> true; - {<<"instructions">>, <<"jabber:x:data">>} -> true; - {<<"field">>, <<"jabber:x:data">>} -> true; - {<<"option">>, <<"jabber:x:data">>} -> true; - {<<"value">>, <<"jabber:x:data">>} -> true; - {<<"desc">>, <<"jabber:x:data">>} -> true; - {<<"required">>, <<"jabber:x:data">>} -> true; - {<<"x">>, <<"vcard-temp:x:update">>} -> true; - {<<"photo">>, <<"vcard-temp:x:update">>} -> true; - {<<"vCard">>, <<"vcard-temp">>} -> true; - {<<"CLASS">>, <<"vcard-temp">>} -> true; - {<<"CATEGORIES">>, <<"vcard-temp">>} -> true; - {<<"KEY">>, <<"vcard-temp">>} -> true; - {<<"SOUND">>, <<"vcard-temp">>} -> true; - {<<"ORG">>, <<"vcard-temp">>} -> true; - {<<"PHOTO">>, <<"vcard-temp">>} -> true; - {<<"LOGO">>, <<"vcard-temp">>} -> true; - {<<"BINVAL">>, <<"vcard-temp">>} -> true; - {<<"GEO">>, <<"vcard-temp">>} -> true; - {<<"EMAIL">>, <<"vcard-temp">>} -> true; - {<<"TEL">>, <<"vcard-temp">>} -> true; - {<<"LABEL">>, <<"vcard-temp">>} -> true; - {<<"ADR">>, <<"vcard-temp">>} -> true; - {<<"N">>, <<"vcard-temp">>} -> true; - {<<"CONFIDENTIAL">>, <<"vcard-temp">>} -> true; - {<<"PRIVATE">>, <<"vcard-temp">>} -> true; - {<<"PUBLIC">>, <<"vcard-temp">>} -> true; - {<<"EXTVAL">>, <<"vcard-temp">>} -> true; - {<<"TYPE">>, <<"vcard-temp">>} -> true; - {<<"DESC">>, <<"vcard-temp">>} -> true; - {<<"URL">>, <<"vcard-temp">>} -> true; - {<<"UID">>, <<"vcard-temp">>} -> true; - {<<"SORT-STRING">>, <<"vcard-temp">>} -> true; - {<<"REV">>, <<"vcard-temp">>} -> true; - {<<"PRODID">>, <<"vcard-temp">>} -> true; - {<<"NOTE">>, <<"vcard-temp">>} -> true; - {<<"KEYWORD">>, <<"vcard-temp">>} -> true; - {<<"ROLE">>, <<"vcard-temp">>} -> true; - {<<"TITLE">>, <<"vcard-temp">>} -> true; - {<<"TZ">>, <<"vcard-temp">>} -> true; - {<<"MAILER">>, <<"vcard-temp">>} -> true; - {<<"JABBERID">>, <<"vcard-temp">>} -> true; - {<<"BDAY">>, <<"vcard-temp">>} -> true; - {<<"NICKNAME">>, <<"vcard-temp">>} -> true; - {<<"FN">>, <<"vcard-temp">>} -> true; - {<<"VERSION">>, <<"vcard-temp">>} -> true; - {<<"CRED">>, <<"vcard-temp">>} -> true; - {<<"PHONETIC">>, <<"vcard-temp">>} -> true; - {<<"ORGUNIT">>, <<"vcard-temp">>} -> true; - {<<"ORGNAME">>, <<"vcard-temp">>} -> true; - {<<"LON">>, <<"vcard-temp">>} -> true; - {<<"LAT">>, <<"vcard-temp">>} -> true; - {<<"USERID">>, <<"vcard-temp">>} -> true; - {<<"NUMBER">>, <<"vcard-temp">>} -> true; - {<<"LINE">>, <<"vcard-temp">>} -> true; - {<<"CTRY">>, <<"vcard-temp">>} -> true; - {<<"PCODE">>, <<"vcard-temp">>} -> true; - {<<"REGION">>, <<"vcard-temp">>} -> true; - {<<"LOCALITY">>, <<"vcard-temp">>} -> true; - {<<"STREET">>, <<"vcard-temp">>} -> true; - {<<"EXTADD">>, <<"vcard-temp">>} -> true; - {<<"POBOX">>, <<"vcard-temp">>} -> true; - {<<"SUFFIX">>, <<"vcard-temp">>} -> true; - {<<"PREFIX">>, <<"vcard-temp">>} -> true; - {<<"MIDDLE">>, <<"vcard-temp">>} -> true; - {<<"GIVEN">>, <<"vcard-temp">>} -> true; - {<<"FAMILY">>, <<"vcard-temp">>} -> true; - {<<"X400">>, <<"vcard-temp">>} -> true; - {<<"INTERNET">>, <<"vcard-temp">>} -> true; - {<<"PREF">>, <<"vcard-temp">>} -> true; - {<<"INTL">>, <<"vcard-temp">>} -> true; - {<<"DOM">>, <<"vcard-temp">>} -> true; - {<<"PARCEL">>, <<"vcard-temp">>} -> true; - {<<"POSTAL">>, <<"vcard-temp">>} -> true; - {<<"PCS">>, <<"vcard-temp">>} -> true; - {<<"ISDN">>, <<"vcard-temp">>} -> true; - {<<"MODEM">>, <<"vcard-temp">>} -> true; - {<<"BBS">>, <<"vcard-temp">>} -> true; - {<<"VIDEO">>, <<"vcard-temp">>} -> true; - {<<"CELL">>, <<"vcard-temp">>} -> true; - {<<"MSG">>, <<"vcard-temp">>} -> true; - {<<"PAGER">>, <<"vcard-temp">>} -> true; - {<<"FAX">>, <<"vcard-temp">>} -> true; - {<<"VOICE">>, <<"vcard-temp">>} -> true; - {<<"WORK">>, <<"vcard-temp">>} -> true; - {<<"HOME">>, <<"vcard-temp">>} -> true; - {<<"stream:error">>, - <<"http://etherx.jabber.org/streams">>} -> + {<<"x">>, <<"jabber:x:data">>, _} -> true; + {<<"x">>, <<>>, <<"jabber:x:data">>} -> true; + {<<"item">>, <<"jabber:x:data">>, _} -> true; + {<<"item">>, <<>>, <<"jabber:x:data">>} -> true; + {<<"reported">>, <<"jabber:x:data">>, _} -> true; + {<<"reported">>, <<>>, <<"jabber:x:data">>} -> true; + {<<"title">>, <<"jabber:x:data">>, _} -> true; + {<<"title">>, <<>>, <<"jabber:x:data">>} -> true; + {<<"instructions">>, <<"jabber:x:data">>, _} -> true; + {<<"instructions">>, <<>>, <<"jabber:x:data">>} -> true; + {<<"field">>, <<"jabber:x:data">>, _} -> true; + {<<"field">>, <<>>, <<"jabber:x:data">>} -> true; + {<<"option">>, <<"jabber:x:data">>, _} -> true; + {<<"option">>, <<>>, <<"jabber:x:data">>} -> true; + {<<"value">>, <<"jabber:x:data">>, _} -> true; + {<<"value">>, <<>>, <<"jabber:x:data">>} -> true; + {<<"desc">>, <<"jabber:x:data">>, _} -> true; + {<<"desc">>, <<>>, <<"jabber:x:data">>} -> true; + {<<"required">>, <<"jabber:x:data">>, _} -> true; + {<<"required">>, <<>>, <<"jabber:x:data">>} -> true; + {<<"x">>, <<"vcard-temp:x:update">>, _} -> true; + {<<"x">>, <<>>, <<"vcard-temp:x:update">>} -> true; + {<<"photo">>, <<"vcard-temp:x:update">>, _} -> true; + {<<"photo">>, <<>>, <<"vcard-temp:x:update">>} -> true; + {<<"vCard">>, <<"vcard-temp">>, _} -> true; + {<<"vCard">>, <<>>, <<"vcard-temp">>} -> true; + {<<"CLASS">>, <<"vcard-temp">>, _} -> true; + {<<"CLASS">>, <<>>, <<"vcard-temp">>} -> true; + {<<"CATEGORIES">>, <<"vcard-temp">>, _} -> true; + {<<"CATEGORIES">>, <<>>, <<"vcard-temp">>} -> true; + {<<"KEY">>, <<"vcard-temp">>, _} -> true; + {<<"KEY">>, <<>>, <<"vcard-temp">>} -> true; + {<<"SOUND">>, <<"vcard-temp">>, _} -> true; + {<<"SOUND">>, <<>>, <<"vcard-temp">>} -> true; + {<<"ORG">>, <<"vcard-temp">>, _} -> true; + {<<"ORG">>, <<>>, <<"vcard-temp">>} -> true; + {<<"PHOTO">>, <<"vcard-temp">>, _} -> true; + {<<"PHOTO">>, <<>>, <<"vcard-temp">>} -> true; + {<<"LOGO">>, <<"vcard-temp">>, _} -> true; + {<<"LOGO">>, <<>>, <<"vcard-temp">>} -> true; + {<<"BINVAL">>, <<"vcard-temp">>, _} -> true; + {<<"BINVAL">>, <<>>, <<"vcard-temp">>} -> true; + {<<"GEO">>, <<"vcard-temp">>, _} -> true; + {<<"GEO">>, <<>>, <<"vcard-temp">>} -> true; + {<<"EMAIL">>, <<"vcard-temp">>, _} -> true; + {<<"EMAIL">>, <<>>, <<"vcard-temp">>} -> true; + {<<"TEL">>, <<"vcard-temp">>, _} -> true; + {<<"TEL">>, <<>>, <<"vcard-temp">>} -> true; + {<<"LABEL">>, <<"vcard-temp">>, _} -> true; + {<<"LABEL">>, <<>>, <<"vcard-temp">>} -> true; + {<<"ADR">>, <<"vcard-temp">>, _} -> true; + {<<"ADR">>, <<>>, <<"vcard-temp">>} -> true; + {<<"N">>, <<"vcard-temp">>, _} -> true; + {<<"N">>, <<>>, <<"vcard-temp">>} -> true; + {<<"CONFIDENTIAL">>, <<"vcard-temp">>, _} -> true; + {<<"CONFIDENTIAL">>, <<>>, <<"vcard-temp">>} -> true; + {<<"PRIVATE">>, <<"vcard-temp">>, _} -> true; + {<<"PRIVATE">>, <<>>, <<"vcard-temp">>} -> true; + {<<"PUBLIC">>, <<"vcard-temp">>, _} -> true; + {<<"PUBLIC">>, <<>>, <<"vcard-temp">>} -> true; + {<<"EXTVAL">>, <<"vcard-temp">>, _} -> true; + {<<"EXTVAL">>, <<>>, <<"vcard-temp">>} -> true; + {<<"TYPE">>, <<"vcard-temp">>, _} -> true; + {<<"TYPE">>, <<>>, <<"vcard-temp">>} -> true; + {<<"DESC">>, <<"vcard-temp">>, _} -> true; + {<<"DESC">>, <<>>, <<"vcard-temp">>} -> true; + {<<"URL">>, <<"vcard-temp">>, _} -> true; + {<<"URL">>, <<>>, <<"vcard-temp">>} -> true; + {<<"UID">>, <<"vcard-temp">>, _} -> true; + {<<"UID">>, <<>>, <<"vcard-temp">>} -> true; + {<<"SORT-STRING">>, <<"vcard-temp">>, _} -> true; + {<<"SORT-STRING">>, <<>>, <<"vcard-temp">>} -> true; + {<<"REV">>, <<"vcard-temp">>, _} -> true; + {<<"REV">>, <<>>, <<"vcard-temp">>} -> true; + {<<"PRODID">>, <<"vcard-temp">>, _} -> true; + {<<"PRODID">>, <<>>, <<"vcard-temp">>} -> true; + {<<"NOTE">>, <<"vcard-temp">>, _} -> true; + {<<"NOTE">>, <<>>, <<"vcard-temp">>} -> true; + {<<"KEYWORD">>, <<"vcard-temp">>, _} -> true; + {<<"KEYWORD">>, <<>>, <<"vcard-temp">>} -> true; + {<<"ROLE">>, <<"vcard-temp">>, _} -> true; + {<<"ROLE">>, <<>>, <<"vcard-temp">>} -> true; + {<<"TITLE">>, <<"vcard-temp">>, _} -> true; + {<<"TITLE">>, <<>>, <<"vcard-temp">>} -> true; + {<<"TZ">>, <<"vcard-temp">>, _} -> true; + {<<"TZ">>, <<>>, <<"vcard-temp">>} -> true; + {<<"MAILER">>, <<"vcard-temp">>, _} -> true; + {<<"MAILER">>, <<>>, <<"vcard-temp">>} -> true; + {<<"JABBERID">>, <<"vcard-temp">>, _} -> true; + {<<"JABBERID">>, <<>>, <<"vcard-temp">>} -> true; + {<<"BDAY">>, <<"vcard-temp">>, _} -> true; + {<<"BDAY">>, <<>>, <<"vcard-temp">>} -> true; + {<<"NICKNAME">>, <<"vcard-temp">>, _} -> true; + {<<"NICKNAME">>, <<>>, <<"vcard-temp">>} -> true; + {<<"FN">>, <<"vcard-temp">>, _} -> true; + {<<"FN">>, <<>>, <<"vcard-temp">>} -> true; + {<<"VERSION">>, <<"vcard-temp">>, _} -> true; + {<<"VERSION">>, <<>>, <<"vcard-temp">>} -> true; + {<<"CRED">>, <<"vcard-temp">>, _} -> true; + {<<"CRED">>, <<>>, <<"vcard-temp">>} -> true; + {<<"PHONETIC">>, <<"vcard-temp">>, _} -> true; + {<<"PHONETIC">>, <<>>, <<"vcard-temp">>} -> true; + {<<"ORGUNIT">>, <<"vcard-temp">>, _} -> true; + {<<"ORGUNIT">>, <<>>, <<"vcard-temp">>} -> true; + {<<"ORGNAME">>, <<"vcard-temp">>, _} -> true; + {<<"ORGNAME">>, <<>>, <<"vcard-temp">>} -> true; + {<<"LON">>, <<"vcard-temp">>, _} -> true; + {<<"LON">>, <<>>, <<"vcard-temp">>} -> true; + {<<"LAT">>, <<"vcard-temp">>, _} -> true; + {<<"LAT">>, <<>>, <<"vcard-temp">>} -> true; + {<<"USERID">>, <<"vcard-temp">>, _} -> true; + {<<"USERID">>, <<>>, <<"vcard-temp">>} -> true; + {<<"NUMBER">>, <<"vcard-temp">>, _} -> true; + {<<"NUMBER">>, <<>>, <<"vcard-temp">>} -> true; + {<<"LINE">>, <<"vcard-temp">>, _} -> true; + {<<"LINE">>, <<>>, <<"vcard-temp">>} -> true; + {<<"CTRY">>, <<"vcard-temp">>, _} -> true; + {<<"CTRY">>, <<>>, <<"vcard-temp">>} -> true; + {<<"PCODE">>, <<"vcard-temp">>, _} -> true; + {<<"PCODE">>, <<>>, <<"vcard-temp">>} -> true; + {<<"REGION">>, <<"vcard-temp">>, _} -> true; + {<<"REGION">>, <<>>, <<"vcard-temp">>} -> true; + {<<"LOCALITY">>, <<"vcard-temp">>, _} -> true; + {<<"LOCALITY">>, <<>>, <<"vcard-temp">>} -> true; + {<<"STREET">>, <<"vcard-temp">>, _} -> true; + {<<"STREET">>, <<>>, <<"vcard-temp">>} -> true; + {<<"EXTADD">>, <<"vcard-temp">>, _} -> true; + {<<"EXTADD">>, <<>>, <<"vcard-temp">>} -> true; + {<<"POBOX">>, <<"vcard-temp">>, _} -> true; + {<<"POBOX">>, <<>>, <<"vcard-temp">>} -> true; + {<<"SUFFIX">>, <<"vcard-temp">>, _} -> true; + {<<"SUFFIX">>, <<>>, <<"vcard-temp">>} -> true; + {<<"PREFIX">>, <<"vcard-temp">>, _} -> true; + {<<"PREFIX">>, <<>>, <<"vcard-temp">>} -> true; + {<<"MIDDLE">>, <<"vcard-temp">>, _} -> true; + {<<"MIDDLE">>, <<>>, <<"vcard-temp">>} -> true; + {<<"GIVEN">>, <<"vcard-temp">>, _} -> true; + {<<"GIVEN">>, <<>>, <<"vcard-temp">>} -> true; + {<<"FAMILY">>, <<"vcard-temp">>, _} -> true; + {<<"FAMILY">>, <<>>, <<"vcard-temp">>} -> true; + {<<"X400">>, <<"vcard-temp">>, _} -> true; + {<<"X400">>, <<>>, <<"vcard-temp">>} -> true; + {<<"INTERNET">>, <<"vcard-temp">>, _} -> true; + {<<"INTERNET">>, <<>>, <<"vcard-temp">>} -> true; + {<<"PREF">>, <<"vcard-temp">>, _} -> true; + {<<"PREF">>, <<>>, <<"vcard-temp">>} -> true; + {<<"INTL">>, <<"vcard-temp">>, _} -> true; + {<<"INTL">>, <<>>, <<"vcard-temp">>} -> true; + {<<"DOM">>, <<"vcard-temp">>, _} -> true; + {<<"DOM">>, <<>>, <<"vcard-temp">>} -> true; + {<<"PARCEL">>, <<"vcard-temp">>, _} -> true; + {<<"PARCEL">>, <<>>, <<"vcard-temp">>} -> true; + {<<"POSTAL">>, <<"vcard-temp">>, _} -> true; + {<<"POSTAL">>, <<>>, <<"vcard-temp">>} -> true; + {<<"PCS">>, <<"vcard-temp">>, _} -> true; + {<<"PCS">>, <<>>, <<"vcard-temp">>} -> true; + {<<"ISDN">>, <<"vcard-temp">>, _} -> true; + {<<"ISDN">>, <<>>, <<"vcard-temp">>} -> true; + {<<"MODEM">>, <<"vcard-temp">>, _} -> true; + {<<"MODEM">>, <<>>, <<"vcard-temp">>} -> true; + {<<"BBS">>, <<"vcard-temp">>, _} -> true; + {<<"BBS">>, <<>>, <<"vcard-temp">>} -> true; + {<<"VIDEO">>, <<"vcard-temp">>, _} -> true; + {<<"VIDEO">>, <<>>, <<"vcard-temp">>} -> true; + {<<"CELL">>, <<"vcard-temp">>, _} -> true; + {<<"CELL">>, <<>>, <<"vcard-temp">>} -> true; + {<<"MSG">>, <<"vcard-temp">>, _} -> true; + {<<"MSG">>, <<>>, <<"vcard-temp">>} -> true; + {<<"PAGER">>, <<"vcard-temp">>, _} -> true; + {<<"PAGER">>, <<>>, <<"vcard-temp">>} -> true; + {<<"FAX">>, <<"vcard-temp">>, _} -> true; + {<<"FAX">>, <<>>, <<"vcard-temp">>} -> true; + {<<"VOICE">>, <<"vcard-temp">>, _} -> true; + {<<"VOICE">>, <<>>, <<"vcard-temp">>} -> true; + {<<"WORK">>, <<"vcard-temp">>, _} -> true; + {<<"WORK">>, <<>>, <<"vcard-temp">>} -> true; + {<<"HOME">>, <<"vcard-temp">>, _} -> true; + {<<"HOME">>, <<>>, <<"vcard-temp">>} -> true; + {<<"stream:error">>, <<"jabber:client">>, _} -> true; + {<<"stream:error">>, <<>>, <<"jabber:client">>} -> true; + {<<"stream:error">>, <<"jabber:server">>, _} -> true; + {<<"stream:error">>, <<>>, <<"jabber:server">>} -> true; + {<<"stream:error">>, <<"jabber:component:accept">>, + _} -> + true; + {<<"stream:error">>, <<>>, + <<"jabber:component:accept">>} -> true; {<<"unsupported-version">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + true; + {<<"unsupported-version">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; {<<"unsupported-stanza-type">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + true; + {<<"unsupported-stanza-type">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; {<<"unsupported-encoding">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + true; + {<<"unsupported-encoding">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; {<<"undefined-condition">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + true; + {<<"undefined-condition">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; {<<"system-shutdown">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + true; + {<<"system-shutdown">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; {<<"see-other-host">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + true; + {<<"see-other-host">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; {<<"restricted-xml">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + true; + {<<"restricted-xml">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; {<<"resource-constraint">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + true; + {<<"resource-constraint">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; - {<<"reset">>, + {<<"reset">>, <<"urn:ietf:params:xml:ns:xmpp-streams">>, + _} -> + true; + {<<"reset">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; {<<"remote-connection-failed">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + true; + {<<"remote-connection-failed">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; {<<"policy-violation">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + true; + {<<"policy-violation">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; {<<"not-well-formed">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + true; + {<<"not-well-formed">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; {<<"not-authorized">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + true; + {<<"not-authorized">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; {<<"invalid-xml">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + true; + {<<"invalid-xml">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; {<<"invalid-namespace">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + true; + {<<"invalid-namespace">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; {<<"invalid-id">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + true; + {<<"invalid-id">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; {<<"invalid-from">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + true; + {<<"invalid-from">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; {<<"internal-server-error">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + true; + {<<"internal-server-error">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; {<<"improper-addressing">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + true; + {<<"improper-addressing">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; {<<"host-unknown">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + true; + {<<"host-unknown">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; {<<"host-gone">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + true; + {<<"host-gone">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; {<<"connection-timeout">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + true; + {<<"connection-timeout">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; {<<"conflict">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + true; + {<<"conflict">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; {<<"bad-namespace-prefix">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + true; + {<<"bad-namespace-prefix">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; {<<"bad-format">>, + <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> + true; + {<<"bad-format">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; - {<<"text">>, + {<<"text">>, <<"urn:ietf:params:xml:ns:xmpp-streams">>, + _} -> + true; + {<<"text">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> true; - {<<"time">>, <<"urn:xmpp:time">>} -> true; - {<<"tzo">>, <<"urn:xmpp:time">>} -> true; - {<<"utc">>, <<"urn:xmpp:time">>} -> true; - {<<"ping">>, <<"urn:xmpp:ping">>} -> true; + {<<"time">>, <<"urn:xmpp:time">>, _} -> true; + {<<"time">>, <<>>, <<"urn:xmpp:time">>} -> true; + {<<"tzo">>, <<"urn:xmpp:time">>, _} -> true; + {<<"tzo">>, <<>>, <<"urn:xmpp:time">>} -> true; + {<<"utc">>, <<"urn:xmpp:time">>, _} -> true; + {<<"utc">>, <<>>, <<"urn:xmpp:time">>} -> true; + {<<"ping">>, <<"urn:xmpp:ping">>, _} -> true; + {<<"ping">>, <<>>, <<"urn:xmpp:ping">>} -> true; {<<"session">>, + <<"urn:ietf:params:xml:ns:xmpp-session">>, _} -> + true; + {<<"session">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-session">>} -> true; {<<"optional">>, + <<"urn:ietf:params:xml:ns:xmpp-session">>, _} -> + true; + {<<"optional">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-session">>} -> true; - {<<"query">>, <<"jabber:iq:register">>} -> true; - {<<"key">>, <<"jabber:iq:register">>} -> true; - {<<"text">>, <<"jabber:iq:register">>} -> true; - {<<"misc">>, <<"jabber:iq:register">>} -> true; - {<<"date">>, <<"jabber:iq:register">>} -> true; - {<<"url">>, <<"jabber:iq:register">>} -> true; - {<<"phone">>, <<"jabber:iq:register">>} -> true; - {<<"zip">>, <<"jabber:iq:register">>} -> true; - {<<"state">>, <<"jabber:iq:register">>} -> true; - {<<"city">>, <<"jabber:iq:register">>} -> true; - {<<"address">>, <<"jabber:iq:register">>} -> true; - {<<"email">>, <<"jabber:iq:register">>} -> true; - {<<"last">>, <<"jabber:iq:register">>} -> true; - {<<"first">>, <<"jabber:iq:register">>} -> true; - {<<"name">>, <<"jabber:iq:register">>} -> true; - {<<"password">>, <<"jabber:iq:register">>} -> true; - {<<"nick">>, <<"jabber:iq:register">>} -> true; - {<<"username">>, <<"jabber:iq:register">>} -> true; - {<<"instructions">>, <<"jabber:iq:register">>} -> true; - {<<"remove">>, <<"jabber:iq:register">>} -> true; - {<<"registered">>, <<"jabber:iq:register">>} -> true; + {<<"query">>, <<"jabber:iq:register">>, _} -> true; + {<<"query">>, <<>>, <<"jabber:iq:register">>} -> true; + {<<"key">>, <<"jabber:iq:register">>, _} -> true; + {<<"key">>, <<>>, <<"jabber:iq:register">>} -> true; + {<<"text">>, <<"jabber:iq:register">>, _} -> true; + {<<"text">>, <<>>, <<"jabber:iq:register">>} -> true; + {<<"misc">>, <<"jabber:iq:register">>, _} -> true; + {<<"misc">>, <<>>, <<"jabber:iq:register">>} -> true; + {<<"date">>, <<"jabber:iq:register">>, _} -> true; + {<<"date">>, <<>>, <<"jabber:iq:register">>} -> true; + {<<"url">>, <<"jabber:iq:register">>, _} -> true; + {<<"url">>, <<>>, <<"jabber:iq:register">>} -> true; + {<<"phone">>, <<"jabber:iq:register">>, _} -> true; + {<<"phone">>, <<>>, <<"jabber:iq:register">>} -> true; + {<<"zip">>, <<"jabber:iq:register">>, _} -> true; + {<<"zip">>, <<>>, <<"jabber:iq:register">>} -> true; + {<<"state">>, <<"jabber:iq:register">>, _} -> true; + {<<"state">>, <<>>, <<"jabber:iq:register">>} -> true; + {<<"city">>, <<"jabber:iq:register">>, _} -> true; + {<<"city">>, <<>>, <<"jabber:iq:register">>} -> true; + {<<"address">>, <<"jabber:iq:register">>, _} -> true; + {<<"address">>, <<>>, <<"jabber:iq:register">>} -> true; + {<<"email">>, <<"jabber:iq:register">>, _} -> true; + {<<"email">>, <<>>, <<"jabber:iq:register">>} -> true; + {<<"last">>, <<"jabber:iq:register">>, _} -> true; + {<<"last">>, <<>>, <<"jabber:iq:register">>} -> true; + {<<"first">>, <<"jabber:iq:register">>, _} -> true; + {<<"first">>, <<>>, <<"jabber:iq:register">>} -> true; + {<<"name">>, <<"jabber:iq:register">>, _} -> true; + {<<"name">>, <<>>, <<"jabber:iq:register">>} -> true; + {<<"password">>, <<"jabber:iq:register">>, _} -> true; + {<<"password">>, <<>>, <<"jabber:iq:register">>} -> + true; + {<<"nick">>, <<"jabber:iq:register">>, _} -> true; + {<<"nick">>, <<>>, <<"jabber:iq:register">>} -> true; + {<<"username">>, <<"jabber:iq:register">>, _} -> true; + {<<"username">>, <<>>, <<"jabber:iq:register">>} -> + true; + {<<"instructions">>, <<"jabber:iq:register">>, _} -> + true; + {<<"instructions">>, <<>>, <<"jabber:iq:register">>} -> + true; + {<<"remove">>, <<"jabber:iq:register">>, _} -> true; + {<<"remove">>, <<>>, <<"jabber:iq:register">>} -> true; + {<<"registered">>, <<"jabber:iq:register">>, _} -> true; + {<<"registered">>, <<>>, <<"jabber:iq:register">>} -> + true; {<<"register">>, + <<"http://jabber.org/features/iq-register">>, _} -> + true; + {<<"register">>, <<>>, <<"http://jabber.org/features/iq-register">>} -> true; - {<<"c">>, <<"http://jabber.org/protocol/caps">>} -> + {<<"c">>, <<"http://jabber.org/protocol/caps">>, _} -> true; - {<<"ack">>, <<"p1:ack">>} -> true; - {<<"rebind">>, <<"p1:rebind">>} -> true; - {<<"push">>, <<"p1:push">>} -> true; - {<<"stream:features">>, - <<"http://etherx.jabber.org/streams">>} -> + {<<"c">>, <<>>, + <<"http://jabber.org/protocol/caps">>} -> + true; + {<<"ack">>, <<"p1:ack">>, _} -> true; + {<<"ack">>, <<>>, <<"p1:ack">>} -> true; + {<<"rebind">>, <<"p1:rebind">>, _} -> true; + {<<"rebind">>, <<>>, <<"p1:rebind">>} -> true; + {<<"push">>, <<"p1:push">>, _} -> true; + {<<"push">>, <<>>, <<"p1:push">>} -> true; + {<<"stream:features">>, <<"jabber:client">>, _} -> true; + {<<"stream:features">>, <<>>, <<"jabber:client">>} -> + true; + {<<"stream:features">>, <<"jabber:server">>, _} -> true; + {<<"stream:features">>, <<>>, <<"jabber:server">>} -> true; {<<"compression">>, + <<"http://jabber.org/features/compress">>, _} -> + true; + {<<"compression">>, <<>>, <<"http://jabber.org/features/compress">>} -> true; {<<"method">>, + <<"http://jabber.org/features/compress">>, _} -> + true; + {<<"method">>, <<>>, <<"http://jabber.org/features/compress">>} -> true; {<<"compressed">>, + <<"http://jabber.org/protocol/compress">>, _} -> + true; + {<<"compressed">>, <<>>, <<"http://jabber.org/protocol/compress">>} -> true; {<<"compress">>, + <<"http://jabber.org/protocol/compress">>, _} -> + true; + {<<"compress">>, <<>>, <<"http://jabber.org/protocol/compress">>} -> true; {<<"method">>, + <<"http://jabber.org/protocol/compress">>, _} -> + true; + {<<"method">>, <<>>, <<"http://jabber.org/protocol/compress">>} -> true; {<<"failure">>, + <<"http://jabber.org/protocol/compress">>, _} -> + true; + {<<"failure">>, <<>>, <<"http://jabber.org/protocol/compress">>} -> true; {<<"unsupported-method">>, + <<"http://jabber.org/protocol/compress">>, _} -> + true; + {<<"unsupported-method">>, <<>>, <<"http://jabber.org/protocol/compress">>} -> true; {<<"processing-failed">>, + <<"http://jabber.org/protocol/compress">>, _} -> + true; + {<<"processing-failed">>, <<>>, <<"http://jabber.org/protocol/compress">>} -> true; {<<"setup-failed">>, + <<"http://jabber.org/protocol/compress">>, _} -> + true; + {<<"setup-failed">>, <<>>, <<"http://jabber.org/protocol/compress">>} -> true; - {<<"failure">>, + {<<"failure">>, <<"urn:ietf:params:xml:ns:xmpp-tls">>, + _} -> + true; + {<<"failure">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-tls">>} -> true; - {<<"proceed">>, + {<<"proceed">>, <<"urn:ietf:params:xml:ns:xmpp-tls">>, + _} -> + true; + {<<"proceed">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-tls">>} -> true; - {<<"starttls">>, + {<<"starttls">>, <<"urn:ietf:params:xml:ns:xmpp-tls">>, + _} -> + true; + {<<"starttls">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-tls">>} -> true; - {<<"required">>, + {<<"required">>, <<"urn:ietf:params:xml:ns:xmpp-tls">>, + _} -> + true; + {<<"required">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-tls">>} -> true; {<<"mechanisms">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + true; + {<<"mechanisms">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> true; {<<"mechanism">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + true; + {<<"mechanism">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> true; - {<<"failure">>, + {<<"failure">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, + _} -> + true; + {<<"failure">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> true; {<<"temporary-auth-failure">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + true; + {<<"temporary-auth-failure">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> true; {<<"bad-protocol">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + true; + {<<"bad-protocol">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> true; {<<"not-authorized">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + true; + {<<"not-authorized">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> true; {<<"mechanism-too-weak">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + true; + {<<"mechanism-too-weak">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> true; {<<"malformed-request">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + true; + {<<"malformed-request">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> true; {<<"invalid-mechanism">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + true; + {<<"invalid-mechanism">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> true; {<<"invalid-authzid">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + true; + {<<"invalid-authzid">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> true; {<<"incorrect-encoding">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + true; + {<<"incorrect-encoding">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> true; {<<"encryption-required">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + true; + {<<"encryption-required">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> true; {<<"credentials-expired">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + true; + {<<"credentials-expired">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> true; {<<"account-disabled">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + true; + {<<"account-disabled">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> true; - {<<"aborted">>, + {<<"aborted">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, + _} -> + true; + {<<"aborted">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> true; - {<<"text">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> + {<<"text">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, + _} -> true; - {<<"success">>, + {<<"text">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> true; - {<<"response">>, + {<<"success">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, + _} -> + true; + {<<"success">>, <<>>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> + true; + {<<"response">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, + _} -> + true; + {<<"response">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> true; {<<"challenge">>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> + true; + {<<"challenge">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> true; - {<<"abort">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> + {<<"abort">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, + _} -> true; - {<<"auth">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> + {<<"abort">>, <<>>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> true; - {<<"query">>, <<"jabber:iq:auth">>} -> true; - {<<"resource">>, <<"jabber:iq:auth">>} -> true; - {<<"digest">>, <<"jabber:iq:auth">>} -> true; - {<<"password">>, <<"jabber:iq:auth">>} -> true; - {<<"username">>, <<"jabber:iq:auth">>} -> true; - {<<"bind">>, <<"urn:ietf:params:xml:ns:xmpp-bind">>} -> + {<<"auth">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, + _} -> true; - {<<"resource">>, + {<<"auth">>, <<>>, + <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> + true; + {<<"query">>, <<"jabber:iq:auth">>, _} -> true; + {<<"query">>, <<>>, <<"jabber:iq:auth">>} -> true; + {<<"resource">>, <<"jabber:iq:auth">>, _} -> true; + {<<"resource">>, <<>>, <<"jabber:iq:auth">>} -> true; + {<<"digest">>, <<"jabber:iq:auth">>, _} -> true; + {<<"digest">>, <<>>, <<"jabber:iq:auth">>} -> true; + {<<"password">>, <<"jabber:iq:auth">>, _} -> true; + {<<"password">>, <<>>, <<"jabber:iq:auth">>} -> true; + {<<"username">>, <<"jabber:iq:auth">>, _} -> true; + {<<"username">>, <<>>, <<"jabber:iq:auth">>} -> true; + {<<"bind">>, <<"urn:ietf:params:xml:ns:xmpp-bind">>, + _} -> + true; + {<<"bind">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-bind">>} -> true; - {<<"jid">>, <<"urn:ietf:params:xml:ns:xmpp-bind">>} -> + {<<"resource">>, <<"urn:ietf:params:xml:ns:xmpp-bind">>, + _} -> true; - {<<"error">>, <<"jabber:client">>} -> true; - {<<"text">>, + {<<"resource">>, <<>>, + <<"urn:ietf:params:xml:ns:xmpp-bind">>} -> + true; + {<<"jid">>, <<"urn:ietf:params:xml:ns:xmpp-bind">>, + _} -> + true; + {<<"jid">>, <<>>, + <<"urn:ietf:params:xml:ns:xmpp-bind">>} -> + true; + {<<"error">>, <<"jabber:client">>, _} -> true; + {<<"error">>, <<>>, <<"jabber:client">>} -> true; + {<<"error">>, <<"jabber:server">>, _} -> true; + {<<"error">>, <<>>, <<"jabber:server">>} -> true; + {<<"error">>, <<"jabber:component:accept">>, _} -> true; + {<<"error">>, <<>>, <<"jabber:component:accept">>} -> + true; + {<<"text">>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + _} -> + true; + {<<"text">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; {<<"unexpected-request">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + true; + {<<"unexpected-request">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; {<<"undefined-condition">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + true; + {<<"undefined-condition">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; {<<"subscription-required">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + true; + {<<"subscription-required">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; {<<"service-unavailable">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + true; + {<<"service-unavailable">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; {<<"resource-constraint">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + true; + {<<"resource-constraint">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; {<<"remote-server-timeout">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + true; + {<<"remote-server-timeout">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; {<<"remote-server-not-found">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + true; + {<<"remote-server-not-found">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; {<<"registration-required">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + true; + {<<"registration-required">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; {<<"redirect">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + true; + {<<"redirect">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; {<<"recipient-unavailable">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + true; + {<<"recipient-unavailable">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; {<<"policy-violation">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + true; + {<<"policy-violation">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; {<<"payment-required">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + true; + {<<"payment-required">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; {<<"not-authorized">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + true; + {<<"not-authorized">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; {<<"not-allowed">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + true; + {<<"not-allowed">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; {<<"not-acceptable">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + true; + {<<"not-acceptable">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; {<<"jid-malformed">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + true; + {<<"jid-malformed">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; {<<"item-not-found">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + true; + {<<"item-not-found">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; {<<"internal-server-error">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + true; + {<<"internal-server-error">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; - {<<"gone">>, + {<<"gone">>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + _} -> + true; + {<<"gone">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; {<<"forbidden">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + true; + {<<"forbidden">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; {<<"feature-not-implemented">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + true; + {<<"feature-not-implemented">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; {<<"conflict">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + true; + {<<"conflict">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; {<<"bad-request">>, + <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> + true; + {<<"bad-request">>, <<>>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> true; - {<<"presence">>, <<"jabber:client">>} -> true; - {<<"priority">>, <<"jabber:client">>} -> true; - {<<"status">>, <<"jabber:client">>} -> true; - {<<"show">>, <<"jabber:client">>} -> true; - {<<"message">>, <<"jabber:client">>} -> true; - {<<"thread">>, <<"jabber:client">>} -> true; - {<<"body">>, <<"jabber:client">>} -> true; - {<<"subject">>, <<"jabber:client">>} -> true; - {<<"iq">>, <<"jabber:client">>} -> true; - {<<"query">>, <<"http://jabber.org/protocol/stats">>} -> + {<<"presence">>, <<"jabber:client">>, _} -> true; + {<<"presence">>, <<>>, <<"jabber:client">>} -> true; + {<<"presence">>, <<"jabber:server">>, _} -> true; + {<<"presence">>, <<>>, <<"jabber:server">>} -> true; + {<<"presence">>, <<"jabber:component:accept">>, _} -> true; - {<<"stat">>, <<"http://jabber.org/protocol/stats">>} -> + {<<"presence">>, <<>>, <<"jabber:component:accept">>} -> true; - {<<"error">>, <<"http://jabber.org/protocol/stats">>} -> + {<<"priority">>, <<"jabber:client">>, _} -> true; + {<<"priority">>, <<>>, <<"jabber:client">>} -> true; + {<<"priority">>, <<"jabber:server">>, _} -> true; + {<<"priority">>, <<>>, <<"jabber:server">>} -> true; + {<<"priority">>, <<"jabber:component:accept">>, _} -> true; - {<<"storage">>, <<"storage:bookmarks">>} -> true; - {<<"url">>, <<"storage:bookmarks">>} -> true; - {<<"conference">>, <<"storage:bookmarks">>} -> true; - {<<"password">>, <<"storage:bookmarks">>} -> true; - {<<"nick">>, <<"storage:bookmarks">>} -> true; - {<<"query">>, <<"jabber:iq:private">>} -> true; + {<<"priority">>, <<>>, <<"jabber:component:accept">>} -> + true; + {<<"status">>, <<"jabber:client">>, _} -> true; + {<<"status">>, <<>>, <<"jabber:client">>} -> true; + {<<"status">>, <<"jabber:server">>, _} -> true; + {<<"status">>, <<>>, <<"jabber:server">>} -> true; + {<<"status">>, <<"jabber:component:accept">>, _} -> + true; + {<<"status">>, <<>>, <<"jabber:component:accept">>} -> + true; + {<<"show">>, <<"jabber:client">>, _} -> true; + {<<"show">>, <<>>, <<"jabber:client">>} -> true; + {<<"show">>, <<"jabber:server">>, _} -> true; + {<<"show">>, <<>>, <<"jabber:server">>} -> true; + {<<"show">>, <<"jabber:component:accept">>, _} -> true; + {<<"show">>, <<>>, <<"jabber:component:accept">>} -> + true; + {<<"message">>, <<"jabber:client">>, _} -> true; + {<<"message">>, <<>>, <<"jabber:client">>} -> true; + {<<"message">>, <<"jabber:server">>, _} -> true; + {<<"message">>, <<>>, <<"jabber:server">>} -> true; + {<<"message">>, <<"jabber:component:accept">>, _} -> + true; + {<<"message">>, <<>>, <<"jabber:component:accept">>} -> + true; + {<<"thread">>, <<"jabber:client">>, _} -> true; + {<<"thread">>, <<>>, <<"jabber:client">>} -> true; + {<<"thread">>, <<"jabber:server">>, _} -> true; + {<<"thread">>, <<>>, <<"jabber:server">>} -> true; + {<<"thread">>, <<"jabber:component:accept">>, _} -> + true; + {<<"thread">>, <<>>, <<"jabber:component:accept">>} -> + true; + {<<"body">>, <<"jabber:client">>, _} -> true; + {<<"body">>, <<>>, <<"jabber:client">>} -> true; + {<<"body">>, <<"jabber:server">>, _} -> true; + {<<"body">>, <<>>, <<"jabber:server">>} -> true; + {<<"body">>, <<"jabber:component:accept">>, _} -> true; + {<<"body">>, <<>>, <<"jabber:component:accept">>} -> + true; + {<<"subject">>, <<"jabber:client">>, _} -> true; + {<<"subject">>, <<>>, <<"jabber:client">>} -> true; + {<<"subject">>, <<"jabber:server">>, _} -> true; + {<<"subject">>, <<>>, <<"jabber:server">>} -> true; + {<<"subject">>, <<"jabber:component:accept">>, _} -> + true; + {<<"subject">>, <<>>, <<"jabber:component:accept">>} -> + true; + {<<"iq">>, <<"jabber:client">>, _} -> true; + {<<"iq">>, <<>>, <<"jabber:client">>} -> true; + {<<"iq">>, <<"jabber:server">>, _} -> true; + {<<"iq">>, <<>>, <<"jabber:server">>} -> true; + {<<"iq">>, <<"jabber:component:accept">>, _} -> true; + {<<"iq">>, <<>>, <<"jabber:component:accept">>} -> true; + {<<"query">>, <<"http://jabber.org/protocol/stats">>, + _} -> + true; + {<<"query">>, <<>>, + <<"http://jabber.org/protocol/stats">>} -> + true; + {<<"stat">>, <<"http://jabber.org/protocol/stats">>, + _} -> + true; + {<<"stat">>, <<>>, + <<"http://jabber.org/protocol/stats">>} -> + true; + {<<"error">>, <<"http://jabber.org/protocol/stats">>, + _} -> + true; + {<<"error">>, <<>>, + <<"http://jabber.org/protocol/stats">>} -> + true; + {<<"storage">>, <<"storage:bookmarks">>, _} -> true; + {<<"storage">>, <<>>, <<"storage:bookmarks">>} -> true; + {<<"url">>, <<"storage:bookmarks">>, _} -> true; + {<<"url">>, <<>>, <<"storage:bookmarks">>} -> true; + {<<"conference">>, <<"storage:bookmarks">>, _} -> true; + {<<"conference">>, <<>>, <<"storage:bookmarks">>} -> + true; + {<<"password">>, <<"storage:bookmarks">>, _} -> true; + {<<"password">>, <<>>, <<"storage:bookmarks">>} -> true; + {<<"nick">>, <<"storage:bookmarks">>, _} -> true; + {<<"nick">>, <<>>, <<"storage:bookmarks">>} -> true; + {<<"query">>, <<"jabber:iq:private">>, _} -> true; + {<<"query">>, <<>>, <<"jabber:iq:private">>} -> true; {<<"query">>, + <<"http://jabber.org/protocol/disco#items">>, _} -> + true; + {<<"query">>, <<>>, <<"http://jabber.org/protocol/disco#items">>} -> true; {<<"item">>, + <<"http://jabber.org/protocol/disco#items">>, _} -> + true; + {<<"item">>, <<>>, <<"http://jabber.org/protocol/disco#items">>} -> true; {<<"query">>, + <<"http://jabber.org/protocol/disco#info">>, _} -> + true; + {<<"query">>, <<>>, <<"http://jabber.org/protocol/disco#info">>} -> true; {<<"feature">>, + <<"http://jabber.org/protocol/disco#info">>, _} -> + true; + {<<"feature">>, <<>>, <<"http://jabber.org/protocol/disco#info">>} -> true; {<<"identity">>, + <<"http://jabber.org/protocol/disco#info">>, _} -> + true; + {<<"identity">>, <<>>, <<"http://jabber.org/protocol/disco#info">>} -> true; - {<<"blocklist">>, <<"urn:xmpp:blocking">>} -> true; - {<<"unblock">>, <<"urn:xmpp:blocking">>} -> true; - {<<"block">>, <<"urn:xmpp:blocking">>} -> true; - {<<"item">>, <<"urn:xmpp:blocking">>} -> true; - {<<"query">>, <<"jabber:iq:privacy">>} -> true; - {<<"active">>, <<"jabber:iq:privacy">>} -> true; - {<<"default">>, <<"jabber:iq:privacy">>} -> true; - {<<"list">>, <<"jabber:iq:privacy">>} -> true; - {<<"item">>, <<"jabber:iq:privacy">>} -> true; - {<<"presence-out">>, <<"jabber:iq:privacy">>} -> true; - {<<"presence-in">>, <<"jabber:iq:privacy">>} -> true; - {<<"iq">>, <<"jabber:iq:privacy">>} -> true; - {<<"message">>, <<"jabber:iq:privacy">>} -> true; - {<<"ver">>, <<"urn:xmpp:features:rosterver">>} -> true; - {<<"query">>, <<"jabber:iq:roster">>} -> true; - {<<"item">>, <<"jabber:iq:roster">>} -> true; - {<<"group">>, <<"jabber:iq:roster">>} -> true; - {<<"query">>, <<"jabber:iq:version">>} -> true; - {<<"os">>, <<"jabber:iq:version">>} -> true; - {<<"version">>, <<"jabber:iq:version">>} -> true; - {<<"name">>, <<"jabber:iq:version">>} -> true; - {<<"query">>, <<"jabber:iq:last">>} -> true; + {<<"blocklist">>, <<"urn:xmpp:blocking">>, _} -> true; + {<<"blocklist">>, <<>>, <<"urn:xmpp:blocking">>} -> + true; + {<<"unblock">>, <<"urn:xmpp:blocking">>, _} -> true; + {<<"unblock">>, <<>>, <<"urn:xmpp:blocking">>} -> true; + {<<"block">>, <<"urn:xmpp:blocking">>, _} -> true; + {<<"block">>, <<>>, <<"urn:xmpp:blocking">>} -> true; + {<<"item">>, <<"urn:xmpp:blocking">>, _} -> true; + {<<"item">>, <<>>, <<"urn:xmpp:blocking">>} -> true; + {<<"query">>, <<"jabber:iq:privacy">>, _} -> true; + {<<"query">>, <<>>, <<"jabber:iq:privacy">>} -> true; + {<<"active">>, <<"jabber:iq:privacy">>, _} -> true; + {<<"active">>, <<>>, <<"jabber:iq:privacy">>} -> true; + {<<"default">>, <<"jabber:iq:privacy">>, _} -> true; + {<<"default">>, <<>>, <<"jabber:iq:privacy">>} -> true; + {<<"list">>, <<"jabber:iq:privacy">>, _} -> true; + {<<"list">>, <<>>, <<"jabber:iq:privacy">>} -> true; + {<<"item">>, <<"jabber:iq:privacy">>, _} -> true; + {<<"item">>, <<>>, <<"jabber:iq:privacy">>} -> true; + {<<"presence-out">>, <<"jabber:iq:privacy">>, _} -> + true; + {<<"presence-out">>, <<>>, <<"jabber:iq:privacy">>} -> + true; + {<<"presence-in">>, <<"jabber:iq:privacy">>, _} -> true; + {<<"presence-in">>, <<>>, <<"jabber:iq:privacy">>} -> + true; + {<<"iq">>, <<"jabber:iq:privacy">>, _} -> true; + {<<"iq">>, <<>>, <<"jabber:iq:privacy">>} -> true; + {<<"message">>, <<"jabber:iq:privacy">>, _} -> true; + {<<"message">>, <<>>, <<"jabber:iq:privacy">>} -> true; + {<<"ver">>, <<"urn:xmpp:features:rosterver">>, _} -> + true; + {<<"ver">>, <<>>, <<"urn:xmpp:features:rosterver">>} -> + true; + {<<"query">>, <<"jabber:iq:roster">>, _} -> true; + {<<"query">>, <<>>, <<"jabber:iq:roster">>} -> true; + {<<"item">>, <<"jabber:iq:roster">>, _} -> true; + {<<"item">>, <<>>, <<"jabber:iq:roster">>} -> true; + {<<"group">>, <<"jabber:iq:roster">>, _} -> true; + {<<"group">>, <<>>, <<"jabber:iq:roster">>} -> true; + {<<"query">>, <<"jabber:iq:version">>, _} -> true; + {<<"query">>, <<>>, <<"jabber:iq:version">>} -> true; + {<<"os">>, <<"jabber:iq:version">>, _} -> true; + {<<"os">>, <<>>, <<"jabber:iq:version">>} -> true; + {<<"version">>, <<"jabber:iq:version">>, _} -> true; + {<<"version">>, <<>>, <<"jabber:iq:version">>} -> true; + {<<"name">>, <<"jabber:iq:version">>, _} -> true; + {<<"name">>, <<>>, <<"jabber:iq:version">>} -> true; + {<<"query">>, <<"jabber:iq:last">>, _} -> true; + {<<"query">>, <<>>, <<"jabber:iq:last">>} -> true; _ -> false end. -encode({xmlel, _, _, _} = El) -> El; -encode({last, _, _} = Query) -> - encode_last(Query, - [{<<"xmlns">>, <<"jabber:iq:last">>}]); -encode({version, _, _, _} = Query) -> - encode_version(Query, - [{<<"xmlns">>, <<"jabber:iq:version">>}]); -encode({roster_item, _, _, _, _, _} = Item) -> - encode_roster_item(Item, - [{<<"xmlns">>, <<"jabber:iq:roster">>}]); -encode({roster_query, _, _} = Query) -> - encode_roster_query(Query, - [{<<"xmlns">>, <<"jabber:iq:roster">>}]); -encode({rosterver_feature} = Ver) -> - encode_rosterver_feature(Ver, - [{<<"xmlns">>, - <<"urn:xmpp:features:rosterver">>}]); -encode({privacy_item, _, _, _, _, _, _, _, _} = Item) -> - encode_privacy_item(Item, - [{<<"xmlns">>, <<"jabber:iq:privacy">>}]); -encode({privacy_list, _, _} = List) -> - encode_privacy_list(List, - [{<<"xmlns">>, <<"jabber:iq:privacy">>}]); -encode({privacy_query, _, _, _} = Query) -> - encode_privacy(Query, - [{<<"xmlns">>, <<"jabber:iq:privacy">>}]); -encode({block, _} = Block) -> - encode_block(Block, - [{<<"xmlns">>, <<"urn:xmpp:blocking">>}]); -encode({unblock, _} = Unblock) -> - encode_unblock(Unblock, - [{<<"xmlns">>, <<"urn:xmpp:blocking">>}]); -encode({block_list, _} = Blocklist) -> - encode_block_list(Blocklist, - [{<<"xmlns">>, <<"urn:xmpp:blocking">>}]); -encode({identity, _, _, _, _} = Identity) -> - encode_disco_identity(Identity, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/disco#info">>}]); -encode({disco_info, _, _, _, _} = Query) -> - encode_disco_info(Query, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/disco#info">>}]); -encode({disco_item, _, _, _} = Item) -> - encode_disco_item(Item, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/disco#items">>}]); -encode({disco_items, _, _, _} = Query) -> - encode_disco_items(Query, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/disco#items">>}]); -encode({private, _} = Query) -> - encode_private(Query, - [{<<"xmlns">>, <<"jabber:iq:private">>}]); +encode(_el) -> encode(_el, <<>>). + +encode({xmlel, _, _, _} = El, _) -> El; +encode({last, _, _} = Query, TopXMLNS) -> + encode_last(Query, TopXMLNS); +encode({version, _, _, _} = Query, TopXMLNS) -> + encode_version(Query, TopXMLNS); +encode({roster_item, _, _, _, _, _} = Item, TopXMLNS) -> + encode_roster_item(Item, TopXMLNS); +encode({roster_query, _, _} = Query, TopXMLNS) -> + encode_roster_query(Query, TopXMLNS); +encode({rosterver_feature} = Ver, TopXMLNS) -> + encode_rosterver_feature(Ver, TopXMLNS); +encode({privacy_item, _, _, _, _, _, _, _, _} = Item, + TopXMLNS) -> + encode_privacy_item(Item, TopXMLNS); +encode({privacy_list, _, _} = List, TopXMLNS) -> + encode_privacy_list(List, TopXMLNS); +encode({privacy_query, _, _, _} = Query, TopXMLNS) -> + encode_privacy(Query, TopXMLNS); +encode({block, _} = Block, TopXMLNS) -> + encode_block(Block, TopXMLNS); +encode({unblock, _} = Unblock, TopXMLNS) -> + encode_unblock(Unblock, TopXMLNS); +encode({block_list, _} = Blocklist, TopXMLNS) -> + encode_block_list(Blocklist, TopXMLNS); +encode({identity, _, _, _, _} = Identity, TopXMLNS) -> + encode_disco_identity(Identity, TopXMLNS); +encode({disco_info, _, _, _, _} = Query, TopXMLNS) -> + encode_disco_info(Query, TopXMLNS); +encode({disco_item, _, _, _} = Item, TopXMLNS) -> + encode_disco_item(Item, TopXMLNS); +encode({disco_items, _, _, _} = Query, TopXMLNS) -> + encode_disco_items(Query, TopXMLNS); +encode({private, _} = Query, TopXMLNS) -> + encode_private(Query, TopXMLNS); encode({bookmark_conference, _, _, _, _, _} = - Conference) -> - encode_bookmark_conference(Conference, - [{<<"xmlns">>, <<"storage:bookmarks">>}]); -encode({bookmark_url, _, _} = Url) -> - encode_bookmark_url(Url, - [{<<"xmlns">>, <<"storage:bookmarks">>}]); -encode({bookmark_storage, _, _} = Storage) -> - encode_bookmarks_storage(Storage, - [{<<"xmlns">>, <<"storage:bookmarks">>}]); -encode({stat_error, _, _} = Error) -> - encode_stat_error(Error, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/stats">>}]); -encode({stat, _, _, _, _} = Stat) -> - encode_stat(Stat, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/stats">>}]); -encode({stats, _, _} = Query) -> - encode_stats(Query, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/stats">>}]); -encode({iq, _, _, _, _, _, _} = Iq) -> - encode_iq(Iq, [{<<"xmlns">>, <<"jabber:client">>}]); -encode({message, _, _, _, _, _, _, _, _, _} = - Message) -> - encode_message(Message, - [{<<"xmlns">>, <<"jabber:client">>}]); -encode({presence, _, _, _, _, _, _, _, _, _} = - Presence) -> - encode_presence(Presence, - [{<<"xmlns">>, <<"jabber:client">>}]); -encode({gone, _} = Gone) -> - encode_error_gone(Gone, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]); -encode({redirect, _} = Redirect) -> - encode_error_redirect(Redirect, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]); -encode({stanza_error, _, _, _, _, _, _} = Error) -> - encode_error(Error, - [{<<"xmlns">>, <<"jabber:client">>}]); -encode({bind, _, _} = Bind) -> - encode_bind(Bind, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-bind">>}]); -encode({legacy_auth, _, _, _, _} = Query) -> - encode_legacy_auth(Query, - [{<<"xmlns">>, <<"jabber:iq:auth">>}]); -encode({sasl_auth, _, _} = Auth) -> - encode_sasl_auth(Auth, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>}]); -encode({sasl_abort} = Abort) -> - encode_sasl_abort(Abort, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>}]); -encode({sasl_challenge, _} = Challenge) -> - encode_sasl_challenge(Challenge, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>}]); -encode({sasl_response, _} = Response) -> - encode_sasl_response(Response, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>}]); -encode({sasl_success, _} = Success) -> - encode_sasl_success(Success, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>}]); -encode({sasl_failure, _, _} = Failure) -> - encode_sasl_failure(Failure, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>}]); -encode({sasl_mechanisms, _} = Mechanisms) -> - encode_sasl_mechanisms(Mechanisms, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>}]); -encode({starttls, _} = Starttls) -> - encode_starttls(Starttls, - [{<<"xmlns">>, <<"urn:ietf:params:xml:ns:xmpp-tls">>}]); -encode({starttls_proceed} = Proceed) -> - encode_starttls_proceed(Proceed, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-tls">>}]); -encode({starttls_failure} = Failure) -> - encode_starttls_failure(Failure, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-tls">>}]); -encode({compress_failure, _} = Failure) -> - encode_compress_failure(Failure, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/compress">>}]); -encode({compress, _} = Compress) -> - encode_compress(Compress, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/compress">>}]); -encode({compressed} = Compressed) -> - encode_compressed(Compressed, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/compress">>}]); -encode({compression, _} = Compression) -> - encode_compression(Compression, - [{<<"xmlns">>, - <<"http://jabber.org/features/compress">>}]); -encode({stream_features, _} = Stream_features) -> - encode_stream_features(Stream_features, - [{<<"xmlns">>, - <<"http://etherx.jabber.org/streams">>}]); -encode({p1_push} = Push) -> - encode_p1_push(Push, [{<<"xmlns">>, <<"p1:push">>}]); -encode({p1_rebind} = Rebind) -> - encode_p1_rebind(Rebind, - [{<<"xmlns">>, <<"p1:rebind">>}]); -encode({p1_ack} = Ack) -> - encode_p1_ack(Ack, [{<<"xmlns">>, <<"p1:ack">>}]); -encode({caps, _, _, _, _} = C) -> - encode_caps(C, - [{<<"xmlns">>, <<"http://jabber.org/protocol/caps">>}]); -encode({feature_register} = Register) -> - encode_feature_register(Register, - [{<<"xmlns">>, - <<"http://jabber.org/features/iq-register">>}]); + Conference, + TopXMLNS) -> + encode_bookmark_conference(Conference, TopXMLNS); +encode({bookmark_url, _, _} = Url, TopXMLNS) -> + encode_bookmark_url(Url, TopXMLNS); +encode({bookmark_storage, _, _} = Storage, TopXMLNS) -> + encode_bookmarks_storage(Storage, TopXMLNS); +encode({stat_error, _, _} = Error, TopXMLNS) -> + encode_stat_error(Error, TopXMLNS); +encode({stat, _, _, _, _} = Stat, TopXMLNS) -> + encode_stat(Stat, TopXMLNS); +encode({stats, _, _} = Query, TopXMLNS) -> + encode_stats(Query, TopXMLNS); +encode({iq, _, _, _, _, _, _} = Iq, TopXMLNS) -> + encode_iq(Iq, TopXMLNS); +encode({message, _, _, _, _, _, _, _, _, _} = Message, + TopXMLNS) -> + encode_message(Message, TopXMLNS); +encode({presence, _, _, _, _, _, _, _, _, _} = Presence, + TopXMLNS) -> + encode_presence(Presence, TopXMLNS); +encode({gone, _} = Gone, TopXMLNS) -> + encode_error_gone(Gone, TopXMLNS); +encode({redirect, _} = Redirect, TopXMLNS) -> + encode_error_redirect(Redirect, TopXMLNS); +encode({stanza_error, _, _, _, _, _, _} = Error, + TopXMLNS) -> + encode_error(Error, TopXMLNS); +encode({bind, _, _} = Bind, TopXMLNS) -> + encode_bind(Bind, TopXMLNS); +encode({legacy_auth, _, _, _, _} = Query, TopXMLNS) -> + encode_legacy_auth(Query, TopXMLNS); +encode({sasl_auth, _, _} = Auth, TopXMLNS) -> + encode_sasl_auth(Auth, TopXMLNS); +encode({sasl_abort} = Abort, TopXMLNS) -> + encode_sasl_abort(Abort, TopXMLNS); +encode({sasl_challenge, _} = Challenge, TopXMLNS) -> + encode_sasl_challenge(Challenge, TopXMLNS); +encode({sasl_response, _} = Response, TopXMLNS) -> + encode_sasl_response(Response, TopXMLNS); +encode({sasl_success, _} = Success, TopXMLNS) -> + encode_sasl_success(Success, TopXMLNS); +encode({sasl_failure, _, _} = Failure, TopXMLNS) -> + encode_sasl_failure(Failure, TopXMLNS); +encode({sasl_mechanisms, _} = Mechanisms, TopXMLNS) -> + encode_sasl_mechanisms(Mechanisms, TopXMLNS); +encode({starttls, _} = Starttls, TopXMLNS) -> + encode_starttls(Starttls, TopXMLNS); +encode({starttls_proceed} = Proceed, TopXMLNS) -> + encode_starttls_proceed(Proceed, TopXMLNS); +encode({starttls_failure} = Failure, TopXMLNS) -> + encode_starttls_failure(Failure, TopXMLNS); +encode({compress_failure, _} = Failure, TopXMLNS) -> + encode_compress_failure(Failure, TopXMLNS); +encode({compress, _} = Compress, TopXMLNS) -> + encode_compress(Compress, TopXMLNS); +encode({compressed} = Compressed, TopXMLNS) -> + encode_compressed(Compressed, TopXMLNS); +encode({compression, _} = Compression, TopXMLNS) -> + encode_compression(Compression, TopXMLNS); +encode({stream_features, _} = Stream_features, + TopXMLNS) -> + encode_stream_features(Stream_features, TopXMLNS); +encode({p1_push} = Push, TopXMLNS) -> + encode_p1_push(Push, TopXMLNS); +encode({p1_rebind} = Rebind, TopXMLNS) -> + encode_p1_rebind(Rebind, TopXMLNS); +encode({p1_ack} = Ack, TopXMLNS) -> + encode_p1_ack(Ack, TopXMLNS); +encode({caps, _, _, _, _} = C, TopXMLNS) -> + encode_caps(C, TopXMLNS); +encode({feature_register} = Register, TopXMLNS) -> + encode_feature_register(Register, TopXMLNS); encode({register, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _} = - Query) -> - encode_register(Query, - [{<<"xmlns">>, <<"jabber:iq:register">>}]); -encode({xmpp_session, _} = Session) -> - encode_session(Session, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-session">>}]); -encode({ping} = Ping) -> - encode_ping(Ping, [{<<"xmlns">>, <<"urn:xmpp:ping">>}]); -encode({time, _, _} = Time) -> - encode_time(Time, [{<<"xmlns">>, <<"urn:xmpp:time">>}]); -encode({text, _, _} = Text) -> - encode_stream_error_text(Text, []); -encode({'see-other-host', _} = See_other_host) -> + Query, + TopXMLNS) -> + encode_register(Query, TopXMLNS); +encode({xmpp_session, _} = Session, TopXMLNS) -> + encode_session(Session, TopXMLNS); +encode({ping} = Ping, TopXMLNS) -> + encode_ping(Ping, TopXMLNS); +encode({time, _, _} = Time, TopXMLNS) -> + encode_time(Time, TopXMLNS); +encode({text, _, _} = Text, TopXMLNS) -> + encode_stream_error_text(Text, TopXMLNS); +encode({'see-other-host', _} = See_other_host, + TopXMLNS) -> encode_stream_error_see_other_host(See_other_host, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]); -encode({stream_error, _, _} = Stream_error) -> - encode_stream_error(Stream_error, - [{<<"xmlns">>, - <<"http://etherx.jabber.org/streams">>}]); -encode({vcard_name, _, _, _, _, _} = N) -> - encode_vcard_N(N, [{<<"xmlns">>, <<"vcard-temp">>}]); + TopXMLNS); +encode({stream_error, _, _} = Stream_error, TopXMLNS) -> + encode_stream_error(Stream_error, TopXMLNS); +encode({vcard_name, _, _, _, _, _} = N, TopXMLNS) -> + encode_vcard_N(N, TopXMLNS); encode({vcard_adr, _, _, _, _, _, _, _, _, _, _, _, _, _, _} = - Adr) -> - encode_vcard_ADR(Adr, - [{<<"xmlns">>, <<"vcard-temp">>}]); -encode({vcard_label, _, _, _, _, _, _, _, _} = Label) -> - encode_vcard_LABEL(Label, - [{<<"xmlns">>, <<"vcard-temp">>}]); + Adr, + TopXMLNS) -> + encode_vcard_ADR(Adr, TopXMLNS); +encode({vcard_label, _, _, _, _, _, _, _, _} = Label, + TopXMLNS) -> + encode_vcard_LABEL(Label, TopXMLNS); encode({vcard_tel, _, _, _, _, _, _, _, _, _, _, _, _, _, _} = - Tel) -> - encode_vcard_TEL(Tel, - [{<<"xmlns">>, <<"vcard-temp">>}]); -encode({vcard_email, _, _, _, _, _, _} = Email) -> - encode_vcard_EMAIL(Email, - [{<<"xmlns">>, <<"vcard-temp">>}]); -encode({vcard_geo, _, _} = Geo) -> - encode_vcard_GEO(Geo, - [{<<"xmlns">>, <<"vcard-temp">>}]); -encode({vcard_logo, _, _, _} = Logo) -> - encode_vcard_LOGO(Logo, - [{<<"xmlns">>, <<"vcard-temp">>}]); -encode({vcard_photo, _, _, _} = Photo) -> - encode_vcard_PHOTO(Photo, - [{<<"xmlns">>, <<"vcard-temp">>}]); -encode({vcard_org, _, _} = Org) -> - encode_vcard_ORG(Org, - [{<<"xmlns">>, <<"vcard-temp">>}]); -encode({vcard_sound, _, _, _} = Sound) -> - encode_vcard_SOUND(Sound, - [{<<"xmlns">>, <<"vcard-temp">>}]); -encode({vcard_key, _, _} = Key) -> - encode_vcard_KEY(Key, - [{<<"xmlns">>, <<"vcard-temp">>}]); + Tel, + TopXMLNS) -> + encode_vcard_TEL(Tel, TopXMLNS); +encode({vcard_email, _, _, _, _, _, _} = Email, + TopXMLNS) -> + encode_vcard_EMAIL(Email, TopXMLNS); +encode({vcard_geo, _, _} = Geo, TopXMLNS) -> + encode_vcard_GEO(Geo, TopXMLNS); +encode({vcard_logo, _, _, _} = Logo, TopXMLNS) -> + encode_vcard_LOGO(Logo, TopXMLNS); +encode({vcard_photo, _, _, _} = Photo, TopXMLNS) -> + encode_vcard_PHOTO(Photo, TopXMLNS); +encode({vcard_org, _, _} = Org, TopXMLNS) -> + encode_vcard_ORG(Org, TopXMLNS); +encode({vcard_sound, _, _, _} = Sound, TopXMLNS) -> + encode_vcard_SOUND(Sound, TopXMLNS); +encode({vcard_key, _, _} = Key, TopXMLNS) -> + encode_vcard_KEY(Key, TopXMLNS); encode({vcard_temp, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _} = - Vcard) -> - encode_vcard_temp(Vcard, - [{<<"xmlns">>, <<"vcard-temp">>}]); -encode({vcard_xupdate, _, _} = X) -> - encode_vcard_xupdate(X, - [{<<"xmlns">>, <<"vcard-temp:x:update">>}]); -encode({xdata_option, _, _} = Option) -> - encode_xdata_field_option(Option, - [{<<"xmlns">>, <<"jabber:x:data">>}]); -encode({xdata_field, _, _, _, _, _, _, _, _} = Field) -> - encode_xdata_field(Field, - [{<<"xmlns">>, <<"jabber:x:data">>}]); -encode({xdata, _, _, _, _, _, _} = X) -> - encode_xdata(X, [{<<"xmlns">>, <<"jabber:x:data">>}]); + Vcard, + TopXMLNS) -> + encode_vcard_temp(Vcard, TopXMLNS); +encode({vcard_xupdate, _, _} = X, TopXMLNS) -> + encode_vcard_xupdate(X, TopXMLNS); +encode({xdata_option, _, _} = Option, TopXMLNS) -> + encode_xdata_field_option(Option, TopXMLNS); +encode({xdata_field, _, _, _, _, _, _, _, _} = Field, + TopXMLNS) -> + encode_xdata_field(Field, TopXMLNS); +encode({xdata, _, _, _, _, _, _} = X, TopXMLNS) -> + encode_xdata(X, TopXMLNS); encode({ps_subscription, _, _, _, _, _, _} = - Subscription) -> - encode_pubsub_subscription(Subscription, []); + Subscription, + TopXMLNS) -> + encode_pubsub_subscription(Subscription, TopXMLNS); encode({ps_affiliation, <<"http://jabber.org/protocol/pubsub">>, _, _, _} = - Affiliation) -> - encode_pubsub_affiliation(Affiliation, []); + Affiliation, + TopXMLNS) -> + encode_pubsub_affiliation(Affiliation, TopXMLNS); +encode({ps_affiliation, <<>>, _, _, _} = Affiliation, + TopXMLNS = <<"http://jabber.org/protocol/pubsub">>) -> + encode_pubsub_affiliation(Affiliation, TopXMLNS); encode({ps_affiliation, <<"http://jabber.org/protocol/pubsub#owner">>, _, _, _} = - Affiliation) -> - encode_pubsub_owner_affiliation(Affiliation, []); -encode({ps_item, _, _, _, _, _} = Item) -> - encode_pubsub_item(Item, []); -encode({ps_items, _, _, _, _, _, _} = Items) -> - encode_pubsub_items(Items, []); -encode({ps_event, _, _, _, _, _, _} = Event) -> - encode_pubsub_event(Event, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#event">>}]); -encode({ps_subscribe, _, _} = Subscribe) -> - encode_pubsub_subscribe(Subscribe, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub">>}]); -encode({ps_unsubscribe, _, _, _} = Unsubscribe) -> - encode_pubsub_unsubscribe(Unsubscribe, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub">>}]); -encode({ps_publish, _, _} = Publish) -> - encode_pubsub_publish(Publish, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub">>}]); -encode({ps_options, _, _, _, _} = Options) -> - encode_pubsub_options(Options, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub">>}]); -encode({ps_retract, _, _, _} = Retract) -> - encode_pubsub_retract(Retract, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub">>}]); + Affiliation, + TopXMLNS) -> + encode_pubsub_owner_affiliation(Affiliation, TopXMLNS); +encode({ps_affiliation, <<>>, _, _, _} = Affiliation, + TopXMLNS = + <<"http://jabber.org/protocol/pubsub#owner">>) -> + encode_pubsub_owner_affiliation(Affiliation, TopXMLNS); +encode({ps_item, _, _, _, _, _} = Item, TopXMLNS) -> + encode_pubsub_item(Item, TopXMLNS); +encode({ps_items, _, _, _, _, _, _} = Items, + TopXMLNS) -> + encode_pubsub_items(Items, TopXMLNS); +encode({ps_event, _, _, _, _, _, _} = Event, + TopXMLNS) -> + encode_pubsub_event(Event, TopXMLNS); +encode({ps_subscribe, _, _} = Subscribe, TopXMLNS) -> + encode_pubsub_subscribe(Subscribe, TopXMLNS); +encode({ps_unsubscribe, _, _, _} = Unsubscribe, + TopXMLNS) -> + encode_pubsub_unsubscribe(Unsubscribe, TopXMLNS); +encode({ps_publish, _, _} = Publish, TopXMLNS) -> + encode_pubsub_publish(Publish, TopXMLNS); +encode({ps_options, _, _, _, _} = Options, TopXMLNS) -> + encode_pubsub_options(Options, TopXMLNS); +encode({ps_retract, _, _, _} = Retract, TopXMLNS) -> + encode_pubsub_retract(Retract, TopXMLNS); encode({pubsub, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _} = - Pubsub) -> - encode_pubsub(Pubsub, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub">>}]); -encode({pubsub_owner, _, _, _, _, _, _} = Pubsub) -> - encode_pubsub_owner(Pubsub, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#owner">>}]); -encode({ps_error, 'closed-node', _} = Closed_node) -> - encode_pubsub_error_closed_node(Closed_node, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#errors">>}]); + Pubsub, + TopXMLNS) -> + encode_pubsub(Pubsub, TopXMLNS); +encode({pubsub_owner, _, _, _, _, _, _} = Pubsub, + TopXMLNS) -> + encode_pubsub_owner(Pubsub, TopXMLNS); +encode({ps_error, 'closed-node', _} = Closed_node, + TopXMLNS) -> + encode_pubsub_error_closed_node(Closed_node, TopXMLNS); encode({ps_error, 'configuration-required', _} = - Configuration_required) -> + Configuration_required, + TopXMLNS) -> encode_pubsub_error_configuration_required(Configuration_required, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#errors">>}]); -encode({ps_error, 'invalid-jid', _} = Invalid_jid) -> - encode_pubsub_error_invalid_jid(Invalid_jid, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#errors">>}]); + TopXMLNS); +encode({ps_error, 'invalid-jid', _} = Invalid_jid, + TopXMLNS) -> + encode_pubsub_error_invalid_jid(Invalid_jid, TopXMLNS); encode({ps_error, 'invalid-options', _} = - Invalid_options) -> + Invalid_options, + TopXMLNS) -> encode_pubsub_error_invalid_options(Invalid_options, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#errors">>}]); + TopXMLNS); encode({ps_error, 'invalid-payload', _} = - Invalid_payload) -> + Invalid_payload, + TopXMLNS) -> encode_pubsub_error_invalid_payload(Invalid_payload, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#errors">>}]); -encode({ps_error, 'invalid-subid', _} = - Invalid_subid) -> + TopXMLNS); +encode({ps_error, 'invalid-subid', _} = Invalid_subid, + TopXMLNS) -> encode_pubsub_error_invalid_subid(Invalid_subid, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#errors">>}]); -encode({ps_error, 'item-forbidden', _} = - Item_forbidden) -> + TopXMLNS); +encode({ps_error, 'item-forbidden', _} = Item_forbidden, + TopXMLNS) -> encode_pubsub_error_item_forbidden(Item_forbidden, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#errors">>}]); -encode({ps_error, 'item-required', _} = - Item_required) -> + TopXMLNS); +encode({ps_error, 'item-required', _} = Item_required, + TopXMLNS) -> encode_pubsub_error_item_required(Item_required, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#errors">>}]); -encode({ps_error, 'jid-required', _} = Jid_required) -> + TopXMLNS); +encode({ps_error, 'jid-required', _} = Jid_required, + TopXMLNS) -> encode_pubsub_error_jid_required(Jid_required, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#errors">>}]); + TopXMLNS); encode({ps_error, 'max-items-exceeded', _} = - Max_items_exceeded) -> + Max_items_exceeded, + TopXMLNS) -> encode_pubsub_error_max_items_exceeded(Max_items_exceeded, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#errors">>}]); + TopXMLNS); encode({ps_error, 'max-nodes-exceeded', _} = - Max_nodes_exceeded) -> + Max_nodes_exceeded, + TopXMLNS) -> encode_pubsub_error_max_nodes_exceeded(Max_nodes_exceeded, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#errors">>}]); + TopXMLNS); encode({ps_error, 'nodeid-required', _} = - Nodeid_required) -> + Nodeid_required, + TopXMLNS) -> encode_pubsub_error_nodeid_required(Nodeid_required, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#errors">>}]); + TopXMLNS); encode({ps_error, 'not-in-roster-group', _} = - Not_in_roster_group) -> + Not_in_roster_group, + TopXMLNS) -> encode_pubsub_error_not_in_roster_group(Not_in_roster_group, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#errors">>}]); -encode({ps_error, 'not-subscribed', _} = - Not_subscribed) -> + TopXMLNS); +encode({ps_error, 'not-subscribed', _} = Not_subscribed, + TopXMLNS) -> encode_pubsub_error_not_subscribed(Not_subscribed, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#errors">>}]); + TopXMLNS); encode({ps_error, 'payload-too-big', _} = - Payload_too_big) -> + Payload_too_big, + TopXMLNS) -> encode_pubsub_error_payload_too_big(Payload_too_big, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#errors">>}]); + TopXMLNS); encode({ps_error, 'payload-required', _} = - Payload_required) -> + Payload_required, + TopXMLNS) -> encode_pubsub_error_payload_required(Payload_required, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#errors">>}]); + TopXMLNS); encode({ps_error, 'pending-subscription', _} = - Pending_subscription) -> + Pending_subscription, + TopXMLNS) -> encode_pubsub_error_pending_subscription(Pending_subscription, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#errors">>}]); + TopXMLNS); encode({ps_error, 'presence-subscription-required', _} = - Presence_subscription_required) -> + Presence_subscription_required, + TopXMLNS) -> encode_pubsub_error_presence_subscription_required(Presence_subscription_required, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#errors">>}]); -encode({ps_error, 'subid-required', _} = - Subid_required) -> + TopXMLNS); +encode({ps_error, 'subid-required', _} = Subid_required, + TopXMLNS) -> encode_pubsub_error_subid_required(Subid_required, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#errors">>}]); + TopXMLNS); encode({ps_error, 'too-many-subscriptions', _} = - Too_many_subscriptions) -> + Too_many_subscriptions, + TopXMLNS) -> encode_pubsub_error_too_many_subscriptions(Too_many_subscriptions, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#errors">>}]); -encode({ps_error, unsupported, _} = Unsupported) -> - encode_pubsub_error_unsupported(Unsupported, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#errors">>}]); + TopXMLNS); +encode({ps_error, unsupported, _} = Unsupported, + TopXMLNS) -> + encode_pubsub_error_unsupported(Unsupported, TopXMLNS); encode({ps_error, 'unsupported-access-model', _} = - Unsupported_access_model) -> + Unsupported_access_model, + TopXMLNS) -> encode_pubsub_error_unsupported_access_model(Unsupported_access_model, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/pubsub#errors">>}]); -encode({shim, _} = Headers) -> - encode_shim_headers(Headers, - [{<<"xmlns">>, <<"http://jabber.org/protocol/shim">>}]); -encode({chatstate, active} = Active) -> - encode_chatstate_active(Active, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/chatstates">>}]); -encode({chatstate, composing} = Composing) -> - encode_chatstate_composing(Composing, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/chatstates">>}]); -encode({chatstate, gone} = Gone) -> - encode_chatstate_gone(Gone, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/chatstates">>}]); -encode({chatstate, inactive} = Inactive) -> - encode_chatstate_inactive(Inactive, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/chatstates">>}]); -encode({chatstate, paused} = Paused) -> - encode_chatstate_paused(Paused, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/chatstates">>}]); -encode({delay, _, _, _} = Delay) -> - encode_delay(Delay, - [{<<"xmlns">>, <<"urn:xmpp:delay">>}]); -encode({streamhost, _, _, _} = Streamhost) -> - encode_bytestreams_streamhost(Streamhost, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/bytestreams">>}]); -encode({bytestreams, _, _, _, _, _, _} = Query) -> - encode_bytestreams(Query, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/bytestreams">>}]); -encode({muc_history, _, _, _, _} = History) -> - encode_muc_history(History, - [{<<"xmlns">>, <<"http://jabber.org/protocol/muc">>}]); -encode({muc_decline, _, _, _} = Decline) -> - encode_muc_user_decline(Decline, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/muc#user">>}]); -encode({muc_destroy, _, _, _, _} = Destroy) -> - encode_muc_destroy(Destroy, []); -encode({muc_invite, _, _, _, _} = Invite) -> - encode_muc_user_invite(Invite, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/muc#user">>}]); -encode({muc_user, _, _, _, _, _, _} = X) -> - encode_muc_user(X, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/muc#user">>}]); -encode({muc_owner, _, _, _} = Query) -> - encode_muc_owner(Query, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/muc#owner">>}]); -encode({muc_item, _, _, _, _, _, _, _} = Item) -> - encode_muc_admin_item(Item, []); -encode({muc_actor, _, _} = Actor) -> - encode_muc_admin_actor(Actor, []); -encode({muc_admin, _} = Query) -> - encode_muc_admin(Query, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/muc#admin">>}]); -encode({muc, _, _} = X) -> - encode_muc(X, - [{<<"xmlns">>, <<"http://jabber.org/protocol/muc">>}]); -encode({muc_unique, _} = Unique) -> - encode_muc_unique(Unique, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/muc#unique">>}]); -encode({x_conference, _, _, _, _, _} = X) -> - encode_x_conference(X, - [{<<"xmlns">>, <<"jabber:x:conference">>}]); -encode({muc_subscriptions, _} = Subscriptions) -> - encode_muc_subscriptions(Subscriptions, - [{<<"xmlns">>, <<"urn:xmpp:mucsub:0">>}]); -encode({muc_subscribe, _, _} = Subscribe) -> - encode_muc_subscribe(Subscribe, - [{<<"xmlns">>, <<"urn:xmpp:mucsub:0">>}]); -encode({muc_unsubscribe} = Unsubscribe) -> - encode_muc_unsubscribe(Unsubscribe, - [{<<"xmlns">>, <<"urn:xmpp:mucsub:0">>}]); -encode({rsm_first, _, _} = First) -> - encode_rsm_first(First, - [{<<"xmlns">>, <<"http://jabber.org/protocol/rsm">>}]); -encode({rsm_set, _, _, _, _, _, _, _} = Set) -> - encode_rsm_set(Set, - [{<<"xmlns">>, <<"http://jabber.org/protocol/rsm">>}]); -encode({mam_query, _, _, _, _, _, _, _, _} = Query) -> - encode_mam_query(Query, []); -encode({mam_archived, _, _} = Archived) -> - encode_mam_archived(Archived, - [{<<"xmlns">>, <<"urn:xmpp:mam:tmp">>}]); -encode({mam_result, _, _, _, _} = Result) -> - encode_mam_result(Result, []); -encode({mam_prefs, _, _, _, _} = Prefs) -> - encode_mam_prefs(Prefs, []); -encode({mam_fin, _, _, _, _, _} = Fin) -> - encode_mam_fin(Fin, []); -encode({forwarded, _, _} = Forwarded) -> - encode_forwarded(Forwarded, - [{<<"xmlns">>, <<"urn:xmpp:forward:0">>}]); -encode({carbons_disable} = Disable) -> - encode_carbons_disable(Disable, - [{<<"xmlns">>, <<"urn:xmpp:carbons:2">>}]); -encode({carbons_enable} = Enable) -> - encode_carbons_enable(Enable, - [{<<"xmlns">>, <<"urn:xmpp:carbons:2">>}]); -encode({carbons_private} = Private) -> - encode_carbons_private(Private, - [{<<"xmlns">>, <<"urn:xmpp:carbons:2">>}]); -encode({carbons_received, _} = Received) -> - encode_carbons_received(Received, - [{<<"xmlns">>, <<"urn:xmpp:carbons:2">>}]); -encode({carbons_sent, _} = Sent) -> - encode_carbons_sent(Sent, - [{<<"xmlns">>, <<"urn:xmpp:carbons:2">>}]); -encode({feature_csi, <<"urn:xmpp:csi:0">>} = Csi) -> - encode_feature_csi(Csi, []); -encode({csi, active} = Active) -> - encode_csi_active(Active, - [{<<"xmlns">>, <<"urn:xmpp:csi:0">>}]); -encode({csi, inactive} = Inactive) -> - encode_csi_inactive(Inactive, - [{<<"xmlns">>, <<"urn:xmpp:csi:0">>}]); -encode({feature_sm, _} = Sm) -> - encode_feature_sm(Sm, []); -encode({sm_enable, _, _, _} = Enable) -> - encode_sm_enable(Enable, []); -encode({sm_enabled, _, _, _, _, _} = Enabled) -> - encode_sm_enabled(Enabled, []); -encode({sm_resume, _, _, _} = Resume) -> - encode_sm_resume(Resume, []); -encode({sm_resumed, _, _, _} = Resumed) -> - encode_sm_resumed(Resumed, []); -encode({sm_r, _} = R) -> encode_sm_r(R, []); -encode({sm_a, _, _} = A) -> encode_sm_a(A, []); -encode({sm_failed, _, _, _} = Failed) -> - encode_sm_failed(Failed, []); -encode({offline_item, _, _} = Item) -> - encode_offline_item(Item, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/offline">>}]); -encode({offline, _, _, _} = Offline) -> - encode_offline(Offline, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/offline">>}]); -encode({mix_join, _, _} = Join) -> - encode_mix_join(Join, - [{<<"xmlns">>, <<"urn:xmpp:mix:0">>}]); -encode({mix_leave} = Leave) -> - encode_mix_leave(Leave, - [{<<"xmlns">>, <<"urn:xmpp:mix:0">>}]); -encode({mix_participant, _, _} = Participant) -> - encode_mix_participant(Participant, - [{<<"xmlns">>, <<"urn:xmpp:mix:0">>}]); -encode({hint, 'no-copy'} = No_copy) -> - encode_hint_no_copy(No_copy, - [{<<"xmlns">>, <<"urn:xmpp:hints">>}]); -encode({hint, 'no-store'} = No_store) -> - encode_hint_no_store(No_store, - [{<<"xmlns">>, <<"urn:xmpp:hints">>}]); -encode({hint, 'no-storage'} = No_storage) -> - encode_hint_no_storage(No_storage, - [{<<"xmlns">>, <<"urn:xmpp:hints">>}]); -encode({hint, store} = Store) -> - encode_hint_store(Store, - [{<<"xmlns">>, <<"urn:xmpp:hints">>}]); + TopXMLNS); +encode({shim, _} = Headers, TopXMLNS) -> + encode_shim_headers(Headers, TopXMLNS); +encode({chatstate, active} = Active, TopXMLNS) -> + encode_chatstate_active(Active, TopXMLNS); +encode({chatstate, composing} = Composing, TopXMLNS) -> + encode_chatstate_composing(Composing, TopXMLNS); +encode({chatstate, gone} = Gone, TopXMLNS) -> + encode_chatstate_gone(Gone, TopXMLNS); +encode({chatstate, inactive} = Inactive, TopXMLNS) -> + encode_chatstate_inactive(Inactive, TopXMLNS); +encode({chatstate, paused} = Paused, TopXMLNS) -> + encode_chatstate_paused(Paused, TopXMLNS); +encode({delay, _, _, _} = Delay, TopXMLNS) -> + encode_delay(Delay, TopXMLNS); +encode({streamhost, _, _, _} = Streamhost, TopXMLNS) -> + encode_bytestreams_streamhost(Streamhost, TopXMLNS); +encode({bytestreams, _, _, _, _, _, _} = Query, + TopXMLNS) -> + encode_bytestreams(Query, TopXMLNS); +encode({muc_history, _, _, _, _} = History, TopXMLNS) -> + encode_muc_history(History, TopXMLNS); +encode({muc_decline, _, _, _} = Decline, TopXMLNS) -> + encode_muc_user_decline(Decline, TopXMLNS); +encode({muc_destroy, _, _, _, _} = Destroy, TopXMLNS) -> + encode_muc_destroy(Destroy, TopXMLNS); +encode({muc_invite, _, _, _, _} = Invite, TopXMLNS) -> + encode_muc_user_invite(Invite, TopXMLNS); +encode({muc_user, _, _, _, _, _, _} = X, TopXMLNS) -> + encode_muc_user(X, TopXMLNS); +encode({muc_owner, _, _, _} = Query, TopXMLNS) -> + encode_muc_owner(Query, TopXMLNS); +encode({muc_item, _, _, _, _, _, _, _} = Item, + TopXMLNS) -> + encode_muc_admin_item(Item, TopXMLNS); +encode({muc_actor, _, _} = Actor, TopXMLNS) -> + encode_muc_admin_actor(Actor, TopXMLNS); +encode({muc_admin, _} = Query, TopXMLNS) -> + encode_muc_admin(Query, TopXMLNS); +encode({muc, _, _} = X, TopXMLNS) -> + encode_muc(X, TopXMLNS); +encode({muc_unique, _} = Unique, TopXMLNS) -> + encode_muc_unique(Unique, TopXMLNS); +encode({x_conference, _, _, _, _, _} = X, TopXMLNS) -> + encode_x_conference(X, TopXMLNS); +encode({muc_subscriptions, _} = Subscriptions, + TopXMLNS) -> + encode_muc_subscriptions(Subscriptions, TopXMLNS); +encode({muc_subscribe, _, _} = Subscribe, TopXMLNS) -> + encode_muc_subscribe(Subscribe, TopXMLNS); +encode({muc_unsubscribe} = Unsubscribe, TopXMLNS) -> + encode_muc_unsubscribe(Unsubscribe, TopXMLNS); +encode({rsm_first, _, _} = First, TopXMLNS) -> + encode_rsm_first(First, TopXMLNS); +encode({rsm_set, _, _, _, _, _, _, _} = Set, + TopXMLNS) -> + encode_rsm_set(Set, TopXMLNS); +encode({mam_query, _, _, _, _, _, _, _, _} = Query, + TopXMLNS) -> + encode_mam_query(Query, TopXMLNS); +encode({mam_archived, _, _} = Archived, TopXMLNS) -> + encode_mam_archived(Archived, TopXMLNS); +encode({mam_result, _, _, _, _} = Result, TopXMLNS) -> + encode_mam_result(Result, TopXMLNS); +encode({mam_prefs, _, _, _, _} = Prefs, TopXMLNS) -> + encode_mam_prefs(Prefs, TopXMLNS); +encode({mam_fin, _, _, _, _, _} = Fin, TopXMLNS) -> + encode_mam_fin(Fin, TopXMLNS); +encode({forwarded, _, _} = Forwarded, TopXMLNS) -> + encode_forwarded(Forwarded, TopXMLNS); +encode({carbons_disable} = Disable, TopXMLNS) -> + encode_carbons_disable(Disable, TopXMLNS); +encode({carbons_enable} = Enable, TopXMLNS) -> + encode_carbons_enable(Enable, TopXMLNS); +encode({carbons_private} = Private, TopXMLNS) -> + encode_carbons_private(Private, TopXMLNS); +encode({carbons_received, _} = Received, TopXMLNS) -> + encode_carbons_received(Received, TopXMLNS); +encode({carbons_sent, _} = Sent, TopXMLNS) -> + encode_carbons_sent(Sent, TopXMLNS); +encode({feature_csi, <<"urn:xmpp:csi:0">>} = Csi, + TopXMLNS) -> + encode_feature_csi(Csi, TopXMLNS); +encode({feature_csi, <<>>} = Csi, + TopXMLNS = <<"urn:xmpp:csi:0">>) -> + encode_feature_csi(Csi, TopXMLNS); +encode({csi, active} = Active, TopXMLNS) -> + encode_csi_active(Active, TopXMLNS); +encode({csi, inactive} = Inactive, TopXMLNS) -> + encode_csi_inactive(Inactive, TopXMLNS); +encode({feature_sm, _} = Sm, TopXMLNS) -> + encode_feature_sm(Sm, TopXMLNS); +encode({sm_enable, _, _, _} = Enable, TopXMLNS) -> + encode_sm_enable(Enable, TopXMLNS); +encode({sm_enabled, _, _, _, _, _} = Enabled, + TopXMLNS) -> + encode_sm_enabled(Enabled, TopXMLNS); +encode({sm_resume, _, _, _} = Resume, TopXMLNS) -> + encode_sm_resume(Resume, TopXMLNS); +encode({sm_resumed, _, _, _} = Resumed, TopXMLNS) -> + encode_sm_resumed(Resumed, TopXMLNS); +encode({sm_r, _} = R, TopXMLNS) -> + encode_sm_r(R, TopXMLNS); +encode({sm_a, _, _} = A, TopXMLNS) -> + encode_sm_a(A, TopXMLNS); +encode({sm_failed, _, _, _} = Failed, TopXMLNS) -> + encode_sm_failed(Failed, TopXMLNS); +encode({offline_item, _, _} = Item, TopXMLNS) -> + encode_offline_item(Item, TopXMLNS); +encode({offline, _, _, _} = Offline, TopXMLNS) -> + encode_offline(Offline, TopXMLNS); +encode({mix_join, _, _} = Join, TopXMLNS) -> + encode_mix_join(Join, TopXMLNS); +encode({mix_leave} = Leave, TopXMLNS) -> + encode_mix_leave(Leave, TopXMLNS); +encode({mix_participant, _, _} = Participant, + TopXMLNS) -> + encode_mix_participant(Participant, TopXMLNS); +encode({hint, 'no-copy'} = No_copy, TopXMLNS) -> + encode_hint_no_copy(No_copy, TopXMLNS); +encode({hint, 'no-store'} = No_store, TopXMLNS) -> + encode_hint_no_store(No_store, TopXMLNS); +encode({hint, 'no-storage'} = No_storage, TopXMLNS) -> + encode_hint_no_storage(No_storage, TopXMLNS); +encode({hint, store} = Store, TopXMLNS) -> + encode_hint_store(Store, TopXMLNS); encode({hint, 'no-permanent-store'} = - No_permanent_store) -> + No_permanent_store, + TopXMLNS) -> encode_hint_no_permanent_store(No_permanent_store, - [{<<"xmlns">>, <<"urn:xmpp:hints">>}]); + TopXMLNS); encode({hint, 'no-permanent-storage'} = - No_permanent_storage) -> + No_permanent_storage, + TopXMLNS) -> encode_hint_no_permanent_storage(No_permanent_storage, - [{<<"xmlns">>, <<"urn:xmpp:hints">>}]); -encode({search_item, _, _, _, _, _} = Item) -> - encode_search_item(Item, - [{<<"xmlns">>, <<"jabber:iq:search">>}]); -encode({search, _, _, _, _, _, _, _} = Query) -> - encode_search(Query, - [{<<"xmlns">>, <<"jabber:iq:search">>}]); -encode({xevent, _, _, _, _, _} = X) -> - encode_xevent(X, [{<<"xmlns">>, <<"jabber:x:event">>}]); -encode({expire, _, _} = X) -> - encode_expire(X, - [{<<"xmlns">>, <<"jabber:x:expire">>}]); -encode({nick, _} = Nick) -> - encode_nick(Nick, - [{<<"xmlns">>, <<"http://jabber.org/protocol/nick">>}]); -encode({address, _, _, _, _, _} = Address) -> - encode_address(Address, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/address">>}]); -encode({addresses, _} = Addresses) -> - encode_addresses(Addresses, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/address">>}]); -encode({stanza_id, _, _} = Stanza_id) -> - encode_stanza_id(Stanza_id, - [{<<"xmlns">>, <<"urn:xmpp:sid:0">>}]); -encode({client_id, _} = Client_id) -> - encode_client_id(Client_id, - [{<<"xmlns">>, <<"urn:xmpp:sid:0">>}]); -encode({adhoc_actions, _, _, _, _} = Actions) -> - encode_adhoc_command_actions(Actions, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/commands">>}]); -encode({adhoc_note, _, _} = Note) -> - encode_adhoc_command_notes(Note, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/commands">>}]); + TopXMLNS); +encode({search_item, _, _, _, _, _} = Item, TopXMLNS) -> + encode_search_item(Item, TopXMLNS); +encode({search, _, _, _, _, _, _, _} = Query, + TopXMLNS) -> + encode_search(Query, TopXMLNS); +encode({xevent, _, _, _, _, _} = X, TopXMLNS) -> + encode_xevent(X, TopXMLNS); +encode({expire, _, _} = X, TopXMLNS) -> + encode_expire(X, TopXMLNS); +encode({nick, _} = Nick, TopXMLNS) -> + encode_nick(Nick, TopXMLNS); +encode({address, _, _, _, _, _} = Address, TopXMLNS) -> + encode_address(Address, TopXMLNS); +encode({addresses, _} = Addresses, TopXMLNS) -> + encode_addresses(Addresses, TopXMLNS); +encode({stanza_id, _, _} = Stanza_id, TopXMLNS) -> + encode_stanza_id(Stanza_id, TopXMLNS); +encode({client_id, _} = Client_id, TopXMLNS) -> + encode_client_id(Client_id, TopXMLNS); +encode({adhoc_actions, _, _, _, _} = Actions, + TopXMLNS) -> + encode_adhoc_command_actions(Actions, TopXMLNS); +encode({adhoc_note, _, _} = Note, TopXMLNS) -> + encode_adhoc_command_notes(Note, TopXMLNS); encode({adhoc_command, _, _, _, _, _, _, _, _} = - Command) -> - encode_adhoc_command(Command, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/commands">>}]); -encode({db_result, _, _, _, _, _} = Db_result) -> - encode_db_result(Db_result, - [{<<"xmlns">>, <<"jabber:client">>}]); -encode({db_verify, _, _, _, _, _, _} = Db_verify) -> - encode_db_verify(Db_verify, - [{<<"xmlns">>, <<"jabber:client">>}]); -encode({handshake, _} = Handshake) -> - encode_handshake(Handshake, - [{<<"xmlns">>, <<"jabber:client">>}]); + Command, + TopXMLNS) -> + encode_adhoc_command(Command, TopXMLNS); +encode({db_result, _, _, _, _, _} = Db_result, + TopXMLNS) -> + encode_db_result(Db_result, TopXMLNS); +encode({db_verify, _, _, _, _, _, _} = Db_verify, + TopXMLNS) -> + encode_db_verify(Db_verify, TopXMLNS); +encode({handshake, _} = Handshake, TopXMLNS) -> + encode_handshake(Handshake, TopXMLNS); encode({stream_start, _, _, _, _, _, _, _, _} = - Stream_stream) -> - encode_stream_start(Stream_stream, []); -encode({bob_data, _, _, _, _} = Data) -> - encode_bob_data(Data, - [{<<"xmlns">>, <<"urn:xmpp:bob">>}]); -encode({xcaptcha, _} = Captcha) -> - encode_captcha(Captcha, - [{<<"xmlns">>, <<"urn:xmpp:captcha">>}]); -encode({media_uri, _, _} = Uri) -> - encode_media_uri(Uri, - [{<<"xmlns">>, <<"urn:xmpp:media-element">>}]); -encode({media, _, _, _} = Media) -> - encode_media(Media, - [{<<"xmlns">>, <<"urn:xmpp:media-element">>}]); -encode({oob_x, _, _, _} = X) -> - encode_oob_x(X, [{<<"xmlns">>, <<"jabber:x:oob">>}]); -encode({sic, _, _, _} = Address) -> - encode_sic(Address, []); -encode({upload_request, _, _, _, _} = Request) -> - encode_upload_request(Request, []); -encode({upload_slot, _, _, _} = Slot) -> - encode_upload_slot(Slot, []); -encode({thumbnail, _, _, _, _} = Thumbnail) -> - encode_thumbnail(Thumbnail, - [{<<"xmlns">>, <<"urn:xmpp:thumbs:1">>}]). + Stream_stream, + TopXMLNS) -> + encode_stream_start(Stream_stream, TopXMLNS); +encode({bob_data, _, _, _, _} = Data, TopXMLNS) -> + encode_bob_data(Data, TopXMLNS); +encode({xcaptcha, _} = Captcha, TopXMLNS) -> + encode_captcha(Captcha, TopXMLNS); +encode({media_uri, _, _} = Uri, TopXMLNS) -> + encode_media_uri(Uri, TopXMLNS); +encode({media, _, _, _} = Media, TopXMLNS) -> + encode_media(Media, TopXMLNS); +encode({oob_x, _, _, _} = X, TopXMLNS) -> + encode_oob_x(X, TopXMLNS); +encode({sic, _, _, _} = Address, TopXMLNS) -> + encode_sic(Address, TopXMLNS); +encode({upload_request, _, _, _, _} = Request, + TopXMLNS) -> + encode_upload_request(Request, TopXMLNS); +encode({upload_slot, _, _, _} = Slot, TopXMLNS) -> + encode_upload_slot(Slot, TopXMLNS); +encode({thumbnail, _, _, _, _} = Thumbnail, TopXMLNS) -> + encode_thumbnail(Thumbnail, TopXMLNS). get_name({address, _, _, _, _, _}) -> <<"address">>; get_name({addresses, _}) -> <<"addresses">>; @@ -3434,9 +6071,9 @@ get_ns({compression, _}) -> get_ns({csi, active}) -> <<"urn:xmpp:csi:0">>; get_ns({csi, inactive}) -> <<"urn:xmpp:csi:0">>; get_ns({db_result, _, _, _, _, _}) -> - <<"jabber:client">>; + <<"jabber:server">>; get_ns({db_verify, _, _, _, _, _, _}) -> - <<"jabber:client">>; + <<"jabber:server">>; get_ns({delay, _, _, _}) -> <<"urn:xmpp:delay">>; get_ns({disco_info, _, _, _, _}) -> <<"http://jabber.org/protocol/disco#info">>; @@ -3452,7 +6089,7 @@ get_ns({feature_sm, Xmlns}) -> Xmlns; get_ns({forwarded, _, _}) -> <<"urn:xmpp:forward:0">>; get_ns({gone, _}) -> <<"urn:ietf:params:xml:ns:xmpp-stanzas">>; -get_ns({handshake, _}) -> <<"jabber:client">>; +get_ns({handshake, _}) -> <<"jabber:component:accept">>; get_ns({hint, 'no-copy'}) -> <<"urn:xmpp:hints">>; get_ns({hint, 'no-permanent-storage'}) -> <<"urn:xmpp:hints">>; @@ -3649,10 +6286,8 @@ get_ns({stat_error, _, _}) -> <<"http://jabber.org/protocol/stats">>; get_ns({stats, _, _}) -> <<"http://jabber.org/protocol/stats">>; -get_ns({stream_error, _, _}) -> - <<"http://etherx.jabber.org/streams">>; -get_ns({stream_features, _}) -> - <<"http://etherx.jabber.org/streams">>; +get_ns({stream_error, _, _}) -> <<"jabber:client">>; +get_ns({stream_features, _}) -> <<"jabber:client">>; get_ns({stream_start, _, _, _, _, Xmlns, _, _, _}) -> Xmlns; get_ns({streamhost, _, _, _}) -> @@ -3735,7 +6370,9 @@ format_error({missing_cdata, <<>>, Tag, XMLNS}) -> "/> qualified by namespace '", XMLNS/binary, "'">>; format_error({unknown_tag, Tag, XMLNS}) -> <<"Unknown tag <", Tag/binary, - "/> qualified by namespace '", XMLNS/binary, "'">>. + "/> qualified by namespace '", XMLNS/binary, "'">>; +format_error({missing_tag_xmlns, Tag}) -> + <<"Missing namespace for tag <", Tag/binary, "/>">>. get_attr(Attr, Attrs) -> case lists:keyfind(Attr, 1, Attrs) of @@ -3743,6 +6380,16 @@ get_attr(Attr, Attrs) -> false -> <<>> end. +enc_xmlns_attrs(XMLNS, XMLNS) -> []; +enc_xmlns_attrs(XMLNS, _) -> [{<<"xmlns">>, XMLNS}]. + +choose_top_xmlns(<<>>, NSList, TopXMLNS) -> + case lists:member(TopXMLNS, NSList) of + true -> TopXMLNS; + false -> hd(NSList) + end; +choose_top_xmlns(XMLNS, _, _) -> XMLNS. + pp(Term) -> io_lib_pretty:print(Term, fun pp/2). pp(last, 2) -> [seconds, status]; @@ -4084,13 +6731,17 @@ decode_thumbnail_attrs(__TopXMLNS, [], Uri, Media_type, encode_thumbnail({thumbnail, Uri, Media_type, Width, Height}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:xmpp:thumbs:1">>, [], + __TopXMLNS), _els = [], _attrs = encode_thumbnail_attr_height(Height, encode_thumbnail_attr_width(Width, 'encode_thumbnail_attr_media-type'(Media_type, encode_thumbnail_attr_uri(Uri, - _xmlns_attrs)))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))))), {xmlel, <<"thumbnail">>, _attrs, _els}. decode_thumbnail_attr_uri(__TopXMLNS, undefined) -> @@ -4221,30 +6872,35 @@ decode_upload_slot_attrs(__TopXMLNS, [], Xmlns) -> decode_upload_slot_attr_xmlns(__TopXMLNS, Xmlns). encode_upload_slot({upload_slot, Get, Put, Xmlns}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(Xmlns, + [<<"urn:xmpp:http:upload">>, + <<"eu:siacs:conversations:http:upload">>], + __TopXMLNS), _els = lists:reverse('encode_upload_slot_$put'(Put, + __NewTopXMLNS, 'encode_upload_slot_$get'(Get, + __NewTopXMLNS, []))), - _attrs = encode_upload_slot_attr_xmlns(Xmlns, - _xmlns_attrs), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"slot">>, _attrs, _els}. -'encode_upload_slot_$put'(undefined, _acc) -> _acc; -'encode_upload_slot_$put'(Put, _acc) -> - [encode_upload_put(Put, []) | _acc]. +'encode_upload_slot_$put'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_upload_slot_$put'(Put, __TopXMLNS, _acc) -> + [encode_upload_put(Put, __TopXMLNS) | _acc]. -'encode_upload_slot_$get'(undefined, _acc) -> _acc; -'encode_upload_slot_$get'(Get, _acc) -> - [encode_upload_get(Get, []) | _acc]. +'encode_upload_slot_$get'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_upload_slot_$get'(Get, __TopXMLNS, _acc) -> + [encode_upload_get(Get, __TopXMLNS) | _acc]. decode_upload_slot_attr_xmlns(__TopXMLNS, undefined) -> <<>>; decode_upload_slot_attr_xmlns(__TopXMLNS, _val) -> _val. -encode_upload_slot_attr_xmlns(<<>>, _acc) -> _acc; -encode_upload_slot_attr_xmlns(_val, _acc) -> - [{<<"xmlns">>, _val} | _acc]. - decode_upload_put(__TopXMLNS, __IgnoreEls, {xmlel, <<"put">>, _attrs, _els}) -> Cdata = decode_upload_put_els(__TopXMLNS, __IgnoreEls, @@ -4263,9 +6919,13 @@ decode_upload_put_els(__TopXMLNS, __IgnoreEls, decode_upload_put_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_upload_put(Cdata, _xmlns_attrs) -> +encode_upload_put(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"urn:xmpp:http:upload">>, + <<"eu:siacs:conversations:http:upload">>], + __TopXMLNS), _els = encode_upload_put_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"put">>, _attrs, _els}. decode_upload_put_cdata(__TopXMLNS, <<>>) -> @@ -4294,9 +6954,13 @@ decode_upload_get_els(__TopXMLNS, __IgnoreEls, decode_upload_get_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_upload_get(Cdata, _xmlns_attrs) -> +encode_upload_get(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"urn:xmpp:http:upload">>, + <<"eu:siacs:conversations:http:upload">>], + __TopXMLNS), _els = encode_upload_get_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"get">>, _attrs, _els}. decode_upload_get_cdata(__TopXMLNS, <<>>) -> @@ -4437,27 +7101,36 @@ decode_upload_request_attrs(__TopXMLNS, [], Xmlns) -> encode_upload_request({upload_request, Filename, Size, Content_type, Xmlns}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(Xmlns, + [<<"urn:xmpp:http:upload">>, + <<"eu:siacs:conversations:http:upload">>], + __TopXMLNS), _els = lists:reverse('encode_upload_request_$content-type'(Content_type, + __NewTopXMLNS, 'encode_upload_request_$size'(Size, + __NewTopXMLNS, 'encode_upload_request_$filename'(Filename, + __NewTopXMLNS, [])))), - _attrs = encode_upload_request_attr_xmlns(Xmlns, - _xmlns_attrs), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"request">>, _attrs, _els}. -'encode_upload_request_$content-type'(<<>>, _acc) -> +'encode_upload_request_$content-type'(<<>>, __TopXMLNS, + _acc) -> _acc; 'encode_upload_request_$content-type'(Content_type, - _acc) -> - [encode_upload_content_type(Content_type, []) | _acc]. + __TopXMLNS, _acc) -> + [encode_upload_content_type(Content_type, __TopXMLNS) + | _acc]. -'encode_upload_request_$size'(Size, _acc) -> - [encode_upload_size(Size, []) | _acc]. +'encode_upload_request_$size'(Size, __TopXMLNS, _acc) -> + [encode_upload_size(Size, __TopXMLNS) | _acc]. -'encode_upload_request_$filename'(Filename, _acc) -> - [encode_upload_filename(Filename, []) | _acc]. +'encode_upload_request_$filename'(Filename, __TopXMLNS, + _acc) -> + [encode_upload_filename(Filename, __TopXMLNS) | _acc]. decode_upload_request_attr_xmlns(__TopXMLNS, undefined) -> @@ -4465,10 +7138,6 @@ decode_upload_request_attr_xmlns(__TopXMLNS, decode_upload_request_attr_xmlns(__TopXMLNS, _val) -> _val. -encode_upload_request_attr_xmlns(<<>>, _acc) -> _acc; -encode_upload_request_attr_xmlns(_val, _acc) -> - [{<<"xmlns">>, _val} | _acc]. - decode_upload_content_type(__TopXMLNS, __IgnoreEls, {xmlel, <<"content-type">>, _attrs, _els}) -> Cdata = decode_upload_content_type_els(__TopXMLNS, @@ -4487,9 +7156,13 @@ decode_upload_content_type_els(__TopXMLNS, __IgnoreEls, decode_upload_content_type_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_upload_content_type(Cdata, _xmlns_attrs) -> +encode_upload_content_type(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"urn:xmpp:http:upload">>, + <<"eu:siacs:conversations:http:upload">>], + __TopXMLNS), _els = encode_upload_content_type_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"content-type">>, _attrs, _els}. decode_upload_content_type_cdata(__TopXMLNS, <<>>) -> @@ -4519,9 +7192,13 @@ decode_upload_size_els(__TopXMLNS, __IgnoreEls, decode_upload_size_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_upload_size(Cdata, _xmlns_attrs) -> +encode_upload_size(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"urn:xmpp:http:upload">>, + <<"eu:siacs:conversations:http:upload">>], + __TopXMLNS), _els = encode_upload_size_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"size">>, _attrs, _els}. decode_upload_size_cdata(__TopXMLNS, <<>>) -> @@ -4556,9 +7233,13 @@ decode_upload_filename_els(__TopXMLNS, __IgnoreEls, decode_upload_filename_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_upload_filename(Cdata, _xmlns_attrs) -> +encode_upload_filename(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"urn:xmpp:http:upload">>, + <<"eu:siacs:conversations:http:upload">>], + __TopXMLNS), _els = encode_upload_filename_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"filename">>, _attrs, _els}. decode_upload_filename_cdata(__TopXMLNS, <<>>) -> @@ -4624,27 +7305,29 @@ decode_sic_attrs(__TopXMLNS, [_ | _attrs], Xmlns) -> decode_sic_attrs(__TopXMLNS, [], Xmlns) -> decode_sic_attr_xmlns(__TopXMLNS, Xmlns). -encode_sic({sic, Ip, Port, Xmlns}, _xmlns_attrs) -> - _els = lists:reverse('encode_sic_$ip'(Ip, - 'encode_sic_$port'(Port, []))), - _attrs = encode_sic_attr_xmlns(Xmlns, _xmlns_attrs), +encode_sic({sic, Ip, Port, Xmlns}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(Xmlns, + [<<"urn:xmpp:sic:0">>, + <<"urn:xmpp:sic:1">>], + __TopXMLNS), + _els = lists:reverse('encode_sic_$ip'(Ip, __NewTopXMLNS, + 'encode_sic_$port'(Port, + __NewTopXMLNS, + []))), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"address">>, _attrs, _els}. -'encode_sic_$ip'(undefined, _acc) -> _acc; -'encode_sic_$ip'(Ip, _acc) -> - [encode_sic_ip(Ip, []) | _acc]. +'encode_sic_$ip'(undefined, __TopXMLNS, _acc) -> _acc; +'encode_sic_$ip'(Ip, __TopXMLNS, _acc) -> + [encode_sic_ip(Ip, __TopXMLNS) | _acc]. -'encode_sic_$port'(undefined, _acc) -> _acc; -'encode_sic_$port'(Port, _acc) -> - [encode_sip_port(Port, []) | _acc]. +'encode_sic_$port'(undefined, __TopXMLNS, _acc) -> _acc; +'encode_sic_$port'(Port, __TopXMLNS, _acc) -> + [encode_sip_port(Port, __TopXMLNS) | _acc]. decode_sic_attr_xmlns(__TopXMLNS, undefined) -> <<>>; decode_sic_attr_xmlns(__TopXMLNS, _val) -> _val. -encode_sic_attr_xmlns(<<>>, _acc) -> _acc; -encode_sic_attr_xmlns(_val, _acc) -> - [{<<"xmlns">>, _val} | _acc]. - decode_sip_port(__TopXMLNS, __IgnoreEls, {xmlel, <<"port">>, _attrs, _els}) -> Cdata = decode_sip_port_els(__TopXMLNS, __IgnoreEls, @@ -4663,9 +7346,11 @@ decode_sip_port_els(__TopXMLNS, __IgnoreEls, [_ | _els], decode_sip_port_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_sip_port(Cdata, _xmlns_attrs) -> +encode_sip_port(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:sic:1">>, + [], __TopXMLNS), _els = encode_sip_port_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"port">>, _attrs, _els}. decode_sip_port_cdata(__TopXMLNS, <<>>) -> @@ -4698,9 +7383,13 @@ decode_sic_ip_els(__TopXMLNS, __IgnoreEls, [_ | _els], Cdata) -> decode_sic_ip_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_sic_ip(Cdata, _xmlns_attrs) -> +encode_sic_ip(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"urn:xmpp:sic:0">>, + <<"urn:xmpp:sic:1">>], + __TopXMLNS), _els = encode_sic_ip_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"ip">>, _attrs, _els}. decode_sic_ip_cdata(__TopXMLNS, <<>>) -> @@ -4779,18 +7468,24 @@ decode_oob_x_attrs(__TopXMLNS, [_ | _attrs], Sid) -> decode_oob_x_attrs(__TopXMLNS, [], Sid) -> decode_oob_x_attr_sid(__TopXMLNS, Sid). -encode_oob_x({oob_x, Url, Desc, Sid}, _xmlns_attrs) -> +encode_oob_x({oob_x, Url, Desc, Sid}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:oob">>, [], + __TopXMLNS), _els = lists:reverse('encode_oob_x_$desc'(Desc, - 'encode_oob_x_$url'(Url, []))), - _attrs = encode_oob_x_attr_sid(Sid, _xmlns_attrs), + __NewTopXMLNS, + 'encode_oob_x_$url'(Url, + __NewTopXMLNS, + []))), + _attrs = encode_oob_x_attr_sid(Sid, + enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS)), {xmlel, <<"x">>, _attrs, _els}. -'encode_oob_x_$desc'(<<>>, _acc) -> _acc; -'encode_oob_x_$desc'(Desc, _acc) -> - [encode_oob_desc(Desc, []) | _acc]. +'encode_oob_x_$desc'(<<>>, __TopXMLNS, _acc) -> _acc; +'encode_oob_x_$desc'(Desc, __TopXMLNS, _acc) -> + [encode_oob_desc(Desc, __TopXMLNS) | _acc]. -'encode_oob_x_$url'(Url, _acc) -> - [encode_oob_url(Url, []) | _acc]. +'encode_oob_x_$url'(Url, __TopXMLNS, _acc) -> + [encode_oob_url(Url, __TopXMLNS) | _acc]. decode_oob_x_attr_sid(__TopXMLNS, undefined) -> <<>>; decode_oob_x_attr_sid(__TopXMLNS, _val) -> _val. @@ -4817,9 +7512,11 @@ decode_oob_desc_els(__TopXMLNS, __IgnoreEls, [_ | _els], decode_oob_desc_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_oob_desc(Cdata, _xmlns_attrs) -> +encode_oob_desc(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:oob">>, [], + __TopXMLNS), _els = encode_oob_desc_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"desc">>, _attrs, _els}. decode_oob_desc_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -4847,9 +7544,11 @@ decode_oob_url_els(__TopXMLNS, __IgnoreEls, [_ | _els], decode_oob_url_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_oob_url(Cdata, _xmlns_attrs) -> +encode_oob_url(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:oob">>, [], + __TopXMLNS), _els = encode_oob_url_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"url">>, _attrs, _els}. decode_oob_url_cdata(__TopXMLNS, <<>>) -> @@ -4903,18 +7602,22 @@ decode_media_attrs(__TopXMLNS, [], Height, Width) -> {decode_media_attr_height(__TopXMLNS, Height), decode_media_attr_width(__TopXMLNS, Width)}. -encode_media({media, Height, Width, Uri}, - _xmlns_attrs) -> - _els = lists:reverse('encode_media_$uri'(Uri, [])), +encode_media({media, Height, Width, Uri}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:xmpp:media-element">>, [], + __TopXMLNS), + _els = lists:reverse('encode_media_$uri'(Uri, + __NewTopXMLNS, [])), _attrs = encode_media_attr_width(Width, encode_media_attr_height(Height, - _xmlns_attrs)), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))), {xmlel, <<"media">>, _attrs, _els}. -'encode_media_$uri'([], _acc) -> _acc; -'encode_media_$uri'([Uri | _els], _acc) -> - 'encode_media_$uri'(_els, - [encode_media_uri(Uri, []) | _acc]). +'encode_media_$uri'([], __TopXMLNS, _acc) -> _acc; +'encode_media_$uri'([Uri | _els], __TopXMLNS, _acc) -> + 'encode_media_$uri'(_els, __TopXMLNS, + [encode_media_uri(Uri, __TopXMLNS) | _acc]). decode_media_attr_height(__TopXMLNS, undefined) -> undefined; @@ -4975,10 +7678,14 @@ decode_media_uri_attrs(__TopXMLNS, [_ | _attrs], decode_media_uri_attrs(__TopXMLNS, [], Type) -> decode_media_uri_attr_type(__TopXMLNS, Type). -encode_media_uri({media_uri, Type, Uri}, - _xmlns_attrs) -> +encode_media_uri({media_uri, Type, Uri}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:xmpp:media-element">>, [], + __TopXMLNS), _els = encode_media_uri_cdata(Uri, []), - _attrs = encode_media_uri_attr_type(Type, _xmlns_attrs), + _attrs = encode_media_uri_attr_type(Type, + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"uri">>, _attrs, _els}. decode_media_uri_attr_type(__TopXMLNS, undefined) -> @@ -5026,16 +7733,16 @@ decode_captcha_els(__TopXMLNS, __IgnoreEls, [_ | _els], decode_captcha_els(__TopXMLNS, __IgnoreEls, _els, Xdata). -encode_captcha({xcaptcha, Xdata}, _xmlns_attrs) -> +encode_captcha({xcaptcha, Xdata}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:captcha">>, + [], __TopXMLNS), _els = lists:reverse('encode_captcha_$xdata'(Xdata, - [])), - _attrs = _xmlns_attrs, + __NewTopXMLNS, [])), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"captcha">>, _attrs, _els}. -'encode_captcha_$xdata'(Xdata, _acc) -> - [encode_xdata(Xdata, - [{<<"xmlns">>, <<"jabber:x:data">>}]) - | _acc]. +'encode_captcha_$xdata'(Xdata, __TopXMLNS, _acc) -> + [encode_xdata(Xdata, __TopXMLNS) | _acc]. decode_bob_data(__TopXMLNS, __IgnoreEls, {xmlel, <<"data">>, _attrs, _els}) -> @@ -5082,12 +7789,15 @@ decode_bob_data_attrs(__TopXMLNS, [], Cid, Max_age, decode_bob_data_attr_type(__TopXMLNS, Type)}. encode_bob_data({bob_data, Cid, Max_age, Type, Data}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:bob">>, [], + __TopXMLNS), _els = encode_bob_data_cdata(Data, []), _attrs = encode_bob_data_attr_type(Type, 'encode_bob_data_attr_max-age'(Max_age, encode_bob_data_attr_cid(Cid, - _xmlns_attrs))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)))), {xmlel, <<"data">>, _attrs, _els}. decode_bob_data_attr_cid(__TopXMLNS, undefined) -> @@ -5206,17 +7916,21 @@ decode_stream_start_attrs(__TopXMLNS, [], From, To, encode_stream_start({stream_start, From, To, Id, Version, Xmlns, Stream_xmlns, Db_xmlns, Lang}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(Xmlns, + [<<"jabber:client">>, <<"jabber:server">>, + <<"jabber:component:accept">>], + __TopXMLNS), _els = [], _attrs = encode_stream_start_attr_id(Id, encode_stream_start_attr_version(Version, 'encode_stream_start_attr_xml:lang'(Lang, 'encode_stream_start_attr_xmlns:db'(Db_xmlns, 'encode_stream_start_attr_xmlns:stream'(Stream_xmlns, - encode_stream_start_attr_xmlns(Xmlns, - encode_stream_start_attr_to(To, - encode_stream_start_attr_from(From, - _xmlns_attrs)))))))), + encode_stream_start_attr_to(To, + encode_stream_start_attr_from(From, + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)))))))), {xmlel, <<"stream:stream">>, _attrs, _els}. decode_stream_start_attr_from(__TopXMLNS, undefined) -> @@ -5254,10 +7968,6 @@ decode_stream_start_attr_xmlns(__TopXMLNS, undefined) -> decode_stream_start_attr_xmlns(__TopXMLNS, _val) -> _val. -encode_stream_start_attr_xmlns(<<>>, _acc) -> _acc; -encode_stream_start_attr_xmlns(_val, _acc) -> - [{<<"xmlns">>, _val} | _acc]. - 'decode_stream_start_attr_xmlns:stream'(__TopXMLNS, undefined) -> <<>>; @@ -5333,9 +8043,12 @@ decode_handshake_els(__TopXMLNS, __IgnoreEls, decode_handshake_els(__TopXMLNS, __IgnoreEls, _els, Data). -encode_handshake({handshake, Data}, _xmlns_attrs) -> +encode_handshake({handshake, Data}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:component:accept">>, [], + __TopXMLNS), _els = encode_handshake_cdata(Data, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"handshake">>, _attrs, _els}. decode_handshake_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -5368,10 +8081,10 @@ decode_db_verify_els(__TopXMLNS, __IgnoreEls, decode_db_verify_els(__TopXMLNS, __IgnoreEls, _els, Key, [_el | __Els]); true -> - case is_known_tag(_el) of + case is_known_tag(_el, __TopXMLNS) of true -> decode_db_verify_els(__TopXMLNS, __IgnoreEls, _els, Key, - [decode(_el) | __Els]); + [decode(_el, __TopXMLNS, []) | __Els]); false -> decode_db_verify_els(__TopXMLNS, __IgnoreEls, _els, Key, __Els) @@ -5407,14 +8120,17 @@ decode_db_verify_attrs(__TopXMLNS, [], From, To, Id, encode_db_verify({db_verify, From, To, Id, Type, Key, __Els}, - _xmlns_attrs) -> - _els = [encode(_el) || _el <- __Els] ++ + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:server">>, + [], __TopXMLNS), + _els = [encode(_el, __NewTopXMLNS) || _el <- __Els] ++ encode_db_verify_cdata(Key, []), _attrs = encode_db_verify_attr_type(Type, encode_db_verify_attr_id(Id, encode_db_verify_attr_to(To, encode_db_verify_attr_from(From, - _xmlns_attrs)))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))))), {xmlel, <<"db:verify">>, _attrs, _els}. decode_db_verify_attr_from(__TopXMLNS, undefined) -> @@ -5501,10 +8217,10 @@ decode_db_result_els(__TopXMLNS, __IgnoreEls, decode_db_result_els(__TopXMLNS, __IgnoreEls, _els, Key, [_el | __Els]); true -> - case is_known_tag(_el) of + case is_known_tag(_el, __TopXMLNS) of true -> decode_db_result_els(__TopXMLNS, __IgnoreEls, _els, Key, - [decode(_el) | __Els]); + [decode(_el, __TopXMLNS, []) | __Els]); false -> decode_db_result_els(__TopXMLNS, __IgnoreEls, _els, Key, __Els) @@ -5535,13 +8251,16 @@ decode_db_result_attrs(__TopXMLNS, [], From, To, encode_db_result({db_result, From, To, Type, Key, __Els}, - _xmlns_attrs) -> - _els = [encode(_el) || _el <- __Els] ++ + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:server">>, + [], __TopXMLNS), + _els = [encode(_el, __NewTopXMLNS) || _el <- __Els] ++ encode_db_result_cdata(Key, []), _attrs = encode_db_result_attr_type(Type, encode_db_result_attr_to(To, encode_db_result_attr_from(From, - _xmlns_attrs))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)))), {xmlel, <<"db:result">>, _attrs, _els}. decode_db_result_attr_from(__TopXMLNS, undefined) -> @@ -5715,36 +8434,49 @@ decode_adhoc_command_attrs(__TopXMLNS, [], Node, Lang, encode_adhoc_command({adhoc_command, Node, Action, Sid, Status, Lang, Actions, Notes, Xdata}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/commands">>, + [], __TopXMLNS), _els = lists:reverse('encode_adhoc_command_$xdata'(Xdata, + __NewTopXMLNS, 'encode_adhoc_command_$notes'(Notes, + __NewTopXMLNS, 'encode_adhoc_command_$actions'(Actions, + __NewTopXMLNS, [])))), _attrs = encode_adhoc_command_attr_action(Action, encode_adhoc_command_attr_status(Status, encode_adhoc_command_attr_sessionid(Sid, 'encode_adhoc_command_attr_xml:lang'(Lang, encode_adhoc_command_attr_node(Node, - _xmlns_attrs))))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)))))), {xmlel, <<"command">>, _attrs, _els}. -'encode_adhoc_command_$xdata'(undefined, _acc) -> _acc; -'encode_adhoc_command_$xdata'(Xdata, _acc) -> - [encode_xdata(Xdata, - [{<<"xmlns">>, <<"jabber:x:data">>}]) - | _acc]. +'encode_adhoc_command_$xdata'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_adhoc_command_$xdata'(Xdata, __TopXMLNS, + _acc) -> + [encode_xdata(Xdata, __TopXMLNS) | _acc]. -'encode_adhoc_command_$notes'([], _acc) -> _acc; -'encode_adhoc_command_$notes'([Notes | _els], _acc) -> - 'encode_adhoc_command_$notes'(_els, - [encode_adhoc_command_notes(Notes, []) +'encode_adhoc_command_$notes'([], __TopXMLNS, _acc) -> + _acc; +'encode_adhoc_command_$notes'([Notes | _els], + __TopXMLNS, _acc) -> + 'encode_adhoc_command_$notes'(_els, __TopXMLNS, + [encode_adhoc_command_notes(Notes, __TopXMLNS) | _acc]). -'encode_adhoc_command_$actions'(undefined, _acc) -> +'encode_adhoc_command_$actions'(undefined, __TopXMLNS, + _acc) -> _acc; -'encode_adhoc_command_$actions'(Actions, _acc) -> - [encode_adhoc_command_actions(Actions, []) | _acc]. +'encode_adhoc_command_$actions'(Actions, __TopXMLNS, + _acc) -> + [encode_adhoc_command_actions(Actions, __TopXMLNS) + | _acc]. decode_adhoc_command_attr_node(__TopXMLNS, undefined) -> erlang:error({xmpp_codec, @@ -5847,10 +8579,14 @@ decode_adhoc_command_notes_attrs(__TopXMLNS, [], decode_adhoc_command_notes_attr_type(__TopXMLNS, Type). encode_adhoc_command_notes({adhoc_note, Type, Data}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/commands">>, + [], __TopXMLNS), _els = encode_adhoc_command_notes_cdata(Data, []), _attrs = encode_adhoc_command_notes_attr_type(Type, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"note">>, _attrs, _els}. decode_adhoc_command_notes_attr_type(__TopXMLNS, @@ -5991,32 +8727,45 @@ decode_adhoc_command_actions_attrs(__TopXMLNS, [], encode_adhoc_command_actions({adhoc_actions, Execute, Prev, Next, Complete}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/commands">>, + [], __TopXMLNS), _els = lists:reverse('encode_adhoc_command_actions_$next'(Next, + __NewTopXMLNS, 'encode_adhoc_command_actions_$complete'(Complete, + __NewTopXMLNS, 'encode_adhoc_command_actions_$prev'(Prev, + __NewTopXMLNS, [])))), _attrs = encode_adhoc_command_actions_attr_execute(Execute, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"actions">>, _attrs, _els}. -'encode_adhoc_command_actions_$next'(false, _acc) -> +'encode_adhoc_command_actions_$next'(false, __TopXMLNS, + _acc) -> _acc; -'encode_adhoc_command_actions_$next'(Next, _acc) -> - [encode_adhoc_command_next(Next, []) | _acc]. +'encode_adhoc_command_actions_$next'(Next, __TopXMLNS, + _acc) -> + [encode_adhoc_command_next(Next, __TopXMLNS) | _acc]. -'encode_adhoc_command_actions_$complete'(false, _acc) -> +'encode_adhoc_command_actions_$complete'(false, + __TopXMLNS, _acc) -> _acc; 'encode_adhoc_command_actions_$complete'(Complete, - _acc) -> - [encode_adhoc_command_complete(Complete, []) | _acc]. + __TopXMLNS, _acc) -> + [encode_adhoc_command_complete(Complete, __TopXMLNS) + | _acc]. -'encode_adhoc_command_actions_$prev'(false, _acc) -> +'encode_adhoc_command_actions_$prev'(false, __TopXMLNS, + _acc) -> _acc; -'encode_adhoc_command_actions_$prev'(Prev, _acc) -> - [encode_adhoc_command_prev(Prev, []) | _acc]. +'encode_adhoc_command_actions_$prev'(Prev, __TopXMLNS, + _acc) -> + [encode_adhoc_command_prev(Prev, __TopXMLNS) | _acc]. decode_adhoc_command_actions_attr_execute(__TopXMLNS, undefined) -> @@ -6041,27 +8790,36 @@ decode_adhoc_command_complete(__TopXMLNS, __IgnoreEls, {xmlel, <<"complete">>, _attrs, _els}) -> true. -encode_adhoc_command_complete(true, _xmlns_attrs) -> +encode_adhoc_command_complete(true, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/commands">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"complete">>, _attrs, _els}. decode_adhoc_command_next(__TopXMLNS, __IgnoreEls, {xmlel, <<"next">>, _attrs, _els}) -> true. -encode_adhoc_command_next(true, _xmlns_attrs) -> +encode_adhoc_command_next(true, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/commands">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"next">>, _attrs, _els}. decode_adhoc_command_prev(__TopXMLNS, __IgnoreEls, {xmlel, <<"prev">>, _attrs, _els}) -> true. -encode_adhoc_command_prev(true, _xmlns_attrs) -> +encode_adhoc_command_prev(true, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/commands">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"prev">>, _attrs, _els}. decode_client_id(__TopXMLNS, __IgnoreEls, @@ -6078,9 +8836,13 @@ decode_client_id_attrs(__TopXMLNS, [_ | _attrs], Id) -> decode_client_id_attrs(__TopXMLNS, [], Id) -> decode_client_id_attr_id(__TopXMLNS, Id). -encode_client_id({client_id, Id}, _xmlns_attrs) -> +encode_client_id({client_id, Id}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:sid:0">>, + [], __TopXMLNS), _els = [], - _attrs = encode_client_id_attr_id(Id, _xmlns_attrs), + _attrs = encode_client_id_attr_id(Id, + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"client-id">>, _attrs, _els}. decode_client_id_attr_id(__TopXMLNS, undefined) -> @@ -6110,11 +8872,14 @@ decode_stanza_id_attrs(__TopXMLNS, [], Id, By) -> {decode_stanza_id_attr_id(__TopXMLNS, Id), decode_stanza_id_attr_by(__TopXMLNS, By)}. -encode_stanza_id({stanza_id, By, Id}, _xmlns_attrs) -> +encode_stanza_id({stanza_id, By, Id}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:sid:0">>, + [], __TopXMLNS), _els = [], _attrs = encode_stanza_id_attr_by(By, encode_stanza_id_attr_id(Id, - _xmlns_attrs)), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))), {xmlel, <<"stanza-id">>, _attrs, _els}. decode_stanza_id_attr_id(__TopXMLNS, undefined) -> @@ -6173,16 +8938,20 @@ decode_addresses_els(__TopXMLNS, __IgnoreEls, decode_addresses_els(__TopXMLNS, __IgnoreEls, _els, List). -encode_addresses({addresses, List}, _xmlns_attrs) -> +encode_addresses({addresses, List}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/address">>, + [], __TopXMLNS), _els = lists:reverse('encode_addresses_$list'(List, - [])), - _attrs = _xmlns_attrs, + __NewTopXMLNS, [])), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"addresses">>, _attrs, _els}. -'encode_addresses_$list'([], _acc) -> _acc; -'encode_addresses_$list'([List | _els], _acc) -> - 'encode_addresses_$list'(_els, - [encode_address(List, []) | _acc]). +'encode_addresses_$list'([], __TopXMLNS, _acc) -> _acc; +'encode_addresses_$list'([List | _els], __TopXMLNS, + _acc) -> + 'encode_addresses_$list'(_els, __TopXMLNS, + [encode_address(List, __TopXMLNS) | _acc]). decode_address(__TopXMLNS, __IgnoreEls, {xmlel, <<"address">>, _attrs, _els}) -> @@ -6230,14 +8999,18 @@ decode_address_attrs(__TopXMLNS, [], Type, Jid, Desc, encode_address({address, Type, Jid, Desc, Node, Delivered}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/address">>, + [], __TopXMLNS), _els = [], _attrs = encode_address_attr_delivered(Delivered, encode_address_attr_node(Node, encode_address_attr_desc(Desc, encode_address_attr_jid(Jid, encode_address_attr_type(Type, - _xmlns_attrs))))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)))))), {xmlel, <<"address">>, _attrs, _els}. decode_address_attr_type(__TopXMLNS, undefined) -> @@ -6317,9 +9090,12 @@ decode_nick_els(__TopXMLNS, __IgnoreEls, [_ | _els], Name) -> decode_nick_els(__TopXMLNS, __IgnoreEls, _els, Name). -encode_nick({nick, Name}, _xmlns_attrs) -> +encode_nick({nick, Name}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/nick">>, + [], __TopXMLNS), _els = encode_nick_cdata(Name, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"nick">>, _attrs, _els}. decode_nick_cdata(__TopXMLNS, <<>>) -> @@ -6350,12 +9126,14 @@ decode_expire_attrs(__TopXMLNS, [], Seconds, Stored) -> {decode_expire_attr_seconds(__TopXMLNS, Seconds), decode_expire_attr_stored(__TopXMLNS, Stored)}. -encode_expire({expire, Seconds, Stored}, - _xmlns_attrs) -> +encode_expire({expire, Seconds, Stored}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:expire">>, + [], __TopXMLNS), _els = [], _attrs = encode_expire_attr_stored(Stored, encode_expire_attr_seconds(Seconds, - _xmlns_attrs)), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))), {xmlel, <<"x">>, _attrs, _els}. decode_expire_attr_seconds(__TopXMLNS, undefined) -> @@ -6495,35 +9273,50 @@ decode_xevent_els(__TopXMLNS, __IgnoreEls, [_ | _els], encode_xevent({xevent, Offline, Delivered, Displayed, Composing, Id}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:event">>, + [], __TopXMLNS), _els = lists:reverse('encode_xevent_$id'(Id, + __NewTopXMLNS, 'encode_xevent_$displayed'(Displayed, + __NewTopXMLNS, 'encode_xevent_$delivered'(Delivered, + __NewTopXMLNS, 'encode_xevent_$offline'(Offline, + __NewTopXMLNS, 'encode_xevent_$composing'(Composing, + __NewTopXMLNS, [])))))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"x">>, _attrs, _els}. -'encode_xevent_$id'(undefined, _acc) -> _acc; -'encode_xevent_$id'(Id, _acc) -> - [encode_xevent_id(Id, []) | _acc]. +'encode_xevent_$id'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_xevent_$id'(Id, __TopXMLNS, _acc) -> + [encode_xevent_id(Id, __TopXMLNS) | _acc]. -'encode_xevent_$displayed'(false, _acc) -> _acc; -'encode_xevent_$displayed'(Displayed, _acc) -> - [encode_xevent_displayed(Displayed, []) | _acc]. +'encode_xevent_$displayed'(false, __TopXMLNS, _acc) -> + _acc; +'encode_xevent_$displayed'(Displayed, __TopXMLNS, + _acc) -> + [encode_xevent_displayed(Displayed, __TopXMLNS) | _acc]. -'encode_xevent_$delivered'(false, _acc) -> _acc; -'encode_xevent_$delivered'(Delivered, _acc) -> - [encode_xevent_delivered(Delivered, []) | _acc]. +'encode_xevent_$delivered'(false, __TopXMLNS, _acc) -> + _acc; +'encode_xevent_$delivered'(Delivered, __TopXMLNS, + _acc) -> + [encode_xevent_delivered(Delivered, __TopXMLNS) | _acc]. -'encode_xevent_$offline'(false, _acc) -> _acc; -'encode_xevent_$offline'(Offline, _acc) -> - [encode_xevent_offline(Offline, []) | _acc]. +'encode_xevent_$offline'(false, __TopXMLNS, _acc) -> + _acc; +'encode_xevent_$offline'(Offline, __TopXMLNS, _acc) -> + [encode_xevent_offline(Offline, __TopXMLNS) | _acc]. -'encode_xevent_$composing'(false, _acc) -> _acc; -'encode_xevent_$composing'(Composing, _acc) -> - [encode_xevent_composing(Composing, []) | _acc]. +'encode_xevent_$composing'(false, __TopXMLNS, _acc) -> + _acc; +'encode_xevent_$composing'(Composing, __TopXMLNS, + _acc) -> + [encode_xevent_composing(Composing, __TopXMLNS) | _acc]. decode_xevent_id(__TopXMLNS, __IgnoreEls, {xmlel, <<"id">>, _attrs, _els}) -> @@ -6543,9 +9336,11 @@ decode_xevent_id_els(__TopXMLNS, __IgnoreEls, decode_xevent_id_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_xevent_id(Cdata, _xmlns_attrs) -> +encode_xevent_id(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:event">>, + [], __TopXMLNS), _els = encode_xevent_id_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"id">>, _attrs, _els}. decode_xevent_id_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -6559,36 +9354,44 @@ decode_xevent_composing(__TopXMLNS, __IgnoreEls, {xmlel, <<"composing">>, _attrs, _els}) -> true. -encode_xevent_composing(true, _xmlns_attrs) -> +encode_xevent_composing(true, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:event">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"composing">>, _attrs, _els}. decode_xevent_displayed(__TopXMLNS, __IgnoreEls, {xmlel, <<"displayed">>, _attrs, _els}) -> true. -encode_xevent_displayed(true, _xmlns_attrs) -> +encode_xevent_displayed(true, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:event">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"displayed">>, _attrs, _els}. decode_xevent_delivered(__TopXMLNS, __IgnoreEls, {xmlel, <<"delivered">>, _attrs, _els}) -> true. -encode_xevent_delivered(true, _xmlns_attrs) -> +encode_xevent_delivered(true, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:event">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"delivered">>, _attrs, _els}. decode_xevent_offline(__TopXMLNS, __IgnoreEls, {xmlel, <<"offline">>, _attrs, _els}) -> true. -encode_xevent_offline(true, _xmlns_attrs) -> +encode_xevent_offline(true, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:event">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"offline">>, _attrs, _els}. decode_search(__TopXMLNS, __IgnoreEls, @@ -6736,48 +9539,65 @@ decode_search_els(__TopXMLNS, __IgnoreEls, [_ | _els], encode_search({search, Instructions, First, Last, Nick, Email, Items, Xdata}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:search">>, + [], __TopXMLNS), _els = lists:reverse('encode_search_$xdata'(Xdata, + __NewTopXMLNS, 'encode_search_$items'(Items, + __NewTopXMLNS, 'encode_search_$instructions'(Instructions, + __NewTopXMLNS, 'encode_search_$last'(Last, + __NewTopXMLNS, 'encode_search_$first'(First, + __NewTopXMLNS, 'encode_search_$nick'(Nick, + __NewTopXMLNS, 'encode_search_$email'(Email, + __NewTopXMLNS, [])))))))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"query">>, _attrs, _els}. -'encode_search_$xdata'(undefined, _acc) -> _acc; -'encode_search_$xdata'(Xdata, _acc) -> - [encode_xdata(Xdata, - [{<<"xmlns">>, <<"jabber:x:data">>}]) +'encode_search_$xdata'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_search_$xdata'(Xdata, __TopXMLNS, _acc) -> + [encode_xdata(Xdata, __TopXMLNS) | _acc]. + +'encode_search_$items'([], __TopXMLNS, _acc) -> _acc; +'encode_search_$items'([Items | _els], __TopXMLNS, + _acc) -> + 'encode_search_$items'(_els, __TopXMLNS, + [encode_search_item(Items, __TopXMLNS) | _acc]). + +'encode_search_$instructions'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_search_$instructions'(Instructions, __TopXMLNS, + _acc) -> + [encode_search_instructions(Instructions, __TopXMLNS) | _acc]. -'encode_search_$items'([], _acc) -> _acc; -'encode_search_$items'([Items | _els], _acc) -> - 'encode_search_$items'(_els, - [encode_search_item(Items, []) | _acc]). +'encode_search_$last'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_search_$last'(Last, __TopXMLNS, _acc) -> + [encode_search_last(Last, __TopXMLNS) | _acc]. -'encode_search_$instructions'(undefined, _acc) -> _acc; -'encode_search_$instructions'(Instructions, _acc) -> - [encode_search_instructions(Instructions, []) | _acc]. +'encode_search_$first'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_search_$first'(First, __TopXMLNS, _acc) -> + [encode_search_first(First, __TopXMLNS) | _acc]. -'encode_search_$last'(undefined, _acc) -> _acc; -'encode_search_$last'(Last, _acc) -> - [encode_search_last(Last, []) | _acc]. +'encode_search_$nick'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_search_$nick'(Nick, __TopXMLNS, _acc) -> + [encode_search_nick(Nick, __TopXMLNS) | _acc]. -'encode_search_$first'(undefined, _acc) -> _acc; -'encode_search_$first'(First, _acc) -> - [encode_search_first(First, []) | _acc]. - -'encode_search_$nick'(undefined, _acc) -> _acc; -'encode_search_$nick'(Nick, _acc) -> - [encode_search_nick(Nick, []) | _acc]. - -'encode_search_$email'(undefined, _acc) -> _acc; -'encode_search_$email'(Email, _acc) -> - [encode_search_email(Email, []) | _acc]. +'encode_search_$email'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_search_$email'(Email, __TopXMLNS, _acc) -> + [encode_search_email(Email, __TopXMLNS) | _acc]. decode_search_item(__TopXMLNS, __IgnoreEls, {xmlel, <<"item">>, _attrs, _els}) -> @@ -6883,30 +9703,46 @@ decode_search_item_attrs(__TopXMLNS, [], Jid) -> encode_search_item({search_item, Jid, First, Last, Nick, Email}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:search">>, + [], __TopXMLNS), _els = lists:reverse('encode_search_item_$last'(Last, + __NewTopXMLNS, 'encode_search_item_$first'(First, + __NewTopXMLNS, 'encode_search_item_$nick'(Nick, + __NewTopXMLNS, 'encode_search_item_$email'(Email, + __NewTopXMLNS, []))))), - _attrs = encode_search_item_attr_jid(Jid, _xmlns_attrs), + _attrs = encode_search_item_attr_jid(Jid, + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"item">>, _attrs, _els}. -'encode_search_item_$last'(undefined, _acc) -> _acc; -'encode_search_item_$last'(Last, _acc) -> - [encode_search_last(Last, []) | _acc]. +'encode_search_item_$last'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_search_item_$last'(Last, __TopXMLNS, _acc) -> + [encode_search_last(Last, __TopXMLNS) | _acc]. -'encode_search_item_$first'(undefined, _acc) -> _acc; -'encode_search_item_$first'(First, _acc) -> - [encode_search_first(First, []) | _acc]. +'encode_search_item_$first'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_search_item_$first'(First, __TopXMLNS, _acc) -> + [encode_search_first(First, __TopXMLNS) | _acc]. -'encode_search_item_$nick'(undefined, _acc) -> _acc; -'encode_search_item_$nick'(Nick, _acc) -> - [encode_search_nick(Nick, []) | _acc]. +'encode_search_item_$nick'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_search_item_$nick'(Nick, __TopXMLNS, _acc) -> + [encode_search_nick(Nick, __TopXMLNS) | _acc]. -'encode_search_item_$email'(undefined, _acc) -> _acc; -'encode_search_item_$email'(Email, _acc) -> - [encode_search_email(Email, []) | _acc]. +'encode_search_item_$email'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_search_item_$email'(Email, __TopXMLNS, _acc) -> + [encode_search_email(Email, __TopXMLNS) | _acc]. decode_search_item_attr_jid(__TopXMLNS, undefined) -> erlang:error({xmpp_codec, @@ -6940,9 +9776,11 @@ decode_search_email_els(__TopXMLNS, __IgnoreEls, decode_search_email_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_search_email(Cdata, _xmlns_attrs) -> +encode_search_email(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:search">>, + [], __TopXMLNS), _els = encode_search_email_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"email">>, _attrs, _els}. decode_search_email_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -6970,9 +9808,11 @@ decode_search_nick_els(__TopXMLNS, __IgnoreEls, decode_search_nick_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_search_nick(Cdata, _xmlns_attrs) -> +encode_search_nick(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:search">>, + [], __TopXMLNS), _els = encode_search_nick_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"nick">>, _attrs, _els}. decode_search_nick_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -7000,9 +9840,11 @@ decode_search_last_els(__TopXMLNS, __IgnoreEls, decode_search_last_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_search_last(Cdata, _xmlns_attrs) -> +encode_search_last(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:search">>, + [], __TopXMLNS), _els = encode_search_last_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"last">>, _attrs, _els}. decode_search_last_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -7030,9 +9872,11 @@ decode_search_first_els(__TopXMLNS, __IgnoreEls, decode_search_first_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_search_first(Cdata, _xmlns_attrs) -> +encode_search_first(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:search">>, + [], __TopXMLNS), _els = encode_search_first_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"first">>, _attrs, _els}. decode_search_first_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -7060,9 +9904,11 @@ decode_search_instructions_els(__TopXMLNS, __IgnoreEls, decode_search_instructions_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_search_instructions(Cdata, _xmlns_attrs) -> +encode_search_instructions(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:search">>, + [], __TopXMLNS), _els = encode_search_instructions_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"instructions">>, _attrs, _els}. decode_search_instructions_cdata(__TopXMLNS, <<>>) -> @@ -7082,9 +9928,11 @@ decode_hint_no_permanent_storage(__TopXMLNS, encode_hint_no_permanent_storage({hint, 'no-permanent-storage'}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:hints">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"no-permanent-storage">>, _attrs, _els}. decode_hint_no_permanent_store(__TopXMLNS, __IgnoreEls, @@ -7094,18 +9942,22 @@ decode_hint_no_permanent_store(__TopXMLNS, __IgnoreEls, encode_hint_no_permanent_store({hint, 'no-permanent-store'}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:hints">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"no-permanent-store">>, _attrs, _els}. decode_hint_store(__TopXMLNS, __IgnoreEls, {xmlel, <<"store">>, _attrs, _els}) -> {hint, store}. -encode_hint_store({hint, store}, _xmlns_attrs) -> +encode_hint_store({hint, store}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:hints">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"store">>, _attrs, _els}. decode_hint_no_storage(__TopXMLNS, __IgnoreEls, @@ -7113,28 +9965,33 @@ decode_hint_no_storage(__TopXMLNS, __IgnoreEls, {hint, 'no-storage'}. encode_hint_no_storage({hint, 'no-storage'}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:hints">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"no-storage">>, _attrs, _els}. decode_hint_no_store(__TopXMLNS, __IgnoreEls, {xmlel, <<"no-store">>, _attrs, _els}) -> {hint, 'no-store'}. -encode_hint_no_store({hint, 'no-store'}, - _xmlns_attrs) -> +encode_hint_no_store({hint, 'no-store'}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:hints">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"no-store">>, _attrs, _els}. decode_hint_no_copy(__TopXMLNS, __IgnoreEls, {xmlel, <<"no-copy">>, _attrs, _els}) -> {hint, 'no-copy'}. -encode_hint_no_copy({hint, 'no-copy'}, _xmlns_attrs) -> +encode_hint_no_copy({hint, 'no-copy'}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:hints">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"no-copy">>, _attrs, _els}. decode_mix_participant(__TopXMLNS, __IgnoreEls, @@ -7161,11 +10018,14 @@ decode_mix_participant_attrs(__TopXMLNS, [], Jid, decode_mix_participant_attr_nick(__TopXMLNS, Nick)}. encode_mix_participant({mix_participant, Jid, Nick}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:mix:0">>, + [], __TopXMLNS), _els = [], _attrs = encode_mix_participant_attr_nick(Nick, encode_mix_participant_attr_jid(Jid, - _xmlns_attrs)), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))), {xmlel, <<"participant">>, _attrs, _els}. decode_mix_participant_attr_jid(__TopXMLNS, @@ -7199,9 +10059,11 @@ decode_mix_leave(__TopXMLNS, __IgnoreEls, {xmlel, <<"leave">>, _attrs, _els}) -> {mix_leave}. -encode_mix_leave({mix_leave}, _xmlns_attrs) -> +encode_mix_leave({mix_leave}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:mix:0">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"leave">>, _attrs, _els}. decode_mix_join(__TopXMLNS, __IgnoreEls, @@ -7247,18 +10109,24 @@ decode_mix_join_attrs(__TopXMLNS, [], Jid) -> decode_mix_join_attr_jid(__TopXMLNS, Jid). encode_mix_join({mix_join, Jid, Subscribe}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:mix:0">>, + [], __TopXMLNS), _els = lists:reverse('encode_mix_join_$subscribe'(Subscribe, - [])), - _attrs = encode_mix_join_attr_jid(Jid, _xmlns_attrs), + __NewTopXMLNS, [])), + _attrs = encode_mix_join_attr_jid(Jid, + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"join">>, _attrs, _els}. -'encode_mix_join_$subscribe'([], _acc) -> _acc; +'encode_mix_join_$subscribe'([], __TopXMLNS, _acc) -> + _acc; 'encode_mix_join_$subscribe'([Subscribe | _els], - _acc) -> - 'encode_mix_join_$subscribe'(_els, - [encode_mix_subscribe(Subscribe, []) | _acc]). + __TopXMLNS, _acc) -> + 'encode_mix_join_$subscribe'(_els, __TopXMLNS, + [encode_mix_subscribe(Subscribe, __TopXMLNS) + | _acc]). decode_mix_join_attr_jid(__TopXMLNS, undefined) -> undefined; @@ -7289,10 +10157,13 @@ decode_mix_subscribe_attrs(__TopXMLNS, [_ | _attrs], decode_mix_subscribe_attrs(__TopXMLNS, [], Node) -> decode_mix_subscribe_attr_node(__TopXMLNS, Node). -encode_mix_subscribe(Node, _xmlns_attrs) -> +encode_mix_subscribe(Node, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:mix:0">>, + [], __TopXMLNS), _els = [], _attrs = encode_mix_subscribe_attr_node(Node, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"subscribe">>, _attrs, _els}. decode_mix_subscribe_attr_node(__TopXMLNS, undefined) -> @@ -7381,26 +10252,35 @@ decode_offline_els(__TopXMLNS, __IgnoreEls, [_ | _els], Purge, Fetch). encode_offline({offline, Items, Purge, Fetch}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/offline">>, + [], __TopXMLNS), _els = lists:reverse('encode_offline_$items'(Items, + __NewTopXMLNS, 'encode_offline_$purge'(Purge, + __NewTopXMLNS, 'encode_offline_$fetch'(Fetch, + __NewTopXMLNS, [])))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"offline">>, _attrs, _els}. -'encode_offline_$items'([], _acc) -> _acc; -'encode_offline_$items'([Items | _els], _acc) -> - 'encode_offline_$items'(_els, - [encode_offline_item(Items, []) | _acc]). +'encode_offline_$items'([], __TopXMLNS, _acc) -> _acc; +'encode_offline_$items'([Items | _els], __TopXMLNS, + _acc) -> + 'encode_offline_$items'(_els, __TopXMLNS, + [encode_offline_item(Items, __TopXMLNS) | _acc]). -'encode_offline_$purge'(false, _acc) -> _acc; -'encode_offline_$purge'(Purge, _acc) -> - [encode_offline_purge(Purge, []) | _acc]. +'encode_offline_$purge'(false, __TopXMLNS, _acc) -> + _acc; +'encode_offline_$purge'(Purge, __TopXMLNS, _acc) -> + [encode_offline_purge(Purge, __TopXMLNS) | _acc]. -'encode_offline_$fetch'(false, _acc) -> _acc; -'encode_offline_$fetch'(Fetch, _acc) -> - [encode_offline_fetch(Fetch, []) | _acc]. +'encode_offline_$fetch'(false, __TopXMLNS, _acc) -> + _acc; +'encode_offline_$fetch'(Fetch, __TopXMLNS, _acc) -> + [encode_offline_fetch(Fetch, __TopXMLNS) | _acc]. decode_offline_item(__TopXMLNS, __IgnoreEls, {xmlel, <<"item">>, _attrs, _els}) -> @@ -7426,11 +10306,15 @@ decode_offline_item_attrs(__TopXMLNS, [], Node, decode_offline_item_attr_action(__TopXMLNS, Action)}. encode_offline_item({offline_item, Node, Action}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/offline">>, + [], __TopXMLNS), _els = [], _attrs = encode_offline_item_attr_action(Action, encode_offline_item_attr_node(Node, - _xmlns_attrs)), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))), {xmlel, <<"item">>, _attrs, _els}. decode_offline_item_attr_node(__TopXMLNS, undefined) -> @@ -7462,18 +10346,24 @@ decode_offline_fetch(__TopXMLNS, __IgnoreEls, {xmlel, <<"fetch">>, _attrs, _els}) -> true. -encode_offline_fetch(true, _xmlns_attrs) -> +encode_offline_fetch(true, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/offline">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"fetch">>, _attrs, _els}. decode_offline_purge(__TopXMLNS, __IgnoreEls, {xmlel, <<"purge">>, _attrs, _els}) -> true. -encode_offline_purge(true, _xmlns_attrs) -> +encode_offline_purge(true, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/offline">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"purge">>, _attrs, _els}. decode_sm_failed(__TopXMLNS, __IgnoreEls, @@ -7793,154 +10683,113 @@ decode_sm_failed_attrs(__TopXMLNS, [], H, Xmlns) -> decode_sm_failed_attr_xmlns(__TopXMLNS, Xmlns)}. encode_sm_failed({sm_failed, Reason, H, Xmlns}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(Xmlns, + [<<"urn:xmpp:sm:2">>, <<"urn:xmpp:sm:3">>], + __TopXMLNS), _els = lists:reverse('encode_sm_failed_$reason'(Reason, - [])), - _attrs = encode_sm_failed_attr_xmlns(Xmlns, - encode_sm_failed_attr_h(H, - _xmlns_attrs)), + __NewTopXMLNS, [])), + _attrs = encode_sm_failed_attr_h(H, + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"failed">>, _attrs, _els}. -'encode_sm_failed_$reason'(undefined, _acc) -> _acc; -'encode_sm_failed_$reason'('bad-request' = Reason, +'encode_sm_failed_$reason'(undefined, __TopXMLNS, _acc) -> - [encode_error_bad_request(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) - | _acc]; -'encode_sm_failed_$reason'(conflict = Reason, _acc) -> - [encode_error_conflict(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) - | _acc]; + _acc; +'encode_sm_failed_$reason'('bad-request' = Reason, + __TopXMLNS, _acc) -> + [encode_error_bad_request(Reason, __TopXMLNS) | _acc]; +'encode_sm_failed_$reason'(conflict = Reason, + __TopXMLNS, _acc) -> + [encode_error_conflict(Reason, __TopXMLNS) | _acc]; 'encode_sm_failed_$reason'('feature-not-implemented' = Reason, - _acc) -> + __TopXMLNS, _acc) -> [encode_error_feature_not_implemented(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) - | _acc]; -'encode_sm_failed_$reason'(forbidden = Reason, _acc) -> - [encode_error_forbidden(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) - | _acc]; -'encode_sm_failed_$reason'({gone, _} = Reason, _acc) -> - [encode_error_gone(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS) | _acc]; +'encode_sm_failed_$reason'(forbidden = Reason, + __TopXMLNS, _acc) -> + [encode_error_forbidden(Reason, __TopXMLNS) | _acc]; +'encode_sm_failed_$reason'({gone, _} = Reason, + __TopXMLNS, _acc) -> + [encode_error_gone(Reason, __TopXMLNS) | _acc]; 'encode_sm_failed_$reason'('internal-server-error' = Reason, - _acc) -> - [encode_error_internal_server_error(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_internal_server_error(Reason, __TopXMLNS) | _acc]; 'encode_sm_failed_$reason'('item-not-found' = Reason, - _acc) -> - [encode_error_item_not_found(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_item_not_found(Reason, __TopXMLNS) | _acc]; 'encode_sm_failed_$reason'('jid-malformed' = Reason, - _acc) -> - [encode_error_jid_malformed(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) - | _acc]; + __TopXMLNS, _acc) -> + [encode_error_jid_malformed(Reason, __TopXMLNS) | _acc]; 'encode_sm_failed_$reason'('not-acceptable' = Reason, - _acc) -> - [encode_error_not_acceptable(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_not_acceptable(Reason, __TopXMLNS) | _acc]; 'encode_sm_failed_$reason'('not-allowed' = Reason, - _acc) -> - [encode_error_not_allowed(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) - | _acc]; + __TopXMLNS, _acc) -> + [encode_error_not_allowed(Reason, __TopXMLNS) | _acc]; 'encode_sm_failed_$reason'('not-authorized' = Reason, - _acc) -> - [encode_error_not_authorized(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_not_authorized(Reason, __TopXMLNS) | _acc]; 'encode_sm_failed_$reason'('policy-violation' = Reason, - _acc) -> - [encode_error_policy_violation(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_policy_violation(Reason, __TopXMLNS) | _acc]; 'encode_sm_failed_$reason'('recipient-unavailable' = Reason, - _acc) -> - [encode_error_recipient_unavailable(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_recipient_unavailable(Reason, __TopXMLNS) | _acc]; 'encode_sm_failed_$reason'({redirect, _} = Reason, - _acc) -> - [encode_error_redirect(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) - | _acc]; + __TopXMLNS, _acc) -> + [encode_error_redirect(Reason, __TopXMLNS) | _acc]; 'encode_sm_failed_$reason'('registration-required' = Reason, - _acc) -> - [encode_error_registration_required(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_registration_required(Reason, __TopXMLNS) | _acc]; 'encode_sm_failed_$reason'('remote-server-not-found' = Reason, - _acc) -> + __TopXMLNS, _acc) -> [encode_error_remote_server_not_found(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS) | _acc]; 'encode_sm_failed_$reason'('remote-server-timeout' = Reason, - _acc) -> - [encode_error_remote_server_timeout(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_remote_server_timeout(Reason, __TopXMLNS) | _acc]; 'encode_sm_failed_$reason'('resource-constraint' = Reason, - _acc) -> - [encode_error_resource_constraint(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_resource_constraint(Reason, __TopXMLNS) | _acc]; 'encode_sm_failed_$reason'('service-unavailable' = Reason, - _acc) -> - [encode_error_service_unavailable(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_service_unavailable(Reason, __TopXMLNS) | _acc]; 'encode_sm_failed_$reason'('subscription-required' = Reason, - _acc) -> - [encode_error_subscription_required(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_subscription_required(Reason, __TopXMLNS) | _acc]; 'encode_sm_failed_$reason'('undefined-condition' = Reason, - _acc) -> - [encode_error_undefined_condition(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_undefined_condition(Reason, __TopXMLNS) | _acc]; 'encode_sm_failed_$reason'('unexpected-request' = Reason, - _acc) -> - [encode_error_unexpected_request(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_unexpected_request(Reason, __TopXMLNS) | _acc]. decode_sm_failed_attr_h(__TopXMLNS, undefined) -> @@ -7961,10 +10810,6 @@ decode_sm_failed_attr_xmlns(__TopXMLNS, undefined) -> <<>>; decode_sm_failed_attr_xmlns(__TopXMLNS, _val) -> _val. -encode_sm_failed_attr_xmlns(<<>>, _acc) -> _acc; -encode_sm_failed_attr_xmlns(_val, _acc) -> - [{<<"xmlns">>, _val} | _acc]. - decode_sm_a(__TopXMLNS, __IgnoreEls, {xmlel, <<"a">>, _attrs, _els}) -> {H, Xmlns} = decode_sm_a_attrs(__TopXMLNS, _attrs, @@ -7983,10 +10828,13 @@ decode_sm_a_attrs(__TopXMLNS, [], H, Xmlns) -> {decode_sm_a_attr_h(__TopXMLNS, H), decode_sm_a_attr_xmlns(__TopXMLNS, Xmlns)}. -encode_sm_a({sm_a, H, Xmlns}, _xmlns_attrs) -> +encode_sm_a({sm_a, H, Xmlns}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(Xmlns, + [<<"urn:xmpp:sm:2">>, <<"urn:xmpp:sm:3">>], + __TopXMLNS), _els = [], - _attrs = encode_sm_a_attr_xmlns(Xmlns, - encode_sm_a_attr_h(H, _xmlns_attrs)), + _attrs = encode_sm_a_attr_h(H, + enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS)), {xmlel, <<"a">>, _attrs, _els}. decode_sm_a_attr_h(__TopXMLNS, undefined) -> @@ -8006,10 +10854,6 @@ encode_sm_a_attr_h(_val, _acc) -> decode_sm_a_attr_xmlns(__TopXMLNS, undefined) -> <<>>; decode_sm_a_attr_xmlns(__TopXMLNS, _val) -> _val. -encode_sm_a_attr_xmlns(<<>>, _acc) -> _acc; -encode_sm_a_attr_xmlns(_val, _acc) -> - [{<<"xmlns">>, _val} | _acc]. - decode_sm_r(__TopXMLNS, __IgnoreEls, {xmlel, <<"r">>, _attrs, _els}) -> Xmlns = decode_sm_r_attrs(__TopXMLNS, _attrs, @@ -8024,18 +10868,17 @@ decode_sm_r_attrs(__TopXMLNS, [_ | _attrs], Xmlns) -> decode_sm_r_attrs(__TopXMLNS, [], Xmlns) -> decode_sm_r_attr_xmlns(__TopXMLNS, Xmlns). -encode_sm_r({sm_r, Xmlns}, _xmlns_attrs) -> +encode_sm_r({sm_r, Xmlns}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(Xmlns, + [<<"urn:xmpp:sm:2">>, <<"urn:xmpp:sm:3">>], + __TopXMLNS), _els = [], - _attrs = encode_sm_r_attr_xmlns(Xmlns, _xmlns_attrs), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"r">>, _attrs, _els}. decode_sm_r_attr_xmlns(__TopXMLNS, undefined) -> <<>>; decode_sm_r_attr_xmlns(__TopXMLNS, _val) -> _val. -encode_sm_r_attr_xmlns(<<>>, _acc) -> _acc; -encode_sm_r_attr_xmlns(_val, _acc) -> - [{<<"xmlns">>, _val} | _acc]. - decode_sm_resumed(__TopXMLNS, __IgnoreEls, {xmlel, <<"resumed">>, _attrs, _els}) -> {H, Xmlns, Previd} = decode_sm_resumed_attrs(__TopXMLNS, @@ -8066,12 +10909,15 @@ decode_sm_resumed_attrs(__TopXMLNS, [], H, Xmlns, decode_sm_resumed_attr_previd(__TopXMLNS, Previd)}. encode_sm_resumed({sm_resumed, H, Previd, Xmlns}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(Xmlns, + [<<"urn:xmpp:sm:2">>, <<"urn:xmpp:sm:3">>], + __TopXMLNS), _els = [], _attrs = encode_sm_resumed_attr_previd(Previd, - encode_sm_resumed_attr_xmlns(Xmlns, - encode_sm_resumed_attr_h(H, - _xmlns_attrs))), + encode_sm_resumed_attr_h(H, + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))), {xmlel, <<"resumed">>, _attrs, _els}. decode_sm_resumed_attr_h(__TopXMLNS, undefined) -> @@ -8092,10 +10938,6 @@ decode_sm_resumed_attr_xmlns(__TopXMLNS, undefined) -> <<>>; decode_sm_resumed_attr_xmlns(__TopXMLNS, _val) -> _val. -encode_sm_resumed_attr_xmlns(<<>>, _acc) -> _acc; -encode_sm_resumed_attr_xmlns(_val, _acc) -> - [{<<"xmlns">>, _val} | _acc]. - decode_sm_resumed_attr_previd(__TopXMLNS, undefined) -> erlang:error({xmpp_codec, {missing_attr, <<"previd">>, <<"resumed">>, @@ -8135,12 +10977,15 @@ decode_sm_resume_attrs(__TopXMLNS, [], H, Xmlns, decode_sm_resume_attr_previd(__TopXMLNS, Previd)}. encode_sm_resume({sm_resume, H, Previd, Xmlns}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(Xmlns, + [<<"urn:xmpp:sm:2">>, <<"urn:xmpp:sm:3">>], + __TopXMLNS), _els = [], _attrs = encode_sm_resume_attr_previd(Previd, - encode_sm_resume_attr_xmlns(Xmlns, - encode_sm_resume_attr_h(H, - _xmlns_attrs))), + encode_sm_resume_attr_h(H, + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))), {xmlel, <<"resume">>, _attrs, _els}. decode_sm_resume_attr_h(__TopXMLNS, undefined) -> @@ -8161,10 +11006,6 @@ decode_sm_resume_attr_xmlns(__TopXMLNS, undefined) -> <<>>; decode_sm_resume_attr_xmlns(__TopXMLNS, _val) -> _val. -encode_sm_resume_attr_xmlns(<<>>, _acc) -> _acc; -encode_sm_resume_attr_xmlns(_val, _acc) -> - [{<<"xmlns">>, _val} | _acc]. - decode_sm_resume_attr_previd(__TopXMLNS, undefined) -> erlang:error({xmpp_codec, {missing_attr, <<"previd">>, <<"resume">>, @@ -8220,14 +11061,17 @@ decode_sm_enabled_attrs(__TopXMLNS, [], Id, Location, encode_sm_enabled({sm_enabled, Id, Location, Max, Resume, Xmlns}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(Xmlns, + [<<"urn:xmpp:sm:2">>, <<"urn:xmpp:sm:3">>], + __TopXMLNS), _els = [], _attrs = encode_sm_enabled_attr_resume(Resume, encode_sm_enabled_attr_max(Max, - encode_sm_enabled_attr_xmlns(Xmlns, - encode_sm_enabled_attr_location(Location, - encode_sm_enabled_attr_id(Id, - _xmlns_attrs))))), + encode_sm_enabled_attr_location(Location, + encode_sm_enabled_attr_id(Id, + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))))), {xmlel, <<"enabled">>, _attrs, _els}. decode_sm_enabled_attr_id(__TopXMLNS, undefined) -> @@ -8252,10 +11096,6 @@ decode_sm_enabled_attr_xmlns(__TopXMLNS, undefined) -> <<>>; decode_sm_enabled_attr_xmlns(__TopXMLNS, _val) -> _val. -encode_sm_enabled_attr_xmlns(<<>>, _acc) -> _acc; -encode_sm_enabled_attr_xmlns(_val, _acc) -> - [{<<"xmlns">>, _val} | _acc]. - decode_sm_enabled_attr_max(__TopXMLNS, undefined) -> undefined; decode_sm_enabled_attr_max(__TopXMLNS, _val) -> @@ -8316,12 +11156,15 @@ decode_sm_enable_attrs(__TopXMLNS, [], Max, Xmlns, decode_sm_enable_attr_resume(__TopXMLNS, Resume)}. encode_sm_enable({sm_enable, Max, Resume, Xmlns}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(Xmlns, + [<<"urn:xmpp:sm:2">>, <<"urn:xmpp:sm:3">>], + __TopXMLNS), _els = [], _attrs = encode_sm_enable_attr_resume(Resume, - encode_sm_enable_attr_xmlns(Xmlns, - encode_sm_enable_attr_max(Max, - _xmlns_attrs))), + encode_sm_enable_attr_max(Max, + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))), {xmlel, <<"enable">>, _attrs, _els}. decode_sm_enable_attr_max(__TopXMLNS, undefined) -> @@ -8342,10 +11185,6 @@ decode_sm_enable_attr_xmlns(__TopXMLNS, undefined) -> <<>>; decode_sm_enable_attr_xmlns(__TopXMLNS, _val) -> _val. -encode_sm_enable_attr_xmlns(<<>>, _acc) -> _acc; -encode_sm_enable_attr_xmlns(_val, _acc) -> - [{<<"xmlns">>, _val} | _acc]. - decode_sm_enable_attr_resume(__TopXMLNS, undefined) -> false; decode_sm_enable_attr_resume(__TopXMLNS, _val) -> @@ -8376,36 +11215,38 @@ decode_feature_sm_attrs(__TopXMLNS, [_ | _attrs], decode_feature_sm_attrs(__TopXMLNS, [], Xmlns) -> decode_feature_sm_attr_xmlns(__TopXMLNS, Xmlns). -encode_feature_sm({feature_sm, Xmlns}, _xmlns_attrs) -> +encode_feature_sm({feature_sm, Xmlns}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(Xmlns, + [<<"urn:xmpp:sm:2">>, <<"urn:xmpp:sm:3">>], + __TopXMLNS), _els = [], - _attrs = encode_feature_sm_attr_xmlns(Xmlns, - _xmlns_attrs), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"sm">>, _attrs, _els}. decode_feature_sm_attr_xmlns(__TopXMLNS, undefined) -> <<>>; decode_feature_sm_attr_xmlns(__TopXMLNS, _val) -> _val. -encode_feature_sm_attr_xmlns(<<>>, _acc) -> _acc; -encode_feature_sm_attr_xmlns(_val, _acc) -> - [{<<"xmlns">>, _val} | _acc]. - decode_csi_inactive(__TopXMLNS, __IgnoreEls, {xmlel, <<"inactive">>, _attrs, _els}) -> {csi, inactive}. -encode_csi_inactive({csi, inactive}, _xmlns_attrs) -> +encode_csi_inactive({csi, inactive}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:csi:0">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"inactive">>, _attrs, _els}. decode_csi_active(__TopXMLNS, __IgnoreEls, {xmlel, <<"active">>, _attrs, _els}) -> {csi, active}. -encode_csi_active({csi, active}, _xmlns_attrs) -> +encode_csi_active({csi, active}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:csi:0">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"active">>, _attrs, _els}. decode_feature_csi(__TopXMLNS, __IgnoreEls, @@ -8423,21 +11264,17 @@ decode_feature_csi_attrs(__TopXMLNS, [_ | _attrs], decode_feature_csi_attrs(__TopXMLNS, [], Xmlns) -> decode_feature_csi_attr_xmlns(__TopXMLNS, Xmlns). -encode_feature_csi({feature_csi, Xmlns}, - _xmlns_attrs) -> +encode_feature_csi({feature_csi, Xmlns}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(Xmlns, + [<<"urn:xmpp:csi:0">>], __TopXMLNS), _els = [], - _attrs = encode_feature_csi_attr_xmlns(Xmlns, - _xmlns_attrs), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"csi">>, _attrs, _els}. decode_feature_csi_attr_xmlns(__TopXMLNS, undefined) -> <<>>; decode_feature_csi_attr_xmlns(__TopXMLNS, _val) -> _val. -encode_feature_csi_attr_xmlns(<<>>, _acc) -> _acc; -encode_feature_csi_attr_xmlns(_val, _acc) -> - [{<<"xmlns">>, _val} | _acc]. - decode_carbons_sent(__TopXMLNS, __IgnoreEls, {xmlel, <<"sent">>, _attrs, _els}) -> Forwarded = decode_carbons_sent_els(__TopXMLNS, @@ -8471,17 +11308,19 @@ decode_carbons_sent_els(__TopXMLNS, __IgnoreEls, Forwarded). encode_carbons_sent({carbons_sent, Forwarded}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:xmpp:carbons:2">>, [], + __TopXMLNS), _els = lists:reverse('encode_carbons_sent_$forwarded'(Forwarded, - [])), - _attrs = _xmlns_attrs, + __NewTopXMLNS, [])), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"sent">>, _attrs, _els}. -'encode_carbons_sent_$forwarded'(Forwarded, _acc) -> - [encode_forwarded(Forwarded, - [{<<"xmlns">>, <<"urn:xmpp:forward:0">>}]) - | _acc]. +'encode_carbons_sent_$forwarded'(Forwarded, __TopXMLNS, + _acc) -> + [encode_forwarded(Forwarded, __TopXMLNS) | _acc]. decode_carbons_received(__TopXMLNS, __IgnoreEls, {xmlel, <<"received">>, _attrs, _els}) -> @@ -8517,45 +11356,54 @@ decode_carbons_received_els(__TopXMLNS, __IgnoreEls, _els, Forwarded). encode_carbons_received({carbons_received, Forwarded}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:xmpp:carbons:2">>, [], + __TopXMLNS), _els = lists:reverse('encode_carbons_received_$forwarded'(Forwarded, - [])), - _attrs = _xmlns_attrs, + __NewTopXMLNS, [])), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"received">>, _attrs, _els}. -'encode_carbons_received_$forwarded'(Forwarded, _acc) -> - [encode_forwarded(Forwarded, - [{<<"xmlns">>, <<"urn:xmpp:forward:0">>}]) - | _acc]. +'encode_carbons_received_$forwarded'(Forwarded, + __TopXMLNS, _acc) -> + [encode_forwarded(Forwarded, __TopXMLNS) | _acc]. decode_carbons_private(__TopXMLNS, __IgnoreEls, {xmlel, <<"private">>, _attrs, _els}) -> {carbons_private}. -encode_carbons_private({carbons_private}, - _xmlns_attrs) -> +encode_carbons_private({carbons_private}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:xmpp:carbons:2">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"private">>, _attrs, _els}. decode_carbons_enable(__TopXMLNS, __IgnoreEls, {xmlel, <<"enable">>, _attrs, _els}) -> {carbons_enable}. -encode_carbons_enable({carbons_enable}, _xmlns_attrs) -> +encode_carbons_enable({carbons_enable}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:xmpp:carbons:2">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"enable">>, _attrs, _els}. decode_carbons_disable(__TopXMLNS, __IgnoreEls, {xmlel, <<"disable">>, _attrs, _els}) -> {carbons_disable}. -encode_carbons_disable({carbons_disable}, - _xmlns_attrs) -> +encode_carbons_disable({carbons_disable}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:xmpp:carbons:2">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"disable">>, _attrs, _els}. decode_forwarded(__TopXMLNS, __IgnoreEls, @@ -8586,10 +11434,11 @@ decode_forwarded_els(__TopXMLNS, __IgnoreEls, decode_forwarded_els(__TopXMLNS, __IgnoreEls, _els, Delay, [_el | __Els]); true -> - case is_known_tag(_el) of + case is_known_tag(_el, __TopXMLNS) of true -> decode_forwarded_els(__TopXMLNS, __IgnoreEls, _els, - Delay, [decode(_el) | __Els]); + Delay, + [decode(_el, __TopXMLNS, []) | __Els]); false -> decode_forwarded_els(__TopXMLNS, __IgnoreEls, _els, Delay, __Els) @@ -8601,17 +11450,21 @@ decode_forwarded_els(__TopXMLNS, __IgnoreEls, Delay, __Els). encode_forwarded({forwarded, Delay, __Els}, - _xmlns_attrs) -> - _els = [encode(_el) || _el <- __Els] ++ - lists:reverse('encode_forwarded_$delay'(Delay, [])), - _attrs = _xmlns_attrs, + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:xmpp:forward:0">>, [], + __TopXMLNS), + _els = [encode(_el, __NewTopXMLNS) || _el <- __Els] ++ + lists:reverse('encode_forwarded_$delay'(Delay, + __NewTopXMLNS, [])), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"forwarded">>, _attrs, _els}. -'encode_forwarded_$delay'(undefined, _acc) -> _acc; -'encode_forwarded_$delay'(Delay, _acc) -> - [encode_delay(Delay, - [{<<"xmlns">>, <<"urn:xmpp:delay">>}]) - | _acc]. +'encode_forwarded_$delay'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_forwarded_$delay'(Delay, __TopXMLNS, _acc) -> + [encode_delay(Delay, __TopXMLNS) | _acc]. decode_mam_fin(__TopXMLNS, __IgnoreEls, {xmlel, <<"fin">>, _attrs, _els}) -> @@ -8671,20 +11524,24 @@ decode_mam_fin_attrs(__TopXMLNS, [], Id, Xmlns, Stable, encode_mam_fin({mam_fin, Xmlns, Id, Rsm, Stable, Complete}, - _xmlns_attrs) -> - _els = lists:reverse('encode_mam_fin_$rsm'(Rsm, [])), + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(Xmlns, + [<<"urn:xmpp:mam:0">>, + <<"urn:xmpp:mam:1">>], + __TopXMLNS), + _els = lists:reverse('encode_mam_fin_$rsm'(Rsm, + __NewTopXMLNS, [])), _attrs = encode_mam_fin_attr_complete(Complete, encode_mam_fin_attr_stable(Stable, - encode_mam_fin_attr_xmlns(Xmlns, - encode_mam_fin_attr_queryid(Id, - _xmlns_attrs)))), + encode_mam_fin_attr_queryid(Id, + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)))), {xmlel, <<"fin">>, _attrs, _els}. -'encode_mam_fin_$rsm'(undefined, _acc) -> _acc; -'encode_mam_fin_$rsm'(Rsm, _acc) -> - [encode_rsm_set(Rsm, - [{<<"xmlns">>, <<"http://jabber.org/protocol/rsm">>}]) - | _acc]. +'encode_mam_fin_$rsm'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_mam_fin_$rsm'(Rsm, __TopXMLNS, _acc) -> + [encode_rsm_set(Rsm, __TopXMLNS) | _acc]. decode_mam_fin_attr_queryid(__TopXMLNS, undefined) -> <<>>; @@ -8698,10 +11555,6 @@ decode_mam_fin_attr_xmlns(__TopXMLNS, undefined) -> <<>>; decode_mam_fin_attr_xmlns(__TopXMLNS, _val) -> _val. -encode_mam_fin_attr_xmlns(<<>>, _acc) -> _acc; -encode_mam_fin_attr_xmlns(_val, _acc) -> - [{<<"xmlns">>, _val} | _acc]. - decode_mam_fin_attr_stable(__TopXMLNS, undefined) -> undefined; decode_mam_fin_attr_stable(__TopXMLNS, _val) -> @@ -8826,22 +11679,33 @@ decode_mam_prefs_attrs(__TopXMLNS, [], Default, encode_mam_prefs({mam_prefs, Xmlns, Default, Always, Never}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(Xmlns, + [<<"urn:xmpp:mam:0">>, + <<"urn:xmpp:mam:1">>, + <<"urn:xmpp:mam:tmp">>], + __TopXMLNS), _els = lists:reverse('encode_mam_prefs_$never'(Never, + __NewTopXMLNS, 'encode_mam_prefs_$always'(Always, + __NewTopXMLNS, []))), - _attrs = encode_mam_prefs_attr_xmlns(Xmlns, - encode_mam_prefs_attr_default(Default, - _xmlns_attrs)), + _attrs = encode_mam_prefs_attr_default(Default, + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"prefs">>, _attrs, _els}. -'encode_mam_prefs_$never'(undefined, _acc) -> _acc; -'encode_mam_prefs_$never'(Never, _acc) -> - [encode_mam_never(Never, []) | _acc]. +'encode_mam_prefs_$never'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_mam_prefs_$never'(Never, __TopXMLNS, _acc) -> + [encode_mam_never(Never, __TopXMLNS) | _acc]. -'encode_mam_prefs_$always'(undefined, _acc) -> _acc; -'encode_mam_prefs_$always'(Always, _acc) -> - [encode_mam_always(Always, []) | _acc]. +'encode_mam_prefs_$always'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_mam_prefs_$always'(Always, __TopXMLNS, _acc) -> + [encode_mam_always(Always, __TopXMLNS) | _acc]. decode_mam_prefs_attr_default(__TopXMLNS, undefined) -> undefined; @@ -8862,10 +11726,6 @@ decode_mam_prefs_attr_xmlns(__TopXMLNS, undefined) -> <<>>; decode_mam_prefs_attr_xmlns(__TopXMLNS, _val) -> _val. -encode_mam_prefs_attr_xmlns(<<>>, _acc) -> _acc; -encode_mam_prefs_attr_xmlns(_val, _acc) -> - [{<<"xmlns">>, _val} | _acc]. - decode_mam_always(__TopXMLNS, __IgnoreEls, {xmlel, <<"always">>, _attrs, _els}) -> Jids = decode_mam_always_els(__TopXMLNS, __IgnoreEls, @@ -8909,16 +11769,22 @@ decode_mam_always_els(__TopXMLNS, __IgnoreEls, decode_mam_always_els(__TopXMLNS, __IgnoreEls, _els, Jids). -encode_mam_always(Jids, _xmlns_attrs) -> +encode_mam_always(Jids, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"urn:xmpp:mam:0">>, + <<"urn:xmpp:mam:1">>, + <<"urn:xmpp:mam:tmp">>], + __TopXMLNS), _els = lists:reverse('encode_mam_always_$jids'(Jids, - [])), - _attrs = _xmlns_attrs, + __NewTopXMLNS, [])), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"always">>, _attrs, _els}. -'encode_mam_always_$jids'([], _acc) -> _acc; -'encode_mam_always_$jids'([Jids | _els], _acc) -> - 'encode_mam_always_$jids'(_els, - [encode_mam_jid(Jids, []) | _acc]). +'encode_mam_always_$jids'([], __TopXMLNS, _acc) -> _acc; +'encode_mam_always_$jids'([Jids | _els], __TopXMLNS, + _acc) -> + 'encode_mam_always_$jids'(_els, __TopXMLNS, + [encode_mam_jid(Jids, __TopXMLNS) | _acc]). decode_mam_never(__TopXMLNS, __IgnoreEls, {xmlel, <<"never">>, _attrs, _els}) -> @@ -8963,16 +11829,22 @@ decode_mam_never_els(__TopXMLNS, __IgnoreEls, decode_mam_never_els(__TopXMLNS, __IgnoreEls, _els, Jids). -encode_mam_never(Jids, _xmlns_attrs) -> +encode_mam_never(Jids, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"urn:xmpp:mam:0">>, + <<"urn:xmpp:mam:1">>, + <<"urn:xmpp:mam:tmp">>], + __TopXMLNS), _els = lists:reverse('encode_mam_never_$jids'(Jids, - [])), - _attrs = _xmlns_attrs, + __NewTopXMLNS, [])), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"never">>, _attrs, _els}. -'encode_mam_never_$jids'([], _acc) -> _acc; -'encode_mam_never_$jids'([Jids | _els], _acc) -> - 'encode_mam_never_$jids'(_els, - [encode_mam_jid(Jids, []) | _acc]). +'encode_mam_never_$jids'([], __TopXMLNS, _acc) -> _acc; +'encode_mam_never_$jids'([Jids | _els], __TopXMLNS, + _acc) -> + 'encode_mam_never_$jids'(_els, __TopXMLNS, + [encode_mam_jid(Jids, __TopXMLNS) | _acc]). decode_mam_jid(__TopXMLNS, __IgnoreEls, {xmlel, <<"jid">>, _attrs, _els}) -> @@ -8992,9 +11864,14 @@ decode_mam_jid_els(__TopXMLNS, __IgnoreEls, [_ | _els], decode_mam_jid_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_mam_jid(Cdata, _xmlns_attrs) -> +encode_mam_jid(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"urn:xmpp:mam:0">>, + <<"urn:xmpp:mam:1">>, + <<"urn:xmpp:mam:tmp">>], + __TopXMLNS), _els = encode_mam_jid_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"jid">>, _attrs, _els}. decode_mam_jid_cdata(__TopXMLNS, <<>>) -> @@ -9029,10 +11906,10 @@ decode_mam_result_els(__TopXMLNS, __IgnoreEls, decode_mam_result_els(__TopXMLNS, __IgnoreEls, _els, [_el | __Els]); true -> - case is_known_tag(_el) of + case is_known_tag(_el, __TopXMLNS) of true -> decode_mam_result_els(__TopXMLNS, __IgnoreEls, _els, - [decode(_el) | __Els]); + [decode(_el, __TopXMLNS, []) | __Els]); false -> decode_mam_result_els(__TopXMLNS, __IgnoreEls, _els, __Els) @@ -9068,12 +11945,17 @@ decode_mam_result_attrs(__TopXMLNS, [], Queryid, Xmlns, encode_mam_result({mam_result, Xmlns, Queryid, Id, __Els}, - _xmlns_attrs) -> - _els = [encode(_el) || _el <- __Els], + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(Xmlns, + [<<"urn:xmpp:mam:0">>, + <<"urn:xmpp:mam:1">>, + <<"urn:xmpp:mam:tmp">>], + __TopXMLNS), + _els = [encode(_el, __NewTopXMLNS) || _el <- __Els], _attrs = encode_mam_result_attr_id(Id, - encode_mam_result_attr_xmlns(Xmlns, - encode_mam_result_attr_queryid(Queryid, - _xmlns_attrs))), + encode_mam_result_attr_queryid(Queryid, + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))), {xmlel, <<"result">>, _attrs, _els}. decode_mam_result_attr_queryid(__TopXMLNS, undefined) -> @@ -9089,10 +11971,6 @@ decode_mam_result_attr_xmlns(__TopXMLNS, undefined) -> <<>>; decode_mam_result_attr_xmlns(__TopXMLNS, _val) -> _val. -encode_mam_result_attr_xmlns(<<>>, _acc) -> _acc; -encode_mam_result_attr_xmlns(_val, _acc) -> - [{<<"xmlns">>, _val} | _acc]. - decode_mam_result_attr_id(__TopXMLNS, undefined) -> <<>>; decode_mam_result_attr_id(__TopXMLNS, _val) -> _val. @@ -9121,11 +11999,14 @@ decode_mam_archived_attrs(__TopXMLNS, [], Id, By) -> decode_mam_archived_attr_by(__TopXMLNS, By)}. encode_mam_archived({mam_archived, By, Id}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:mam:tmp">>, + [], __TopXMLNS), _els = [], _attrs = encode_mam_archived_attr_by(By, encode_mam_archived_attr_id(Id, - _xmlns_attrs)), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))), {xmlel, <<"archived">>, _attrs, _els}. decode_mam_archived_attr_id(__TopXMLNS, undefined) -> @@ -9288,46 +12169,63 @@ decode_mam_query_attrs(__TopXMLNS, [], Id, Xmlns) -> encode_mam_query({mam_query, Xmlns, Id, Start, End, With, Withtext, Rsm, Xdata}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(Xmlns, + [<<"urn:xmpp:mam:0">>, + <<"urn:xmpp:mam:1">>, + <<"urn:xmpp:mam:tmp">>], + __TopXMLNS), _els = lists:reverse('encode_mam_query_$xdata'(Xdata, + __NewTopXMLNS, 'encode_mam_query_$withtext'(Withtext, + __NewTopXMLNS, 'encode_mam_query_$end'(End, + __NewTopXMLNS, 'encode_mam_query_$start'(Start, + __NewTopXMLNS, 'encode_mam_query_$with'(With, + __NewTopXMLNS, 'encode_mam_query_$rsm'(Rsm, + __NewTopXMLNS, []))))))), - _attrs = encode_mam_query_attr_xmlns(Xmlns, - encode_mam_query_attr_queryid(Id, - _xmlns_attrs)), + _attrs = encode_mam_query_attr_queryid(Id, + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"query">>, _attrs, _els}. -'encode_mam_query_$xdata'(undefined, _acc) -> _acc; -'encode_mam_query_$xdata'(Xdata, _acc) -> - [encode_xdata(Xdata, - [{<<"xmlns">>, <<"jabber:x:data">>}]) - | _acc]. +'encode_mam_query_$xdata'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_mam_query_$xdata'(Xdata, __TopXMLNS, _acc) -> + [encode_xdata(Xdata, __TopXMLNS) | _acc]. -'encode_mam_query_$withtext'(undefined, _acc) -> _acc; -'encode_mam_query_$withtext'(Withtext, _acc) -> - [encode_mam_withtext(Withtext, []) | _acc]. +'encode_mam_query_$withtext'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_mam_query_$withtext'(Withtext, __TopXMLNS, + _acc) -> + [encode_mam_withtext(Withtext, __TopXMLNS) | _acc]. -'encode_mam_query_$end'(undefined, _acc) -> _acc; -'encode_mam_query_$end'(End, _acc) -> - [encode_mam_end(End, []) | _acc]. +'encode_mam_query_$end'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_mam_query_$end'(End, __TopXMLNS, _acc) -> + [encode_mam_end(End, __TopXMLNS) | _acc]. -'encode_mam_query_$start'(undefined, _acc) -> _acc; -'encode_mam_query_$start'(Start, _acc) -> - [encode_mam_start(Start, []) | _acc]. +'encode_mam_query_$start'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_mam_query_$start'(Start, __TopXMLNS, _acc) -> + [encode_mam_start(Start, __TopXMLNS) | _acc]. -'encode_mam_query_$with'(undefined, _acc) -> _acc; -'encode_mam_query_$with'(With, _acc) -> - [encode_mam_with(With, []) | _acc]. +'encode_mam_query_$with'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_mam_query_$with'(With, __TopXMLNS, _acc) -> + [encode_mam_with(With, __TopXMLNS) | _acc]. -'encode_mam_query_$rsm'(undefined, _acc) -> _acc; -'encode_mam_query_$rsm'(Rsm, _acc) -> - [encode_rsm_set(Rsm, - [{<<"xmlns">>, <<"http://jabber.org/protocol/rsm">>}]) - | _acc]. +'encode_mam_query_$rsm'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_mam_query_$rsm'(Rsm, __TopXMLNS, _acc) -> + [encode_rsm_set(Rsm, __TopXMLNS) | _acc]. decode_mam_query_attr_queryid(__TopXMLNS, undefined) -> <<>>; @@ -9341,10 +12239,6 @@ decode_mam_query_attr_xmlns(__TopXMLNS, undefined) -> <<>>; decode_mam_query_attr_xmlns(__TopXMLNS, _val) -> _val. -encode_mam_query_attr_xmlns(<<>>, _acc) -> _acc; -encode_mam_query_attr_xmlns(_val, _acc) -> - [{<<"xmlns">>, _val} | _acc]. - decode_mam_withtext(__TopXMLNS, __IgnoreEls, {xmlel, <<"withtext">>, _attrs, _els}) -> Cdata = decode_mam_withtext_els(__TopXMLNS, __IgnoreEls, @@ -9363,9 +12257,11 @@ decode_mam_withtext_els(__TopXMLNS, __IgnoreEls, decode_mam_withtext_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_mam_withtext(Cdata, _xmlns_attrs) -> +encode_mam_withtext(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:mam:tmp">>, + [], __TopXMLNS), _els = encode_mam_withtext_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"withtext">>, _attrs, _els}. decode_mam_withtext_cdata(__TopXMLNS, <<>>) -> @@ -9394,9 +12290,11 @@ decode_mam_with_els(__TopXMLNS, __IgnoreEls, [_ | _els], decode_mam_with_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_mam_with(Cdata, _xmlns_attrs) -> +encode_mam_with(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:mam:tmp">>, + [], __TopXMLNS), _els = encode_mam_with_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"with">>, _attrs, _els}. decode_mam_with_cdata(__TopXMLNS, <<>>) -> @@ -9431,9 +12329,11 @@ decode_mam_end_els(__TopXMLNS, __IgnoreEls, [_ | _els], decode_mam_end_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_mam_end(Cdata, _xmlns_attrs) -> +encode_mam_end(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:mam:tmp">>, + [], __TopXMLNS), _els = encode_mam_end_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"end">>, _attrs, _els}. decode_mam_end_cdata(__TopXMLNS, <<>>) -> @@ -9468,9 +12368,11 @@ decode_mam_start_els(__TopXMLNS, __IgnoreEls, decode_mam_start_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_mam_start(Cdata, _xmlns_attrs) -> +encode_mam_start(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:mam:tmp">>, + [], __TopXMLNS), _els = encode_mam_start_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"start">>, _attrs, _els}. decode_mam_start_cdata(__TopXMLNS, <<>>) -> @@ -9647,45 +12549,62 @@ decode_rsm_set_els(__TopXMLNS, __IgnoreEls, [_ | _els], encode_rsm_set({rsm_set, After, Before, Count, First, Index, Last, Max}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/rsm">>, + [], __TopXMLNS), _els = lists:reverse('encode_rsm_set_$after'(After, + __NewTopXMLNS, 'encode_rsm_set_$last'(Last, + __NewTopXMLNS, 'encode_rsm_set_$first'(First, + __NewTopXMLNS, 'encode_rsm_set_$count'(Count, + __NewTopXMLNS, 'encode_rsm_set_$before'(Before, + __NewTopXMLNS, 'encode_rsm_set_$max'(Max, + __NewTopXMLNS, 'encode_rsm_set_$index'(Index, + __NewTopXMLNS, [])))))))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"set">>, _attrs, _els}. -'encode_rsm_set_$after'(undefined, _acc) -> _acc; -'encode_rsm_set_$after'(After, _acc) -> - [encode_rsm_after(After, []) | _acc]. +'encode_rsm_set_$after'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_rsm_set_$after'(After, __TopXMLNS, _acc) -> + [encode_rsm_after(After, __TopXMLNS) | _acc]. -'encode_rsm_set_$last'(undefined, _acc) -> _acc; -'encode_rsm_set_$last'(Last, _acc) -> - [encode_rsm_last(Last, []) | _acc]. +'encode_rsm_set_$last'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_rsm_set_$last'(Last, __TopXMLNS, _acc) -> + [encode_rsm_last(Last, __TopXMLNS) | _acc]. -'encode_rsm_set_$first'(undefined, _acc) -> _acc; -'encode_rsm_set_$first'(First, _acc) -> - [encode_rsm_first(First, []) | _acc]. +'encode_rsm_set_$first'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_rsm_set_$first'(First, __TopXMLNS, _acc) -> + [encode_rsm_first(First, __TopXMLNS) | _acc]. -'encode_rsm_set_$count'(undefined, _acc) -> _acc; -'encode_rsm_set_$count'(Count, _acc) -> - [encode_rsm_count(Count, []) | _acc]. +'encode_rsm_set_$count'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_rsm_set_$count'(Count, __TopXMLNS, _acc) -> + [encode_rsm_count(Count, __TopXMLNS) | _acc]. -'encode_rsm_set_$before'(undefined, _acc) -> _acc; -'encode_rsm_set_$before'(Before, _acc) -> - [encode_rsm_before(Before, []) | _acc]. +'encode_rsm_set_$before'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_rsm_set_$before'(Before, __TopXMLNS, _acc) -> + [encode_rsm_before(Before, __TopXMLNS) | _acc]. -'encode_rsm_set_$max'(undefined, _acc) -> _acc; -'encode_rsm_set_$max'(Max, _acc) -> - [encode_rsm_max(Max, []) | _acc]. +'encode_rsm_set_$max'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_rsm_set_$max'(Max, __TopXMLNS, _acc) -> + [encode_rsm_max(Max, __TopXMLNS) | _acc]. -'encode_rsm_set_$index'(undefined, _acc) -> _acc; -'encode_rsm_set_$index'(Index, _acc) -> - [encode_rsm_index(Index, []) | _acc]. +'encode_rsm_set_$index'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_rsm_set_$index'(Index, __TopXMLNS, _acc) -> + [encode_rsm_index(Index, __TopXMLNS) | _acc]. decode_rsm_first(__TopXMLNS, __IgnoreEls, {xmlel, <<"first">>, _attrs, _els}) -> @@ -9717,10 +12636,14 @@ decode_rsm_first_attrs(__TopXMLNS, [], Index) -> decode_rsm_first_attr_index(__TopXMLNS, Index). encode_rsm_first({rsm_first, Index, Data}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/rsm">>, + [], __TopXMLNS), _els = encode_rsm_first_cdata(Data, []), _attrs = encode_rsm_first_attr_index(Index, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"first">>, _attrs, _els}. decode_rsm_first_attr_index(__TopXMLNS, undefined) -> @@ -9763,9 +12686,12 @@ decode_rsm_max_els(__TopXMLNS, __IgnoreEls, [_ | _els], decode_rsm_max_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_rsm_max(Cdata, _xmlns_attrs) -> +encode_rsm_max(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/rsm">>, + [], __TopXMLNS), _els = encode_rsm_max_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"max">>, _attrs, _els}. decode_rsm_max_cdata(__TopXMLNS, <<>>) -> undefined; @@ -9799,9 +12725,12 @@ decode_rsm_index_els(__TopXMLNS, __IgnoreEls, decode_rsm_index_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_rsm_index(Cdata, _xmlns_attrs) -> +encode_rsm_index(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/rsm">>, + [], __TopXMLNS), _els = encode_rsm_index_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"index">>, _attrs, _els}. decode_rsm_index_cdata(__TopXMLNS, <<>>) -> undefined; @@ -9835,9 +12764,12 @@ decode_rsm_count_els(__TopXMLNS, __IgnoreEls, decode_rsm_count_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_rsm_count(Cdata, _xmlns_attrs) -> +encode_rsm_count(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/rsm">>, + [], __TopXMLNS), _els = encode_rsm_count_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"count">>, _attrs, _els}. decode_rsm_count_cdata(__TopXMLNS, <<>>) -> undefined; @@ -9871,9 +12803,12 @@ decode_rsm_last_els(__TopXMLNS, __IgnoreEls, [_ | _els], decode_rsm_last_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_rsm_last(Cdata, _xmlns_attrs) -> +encode_rsm_last(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/rsm">>, + [], __TopXMLNS), _els = encode_rsm_last_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"last">>, _attrs, _els}. decode_rsm_last_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -9901,9 +12836,12 @@ decode_rsm_before_els(__TopXMLNS, __IgnoreEls, decode_rsm_before_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_rsm_before(Cdata, _xmlns_attrs) -> +encode_rsm_before(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/rsm">>, + [], __TopXMLNS), _els = encode_rsm_before_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"before">>, _attrs, _els}. decode_rsm_before_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -9931,9 +12869,12 @@ decode_rsm_after_els(__TopXMLNS, __IgnoreEls, decode_rsm_after_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_rsm_after(Cdata, _xmlns_attrs) -> +encode_rsm_after(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/rsm">>, + [], __TopXMLNS), _els = encode_rsm_after_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"after">>, _attrs, _els}. decode_rsm_after_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -9947,10 +12888,12 @@ decode_muc_unsubscribe(__TopXMLNS, __IgnoreEls, {xmlel, <<"unsubscribe">>, _attrs, _els}) -> {muc_unsubscribe}. -encode_muc_unsubscribe({muc_unsubscribe}, - _xmlns_attrs) -> +encode_muc_unsubscribe({muc_unsubscribe}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:xmpp:mucsub:0">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"unsubscribe">>, _attrs, _els}. decode_muc_subscribe(__TopXMLNS, __IgnoreEls, @@ -9997,18 +12940,25 @@ decode_muc_subscribe_attrs(__TopXMLNS, [], Nick) -> decode_muc_subscribe_attr_nick(__TopXMLNS, Nick). encode_muc_subscribe({muc_subscribe, Nick, Events}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:xmpp:mucsub:0">>, [], + __TopXMLNS), _els = lists:reverse('encode_muc_subscribe_$events'(Events, - [])), + __NewTopXMLNS, [])), _attrs = encode_muc_subscribe_attr_nick(Nick, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"subscribe">>, _attrs, _els}. -'encode_muc_subscribe_$events'([], _acc) -> _acc; -'encode_muc_subscribe_$events'([Events | _els], _acc) -> - 'encode_muc_subscribe_$events'(_els, - [encode_muc_subscribe_event(Events, []) +'encode_muc_subscribe_$events'([], __TopXMLNS, _acc) -> + _acc; +'encode_muc_subscribe_$events'([Events | _els], + __TopXMLNS, _acc) -> + 'encode_muc_subscribe_$events'(_els, __TopXMLNS, + [encode_muc_subscribe_event(Events, + __TopXMLNS) | _acc]). decode_muc_subscribe_attr_nick(__TopXMLNS, undefined) -> @@ -10039,10 +12989,14 @@ decode_muc_subscribe_event_attrs(__TopXMLNS, [], Node) -> decode_muc_subscribe_event_attr_node(__TopXMLNS, Node). -encode_muc_subscribe_event(Node, _xmlns_attrs) -> +encode_muc_subscribe_event(Node, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:xmpp:mucsub:0">>, [], + __TopXMLNS), _els = [], _attrs = encode_muc_subscribe_event_attr_node(Node, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"event">>, _attrs, _els}. decode_muc_subscribe_event_attr_node(__TopXMLNS, @@ -10094,17 +13048,23 @@ decode_muc_subscriptions_els(__TopXMLNS, __IgnoreEls, _els, List). encode_muc_subscriptions({muc_subscriptions, List}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:xmpp:mucsub:0">>, [], + __TopXMLNS), _els = lists:reverse('encode_muc_subscriptions_$list'(List, - [])), - _attrs = _xmlns_attrs, + __NewTopXMLNS, [])), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"subscriptions">>, _attrs, _els}. -'encode_muc_subscriptions_$list'([], _acc) -> _acc; -'encode_muc_subscriptions_$list'([List | _els], _acc) -> - 'encode_muc_subscriptions_$list'(_els, - [encode_muc_subscription(List, []) +'encode_muc_subscriptions_$list'([], __TopXMLNS, + _acc) -> + _acc; +'encode_muc_subscriptions_$list'([List | _els], + __TopXMLNS, _acc) -> + 'encode_muc_subscriptions_$list'(_els, __TopXMLNS, + [encode_muc_subscription(List, __TopXMLNS) | _acc]). decode_muc_subscription(__TopXMLNS, __IgnoreEls, @@ -10122,10 +13082,14 @@ decode_muc_subscription_attrs(__TopXMLNS, [_ | _attrs], decode_muc_subscription_attrs(__TopXMLNS, [], Jid) -> decode_muc_subscription_attr_jid(__TopXMLNS, Jid). -encode_muc_subscription(Jid, _xmlns_attrs) -> +encode_muc_subscription(Jid, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:xmpp:mucsub:0">>, [], + __TopXMLNS), _els = [], _attrs = encode_muc_subscription_attr_jid(Jid, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"subscription">>, _attrs, _els}. decode_muc_subscription_attr_jid(__TopXMLNS, @@ -10192,14 +13156,18 @@ decode_x_conference_attrs(__TopXMLNS, [], Jid, Password, encode_x_conference({x_conference, Jid, Password, Reason, Continue, Thread}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:x:conference">>, [], + __TopXMLNS), _els = [], _attrs = encode_x_conference_attr_continue(Continue, encode_x_conference_attr_thread(Thread, encode_x_conference_attr_reason(Reason, encode_x_conference_attr_password(Password, encode_x_conference_attr_jid(Jid, - _xmlns_attrs))))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)))))), {xmlel, <<"x">>, _attrs, _els}. decode_x_conference_attr_jid(__TopXMLNS, undefined) -> @@ -10280,9 +13248,12 @@ decode_muc_unique_els(__TopXMLNS, __IgnoreEls, decode_muc_unique_els(__TopXMLNS, __IgnoreEls, _els, Name). -encode_muc_unique({muc_unique, Name}, _xmlns_attrs) -> +encode_muc_unique({muc_unique, Name}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/muc#unique">>, + [], __TopXMLNS), _els = encode_muc_unique_cdata(Name, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"unique">>, _attrs, _els}. decode_muc_unique_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -10353,20 +13324,27 @@ decode_muc_els(__TopXMLNS, __IgnoreEls, [_ | _els], decode_muc_els(__TopXMLNS, __IgnoreEls, _els, Password, History). -encode_muc({muc, History, Password}, _xmlns_attrs) -> +encode_muc({muc, History, Password}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/muc">>, + [], __TopXMLNS), _els = lists:reverse('encode_muc_$password'(Password, + __NewTopXMLNS, 'encode_muc_$history'(History, + __NewTopXMLNS, []))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"x">>, _attrs, _els}. -'encode_muc_$password'(undefined, _acc) -> _acc; -'encode_muc_$password'(Password, _acc) -> - [encode_muc_password(Password, []) | _acc]. +'encode_muc_$password'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_muc_$password'(Password, __TopXMLNS, _acc) -> + [encode_muc_password(Password, __TopXMLNS) | _acc]. -'encode_muc_$history'(undefined, _acc) -> _acc; -'encode_muc_$history'(History, _acc) -> - [encode_muc_history(History, []) | _acc]. +'encode_muc_$history'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_muc_$history'(History, __TopXMLNS, _acc) -> + [encode_muc_history(History, __TopXMLNS) | _acc]. decode_muc_admin(__TopXMLNS, __IgnoreEls, {xmlel, <<"query">>, _attrs, _els}) -> @@ -10401,16 +13379,21 @@ decode_muc_admin_els(__TopXMLNS, __IgnoreEls, decode_muc_admin_els(__TopXMLNS, __IgnoreEls, _els, Items). -encode_muc_admin({muc_admin, Items}, _xmlns_attrs) -> +encode_muc_admin({muc_admin, Items}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/muc#admin">>, + [], __TopXMLNS), _els = lists:reverse('encode_muc_admin_$items'(Items, - [])), - _attrs = _xmlns_attrs, + __NewTopXMLNS, [])), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"query">>, _attrs, _els}. -'encode_muc_admin_$items'([], _acc) -> _acc; -'encode_muc_admin_$items'([Items | _els], _acc) -> - 'encode_muc_admin_$items'(_els, - [encode_muc_admin_item(Items, []) | _acc]). +'encode_muc_admin_$items'([], __TopXMLNS, _acc) -> _acc; +'encode_muc_admin_$items'([Items | _els], __TopXMLNS, + _acc) -> + 'encode_muc_admin_$items'(_els, __TopXMLNS, + [encode_muc_admin_item(Items, __TopXMLNS) + | _acc]). decode_muc_admin_continue(__TopXMLNS, __IgnoreEls, {xmlel, <<"continue">>, _attrs, _els}) -> @@ -10431,10 +13414,14 @@ decode_muc_admin_continue_attrs(__TopXMLNS, [], decode_muc_admin_continue_attr_thread(__TopXMLNS, Thread). -encode_muc_admin_continue(Thread, _xmlns_attrs) -> +encode_muc_admin_continue(Thread, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/muc#admin">>, + [], __TopXMLNS), _els = [], _attrs = encode_muc_admin_continue_attr_thread(Thread, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"continue">>, _attrs, _els}. decode_muc_admin_continue_attr_thread(__TopXMLNS, @@ -10473,11 +13460,15 @@ decode_muc_admin_actor_attrs(__TopXMLNS, [], Jid, decode_muc_admin_actor_attr_nick(__TopXMLNS, Nick)}. encode_muc_admin_actor({muc_actor, Jid, Nick}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/muc#admin">>, + [], __TopXMLNS), _els = [], _attrs = encode_muc_admin_actor_attr_nick(Nick, encode_muc_admin_actor_attr_jid(Jid, - _xmlns_attrs)), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))), {xmlel, <<"actor">>, _attrs, _els}. decode_muc_admin_actor_attr_jid(__TopXMLNS, @@ -10631,31 +13622,47 @@ decode_muc_admin_item_attrs(__TopXMLNS, [], Affiliation, encode_muc_admin_item({muc_item, Actor, Continue, Reason, Affiliation, Role, Jid, Nick}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/muc#admin">>, + [], __TopXMLNS), _els = lists:reverse('encode_muc_admin_item_$actor'(Actor, + __NewTopXMLNS, 'encode_muc_admin_item_$continue'(Continue, + __NewTopXMLNS, 'encode_muc_admin_item_$reason'(Reason, + __NewTopXMLNS, [])))), _attrs = encode_muc_admin_item_attr_nick(Nick, encode_muc_admin_item_attr_jid(Jid, encode_muc_admin_item_attr_role(Role, encode_muc_admin_item_attr_affiliation(Affiliation, - _xmlns_attrs)))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))))), {xmlel, <<"item">>, _attrs, _els}. -'encode_muc_admin_item_$actor'(undefined, _acc) -> _acc; -'encode_muc_admin_item_$actor'(Actor, _acc) -> - [encode_muc_admin_actor(Actor, []) | _acc]. - -'encode_muc_admin_item_$continue'(undefined, _acc) -> +'encode_muc_admin_item_$actor'(undefined, __TopXMLNS, + _acc) -> _acc; -'encode_muc_admin_item_$continue'(Continue, _acc) -> - [encode_muc_admin_continue(Continue, []) | _acc]. +'encode_muc_admin_item_$actor'(Actor, __TopXMLNS, + _acc) -> + [encode_muc_admin_actor(Actor, __TopXMLNS) | _acc]. -'encode_muc_admin_item_$reason'(<<>>, _acc) -> _acc; -'encode_muc_admin_item_$reason'(Reason, _acc) -> - [encode_muc_reason(Reason, []) | _acc]. +'encode_muc_admin_item_$continue'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_muc_admin_item_$continue'(Continue, __TopXMLNS, + _acc) -> + [encode_muc_admin_continue(Continue, __TopXMLNS) + | _acc]. + +'encode_muc_admin_item_$reason'(<<>>, __TopXMLNS, + _acc) -> + _acc; +'encode_muc_admin_item_$reason'(Reason, __TopXMLNS, + _acc) -> + [encode_muc_reason(Reason, __TopXMLNS) | _acc]. decode_muc_admin_item_attr_affiliation(__TopXMLNS, undefined) -> @@ -10830,37 +13837,47 @@ decode_muc_owner_item_attrs(__TopXMLNS, [], Affiliation, encode_muc_owner_item({muc_item, Actor, Continue, Reason, Affiliation, Role, Jid, Nick}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/muc#owner">>, + [], __TopXMLNS), _els = lists:reverse('encode_muc_owner_item_$actor'(Actor, + __NewTopXMLNS, 'encode_muc_owner_item_$continue'(Continue, + __NewTopXMLNS, 'encode_muc_owner_item_$reason'(Reason, + __NewTopXMLNS, [])))), _attrs = encode_muc_owner_item_attr_nick(Nick, encode_muc_owner_item_attr_jid(Jid, encode_muc_owner_item_attr_role(Role, encode_muc_owner_item_attr_affiliation(Affiliation, - _xmlns_attrs)))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))))), {xmlel, <<"item">>, _attrs, _els}. -'encode_muc_owner_item_$actor'(undefined, _acc) -> _acc; -'encode_muc_owner_item_$actor'(Actor, _acc) -> - [encode_muc_admin_actor(Actor, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/muc#admin">>}]) - | _acc]. - -'encode_muc_owner_item_$continue'(undefined, _acc) -> +'encode_muc_owner_item_$actor'(undefined, __TopXMLNS, + _acc) -> _acc; -'encode_muc_owner_item_$continue'(Continue, _acc) -> - [encode_muc_admin_continue(Continue, - [{<<"xmlns">>, - <<"http://jabber.org/protocol/muc#admin">>}]) +'encode_muc_owner_item_$actor'(Actor, __TopXMLNS, + _acc) -> + [encode_muc_admin_actor(Actor, __TopXMLNS) | _acc]. + +'encode_muc_owner_item_$continue'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_muc_owner_item_$continue'(Continue, __TopXMLNS, + _acc) -> + [encode_muc_admin_continue(Continue, __TopXMLNS) | _acc]. -'encode_muc_owner_item_$reason'(<<>>, _acc) -> _acc; -'encode_muc_owner_item_$reason'(Reason, _acc) -> - [encode_muc_reason(Reason, []) | _acc]. +'encode_muc_owner_item_$reason'(<<>>, __TopXMLNS, + _acc) -> + _acc; +'encode_muc_owner_item_$reason'(Reason, __TopXMLNS, + _acc) -> + [encode_muc_reason(Reason, __TopXMLNS) | _acc]. decode_muc_owner_item_attr_affiliation(__TopXMLNS, undefined) -> @@ -11002,28 +14019,39 @@ decode_muc_owner_els(__TopXMLNS, __IgnoreEls, Items, Config, Destroy). encode_muc_owner({muc_owner, Destroy, Config, Items}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/muc#owner">>, + [], __TopXMLNS), _els = lists:reverse('encode_muc_owner_$items'(Items, + __NewTopXMLNS, 'encode_muc_owner_$config'(Config, + __NewTopXMLNS, 'encode_muc_owner_$destroy'(Destroy, + __NewTopXMLNS, [])))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"query">>, _attrs, _els}. -'encode_muc_owner_$items'([], _acc) -> _acc; -'encode_muc_owner_$items'([Items | _els], _acc) -> - 'encode_muc_owner_$items'(_els, - [encode_muc_owner_item(Items, []) | _acc]). +'encode_muc_owner_$items'([], __TopXMLNS, _acc) -> _acc; +'encode_muc_owner_$items'([Items | _els], __TopXMLNS, + _acc) -> + 'encode_muc_owner_$items'(_els, __TopXMLNS, + [encode_muc_owner_item(Items, __TopXMLNS) + | _acc]). -'encode_muc_owner_$config'(undefined, _acc) -> _acc; -'encode_muc_owner_$config'(Config, _acc) -> - [encode_xdata(Config, - [{<<"xmlns">>, <<"jabber:x:data">>}]) - | _acc]. +'encode_muc_owner_$config'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_muc_owner_$config'(Config, __TopXMLNS, _acc) -> + [encode_xdata(Config, __TopXMLNS) | _acc]. -'encode_muc_owner_$destroy'(undefined, _acc) -> _acc; -'encode_muc_owner_$destroy'(Destroy, _acc) -> - [encode_muc_destroy(Destroy, []) | _acc]. +'encode_muc_owner_$destroy'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_muc_owner_$destroy'(Destroy, __TopXMLNS, + _acc) -> + [encode_muc_destroy(Destroy, __TopXMLNS) | _acc]. decode_muc_password(__TopXMLNS, __IgnoreEls, {xmlel, <<"password">>, _attrs, _els}) -> @@ -11043,9 +14071,14 @@ decode_muc_password_els(__TopXMLNS, __IgnoreEls, decode_muc_password_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_muc_password(Cdata, _xmlns_attrs) -> +encode_muc_password(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"http://jabber.org/protocol/muc#owner">>, + <<"http://jabber.org/protocol/muc#user">>, + <<"http://jabber.org/protocol/muc">>], + __TopXMLNS), _els = encode_muc_password_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"password">>, _attrs, _els}. decode_muc_password_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -11246,46 +14279,68 @@ decode_muc_user_els(__TopXMLNS, __IgnoreEls, [_ | _els], encode_muc_user({muc_user, Decline, Destroy, Invites, Items, Status_codes, Password}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/muc#user">>, + [], __TopXMLNS), _els = lists:reverse('encode_muc_user_$status_codes'(Status_codes, + __NewTopXMLNS, 'encode_muc_user_$items'(Items, + __NewTopXMLNS, 'encode_muc_user_$invites'(Invites, + __NewTopXMLNS, 'encode_muc_user_$password'(Password, + __NewTopXMLNS, 'encode_muc_user_$decline'(Decline, + __NewTopXMLNS, 'encode_muc_user_$destroy'(Destroy, + __NewTopXMLNS, []))))))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"x">>, _attrs, _els}. -'encode_muc_user_$status_codes'([], _acc) -> _acc; +'encode_muc_user_$status_codes'([], __TopXMLNS, _acc) -> + _acc; 'encode_muc_user_$status_codes'([Status_codes | _els], - _acc) -> - 'encode_muc_user_$status_codes'(_els, - [encode_muc_user_status(Status_codes, []) + __TopXMLNS, _acc) -> + 'encode_muc_user_$status_codes'(_els, __TopXMLNS, + [encode_muc_user_status(Status_codes, + __TopXMLNS) | _acc]). -'encode_muc_user_$items'([], _acc) -> _acc; -'encode_muc_user_$items'([Items | _els], _acc) -> - 'encode_muc_user_$items'(_els, - [encode_muc_user_item(Items, []) | _acc]). +'encode_muc_user_$items'([], __TopXMLNS, _acc) -> _acc; +'encode_muc_user_$items'([Items | _els], __TopXMLNS, + _acc) -> + 'encode_muc_user_$items'(_els, __TopXMLNS, + [encode_muc_user_item(Items, __TopXMLNS) | _acc]). -'encode_muc_user_$invites'([], _acc) -> _acc; -'encode_muc_user_$invites'([Invites | _els], _acc) -> - 'encode_muc_user_$invites'(_els, - [encode_muc_user_invite(Invites, []) | _acc]). +'encode_muc_user_$invites'([], __TopXMLNS, _acc) -> + _acc; +'encode_muc_user_$invites'([Invites | _els], __TopXMLNS, + _acc) -> + 'encode_muc_user_$invites'(_els, __TopXMLNS, + [encode_muc_user_invite(Invites, __TopXMLNS) + | _acc]). -'encode_muc_user_$password'(undefined, _acc) -> _acc; -'encode_muc_user_$password'(Password, _acc) -> - [encode_muc_password(Password, []) | _acc]. +'encode_muc_user_$password'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_muc_user_$password'(Password, __TopXMLNS, + _acc) -> + [encode_muc_password(Password, __TopXMLNS) | _acc]. -'encode_muc_user_$decline'(undefined, _acc) -> _acc; -'encode_muc_user_$decline'(Decline, _acc) -> - [encode_muc_user_decline(Decline, []) | _acc]. +'encode_muc_user_$decline'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_muc_user_$decline'(Decline, __TopXMLNS, _acc) -> + [encode_muc_user_decline(Decline, __TopXMLNS) | _acc]. -'encode_muc_user_$destroy'(undefined, _acc) -> _acc; -'encode_muc_user_$destroy'(Destroy, _acc) -> - [encode_muc_destroy(Destroy, []) | _acc]. +'encode_muc_user_$destroy'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_muc_user_$destroy'(Destroy, __TopXMLNS, _acc) -> + [encode_muc_destroy(Destroy, __TopXMLNS) | _acc]. decode_muc_user_item(__TopXMLNS, __IgnoreEls, {xmlel, <<"item">>, _attrs, _els}) -> @@ -11412,31 +14467,46 @@ decode_muc_user_item_attrs(__TopXMLNS, [], Affiliation, encode_muc_user_item({muc_item, Actor, Continue, Reason, Affiliation, Role, Jid, Nick}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/muc#user">>, + [], __TopXMLNS), _els = lists:reverse('encode_muc_user_item_$actor'(Actor, + __NewTopXMLNS, 'encode_muc_user_item_$continue'(Continue, + __NewTopXMLNS, 'encode_muc_user_item_$reason'(Reason, + __NewTopXMLNS, [])))), _attrs = encode_muc_user_item_attr_nick(Nick, encode_muc_user_item_attr_jid(Jid, encode_muc_user_item_attr_role(Role, encode_muc_user_item_attr_affiliation(Affiliation, - _xmlns_attrs)))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))))), {xmlel, <<"item">>, _attrs, _els}. -'encode_muc_user_item_$actor'(undefined, _acc) -> _acc; -'encode_muc_user_item_$actor'(Actor, _acc) -> - [encode_muc_user_actor(Actor, []) | _acc]. - -'encode_muc_user_item_$continue'(undefined, _acc) -> +'encode_muc_user_item_$actor'(undefined, __TopXMLNS, + _acc) -> _acc; -'encode_muc_user_item_$continue'(Continue, _acc) -> - [encode_muc_user_continue(Continue, []) | _acc]. +'encode_muc_user_item_$actor'(Actor, __TopXMLNS, + _acc) -> + [encode_muc_user_actor(Actor, __TopXMLNS) | _acc]. -'encode_muc_user_item_$reason'(<<>>, _acc) -> _acc; -'encode_muc_user_item_$reason'(Reason, _acc) -> - [encode_muc_reason(Reason, []) | _acc]. +'encode_muc_user_item_$continue'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_muc_user_item_$continue'(Continue, __TopXMLNS, + _acc) -> + [encode_muc_user_continue(Continue, __TopXMLNS) | _acc]. + +'encode_muc_user_item_$reason'(<<>>, __TopXMLNS, + _acc) -> + _acc; +'encode_muc_user_item_$reason'(Reason, __TopXMLNS, + _acc) -> + [encode_muc_reason(Reason, __TopXMLNS) | _acc]. decode_muc_user_item_attr_affiliation(__TopXMLNS, undefined) -> @@ -11513,10 +14583,14 @@ decode_muc_user_status_attrs(__TopXMLNS, [_ | _attrs], decode_muc_user_status_attrs(__TopXMLNS, [], Code) -> decode_muc_user_status_attr_code(__TopXMLNS, Code). -encode_muc_user_status(Code, _xmlns_attrs) -> +encode_muc_user_status(Code, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/muc#user">>, + [], __TopXMLNS), _els = [], _attrs = encode_muc_user_status_attr_code(Code, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"status">>, _attrs, _els}. decode_muc_user_status_attr_code(__TopXMLNS, @@ -11555,10 +14629,14 @@ decode_muc_user_continue_attrs(__TopXMLNS, [], decode_muc_user_continue_attr_thread(__TopXMLNS, Thread). -encode_muc_user_continue(Thread, _xmlns_attrs) -> +encode_muc_user_continue(Thread, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/muc#user">>, + [], __TopXMLNS), _els = [], _attrs = encode_muc_user_continue_attr_thread(Thread, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"continue">>, _attrs, _els}. decode_muc_user_continue_attr_thread(__TopXMLNS, @@ -11597,11 +14675,15 @@ decode_muc_user_actor_attrs(__TopXMLNS, [], Jid, decode_muc_user_actor_attr_nick(__TopXMLNS, Nick)}. encode_muc_user_actor({muc_actor, Jid, Nick}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/muc#user">>, + [], __TopXMLNS), _els = [], _attrs = encode_muc_user_actor_attr_nick(Nick, encode_muc_user_actor_attr_jid(Jid, - _xmlns_attrs)), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))), {xmlel, <<"actor">>, _attrs, _els}. decode_muc_user_actor_attr_jid(__TopXMLNS, undefined) -> @@ -11716,24 +14798,35 @@ decode_muc_user_invite_attrs(__TopXMLNS, [], To, encode_muc_user_invite({muc_invite, Reason, From, To, Continue}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/muc#user">>, + [], __TopXMLNS), _els = lists:reverse('encode_muc_user_invite_$continue'(Continue, + __NewTopXMLNS, 'encode_muc_user_invite_$reason'(Reason, + __NewTopXMLNS, []))), _attrs = encode_muc_user_invite_attr_from(From, encode_muc_user_invite_attr_to(To, - _xmlns_attrs)), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))), {xmlel, <<"invite">>, _attrs, _els}. -'encode_muc_user_invite_$continue'(undefined, _acc) -> +'encode_muc_user_invite_$continue'(undefined, + __TopXMLNS, _acc) -> _acc; -'encode_muc_user_invite_$continue'(Continue, _acc) -> - [encode_muc_user_continue(Continue, []) | _acc]. +'encode_muc_user_invite_$continue'(Continue, __TopXMLNS, + _acc) -> + [encode_muc_user_continue(Continue, __TopXMLNS) | _acc]. -'encode_muc_user_invite_$reason'(<<>>, _acc) -> _acc; -'encode_muc_user_invite_$reason'(Reason, _acc) -> - [encode_muc_reason(Reason, []) | _acc]. +'encode_muc_user_invite_$reason'(<<>>, __TopXMLNS, + _acc) -> + _acc; +'encode_muc_user_invite_$reason'(Reason, __TopXMLNS, + _acc) -> + [encode_muc_reason(Reason, __TopXMLNS) | _acc]. decode_muc_user_invite_attr_to(__TopXMLNS, undefined) -> undefined; @@ -11864,23 +14957,34 @@ decode_muc_destroy_attrs(__TopXMLNS, [], Jid, Xmlns) -> encode_muc_destroy({muc_destroy, Xmlns, Jid, Reason, Password}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(Xmlns, + [<<"http://jabber.org/protocol/muc#user">>, + <<"http://jabber.org/protocol/muc#owner">>], + __TopXMLNS), _els = lists:reverse('encode_muc_destroy_$password'(Password, + __NewTopXMLNS, 'encode_muc_destroy_$reason'(Reason, + __NewTopXMLNS, []))), - _attrs = encode_muc_destroy_attr_xmlns(Xmlns, - encode_muc_destroy_attr_jid(Jid, - _xmlns_attrs)), + _attrs = encode_muc_destroy_attr_jid(Jid, + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"destroy">>, _attrs, _els}. -'encode_muc_destroy_$password'(undefined, _acc) -> _acc; -'encode_muc_destroy_$password'(Password, _acc) -> - [encode_muc_password(Password, []) | _acc]. +'encode_muc_destroy_$password'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_muc_destroy_$password'(Password, __TopXMLNS, + _acc) -> + [encode_muc_password(Password, __TopXMLNS) | _acc]. -'encode_muc_destroy_$reason'(<<>>, _acc) -> _acc; -'encode_muc_destroy_$reason'(Reason, _acc) -> - [encode_muc_reason(Reason, []) | _acc]. +'encode_muc_destroy_$reason'(<<>>, __TopXMLNS, _acc) -> + _acc; +'encode_muc_destroy_$reason'(Reason, __TopXMLNS, + _acc) -> + [encode_muc_reason(Reason, __TopXMLNS) | _acc]. decode_muc_destroy_attr_jid(__TopXMLNS, undefined) -> undefined; @@ -11901,10 +15005,6 @@ decode_muc_destroy_attr_xmlns(__TopXMLNS, undefined) -> <<>>; decode_muc_destroy_attr_xmlns(__TopXMLNS, _val) -> _val. -encode_muc_destroy_attr_xmlns(<<>>, _acc) -> _acc; -encode_muc_destroy_attr_xmlns(_val, _acc) -> - [{<<"xmlns">>, _val} | _acc]. - decode_muc_user_decline(__TopXMLNS, __IgnoreEls, {xmlel, <<"decline">>, _attrs, _els}) -> Reason = decode_muc_user_decline_els(__TopXMLNS, @@ -11969,18 +15069,25 @@ decode_muc_user_decline_attrs(__TopXMLNS, [], To, decode_muc_user_decline_attr_from(__TopXMLNS, From)}. encode_muc_user_decline({muc_decline, Reason, From, To}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/muc#user">>, + [], __TopXMLNS), _els = lists:reverse('encode_muc_user_decline_$reason'(Reason, - [])), + __NewTopXMLNS, [])), _attrs = encode_muc_user_decline_attr_from(From, encode_muc_user_decline_attr_to(To, - _xmlns_attrs)), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))), {xmlel, <<"decline">>, _attrs, _els}. -'encode_muc_user_decline_$reason'(<<>>, _acc) -> _acc; -'encode_muc_user_decline_$reason'(Reason, _acc) -> - [encode_muc_reason(Reason, []) | _acc]. +'encode_muc_user_decline_$reason'(<<>>, __TopXMLNS, + _acc) -> + _acc; +'encode_muc_user_decline_$reason'(Reason, __TopXMLNS, + _acc) -> + [encode_muc_reason(Reason, __TopXMLNS) | _acc]. decode_muc_user_decline_attr_to(__TopXMLNS, undefined) -> @@ -12033,9 +15140,14 @@ decode_muc_reason_els(__TopXMLNS, __IgnoreEls, decode_muc_reason_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_muc_reason(Cdata, _xmlns_attrs) -> +encode_muc_reason(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"http://jabber.org/protocol/muc#user">>, + <<"http://jabber.org/protocol/muc#admin">>, + <<"http://jabber.org/protocol/muc#owner">>], + __TopXMLNS), _els = encode_muc_reason_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"reason">>, _attrs, _els}. decode_muc_reason_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -12086,13 +15198,17 @@ decode_muc_history_attrs(__TopXMLNS, [], Maxchars, encode_muc_history({muc_history, Maxchars, Maxstanzas, Seconds, Since}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/muc">>, + [], __TopXMLNS), _els = [], _attrs = encode_muc_history_attr_since(Since, encode_muc_history_attr_seconds(Seconds, encode_muc_history_attr_maxstanzas(Maxstanzas, encode_muc_history_attr_maxchars(Maxchars, - _xmlns_attrs)))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))))), {xmlel, <<"history">>, _attrs, _els}. decode_muc_history_attr_maxchars(__TopXMLNS, @@ -12274,30 +15390,47 @@ decode_bytestreams_attrs(__TopXMLNS, [], Dstaddr, Sid, encode_bytestreams({bytestreams, Hosts, Used, Activate, Dstaddr, Mode, Sid}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/bytestreams">>, + [], __TopXMLNS), _els = lists:reverse('encode_bytestreams_$hosts'(Hosts, + __NewTopXMLNS, 'encode_bytestreams_$used'(Used, + __NewTopXMLNS, 'encode_bytestreams_$activate'(Activate, + __NewTopXMLNS, [])))), _attrs = encode_bytestreams_attr_mode(Mode, encode_bytestreams_attr_sid(Sid, encode_bytestreams_attr_dstaddr(Dstaddr, - _xmlns_attrs))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)))), {xmlel, <<"query">>, _attrs, _els}. -'encode_bytestreams_$hosts'([], _acc) -> _acc; -'encode_bytestreams_$hosts'([Hosts | _els], _acc) -> - 'encode_bytestreams_$hosts'(_els, - [encode_bytestreams_streamhost(Hosts, []) +'encode_bytestreams_$hosts'([], __TopXMLNS, _acc) -> + _acc; +'encode_bytestreams_$hosts'([Hosts | _els], __TopXMLNS, + _acc) -> + 'encode_bytestreams_$hosts'(_els, __TopXMLNS, + [encode_bytestreams_streamhost(Hosts, + __TopXMLNS) | _acc]). -'encode_bytestreams_$used'(undefined, _acc) -> _acc; -'encode_bytestreams_$used'(Used, _acc) -> - [encode_bytestreams_streamhost_used(Used, []) | _acc]. +'encode_bytestreams_$used'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_bytestreams_$used'(Used, __TopXMLNS, _acc) -> + [encode_bytestreams_streamhost_used(Used, __TopXMLNS) + | _acc]. -'encode_bytestreams_$activate'(undefined, _acc) -> _acc; -'encode_bytestreams_$activate'(Activate, _acc) -> - [encode_bytestreams_activate(Activate, []) | _acc]. +'encode_bytestreams_$activate'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_bytestreams_$activate'(Activate, __TopXMLNS, + _acc) -> + [encode_bytestreams_activate(Activate, __TopXMLNS) + | _acc]. decode_bytestreams_attr_dstaddr(__TopXMLNS, undefined) -> @@ -12349,9 +15482,12 @@ decode_bytestreams_activate_els(__TopXMLNS, __IgnoreEls, decode_bytestreams_activate_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_bytestreams_activate(Cdata, _xmlns_attrs) -> +encode_bytestreams_activate(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/bytestreams">>, + [], __TopXMLNS), _els = encode_bytestreams_activate_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"activate">>, _attrs, _els}. decode_bytestreams_activate_cdata(__TopXMLNS, <<>>) -> @@ -12391,11 +15527,15 @@ decode_bytestreams_streamhost_used_attrs(__TopXMLNS, [], decode_bytestreams_streamhost_used_attr_jid(__TopXMLNS, Jid). -encode_bytestreams_streamhost_used(Jid, _xmlns_attrs) -> +encode_bytestreams_streamhost_used(Jid, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/bytestreams">>, + [], __TopXMLNS), _els = [], _attrs = encode_bytestreams_streamhost_used_attr_jid(Jid, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"streamhost-used">>, _attrs, _els}. decode_bytestreams_streamhost_used_attr_jid(__TopXMLNS, @@ -12454,12 +15594,16 @@ decode_bytestreams_streamhost_attrs(__TopXMLNS, [], Jid, encode_bytestreams_streamhost({streamhost, Jid, Host, Port}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/bytestreams">>, + [], __TopXMLNS), _els = [], _attrs = encode_bytestreams_streamhost_attr_port(Port, encode_bytestreams_streamhost_attr_host(Host, encode_bytestreams_streamhost_attr_jid(Jid, - _xmlns_attrs))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)))), {xmlel, <<"streamhost">>, _attrs, _els}. decode_bytestreams_streamhost_attr_jid(__TopXMLNS, @@ -12541,12 +15685,14 @@ decode_delay_attrs(__TopXMLNS, [], Stamp, From) -> {decode_delay_attr_stamp(__TopXMLNS, Stamp), decode_delay_attr_from(__TopXMLNS, From)}. -encode_delay({delay, Stamp, From, Desc}, - _xmlns_attrs) -> +encode_delay({delay, Stamp, From, Desc}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:delay">>, + [], __TopXMLNS), _els = encode_delay_cdata(Desc, []), _attrs = encode_delay_attr_from(From, encode_delay_attr_stamp(Stamp, - _xmlns_attrs)), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))), {xmlel, <<"delay">>, _attrs, _els}. decode_delay_attr_stamp(__TopXMLNS, undefined) -> @@ -12590,9 +15736,12 @@ decode_chatstate_paused(__TopXMLNS, __IgnoreEls, {chatstate, paused}. encode_chatstate_paused({chatstate, paused}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/chatstates">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"paused">>, _attrs, _els}. decode_chatstate_inactive(__TopXMLNS, __IgnoreEls, @@ -12600,19 +15749,24 @@ decode_chatstate_inactive(__TopXMLNS, __IgnoreEls, {chatstate, inactive}. encode_chatstate_inactive({chatstate, inactive}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/chatstates">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"inactive">>, _attrs, _els}. decode_chatstate_gone(__TopXMLNS, __IgnoreEls, {xmlel, <<"gone">>, _attrs, _els}) -> {chatstate, gone}. -encode_chatstate_gone({chatstate, gone}, - _xmlns_attrs) -> +encode_chatstate_gone({chatstate, gone}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/chatstates">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"gone">>, _attrs, _els}. decode_chatstate_composing(__TopXMLNS, __IgnoreEls, @@ -12620,9 +15774,12 @@ decode_chatstate_composing(__TopXMLNS, __IgnoreEls, {chatstate, composing}. encode_chatstate_composing({chatstate, composing}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/chatstates">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"composing">>, _attrs, _els}. decode_chatstate_active(__TopXMLNS, __IgnoreEls, @@ -12630,9 +15787,12 @@ decode_chatstate_active(__TopXMLNS, __IgnoreEls, {chatstate, active}. encode_chatstate_active({chatstate, active}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/chatstates">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"active">>, _attrs, _els}. decode_shim_headers(__TopXMLNS, __IgnoreEls, @@ -12669,18 +15829,23 @@ decode_shim_headers_els(__TopXMLNS, __IgnoreEls, decode_shim_headers_els(__TopXMLNS, __IgnoreEls, _els, Headers). -encode_shim_headers({shim, Headers}, _xmlns_attrs) -> +encode_shim_headers({shim, Headers}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/shim">>, + [], __TopXMLNS), _els = lists:reverse('encode_shim_headers_$headers'(Headers, - [])), - _attrs = _xmlns_attrs, + __NewTopXMLNS, [])), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"headers">>, _attrs, _els}. -'encode_shim_headers_$headers'([], _acc) -> _acc; +'encode_shim_headers_$headers'([], __TopXMLNS, _acc) -> + _acc; 'encode_shim_headers_$headers'([Headers | _els], - _acc) -> - 'encode_shim_headers_$headers'(_els, - [encode_shim_header(Headers, []) | _acc]). + __TopXMLNS, _acc) -> + 'encode_shim_headers_$headers'(_els, __TopXMLNS, + [encode_shim_header(Headers, __TopXMLNS) + | _acc]). decode_shim_header(__TopXMLNS, __IgnoreEls, {xmlel, <<"header">>, _attrs, _els}) -> @@ -12711,10 +15876,14 @@ decode_shim_header_attrs(__TopXMLNS, [_ | _attrs], decode_shim_header_attrs(__TopXMLNS, [], Name) -> decode_shim_header_attr_name(__TopXMLNS, Name). -encode_shim_header({Name, Cdata}, _xmlns_attrs) -> +encode_shim_header({Name, Cdata}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/shim">>, + [], __TopXMLNS), _els = encode_shim_header_cdata(Cdata, []), _attrs = encode_shim_header_attr_name(Name, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"header">>, _attrs, _els}. decode_shim_header_attr_name(__TopXMLNS, undefined) -> @@ -12741,9 +15910,12 @@ decode_pubsub_error_unsupported_access_model(__TopXMLNS, encode_pubsub_error_unsupported_access_model({ps_error, 'unsupported-access-model', _}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"unsupported-access-model">>, _attrs, _els}. decode_pubsub_error_unsupported(__TopXMLNS, __IgnoreEls, @@ -12769,11 +15941,15 @@ decode_pubsub_error_unsupported_attrs(__TopXMLNS, [], encode_pubsub_error_unsupported({ps_error, unsupported, Feature}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, + [], __TopXMLNS), _els = [], _attrs = encode_pubsub_error_unsupported_attr_feature(Feature, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"unsupported">>, _attrs, _els}. decode_pubsub_error_unsupported_attr_feature(__TopXMLNS, @@ -12821,9 +15997,12 @@ decode_pubsub_error_too_many_subscriptions(__TopXMLNS, encode_pubsub_error_too_many_subscriptions({ps_error, 'too-many-subscriptions', _}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"too-many-subscriptions">>, _attrs, _els}. decode_pubsub_error_subid_required(__TopXMLNS, @@ -12834,9 +16013,12 @@ decode_pubsub_error_subid_required(__TopXMLNS, encode_pubsub_error_subid_required({ps_error, 'subid-required', _}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"subid-required">>, _attrs, _els}. decode_pubsub_error_presence_subscription_required(__TopXMLNS, @@ -12849,9 +16031,12 @@ decode_pubsub_error_presence_subscription_required(__TopXMLNS, encode_pubsub_error_presence_subscription_required({ps_error, 'presence-subscription-required', _}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"presence-subscription-required">>, _attrs, _els}. @@ -12863,9 +16048,12 @@ decode_pubsub_error_pending_subscription(__TopXMLNS, encode_pubsub_error_pending_subscription({ps_error, 'pending-subscription', _}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"pending-subscription">>, _attrs, _els}. decode_pubsub_error_payload_required(__TopXMLNS, @@ -12876,9 +16064,12 @@ decode_pubsub_error_payload_required(__TopXMLNS, encode_pubsub_error_payload_required({ps_error, 'payload-required', _}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"payload-required">>, _attrs, _els}. decode_pubsub_error_payload_too_big(__TopXMLNS, @@ -12889,9 +16080,12 @@ decode_pubsub_error_payload_too_big(__TopXMLNS, encode_pubsub_error_payload_too_big({ps_error, 'payload-too-big', _}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"payload-too-big">>, _attrs, _els}. decode_pubsub_error_not_subscribed(__TopXMLNS, @@ -12902,9 +16096,12 @@ decode_pubsub_error_not_subscribed(__TopXMLNS, encode_pubsub_error_not_subscribed({ps_error, 'not-subscribed', _}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"not-subscribed">>, _attrs, _els}. decode_pubsub_error_not_in_roster_group(__TopXMLNS, @@ -12915,9 +16112,12 @@ decode_pubsub_error_not_in_roster_group(__TopXMLNS, encode_pubsub_error_not_in_roster_group({ps_error, 'not-in-roster-group', _}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"not-in-roster-group">>, _attrs, _els}. decode_pubsub_error_nodeid_required(__TopXMLNS, @@ -12928,9 +16128,12 @@ decode_pubsub_error_nodeid_required(__TopXMLNS, encode_pubsub_error_nodeid_required({ps_error, 'nodeid-required', _}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"nodeid-required">>, _attrs, _els}. decode_pubsub_error_max_nodes_exceeded(__TopXMLNS, @@ -12941,9 +16144,12 @@ decode_pubsub_error_max_nodes_exceeded(__TopXMLNS, encode_pubsub_error_max_nodes_exceeded({ps_error, 'max-nodes-exceeded', _}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"max-nodes-exceeded">>, _attrs, _els}. decode_pubsub_error_max_items_exceeded(__TopXMLNS, @@ -12954,9 +16160,12 @@ decode_pubsub_error_max_items_exceeded(__TopXMLNS, encode_pubsub_error_max_items_exceeded({ps_error, 'max-items-exceeded', _}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"max-items-exceeded">>, _attrs, _els}. decode_pubsub_error_jid_required(__TopXMLNS, @@ -12966,9 +16175,12 @@ decode_pubsub_error_jid_required(__TopXMLNS, encode_pubsub_error_jid_required({ps_error, 'jid-required', _}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"jid-required">>, _attrs, _els}. decode_pubsub_error_item_required(__TopXMLNS, @@ -12978,9 +16190,12 @@ decode_pubsub_error_item_required(__TopXMLNS, encode_pubsub_error_item_required({ps_error, 'item-required', _}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"item-required">>, _attrs, _els}. decode_pubsub_error_item_forbidden(__TopXMLNS, @@ -12991,9 +16206,12 @@ decode_pubsub_error_item_forbidden(__TopXMLNS, encode_pubsub_error_item_forbidden({ps_error, 'item-forbidden', _}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"item-forbidden">>, _attrs, _els}. decode_pubsub_error_invalid_subid(__TopXMLNS, @@ -13003,9 +16221,12 @@ decode_pubsub_error_invalid_subid(__TopXMLNS, encode_pubsub_error_invalid_subid({ps_error, 'invalid-subid', _}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"invalid-subid">>, _attrs, _els}. decode_pubsub_error_invalid_payload(__TopXMLNS, @@ -13016,9 +16237,12 @@ decode_pubsub_error_invalid_payload(__TopXMLNS, encode_pubsub_error_invalid_payload({ps_error, 'invalid-payload', _}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"invalid-payload">>, _attrs, _els}. decode_pubsub_error_invalid_options(__TopXMLNS, @@ -13029,9 +16253,12 @@ decode_pubsub_error_invalid_options(__TopXMLNS, encode_pubsub_error_invalid_options({ps_error, 'invalid-options', _}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"invalid-options">>, _attrs, _els}. decode_pubsub_error_invalid_jid(__TopXMLNS, __IgnoreEls, @@ -13040,9 +16267,12 @@ decode_pubsub_error_invalid_jid(__TopXMLNS, __IgnoreEls, encode_pubsub_error_invalid_jid({ps_error, 'invalid-jid', _}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"invalid-jid">>, _attrs, _els}. decode_pubsub_error_configuration_required(__TopXMLNS, @@ -13053,9 +16283,12 @@ decode_pubsub_error_configuration_required(__TopXMLNS, encode_pubsub_error_configuration_required({ps_error, 'configuration-required', _}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"configuration-required">>, _attrs, _els}. decode_pubsub_error_closed_node(__TopXMLNS, __IgnoreEls, @@ -13064,9 +16297,12 @@ decode_pubsub_error_closed_node(__TopXMLNS, __IgnoreEls, encode_pubsub_error_closed_node({ps_error, 'closed-node', _}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"closed-node">>, _attrs, _els}. decode_pubsub_owner(__TopXMLNS, __IgnoreEls, @@ -13281,47 +16517,70 @@ decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, encode_pubsub_owner({pubsub_owner, Affiliations, Configure, Default, Delete, Purge, Subscriptions}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#owner">>, + [], __TopXMLNS), _els = lists:reverse('encode_pubsub_owner_$subscriptions'(Subscriptions, + __NewTopXMLNS, 'encode_pubsub_owner_$affiliations'(Affiliations, + __NewTopXMLNS, 'encode_pubsub_owner_$default'(Default, + __NewTopXMLNS, 'encode_pubsub_owner_$purge'(Purge, + __NewTopXMLNS, 'encode_pubsub_owner_$delete'(Delete, + __NewTopXMLNS, 'encode_pubsub_owner_$configure'(Configure, + __NewTopXMLNS, []))))))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"pubsub">>, _attrs, _els}. -'encode_pubsub_owner_$subscriptions'(undefined, _acc) -> +'encode_pubsub_owner_$subscriptions'(undefined, + __TopXMLNS, _acc) -> _acc; 'encode_pubsub_owner_$subscriptions'(Subscriptions, - _acc) -> - [encode_pubsub_subscriptions(Subscriptions, []) | _acc]. - -'encode_pubsub_owner_$affiliations'(undefined, _acc) -> - _acc; -'encode_pubsub_owner_$affiliations'(Affiliations, - _acc) -> - [encode_pubsub_owner_affiliations(Affiliations, []) + __TopXMLNS, _acc) -> + [encode_pubsub_subscriptions(Subscriptions, __TopXMLNS) | _acc]. -'encode_pubsub_owner_$default'(undefined, _acc) -> _acc; -'encode_pubsub_owner_$default'(Default, _acc) -> - [encode_pubsub_default(Default, []) | _acc]. - -'encode_pubsub_owner_$purge'(undefined, _acc) -> _acc; -'encode_pubsub_owner_$purge'(Purge, _acc) -> - [encode_pubsub_purge(Purge, []) | _acc]. - -'encode_pubsub_owner_$delete'(undefined, _acc) -> _acc; -'encode_pubsub_owner_$delete'(Delete, _acc) -> - [encode_pubsub_delete(Delete, []) | _acc]. - -'encode_pubsub_owner_$configure'(undefined, _acc) -> +'encode_pubsub_owner_$affiliations'(undefined, + __TopXMLNS, _acc) -> _acc; -'encode_pubsub_owner_$configure'(Configure, _acc) -> - [encode_pubsub_configure(Configure, []) | _acc]. +'encode_pubsub_owner_$affiliations'(Affiliations, + __TopXMLNS, _acc) -> + [encode_pubsub_owner_affiliations(Affiliations, + __TopXMLNS) + | _acc]. + +'encode_pubsub_owner_$default'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_pubsub_owner_$default'(Default, __TopXMLNS, + _acc) -> + [encode_pubsub_default(Default, __TopXMLNS) | _acc]. + +'encode_pubsub_owner_$purge'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_pubsub_owner_$purge'(Purge, __TopXMLNS, _acc) -> + [encode_pubsub_purge(Purge, __TopXMLNS) | _acc]. + +'encode_pubsub_owner_$delete'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_pubsub_owner_$delete'(Delete, __TopXMLNS, + _acc) -> + [encode_pubsub_delete(Delete, __TopXMLNS) | _acc]. + +'encode_pubsub_owner_$configure'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_pubsub_owner_$configure'(Configure, __TopXMLNS, + _acc) -> + [encode_pubsub_configure(Configure, __TopXMLNS) | _acc]. decode_pubsub(__TopXMLNS, __IgnoreEls, {xmlel, <<"pubsub">>, _attrs, _els}) -> @@ -13941,96 +17200,146 @@ encode_pubsub({pubsub, Subscriptions, Subscription, Affiliations, Publish, Publish_options, Subscribe, Unsubscribe, Options, Items, Retract, Create, Configure, Default, Delete, Purge, Rsm}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub">>, + [], __TopXMLNS), _els = lists:reverse('encode_pubsub_$publish_options'(Publish_options, + __NewTopXMLNS, 'encode_pubsub_$items'(Items, + __NewTopXMLNS, 'encode_pubsub_$options'(Options, + __NewTopXMLNS, 'encode_pubsub_$affiliations'(Affiliations, + __NewTopXMLNS, 'encode_pubsub_$subscriptions'(Subscriptions, + __NewTopXMLNS, 'encode_pubsub_$default'(Default, + __NewTopXMLNS, 'encode_pubsub_$retract'(Retract, + __NewTopXMLNS, 'encode_pubsub_$purge'(Purge, + __NewTopXMLNS, 'encode_pubsub_$delete'(Delete, + __NewTopXMLNS, 'encode_pubsub_$configure'(Configure, + __NewTopXMLNS, 'encode_pubsub_$create'(Create, + __NewTopXMLNS, 'encode_pubsub_$unsubscribe'(Unsubscribe, + __NewTopXMLNS, 'encode_pubsub_$subscribe'(Subscribe, + __NewTopXMLNS, 'encode_pubsub_$publish'(Publish, + __NewTopXMLNS, 'encode_pubsub_$rsm'(Rsm, + __NewTopXMLNS, 'encode_pubsub_$subscription'(Subscription, + __NewTopXMLNS, []))))))))))))))))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"pubsub">>, _attrs, _els}. -'encode_pubsub_$publish_options'(undefined, _acc) -> +'encode_pubsub_$publish_options'(undefined, __TopXMLNS, + _acc) -> _acc; 'encode_pubsub_$publish_options'(Publish_options, - _acc) -> - [encode_pubsub_publish_options(Publish_options, []) + __TopXMLNS, _acc) -> + [encode_pubsub_publish_options(Publish_options, + __TopXMLNS) | _acc]. -'encode_pubsub_$items'(undefined, _acc) -> _acc; -'encode_pubsub_$items'(Items, _acc) -> - [encode_pubsub_items(Items, []) | _acc]. +'encode_pubsub_$items'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_pubsub_$items'(Items, __TopXMLNS, _acc) -> + [encode_pubsub_items(Items, __TopXMLNS) | _acc]. -'encode_pubsub_$options'(undefined, _acc) -> _acc; -'encode_pubsub_$options'(Options, _acc) -> - [encode_pubsub_options(Options, []) | _acc]. +'encode_pubsub_$options'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_pubsub_$options'(Options, __TopXMLNS, _acc) -> + [encode_pubsub_options(Options, __TopXMLNS) | _acc]. -'encode_pubsub_$affiliations'(undefined, _acc) -> _acc; -'encode_pubsub_$affiliations'(Affiliations, _acc) -> - [encode_pubsub_affiliations(Affiliations, []) | _acc]. - -'encode_pubsub_$subscriptions'(undefined, _acc) -> _acc; -'encode_pubsub_$subscriptions'(Subscriptions, _acc) -> - [encode_pubsub_subscriptions(Subscriptions, []) | _acc]. - -'encode_pubsub_$default'(undefined, _acc) -> _acc; -'encode_pubsub_$default'(Default, _acc) -> - [encode_pubsub_default(Default, []) | _acc]. - -'encode_pubsub_$retract'(undefined, _acc) -> _acc; -'encode_pubsub_$retract'(Retract, _acc) -> - [encode_pubsub_retract(Retract, []) | _acc]. - -'encode_pubsub_$purge'(undefined, _acc) -> _acc; -'encode_pubsub_$purge'(Purge, _acc) -> - [encode_pubsub_purge(Purge, []) | _acc]. - -'encode_pubsub_$delete'(undefined, _acc) -> _acc; -'encode_pubsub_$delete'(Delete, _acc) -> - [encode_pubsub_delete(Delete, []) | _acc]. - -'encode_pubsub_$configure'(undefined, _acc) -> _acc; -'encode_pubsub_$configure'(Configure, _acc) -> - [encode_pubsub_configure(Configure, []) | _acc]. - -'encode_pubsub_$create'(undefined, _acc) -> _acc; -'encode_pubsub_$create'(Create, _acc) -> - [encode_pubsub_create(Create, []) | _acc]. - -'encode_pubsub_$unsubscribe'(undefined, _acc) -> _acc; -'encode_pubsub_$unsubscribe'(Unsubscribe, _acc) -> - [encode_pubsub_unsubscribe(Unsubscribe, []) | _acc]. - -'encode_pubsub_$subscribe'(undefined, _acc) -> _acc; -'encode_pubsub_$subscribe'(Subscribe, _acc) -> - [encode_pubsub_subscribe(Subscribe, []) | _acc]. - -'encode_pubsub_$publish'(undefined, _acc) -> _acc; -'encode_pubsub_$publish'(Publish, _acc) -> - [encode_pubsub_publish(Publish, []) | _acc]. - -'encode_pubsub_$rsm'(undefined, _acc) -> _acc; -'encode_pubsub_$rsm'(Rsm, _acc) -> - [encode_rsm_set(Rsm, - [{<<"xmlns">>, <<"http://jabber.org/protocol/rsm">>}]) +'encode_pubsub_$affiliations'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_pubsub_$affiliations'(Affiliations, __TopXMLNS, + _acc) -> + [encode_pubsub_affiliations(Affiliations, __TopXMLNS) | _acc]. -'encode_pubsub_$subscription'(undefined, _acc) -> _acc; -'encode_pubsub_$subscription'(Subscription, _acc) -> - [encode_pubsub_subscription(Subscription, []) | _acc]. +'encode_pubsub_$subscriptions'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_pubsub_$subscriptions'(Subscriptions, + __TopXMLNS, _acc) -> + [encode_pubsub_subscriptions(Subscriptions, __TopXMLNS) + | _acc]. + +'encode_pubsub_$default'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_pubsub_$default'(Default, __TopXMLNS, _acc) -> + [encode_pubsub_default(Default, __TopXMLNS) | _acc]. + +'encode_pubsub_$retract'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_pubsub_$retract'(Retract, __TopXMLNS, _acc) -> + [encode_pubsub_retract(Retract, __TopXMLNS) | _acc]. + +'encode_pubsub_$purge'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_pubsub_$purge'(Purge, __TopXMLNS, _acc) -> + [encode_pubsub_purge(Purge, __TopXMLNS) | _acc]. + +'encode_pubsub_$delete'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_pubsub_$delete'(Delete, __TopXMLNS, _acc) -> + [encode_pubsub_delete(Delete, __TopXMLNS) | _acc]. + +'encode_pubsub_$configure'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_pubsub_$configure'(Configure, __TopXMLNS, + _acc) -> + [encode_pubsub_configure(Configure, __TopXMLNS) | _acc]. + +'encode_pubsub_$create'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_pubsub_$create'(Create, __TopXMLNS, _acc) -> + [encode_pubsub_create(Create, __TopXMLNS) | _acc]. + +'encode_pubsub_$unsubscribe'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_pubsub_$unsubscribe'(Unsubscribe, __TopXMLNS, + _acc) -> + [encode_pubsub_unsubscribe(Unsubscribe, __TopXMLNS) + | _acc]. + +'encode_pubsub_$subscribe'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_pubsub_$subscribe'(Subscribe, __TopXMLNS, + _acc) -> + [encode_pubsub_subscribe(Subscribe, __TopXMLNS) | _acc]. + +'encode_pubsub_$publish'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_pubsub_$publish'(Publish, __TopXMLNS, _acc) -> + [encode_pubsub_publish(Publish, __TopXMLNS) | _acc]. + +'encode_pubsub_$rsm'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_pubsub_$rsm'(Rsm, __TopXMLNS, _acc) -> + [encode_rsm_set(Rsm, __TopXMLNS) | _acc]. + +'encode_pubsub_$subscription'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_pubsub_$subscription'(Subscription, __TopXMLNS, + _acc) -> + [encode_pubsub_subscription(Subscription, __TopXMLNS) + | _acc]. decode_pubsub_purge(__TopXMLNS, __IgnoreEls, {xmlel, <<"purge">>, _attrs, _els}) -> @@ -14047,10 +17356,16 @@ decode_pubsub_purge_attrs(__TopXMLNS, [_ | _attrs], decode_pubsub_purge_attrs(__TopXMLNS, [], Node) -> decode_pubsub_purge_attr_node(__TopXMLNS, Node). -encode_pubsub_purge(Node, _xmlns_attrs) -> +encode_pubsub_purge(Node, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"http://jabber.org/protocol/pubsub">>, + <<"http://jabber.org/protocol/pubsub#owner">>, + <<"http://jabber.org/protocol/pubsub#event">>], + __TopXMLNS), _els = [], _attrs = encode_pubsub_purge_attr_node(Node, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"purge">>, _attrs, _els}. decode_pubsub_purge_attr_node(__TopXMLNS, undefined) -> @@ -14116,16 +17431,23 @@ decode_pubsub_delete_attrs(__TopXMLNS, [_ | _attrs], decode_pubsub_delete_attrs(__TopXMLNS, [], Node) -> decode_pubsub_delete_attr_node(__TopXMLNS, Node). -encode_pubsub_delete({Node, Uri}, _xmlns_attrs) -> +encode_pubsub_delete({Node, Uri}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"http://jabber.org/protocol/pubsub">>, + <<"http://jabber.org/protocol/pubsub#owner">>, + <<"http://jabber.org/protocol/pubsub#event">>], + __TopXMLNS), _els = lists:reverse('encode_pubsub_delete_$uri'(Uri, - [])), + __NewTopXMLNS, [])), _attrs = encode_pubsub_delete_attr_node(Node, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"delete">>, _attrs, _els}. -'encode_pubsub_delete_$uri'(<<>>, _acc) -> _acc; -'encode_pubsub_delete_$uri'(Uri, _acc) -> - [encode_pubsub_redirect(Uri, []) | _acc]. +'encode_pubsub_delete_$uri'(<<>>, __TopXMLNS, _acc) -> + _acc; +'encode_pubsub_delete_$uri'(Uri, __TopXMLNS, _acc) -> + [encode_pubsub_redirect(Uri, __TopXMLNS) | _acc]. decode_pubsub_delete_attr_node(__TopXMLNS, undefined) -> erlang:error({xmpp_codec, @@ -14151,10 +17473,16 @@ decode_pubsub_redirect_attrs(__TopXMLNS, [_ | _attrs], decode_pubsub_redirect_attrs(__TopXMLNS, [], Uri) -> decode_pubsub_redirect_attr_uri(__TopXMLNS, Uri). -encode_pubsub_redirect(Uri, _xmlns_attrs) -> +encode_pubsub_redirect(Uri, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"http://jabber.org/protocol/pubsub">>, + <<"http://jabber.org/protocol/pubsub#owner">>, + <<"http://jabber.org/protocol/pubsub#event">>], + __TopXMLNS), _els = [], _attrs = encode_pubsub_redirect_attr_uri(Uri, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"redirect">>, _attrs, _els}. decode_pubsub_redirect_attr_uri(__TopXMLNS, @@ -14203,19 +17531,25 @@ decode_pubsub_default_attrs(__TopXMLNS, [_ | _attrs], decode_pubsub_default_attrs(__TopXMLNS, [], Node) -> decode_pubsub_default_attr_node(__TopXMLNS, Node). -encode_pubsub_default({Node, Xdata}, _xmlns_attrs) -> +encode_pubsub_default({Node, Xdata}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"http://jabber.org/protocol/pubsub">>, + <<"http://jabber.org/protocol/pubsub#owner">>], + __TopXMLNS), _els = lists:reverse('encode_pubsub_default_$xdata'(Xdata, - [])), + __NewTopXMLNS, [])), _attrs = encode_pubsub_default_attr_node(Node, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"default">>, _attrs, _els}. -'encode_pubsub_default_$xdata'(undefined, _acc) -> _acc; -'encode_pubsub_default_$xdata'(Xdata, _acc) -> - [encode_xdata(Xdata, - [{<<"xmlns">>, <<"jabber:x:data">>}]) - | _acc]. +'encode_pubsub_default_$xdata'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_pubsub_default_$xdata'(Xdata, __TopXMLNS, + _acc) -> + [encode_xdata(Xdata, __TopXMLNS) | _acc]. decode_pubsub_default_attr_node(__TopXMLNS, undefined) -> @@ -14255,20 +17589,23 @@ decode_pubsub_publish_options_els(__TopXMLNS, decode_pubsub_publish_options_els(__TopXMLNS, __IgnoreEls, _els, Xdata). -encode_pubsub_publish_options(Xdata, _xmlns_attrs) -> +encode_pubsub_publish_options(Xdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub">>, + [], __TopXMLNS), _els = lists:reverse('encode_pubsub_publish_options_$xdata'(Xdata, + __NewTopXMLNS, [])), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"publish-options">>, _attrs, _els}. 'encode_pubsub_publish_options_$xdata'(undefined, - _acc) -> + __TopXMLNS, _acc) -> _acc; -'encode_pubsub_publish_options_$xdata'(Xdata, _acc) -> - [encode_xdata(Xdata, - [{<<"xmlns">>, <<"jabber:x:data">>}]) - | _acc]. +'encode_pubsub_publish_options_$xdata'(Xdata, + __TopXMLNS, _acc) -> + [encode_xdata(Xdata, __TopXMLNS) | _acc]. decode_pubsub_configure(__TopXMLNS, __IgnoreEls, {xmlel, <<"configure">>, _attrs, _els}) -> @@ -14308,20 +17645,25 @@ decode_pubsub_configure_attrs(__TopXMLNS, [_ | _attrs], decode_pubsub_configure_attrs(__TopXMLNS, [], Node) -> decode_pubsub_configure_attr_node(__TopXMLNS, Node). -encode_pubsub_configure({Node, Xdata}, _xmlns_attrs) -> +encode_pubsub_configure({Node, Xdata}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"http://jabber.org/protocol/pubsub">>, + <<"http://jabber.org/protocol/pubsub#owner">>], + __TopXMLNS), _els = lists:reverse('encode_pubsub_configure_$xdata'(Xdata, - [])), + __NewTopXMLNS, [])), _attrs = encode_pubsub_configure_attr_node(Node, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"configure">>, _attrs, _els}. -'encode_pubsub_configure_$xdata'(undefined, _acc) -> +'encode_pubsub_configure_$xdata'(undefined, __TopXMLNS, + _acc) -> _acc; -'encode_pubsub_configure_$xdata'(Xdata, _acc) -> - [encode_xdata(Xdata, - [{<<"xmlns">>, <<"jabber:x:data">>}]) - | _acc]. +'encode_pubsub_configure_$xdata'(Xdata, __TopXMLNS, + _acc) -> + [encode_xdata(Xdata, __TopXMLNS) | _acc]. decode_pubsub_configure_attr_node(__TopXMLNS, undefined) -> @@ -14348,10 +17690,15 @@ decode_pubsub_create_attrs(__TopXMLNS, [_ | _attrs], decode_pubsub_create_attrs(__TopXMLNS, [], Node) -> decode_pubsub_create_attr_node(__TopXMLNS, Node). -encode_pubsub_create(Node, _xmlns_attrs) -> +encode_pubsub_create(Node, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"http://jabber.org/protocol/pubsub">>, + <<"http://jabber.org/protocol/pubsub#event">>], + __TopXMLNS), _els = [], _attrs = encode_pubsub_create_attr_node(Node, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"create">>, _attrs, _els}. decode_pubsub_create_attr_node(__TopXMLNS, undefined) -> @@ -14422,19 +17769,26 @@ decode_pubsub_retract_attrs(__TopXMLNS, [], Node, decode_pubsub_retract_attr_notify(__TopXMLNS, Notify)}. encode_pubsub_retract({ps_retract, Node, Notify, Items}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub">>, + [], __TopXMLNS), _els = lists:reverse('encode_pubsub_retract_$items'(Items, - [])), + __NewTopXMLNS, [])), _attrs = encode_pubsub_retract_attr_notify(Notify, encode_pubsub_retract_attr_node(Node, - _xmlns_attrs)), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))), {xmlel, <<"retract">>, _attrs, _els}. -'encode_pubsub_retract_$items'([], _acc) -> _acc; -'encode_pubsub_retract_$items'([Items | _els], _acc) -> - 'encode_pubsub_retract_$items'(_els, - [encode_pubsub_item(Items, []) | _acc]). +'encode_pubsub_retract_$items'([], __TopXMLNS, _acc) -> + _acc; +'encode_pubsub_retract_$items'([Items | _els], + __TopXMLNS, _acc) -> + 'encode_pubsub_retract_$items'(_els, __TopXMLNS, + [encode_pubsub_item(Items, __TopXMLNS) + | _acc]). decode_pubsub_retract_attr_node(__TopXMLNS, undefined) -> @@ -14515,21 +17869,26 @@ decode_pubsub_options_attrs(__TopXMLNS, [], Node, Subid, encode_pubsub_options({ps_options, Node, Jid, Subid, Xdata}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub">>, + [], __TopXMLNS), _els = lists:reverse('encode_pubsub_options_$xdata'(Xdata, - [])), + __NewTopXMLNS, [])), _attrs = encode_pubsub_options_attr_jid(Jid, encode_pubsub_options_attr_subid(Subid, encode_pubsub_options_attr_node(Node, - _xmlns_attrs))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)))), {xmlel, <<"options">>, _attrs, _els}. -'encode_pubsub_options_$xdata'(undefined, _acc) -> _acc; -'encode_pubsub_options_$xdata'(Xdata, _acc) -> - [encode_xdata(Xdata, - [{<<"xmlns">>, <<"jabber:x:data">>}]) - | _acc]. +'encode_pubsub_options_$xdata'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_pubsub_options_$xdata'(Xdata, __TopXMLNS, + _acc) -> + [encode_xdata(Xdata, __TopXMLNS) | _acc]. decode_pubsub_options_attr_node(__TopXMLNS, undefined) -> @@ -14617,18 +17976,25 @@ decode_pubsub_publish_attrs(__TopXMLNS, [], Node) -> decode_pubsub_publish_attr_node(__TopXMLNS, Node). encode_pubsub_publish({ps_publish, Node, Items}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub">>, + [], __TopXMLNS), _els = lists:reverse('encode_pubsub_publish_$items'(Items, - [])), + __NewTopXMLNS, [])), _attrs = encode_pubsub_publish_attr_node(Node, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"publish">>, _attrs, _els}. -'encode_pubsub_publish_$items'([], _acc) -> _acc; -'encode_pubsub_publish_$items'([Items | _els], _acc) -> - 'encode_pubsub_publish_$items'(_els, - [encode_pubsub_item(Items, []) | _acc]). +'encode_pubsub_publish_$items'([], __TopXMLNS, _acc) -> + _acc; +'encode_pubsub_publish_$items'([Items | _els], + __TopXMLNS, _acc) -> + 'encode_pubsub_publish_$items'(_els, __TopXMLNS, + [encode_pubsub_item(Items, __TopXMLNS) + | _acc]). decode_pubsub_publish_attr_node(__TopXMLNS, undefined) -> @@ -14674,12 +18040,16 @@ decode_pubsub_unsubscribe_attrs(__TopXMLNS, [], Node, encode_pubsub_unsubscribe({ps_unsubscribe, Node, Jid, Subid}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub">>, + [], __TopXMLNS), _els = [], _attrs = encode_pubsub_unsubscribe_attr_jid(Jid, encode_pubsub_unsubscribe_attr_subid(Subid, encode_pubsub_unsubscribe_attr_node(Node, - _xmlns_attrs))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)))), {xmlel, <<"unsubscribe">>, _attrs, _els}. decode_pubsub_unsubscribe_attr_node(__TopXMLNS, @@ -14745,11 +18115,15 @@ decode_pubsub_subscribe_attrs(__TopXMLNS, [], Node, decode_pubsub_subscribe_attr_jid(__TopXMLNS, Jid)}. encode_pubsub_subscribe({ps_subscribe, Node, Jid}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub">>, + [], __TopXMLNS), _els = [], _attrs = encode_pubsub_subscribe_attr_jid(Jid, encode_pubsub_subscribe_attr_node(Node, - _xmlns_attrs)), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))), {xmlel, <<"subscribe">>, _attrs, _els}. decode_pubsub_subscribe_attr_node(__TopXMLNS, @@ -14839,24 +18213,30 @@ decode_pubsub_owner_affiliations_attrs(__TopXMLNS, [], Node). encode_pubsub_owner_affiliations({Node, Affiliations}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#owner">>, + [], __TopXMLNS), _els = lists:reverse('encode_pubsub_owner_affiliations_$affiliations'(Affiliations, + __NewTopXMLNS, [])), _attrs = encode_pubsub_owner_affiliations_attr_node(Node, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"affiliations">>, _attrs, _els}. 'encode_pubsub_owner_affiliations_$affiliations'([], - _acc) -> + __TopXMLNS, _acc) -> _acc; 'encode_pubsub_owner_affiliations_$affiliations'([Affiliations | _els], - _acc) -> + __TopXMLNS, _acc) -> 'encode_pubsub_owner_affiliations_$affiliations'(_els, + __TopXMLNS, [encode_pubsub_owner_affiliation(Affiliations, - []) + __TopXMLNS) | _acc]). decode_pubsub_owner_affiliations_attr_node(__TopXMLNS, @@ -14928,22 +18308,29 @@ decode_pubsub_affiliations_attrs(__TopXMLNS, [], decode_pubsub_affiliations_attr_node(__TopXMLNS, Node). encode_pubsub_affiliations({Node, Affiliations}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub">>, + [], __TopXMLNS), _els = lists:reverse('encode_pubsub_affiliations_$affiliations'(Affiliations, + __NewTopXMLNS, [])), _attrs = encode_pubsub_affiliations_attr_node(Node, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"affiliations">>, _attrs, _els}. -'encode_pubsub_affiliations_$affiliations'([], _acc) -> +'encode_pubsub_affiliations_$affiliations'([], + __TopXMLNS, _acc) -> _acc; 'encode_pubsub_affiliations_$affiliations'([Affiliations | _els], - _acc) -> + __TopXMLNS, _acc) -> 'encode_pubsub_affiliations_$affiliations'(_els, + __TopXMLNS, [encode_pubsub_affiliation(Affiliations, - []) + __TopXMLNS) | _acc]). decode_pubsub_affiliations_attr_node(__TopXMLNS, @@ -15029,23 +18416,30 @@ decode_pubsub_subscriptions_attrs(__TopXMLNS, [], decode_pubsub_subscriptions_attr_node(__TopXMLNS, Node). encode_pubsub_subscriptions({Node, Subscriptions}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"http://jabber.org/protocol/pubsub">>, + <<"http://jabber.org/protocol/pubsub#owner">>], + __TopXMLNS), _els = lists:reverse('encode_pubsub_subscriptions_$subscriptions'(Subscriptions, + __NewTopXMLNS, [])), _attrs = encode_pubsub_subscriptions_attr_node(Node, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"subscriptions">>, _attrs, _els}. 'encode_pubsub_subscriptions_$subscriptions'([], - _acc) -> + __TopXMLNS, _acc) -> _acc; 'encode_pubsub_subscriptions_$subscriptions'([Subscriptions | _els], - _acc) -> + __TopXMLNS, _acc) -> 'encode_pubsub_subscriptions_$subscriptions'(_els, + __TopXMLNS, [encode_pubsub_subscription(Subscriptions, - []) + __TopXMLNS) | _acc]). decode_pubsub_subscriptions_attr_node(__TopXMLNS, @@ -15270,45 +18664,68 @@ decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, encode_pubsub_event({ps_event, Items, Purge, Subscription, Delete, Create, Configuration}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#event">>, + [], __TopXMLNS), _els = lists:reverse('encode_pubsub_event_$items'(Items, + __NewTopXMLNS, 'encode_pubsub_event_$create'(Create, + __NewTopXMLNS, 'encode_pubsub_event_$delete'(Delete, + __NewTopXMLNS, 'encode_pubsub_event_$purge'(Purge, + __NewTopXMLNS, 'encode_pubsub_event_$configuration'(Configuration, + __NewTopXMLNS, 'encode_pubsub_event_$subscription'(Subscription, + __NewTopXMLNS, []))))))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"event">>, _attrs, _els}. -'encode_pubsub_event_$items'(undefined, _acc) -> _acc; -'encode_pubsub_event_$items'(Items, _acc) -> - [encode_pubsub_items(Items, []) | _acc]. +'encode_pubsub_event_$items'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_pubsub_event_$items'(Items, __TopXMLNS, _acc) -> + [encode_pubsub_items(Items, __TopXMLNS) | _acc]. -'encode_pubsub_event_$create'(undefined, _acc) -> _acc; -'encode_pubsub_event_$create'(Create, _acc) -> - [encode_pubsub_create(Create, []) | _acc]. +'encode_pubsub_event_$create'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_pubsub_event_$create'(Create, __TopXMLNS, + _acc) -> + [encode_pubsub_create(Create, __TopXMLNS) | _acc]. -'encode_pubsub_event_$delete'(undefined, _acc) -> _acc; -'encode_pubsub_event_$delete'(Delete, _acc) -> - [encode_pubsub_delete(Delete, []) | _acc]. +'encode_pubsub_event_$delete'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_pubsub_event_$delete'(Delete, __TopXMLNS, + _acc) -> + [encode_pubsub_delete(Delete, __TopXMLNS) | _acc]. -'encode_pubsub_event_$purge'(undefined, _acc) -> _acc; -'encode_pubsub_event_$purge'(Purge, _acc) -> - [encode_pubsub_purge(Purge, []) | _acc]. +'encode_pubsub_event_$purge'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_pubsub_event_$purge'(Purge, __TopXMLNS, _acc) -> + [encode_pubsub_purge(Purge, __TopXMLNS) | _acc]. -'encode_pubsub_event_$configuration'(undefined, _acc) -> +'encode_pubsub_event_$configuration'(undefined, + __TopXMLNS, _acc) -> _acc; 'encode_pubsub_event_$configuration'(Configuration, - _acc) -> - [encode_pubsub_event_configuration(Configuration, []) + __TopXMLNS, _acc) -> + [encode_pubsub_event_configuration(Configuration, + __TopXMLNS) | _acc]. -'encode_pubsub_event_$subscription'(undefined, _acc) -> +'encode_pubsub_event_$subscription'(undefined, + __TopXMLNS, _acc) -> _acc; 'encode_pubsub_event_$subscription'(Subscription, - _acc) -> - [encode_pubsub_subscription(Subscription, []) | _acc]. + __TopXMLNS, _acc) -> + [encode_pubsub_subscription(Subscription, __TopXMLNS) + | _acc]. decode_pubsub_items(__TopXMLNS, __IgnoreEls, {xmlel, <<"items">>, _attrs, _els}) -> @@ -15415,35 +18832,44 @@ decode_pubsub_items_attrs(__TopXMLNS, [], Xmlns, encode_pubsub_items({ps_items, Xmlns, Node, Items, Max_items, Subid, Retract}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(Xmlns, + [<<"http://jabber.org/protocol/pubsub">>, + <<"http://jabber.org/protocol/pubsub#event">>], + __TopXMLNS), _els = lists:reverse('encode_pubsub_items_$items'(Items, + __NewTopXMLNS, 'encode_pubsub_items_$retract'(Retract, + __NewTopXMLNS, []))), _attrs = encode_pubsub_items_attr_subid(Subid, encode_pubsub_items_attr_node(Node, encode_pubsub_items_attr_max_items(Max_items, - encode_pubsub_items_attr_xmlns(Xmlns, - _xmlns_attrs)))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)))), {xmlel, <<"items">>, _attrs, _els}. -'encode_pubsub_items_$items'([], _acc) -> _acc; -'encode_pubsub_items_$items'([Items | _els], _acc) -> - 'encode_pubsub_items_$items'(_els, - [encode_pubsub_item(Items, []) | _acc]). +'encode_pubsub_items_$items'([], __TopXMLNS, _acc) -> + _acc; +'encode_pubsub_items_$items'([Items | _els], __TopXMLNS, + _acc) -> + 'encode_pubsub_items_$items'(_els, __TopXMLNS, + [encode_pubsub_item(Items, __TopXMLNS) + | _acc]). -'encode_pubsub_items_$retract'(undefined, _acc) -> _acc; -'encode_pubsub_items_$retract'(Retract, _acc) -> - [encode_pubsub_event_retract(Retract, []) | _acc]. +'encode_pubsub_items_$retract'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_pubsub_items_$retract'(Retract, __TopXMLNS, + _acc) -> + [encode_pubsub_event_retract(Retract, __TopXMLNS) + | _acc]. decode_pubsub_items_attr_xmlns(__TopXMLNS, undefined) -> <<>>; decode_pubsub_items_attr_xmlns(__TopXMLNS, _val) -> _val. -encode_pubsub_items_attr_xmlns(<<>>, _acc) -> _acc; -encode_pubsub_items_attr_xmlns(_val, _acc) -> - [{<<"xmlns">>, _val} | _acc]. - decode_pubsub_items_attr_max_items(__TopXMLNS, undefined) -> undefined; @@ -15533,13 +18959,17 @@ decode_pubsub_item_attrs(__TopXMLNS, [], Id, Xmlns, encode_pubsub_item({ps_item, Xmlns, Id, __Xmls, Node, Publisher}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(Xmlns, + [<<"http://jabber.org/protocol/pubsub">>, + <<"http://jabber.org/protocol/pubsub#event">>], + __TopXMLNS), _els = __Xmls, _attrs = encode_pubsub_item_attr_publisher(Publisher, encode_pubsub_item_attr_node(Node, - encode_pubsub_item_attr_xmlns(Xmlns, - encode_pubsub_item_attr_id(Id, - _xmlns_attrs)))), + encode_pubsub_item_attr_id(Id, + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)))), {xmlel, <<"item">>, _attrs, _els}. decode_pubsub_item_attr_id(__TopXMLNS, undefined) -> @@ -15554,10 +18984,6 @@ decode_pubsub_item_attr_xmlns(__TopXMLNS, undefined) -> <<>>; decode_pubsub_item_attr_xmlns(__TopXMLNS, _val) -> _val. -encode_pubsub_item_attr_xmlns(<<>>, _acc) -> _acc; -encode_pubsub_item_attr_xmlns(_val, _acc) -> - [{<<"xmlns">>, _val} | _acc]. - decode_pubsub_item_attr_node(__TopXMLNS, undefined) -> <<>>; decode_pubsub_item_attr_node(__TopXMLNS, _val) -> _val. @@ -15593,10 +19019,14 @@ decode_pubsub_event_retract_attrs(__TopXMLNS, decode_pubsub_event_retract_attrs(__TopXMLNS, [], Id) -> decode_pubsub_event_retract_attr_id(__TopXMLNS, Id). -encode_pubsub_event_retract(Id, _xmlns_attrs) -> +encode_pubsub_event_retract(Id, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#event">>, + [], __TopXMLNS), _els = [], _attrs = encode_pubsub_event_retract_attr_id(Id, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"retract">>, _attrs, _els}. decode_pubsub_event_retract_attr_id(__TopXMLNS, @@ -15657,23 +19087,26 @@ decode_pubsub_event_configuration_attrs(__TopXMLNS, [], Node). encode_pubsub_event_configuration({Node, Xdata}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#event">>, + [], __TopXMLNS), _els = lists:reverse('encode_pubsub_event_configuration_$xdata'(Xdata, + __NewTopXMLNS, [])), _attrs = encode_pubsub_event_configuration_attr_node(Node, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"configuration">>, _attrs, _els}. 'encode_pubsub_event_configuration_$xdata'(undefined, - _acc) -> + __TopXMLNS, _acc) -> _acc; 'encode_pubsub_event_configuration_$xdata'(Xdata, - _acc) -> - [encode_xdata(Xdata, - [{<<"xmlns">>, <<"jabber:x:data">>}]) - | _acc]. + __TopXMLNS, _acc) -> + [encode_xdata(Xdata, __TopXMLNS) | _acc]. decode_pubsub_event_configuration_attr_node(__TopXMLNS, undefined) -> @@ -15726,13 +19159,16 @@ decode_pubsub_owner_affiliation_attrs(__TopXMLNS, [], encode_pubsub_owner_affiliation({ps_affiliation, Xmlns, _, Type, Jid}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(Xmlns, + [<<"http://jabber.org/protocol/pubsub#owner">>], + __TopXMLNS), _els = [], _attrs = encode_pubsub_owner_affiliation_attr_affiliation(Type, - encode_pubsub_owner_affiliation_attr_xmlns(Xmlns, - encode_pubsub_owner_affiliation_attr_jid(Jid, - _xmlns_attrs))), + encode_pubsub_owner_affiliation_attr_jid(Jid, + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))), {xmlel, <<"affiliation">>, _attrs, _els}. decode_pubsub_owner_affiliation_attr_jid(__TopXMLNS, @@ -15760,13 +19196,6 @@ decode_pubsub_owner_affiliation_attr_xmlns(__TopXMLNS, _val) -> _val. -encode_pubsub_owner_affiliation_attr_xmlns(<<>>, - _acc) -> - _acc; -encode_pubsub_owner_affiliation_attr_xmlns(_val, - _acc) -> - [{<<"xmlns">>, _val} | _acc]. - decode_pubsub_owner_affiliation_attr_affiliation(__TopXMLNS, undefined) -> erlang:error({xmpp_codec, @@ -15824,13 +19253,16 @@ decode_pubsub_affiliation_attrs(__TopXMLNS, [], Node, encode_pubsub_affiliation({ps_affiliation, Xmlns, Node, Type, _}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(Xmlns, + [<<"http://jabber.org/protocol/pubsub">>], + __TopXMLNS), _els = [], _attrs = encode_pubsub_affiliation_attr_affiliation(Type, - encode_pubsub_affiliation_attr_xmlns(Xmlns, - encode_pubsub_affiliation_attr_node(Node, - _xmlns_attrs))), + encode_pubsub_affiliation_attr_node(Node, + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))), {xmlel, <<"affiliation">>, _attrs, _els}. decode_pubsub_affiliation_attr_node(__TopXMLNS, @@ -15851,11 +19283,6 @@ decode_pubsub_affiliation_attr_xmlns(__TopXMLNS, _val) -> _val. -encode_pubsub_affiliation_attr_xmlns(<<>>, _acc) -> - _acc; -encode_pubsub_affiliation_attr_xmlns(_val, _acc) -> - [{<<"xmlns">>, _val} | _acc]. - decode_pubsub_affiliation_attr_affiliation(__TopXMLNS, undefined) -> erlang:error({xmpp_codec, @@ -15937,15 +19364,20 @@ decode_pubsub_subscription_attrs(__TopXMLNS, [], Xmlns, encode_pubsub_subscription({ps_subscription, Xmlns, Jid, Type, Node, Subid, Expiry}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(Xmlns, + [<<"http://jabber.org/protocol/pubsub">>, + <<"http://jabber.org/protocol/pubsub#owner">>, + <<"http://jabber.org/protocol/pubsub#event">>], + __TopXMLNS), _els = [], _attrs = encode_pubsub_subscription_attr_expiry(Expiry, encode_pubsub_subscription_attr_subscription(Type, encode_pubsub_subscription_attr_subid(Subid, encode_pubsub_subscription_attr_node(Node, encode_pubsub_subscription_attr_jid(Jid, - encode_pubsub_subscription_attr_xmlns(Xmlns, - _xmlns_attrs)))))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)))))), {xmlel, <<"subscription">>, _attrs, _els}. decode_pubsub_subscription_attr_xmlns(__TopXMLNS, @@ -15955,11 +19387,6 @@ decode_pubsub_subscription_attr_xmlns(__TopXMLNS, _val) -> _val. -encode_pubsub_subscription_attr_xmlns(<<>>, _acc) -> - _acc; -encode_pubsub_subscription_attr_xmlns(_val, _acc) -> - [{<<"xmlns">>, _val} | _acc]. - decode_pubsub_subscription_attr_jid(__TopXMLNS, undefined) -> erlang:error({xmpp_codec, @@ -16167,40 +19594,54 @@ decode_xdata_attrs(__TopXMLNS, [], Type) -> encode_xdata({xdata, Type, Instructions, Title, Reported, Items, Fields}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:data">>, + [], __TopXMLNS), _els = lists:reverse('encode_xdata_$fields'(Fields, + __NewTopXMLNS, 'encode_xdata_$items'(Items, + __NewTopXMLNS, 'encode_xdata_$instructions'(Instructions, + __NewTopXMLNS, 'encode_xdata_$reported'(Reported, + __NewTopXMLNS, 'encode_xdata_$title'(Title, + __NewTopXMLNS, [])))))), - _attrs = encode_xdata_attr_type(Type, _xmlns_attrs), + _attrs = encode_xdata_attr_type(Type, + enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS)), {xmlel, <<"x">>, _attrs, _els}. -'encode_xdata_$fields'([], _acc) -> _acc; -'encode_xdata_$fields'([Fields | _els], _acc) -> - 'encode_xdata_$fields'(_els, - [encode_xdata_field(Fields, []) | _acc]). +'encode_xdata_$fields'([], __TopXMLNS, _acc) -> _acc; +'encode_xdata_$fields'([Fields | _els], __TopXMLNS, + _acc) -> + 'encode_xdata_$fields'(_els, __TopXMLNS, + [encode_xdata_field(Fields, __TopXMLNS) | _acc]). -'encode_xdata_$items'([], _acc) -> _acc; -'encode_xdata_$items'([Items | _els], _acc) -> - 'encode_xdata_$items'(_els, - [encode_xdata_item(Items, []) | _acc]). +'encode_xdata_$items'([], __TopXMLNS, _acc) -> _acc; +'encode_xdata_$items'([Items | _els], __TopXMLNS, + _acc) -> + 'encode_xdata_$items'(_els, __TopXMLNS, + [encode_xdata_item(Items, __TopXMLNS) | _acc]). -'encode_xdata_$instructions'([], _acc) -> _acc; +'encode_xdata_$instructions'([], __TopXMLNS, _acc) -> + _acc; 'encode_xdata_$instructions'([Instructions | _els], - _acc) -> - 'encode_xdata_$instructions'(_els, - [encode_xdata_instructions(Instructions, []) + __TopXMLNS, _acc) -> + 'encode_xdata_$instructions'(_els, __TopXMLNS, + [encode_xdata_instructions(Instructions, + __TopXMLNS) | _acc]). -'encode_xdata_$reported'(undefined, _acc) -> _acc; -'encode_xdata_$reported'(Reported, _acc) -> - [encode_xdata_reported(Reported, []) | _acc]. +'encode_xdata_$reported'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_xdata_$reported'(Reported, __TopXMLNS, _acc) -> + [encode_xdata_reported(Reported, __TopXMLNS) | _acc]. -'encode_xdata_$title'(undefined, _acc) -> _acc; -'encode_xdata_$title'(Title, _acc) -> - [encode_xdata_title(Title, []) | _acc]. +'encode_xdata_$title'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_xdata_$title'(Title, __TopXMLNS, _acc) -> + [encode_xdata_title(Title, __TopXMLNS) | _acc]. decode_xdata_attr_type(__TopXMLNS, undefined) -> erlang:error({xmpp_codec, @@ -16250,16 +19691,21 @@ decode_xdata_item_els(__TopXMLNS, __IgnoreEls, decode_xdata_item_els(__TopXMLNS, __IgnoreEls, _els, Fields). -encode_xdata_item(Fields, _xmlns_attrs) -> +encode_xdata_item(Fields, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:data">>, + [], __TopXMLNS), _els = lists:reverse('encode_xdata_item_$fields'(Fields, - [])), - _attrs = _xmlns_attrs, + __NewTopXMLNS, [])), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"item">>, _attrs, _els}. -'encode_xdata_item_$fields'([], _acc) -> _acc; -'encode_xdata_item_$fields'([Fields | _els], _acc) -> - 'encode_xdata_item_$fields'(_els, - [encode_xdata_field(Fields, []) | _acc]). +'encode_xdata_item_$fields'([], __TopXMLNS, _acc) -> + _acc; +'encode_xdata_item_$fields'([Fields | _els], __TopXMLNS, + _acc) -> + 'encode_xdata_item_$fields'(_els, __TopXMLNS, + [encode_xdata_field(Fields, __TopXMLNS) + | _acc]). decode_xdata_reported(__TopXMLNS, __IgnoreEls, {xmlel, <<"reported">>, _attrs, _els}) -> @@ -16293,18 +19739,22 @@ decode_xdata_reported_els(__TopXMLNS, __IgnoreEls, decode_xdata_reported_els(__TopXMLNS, __IgnoreEls, _els, Fields). -encode_xdata_reported(Fields, _xmlns_attrs) -> +encode_xdata_reported(Fields, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:data">>, + [], __TopXMLNS), _els = lists:reverse('encode_xdata_reported_$fields'(Fields, - [])), - _attrs = _xmlns_attrs, + __NewTopXMLNS, [])), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"reported">>, _attrs, _els}. -'encode_xdata_reported_$fields'([], _acc) -> _acc; +'encode_xdata_reported_$fields'([], __TopXMLNS, _acc) -> + _acc; 'encode_xdata_reported_$fields'([Fields | _els], - _acc) -> - 'encode_xdata_reported_$fields'(_els, - [encode_xdata_field(Fields, []) | _acc]). + __TopXMLNS, _acc) -> + 'encode_xdata_reported_$fields'(_els, __TopXMLNS, + [encode_xdata_field(Fields, __TopXMLNS) + | _acc]). decode_xdata_title(__TopXMLNS, __IgnoreEls, {xmlel, <<"title">>, _attrs, _els}) -> @@ -16324,9 +19774,11 @@ decode_xdata_title_els(__TopXMLNS, __IgnoreEls, decode_xdata_title_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_xdata_title(Cdata, _xmlns_attrs) -> +encode_xdata_title(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:data">>, + [], __TopXMLNS), _els = encode_xdata_title_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"title">>, _attrs, _els}. decode_xdata_title_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -16354,9 +19806,11 @@ decode_xdata_instructions_els(__TopXMLNS, __IgnoreEls, decode_xdata_instructions_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_xdata_instructions(Cdata, _xmlns_attrs) -> +encode_xdata_instructions(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:data">>, + [], __TopXMLNS), _els = encode_xdata_instructions_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"instructions">>, _attrs, _els}. decode_xdata_instructions_cdata(__TopXMLNS, <<>>) -> @@ -16473,11 +19927,11 @@ decode_xdata_field_els(__TopXMLNS, __IgnoreEls, Options, Values, Desc, Required, [_el | __Els]); true -> - case is_known_tag(_el) of + case is_known_tag(_el, __TopXMLNS) of true -> decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, Options, Values, Desc, Required, - [decode(_el) | __Els]); + [decode(_el, __TopXMLNS, []) | __Els]); false -> decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, Options, Values, Desc, Required, __Els) @@ -16512,37 +19966,56 @@ decode_xdata_field_attrs(__TopXMLNS, [], Label, Type, encode_xdata_field({xdata_field, Label, Type, Var, Required, Desc, Values, Options, __Els}, - _xmlns_attrs) -> - _els = [encode(_el) || _el <- __Els] ++ + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:data">>, + [], __TopXMLNS), + _els = [encode(_el, __NewTopXMLNS) || _el <- __Els] ++ lists:reverse('encode_xdata_field_$options'(Options, + __NewTopXMLNS, 'encode_xdata_field_$values'(Values, + __NewTopXMLNS, 'encode_xdata_field_$desc'(Desc, + __NewTopXMLNS, 'encode_xdata_field_$required'(Required, + __NewTopXMLNS, []))))), _attrs = encode_xdata_field_attr_var(Var, encode_xdata_field_attr_type(Type, encode_xdata_field_attr_label(Label, - _xmlns_attrs))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)))), {xmlel, <<"field">>, _attrs, _els}. -'encode_xdata_field_$options'([], _acc) -> _acc; -'encode_xdata_field_$options'([Options | _els], _acc) -> - 'encode_xdata_field_$options'(_els, - [encode_xdata_field_option(Options, []) +'encode_xdata_field_$options'([], __TopXMLNS, _acc) -> + _acc; +'encode_xdata_field_$options'([Options | _els], + __TopXMLNS, _acc) -> + 'encode_xdata_field_$options'(_els, __TopXMLNS, + [encode_xdata_field_option(Options, + __TopXMLNS) | _acc]). -'encode_xdata_field_$values'([], _acc) -> _acc; -'encode_xdata_field_$values'([Values | _els], _acc) -> - 'encode_xdata_field_$values'(_els, - [encode_xdata_field_value(Values, []) | _acc]). +'encode_xdata_field_$values'([], __TopXMLNS, _acc) -> + _acc; +'encode_xdata_field_$values'([Values | _els], + __TopXMLNS, _acc) -> + 'encode_xdata_field_$values'(_els, __TopXMLNS, + [encode_xdata_field_value(Values, __TopXMLNS) + | _acc]). -'encode_xdata_field_$desc'(undefined, _acc) -> _acc; -'encode_xdata_field_$desc'(Desc, _acc) -> - [encode_xdata_field_desc(Desc, []) | _acc]. +'encode_xdata_field_$desc'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_xdata_field_$desc'(Desc, __TopXMLNS, _acc) -> + [encode_xdata_field_desc(Desc, __TopXMLNS) | _acc]. -'encode_xdata_field_$required'(false, _acc) -> _acc; -'encode_xdata_field_$required'(Required, _acc) -> - [encode_xdata_field_required(Required, []) | _acc]. +'encode_xdata_field_$required'(false, __TopXMLNS, + _acc) -> + _acc; +'encode_xdata_field_$required'(Required, __TopXMLNS, + _acc) -> + [encode_xdata_field_required(Required, __TopXMLNS) + | _acc]. decode_xdata_field_attr_label(__TopXMLNS, undefined) -> <<>>; @@ -16634,16 +20107,20 @@ decode_xdata_field_option_attrs(__TopXMLNS, [], decode_xdata_field_option_attr_label(__TopXMLNS, Label). encode_xdata_field_option({xdata_option, Label, Value}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:data">>, + [], __TopXMLNS), _els = lists:reverse('encode_xdata_field_option_$value'(Value, - [])), + __NewTopXMLNS, [])), _attrs = encode_xdata_field_option_attr_label(Label, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"option">>, _attrs, _els}. -'encode_xdata_field_option_$value'(Value, _acc) -> - [encode_xdata_field_value(Value, []) | _acc]. +'encode_xdata_field_option_$value'(Value, __TopXMLNS, + _acc) -> + [encode_xdata_field_value(Value, __TopXMLNS) | _acc]. decode_xdata_field_option_attr_label(__TopXMLNS, undefined) -> @@ -16675,9 +20152,11 @@ decode_xdata_field_value_els(__TopXMLNS, __IgnoreEls, decode_xdata_field_value_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_xdata_field_value(Cdata, _xmlns_attrs) -> +encode_xdata_field_value(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:data">>, + [], __TopXMLNS), _els = encode_xdata_field_value_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"value">>, _attrs, _els}. decode_xdata_field_value_cdata(__TopXMLNS, <<>>) -> @@ -16707,9 +20186,11 @@ decode_xdata_field_desc_els(__TopXMLNS, __IgnoreEls, decode_xdata_field_desc_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_xdata_field_desc(Cdata, _xmlns_attrs) -> +encode_xdata_field_desc(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:data">>, + [], __TopXMLNS), _els = encode_xdata_field_desc_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"desc">>, _attrs, _els}. decode_xdata_field_desc_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -16723,9 +20204,11 @@ decode_xdata_field_required(__TopXMLNS, __IgnoreEls, {xmlel, <<"required">>, _attrs, _els}) -> true. -encode_xdata_field_required(true, _xmlns_attrs) -> +encode_xdata_field_required(true, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:data">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"required">>, _attrs, _els}. decode_vcard_xupdate(__TopXMLNS, __IgnoreEls, @@ -16761,15 +20244,20 @@ decode_vcard_xupdate_els(__TopXMLNS, __IgnoreEls, Hash). encode_vcard_xupdate({vcard_xupdate, _, Hash}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"vcard-temp:x:update">>, [], + __TopXMLNS), _els = lists:reverse('encode_vcard_xupdate_$hash'(Hash, - [])), - _attrs = _xmlns_attrs, + __NewTopXMLNS, [])), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"x">>, _attrs, _els}. -'encode_vcard_xupdate_$hash'(undefined, _acc) -> _acc; -'encode_vcard_xupdate_$hash'(Hash, _acc) -> - [encode_vcard_xupdate_photo(Hash, []) | _acc]. +'encode_vcard_xupdate_$hash'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_xupdate_$hash'(Hash, __TopXMLNS, _acc) -> + [encode_vcard_xupdate_photo(Hash, __TopXMLNS) | _acc]. decode_vcard_xupdate_photo(__TopXMLNS, __IgnoreEls, {xmlel, <<"photo">>, _attrs, _els}) -> @@ -16789,9 +20277,12 @@ decode_vcard_xupdate_photo_els(__TopXMLNS, __IgnoreEls, decode_vcard_xupdate_photo_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_xupdate_photo(Cdata, _xmlns_attrs) -> +encode_vcard_xupdate_photo(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"vcard-temp:x:update">>, [], + __TopXMLNS), _els = encode_vcard_xupdate_photo_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"photo">>, _attrs, _els}. decode_vcard_xupdate_photo_cdata(__TopXMLNS, <<>>) -> @@ -17797,160 +21288,243 @@ encode_vcard_temp({vcard_temp, Version, Fn, N, Nickname, Tz, Geo, Title, Role, Logo, Org, Categories, Note, Prodid, Rev, Sort_string, Sound, Uid, Url, Class, Key, Desc}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = lists:reverse('encode_vcard_temp_$mailer'(Mailer, + __NewTopXMLNS, 'encode_vcard_temp_$adr'(Adr, + __NewTopXMLNS, 'encode_vcard_temp_$class'(Class, + __NewTopXMLNS, 'encode_vcard_temp_$categories'(Categories, + __NewTopXMLNS, 'encode_vcard_temp_$desc'(Desc, + __NewTopXMLNS, 'encode_vcard_temp_$uid'(Uid, + __NewTopXMLNS, 'encode_vcard_temp_$prodid'(Prodid, + __NewTopXMLNS, 'encode_vcard_temp_$jabberid'(Jabberid, + __NewTopXMLNS, 'encode_vcard_temp_$sound'(Sound, + __NewTopXMLNS, 'encode_vcard_temp_$note'(Note, + __NewTopXMLNS, 'encode_vcard_temp_$role'(Role, + __NewTopXMLNS, 'encode_vcard_temp_$title'(Title, + __NewTopXMLNS, 'encode_vcard_temp_$nickname'(Nickname, + __NewTopXMLNS, 'encode_vcard_temp_$rev'(Rev, + __NewTopXMLNS, 'encode_vcard_temp_$sort_string'(Sort_string, + __NewTopXMLNS, 'encode_vcard_temp_$org'(Org, + __NewTopXMLNS, 'encode_vcard_temp_$bday'(Bday, + __NewTopXMLNS, 'encode_vcard_temp_$key'(Key, + __NewTopXMLNS, 'encode_vcard_temp_$tz'(Tz, + __NewTopXMLNS, 'encode_vcard_temp_$url'(Url, + __NewTopXMLNS, 'encode_vcard_temp_$email'(Email, + __NewTopXMLNS, 'encode_vcard_temp_$tel'(Tel, + __NewTopXMLNS, 'encode_vcard_temp_$label'(Label, + __NewTopXMLNS, 'encode_vcard_temp_$fn'(Fn, + __NewTopXMLNS, 'encode_vcard_temp_$version'(Version, + __NewTopXMLNS, 'encode_vcard_temp_$n'(N, + __NewTopXMLNS, 'encode_vcard_temp_$photo'(Photo, + __NewTopXMLNS, 'encode_vcard_temp_$logo'(Logo, + __NewTopXMLNS, 'encode_vcard_temp_$geo'(Geo, + __NewTopXMLNS, [])))))))))))))))))))))))))))))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"vCard">>, _attrs, _els}. -'encode_vcard_temp_$mailer'(undefined, _acc) -> _acc; -'encode_vcard_temp_$mailer'(Mailer, _acc) -> - [encode_vcard_MAILER(Mailer, []) | _acc]. - -'encode_vcard_temp_$adr'([], _acc) -> _acc; -'encode_vcard_temp_$adr'([Adr | _els], _acc) -> - 'encode_vcard_temp_$adr'(_els, - [encode_vcard_ADR(Adr, []) | _acc]). - -'encode_vcard_temp_$class'(undefined, _acc) -> _acc; -'encode_vcard_temp_$class'(Class, _acc) -> - [encode_vcard_CLASS(Class, []) | _acc]. - -'encode_vcard_temp_$categories'([], _acc) -> _acc; -'encode_vcard_temp_$categories'(Categories, _acc) -> - [encode_vcard_CATEGORIES(Categories, []) | _acc]. - -'encode_vcard_temp_$desc'(undefined, _acc) -> _acc; -'encode_vcard_temp_$desc'(Desc, _acc) -> - [encode_vcard_DESC(Desc, []) | _acc]. - -'encode_vcard_temp_$uid'(undefined, _acc) -> _acc; -'encode_vcard_temp_$uid'(Uid, _acc) -> - [encode_vcard_UID(Uid, []) | _acc]. - -'encode_vcard_temp_$prodid'(undefined, _acc) -> _acc; -'encode_vcard_temp_$prodid'(Prodid, _acc) -> - [encode_vcard_PRODID(Prodid, []) | _acc]. - -'encode_vcard_temp_$jabberid'(undefined, _acc) -> _acc; -'encode_vcard_temp_$jabberid'(Jabberid, _acc) -> - [encode_vcard_JABBERID(Jabberid, []) | _acc]. - -'encode_vcard_temp_$sound'(undefined, _acc) -> _acc; -'encode_vcard_temp_$sound'(Sound, _acc) -> - [encode_vcard_SOUND(Sound, []) | _acc]. - -'encode_vcard_temp_$note'(undefined, _acc) -> _acc; -'encode_vcard_temp_$note'(Note, _acc) -> - [encode_vcard_NOTE(Note, []) | _acc]. - -'encode_vcard_temp_$role'(undefined, _acc) -> _acc; -'encode_vcard_temp_$role'(Role, _acc) -> - [encode_vcard_ROLE(Role, []) | _acc]. - -'encode_vcard_temp_$title'(undefined, _acc) -> _acc; -'encode_vcard_temp_$title'(Title, _acc) -> - [encode_vcard_TITLE(Title, []) | _acc]. - -'encode_vcard_temp_$nickname'(undefined, _acc) -> _acc; -'encode_vcard_temp_$nickname'(Nickname, _acc) -> - [encode_vcard_NICKNAME(Nickname, []) | _acc]. - -'encode_vcard_temp_$rev'(undefined, _acc) -> _acc; -'encode_vcard_temp_$rev'(Rev, _acc) -> - [encode_vcard_REV(Rev, []) | _acc]. - -'encode_vcard_temp_$sort_string'(undefined, _acc) -> +'encode_vcard_temp_$mailer'(undefined, __TopXMLNS, + _acc) -> _acc; -'encode_vcard_temp_$sort_string'(Sort_string, _acc) -> - [encode_vcard_SORT_STRING(Sort_string, []) | _acc]. +'encode_vcard_temp_$mailer'(Mailer, __TopXMLNS, _acc) -> + [encode_vcard_MAILER(Mailer, __TopXMLNS) | _acc]. -'encode_vcard_temp_$org'(undefined, _acc) -> _acc; -'encode_vcard_temp_$org'(Org, _acc) -> - [encode_vcard_ORG(Org, []) | _acc]. +'encode_vcard_temp_$adr'([], __TopXMLNS, _acc) -> _acc; +'encode_vcard_temp_$adr'([Adr | _els], __TopXMLNS, + _acc) -> + 'encode_vcard_temp_$adr'(_els, __TopXMLNS, + [encode_vcard_ADR(Adr, __TopXMLNS) | _acc]). -'encode_vcard_temp_$bday'(undefined, _acc) -> _acc; -'encode_vcard_temp_$bday'(Bday, _acc) -> - [encode_vcard_BDAY(Bday, []) | _acc]. +'encode_vcard_temp_$class'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_temp_$class'(Class, __TopXMLNS, _acc) -> + [encode_vcard_CLASS(Class, __TopXMLNS) | _acc]. -'encode_vcard_temp_$key'(undefined, _acc) -> _acc; -'encode_vcard_temp_$key'(Key, _acc) -> - [encode_vcard_KEY(Key, []) | _acc]. +'encode_vcard_temp_$categories'([], __TopXMLNS, _acc) -> + _acc; +'encode_vcard_temp_$categories'(Categories, __TopXMLNS, + _acc) -> + [encode_vcard_CATEGORIES(Categories, __TopXMLNS) + | _acc]. -'encode_vcard_temp_$tz'(undefined, _acc) -> _acc; -'encode_vcard_temp_$tz'(Tz, _acc) -> - [encode_vcard_TZ(Tz, []) | _acc]. +'encode_vcard_temp_$desc'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_temp_$desc'(Desc, __TopXMLNS, _acc) -> + [encode_vcard_DESC(Desc, __TopXMLNS) | _acc]. -'encode_vcard_temp_$url'(undefined, _acc) -> _acc; -'encode_vcard_temp_$url'(Url, _acc) -> - [encode_vcard_URL(Url, []) | _acc]. +'encode_vcard_temp_$uid'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_temp_$uid'(Uid, __TopXMLNS, _acc) -> + [encode_vcard_UID(Uid, __TopXMLNS) | _acc]. -'encode_vcard_temp_$email'([], _acc) -> _acc; -'encode_vcard_temp_$email'([Email | _els], _acc) -> - 'encode_vcard_temp_$email'(_els, - [encode_vcard_EMAIL(Email, []) | _acc]). +'encode_vcard_temp_$prodid'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_temp_$prodid'(Prodid, __TopXMLNS, _acc) -> + [encode_vcard_PRODID(Prodid, __TopXMLNS) | _acc]. -'encode_vcard_temp_$tel'([], _acc) -> _acc; -'encode_vcard_temp_$tel'([Tel | _els], _acc) -> - 'encode_vcard_temp_$tel'(_els, - [encode_vcard_TEL(Tel, []) | _acc]). +'encode_vcard_temp_$jabberid'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_temp_$jabberid'(Jabberid, __TopXMLNS, + _acc) -> + [encode_vcard_JABBERID(Jabberid, __TopXMLNS) | _acc]. -'encode_vcard_temp_$label'([], _acc) -> _acc; -'encode_vcard_temp_$label'([Label | _els], _acc) -> - 'encode_vcard_temp_$label'(_els, - [encode_vcard_LABEL(Label, []) | _acc]). +'encode_vcard_temp_$sound'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_temp_$sound'(Sound, __TopXMLNS, _acc) -> + [encode_vcard_SOUND(Sound, __TopXMLNS) | _acc]. -'encode_vcard_temp_$fn'(undefined, _acc) -> _acc; -'encode_vcard_temp_$fn'(Fn, _acc) -> - [encode_vcard_FN(Fn, []) | _acc]. +'encode_vcard_temp_$note'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_temp_$note'(Note, __TopXMLNS, _acc) -> + [encode_vcard_NOTE(Note, __TopXMLNS) | _acc]. -'encode_vcard_temp_$version'(undefined, _acc) -> _acc; -'encode_vcard_temp_$version'(Version, _acc) -> - [encode_vcard_VERSION(Version, []) | _acc]. +'encode_vcard_temp_$role'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_temp_$role'(Role, __TopXMLNS, _acc) -> + [encode_vcard_ROLE(Role, __TopXMLNS) | _acc]. -'encode_vcard_temp_$n'(undefined, _acc) -> _acc; -'encode_vcard_temp_$n'(N, _acc) -> - [encode_vcard_N(N, []) | _acc]. +'encode_vcard_temp_$title'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_temp_$title'(Title, __TopXMLNS, _acc) -> + [encode_vcard_TITLE(Title, __TopXMLNS) | _acc]. -'encode_vcard_temp_$photo'(undefined, _acc) -> _acc; -'encode_vcard_temp_$photo'(Photo, _acc) -> - [encode_vcard_PHOTO(Photo, []) | _acc]. +'encode_vcard_temp_$nickname'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_temp_$nickname'(Nickname, __TopXMLNS, + _acc) -> + [encode_vcard_NICKNAME(Nickname, __TopXMLNS) | _acc]. -'encode_vcard_temp_$logo'(undefined, _acc) -> _acc; -'encode_vcard_temp_$logo'(Logo, _acc) -> - [encode_vcard_LOGO(Logo, []) | _acc]. +'encode_vcard_temp_$rev'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_temp_$rev'(Rev, __TopXMLNS, _acc) -> + [encode_vcard_REV(Rev, __TopXMLNS) | _acc]. -'encode_vcard_temp_$geo'(undefined, _acc) -> _acc; -'encode_vcard_temp_$geo'(Geo, _acc) -> - [encode_vcard_GEO(Geo, []) | _acc]. +'encode_vcard_temp_$sort_string'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_temp_$sort_string'(Sort_string, + __TopXMLNS, _acc) -> + [encode_vcard_SORT_STRING(Sort_string, __TopXMLNS) + | _acc]. + +'encode_vcard_temp_$org'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_temp_$org'(Org, __TopXMLNS, _acc) -> + [encode_vcard_ORG(Org, __TopXMLNS) | _acc]. + +'encode_vcard_temp_$bday'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_temp_$bday'(Bday, __TopXMLNS, _acc) -> + [encode_vcard_BDAY(Bday, __TopXMLNS) | _acc]. + +'encode_vcard_temp_$key'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_temp_$key'(Key, __TopXMLNS, _acc) -> + [encode_vcard_KEY(Key, __TopXMLNS) | _acc]. + +'encode_vcard_temp_$tz'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_temp_$tz'(Tz, __TopXMLNS, _acc) -> + [encode_vcard_TZ(Tz, __TopXMLNS) | _acc]. + +'encode_vcard_temp_$url'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_temp_$url'(Url, __TopXMLNS, _acc) -> + [encode_vcard_URL(Url, __TopXMLNS) | _acc]. + +'encode_vcard_temp_$email'([], __TopXMLNS, _acc) -> + _acc; +'encode_vcard_temp_$email'([Email | _els], __TopXMLNS, + _acc) -> + 'encode_vcard_temp_$email'(_els, __TopXMLNS, + [encode_vcard_EMAIL(Email, __TopXMLNS) | _acc]). + +'encode_vcard_temp_$tel'([], __TopXMLNS, _acc) -> _acc; +'encode_vcard_temp_$tel'([Tel | _els], __TopXMLNS, + _acc) -> + 'encode_vcard_temp_$tel'(_els, __TopXMLNS, + [encode_vcard_TEL(Tel, __TopXMLNS) | _acc]). + +'encode_vcard_temp_$label'([], __TopXMLNS, _acc) -> + _acc; +'encode_vcard_temp_$label'([Label | _els], __TopXMLNS, + _acc) -> + 'encode_vcard_temp_$label'(_els, __TopXMLNS, + [encode_vcard_LABEL(Label, __TopXMLNS) | _acc]). + +'encode_vcard_temp_$fn'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_temp_$fn'(Fn, __TopXMLNS, _acc) -> + [encode_vcard_FN(Fn, __TopXMLNS) | _acc]. + +'encode_vcard_temp_$version'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_temp_$version'(Version, __TopXMLNS, + _acc) -> + [encode_vcard_VERSION(Version, __TopXMLNS) | _acc]. + +'encode_vcard_temp_$n'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_temp_$n'(N, __TopXMLNS, _acc) -> + [encode_vcard_N(N, __TopXMLNS) | _acc]. + +'encode_vcard_temp_$photo'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_temp_$photo'(Photo, __TopXMLNS, _acc) -> + [encode_vcard_PHOTO(Photo, __TopXMLNS) | _acc]. + +'encode_vcard_temp_$logo'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_temp_$logo'(Logo, __TopXMLNS, _acc) -> + [encode_vcard_LOGO(Logo, __TopXMLNS) | _acc]. + +'encode_vcard_temp_$geo'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_temp_$geo'(Geo, __TopXMLNS, _acc) -> + [encode_vcard_GEO(Geo, __TopXMLNS) | _acc]. decode_vcard_CLASS(__TopXMLNS, __IgnoreEls, {xmlel, <<"CLASS">>, _attrs, _els}) -> @@ -18014,20 +21588,26 @@ decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, Class). -encode_vcard_CLASS(Class, _xmlns_attrs) -> +encode_vcard_CLASS(Class, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = lists:reverse('encode_vcard_CLASS_$class'(Class, - [])), - _attrs = _xmlns_attrs, + __NewTopXMLNS, [])), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"CLASS">>, _attrs, _els}. -'encode_vcard_CLASS_$class'(undefined, _acc) -> _acc; -'encode_vcard_CLASS_$class'(public = Class, _acc) -> - [encode_vcard_PUBLIC(Class, []) | _acc]; -'encode_vcard_CLASS_$class'(private = Class, _acc) -> - [encode_vcard_PRIVATE(Class, []) | _acc]; -'encode_vcard_CLASS_$class'(confidential = Class, +'encode_vcard_CLASS_$class'(undefined, __TopXMLNS, _acc) -> - [encode_vcard_CONFIDENTIAL(Class, []) | _acc]. + _acc; +'encode_vcard_CLASS_$class'(public = Class, __TopXMLNS, + _acc) -> + [encode_vcard_PUBLIC(Class, __TopXMLNS) | _acc]; +'encode_vcard_CLASS_$class'(private = Class, __TopXMLNS, + _acc) -> + [encode_vcard_PRIVATE(Class, __TopXMLNS) | _acc]; +'encode_vcard_CLASS_$class'(confidential = Class, + __TopXMLNS, _acc) -> + [encode_vcard_CONFIDENTIAL(Class, __TopXMLNS) | _acc]. decode_vcard_CATEGORIES(__TopXMLNS, __IgnoreEls, {xmlel, <<"CATEGORIES">>, _attrs, _els}) -> @@ -18063,18 +21643,23 @@ decode_vcard_CATEGORIES_els(__TopXMLNS, __IgnoreEls, decode_vcard_CATEGORIES_els(__TopXMLNS, __IgnoreEls, _els, Keywords). -encode_vcard_CATEGORIES(Keywords, _xmlns_attrs) -> +encode_vcard_CATEGORIES(Keywords, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = lists:reverse('encode_vcard_CATEGORIES_$keywords'(Keywords, - [])), - _attrs = _xmlns_attrs, + __NewTopXMLNS, [])), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"CATEGORIES">>, _attrs, _els}. -'encode_vcard_CATEGORIES_$keywords'([], _acc) -> _acc; -'encode_vcard_CATEGORIES_$keywords'([Keywords | _els], +'encode_vcard_CATEGORIES_$keywords'([], __TopXMLNS, _acc) -> - 'encode_vcard_CATEGORIES_$keywords'(_els, - [encode_vcard_KEYWORD(Keywords, []) + _acc; +'encode_vcard_CATEGORIES_$keywords'([Keywords | _els], + __TopXMLNS, _acc) -> + 'encode_vcard_CATEGORIES_$keywords'(_els, __TopXMLNS, + [encode_vcard_KEYWORD(Keywords, + __TopXMLNS) | _acc]). decode_vcard_KEY(__TopXMLNS, __IgnoreEls, @@ -18126,21 +21711,26 @@ decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, _els, Cred, Type). -encode_vcard_KEY({vcard_key, Type, Cred}, - _xmlns_attrs) -> +encode_vcard_KEY({vcard_key, Type, Cred}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = lists:reverse('encode_vcard_KEY_$cred'(Cred, + __NewTopXMLNS, 'encode_vcard_KEY_$type'(Type, + __NewTopXMLNS, []))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"KEY">>, _attrs, _els}. -'encode_vcard_KEY_$cred'(undefined, _acc) -> _acc; -'encode_vcard_KEY_$cred'(Cred, _acc) -> - [encode_vcard_CRED(Cred, []) | _acc]. +'encode_vcard_KEY_$cred'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_KEY_$cred'(Cred, __TopXMLNS, _acc) -> + [encode_vcard_CRED(Cred, __TopXMLNS) | _acc]. -'encode_vcard_KEY_$type'(undefined, _acc) -> _acc; -'encode_vcard_KEY_$type'(Type, _acc) -> - [encode_vcard_TYPE(Type, []) | _acc]. +'encode_vcard_KEY_$type'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_KEY_$type'(Type, __TopXMLNS, _acc) -> + [encode_vcard_TYPE(Type, __TopXMLNS) | _acc]. decode_vcard_SOUND(__TopXMLNS, __IgnoreEls, {xmlel, <<"SOUND">>, _attrs, _els}) -> @@ -18215,26 +21805,40 @@ decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, encode_vcard_SOUND({vcard_sound, Phonetic, Binval, Extval}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = lists:reverse('encode_vcard_SOUND_$phonetic'(Phonetic, + __NewTopXMLNS, 'encode_vcard_SOUND_$extval'(Extval, + __NewTopXMLNS, 'encode_vcard_SOUND_$binval'(Binval, + __NewTopXMLNS, [])))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"SOUND">>, _attrs, _els}. -'encode_vcard_SOUND_$phonetic'(undefined, _acc) -> _acc; -'encode_vcard_SOUND_$phonetic'(Phonetic, _acc) -> - [encode_vcard_PHONETIC(Phonetic, []) | _acc]. +'encode_vcard_SOUND_$phonetic'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_SOUND_$phonetic'(Phonetic, __TopXMLNS, + _acc) -> + [encode_vcard_PHONETIC(Phonetic, __TopXMLNS) | _acc]. -'encode_vcard_SOUND_$extval'(undefined, _acc) -> _acc; -'encode_vcard_SOUND_$extval'(Extval, _acc) -> - [encode_vcard_EXTVAL(Extval, []) | _acc]. +'encode_vcard_SOUND_$extval'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_SOUND_$extval'(Extval, __TopXMLNS, + _acc) -> + [encode_vcard_EXTVAL(Extval, __TopXMLNS) | _acc]. -'encode_vcard_SOUND_$binval'(undefined, _acc) -> _acc; -'encode_vcard_SOUND_$binval'(Binval, _acc) -> - [encode_vcard_BINVAL(Binval, []) | _acc]. +'encode_vcard_SOUND_$binval'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_SOUND_$binval'(Binval, __TopXMLNS, + _acc) -> + [encode_vcard_BINVAL(Binval, __TopXMLNS) | _acc]. decode_vcard_ORG(__TopXMLNS, __IgnoreEls, {xmlel, <<"ORG">>, _attrs, _els}) -> @@ -18289,21 +21893,27 @@ decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, Units, Name). encode_vcard_ORG({vcard_org, Name, Units}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = lists:reverse('encode_vcard_ORG_$units'(Units, + __NewTopXMLNS, 'encode_vcard_ORG_$name'(Name, + __NewTopXMLNS, []))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"ORG">>, _attrs, _els}. -'encode_vcard_ORG_$units'([], _acc) -> _acc; -'encode_vcard_ORG_$units'([Units | _els], _acc) -> - 'encode_vcard_ORG_$units'(_els, - [encode_vcard_ORGUNIT(Units, []) | _acc]). +'encode_vcard_ORG_$units'([], __TopXMLNS, _acc) -> _acc; +'encode_vcard_ORG_$units'([Units | _els], __TopXMLNS, + _acc) -> + 'encode_vcard_ORG_$units'(_els, __TopXMLNS, + [encode_vcard_ORGUNIT(Units, __TopXMLNS) | _acc]). -'encode_vcard_ORG_$name'(undefined, _acc) -> _acc; -'encode_vcard_ORG_$name'(Name, _acc) -> - [encode_vcard_ORGNAME(Name, []) | _acc]. +'encode_vcard_ORG_$name'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_ORG_$name'(Name, __TopXMLNS, _acc) -> + [encode_vcard_ORGNAME(Name, __TopXMLNS) | _acc]. decode_vcard_PHOTO(__TopXMLNS, __IgnoreEls, {xmlel, <<"PHOTO">>, _attrs, _els}) -> @@ -18377,25 +21987,38 @@ decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, Type, Extval, Binval). encode_vcard_PHOTO({vcard_photo, Type, Binval, Extval}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = lists:reverse('encode_vcard_PHOTO_$type'(Type, + __NewTopXMLNS, 'encode_vcard_PHOTO_$extval'(Extval, + __NewTopXMLNS, 'encode_vcard_PHOTO_$binval'(Binval, + __NewTopXMLNS, [])))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"PHOTO">>, _attrs, _els}. -'encode_vcard_PHOTO_$type'(undefined, _acc) -> _acc; -'encode_vcard_PHOTO_$type'(Type, _acc) -> - [encode_vcard_TYPE(Type, []) | _acc]. +'encode_vcard_PHOTO_$type'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_PHOTO_$type'(Type, __TopXMLNS, _acc) -> + [encode_vcard_TYPE(Type, __TopXMLNS) | _acc]. -'encode_vcard_PHOTO_$extval'(undefined, _acc) -> _acc; -'encode_vcard_PHOTO_$extval'(Extval, _acc) -> - [encode_vcard_EXTVAL(Extval, []) | _acc]. +'encode_vcard_PHOTO_$extval'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_PHOTO_$extval'(Extval, __TopXMLNS, + _acc) -> + [encode_vcard_EXTVAL(Extval, __TopXMLNS) | _acc]. -'encode_vcard_PHOTO_$binval'(undefined, _acc) -> _acc; -'encode_vcard_PHOTO_$binval'(Binval, _acc) -> - [encode_vcard_BINVAL(Binval, []) | _acc]. +'encode_vcard_PHOTO_$binval'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_PHOTO_$binval'(Binval, __TopXMLNS, + _acc) -> + [encode_vcard_BINVAL(Binval, __TopXMLNS) | _acc]. decode_vcard_LOGO(__TopXMLNS, __IgnoreEls, {xmlel, <<"LOGO">>, _attrs, _els}) -> @@ -18468,25 +22091,36 @@ decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, Type, Extval, Binval). encode_vcard_LOGO({vcard_logo, Type, Binval, Extval}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = lists:reverse('encode_vcard_LOGO_$type'(Type, + __NewTopXMLNS, 'encode_vcard_LOGO_$extval'(Extval, + __NewTopXMLNS, 'encode_vcard_LOGO_$binval'(Binval, + __NewTopXMLNS, [])))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"LOGO">>, _attrs, _els}. -'encode_vcard_LOGO_$type'(undefined, _acc) -> _acc; -'encode_vcard_LOGO_$type'(Type, _acc) -> - [encode_vcard_TYPE(Type, []) | _acc]. +'encode_vcard_LOGO_$type'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_LOGO_$type'(Type, __TopXMLNS, _acc) -> + [encode_vcard_TYPE(Type, __TopXMLNS) | _acc]. -'encode_vcard_LOGO_$extval'(undefined, _acc) -> _acc; -'encode_vcard_LOGO_$extval'(Extval, _acc) -> - [encode_vcard_EXTVAL(Extval, []) | _acc]. +'encode_vcard_LOGO_$extval'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_LOGO_$extval'(Extval, __TopXMLNS, _acc) -> + [encode_vcard_EXTVAL(Extval, __TopXMLNS) | _acc]. -'encode_vcard_LOGO_$binval'(undefined, _acc) -> _acc; -'encode_vcard_LOGO_$binval'(Binval, _acc) -> - [encode_vcard_BINVAL(Binval, []) | _acc]. +'encode_vcard_LOGO_$binval'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_LOGO_$binval'(Binval, __TopXMLNS, _acc) -> + [encode_vcard_BINVAL(Binval, __TopXMLNS) | _acc]. decode_vcard_BINVAL(__TopXMLNS, __IgnoreEls, {xmlel, <<"BINVAL">>, _attrs, _els}) -> @@ -18506,9 +22140,11 @@ decode_vcard_BINVAL_els(__TopXMLNS, __IgnoreEls, decode_vcard_BINVAL_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_BINVAL(Cdata, _xmlns_attrs) -> +encode_vcard_BINVAL(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_BINVAL_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"BINVAL">>, _attrs, _els}. decode_vcard_BINVAL_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -18570,20 +22206,26 @@ decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, _els, Lat, Lon). -encode_vcard_GEO({vcard_geo, Lat, Lon}, _xmlns_attrs) -> +encode_vcard_GEO({vcard_geo, Lat, Lon}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = lists:reverse('encode_vcard_GEO_$lat'(Lat, + __NewTopXMLNS, 'encode_vcard_GEO_$lon'(Lon, + __NewTopXMLNS, []))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"GEO">>, _attrs, _els}. -'encode_vcard_GEO_$lat'(undefined, _acc) -> _acc; -'encode_vcard_GEO_$lat'(Lat, _acc) -> - [encode_vcard_LAT(Lat, []) | _acc]. +'encode_vcard_GEO_$lat'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_GEO_$lat'(Lat, __TopXMLNS, _acc) -> + [encode_vcard_LAT(Lat, __TopXMLNS) | _acc]. -'encode_vcard_GEO_$lon'(undefined, _acc) -> _acc; -'encode_vcard_GEO_$lon'(Lon, _acc) -> - [encode_vcard_LON(Lon, []) | _acc]. +'encode_vcard_GEO_$lon'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_GEO_$lon'(Lon, __TopXMLNS, _acc) -> + [encode_vcard_LON(Lon, __TopXMLNS) | _acc]. decode_vcard_EMAIL(__TopXMLNS, __IgnoreEls, {xmlel, <<"EMAIL">>, _attrs, _els}) -> @@ -18718,40 +22360,58 @@ decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, encode_vcard_EMAIL({vcard_email, Home, Work, Internet, Pref, X400, Userid}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = lists:reverse('encode_vcard_EMAIL_$x400'(X400, + __NewTopXMLNS, 'encode_vcard_EMAIL_$userid'(Userid, + __NewTopXMLNS, 'encode_vcard_EMAIL_$internet'(Internet, + __NewTopXMLNS, 'encode_vcard_EMAIL_$home'(Home, + __NewTopXMLNS, 'encode_vcard_EMAIL_$pref'(Pref, + __NewTopXMLNS, 'encode_vcard_EMAIL_$work'(Work, + __NewTopXMLNS, []))))))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"EMAIL">>, _attrs, _els}. -'encode_vcard_EMAIL_$x400'(false, _acc) -> _acc; -'encode_vcard_EMAIL_$x400'(X400, _acc) -> - [encode_vcard_X400(X400, []) | _acc]. +'encode_vcard_EMAIL_$x400'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_EMAIL_$x400'(X400, __TopXMLNS, _acc) -> + [encode_vcard_X400(X400, __TopXMLNS) | _acc]. -'encode_vcard_EMAIL_$userid'(undefined, _acc) -> _acc; -'encode_vcard_EMAIL_$userid'(Userid, _acc) -> - [encode_vcard_USERID(Userid, []) | _acc]. +'encode_vcard_EMAIL_$userid'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_EMAIL_$userid'(Userid, __TopXMLNS, + _acc) -> + [encode_vcard_USERID(Userid, __TopXMLNS) | _acc]. -'encode_vcard_EMAIL_$internet'(false, _acc) -> _acc; -'encode_vcard_EMAIL_$internet'(Internet, _acc) -> - [encode_vcard_INTERNET(Internet, []) | _acc]. +'encode_vcard_EMAIL_$internet'(false, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_EMAIL_$internet'(Internet, __TopXMLNS, + _acc) -> + [encode_vcard_INTERNET(Internet, __TopXMLNS) | _acc]. -'encode_vcard_EMAIL_$home'(false, _acc) -> _acc; -'encode_vcard_EMAIL_$home'(Home, _acc) -> - [encode_vcard_HOME(Home, []) | _acc]. +'encode_vcard_EMAIL_$home'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_EMAIL_$home'(Home, __TopXMLNS, _acc) -> + [encode_vcard_HOME(Home, __TopXMLNS) | _acc]. -'encode_vcard_EMAIL_$pref'(false, _acc) -> _acc; -'encode_vcard_EMAIL_$pref'(Pref, _acc) -> - [encode_vcard_PREF(Pref, []) | _acc]. +'encode_vcard_EMAIL_$pref'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_EMAIL_$pref'(Pref, __TopXMLNS, _acc) -> + [encode_vcard_PREF(Pref, __TopXMLNS) | _acc]. -'encode_vcard_EMAIL_$work'(false, _acc) -> _acc; -'encode_vcard_EMAIL_$work'(Work, _acc) -> - [encode_vcard_WORK(Work, []) | _acc]. +'encode_vcard_EMAIL_$work'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_EMAIL_$work'(Work, __TopXMLNS, _acc) -> + [encode_vcard_WORK(Work, __TopXMLNS) | _acc]. decode_vcard_TEL(__TopXMLNS, __IgnoreEls, {xmlel, <<"TEL">>, _attrs, _els}) -> @@ -19091,80 +22751,111 @@ decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, encode_vcard_TEL({vcard_tel, Home, Work, Voice, Fax, Pager, Msg, Cell, Video, Bbs, Modem, Isdn, Pcs, Pref, Number}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = lists:reverse('encode_vcard_TEL_$number'(Number, + __NewTopXMLNS, 'encode_vcard_TEL_$pager'(Pager, + __NewTopXMLNS, 'encode_vcard_TEL_$pcs'(Pcs, + __NewTopXMLNS, 'encode_vcard_TEL_$bbs'(Bbs, + __NewTopXMLNS, 'encode_vcard_TEL_$voice'(Voice, + __NewTopXMLNS, 'encode_vcard_TEL_$home'(Home, + __NewTopXMLNS, 'encode_vcard_TEL_$pref'(Pref, + __NewTopXMLNS, 'encode_vcard_TEL_$msg'(Msg, + __NewTopXMLNS, 'encode_vcard_TEL_$fax'(Fax, + __NewTopXMLNS, 'encode_vcard_TEL_$work'(Work, + __NewTopXMLNS, 'encode_vcard_TEL_$cell'(Cell, + __NewTopXMLNS, 'encode_vcard_TEL_$modem'(Modem, + __NewTopXMLNS, 'encode_vcard_TEL_$isdn'(Isdn, + __NewTopXMLNS, 'encode_vcard_TEL_$video'(Video, + __NewTopXMLNS, []))))))))))))))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"TEL">>, _attrs, _els}. -'encode_vcard_TEL_$number'(undefined, _acc) -> _acc; -'encode_vcard_TEL_$number'(Number, _acc) -> - [encode_vcard_NUMBER(Number, []) | _acc]. +'encode_vcard_TEL_$number'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_TEL_$number'(Number, __TopXMLNS, _acc) -> + [encode_vcard_NUMBER(Number, __TopXMLNS) | _acc]. -'encode_vcard_TEL_$pager'(false, _acc) -> _acc; -'encode_vcard_TEL_$pager'(Pager, _acc) -> - [encode_vcard_PAGER(Pager, []) | _acc]. +'encode_vcard_TEL_$pager'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_TEL_$pager'(Pager, __TopXMLNS, _acc) -> + [encode_vcard_PAGER(Pager, __TopXMLNS) | _acc]. -'encode_vcard_TEL_$pcs'(false, _acc) -> _acc; -'encode_vcard_TEL_$pcs'(Pcs, _acc) -> - [encode_vcard_PCS(Pcs, []) | _acc]. +'encode_vcard_TEL_$pcs'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_TEL_$pcs'(Pcs, __TopXMLNS, _acc) -> + [encode_vcard_PCS(Pcs, __TopXMLNS) | _acc]. -'encode_vcard_TEL_$bbs'(false, _acc) -> _acc; -'encode_vcard_TEL_$bbs'(Bbs, _acc) -> - [encode_vcard_BBS(Bbs, []) | _acc]. +'encode_vcard_TEL_$bbs'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_TEL_$bbs'(Bbs, __TopXMLNS, _acc) -> + [encode_vcard_BBS(Bbs, __TopXMLNS) | _acc]. -'encode_vcard_TEL_$voice'(false, _acc) -> _acc; -'encode_vcard_TEL_$voice'(Voice, _acc) -> - [encode_vcard_VOICE(Voice, []) | _acc]. +'encode_vcard_TEL_$voice'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_TEL_$voice'(Voice, __TopXMLNS, _acc) -> + [encode_vcard_VOICE(Voice, __TopXMLNS) | _acc]. -'encode_vcard_TEL_$home'(false, _acc) -> _acc; -'encode_vcard_TEL_$home'(Home, _acc) -> - [encode_vcard_HOME(Home, []) | _acc]. +'encode_vcard_TEL_$home'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_TEL_$home'(Home, __TopXMLNS, _acc) -> + [encode_vcard_HOME(Home, __TopXMLNS) | _acc]. -'encode_vcard_TEL_$pref'(false, _acc) -> _acc; -'encode_vcard_TEL_$pref'(Pref, _acc) -> - [encode_vcard_PREF(Pref, []) | _acc]. +'encode_vcard_TEL_$pref'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_TEL_$pref'(Pref, __TopXMLNS, _acc) -> + [encode_vcard_PREF(Pref, __TopXMLNS) | _acc]. -'encode_vcard_TEL_$msg'(false, _acc) -> _acc; -'encode_vcard_TEL_$msg'(Msg, _acc) -> - [encode_vcard_MSG(Msg, []) | _acc]. +'encode_vcard_TEL_$msg'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_TEL_$msg'(Msg, __TopXMLNS, _acc) -> + [encode_vcard_MSG(Msg, __TopXMLNS) | _acc]. -'encode_vcard_TEL_$fax'(false, _acc) -> _acc; -'encode_vcard_TEL_$fax'(Fax, _acc) -> - [encode_vcard_FAX(Fax, []) | _acc]. +'encode_vcard_TEL_$fax'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_TEL_$fax'(Fax, __TopXMLNS, _acc) -> + [encode_vcard_FAX(Fax, __TopXMLNS) | _acc]. -'encode_vcard_TEL_$work'(false, _acc) -> _acc; -'encode_vcard_TEL_$work'(Work, _acc) -> - [encode_vcard_WORK(Work, []) | _acc]. +'encode_vcard_TEL_$work'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_TEL_$work'(Work, __TopXMLNS, _acc) -> + [encode_vcard_WORK(Work, __TopXMLNS) | _acc]. -'encode_vcard_TEL_$cell'(false, _acc) -> _acc; -'encode_vcard_TEL_$cell'(Cell, _acc) -> - [encode_vcard_CELL(Cell, []) | _acc]. +'encode_vcard_TEL_$cell'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_TEL_$cell'(Cell, __TopXMLNS, _acc) -> + [encode_vcard_CELL(Cell, __TopXMLNS) | _acc]. -'encode_vcard_TEL_$modem'(false, _acc) -> _acc; -'encode_vcard_TEL_$modem'(Modem, _acc) -> - [encode_vcard_MODEM(Modem, []) | _acc]. +'encode_vcard_TEL_$modem'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_TEL_$modem'(Modem, __TopXMLNS, _acc) -> + [encode_vcard_MODEM(Modem, __TopXMLNS) | _acc]. -'encode_vcard_TEL_$isdn'(false, _acc) -> _acc; -'encode_vcard_TEL_$isdn'(Isdn, _acc) -> - [encode_vcard_ISDN(Isdn, []) | _acc]. +'encode_vcard_TEL_$isdn'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_TEL_$isdn'(Isdn, __TopXMLNS, _acc) -> + [encode_vcard_ISDN(Isdn, __TopXMLNS) | _acc]. -'encode_vcard_TEL_$video'(false, _acc) -> _acc; -'encode_vcard_TEL_$video'(Video, _acc) -> - [encode_vcard_VIDEO(Video, []) | _acc]. +'encode_vcard_TEL_$video'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_TEL_$video'(Video, __TopXMLNS, _acc) -> + [encode_vcard_VIDEO(Video, __TopXMLNS) | _acc]. decode_vcard_LABEL(__TopXMLNS, __IgnoreEls, {xmlel, <<"LABEL">>, _attrs, _els}) -> @@ -19353,51 +23044,72 @@ decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, encode_vcard_LABEL({vcard_label, Home, Work, Postal, Parcel, Dom, Intl, Pref, Line}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = lists:reverse('encode_vcard_LABEL_$line'(Line, + __NewTopXMLNS, 'encode_vcard_LABEL_$home'(Home, + __NewTopXMLNS, 'encode_vcard_LABEL_$pref'(Pref, + __NewTopXMLNS, 'encode_vcard_LABEL_$work'(Work, + __NewTopXMLNS, 'encode_vcard_LABEL_$intl'(Intl, + __NewTopXMLNS, 'encode_vcard_LABEL_$parcel'(Parcel, + __NewTopXMLNS, 'encode_vcard_LABEL_$postal'(Postal, + __NewTopXMLNS, 'encode_vcard_LABEL_$dom'(Dom, + __NewTopXMLNS, []))))))))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"LABEL">>, _attrs, _els}. -'encode_vcard_LABEL_$line'([], _acc) -> _acc; -'encode_vcard_LABEL_$line'([Line | _els], _acc) -> - 'encode_vcard_LABEL_$line'(_els, - [encode_vcard_LINE(Line, []) | _acc]). +'encode_vcard_LABEL_$line'([], __TopXMLNS, _acc) -> + _acc; +'encode_vcard_LABEL_$line'([Line | _els], __TopXMLNS, + _acc) -> + 'encode_vcard_LABEL_$line'(_els, __TopXMLNS, + [encode_vcard_LINE(Line, __TopXMLNS) | _acc]). -'encode_vcard_LABEL_$home'(false, _acc) -> _acc; -'encode_vcard_LABEL_$home'(Home, _acc) -> - [encode_vcard_HOME(Home, []) | _acc]. +'encode_vcard_LABEL_$home'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_LABEL_$home'(Home, __TopXMLNS, _acc) -> + [encode_vcard_HOME(Home, __TopXMLNS) | _acc]. -'encode_vcard_LABEL_$pref'(false, _acc) -> _acc; -'encode_vcard_LABEL_$pref'(Pref, _acc) -> - [encode_vcard_PREF(Pref, []) | _acc]. +'encode_vcard_LABEL_$pref'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_LABEL_$pref'(Pref, __TopXMLNS, _acc) -> + [encode_vcard_PREF(Pref, __TopXMLNS) | _acc]. -'encode_vcard_LABEL_$work'(false, _acc) -> _acc; -'encode_vcard_LABEL_$work'(Work, _acc) -> - [encode_vcard_WORK(Work, []) | _acc]. +'encode_vcard_LABEL_$work'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_LABEL_$work'(Work, __TopXMLNS, _acc) -> + [encode_vcard_WORK(Work, __TopXMLNS) | _acc]. -'encode_vcard_LABEL_$intl'(false, _acc) -> _acc; -'encode_vcard_LABEL_$intl'(Intl, _acc) -> - [encode_vcard_INTL(Intl, []) | _acc]. +'encode_vcard_LABEL_$intl'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_LABEL_$intl'(Intl, __TopXMLNS, _acc) -> + [encode_vcard_INTL(Intl, __TopXMLNS) | _acc]. -'encode_vcard_LABEL_$parcel'(false, _acc) -> _acc; -'encode_vcard_LABEL_$parcel'(Parcel, _acc) -> - [encode_vcard_PARCEL(Parcel, []) | _acc]. +'encode_vcard_LABEL_$parcel'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_LABEL_$parcel'(Parcel, __TopXMLNS, + _acc) -> + [encode_vcard_PARCEL(Parcel, __TopXMLNS) | _acc]. -'encode_vcard_LABEL_$postal'(false, _acc) -> _acc; -'encode_vcard_LABEL_$postal'(Postal, _acc) -> - [encode_vcard_POSTAL(Postal, []) | _acc]. +'encode_vcard_LABEL_$postal'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_LABEL_$postal'(Postal, __TopXMLNS, + _acc) -> + [encode_vcard_POSTAL(Postal, __TopXMLNS) | _acc]. -'encode_vcard_LABEL_$dom'(false, _acc) -> _acc; -'encode_vcard_LABEL_$dom'(Dom, _acc) -> - [encode_vcard_DOM(Dom, []) | _acc]. +'encode_vcard_LABEL_$dom'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_LABEL_$dom'(Dom, __TopXMLNS, _acc) -> + [encode_vcard_DOM(Dom, __TopXMLNS) | _acc]. decode_vcard_ADR(__TopXMLNS, __IgnoreEls, {xmlel, <<"ADR">>, _attrs, _els}) -> @@ -19762,80 +23474,117 @@ decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, encode_vcard_ADR({vcard_adr, Home, Work, Postal, Parcel, Dom, Intl, Pref, Pobox, Extadd, Street, Locality, Region, Pcode, Ctry}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = lists:reverse('encode_vcard_ADR_$street'(Street, + __NewTopXMLNS, 'encode_vcard_ADR_$extadd'(Extadd, + __NewTopXMLNS, 'encode_vcard_ADR_$pcode'(Pcode, + __NewTopXMLNS, 'encode_vcard_ADR_$home'(Home, + __NewTopXMLNS, 'encode_vcard_ADR_$pref'(Pref, + __NewTopXMLNS, 'encode_vcard_ADR_$pobox'(Pobox, + __NewTopXMLNS, 'encode_vcard_ADR_$ctry'(Ctry, + __NewTopXMLNS, 'encode_vcard_ADR_$locality'(Locality, + __NewTopXMLNS, 'encode_vcard_ADR_$work'(Work, + __NewTopXMLNS, 'encode_vcard_ADR_$intl'(Intl, + __NewTopXMLNS, 'encode_vcard_ADR_$parcel'(Parcel, + __NewTopXMLNS, 'encode_vcard_ADR_$postal'(Postal, + __NewTopXMLNS, 'encode_vcard_ADR_$dom'(Dom, + __NewTopXMLNS, 'encode_vcard_ADR_$region'(Region, + __NewTopXMLNS, []))))))))))))))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"ADR">>, _attrs, _els}. -'encode_vcard_ADR_$street'(undefined, _acc) -> _acc; -'encode_vcard_ADR_$street'(Street, _acc) -> - [encode_vcard_STREET(Street, []) | _acc]. +'encode_vcard_ADR_$street'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_ADR_$street'(Street, __TopXMLNS, _acc) -> + [encode_vcard_STREET(Street, __TopXMLNS) | _acc]. -'encode_vcard_ADR_$extadd'(undefined, _acc) -> _acc; -'encode_vcard_ADR_$extadd'(Extadd, _acc) -> - [encode_vcard_EXTADD(Extadd, []) | _acc]. +'encode_vcard_ADR_$extadd'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_ADR_$extadd'(Extadd, __TopXMLNS, _acc) -> + [encode_vcard_EXTADD(Extadd, __TopXMLNS) | _acc]. -'encode_vcard_ADR_$pcode'(undefined, _acc) -> _acc; -'encode_vcard_ADR_$pcode'(Pcode, _acc) -> - [encode_vcard_PCODE(Pcode, []) | _acc]. +'encode_vcard_ADR_$pcode'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_ADR_$pcode'(Pcode, __TopXMLNS, _acc) -> + [encode_vcard_PCODE(Pcode, __TopXMLNS) | _acc]. -'encode_vcard_ADR_$home'(false, _acc) -> _acc; -'encode_vcard_ADR_$home'(Home, _acc) -> - [encode_vcard_HOME(Home, []) | _acc]. +'encode_vcard_ADR_$home'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_ADR_$home'(Home, __TopXMLNS, _acc) -> + [encode_vcard_HOME(Home, __TopXMLNS) | _acc]. -'encode_vcard_ADR_$pref'(false, _acc) -> _acc; -'encode_vcard_ADR_$pref'(Pref, _acc) -> - [encode_vcard_PREF(Pref, []) | _acc]. +'encode_vcard_ADR_$pref'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_ADR_$pref'(Pref, __TopXMLNS, _acc) -> + [encode_vcard_PREF(Pref, __TopXMLNS) | _acc]. -'encode_vcard_ADR_$pobox'(undefined, _acc) -> _acc; -'encode_vcard_ADR_$pobox'(Pobox, _acc) -> - [encode_vcard_POBOX(Pobox, []) | _acc]. +'encode_vcard_ADR_$pobox'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_ADR_$pobox'(Pobox, __TopXMLNS, _acc) -> + [encode_vcard_POBOX(Pobox, __TopXMLNS) | _acc]. -'encode_vcard_ADR_$ctry'(undefined, _acc) -> _acc; -'encode_vcard_ADR_$ctry'(Ctry, _acc) -> - [encode_vcard_CTRY(Ctry, []) | _acc]. +'encode_vcard_ADR_$ctry'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_ADR_$ctry'(Ctry, __TopXMLNS, _acc) -> + [encode_vcard_CTRY(Ctry, __TopXMLNS) | _acc]. -'encode_vcard_ADR_$locality'(undefined, _acc) -> _acc; -'encode_vcard_ADR_$locality'(Locality, _acc) -> - [encode_vcard_LOCALITY(Locality, []) | _acc]. +'encode_vcard_ADR_$locality'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_ADR_$locality'(Locality, __TopXMLNS, + _acc) -> + [encode_vcard_LOCALITY(Locality, __TopXMLNS) | _acc]. -'encode_vcard_ADR_$work'(false, _acc) -> _acc; -'encode_vcard_ADR_$work'(Work, _acc) -> - [encode_vcard_WORK(Work, []) | _acc]. +'encode_vcard_ADR_$work'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_ADR_$work'(Work, __TopXMLNS, _acc) -> + [encode_vcard_WORK(Work, __TopXMLNS) | _acc]. -'encode_vcard_ADR_$intl'(false, _acc) -> _acc; -'encode_vcard_ADR_$intl'(Intl, _acc) -> - [encode_vcard_INTL(Intl, []) | _acc]. +'encode_vcard_ADR_$intl'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_ADR_$intl'(Intl, __TopXMLNS, _acc) -> + [encode_vcard_INTL(Intl, __TopXMLNS) | _acc]. -'encode_vcard_ADR_$parcel'(false, _acc) -> _acc; -'encode_vcard_ADR_$parcel'(Parcel, _acc) -> - [encode_vcard_PARCEL(Parcel, []) | _acc]. +'encode_vcard_ADR_$parcel'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_ADR_$parcel'(Parcel, __TopXMLNS, _acc) -> + [encode_vcard_PARCEL(Parcel, __TopXMLNS) | _acc]. -'encode_vcard_ADR_$postal'(false, _acc) -> _acc; -'encode_vcard_ADR_$postal'(Postal, _acc) -> - [encode_vcard_POSTAL(Postal, []) | _acc]. +'encode_vcard_ADR_$postal'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_ADR_$postal'(Postal, __TopXMLNS, _acc) -> + [encode_vcard_POSTAL(Postal, __TopXMLNS) | _acc]. -'encode_vcard_ADR_$dom'(false, _acc) -> _acc; -'encode_vcard_ADR_$dom'(Dom, _acc) -> - [encode_vcard_DOM(Dom, []) | _acc]. +'encode_vcard_ADR_$dom'(false, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_ADR_$dom'(Dom, __TopXMLNS, _acc) -> + [encode_vcard_DOM(Dom, __TopXMLNS) | _acc]. -'encode_vcard_ADR_$region'(undefined, _acc) -> _acc; -'encode_vcard_ADR_$region'(Region, _acc) -> - [encode_vcard_REGION(Region, []) | _acc]. +'encode_vcard_ADR_$region'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_vcard_ADR_$region'(Region, __TopXMLNS, _acc) -> + [encode_vcard_REGION(Region, __TopXMLNS) | _acc]. decode_vcard_N(__TopXMLNS, __IgnoreEls, {xmlel, <<"N">>, _attrs, _els}) -> @@ -19946,61 +23695,79 @@ decode_vcard_N_els(__TopXMLNS, __IgnoreEls, [_ | _els], encode_vcard_N({vcard_name, Family, Given, Middle, Prefix, Suffix}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = lists:reverse('encode_vcard_N_$middle'(Middle, + __NewTopXMLNS, 'encode_vcard_N_$suffix'(Suffix, + __NewTopXMLNS, 'encode_vcard_N_$prefix'(Prefix, + __NewTopXMLNS, 'encode_vcard_N_$family'(Family, + __NewTopXMLNS, 'encode_vcard_N_$given'(Given, + __NewTopXMLNS, [])))))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"N">>, _attrs, _els}. -'encode_vcard_N_$middle'(undefined, _acc) -> _acc; -'encode_vcard_N_$middle'(Middle, _acc) -> - [encode_vcard_MIDDLE(Middle, []) | _acc]. +'encode_vcard_N_$middle'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_N_$middle'(Middle, __TopXMLNS, _acc) -> + [encode_vcard_MIDDLE(Middle, __TopXMLNS) | _acc]. -'encode_vcard_N_$suffix'(undefined, _acc) -> _acc; -'encode_vcard_N_$suffix'(Suffix, _acc) -> - [encode_vcard_SUFFIX(Suffix, []) | _acc]. +'encode_vcard_N_$suffix'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_N_$suffix'(Suffix, __TopXMLNS, _acc) -> + [encode_vcard_SUFFIX(Suffix, __TopXMLNS) | _acc]. -'encode_vcard_N_$prefix'(undefined, _acc) -> _acc; -'encode_vcard_N_$prefix'(Prefix, _acc) -> - [encode_vcard_PREFIX(Prefix, []) | _acc]. +'encode_vcard_N_$prefix'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_N_$prefix'(Prefix, __TopXMLNS, _acc) -> + [encode_vcard_PREFIX(Prefix, __TopXMLNS) | _acc]. -'encode_vcard_N_$family'(undefined, _acc) -> _acc; -'encode_vcard_N_$family'(Family, _acc) -> - [encode_vcard_FAMILY(Family, []) | _acc]. +'encode_vcard_N_$family'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_N_$family'(Family, __TopXMLNS, _acc) -> + [encode_vcard_FAMILY(Family, __TopXMLNS) | _acc]. -'encode_vcard_N_$given'(undefined, _acc) -> _acc; -'encode_vcard_N_$given'(Given, _acc) -> - [encode_vcard_GIVEN(Given, []) | _acc]. +'encode_vcard_N_$given'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_vcard_N_$given'(Given, __TopXMLNS, _acc) -> + [encode_vcard_GIVEN(Given, __TopXMLNS) | _acc]. decode_vcard_CONFIDENTIAL(__TopXMLNS, __IgnoreEls, {xmlel, <<"CONFIDENTIAL">>, _attrs, _els}) -> confidential. -encode_vcard_CONFIDENTIAL(confidential, _xmlns_attrs) -> +encode_vcard_CONFIDENTIAL(confidential, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"CONFIDENTIAL">>, _attrs, _els}. decode_vcard_PRIVATE(__TopXMLNS, __IgnoreEls, {xmlel, <<"PRIVATE">>, _attrs, _els}) -> private. -encode_vcard_PRIVATE(private, _xmlns_attrs) -> +encode_vcard_PRIVATE(private, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"PRIVATE">>, _attrs, _els}. decode_vcard_PUBLIC(__TopXMLNS, __IgnoreEls, {xmlel, <<"PUBLIC">>, _attrs, _els}) -> public. -encode_vcard_PUBLIC(public, _xmlns_attrs) -> +encode_vcard_PUBLIC(public, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"PUBLIC">>, _attrs, _els}. decode_vcard_EXTVAL(__TopXMLNS, __IgnoreEls, @@ -20021,9 +23788,11 @@ decode_vcard_EXTVAL_els(__TopXMLNS, __IgnoreEls, decode_vcard_EXTVAL_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_EXTVAL(Cdata, _xmlns_attrs) -> +encode_vcard_EXTVAL(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_EXTVAL_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"EXTVAL">>, _attrs, _els}. decode_vcard_EXTVAL_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20051,9 +23820,11 @@ decode_vcard_TYPE_els(__TopXMLNS, __IgnoreEls, decode_vcard_TYPE_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_TYPE(Cdata, _xmlns_attrs) -> +encode_vcard_TYPE(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_TYPE_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"TYPE">>, _attrs, _els}. decode_vcard_TYPE_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20081,9 +23852,11 @@ decode_vcard_DESC_els(__TopXMLNS, __IgnoreEls, decode_vcard_DESC_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_DESC(Cdata, _xmlns_attrs) -> +encode_vcard_DESC(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_DESC_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"DESC">>, _attrs, _els}. decode_vcard_DESC_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20111,9 +23884,11 @@ decode_vcard_URL_els(__TopXMLNS, __IgnoreEls, decode_vcard_URL_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_URL(Cdata, _xmlns_attrs) -> +encode_vcard_URL(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_URL_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"URL">>, _attrs, _els}. decode_vcard_URL_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20141,9 +23916,11 @@ decode_vcard_UID_els(__TopXMLNS, __IgnoreEls, decode_vcard_UID_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_UID(Cdata, _xmlns_attrs) -> +encode_vcard_UID(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_UID_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"UID">>, _attrs, _els}. decode_vcard_UID_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20171,9 +23948,11 @@ decode_vcard_SORT_STRING_els(__TopXMLNS, __IgnoreEls, decode_vcard_SORT_STRING_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_SORT_STRING(Cdata, _xmlns_attrs) -> +encode_vcard_SORT_STRING(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_SORT_STRING_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"SORT-STRING">>, _attrs, _els}. decode_vcard_SORT_STRING_cdata(__TopXMLNS, <<>>) -> @@ -20203,9 +23982,11 @@ decode_vcard_REV_els(__TopXMLNS, __IgnoreEls, decode_vcard_REV_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_REV(Cdata, _xmlns_attrs) -> +encode_vcard_REV(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_REV_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"REV">>, _attrs, _els}. decode_vcard_REV_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20233,9 +24014,11 @@ decode_vcard_PRODID_els(__TopXMLNS, __IgnoreEls, decode_vcard_PRODID_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_PRODID(Cdata, _xmlns_attrs) -> +encode_vcard_PRODID(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_PRODID_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"PRODID">>, _attrs, _els}. decode_vcard_PRODID_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20263,9 +24046,11 @@ decode_vcard_NOTE_els(__TopXMLNS, __IgnoreEls, decode_vcard_NOTE_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_NOTE(Cdata, _xmlns_attrs) -> +encode_vcard_NOTE(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_NOTE_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"NOTE">>, _attrs, _els}. decode_vcard_NOTE_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20293,9 +24078,11 @@ decode_vcard_KEYWORD_els(__TopXMLNS, __IgnoreEls, decode_vcard_KEYWORD_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_KEYWORD(Cdata, _xmlns_attrs) -> +encode_vcard_KEYWORD(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_KEYWORD_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"KEYWORD">>, _attrs, _els}. decode_vcard_KEYWORD_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20323,9 +24110,11 @@ decode_vcard_ROLE_els(__TopXMLNS, __IgnoreEls, decode_vcard_ROLE_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_ROLE(Cdata, _xmlns_attrs) -> +encode_vcard_ROLE(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_ROLE_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"ROLE">>, _attrs, _els}. decode_vcard_ROLE_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20353,9 +24142,11 @@ decode_vcard_TITLE_els(__TopXMLNS, __IgnoreEls, decode_vcard_TITLE_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_TITLE(Cdata, _xmlns_attrs) -> +encode_vcard_TITLE(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_TITLE_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"TITLE">>, _attrs, _els}. decode_vcard_TITLE_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20383,9 +24174,11 @@ decode_vcard_TZ_els(__TopXMLNS, __IgnoreEls, [_ | _els], decode_vcard_TZ_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_TZ(Cdata, _xmlns_attrs) -> +encode_vcard_TZ(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_TZ_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"TZ">>, _attrs, _els}. decode_vcard_TZ_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20413,9 +24206,11 @@ decode_vcard_MAILER_els(__TopXMLNS, __IgnoreEls, decode_vcard_MAILER_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_MAILER(Cdata, _xmlns_attrs) -> +encode_vcard_MAILER(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_MAILER_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"MAILER">>, _attrs, _els}. decode_vcard_MAILER_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20443,9 +24238,11 @@ decode_vcard_JABBERID_els(__TopXMLNS, __IgnoreEls, decode_vcard_JABBERID_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_JABBERID(Cdata, _xmlns_attrs) -> +encode_vcard_JABBERID(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_JABBERID_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"JABBERID">>, _attrs, _els}. decode_vcard_JABBERID_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20473,9 +24270,11 @@ decode_vcard_BDAY_els(__TopXMLNS, __IgnoreEls, decode_vcard_BDAY_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_BDAY(Cdata, _xmlns_attrs) -> +encode_vcard_BDAY(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_BDAY_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"BDAY">>, _attrs, _els}. decode_vcard_BDAY_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20503,9 +24302,11 @@ decode_vcard_NICKNAME_els(__TopXMLNS, __IgnoreEls, decode_vcard_NICKNAME_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_NICKNAME(Cdata, _xmlns_attrs) -> +encode_vcard_NICKNAME(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_NICKNAME_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"NICKNAME">>, _attrs, _els}. decode_vcard_NICKNAME_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20533,9 +24334,11 @@ decode_vcard_FN_els(__TopXMLNS, __IgnoreEls, [_ | _els], decode_vcard_FN_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_FN(Cdata, _xmlns_attrs) -> +encode_vcard_FN(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_FN_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"FN">>, _attrs, _els}. decode_vcard_FN_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20563,9 +24366,11 @@ decode_vcard_VERSION_els(__TopXMLNS, __IgnoreEls, decode_vcard_VERSION_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_VERSION(Cdata, _xmlns_attrs) -> +encode_vcard_VERSION(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_VERSION_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"VERSION">>, _attrs, _els}. decode_vcard_VERSION_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20593,9 +24398,11 @@ decode_vcard_CRED_els(__TopXMLNS, __IgnoreEls, decode_vcard_CRED_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_CRED(Cdata, _xmlns_attrs) -> +encode_vcard_CRED(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_CRED_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"CRED">>, _attrs, _els}. decode_vcard_CRED_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20623,9 +24430,11 @@ decode_vcard_PHONETIC_els(__TopXMLNS, __IgnoreEls, decode_vcard_PHONETIC_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_PHONETIC(Cdata, _xmlns_attrs) -> +encode_vcard_PHONETIC(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_PHONETIC_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"PHONETIC">>, _attrs, _els}. decode_vcard_PHONETIC_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20653,9 +24462,11 @@ decode_vcard_ORGUNIT_els(__TopXMLNS, __IgnoreEls, decode_vcard_ORGUNIT_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_ORGUNIT(Cdata, _xmlns_attrs) -> +encode_vcard_ORGUNIT(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_ORGUNIT_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"ORGUNIT">>, _attrs, _els}. decode_vcard_ORGUNIT_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20683,9 +24494,11 @@ decode_vcard_ORGNAME_els(__TopXMLNS, __IgnoreEls, decode_vcard_ORGNAME_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_ORGNAME(Cdata, _xmlns_attrs) -> +encode_vcard_ORGNAME(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_ORGNAME_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"ORGNAME">>, _attrs, _els}. decode_vcard_ORGNAME_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20713,9 +24526,11 @@ decode_vcard_LON_els(__TopXMLNS, __IgnoreEls, decode_vcard_LON_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_LON(Cdata, _xmlns_attrs) -> +encode_vcard_LON(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_LON_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"LON">>, _attrs, _els}. decode_vcard_LON_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20743,9 +24558,11 @@ decode_vcard_LAT_els(__TopXMLNS, __IgnoreEls, decode_vcard_LAT_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_LAT(Cdata, _xmlns_attrs) -> +encode_vcard_LAT(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_LAT_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"LAT">>, _attrs, _els}. decode_vcard_LAT_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20773,9 +24590,11 @@ decode_vcard_USERID_els(__TopXMLNS, __IgnoreEls, decode_vcard_USERID_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_USERID(Cdata, _xmlns_attrs) -> +encode_vcard_USERID(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_USERID_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"USERID">>, _attrs, _els}. decode_vcard_USERID_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20803,9 +24622,11 @@ decode_vcard_NUMBER_els(__TopXMLNS, __IgnoreEls, decode_vcard_NUMBER_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_NUMBER(Cdata, _xmlns_attrs) -> +encode_vcard_NUMBER(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_NUMBER_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"NUMBER">>, _attrs, _els}. decode_vcard_NUMBER_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20833,9 +24654,11 @@ decode_vcard_LINE_els(__TopXMLNS, __IgnoreEls, decode_vcard_LINE_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_LINE(Cdata, _xmlns_attrs) -> +encode_vcard_LINE(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_LINE_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"LINE">>, _attrs, _els}. decode_vcard_LINE_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20863,9 +24686,11 @@ decode_vcard_CTRY_els(__TopXMLNS, __IgnoreEls, decode_vcard_CTRY_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_CTRY(Cdata, _xmlns_attrs) -> +encode_vcard_CTRY(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_CTRY_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"CTRY">>, _attrs, _els}. decode_vcard_CTRY_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20893,9 +24718,11 @@ decode_vcard_PCODE_els(__TopXMLNS, __IgnoreEls, decode_vcard_PCODE_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_PCODE(Cdata, _xmlns_attrs) -> +encode_vcard_PCODE(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_PCODE_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"PCODE">>, _attrs, _els}. decode_vcard_PCODE_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20923,9 +24750,11 @@ decode_vcard_REGION_els(__TopXMLNS, __IgnoreEls, decode_vcard_REGION_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_REGION(Cdata, _xmlns_attrs) -> +encode_vcard_REGION(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_REGION_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"REGION">>, _attrs, _els}. decode_vcard_REGION_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20953,9 +24782,11 @@ decode_vcard_LOCALITY_els(__TopXMLNS, __IgnoreEls, decode_vcard_LOCALITY_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_LOCALITY(Cdata, _xmlns_attrs) -> +encode_vcard_LOCALITY(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_LOCALITY_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"LOCALITY">>, _attrs, _els}. decode_vcard_LOCALITY_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -20983,9 +24814,11 @@ decode_vcard_STREET_els(__TopXMLNS, __IgnoreEls, decode_vcard_STREET_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_STREET(Cdata, _xmlns_attrs) -> +encode_vcard_STREET(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_STREET_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"STREET">>, _attrs, _els}. decode_vcard_STREET_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -21013,9 +24846,11 @@ decode_vcard_EXTADD_els(__TopXMLNS, __IgnoreEls, decode_vcard_EXTADD_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_EXTADD(Cdata, _xmlns_attrs) -> +encode_vcard_EXTADD(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_EXTADD_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"EXTADD">>, _attrs, _els}. decode_vcard_EXTADD_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -21043,9 +24878,11 @@ decode_vcard_POBOX_els(__TopXMLNS, __IgnoreEls, decode_vcard_POBOX_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_POBOX(Cdata, _xmlns_attrs) -> +encode_vcard_POBOX(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_POBOX_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"POBOX">>, _attrs, _els}. decode_vcard_POBOX_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -21073,9 +24910,11 @@ decode_vcard_SUFFIX_els(__TopXMLNS, __IgnoreEls, decode_vcard_SUFFIX_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_SUFFIX(Cdata, _xmlns_attrs) -> +encode_vcard_SUFFIX(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_SUFFIX_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"SUFFIX">>, _attrs, _els}. decode_vcard_SUFFIX_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -21103,9 +24942,11 @@ decode_vcard_PREFIX_els(__TopXMLNS, __IgnoreEls, decode_vcard_PREFIX_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_PREFIX(Cdata, _xmlns_attrs) -> +encode_vcard_PREFIX(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_PREFIX_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"PREFIX">>, _attrs, _els}. decode_vcard_PREFIX_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -21133,9 +24974,11 @@ decode_vcard_MIDDLE_els(__TopXMLNS, __IgnoreEls, decode_vcard_MIDDLE_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_MIDDLE(Cdata, _xmlns_attrs) -> +encode_vcard_MIDDLE(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_MIDDLE_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"MIDDLE">>, _attrs, _els}. decode_vcard_MIDDLE_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -21163,9 +25006,11 @@ decode_vcard_GIVEN_els(__TopXMLNS, __IgnoreEls, decode_vcard_GIVEN_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_GIVEN(Cdata, _xmlns_attrs) -> +encode_vcard_GIVEN(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_GIVEN_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"GIVEN">>, _attrs, _els}. decode_vcard_GIVEN_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -21193,9 +25038,11 @@ decode_vcard_FAMILY_els(__TopXMLNS, __IgnoreEls, decode_vcard_FAMILY_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_vcard_FAMILY(Cdata, _xmlns_attrs) -> +encode_vcard_FAMILY(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = encode_vcard_FAMILY_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"FAMILY">>, _attrs, _els}. decode_vcard_FAMILY_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -21209,171 +25056,209 @@ decode_vcard_X400(__TopXMLNS, __IgnoreEls, {xmlel, <<"X400">>, _attrs, _els}) -> true. -encode_vcard_X400(true, _xmlns_attrs) -> +encode_vcard_X400(true, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"X400">>, _attrs, _els}. decode_vcard_INTERNET(__TopXMLNS, __IgnoreEls, {xmlel, <<"INTERNET">>, _attrs, _els}) -> true. -encode_vcard_INTERNET(true, _xmlns_attrs) -> +encode_vcard_INTERNET(true, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"INTERNET">>, _attrs, _els}. decode_vcard_PREF(__TopXMLNS, __IgnoreEls, {xmlel, <<"PREF">>, _attrs, _els}) -> true. -encode_vcard_PREF(true, _xmlns_attrs) -> +encode_vcard_PREF(true, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"PREF">>, _attrs, _els}. decode_vcard_INTL(__TopXMLNS, __IgnoreEls, {xmlel, <<"INTL">>, _attrs, _els}) -> true. -encode_vcard_INTL(true, _xmlns_attrs) -> +encode_vcard_INTL(true, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"INTL">>, _attrs, _els}. decode_vcard_DOM(__TopXMLNS, __IgnoreEls, {xmlel, <<"DOM">>, _attrs, _els}) -> true. -encode_vcard_DOM(true, _xmlns_attrs) -> +encode_vcard_DOM(true, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"DOM">>, _attrs, _els}. decode_vcard_PARCEL(__TopXMLNS, __IgnoreEls, {xmlel, <<"PARCEL">>, _attrs, _els}) -> true. -encode_vcard_PARCEL(true, _xmlns_attrs) -> +encode_vcard_PARCEL(true, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"PARCEL">>, _attrs, _els}. decode_vcard_POSTAL(__TopXMLNS, __IgnoreEls, {xmlel, <<"POSTAL">>, _attrs, _els}) -> true. -encode_vcard_POSTAL(true, _xmlns_attrs) -> +encode_vcard_POSTAL(true, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"POSTAL">>, _attrs, _els}. decode_vcard_PCS(__TopXMLNS, __IgnoreEls, {xmlel, <<"PCS">>, _attrs, _els}) -> true. -encode_vcard_PCS(true, _xmlns_attrs) -> +encode_vcard_PCS(true, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"PCS">>, _attrs, _els}. decode_vcard_ISDN(__TopXMLNS, __IgnoreEls, {xmlel, <<"ISDN">>, _attrs, _els}) -> true. -encode_vcard_ISDN(true, _xmlns_attrs) -> +encode_vcard_ISDN(true, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"ISDN">>, _attrs, _els}. decode_vcard_MODEM(__TopXMLNS, __IgnoreEls, {xmlel, <<"MODEM">>, _attrs, _els}) -> true. -encode_vcard_MODEM(true, _xmlns_attrs) -> +encode_vcard_MODEM(true, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"MODEM">>, _attrs, _els}. decode_vcard_BBS(__TopXMLNS, __IgnoreEls, {xmlel, <<"BBS">>, _attrs, _els}) -> true. -encode_vcard_BBS(true, _xmlns_attrs) -> +encode_vcard_BBS(true, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"BBS">>, _attrs, _els}. decode_vcard_VIDEO(__TopXMLNS, __IgnoreEls, {xmlel, <<"VIDEO">>, _attrs, _els}) -> true. -encode_vcard_VIDEO(true, _xmlns_attrs) -> +encode_vcard_VIDEO(true, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"VIDEO">>, _attrs, _els}. decode_vcard_CELL(__TopXMLNS, __IgnoreEls, {xmlel, <<"CELL">>, _attrs, _els}) -> true. -encode_vcard_CELL(true, _xmlns_attrs) -> +encode_vcard_CELL(true, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"CELL">>, _attrs, _els}. decode_vcard_MSG(__TopXMLNS, __IgnoreEls, {xmlel, <<"MSG">>, _attrs, _els}) -> true. -encode_vcard_MSG(true, _xmlns_attrs) -> +encode_vcard_MSG(true, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"MSG">>, _attrs, _els}. decode_vcard_PAGER(__TopXMLNS, __IgnoreEls, {xmlel, <<"PAGER">>, _attrs, _els}) -> true. -encode_vcard_PAGER(true, _xmlns_attrs) -> +encode_vcard_PAGER(true, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"PAGER">>, _attrs, _els}. decode_vcard_FAX(__TopXMLNS, __IgnoreEls, {xmlel, <<"FAX">>, _attrs, _els}) -> true. -encode_vcard_FAX(true, _xmlns_attrs) -> +encode_vcard_FAX(true, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"FAX">>, _attrs, _els}. decode_vcard_VOICE(__TopXMLNS, __IgnoreEls, {xmlel, <<"VOICE">>, _attrs, _els}) -> true. -encode_vcard_VOICE(true, _xmlns_attrs) -> +encode_vcard_VOICE(true, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"VOICE">>, _attrs, _els}. decode_vcard_WORK(__TopXMLNS, __IgnoreEls, {xmlel, <<"WORK">>, _attrs, _els}) -> true. -encode_vcard_WORK(true, _xmlns_attrs) -> +encode_vcard_WORK(true, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"WORK">>, _attrs, _els}. decode_vcard_HOME(__TopXMLNS, __IgnoreEls, {xmlel, <<"HOME">>, _attrs, _els}) -> true. -encode_vcard_HOME(true, _xmlns_attrs) -> +encode_vcard_HOME(true, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"HOME">>, _attrs, _els}. decode_stream_error(__TopXMLNS, __IgnoreEls, @@ -21769,184 +25654,153 @@ decode_stream_error_els(__TopXMLNS, __IgnoreEls, Text, Reason). encode_stream_error({stream_error, Reason, Text}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"jabber:client">>, <<"jabber:server">>, + <<"jabber:component:accept">>], + __TopXMLNS), _els = lists:reverse('encode_stream_error_$text'(Text, + __NewTopXMLNS, 'encode_stream_error_$reason'(Reason, + __NewTopXMLNS, []))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"stream:error">>, _attrs, _els}. -'encode_stream_error_$text'(undefined, _acc) -> _acc; -'encode_stream_error_$text'(Text, _acc) -> - [encode_stream_error_text(Text, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) - | _acc]. +'encode_stream_error_$text'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_stream_error_$text'(Text, __TopXMLNS, _acc) -> + [encode_stream_error_text(Text, __TopXMLNS) | _acc]. -'encode_stream_error_$reason'(undefined, _acc) -> _acc; -'encode_stream_error_$reason'('bad-format' = Reason, +'encode_stream_error_$reason'(undefined, __TopXMLNS, _acc) -> - [encode_stream_error_bad_format(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) + _acc; +'encode_stream_error_$reason'('bad-format' = Reason, + __TopXMLNS, _acc) -> + [encode_stream_error_bad_format(Reason, __TopXMLNS) | _acc]; 'encode_stream_error_$reason'('bad-namespace-prefix' = Reason, - _acc) -> + __TopXMLNS, _acc) -> [encode_stream_error_bad_namespace_prefix(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) + __TopXMLNS) | _acc]; 'encode_stream_error_$reason'(conflict = Reason, - _acc) -> - [encode_stream_error_conflict(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) + __TopXMLNS, _acc) -> + [encode_stream_error_conflict(Reason, __TopXMLNS) | _acc]; 'encode_stream_error_$reason'('connection-timeout' = Reason, - _acc) -> + __TopXMLNS, _acc) -> [encode_stream_error_connection_timeout(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) + __TopXMLNS) | _acc]; 'encode_stream_error_$reason'('host-gone' = Reason, - _acc) -> - [encode_stream_error_host_gone(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) + __TopXMLNS, _acc) -> + [encode_stream_error_host_gone(Reason, __TopXMLNS) | _acc]; 'encode_stream_error_$reason'('host-unknown' = Reason, - _acc) -> - [encode_stream_error_host_unknown(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) + __TopXMLNS, _acc) -> + [encode_stream_error_host_unknown(Reason, __TopXMLNS) | _acc]; 'encode_stream_error_$reason'('improper-addressing' = Reason, - _acc) -> + __TopXMLNS, _acc) -> [encode_stream_error_improper_addressing(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) + __TopXMLNS) | _acc]; 'encode_stream_error_$reason'('internal-server-error' = Reason, - _acc) -> + __TopXMLNS, _acc) -> [encode_stream_error_internal_server_error(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) + __TopXMLNS) | _acc]; 'encode_stream_error_$reason'('invalid-from' = Reason, - _acc) -> - [encode_stream_error_invalid_from(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) + __TopXMLNS, _acc) -> + [encode_stream_error_invalid_from(Reason, __TopXMLNS) | _acc]; 'encode_stream_error_$reason'('invalid-id' = Reason, - _acc) -> - [encode_stream_error_invalid_id(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) + __TopXMLNS, _acc) -> + [encode_stream_error_invalid_id(Reason, __TopXMLNS) | _acc]; 'encode_stream_error_$reason'('invalid-namespace' = Reason, - _acc) -> + __TopXMLNS, _acc) -> [encode_stream_error_invalid_namespace(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) + __TopXMLNS) | _acc]; 'encode_stream_error_$reason'('invalid-xml' = Reason, - _acc) -> - [encode_stream_error_invalid_xml(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) + __TopXMLNS, _acc) -> + [encode_stream_error_invalid_xml(Reason, __TopXMLNS) | _acc]; 'encode_stream_error_$reason'('not-authorized' = Reason, - _acc) -> - [encode_stream_error_not_authorized(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) + __TopXMLNS, _acc) -> + [encode_stream_error_not_authorized(Reason, __TopXMLNS) | _acc]; 'encode_stream_error_$reason'('not-well-formed' = Reason, - _acc) -> - [encode_stream_error_not_well_formed(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) + __TopXMLNS, _acc) -> + [encode_stream_error_not_well_formed(Reason, __TopXMLNS) | _acc]; 'encode_stream_error_$reason'('policy-violation' = Reason, - _acc) -> + __TopXMLNS, _acc) -> [encode_stream_error_policy_violation(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) + __TopXMLNS) | _acc]; 'encode_stream_error_$reason'('remote-connection-failed' = Reason, - _acc) -> + __TopXMLNS, _acc) -> [encode_stream_error_remote_connection_failed(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) - | _acc]; -'encode_stream_error_$reason'(reset = Reason, _acc) -> - [encode_stream_error_reset(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) + __TopXMLNS) | _acc]; +'encode_stream_error_$reason'(reset = Reason, + __TopXMLNS, _acc) -> + [encode_stream_error_reset(Reason, __TopXMLNS) | _acc]; 'encode_stream_error_$reason'('resource-constraint' = Reason, - _acc) -> + __TopXMLNS, _acc) -> [encode_stream_error_resource_constraint(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) + __TopXMLNS) | _acc]; 'encode_stream_error_$reason'('restricted-xml' = Reason, - _acc) -> - [encode_stream_error_restricted_xml(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) + __TopXMLNS, _acc) -> + [encode_stream_error_restricted_xml(Reason, __TopXMLNS) | _acc]; 'encode_stream_error_$reason'({'see-other-host', _} = Reason, - _acc) -> - [encode_stream_error_see_other_host(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) + __TopXMLNS, _acc) -> + [encode_stream_error_see_other_host(Reason, __TopXMLNS) | _acc]; 'encode_stream_error_$reason'('system-shutdown' = Reason, - _acc) -> - [encode_stream_error_system_shutdown(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) + __TopXMLNS, _acc) -> + [encode_stream_error_system_shutdown(Reason, __TopXMLNS) | _acc]; 'encode_stream_error_$reason'('undefined-condition' = Reason, - _acc) -> + __TopXMLNS, _acc) -> [encode_stream_error_undefined_condition(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) + __TopXMLNS) | _acc]; 'encode_stream_error_$reason'('unsupported-encoding' = Reason, - _acc) -> + __TopXMLNS, _acc) -> [encode_stream_error_unsupported_encoding(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) + __TopXMLNS) | _acc]; 'encode_stream_error_$reason'('unsupported-stanza-type' = Reason, - _acc) -> + __TopXMLNS, _acc) -> [encode_stream_error_unsupported_stanza_type(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) + __TopXMLNS) | _acc]; 'encode_stream_error_$reason'('unsupported-version' = Reason, - _acc) -> + __TopXMLNS, _acc) -> [encode_stream_error_unsupported_version(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>}]) + __TopXMLNS) | _acc]. decode_stream_error_unsupported_version(__TopXMLNS, @@ -21956,9 +25810,12 @@ decode_stream_error_unsupported_version(__TopXMLNS, 'unsupported-version'. encode_stream_error_unsupported_version('unsupported-version', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"unsupported-version">>, _attrs, _els}. decode_stream_error_unsupported_stanza_type(__TopXMLNS, @@ -21969,9 +25826,12 @@ decode_stream_error_unsupported_stanza_type(__TopXMLNS, 'unsupported-stanza-type'. encode_stream_error_unsupported_stanza_type('unsupported-stanza-type', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"unsupported-stanza-type">>, _attrs, _els}. decode_stream_error_unsupported_encoding(__TopXMLNS, @@ -21981,9 +25841,12 @@ decode_stream_error_unsupported_encoding(__TopXMLNS, 'unsupported-encoding'. encode_stream_error_unsupported_encoding('unsupported-encoding', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"unsupported-encoding">>, _attrs, _els}. decode_stream_error_undefined_condition(__TopXMLNS, @@ -21993,9 +25856,12 @@ decode_stream_error_undefined_condition(__TopXMLNS, 'undefined-condition'. encode_stream_error_undefined_condition('undefined-condition', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"undefined-condition">>, _attrs, _els}. decode_stream_error_system_shutdown(__TopXMLNS, @@ -22005,9 +25871,12 @@ decode_stream_error_system_shutdown(__TopXMLNS, 'system-shutdown'. encode_stream_error_system_shutdown('system-shutdown', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"system-shutdown">>, _attrs, _els}. decode_stream_error_see_other_host(__TopXMLNS, @@ -22036,10 +25905,13 @@ decode_stream_error_see_other_host_els(__TopXMLNS, encode_stream_error_see_other_host({'see-other-host', Host}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = encode_stream_error_see_other_host_cdata(Host, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"see-other-host">>, _attrs, _els}. decode_stream_error_see_other_host_cdata(__TopXMLNS, @@ -22067,9 +25939,12 @@ decode_stream_error_restricted_xml(__TopXMLNS, 'restricted-xml'. encode_stream_error_restricted_xml('restricted-xml', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"restricted-xml">>, _attrs, _els}. decode_stream_error_resource_constraint(__TopXMLNS, @@ -22079,18 +25954,24 @@ decode_stream_error_resource_constraint(__TopXMLNS, 'resource-constraint'. encode_stream_error_resource_constraint('resource-constraint', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"resource-constraint">>, _attrs, _els}. decode_stream_error_reset(__TopXMLNS, __IgnoreEls, {xmlel, <<"reset">>, _attrs, _els}) -> reset. -encode_stream_error_reset(reset, _xmlns_attrs) -> +encode_stream_error_reset(reset, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"reset">>, _attrs, _els}. decode_stream_error_remote_connection_failed(__TopXMLNS, @@ -22101,9 +25982,12 @@ decode_stream_error_remote_connection_failed(__TopXMLNS, 'remote-connection-failed'. encode_stream_error_remote_connection_failed('remote-connection-failed', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"remote-connection-failed">>, _attrs, _els}. decode_stream_error_policy_violation(__TopXMLNS, @@ -22113,9 +25997,12 @@ decode_stream_error_policy_violation(__TopXMLNS, 'policy-violation'. encode_stream_error_policy_violation('policy-violation', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"policy-violation">>, _attrs, _els}. decode_stream_error_not_well_formed(__TopXMLNS, @@ -22125,9 +26012,12 @@ decode_stream_error_not_well_formed(__TopXMLNS, 'not-well-formed'. encode_stream_error_not_well_formed('not-well-formed', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"not-well-formed">>, _attrs, _els}. decode_stream_error_not_authorized(__TopXMLNS, @@ -22137,9 +26027,12 @@ decode_stream_error_not_authorized(__TopXMLNS, 'not-authorized'. encode_stream_error_not_authorized('not-authorized', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"not-authorized">>, _attrs, _els}. decode_stream_error_invalid_xml(__TopXMLNS, __IgnoreEls, @@ -22147,9 +26040,12 @@ decode_stream_error_invalid_xml(__TopXMLNS, __IgnoreEls, 'invalid-xml'. encode_stream_error_invalid_xml('invalid-xml', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"invalid-xml">>, _attrs, _els}. decode_stream_error_invalid_namespace(__TopXMLNS, @@ -22159,9 +26055,12 @@ decode_stream_error_invalid_namespace(__TopXMLNS, 'invalid-namespace'. encode_stream_error_invalid_namespace('invalid-namespace', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"invalid-namespace">>, _attrs, _els}. decode_stream_error_invalid_id(__TopXMLNS, __IgnoreEls, @@ -22169,9 +26068,12 @@ decode_stream_error_invalid_id(__TopXMLNS, __IgnoreEls, 'invalid-id'. encode_stream_error_invalid_id('invalid-id', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"invalid-id">>, _attrs, _els}. decode_stream_error_invalid_from(__TopXMLNS, @@ -22180,9 +26082,12 @@ decode_stream_error_invalid_from(__TopXMLNS, 'invalid-from'. encode_stream_error_invalid_from('invalid-from', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"invalid-from">>, _attrs, _els}. decode_stream_error_internal_server_error(__TopXMLNS, @@ -22192,9 +26097,12 @@ decode_stream_error_internal_server_error(__TopXMLNS, 'internal-server-error'. encode_stream_error_internal_server_error('internal-server-error', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"internal-server-error">>, _attrs, _els}. decode_stream_error_improper_addressing(__TopXMLNS, @@ -22204,9 +26112,12 @@ decode_stream_error_improper_addressing(__TopXMLNS, 'improper-addressing'. encode_stream_error_improper_addressing('improper-addressing', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"improper-addressing">>, _attrs, _els}. decode_stream_error_host_unknown(__TopXMLNS, @@ -22215,9 +26126,12 @@ decode_stream_error_host_unknown(__TopXMLNS, 'host-unknown'. encode_stream_error_host_unknown('host-unknown', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"host-unknown">>, _attrs, _els}. decode_stream_error_host_gone(__TopXMLNS, __IgnoreEls, @@ -22225,9 +26139,12 @@ decode_stream_error_host_gone(__TopXMLNS, __IgnoreEls, 'host-gone'. encode_stream_error_host_gone('host-gone', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"host-gone">>, _attrs, _els}. decode_stream_error_connection_timeout(__TopXMLNS, @@ -22237,18 +26154,24 @@ decode_stream_error_connection_timeout(__TopXMLNS, 'connection-timeout'. encode_stream_error_connection_timeout('connection-timeout', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"connection-timeout">>, _attrs, _els}. decode_stream_error_conflict(__TopXMLNS, __IgnoreEls, {xmlel, <<"conflict">>, _attrs, _els}) -> conflict. -encode_stream_error_conflict(conflict, _xmlns_attrs) -> +encode_stream_error_conflict(conflict, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"conflict">>, _attrs, _els}. decode_stream_error_bad_namespace_prefix(__TopXMLNS, @@ -22258,9 +26181,12 @@ decode_stream_error_bad_namespace_prefix(__TopXMLNS, 'bad-namespace-prefix'. encode_stream_error_bad_namespace_prefix('bad-namespace-prefix', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"bad-namespace-prefix">>, _attrs, _els}. decode_stream_error_bad_format(__TopXMLNS, __IgnoreEls, @@ -22268,9 +26194,12 @@ decode_stream_error_bad_format(__TopXMLNS, __IgnoreEls, 'bad-format'. encode_stream_error_bad_format('bad-format', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"bad-format">>, _attrs, _els}. decode_stream_error_text(__TopXMLNS, __IgnoreEls, @@ -22306,10 +26235,14 @@ decode_stream_error_text_attrs(__TopXMLNS, [], Lang) -> Lang). encode_stream_error_text({text, Lang, Data}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, + [], __TopXMLNS), _els = encode_stream_error_text_cdata(Data, []), _attrs = 'encode_stream_error_text_attr_xml:lang'(Lang, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"text">>, _attrs, _els}. 'decode_stream_error_text_attr_xml:lang'(__TopXMLNS, @@ -22376,19 +26309,24 @@ decode_time_els(__TopXMLNS, __IgnoreEls, [_ | _els], decode_time_els(__TopXMLNS, __IgnoreEls, _els, Utc, Tzo). -encode_time({time, Tzo, Utc}, _xmlns_attrs) -> +encode_time({time, Tzo, Utc}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:time">>, + [], __TopXMLNS), _els = lists:reverse('encode_time_$utc'(Utc, - 'encode_time_$tzo'(Tzo, []))), - _attrs = _xmlns_attrs, + __NewTopXMLNS, + 'encode_time_$tzo'(Tzo, + __NewTopXMLNS, + []))), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"time">>, _attrs, _els}. -'encode_time_$utc'(undefined, _acc) -> _acc; -'encode_time_$utc'(Utc, _acc) -> - [encode_time_utc(Utc, []) | _acc]. +'encode_time_$utc'(undefined, __TopXMLNS, _acc) -> _acc; +'encode_time_$utc'(Utc, __TopXMLNS, _acc) -> + [encode_time_utc(Utc, __TopXMLNS) | _acc]. -'encode_time_$tzo'(undefined, _acc) -> _acc; -'encode_time_$tzo'(Tzo, _acc) -> - [encode_time_tzo(Tzo, []) | _acc]. +'encode_time_$tzo'(undefined, __TopXMLNS, _acc) -> _acc; +'encode_time_$tzo'(Tzo, __TopXMLNS, _acc) -> + [encode_time_tzo(Tzo, __TopXMLNS) | _acc]. decode_time_tzo(__TopXMLNS, __IgnoreEls, {xmlel, <<"tzo">>, _attrs, _els}) -> @@ -22408,9 +26346,11 @@ decode_time_tzo_els(__TopXMLNS, __IgnoreEls, [_ | _els], decode_time_tzo_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_time_tzo(Cdata, _xmlns_attrs) -> +encode_time_tzo(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:time">>, + [], __TopXMLNS), _els = encode_time_tzo_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"tzo">>, _attrs, _els}. decode_time_tzo_cdata(__TopXMLNS, <<>>) -> undefined; @@ -22444,9 +26384,11 @@ decode_time_utc_els(__TopXMLNS, __IgnoreEls, [_ | _els], decode_time_utc_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_time_utc(Cdata, _xmlns_attrs) -> +encode_time_utc(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:time">>, + [], __TopXMLNS), _els = encode_time_utc_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"utc">>, _attrs, _els}. decode_time_utc_cdata(__TopXMLNS, <<>>) -> undefined; @@ -22466,9 +26408,11 @@ decode_ping(__TopXMLNS, __IgnoreEls, {xmlel, <<"ping">>, _attrs, _els}) -> {ping}. -encode_ping({ping}, _xmlns_attrs) -> +encode_ping({ping}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:ping">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"ping">>, _attrs, _els}. decode_session(__TopXMLNS, __IgnoreEls, @@ -22503,24 +26447,32 @@ decode_session_els(__TopXMLNS, __IgnoreEls, [_ | _els], decode_session_els(__TopXMLNS, __IgnoreEls, _els, Optional). -encode_session({xmpp_session, Optional}, - _xmlns_attrs) -> +encode_session({xmpp_session, Optional}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-session">>, + [], __TopXMLNS), _els = - lists:reverse('encode_session_$optional'(Optional, [])), - _attrs = _xmlns_attrs, + lists:reverse('encode_session_$optional'(Optional, + __NewTopXMLNS, [])), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"session">>, _attrs, _els}. -'encode_session_$optional'(false, _acc) -> _acc; -'encode_session_$optional'(Optional, _acc) -> - [encode_session_optional(Optional, []) | _acc]. +'encode_session_$optional'(false, __TopXMLNS, _acc) -> + _acc; +'encode_session_$optional'(Optional, __TopXMLNS, + _acc) -> + [encode_session_optional(Optional, __TopXMLNS) | _acc]. decode_session_optional(__TopXMLNS, __IgnoreEls, {xmlel, <<"optional">>, _attrs, _els}) -> true. -encode_session_optional(true, _xmlns_attrs) -> +encode_session_optional(true, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-session">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"optional">>, _attrs, _els}. decode_register(__TopXMLNS, __IgnoreEls, @@ -23159,14 +27111,14 @@ decode_register_els(__TopXMLNS, __IgnoreEls, Name, Username, Remove, Key, City, Nick, Url, Email, [_el | __Els]); true -> - case is_known_tag(_el) of + case is_known_tag(_el, __TopXMLNS) of true -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, Last, First, Password, Registered, Date, Phone, State, Name, Username, Remove, Key, City, Nick, Url, Email, - [decode(_el) | __Els]); + [decode(_el, __TopXMLNS, []) | __Els]); false -> decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, Xdata, Misc, Address, Instructions, Text, @@ -23188,119 +27140,171 @@ encode_register({register, Registered, Remove, Instructions, Username, Nick, Password, Name, First, Last, Email, Address, City, State, Zip, Phone, Url, Date, Misc, Text, Key, Xdata, __Els}, - _xmlns_attrs) -> - _els = [encode(_el) || _el <- __Els] ++ - lists:reverse('encode_register_$zip'(Zip, + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:register">>, [], + __TopXMLNS), + _els = [encode(_el, __NewTopXMLNS) || _el <- __Els] ++ + lists:reverse('encode_register_$zip'(Zip, __NewTopXMLNS, 'encode_register_$xdata'(Xdata, + __NewTopXMLNS, 'encode_register_$misc'(Misc, + __NewTopXMLNS, 'encode_register_$address'(Address, + __NewTopXMLNS, 'encode_register_$instructions'(Instructions, + __NewTopXMLNS, 'encode_register_$text'(Text, + __NewTopXMLNS, 'encode_register_$last'(Last, + __NewTopXMLNS, 'encode_register_$first'(First, + __NewTopXMLNS, 'encode_register_$password'(Password, + __NewTopXMLNS, 'encode_register_$registered'(Registered, + __NewTopXMLNS, 'encode_register_$date'(Date, + __NewTopXMLNS, 'encode_register_$phone'(Phone, + __NewTopXMLNS, 'encode_register_$state'(State, + __NewTopXMLNS, 'encode_register_$name'(Name, + __NewTopXMLNS, 'encode_register_$username'(Username, + __NewTopXMLNS, 'encode_register_$remove'(Remove, + __NewTopXMLNS, 'encode_register_$key'(Key, + __NewTopXMLNS, 'encode_register_$city'(City, + __NewTopXMLNS, 'encode_register_$nick'(Nick, + __NewTopXMLNS, 'encode_register_$url'(Url, + __NewTopXMLNS, 'encode_register_$email'(Email, + __NewTopXMLNS, [])))))))))))))))))))))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"query">>, _attrs, _els}. -'encode_register_$zip'(undefined, _acc) -> _acc; -'encode_register_$zip'(Zip, _acc) -> - [encode_register_zip(Zip, []) | _acc]. +'encode_register_$zip'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_register_$zip'(Zip, __TopXMLNS, _acc) -> + [encode_register_zip(Zip, __TopXMLNS) | _acc]. -'encode_register_$xdata'(undefined, _acc) -> _acc; -'encode_register_$xdata'(Xdata, _acc) -> - [encode_xdata(Xdata, - [{<<"xmlns">>, <<"jabber:x:data">>}]) +'encode_register_$xdata'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_register_$xdata'(Xdata, __TopXMLNS, _acc) -> + [encode_xdata(Xdata, __TopXMLNS) | _acc]. + +'encode_register_$misc'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_register_$misc'(Misc, __TopXMLNS, _acc) -> + [encode_register_misc(Misc, __TopXMLNS) | _acc]. + +'encode_register_$address'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_register_$address'(Address, __TopXMLNS, _acc) -> + [encode_register_address(Address, __TopXMLNS) | _acc]. + +'encode_register_$instructions'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_register_$instructions'(Instructions, + __TopXMLNS, _acc) -> + [encode_register_instructions(Instructions, __TopXMLNS) | _acc]. -'encode_register_$misc'(undefined, _acc) -> _acc; -'encode_register_$misc'(Misc, _acc) -> - [encode_register_misc(Misc, []) | _acc]. - -'encode_register_$address'(undefined, _acc) -> _acc; -'encode_register_$address'(Address, _acc) -> - [encode_register_address(Address, []) | _acc]. - -'encode_register_$instructions'(undefined, _acc) -> +'encode_register_$text'(undefined, __TopXMLNS, _acc) -> _acc; -'encode_register_$instructions'(Instructions, _acc) -> - [encode_register_instructions(Instructions, []) | _acc]. +'encode_register_$text'(Text, __TopXMLNS, _acc) -> + [encode_register_text(Text, __TopXMLNS) | _acc]. -'encode_register_$text'(undefined, _acc) -> _acc; -'encode_register_$text'(Text, _acc) -> - [encode_register_text(Text, []) | _acc]. +'encode_register_$last'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_register_$last'(Last, __TopXMLNS, _acc) -> + [encode_register_last(Last, __TopXMLNS) | _acc]. -'encode_register_$last'(undefined, _acc) -> _acc; -'encode_register_$last'(Last, _acc) -> - [encode_register_last(Last, []) | _acc]. +'encode_register_$first'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_register_$first'(First, __TopXMLNS, _acc) -> + [encode_register_first(First, __TopXMLNS) | _acc]. -'encode_register_$first'(undefined, _acc) -> _acc; -'encode_register_$first'(First, _acc) -> - [encode_register_first(First, []) | _acc]. +'encode_register_$password'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_register_$password'(Password, __TopXMLNS, + _acc) -> + [encode_register_password(Password, __TopXMLNS) | _acc]. -'encode_register_$password'(undefined, _acc) -> _acc; -'encode_register_$password'(Password, _acc) -> - [encode_register_password(Password, []) | _acc]. +'encode_register_$registered'(false, __TopXMLNS, + _acc) -> + _acc; +'encode_register_$registered'(Registered, __TopXMLNS, + _acc) -> + [encode_register_registered(Registered, __TopXMLNS) + | _acc]. -'encode_register_$registered'(false, _acc) -> _acc; -'encode_register_$registered'(Registered, _acc) -> - [encode_register_registered(Registered, []) | _acc]. +'encode_register_$date'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_register_$date'(Date, __TopXMLNS, _acc) -> + [encode_register_date(Date, __TopXMLNS) | _acc]. -'encode_register_$date'(undefined, _acc) -> _acc; -'encode_register_$date'(Date, _acc) -> - [encode_register_date(Date, []) | _acc]. +'encode_register_$phone'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_register_$phone'(Phone, __TopXMLNS, _acc) -> + [encode_register_phone(Phone, __TopXMLNS) | _acc]. -'encode_register_$phone'(undefined, _acc) -> _acc; -'encode_register_$phone'(Phone, _acc) -> - [encode_register_phone(Phone, []) | _acc]. +'encode_register_$state'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_register_$state'(State, __TopXMLNS, _acc) -> + [encode_register_state(State, __TopXMLNS) | _acc]. -'encode_register_$state'(undefined, _acc) -> _acc; -'encode_register_$state'(State, _acc) -> - [encode_register_state(State, []) | _acc]. +'encode_register_$name'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_register_$name'(Name, __TopXMLNS, _acc) -> + [encode_register_name(Name, __TopXMLNS) | _acc]. -'encode_register_$name'(undefined, _acc) -> _acc; -'encode_register_$name'(Name, _acc) -> - [encode_register_name(Name, []) | _acc]. +'encode_register_$username'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_register_$username'(Username, __TopXMLNS, + _acc) -> + [encode_register_username(Username, __TopXMLNS) | _acc]. -'encode_register_$username'(undefined, _acc) -> _acc; -'encode_register_$username'(Username, _acc) -> - [encode_register_username(Username, []) | _acc]. +'encode_register_$remove'(false, __TopXMLNS, _acc) -> + _acc; +'encode_register_$remove'(Remove, __TopXMLNS, _acc) -> + [encode_register_remove(Remove, __TopXMLNS) | _acc]. -'encode_register_$remove'(false, _acc) -> _acc; -'encode_register_$remove'(Remove, _acc) -> - [encode_register_remove(Remove, []) | _acc]. +'encode_register_$key'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_register_$key'(Key, __TopXMLNS, _acc) -> + [encode_register_key(Key, __TopXMLNS) | _acc]. -'encode_register_$key'(undefined, _acc) -> _acc; -'encode_register_$key'(Key, _acc) -> - [encode_register_key(Key, []) | _acc]. +'encode_register_$city'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_register_$city'(City, __TopXMLNS, _acc) -> + [encode_register_city(City, __TopXMLNS) | _acc]. -'encode_register_$city'(undefined, _acc) -> _acc; -'encode_register_$city'(City, _acc) -> - [encode_register_city(City, []) | _acc]. +'encode_register_$nick'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_register_$nick'(Nick, __TopXMLNS, _acc) -> + [encode_register_nick(Nick, __TopXMLNS) | _acc]. -'encode_register_$nick'(undefined, _acc) -> _acc; -'encode_register_$nick'(Nick, _acc) -> - [encode_register_nick(Nick, []) | _acc]. +'encode_register_$url'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_register_$url'(Url, __TopXMLNS, _acc) -> + [encode_register_url(Url, __TopXMLNS) | _acc]. -'encode_register_$url'(undefined, _acc) -> _acc; -'encode_register_$url'(Url, _acc) -> - [encode_register_url(Url, []) | _acc]. - -'encode_register_$email'(undefined, _acc) -> _acc; -'encode_register_$email'(Email, _acc) -> - [encode_register_email(Email, []) | _acc]. +'encode_register_$email'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_register_$email'(Email, __TopXMLNS, _acc) -> + [encode_register_email(Email, __TopXMLNS) | _acc]. decode_register_key(__TopXMLNS, __IgnoreEls, {xmlel, <<"key">>, _attrs, _els}) -> @@ -23320,9 +27324,12 @@ decode_register_key_els(__TopXMLNS, __IgnoreEls, decode_register_key_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_register_key(Cdata, _xmlns_attrs) -> +encode_register_key(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:register">>, [], + __TopXMLNS), _els = encode_register_key_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"key">>, _attrs, _els}. decode_register_key_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -23350,9 +27357,12 @@ decode_register_text_els(__TopXMLNS, __IgnoreEls, decode_register_text_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_register_text(Cdata, _xmlns_attrs) -> +encode_register_text(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:register">>, [], + __TopXMLNS), _els = encode_register_text_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"text">>, _attrs, _els}. decode_register_text_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -23380,9 +27390,12 @@ decode_register_misc_els(__TopXMLNS, __IgnoreEls, decode_register_misc_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_register_misc(Cdata, _xmlns_attrs) -> +encode_register_misc(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:register">>, [], + __TopXMLNS), _els = encode_register_misc_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"misc">>, _attrs, _els}. decode_register_misc_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -23410,9 +27423,12 @@ decode_register_date_els(__TopXMLNS, __IgnoreEls, decode_register_date_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_register_date(Cdata, _xmlns_attrs) -> +encode_register_date(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:register">>, [], + __TopXMLNS), _els = encode_register_date_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"date">>, _attrs, _els}. decode_register_date_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -23440,9 +27456,12 @@ decode_register_url_els(__TopXMLNS, __IgnoreEls, decode_register_url_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_register_url(Cdata, _xmlns_attrs) -> +encode_register_url(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:register">>, [], + __TopXMLNS), _els = encode_register_url_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"url">>, _attrs, _els}. decode_register_url_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -23470,9 +27489,12 @@ decode_register_phone_els(__TopXMLNS, __IgnoreEls, decode_register_phone_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_register_phone(Cdata, _xmlns_attrs) -> +encode_register_phone(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:register">>, [], + __TopXMLNS), _els = encode_register_phone_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"phone">>, _attrs, _els}. decode_register_phone_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -23500,9 +27522,12 @@ decode_register_zip_els(__TopXMLNS, __IgnoreEls, decode_register_zip_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_register_zip(Cdata, _xmlns_attrs) -> +encode_register_zip(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:register">>, [], + __TopXMLNS), _els = encode_register_zip_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"zip">>, _attrs, _els}. decode_register_zip_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -23530,9 +27555,12 @@ decode_register_state_els(__TopXMLNS, __IgnoreEls, decode_register_state_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_register_state(Cdata, _xmlns_attrs) -> +encode_register_state(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:register">>, [], + __TopXMLNS), _els = encode_register_state_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"state">>, _attrs, _els}. decode_register_state_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -23560,9 +27588,12 @@ decode_register_city_els(__TopXMLNS, __IgnoreEls, decode_register_city_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_register_city(Cdata, _xmlns_attrs) -> +encode_register_city(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:register">>, [], + __TopXMLNS), _els = encode_register_city_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"city">>, _attrs, _els}. decode_register_city_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -23590,9 +27621,12 @@ decode_register_address_els(__TopXMLNS, __IgnoreEls, decode_register_address_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_register_address(Cdata, _xmlns_attrs) -> +encode_register_address(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:register">>, [], + __TopXMLNS), _els = encode_register_address_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"address">>, _attrs, _els}. decode_register_address_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -23620,9 +27654,12 @@ decode_register_email_els(__TopXMLNS, __IgnoreEls, decode_register_email_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_register_email(Cdata, _xmlns_attrs) -> +encode_register_email(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:register">>, [], + __TopXMLNS), _els = encode_register_email_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"email">>, _attrs, _els}. decode_register_email_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -23650,9 +27687,12 @@ decode_register_last_els(__TopXMLNS, __IgnoreEls, decode_register_last_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_register_last(Cdata, _xmlns_attrs) -> +encode_register_last(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:register">>, [], + __TopXMLNS), _els = encode_register_last_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"last">>, _attrs, _els}. decode_register_last_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -23680,9 +27720,12 @@ decode_register_first_els(__TopXMLNS, __IgnoreEls, decode_register_first_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_register_first(Cdata, _xmlns_attrs) -> +encode_register_first(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:register">>, [], + __TopXMLNS), _els = encode_register_first_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"first">>, _attrs, _els}. decode_register_first_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -23710,9 +27753,12 @@ decode_register_name_els(__TopXMLNS, __IgnoreEls, decode_register_name_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_register_name(Cdata, _xmlns_attrs) -> +encode_register_name(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:register">>, [], + __TopXMLNS), _els = encode_register_name_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"name">>, _attrs, _els}. decode_register_name_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -23740,9 +27786,12 @@ decode_register_password_els(__TopXMLNS, __IgnoreEls, decode_register_password_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_register_password(Cdata, _xmlns_attrs) -> +encode_register_password(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:register">>, [], + __TopXMLNS), _els = encode_register_password_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"password">>, _attrs, _els}. decode_register_password_cdata(__TopXMLNS, <<>>) -> @@ -23772,9 +27821,12 @@ decode_register_nick_els(__TopXMLNS, __IgnoreEls, decode_register_nick_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_register_nick(Cdata, _xmlns_attrs) -> +encode_register_nick(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:register">>, [], + __TopXMLNS), _els = encode_register_nick_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"nick">>, _attrs, _els}. decode_register_nick_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -23802,9 +27854,12 @@ decode_register_username_els(__TopXMLNS, __IgnoreEls, decode_register_username_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_register_username(Cdata, _xmlns_attrs) -> +encode_register_username(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:register">>, [], + __TopXMLNS), _els = encode_register_username_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"username">>, _attrs, _els}. decode_register_username_cdata(__TopXMLNS, <<>>) -> @@ -23836,9 +27891,12 @@ decode_register_instructions_els(__TopXMLNS, decode_register_instructions_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_register_instructions(Cdata, _xmlns_attrs) -> +encode_register_instructions(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:register">>, [], + __TopXMLNS), _els = encode_register_instructions_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"instructions">>, _attrs, _els}. decode_register_instructions_cdata(__TopXMLNS, <<>>) -> @@ -23854,18 +27912,24 @@ decode_register_remove(__TopXMLNS, __IgnoreEls, {xmlel, <<"remove">>, _attrs, _els}) -> true. -encode_register_remove(true, _xmlns_attrs) -> +encode_register_remove(true, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:register">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"remove">>, _attrs, _els}. decode_register_registered(__TopXMLNS, __IgnoreEls, {xmlel, <<"registered">>, _attrs, _els}) -> true. -encode_register_registered(true, _xmlns_attrs) -> +encode_register_registered(true, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:register">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"registered">>, _attrs, _els}. decode_feature_register(__TopXMLNS, __IgnoreEls, @@ -23873,9 +27937,12 @@ decode_feature_register(__TopXMLNS, __IgnoreEls, {feature_register}. encode_feature_register({feature_register}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/features/iq-register">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"register">>, _attrs, _els}. decode_caps(__TopXMLNS, __IgnoreEls, @@ -23917,13 +27984,17 @@ decode_caps_attrs(__TopXMLNS, [], Hash, Node, Exts, decode_caps_attr_ver(__TopXMLNS, Version)}. encode_caps({caps, Node, Version, Hash, Exts}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/caps">>, + [], __TopXMLNS), _els = [], _attrs = encode_caps_attr_ver(Version, encode_caps_attr_ext(Exts, encode_caps_attr_node(Node, encode_caps_attr_hash(Hash, - _xmlns_attrs)))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))))), {xmlel, <<"c">>, _attrs, _els}. decode_caps_attr_hash(__TopXMLNS, undefined) -> <<>>; @@ -23964,27 +28035,33 @@ decode_p1_ack(__TopXMLNS, __IgnoreEls, {xmlel, <<"ack">>, _attrs, _els}) -> {p1_ack}. -encode_p1_ack({p1_ack}, _xmlns_attrs) -> +encode_p1_ack({p1_ack}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"p1:ack">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"ack">>, _attrs, _els}. decode_p1_rebind(__TopXMLNS, __IgnoreEls, {xmlel, <<"rebind">>, _attrs, _els}) -> {p1_rebind}. -encode_p1_rebind({p1_rebind}, _xmlns_attrs) -> +encode_p1_rebind({p1_rebind}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"p1:rebind">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"rebind">>, _attrs, _els}. decode_p1_push(__TopXMLNS, __IgnoreEls, {xmlel, <<"push">>, _attrs, _els}) -> {p1_push}. -encode_p1_push({p1_push}, _xmlns_attrs) -> +encode_p1_push({p1_push}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"p1:push">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"push">>, _attrs, _els}. decode_stream_features(__TopXMLNS, __IgnoreEls, @@ -24002,10 +28079,12 @@ decode_stream_features_els(__TopXMLNS, __IgnoreEls, decode_stream_features_els(__TopXMLNS, __IgnoreEls, _els, [_el | __Els]); true -> - case is_known_tag(_el) of + case is_known_tag(_el, __TopXMLNS) of true -> decode_stream_features_els(__TopXMLNS, __IgnoreEls, - _els, [decode(_el) | __Els]); + _els, + [decode(_el, __TopXMLNS, []) + | __Els]); false -> decode_stream_features_els(__TopXMLNS, __IgnoreEls, _els, __Els) @@ -24017,9 +28096,12 @@ decode_stream_features_els(__TopXMLNS, __IgnoreEls, _els, __Els). encode_stream_features({stream_features, __Els}, - _xmlns_attrs) -> - _els = [encode(_el) || _el <- __Els], - _attrs = _xmlns_attrs, + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"jabber:client">>, <<"jabber:server">>], + __TopXMLNS), + _els = [encode(_el, __NewTopXMLNS) || _el <- __Els], + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"stream:features">>, _attrs, _els}. decode_compression(__TopXMLNS, __IgnoreEls, @@ -24057,17 +28139,23 @@ decode_compression_els(__TopXMLNS, __IgnoreEls, Methods). encode_compression({compression, Methods}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/features/compress">>, + [], __TopXMLNS), _els = lists:reverse('encode_compression_$methods'(Methods, - [])), - _attrs = _xmlns_attrs, + __NewTopXMLNS, [])), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"compression">>, _attrs, _els}. -'encode_compression_$methods'([], _acc) -> _acc; -'encode_compression_$methods'([Methods | _els], _acc) -> - 'encode_compression_$methods'(_els, - [encode_compression_method(Methods, []) +'encode_compression_$methods'([], __TopXMLNS, _acc) -> + _acc; +'encode_compression_$methods'([Methods | _els], + __TopXMLNS, _acc) -> + 'encode_compression_$methods'(_els, __TopXMLNS, + [encode_compression_method(Methods, + __TopXMLNS) | _acc]). decode_compression_method(__TopXMLNS, __IgnoreEls, @@ -24088,9 +28176,12 @@ decode_compression_method_els(__TopXMLNS, __IgnoreEls, decode_compression_method_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_compression_method(Cdata, _xmlns_attrs) -> +encode_compression_method(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/features/compress">>, + [], __TopXMLNS), _els = encode_compression_method_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"method">>, _attrs, _els}. decode_compression_method_cdata(__TopXMLNS, <<>>) -> @@ -24106,9 +28197,12 @@ decode_compressed(__TopXMLNS, __IgnoreEls, {xmlel, <<"compressed">>, _attrs, _els}) -> {compressed}. -encode_compressed({compressed}, _xmlns_attrs) -> +encode_compressed({compressed}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/compress">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"compressed">>, _attrs, _els}. decode_compress(__TopXMLNS, __IgnoreEls, @@ -24145,16 +28239,22 @@ decode_compress_els(__TopXMLNS, __IgnoreEls, [_ | _els], decode_compress_els(__TopXMLNS, __IgnoreEls, _els, Methods). -encode_compress({compress, Methods}, _xmlns_attrs) -> +encode_compress({compress, Methods}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/compress">>, + [], __TopXMLNS), _els = lists:reverse('encode_compress_$methods'(Methods, - [])), - _attrs = _xmlns_attrs, + __NewTopXMLNS, [])), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"compress">>, _attrs, _els}. -'encode_compress_$methods'([], _acc) -> _acc; -'encode_compress_$methods'([Methods | _els], _acc) -> - 'encode_compress_$methods'(_els, - [encode_compress_method(Methods, []) | _acc]). +'encode_compress_$methods'([], __TopXMLNS, _acc) -> + _acc; +'encode_compress_$methods'([Methods | _els], __TopXMLNS, + _acc) -> + 'encode_compress_$methods'(_els, __TopXMLNS, + [encode_compress_method(Methods, __TopXMLNS) + | _acc]). decode_compress_method(__TopXMLNS, __IgnoreEls, {xmlel, <<"method">>, _attrs, _els}) -> @@ -24174,9 +28274,12 @@ decode_compress_method_els(__TopXMLNS, __IgnoreEls, decode_compress_method_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_compress_method(Cdata, _xmlns_attrs) -> +encode_compress_method(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/compress">>, + [], __TopXMLNS), _els = encode_compress_method_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"method">>, _attrs, _els}. decode_compress_method_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -24270,29 +28373,36 @@ decode_compress_failure_els(__TopXMLNS, __IgnoreEls, _els, Reason). encode_compress_failure({compress_failure, Reason}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/compress">>, + [], __TopXMLNS), _els = lists:reverse('encode_compress_failure_$reason'(Reason, - [])), - _attrs = _xmlns_attrs, + __NewTopXMLNS, [])), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"failure">>, _attrs, _els}. -'encode_compress_failure_$reason'(undefined, _acc) -> +'encode_compress_failure_$reason'(undefined, __TopXMLNS, + _acc) -> _acc; 'encode_compress_failure_$reason'('setup-failed' = Reason, - _acc) -> - [encode_compress_failure_setup_failed(Reason, []) + __TopXMLNS, _acc) -> + [encode_compress_failure_setup_failed(Reason, + __TopXMLNS) | _acc]; 'encode_compress_failure_$reason'('processing-failed' = Reason, - _acc) -> - [encode_compress_failure_processing_failed(Reason, []) + __TopXMLNS, _acc) -> + [encode_compress_failure_processing_failed(Reason, + __TopXMLNS) | _acc]; 'encode_compress_failure_$reason'('unsupported-method' = Reason, - _acc) -> - [encode_compress_failure_unsupported_method(Reason, []) + __TopXMLNS, _acc) -> + [encode_compress_failure_unsupported_method(Reason, + __TopXMLNS) | _acc]. decode_compress_failure_unsupported_method(__TopXMLNS, @@ -24302,9 +28412,12 @@ decode_compress_failure_unsupported_method(__TopXMLNS, 'unsupported-method'. encode_compress_failure_unsupported_method('unsupported-method', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/compress">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"unsupported-method">>, _attrs, _els}. decode_compress_failure_processing_failed(__TopXMLNS, @@ -24314,9 +28427,12 @@ decode_compress_failure_processing_failed(__TopXMLNS, 'processing-failed'. encode_compress_failure_processing_failed('processing-failed', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/compress">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"processing-failed">>, _attrs, _els}. decode_compress_failure_setup_failed(__TopXMLNS, @@ -24326,9 +28442,12 @@ decode_compress_failure_setup_failed(__TopXMLNS, 'setup-failed'. encode_compress_failure_setup_failed('setup-failed', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/compress">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"setup-failed">>, _attrs, _els}. decode_starttls_failure(__TopXMLNS, __IgnoreEls, @@ -24336,9 +28455,12 @@ decode_starttls_failure(__TopXMLNS, __IgnoreEls, {starttls_failure}. encode_starttls_failure({starttls_failure}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-tls">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"failure">>, _attrs, _els}. decode_starttls_proceed(__TopXMLNS, __IgnoreEls, @@ -24346,9 +28468,12 @@ decode_starttls_proceed(__TopXMLNS, __IgnoreEls, {starttls_proceed}. encode_starttls_proceed({starttls_proceed}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-tls">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"proceed">>, _attrs, _els}. decode_starttls(__TopXMLNS, __IgnoreEls, @@ -24383,24 +28508,32 @@ decode_starttls_els(__TopXMLNS, __IgnoreEls, [_ | _els], decode_starttls_els(__TopXMLNS, __IgnoreEls, _els, Required). -encode_starttls({starttls, Required}, _xmlns_attrs) -> +encode_starttls({starttls, Required}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-tls">>, + [], __TopXMLNS), _els = lists:reverse('encode_starttls_$required'(Required, - [])), - _attrs = _xmlns_attrs, + __NewTopXMLNS, [])), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"starttls">>, _attrs, _els}. -'encode_starttls_$required'(false, _acc) -> _acc; -'encode_starttls_$required'(Required, _acc) -> - [encode_starttls_required(Required, []) | _acc]. +'encode_starttls_$required'(false, __TopXMLNS, _acc) -> + _acc; +'encode_starttls_$required'(Required, __TopXMLNS, + _acc) -> + [encode_starttls_required(Required, __TopXMLNS) | _acc]. decode_starttls_required(__TopXMLNS, __IgnoreEls, {xmlel, <<"required">>, _attrs, _els}) -> true. -encode_starttls_required(true, _xmlns_attrs) -> +encode_starttls_required(true, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-tls">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"required">>, _attrs, _els}. decode_sasl_mechanisms(__TopXMLNS, __IgnoreEls, @@ -24440,16 +28573,23 @@ decode_sasl_mechanisms_els(__TopXMLNS, __IgnoreEls, _els, List). encode_sasl_mechanisms({sasl_mechanisms, List}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + [], __TopXMLNS), _els = - lists:reverse('encode_sasl_mechanisms_$list'(List, [])), - _attrs = _xmlns_attrs, + lists:reverse('encode_sasl_mechanisms_$list'(List, + __NewTopXMLNS, [])), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"mechanisms">>, _attrs, _els}. -'encode_sasl_mechanisms_$list'([], _acc) -> _acc; -'encode_sasl_mechanisms_$list'([List | _els], _acc) -> - 'encode_sasl_mechanisms_$list'(_els, - [encode_sasl_mechanism(List, []) | _acc]). +'encode_sasl_mechanisms_$list'([], __TopXMLNS, _acc) -> + _acc; +'encode_sasl_mechanisms_$list'([List | _els], + __TopXMLNS, _acc) -> + 'encode_sasl_mechanisms_$list'(_els, __TopXMLNS, + [encode_sasl_mechanism(List, __TopXMLNS) + | _acc]). decode_sasl_mechanism(__TopXMLNS, __IgnoreEls, {xmlel, <<"mechanism">>, _attrs, _els}) -> @@ -24469,9 +28609,12 @@ decode_sasl_mechanism_els(__TopXMLNS, __IgnoreEls, decode_sasl_mechanism_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_sasl_mechanism(Cdata, _xmlns_attrs) -> +encode_sasl_mechanism(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + [], __TopXMLNS), _els = encode_sasl_mechanism_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"mechanism">>, _attrs, _els}. decode_sasl_mechanism_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -24791,71 +28934,93 @@ decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, Text, Reason). encode_sasl_failure({sasl_failure, Reason, Text}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + [], __TopXMLNS), _els = lists:reverse('encode_sasl_failure_$text'(Text, + __NewTopXMLNS, 'encode_sasl_failure_$reason'(Reason, + __NewTopXMLNS, []))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"failure">>, _attrs, _els}. -'encode_sasl_failure_$text'([], _acc) -> _acc; -'encode_sasl_failure_$text'([Text | _els], _acc) -> - 'encode_sasl_failure_$text'(_els, - [encode_sasl_failure_text(Text, []) | _acc]). +'encode_sasl_failure_$text'([], __TopXMLNS, _acc) -> + _acc; +'encode_sasl_failure_$text'([Text | _els], __TopXMLNS, + _acc) -> + 'encode_sasl_failure_$text'(_els, __TopXMLNS, + [encode_sasl_failure_text(Text, __TopXMLNS) + | _acc]). -'encode_sasl_failure_$reason'(undefined, _acc) -> _acc; -'encode_sasl_failure_$reason'(aborted = Reason, _acc) -> - [encode_sasl_failure_aborted(Reason, []) | _acc]; +'encode_sasl_failure_$reason'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_sasl_failure_$reason'(aborted = Reason, + __TopXMLNS, _acc) -> + [encode_sasl_failure_aborted(Reason, __TopXMLNS) + | _acc]; 'encode_sasl_failure_$reason'('account-disabled' = Reason, - _acc) -> - [encode_sasl_failure_account_disabled(Reason, []) + __TopXMLNS, _acc) -> + [encode_sasl_failure_account_disabled(Reason, + __TopXMLNS) | _acc]; 'encode_sasl_failure_$reason'('credentials-expired' = Reason, - _acc) -> - [encode_sasl_failure_credentials_expired(Reason, []) + __TopXMLNS, _acc) -> + [encode_sasl_failure_credentials_expired(Reason, + __TopXMLNS) | _acc]; 'encode_sasl_failure_$reason'('encryption-required' = Reason, - _acc) -> - [encode_sasl_failure_encryption_required(Reason, []) + __TopXMLNS, _acc) -> + [encode_sasl_failure_encryption_required(Reason, + __TopXMLNS) | _acc]; 'encode_sasl_failure_$reason'('incorrect-encoding' = Reason, - _acc) -> - [encode_sasl_failure_incorrect_encoding(Reason, []) + __TopXMLNS, _acc) -> + [encode_sasl_failure_incorrect_encoding(Reason, + __TopXMLNS) | _acc]; 'encode_sasl_failure_$reason'('invalid-authzid' = Reason, - _acc) -> - [encode_sasl_failure_invalid_authzid(Reason, []) + __TopXMLNS, _acc) -> + [encode_sasl_failure_invalid_authzid(Reason, __TopXMLNS) | _acc]; 'encode_sasl_failure_$reason'('invalid-mechanism' = Reason, - _acc) -> - [encode_sasl_failure_invalid_mechanism(Reason, []) + __TopXMLNS, _acc) -> + [encode_sasl_failure_invalid_mechanism(Reason, + __TopXMLNS) | _acc]; 'encode_sasl_failure_$reason'('malformed-request' = Reason, - _acc) -> - [encode_sasl_failure_malformed_request(Reason, []) + __TopXMLNS, _acc) -> + [encode_sasl_failure_malformed_request(Reason, + __TopXMLNS) | _acc]; 'encode_sasl_failure_$reason'('mechanism-too-weak' = Reason, - _acc) -> - [encode_sasl_failure_mechanism_too_weak(Reason, []) + __TopXMLNS, _acc) -> + [encode_sasl_failure_mechanism_too_weak(Reason, + __TopXMLNS) | _acc]; 'encode_sasl_failure_$reason'('not-authorized' = Reason, - _acc) -> - [encode_sasl_failure_not_authorized(Reason, []) | _acc]; + __TopXMLNS, _acc) -> + [encode_sasl_failure_not_authorized(Reason, __TopXMLNS) + | _acc]; 'encode_sasl_failure_$reason'('bad-protocol' = Reason, - _acc) -> - [encode_sasl_failure_bad_protocol(Reason, []) | _acc]; + __TopXMLNS, _acc) -> + [encode_sasl_failure_bad_protocol(Reason, __TopXMLNS) + | _acc]; 'encode_sasl_failure_$reason'('temporary-auth-failure' = Reason, - _acc) -> - [encode_sasl_failure_temporary_auth_failure(Reason, []) + __TopXMLNS, _acc) -> + [encode_sasl_failure_temporary_auth_failure(Reason, + __TopXMLNS) | _acc]. decode_sasl_failure_temporary_auth_failure(__TopXMLNS, @@ -24865,9 +29030,12 @@ decode_sasl_failure_temporary_auth_failure(__TopXMLNS, 'temporary-auth-failure'. encode_sasl_failure_temporary_auth_failure('temporary-auth-failure', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"temporary-auth-failure">>, _attrs, _els}. decode_sasl_failure_bad_protocol(__TopXMLNS, @@ -24876,9 +29044,12 @@ decode_sasl_failure_bad_protocol(__TopXMLNS, 'bad-protocol'. encode_sasl_failure_bad_protocol('bad-protocol', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"bad-protocol">>, _attrs, _els}. decode_sasl_failure_not_authorized(__TopXMLNS, @@ -24888,9 +29059,12 @@ decode_sasl_failure_not_authorized(__TopXMLNS, 'not-authorized'. encode_sasl_failure_not_authorized('not-authorized', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"not-authorized">>, _attrs, _els}. decode_sasl_failure_mechanism_too_weak(__TopXMLNS, @@ -24900,9 +29074,12 @@ decode_sasl_failure_mechanism_too_weak(__TopXMLNS, 'mechanism-too-weak'. encode_sasl_failure_mechanism_too_weak('mechanism-too-weak', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"mechanism-too-weak">>, _attrs, _els}. decode_sasl_failure_malformed_request(__TopXMLNS, @@ -24912,9 +29089,12 @@ decode_sasl_failure_malformed_request(__TopXMLNS, 'malformed-request'. encode_sasl_failure_malformed_request('malformed-request', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"malformed-request">>, _attrs, _els}. decode_sasl_failure_invalid_mechanism(__TopXMLNS, @@ -24924,9 +29104,12 @@ decode_sasl_failure_invalid_mechanism(__TopXMLNS, 'invalid-mechanism'. encode_sasl_failure_invalid_mechanism('invalid-mechanism', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"invalid-mechanism">>, _attrs, _els}. decode_sasl_failure_invalid_authzid(__TopXMLNS, @@ -24936,9 +29119,12 @@ decode_sasl_failure_invalid_authzid(__TopXMLNS, 'invalid-authzid'. encode_sasl_failure_invalid_authzid('invalid-authzid', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"invalid-authzid">>, _attrs, _els}. decode_sasl_failure_incorrect_encoding(__TopXMLNS, @@ -24948,9 +29134,12 @@ decode_sasl_failure_incorrect_encoding(__TopXMLNS, 'incorrect-encoding'. encode_sasl_failure_incorrect_encoding('incorrect-encoding', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"incorrect-encoding">>, _attrs, _els}. decode_sasl_failure_encryption_required(__TopXMLNS, @@ -24960,9 +29149,12 @@ decode_sasl_failure_encryption_required(__TopXMLNS, 'encryption-required'. encode_sasl_failure_encryption_required('encryption-required', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"encryption-required">>, _attrs, _els}. decode_sasl_failure_credentials_expired(__TopXMLNS, @@ -24972,9 +29164,12 @@ decode_sasl_failure_credentials_expired(__TopXMLNS, 'credentials-expired'. encode_sasl_failure_credentials_expired('credentials-expired', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"credentials-expired">>, _attrs, _els}. decode_sasl_failure_account_disabled(__TopXMLNS, @@ -24984,18 +29179,24 @@ decode_sasl_failure_account_disabled(__TopXMLNS, 'account-disabled'. encode_sasl_failure_account_disabled('account-disabled', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"account-disabled">>, _attrs, _els}. decode_sasl_failure_aborted(__TopXMLNS, __IgnoreEls, {xmlel, <<"aborted">>, _attrs, _els}) -> aborted. -encode_sasl_failure_aborted(aborted, _xmlns_attrs) -> +encode_sasl_failure_aborted(aborted, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"aborted">>, _attrs, _els}. decode_sasl_failure_text(__TopXMLNS, __IgnoreEls, @@ -25031,10 +29232,14 @@ decode_sasl_failure_text_attrs(__TopXMLNS, [], Lang) -> Lang). encode_sasl_failure_text({text, Lang, Data}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + [], __TopXMLNS), _els = encode_sasl_failure_text_cdata(Data, []), _attrs = 'encode_sasl_failure_text_attr_xml:lang'(Lang, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"text">>, _attrs, _els}. 'decode_sasl_failure_text_attr_xml:lang'(__TopXMLNS, @@ -25076,10 +29281,12 @@ decode_sasl_success_els(__TopXMLNS, __IgnoreEls, decode_sasl_success_els(__TopXMLNS, __IgnoreEls, _els, Text). -encode_sasl_success({sasl_success, Text}, - _xmlns_attrs) -> +encode_sasl_success({sasl_success, Text}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + [], __TopXMLNS), _els = encode_sasl_success_cdata(Text, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"success">>, _attrs, _els}. decode_sasl_success_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -25114,9 +29321,12 @@ decode_sasl_response_els(__TopXMLNS, __IgnoreEls, Text). encode_sasl_response({sasl_response, Text}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + [], __TopXMLNS), _els = encode_sasl_response_cdata(Text, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"response">>, _attrs, _els}. decode_sasl_response_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -25151,9 +29361,12 @@ decode_sasl_challenge_els(__TopXMLNS, __IgnoreEls, Text). encode_sasl_challenge({sasl_challenge, Text}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + [], __TopXMLNS), _els = encode_sasl_challenge_cdata(Text, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"challenge">>, _attrs, _els}. decode_sasl_challenge_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -25173,9 +29386,12 @@ decode_sasl_abort(__TopXMLNS, __IgnoreEls, {xmlel, <<"abort">>, _attrs, _els}) -> {sasl_abort}. -encode_sasl_abort({sasl_abort}, _xmlns_attrs) -> +encode_sasl_abort({sasl_abort}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"abort">>, _attrs, _els}. decode_sasl_auth(__TopXMLNS, __IgnoreEls, @@ -25208,10 +29424,14 @@ decode_sasl_auth_attrs(__TopXMLNS, [], Mechanism) -> decode_sasl_auth_attr_mechanism(__TopXMLNS, Mechanism). encode_sasl_auth({sasl_auth, Mechanism, Text}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, + [], __TopXMLNS), _els = encode_sasl_auth_cdata(Text, []), _attrs = encode_sasl_auth_attr_mechanism(Mechanism, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"auth">>, _attrs, _els}. decode_sasl_auth_attr_mechanism(__TopXMLNS, @@ -25331,31 +29551,52 @@ decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, encode_legacy_auth({legacy_auth, Username, Password, Digest, Resource}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:auth">>, + [], __TopXMLNS), _els = lists:reverse('encode_legacy_auth_$digest'(Digest, + __NewTopXMLNS, 'encode_legacy_auth_$password'(Password, + __NewTopXMLNS, 'encode_legacy_auth_$resource'(Resource, + __NewTopXMLNS, 'encode_legacy_auth_$username'(Username, + __NewTopXMLNS, []))))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"query">>, _attrs, _els}. -'encode_legacy_auth_$digest'(undefined, _acc) -> _acc; -'encode_legacy_auth_$digest'(Digest, _acc) -> - [encode_legacy_auth_digest(Digest, []) | _acc]. +'encode_legacy_auth_$digest'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_legacy_auth_$digest'(Digest, __TopXMLNS, + _acc) -> + [encode_legacy_auth_digest(Digest, __TopXMLNS) | _acc]. -'encode_legacy_auth_$password'(undefined, _acc) -> _acc; -'encode_legacy_auth_$password'(Password, _acc) -> - [encode_legacy_auth_password(Password, []) | _acc]. +'encode_legacy_auth_$password'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_legacy_auth_$password'(Password, __TopXMLNS, + _acc) -> + [encode_legacy_auth_password(Password, __TopXMLNS) + | _acc]. -'encode_legacy_auth_$resource'(undefined, _acc) -> _acc; -'encode_legacy_auth_$resource'(Resource, _acc) -> - [encode_legacy_auth_resource(Resource, []) | _acc]. +'encode_legacy_auth_$resource'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_legacy_auth_$resource'(Resource, __TopXMLNS, + _acc) -> + [encode_legacy_auth_resource(Resource, __TopXMLNS) + | _acc]. -'encode_legacy_auth_$username'(undefined, _acc) -> _acc; -'encode_legacy_auth_$username'(Username, _acc) -> - [encode_legacy_auth_username(Username, []) | _acc]. +'encode_legacy_auth_$username'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_legacy_auth_$username'(Username, __TopXMLNS, + _acc) -> + [encode_legacy_auth_username(Username, __TopXMLNS) + | _acc]. decode_legacy_auth_resource(__TopXMLNS, __IgnoreEls, {xmlel, <<"resource">>, _attrs, _els}) -> @@ -25375,9 +29616,11 @@ decode_legacy_auth_resource_els(__TopXMLNS, __IgnoreEls, decode_legacy_auth_resource_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_legacy_auth_resource(Cdata, _xmlns_attrs) -> +encode_legacy_auth_resource(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:auth">>, + [], __TopXMLNS), _els = encode_legacy_auth_resource_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"resource">>, _attrs, _els}. decode_legacy_auth_resource_cdata(__TopXMLNS, <<>>) -> @@ -25407,9 +29650,11 @@ decode_legacy_auth_digest_els(__TopXMLNS, __IgnoreEls, decode_legacy_auth_digest_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_legacy_auth_digest(Cdata, _xmlns_attrs) -> +encode_legacy_auth_digest(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:auth">>, + [], __TopXMLNS), _els = encode_legacy_auth_digest_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"digest">>, _attrs, _els}. decode_legacy_auth_digest_cdata(__TopXMLNS, <<>>) -> @@ -25439,9 +29684,11 @@ decode_legacy_auth_password_els(__TopXMLNS, __IgnoreEls, decode_legacy_auth_password_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_legacy_auth_password(Cdata, _xmlns_attrs) -> +encode_legacy_auth_password(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:auth">>, + [], __TopXMLNS), _els = encode_legacy_auth_password_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"password">>, _attrs, _els}. decode_legacy_auth_password_cdata(__TopXMLNS, <<>>) -> @@ -25471,9 +29718,11 @@ decode_legacy_auth_username_els(__TopXMLNS, __IgnoreEls, decode_legacy_auth_username_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_legacy_auth_username(Cdata, _xmlns_attrs) -> +encode_legacy_auth_username(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:auth">>, + [], __TopXMLNS), _els = encode_legacy_auth_username_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"username">>, _attrs, _els}. decode_legacy_auth_username_cdata(__TopXMLNS, <<>>) -> @@ -25535,20 +29784,26 @@ decode_bind_els(__TopXMLNS, __IgnoreEls, [_ | _els], decode_bind_els(__TopXMLNS, __IgnoreEls, _els, Jid, Resource). -encode_bind({bind, Jid, Resource}, _xmlns_attrs) -> +encode_bind({bind, Jid, Resource}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-bind">>, + [], __TopXMLNS), _els = lists:reverse('encode_bind_$jid'(Jid, + __NewTopXMLNS, 'encode_bind_$resource'(Resource, + __NewTopXMLNS, []))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"bind">>, _attrs, _els}. -'encode_bind_$jid'(undefined, _acc) -> _acc; -'encode_bind_$jid'(Jid, _acc) -> - [encode_bind_jid(Jid, []) | _acc]. +'encode_bind_$jid'(undefined, __TopXMLNS, _acc) -> _acc; +'encode_bind_$jid'(Jid, __TopXMLNS, _acc) -> + [encode_bind_jid(Jid, __TopXMLNS) | _acc]. -'encode_bind_$resource'(undefined, _acc) -> _acc; -'encode_bind_$resource'(Resource, _acc) -> - [encode_bind_resource(Resource, []) | _acc]. +'encode_bind_$resource'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_bind_$resource'(Resource, __TopXMLNS, _acc) -> + [encode_bind_resource(Resource, __TopXMLNS) | _acc]. decode_bind_resource(__TopXMLNS, __IgnoreEls, {xmlel, <<"resource">>, _attrs, _els}) -> @@ -25568,9 +29823,12 @@ decode_bind_resource_els(__TopXMLNS, __IgnoreEls, decode_bind_resource_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_bind_resource(Cdata, _xmlns_attrs) -> +encode_bind_resource(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-bind">>, + [], __TopXMLNS), _els = encode_bind_resource_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"resource">>, _attrs, _els}. decode_bind_resource_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -25604,9 +29862,12 @@ decode_bind_jid_els(__TopXMLNS, __IgnoreEls, [_ | _els], decode_bind_jid_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_bind_jid(Cdata, _xmlns_attrs) -> +encode_bind_jid(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-bind">>, + [], __TopXMLNS), _els = encode_bind_jid_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"jid">>, _attrs, _els}. decode_bind_jid_cdata(__TopXMLNS, <<>>) -> undefined; @@ -25968,10 +30229,11 @@ decode_error_els(__TopXMLNS, __IgnoreEls, decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, Reason, [_el | __Els]); true -> - case is_known_tag(_el) of + case is_known_tag(_el, __TopXMLNS) of true -> decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, [decode(_el) | __Els]); + Reason, + [decode(_el, __TopXMLNS, []) | __Els]); false -> decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, Reason, __Els) @@ -26002,158 +30264,118 @@ decode_error_attrs(__TopXMLNS, [], Type, Code, By) -> encode_error({stanza_error, Type, Code, By, Reason, Text, __Els}, - _xmlns_attrs) -> - _els = [encode(_el) || _el <- __Els] ++ - lists:reverse('encode_error_$text'(Text, + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"jabber:client">>, <<"jabber:server">>, + <<"jabber:component:accept">>], + __TopXMLNS), + _els = [encode(_el, __NewTopXMLNS) || _el <- __Els] ++ + lists:reverse('encode_error_$text'(Text, __NewTopXMLNS, 'encode_error_$reason'(Reason, + __NewTopXMLNS, []))), _attrs = encode_error_attr_by(By, encode_error_attr_code(Code, encode_error_attr_type(Type, - _xmlns_attrs))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)))), {xmlel, <<"error">>, _attrs, _els}. -'encode_error_$text'(undefined, _acc) -> _acc; -'encode_error_$text'(Text, _acc) -> - [encode_error_text(Text, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) - | _acc]. +'encode_error_$text'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_error_$text'(Text, __TopXMLNS, _acc) -> + [encode_error_text(Text, __TopXMLNS) | _acc]. -'encode_error_$reason'(undefined, _acc) -> _acc; -'encode_error_$reason'('bad-request' = Reason, _acc) -> - [encode_error_bad_request(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) - | _acc]; -'encode_error_$reason'(conflict = Reason, _acc) -> - [encode_error_conflict(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) - | _acc]; +'encode_error_$reason'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_error_$reason'('bad-request' = Reason, + __TopXMLNS, _acc) -> + [encode_error_bad_request(Reason, __TopXMLNS) | _acc]; +'encode_error_$reason'(conflict = Reason, __TopXMLNS, + _acc) -> + [encode_error_conflict(Reason, __TopXMLNS) | _acc]; 'encode_error_$reason'('feature-not-implemented' = Reason, - _acc) -> + __TopXMLNS, _acc) -> [encode_error_feature_not_implemented(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS) | _acc]; -'encode_error_$reason'(forbidden = Reason, _acc) -> - [encode_error_forbidden(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) - | _acc]; -'encode_error_$reason'({gone, _} = Reason, _acc) -> - [encode_error_gone(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) - | _acc]; -'encode_error_$reason'('internal-server-error' = Reason, +'encode_error_$reason'(forbidden = Reason, __TopXMLNS, _acc) -> - [encode_error_internal_server_error(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + [encode_error_forbidden(Reason, __TopXMLNS) | _acc]; +'encode_error_$reason'({gone, _} = Reason, __TopXMLNS, + _acc) -> + [encode_error_gone(Reason, __TopXMLNS) | _acc]; +'encode_error_$reason'('internal-server-error' = Reason, + __TopXMLNS, _acc) -> + [encode_error_internal_server_error(Reason, __TopXMLNS) | _acc]; 'encode_error_$reason'('item-not-found' = Reason, - _acc) -> - [encode_error_item_not_found(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_item_not_found(Reason, __TopXMLNS) | _acc]; 'encode_error_$reason'('jid-malformed' = Reason, - _acc) -> - [encode_error_jid_malformed(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) - | _acc]; + __TopXMLNS, _acc) -> + [encode_error_jid_malformed(Reason, __TopXMLNS) | _acc]; 'encode_error_$reason'('not-acceptable' = Reason, - _acc) -> - [encode_error_not_acceptable(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) - | _acc]; -'encode_error_$reason'('not-allowed' = Reason, _acc) -> - [encode_error_not_allowed(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_not_acceptable(Reason, __TopXMLNS) | _acc]; +'encode_error_$reason'('not-allowed' = Reason, + __TopXMLNS, _acc) -> + [encode_error_not_allowed(Reason, __TopXMLNS) | _acc]; 'encode_error_$reason'('not-authorized' = Reason, - _acc) -> - [encode_error_not_authorized(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_not_authorized(Reason, __TopXMLNS) | _acc]; 'encode_error_$reason'('payment-required' = Reason, - _acc) -> - [encode_error_payment_required(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_payment_required(Reason, __TopXMLNS) | _acc]; 'encode_error_$reason'('policy-violation' = Reason, - _acc) -> - [encode_error_policy_violation(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_policy_violation(Reason, __TopXMLNS) | _acc]; 'encode_error_$reason'('recipient-unavailable' = Reason, - _acc) -> - [encode_error_recipient_unavailable(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) - | _acc]; -'encode_error_$reason'({redirect, _} = Reason, _acc) -> - [encode_error_redirect(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_recipient_unavailable(Reason, __TopXMLNS) | _acc]; +'encode_error_$reason'({redirect, _} = Reason, + __TopXMLNS, _acc) -> + [encode_error_redirect(Reason, __TopXMLNS) | _acc]; 'encode_error_$reason'('registration-required' = Reason, - _acc) -> - [encode_error_registration_required(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_registration_required(Reason, __TopXMLNS) | _acc]; 'encode_error_$reason'('remote-server-not-found' = Reason, - _acc) -> + __TopXMLNS, _acc) -> [encode_error_remote_server_not_found(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS) | _acc]; 'encode_error_$reason'('remote-server-timeout' = Reason, - _acc) -> - [encode_error_remote_server_timeout(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_remote_server_timeout(Reason, __TopXMLNS) | _acc]; 'encode_error_$reason'('resource-constraint' = Reason, - _acc) -> - [encode_error_resource_constraint(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_resource_constraint(Reason, __TopXMLNS) | _acc]; 'encode_error_$reason'('service-unavailable' = Reason, - _acc) -> - [encode_error_service_unavailable(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_service_unavailable(Reason, __TopXMLNS) | _acc]; 'encode_error_$reason'('subscription-required' = Reason, - _acc) -> - [encode_error_subscription_required(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_subscription_required(Reason, __TopXMLNS) | _acc]; 'encode_error_$reason'('undefined-condition' = Reason, - _acc) -> - [encode_error_undefined_condition(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_undefined_condition(Reason, __TopXMLNS) | _acc]; 'encode_error_$reason'('unexpected-request' = Reason, - _acc) -> - [encode_error_unexpected_request(Reason, - [{<<"xmlns">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>}]) + __TopXMLNS, _acc) -> + [encode_error_unexpected_request(Reason, __TopXMLNS) | _acc]. decode_error_attr_type(__TopXMLNS, undefined) -> @@ -26222,10 +30444,14 @@ decode_error_text_attrs(__TopXMLNS, [_ | _attrs], decode_error_text_attrs(__TopXMLNS, [], Lang) -> 'decode_error_text_attr_xml:lang'(__TopXMLNS, Lang). -encode_error_text({text, Lang, Data}, _xmlns_attrs) -> +encode_error_text({text, Lang, Data}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + [], __TopXMLNS), _els = encode_error_text_cdata(Data, []), _attrs = 'encode_error_text_attr_xml:lang'(Lang, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"text">>, _attrs, _els}. 'decode_error_text_attr_xml:lang'(__TopXMLNS, @@ -26251,9 +30477,12 @@ decode_error_unexpected_request(__TopXMLNS, __IgnoreEls, 'unexpected-request'. encode_error_unexpected_request('unexpected-request', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"unexpected-request">>, _attrs, _els}. decode_error_undefined_condition(__TopXMLNS, @@ -26263,9 +30492,12 @@ decode_error_undefined_condition(__TopXMLNS, 'undefined-condition'. encode_error_undefined_condition('undefined-condition', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"undefined-condition">>, _attrs, _els}. decode_error_subscription_required(__TopXMLNS, @@ -26275,9 +30507,12 @@ decode_error_subscription_required(__TopXMLNS, 'subscription-required'. encode_error_subscription_required('subscription-required', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"subscription-required">>, _attrs, _els}. decode_error_service_unavailable(__TopXMLNS, @@ -26287,9 +30522,12 @@ decode_error_service_unavailable(__TopXMLNS, 'service-unavailable'. encode_error_service_unavailable('service-unavailable', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"service-unavailable">>, _attrs, _els}. decode_error_resource_constraint(__TopXMLNS, @@ -26299,9 +30537,12 @@ decode_error_resource_constraint(__TopXMLNS, 'resource-constraint'. encode_error_resource_constraint('resource-constraint', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"resource-constraint">>, _attrs, _els}. decode_error_remote_server_timeout(__TopXMLNS, @@ -26311,9 +30552,12 @@ decode_error_remote_server_timeout(__TopXMLNS, 'remote-server-timeout'. encode_error_remote_server_timeout('remote-server-timeout', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"remote-server-timeout">>, _attrs, _els}. decode_error_remote_server_not_found(__TopXMLNS, @@ -26323,9 +30567,12 @@ decode_error_remote_server_not_found(__TopXMLNS, 'remote-server-not-found'. encode_error_remote_server_not_found('remote-server-not-found', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"remote-server-not-found">>, _attrs, _els}. decode_error_registration_required(__TopXMLNS, @@ -26335,9 +30582,12 @@ decode_error_registration_required(__TopXMLNS, 'registration-required'. encode_error_registration_required('registration-required', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"registration-required">>, _attrs, _els}. decode_error_redirect(__TopXMLNS, __IgnoreEls, @@ -26358,9 +30608,12 @@ decode_error_redirect_els(__TopXMLNS, __IgnoreEls, decode_error_redirect_els(__TopXMLNS, __IgnoreEls, _els, Uri). -encode_error_redirect({redirect, Uri}, _xmlns_attrs) -> +encode_error_redirect({redirect, Uri}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + [], __TopXMLNS), _els = encode_error_redirect_cdata(Uri, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"redirect">>, _attrs, _els}. decode_error_redirect_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -26377,9 +30630,12 @@ decode_error_recipient_unavailable(__TopXMLNS, 'recipient-unavailable'. encode_error_recipient_unavailable('recipient-unavailable', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"recipient-unavailable">>, _attrs, _els}. decode_error_policy_violation(__TopXMLNS, __IgnoreEls, @@ -26387,9 +30643,12 @@ decode_error_policy_violation(__TopXMLNS, __IgnoreEls, 'policy-violation'. encode_error_policy_violation('policy-violation', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"policy-violation">>, _attrs, _els}. decode_error_payment_required(__TopXMLNS, __IgnoreEls, @@ -26397,9 +30656,12 @@ decode_error_payment_required(__TopXMLNS, __IgnoreEls, 'payment-required'. encode_error_payment_required('payment-required', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"payment-required">>, _attrs, _els}. decode_error_not_authorized(__TopXMLNS, __IgnoreEls, @@ -26407,18 +30669,24 @@ decode_error_not_authorized(__TopXMLNS, __IgnoreEls, 'not-authorized'. encode_error_not_authorized('not-authorized', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"not-authorized">>, _attrs, _els}. decode_error_not_allowed(__TopXMLNS, __IgnoreEls, {xmlel, <<"not-allowed">>, _attrs, _els}) -> 'not-allowed'. -encode_error_not_allowed('not-allowed', _xmlns_attrs) -> +encode_error_not_allowed('not-allowed', __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"not-allowed">>, _attrs, _els}. decode_error_not_acceptable(__TopXMLNS, __IgnoreEls, @@ -26426,9 +30694,12 @@ decode_error_not_acceptable(__TopXMLNS, __IgnoreEls, 'not-acceptable'. encode_error_not_acceptable('not-acceptable', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"not-acceptable">>, _attrs, _els}. decode_error_jid_malformed(__TopXMLNS, __IgnoreEls, @@ -26436,9 +30707,12 @@ decode_error_jid_malformed(__TopXMLNS, __IgnoreEls, 'jid-malformed'. encode_error_jid_malformed('jid-malformed', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"jid-malformed">>, _attrs, _els}. decode_error_item_not_found(__TopXMLNS, __IgnoreEls, @@ -26446,9 +30720,12 @@ decode_error_item_not_found(__TopXMLNS, __IgnoreEls, 'item-not-found'. encode_error_item_not_found('item-not-found', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"item-not-found">>, _attrs, _els}. decode_error_internal_server_error(__TopXMLNS, @@ -26458,9 +30735,12 @@ decode_error_internal_server_error(__TopXMLNS, 'internal-server-error'. encode_error_internal_server_error('internal-server-error', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"internal-server-error">>, _attrs, _els}. decode_error_gone(__TopXMLNS, __IgnoreEls, @@ -26481,9 +30761,12 @@ decode_error_gone_els(__TopXMLNS, __IgnoreEls, decode_error_gone_els(__TopXMLNS, __IgnoreEls, _els, Uri). -encode_error_gone({gone, Uri}, _xmlns_attrs) -> +encode_error_gone({gone, Uri}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + [], __TopXMLNS), _els = encode_error_gone_cdata(Uri, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"gone">>, _attrs, _els}. decode_error_gone_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -26497,9 +30780,12 @@ decode_error_forbidden(__TopXMLNS, __IgnoreEls, {xmlel, <<"forbidden">>, _attrs, _els}) -> forbidden. -encode_error_forbidden(forbidden, _xmlns_attrs) -> +encode_error_forbidden(forbidden, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"forbidden">>, _attrs, _els}. decode_error_feature_not_implemented(__TopXMLNS, @@ -26509,27 +30795,36 @@ decode_error_feature_not_implemented(__TopXMLNS, 'feature-not-implemented'. encode_error_feature_not_implemented('feature-not-implemented', - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"feature-not-implemented">>, _attrs, _els}. decode_error_conflict(__TopXMLNS, __IgnoreEls, {xmlel, <<"conflict">>, _attrs, _els}) -> conflict. -encode_error_conflict(conflict, _xmlns_attrs) -> +encode_error_conflict(conflict, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"conflict">>, _attrs, _els}. decode_error_bad_request(__TopXMLNS, __IgnoreEls, {xmlel, <<"bad-request">>, _attrs, _els}) -> 'bad-request'. -encode_error_bad_request('bad-request', _xmlns_attrs) -> +encode_error_bad_request('bad-request', __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, + [], __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"bad-request">>, _attrs, _els}. decode_presence(__TopXMLNS, __IgnoreEls, @@ -26551,7 +30846,10 @@ decode_presence_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"show">>, _attrs, _} = _el | _els], Status, Show, Priority, __Els) -> case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:client">> -> + <<"">> + when __TopXMLNS == <<"jabber:server">>; + __TopXMLNS == <<"jabber:component:accept">>; + __TopXMLNS == <<"jabber:client">> -> decode_presence_els(__TopXMLNS, __IgnoreEls, _els, Status, decode_presence_show(__TopXMLNS, __IgnoreEls, @@ -26563,6 +30861,18 @@ decode_presence_els(__TopXMLNS, __IgnoreEls, decode_presence_show(<<"jabber:client">>, __IgnoreEls, _el), Priority, __Els); + <<"jabber:server">> -> + decode_presence_els(__TopXMLNS, __IgnoreEls, _els, + Status, + decode_presence_show(<<"jabber:server">>, + __IgnoreEls, _el), + Priority, __Els); + <<"jabber:component:accept">> -> + decode_presence_els(__TopXMLNS, __IgnoreEls, _els, + Status, + decode_presence_show(<<"jabber:component:accept">>, + __IgnoreEls, _el), + Priority, __Els); _ -> decode_presence_els(__TopXMLNS, __IgnoreEls, _els, Status, Show, Priority, __Els) @@ -26571,7 +30881,10 @@ decode_presence_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"status">>, _attrs, _} = _el | _els], Status, Show, Priority, __Els) -> case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:client">> -> + <<"">> + when __TopXMLNS == <<"jabber:server">>; + __TopXMLNS == <<"jabber:component:accept">>; + __TopXMLNS == <<"jabber:client">> -> decode_presence_els(__TopXMLNS, __IgnoreEls, _els, [decode_presence_status(__TopXMLNS, __IgnoreEls, _el) @@ -26583,6 +30896,18 @@ decode_presence_els(__TopXMLNS, __IgnoreEls, __IgnoreEls, _el) | Status], Show, Priority, __Els); + <<"jabber:server">> -> + decode_presence_els(__TopXMLNS, __IgnoreEls, _els, + [decode_presence_status(<<"jabber:server">>, + __IgnoreEls, _el) + | Status], + Show, Priority, __Els); + <<"jabber:component:accept">> -> + decode_presence_els(__TopXMLNS, __IgnoreEls, _els, + [decode_presence_status(<<"jabber:component:accept">>, + __IgnoreEls, _el) + | Status], + Show, Priority, __Els); _ -> decode_presence_els(__TopXMLNS, __IgnoreEls, _els, Status, Show, Priority, __Els) @@ -26591,7 +30916,10 @@ decode_presence_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"priority">>, _attrs, _} = _el | _els], Status, Show, Priority, __Els) -> case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:client">> -> + <<"">> + when __TopXMLNS == <<"jabber:server">>; + __TopXMLNS == <<"jabber:component:accept">>; + __TopXMLNS == <<"jabber:client">> -> decode_presence_els(__TopXMLNS, __IgnoreEls, _els, Status, Show, decode_presence_priority(__TopXMLNS, __IgnoreEls, @@ -26603,6 +30931,18 @@ decode_presence_els(__TopXMLNS, __IgnoreEls, decode_presence_priority(<<"jabber:client">>, __IgnoreEls, _el), __Els); + <<"jabber:server">> -> + decode_presence_els(__TopXMLNS, __IgnoreEls, _els, + Status, Show, + decode_presence_priority(<<"jabber:server">>, + __IgnoreEls, _el), + __Els); + <<"jabber:component:accept">> -> + decode_presence_els(__TopXMLNS, __IgnoreEls, _els, + Status, Show, + decode_presence_priority(<<"jabber:component:accept">>, + __IgnoreEls, _el), + __Els); _ -> decode_presence_els(__TopXMLNS, __IgnoreEls, _els, Status, Show, Priority, __Els) @@ -26614,11 +30954,11 @@ decode_presence_els(__TopXMLNS, __IgnoreEls, decode_presence_els(__TopXMLNS, __IgnoreEls, _els, Status, Show, Priority, [_el | __Els]); true -> - case is_known_tag(_el) of + case is_known_tag(_el, __TopXMLNS) of true -> decode_presence_els(__TopXMLNS, __IgnoreEls, _els, Status, Show, Priority, - [decode(_el) | __Els]); + [decode(_el, __TopXMLNS, []) | __Els]); false -> decode_presence_els(__TopXMLNS, __IgnoreEls, _els, Status, Show, Priority, __Els) @@ -26668,32 +31008,46 @@ decode_presence_attrs(__TopXMLNS, [], Id, Type, From, encode_presence({presence, Id, Type, Lang, From, To, Show, Status, Priority, __Els}, - _xmlns_attrs) -> - _els = [encode(_el) || _el <- __Els] ++ + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"jabber:client">>, <<"jabber:server">>, + <<"jabber:component:accept">>], + __TopXMLNS), + _els = [encode(_el, __NewTopXMLNS) || _el <- __Els] ++ lists:reverse('encode_presence_$status'(Status, + __NewTopXMLNS, 'encode_presence_$show'(Show, + __NewTopXMLNS, 'encode_presence_$priority'(Priority, + __NewTopXMLNS, [])))), _attrs = 'encode_presence_attr_xml:lang'(Lang, encode_presence_attr_to(To, encode_presence_attr_from(From, encode_presence_attr_type(Type, encode_presence_attr_id(Id, - _xmlns_attrs))))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)))))), {xmlel, <<"presence">>, _attrs, _els}. -'encode_presence_$status'([], _acc) -> _acc; -'encode_presence_$status'([Status | _els], _acc) -> - 'encode_presence_$status'(_els, - [encode_presence_status(Status, []) | _acc]). +'encode_presence_$status'([], __TopXMLNS, _acc) -> _acc; +'encode_presence_$status'([Status | _els], __TopXMLNS, + _acc) -> + 'encode_presence_$status'(_els, __TopXMLNS, + [encode_presence_status(Status, __TopXMLNS) + | _acc]). -'encode_presence_$show'(undefined, _acc) -> _acc; -'encode_presence_$show'(Show, _acc) -> - [encode_presence_show(Show, []) | _acc]. +'encode_presence_$show'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_presence_$show'(Show, __TopXMLNS, _acc) -> + [encode_presence_show(Show, __TopXMLNS) | _acc]. -'encode_presence_$priority'(undefined, _acc) -> _acc; -'encode_presence_$priority'(Priority, _acc) -> - [encode_presence_priority(Priority, []) | _acc]. +'encode_presence_$priority'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_presence_$priority'(Priority, __TopXMLNS, + _acc) -> + [encode_presence_priority(Priority, __TopXMLNS) | _acc]. decode_presence_attr_id(__TopXMLNS, undefined) -> <<>>; decode_presence_attr_id(__TopXMLNS, _val) -> _val. @@ -26778,9 +31132,13 @@ decode_presence_priority_els(__TopXMLNS, __IgnoreEls, decode_presence_priority_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_presence_priority(Cdata, _xmlns_attrs) -> +encode_presence_priority(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"jabber:client">>, <<"jabber:server">>, + <<"jabber:component:accept">>], + __TopXMLNS), _els = encode_presence_priority_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"priority">>, _attrs, _els}. decode_presence_priority_cdata(__TopXMLNS, <<>>) -> @@ -26828,10 +31186,15 @@ decode_presence_status_attrs(__TopXMLNS, [], Lang) -> Lang). encode_presence_status({text, Lang, Data}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"jabber:client">>, <<"jabber:server">>, + <<"jabber:component:accept">>], + __TopXMLNS), _els = encode_presence_status_cdata(Data, []), _attrs = 'encode_presence_status_attr_xml:lang'(Lang, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"status">>, _attrs, _els}. 'decode_presence_status_attr_xml:lang'(__TopXMLNS, @@ -26871,9 +31234,13 @@ decode_presence_show_els(__TopXMLNS, __IgnoreEls, decode_presence_show_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_presence_show(Cdata, _xmlns_attrs) -> +encode_presence_show(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"jabber:client">>, <<"jabber:server">>, + <<"jabber:component:accept">>], + __TopXMLNS), _els = encode_presence_show_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"show">>, _attrs, _els}. decode_presence_show_cdata(__TopXMLNS, <<>>) -> @@ -26909,7 +31276,10 @@ decode_message_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"subject">>, _attrs, _} = _el | _els], Thread, Subject, Body, __Els) -> case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:client">> -> + <<"">> + when __TopXMLNS == <<"jabber:server">>; + __TopXMLNS == <<"jabber:component:accept">>; + __TopXMLNS == <<"jabber:client">> -> decode_message_els(__TopXMLNS, __IgnoreEls, _els, Thread, [decode_message_subject(__TopXMLNS, __IgnoreEls, @@ -26923,6 +31293,20 @@ decode_message_els(__TopXMLNS, __IgnoreEls, __IgnoreEls, _el) | Subject], Body, __Els); + <<"jabber:server">> -> + decode_message_els(__TopXMLNS, __IgnoreEls, _els, + Thread, + [decode_message_subject(<<"jabber:server">>, + __IgnoreEls, _el) + | Subject], + Body, __Els); + <<"jabber:component:accept">> -> + decode_message_els(__TopXMLNS, __IgnoreEls, _els, + Thread, + [decode_message_subject(<<"jabber:component:accept">>, + __IgnoreEls, _el) + | Subject], + Body, __Els); _ -> decode_message_els(__TopXMLNS, __IgnoreEls, _els, Thread, Subject, Body, __Els) @@ -26931,7 +31315,10 @@ decode_message_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"thread">>, _attrs, _} = _el | _els], Thread, Subject, Body, __Els) -> case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:client">> -> + <<"">> + when __TopXMLNS == <<"jabber:server">>; + __TopXMLNS == <<"jabber:component:accept">>; + __TopXMLNS == <<"jabber:client">> -> decode_message_els(__TopXMLNS, __IgnoreEls, _els, decode_message_thread(__TopXMLNS, __IgnoreEls, _el), @@ -26941,6 +31328,16 @@ decode_message_els(__TopXMLNS, __IgnoreEls, decode_message_thread(<<"jabber:client">>, __IgnoreEls, _el), Subject, Body, __Els); + <<"jabber:server">> -> + decode_message_els(__TopXMLNS, __IgnoreEls, _els, + decode_message_thread(<<"jabber:server">>, + __IgnoreEls, _el), + Subject, Body, __Els); + <<"jabber:component:accept">> -> + decode_message_els(__TopXMLNS, __IgnoreEls, _els, + decode_message_thread(<<"jabber:component:accept">>, + __IgnoreEls, _el), + Subject, Body, __Els); _ -> decode_message_els(__TopXMLNS, __IgnoreEls, _els, Thread, Subject, Body, __Els) @@ -26949,7 +31346,10 @@ decode_message_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"body">>, _attrs, _} = _el | _els], Thread, Subject, Body, __Els) -> case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:client">> -> + <<"">> + when __TopXMLNS == <<"jabber:server">>; + __TopXMLNS == <<"jabber:component:accept">>; + __TopXMLNS == <<"jabber:client">> -> decode_message_els(__TopXMLNS, __IgnoreEls, _els, Thread, Subject, [decode_message_body(__TopXMLNS, __IgnoreEls, _el) @@ -26962,6 +31362,20 @@ decode_message_els(__TopXMLNS, __IgnoreEls, __IgnoreEls, _el) | Body], __Els); + <<"jabber:server">> -> + decode_message_els(__TopXMLNS, __IgnoreEls, _els, + Thread, Subject, + [decode_message_body(<<"jabber:server">>, + __IgnoreEls, _el) + | Body], + __Els); + <<"jabber:component:accept">> -> + decode_message_els(__TopXMLNS, __IgnoreEls, _els, + Thread, Subject, + [decode_message_body(<<"jabber:component:accept">>, + __IgnoreEls, _el) + | Body], + __Els); _ -> decode_message_els(__TopXMLNS, __IgnoreEls, _els, Thread, Subject, Body, __Els) @@ -26973,11 +31387,11 @@ decode_message_els(__TopXMLNS, __IgnoreEls, decode_message_els(__TopXMLNS, __IgnoreEls, _els, Thread, Subject, Body, [_el | __Els]); true -> - case is_known_tag(_el) of + case is_known_tag(_el, __TopXMLNS) of true -> decode_message_els(__TopXMLNS, __IgnoreEls, _els, Thread, Subject, Body, - [decode(_el) | __Els]); + [decode(_el, __TopXMLNS, []) | __Els]); false -> decode_message_els(__TopXMLNS, __IgnoreEls, _els, Thread, Subject, Body, __Els) @@ -27027,33 +31441,45 @@ decode_message_attrs(__TopXMLNS, [], Id, Type, From, To, encode_message({message, Id, Type, Lang, From, To, Subject, Body, Thread, __Els}, - _xmlns_attrs) -> - _els = [encode(_el) || _el <- __Els] ++ + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"jabber:client">>, <<"jabber:server">>, + <<"jabber:component:accept">>], + __TopXMLNS), + _els = [encode(_el, __NewTopXMLNS) || _el <- __Els] ++ lists:reverse('encode_message_$thread'(Thread, + __NewTopXMLNS, 'encode_message_$subject'(Subject, + __NewTopXMLNS, 'encode_message_$body'(Body, + __NewTopXMLNS, [])))), _attrs = 'encode_message_attr_xml:lang'(Lang, encode_message_attr_to(To, encode_message_attr_from(From, encode_message_attr_type(Type, encode_message_attr_id(Id, - _xmlns_attrs))))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)))))), {xmlel, <<"message">>, _attrs, _els}. -'encode_message_$thread'(undefined, _acc) -> _acc; -'encode_message_$thread'(Thread, _acc) -> - [encode_message_thread(Thread, []) | _acc]. +'encode_message_$thread'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_message_$thread'(Thread, __TopXMLNS, _acc) -> + [encode_message_thread(Thread, __TopXMLNS) | _acc]. -'encode_message_$subject'([], _acc) -> _acc; -'encode_message_$subject'([Subject | _els], _acc) -> - 'encode_message_$subject'(_els, - [encode_message_subject(Subject, []) | _acc]). +'encode_message_$subject'([], __TopXMLNS, _acc) -> _acc; +'encode_message_$subject'([Subject | _els], __TopXMLNS, + _acc) -> + 'encode_message_$subject'(_els, __TopXMLNS, + [encode_message_subject(Subject, __TopXMLNS) + | _acc]). -'encode_message_$body'([], _acc) -> _acc; -'encode_message_$body'([Body | _els], _acc) -> - 'encode_message_$body'(_els, - [encode_message_body(Body, []) | _acc]). +'encode_message_$body'([], __TopXMLNS, _acc) -> _acc; +'encode_message_$body'([Body | _els], __TopXMLNS, + _acc) -> + 'encode_message_$body'(_els, __TopXMLNS, + [encode_message_body(Body, __TopXMLNS) | _acc]). decode_message_attr_id(__TopXMLNS, undefined) -> <<>>; decode_message_attr_id(__TopXMLNS, _val) -> _val. @@ -27135,9 +31561,13 @@ decode_message_thread_els(__TopXMLNS, __IgnoreEls, decode_message_thread_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_message_thread(Cdata, _xmlns_attrs) -> +encode_message_thread(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"jabber:client">>, <<"jabber:server">>, + <<"jabber:component:accept">>], + __TopXMLNS), _els = encode_message_thread_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"thread">>, _attrs, _els}. decode_message_thread_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -27176,10 +31606,15 @@ decode_message_body_attrs(__TopXMLNS, [_ | _attrs], decode_message_body_attrs(__TopXMLNS, [], Lang) -> 'decode_message_body_attr_xml:lang'(__TopXMLNS, Lang). -encode_message_body({text, Lang, Data}, _xmlns_attrs) -> +encode_message_body({text, Lang, Data}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"jabber:client">>, <<"jabber:server">>, + <<"jabber:component:accept">>], + __TopXMLNS), _els = encode_message_body_cdata(Data, []), _attrs = 'encode_message_body_attr_xml:lang'(Lang, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"body">>, _attrs, _els}. 'decode_message_body_attr_xml:lang'(__TopXMLNS, @@ -27230,10 +31665,15 @@ decode_message_subject_attrs(__TopXMLNS, [], Lang) -> Lang). encode_message_subject({text, Lang, Data}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"jabber:client">>, <<"jabber:server">>, + <<"jabber:component:accept">>], + __TopXMLNS), _els = encode_message_subject_cdata(Data, []), _attrs = 'encode_message_subject_attr_xml:lang'(Lang, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"subject">>, _attrs, _els}. 'decode_message_subject_attr_xml:lang'(__TopXMLNS, @@ -27273,10 +31713,10 @@ decode_iq_els(__TopXMLNS, __IgnoreEls, decode_iq_els(__TopXMLNS, __IgnoreEls, _els, [_el | __Els]); true -> - case is_known_tag(_el) of + case is_known_tag(_el, __TopXMLNS) of true -> decode_iq_els(__TopXMLNS, __IgnoreEls, _els, - [decode(_el) | __Els]); + [decode(_el, __TopXMLNS, []) | __Els]); false -> decode_iq_els(__TopXMLNS, __IgnoreEls, _els, __Els) end @@ -27321,14 +31761,19 @@ decode_iq_attrs(__TopXMLNS, [], Id, Type, From, To, 'decode_iq_attr_xml:lang'(__TopXMLNS, Lang)}. encode_iq({iq, Id, Type, Lang, From, To, __Els}, - _xmlns_attrs) -> - _els = [encode(_el) || _el <- __Els], + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<>>, + [<<"jabber:client">>, <<"jabber:server">>, + <<"jabber:component:accept">>], + __TopXMLNS), + _els = [encode(_el, __NewTopXMLNS) || _el <- __Els], _attrs = 'encode_iq_attr_xml:lang'(Lang, encode_iq_attr_to(To, encode_iq_attr_from(From, encode_iq_attr_type(Type, encode_iq_attr_id(Id, - _xmlns_attrs))))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)))))), {xmlel, <<"iq">>, _attrs, _els}. decode_iq_attr_id(__TopXMLNS, undefined) -> @@ -27425,15 +31870,20 @@ decode_stats_attrs(__TopXMLNS, [_ | _attrs], Node) -> decode_stats_attrs(__TopXMLNS, [], Node) -> decode_stats_attr_node(__TopXMLNS, Node). -encode_stats({stats, List, Node}, _xmlns_attrs) -> - _els = lists:reverse('encode_stats_$list'(List, [])), - _attrs = encode_stats_attr_node(Node, _xmlns_attrs), +encode_stats({stats, List, Node}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/stats">>, + [], __TopXMLNS), + _els = lists:reverse('encode_stats_$list'(List, + __NewTopXMLNS, [])), + _attrs = encode_stats_attr_node(Node, + enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS)), {xmlel, <<"query">>, _attrs, _els}. -'encode_stats_$list'([], _acc) -> _acc; -'encode_stats_$list'([List | _els], _acc) -> - 'encode_stats_$list'(_els, - [encode_stat(List, []) | _acc]). +'encode_stats_$list'([], __TopXMLNS, _acc) -> _acc; +'encode_stats_$list'([List | _els], __TopXMLNS, _acc) -> + 'encode_stats_$list'(_els, __TopXMLNS, + [encode_stat(List, __TopXMLNS) | _acc]). decode_stats_attr_node(__TopXMLNS, undefined) -> <<>>; decode_stats_attr_node(__TopXMLNS, _val) -> _val. @@ -27495,17 +31945,23 @@ decode_stat_attrs(__TopXMLNS, [], Name, Units, Value) -> decode_stat_attr_value(__TopXMLNS, Value)}. encode_stat({stat, Name, Units, Value, Error}, - _xmlns_attrs) -> - _els = lists:reverse('encode_stat_$error'(Error, [])), + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/stats">>, + [], __TopXMLNS), + _els = lists:reverse('encode_stat_$error'(Error, + __NewTopXMLNS, [])), _attrs = encode_stat_attr_value(Value, encode_stat_attr_units(Units, encode_stat_attr_name(Name, - _xmlns_attrs))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)))), {xmlel, <<"stat">>, _attrs, _els}. -'encode_stat_$error'(undefined, _acc) -> _acc; -'encode_stat_$error'(Error, _acc) -> - [encode_stat_error(Error, []) | _acc]. +'encode_stat_$error'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_stat_$error'(Error, __TopXMLNS, _acc) -> + [encode_stat_error(Error, __TopXMLNS) | _acc]. decode_stat_attr_name(__TopXMLNS, undefined) -> erlang:error({xmpp_codec, @@ -27559,10 +32015,14 @@ decode_stat_error_attrs(__TopXMLNS, [], Code) -> decode_stat_error_attr_code(__TopXMLNS, Code). encode_stat_error({stat_error, Code, Reason}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/stats">>, + [], __TopXMLNS), _els = encode_stat_error_cdata(Reason, []), _attrs = encode_stat_error_attr_code(Code, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"error">>, _attrs, _els}. decode_stat_error_attr_code(__TopXMLNS, undefined) -> @@ -27648,28 +32108,37 @@ decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, encode_bookmarks_storage({bookmark_storage, Conference, Url}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"storage:bookmarks">>, [], + __TopXMLNS), _els = lists:reverse('encode_bookmarks_storage_$conference'(Conference, + __NewTopXMLNS, 'encode_bookmarks_storage_$url'(Url, + __NewTopXMLNS, []))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"storage">>, _attrs, _els}. -'encode_bookmarks_storage_$conference'([], _acc) -> +'encode_bookmarks_storage_$conference'([], __TopXMLNS, + _acc) -> _acc; 'encode_bookmarks_storage_$conference'([Conference | _els], - _acc) -> - 'encode_bookmarks_storage_$conference'(_els, + __TopXMLNS, _acc) -> + 'encode_bookmarks_storage_$conference'(_els, __TopXMLNS, [encode_bookmark_conference(Conference, - []) + __TopXMLNS) | _acc]). -'encode_bookmarks_storage_$url'([], _acc) -> _acc; -'encode_bookmarks_storage_$url'([Url | _els], _acc) -> - 'encode_bookmarks_storage_$url'(_els, - [encode_bookmark_url(Url, []) | _acc]). +'encode_bookmarks_storage_$url'([], __TopXMLNS, _acc) -> + _acc; +'encode_bookmarks_storage_$url'([Url | _els], + __TopXMLNS, _acc) -> + 'encode_bookmarks_storage_$url'(_els, __TopXMLNS, + [encode_bookmark_url(Url, __TopXMLNS) + | _acc]). decode_bookmark_url(__TopXMLNS, __IgnoreEls, {xmlel, <<"url">>, _attrs, _els}) -> @@ -27694,11 +32163,15 @@ decode_bookmark_url_attrs(__TopXMLNS, [], Name, Url) -> decode_bookmark_url_attr_url(__TopXMLNS, Url)}. encode_bookmark_url({bookmark_url, Name, Url}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"storage:bookmarks">>, [], + __TopXMLNS), _els = [], _attrs = encode_bookmark_url_attr_url(Url, encode_bookmark_url_attr_name(Name, - _xmlns_attrs)), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))), {xmlel, <<"url">>, _attrs, _els}. decode_bookmark_url_attr_name(__TopXMLNS, undefined) -> @@ -27807,29 +32280,38 @@ decode_bookmark_conference_attrs(__TopXMLNS, [], Name, encode_bookmark_conference({bookmark_conference, Name, Jid, Autojoin, Nick, Password}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"storage:bookmarks">>, [], + __TopXMLNS), _els = lists:reverse('encode_bookmark_conference_$password'(Password, + __NewTopXMLNS, 'encode_bookmark_conference_$nick'(Nick, + __NewTopXMLNS, []))), _attrs = encode_bookmark_conference_attr_autojoin(Autojoin, encode_bookmark_conference_attr_jid(Jid, encode_bookmark_conference_attr_name(Name, - _xmlns_attrs))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)))), {xmlel, <<"conference">>, _attrs, _els}. 'encode_bookmark_conference_$password'(undefined, - _acc) -> + __TopXMLNS, _acc) -> _acc; 'encode_bookmark_conference_$password'(Password, - _acc) -> - [encode_conference_password(Password, []) | _acc]. + __TopXMLNS, _acc) -> + [encode_conference_password(Password, __TopXMLNS) + | _acc]. -'encode_bookmark_conference_$nick'(undefined, _acc) -> +'encode_bookmark_conference_$nick'(undefined, + __TopXMLNS, _acc) -> _acc; -'encode_bookmark_conference_$nick'(Nick, _acc) -> - [encode_conference_nick(Nick, []) | _acc]. +'encode_bookmark_conference_$nick'(Nick, __TopXMLNS, + _acc) -> + [encode_conference_nick(Nick, __TopXMLNS) | _acc]. decode_bookmark_conference_attr_name(__TopXMLNS, undefined) -> @@ -27896,9 +32378,12 @@ decode_conference_password_els(__TopXMLNS, __IgnoreEls, decode_conference_password_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_conference_password(Cdata, _xmlns_attrs) -> +encode_conference_password(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"storage:bookmarks">>, [], + __TopXMLNS), _els = encode_conference_password_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"password">>, _attrs, _els}. decode_conference_password_cdata(__TopXMLNS, <<>>) -> @@ -27928,9 +32413,12 @@ decode_conference_nick_els(__TopXMLNS, __IgnoreEls, decode_conference_nick_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_conference_nick(Cdata, _xmlns_attrs) -> +encode_conference_nick(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"storage:bookmarks">>, [], + __TopXMLNS), _els = encode_conference_nick_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"nick">>, _attrs, _els}. decode_conference_nick_cdata(__TopXMLNS, <<>>) -> <<>>; @@ -27958,9 +32446,12 @@ decode_private_els(__TopXMLNS, __IgnoreEls, [_ | _els], decode_private_els(__TopXMLNS, __IgnoreEls, _els, __Xmls). -encode_private({private, __Xmls}, _xmlns_attrs) -> +encode_private({private, __Xmls}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:private">>, [], + __TopXMLNS), _els = __Xmls, - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"query">>, _attrs, _els}. decode_disco_items(__TopXMLNS, __IgnoreEls, @@ -28024,24 +32515,32 @@ decode_disco_items_attrs(__TopXMLNS, [], Node) -> decode_disco_items_attr_node(__TopXMLNS, Node). encode_disco_items({disco_items, Node, Items, Rsm}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/disco#items">>, + [], __TopXMLNS), _els = lists:reverse('encode_disco_items_$items'(Items, + __NewTopXMLNS, 'encode_disco_items_$rsm'(Rsm, + __NewTopXMLNS, []))), _attrs = encode_disco_items_attr_node(Node, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"query">>, _attrs, _els}. -'encode_disco_items_$items'([], _acc) -> _acc; -'encode_disco_items_$items'([Items | _els], _acc) -> - 'encode_disco_items_$items'(_els, - [encode_disco_item(Items, []) | _acc]). +'encode_disco_items_$items'([], __TopXMLNS, _acc) -> + _acc; +'encode_disco_items_$items'([Items | _els], __TopXMLNS, + _acc) -> + 'encode_disco_items_$items'(_els, __TopXMLNS, + [encode_disco_item(Items, __TopXMLNS) | _acc]). -'encode_disco_items_$rsm'(undefined, _acc) -> _acc; -'encode_disco_items_$rsm'(Rsm, _acc) -> - [encode_rsm_set(Rsm, - [{<<"xmlns">>, <<"http://jabber.org/protocol/rsm">>}]) - | _acc]. +'encode_disco_items_$rsm'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_disco_items_$rsm'(Rsm, __TopXMLNS, _acc) -> + [encode_rsm_set(Rsm, __TopXMLNS) | _acc]. decode_disco_items_attr_node(__TopXMLNS, undefined) -> <<>>; @@ -28081,12 +32580,16 @@ decode_disco_item_attrs(__TopXMLNS, [], Jid, Name, decode_disco_item_attr_node(__TopXMLNS, Node)}. encode_disco_item({disco_item, Jid, Name, Node}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/disco#items">>, + [], __TopXMLNS), _els = [], _attrs = encode_disco_item_attr_node(Node, encode_disco_item_attr_name(Name, encode_disco_item_attr_jid(Jid, - _xmlns_attrs))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)))), {xmlel, <<"item">>, _attrs, _els}. decode_disco_item_attr_jid(__TopXMLNS, undefined) -> @@ -28208,34 +32711,44 @@ decode_disco_info_attrs(__TopXMLNS, [], Node) -> encode_disco_info({disco_info, Node, Identities, Features, Xdata}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/disco#info">>, + [], __TopXMLNS), _els = lists:reverse('encode_disco_info_$xdata'(Xdata, + __NewTopXMLNS, 'encode_disco_info_$features'(Features, + __NewTopXMLNS, 'encode_disco_info_$identities'(Identities, + __NewTopXMLNS, [])))), _attrs = encode_disco_info_attr_node(Node, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"query">>, _attrs, _els}. -'encode_disco_info_$xdata'([], _acc) -> _acc; -'encode_disco_info_$xdata'([Xdata | _els], _acc) -> - 'encode_disco_info_$xdata'(_els, - [encode_xdata(Xdata, - [{<<"xmlns">>, - <<"jabber:x:data">>}]) - | _acc]). +'encode_disco_info_$xdata'([], __TopXMLNS, _acc) -> + _acc; +'encode_disco_info_$xdata'([Xdata | _els], __TopXMLNS, + _acc) -> + 'encode_disco_info_$xdata'(_els, __TopXMLNS, + [encode_xdata(Xdata, __TopXMLNS) | _acc]). -'encode_disco_info_$features'([], _acc) -> _acc; +'encode_disco_info_$features'([], __TopXMLNS, _acc) -> + _acc; 'encode_disco_info_$features'([Features | _els], - _acc) -> - 'encode_disco_info_$features'(_els, - [encode_disco_feature(Features, []) | _acc]). + __TopXMLNS, _acc) -> + 'encode_disco_info_$features'(_els, __TopXMLNS, + [encode_disco_feature(Features, __TopXMLNS) + | _acc]). -'encode_disco_info_$identities'([], _acc) -> _acc; +'encode_disco_info_$identities'([], __TopXMLNS, _acc) -> + _acc; 'encode_disco_info_$identities'([Identities | _els], - _acc) -> - 'encode_disco_info_$identities'(_els, - [encode_disco_identity(Identities, []) + __TopXMLNS, _acc) -> + 'encode_disco_info_$identities'(_els, __TopXMLNS, + [encode_disco_identity(Identities, + __TopXMLNS) | _acc]). decode_disco_info_attr_node(__TopXMLNS, undefined) -> @@ -28261,10 +32774,14 @@ decode_disco_feature_attrs(__TopXMLNS, [_ | _attrs], decode_disco_feature_attrs(__TopXMLNS, [], Var) -> decode_disco_feature_attr_var(__TopXMLNS, Var). -encode_disco_feature(Var, _xmlns_attrs) -> +encode_disco_feature(Var, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/disco#info">>, + [], __TopXMLNS), _els = [], _attrs = encode_disco_feature_attr_var(Var, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"feature">>, _attrs, _els}. decode_disco_feature_attr_var(__TopXMLNS, undefined) -> @@ -28316,13 +32833,17 @@ decode_disco_identity_attrs(__TopXMLNS, [], Category, encode_disco_identity({identity, Category, Type, Lang, Name}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"http://jabber.org/protocol/disco#info">>, + [], __TopXMLNS), _els = [], _attrs = encode_disco_identity_attr_name(Name, 'encode_disco_identity_attr_xml:lang'(Lang, encode_disco_identity_attr_type(Type, encode_disco_identity_attr_category(Category, - _xmlns_attrs)))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))))), {xmlel, <<"identity">>, _attrs, _els}. decode_disco_identity_attr_category(__TopXMLNS, @@ -28399,16 +32920,21 @@ decode_block_list_els(__TopXMLNS, __IgnoreEls, decode_block_list_els(__TopXMLNS, __IgnoreEls, _els, Items). -encode_block_list({block_list, Items}, _xmlns_attrs) -> +encode_block_list({block_list, Items}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:xmpp:blocking">>, [], + __TopXMLNS), _els = lists:reverse('encode_block_list_$items'(Items, - [])), - _attrs = _xmlns_attrs, + __NewTopXMLNS, [])), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"blocklist">>, _attrs, _els}. -'encode_block_list_$items'([], _acc) -> _acc; -'encode_block_list_$items'([Items | _els], _acc) -> - 'encode_block_list_$items'(_els, - [encode_block_item(Items, []) | _acc]). +'encode_block_list_$items'([], __TopXMLNS, _acc) -> + _acc; +'encode_block_list_$items'([Items | _els], __TopXMLNS, + _acc) -> + 'encode_block_list_$items'(_els, __TopXMLNS, + [encode_block_item(Items, __TopXMLNS) | _acc]). decode_unblock(__TopXMLNS, __IgnoreEls, {xmlel, <<"unblock">>, _attrs, _els}) -> @@ -28439,16 +32965,20 @@ decode_unblock_els(__TopXMLNS, __IgnoreEls, [_ | _els], decode_unblock_els(__TopXMLNS, __IgnoreEls, _els, Items). -encode_unblock({unblock, Items}, _xmlns_attrs) -> +encode_unblock({unblock, Items}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:xmpp:blocking">>, [], + __TopXMLNS), _els = lists:reverse('encode_unblock_$items'(Items, - [])), - _attrs = _xmlns_attrs, + __NewTopXMLNS, [])), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"unblock">>, _attrs, _els}. -'encode_unblock_$items'([], _acc) -> _acc; -'encode_unblock_$items'([Items | _els], _acc) -> - 'encode_unblock_$items'(_els, - [encode_block_item(Items, []) | _acc]). +'encode_unblock_$items'([], __TopXMLNS, _acc) -> _acc; +'encode_unblock_$items'([Items | _els], __TopXMLNS, + _acc) -> + 'encode_unblock_$items'(_els, __TopXMLNS, + [encode_block_item(Items, __TopXMLNS) | _acc]). decode_block(__TopXMLNS, __IgnoreEls, {xmlel, <<"block">>, _attrs, _els}) -> @@ -28477,15 +33007,20 @@ decode_block_els(__TopXMLNS, __IgnoreEls, [_ | _els], Items) -> decode_block_els(__TopXMLNS, __IgnoreEls, _els, Items). -encode_block({block, Items}, _xmlns_attrs) -> - _els = lists:reverse('encode_block_$items'(Items, [])), - _attrs = _xmlns_attrs, +encode_block({block, Items}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:xmpp:blocking">>, [], + __TopXMLNS), + _els = lists:reverse('encode_block_$items'(Items, + __NewTopXMLNS, [])), + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"block">>, _attrs, _els}. -'encode_block_$items'([], _acc) -> _acc; -'encode_block_$items'([Items | _els], _acc) -> - 'encode_block_$items'(_els, - [encode_block_item(Items, []) | _acc]). +'encode_block_$items'([], __TopXMLNS, _acc) -> _acc; +'encode_block_$items'([Items | _els], __TopXMLNS, + _acc) -> + 'encode_block_$items'(_els, __TopXMLNS, + [encode_block_item(Items, __TopXMLNS) | _acc]). decode_block_item(__TopXMLNS, __IgnoreEls, {xmlel, <<"item">>, _attrs, _els}) -> @@ -28502,9 +33037,14 @@ decode_block_item_attrs(__TopXMLNS, [_ | _attrs], decode_block_item_attrs(__TopXMLNS, [], Jid) -> decode_block_item_attr_jid(__TopXMLNS, Jid). -encode_block_item(Jid, _xmlns_attrs) -> +encode_block_item(Jid, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:xmpp:blocking">>, [], + __TopXMLNS), _els = [], - _attrs = encode_block_item_attr_jid(Jid, _xmlns_attrs), + _attrs = encode_block_item_attr_jid(Jid, + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"item">>, _attrs, _els}. decode_block_item_attr_jid(__TopXMLNS, undefined) -> @@ -28592,26 +33132,37 @@ decode_privacy_els(__TopXMLNS, __IgnoreEls, [_ | _els], Default, Active). encode_privacy({privacy_query, Lists, Default, Active}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:privacy">>, [], + __TopXMLNS), _els = lists:reverse('encode_privacy_$lists'(Lists, + __NewTopXMLNS, 'encode_privacy_$default'(Default, + __NewTopXMLNS, 'encode_privacy_$active'(Active, + __NewTopXMLNS, [])))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"query">>, _attrs, _els}. -'encode_privacy_$lists'([], _acc) -> _acc; -'encode_privacy_$lists'([Lists | _els], _acc) -> - 'encode_privacy_$lists'(_els, - [encode_privacy_list(Lists, []) | _acc]). +'encode_privacy_$lists'([], __TopXMLNS, _acc) -> _acc; +'encode_privacy_$lists'([Lists | _els], __TopXMLNS, + _acc) -> + 'encode_privacy_$lists'(_els, __TopXMLNS, + [encode_privacy_list(Lists, __TopXMLNS) | _acc]). -'encode_privacy_$default'(undefined, _acc) -> _acc; -'encode_privacy_$default'(Default, _acc) -> - [encode_privacy_default_list(Default, []) | _acc]. +'encode_privacy_$default'(undefined, __TopXMLNS, + _acc) -> + _acc; +'encode_privacy_$default'(Default, __TopXMLNS, _acc) -> + [encode_privacy_default_list(Default, __TopXMLNS) + | _acc]. -'encode_privacy_$active'(undefined, _acc) -> _acc; -'encode_privacy_$active'(Active, _acc) -> - [encode_privacy_active_list(Active, []) | _acc]. +'encode_privacy_$active'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_privacy_$active'(Active, __TopXMLNS, _acc) -> + [encode_privacy_active_list(Active, __TopXMLNS) | _acc]. decode_privacy_active_list(__TopXMLNS, __IgnoreEls, {xmlel, <<"active">>, _attrs, _els}) -> @@ -28631,10 +33182,14 @@ decode_privacy_active_list_attrs(__TopXMLNS, [], Name) -> decode_privacy_active_list_attr_name(__TopXMLNS, Name). -encode_privacy_active_list(Name, _xmlns_attrs) -> +encode_privacy_active_list(Name, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:privacy">>, [], + __TopXMLNS), _els = [], _attrs = encode_privacy_active_list_attr_name(Name, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"active">>, _attrs, _els}. decode_privacy_active_list_attr_name(__TopXMLNS, @@ -28667,10 +33222,14 @@ decode_privacy_default_list_attrs(__TopXMLNS, [], Name) -> decode_privacy_default_list_attr_name(__TopXMLNS, Name). -encode_privacy_default_list(Name, _xmlns_attrs) -> +encode_privacy_default_list(Name, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:privacy">>, [], + __TopXMLNS), _els = [], _attrs = encode_privacy_default_list_attr_name(Name, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"default">>, _attrs, _els}. decode_privacy_default_list_attr_name(__TopXMLNS, @@ -28728,17 +33287,24 @@ decode_privacy_list_attrs(__TopXMLNS, [], Name) -> decode_privacy_list_attr_name(__TopXMLNS, Name). encode_privacy_list({privacy_list, Name, Items}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:privacy">>, [], + __TopXMLNS), _els = lists:reverse('encode_privacy_list_$items'(Items, - [])), + __NewTopXMLNS, [])), _attrs = encode_privacy_list_attr_name(Name, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"list">>, _attrs, _els}. -'encode_privacy_list_$items'([], _acc) -> _acc; -'encode_privacy_list_$items'([Items | _els], _acc) -> - 'encode_privacy_list_$items'(_els, - [encode_privacy_item(Items, []) | _acc]). +'encode_privacy_list_$items'([], __TopXMLNS, _acc) -> + _acc; +'encode_privacy_list_$items'([Items | _els], __TopXMLNS, + _acc) -> + 'encode_privacy_list_$items'(_els, __TopXMLNS, + [encode_privacy_item(Items, __TopXMLNS) + | _acc]). decode_privacy_list_attr_name(__TopXMLNS, undefined) -> erlang:error({xmpp_codec, @@ -28876,36 +33442,54 @@ decode_privacy_item_attrs(__TopXMLNS, [], Action, Order, encode_privacy_item({privacy_item, Order, Action, Type, Value, Message, Iq, Presence_in, Presence_out}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:privacy">>, [], + __TopXMLNS), _els = lists:reverse('encode_privacy_item_$iq'(Iq, + __NewTopXMLNS, 'encode_privacy_item_$presence_out'(Presence_out, + __NewTopXMLNS, 'encode_privacy_item_$message'(Message, + __NewTopXMLNS, 'encode_privacy_item_$presence_in'(Presence_in, + __NewTopXMLNS, []))))), _attrs = encode_privacy_item_attr_value(Value, encode_privacy_item_attr_type(Type, encode_privacy_item_attr_order(Order, encode_privacy_item_attr_action(Action, - _xmlns_attrs)))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))))), {xmlel, <<"item">>, _attrs, _els}. -'encode_privacy_item_$iq'(false, _acc) -> _acc; -'encode_privacy_item_$iq'(Iq, _acc) -> - [encode_privacy_iq(Iq, []) | _acc]. +'encode_privacy_item_$iq'(false, __TopXMLNS, _acc) -> + _acc; +'encode_privacy_item_$iq'(Iq, __TopXMLNS, _acc) -> + [encode_privacy_iq(Iq, __TopXMLNS) | _acc]. -'encode_privacy_item_$presence_out'(false, _acc) -> +'encode_privacy_item_$presence_out'(false, __TopXMLNS, + _acc) -> _acc; 'encode_privacy_item_$presence_out'(Presence_out, - _acc) -> - [encode_privacy_presence_out(Presence_out, []) | _acc]. + __TopXMLNS, _acc) -> + [encode_privacy_presence_out(Presence_out, __TopXMLNS) + | _acc]. -'encode_privacy_item_$message'(false, _acc) -> _acc; -'encode_privacy_item_$message'(Message, _acc) -> - [encode_privacy_message(Message, []) | _acc]. +'encode_privacy_item_$message'(false, __TopXMLNS, + _acc) -> + _acc; +'encode_privacy_item_$message'(Message, __TopXMLNS, + _acc) -> + [encode_privacy_message(Message, __TopXMLNS) | _acc]. -'encode_privacy_item_$presence_in'(false, _acc) -> _acc; -'encode_privacy_item_$presence_in'(Presence_in, _acc) -> - [encode_privacy_presence_in(Presence_in, []) | _acc]. +'encode_privacy_item_$presence_in'(false, __TopXMLNS, + _acc) -> + _acc; +'encode_privacy_item_$presence_in'(Presence_in, + __TopXMLNS, _acc) -> + [encode_privacy_presence_in(Presence_in, __TopXMLNS) + | _acc]. decode_privacy_item_attr_action(__TopXMLNS, undefined) -> @@ -28964,36 +33548,48 @@ decode_privacy_presence_out(__TopXMLNS, __IgnoreEls, {xmlel, <<"presence-out">>, _attrs, _els}) -> true. -encode_privacy_presence_out(true, _xmlns_attrs) -> +encode_privacy_presence_out(true, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:privacy">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"presence-out">>, _attrs, _els}. decode_privacy_presence_in(__TopXMLNS, __IgnoreEls, {xmlel, <<"presence-in">>, _attrs, _els}) -> true. -encode_privacy_presence_in(true, _xmlns_attrs) -> +encode_privacy_presence_in(true, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:privacy">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"presence-in">>, _attrs, _els}. decode_privacy_iq(__TopXMLNS, __IgnoreEls, {xmlel, <<"iq">>, _attrs, _els}) -> true. -encode_privacy_iq(true, _xmlns_attrs) -> +encode_privacy_iq(true, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:privacy">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"iq">>, _attrs, _els}. decode_privacy_message(__TopXMLNS, __IgnoreEls, {xmlel, <<"message">>, _attrs, _els}) -> true. -encode_privacy_message(true, _xmlns_attrs) -> +encode_privacy_message(true, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:privacy">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"message">>, _attrs, _els}. decode_rosterver_feature(__TopXMLNS, __IgnoreEls, @@ -29001,9 +33597,12 @@ decode_rosterver_feature(__TopXMLNS, __IgnoreEls, {rosterver_feature}. encode_rosterver_feature({rosterver_feature}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"urn:xmpp:features:rosterver">>, [], + __TopXMLNS), _els = [], - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"ver">>, _attrs, _els}. decode_roster_query(__TopXMLNS, __IgnoreEls, @@ -29049,17 +33648,23 @@ decode_roster_query_attrs(__TopXMLNS, [], Ver) -> decode_roster_query_attr_ver(__TopXMLNS, Ver). encode_roster_query({roster_query, Items, Ver}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:roster">>, + [], __TopXMLNS), _els = lists:reverse('encode_roster_query_$items'(Items, - [])), + __NewTopXMLNS, [])), _attrs = encode_roster_query_attr_ver(Ver, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"query">>, _attrs, _els}. -'encode_roster_query_$items'([], _acc) -> _acc; -'encode_roster_query_$items'([Items | _els], _acc) -> - 'encode_roster_query_$items'(_els, - [encode_roster_item(Items, []) | _acc]). +'encode_roster_query_$items'([], __TopXMLNS, _acc) -> + _acc; +'encode_roster_query_$items'([Items | _els], __TopXMLNS, + _acc) -> + 'encode_roster_query_$items'(_els, __TopXMLNS, + [encode_roster_item(Items, __TopXMLNS) + | _acc]). decode_roster_query_attr_ver(__TopXMLNS, undefined) -> undefined; @@ -29138,20 +33743,27 @@ decode_roster_item_attrs(__TopXMLNS, [], Jid, Name, encode_roster_item({roster_item, Jid, Name, Groups, Subscription, Ask}, - _xmlns_attrs) -> + __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:roster">>, + [], __TopXMLNS), _els = - lists:reverse('encode_roster_item_$groups'(Groups, [])), + lists:reverse('encode_roster_item_$groups'(Groups, + __NewTopXMLNS, [])), _attrs = encode_roster_item_attr_ask(Ask, encode_roster_item_attr_subscription(Subscription, encode_roster_item_attr_name(Name, encode_roster_item_attr_jid(Jid, - _xmlns_attrs)))), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS))))), {xmlel, <<"item">>, _attrs, _els}. -'encode_roster_item_$groups'([], _acc) -> _acc; -'encode_roster_item_$groups'([Groups | _els], _acc) -> - 'encode_roster_item_$groups'(_els, - [encode_roster_group(Groups, []) | _acc]). +'encode_roster_item_$groups'([], __TopXMLNS, _acc) -> + _acc; +'encode_roster_item_$groups'([Groups | _els], + __TopXMLNS, _acc) -> + 'encode_roster_item_$groups'(_els, __TopXMLNS, + [encode_roster_group(Groups, __TopXMLNS) + | _acc]). decode_roster_item_attr_jid(__TopXMLNS, undefined) -> erlang:error({xmpp_codec, @@ -29227,9 +33839,11 @@ decode_roster_group_els(__TopXMLNS, __IgnoreEls, decode_roster_group_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_roster_group(Cdata, _xmlns_attrs) -> +encode_roster_group(Cdata, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:roster">>, + [], __TopXMLNS), _els = encode_roster_group_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"group">>, _attrs, _els}. decode_roster_group_cdata(__TopXMLNS, <<>>) -> @@ -29306,26 +33920,34 @@ decode_version_els(__TopXMLNS, __IgnoreEls, [_ | _els], decode_version_els(__TopXMLNS, __IgnoreEls, _els, Ver, Os, Name). -encode_version({version, Name, Ver, Os}, - _xmlns_attrs) -> +encode_version({version, Name, Ver, Os}, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:version">>, [], + __TopXMLNS), _els = lists:reverse('encode_version_$ver'(Ver, + __NewTopXMLNS, 'encode_version_$os'(Os, + __NewTopXMLNS, 'encode_version_$name'(Name, + __NewTopXMLNS, [])))), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"query">>, _attrs, _els}. -'encode_version_$ver'(undefined, _acc) -> _acc; -'encode_version_$ver'(Ver, _acc) -> - [encode_version_ver(Ver, []) | _acc]. +'encode_version_$ver'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_version_$ver'(Ver, __TopXMLNS, _acc) -> + [encode_version_ver(Ver, __TopXMLNS) | _acc]. -'encode_version_$os'(undefined, _acc) -> _acc; -'encode_version_$os'(Os, _acc) -> - [encode_version_os(Os, []) | _acc]. +'encode_version_$os'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_version_$os'(Os, __TopXMLNS, _acc) -> + [encode_version_os(Os, __TopXMLNS) | _acc]. -'encode_version_$name'(undefined, _acc) -> _acc; -'encode_version_$name'(Name, _acc) -> - [encode_version_name(Name, []) | _acc]. +'encode_version_$name'(undefined, __TopXMLNS, _acc) -> + _acc; +'encode_version_$name'(Name, __TopXMLNS, _acc) -> + [encode_version_name(Name, __TopXMLNS) | _acc]. decode_version_os(__TopXMLNS, __IgnoreEls, {xmlel, <<"os">>, _attrs, _els}) -> @@ -29345,9 +33967,12 @@ decode_version_os_els(__TopXMLNS, __IgnoreEls, decode_version_os_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_version_os(Cdata, _xmlns_attrs) -> +encode_version_os(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:version">>, [], + __TopXMLNS), _els = encode_version_os_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"os">>, _attrs, _els}. decode_version_os_cdata(__TopXMLNS, <<>>) -> @@ -29376,9 +34001,12 @@ decode_version_ver_els(__TopXMLNS, __IgnoreEls, decode_version_ver_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_version_ver(Cdata, _xmlns_attrs) -> +encode_version_ver(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:version">>, [], + __TopXMLNS), _els = encode_version_ver_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"version">>, _attrs, _els}. decode_version_ver_cdata(__TopXMLNS, <<>>) -> @@ -29407,9 +34035,12 @@ decode_version_name_els(__TopXMLNS, __IgnoreEls, decode_version_name_els(__TopXMLNS, __IgnoreEls, _els, Cdata). -encode_version_name(Cdata, _xmlns_attrs) -> +encode_version_name(Cdata, __TopXMLNS) -> + __NewTopXMLNS = + choose_top_xmlns(<<"jabber:iq:version">>, [], + __TopXMLNS), _els = encode_version_name_cdata(Cdata, []), - _attrs = _xmlns_attrs, + _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), {xmlel, <<"name">>, _attrs, _els}. decode_version_name_cdata(__TopXMLNS, <<>>) -> @@ -29446,10 +34077,13 @@ decode_last_attrs(__TopXMLNS, [_ | _attrs], Seconds) -> decode_last_attrs(__TopXMLNS, [], Seconds) -> decode_last_attr_seconds(__TopXMLNS, Seconds). -encode_last({last, Seconds, Status}, _xmlns_attrs) -> +encode_last({last, Seconds, Status}, __TopXMLNS) -> + __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:last">>, + [], __TopXMLNS), _els = encode_last_cdata(Status, []), _attrs = encode_last_attr_seconds(Seconds, - _xmlns_attrs), + enc_xmlns_attrs(__NewTopXMLNS, + __TopXMLNS)), {xmlel, <<"query">>, _attrs, _els}. decode_last_attr_seconds(__TopXMLNS, undefined) -> diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index 063f51bd1..4c63bf295 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -11,7 +11,7 @@ -compile(export_all). -import(suite, [init_config/1, connect/1, disconnect/1, - recv/0, send/2, send_recv/2, my_jid/1, server_jid/1, + recv/1, send/2, send_recv/2, my_jid/1, server_jid/1, pubsub_jid/1, proxy_jid/1, muc_jid/1, muc_room_jid/1, mix_jid/1, mix_room_jid/1, get_features/2, re_register/1, is_feature_advertised/2, subscribe_to_events/1, @@ -974,7 +974,7 @@ sm_resume(Config) -> Txt = #text{data = <<"body">>}, Msg = #message{from = ServerJID, to = MyJID, body = [Txt]}, %% Route message. The message should be queued by the C2S process. - ejabberd_router:route(ServerJID, MyJID, xmpp_codec:encode(Msg)), + ejabberd_router:route(ServerJID, MyJID, Msg), send(Config, #sm_resume{previd = ID, h = 0, xmlns = ?NS_STREAM_MGMT_3}), ?recv1(#sm_resumed{previd = ID, h = 3}), ?recv1(#message{from = ServerJID, to = MyJID, body = [Txt]}), @@ -1001,7 +1001,7 @@ private(Config) -> <<"some.conference.org">>, <<>>)}, Storage = #bookmark_storage{conference = [Conference]}, - StorageXMLOut = xmpp_codec:encode(Storage), + StorageXMLOut = xmpp:encode(Storage), WrongEl = #xmlel{name = <<"wrong">>}, #iq{type = error} = send_recv(Config, #iq{type = get, @@ -1015,9 +1015,9 @@ private(Config) -> send_recv( Config, #iq{type = get, - sub_els = [#private{xml_els = [xmpp_codec:encode( + sub_els = [#private{xml_els = [xmpp:encode( #bookmark_storage{})]}]}), - Storage = xmpp_codec:decode(StorageXMLIn), + Storage = xmpp:decode(StorageXMLIn), disconnect(Config). last(Config) -> @@ -1221,7 +1221,7 @@ pubsub(Config) -> ItemID = randoms:get_string(), Node = <<"presence!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>, Item = #ps_item{id = ItemID, - xml_els = [xmpp_codec:encode(#presence{})]}, + xml_els = [xmpp:encode(#presence{})]}, #iq{type = result, sub_els = [#pubsub{publish = #ps_publish{ node = Node, @@ -1320,10 +1320,10 @@ mix_master(Config) -> ?recv2(#iq{type = result, id = I0, sub_els = [#mix_join{subscribe = Nodes, jid = MyBareJID}]}, #message{from = Room}), - #mix_participant{jid = MyBareJID} = xmpp_codec:decode(PXML), + #mix_participant{jid = MyBareJID} = xmpp:decode(PXML), %% Coming online PresenceID = randoms:get_string(), - Presence = xmpp_codec:encode(#presence{}), + Presence = xmpp:encode(#presence{}), I1 = send( Config, #iq{type = set, to = Room, @@ -1355,7 +1355,7 @@ mix_master(Config) -> sub_els = [#ps_event{ items = #ps_items{ node = ?NS_MIX_NODES_PRESENCE, - retract = PresenceID}}]} = recv(), + retract = PresenceID}}]} = recv(Config), %% Leaving I2 = send(Config, #iq{type = set, to = Room, sub_els = [#mix_leave{}]}), ?recv2(#iq{type = result, id = I2, sub_els = []}, @@ -2367,7 +2367,7 @@ mam_query_all(Config, NS) -> _ -> set end, I = send(Config, #iq{type = Type, sub_els = [#mam_query{xmlns = NS, id = QID}]}), - maybe_recv_iq_result(NS, I), + maybe_recv_iq_result(Config, NS, I), Iter = if NS == ?NS_MAM_TMP -> lists:seq(1, 5); true -> lists:seq(1, 5) ++ lists:seq(1, 5) end, @@ -2408,7 +2408,7 @@ mam_query_with(Config, JID, NS) -> Iter = if NS == ?NS_MAM_TMP -> lists:seq(1, 5); true -> lists:seq(1, 5) ++ lists:seq(1, 5) end, - maybe_recv_iq_result(NS, I), + maybe_recv_iq_result(Config, NS, I), lists:foreach( fun(N) -> Text = #text{data = integer_to_binary(N)}, @@ -2430,9 +2430,9 @@ mam_query_with(Config, JID, NS) -> ?recv1(#message{sub_els = [#mam_fin{complete = true}]}) end. -maybe_recv_iq_result(?NS_MAM_0, I1) -> +maybe_recv_iq_result(Config, ?NS_MAM_0, I1) -> ?recv1(#iq{type = result, id = I1}); -maybe_recv_iq_result(_, _) -> +maybe_recv_iq_result(_, _, _) -> ok. mam_query_rsm(Config, NS) -> @@ -2446,7 +2446,7 @@ mam_query_rsm(Config, NS) -> I1 = send(Config, #iq{type = Type, sub_els = [#mam_query{xmlns = NS, rsm = #rsm_set{max = 3}}]}), - maybe_recv_iq_result(NS, I1), + maybe_recv_iq_result(Config, NS, I1), lists:foreach( fun(N) -> Text = #text{data = integer_to_binary(N)}, @@ -2478,7 +2478,7 @@ mam_query_rsm(Config, NS) -> sub_els = [#mam_query{xmlns = NS, rsm = #rsm_set{max = 2, 'after' = Last}}]}), - maybe_recv_iq_result(NS, I2), + maybe_recv_iq_result(Config, NS, I2), lists:foreach( fun(N) -> Text = #text{data = integer_to_binary(N)}, @@ -2515,7 +2515,7 @@ mam_query_rsm(Config, NS) -> sub_els = [#mam_query{xmlns = NS, rsm = #rsm_set{max = 3, before = First}}]}), - maybe_recv_iq_result(NS, I3), + maybe_recv_iq_result(Config, NS, I3), lists:foreach( fun(N) -> Text = #text{data = integer_to_binary(N)}, @@ -2544,7 +2544,7 @@ mam_query_rsm(Config, NS) -> #iq{type = Type, sub_els = [#mam_query{xmlns = NS, rsm = #rsm_set{max = 0}}]}), - maybe_recv_iq_result(NS, I4), + maybe_recv_iq_result(Config, NS, I4), if NS == ?NS_MAM_TMP -> ?recv1(#iq{type = result, id = I4, sub_els = [#mam_query{ @@ -2566,7 +2566,7 @@ mam_query_rsm(Config, NS) -> sub_els = [#mam_query{xmlns = NS, rsm = #rsm_set{max = 2, before = <<"">>}}]}), - maybe_recv_iq_result(NS, I5), + maybe_recv_iq_result(Config, NS, I5), lists:foreach( fun(N) -> Text = #text{data = integer_to_binary(N)}, @@ -2598,7 +2598,7 @@ client_state_master(Config) -> ChatState = #message{to = Peer, thread = <<"1">>, sub_els = [#chatstate{type = active}]}, Message = ChatState#message{body = [#text{data = <<"body">>}]}, - PepPayload = xmpp_codec:encode(#presence{}), + PepPayload = xmpp:encode(#presence{}), PepOne = #message{ to = Peer, sub_els = @@ -2661,7 +2661,7 @@ client_state_slave(Config) -> items = [#ps_item{ id = <<"pep-1">>}]}}, - #delay{}]} = recv(), + #delay{}]} = recv(Config), #message{ from = Peer, sub_els = @@ -2672,7 +2672,7 @@ client_state_slave(Config) -> items = [#ps_item{ id = <<"pep-2">>}]}}, - #delay{}]} = recv(), + #delay{}]} = recv(Config), ?recv1(#message{from = Peer, thread = <<"1">>, sub_els = [#chatstate{type = composing}, #delay{}]}), diff --git a/test/suite.erl b/test/suite.erl index e4be0054f..e10c7e0c4 100644 --- a/test/suite.erl +++ b/test/suite.erl @@ -184,11 +184,11 @@ init_stream(Config) -> component -> ?NS_COMPONENT; server -> ?NS_SERVER end, - #stream_start{id = ID, xmlns = XMLNS, version = Version} = recv(), + #stream_start{id = ID, xmlns = XMLNS, version = Version} = recv(Config), set_opt(stream_id, ID, NewConfig). process_stream_features(Config) -> - #stream_features{sub_els = Fs} = recv(), + #stream_features{sub_els = Fs} = recv(Config), Mechs = lists:flatmap( fun(#sasl_mechanisms{list = Ms}) -> Ms; @@ -213,7 +213,7 @@ disconnect(Config) -> catch exit:normal -> ok end, - {xmlstreamend, <<"stream:stream">>} = recv(), + {xmlstreamend, <<"stream:stream">>} = recv(Config), ejabberd_socket:close(Socket), Config. @@ -227,7 +227,7 @@ starttls(Config) -> starttls(Config, ShouldFail) -> send(Config, #starttls{}), - case recv() of + case recv(Config) of #starttls_proceed{} when ShouldFail -> ct:fail(starttls_should_have_failed); #starttls_failure{} when ShouldFail -> @@ -244,7 +244,7 @@ starttls(Config, ShouldFail) -> zlib(Config) -> send(Config, #compress{methods = [<<"zlib">>]}), - #compressed{} = recv(), + #compressed{} = recv(Config), ZlibSocket = ejabberd_socket:compress(?config(socket, Config)), process_stream_features(init_stream(set_opt(socket, ZlibSocket, Config))). @@ -346,7 +346,7 @@ auth_component(Config, ShouldFail) -> Password = ?config(password, Config), Digest = p1_sha:sha(<>), send(Config, #handshake{data = Digest}), - case recv() of + case recv(Config) of #handshake{} when ShouldFail -> ct:fail(component_auth_should_have_failed); #handshake{} -> @@ -369,7 +369,7 @@ auth_SASL(Mech, Config, ShouldFail) -> wait_auth_SASL_result(set_opt(sasl, SASL, Config), ShouldFail). wait_auth_SASL_result(Config, ShouldFail) -> - case recv() of + case recv(Config) of #sasl_success{} when ShouldFail -> ct:fail(sasl_auth_should_have_failed); #sasl_success{} -> @@ -379,8 +379,8 @@ wait_auth_SASL_result(Config, ShouldFail) -> NS = if Type == client -> ?NS_CLIENT; Type == server -> ?NS_SERVER end, - #stream_start{xmlns = NS, version = {1,0}} = recv(), - #stream_features{sub_els = Fs} = recv(), + #stream_start{xmlns = NS, version = {1,0}} = recv(Config), + #stream_features{sub_els = Fs} = recv(Config), if Type == client -> #xmpp_session{optional = true} = lists:keyfind(xmpp_session, 1, Fs); @@ -417,39 +417,31 @@ match_failure(Received, [Match]) when is_list(Match)-> match_failure(Received, Matches) -> ct:fail("Received input:~n~n~p~n~ndon't match expected patterns:~n~n~p", [Received, Matches]). -recv() -> +recv(Config) -> receive {'$gen_event', {xmlstreamelement, El}} -> - decode(El); + NS = case ?config(type, Config) of + client -> ?NS_CLIENT; + server -> ?NS_SERVER; + component -> ?NS_COMPONENT + end, + decode(El, NS, []); {'$gen_event', {xmlstreamstart, Name, Attrs}} -> - decode(#xmlel{name = Name, attrs = Attrs}); + decode(#xmlel{name = Name, attrs = Attrs}, <<>>, []); {'$gen_event', Event} -> Event end. -decode(El) -> +decode(El, NS, Opts) -> try - Pkt = xmpp:decode(El), - ct:pal("recv: ~p ->~n~s", [El, xmpp_codec:pp(Pkt)]), + Pkt = xmpp:decode(El, NS, Opts), + ct:pal("recv: ~p ->~n~s", [El, xmpp:pp(Pkt)]), Pkt catch _:{xmpp_codec, Why} -> ct:fail("recv failed: ~p->~n~s", [El, xmpp:format_error(Why)]) end. -fix_ns(#xmlel{name = Tag, attrs = Attrs} = El) - when Tag == <<"stream:features">>; Tag == <<"stream:error">> -> - NewAttrs = [{<<"xmlns">>, <<"http://etherx.jabber.org/streams">>} - |lists:keydelete(<<"xmlns">>, 1, Attrs)], - El#xmlel{attrs = NewAttrs}; -fix_ns(#xmlel{name = Tag, attrs = Attrs} = El) - when Tag == <<"message">>; Tag == <<"iq">>; Tag == <<"presence">> -> - NewAttrs = [{<<"xmlns">>, <<"jabber:client">>} - |lists:keydelete(<<"xmlns">>, 1, Attrs)], - El#xmlel{attrs = NewAttrs}; -fix_ns(El) -> - El. - send_text(Config, Text) -> ejabberd_socket:send(?config(socket, Config), Text). @@ -467,8 +459,8 @@ send(State, Pkt) -> _ -> {undefined, Pkt} end, - El = xmpp_codec:encode(NewPkt), - ct:pal("sent: ~p <-~n~s", [El, xmpp_codec:pp(NewPkt)]), + El = xmpp:encode(NewPkt), + ct:pal("sent: ~p <-~n~s", [El, xmpp:pp(NewPkt)]), Data = case NewPkt of #stream_start{} -> fxml:element_to_header(El); _ -> fxml:element_to_binary(El) @@ -478,7 +470,7 @@ send(State, Pkt) -> send_recv(State, IQ) -> ID = send(State, IQ), - #iq{id = ID} = recv(). + #iq{id = ID} = recv(State). sasl_new(<<"PLAIN">>, User, Server, Password) -> {<>, diff --git a/test/suite.hrl b/test/suite.hrl index cbeedff53..4110da0df 100644 --- a/test/suite.hrl +++ b/test/suite.hrl @@ -13,7 +13,7 @@ -define(recv1(P1), P1 = (fun() -> - V = recv(), + V = recv(Config), case V of P1 -> V; _ -> suite:match_failure([V], [??P1]) @@ -22,7 +22,7 @@ -define(recv2(P1, P2), (fun() -> - case {R1 = recv(), R2 = recv()} of + case {R1 = recv(Config), R2 = recv(Config)} of {P1, P2} -> {R1, R2}; {P2, P1} -> {R2, R1}; {P1, V1} -> suite:match_failure([V1], [P2]); @@ -35,7 +35,7 @@ -define(recv3(P1, P2, P3), (fun() -> - case R3 = recv() of + case R3 = recv(Config) of P1 -> insert(R3, 1, ?recv2(P2, P3)); P2 -> insert(R3, 2, ?recv2(P1, P3)); P3 -> insert(R3, 3, ?recv2(P1, P2)); @@ -45,7 +45,7 @@ -define(recv4(P1, P2, P3, P4), (fun() -> - case R4 = recv() of + case R4 = recv(Config) of P1 -> insert(R4, 1, ?recv3(P2, P3, P4)); P2 -> insert(R4, 2, ?recv3(P1, P3, P4)); P3 -> insert(R4, 3, ?recv3(P1, P2, P4)); @@ -56,7 +56,7 @@ -define(recv5(P1, P2, P3, P4, P5), (fun() -> - case R5 = recv() of + case R5 = recv(Config) of P1 -> insert(R5, 1, ?recv4(P2, P3, P4, P5)); P2 -> insert(R5, 2, ?recv4(P1, P3, P4, P5)); P3 -> insert(R5, 3, ?recv4(P1, P2, P4, P5)); diff --git a/tools/xmpp_codec.spec b/tools/xmpp_codec.spec index 7b5ca5e66..ba402969e 100644 --- a/tools/xmpp_codec.spec +++ b/tools/xmpp_codec.spec @@ -316,7 +316,8 @@ -xml(iq, #elem{name = <<"iq">>, - xmlns = <<"jabber:client">>, + xmlns = [<<"jabber:client">>, <<"jabber:server">>, + <<"jabber:component:accept">>], result = {iq, '$id', '$type', '$lang', '$from', '$to', '$_els'}, attrs = [#attr{name = <<"id">>, required = true}, @@ -335,26 +336,30 @@ -xml(message_subject, #elem{name = <<"subject">>, - xmlns = <<"jabber:client">>, + xmlns = [<<"jabber:client">>, <<"jabber:server">>, + <<"jabber:component:accept">>], result = {text, '$lang', '$data'}, cdata = #cdata{label = '$data'}, attrs = [#attr{name = <<"xml:lang">>, label = '$lang'}]}). -xml(message_body, #elem{name = <<"body">>, - xmlns = <<"jabber:client">>, + xmlns = [<<"jabber:client">>, <<"jabber:server">>, + <<"jabber:component:accept">>], result = {text, '$lang', '$data'}, cdata = #cdata{label = '$data'}, attrs = [#attr{name = <<"xml:lang">>, label = '$lang'}]}). -xml(message_thread, #elem{name = <<"thread">>, - xmlns = <<"jabber:client">>, + xmlns = [<<"jabber:client">>, <<"jabber:server">>, + <<"jabber:component:accept">>], result = '$cdata'}). -xml(message, #elem{name = <<"message">>, - xmlns = <<"jabber:client">>, + xmlns = [<<"jabber:client">>, <<"jabber:server">>, + <<"jabber:component:accept">>], result = {message, '$id', '$type', '$lang', '$from', '$to', '$subject', '$body', '$thread', '$_els'}, attrs = [#attr{name = <<"id">>}, @@ -377,14 +382,16 @@ -xml(presence_show, #elem{name = <<"show">>, - xmlns = <<"jabber:client">>, + xmlns = [<<"jabber:client">>, <<"jabber:server">>, + <<"jabber:component:accept">>], result = '$cdata', cdata = #cdata{enc = {enc_enum, []}, dec = {dec_enum, [[away, chat, dnd, xa]]}}}). -xml(presence_status, #elem{name = <<"status">>, - xmlns = <<"jabber:client">>, + xmlns = [<<"jabber:client">>, <<"jabber:server">>, + <<"jabber:component:accept">>], result = {text, '$lang', '$data'}, cdata = #cdata{label = '$data'}, attrs = [#attr{name = <<"xml:lang">>, @@ -392,14 +399,16 @@ -xml(presence_priority, #elem{name = <<"priority">>, - xmlns = <<"jabber:client">>, + xmlns = [<<"jabber:client">>, <<"jabber:server">>, + <<"jabber:component:accept">>], result = '$cdata', cdata = #cdata{enc = {enc_int, []}, dec = {dec_int, []}}}). -xml(presence, #elem{name = <<"presence">>, - xmlns = <<"jabber:client">>, + xmlns = [<<"jabber:client">>, <<"jabber:server">>, + <<"jabber:component:accept">>], result = {presence, '$id', '$type', '$lang', '$from', '$to', '$show', '$status', '$priority', '$_els'}, attrs = [#attr{name = <<"id">>}, @@ -527,7 +536,8 @@ -xml(error, #elem{name = <<"error">>, - xmlns = <<"jabber:client">>, + xmlns = [<<"jabber:client">>, <<"jabber:server">>, + <<"jabber:component:accept">>], result = {stanza_error, '$type', '$code', '$by', '$reason', '$text', '$_els'}, attrs = [#attr{name = <<"type">>, label = '$type', @@ -861,7 +871,7 @@ -xml(stream_features, #elem{name = <<"stream:features">>, - xmlns = <<"http://etherx.jabber.org/streams">>, + xmlns = [<<"jabber:client">>, <<"jabber:server">>], result = {stream_features, '$_els'}}). -xml(p1_push, @@ -1187,7 +1197,8 @@ -xml(stream_error, #elem{name = <<"stream:error">>, - xmlns = <<"http://etherx.jabber.org/streams">>, + xmlns = [<<"jabber:client">>, <<"jabber:server">>, + <<"jabber:component:accept">>], result = {stream_error, '$reason', '$text'}, refs = [#ref{name = stream_error_text, label = '$text', @@ -3162,7 +3173,7 @@ -xml(db_result, #elem{name = <<"db:result">>, - xmlns = <<"jabber:client">>, + xmlns = <<"jabber:server">>, result = {db_result, '$from', '$to', '$type', '$key', '$_els'}, cdata = #cdata{default = <<"">>, label = '$key'}, attrs = [#attr{name = <<"from">>, required = true, @@ -3175,7 +3186,7 @@ -xml(db_verify, #elem{name = <<"db:verify">>, - xmlns = <<"jabber:client">>, + xmlns = <<"jabber:server">>, result = {db_verify, '$from', '$to', '$id', '$type', '$key', '$_els'}, cdata = #cdata{default = <<"">>, label = '$key'}, attrs = [#attr{name = <<"from">>, required = true, @@ -3189,7 +3200,7 @@ -xml(handshake, #elem{name = <<"handshake">>, - xmlns = <<"jabber:client">>, + xmlns = <<"jabber:component:accept">>, result = {handshake, '$data'}, cdata = #cdata{default = <<"">>, label = '$data'}}). From fa31e3ef2321e3901d167d3654693b85313acf08 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sat, 24 Sep 2016 23:34:28 +0300 Subject: [PATCH 045/151] Deprecate jlib:integer_to_binary/1 and jlib:binary_to_integer/1 --- src/cyrsasl_anonymous.erl | 2 +- src/ejabberd_c2s.erl | 2 +- src/ejabberd_captcha.erl | 2 +- src/ejabberd_commands_doc.erl | 4 ++-- src/ejabberd_http.erl | 12 ++++++------ src/ejabberd_http_bind.erl | 4 ++-- src/ejabberd_sm_sql.erl | 4 ++-- src/ejabberd_sql.erl | 10 +++++----- src/ejabberd_system_monitor.erl | 2 +- src/ejabberd_web_admin.erl | 8 ++++---- src/jd2ejd.erl | 2 +- src/jlib.erl | 4 +++- src/mod_caps.erl | 2 +- src/mod_caps_sql.erl | 4 ++-- src/mod_configure.erl | 10 +++++----- src/mod_http_api.erl | 2 +- src/mod_http_upload.erl | 8 ++++---- src/mod_last_sql.erl | 2 +- src/mod_mam_mnesia.erl | 4 ++-- src/mod_mam_sql.erl | 18 +++++++++--------- src/mod_muc_admin.erl | 2 +- src/mod_offline.erl | 2 +- src/mod_privacy_sql.erl | 2 +- src/mod_pubsub.erl | 4 ++-- src/mod_shared_roster.erl | 6 +++--- src/mod_vcard_sql.erl | 2 +- src/pubsub_db_sql.erl | 2 +- src/pubsub_subscription.erl | 4 ++-- src/pubsub_subscription_sql.erl | 4 ++-- src/randoms.erl | 2 +- src/xmpp_codec.erl | 4 ++-- tools/xmpp_codec.spec | 4 ++-- 32 files changed, 73 insertions(+), 71 deletions(-) diff --git a/src/cyrsasl_anonymous.erl b/src/cyrsasl_anonymous.erl index 802e1cd7b..15980afc5 100644 --- a/src/cyrsasl_anonymous.erl +++ b/src/cyrsasl_anonymous.erl @@ -45,7 +45,7 @@ mech_new(Host, _GetPassword, _CheckPassword, _CheckPasswordDigest) -> mech_step(#state{server = Server} = S, ClientIn) -> User = iolist_to_binary([randoms:get_string(), - jlib:integer_to_binary(p1_time_compat:unique_integer([positive]))]), + integer_to_binary(p1_time_compat:unique_integer([positive]))]), case ejabberd_auth:is_user_exists(User, Server) of true -> mech_step(S, ClientIn); false -> {ok, [{username, User}, {authzid, User}, {auth_module, ejabberd_auth_anonymous}]} diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index d89290d47..02540259a 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1633,7 +1633,7 @@ new_id() -> randoms:get_string(). -spec new_uniq_id() -> binary(). new_uniq_id() -> iolist_to_binary([randoms:get_string(), - jlib:integer_to_binary(p1_time_compat:unique_integer([positive]))]). + integer_to_binary(p1_time_compat:unique_integer([positive]))]). -spec get_conn_type(state()) -> c2s | c2s_tls | c2s_compressed | websocket | c2s_compressed_tls | http_bind. diff --git a/src/ejabberd_captcha.erl b/src/ejabberd_captcha.erl index df74a68b1..9650f3773 100644 --- a/src/ejabberd_captcha.erl +++ b/src/ejabberd_captcha.erl @@ -392,7 +392,7 @@ get_url(Str) -> end. get_transfer_protocol(PortString) -> - PortNumber = jlib:binary_to_integer(PortString), + PortNumber = binary_to_integer(PortString), PortListeners = get_port_listeners(PortNumber), get_captcha_transfer_protocol(PortListeners). diff --git a/src/ejabberd_commands_doc.erl b/src/ejabberd_commands_doc.erl index dc00c5d2a..477e4f5d5 100644 --- a/src/ejabberd_commands_doc.erl +++ b/src/ejabberd_commands_doc.erl @@ -41,7 +41,7 @@ -define(SPAN(N, V), ?TAG_R(span, ??N, V)). -define(STR(A), ?SPAN(str,[<<"\"">>, A, <<"\"">>])). --define(NUM(A), ?SPAN(num,jlib:integer_to_binary(A))). +-define(NUM(A), ?SPAN(num,integer_to_binary(A))). -define(FIELD(A), ?SPAN(field,A)). -define(ID(A), ?SPAN(id,A)). -define(OP(A), ?SPAN(op,A)). @@ -171,7 +171,7 @@ xml_gen({Name, integer}, Int, Indent, HTMLOutput) -> [?XML(member, Indent, [?XML_L(name, Indent, 1, ?ID_A(Name)), ?XML(value, Indent, 1, - [?XML_L(integer, Indent, 2, ?ID(jlib:integer_to_binary(Int)))])])]; + [?XML_L(integer, Indent, 2, ?ID(integer_to_binary(Int)))])])]; xml_gen({Name, string}, Str, Indent, HTMLOutput) -> [?XML(member, Indent, [?XML_L(name, Indent, 1, ?ID_A(Name)), diff --git a/src/ejabberd_http.erl b/src/ejabberd_http.erl index 1c8de2fbf..35679ccd3 100644 --- a/src/ejabberd_http.erl +++ b/src/ejabberd_http.erl @@ -252,7 +252,7 @@ process_header(State, Data) -> request_headers = add_header(Name, Auth, State)}; {ok, {http_header, _, 'Content-Length' = Name, _, SLen}} -> - case catch jlib:binary_to_integer(SLen) of + case catch binary_to_integer(SLen) of Len when is_integer(Len) -> State#state{request_content_length = Len, request_headers = add_header(Name, SLen, State)}; @@ -327,10 +327,10 @@ get_transfer_protocol(SockMod, HostPort) -> case {SockMod, PortList} of {gen_tcp, []} -> {Host, 80, http}; {gen_tcp, [Port]} -> - {Host, jlib:binary_to_integer(Port), http}; + {Host, binary_to_integer(Port), http}; {fast_tls, []} -> {Host, 443, https}; {fast_tls, [Port]} -> - {Host, jlib:binary_to_integer(Port), https} + {Host, binary_to_integer(Port), https} end. %% XXX bard: search through request handlers looking for one that @@ -587,12 +587,12 @@ make_text_output(State, Status, Reason, Headers, Text) -> of {value, _} -> [{<<"Content-Length">>, - jlib:integer_to_binary(byte_size(Data))} + integer_to_binary(byte_size(Data))} | Headers]; _ -> [{<<"Content-Type">>, <<"text/html; charset=utf-8">>}, {<<"Content-Length">>, - jlib:integer_to_binary(byte_size(Data))} + integer_to_binary(byte_size(Data))} | Headers] end, HeadersOut = case {State#state.request_version, @@ -617,7 +617,7 @@ make_text_output(State, Status, Reason, Headers, Text) -> _ -> Reason end, SL = [Version, - jlib:integer_to_binary(Status), <<" ">>, + integer_to_binary(Status), <<" ">>, NewReason, <<"\r\n">>], Data2 = case State#state.request_method of 'HEAD' -> <<"">>; diff --git a/src/ejabberd_http_bind.erl b/src/ejabberd_http_bind.erl index 1a238607a..20edaa178 100644 --- a/src/ejabberd_http_bind.erl +++ b/src/ejabberd_http_bind.erl @@ -853,7 +853,7 @@ rid_allow(OldRid, NewRid, Attrs, Hold, MaxPause) -> %% We did not miss any packet, we can process it immediately: NewRid == OldRid + 1 -> case catch - jlib:binary_to_integer(fxml:get_attr_s(<<"pause">>, + binary_to_integer(fxml:get_attr_s(<<"pause">>, Attrs)) of {'EXIT', _} -> {true, 0}; @@ -1119,7 +1119,7 @@ parse_request(Data, PayloadSize, MaxStanzaSize) -> if Xmlns /= (?NS_HTTP_BIND) -> {error, bad_request}; true -> case catch - jlib:binary_to_integer(fxml:get_attr_s(<<"rid">>, + binary_to_integer(fxml:get_attr_s(<<"rid">>, Attrs)) of {'EXIT', _} -> {error, bad_request}; diff --git a/src/ejabberd_sm_sql.erl b/src/ejabberd_sm_sql.erl index 28796aca0..2a7b80c19 100644 --- a/src/ejabberd_sm_sql.erl +++ b/src/ejabberd_sm_sql.erl @@ -147,7 +147,7 @@ timestamp_to_now(I) -> {MSec, Sec, USec}. dec_priority(Prio) -> - case catch jlib:binary_to_integer(Prio) of + case catch binary_to_integer(Prio) of {'EXIT', _} -> undefined; Int -> @@ -157,7 +157,7 @@ dec_priority(Prio) -> enc_priority(undefined) -> <<"">>; enc_priority(Int) when is_integer(Int) -> - jlib:integer_to_binary(Int). + integer_to_binary(Int). row_to_session(LServer, {USec, PidS, User, Resource, PrioS, InfoS}) -> Now = timestamp_to_now(USec), diff --git a/src/ejabberd_sql.erl b/src/ejabberd_sql.erl index a480a1bd3..8116d617f 100644 --- a/src/ejabberd_sql.erl +++ b/src/ejabberd_sql.erl @@ -768,7 +768,7 @@ sqlite_to_odbc(Host, {rowid, _}) -> sqlite_to_odbc(_Host, [{columns, Columns}, {rows, TRows}]) -> Rows = [lists:map( fun(I) when is_integer(I) -> - jlib:integer_to_binary(I); + integer_to_binary(I); (B) -> B end, tuple_to_list(Row)) || Row <- TRows], @@ -813,11 +813,11 @@ pgsql_item_to_odbc({<<"FETCH", _/binary>>, Rows, {selected, [element(1, Row) || Row <- Rows], Recs}; pgsql_item_to_odbc(<<"INSERT ", OIDN/binary>>) -> [_OID, N] = str:tokens(OIDN, <<" ">>), - {updated, jlib:binary_to_integer(N)}; + {updated, binary_to_integer(N)}; pgsql_item_to_odbc(<<"DELETE ", N/binary>>) -> - {updated, jlib:binary_to_integer(N)}; + {updated, binary_to_integer(N)}; pgsql_item_to_odbc(<<"UPDATE ", N/binary>>) -> - {updated, jlib:binary_to_integer(N)}; + {updated, binary_to_integer(N)}; pgsql_item_to_odbc({error, Error}) -> {error, Error}; pgsql_item_to_odbc(_) -> {updated, undefined}. @@ -875,7 +875,7 @@ mysql_item_to_odbc(Columns, Recs) -> to_odbc({selected, Columns, Recs}) -> Rows = [lists:map( fun(I) when is_integer(I) -> - jlib:integer_to_binary(I); + integer_to_binary(I); (B) -> B end, Row) || Row <- Recs], diff --git a/src/ejabberd_system_monitor.erl b/src/ejabberd_system_monitor.erl index 7f815a57e..df6af1c95 100644 --- a/src/ejabberd_system_monitor.erl +++ b/src/ejabberd_system_monitor.erl @@ -300,7 +300,7 @@ process_command2([<<"showlh">>, SNode], From, To) -> process_command2([<<"setlh">>, SNode, NewValueString], From, To) -> Node = jlib:binary_to_atom(SNode), - NewValue = jlib:binary_to_integer(NewValueString), + NewValue = binary_to_integer(NewValueString), remote_command(Node, [setlh, NewValue], From, To); process_command2([<<"help">>], From, To) -> send_message(To, From, help()); diff --git a/src/ejabberd_web_admin.erl b/src/ejabberd_web_admin.erl index 2740e2879..498fcf9b0 100644 --- a/src/ejabberd_web_admin.erl +++ b/src/ejabberd_web_admin.erl @@ -1458,8 +1458,8 @@ list_users_in_diapason(Host, Diap, Lang, URLFunc) -> Users = ejabberd_auth:get_vh_registered_users(Host), SUsers = lists:sort([{S, U} || {U, S} <- Users]), [S1, S2] = ejabberd_regexp:split(Diap, <<"-">>), - N1 = jlib:binary_to_integer(S1), - N2 = jlib:binary_to_integer(S2), + N1 = binary_to_integer(S1), + N2 = binary_to_integer(S2), Sub = lists:sublist(SUsers, N1, N2 - N1 + 1), [list_given_users(Host, Sub, <<"../../">>, Lang, URLFunc)]. @@ -1648,7 +1648,7 @@ user_info(User, Server, Query, Lang) -> "://", (jlib:ip_to_list(IP))/binary, ":", - (jlib:integer_to_binary(Port))/binary, + (integer_to_binary(Port))/binary, "#", (jlib:atom_to_binary(Node))/binary>> end, @@ -2520,7 +2520,7 @@ make_netprot_html(NetProt) -> get_port_data(PortIP, Opts) -> {Port, IPT, IPS, _IPV, NetProt, OptsClean} = ejabberd_listener:parse_listener_portip(PortIP, Opts), - SPort = jlib:integer_to_binary(Port), + SPort = integer_to_binary(Port), SSPort = list_to_binary( lists:map(fun (N) -> io_lib:format("~.16b", [N]) diff --git a/src/jd2ejd.erl b/src/jd2ejd.erl index 037d6d63a..fd70f8b1e 100644 --- a/src/jd2ejd.erl +++ b/src/jd2ejd.erl @@ -126,7 +126,7 @@ xdb_data(User, Server, #xmlel{attrs = Attrs} = El) -> TimeStamp = fxml:get_attr_s(<<"last">>, Attrs), Status = fxml:get_tag_cdata(El), catch mod_last:store_last_info(User, Server, - jlib:binary_to_integer(TimeStamp), + binary_to_integer(TimeStamp), Status), ok; ?NS_VCARD -> diff --git a/src/jlib.erl b/src/jlib.erl index 532a74610..b79b8fa7c 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -74,7 +74,9 @@ {resourceprep, 1}, {jid_tolower, 1}, {jid_remove_resource, 1}, - {jid_replace_resource, 2}]). + {jid_replace_resource, 2}, + {integer_to_binary, 1}, + {binary_to_integer, 1}]). -include("ejabberd.hrl"). -include("jlib.hrl"). diff --git a/src/mod_caps.erl b/src/mod_caps.erl index ae11ab651..4d9bdd61f 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -546,7 +546,7 @@ import_start(LServer, DBType) -> import(_LServer, {sql, _}, _DBType, <<"caps_features">>, [Node, SubNode, Feature, _TimeStamp]) -> - Feature1 = case catch jlib:binary_to_integer(Feature) of + Feature1 = case catch binary_to_integer(Feature) of I when is_integer(I), I>0 -> I; _ -> Feature end, diff --git a/src/mod_caps_sql.erl b/src/mod_caps_sql.erl index 5faff98b6..dde301575 100644 --- a/src/mod_caps_sql.erl +++ b/src/mod_caps_sql.erl @@ -29,7 +29,7 @@ caps_read(LServer, {Node, SubNode}) -> ?SQL("select @(feature)s from caps_features where" " node=%(Node)s and subnode=%(SubNode)s")) of {selected, [{H}|_] = Fs} -> - case catch jlib:binary_to_integer(H) of + case catch binary_to_integer(H) of Int when is_integer(Int), Int>=0 -> {ok, Int}; _ -> @@ -58,7 +58,7 @@ export(_Server) -> %%%=================================================================== sql_write_features_t({Node, SubNode}, Features) -> NewFeatures = if is_integer(Features) -> - [jlib:integer_to_binary(Features)]; + [integer_to_binary(Features)]; true -> Features end, diff --git a/src/mod_configure.erl b/src/mod_configure.erl index dd361028b..5e2ff351c 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -552,8 +552,8 @@ get_local_items({_, Host}, SUsers = lists:sort([{S, U} || {U, S} <- Users]), try [S1, S2] = ejabberd_regexp:split(Diap, <<"-">>), - N1 = jlib:binary_to_integer(S1), - N2 = jlib:binary_to_integer(S2), + N1 = binary_to_integer(S1), + N2 = binary_to_integer(S2), Sub = lists:sublist(SUsers, N1, N2 - N1 + 1), {result, lists:map( fun({S, U}) -> @@ -1659,11 +1659,11 @@ set_form(From, Host, ?NS_ADMINL(<<"user-stats">>), Lang, IPs1 = [ejabberd_sm:get_user_ip(User, Server, Resource) || Resource <- Resources], IPs = [<<(jlib:ip_to_list(IP))/binary, ":", - (jlib:integer_to_binary(Port))/binary>> + (integer_to_binary(Port))/binary>> || {IP, Port} <- IPs1], Items = ejabberd_hooks:run_fold(roster_get, Server, [], [{User, Server}]), - Rostersize = jlib:integer_to_binary(erlang:length(Items)), + Rostersize = integer_to_binary(erlang:length(Items)), {result, #xdata{type = form, fields = [?HFIELD(), @@ -1695,7 +1695,7 @@ search_running_node(SNode, [Node | Nodes]) -> end. stop_node(From, Host, ENode, Action, XData) -> - Delay = jlib:binary_to_integer(get_value(<<"delay">>, XData)), + Delay = binary_to_integer(get_value(<<"delay">>, XData)), Subject = case get_value(<<"subject">>, XData) of <<"">> -> []; diff --git a/src/mod_http_api.erl b/src/mod_http_api.erl index f3a69aa80..1578be964 100644 --- a/src/mod_http_api.erl +++ b/src/mod_http_api.erl @@ -267,7 +267,7 @@ process(_Path, Request) -> get_api_version(#request{path = Path}) -> get_api_version(lists:reverse(Path)); get_api_version([<<"v", String/binary>> | Tail]) -> - case catch jlib:binary_to_integer(String) of + case catch binary_to_integer(String) of N when is_integer(N) -> N; _ -> diff --git a/src/mod_http_upload.erl b/src/mod_http_upload.erl index f1f5d8173..6ad18531c 100644 --- a/src/mod_http_upload.erl +++ b/src/mod_http_upload.erl @@ -35,7 +35,7 @@ -define(FORMAT(Error), file:format_error(Error)). -define(URL_ENC(URL), binary_to_list(ejabberd_http:url_encode(URL))). -define(ADDR_TO_STR(IP), ejabberd_config:may_hide_data(jlib:ip_to_list(IP))). --define(STR_TO_INT(Str, B), jlib:binary_to_integer(iolist_to_binary(Str), B)). +-define(STR_TO_INT(Str, B), binary_to_integer(iolist_to_binary(Str), B)). -define(DEFAULT_CONTENT_TYPE, <<"application/octet-stream">>). -define(CONTENT_TYPES, [{<<".avi">>, <<"video/avi">>}, @@ -578,7 +578,7 @@ process_iq(_From, #iq{}, _State) -> create_slot(#state{service_url = undefined, max_size = MaxSize}, JID, File, Size, _ContentType, Lang) when MaxSize /= infinity, Size > MaxSize -> - Text = <<"File larger than ", (jlib:integer_to_binary(MaxSize))/binary, + Text = <<"File larger than ", (integer_to_binary(MaxSize))/binary, " Bytes.">>, ?INFO_MSG("Rejecting file ~s from ~s (too large: ~B bytes)", [File, jid:to_string(JID), Size]), @@ -609,7 +609,7 @@ create_slot(#state{service_url = ServiceURL}, Lang) -> Options = [{body_format, binary}, {full_result, false}], HttpOptions = [{timeout, ?SERVICE_REQUEST_TIMEOUT}], - SizeStr = jlib:integer_to_binary(Size), + SizeStr = integer_to_binary(Size), GetRequest = binary_to_list(ServiceURL) ++ "?jid=" ++ ?URL_ENC(jid:to_string({U, S, <<"">>})) ++ "&name=" ++ ?URL_ENC(File) ++ @@ -727,7 +727,7 @@ iq_disco_info(Host, Lang, Name, AddInfo) -> infinity -> AddInfo; MaxSize -> - MaxSizeStr = jlib:integer_to_binary(MaxSize), + MaxSizeStr = integer_to_binary(MaxSize), Fields = [#xdata_field{type = hidden, var = <<"FORM_TYPE">>, values = [?NS_HTTP_UPLOAD]}, diff --git a/src/mod_last_sql.erl b/src/mod_last_sql.erl index 13b028c6f..718f01dff 100644 --- a/src/mod_last_sql.erl +++ b/src/mod_last_sql.erl @@ -62,7 +62,7 @@ import(LServer) -> [{<<"select username, seconds, state from last">>, fun([LUser, TimeStamp, State]) -> #last_activity{us = {LUser, LServer}, - timestamp = jlib:binary_to_integer( + timestamp = binary_to_integer( TimeStamp), status = State} end}]. diff --git a/src/mod_mam_mnesia.erl b/src/mod_mam_mnesia.erl index ecaa4d053..e913d5a45 100644 --- a/src/mod_mam_mnesia.erl +++ b/src/mod_mam_mnesia.erl @@ -97,7 +97,7 @@ store(Pkt, _, {LUser, LServer}, Type, Peer, Nick, _Dir) -> _ -> LPeer = {PUser, PServer, _} = jid:tolower(Peer), TS = p1_time_compat:timestamp(), - ID = jlib:integer_to_binary(now_to_usec(TS)), + ID = integer_to_binary(now_to_usec(TS)), F = fun() -> mnesia:write( #archive_msg{us = {LUser, LServer}, @@ -145,7 +145,7 @@ select(_LServer, JidRequestor, Result = {lists:map( fun(Msg) -> {Msg#archive_msg.id, - jlib:binary_to_integer(Msg#archive_msg.id), + binary_to_integer(Msg#archive_msg.id), mod_mam:msg_to_el(Msg, MsgType, JidRequestor, JidArchive)} end, FilteredMsgs), IsComplete, Count}, diff --git a/src/mod_mam_sql.erl b/src/mod_mam_sql.erl index 2a0dcce95..1491f70f2 100644 --- a/src/mod_mam_sql.erl +++ b/src/mod_mam_sql.erl @@ -55,7 +55,7 @@ extended_fields() -> store(Pkt, LServer, {LUser, LHost}, Type, Peer, Nick, _Dir) -> TSinteger = p1_time_compat:system_time(micro_seconds), - ID = jlib:integer_to_binary(TSinteger), + ID = integer_to_binary(TSinteger), SUser = case Type of chat -> LUser; groupchat -> jid:to_string({LUser, LHost, <<>>}) @@ -154,14 +154,14 @@ select(LServer, JidRequestor, #jid{luser = LUser} = JidArchive, fun([TS, XML, PeerBin, Kind, Nick]) -> try #xmlel{} = El = fxml_stream:parse_element(XML), - Now = usec_to_now(jlib:binary_to_integer(TS)), + Now = usec_to_now(binary_to_integer(TS)), PeerJid = jid:tolower(jid:from_string(PeerBin)), T = case Kind of <<"">> -> chat; null -> chat; _ -> jlib:binary_to_atom(Kind) end, - [{TS, jlib:binary_to_integer(TS), + [{TS, binary_to_integer(TS), mod_mam:msg_to_el(#archive_msg{timestamp = Now, packet = El, type = T, @@ -176,7 +176,7 @@ select(LServer, JidRequestor, #jid{luser = LUser} = JidArchive, [Err, TS, XML, PeerBin, Kind, Nick]), [] end - end, Res1), IsComplete, jlib:binary_to_integer(Count)}; + end, Res1), IsComplete, binary_to_integer(Count)}; _ -> {[], false, 0} end. @@ -208,12 +208,12 @@ make_sql_query(User, LServer, _ -> fun ejabberd_sql:escape/1 end, LimitClause = if is_integer(Max), Max >= 0, ODBCType /= mssql -> - [<<" limit ">>, jlib:integer_to_binary(Max+1)]; + [<<" limit ">>, integer_to_binary(Max+1)]; true -> [] end, TopClause = if is_integer(Max), Max >= 0, ODBCType == mssql -> - [<<" TOP ">>, jlib:integer_to_binary(Max+1)]; + [<<" TOP ">>, integer_to_binary(Max+1)]; true -> [] end, @@ -235,7 +235,7 @@ make_sql_query(User, LServer, _ -> [] end, - PageClause = case catch jlib:binary_to_integer(ID) of + PageClause = case catch binary_to_integer(ID) of I when is_integer(I), I >= 0 -> case Direction of before -> @@ -251,14 +251,14 @@ make_sql_query(User, LServer, StartClause = case Start of {_, _, _} -> [<<" and timestamp >= ">>, - jlib:integer_to_binary(now_to_usec(Start))]; + integer_to_binary(now_to_usec(Start))]; _ -> [] end, EndClause = case End of {_, _, _} -> [<<" and timestamp <= ">>, - jlib:integer_to_binary(now_to_usec(End))]; + integer_to_binary(now_to_usec(End))]; _ -> [] end, diff --git a/src/mod_muc_admin.erl b/src/mod_muc_admin.erl index a7ba16138..4d56093e1 100644 --- a/src/mod_muc_admin.erl +++ b/src/mod_muc_admin.erl @@ -761,7 +761,7 @@ change_room_option(Name, Service, OptionString, ValueString) -> password -> ValueString; subject ->ValueString; subject_author ->ValueString; - max_users -> jlib:binary_to_integer(ValueString); + max_users -> binary_to_integer(ValueString); _ -> jlib:binary_to_atom(ValueString) end, change_room_option(Name, Service, Option, Value). diff --git a/src/mod_offline.erl b/src/mod_offline.erl index 9c062065d..258c97d4f 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -301,7 +301,7 @@ get_sm_items(Acc, _From, _To, _Node, _Lang) -> ([xdata()], jid(), jid(), binary(), binary()) -> [xdata()]. get_info(_Acc, #jid{luser = U, lserver = S, lresource = R}, #jid{luser = U, lserver = S}, ?NS_FLEX_OFFLINE, _Lang) -> - N = jlib:integer_to_binary(count_offline_messages(U, S)), + N = integer_to_binary(count_offline_messages(U, S)), case ejabberd_sm:get_session_pid(U, S, R) of Pid when is_pid(Pid) -> Pid ! dont_ask_offline; diff --git a/src/mod_privacy_sql.erl b/src/mod_privacy_sql.erl index a1f743657..7ca19b5e9 100644 --- a/src/mod_privacy_sql.erl +++ b/src/mod_privacy_sql.erl @@ -198,7 +198,7 @@ export(Server) -> [<<"select id from privacy_list order by " "id desc limit 1;">>]) of {selected, [<<"id">>], [[I]]} -> - put(id, jlib:binary_to_integer(I)); + put(id, binary_to_integer(I)); _ -> put(id, 0) end, diff --git a/src/mod_pubsub.erl b/src/mod_pubsub.erl index f7e1a9834..b55115c9a 100644 --- a/src/mod_pubsub.erl +++ b/src/mod_pubsub.erl @@ -3279,7 +3279,7 @@ max_items(Host, Options) -> -define(INTEGER_CONFIG_FIELD(Label, Var), ?STRINGXFIELD(Label, <<"pubsub#", (atom_to_binary(Var, latin1))/binary>>, - (jlib:integer_to_binary(get_option(Options, Var))))). + (integer_to_binary(get_option(Options, Var))))). -define(JLIST_CONFIG_FIELD(Label, Var, Opts), ?LISTXFIELD(Label, @@ -3418,7 +3418,7 @@ add_opt(Key, Value, Opts) -> set_xoption(Host, Opts, add_opt(Opt, Val, NewOpts))). -define(SET_INTEGER_XOPT(Opt, Val, Min, Max), - case catch jlib:binary_to_integer(Val) of + case catch binary_to_integer(Val) of IVal when is_integer(IVal), IVal >= Min -> if (Max =:= undefined) orelse (IVal =< Max) -> set_xoption(Host, Opts, add_opt(Opt, IVal, NewOpts)); diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index 8b620514b..45d91bccd 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -907,21 +907,21 @@ shared_roster_group(Host, Group, Query, Lang) -> [?XCT(<<"td">>, <<"Description:">>), ?XE(<<"td">>, [?TEXTAREA(<<"description">>, - jlib:integer_to_binary(lists:max([3, + integer_to_binary(lists:max([3, DescNL])), <<"20">>, Description)])]), ?XE(<<"tr">>, [?XCT(<<"td">>, <<"Members:">>), ?XE(<<"td">>, [?TEXTAREA(<<"members">>, - jlib:integer_to_binary(lists:max([3, + integer_to_binary(lists:max([3, byte_size(FMembers)])), <<"20">>, FMembers)])]), ?XE(<<"tr">>, [?XCT(<<"td">>, <<"Displayed Groups:">>), ?XE(<<"td">>, [?TEXTAREA(<<"dispgroups">>, - jlib:integer_to_binary(lists:max([3, length(FDisplayedGroups)])), + integer_to_binary(lists:max([3, length(FDisplayedGroups)])), <<"20">>, list_to_binary(FDisplayedGroups))])])])])), (?H1GL((?T(<<"Shared Roster Groups">>)), diff --git a/src/mod_vcard_sql.erl b/src/mod_vcard_sql.erl index f8ac6be97..129f76b5a 100644 --- a/src/mod_vcard_sql.erl +++ b/src/mod_vcard_sql.erl @@ -82,7 +82,7 @@ search(LServer, Data, AllowReturnAll, MaxMatch) -> infinity -> <<"">>; Val -> - [<<" LIMIT ">>, jlib:integer_to_binary(Val)] + [<<" LIMIT ">>, integer_to_binary(Val)] end, case catch ejabberd_sql:sql_query( LServer, diff --git a/src/pubsub_db_sql.erl b/src/pubsub_db_sql.erl index a6f8888a9..69b476539 100644 --- a/src/pubsub_db_sql.erl +++ b/src/pubsub_db_sql.erl @@ -134,7 +134,7 @@ boolean_to_sql(false) -> <<"0">>. timestamp_to_sql(T) -> jlib:now_to_utc_string(T). -sql_to_integer(N) -> jlib:binary_to_integer(N). +sql_to_integer(N) -> binary_to_integer(N). sql_to_boolean(B) -> B == <<"1">>. diff --git a/src/pubsub_subscription.erl b/src/pubsub_subscription.erl index 33c884afb..de1a363db 100644 --- a/src/pubsub_subscription.erl +++ b/src/pubsub_subscription.erl @@ -203,7 +203,7 @@ var_xfield(_) -> {error, badarg}. val_xfield(deliver = Opt, [Val]) -> xopt_to_bool(Opt, Val); val_xfield(digest = Opt, [Val]) -> xopt_to_bool(Opt, Val); val_xfield(digest_frequency = Opt, [Val]) -> - case catch jlib:binary_to_integer(Val) of + case catch binary_to_integer(Val) of N when is_integer(N) -> N; _ -> Txt = <<"Value of '~s' should be integer">>, @@ -225,7 +225,7 @@ val_xfield(subscription_type, [<<"items">>]) -> items; val_xfield(subscription_type, [<<"nodes">>]) -> nodes; val_xfield(subscription_depth, [<<"all">>]) -> all; val_xfield(subscription_depth = Opt, [Depth]) -> - case catch jlib:binary_to_integer(Depth) of + case catch binary_to_integer(Depth) of N when is_integer(N) -> N; _ -> Txt = <<"Value of '~s' should be integer">>, diff --git a/src/pubsub_subscription_sql.erl b/src/pubsub_subscription_sql.erl index 7c0670957..32aa41a93 100644 --- a/src/pubsub_subscription_sql.erl +++ b/src/pubsub_subscription_sql.erl @@ -168,7 +168,7 @@ var_xfield(_) -> {error, badarg}. val_xfield(deliver = Opt, [Val]) -> xopt_to_bool(Opt, Val); val_xfield(digest = Opt, [Val]) -> xopt_to_bool(Opt, Val); val_xfield(digest_frequency = Opt, [Val]) -> - case catch jlib:binary_to_integer(Val) of + case catch binary_to_integer(Val) of N when is_integer(N) -> N; _ -> Txt = <<"Value of '~s' should be integer">>, @@ -190,7 +190,7 @@ val_xfield(subscription_type, [<<"items">>]) -> items; val_xfield(subscription_type, [<<"nodes">>]) -> nodes; val_xfield(subscription_depth, [<<"all">>]) -> all; val_xfield(subscription_depth = Opt, [Depth]) -> - case catch jlib:binary_to_integer(Depth) of + case catch binary_to_integer(Depth) of N when is_integer(N) -> N; _ -> Txt = <<"Value of '~s' should be integer">>, diff --git a/src/randoms.erl b/src/randoms.erl index 52fceef4e..60d0b4e3d 100644 --- a/src/randoms.erl +++ b/src/randoms.erl @@ -36,5 +36,5 @@ start() -> get_string() -> R = crypto:rand_uniform(0, 16#10000000000000000), - jlib:integer_to_binary(R). + integer_to_binary(R). diff --git a/src/xmpp_codec.erl b/src/xmpp_codec.erl index bffe2f1ad..a0181e1e6 100644 --- a/src/xmpp_codec.erl +++ b/src/xmpp_codec.erl @@ -6686,8 +6686,8 @@ enc_tzo({H, M}) -> dec_tzo(Val) -> [H1, M1] = str:tokens(Val, <<":">>), - H = jlib:binary_to_integer(H1), - M = jlib:binary_to_integer(M1), + H = binary_to_integer(H1), + M = binary_to_integer(M1), if H >= -12, H =< 12, M >= 0, M < 60 -> {H, M} end. decode_thumbnail(__TopXMLNS, __IgnoreEls, diff --git a/tools/xmpp_codec.spec b/tools/xmpp_codec.spec index ba402969e..6824cf387 100644 --- a/tools/xmpp_codec.spec +++ b/tools/xmpp_codec.spec @@ -3390,8 +3390,8 @@ -spec dec_tzo(_) -> {integer(), integer()}. dec_tzo(Val) -> [H1, M1] = str:tokens(Val, <<":">>), - H = jlib:binary_to_integer(H1), - M = jlib:binary_to_integer(M1), + H = binary_to_integer(H1), + M = binary_to_integer(M1), if H >= -12, H =< 12, M >= 0, M < 60 -> {H, M} end. From 7100c67be64b2833ac5bf5b93cbe8f920fc438c0 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sun, 25 Sep 2016 08:38:41 +0300 Subject: [PATCH 046/151] Get rid of compile warnings in test suite --- test/ejabberd_SUITE.erl | 66 ++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index 4c63bf295..b5aa50bdb 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -769,7 +769,6 @@ test_legacy_auth(Config) -> disconnect(auth_legacy(Config, _Digest = false)). test_legacy_auth_digest(Config) -> - ServerJID = server_jid(Config), disconnect(auth_legacy(Config, _Digest = true)). test_legacy_auth_no_resource(Config0) -> @@ -818,7 +817,7 @@ roster_ver(Config) -> %% Attempting to subscribe to server's JID send(Config, #presence{type = subscribe, to = server_jid(Config)}), %% Receive a single roster push with the new "ver" - ?recv1(#iq{type = set, sub_els = [#roster_query{ver = Ver2}]}), + #iq{type = set, sub_els = [#roster_query{ver = Ver2}]} = recv(Config), %% Requesting roster with the previous "ver". Should receive Ver2 again #iq{type = result, sub_els = [#roster_query{ver = Ver2}]} = send_recv(Config, #iq{type = get, @@ -952,7 +951,7 @@ sm(Config) -> true = ?config(sm, Config), %% Enable the session management with resumption enabled send(Config, #sm_enable{resume = true, xmlns = ?NS_STREAM_MGMT_3}), - ?recv1(#sm_enabled{id = ID, resume = true}), + #sm_enabled{id = ID, resume = true} = recv(Config), %% Initial request; 'h' should be 0. send(Config, #sm_r{xmlns = ?NS_STREAM_MGMT_3}), ?recv1(#sm_a{h = 0}), @@ -1564,6 +1563,7 @@ retrieve_messages_from_room_via_mam(Config, Range) -> MyNick = ?config(master_nick, Config), Room = muc_room_jid(Config), MyNickJID = jid:replace_resource(Room, MyNick), + MyJID = my_jid(Config), QID = randoms:get_string(), Count = length(Range), I = send(Config, #iq{type = set, to = Room, @@ -1592,7 +1592,6 @@ retrieve_messages_from_room_via_mam(Config, Range) -> complete = true}]}). muc_mam_master(Config) -> - MyJID = my_jid(Config), MyNick = ?config(master_nick, Config), Room = muc_room_jid(Config), MyNickJID = jid:replace_resource(Room, MyNick), @@ -1735,10 +1734,10 @@ muc_master(Config) -> affiliation = none}]} = xmpp:get_subtag(?recv1(#presence{from = PeerNickJID}), #muc_user{}), %% Receiving a voice request - ?recv1(#message{from = Room, + #message{from = Room, sub_els = [#xdata{type = form, instructions = [_], - fields = VoiceReqFs}]}), + fields = VoiceReqFs}]} = recv(Config), %% Approving the voice request ReplyVoiceReqFs = lists:map( @@ -1801,7 +1800,7 @@ muc_master(Config) -> [#muc_item{affiliation = member, jid = Localhost}, #muc_item{affiliation = member, - jid = MyBareJID}] = lists:keysort(#muc_item.jid, MemberList), + jid = PeerBareJID}] = lists:keysort(#muc_item.jid, MemberList), %% Kick the peer I2 = send(Config, #iq{type = set, to = Room, @@ -1833,8 +1832,6 @@ muc_master(Config) -> disconnect(Config). muc_slave(Config) -> - MyJID = my_jid(Config), - MyBareJID = jid:remove_resource(MyJID), PeerJID = ?config(master, Config), MUC = muc_jid(Config), Room = muc_room_jid(Config), @@ -1843,7 +1840,6 @@ muc_slave(Config) -> PeerNick = ?config(master_nick, Config), PeerNickJID = jid:replace_resource(Room, PeerNick), Subject = ?config(room_subject, Config), - Localhost = jid:make(<<"">>, <<"localhost">>, <<"">>), %% Receive an invite from the peer #muc_user{invites = [#muc_invite{from = PeerJID}]} = xmpp:get_subtag(?recv1(#message{from = Room, type = normal}), @@ -2075,7 +2071,7 @@ flex_offline_slave(Config) -> lists:foreach( fun({I, N}) -> Text = integer_to_binary(I), - ?recv1(#message{body = Body, sub_els = SubEls}), + #message{body = Body, sub_els = SubEls} = recv(Config), [#text{data = Text}] = Body, #offline{items = [#offline_item{node = N}]} = lists:keyfind(offline, 1, SubEls), @@ -2095,7 +2091,8 @@ flex_offline_slave(Config) -> lists:foreach( fun({I, N}) -> Text = integer_to_binary(I), - ?recv1(#message{body = [#text{data = Text}], sub_els = SubEls}), + #message{body = [#text{data = Text}], + sub_els = SubEls} = recv(Config), #offline{items = [#offline_item{node = N}]} = lists:keyfind(offline, 1, SubEls) end, lists:zip([2, 4], [lists:nth(2, Nodes), lists:nth(4, Nodes)])), @@ -2335,10 +2332,11 @@ mam_new_slave(Config) -> mam_slave(Config, NS) -> Peer = ?config(master, Config), + MyJID = my_jid(Config), ServerJID = server_jid(Config), wait_for_master(Config), send(Config, #presence{}), - ?recv2(#presence{}, #presence{from = Peer}), + ?recv2(#presence{from = MyJID}, #presence{from = Peer}), #iq{type = result, sub_els = [#mam_prefs{xmlns = NS, default = always}]} = send_recv(Config, #iq{type = set, @@ -2463,13 +2461,17 @@ mam_query_rsm(Config, NS) -> body = [Text]}]}]}]}) end, lists:seq(1, 3)), if NS == ?NS_MAM_TMP -> - ?recv1(#iq{type = result, id = I1, - sub_els = [#mam_query{xmlns = NS, - rsm = #rsm_set{last = Last, count = 5}}]}); + #iq{type = result, id = I1, + sub_els = [#mam_query{xmlns = NS, + rsm = #rsm_set{last = Last, + count = 5}}]} = + recv(Config); true -> - ?recv1(#message{sub_els = [#mam_fin{ - complete = false, - rsm = #rsm_set{last = Last, count = 10}}]}) + #message{sub_els = [#mam_fin{ + complete = false, + rsm = #rsm_set{last = Last, + count = 10}}]} = + recv(Config) end, %% Get the next items starting from the `Last`. %% Limit the response to 2 items. @@ -2495,19 +2497,21 @@ mam_query_rsm(Config, NS) -> body = [Text]}]}]}]}) end, lists:seq(4, 5)), if NS == ?NS_MAM_TMP -> - ?recv1(#iq{type = result, id = I2, - sub_els = [#mam_query{ - xmlns = NS, - rsm = #rsm_set{ - count = 5, - first = #rsm_first{data = First}}}]}); + #iq{type = result, id = I2, + sub_els = [#mam_query{ + xmlns = NS, + rsm = #rsm_set{ + count = 5, + first = #rsm_first{data = First}}}]} = + recv(Config); true -> - ?recv1(#message{ - sub_els = [#mam_fin{ - complete = false, - rsm = #rsm_set{ - count = 10, - first = #rsm_first{data = First}}}]}) + #message{ + sub_els = [#mam_fin{ + complete = false, + rsm = #rsm_set{ + count = 10, + first = #rsm_first{data = First}}}]} = + recv(Config) end, %% Paging back. Should receive 3 elements: 1, 2, 3. I3 = send(Config, From 3112a7187f1d313de424aac157ba4484fc1b506c Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sun, 25 Sep 2016 09:57:56 +0300 Subject: [PATCH 047/151] Test anonymous auth --- include/xmpp_codec.hrl | 2 +- src/ejabberd_c2s.erl | 6 +++- src/xmpp_codec.erl | 5 ++-- test/ejabberd_SUITE.erl | 40 +++++++++++++++------------ test/ejabberd_SUITE_data/ejabberd.yml | 2 +- test/suite.erl | 32 +++++++++++++++------ tools/xmpp_codec.spec | 1 + 7 files changed, 56 insertions(+), 32 deletions(-) diff --git a/include/xmpp_codec.hrl b/include/xmpp_codec.hrl index 5428aad11..8ffb37808 100644 --- a/include/xmpp_codec.hrl +++ b/include/xmpp_codec.hrl @@ -522,7 +522,7 @@ -type version() :: #version{}. -record(bind, {jid :: jid:jid(), - resource :: binary()}). + resource = <<>> :: binary()}). -type bind() :: #bind{}. -record(rosterver_feature, {}). diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 02540259a..f7d8e9dbb 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -907,8 +907,12 @@ wait_for_bind(#sm_resume{} = Pkt, StateData) -> wait_for_bind(Pkt, StateData) when ?IS_STREAM_MGMT_PACKET(Pkt) -> fsm_next_state(wait_for_bind, dispatch_stream_mgmt(Pkt, StateData)); wait_for_bind(#iq{type = set, - sub_els = [#bind{resource = R}]} = IQ, StateData) -> + sub_els = [#bind{resource = R0}]} = IQ, StateData) -> U = StateData#state.user, + R = case R0 of + <<>> -> new_uniq_id(); + _ -> R0 + end, case resource_conflict_action(U, StateData#state.server, R) of closenew -> Err = xmpp:make_error(IQ, xmpp:err_conflict()), diff --git a/src/xmpp_codec.erl b/src/xmpp_codec.erl index a0181e1e6..f8f8b205f 100644 --- a/src/xmpp_codec.erl +++ b/src/xmpp_codec.erl @@ -29737,7 +29737,7 @@ encode_legacy_auth_username_cdata(_val, _acc) -> decode_bind(__TopXMLNS, __IgnoreEls, {xmlel, <<"bind">>, _attrs, _els}) -> {Jid, Resource} = decode_bind_els(__TopXMLNS, - __IgnoreEls, _els, undefined, undefined), + __IgnoreEls, _els, undefined, <<>>), {bind, Jid, Resource}. decode_bind_els(__TopXMLNS, __IgnoreEls, [], Jid, @@ -29800,8 +29800,7 @@ encode_bind({bind, Jid, Resource}, __TopXMLNS) -> 'encode_bind_$jid'(Jid, __TopXMLNS, _acc) -> [encode_bind_jid(Jid, __TopXMLNS) | _acc]. -'encode_bind_$resource'(undefined, __TopXMLNS, _acc) -> - _acc; +'encode_bind_$resource'(<<>>, __TopXMLNS, _acc) -> _acc; 'encode_bind_$resource'(Resource, __TopXMLNS, _acc) -> [encode_bind_resource(Resource, __TopXMLNS) | _acc]. diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index b5aa50bdb..4e02389d4 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -148,9 +148,13 @@ do_init_per_group(component, Config) -> set_opt(server_port, Port, set_opt(stream_version, undefined, set_opt(lang, <<"">>, Config)))))); -do_init_per_group(_GroupName, Config) -> +do_init_per_group(GroupName, Config) -> Pid = start_event_relay(), - set_opt(event_relay, Pid, Config). + NewConfig = set_opt(event_relay, Pid, Config), + case GroupName of + anonymous -> set_opt(anonymous, true, NewConfig); + _ -> NewConfig + end. end_per_group(mnesia, _Config) -> ok; @@ -176,7 +180,7 @@ end_per_group(s2s, _Config) -> ejabberd_config:add_option(s2s_use_starttls, false); end_per_group(_GroupName, Config) -> stop_event_relay(Config), - ok. + set_opt(anonymous, false, Config). init_per_testcase(stop_ejabberd, Config) -> open_session(bind(auth(connect(Config)))); @@ -186,8 +190,8 @@ init_per_testcase(TestCase, OrigConfig) -> name, ?config(tc_group_properties, OrigConfig)), Server = ?config(server, OrigConfig), Resource = case TestGroup of - generic -> - randoms:get_string(); + anonymous -> + <<"">>; legacy_auth -> randoms:get_string(); _ -> @@ -278,7 +282,7 @@ legacy_auth_tests() -> test_legacy_auth_fail]}. no_db_tests() -> - [{generic, [parallel], + [{anonymous, [parallel], [test_connect_bad_xml, test_connect_unexpected_xml, test_connect_unknown_ns, @@ -293,7 +297,6 @@ no_db_tests() -> test_starttls, test_zlib, test_auth, - test_auth_fail, test_bind, test_open_session, codec_failure, @@ -306,7 +309,8 @@ no_db_tests() -> stats, disco]}, {presence_and_s2s, [sequence], - [presence, + [test_auth_fail, + presence, s2s_dialback, s2s_optional, s2s_required, @@ -507,17 +511,17 @@ groups() -> {riak, [sequence], db_tests(riak)}]. all() -> - [{group, ldap}, + [%%{group, ldap}, {group, no_db}, - {group, mnesia}, - {group, redis}, - {group, mysql}, - {group, pgsql}, - {group, sqlite}, - {group, extauth}, - {group, riak}, - {group, component}, - {group, s2s}, + %% {group, mnesia}, + %% {group, redis}, + %% {group, mysql}, + %% {group, pgsql}, + %% {group, sqlite}, + %% {group, extauth}, + %% {group, riak}, + %% {group, component}, + %% {group, s2s}, stop_ejabberd]. stop_ejabberd(Config) -> diff --git a/test/ejabberd_SUITE_data/ejabberd.yml b/test/ejabberd_SUITE_data/ejabberd.yml index 128be2aed..c9ea5fd7a 100644 --- a/test/ejabberd_SUITE_data/ejabberd.yml +++ b/test/ejabberd_SUITE_data/ejabberd.yml @@ -327,7 +327,7 @@ Welcome to this XMPP server." mod_time: [] mod_version: [] "localhost": - auth_method: internal + auth_method: [internal, anonymous] "ldap.localhost": ldap_servers: - "localhost" diff --git a/test/suite.erl b/test/suite.erl index e10c7e0c4..42c5dcfbe 100644 --- a/test/suite.erl +++ b/test/suite.erl @@ -74,6 +74,7 @@ init_config(Config) -> {slave_nick, <<"slave_nick!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, {room_subject, <<"hello, world!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, {certfile, CertFile}, + {anonymous, false}, {type, client}, {xmlns, ?NS_CLIENT}, {ns_stream, ?NS_STREAM}, @@ -253,11 +254,15 @@ auth(Config) -> auth(Config, ShouldFail) -> Type = ?config(type, Config), + IsAnonymous = ?config(anonymous, Config), Mechs = ?config(mechs, Config), HaveMD5 = lists:member(<<"DIGEST-MD5">>, Mechs), HavePLAIN = lists:member(<<"PLAIN">>, Mechs), HaveExternal = lists:member(<<"EXTERNAL">>, Mechs), - if HavePLAIN -> + HaveAnonymous = lists:member(<<"ANONYMOUS">>, Mechs), + if HaveAnonymous and IsAnonymous -> + auth_SASL(<<"ANONYMOUS">>, Config, ShouldFail); + HavePLAIN -> auth_SASL(<<"PLAIN">>, Config, ShouldFail); HaveMD5 -> auth_SASL(<<"DIGEST-MD5">>, Config, ShouldFail); @@ -272,17 +277,25 @@ auth(Config, ShouldFail) -> end. bind(Config) -> + U = ?config(user, Config), + S = ?config(server, Config), + R = ?config(resource, Config), case ?config(type, Config) of client -> - #iq{type = result, sub_els = [#bind{}]} = + #iq{type = result, sub_els = [#bind{jid = JID}]} = send_recv( - Config, - #iq{type = set, - sub_els = [#bind{resource = ?config(resource, Config)}]}); + Config, #iq{type = set, sub_els = [#bind{resource = R}]}), + case ?config(anonymous, Config) of + false -> + {U, S, R} = jid:tolower(JID), + Config; + true -> + {User, S, Resource} = jid:tolower(JID), + set_opt(user, User, set_opt(resource, Resource, Config)) + end; component -> - ok - end, - Config. + Config + end. open_session(Config) -> open_session(Config, false). @@ -478,6 +491,9 @@ sasl_new(<<"PLAIN">>, User, Server, Password) -> sasl_new(<<"EXTERNAL">>, _User, _Server, _Password) -> {<<"">>, fun(_) -> ct:fail(sasl_challenge_is_not_expected) end}; +sasl_new(<<"ANONYMOUS">>, _User, _Server, _Password) -> + {<<"">>, + fun(_) -> ct:fail(sasl_challenge_is_not_expected) end}; sasl_new(<<"DIGEST-MD5">>, User, Server, Password) -> {<<"">>, fun (ServerIn) -> diff --git a/tools/xmpp_codec.spec b/tools/xmpp_codec.spec index 6824cf387..1f9b50066 100644 --- a/tools/xmpp_codec.spec +++ b/tools/xmpp_codec.spec @@ -621,6 +621,7 @@ min = 0, max = 1}, #ref{name = bind_resource, min = 0, max = 1, + default = <<"">>, label = '$resource'}]}). -xml(legacy_auth_username, From d327119cf7d60427a52a58ce3f6f78a389be37e8 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sun, 25 Sep 2016 10:17:03 +0300 Subject: [PATCH 048/151] Text legacy IQ handler support --- test/ejabberd_SUITE.erl | 9 ++++++++ test/ejabberd_SUITE_data/ejabberd.yml | 1 + test/mod_legacy.erl | 32 +++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 test/mod_legacy.erl diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index 4e02389d4..81e35d52a 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -303,6 +303,7 @@ no_db_tests() -> unsupported_query, bad_nonza, invalid_from, + legacy_iq, ping, version, time, @@ -895,6 +896,14 @@ presence_broadcast(Config) -> end, [], [0, 100, 200, 2000, 5000, 10000]), disconnect(Config). +legacy_iq(Config) -> + true = is_feature_advertised(Config, ?NS_EVENT), + ServerJID = server_jid(Config), + #iq{type = result, sub_els = []} = + send_recv(Config, #iq{to = ServerJID, type = get, + sub_els = [#xevent{}]}), + disconnect(Config). + ping(Config) -> true = is_feature_advertised(Config, ?NS_PING), #iq{type = result, sub_els = []} = diff --git a/test/ejabberd_SUITE_data/ejabberd.yml b/test/ejabberd_SUITE_data/ejabberd.yml index c9ea5fd7a..2d2e098de 100644 --- a/test/ejabberd_SUITE_data/ejabberd.yml +++ b/test/ejabberd_SUITE_data/ejabberd.yml @@ -442,6 +442,7 @@ modules: mod_disco: [] mod_ping: [] mod_proxy65: [] + mod_legacy: [] mod_register: welcome_message: subject: "Welcome!" diff --git a/test/mod_legacy.erl b/test/mod_legacy.erl new file mode 100644 index 000000000..6024acfeb --- /dev/null +++ b/test/mod_legacy.erl @@ -0,0 +1,32 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 25 Sep 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(mod_legacy). +-behaviour(gen_mod). + +%% API +-export([start/2, stop/1, process_iq/3]). +-include("jlib.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +start(Host, Opts) -> + IQDisc = gen_mod:get_opt(iqdisc, Opts, fun gen_iq_handler:check_type/1, + one_queue), + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_EVENT, + ?MODULE, process_iq, IQDisc). + +stop(Host) -> + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?MODULE). + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +process_iq(_From, _To, IQ) -> + IQ#iq{type = result, sub_el = []}. From 7566e267a757146e0b333429010aed922ad57766 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Thu, 29 Sep 2016 11:20:56 +0200 Subject: [PATCH 049/151] PubSub: fix error type on item deletion with insufficient priviledge --- src/node_flat.erl | 10 +++++----- src/node_flat_sql.erl | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/node_flat.erl b/src/node_flat.erl index e80aaad34..e3170a263 100644 --- a/src/node_flat.erl +++ b/src/node_flat.erl @@ -419,11 +419,11 @@ delete_item(Nidx, Publisher, PublishModel, ItemId) -> #pubsub_state{affiliation = Affiliation, items = Items} = GenState, Allowed = Affiliation == publisher orelse Affiliation == owner orelse - PublishModel == open orelse - case get_item(Nidx, ItemId) of - {result, #pubsub_item{creation = {_, GenKey}}} -> true; - _ -> false - end, + (PublishModel == open andalso + case get_item(Nidx, ItemId) of + {result, #pubsub_item{creation = {_, GenKey}}} -> true; + _ -> false + end), if not Allowed -> {error, xmpp:err_forbidden()}; true -> diff --git a/src/node_flat_sql.erl b/src/node_flat_sql.erl index 025f6caa8..ac590a1dc 100644 --- a/src/node_flat_sql.erl +++ b/src/node_flat_sql.erl @@ -276,11 +276,11 @@ delete_item(Nidx, Publisher, PublishModel, ItemId) -> {result, Affiliation} = get_affiliation(Nidx, GenKey), Allowed = Affiliation == publisher orelse Affiliation == owner orelse - PublishModel == open orelse - case get_item(Nidx, ItemId) of - {result, #pubsub_item{creation = {_, GenKey}}} -> true; - _ -> false - end, + (PublishModel == open andalso + case get_item(Nidx, ItemId) of + {result, #pubsub_item{creation = {_, GenKey}}} -> true; + _ -> false + end), if not Allowed -> {error, xmpp:err_forbidden()}; true -> From 1de0bb83a0bd42af502e0407f185cd6be0fd4a12 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Thu, 29 Sep 2016 16:10:11 +0200 Subject: [PATCH 050/151] PubSub: creation jid must be bare jid --- src/node_flat_sql.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node_flat_sql.erl b/src/node_flat_sql.erl index ac590a1dc..bd084333b 100644 --- a/src/node_flat_sql.erl +++ b/src/node_flat_sql.erl @@ -1036,6 +1036,6 @@ raw_to_item(Nidx, {ItemId, SJID, Creation, Modification, XML}) -> El -> [El] end, #pubsub_item{itemid = {ItemId, Nidx}, - creation = {ToTime(Creation), JID}, + creation = {ToTime(Creation), jid:remove_resource(JID)}, modification = {ToTime(Modification), JID}, payload = Payload}. From 6a3691ef7ce33c17d379ba40fa0c27f21c5ed75d Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Fri, 7 Oct 2016 10:31:03 +0300 Subject: [PATCH 051/151] Add xdata generator and make some code using it --- Makefile.in | 6 +- include/flex_offline.hrl | 10 + include/muc_register.hrl | 16 + include/muc_request.hrl | 16 + include/muc_roomconfig.hrl | 55 + include/muc_roominfo.hrl | 18 + include/pubsub_get_pending.hrl | 13 + include/pubsub_node_config.hrl | 60 + include/pubsub_publish_options.hrl | 14 + include/pubsub_subscribe_authorization.hrl | 13 + include/pubsub_subscribe_options.hrl | 25 + include/xmpp_codec.hrl | 4 +- specs/flex_offline.cfg | 1 + specs/flex_offline.xdata | 12 + specs/muc_register.cfg | 2 + specs/muc_register.xdata | 37 + specs/muc_request.cfg | 2 + specs/muc_request.xdata | 31 + specs/muc_roomconfig.cfg | 11 + specs/muc_roomconfig.xdata | 192 +++ specs/muc_roominfo.cfg | 11 + specs/muc_roominfo.xdata | 55 + specs/pubsub_get_pending.cfg | 7 + specs/pubsub_get_pending.xdata | 15 + specs/pubsub_node_config.cfg | 8 + specs/pubsub_node_config.xdata | 189 +++ specs/pubsub_publish_options.cfg | 6 + specs/pubsub_publish_options.xdata | 34 + specs/pubsub_subscribe_authorization.cfg | 7 + specs/pubsub_subscribe_authorization.xdata | 27 + specs/pubsub_subscribe_options.cfg | 1 + specs/pubsub_subscribe_options.xdata | 70 + {tools => specs}/xmpp_codec.spec | 29 +- src/ejabberd_captcha.erl | 1 + src/flex_offline.erl | 128 ++ src/mod_caps.erl | 11 +- src/mod_mam.erl | 40 +- src/mod_muc.erl | 30 +- src/mod_muc_room.erl | 933 ++++------- src/mod_offline.erl | 11 +- src/mod_pubsub.erl | 639 +++----- src/muc_register.erl | 364 +++++ src/muc_request.erl | 269 ++++ src/muc_roomconfig.erl | 1675 ++++++++++++++++++++ src/muc_roominfo.erl | 491 ++++++ src/node_flat.erl | 3 +- src/node_flat_sql.erl | 2 +- src/pubsub_get_pending.erl | 130 ++ src/pubsub_node_config.erl | 1666 +++++++++++++++++++ src/pubsub_publish_options.erl | 157 ++ src/pubsub_subscribe_authorization.erl | 279 ++++ src/pubsub_subscribe_options.erl | 508 ++++++ src/xdata_codec.erl | 648 ++++++++ src/xmpp_codec.erl | 33 +- src/xmpp_util.erl | 60 +- test/ejabberd_SUITE.erl | 888 +++++++++-- test/suite.erl | 2 + test/suite.hrl | 8 + 58 files changed, 8719 insertions(+), 1254 deletions(-) create mode 100644 include/flex_offline.hrl create mode 100644 include/muc_register.hrl create mode 100644 include/muc_request.hrl create mode 100644 include/muc_roomconfig.hrl create mode 100644 include/muc_roominfo.hrl create mode 100644 include/pubsub_get_pending.hrl create mode 100644 include/pubsub_node_config.hrl create mode 100644 include/pubsub_publish_options.hrl create mode 100644 include/pubsub_subscribe_authorization.hrl create mode 100644 include/pubsub_subscribe_options.hrl create mode 100644 specs/flex_offline.cfg create mode 100644 specs/flex_offline.xdata create mode 100644 specs/muc_register.cfg create mode 100644 specs/muc_register.xdata create mode 100644 specs/muc_request.cfg create mode 100644 specs/muc_request.xdata create mode 100644 specs/muc_roomconfig.cfg create mode 100644 specs/muc_roomconfig.xdata create mode 100644 specs/muc_roominfo.cfg create mode 100644 specs/muc_roominfo.xdata create mode 100644 specs/pubsub_get_pending.cfg create mode 100644 specs/pubsub_get_pending.xdata create mode 100644 specs/pubsub_node_config.cfg create mode 100644 specs/pubsub_node_config.xdata create mode 100644 specs/pubsub_publish_options.cfg create mode 100644 specs/pubsub_publish_options.xdata create mode 100644 specs/pubsub_subscribe_authorization.cfg create mode 100644 specs/pubsub_subscribe_authorization.xdata create mode 100644 specs/pubsub_subscribe_options.cfg create mode 100644 specs/pubsub_subscribe_options.xdata rename {tools => specs}/xmpp_codec.spec (99%) create mode 100644 src/flex_offline.erl create mode 100644 src/muc_register.erl create mode 100644 src/muc_request.erl create mode 100644 src/muc_roomconfig.erl create mode 100644 src/muc_roominfo.erl create mode 100644 src/pubsub_get_pending.erl create mode 100644 src/pubsub_node_config.erl create mode 100644 src/pubsub_publish_options.erl create mode 100644 src/pubsub_subscribe_authorization.erl create mode 100644 src/pubsub_subscribe_options.erl create mode 100644 src/xdata_codec.erl diff --git a/Makefile.in b/Makefile.in index 07502f06e..728b2fa98 100644 --- a/Makefile.in +++ b/Makefile.in @@ -110,7 +110,11 @@ edoc: spec: $(ERL) -noinput +B -pa ebin -pa deps/*/ebin -eval \ - 'case fxml_gen:compile("tools/xmpp_codec.spec", [{add_type_specs, xmpp_element}, {erl_dir, "src"}, {hrl_dir, "include"}]) of ok -> halt(0); _ -> halt(1) end.' + 'case fxml_gen:compile("specs/xmpp_codec.spec", [{add_type_specs, xmpp_element}, {erl_dir, "src"}, {hrl_dir, "include"}]) of ok -> halt(0); _ -> halt(1) end.' + +xdata: + $(ERL) -noinput +B -pa ebin -pa deps/*/ebin -eval \ + 'case xdata_codec:compile("specs", [{erl_dir, "src"}, {hrl_dir, "include"}]) of ok -> halt(0); _ -> halt(1) end.' JOIN_PATHS=$(if $(wordlist 2,1000,$(1)),$(firstword $(1))/$(call JOIN_PATHS,$(wordlist 2,1000,$(1))),$(1)) diff --git a/include/flex_offline.hrl b/include/flex_offline.hrl new file mode 100644 index 000000000..74a38fbb3 --- /dev/null +++ b/include/flex_offline.hrl @@ -0,0 +1,10 @@ +%% Created automatically by xdata generator (xdata_codec.erl) +%% Source: flex_offline.xdata +%% Form type: http://jabber.org/protocol/offline +%% Document: XEP-0013 + + +-type property() :: {'number_of_messages', non_neg_integer()}. +-type result() :: [property()]. + +-type form() :: [property() | xdata_field()]. diff --git a/include/muc_register.hrl b/include/muc_register.hrl new file mode 100644 index 000000000..0cfc928c2 --- /dev/null +++ b/include/muc_register.hrl @@ -0,0 +1,16 @@ +%% Created automatically by xdata generator (xdata_codec.erl) +%% Source: muc_register.xdata +%% Form type: http://jabber.org/protocol/muc#register +%% Document: XEP-0045 + + +-type property() :: {'allow', boolean()} | + {'email', binary()} | + {'faqentry', [binary()]} | + {'first', binary()} | + {'last', binary()} | + {'roomnick', binary()} | + {'url', binary()}. +-type result() :: [property()]. + +-type form() :: [property() | xdata_field()]. diff --git a/include/muc_request.hrl b/include/muc_request.hrl new file mode 100644 index 000000000..bc14be35f --- /dev/null +++ b/include/muc_request.hrl @@ -0,0 +1,16 @@ +%% Created automatically by xdata generator (xdata_codec.erl) +%% Source: muc_request.xdata +%% Form type: http://jabber.org/protocol/muc#request +%% Document: XEP-0045 + + +-type property() :: {'role', participant} | + {'jid', jid:jid()} | + {'roomnick', binary()} | + {'request_allow', boolean()}. +-type result() :: [property()]. + +-type options(T) :: [{binary(), T}]. +-type property_with_options() :: + {'role', participant, options(participant)}. +-type form() :: [property() | property_with_options() | xdata_field()]. diff --git a/include/muc_roomconfig.hrl b/include/muc_roomconfig.hrl new file mode 100644 index 000000000..89cfc3346 --- /dev/null +++ b/include/muc_roomconfig.hrl @@ -0,0 +1,55 @@ +%% Created automatically by xdata generator (xdata_codec.erl) +%% Source: muc_roomconfig.xdata +%% Form type: http://jabber.org/protocol/muc#roomconfig +%% Document: XEP-0045 + +-type 'allow_private_messages_from_visitors'() :: nobody | moderators | anyone. +-type 'maxusers'() :: none | non_neg_integer(). +-type 'presencebroadcast'() :: moderator | participant | visitor. +-type 'whois'() :: moderators | anyone. + +-type property() :: {'maxhistoryfetch', binary()} | + {'allowpm', binary()} | + {'allow_private_messages', boolean()} | + {'allow_private_messages_from_visitors', 'allow_private_messages_from_visitors'()} | + {'allow_visitor_status', boolean()} | + {'allow_visitor_nickchange', boolean()} | + {'allow_voice_requests', boolean()} | + {'allow_subscription', boolean()} | + {'voice_request_min_interval', non_neg_integer()} | + {'captcha_protected', boolean()} | + {'captcha_whitelist', [jid:jid()]} | + {'allow_query_users', boolean()} | + {'allowinvites', boolean()} | + {'changesubject', boolean()} | + {'enablelogging', boolean()} | + {'getmemberlist', [binary()]} | + {'lang', binary()} | + {'pubsub', binary()} | + {'maxusers', 'maxusers'()} | + {'membersonly', boolean()} | + {'moderatedroom', boolean()} | + {'members_by_default', boolean()} | + {'passwordprotectedroom', boolean()} | + {'persistentroom', boolean()} | + {'presencebroadcast', ['presencebroadcast'()]} | + {'publicroom', boolean()} | + {'public_list', boolean()} | + {'roomadmins', [jid:jid()]} | + {'roomdesc', binary()} | + {'roomname', binary()} | + {'roomowners', [jid:jid()]} | + {'roomsecret', binary()} | + {'whois', 'whois'()} | + {'mam', boolean()}. +-type result() :: [property()]. + +-type options(T) :: [{binary(), T}]. +-type property_with_options() :: + {'allowpm', binary(), options(binary())} | + {'allow_private_messages_from_visitors', 'allow_private_messages_from_visitors'(), options('allow_private_messages_from_visitors'())} | + {'getmemberlist', [binary()], options(binary())} | + {'maxusers', 'maxusers'(), options('maxusers'())} | + {'presencebroadcast', ['presencebroadcast'()], options('presencebroadcast'())} | + {'whois', 'whois'(), options('whois'())}. +-type form() :: [property() | property_with_options() | xdata_field()]. diff --git a/include/muc_roominfo.hrl b/include/muc_roominfo.hrl new file mode 100644 index 000000000..cf4f4ebf0 --- /dev/null +++ b/include/muc_roominfo.hrl @@ -0,0 +1,18 @@ +%% Created automatically by xdata generator (xdata_codec.erl) +%% Source: muc_roominfo.xdata +%% Form type: http://jabber.org/protocol/muc#roominfo +%% Document: XEP-0045 + + +-type property() :: {'maxhistoryfetch', non_neg_integer()} | + {'contactjid', [jid:jid()]} | + {'description', binary()} | + {'lang', binary()} | + {'ldapgroup', binary()} | + {'logs', binary()} | + {'occupants', non_neg_integer()} | + {'subject', binary()} | + {'subjectmod', boolean()}. +-type result() :: [property()]. + +-type form() :: [property() | xdata_field()]. diff --git a/include/pubsub_get_pending.hrl b/include/pubsub_get_pending.hrl new file mode 100644 index 000000000..4ddf9bad0 --- /dev/null +++ b/include/pubsub_get_pending.hrl @@ -0,0 +1,13 @@ +%% Created automatically by xdata generator (xdata_codec.erl) +%% Source: pubsub_get_pending.xdata +%% Form type: http://jabber.org/protocol/pubsub#subscribe_authorization +%% Document: XEP-0060 + + +-type property() :: {'node', binary()}. +-type result() :: [property()]. + +-type options(T) :: [{binary(), T}]. +-type property_with_options() :: + {'node', binary(), options(binary())}. +-type form() :: [property() | property_with_options() | xdata_field()]. diff --git a/include/pubsub_node_config.hrl b/include/pubsub_node_config.hrl new file mode 100644 index 000000000..e1519cdc0 --- /dev/null +++ b/include/pubsub_node_config.hrl @@ -0,0 +1,60 @@ +%% Created automatically by xdata generator (xdata_codec.erl) +%% Source: pubsub_node_config.xdata +%% Form type: http://jabber.org/protocol/pubsub#node_config +%% Document: XEP-0060 + +-type 'access_model'() :: authorize | open | presence | roster | whitelist. +-type 'children_association_policy'() :: all | owners | whitelist. +-type 'itemreply'() :: owner | publisher | none. +-type 'node_type'() :: leaf | collection. +-type 'notification_type'() :: normal | headline. +-type 'publish_model'() :: publishers | subscribers | open. +-type 'send_last_published_item'() :: never | on_sub | on_sub_and_presence. + +-type property() :: {'access_model', 'access_model'()} | + {'body_xslt', binary()} | + {'children_association_policy', 'children_association_policy'()} | + {'children_association_whitelist', [jid:jid()]} | + {'children', [binary()]} | + {'children_max', binary()} | + {'collection', [binary()]} | + {'contact', [jid:jid()]} | + {'dataform_xslt', binary()} | + {'deliver_notifications', boolean()} | + {'deliver_payloads', boolean()} | + {'description', binary()} | + {'item_expire', binary()} | + {'itemreply', 'itemreply'()} | + {'language', binary()} | + {'max_items', non_neg_integer()} | + {'max_payload_size', non_neg_integer()} | + {'node_type', 'node_type'()} | + {'notification_type', 'notification_type'()} | + {'notify_config', boolean()} | + {'notify_delete', boolean()} | + {'notify_retract', boolean()} | + {'notify_sub', boolean()} | + {'persist_items', boolean()} | + {'presence_based_delivery', boolean()} | + {'publish_model', 'publish_model'()} | + {'purge_offline', boolean()} | + {'roster_groups_allowed', [binary()]} | + {'send_last_published_item', 'send_last_published_item'()} | + {'tempsub', boolean()} | + {'subscribe', boolean()} | + {'title', binary()} | + {'type', binary()}. +-type result() :: [property()]. + +-type options(T) :: [{binary(), T}]. +-type property_with_options() :: + {'access_model', 'access_model'(), options('access_model'())} | + {'children_association_policy', 'children_association_policy'(), options('children_association_policy'())} | + {'itemreply', 'itemreply'(), options('itemreply'())} | + {'language', binary(), options(binary())} | + {'node_type', 'node_type'(), options('node_type'())} | + {'notification_type', 'notification_type'(), options('notification_type'())} | + {'publish_model', 'publish_model'(), options('publish_model'())} | + {'roster_groups_allowed', [binary()], options(binary())} | + {'send_last_published_item', 'send_last_published_item'(), options('send_last_published_item'())}. +-type form() :: [property() | property_with_options() | xdata_field()]. diff --git a/include/pubsub_publish_options.hrl b/include/pubsub_publish_options.hrl new file mode 100644 index 000000000..3b04b4826 --- /dev/null +++ b/include/pubsub_publish_options.hrl @@ -0,0 +1,14 @@ +%% Created automatically by xdata generator (xdata_codec.erl) +%% Source: pubsub_publish_options.xdata +%% Form type: http://jabber.org/protocol/pubsub#publish-options +%% Document: XEP-0060 + +-type 'access_model'() :: authorize | open | presence | roster | whitelist. + +-type property() :: {'access_model', 'access_model'()}. +-type result() :: [property()]. + +-type options(T) :: [{binary(), T}]. +-type property_with_options() :: + {'access_model', 'access_model'(), options('access_model'())}. +-type form() :: [property() | property_with_options() | xdata_field()]. diff --git a/include/pubsub_subscribe_authorization.hrl b/include/pubsub_subscribe_authorization.hrl new file mode 100644 index 000000000..fb67ab47a --- /dev/null +++ b/include/pubsub_subscribe_authorization.hrl @@ -0,0 +1,13 @@ +%% Created automatically by xdata generator (xdata_codec.erl) +%% Source: pubsub_subscribe_authorization.xdata +%% Form type: http://jabber.org/protocol/pubsub#subscribe_authorization +%% Document: XEP-0060 + + +-type property() :: {'allow', boolean()} | + {'node', binary()} | + {'subscriber_jid', jid:jid()} | + {'subid', binary()}. +-type result() :: [property()]. + +-type form() :: [property() | xdata_field()]. diff --git a/include/pubsub_subscribe_options.hrl b/include/pubsub_subscribe_options.hrl new file mode 100644 index 000000000..9a05822a5 --- /dev/null +++ b/include/pubsub_subscribe_options.hrl @@ -0,0 +1,25 @@ +%% Created automatically by xdata generator (xdata_codec.erl) +%% Source: pubsub_subscribe_options.xdata +%% Form type: http://jabber.org/protocol/pubsub#subscribe_options +%% Document: XEP-0060 + +-type 'show-values'() :: away | chat | dnd | online | xa. +-type 'subscription_type'() :: items | nodes. +-type 'subscription_depth'() :: 1 | all. + +-type property() :: {'deliver', boolean()} | + {'digest', boolean()} | + {'digest_frequency', binary()} | + {'expire', binary()} | + {'include_body', boolean()} | + {'show-values', ['show-values'()]} | + {'subscription_type', 'subscription_type'()} | + {'subscription_depth', 'subscription_depth'()}. +-type result() :: [property()]. + +-type options(T) :: [{binary(), T}]. +-type property_with_options() :: + {'show-values', ['show-values'()], options('show-values'())} | + {'subscription_type', 'subscription_type'(), options('subscription_type'())} | + {'subscription_depth', 'subscription_depth'(), options('subscription_depth'())}. +-type form() :: [property() | property_with_options() | xdata_field()]. diff --git a/include/xmpp_codec.hrl b/include/xmpp_codec.hrl index 8ffb37808..443769bb7 100644 --- a/include/xmpp_codec.hrl +++ b/include/xmpp_codec.hrl @@ -8,7 +8,7 @@ -record(ps_affiliation, {xmlns = <<>> :: binary(), node = <<>> :: binary(), type :: member | none | outcast | - owner | publisher | 'publish-only', + owner | publisher | publish_only, jid :: jid:jid()}). -type ps_affiliation() :: #ps_affiliation{}. @@ -510,7 +510,7 @@ type :: 'boolean' | 'fixed' | 'hidden' | 'jid-multi' | 'jid-single' | 'list-multi' | 'list-single' | 'text-multi' | 'text-private' | 'text-single', var = <<>> :: binary(), required = false :: boolean(), - desc :: binary(), + desc = <<>> :: binary(), values = [] :: [binary()], options = [] :: [#xdata_option{}], sub_els = [] :: [xmpp_element() | fxml:xmlel()]}). diff --git a/specs/flex_offline.cfg b/specs/flex_offline.cfg new file mode 100644 index 000000000..5d5b2685e --- /dev/null +++ b/specs/flex_offline.cfg @@ -0,0 +1 @@ +[{decode, [{<<"number_of_messages">>, {dec_int, [0, infinity]}}]}]. diff --git a/specs/flex_offline.xdata b/specs/flex_offline.xdata new file mode 100644 index 000000000..d0c786289 --- /dev/null +++ b/specs/flex_offline.xdata @@ -0,0 +1,12 @@ + + http://jabber.org/protocol/offline + XEP-0013 + + Service Discovery extension for number of messages + in an offline message queue. + + + diff --git a/specs/muc_register.cfg b/specs/muc_register.cfg new file mode 100644 index 000000000..3efd0cf0b --- /dev/null +++ b/specs/muc_register.cfg @@ -0,0 +1,2 @@ +[{prefix, <<"muc#register_">>}, + {required, [<<"muc#register_roomnick">>]}]. diff --git a/specs/muc_register.xdata b/specs/muc_register.xdata new file mode 100644 index 000000000..e808b44e0 --- /dev/null +++ b/specs/muc_register.xdata @@ -0,0 +1,37 @@ + + http://jabber.org/protocol/muc#register + XEP-0045 + + Forms enabling user registration with a + Multi-User Chat (MUC) room or admin approval + of user registration requests. + + + + + + + + + diff --git a/specs/muc_request.cfg b/specs/muc_request.cfg new file mode 100644 index 000000000..4811b32e2 --- /dev/null +++ b/specs/muc_request.cfg @@ -0,0 +1,2 @@ +[{prefix, <<"muc#">>}, + {required, [<<"muc#role">>]}]. diff --git a/specs/muc_request.xdata b/specs/muc_request.xdata new file mode 100644 index 000000000..64fa1388b --- /dev/null +++ b/specs/muc_request.xdata @@ -0,0 +1,31 @@ + + http://jabber.org/protocol/muc#request + XEP-0045 + + Forms enabling voice requests in a + Multi-User Chat (MUC) room or admin + approval of such requests. + + + + + + + + + + diff --git a/specs/muc_roomconfig.cfg b/specs/muc_roomconfig.cfg new file mode 100644 index 000000000..de16099d5 --- /dev/null +++ b/specs/muc_roomconfig.cfg @@ -0,0 +1,11 @@ +[{prefix, <<"muc#roomconfig_">>}, + {prefix, <<"muc#">>}, + {decode, [{<<"muc#roomconfig_maxusers">>, + {dec_enum_int, [[none], 0, infinity]}}, + {<<"voice_request_min_interval">>, + {dec_int, [0, infinity]}}]}]. + +%% Local Variables: +%% mode: erlang +%% End: +%% vim: set filetype=erlang tabstop=8: diff --git a/specs/muc_roomconfig.xdata b/specs/muc_roomconfig.xdata new file mode 100644 index 000000000..cab6465dc --- /dev/null +++ b/specs/muc_roomconfig.xdata @@ -0,0 +1,192 @@ + + http://jabber.org/protocol/muc#roomconfig + XEP-0045 + + Forms enabling creation and configuration of + a Multi-User Chat (MUC) room. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/specs/muc_roominfo.cfg b/specs/muc_roominfo.cfg new file mode 100644 index 000000000..98a985e7b --- /dev/null +++ b/specs/muc_roominfo.cfg @@ -0,0 +1,11 @@ +[{prefix, <<"muc#roominfo_">>}, + {prefix, <<"muc#">>}, + {decode, [{<<"muc#maxhistoryfetch">>, + {dec_int, [0, infinity]}}, + {<<"muc#roominfo_occupants">>, + {dec_int, [0, infinity]}}]}]. + +%% Local Variables: +%% mode: erlang +%% End: +%% vim: set filetype=erlang tabstop=8: diff --git a/specs/muc_roominfo.xdata b/specs/muc_roominfo.xdata new file mode 100644 index 000000000..70f696383 --- /dev/null +++ b/specs/muc_roominfo.xdata @@ -0,0 +1,55 @@ + + http://jabber.org/protocol/muc#roominfo + XEP-0045 + + Forms enabling the communication of extended service discovery + information about a Multi-User Chat (MUC) room. + + + + + + + + + + + + + diff --git a/specs/pubsub_get_pending.cfg b/specs/pubsub_get_pending.cfg new file mode 100644 index 000000000..4ae57ac88 --- /dev/null +++ b/specs/pubsub_get_pending.cfg @@ -0,0 +1,7 @@ +[{prefix, <<"pubsub#">>}, + {required, [<<"pubsub#node">>]}]. + +%% Local Variables: +%% mode: erlang +%% End: +%% vim: set filetype=erlang tabstop=8: diff --git a/specs/pubsub_get_pending.xdata b/specs/pubsub_get_pending.xdata new file mode 100644 index 000000000..1a6f55297 --- /dev/null +++ b/specs/pubsub_get_pending.xdata @@ -0,0 +1,15 @@ + + http://jabber.org/protocol/pubsub#subscribe_authorization + XEP-0060 + Forms enabling authorization of subscriptions to pubsub nodes + + + + diff --git a/specs/pubsub_node_config.cfg b/specs/pubsub_node_config.cfg new file mode 100644 index 000000000..f3bf72d2d --- /dev/null +++ b/specs/pubsub_node_config.cfg @@ -0,0 +1,8 @@ +[{prefix, <<"pubsub#">>}, + {decode, [{<<"pubsub#max_items">>, {dec_int, [0,infinity]}}, + {<<"pubsub#max_payload_size">>, {dec_int, [0,infinity]}}]}]. + +%% Local Variables: +%% mode: erlang +%% End: +%% vim: set filetype=erlang tabstop=8: diff --git a/specs/pubsub_node_config.xdata b/specs/pubsub_node_config.xdata new file mode 100644 index 000000000..1691808f7 --- /dev/null +++ b/specs/pubsub_node_config.xdata @@ -0,0 +1,189 @@ + + http://jabber.org/protocol/pubsub#node_config + XEP-0060 + Forms enabling configuration of pubsub nodes + + + + + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + diff --git a/specs/pubsub_publish_options.cfg b/specs/pubsub_publish_options.cfg new file mode 100644 index 000000000..2a853e834 --- /dev/null +++ b/specs/pubsub_publish_options.cfg @@ -0,0 +1,6 @@ +[{prefix, <<"pubsub#">>}]. + +%% Local Variables: +%% mode: erlang +%% End: +%% vim: set filetype=erlang tabstop=8: diff --git a/specs/pubsub_publish_options.xdata b/specs/pubsub_publish_options.xdata new file mode 100644 index 000000000..26cac6ad5 --- /dev/null +++ b/specs/pubsub_publish_options.xdata @@ -0,0 +1,34 @@ + + http://jabber.org/protocol/pubsub#publish-options + XEP-0060 + + Forms enabling publication with options; each field must specify whether it + defines METADATA to be attached to the item, a per-item OVERRIDE of the node + configuration, or a PRECONDITION to be checked against the node configuration. + + + + + + + + + + + diff --git a/specs/pubsub_subscribe_authorization.cfg b/specs/pubsub_subscribe_authorization.cfg new file mode 100644 index 000000000..1f38fdb27 --- /dev/null +++ b/specs/pubsub_subscribe_authorization.cfg @@ -0,0 +1,7 @@ +[{prefix, <<"pubsub#">>}, + {required, [<<"pubsub#node">>, <<"pubsub#subscriber_jid">>, <<"pubsub#allow">>]}]. + +%% Local Variables: +%% mode: erlang +%% End: +%% vim: set filetype=erlang tabstop=8: diff --git a/specs/pubsub_subscribe_authorization.xdata b/specs/pubsub_subscribe_authorization.xdata new file mode 100644 index 000000000..250d8754b --- /dev/null +++ b/specs/pubsub_subscribe_authorization.xdata @@ -0,0 +1,27 @@ + + http://jabber.org/protocol/pubsub#subscribe_authorization + XEP-0060 + Forms enabling authorization of subscriptions to pubsub nodes + + + + + + + diff --git a/specs/pubsub_subscribe_options.cfg b/specs/pubsub_subscribe_options.cfg new file mode 100644 index 000000000..e4ac06ad9 --- /dev/null +++ b/specs/pubsub_subscribe_options.cfg @@ -0,0 +1 @@ +[{prefix, <<"pubsub#">>}]. diff --git a/specs/pubsub_subscribe_options.xdata b/specs/pubsub_subscribe_options.xdata new file mode 100644 index 000000000..59b134676 --- /dev/null +++ b/specs/pubsub_subscribe_options.xdata @@ -0,0 +1,70 @@ + + http://jabber.org/protocol/pubsub#subscribe_options + XEP-0060 + Forms enabling configuration of subscription options for pubsub nodes + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/xmpp_codec.spec b/specs/xmpp_codec.spec similarity index 99% rename from tools/xmpp_codec.spec rename to specs/xmpp_codec.spec index 1f9b50066..81f674bf3 100644 --- a/tools/xmpp_codec.spec +++ b/specs/xmpp_codec.spec @@ -1610,6 +1610,7 @@ default = false, min = 0, max = 1}, #ref{name = xdata_field_desc, + default = <<"">>, label = '$desc', min = 0, max = 1}, #ref{name = xdata_field_value, @@ -1682,7 +1683,7 @@ -record(ps_affiliation, {xmlns = <<>> :: binary(), node = <<>> :: binary(), type :: member | none | outcast | - owner | publisher | 'publish-only', + owner | publisher | publish_only, jid :: jid:jid()}). -type ps_affiliation() :: #ps_affiliation{}. @@ -1695,9 +1696,8 @@ #attr{name = <<"affiliation">>, label = '$type', required = true, - dec = {dec_enum, [[member, none, outcast, owner, - publisher, 'publish-only']]}, - enc = {enc_enum, []}}]}). + dec = {dec_ps_aff, []}, + enc = {enc_ps_aff, []}}]}). -xml(pubsub_owner_affiliation, #elem{name = <<"affiliation">>, @@ -1711,9 +1711,8 @@ #attr{name = <<"affiliation">>, label = '$type', required = true, - dec = {dec_enum, [[member, none, outcast, owner, - publisher, 'publish-only']]}, - enc = {enc_enum, []}}]}). + dec = {dec_ps_aff, []}, + enc = {enc_ps_aff, []}}]}). -xml(pubsub_event_configuration, #elem{name = <<"configuration">>, @@ -3501,6 +3500,22 @@ dec_version(S) -> enc_version({Maj, Min}) -> <<(integer_to_binary(Maj))/binary, $., (integer_to_binary(Min))/binary>>. +-spec dec_ps_aff(_) -> member | none | outcast | + owner | publisher | publish_only. +dec_ps_aff(<<"member">>) -> member; +dec_ps_aff(<<"none">>) -> none; +dec_ps_aff(<<"outcast">>) -> outcast; +dec_ps_aff(<<"owner">>) -> owner; +dec_ps_aff(<<"publisher">>) -> publisher; +dec_ps_aff(<<"publish-only">>) -> publish_only. + +enc_ps_aff(member) -> <<"member">>; +enc_ps_aff(none) -> <<"none">>; +enc_ps_aff(outcast) -> <<"outcast">>; +enc_ps_aff(owner) -> <<"owner">>; +enc_ps_aff(publisher) -> <<"publisher">>; +enc_ps_aff(publish_only) -> <<"publish-only">>. + %% Local Variables: %% mode: erlang %% End: diff --git a/src/ejabberd_captcha.erl b/src/ejabberd_captcha.erl index 9650f3773..a122eda8e 100644 --- a/src/ejabberd_captcha.erl +++ b/src/ejabberd_captcha.erl @@ -73,6 +73,7 @@ captcha_text(Lang) -> mk_ocr_field(Lang, CID, Type) -> URI = #media_uri{type = Type, uri = <<"cid:", CID/binary>>}, #xdata_field{var = <<"ocr">>, + type = 'text-single', label = captcha_text(Lang), required = true, sub_els = [#media{uri = [URI]}]}. diff --git a/src/flex_offline.erl b/src/flex_offline.erl new file mode 100644 index 000000000..090ab3ddf --- /dev/null +++ b/src/flex_offline.erl @@ -0,0 +1,128 @@ +%% Created automatically by xdata generator (xdata_codec.erl) +%% Source: flex_offline.xdata +%% Form type: http://jabber.org/protocol/offline +%% Document: XEP-0013 + +-module(flex_offline). + +-export([decode/1, decode/2, encode/1, encode/2, + format_error/1]). + +-include("xmpp_codec.hrl"). + +-include("flex_offline.hrl"). + +-export_type([{property, 0}, {result, 0}, {form, 0}]). + +dec_int(Val, Min, Max) -> + case list_to_integer(binary_to_list(Val)) of + Int when Int =< Max, Min == infinity -> Int; + Int when Int =< Max, Int >= Min -> Int + end. + +enc_int(Int) -> integer_to_binary(Int). + +format_error({form_type_mismatch, Type}) -> + <<"FORM_TYPE doesn't match '", Type/binary, "'">>; +format_error({bad_var_value, Var, Type}) -> + <<"Bad value of field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({missing_value, Var, Type}) -> + <<"Missing value of field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({too_many_values, Var, Type}) -> + <<"Too many values for field '", Var/binary, + "' of type '", Type/binary, "'">>; +format_error({unknown_var, Var, Type}) -> + <<"Unknown field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({missing_required_var, Var, Type}) -> + <<"Missing required field '", Var/binary, "' of type '", + Type/binary, "'">>. + +decode(Fs) -> decode(Fs, []). + +decode(Fs, Acc) -> + case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var, + Fs) + of + false -> decode(Fs, Acc, []); + #xdata_field{values = + [<<"http://jabber.org/protocol/offline">>]} -> + decode(Fs, Acc, []); + _ -> + erlang:error({?MODULE, + {form_type_mismatch, + <<"http://jabber.org/protocol/offline">>}}) + end. + +encode(Cfg) -> encode(Cfg, fun (Text) -> Text end). + +encode(List, Translate) when is_list(List) -> + Fs = [case Opt of + {number_of_messages, Val} -> + [encode_number_of_messages(Val, Translate)]; + {number_of_messages, _, _} -> + erlang:error({badarg, Opt}); + #xdata_field{} -> [Opt]; + _ -> [] + end + || Opt <- List], + FormType = #xdata_field{var = <<"FORM_TYPE">>, + type = hidden, + values = + [<<"http://jabber.org/protocol/offline">>]}, + [FormType | lists:flatten(Fs)]. + +decode([#xdata_field{var = <<"number_of_messages">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_int(Value, 0, infinity) of + Result -> + decode(Fs, [{number_of_messages, Result} | Acc], + lists:delete(<<"number_of_messages">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"number_of_messages">>, + <<"http://jabber.org/protocol/offline">>}}) + end; +decode([#xdata_field{var = <<"number_of_messages">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"number_of_messages">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"number_of_messages">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"number_of_messages">>, + <<"http://jabber.org/protocol/offline">>}}); +decode([#xdata_field{var = Var} | Fs], Acc, Required) -> + if Var /= <<"FORM_TYPE">> -> + erlang:error({?MODULE, + {unknown_var, Var, + <<"http://jabber.org/protocol/offline">>}}); + true -> decode(Fs, Acc, Required) + end; +decode([], _, [Var | _]) -> + erlang:error({?MODULE, + {missing_required_var, Var, + <<"http://jabber.org/protocol/offline">>}}); +decode([], Acc, []) -> Acc. + +encode_number_of_messages(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_int(Value)] + end, + Opts = [], + #xdata_field{var = <<"number_of_messages">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = Translate(<<"Number of Offline Messages">>)}. diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 4d9bdd61f..65a745d2d 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -488,14 +488,11 @@ concat_identities(#disco_info{identities = Identities}) -> -spec concat_info(disco_info()) -> iolist(). concat_info(#disco_info{xdata = Xs}) -> lists:sort( - [concat_xdata_fields(Fs) || #xdata{type = result, fields = Fs} <- Xs]). + [concat_xdata_fields(X) || #xdata{type = result} = X <- Xs]). --spec concat_xdata_fields([xdata_field()]) -> iolist(). -concat_xdata_fields(Fields) -> - Form = case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var, Fields) of - #xdata_field{values = Values} -> Values; - false -> [] - end, +-spec concat_xdata_fields(xdata()) -> iolist(). +concat_xdata_fields(#xdata{fields = Fields} = X) -> + Form = xmpp_util:get_xdata_values(<<"FORM_TYPE">>, X), Res = [[Var, $<, lists:sort([[Val, $<] || Val <- Values])] || #xdata_field{var = Var, values = Values} <- Fields, is_binary(Var), Var /= <<"FORM_TYPE">>], diff --git a/src/mod_mam.erl b/src/mod_mam.erl index 8569ee020..1daae5aa2 100644 --- a/src/mod_mam.erl +++ b/src/mod_mam.erl @@ -37,7 +37,7 @@ process_iq_v0_2/1, process_iq_v0_3/1, disco_sm_features/5, remove_user/2, remove_room/3, mod_opt_type/1, muc_process_iq/2, muc_filter_message/5, message_is_archived/5, delete_old_messages/2, - get_commands_spec/0, msg_to_el/4, get_room_config/4, set_room_option/4]). + get_commands_spec/0, msg_to_el/4, get_room_config/4, set_room_option/3]). -include("xmpp.hrl"). -include("logger.hrl"). @@ -191,39 +191,17 @@ remove_room(LServer, Name, Host) -> Mod:remove_room(LServer, LName, LHost), ok. --spec get_room_config([xdata_field()], mod_muc_room:state(), jid(), binary()) - -> [xdata_field()]. -get_room_config(XFields, RoomState, _From, Lang) -> +-spec get_room_config([muc_roomconfig:property()], mod_muc_room:state(), + jid(), binary()) -> [muc_roomconfig:property()]. +get_room_config(Fields, RoomState, _From, _Lang) -> Config = RoomState#state.config, - Label = <<"Enable message archiving">>, - Var = <<"muc#roomconfig_mam">>, - Val = case Config#config.mam of - true -> <<"1">>; - _ -> <<"0">> - end, - XField = #xdata_field{type = boolean, - label = translate:translate(Lang, Label), - var = Var, - values = [Val]}, - XFields ++ [XField]. + Fields ++ [{mam, Config#config.mam}]. --spec set_room_option({pos_integer(), _}, binary(), [binary()], binary()) +-spec set_room_option({pos_integer(), _}, muc_roomconfig:property(), binary()) -> {pos_integer(), _}. -set_room_option(_Acc, <<"muc#roomconfig_mam">> = Opt, Vals, Lang) -> - try - Val = case Vals of - [<<"0">>|_] -> false; - [<<"false">>|_] -> false; - [<<"1">>|_] -> true; - [<<"true">>|_] -> true - end, - {#config.mam, Val} - catch _:{case_clause, _} -> - Txt = <<"Value of '~s' should be boolean">>, - ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), - {error, xmpp:err_bad_request(ErrTxt, Lang)} - end; -set_room_option(Acc, _Opt, _Vals, _Lang) -> +set_room_option(_Acc, {mam, Val}, _Lang) -> + {#config.mam, Val}; +set_room_option(Acc, _Property, _Lang) -> Acc. -spec user_receive_packet(stanza(), ejabberd_c2s:state(), jid(), jid(), jid()) -> stanza(). diff --git a/src/mod_muc.erl b/src/mod_muc.erl index 66604394b..b189508a8 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -668,19 +668,18 @@ get_nick(ServerHost, Host, From) -> Mod:get_nick(LServer, Host, From). iq_get_register_info(ServerHost, Host, From, Lang) -> - {Nick, NickVals, Registered} = case get_nick(ServerHost, Host, From) of - error -> {<<"">>, [], false}; - N -> {N, [N], true} - end, + {Nick, Registered} = case get_nick(ServerHost, Host, From) of + error -> {<<"">>, false}; + N -> {N, true} + end, Title = <<(translate:translate( Lang, <<"Nickname Registration at ">>))/binary, Host/binary>>, Inst = translate:translate(Lang, <<"Enter nickname you want to register">>), - Field = #xdata_field{type = 'text-single', - label = translate:translate(Lang, <<"Nickname">>), - var = <<"nick">>, - values = NickVals}, + Fields = muc_register:encode( + [{roomnick, Nick}], + fun(T) -> translate:translate(Lang, T) end), X = #xdata{type = form, title = Title, - instructions = [Inst], fields = [Field]}, + instructions = [Inst], fields = Fields}, #register{nick = Nick, registered = Registered, instructions = @@ -717,12 +716,13 @@ process_iq_register_set(ServerHost, Host, From, #register{nick = Nick, xdata = XData}, Lang) -> case XData of #xdata{type = submit, fields = Fs} -> - case lists:keyfind(<<"nick">>, #xdata_field.var, Fs) of - #xdata_field{values = [N]} -> - iq_set_register_info(ServerHost, Host, From, N, Lang); - _ -> - ErrText = <<"You must fill in field \"Nickname\" in the form">>, - {error, xmpp:err_not_acceptable(ErrText, Lang)} + try + Options = muc_register:decode(Fs), + N = proplists:get_value(roomnick, Options), + iq_set_register_info(ServerHost, Host, From, N, Lang) + catch _:{muc_register, Why} -> + ErrText = muc_register:format_error(Why), + {error, xmpp:err_bad_request(ErrText, Lang)} end; #xdata{} -> Txt = <<"Incorrect data form">>, diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl index 339b85ecb..52401f835 100644 --- a/src/mod_muc_room.erl +++ b/src/mod_muc_room.erl @@ -754,100 +754,131 @@ process_groupchat_message(From, #message{lang = Lang} = Packet, StateData) -> -spec process_normal_message(jid(), message(), state()) -> state(). process_normal_message(From, #message{lang = Lang} = Pkt, StateData) -> - IsInvitation = is_invitation(Pkt), - IsVoiceRequest = is_voice_request(Pkt) and - is_visitor(From, StateData), - IsVoiceApprovement = is_voice_approvement(Pkt) and - not is_visitor(From, StateData), - if IsInvitation -> - case check_invitation(From, Pkt, StateData) of - {error, Error} -> - ejabberd_router:route_error(StateData#state.jid, From, Pkt, Error), - StateData; - IJID -> - Config = StateData#state.config, - case Config#config.members_only of - true -> - case get_affiliation(IJID, StateData) of - none -> - NSD = set_affiliation(IJID, member, StateData), - send_affiliation(IJID, member, StateData), - store_room(NSD), - NSD; - _ -> - StateData - end; - false -> - StateData - end - end; - IsVoiceRequest -> - case (StateData#state.config)#config.allow_voice_requests of + Action = lists:foldl( + fun(_, {error, _} = Err) -> + Err; + (#muc_user{invites = [#muc_invite{to = undefined}]}, _) -> + Txt = <<"No 'to' attribute found">>, + {error, xmpp:err_bad_request(Txt, Lang)}; + (#muc_user{invites = [I]}, _) -> + {ok, I}; + (#muc_user{invites = [_|_]}, _) -> + Txt = <<"Multiple elements are not allowed">>, + {error, xmpp:err_resource_constraint(Txt, Lang)}; + (#xdata{type = submit, fields = Fs}, _) -> + try {ok, muc_request:decode(Fs)} + catch _:{muc_request, Why} -> + Txt = muc_request:format_error(Why), + {error, xmpp:err_bad_request(Txt, Lang)} + end; + (_, Acc) -> + Acc + end, ok, xmpp:get_els(Pkt)), + case Action of + {ok, #muc_invite{} = Invitation} -> + process_invitation(From, Pkt, Invitation, StateData); + {ok, [{role, participant}]} -> + process_voice_request(From, Pkt, StateData); + {ok, VoiceApproval} -> + process_voice_approval(From, Pkt, VoiceApproval, StateData); + {error, Err} -> + ejabberd_router:route_error(StateData#state.jid, From, Pkt, Err), + StateData; + ok -> + StateData + end. + +-spec process_invitation(jid(), message(), muc_invite(), state()) -> state(). +process_invitation(From, Pkt, Invitation, StateData) -> + Lang = xmpp:get_lang(Pkt), + case check_invitation(From, Invitation, Lang, StateData) of + {error, Error} -> + ejabberd_router:route_error(StateData#state.jid, From, Pkt, Error), + StateData; + IJID -> + Config = StateData#state.config, + case Config#config.members_only of true -> - MinInterval = (StateData#state.config)#config.voice_request_min_interval, - BareFrom = jid:remove_resource(jid:tolower(From)), - NowPriority = -p1_time_compat:system_time(micro_seconds), - CleanPriority = NowPriority + MinInterval * 1000000, - Times = clean_treap(StateData#state.last_voice_request_time, - CleanPriority), - case treap:lookup(BareFrom, Times) of - error -> - Times1 = treap:insert(BareFrom, - NowPriority, - true, Times), - NSD = StateData#state{last_voice_request_time = Times1}, - send_voice_request(From, Lang, NSD), + case get_affiliation(IJID, StateData) of + none -> + NSD = set_affiliation(IJID, member, StateData), + send_affiliation(IJID, member, StateData), + store_room(NSD), NSD; - {ok, _, _} -> - ErrText = <<"Please, wait for a while before sending " - "new voice request">>, - Err = xmpp:err_not_acceptable(ErrText, Lang), - ejabberd_router:route_error( - StateData#state.jid, From, Pkt, Err), - StateData#state{last_voice_request_time = Times} + _ -> + StateData end; false -> - ErrText = <<"Voice requests are disabled in this conference">>, - Err = xmpp:err_forbidden(ErrText, Lang), + StateData + end + end. + +-spec process_voice_request(jid(), message(), state()) -> state(). +process_voice_request(From, Pkt, StateData) -> + Lang = xmpp:get_lang(Pkt), + case (StateData#state.config)#config.allow_voice_requests of + true -> + MinInterval = (StateData#state.config)#config.voice_request_min_interval, + BareFrom = jid:remove_resource(jid:tolower(From)), + NowPriority = -p1_time_compat:system_time(micro_seconds), + CleanPriority = NowPriority + MinInterval * 1000000, + Times = clean_treap(StateData#state.last_voice_request_time, + CleanPriority), + case treap:lookup(BareFrom, Times) of + error -> + Times1 = treap:insert(BareFrom, + NowPriority, + true, Times), + NSD = StateData#state{last_voice_request_time = Times1}, + send_voice_request(From, Lang, NSD), + NSD; + {ok, _, _} -> + ErrText = <<"Please, wait for a while before sending " + "new voice request">>, + Err = xmpp:err_not_acceptable(ErrText, Lang), ejabberd_router:route_error( StateData#state.jid, From, Pkt, Err), - StateData + StateData#state{last_voice_request_time = Times} end; - IsVoiceApprovement -> - case is_moderator(From, StateData) of - true -> - case extract_jid_from_voice_approvement(Pkt) of - error -> - ErrText = <<"Failed to extract JID from your voice " - "request approval">>, - Err = xmpp:err_bad_request(ErrText, Lang), - ejabberd_router:route_error( - StateData#state.jid, From, Pkt, Err), - StateData; - TargetJid -> - case is_visitor(TargetJid, StateData) of - true -> - Reason = <<>>, - NSD = set_role(TargetJid, - participant, - StateData), - catch send_new_presence(TargetJid, - Reason, - NSD, - StateData), - NSD; - _ -> - StateData - end + false -> + ErrText = <<"Voice requests are disabled in this conference">>, + Err = xmpp:err_forbidden(ErrText, Lang), + ejabberd_router:route_error( + StateData#state.jid, From, Pkt, Err), + StateData + end. + +-spec process_voice_approval(jid(), message(), [muc_request:property()], state()) -> state(). +process_voice_approval(From, Pkt, VoiceApproval, StateData) -> + Lang = xmpp:get_lang(Pkt), + case is_moderator(From, StateData) of + true -> + case lists:keyfind(jid, 1, VoiceApproval) of + {_, TargetJid} -> + Allow = proplists:get_bool(request_allow, VoiceApproval), + case is_visitor(TargetJid, StateData) of + true when Allow -> + Reason = <<>>, + NSD = set_role(TargetJid, participant, StateData), + catch send_new_presence( + TargetJid, Reason, NSD, StateData), + NSD; + _ -> + StateData end; - _ -> - ErrText = <<"Only moderators can approve voice requests">>, - Err = xmpp:err_not_allowed(ErrText, Lang), + false -> + ErrText = <<"Failed to extract JID from your voice " + "request approval">>, + Err = xmpp:err_bad_request(ErrText, Lang), ejabberd_router:route_error( StateData#state.jid, From, Pkt, Err), StateData end; - true -> + false -> + ErrText = <<"Only moderators can approve voice requests">>, + Err = xmpp:err_not_allowed(ErrText, Lang), + ejabberd_router:route_error( + StateData#state.jid, From, Pkt, Err), StateData end. @@ -3090,34 +3121,6 @@ is_password_settings_correct(XData, StateData) -> _ -> true end. --define(XFIELD(Type, Label, Var, Vals), - #xdata_field{type = Type, - label = translate:translate(Lang, Label), - var = Var, - values = Vals}). - --define(BOOLXFIELD(Label, Var, Val), - ?XFIELD(boolean, Label, Var, - case Val of - true -> [<<"1">>]; - _ -> [<<"0">>] - end)). - --define(STRINGXFIELD(Label, Var, Val), - ?XFIELD('text-single', Label, Var, [Val])). - --define(PRIVATEXFIELD(Label, Var, Val), - ?XFIELD('text-private', Label, Var, [Val])). - --define(JIDMULTIXFIELD(Label, Var, JIDList), - ?XFIELD('jid-multi', Label, Var, - [jid:to_string(JID) || JID <- JIDList])). - --spec make_options([{binary(), binary()}], binary()) -> [xdata_option()]. -make_options(Options, Lang) -> - [#xdata_option{label = translate:translate(Lang, Label), - value = Value} || {Label, Value} <- Options]. - -spec get_default_room_maxusers(state()) -> non_neg_integer(). get_default_room_maxusers(RoomState) -> DefRoomOpts = @@ -3138,424 +3141,156 @@ get_config(Lang, StateData, From) -> {MaxUsersRoomInteger, MaxUsersRoomString} = case get_max_users(StateData) of N when is_integer(N) -> - {N, integer_to_binary(N)}; - _ -> {0, <<"none">>} + {N, N}; + _ -> {0, none} end, Title = iolist_to_binary( io_lib:format( translate:translate(Lang, <<"Configuration of room ~s">>), [jid:to_string(StateData#state.jid)])), - Fs = [#xdata_field{type = hidden, - var = <<"FORM_TYPE">>, - values = [<<"http://jabber.org/protocol/muc#roomconfig">>]}, - ?STRINGXFIELD(<<"Room title">>, - <<"muc#roomconfig_roomname">>, (Config#config.title)), - ?STRINGXFIELD(<<"Room description">>, - <<"muc#roomconfig_roomdesc">>, - (Config#config.description))] ++ + Fs = [{roomname, Config#config.title}, + {roomdesc, Config#config.description}] ++ case acl:match_rule(StateData#state.server_host, AccessPersistent, From) of - allow -> - [?BOOLXFIELD(<<"Make room persistent">>, - <<"muc#roomconfig_persistentroom">>, - (Config#config.persistent))]; + allow -> [{persistentroom, Config#config.persistent}]; deny -> [] end ++ - [?BOOLXFIELD(<<"Make room public searchable">>, - <<"muc#roomconfig_publicroom">>, - (Config#config.public)), - ?BOOLXFIELD(<<"Make participants list public">>, - <<"public_list">>, (Config#config.public_list)), - ?BOOLXFIELD(<<"Make room password protected">>, - <<"muc#roomconfig_passwordprotectedroom">>, - (Config#config.password_protected)), - ?PRIVATEXFIELD(<<"Password">>, - <<"muc#roomconfig_roomsecret">>, - case Config#config.password_protected of - true -> Config#config.password; - false -> <<"">> - end), - #xdata_field{type = 'list-single', - label = translate:translate( - Lang, <<"Maximum Number of Occupants">>), - var = <<"muc#roomconfig_maxusers">>, - values = [MaxUsersRoomString], - options = - if is_integer(ServiceMaxUsers) -> []; - true -> make_options( - [{<<"No limit">>, <<"none">>}], - Lang) - end ++ - make_options( - [{integer_to_binary(N), integer_to_binary(N)} - || N <- lists:usort([ServiceMaxUsers, - DefaultRoomMaxUsers, - MaxUsersRoomInteger - | ?MAX_USERS_DEFAULT_LIST]), - N =< ServiceMaxUsers], - Lang)}, - #xdata_field{type = 'list-single', - label = translate:translate( - Lang, <<"Present real Jabber IDs to">>), - var = <<"muc#roomconfig_whois">>, - values = [if Config#config.anonymous -> <<"moderators">>; - true -> <<"anyone">> - end], - options = make_options( - [{<<"moderators only">>, <<"moderators">>}, - {<<"anyone">>, <<"anyone">>}], - Lang)}, - #xdata_field{type = 'list-multi', - label = translate:translate( - Lang, - <<"Roles for which Presence is Broadcasted">>), - var = <<"muc#roomconfig_presencebroadcast">>, - values = [atom_to_binary(Role, utf8) - || Role <- Config#config.presence_broadcast], - options = make_options( - [{<<"Moderator">>, <<"moderator">>}, - {<<"Participant">>, <<"participant">>}, - {<<"Visitor">>, <<"visitor">>}], - Lang)}, - ?BOOLXFIELD(<<"Make room members-only">>, - <<"muc#roomconfig_membersonly">>, - (Config#config.members_only)), - ?BOOLXFIELD(<<"Make room moderated">>, - <<"muc#roomconfig_moderatedroom">>, - (Config#config.moderated)), - ?BOOLXFIELD(<<"Default users as participants">>, - <<"members_by_default">>, - (Config#config.members_by_default)), - ?BOOLXFIELD(<<"Allow users to change the subject">>, - <<"muc#roomconfig_changesubject">>, - (Config#config.allow_change_subj)), - ?BOOLXFIELD(<<"Allow users to send private messages">>, - <<"allow_private_messages">>, - (Config#config.allow_private_messages)), - #xdata_field{type = 'list-single', - label = translate:translate( - Lang, - <<"Allow visitors to send private messages to">>), - var = <<"allow_private_messages_from_visitors">>, - values = [case Config#config.allow_private_messages_from_visitors of - anyone -> <<"anyone">>; - moderators -> <<"moderators">>; - nobody -> <<"nobody">> - end], - options = make_options( - [{<<"nobody">>, <<"nobody">>}, - {<<"moderators only">>, <<"moderators">>}, - {<<"anyone">>, <<"anyone">>}], - Lang)}, - ?BOOLXFIELD(<<"Allow users to query other users">>, - <<"allow_query_users">>, - (Config#config.allow_query_users)), - ?BOOLXFIELD(<<"Allow users to send invites">>, - <<"muc#roomconfig_allowinvites">>, - (Config#config.allow_user_invites)), - ?BOOLXFIELD(<<"Allow visitors to send status text in " - "presence updates">>, - <<"muc#roomconfig_allowvisitorstatus">>, - (Config#config.allow_visitor_status)), - ?BOOLXFIELD(<<"Allow visitors to change nickname">>, - <<"muc#roomconfig_allowvisitornickchange">>, - (Config#config.allow_visitor_nickchange)), - ?BOOLXFIELD(<<"Allow visitors to send voice requests">>, - <<"muc#roomconfig_allowvoicerequests">>, - (Config#config.allow_voice_requests)), - ?BOOLXFIELD(<<"Allow subscription">>, - <<"muc#roomconfig_allow_subscription">>, - (Config#config.allow_subscription)), - ?STRINGXFIELD(<<"Minimum interval between voice requests " - "(in seconds)">>, - <<"muc#roomconfig_voicerequestmininterval">>, - integer_to_binary(Config#config.voice_request_min_interval))] + [{publicroom, Config#config.public}, + {public_list, Config#config.public_list}, + {passwordprotectedroom, Config#config.password_protected}, + {roomsecret, case Config#config.password_protected of + true -> Config#config.password; + false -> <<"">> + end}, + {maxusers, MaxUsersRoomString, + [if is_integer(ServiceMaxUsers) -> []; + true -> [{<<"No limit">>, <<"none">>}] + end] ++ [{integer_to_binary(N), N} + || N <- lists:usort([ServiceMaxUsers, + DefaultRoomMaxUsers, + MaxUsersRoomInteger + | ?MAX_USERS_DEFAULT_LIST]), + N =< ServiceMaxUsers]}, + {whois, if Config#config.anonymous -> moderators; + true -> anyone + end}, + {presencebroadcast, Config#config.presence_broadcast}, + {membersonly, Config#config.members_only}, + {moderatedroom, Config#config.moderated}, + {members_by_default, Config#config.members_by_default}, + {changesubject, Config#config.allow_change_subj}, + {allow_private_messages, Config#config.allow_private_messages}, + {allow_private_messages_from_visitors, + Config#config.allow_private_messages_from_visitors}, + {allow_query_users, Config#config.allow_query_users}, + {allowinvites, Config#config.allow_user_invites}, + {allow_visitor_status, Config#config.allow_visitor_status}, + {allow_visitor_nickchange, Config#config.allow_visitor_nickchange}, + {allow_voice_requests, Config#config.allow_voice_requests}, + {allow_subscription, Config#config.allow_subscription}, + {voice_request_min_interval, Config#config.voice_request_min_interval}] ++ case ejabberd_captcha:is_feature_available() of - true -> - [?BOOLXFIELD(<<"Make room CAPTCHA protected">>, - <<"captcha_protected">>, - (Config#config.captcha_protected))]; + true -> [{captcha_protected, Config#config.captcha_protected}]; false -> [] end ++ - [?JIDMULTIXFIELD(<<"Exclude Jabber IDs from CAPTCHA challenge">>, - <<"muc#roomconfig_captcha_whitelist">>, - ((?SETS):to_list(Config#config.captcha_whitelist)))] + [{captcha_whitelist, + lists:map(fun jid:make/1, ?SETS:to_list(Config#config.captcha_whitelist))}] ++ case mod_muc_log:check_access_log(StateData#state.server_host, From) of - allow -> - [?BOOLXFIELD(<<"Enable logging">>, - <<"muc#roomconfig_enablelogging">>, - (Config#config.logging))]; + allow -> [{enablelogging, Config#config.logging}]; deny -> [] end, Fields = ejabberd_hooks:run_fold(get_room_config, StateData#state.server_host, Fs, [StateData, From, Lang]), - #xdata{type = form, title = Title, fields = Fields}. + #xdata{type = form, title = Title, + fields = muc_roomconfig:encode( + Fields, fun(T) -> translate:translate(Lang, T) end)}. -spec set_config(xdata(), state(), binary()) -> {error, stanza_error()} | {result, undefined, state()}. set_config(#xdata{fields = Fields}, StateData, Lang) -> - Options = [{Var, Vals} || #xdata_field{var = Var, values = Vals} <- Fields], - case set_xoption(Options, StateData#state.config, - StateData#state.server_host, Lang) of - #config{} = Config -> - Res = change_config(Config, StateData), - {result, _, NSD} = Res, - Type = case {(StateData#state.config)#config.logging, - Config#config.logging} - of - {true, false} -> roomconfig_change_disabledlogging; - {false, true} -> roomconfig_change_enabledlogging; - {_, _} -> roomconfig_change - end, - Users = [{U#user.jid, U#user.nick, U#user.role} - || {_, U} <- (?DICT):to_list(StateData#state.users)], - add_to_log(Type, Users, NSD), - Res; - Err -> Err + try + Options = muc_roomconfig:decode(Fields), + #config{} = Config = set_config(Options, StateData#state.config, + StateData#state.server_host, Lang), + {result, _, NSD} = Res = change_config(Config, StateData), + Type = case {(StateData#state.config)#config.logging, + Config#config.logging} + of + {true, false} -> roomconfig_change_disabledlogging; + {false, true} -> roomconfig_change_enabledlogging; + {_, _} -> roomconfig_change + end, + Users = [{U#user.jid, U#user.nick, U#user.role} + || {_, U} <- (?DICT):to_list(StateData#state.users)], + add_to_log(Type, Users, NSD), + Res + catch _:{muc_roomconfig, Why} -> + Txt = muc_roomconfig:format_error(Why), + {error, xmpp:err_bad_request(Txt, Lang)}; + _:{badmatch, {error, #stanza_error{}} = Err} -> + Err end. get_config_opt_name(Pos) -> Fs = [config|record_info(fields, config)], lists:nth(Pos, Fs). --define(SET_BOOL_XOPT(Opt, Val), - case Val of - <<"0">> -> - set_xoption(Opts, setelement(Opt, Config, false), ServerHost, Lang); - <<"false">> -> - set_xoption(Opts, setelement(Opt, Config, false), ServerHost, Lang); - <<"1">> -> set_xoption(Opts, setelement(Opt, Config, true), ServerHost, Lang); - <<"true">> -> - set_xoption(Opts, setelement(Opt, Config, true), ServerHost, Lang); - _ -> - Txt = <<"Value of '~s' should be boolean">>, - OptName = get_config_opt_name(Opt), - ErrTxt = iolist_to_binary(io_lib:format(Txt, [OptName])), - {error, xmpp:err_bad_request(ErrTxt, Lang)} - end). - --define(SET_NAT_XOPT(Opt, Val), - case catch binary_to_integer(Val) of - I when is_integer(I), I > 0 -> - set_xoption(Opts, setelement(Opt, Config, I), ServerHost, Lang); - _ -> - Txt = <<"Value of '~s' should be integer">>, - OptName = get_config_opt_name(Opt), - ErrTxt = iolist_to_binary(io_lib:format(Txt, [OptName])), - {error, xmpp:err_bad_request(ErrTxt, Lang)} - end). - --define(SET_STRING_XOPT(Opt, Vals), - try - V = case Vals of - [] -> <<"">>; - [Val] -> Val; - _ when is_atom(Vals) -> Vals - end, - set_xoption(Opts, setelement(Opt, Config, V), ServerHost, Lang) - catch _:_ -> - Txt = <<"Incorrect value of option '~s'">>, - OptName = get_config_opt_name(Opt), - ErrTxt = iolist_to_binary(io_lib:format(Txt, [OptName])), - {error, xmpp:err_bad_request(ErrTxt, Lang)} - end). - --define(SET_JIDMULTI_XOPT(Opt, Vals), - begin - Set = lists:foldl(fun ({U, S, R}, Set1) -> - (?SETS):add_element({U, S, R}, Set1); - (#jid{luser = U, lserver = S, lresource = R}, - Set1) -> - (?SETS):add_element({U, S, R}, Set1); - (_, Set1) -> Set1 - end, - (?SETS):empty(), Vals), - set_xoption(Opts, setelement(Opt, Config, Set), ServerHost, Lang) - end). - --spec set_xoption([{binary(), [binary()]}], #config{}, +-spec set_config([muc_roomconfig:property()], #config{}, binary(), binary()) -> #config{} | {error, stanza_error()}. -set_xoption([], Config, _ServerHost, _Lang) -> Config; -set_xoption([{<<"muc#roomconfig_roomname">>, Vals} - | Opts], - Config, ServerHost, Lang) -> - ?SET_STRING_XOPT(#config.title, Vals); -set_xoption([{<<"muc#roomconfig_roomdesc">>, Vals} - | Opts], - Config, ServerHost, Lang) -> - ?SET_STRING_XOPT(#config.description, Vals); -set_xoption([{<<"muc#roomconfig_changesubject">>, [Val]} - | Opts], - Config, ServerHost, Lang) -> - ?SET_BOOL_XOPT(#config.allow_change_subj, Val); -set_xoption([{<<"allow_query_users">>, [Val]} | Opts], - Config, ServerHost, Lang) -> - ?SET_BOOL_XOPT(#config.allow_query_users, Val); -set_xoption([{<<"allow_private_messages">>, [Val]} - | Opts], - Config, ServerHost, Lang) -> - ?SET_BOOL_XOPT(#config.allow_private_messages, Val); -set_xoption([{<<"allow_private_messages_from_visitors">>, - [Val]} - | Opts], - Config, ServerHost, Lang) -> - case Val of - <<"anyone">> -> - ?SET_STRING_XOPT(#config.allow_private_messages_from_visitors, - anyone); - <<"moderators">> -> - ?SET_STRING_XOPT(#config.allow_private_messages_from_visitors, - moderators); - <<"nobody">> -> - ?SET_STRING_XOPT(#config.allow_private_messages_from_visitors, - nobody); - _ -> - Txt = <<"Value of 'allow_private_messages_from_visitors' " - "should be anyone|moderators|nobody">>, - {error, xmpp:err_bad_request(Txt, Lang)} - end; -set_xoption([{<<"muc#roomconfig_allowvisitorstatus">>, - [Val]} - | Opts], - Config, ServerHost, Lang) -> - ?SET_BOOL_XOPT(#config.allow_visitor_status, Val); -set_xoption([{<<"muc#roomconfig_allowvisitornickchange">>, - [Val]} - | Opts], - Config, ServerHost, Lang) -> - ?SET_BOOL_XOPT(#config.allow_visitor_nickchange, Val); -set_xoption([{<<"muc#roomconfig_publicroom">>, [Val]} - | Opts], - Config, ServerHost, Lang) -> - ?SET_BOOL_XOPT(#config.public, Val); -set_xoption([{<<"public_list">>, [Val]} | Opts], - Config, ServerHost, Lang) -> - ?SET_BOOL_XOPT(#config.public_list, Val); -set_xoption([{<<"muc#roomconfig_persistentroom">>, - [Val]} - | Opts], - Config, ServerHost, Lang) -> - ?SET_BOOL_XOPT(#config.persistent, Val); -set_xoption([{<<"muc#roomconfig_moderatedroom">>, [Val]} - | Opts], - Config, ServerHost, Lang) -> - ?SET_BOOL_XOPT(#config.moderated, Val); -set_xoption([{<<"members_by_default">>, [Val]} | Opts], - Config, ServerHost, Lang) -> - ?SET_BOOL_XOPT(#config.members_by_default, Val); -set_xoption([{<<"muc#roomconfig_membersonly">>, [Val]} - | Opts], - Config, ServerHost, Lang) -> - ?SET_BOOL_XOPT(#config.members_only, Val); -set_xoption([{<<"captcha_protected">>, [Val]} | Opts], - Config, ServerHost, Lang) -> - ?SET_BOOL_XOPT(#config.captcha_protected, Val); -set_xoption([{<<"muc#roomconfig_allowinvites">>, [Val]} - | Opts], - Config, ServerHost, Lang) -> - ?SET_BOOL_XOPT(#config.allow_user_invites, Val); -set_xoption([{<<"muc#roomconfig_allow_subscription">>, [Val]} - | Opts], - Config, ServerHost, Lang) -> - ?SET_BOOL_XOPT(#config.allow_subscription, Val); -set_xoption([{<<"muc#roomconfig_passwordprotectedroom">>, - [Val]} - | Opts], - Config, ServerHost, Lang) -> - ?SET_BOOL_XOPT(#config.password_protected, Val); -set_xoption([{<<"muc#roomconfig_roomsecret">>, Vals} - | Opts], - Config, ServerHost, Lang) -> - ?SET_STRING_XOPT(#config.password, Vals); -set_xoption([{<<"anonymous">>, [Val]} | Opts], - Config, ServerHost, Lang) -> - ?SET_BOOL_XOPT(#config.anonymous, Val); -set_xoption([{<<"muc#roomconfig_presencebroadcast">>, Vals} | Opts], - Config, ServerHost, Lang) -> - Roles = - lists:foldl( - fun(_S, error) -> error; - (S, {M, P, V}) -> - case S of - <<"moderator">> -> {true, P, V}; - <<"participant">> -> {M, true, V}; - <<"visitor">> -> {M, P, true}; - _ -> error - end - end, {false, false, false}, Vals), - case Roles of - error -> - Txt = <<"Value of 'muc#roomconfig_presencebroadcast' should " - "be moderator|participant|visitor">>, - {error, xmpp:err_bad_request(Txt, Lang)}; - {M, P, V} -> - Res = - if M -> [moderator]; true -> [] end ++ - if P -> [participant]; true -> [] end ++ - if V -> [visitor]; true -> [] end, - set_xoption(Opts, Config#config{presence_broadcast = Res}, - ServerHost, Lang) - end; -set_xoption([{<<"muc#roomconfig_allowvoicerequests">>, - [Val]} - | Opts], - Config, ServerHost, Lang) -> - ?SET_BOOL_XOPT(#config.allow_voice_requests, Val); -set_xoption([{<<"muc#roomconfig_voicerequestmininterval">>, - [Val]} - | Opts], - Config, ServerHost, Lang) -> - ?SET_NAT_XOPT(#config.voice_request_min_interval, Val); -set_xoption([{<<"muc#roomconfig_whois">>, [Val]} - | Opts], - Config, ServerHost, Lang) -> - case Val of - <<"moderators">> -> - ?SET_BOOL_XOPT(#config.anonymous, - (iolist_to_binary(integer_to_list(1)))); - <<"anyone">> -> - ?SET_BOOL_XOPT(#config.anonymous, - (iolist_to_binary(integer_to_list(0)))); - _ -> - Txt = <<"Value of 'muc#roomconfig_whois' should be " - "moderators|anyone">>, - {error, xmpp:err_bad_request(Txt, Lang)} - end; -set_xoption([{<<"muc#roomconfig_maxusers">>, [Val]} - | Opts], - Config, ServerHost, Lang) -> - case Val of - <<"none">> -> ?SET_STRING_XOPT(#config.max_users, none); - _ -> ?SET_NAT_XOPT(#config.max_users, Val) - end; -set_xoption([{<<"muc#roomconfig_enablelogging">>, [Val]} - | Opts], - Config, ServerHost, Lang) -> - ?SET_BOOL_XOPT(#config.logging, Val); -set_xoption([{<<"muc#roomconfig_captcha_whitelist">>, - Vals} - | Opts], - Config, ServerHost, Lang) -> - JIDs = [jid:from_string(Val) || Val <- Vals], - ?SET_JIDMULTI_XOPT(#config.captcha_whitelist, JIDs); -set_xoption([{<<"FORM_TYPE">>, _} | Opts], Config, ServerHost, Lang) -> - set_xoption(Opts, Config, ServerHost, Lang); -set_xoption([{Opt, Vals} | Opts], Config, ServerHost, Lang) -> - Txt = <<"Unknown option '~s'">>, - ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), - Err = {error, xmpp:err_bad_request(ErrTxt, Lang)}, - case ejabberd_hooks:run_fold(set_room_option, - ServerHost, - Err, - [Opt, Vals, Lang]) of - {error, Reason} -> - {error, Reason}; - {Pos, Val} -> - set_xoption(Opts, setelement(Pos, Config, Val), ServerHost, Lang) - end. +set_config(Opts, Config, ServerHost, Lang) -> + lists:foldl( + fun(_, {error, _} = Err) -> Err; + ({roomname, Title}, C) -> C#config{title = Title}; + ({roomdesc, Desc}, C) -> C#config{description = Desc}; + ({changesubject, V}, C) -> C#config{allow_change_subj = V}; + ({allow_query_users, V}, C) -> C#config{allow_query_users = V}; + ({allow_private_messages, V}, C) -> + C#config{allow_private_messages = V}; + ({allow_private_messages_from_visitors, V}, C) -> + C#config{allow_private_messages_from_visitors = V}; + ({allow_visitor_status, V}, C) -> C#config{allow_visitor_status = V}; + ({allow_visitor_nickchange, V}, C) -> + C#config{allow_visitor_nickchange = V}; + ({publicroom, V}, C) -> C#config{public = V}; + ({public_list, V}, C) -> C#config{public_list = V}; + ({persistentroom, V}, C) -> C#config{persistent = V}; + ({moderatedroom, V}, C) -> C#config{moderated = V}; + ({members_by_default, V}, C) -> C#config{members_by_default = V}; + ({membersonly, V}, C) -> C#config{members_only = V}; + ({captcha_protected, V}, C) -> C#config{captcha_protected = V}; + ({allowinvites, V}, C) -> C#config{allow_user_invites = V}; + ({allow_subscription, V}, C) -> C#config{allow_subscription = V}; + ({passwordprotectedroom, V}, C) -> C#config{password_protected = V}; + ({roomsecret, V}, C) -> C#config{password = V}; + ({anonymous, V}, C) -> C#config{anonymous = V}; + ({presencebroadcast, V}, C) -> C#config{presence_broadcast = V}; + ({allow_voice_requests, V}, C) -> C#config{allow_voice_requests = V}; + ({voice_request_min_interval, V}, C) -> + C#config{voice_request_min_interval = V}; + ({whois, moderators}, C) -> C#config{anonymous = true}; + ({whois, anyone}, C) -> C#config{anonymous = false}; + ({maxusers, V}, C) -> C#config{max_users = V}; + ({enablelogging, V}, C) -> C#config{logging = V}; + ({captcha_whitelist, Js}, C) -> + LJIDs = [jid:tolower(J) || J <- Js], + C#config{captcha_whitelist = ?SETS:from_list(LJIDs)}; + ({O, V} = Opt, C) -> + case ejabberd_hooks:run_fold(set_room_option, + ServerHost, + {0, undefined}, + [Opt, Lang]) of + {0, undefined} -> + ?ERROR_MSG("set_room_option hook failed for " + "option '~s' with value ~p", [O, V]), + Txt = <<"Failed to process option '", O/binary, "'">>, + {error, xmpp:err_internal_server_error(Txt, Lang)}; + {Pos, Val} -> + setelement(Pos, C, Val) + end + end, Config, Opts). -spec change_config(#config{}, state()) -> {result, undefined, state()}. change_config(Config, StateData) -> @@ -3872,33 +3607,13 @@ process_iq_disco_info(_From, #iq{type = get, lang = Lang}, StateData) -> name = get_title(StateData)}], features = Feats}}. --spec mk_rfieldt('boolean' | 'fixed' | 'hidden' | - 'jid-multi' | 'jid-single' | 'list-multi' | - 'list-single' | 'text-multi' | 'text-private' | - 'text-single', binary(), binary()) -> xdata_field(). -mk_rfieldt(Type, Var, Val) -> - #xdata_field{type = Type, var = Var, values = [Val]}. - --spec mk_rfield(binary(), binary(), binary(), binary()) -> xdata_field(). -mk_rfield(Label, Var, Val, Lang) -> - #xdata_field{type = 'text-single', - label = translate:translate(Lang, Label), - var = Var, - values = [Val]}. - -spec iq_disco_info_extras(binary(), state()) -> xdata(). iq_disco_info_extras(Lang, StateData) -> - Len = (?DICT):size(StateData#state.users), - RoomDescription = (StateData#state.config)#config.description, + Fs = [{description, (StateData#state.config)#config.description}, + {occupants, ?DICT:size(StateData#state.users)}], #xdata{type = result, - fields = [mk_rfieldt(hidden, <<"FORM_TYPE">>, - "http://jabber.org/protocol/muc#roominfo"), - mk_rfield(<<"Room description">>, - <<"muc#roominfo_description">>, - RoomDescription, Lang), - mk_rfield(<<"Number of occupants">>, - <<"muc#roominfo_occupants">>, - integer_to_binary(Len), Lang)]}. + fields = muc_roominfo:encode( + Fs, fun(T) -> translate:translate(Lang, T) end)}. -spec process_iq_disco_items(jid(), iq(), state()) -> {error, stanza_error()} | {result, disco_items()}. @@ -4105,39 +3820,16 @@ get_mucroom_disco_items(StateData) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Voice request support --spec is_voice_request(message()) -> boolean(). -is_voice_request(Packet) -> - Els = xmpp:get_els(Packet), - lists:any( - fun(#xdata{} = X) -> - case {xmpp_util:get_xdata_values(<<"FORM_TYPE">>, X), - xmpp_util:get_xdata_values(<<"muc#role">>, X)} of - {[<<"http://jabber.org/protocol/muc#request">>], - [<<"participant">>]} -> - true; - _ -> - false - end; - (_) -> - false - end, Els). - -spec prepare_request_form(jid(), binary(), binary()) -> message(). prepare_request_form(Requester, Nick, Lang) -> Title = translate:translate(Lang, <<"Voice request">>), Instruction = translate:translate( Lang, <<"Either approve or decline the voice request.">>), - Fs = [#xdata_field{var = <<"FORM_TYPE">>, - type = hidden, - values = [<<"http://jabber.org/protocol/muc#request">>]}, - #xdata_field{var = <<"muc#role">>, - type = hidden, - values = [<<"participant">>]}, - ?STRINGXFIELD(<<"User JID">>, <<"muc#jid">>, - jid:to_string(Requester)), - ?STRINGXFIELD(<<"Nickname">>, <<"muc#roomnick">>, Nick), - ?BOOLXFIELD(<<"Grant voice to this person?">>, - <<"muc#request_allow">>, false)], + Fs = muc_request:encode([{role, participant}, + {jid, Requester}, + {roomnick, Nick}, + {request_allow, false}], + fun(T) -> translate:translate(Lang, T) end), #message{type = normal, sub_els = [#xdata{type = form, title = Title, @@ -4155,59 +3847,11 @@ send_voice_request(From, Lang, StateData) -> end, Moderators). --spec is_voice_approvement(message()) -> boolean(). -is_voice_approvement(Packet) -> - Els = xmpp:get_els(Packet), - lists:any( - fun(#xdata{} = X) -> - case {xmpp_util:get_xdata_values(<<"FORM_TYPE">>, X), - xmpp_util:get_xdata_values(<<"muc#role">>, X), - xmpp_util:get_xdata_values(<<"muc#request_allow">>, X)} of - {[<<"http://jabber.org/protocol/muc#request">>], - [<<"participant">>], [Flag]} when Flag == <<"true">>; - Flag == <<"1">> -> - true; - _ -> - false - end; - (_) -> - false - end, Els). - --spec extract_jid_from_voice_approvement(message()) -> jid() | error. -extract_jid_from_voice_approvement(Packet) -> - Els = xmpp:get_els(Packet), - lists:foldl( - fun(#xdata{} = X, error) -> - case {xmpp_util:get_xdata_values(<<"FORM_TYPE">>, X), - xmpp_util:get_xdata_values(<<"muc#role">>, X), - xmpp_util:get_xdata_values(<<"muc#request_allow">>, X), - xmpp_util:get_xdata_values(<<"muc#jid">>, X)} of - {[<<"http://jabber.org/protocol/muc#request">>], - [<<"participant">>], [Flag], [J]} when Flag == <<"true">>; - Flag == <<"1">> -> - jid:from_string(J); - _ -> - error - end; - (_, Acc) -> - Acc - end, error, Els). - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Invitation support --spec is_invitation(message()) -> boolean(). -is_invitation(Packet) -> - Els = xmpp:get_els(Packet), - lists:any( - fun(#muc_user{invites = [_|_]}) -> true; - (_) -> false - end, Els). - --spec check_invitation(jid(), message(), state()) -> {error, stanza_error()} | jid(). -check_invitation(From, Packet, StateData) -> - Lang = xmpp:get_lang(Packet), +-spec check_invitation(jid(), muc_invite(), binary(), state()) -> {error, stanza_error()} | jid(). +check_invitation(From, Invitation, Lang, StateData) -> FAffiliation = get_affiliation(From, StateData), CanInvite = (StateData#state.config)#config.allow_user_invites orelse @@ -4217,57 +3861,46 @@ check_invitation(From, Packet, StateData) -> Txt = <<"Invitations are not allowed in this conference">>, {error, xmpp:err_not_allowed(Txt, Lang)}; true -> - case xmpp:get_subtag(Packet, #muc_user{}) of - #muc_user{invites = [#muc_invite{to = undefined}]} -> - Txt = <<"No 'to' attribute found">>, - {error, xmpp:err_bad_request(Txt, Lang)}; - #muc_user{invites = [#muc_invite{to = JID, reason = Reason} = I]} -> - Invite = I#muc_invite{to = undefined, from = From}, - Password = case (StateData#state.config)#config.password_protected of - true -> - (StateData#state.config)#config.password; - false -> - undefined - end, - XUser = #muc_user{password = Password, invites = [Invite]}, - XConference = #x_conference{jid = jid:make(StateData#state.room, - StateData#state.host), - reason = Reason}, - Body = iolist_to_binary( - [io_lib:format( - translate:translate( - Lang, - <<"~s invites you to the room ~s">>), - [jid:to_string(From), - jid:to_string({StateData#state.room, - StateData#state.host, - <<"">>})]), - case (StateData#state.config)#config.password_protected of - true -> - <<", ", - (translate:translate( - Lang, <<"the password is">>))/binary, - " '", - ((StateData#state.config)#config.password)/binary, - "'">>; - _ -> <<"">> - end, - case Reason of - <<"">> -> <<"">>; - _ -> <<" (", Reason/binary, ") ">> - end]), - Msg = #message{type = normal, - body = xmpp:mk_text(Body), - sub_els = [XUser, XConference]}, - ejabberd_router:route(StateData#state.jid, JID, Msg), - JID; - #muc_user{invites = [_|_]} -> - Txt = <<"Multiple elements are not allowed">>, - {error, xmpp:err_forbidden(Txt, Lang)}; - _ -> - Txt = <<"No element found">>, - {error, xmpp:err_bad_request(Txt, Lang)} - end + #muc_invite{to = JID, reason = Reason} = Invitation, + Invite = Invitation#muc_invite{to = undefined, from = From}, + Password = case (StateData#state.config)#config.password_protected of + true -> + (StateData#state.config)#config.password; + false -> + undefined + end, + XUser = #muc_user{password = Password, invites = [Invite]}, + XConference = #x_conference{jid = jid:make(StateData#state.room, + StateData#state.host), + reason = Reason}, + Body = iolist_to_binary( + [io_lib:format( + translate:translate( + Lang, + <<"~s invites you to the room ~s">>), + [jid:to_string(From), + jid:to_string({StateData#state.room, + StateData#state.host, + <<"">>})]), + case (StateData#state.config)#config.password_protected of + true -> + <<", ", + (translate:translate( + Lang, <<"the password is">>))/binary, + " '", + ((StateData#state.config)#config.password)/binary, + "'">>; + _ -> <<"">> + end, + case Reason of + <<"">> -> <<"">>; + _ -> <<" (", Reason/binary, ") ">> + end]), + Msg = #message{type = normal, + body = xmpp:mk_text(Body), + sub_els = [XUser, XConference]}, + ejabberd_router:route(StateData#state.jid, JID, Msg), + JID end. %% Handle a message sent to the room by a non-participant. diff --git a/src/mod_offline.erl b/src/mod_offline.erl index 258c97d4f..240650234 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -300,8 +300,7 @@ get_sm_items(Acc, _From, _To, _Node, _Lang) -> -spec get_info([xdata()], binary(), module(), binary(), binary()) -> [xdata()]; ([xdata()], jid(), jid(), binary(), binary()) -> [xdata()]. get_info(_Acc, #jid{luser = U, lserver = S, lresource = R}, - #jid{luser = U, lserver = S}, ?NS_FLEX_OFFLINE, _Lang) -> - N = integer_to_binary(count_offline_messages(U, S)), + #jid{luser = U, lserver = S}, ?NS_FLEX_OFFLINE, Lang) -> case ejabberd_sm:get_session_pid(U, S, R) of Pid when is_pid(Pid) -> Pid ! dont_ask_offline; @@ -309,11 +308,9 @@ get_info(_Acc, #jid{luser = U, lserver = S, lresource = R}, ok end, [#xdata{type = result, - fields = [#xdata_field{var = <<"FORM_TYPE">>, - type = hidden, - values = [?NS_FLEX_OFFLINE]}, - #xdata_field{var = <<"number_of_messages">>, - values = [N]}]}]; + fields = flex_offline:encode( + [{number_of_messages, count_offline_messages(U, S)}], + fun(T) -> translate:translate(Lang, T) end)}]; get_info(Acc, _From, _To, _Node, _Lang) -> Acc. diff --git a/src/mod_pubsub.erl b/src/mod_pubsub.erl index b55115c9a..e3fe64c16 100644 --- a/src/mod_pubsub.erl +++ b/src/mod_pubsub.erl @@ -1028,8 +1028,11 @@ do_route(Host, From, To, Packet) -> case find_authorization_response(Packet) of undefined -> ok; - XData -> - handle_authorization_response(Host, From, To, Packet, XData) + {error, Err} -> + ejabberd_router:route_error(To, From, Packet, Err); + AuthResponse -> + handle_authorization_response( + Host, From, To, Packet, AuthResponse) end; _ -> Err = xmpp:err_service_unavailable(), @@ -1200,19 +1203,28 @@ iq_pubsub(Host, Access, #iq{from = From, type = IQType, lang = Lang, ServerHost = serverhost(Host), Plugins = config(ServerHost, plugins), Config = case Configure of - {_, XData} -> get_xdata_fields(XData); + {_, XData} -> decode_node_config(XData, Host, Lang); undefined -> [] end, Type = hd(Plugins), - create_node(Host, ServerHost, Node, From, Type, Access, Config); + case Config of + {error, _} = Err -> + Err; + _ -> + create_node(Host, ServerHost, Node, From, Type, Access, Config) + end; {set, #pubsub{publish = #ps_publish{node = Node, items = Items}, publish_options = XData, _ = undefined}} -> ServerHost = serverhost(Host), case Items of [#ps_item{id = ItemId, xml_els = Payload}] -> - PubOpts = get_xdata_fields(XData), - publish_item(Host, ServerHost, Node, From, ItemId, - Payload, PubOpts, Access); + case decode_publish_options(XData, Lang) of + {error, _} = Err -> + Err; + PubOpts -> + publish_item(Host, ServerHost, Node, From, ItemId, + Payload, PubOpts, Access) + end; [] -> {error, extended_error(xmpp:err_bad_request(), err_item_required())}; _ -> @@ -1236,10 +1248,17 @@ iq_pubsub(Host, Access, #iq{from = From, type = IQType, lang = Lang, {set, #pubsub{subscribe = #ps_subscribe{node = Node, jid = JID}, options = Options, _ = undefined}} -> Config = case Options of - #ps_options{xdata = XData} -> get_xdata_fields(XData); - _ -> [] + #ps_options{xdata = XData} -> + decode_subscribe_options(XData, Lang); + _ -> + [] end, - subscribe_node(Host, Node, From, JID, Config); + case Config of + {error, _} = Err -> + Err; + _ -> + subscribe_node(Host, Node, From, JID, Config) + end; {set, #pubsub{unsubscribe = #ps_unsubscribe{node = Node, jid = JID, subid = SubId}, _ = undefined}} -> unsubscribe_node(Host, Node, From, JID, SubId); @@ -1262,7 +1281,12 @@ iq_pubsub(Host, Access, #iq{from = From, type = IQType, lang = Lang, {set, #pubsub{options = #ps_options{node = Node, subid = SubId, jid = JID, xdata = XData}, _ = undefined}} -> - set_options(Host, Node, JID, SubId, get_xdata_fields(XData)); + case decode_subscribe_options(XData, Lang) of + {error, _} = Err -> + Err; + Config -> + set_options(Host, Node, JID, SubId, Config) + end; {set, #pubsub{}} -> {error, xmpp:err_bad_request()}; _ -> @@ -1284,8 +1308,12 @@ iq_pubsub_owner(Host, #iq{type = IQType, from = From, #xdata{type = cancel} -> {result, #pubsub_owner{}}; #xdata{type = submit} -> - Config = get_xdata_fields(XData), - set_configure(Host, Node, From, Config, Lang); + case decode_node_config(XData, Host, Lang) of + {error, _} = Err -> + Err; + Config -> + set_configure(Host, Node, From, Config, Lang) + end; #xdata{} -> {error, xmpp:err_bad_request(<<"Incorrect data form">>, Lang)} end; @@ -1318,19 +1346,20 @@ adhoc_request(Host, _ServerHost, Owner, send_pending_node_form(Host, Owner, Lang, Plugins); adhoc_request(Host, _ServerHost, Owner, #adhoc_command{node = ?NS_PUBSUB_GET_PENDING, lang = Lang, - action = execute, xdata = #xdata{} = XData}, + action = execute, xdata = #xdata{} = XData} = Request, _Access, _Plugins) -> - Config = get_xdata_fields(XData), - case set_xoption(Host, Config, []) of - XForm when is_list(XForm) -> - case lists:keysearch(node, 1, XForm) of - {value, {_, Node}} -> - send_pending_auth_events(Host, Node, Owner, Lang); - false -> - {error, extended_error(xmpp:err_bad_request(), err_invalid_payload())} - end; - Err -> - Err + case decode_get_pending(XData, Lang) of + {error, _} = Err -> + Err; + Config -> + Node = proplists:get_value(node, Config), + case send_pending_auth_events(Host, Node, Owner, Lang) of + ok -> + xmpp_util:make_adhoc_response( + Request, #adhoc_command{action = completed}); + Err -> + Err + end end; adhoc_request(_Host, _ServerHost, _Owner, #adhoc_command{action = cancel}, _Access, _Plugins) -> @@ -1353,12 +1382,9 @@ send_pending_node_form(Host, Owner, _Lang, Plugins) -> Ps -> case get_pending_nodes(Host, Owner, Ps) of {ok, Nodes} -> - XOpts = [#xdata_option{value = Node} || Node <- Nodes], XForm = #xdata{type = form, - fields = [#xdata_field{ - type = 'list-single', - var = <<"pubsub#node">>, - options = lists:usort(XOpts)}]}, + fields = pubsub_get_pending:encode( + [{node, Nodes}])}, #adhoc_command{status = executing, action = execute, xdata = XForm}; Err -> @@ -1423,24 +1449,11 @@ send_authorization_request(#pubsub_node{nodeid = {Host, Node}, Subscriber) -> %% TODO: pass lang to this function Lang = <<"en">>, - Fs = [#xdata_field{var = <<"FORM_TYPE">>, - type = hidden, - values = [?NS_PUBSUB_SUB_AUTH]}, - #xdata_field{var = <<"pubsub#node">>, - type = 'text-single', - label = translate:translate(Lang, <<"Node ID">>), - values = [Node]}, - #xdata_field{var = <<"pubsub#subscriber_jid">>, - type = 'jid-single', - label = translate:translate(Lang, <<"Subscriber Address">>), - values = [jid:to_string(Subscriber)]}, - #xdata_field{var = <<"pubsub#allow">>, - type = boolean, - label = translate:translate( - Lang, - <<"Allow this Jabber ID to subscribe to " - "this pubsub node?">>), - values = [<<"false">>]}], + Fs = pubsub_subscribe_authorization:encode( + [{node, Node}, + {subscriber_jid, Subscriber}, + {allow, false}], + fun(T) -> translate:translate(Lang, T) end), X = #xdata{type = form, title = translate:translate( Lang, <<"PubSub subscriber request">>), @@ -1455,15 +1468,24 @@ send_authorization_request(#pubsub_node{nodeid = {Host, Node}, ejabberd_router:route(service_jid(Host), jid:make(Owner), Stanza) end, node_owners_action(Host, Type, Nidx, O)). --spec find_authorization_response(message()) -> undefined | xdata(). +-spec find_authorization_response(message()) -> undefined | + pubsub_subscribe_authorization:result() | + {error, stanza_error()}. find_authorization_response(Packet) -> case xmpp:get_subtag(Packet, #xdata{}) of - #xdata{type = submit} = X -> - case xmpp_util:get_xdata_values(<<"FORM_TYPE">>, X) of - [?NS_PUBSUB_SUB_AUTH] -> X; - _ -> undefined + #xdata{type = cancel} -> + undefined; + #xdata{type = submit, fields = Fs} -> + try pubsub_subscribe_authorization:decode(Fs) of + Result -> Result + catch _:{pubsub_subscribe_authorization, Why} -> + Lang = xmpp:get_lang(Packet), + Txt = pubsub_subscribe_authorization:format_error(Why), + {error, xmpp:err_bad_request(Txt, Lang)} end; - _ -> + #xdata{} -> + {error, xmpp:err_bad_request()}; + false -> undefined end. @@ -1477,43 +1499,33 @@ send_authorization_approval(Host, JID, SNode, Subscription) -> Stanza = #message{sub_els = [Event]}, ejabberd_router:route(service_jid(Host), JID, Stanza). --spec handle_authorization_response(binary(), jid(), jid(), message(), xdata()) -> ok. -handle_authorization_response(Host, From, To, Packet, X) -> +-spec handle_authorization_response(binary(), jid(), jid(), message(), + pubsub_subscribe_authorization:result()) -> ok. +handle_authorization_response(Host, From, To, Packet, Response) -> + Node = proplists:get_value(node, Response), + Subscriber = proplists:get_value(subscriber_jid, Response), + Allow = proplists:get_value(allow, Response), Lang = xmpp:get_lang(Packet), - case {xmpp_util:get_xdata_values(<<"pubsub#node">>, X), - xmpp_util:get_xdata_values(<<"pubsub#subscriber_jid">>, X), - xmpp_util:get_xdata_values(<<"pubsub#allow">>, X)} of - {[Node], [SSubscriber], [SAllow]} -> - FromLJID = jid:tolower(jid:remove_resource(From)), - Subscriber = jid:from_string(SSubscriber), - Allow = case SAllow of - <<"1">> -> true; - <<"true">> -> true; - _ -> false - end, - Action = - fun(#pubsub_node{type = Type, id = Nidx, owners = O}) -> - Owners = node_owners_call(Host, Type, Nidx, O), - case lists:member(FromLJID, Owners) of - true -> - {result, Subs} = node_call(Host, Type, get_subscriptions, [Nidx, Subscriber]), - update_auth(Host, Node, Type, Nidx, Subscriber, Allow, Subs); - false -> - {error, xmpp:err_forbidden(<<"Owner privileges required">>, Lang)} - end - end, - case transaction(Host, Node, Action, sync_dirty) of - {error, Error} -> - ejabberd_router:route_error(To, From, Packet, Error); - {result, {_, _NewSubscription}} -> - %% XXX: notify about subscription state change, section 12.11 - ok; - _ -> - Err = xmpp:err_internal_server_error(), - ejabberd_router:route_error(To, From, Packet, Err) - end; + FromLJID = jid:tolower(jid:remove_resource(From)), + Action = + fun(#pubsub_node{type = Type, id = Nidx, owners = O}) -> + Owners = node_owners_call(Host, Type, Nidx, O), + case lists:member(FromLJID, Owners) of + true -> + {result, Subs} = node_call(Host, Type, get_subscriptions, [Nidx, Subscriber]), + update_auth(Host, Node, Type, Nidx, Subscriber, Allow, Subs); + false -> + {error, xmpp:err_forbidden(<<"Owner privileges required">>, Lang)} + end + end, + case transaction(Host, Node, Action, sync_dirty) of + {error, Error} -> + ejabberd_router:route_error(To, From, Packet, Error); + {result, {_, _NewSubscription}} -> + %% XXX: notify about subscription state change, section 12.11 + ok; _ -> - Err = xmpp:err_not_acceptable(<<"Incorrect data form">>, Lang), + Err = xmpp:err_internal_server_error(), ejabberd_router:route_error(To, From, Packet, Err) end. @@ -1539,45 +1551,6 @@ update_auth(Host, Node, Type, Nidx, Subscriber, Allow, Subs) -> {error, xmpp:err_unexpected_request(Txt, ?MYLANG)} end. --define(XFIELD(Type, Label, Var, Val), - #xdata_field{type = Type, - label = translate:translate(Lang, Label), - var = Var, - values = [Val]}). - --define(BOOLXFIELD(Label, Var, Val), - ?XFIELD(boolean, Label, Var, - case Val of - true -> <<"1">>; - _ -> <<"0">> - end)). - --define(STRINGXFIELD(Label, Var, Val), - ?XFIELD('text-single', Label, Var, Val)). - --define(STRINGMXFIELD(Label, Var, Vals), - #xdata_field{type = 'text-multi', - label = translate:translate(Lang, Label), - var = Var, - values = Vals}). - --define(XFIELDOPT(Type, Label, Var, Val, Opts), - #xdata_field{type = Type, - label = translate:translate(Lang, Label), - var = Var, - options = [#xdata_option{value = Opt} || Opt <- Opts], - values = [Val]}). - --define(LISTXFIELD(Label, Var, Val, Opts), - ?XFIELDOPT('list-single', Label, Var, Val, Opts)). - --define(LISTMXFIELD(Label, Var, Vals, Opts), - #xdata_field{type = 'list-multi', - label = translate:translate(Lang, Label), - var = Var, - options = [#xdata_option{value = Opt} || Opt <- Opts], - values = Vals}). - %% @doc

    Create new pubsub nodes

    %%

    In addition to method-specific error conditions, there are several general reasons why the node creation request might fail:

    %%
      @@ -1617,70 +1590,66 @@ create_node(Host, ServerHost, <<>>, Owner, Type, Access, Configuration) -> end; create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> Type = select_type(ServerHost, Host, Node, GivenType), - case set_xoption(Host, Configuration, node_options(Host, Type)) of - NodeOptions when is_list(NodeOptions) -> - CreateNode = - fun() -> - Parent = case node_call(Host, Type, node_to_path, [Node]) of - {result, [Node]} -> - <<>>; - {result, Path} -> - element(2, node_call(Host, Type, path_to_node, - [lists:sublist(Path, length(Path)-1)])) - end, - Parents = case Parent of - <<>> -> []; - _ -> [Parent] - end, - case node_call(Host, Type, create_node_permission, - [Host, ServerHost, Node, Parent, Owner, Access]) of - {result, true} -> - case tree_call(Host, create_node, - [Host, Node, Type, Owner, NodeOptions, Parents]) - of - {ok, Nidx} -> - SubsByDepth = get_node_subs_by_depth(Host, Node, Owner), - case node_call(Host, Type, create_node, [Nidx, Owner]) of - {result, Result} -> {result, {Nidx, SubsByDepth, Result}}; - Error -> Error - end; - {error, {virtual, Nidx}} -> - case node_call(Host, Type, create_node, [Nidx, Owner]) of - {result, Result} -> {result, {Nidx, [], Result}}; - Error -> Error - end; - Error -> - Error + NodeOptions = merge_config(Configuration, node_options(Host, Type)), + CreateNode = + fun() -> + Parent = case node_call(Host, Type, node_to_path, [Node]) of + {result, [Node]} -> + <<>>; + {result, Path} -> + element(2, node_call(Host, Type, path_to_node, + [lists:sublist(Path, length(Path)-1)])) + end, + Parents = case Parent of + <<>> -> []; + _ -> [Parent] + end, + case node_call(Host, Type, create_node_permission, + [Host, ServerHost, Node, Parent, Owner, Access]) of + {result, true} -> + case tree_call(Host, create_node, + [Host, Node, Type, Owner, NodeOptions, Parents]) + of + {ok, Nidx} -> + SubsByDepth = get_node_subs_by_depth(Host, Node, Owner), + case node_call(Host, Type, create_node, [Nidx, Owner]) of + {result, Result} -> {result, {Nidx, SubsByDepth, Result}}; + Error -> Error end; - _ -> - Txt = <<"You're not allowed to create nodes">>, - {error, xmpp:err_forbidden(Txt, ?MYLANG)} - end - end, - Reply = #pubsub{create = Node}, - case transaction(Host, CreateNode, transaction) of - {result, {Nidx, SubsByDepth, {Result, broadcast}}} -> - broadcast_created_node(Host, Node, Nidx, Type, NodeOptions, SubsByDepth), - ejabberd_hooks:run(pubsub_create_node, ServerHost, - [ServerHost, Host, Node, Nidx, NodeOptions]), - case Result of - default -> {result, Reply}; - _ -> {result, Result} - end; - {result, {Nidx, _SubsByDepth, Result}} -> - ejabberd_hooks:run(pubsub_create_node, ServerHost, - [ServerHost, Host, Node, Nidx, NodeOptions]), - case Result of - default -> {result, Reply}; - _ -> {result, Result} - end; - Error -> - %% in case we change transaction to sync_dirty... - %% node_call(Host, Type, delete_node, [Host, Node]), - %% tree_call(Host, delete_node, [Host, Node]), - Error + {error, {virtual, Nidx}} -> + case node_call(Host, Type, create_node, [Nidx, Owner]) of + {result, Result} -> {result, {Nidx, [], Result}}; + Error -> Error + end; + Error -> + Error + end; + _ -> + Txt = <<"You're not allowed to create nodes">>, + {error, xmpp:err_forbidden(Txt, ?MYLANG)} + end + end, + Reply = #pubsub{create = Node}, + case transaction(Host, CreateNode, transaction) of + {result, {Nidx, SubsByDepth, {Result, broadcast}}} -> + broadcast_created_node(Host, Node, Nidx, Type, NodeOptions, SubsByDepth), + ejabberd_hooks:run(pubsub_create_node, ServerHost, + [ServerHost, Host, Node, Nidx, NodeOptions]), + case Result of + default -> {result, Reply}; + _ -> {result, Result} + end; + {result, {Nidx, _SubsByDepth, Result}} -> + ejabberd_hooks:run(pubsub_create_node, ServerHost, + [ServerHost, Host, Node, Nidx, NodeOptions]), + case Result of + default -> {result, Reply}; + _ -> {result, Result} end; Error -> + %% in case we change transaction to sync_dirty... + %% node_call(Host, Type, delete_node, [Host, Node]), + %% tree_call(Host, delete_node, [Host, Node]), Error end. @@ -2636,7 +2605,7 @@ set_subscriptions(Host, Node, From, Entities) -> Owner = jid:tolower(jid:remove_resource(From)), Notify = fun(#ps_subscription{jid = JID, type = Sub}) -> Stanza = #message{ - sub_els = [#pubsub{ + sub_els = [#ps_event{ subscription = #ps_subscription{ jid = JID, type = Sub, @@ -3266,83 +3235,17 @@ max_items(Host, Options) -> end end. --define(BOOL_CONFIG_FIELD(Label, Var), - ?BOOLXFIELD(Label, - <<"pubsub#", (atom_to_binary(Var, latin1))/binary>>, - (get_option(Options, Var)))). - --define(STRING_CONFIG_FIELD(Label, Var), - ?STRINGXFIELD(Label, - <<"pubsub#", (atom_to_binary(Var, latin1))/binary>>, - (get_option(Options, Var, <<>>)))). - --define(INTEGER_CONFIG_FIELD(Label, Var), - ?STRINGXFIELD(Label, - <<"pubsub#", (atom_to_binary(Var, latin1))/binary>>, - (integer_to_binary(get_option(Options, Var))))). - --define(JLIST_CONFIG_FIELD(Label, Var, Opts), - ?LISTXFIELD(Label, - <<"pubsub#", (atom_to_binary(Var, latin1))/binary>>, - (jid:to_string(get_option(Options, Var))), - [jid:to_string(O) || O <- Opts])). - --define(ALIST_CONFIG_FIELD(Label, Var, Opts), - ?LISTXFIELD(Label, - <<"pubsub#", (atom_to_binary(Var, latin1))/binary>>, - (atom_to_binary(get_option(Options, Var), latin1)), - [atom_to_binary(O, latin1) || O <- Opts])). - --define(LISTM_CONFIG_FIELD(Label, Var, Opts), - ?LISTMXFIELD(Label, - <<"pubsub#", (atom_to_binary(Var, latin1))/binary>>, - (get_option(Options, Var)), Opts)). - --define(NLIST_CONFIG_FIELD(Label, Var), - ?STRINGMXFIELD(Label, - <<"pubsub#", (atom_to_binary(Var, latin1))/binary>>, - get_option(Options, Var, []))). - +-spec get_configure_xfields(_, pubsub_node_config:result(), + binary(), [binary()]) -> [xdata_field()]. get_configure_xfields(_Type, Options, Lang, Groups) -> - [?XFIELD(hidden, <<>>, <<"FORM_TYPE">>, ?NS_PUBSUB_NODE_CONFIG), - ?BOOL_CONFIG_FIELD(<<"Deliver payloads with event notifications">>, - deliver_payloads), - ?BOOL_CONFIG_FIELD(<<"Deliver event notifications">>, - deliver_notifications), - ?BOOL_CONFIG_FIELD(<<"Notify subscribers when the node configuration changes">>, - notify_config), - ?BOOL_CONFIG_FIELD(<<"Notify subscribers when the node is deleted">>, - notify_delete), - ?BOOL_CONFIG_FIELD(<<"Notify subscribers when items are removed from the node">>, - notify_retract), - ?BOOL_CONFIG_FIELD(<<"Persist items to storage">>, - persist_items), - ?STRING_CONFIG_FIELD(<<"A friendly name for the node">>, - title), - ?INTEGER_CONFIG_FIELD(<<"Max # of items to persist">>, - max_items), - ?BOOL_CONFIG_FIELD(<<"Whether to allow subscriptions">>, - subscribe), - ?ALIST_CONFIG_FIELD(<<"Specify the access model">>, - access_model, [open, authorize, presence, roster, whitelist]), - ?LISTM_CONFIG_FIELD(<<"Roster groups allowed to subscribe">>, - roster_groups_allowed, Groups), - ?ALIST_CONFIG_FIELD(<<"Specify the publisher model">>, - publish_model, [publishers, subscribers, open]), - ?BOOL_CONFIG_FIELD(<<"Purge all items when the relevant publisher goes offline">>, - purge_offline), - ?ALIST_CONFIG_FIELD(<<"Specify the event message type">>, - notification_type, [headline, normal]), - ?INTEGER_CONFIG_FIELD(<<"Max payload size in bytes">>, - max_payload_size), - ?ALIST_CONFIG_FIELD(<<"When to send the last published item">>, - send_last_published_item, [never, on_sub, on_sub_and_presence]), - ?BOOL_CONFIG_FIELD(<<"Only deliver notifications to available users">>, - presence_based_delivery), - ?NLIST_CONFIG_FIELD(<<"The collections with which a node is affiliated">>, - collection), - ?ALIST_CONFIG_FIELD(<<"Whether owners or publisher should receive replies to items">>, - itemreply, [none, owner, publisher])]. + pubsub_node_config:encode( + lists:map( + fun({roster_groups_allowed, Value}) -> + {roster_groups_allowed, Value, Groups}; + (Opt) -> + Opt + end, Options), + fun(Txt) -> translate:translate(Lang, Txt) end). %%

      There are several reasons why the node configuration request might fail:

      %%
        @@ -3365,18 +3268,13 @@ set_configure(Host, Node, From, Config, Lang) -> [] -> node_options(Host, Type); _ -> Options end, - case set_xoption(Host, Config, OldOpts) of - NewOpts when is_list(NewOpts) -> - case tree_call(Host, - set_node, - [N#pubsub_node{options = NewOpts}]) - of - {result, Nidx} -> {result, ok}; - ok -> {result, ok}; - Err -> Err - end; - Error -> - Error + NewOpts = merge_config(Config, OldOpts), + case tree_call(Host, + set_node, + [N#pubsub_node{options = NewOpts}]) of + {result, Nidx} -> {result, ok}; + ok -> {result, ok}; + Err -> Err end; _ -> {error, xmpp:err_forbidden( @@ -3394,119 +3292,82 @@ set_configure(Host, Node, From, Config, Lang) -> Other end. --spec add_opt(atom(), any(), [{atom(), any()}]) -> [{atom(), any()}]. -add_opt(Key, Value, Opts) -> - lists:keystore(Key, 1, Opts, {Key, Value}). +-spec merge_config([proplists:property()], [proplists:property()]) -> [proplists:property()]. +merge_config(Config1, Config2) -> + lists:foldl( + fun({Opt, Val}, Acc) -> + lists:keystore(Opt, 1, Acc, {Opt, Val}) + end, Config2, Config1). --define(SET_BOOL_XOPT(Opt, Val), - BoolVal = case Val of - <<"0">> -> false; - <<"1">> -> true; - <<"false">> -> false; - <<"true">> -> true; - _ -> error - end, - case BoolVal of - error -> - Txt = <<"Value of '~s' should be boolean">>, - ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), - {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)}; - _ -> set_xoption(Host, Opts, add_opt(Opt, BoolVal, NewOpts)) - end). - --define(SET_STRING_XOPT(Opt, Val), - set_xoption(Host, Opts, add_opt(Opt, Val, NewOpts))). - --define(SET_INTEGER_XOPT(Opt, Val, Min, Max), - case catch binary_to_integer(Val) of - IVal when is_integer(IVal), IVal >= Min -> - if (Max =:= undefined) orelse (IVal =< Max) -> - set_xoption(Host, Opts, add_opt(Opt, IVal, NewOpts)); - true -> - Txt = <<"Incorrect value of '~s'">>, - ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), - {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} - end; - _ -> - Txt = <<"Value of '~s' should be integer">>, - ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), - {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} - end). - --define(SET_ALIST_XOPT(Opt, Val, Vals), - case lists:member(Val, [atom_to_binary(V, latin1) || V <- Vals]) of - true -> - set_xoption(Host, Opts, add_opt(Opt, jlib:binary_to_atom(Val), NewOpts)); - false -> - Txt = <<"Incorrect value of '~s'">>, - ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), - {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} - end). - --define(SET_LIST_XOPT(Opt, Val), - set_xoption(Host, Opts, add_opt(Opt, Val, NewOpts))). - --spec set_xoption(host(), [{binary(), [binary()]}], [{atom(), any()}]) -> [{atom(), any()}]. -set_xoption(_Host, [], NewOpts) -> NewOpts; -set_xoption(Host, [{<<"FORM_TYPE">>, _} | Opts], NewOpts) -> - set_xoption(Host, Opts, NewOpts); -set_xoption(Host, [{<<"pubsub#roster_groups_allowed">>, Value} | Opts], NewOpts) -> - ?SET_LIST_XOPT(roster_groups_allowed, Value); -set_xoption(Host, [{<<"pubsub#deliver_payloads">>, [Val]} | Opts], NewOpts) -> - ?SET_BOOL_XOPT(deliver_payloads, Val); -set_xoption(Host, [{<<"pubsub#deliver_notifications">>, [Val]} | Opts], NewOpts) -> - ?SET_BOOL_XOPT(deliver_notifications, Val); -set_xoption(Host, [{<<"pubsub#notify_config">>, [Val]} | Opts], NewOpts) -> - ?SET_BOOL_XOPT(notify_config, Val); -set_xoption(Host, [{<<"pubsub#notify_delete">>, [Val]} | Opts], NewOpts) -> - ?SET_BOOL_XOPT(notify_delete, Val); -set_xoption(Host, [{<<"pubsub#notify_retract">>, [Val]} | Opts], NewOpts) -> - ?SET_BOOL_XOPT(notify_retract, Val); -set_xoption(Host, [{<<"pubsub#persist_items">>, [Val]} | Opts], NewOpts) -> - ?SET_BOOL_XOPT(persist_items, Val); -set_xoption(Host, [{<<"pubsub#max_items">>, [Val]} | Opts], NewOpts) -> - MaxItems = get_max_items_node(Host), - ?SET_INTEGER_XOPT(max_items, Val, 0, MaxItems); -set_xoption(Host, [{<<"pubsub#subscribe">>, [Val]} | Opts], NewOpts) -> - ?SET_BOOL_XOPT(subscribe, Val); -set_xoption(Host, [{<<"pubsub#access_model">>, [Val]} | Opts], NewOpts) -> - ?SET_ALIST_XOPT(access_model, Val, [open, authorize, presence, roster, whitelist]); -set_xoption(Host, [{<<"pubsub#publish_model">>, [Val]} | Opts], NewOpts) -> - ?SET_ALIST_XOPT(publish_model, Val, [publishers, subscribers, open]); -set_xoption(Host, [{<<"pubsub#notification_type">>, [Val]} | Opts], NewOpts) -> - ?SET_ALIST_XOPT(notification_type, Val, [headline, normal]); -set_xoption(Host, [{<<"pubsub#node_type">>, [Val]} | Opts], NewOpts) -> - ?SET_ALIST_XOPT(node_type, Val, [leaf, collection]); -set_xoption(Host, [{<<"pubsub#max_payload_size">>, [Val]} | Opts], NewOpts) -> - ?SET_INTEGER_XOPT(max_payload_size, Val, 0, (?MAX_PAYLOAD_SIZE)); -set_xoption(Host, [{<<"pubsub#send_last_published_item">>, [Val]} | Opts], NewOpts) -> - ?SET_ALIST_XOPT(send_last_published_item, Val, [never, on_sub, on_sub_and_presence]); -set_xoption(Host, [{<<"pubsub#presence_based_delivery">>, [Val]} | Opts], NewOpts) -> - ?SET_BOOL_XOPT(presence_based_delivery, Val); -set_xoption(Host, [{<<"pubsub#purge_offline">>, [Val]} | Opts], NewOpts) -> - ?SET_BOOL_XOPT(purge_offline, Val); -set_xoption(Host, [{<<"pubsub#title">>, Value} | Opts], NewOpts) -> - ?SET_STRING_XOPT(title, Value); -set_xoption(Host, [{<<"pubsub#type">>, Value} | Opts], NewOpts) -> - ?SET_STRING_XOPT(type, Value); -set_xoption(Host, [{<<"pubsub#body_xslt">>, Value} | Opts], NewOpts) -> - ?SET_STRING_XOPT(body_xslt, Value); -set_xoption(Host, [{<<"pubsub#collection">>, Value} | Opts], NewOpts) -> - % NewValue = [string_to_node(V) || V <- Value], - ?SET_LIST_XOPT(collection, Value); -set_xoption(Host, [{<<"pubsub#node">>, [Value]} | Opts], NewOpts) -> - % NewValue = string_to_node(Value), - ?SET_LIST_XOPT(node, Value); -set_xoption(Host, [{<<"pubsub#itemreply">>, [Val]} | Opts], NewOpts) -> - ?SET_ALIST_XOPT(itemreply, Val, [none, owner, publisher]); -set_xoption(Host, [_ | Opts], NewOpts) -> - set_xoption(Host, Opts, NewOpts). - --spec get_xdata_fields(undefined | xdata()) -> [{binary(), [binary()]}]. -get_xdata_fields(undefined) -> +-spec decode_node_config(undefined | xdata(), binary(), binary()) -> + pubsub_node_config:result() | + {error, stanza_error()}. +decode_node_config(undefined, _, _) -> []; -get_xdata_fields(#xdata{fields = Fs}) -> - [{Var, Vals} || #xdata_field{var = Var, values = Vals} <- Fs]. +decode_node_config(#xdata{fields = Fs}, Host, Lang) -> + try + Config = pubsub_node_config:decode(Fs), + Max = get_max_items_node(Host), + case {check_opt_range(max_items, Config, Max), + check_opt_range(max_payload_size, Config, ?MAX_PAYLOAD_SIZE)} of + {true, true} -> + Config; + {true, false} -> + erlang:error( + {pubsub_node_config, + {bad_var_value, <<"pubsub#max_payload_size">>, + ?NS_PUBSUB_NODE_CONFIG}}); + {false, _} -> + erlang:error( + {pubsub_node_config, + {bad_var_value, <<"pubsub#max_items">>, + ?NS_PUBSUB_NODE_CONFIG}}) + end + catch _:{pubsub_node_config, Why} -> + Txt = pubsub_node_config:format_error(Why), + {error, xmpp:err_resource_constraint(Txt, Lang)} + end. + +-spec decode_subscribe_options(undefined | xdata(), binary()) -> + pubsub_subscribe_options:result() | + {error, stanza_error()}. +decode_subscribe_options(undefined, _) -> + []; +decode_subscribe_options(#xdata{fields = Fs}, Lang) -> + try pubsub_subscribe_options:decode(Fs) + catch _:{pubsub_subscribe_options, Why} -> + Txt = pubsub_subscribe_options:format_error(Why), + {error, xmpp:err_resource_constraint(Txt, Lang)} + end. + +-spec decode_publish_options(undefined | xdata(), binary()) -> + pubsub_publish_options:result() | + {error, stanza_error()}. +decode_publish_options(undefined, _) -> + []; +decode_publish_options(#xdata{fields = Fs}, Lang) -> + try pubsub_publish_options:decode(Fs) + catch _:{pubsub_publish_options, Why} -> + Txt = pubsub_publish_options:format_error(Why), + {error, xmpp:err_resource_constraint(Txt, Lang)} + end. + +-spec decode_get_pending(xdata(), binary()) -> + pubsub_get_pending:result() | + {error, stanza_error()}. +decode_get_pending(#xdata{fields = Fs}, Lang) -> + try pubsub_get_pending:decode(Fs) + catch _:{pubsub_get_pending, Why} -> + Txt = pubsub_get_pending:format_error(Why), + {error, xmpp:err_resource_constraint(Txt, Lang)} + end; +decode_get_pending(undefined, Lang) -> + {error, xmpp:err_bad_request(<<"No data form found">>, Lang)}. + +-spec check_opt_range(atom(), [proplists:property()], non_neg_integer()) -> boolean(). +check_opt_range(Opt, Opts, Max) -> + Val = proplists:get_value(Opt, Opts, Max), + Val =< Max. -spec get_max_items_node(host()) -> undefined | non_neg_integer(). get_max_items_node(Host) -> diff --git a/src/muc_register.erl b/src/muc_register.erl new file mode 100644 index 000000000..cddce2b98 --- /dev/null +++ b/src/muc_register.erl @@ -0,0 +1,364 @@ +%% Created automatically by xdata generator (xdata_codec.erl) +%% Source: muc_register.xdata +%% Form type: http://jabber.org/protocol/muc#register +%% Document: XEP-0045 + +-module(muc_register). + +-export([decode/1, decode/2, encode/1, encode/2, + format_error/1]). + +-include("xmpp_codec.hrl"). + +-include("muc_register.hrl"). + +-export_type([{property, 0}, {result, 0}, {form, 0}]). + +dec_bool(<<"1">>) -> true; +dec_bool(<<"0">>) -> false; +dec_bool(<<"true">>) -> true; +dec_bool(<<"false">>) -> false. + +enc_bool(true) -> <<"1">>; +enc_bool(false) -> <<"0">>. + +format_error({form_type_mismatch, Type}) -> + <<"FORM_TYPE doesn't match '", Type/binary, "'">>; +format_error({bad_var_value, Var, Type}) -> + <<"Bad value of field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({missing_value, Var, Type}) -> + <<"Missing value of field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({too_many_values, Var, Type}) -> + <<"Too many values for field '", Var/binary, + "' of type '", Type/binary, "'">>; +format_error({unknown_var, Var, Type}) -> + <<"Unknown field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({missing_required_var, Var, Type}) -> + <<"Missing required field '", Var/binary, "' of type '", + Type/binary, "'">>. + +decode(Fs) -> decode(Fs, []). + +decode(Fs, Acc) -> + case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var, + Fs) + of + false -> decode(Fs, Acc, [<<"muc#register_roomnick">>]); + #xdata_field{values = + [<<"http://jabber.org/protocol/muc#register">>]} -> + decode(Fs, Acc, [<<"muc#register_roomnick">>]); + _ -> + erlang:error({?MODULE, + {form_type_mismatch, + <<"http://jabber.org/protocol/muc#register">>}}) + end. + +encode(Cfg) -> encode(Cfg, fun (Text) -> Text end). + +encode(List, Translate) when is_list(List) -> + Fs = [case Opt of + {allow, Val} -> [encode_allow(Val, Translate)]; + {allow, _, _} -> erlang:error({badarg, Opt}); + {email, Val} -> [encode_email(Val, Translate)]; + {email, _, _} -> erlang:error({badarg, Opt}); + {faqentry, Val} -> [encode_faqentry(Val, Translate)]; + {faqentry, _, _} -> erlang:error({badarg, Opt}); + {first, Val} -> [encode_first(Val, Translate)]; + {first, _, _} -> erlang:error({badarg, Opt}); + {last, Val} -> [encode_last(Val, Translate)]; + {last, _, _} -> erlang:error({badarg, Opt}); + {roomnick, Val} -> [encode_roomnick(Val, Translate)]; + {roomnick, _, _} -> erlang:error({badarg, Opt}); + {url, Val} -> [encode_url(Val, Translate)]; + {url, _, _} -> erlang:error({badarg, Opt}); + #xdata_field{} -> [Opt]; + _ -> [] + end + || Opt <- List], + FormType = #xdata_field{var = <<"FORM_TYPE">>, + type = hidden, + values = + [<<"http://jabber.org/protocol/muc#register">>]}, + [FormType | lists:flatten(Fs)]. + +decode([#xdata_field{var = <<"muc#register_allow">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{allow, Result} | Acc], + lists:delete(<<"muc#register_allow">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#register_allow">>, + <<"http://jabber.org/protocol/muc#register">>}}) + end; +decode([#xdata_field{var = <<"muc#register_allow">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"muc#register_allow">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"muc#register_allow">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#register_allow">>, + <<"http://jabber.org/protocol/muc#register">>}}); +decode([#xdata_field{var = <<"muc#register_email">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{email, Result} | Acc], + lists:delete(<<"muc#register_email">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#register_email">>, + <<"http://jabber.org/protocol/muc#register">>}}) + end; +decode([#xdata_field{var = <<"muc#register_email">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"muc#register_email">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"muc#register_email">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#register_email">>, + <<"http://jabber.org/protocol/muc#register">>}}); +decode([#xdata_field{var = <<"muc#register_faqentry">>, + values = Values} + | Fs], + Acc, Required) -> + try [Value || Value <- Values] of + Result -> + decode(Fs, [{faqentry, Result} | Acc], + lists:delete(<<"muc#register_faqentry">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#register_faqentry">>, + <<"http://jabber.org/protocol/muc#register">>}}) + end; +decode([#xdata_field{var = <<"muc#register_first">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{first, Result} | Acc], + lists:delete(<<"muc#register_first">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#register_first">>, + <<"http://jabber.org/protocol/muc#register">>}}) + end; +decode([#xdata_field{var = <<"muc#register_first">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"muc#register_first">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"muc#register_first">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#register_first">>, + <<"http://jabber.org/protocol/muc#register">>}}); +decode([#xdata_field{var = <<"muc#register_last">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{last, Result} | Acc], + lists:delete(<<"muc#register_last">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#register_last">>, + <<"http://jabber.org/protocol/muc#register">>}}) + end; +decode([#xdata_field{var = <<"muc#register_last">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"muc#register_last">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"muc#register_last">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#register_last">>, + <<"http://jabber.org/protocol/muc#register">>}}); +decode([#xdata_field{var = <<"muc#register_roomnick">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{roomnick, Result} | Acc], + lists:delete(<<"muc#register_roomnick">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#register_roomnick">>, + <<"http://jabber.org/protocol/muc#register">>}}) + end; +decode([#xdata_field{var = <<"muc#register_roomnick">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"muc#register_roomnick">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"muc#register_roomnick">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#register_roomnick">>, + <<"http://jabber.org/protocol/muc#register">>}}); +decode([#xdata_field{var = <<"muc#register_url">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{url, Result} | Acc], + lists:delete(<<"muc#register_url">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#register_url">>, + <<"http://jabber.org/protocol/muc#register">>}}) + end; +decode([#xdata_field{var = <<"muc#register_url">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"muc#register_url">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"muc#register_url">>} | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#register_url">>, + <<"http://jabber.org/protocol/muc#register">>}}); +decode([#xdata_field{var = Var} | Fs], Acc, Required) -> + if Var /= <<"FORM_TYPE">> -> + erlang:error({?MODULE, + {unknown_var, Var, + <<"http://jabber.org/protocol/muc#register">>}}); + true -> decode(Fs, Acc, Required) + end; +decode([], _, [Var | _]) -> + erlang:error({?MODULE, + {missing_required_var, Var, + <<"http://jabber.org/protocol/muc#register">>}}); +decode([], Acc, []) -> Acc. + +encode_allow(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"muc#register_allow">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = + Translate(<<"Allow this person to register with the " + "room?">>)}. + +encode_email(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"muc#register_email">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = Translate(<<"Email Address">>)}. + +encode_faqentry(Value, Translate) -> + Values = case Value of + [] -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"muc#register_faqentry">>, + values = Values, required = false, type = 'text-multi', + options = Opts, desc = <<>>, + label = Translate(<<"FAQ Entry">>)}. + +encode_first(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"muc#register_first">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = Translate(<<"Given Name">>)}. + +encode_last(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"muc#register_last">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = Translate(<<"Family Name">>)}. + +encode_roomnick(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"muc#register_roomnick">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = Translate(<<"Nickname">>)}. + +encode_url(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"muc#register_url">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = Translate(<<"A Web Page">>)}. diff --git a/src/muc_request.erl b/src/muc_request.erl new file mode 100644 index 000000000..4c7becd2e --- /dev/null +++ b/src/muc_request.erl @@ -0,0 +1,269 @@ +%% Created automatically by xdata generator (xdata_codec.erl) +%% Source: muc_request.xdata +%% Form type: http://jabber.org/protocol/muc#request +%% Document: XEP-0045 + +-module(muc_request). + +-export([decode/1, decode/2, encode/1, encode/2, + format_error/1]). + +-include("xmpp_codec.hrl"). + +-include("muc_request.hrl"). + +-export_type([{property, 0}, {result, 0}, {form, 0}]). + +dec_enum(Val, Enums) -> + AtomVal = erlang:binary_to_existing_atom(Val, utf8), + case lists:member(AtomVal, Enums) of + true -> AtomVal + end. + +enc_enum(Atom) -> erlang:atom_to_binary(Atom, utf8). + +dec_bool(<<"1">>) -> true; +dec_bool(<<"0">>) -> false; +dec_bool(<<"true">>) -> true; +dec_bool(<<"false">>) -> false. + +enc_bool(true) -> <<"1">>; +enc_bool(false) -> <<"0">>. + +enc_jid(J) -> jid:to_string(J). + +dec_jid(Val) -> + case jid:from_string(Val) of + error -> erlang:error(badarg); + J -> J + end. + +format_error({form_type_mismatch, Type}) -> + <<"FORM_TYPE doesn't match '", Type/binary, "'">>; +format_error({bad_var_value, Var, Type}) -> + <<"Bad value of field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({missing_value, Var, Type}) -> + <<"Missing value of field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({too_many_values, Var, Type}) -> + <<"Too many values for field '", Var/binary, + "' of type '", Type/binary, "'">>; +format_error({unknown_var, Var, Type}) -> + <<"Unknown field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({missing_required_var, Var, Type}) -> + <<"Missing required field '", Var/binary, "' of type '", + Type/binary, "'">>. + +decode(Fs) -> decode(Fs, []). + +decode(Fs, Acc) -> + case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var, + Fs) + of + false -> decode(Fs, Acc, [<<"muc#role">>]); + #xdata_field{values = + [<<"http://jabber.org/protocol/muc#request">>]} -> + decode(Fs, Acc, [<<"muc#role">>]); + _ -> + erlang:error({?MODULE, + {form_type_mismatch, + <<"http://jabber.org/protocol/muc#request">>}}) + end. + +encode(Cfg) -> encode(Cfg, fun (Text) -> Text end). + +encode(List, Translate) when is_list(List) -> + Fs = [case Opt of + {role, Val} -> [encode_role(Val, default, Translate)]; + {role, Val, Opts} -> + [encode_role(Val, Opts, Translate)]; + {jid, Val} -> [encode_jid(Val, Translate)]; + {jid, _, _} -> erlang:error({badarg, Opt}); + {roomnick, Val} -> [encode_roomnick(Val, Translate)]; + {roomnick, _, _} -> erlang:error({badarg, Opt}); + {request_allow, Val} -> + [encode_request_allow(Val, Translate)]; + {request_allow, _, _} -> erlang:error({badarg, Opt}); + #xdata_field{} -> [Opt]; + _ -> [] + end + || Opt <- List], + FormType = #xdata_field{var = <<"FORM_TYPE">>, + type = hidden, + values = + [<<"http://jabber.org/protocol/muc#request">>]}, + [FormType | lists:flatten(Fs)]. + +decode([#xdata_field{var = <<"muc#role">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_enum(Value, [participant]) of + Result -> + decode(Fs, [{role, Result} | Acc], + lists:delete(<<"muc#role">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#role">>, + <<"http://jabber.org/protocol/muc#request">>}}) + end; +decode([#xdata_field{var = <<"muc#role">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"muc#role">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"muc#role">>} | _], _, + _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#role">>, + <<"http://jabber.org/protocol/muc#request">>}}); +decode([#xdata_field{var = <<"muc#jid">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_jid(Value) of + Result -> + decode(Fs, [{jid, Result} | Acc], + lists:delete(<<"muc#jid">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#jid">>, + <<"http://jabber.org/protocol/muc#request">>}}) + end; +decode([#xdata_field{var = <<"muc#jid">>, values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"muc#jid">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"muc#jid">>} | _], _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#jid">>, + <<"http://jabber.org/protocol/muc#request">>}}); +decode([#xdata_field{var = <<"muc#roomnick">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{roomnick, Result} | Acc], + lists:delete(<<"muc#roomnick">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roomnick">>, + <<"http://jabber.org/protocol/muc#request">>}}) + end; +decode([#xdata_field{var = <<"muc#roomnick">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"muc#roomnick">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"muc#roomnick">>} | _], _, + _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#roomnick">>, + <<"http://jabber.org/protocol/muc#request">>}}); +decode([#xdata_field{var = <<"muc#request_allow">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{request_allow, Result} | Acc], + lists:delete(<<"muc#request_allow">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#request_allow">>, + <<"http://jabber.org/protocol/muc#request">>}}) + end; +decode([#xdata_field{var = <<"muc#request_allow">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"muc#request_allow">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"muc#request_allow">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#request_allow">>, + <<"http://jabber.org/protocol/muc#request">>}}); +decode([#xdata_field{var = Var} | Fs], Acc, Required) -> + if Var /= <<"FORM_TYPE">> -> + erlang:error({?MODULE, + {unknown_var, Var, + <<"http://jabber.org/protocol/muc#request">>}}); + true -> decode(Fs, Acc, Required) + end; +decode([], _, [Var | _]) -> + erlang:error({?MODULE, + {missing_required_var, Var, + <<"http://jabber.org/protocol/muc#request">>}}); +decode([], Acc, []) -> Acc. + +encode_role(Value, Options, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_enum(Value)] + end, + Opts = if Options == default -> + [#xdata_option{label = Translate(<<"Participant">>), + value = <<"participant">>}]; + true -> + [#xdata_option{label = Translate(L), + value = enc_enum(V)} + || {L, V} <- Options] + end, + #xdata_field{var = <<"muc#role">>, values = Values, + required = false, type = 'list-single', options = Opts, + desc = <<>>, label = Translate(<<"Requested role">>)}. + +encode_jid(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_jid(Value)] + end, + Opts = [], + #xdata_field{var = <<"muc#jid">>, values = Values, + required = false, type = 'jid-single', options = Opts, + desc = <<>>, label = Translate(<<"User JID">>)}. + +encode_roomnick(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"muc#roomnick">>, values = Values, + required = false, type = 'text-single', options = Opts, + desc = <<>>, label = Translate(<<"Nickname">>)}. + +encode_request_allow(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"muc#request_allow">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = Translate(<<"Grant voice to this person?">>)}. diff --git a/src/muc_roomconfig.erl b/src/muc_roomconfig.erl new file mode 100644 index 000000000..73ceb649e --- /dev/null +++ b/src/muc_roomconfig.erl @@ -0,0 +1,1675 @@ +%% Created automatically by xdata generator (xdata_codec.erl) +%% Source: muc_roomconfig.xdata +%% Form type: http://jabber.org/protocol/muc#roomconfig +%% Document: XEP-0045 + +-module(muc_roomconfig). + +-export([decode/1, decode/2, encode/1, encode/2, + format_error/1]). + +-include("xmpp_codec.hrl"). + +-include("muc_roomconfig.hrl"). + +-export_type([{property, 0}, {result, 0}, {form, 0}]). + +dec_int(Val, Min, Max) -> + case list_to_integer(binary_to_list(Val)) of + Int when Int =< Max, Min == infinity -> Int; + Int when Int =< Max, Int >= Min -> Int + end. + +enc_int(Int) -> integer_to_binary(Int). + +dec_enum(Val, Enums) -> + AtomVal = erlang:binary_to_existing_atom(Val, utf8), + case lists:member(AtomVal, Enums) of + true -> AtomVal + end. + +enc_enum(Atom) -> erlang:atom_to_binary(Atom, utf8). + +dec_enum_int(Val, Enums, Min, Max) -> + try dec_int(Val, Min, Max) catch + _:_ -> dec_enum(Val, Enums) + end. + +enc_enum_int(Int) when is_integer(Int) -> enc_int(Int); +enc_enum_int(Atom) -> enc_enum(Atom). + +dec_bool(<<"1">>) -> true; +dec_bool(<<"0">>) -> false; +dec_bool(<<"true">>) -> true; +dec_bool(<<"false">>) -> false. + +enc_bool(true) -> <<"1">>; +enc_bool(false) -> <<"0">>. + +enc_jid(J) -> jid:to_string(J). + +dec_jid(Val) -> + case jid:from_string(Val) of + error -> erlang:error(badarg); + J -> J + end. + +format_error({form_type_mismatch, Type}) -> + <<"FORM_TYPE doesn't match '", Type/binary, "'">>; +format_error({bad_var_value, Var, Type}) -> + <<"Bad value of field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({missing_value, Var, Type}) -> + <<"Missing value of field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({too_many_values, Var, Type}) -> + <<"Too many values for field '", Var/binary, + "' of type '", Type/binary, "'">>; +format_error({unknown_var, Var, Type}) -> + <<"Unknown field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({missing_required_var, Var, Type}) -> + <<"Missing required field '", Var/binary, "' of type '", + Type/binary, "'">>. + +decode(Fs) -> decode(Fs, []). + +decode(Fs, Acc) -> + case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var, + Fs) + of + false -> decode(Fs, Acc, []); + #xdata_field{values = + [<<"http://jabber.org/protocol/muc#roomconfig">>]} -> + decode(Fs, Acc, []); + _ -> + erlang:error({?MODULE, + {form_type_mismatch, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end. + +encode(Cfg) -> encode(Cfg, fun (Text) -> Text end). + +encode(List, Translate) when is_list(List) -> + Fs = [case Opt of + {maxhistoryfetch, Val} -> + [encode_maxhistoryfetch(Val, Translate)]; + {maxhistoryfetch, _, _} -> erlang:error({badarg, Opt}); + {allowpm, Val} -> + [encode_allowpm(Val, default, Translate)]; + {allowpm, Val, Opts} -> + [encode_allowpm(Val, Opts, Translate)]; + {allow_private_messages, Val} -> + [encode_allow_private_messages(Val, Translate)]; + {allow_private_messages, _, _} -> + erlang:error({badarg, Opt}); + {allow_private_messages_from_visitors, Val} -> + [encode_allow_private_messages_from_visitors(Val, + default, + Translate)]; + {allow_private_messages_from_visitors, Val, Opts} -> + [encode_allow_private_messages_from_visitors(Val, Opts, + Translate)]; + {allow_visitor_status, Val} -> + [encode_allow_visitor_status(Val, Translate)]; + {allow_visitor_status, _, _} -> + erlang:error({badarg, Opt}); + {allow_visitor_nickchange, Val} -> + [encode_allow_visitor_nickchange(Val, Translate)]; + {allow_visitor_nickchange, _, _} -> + erlang:error({badarg, Opt}); + {allow_voice_requests, Val} -> + [encode_allow_voice_requests(Val, Translate)]; + {allow_voice_requests, _, _} -> + erlang:error({badarg, Opt}); + {allow_subscription, Val} -> + [encode_allow_subscription(Val, Translate)]; + {allow_subscription, _, _} -> + erlang:error({badarg, Opt}); + {voice_request_min_interval, Val} -> + [encode_voice_request_min_interval(Val, Translate)]; + {voice_request_min_interval, _, _} -> + erlang:error({badarg, Opt}); + {captcha_protected, Val} -> + [encode_captcha_protected(Val, Translate)]; + {captcha_protected, _, _} -> + erlang:error({badarg, Opt}); + {captcha_whitelist, Val} -> + [encode_captcha_whitelist(Val, Translate)]; + {captcha_whitelist, _, _} -> + erlang:error({badarg, Opt}); + {allow_query_users, Val} -> + [encode_allow_query_users(Val, Translate)]; + {allow_query_users, _, _} -> + erlang:error({badarg, Opt}); + {allowinvites, Val} -> + [encode_allowinvites(Val, Translate)]; + {allowinvites, _, _} -> erlang:error({badarg, Opt}); + {changesubject, Val} -> + [encode_changesubject(Val, Translate)]; + {changesubject, _, _} -> erlang:error({badarg, Opt}); + {enablelogging, Val} -> + [encode_enablelogging(Val, Translate)]; + {enablelogging, _, _} -> erlang:error({badarg, Opt}); + {getmemberlist, Val} -> + [encode_getmemberlist(Val, default, Translate)]; + {getmemberlist, Val, Opts} -> + [encode_getmemberlist(Val, Opts, Translate)]; + {lang, Val} -> [encode_lang(Val, Translate)]; + {lang, _, _} -> erlang:error({badarg, Opt}); + {pubsub, Val} -> [encode_pubsub(Val, Translate)]; + {pubsub, _, _} -> erlang:error({badarg, Opt}); + {maxusers, Val} -> + [encode_maxusers(Val, default, Translate)]; + {maxusers, Val, Opts} -> + [encode_maxusers(Val, Opts, Translate)]; + {membersonly, Val} -> + [encode_membersonly(Val, Translate)]; + {membersonly, _, _} -> erlang:error({badarg, Opt}); + {moderatedroom, Val} -> + [encode_moderatedroom(Val, Translate)]; + {moderatedroom, _, _} -> erlang:error({badarg, Opt}); + {members_by_default, Val} -> + [encode_members_by_default(Val, Translate)]; + {members_by_default, _, _} -> + erlang:error({badarg, Opt}); + {passwordprotectedroom, Val} -> + [encode_passwordprotectedroom(Val, Translate)]; + {passwordprotectedroom, _, _} -> + erlang:error({badarg, Opt}); + {persistentroom, Val} -> + [encode_persistentroom(Val, Translate)]; + {persistentroom, _, _} -> erlang:error({badarg, Opt}); + {presencebroadcast, Val} -> + [encode_presencebroadcast(Val, default, Translate)]; + {presencebroadcast, Val, Opts} -> + [encode_presencebroadcast(Val, Opts, Translate)]; + {publicroom, Val} -> + [encode_publicroom(Val, Translate)]; + {publicroom, _, _} -> erlang:error({badarg, Opt}); + {public_list, Val} -> + [encode_public_list(Val, Translate)]; + {public_list, _, _} -> erlang:error({badarg, Opt}); + {roomadmins, Val} -> + [encode_roomadmins(Val, Translate)]; + {roomadmins, _, _} -> erlang:error({badarg, Opt}); + {roomdesc, Val} -> [encode_roomdesc(Val, Translate)]; + {roomdesc, _, _} -> erlang:error({badarg, Opt}); + {roomname, Val} -> [encode_roomname(Val, Translate)]; + {roomname, _, _} -> erlang:error({badarg, Opt}); + {roomowners, Val} -> + [encode_roomowners(Val, Translate)]; + {roomowners, _, _} -> erlang:error({badarg, Opt}); + {roomsecret, Val} -> + [encode_roomsecret(Val, Translate)]; + {roomsecret, _, _} -> erlang:error({badarg, Opt}); + {whois, Val} -> [encode_whois(Val, default, Translate)]; + {whois, Val, Opts} -> + [encode_whois(Val, Opts, Translate)]; + {mam, Val} -> [encode_mam(Val, Translate)]; + {mam, _, _} -> erlang:error({badarg, Opt}); + #xdata_field{} -> [Opt]; + _ -> [] + end + || Opt <- List], + FormType = #xdata_field{var = <<"FORM_TYPE">>, + type = hidden, + values = + [<<"http://jabber.org/protocol/muc#roomconfig">>]}, + [FormType | lists:flatten(Fs)]. + +decode([#xdata_field{var = <<"muc#maxhistoryfetch">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{maxhistoryfetch, Result} | Acc], + lists:delete(<<"muc#maxhistoryfetch">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#maxhistoryfetch">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = <<"muc#maxhistoryfetch">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"muc#maxhistoryfetch">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"muc#maxhistoryfetch">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#maxhistoryfetch">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = <<"muc#roomconfig_allowpm">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{allowpm, Result} | Acc], + lists:delete(<<"muc#roomconfig_allowpm">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roomconfig_allowpm">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = <<"muc#roomconfig_allowpm">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"muc#roomconfig_allowpm">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"muc#roomconfig_allowpm">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#roomconfig_allowpm">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = <<"allow_private_messages">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{allow_private_messages, Result} | Acc], + lists:delete(<<"allow_private_messages">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"allow_private_messages">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = <<"allow_private_messages">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"allow_private_messages">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"allow_private_messages">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"allow_private_messages">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = + <<"allow_private_messages_from_visitors">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_enum(Value, [nobody, moderators, anyone]) of + Result -> + decode(Fs, + [{allow_private_messages_from_visitors, Result} | Acc], + lists:delete(<<"allow_private_messages_from_visitors">>, + Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, + <<"allow_private_messages_from_visitors">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = + <<"allow_private_messages_from_visitors">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"allow_private_messages_from_visitors">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"allow_private_messages_from_visitors">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, + <<"allow_private_messages_from_visitors">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = <<"allow_visitor_status">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{allow_visitor_status, Result} | Acc], + lists:delete(<<"allow_visitor_status">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"allow_visitor_status">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = <<"allow_visitor_status">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"allow_visitor_status">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"allow_visitor_status">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"allow_visitor_status">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = + <<"allow_visitor_nickchange">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{allow_visitor_nickchange, Result} | Acc], + lists:delete(<<"allow_visitor_nickchange">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"allow_visitor_nickchange">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = + <<"allow_visitor_nickchange">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"allow_visitor_nickchange">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"allow_visitor_nickchange">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"allow_visitor_nickchange">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = <<"allow_voice_requests">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{allow_voice_requests, Result} | Acc], + lists:delete(<<"allow_voice_requests">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"allow_voice_requests">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = <<"allow_voice_requests">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"allow_voice_requests">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"allow_voice_requests">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"allow_voice_requests">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = <<"allow_subscription">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{allow_subscription, Result} | Acc], + lists:delete(<<"allow_subscription">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"allow_subscription">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = <<"allow_subscription">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"allow_subscription">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"allow_subscription">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"allow_subscription">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = + <<"voice_request_min_interval">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_int(Value, 0, infinity) of + Result -> + decode(Fs, [{voice_request_min_interval, Result} | Acc], + lists:delete(<<"voice_request_min_interval">>, + Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"voice_request_min_interval">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = + <<"voice_request_min_interval">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"voice_request_min_interval">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"voice_request_min_interval">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"voice_request_min_interval">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = <<"captcha_protected">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{captcha_protected, Result} | Acc], + lists:delete(<<"captcha_protected">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"captcha_protected">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = <<"captcha_protected">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"captcha_protected">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"captcha_protected">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"captcha_protected">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = <<"captcha_whitelist">>, + values = Values} + | Fs], + Acc, Required) -> + try [dec_jid(Value) || Value <- Values] of + Result -> + decode(Fs, [{captcha_whitelist, Result} | Acc], + lists:delete(<<"captcha_whitelist">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"captcha_whitelist">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = <<"allow_query_users">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{allow_query_users, Result} | Acc], + lists:delete(<<"allow_query_users">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"allow_query_users">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = <<"allow_query_users">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"allow_query_users">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"allow_query_users">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"allow_query_users">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = + <<"muc#roomconfig_allowinvites">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{allowinvites, Result} | Acc], + lists:delete(<<"muc#roomconfig_allowinvites">>, + Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roomconfig_allowinvites">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = + <<"muc#roomconfig_allowinvites">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"muc#roomconfig_allowinvites">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"muc#roomconfig_allowinvites">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#roomconfig_allowinvites">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = + <<"muc#roomconfig_changesubject">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{changesubject, Result} | Acc], + lists:delete(<<"muc#roomconfig_changesubject">>, + Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roomconfig_changesubject">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = + <<"muc#roomconfig_changesubject">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"muc#roomconfig_changesubject">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"muc#roomconfig_changesubject">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#roomconfig_changesubject">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = + <<"muc#roomconfig_enablelogging">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{enablelogging, Result} | Acc], + lists:delete(<<"muc#roomconfig_enablelogging">>, + Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roomconfig_enablelogging">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = + <<"muc#roomconfig_enablelogging">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"muc#roomconfig_enablelogging">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"muc#roomconfig_enablelogging">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#roomconfig_enablelogging">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = + <<"muc#roomconfig_getmemberlist">>, + values = Values} + | Fs], + Acc, Required) -> + try [Value || Value <- Values] of + Result -> + decode(Fs, [{getmemberlist, Result} | Acc], + lists:delete(<<"muc#roomconfig_getmemberlist">>, + Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roomconfig_getmemberlist">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = <<"muc#roomconfig_lang">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{lang, Result} | Acc], + lists:delete(<<"muc#roomconfig_lang">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roomconfig_lang">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = <<"muc#roomconfig_lang">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"muc#roomconfig_lang">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"muc#roomconfig_lang">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#roomconfig_lang">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = <<"muc#roomconfig_pubsub">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{pubsub, Result} | Acc], + lists:delete(<<"muc#roomconfig_pubsub">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roomconfig_pubsub">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = <<"muc#roomconfig_pubsub">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"muc#roomconfig_pubsub">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"muc#roomconfig_pubsub">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#roomconfig_pubsub">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = + <<"muc#roomconfig_maxusers">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_enum_int(Value, [none], 0, infinity) of + Result -> + decode(Fs, [{maxusers, Result} | Acc], + lists:delete(<<"muc#roomconfig_maxusers">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roomconfig_maxusers">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = + <<"muc#roomconfig_maxusers">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"muc#roomconfig_maxusers">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"muc#roomconfig_maxusers">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#roomconfig_maxusers">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = + <<"muc#roomconfig_membersonly">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{membersonly, Result} | Acc], + lists:delete(<<"muc#roomconfig_membersonly">>, + Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roomconfig_membersonly">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = + <<"muc#roomconfig_membersonly">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"muc#roomconfig_membersonly">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"muc#roomconfig_membersonly">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#roomconfig_membersonly">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = + <<"muc#roomconfig_moderatedroom">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{moderatedroom, Result} | Acc], + lists:delete(<<"muc#roomconfig_moderatedroom">>, + Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roomconfig_moderatedroom">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = + <<"muc#roomconfig_moderatedroom">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"muc#roomconfig_moderatedroom">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"muc#roomconfig_moderatedroom">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#roomconfig_moderatedroom">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = <<"members_by_default">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{members_by_default, Result} | Acc], + lists:delete(<<"members_by_default">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"members_by_default">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = <<"members_by_default">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"members_by_default">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"members_by_default">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"members_by_default">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = + <<"muc#roomconfig_passwordprotectedroom">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{passwordprotectedroom, Result} | Acc], + lists:delete(<<"muc#roomconfig_passwordprotectedroom">>, + Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, + <<"muc#roomconfig_passwordprotectedroom">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = + <<"muc#roomconfig_passwordprotectedroom">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"muc#roomconfig_passwordprotectedroom">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"muc#roomconfig_passwordprotectedroom">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, + <<"muc#roomconfig_passwordprotectedroom">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = + <<"muc#roomconfig_persistentroom">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{persistentroom, Result} | Acc], + lists:delete(<<"muc#roomconfig_persistentroom">>, + Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roomconfig_persistentroom">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = + <<"muc#roomconfig_persistentroom">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"muc#roomconfig_persistentroom">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"muc#roomconfig_persistentroom">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#roomconfig_persistentroom">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = + <<"muc#roomconfig_presencebroadcast">>, + values = Values} + | Fs], + Acc, Required) -> + try [dec_enum(Value, [moderator, participant, visitor]) + || Value <- Values] + of + Result -> + decode(Fs, [{presencebroadcast, Result} | Acc], + lists:delete(<<"muc#roomconfig_presencebroadcast">>, + Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roomconfig_presencebroadcast">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = + <<"muc#roomconfig_publicroom">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{publicroom, Result} | Acc], + lists:delete(<<"muc#roomconfig_publicroom">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roomconfig_publicroom">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = + <<"muc#roomconfig_publicroom">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"muc#roomconfig_publicroom">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"muc#roomconfig_publicroom">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#roomconfig_publicroom">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = <<"public_list">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{public_list, Result} | Acc], + lists:delete(<<"public_list">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"public_list">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = <<"public_list">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"public_list">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"public_list">>} | _], _, + _) -> + erlang:error({?MODULE, + {too_many_values, <<"public_list">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = + <<"muc#roomconfig_roomadmins">>, + values = Values} + | Fs], + Acc, Required) -> + try [dec_jid(Value) || Value <- Values] of + Result -> + decode(Fs, [{roomadmins, Result} | Acc], + lists:delete(<<"muc#roomconfig_roomadmins">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roomconfig_roomadmins">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = + <<"muc#roomconfig_roomdesc">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{roomdesc, Result} | Acc], + lists:delete(<<"muc#roomconfig_roomdesc">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roomconfig_roomdesc">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = + <<"muc#roomconfig_roomdesc">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"muc#roomconfig_roomdesc">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"muc#roomconfig_roomdesc">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#roomconfig_roomdesc">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = + <<"muc#roomconfig_roomname">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{roomname, Result} | Acc], + lists:delete(<<"muc#roomconfig_roomname">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roomconfig_roomname">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = + <<"muc#roomconfig_roomname">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"muc#roomconfig_roomname">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"muc#roomconfig_roomname">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#roomconfig_roomname">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = + <<"muc#roomconfig_roomowners">>, + values = Values} + | Fs], + Acc, Required) -> + try [dec_jid(Value) || Value <- Values] of + Result -> + decode(Fs, [{roomowners, Result} | Acc], + lists:delete(<<"muc#roomconfig_roomowners">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roomconfig_roomowners">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = + <<"muc#roomconfig_roomsecret">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{roomsecret, Result} | Acc], + lists:delete(<<"muc#roomconfig_roomsecret">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roomconfig_roomsecret">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = + <<"muc#roomconfig_roomsecret">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"muc#roomconfig_roomsecret">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"muc#roomconfig_roomsecret">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#roomconfig_roomsecret">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = <<"muc#roomconfig_whois">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_enum(Value, [moderators, anyone]) of + Result -> + decode(Fs, [{whois, Result} | Acc], + lists:delete(<<"muc#roomconfig_whois">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roomconfig_whois">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = <<"muc#roomconfig_whois">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"muc#roomconfig_whois">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"muc#roomconfig_whois">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#roomconfig_whois">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = <<"mam">>, values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{mam, Result} | Acc], + lists:delete(<<"mam">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"mam">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}) + end; +decode([#xdata_field{var = <<"mam">>, values = []} = F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"mam">>, values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"mam">>} | _], _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"mam">>, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([#xdata_field{var = Var} | Fs], Acc, Required) -> + if Var /= <<"FORM_TYPE">> -> + erlang:error({?MODULE, + {unknown_var, Var, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); + true -> decode(Fs, Acc, Required) + end; +decode([], _, [Var | _]) -> + erlang:error({?MODULE, + {missing_required_var, Var, + <<"http://jabber.org/protocol/muc#roomconfig">>}}); +decode([], Acc, []) -> Acc. + +encode_maxhistoryfetch(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"muc#maxhistoryfetch">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = + Translate(<<"Maximum Number of History Messages Returned " + "by Room">>)}. + +encode_allowpm(Value, Options, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = if Options == default -> []; + true -> + [#xdata_option{label = Translate(L), value = V} + || {L, V} <- Options] + end, + #xdata_field{var = <<"muc#roomconfig_allowpm">>, + values = Values, required = false, type = 'list-single', + options = Opts, desc = <<>>, + label = + Translate(<<"Roles that May Send Private Messages">>)}. + +encode_allow_private_messages(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"allow_private_messages">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = + Translate(<<"Allow users to send private messages">>)}. + +encode_allow_private_messages_from_visitors(Value, + Options, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_enum(Value)] + end, + Opts = if Options == default -> + [#xdata_option{label = Translate(<<"nobody">>), + value = <<"nobody">>}, + #xdata_option{label = Translate(<<"moderators only">>), + value = <<"moderators">>}, + #xdata_option{label = Translate(<<"anyone">>), + value = <<"anyone">>}]; + true -> + [#xdata_option{label = Translate(L), + value = enc_enum(V)} + || {L, V} <- Options] + end, + #xdata_field{var = + <<"allow_private_messages_from_visitors">>, + values = Values, required = false, type = 'list-single', + options = Opts, desc = <<>>, + label = + Translate(<<"Allow visitors to send private messages to">>)}. + +encode_allow_visitor_status(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"allow_visitor_status">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = + Translate(<<"Allow visitors to send status text in " + "presence updates">>)}. + +encode_allow_visitor_nickchange(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"allow_visitor_nickchange">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = + Translate(<<"Allow visitors to change nickname">>)}. + +encode_allow_voice_requests(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"allow_voice_requests">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = + Translate(<<"Allow visitors to send voice requests">>)}. + +encode_allow_subscription(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"allow_subscription">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = Translate(<<"Allow subscription">>)}. + +encode_voice_request_min_interval(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_int(Value)] + end, + Opts = [], + #xdata_field{var = <<"voice_request_min_interval">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = + Translate(<<"Minimum interval between voice requests " + "(in seconds)">>)}. + +encode_captcha_protected(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"captcha_protected">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = Translate(<<"Make room CAPTCHA protected">>)}. + +encode_captcha_whitelist(Value, Translate) -> + Values = case Value of + [] -> []; + Value -> [enc_jid(V) || V <- Value] + end, + Opts = [], + #xdata_field{var = <<"captcha_whitelist">>, + values = Values, required = false, type = 'jid-multi', + options = Opts, desc = <<>>, + label = + Translate(<<"Exclude Jabber IDs from CAPTCHA challenge">>)}. + +encode_allow_query_users(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"allow_query_users">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = + Translate(<<"Allow users to query other users">>)}. + +encode_allowinvites(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"muc#roomconfig_allowinvites">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = Translate(<<"Allow users to send invites">>)}. + +encode_changesubject(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"muc#roomconfig_changesubject">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = + Translate(<<"Allow users to change the subject">>)}. + +encode_enablelogging(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"muc#roomconfig_enablelogging">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = Translate(<<"Enable logging">>)}. + +encode_getmemberlist(Value, Options, Translate) -> + Values = case Value of + [] -> []; + Value -> [Value] + end, + Opts = if Options == default -> []; + true -> + [#xdata_option{label = Translate(L), value = V} + || {L, V} <- Options] + end, + #xdata_field{var = <<"muc#roomconfig_getmemberlist">>, + values = Values, required = false, type = 'list-multi', + options = Opts, desc = <<>>, + label = + Translate(<<"Roles and Affiliations that May Retrieve " + "Member List">>)}. + +encode_lang(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"muc#roomconfig_lang">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = + Translate(<<"Natural Language for Room Discussions">>)}. + +encode_pubsub(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"muc#roomconfig_pubsub">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = + Translate(<<"XMPP URI of Associated Publish-Subscribe " + "Node">>)}. + +encode_maxusers(Value, Options, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_enum_int(Value)] + end, + Opts = if Options == default -> + [#xdata_option{label = Translate(<<"No limit">>), + value = <<"none">>}, + #xdata_option{value = <<"5">>}, + #xdata_option{value = <<"10">>}, + #xdata_option{value = <<"20">>}, + #xdata_option{value = <<"30">>}, + #xdata_option{value = <<"50">>}, + #xdata_option{value = <<"100">>}, + #xdata_option{value = <<"200">>}, + #xdata_option{value = <<"500">>}, + #xdata_option{value = <<"1000">>}, + #xdata_option{value = <<"2000">>}, + #xdata_option{value = <<"5000">>}]; + true -> + [#xdata_option{label = Translate(L), + value = enc_enum_int(V)} + || {L, V} <- Options] + end, + #xdata_field{var = <<"muc#roomconfig_maxusers">>, + values = Values, required = false, type = 'list-single', + options = Opts, desc = <<>>, + label = Translate(<<"Maximum Number of Occupants">>)}. + +encode_membersonly(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"muc#roomconfig_membersonly">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = Translate(<<"Make room members-only">>)}. + +encode_moderatedroom(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"muc#roomconfig_moderatedroom">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = Translate(<<"Make room moderated">>)}. + +encode_members_by_default(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"members_by_default">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = Translate(<<"Default users as participants">>)}. + +encode_passwordprotectedroom(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = + <<"muc#roomconfig_passwordprotectedroom">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = Translate(<<"Make room password protected">>)}. + +encode_persistentroom(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"muc#roomconfig_persistentroom">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = Translate(<<"Make room persistent">>)}. + +encode_presencebroadcast(Value, Options, Translate) -> + Values = case Value of + [] -> []; + Value -> [enc_enum(V) || V <- Value] + end, + Opts = if Options == default -> + [#xdata_option{label = Translate(<<"Moderator">>), + value = <<"moderator">>}, + #xdata_option{label = Translate(<<"Participant">>), + value = <<"participant">>}, + #xdata_option{label = Translate(<<"Visitor">>), + value = <<"visitor">>}]; + true -> + [#xdata_option{label = Translate(L), + value = enc_enum(V)} + || {L, V} <- Options] + end, + #xdata_field{var = + <<"muc#roomconfig_presencebroadcast">>, + values = Values, required = false, type = 'list-multi', + options = Opts, desc = <<>>, + label = + Translate(<<"Roles for which Presence is Broadcasted">>)}. + +encode_publicroom(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"muc#roomconfig_publicroom">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = Translate(<<"Make room public searchable">>)}. + +encode_public_list(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"public_list">>, values = Values, + required = false, type = boolean, options = Opts, + desc = <<>>, + label = Translate(<<"Make participants list public">>)}. + +encode_roomadmins(Value, Translate) -> + Values = case Value of + [] -> []; + Value -> [enc_jid(V) || V <- Value] + end, + Opts = [], + #xdata_field{var = <<"muc#roomconfig_roomadmins">>, + values = Values, required = false, type = 'jid-multi', + options = Opts, desc = <<>>, + label = Translate(<<"Full List of Room Admins">>)}. + +encode_roomdesc(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"muc#roomconfig_roomdesc">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = Translate(<<"Room description">>)}. + +encode_roomname(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"muc#roomconfig_roomname">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = Translate(<<"Room title">>)}. + +encode_roomowners(Value, Translate) -> + Values = case Value of + [] -> []; + Value -> [enc_jid(V) || V <- Value] + end, + Opts = [], + #xdata_field{var = <<"muc#roomconfig_roomowners">>, + values = Values, required = false, type = 'jid-multi', + options = Opts, desc = <<>>, + label = Translate(<<"Full List of Room Owners">>)}. + +encode_roomsecret(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"muc#roomconfig_roomsecret">>, + values = Values, required = false, + type = 'text-private', options = Opts, desc = <<>>, + label = Translate(<<"Password">>)}. + +encode_whois(Value, Options, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_enum(Value)] + end, + Opts = if Options == default -> + [#xdata_option{label = Translate(<<"moderators only">>), + value = <<"moderators">>}, + #xdata_option{label = Translate(<<"anyone">>), + value = <<"anyone">>}]; + true -> + [#xdata_option{label = Translate(L), + value = enc_enum(V)} + || {L, V} <- Options] + end, + #xdata_field{var = <<"muc#roomconfig_whois">>, + values = Values, required = false, type = 'list-single', + options = Opts, desc = <<>>, + label = Translate(<<"Present real Jabber IDs to">>)}. + +encode_mam(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"mam">>, values = Values, + required = false, type = boolean, options = Opts, + desc = <<>>, + label = Translate(<<"Enable message archiving">>)}. diff --git a/src/muc_roominfo.erl b/src/muc_roominfo.erl new file mode 100644 index 000000000..809dcef5b --- /dev/null +++ b/src/muc_roominfo.erl @@ -0,0 +1,491 @@ +%% Created automatically by xdata generator (xdata_codec.erl) +%% Source: muc_roominfo.xdata +%% Form type: http://jabber.org/protocol/muc#roominfo +%% Document: XEP-0045 + +-module(muc_roominfo). + +-export([decode/1, decode/2, encode/1, encode/2, + format_error/1]). + +-include("xmpp_codec.hrl"). + +-include("muc_roominfo.hrl"). + +-export_type([{property, 0}, {result, 0}, {form, 0}]). + +dec_int(Val, Min, Max) -> + case list_to_integer(binary_to_list(Val)) of + Int when Int =< Max, Min == infinity -> Int; + Int when Int =< Max, Int >= Min -> Int + end. + +enc_int(Int) -> integer_to_binary(Int). + +dec_bool(<<"1">>) -> true; +dec_bool(<<"0">>) -> false; +dec_bool(<<"true">>) -> true; +dec_bool(<<"false">>) -> false. + +enc_bool(true) -> <<"1">>; +enc_bool(false) -> <<"0">>. + +enc_jid(J) -> jid:to_string(J). + +dec_jid(Val) -> + case jid:from_string(Val) of + error -> erlang:error(badarg); + J -> J + end. + +format_error({form_type_mismatch, Type}) -> + <<"FORM_TYPE doesn't match '", Type/binary, "'">>; +format_error({bad_var_value, Var, Type}) -> + <<"Bad value of field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({missing_value, Var, Type}) -> + <<"Missing value of field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({too_many_values, Var, Type}) -> + <<"Too many values for field '", Var/binary, + "' of type '", Type/binary, "'">>; +format_error({unknown_var, Var, Type}) -> + <<"Unknown field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({missing_required_var, Var, Type}) -> + <<"Missing required field '", Var/binary, "' of type '", + Type/binary, "'">>. + +decode(Fs) -> decode(Fs, []). + +decode(Fs, Acc) -> + case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var, + Fs) + of + false -> decode(Fs, Acc, []); + #xdata_field{values = + [<<"http://jabber.org/protocol/muc#roominfo">>]} -> + decode(Fs, Acc, []); + _ -> + erlang:error({?MODULE, + {form_type_mismatch, + <<"http://jabber.org/protocol/muc#roominfo">>}}) + end. + +encode(Cfg) -> encode(Cfg, fun (Text) -> Text end). + +encode(List, Translate) when is_list(List) -> + Fs = [case Opt of + {maxhistoryfetch, Val} -> + [encode_maxhistoryfetch(Val, Translate)]; + {maxhistoryfetch, _, _} -> erlang:error({badarg, Opt}); + {contactjid, Val} -> + [encode_contactjid(Val, Translate)]; + {contactjid, _, _} -> erlang:error({badarg, Opt}); + {description, Val} -> + [encode_description(Val, Translate)]; + {description, _, _} -> erlang:error({badarg, Opt}); + {lang, Val} -> [encode_lang(Val, Translate)]; + {lang, _, _} -> erlang:error({badarg, Opt}); + {ldapgroup, Val} -> [encode_ldapgroup(Val, Translate)]; + {ldapgroup, _, _} -> erlang:error({badarg, Opt}); + {logs, Val} -> [encode_logs(Val, Translate)]; + {logs, _, _} -> erlang:error({badarg, Opt}); + {occupants, Val} -> [encode_occupants(Val, Translate)]; + {occupants, _, _} -> erlang:error({badarg, Opt}); + {subject, Val} -> [encode_subject(Val, Translate)]; + {subject, _, _} -> erlang:error({badarg, Opt}); + {subjectmod, Val} -> + [encode_subjectmod(Val, Translate)]; + {subjectmod, _, _} -> erlang:error({badarg, Opt}); + #xdata_field{} -> [Opt]; + _ -> [] + end + || Opt <- List], + FormType = #xdata_field{var = <<"FORM_TYPE">>, + type = hidden, + values = + [<<"http://jabber.org/protocol/muc#roominfo">>]}, + [FormType | lists:flatten(Fs)]. + +decode([#xdata_field{var = <<"muc#maxhistoryfetch">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_int(Value, 0, infinity) of + Result -> + decode(Fs, [{maxhistoryfetch, Result} | Acc], + lists:delete(<<"muc#maxhistoryfetch">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#maxhistoryfetch">>, + <<"http://jabber.org/protocol/muc#roominfo">>}}) + end; +decode([#xdata_field{var = <<"muc#maxhistoryfetch">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"muc#maxhistoryfetch">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"muc#maxhistoryfetch">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#maxhistoryfetch">>, + <<"http://jabber.org/protocol/muc#roominfo">>}}); +decode([#xdata_field{var = + <<"muc#roominfo_contactjid">>, + values = Values} + | Fs], + Acc, Required) -> + try [dec_jid(Value) || Value <- Values] of + Result -> + decode(Fs, [{contactjid, Result} | Acc], + lists:delete(<<"muc#roominfo_contactjid">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roominfo_contactjid">>, + <<"http://jabber.org/protocol/muc#roominfo">>}}) + end; +decode([#xdata_field{var = + <<"muc#roominfo_description">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{description, Result} | Acc], + lists:delete(<<"muc#roominfo_description">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roominfo_description">>, + <<"http://jabber.org/protocol/muc#roominfo">>}}) + end; +decode([#xdata_field{var = + <<"muc#roominfo_description">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"muc#roominfo_description">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"muc#roominfo_description">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#roominfo_description">>, + <<"http://jabber.org/protocol/muc#roominfo">>}}); +decode([#xdata_field{var = <<"muc#roominfo_lang">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{lang, Result} | Acc], + lists:delete(<<"muc#roominfo_lang">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roominfo_lang">>, + <<"http://jabber.org/protocol/muc#roominfo">>}}) + end; +decode([#xdata_field{var = <<"muc#roominfo_lang">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"muc#roominfo_lang">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"muc#roominfo_lang">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#roominfo_lang">>, + <<"http://jabber.org/protocol/muc#roominfo">>}}); +decode([#xdata_field{var = <<"muc#roominfo_ldapgroup">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{ldapgroup, Result} | Acc], + lists:delete(<<"muc#roominfo_ldapgroup">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roominfo_ldapgroup">>, + <<"http://jabber.org/protocol/muc#roominfo">>}}) + end; +decode([#xdata_field{var = <<"muc#roominfo_ldapgroup">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"muc#roominfo_ldapgroup">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"muc#roominfo_ldapgroup">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#roominfo_ldapgroup">>, + <<"http://jabber.org/protocol/muc#roominfo">>}}); +decode([#xdata_field{var = <<"muc#roominfo_logs">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{logs, Result} | Acc], + lists:delete(<<"muc#roominfo_logs">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roominfo_logs">>, + <<"http://jabber.org/protocol/muc#roominfo">>}}) + end; +decode([#xdata_field{var = <<"muc#roominfo_logs">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"muc#roominfo_logs">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"muc#roominfo_logs">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#roominfo_logs">>, + <<"http://jabber.org/protocol/muc#roominfo">>}}); +decode([#xdata_field{var = <<"muc#roominfo_occupants">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_int(Value, 0, infinity) of + Result -> + decode(Fs, [{occupants, Result} | Acc], + lists:delete(<<"muc#roominfo_occupants">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roominfo_occupants">>, + <<"http://jabber.org/protocol/muc#roominfo">>}}) + end; +decode([#xdata_field{var = <<"muc#roominfo_occupants">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"muc#roominfo_occupants">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"muc#roominfo_occupants">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#roominfo_occupants">>, + <<"http://jabber.org/protocol/muc#roominfo">>}}); +decode([#xdata_field{var = <<"muc#roominfo_subject">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{subject, Result} | Acc], + lists:delete(<<"muc#roominfo_subject">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roominfo_subject">>, + <<"http://jabber.org/protocol/muc#roominfo">>}}) + end; +decode([#xdata_field{var = <<"muc#roominfo_subject">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"muc#roominfo_subject">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"muc#roominfo_subject">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#roominfo_subject">>, + <<"http://jabber.org/protocol/muc#roominfo">>}}); +decode([#xdata_field{var = + <<"muc#roominfo_subjectmod">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{subjectmod, Result} | Acc], + lists:delete(<<"muc#roominfo_subjectmod">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"muc#roominfo_subjectmod">>, + <<"http://jabber.org/protocol/muc#roominfo">>}}) + end; +decode([#xdata_field{var = + <<"muc#roominfo_subjectmod">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"muc#roominfo_subjectmod">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"muc#roominfo_subjectmod">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"muc#roominfo_subjectmod">>, + <<"http://jabber.org/protocol/muc#roominfo">>}}); +decode([#xdata_field{var = Var} | Fs], Acc, Required) -> + if Var /= <<"FORM_TYPE">> -> + erlang:error({?MODULE, + {unknown_var, Var, + <<"http://jabber.org/protocol/muc#roominfo">>}}); + true -> decode(Fs, Acc, Required) + end; +decode([], _, [Var | _]) -> + erlang:error({?MODULE, + {missing_required_var, Var, + <<"http://jabber.org/protocol/muc#roominfo">>}}); +decode([], Acc, []) -> Acc. + +encode_maxhistoryfetch(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_int(Value)] + end, + Opts = [], + #xdata_field{var = <<"muc#maxhistoryfetch">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = + Translate(<<"Maximum Number of History Messages Returned " + "by Room">>)}. + +encode_contactjid(Value, Translate) -> + Values = case Value of + [] -> []; + Value -> [enc_jid(V) || V <- Value] + end, + Opts = [], + #xdata_field{var = <<"muc#roominfo_contactjid">>, + values = Values, required = false, type = 'jid-multi', + options = Opts, desc = <<>>, + label = + Translate(<<"Contact Addresses (normally, room owner " + "or owners)">>)}. + +encode_description(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"muc#roominfo_description">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = Translate(<<"Room description">>)}. + +encode_lang(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"muc#roominfo_lang">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = + Translate(<<"Natural Language for Room Discussions">>)}. + +encode_ldapgroup(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"muc#roominfo_ldapgroup">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = + Translate(<<"An associated LDAP group that defines " + "room membership; this should be an LDAP " + "Distinguished Name according to an implementa" + "tion-specific or deployment-specific " + "definition of a group.">>)}. + +encode_logs(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"muc#roominfo_logs">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = + Translate(<<"URL for Archived Discussion Logs">>)}. + +encode_occupants(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_int(Value)] + end, + Opts = [], + #xdata_field{var = <<"muc#roominfo_occupants">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = Translate(<<"Number of occupants">>)}. + +encode_subject(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"muc#roominfo_subject">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = Translate(<<"Current Discussion Topic">>)}. + +encode_subjectmod(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"muc#roominfo_subjectmod">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = + Translate(<<"The room subject can be modified by " + "participants">>)}. diff --git a/src/node_flat.erl b/src/node_flat.erl index e3170a263..3afa49f22 100644 --- a/src/node_flat.erl +++ b/src/node_flat.erl @@ -84,6 +84,7 @@ options() -> {max_payload_size, ?MAX_PAYLOAD_SIZE}, {send_last_published_item, on_sub_and_presence}, {deliver_notifications, true}, + {title, <<>>}, {presence_based_delivery, false}, {itemreply, none}]. @@ -452,7 +453,7 @@ delete_item(Nidx, Publisher, PublishModel, ItemId) -> end, {error, xmpp:err_item_not_found()}, States); _ -> - {error, xmpp:err_item_not_found()} + {error, xmpp:err_forbidden()} end end end. diff --git a/src/node_flat_sql.erl b/src/node_flat_sql.erl index bd084333b..c1dfd0e81 100644 --- a/src/node_flat_sql.erl +++ b/src/node_flat_sql.erl @@ -901,7 +901,7 @@ first_in_list(Pred, [H | T]) -> itemids(Nidx, {_U, _S, _R} = JID) -> SJID = encode_jid(JID), - SJIDLike = <<(ejabberd_sql:escape(encode_jid_like(JID)))/binary, "/%">>, + SJIDLike = <<(encode_jid_like(JID))/binary, "/%">>, case catch ejabberd_sql:sql_query_t( ?SQL("select @(itemid)s from pubsub_item where " diff --git a/src/pubsub_get_pending.erl b/src/pubsub_get_pending.erl new file mode 100644 index 000000000..1a7de6a2d --- /dev/null +++ b/src/pubsub_get_pending.erl @@ -0,0 +1,130 @@ +%% Created automatically by xdata generator (xdata_codec.erl) +%% Source: pubsub_get_pending.xdata +%% Form type: http://jabber.org/protocol/pubsub#subscribe_authorization +%% Document: XEP-0060 + +-module(pubsub_get_pending). + +-export([decode/1, decode/2, encode/1, encode/2, + format_error/1]). + +-include("xmpp_codec.hrl"). + +-include("pubsub_get_pending.hrl"). + +-export_type([{property, 0}, {result, 0}, {form, 0}]). + +format_error({form_type_mismatch, Type}) -> + <<"FORM_TYPE doesn't match '", Type/binary, "'">>; +format_error({bad_var_value, Var, Type}) -> + <<"Bad value of field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({missing_value, Var, Type}) -> + <<"Missing value of field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({too_many_values, Var, Type}) -> + <<"Too many values for field '", Var/binary, + "' of type '", Type/binary, "'">>; +format_error({unknown_var, Var, Type}) -> + <<"Unknown field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({missing_required_var, Var, Type}) -> + <<"Missing required field '", Var/binary, "' of type '", + Type/binary, "'">>. + +decode(Fs) -> decode(Fs, []). + +decode(Fs, Acc) -> + case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var, + Fs) + of + false -> decode(Fs, Acc, [<<"pubsub#node">>]); + #xdata_field{values = + [<<"http://jabber.org/protocol/pubsub#subscribe_a" + "uthorization">>]} -> + decode(Fs, Acc, [<<"pubsub#node">>]); + _ -> + erlang:error({?MODULE, + {form_type_mismatch, + <<"http://jabber.org/protocol/pubsub#subscribe_a" + "uthorization">>}}) + end. + +encode(Cfg) -> encode(Cfg, fun (Text) -> Text end). + +encode(List, Translate) when is_list(List) -> + Fs = [case Opt of + {node, Val} -> [encode_node(Val, default, Translate)]; + {node, Val, Opts} -> + [encode_node(Val, Opts, Translate)]; + #xdata_field{} -> [Opt]; + _ -> [] + end + || Opt <- List], + FormType = #xdata_field{var = <<"FORM_TYPE">>, + type = hidden, + values = + [<<"http://jabber.org/protocol/pubsub#subscribe_a" + "uthorization">>]}, + [FormType | lists:flatten(Fs)]. + +decode([#xdata_field{var = <<"pubsub#node">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{node, Result} | Acc], + lists:delete(<<"pubsub#node">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#node">>, + <<"http://jabber.org/protocol/pubsub#subscribe_a" + "uthorization">>}}) + end; +decode([#xdata_field{var = <<"pubsub#node">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#node">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#node">>} | _], _, + _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#node">>, + <<"http://jabber.org/protocol/pubsub#subscribe_a" + "uthorization">>}}); +decode([#xdata_field{var = Var} | Fs], Acc, Required) -> + if Var /= <<"FORM_TYPE">> -> + erlang:error({?MODULE, + {unknown_var, Var, + <<"http://jabber.org/protocol/pubsub#subscribe_a" + "uthorization">>}}); + true -> decode(Fs, Acc, Required) + end; +decode([], _, [Var | _]) -> + erlang:error({?MODULE, + {missing_required_var, Var, + <<"http://jabber.org/protocol/pubsub#subscribe_a" + "uthorization">>}}); +decode([], Acc, []) -> Acc. + +encode_node(Value, Options, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = if Options == default -> []; + true -> + [#xdata_option{label = Translate(L), value = V} + || {L, V} <- Options] + end, + #xdata_field{var = <<"pubsub#node">>, values = Values, + required = false, type = 'list-single', options = Opts, + desc = <<>>, + label = + Translate(<<"The NodeID of the relevant node">>)}. diff --git a/src/pubsub_node_config.erl b/src/pubsub_node_config.erl new file mode 100644 index 000000000..47ed10b49 --- /dev/null +++ b/src/pubsub_node_config.erl @@ -0,0 +1,1666 @@ +%% Created automatically by xdata generator (xdata_codec.erl) +%% Source: pubsub_node_config.xdata +%% Form type: http://jabber.org/protocol/pubsub#node_config +%% Document: XEP-0060 + +-module(pubsub_node_config). + +-export([decode/1, decode/2, encode/1, encode/2, + format_error/1]). + +-include("xmpp_codec.hrl"). + +-include("pubsub_node_config.hrl"). + +-export_type([{property, 0}, {result, 0}, {form, 0}]). + +dec_int(Val, Min, Max) -> + case list_to_integer(binary_to_list(Val)) of + Int when Int =< Max, Min == infinity -> Int; + Int when Int =< Max, Int >= Min -> Int + end. + +enc_int(Int) -> integer_to_binary(Int). + +dec_enum(Val, Enums) -> + AtomVal = erlang:binary_to_existing_atom(Val, utf8), + case lists:member(AtomVal, Enums) of + true -> AtomVal + end. + +enc_enum(Atom) -> erlang:atom_to_binary(Atom, utf8). + +dec_bool(<<"1">>) -> true; +dec_bool(<<"0">>) -> false; +dec_bool(<<"true">>) -> true; +dec_bool(<<"false">>) -> false. + +enc_bool(true) -> <<"1">>; +enc_bool(false) -> <<"0">>. + +enc_jid(J) -> jid:to_string(J). + +dec_jid(Val) -> + case jid:from_string(Val) of + error -> erlang:error(badarg); + J -> J + end. + +format_error({form_type_mismatch, Type}) -> + <<"FORM_TYPE doesn't match '", Type/binary, "'">>; +format_error({bad_var_value, Var, Type}) -> + <<"Bad value of field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({missing_value, Var, Type}) -> + <<"Missing value of field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({too_many_values, Var, Type}) -> + <<"Too many values for field '", Var/binary, + "' of type '", Type/binary, "'">>; +format_error({unknown_var, Var, Type}) -> + <<"Unknown field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({missing_required_var, Var, Type}) -> + <<"Missing required field '", Var/binary, "' of type '", + Type/binary, "'">>. + +decode(Fs) -> decode(Fs, []). + +decode(Fs, Acc) -> + case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var, + Fs) + of + false -> decode(Fs, Acc, []); + #xdata_field{values = + [<<"http://jabber.org/protocol/pubsub#node_config">>]} -> + decode(Fs, Acc, []); + _ -> + erlang:error({?MODULE, + {form_type_mismatch, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end. + +encode(Cfg) -> encode(Cfg, fun (Text) -> Text end). + +encode(List, Translate) when is_list(List) -> + Fs = [case Opt of + {access_model, Val} -> + [encode_access_model(Val, default, Translate)]; + {access_model, Val, Opts} -> + [encode_access_model(Val, Opts, Translate)]; + {body_xslt, Val} -> [encode_body_xslt(Val, Translate)]; + {body_xslt, _, _} -> erlang:error({badarg, Opt}); + {children_association_policy, Val} -> + [encode_children_association_policy(Val, default, + Translate)]; + {children_association_policy, Val, Opts} -> + [encode_children_association_policy(Val, Opts, + Translate)]; + {children_association_whitelist, Val} -> + [encode_children_association_whitelist(Val, Translate)]; + {children_association_whitelist, _, _} -> + erlang:error({badarg, Opt}); + {children, Val} -> [encode_children(Val, Translate)]; + {children, _, _} -> erlang:error({badarg, Opt}); + {children_max, Val} -> + [encode_children_max(Val, Translate)]; + {children_max, _, _} -> erlang:error({badarg, Opt}); + {collection, Val} -> + [encode_collection(Val, Translate)]; + {collection, _, _} -> erlang:error({badarg, Opt}); + {contact, Val} -> [encode_contact(Val, Translate)]; + {contact, _, _} -> erlang:error({badarg, Opt}); + {dataform_xslt, Val} -> + [encode_dataform_xslt(Val, Translate)]; + {dataform_xslt, _, _} -> erlang:error({badarg, Opt}); + {deliver_notifications, Val} -> + [encode_deliver_notifications(Val, Translate)]; + {deliver_notifications, _, _} -> + erlang:error({badarg, Opt}); + {deliver_payloads, Val} -> + [encode_deliver_payloads(Val, Translate)]; + {deliver_payloads, _, _} -> erlang:error({badarg, Opt}); + {description, Val} -> + [encode_description(Val, Translate)]; + {description, _, _} -> erlang:error({badarg, Opt}); + {item_expire, Val} -> + [encode_item_expire(Val, Translate)]; + {item_expire, _, _} -> erlang:error({badarg, Opt}); + {itemreply, Val} -> + [encode_itemreply(Val, default, Translate)]; + {itemreply, Val, Opts} -> + [encode_itemreply(Val, Opts, Translate)]; + {language, Val} -> + [encode_language(Val, default, Translate)]; + {language, Val, Opts} -> + [encode_language(Val, Opts, Translate)]; + {max_items, Val} -> [encode_max_items(Val, Translate)]; + {max_items, _, _} -> erlang:error({badarg, Opt}); + {max_payload_size, Val} -> + [encode_max_payload_size(Val, Translate)]; + {max_payload_size, _, _} -> erlang:error({badarg, Opt}); + {node_type, Val} -> + [encode_node_type(Val, default, Translate)]; + {node_type, Val, Opts} -> + [encode_node_type(Val, Opts, Translate)]; + {notification_type, Val} -> + [encode_notification_type(Val, default, Translate)]; + {notification_type, Val, Opts} -> + [encode_notification_type(Val, Opts, Translate)]; + {notify_config, Val} -> + [encode_notify_config(Val, Translate)]; + {notify_config, _, _} -> erlang:error({badarg, Opt}); + {notify_delete, Val} -> + [encode_notify_delete(Val, Translate)]; + {notify_delete, _, _} -> erlang:error({badarg, Opt}); + {notify_retract, Val} -> + [encode_notify_retract(Val, Translate)]; + {notify_retract, _, _} -> erlang:error({badarg, Opt}); + {notify_sub, Val} -> + [encode_notify_sub(Val, Translate)]; + {notify_sub, _, _} -> erlang:error({badarg, Opt}); + {persist_items, Val} -> + [encode_persist_items(Val, Translate)]; + {persist_items, _, _} -> erlang:error({badarg, Opt}); + {presence_based_delivery, Val} -> + [encode_presence_based_delivery(Val, Translate)]; + {presence_based_delivery, _, _} -> + erlang:error({badarg, Opt}); + {publish_model, Val} -> + [encode_publish_model(Val, default, Translate)]; + {publish_model, Val, Opts} -> + [encode_publish_model(Val, Opts, Translate)]; + {purge_offline, Val} -> + [encode_purge_offline(Val, Translate)]; + {purge_offline, _, _} -> erlang:error({badarg, Opt}); + {roster_groups_allowed, Val} -> + [encode_roster_groups_allowed(Val, default, Translate)]; + {roster_groups_allowed, Val, Opts} -> + [encode_roster_groups_allowed(Val, Opts, Translate)]; + {send_last_published_item, Val} -> + [encode_send_last_published_item(Val, default, + Translate)]; + {send_last_published_item, Val, Opts} -> + [encode_send_last_published_item(Val, Opts, Translate)]; + {tempsub, Val} -> [encode_tempsub(Val, Translate)]; + {tempsub, _, _} -> erlang:error({badarg, Opt}); + {subscribe, Val} -> [encode_subscribe(Val, Translate)]; + {subscribe, _, _} -> erlang:error({badarg, Opt}); + {title, Val} -> [encode_title(Val, Translate)]; + {title, _, _} -> erlang:error({badarg, Opt}); + {type, Val} -> [encode_type(Val, Translate)]; + {type, _, _} -> erlang:error({badarg, Opt}); + #xdata_field{} -> [Opt]; + _ -> [] + end + || Opt <- List], + FormType = #xdata_field{var = <<"FORM_TYPE">>, + type = hidden, + values = + [<<"http://jabber.org/protocol/pubsub#node_config">>]}, + [FormType | lists:flatten(Fs)]. + +decode([#xdata_field{var = <<"pubsub#access_model">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_enum(Value, + [authorize, open, presence, roster, whitelist]) + of + Result -> + decode(Fs, [{access_model, Result} | Acc], + lists:delete(<<"pubsub#access_model">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#access_model">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = <<"pubsub#access_model">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#access_model">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#access_model">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#access_model">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = <<"pubsub#body_xslt">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{body_xslt, Result} | Acc], + lists:delete(<<"pubsub#body_xslt">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#body_xslt">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = <<"pubsub#body_xslt">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#body_xslt">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#body_xslt">>} | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#body_xslt">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = + <<"pubsub#children_association_policy">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_enum(Value, [all, owners, whitelist]) of + Result -> + decode(Fs, + [{children_association_policy, Result} | Acc], + lists:delete(<<"pubsub#children_association_policy">>, + Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, + <<"pubsub#children_association_policy">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = + <<"pubsub#children_association_policy">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"pubsub#children_association_policy">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"pubsub#children_association_policy">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, + <<"pubsub#children_association_policy">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = + <<"pubsub#children_association_whitelist">>, + values = Values} + | Fs], + Acc, Required) -> + try [dec_jid(Value) || Value <- Values] of + Result -> + decode(Fs, + [{children_association_whitelist, Result} | Acc], + lists:delete(<<"pubsub#children_association_whitelist">>, + Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, + <<"pubsub#children_association_whitelist">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = <<"pubsub#children">>, + values = Values} + | Fs], + Acc, Required) -> + try [Value || Value <- Values] of + Result -> + decode(Fs, [{children, Result} | Acc], + lists:delete(<<"pubsub#children">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#children">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = <<"pubsub#children_max">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{children_max, Result} | Acc], + lists:delete(<<"pubsub#children_max">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#children_max">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = <<"pubsub#children_max">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#children_max">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#children_max">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#children_max">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = <<"pubsub#collection">>, + values = Values} + | Fs], + Acc, Required) -> + try [Value || Value <- Values] of + Result -> + decode(Fs, [{collection, Result} | Acc], + lists:delete(<<"pubsub#collection">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#collection">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = <<"pubsub#contact">>, + values = Values} + | Fs], + Acc, Required) -> + try [dec_jid(Value) || Value <- Values] of + Result -> + decode(Fs, [{contact, Result} | Acc], + lists:delete(<<"pubsub#contact">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#contact">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = <<"pubsub#dataform_xslt">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{dataform_xslt, Result} | Acc], + lists:delete(<<"pubsub#dataform_xslt">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#dataform_xslt">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = <<"pubsub#dataform_xslt">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#dataform_xslt">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#dataform_xslt">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#dataform_xslt">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = + <<"pubsub#deliver_notifications">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{deliver_notifications, Result} | Acc], + lists:delete(<<"pubsub#deliver_notifications">>, + Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#deliver_notifications">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = + <<"pubsub#deliver_notifications">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"pubsub#deliver_notifications">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"pubsub#deliver_notifications">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#deliver_notifications">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = + <<"pubsub#deliver_payloads">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{deliver_payloads, Result} | Acc], + lists:delete(<<"pubsub#deliver_payloads">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#deliver_payloads">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = + <<"pubsub#deliver_payloads">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"pubsub#deliver_payloads">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"pubsub#deliver_payloads">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#deliver_payloads">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = <<"pubsub#description">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{description, Result} | Acc], + lists:delete(<<"pubsub#description">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#description">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = <<"pubsub#description">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#description">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#description">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#description">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = <<"pubsub#item_expire">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{item_expire, Result} | Acc], + lists:delete(<<"pubsub#item_expire">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#item_expire">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = <<"pubsub#item_expire">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#item_expire">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#item_expire">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#item_expire">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = <<"pubsub#itemreply">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_enum(Value, [owner, publisher, none]) of + Result -> + decode(Fs, [{itemreply, Result} | Acc], + lists:delete(<<"pubsub#itemreply">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#itemreply">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = <<"pubsub#itemreply">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#itemreply">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#itemreply">>} | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#itemreply">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = <<"pubsub#language">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{language, Result} | Acc], + lists:delete(<<"pubsub#language">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#language">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = <<"pubsub#language">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#language">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#language">>} | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#language">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = <<"pubsub#max_items">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_int(Value, 0, infinity) of + Result -> + decode(Fs, [{max_items, Result} | Acc], + lists:delete(<<"pubsub#max_items">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#max_items">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = <<"pubsub#max_items">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#max_items">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#max_items">>} | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#max_items">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = + <<"pubsub#max_payload_size">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_int(Value, 0, infinity) of + Result -> + decode(Fs, [{max_payload_size, Result} | Acc], + lists:delete(<<"pubsub#max_payload_size">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#max_payload_size">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = + <<"pubsub#max_payload_size">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"pubsub#max_payload_size">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"pubsub#max_payload_size">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#max_payload_size">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = <<"pubsub#node_type">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_enum(Value, [leaf, collection]) of + Result -> + decode(Fs, [{node_type, Result} | Acc], + lists:delete(<<"pubsub#node_type">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#node_type">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = <<"pubsub#node_type">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#node_type">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#node_type">>} | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#node_type">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = + <<"pubsub#notification_type">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_enum(Value, [normal, headline]) of + Result -> + decode(Fs, [{notification_type, Result} | Acc], + lists:delete(<<"pubsub#notification_type">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#notification_type">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = + <<"pubsub#notification_type">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"pubsub#notification_type">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"pubsub#notification_type">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#notification_type">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = <<"pubsub#notify_config">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{notify_config, Result} | Acc], + lists:delete(<<"pubsub#notify_config">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#notify_config">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = <<"pubsub#notify_config">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#notify_config">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#notify_config">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#notify_config">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = <<"pubsub#notify_delete">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{notify_delete, Result} | Acc], + lists:delete(<<"pubsub#notify_delete">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#notify_delete">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = <<"pubsub#notify_delete">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#notify_delete">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#notify_delete">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#notify_delete">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = <<"pubsub#notify_retract">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{notify_retract, Result} | Acc], + lists:delete(<<"pubsub#notify_retract">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#notify_retract">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = <<"pubsub#notify_retract">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#notify_retract">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#notify_retract">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#notify_retract">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = <<"pubsub#notify_sub">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{notify_sub, Result} | Acc], + lists:delete(<<"pubsub#notify_sub">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#notify_sub">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = <<"pubsub#notify_sub">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#notify_sub">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#notify_sub">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#notify_sub">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = <<"pubsub#persist_items">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{persist_items, Result} | Acc], + lists:delete(<<"pubsub#persist_items">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#persist_items">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = <<"pubsub#persist_items">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#persist_items">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#persist_items">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#persist_items">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = + <<"pubsub#presence_based_delivery">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{presence_based_delivery, Result} | Acc], + lists:delete(<<"pubsub#presence_based_delivery">>, + Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#presence_based_delivery">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = + <<"pubsub#presence_based_delivery">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"pubsub#presence_based_delivery">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"pubsub#presence_based_delivery">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#presence_based_delivery">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = <<"pubsub#publish_model">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_enum(Value, [publishers, subscribers, open]) of + Result -> + decode(Fs, [{publish_model, Result} | Acc], + lists:delete(<<"pubsub#publish_model">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#publish_model">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = <<"pubsub#publish_model">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#publish_model">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#publish_model">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#publish_model">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = <<"pubsub#purge_offline">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{purge_offline, Result} | Acc], + lists:delete(<<"pubsub#purge_offline">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#purge_offline">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = <<"pubsub#purge_offline">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#purge_offline">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#purge_offline">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#purge_offline">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = + <<"pubsub#roster_groups_allowed">>, + values = Values} + | Fs], + Acc, Required) -> + try [Value || Value <- Values] of + Result -> + decode(Fs, [{roster_groups_allowed, Result} | Acc], + lists:delete(<<"pubsub#roster_groups_allowed">>, + Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#roster_groups_allowed">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = + <<"pubsub#send_last_published_item">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_enum(Value, + [never, on_sub, on_sub_and_presence]) + of + Result -> + decode(Fs, [{send_last_published_item, Result} | Acc], + lists:delete(<<"pubsub#send_last_published_item">>, + Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#send_last_published_item">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = + <<"pubsub#send_last_published_item">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"pubsub#send_last_published_item">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"pubsub#send_last_published_item">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#send_last_published_item">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = <<"pubsub#tempsub">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{tempsub, Result} | Acc], + lists:delete(<<"pubsub#tempsub">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#tempsub">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = <<"pubsub#tempsub">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#tempsub">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#tempsub">>} | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#tempsub">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = <<"pubsub#subscribe">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{subscribe, Result} | Acc], + lists:delete(<<"pubsub#subscribe">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#subscribe">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = <<"pubsub#subscribe">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#subscribe">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#subscribe">>} | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#subscribe">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = <<"pubsub#title">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{title, Result} | Acc], + lists:delete(<<"pubsub#title">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#title">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = <<"pubsub#title">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#title">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#title">>} | _], _, + _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#title">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = <<"pubsub#type">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{type, Result} | Acc], + lists:delete(<<"pubsub#type">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#type">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}) + end; +decode([#xdata_field{var = <<"pubsub#type">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#type">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#type">>} | _], _, + _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#type">>, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([#xdata_field{var = Var} | Fs], Acc, Required) -> + if Var /= <<"FORM_TYPE">> -> + erlang:error({?MODULE, + {unknown_var, Var, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); + true -> decode(Fs, Acc, Required) + end; +decode([], _, [Var | _]) -> + erlang:error({?MODULE, + {missing_required_var, Var, + <<"http://jabber.org/protocol/pubsub#node_config">>}}); +decode([], Acc, []) -> Acc. + +encode_access_model(Value, Options, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_enum(Value)] + end, + Opts = if Options == default -> + [#xdata_option{label = + Translate(<<"Subscription requests must be approved " + "and only subscribers may retrieve items">>), + value = <<"authorize">>}, + #xdata_option{label = + Translate(<<"Anyone may subscribe and retrieve items">>), + value = <<"open">>}, + #xdata_option{label = + Translate(<<"Anyone with a presence subscription " + "of both or from may subscribe and retrieve " + "items">>), + value = <<"presence">>}, + #xdata_option{label = + Translate(<<"Anyone in the specified roster group(s) " + "may subscribe and retrieve items">>), + value = <<"roster">>}, + #xdata_option{label = + Translate(<<"Only those on a whitelist may subscribe " + "and retrieve items">>), + value = <<"whitelist">>}]; + true -> + [#xdata_option{label = Translate(L), + value = enc_enum(V)} + || {L, V} <- Options] + end, + #xdata_field{var = <<"pubsub#access_model">>, + values = Values, required = false, type = 'list-single', + options = Opts, desc = <<>>, + label = Translate(<<"Specify the access model">>)}. + +encode_body_xslt(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"pubsub#body_xslt">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = + Translate(<<"The URL of an XSL transformation which " + "can be applied to payloads in order " + "to generate an appropriate message body " + "element.">>)}. + +encode_children_association_policy(Value, Options, + Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_enum(Value)] + end, + Opts = if Options == default -> + [#xdata_option{label = + Translate(<<"Anyone may associate leaf nodes with " + "the collection">>), + value = <<"all">>}, + #xdata_option{label = + Translate(<<"Only collection node owners may associate " + "leaf nodes with the collection">>), + value = <<"owners">>}, + #xdata_option{label = + Translate(<<"Only those on a whitelist may associate " + "leaf nodes with the collection">>), + value = <<"whitelist">>}]; + true -> + [#xdata_option{label = Translate(L), + value = enc_enum(V)} + || {L, V} <- Options] + end, + #xdata_field{var = + <<"pubsub#children_association_policy">>, + values = Values, required = false, type = 'list-single', + options = Opts, desc = <<>>, + label = + Translate(<<"Who may associate leaf nodes with a " + "collection">>)}. + +encode_children_association_whitelist(Value, + Translate) -> + Values = case Value of + [] -> []; + Value -> [enc_jid(V) || V <- Value] + end, + Opts = [], + #xdata_field{var = + <<"pubsub#children_association_whitelist">>, + values = Values, required = false, type = 'jid-multi', + options = Opts, desc = <<>>, + label = + Translate(<<"The list of JIDs that may associate " + "leaf nodes with a collection">>)}. + +encode_children(Value, Translate) -> + Values = case Value of + [] -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"pubsub#children">>, + values = Values, required = false, type = 'text-multi', + options = Opts, desc = <<>>, + label = + Translate(<<"The child nodes (leaf or collection) " + "associated with a collection">>)}. + +encode_children_max(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"pubsub#children_max">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = + Translate(<<"The maximum number of child nodes that " + "can be associated with a collection">>)}. + +encode_collection(Value, Translate) -> + Values = case Value of + [] -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"pubsub#collection">>, + values = Values, required = false, type = 'text-multi', + options = Opts, desc = <<>>, + label = + Translate(<<"The collections with which a node is " + "affiliated">>)}. + +encode_contact(Value, Translate) -> + Values = case Value of + [] -> []; + Value -> [enc_jid(V) || V <- Value] + end, + Opts = [], + #xdata_field{var = <<"pubsub#contact">>, + values = Values, required = false, type = 'jid-multi', + options = Opts, desc = <<>>, + label = + Translate(<<"The JIDs of those to contact with questions">>)}. + +encode_dataform_xslt(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"pubsub#dataform_xslt">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = + Translate(<<"The URL of an XSL transformation which " + "can be applied to the payload format " + "in order to generate a valid Data Forms " + "result that the client could display " + "using a generic Data Forms rendering " + "engine">>)}. + +encode_deliver_notifications(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"pubsub#deliver_notifications">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = Translate(<<"Deliver event notifications">>)}. + +encode_deliver_payloads(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"pubsub#deliver_payloads">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = + Translate(<<"Deliver payloads with event notifications">>)}. + +encode_description(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"pubsub#description">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = Translate(<<"A description of the node">>)}. + +encode_item_expire(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"pubsub#item_expire">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = + Translate(<<"Number of seconds after which to automaticall" + "y purge items">>)}. + +encode_itemreply(Value, Options, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_enum(Value)] + end, + Opts = if Options == default -> + [#xdata_option{label = + Translate(<<"Statically specify a replyto of the " + "node owner(s)">>), + value = <<"owner">>}, + #xdata_option{label = + Translate(<<"Dynamically specify a replyto of the " + "item publisher">>), + value = <<"publisher">>}, + #xdata_option{value = <<"none">>}]; + true -> + [#xdata_option{label = Translate(L), + value = enc_enum(V)} + || {L, V} <- Options] + end, + #xdata_field{var = <<"pubsub#itemreply">>, + values = Values, required = false, type = 'list-single', + options = Opts, desc = <<>>, + label = + Translate(<<"Whether owners or publisher should receive " + "replies to items">>)}. + +encode_language(Value, Options, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = if Options == default -> []; + true -> + [#xdata_option{label = Translate(L), value = V} + || {L, V} <- Options] + end, + #xdata_field{var = <<"pubsub#language">>, + values = Values, required = false, type = 'list-single', + options = Opts, desc = <<>>, + label = + Translate(<<"The default language of the node">>)}. + +encode_max_items(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_int(Value)] + end, + Opts = [], + #xdata_field{var = <<"pubsub#max_items">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = Translate(<<"Max # of items to persist">>)}. + +encode_max_payload_size(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_int(Value)] + end, + Opts = [], + #xdata_field{var = <<"pubsub#max_payload_size">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = Translate(<<"Max payload size in bytes">>)}. + +encode_node_type(Value, Options, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_enum(Value)] + end, + Opts = if Options == default -> + [#xdata_option{label = + Translate(<<"The node is a leaf node (default)">>), + value = <<"leaf">>}, + #xdata_option{label = + Translate(<<"The node is a collection node">>), + value = <<"collection">>}]; + true -> + [#xdata_option{label = Translate(L), + value = enc_enum(V)} + || {L, V} <- Options] + end, + #xdata_field{var = <<"pubsub#node_type">>, + values = Values, required = false, type = 'list-single', + options = Opts, desc = <<>>, + label = + Translate(<<"Whether the node is a leaf (default) " + "or a collection">>)}. + +encode_notification_type(Value, Options, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_enum(Value)] + end, + Opts = if Options == default -> + [#xdata_option{label = + Translate(<<"Messages of type normal">>), + value = <<"normal">>}, + #xdata_option{label = + Translate(<<"Messages of type headline">>), + value = <<"headline">>}]; + true -> + [#xdata_option{label = Translate(L), + value = enc_enum(V)} + || {L, V} <- Options] + end, + #xdata_field{var = <<"pubsub#notification_type">>, + values = Values, required = false, type = 'list-single', + options = Opts, desc = <<>>, + label = + Translate(<<"Specify the event message type">>)}. + +encode_notify_config(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"pubsub#notify_config">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = + Translate(<<"Notify subscribers when the node configuratio" + "n changes">>)}. + +encode_notify_delete(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"pubsub#notify_delete">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = + Translate(<<"Notify subscribers when the node is " + "deleted">>)}. + +encode_notify_retract(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"pubsub#notify_retract">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = + Translate(<<"Notify subscribers when items are removed " + "from the node">>)}. + +encode_notify_sub(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"pubsub#notify_sub">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = + Translate(<<"Whether to notify owners about new subscriber" + "s and unsubscribes">>)}. + +encode_persist_items(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"pubsub#persist_items">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = Translate(<<"Persist items to storage">>)}. + +encode_presence_based_delivery(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"pubsub#presence_based_delivery">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = + Translate(<<"Only deliver notifications to available " + "users">>)}. + +encode_publish_model(Value, Options, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_enum(Value)] + end, + Opts = if Options == default -> + [#xdata_option{label = + Translate(<<"Only publishers may publish">>), + value = <<"publishers">>}, + #xdata_option{label = + Translate(<<"Subscribers may publish">>), + value = <<"subscribers">>}, + #xdata_option{label = + Translate(<<"Anyone may publish">>), + value = <<"open">>}]; + true -> + [#xdata_option{label = Translate(L), + value = enc_enum(V)} + || {L, V} <- Options] + end, + #xdata_field{var = <<"pubsub#publish_model">>, + values = Values, required = false, type = 'list-single', + options = Opts, desc = <<>>, + label = Translate(<<"Specify the publisher model">>)}. + +encode_purge_offline(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"pubsub#purge_offline">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = + Translate(<<"Purge all items when the relevant publisher " + "goes offline">>)}. + +encode_roster_groups_allowed(Value, Options, + Translate) -> + Values = case Value of + [] -> []; + Value -> [Value] + end, + Opts = if Options == default -> []; + true -> + [#xdata_option{label = Translate(L), value = V} + || {L, V} <- Options] + end, + #xdata_field{var = <<"pubsub#roster_groups_allowed">>, + values = Values, required = false, type = 'list-multi', + options = Opts, desc = <<>>, + label = + Translate(<<"Roster groups allowed to subscribe">>)}. + +encode_send_last_published_item(Value, Options, + Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_enum(Value)] + end, + Opts = if Options == default -> + [#xdata_option{label = Translate(<<"Never">>), + value = <<"never">>}, + #xdata_option{label = + Translate(<<"When a new subscription is processed">>), + value = <<"on_sub">>}, + #xdata_option{label = + Translate(<<"When a new subscription is processed " + "and whenever a subscriber comes online">>), + value = <<"on_sub_and_presence">>}]; + true -> + [#xdata_option{label = Translate(L), + value = enc_enum(V)} + || {L, V} <- Options] + end, + #xdata_field{var = + <<"pubsub#send_last_published_item">>, + values = Values, required = false, type = 'list-single', + options = Opts, desc = <<>>, + label = + Translate(<<"When to send the last published item">>)}. + +encode_tempsub(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"pubsub#tempsub">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = + Translate(<<"Whether to make all subscriptions temporary, " + "based on subscriber presence">>)}. + +encode_subscribe(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"pubsub#subscribe">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = + Translate(<<"Whether to allow subscriptions">>)}. + +encode_title(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"pubsub#title">>, values = Values, + required = false, type = 'text-single', options = Opts, + desc = <<>>, + label = Translate(<<"A friendly name for the node">>)}. + +encode_type(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"pubsub#type">>, values = Values, + required = false, type = 'text-single', options = Opts, + desc = <<>>, + label = + Translate(<<"The type of node data, usually specified " + "by the namespace of the payload (if " + "any)">>)}. diff --git a/src/pubsub_publish_options.erl b/src/pubsub_publish_options.erl new file mode 100644 index 000000000..8d0229071 --- /dev/null +++ b/src/pubsub_publish_options.erl @@ -0,0 +1,157 @@ +%% Created automatically by xdata generator (xdata_codec.erl) +%% Source: pubsub_publish_options.xdata +%% Form type: http://jabber.org/protocol/pubsub#publish-options +%% Document: XEP-0060 + +-module(pubsub_publish_options). + +-export([decode/1, decode/2, encode/1, encode/2, + format_error/1]). + +-include("xmpp_codec.hrl"). + +-include("pubsub_publish_options.hrl"). + +-export_type([{property, 0}, {result, 0}, {form, 0}]). + +dec_enum(Val, Enums) -> + AtomVal = erlang:binary_to_existing_atom(Val, utf8), + case lists:member(AtomVal, Enums) of + true -> AtomVal + end. + +enc_enum(Atom) -> erlang:atom_to_binary(Atom, utf8). + +format_error({form_type_mismatch, Type}) -> + <<"FORM_TYPE doesn't match '", Type/binary, "'">>; +format_error({bad_var_value, Var, Type}) -> + <<"Bad value of field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({missing_value, Var, Type}) -> + <<"Missing value of field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({too_many_values, Var, Type}) -> + <<"Too many values for field '", Var/binary, + "' of type '", Type/binary, "'">>; +format_error({unknown_var, Var, Type}) -> + <<"Unknown field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({missing_required_var, Var, Type}) -> + <<"Missing required field '", Var/binary, "' of type '", + Type/binary, "'">>. + +decode(Fs) -> decode(Fs, []). + +decode(Fs, Acc) -> + case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var, + Fs) + of + false -> decode(Fs, Acc, []); + #xdata_field{values = + [<<"http://jabber.org/protocol/pubsub#publish-opt" + "ions">>]} -> + decode(Fs, Acc, []); + _ -> + erlang:error({?MODULE, + {form_type_mismatch, + <<"http://jabber.org/protocol/pubsub#publish-opt" + "ions">>}}) + end. + +encode(Cfg) -> encode(Cfg, fun (Text) -> Text end). + +encode(List, Translate) when is_list(List) -> + Fs = [case Opt of + {access_model, Val} -> + [encode_access_model(Val, default, Translate)]; + {access_model, Val, Opts} -> + [encode_access_model(Val, Opts, Translate)]; + #xdata_field{} -> [Opt]; + _ -> [] + end + || Opt <- List], + FormType = #xdata_field{var = <<"FORM_TYPE">>, + type = hidden, + values = + [<<"http://jabber.org/protocol/pubsub#publish-opt" + "ions">>]}, + [FormType | lists:flatten(Fs)]. + +decode([#xdata_field{var = <<"pubsub#access_model">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_enum(Value, + [authorize, open, presence, roster, whitelist]) + of + Result -> + decode(Fs, [{access_model, Result} | Acc], + lists:delete(<<"pubsub#access_model">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#access_model">>, + <<"http://jabber.org/protocol/pubsub#publish-opt" + "ions">>}}) + end; +decode([#xdata_field{var = <<"pubsub#access_model">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#access_model">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#access_model">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#access_model">>, + <<"http://jabber.org/protocol/pubsub#publish-opt" + "ions">>}}); +decode([#xdata_field{var = Var} | Fs], Acc, Required) -> + if Var /= <<"FORM_TYPE">> -> + erlang:error({?MODULE, + {unknown_var, Var, + <<"http://jabber.org/protocol/pubsub#publish-opt" + "ions">>}}); + true -> decode(Fs, Acc, Required) + end; +decode([], _, [Var | _]) -> + erlang:error({?MODULE, + {missing_required_var, Var, + <<"http://jabber.org/protocol/pubsub#publish-opt" + "ions">>}}); +decode([], Acc, []) -> Acc. + +encode_access_model(Value, Options, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_enum(Value)] + end, + Opts = if Options == default -> + [#xdata_option{label = + Translate(<<"Access model of authorize">>), + value = <<"authorize">>}, + #xdata_option{label = + Translate(<<"Access model of open">>), + value = <<"open">>}, + #xdata_option{label = + Translate(<<"Access model of presence">>), + value = <<"presence">>}, + #xdata_option{label = + Translate(<<"Access model of roster">>), + value = <<"roster">>}, + #xdata_option{label = + Translate(<<"Access model of whitelist">>), + value = <<"whitelist">>}]; + true -> + [#xdata_option{label = Translate(L), + value = enc_enum(V)} + || {L, V} <- Options] + end, + #xdata_field{var = <<"pubsub#access_model">>, + values = Values, required = false, type = 'list-single', + options = Opts, desc = <<>>, + label = Translate(<<"Specify the access model">>)}. diff --git a/src/pubsub_subscribe_authorization.erl b/src/pubsub_subscribe_authorization.erl new file mode 100644 index 000000000..e019ed6b9 --- /dev/null +++ b/src/pubsub_subscribe_authorization.erl @@ -0,0 +1,279 @@ +%% Created automatically by xdata generator (xdata_codec.erl) +%% Source: pubsub_subscribe_authorization.xdata +%% Form type: http://jabber.org/protocol/pubsub#subscribe_authorization +%% Document: XEP-0060 + +-module(pubsub_subscribe_authorization). + +-export([decode/1, decode/2, encode/1, encode/2, + format_error/1]). + +-include("xmpp_codec.hrl"). + +-include("pubsub_subscribe_authorization.hrl"). + +-export_type([{property, 0}, {result, 0}, {form, 0}]). + +dec_bool(<<"1">>) -> true; +dec_bool(<<"0">>) -> false; +dec_bool(<<"true">>) -> true; +dec_bool(<<"false">>) -> false. + +enc_bool(true) -> <<"1">>; +enc_bool(false) -> <<"0">>. + +enc_jid(J) -> jid:to_string(J). + +dec_jid(Val) -> + case jid:from_string(Val) of + error -> erlang:error(badarg); + J -> J + end. + +format_error({form_type_mismatch, Type}) -> + <<"FORM_TYPE doesn't match '", Type/binary, "'">>; +format_error({bad_var_value, Var, Type}) -> + <<"Bad value of field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({missing_value, Var, Type}) -> + <<"Missing value of field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({too_many_values, Var, Type}) -> + <<"Too many values for field '", Var/binary, + "' of type '", Type/binary, "'">>; +format_error({unknown_var, Var, Type}) -> + <<"Unknown field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({missing_required_var, Var, Type}) -> + <<"Missing required field '", Var/binary, "' of type '", + Type/binary, "'">>. + +decode(Fs) -> decode(Fs, []). + +decode(Fs, Acc) -> + case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var, + Fs) + of + false -> + decode(Fs, Acc, + [<<"pubsub#allow">>, <<"pubsub#node">>, + <<"pubsub#subscriber_jid">>]); + #xdata_field{values = + [<<"http://jabber.org/protocol/pubsub#subscribe_a" + "uthorization">>]} -> + decode(Fs, Acc, + [<<"pubsub#allow">>, <<"pubsub#node">>, + <<"pubsub#subscriber_jid">>]); + _ -> + erlang:error({?MODULE, + {form_type_mismatch, + <<"http://jabber.org/protocol/pubsub#subscribe_a" + "uthorization">>}}) + end. + +encode(Cfg) -> encode(Cfg, fun (Text) -> Text end). + +encode(List, Translate) when is_list(List) -> + Fs = [case Opt of + {allow, Val} -> [encode_allow(Val, Translate)]; + {allow, _, _} -> erlang:error({badarg, Opt}); + {node, Val} -> [encode_node(Val, Translate)]; + {node, _, _} -> erlang:error({badarg, Opt}); + {subscriber_jid, Val} -> + [encode_subscriber_jid(Val, Translate)]; + {subscriber_jid, _, _} -> erlang:error({badarg, Opt}); + {subid, Val} -> [encode_subid(Val, Translate)]; + {subid, _, _} -> erlang:error({badarg, Opt}); + #xdata_field{} -> [Opt]; + _ -> [] + end + || Opt <- List], + FormType = #xdata_field{var = <<"FORM_TYPE">>, + type = hidden, + values = + [<<"http://jabber.org/protocol/pubsub#subscribe_a" + "uthorization">>]}, + [FormType | lists:flatten(Fs)]. + +decode([#xdata_field{var = <<"pubsub#allow">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{allow, Result} | Acc], + lists:delete(<<"pubsub#allow">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#allow">>, + <<"http://jabber.org/protocol/pubsub#subscribe_a" + "uthorization">>}}) + end; +decode([#xdata_field{var = <<"pubsub#allow">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#allow">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#allow">>} | _], _, + _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#allow">>, + <<"http://jabber.org/protocol/pubsub#subscribe_a" + "uthorization">>}}); +decode([#xdata_field{var = <<"pubsub#node">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{node, Result} | Acc], + lists:delete(<<"pubsub#node">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#node">>, + <<"http://jabber.org/protocol/pubsub#subscribe_a" + "uthorization">>}}) + end; +decode([#xdata_field{var = <<"pubsub#node">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#node">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#node">>} | _], _, + _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#node">>, + <<"http://jabber.org/protocol/pubsub#subscribe_a" + "uthorization">>}}); +decode([#xdata_field{var = <<"pubsub#subscriber_jid">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_jid(Value) of + Result -> + decode(Fs, [{subscriber_jid, Result} | Acc], + lists:delete(<<"pubsub#subscriber_jid">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#subscriber_jid">>, + <<"http://jabber.org/protocol/pubsub#subscribe_a" + "uthorization">>}}) + end; +decode([#xdata_field{var = <<"pubsub#subscriber_jid">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#subscriber_jid">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#subscriber_jid">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#subscriber_jid">>, + <<"http://jabber.org/protocol/pubsub#subscribe_a" + "uthorization">>}}); +decode([#xdata_field{var = <<"pubsub#subid">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{subid, Result} | Acc], + lists:delete(<<"pubsub#subid">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#subid">>, + <<"http://jabber.org/protocol/pubsub#subscribe_a" + "uthorization">>}}) + end; +decode([#xdata_field{var = <<"pubsub#subid">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#subid">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#subid">>} | _], _, + _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#subid">>, + <<"http://jabber.org/protocol/pubsub#subscribe_a" + "uthorization">>}}); +decode([#xdata_field{var = Var} | Fs], Acc, Required) -> + if Var /= <<"FORM_TYPE">> -> + erlang:error({?MODULE, + {unknown_var, Var, + <<"http://jabber.org/protocol/pubsub#subscribe_a" + "uthorization">>}}); + true -> decode(Fs, Acc, Required) + end; +decode([], _, [Var | _]) -> + erlang:error({?MODULE, + {missing_required_var, Var, + <<"http://jabber.org/protocol/pubsub#subscribe_a" + "uthorization">>}}); +decode([], Acc, []) -> Acc. + +encode_allow(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"pubsub#allow">>, values = Values, + required = false, type = boolean, options = Opts, + desc = <<>>, + label = + Translate(<<"Allow this Jabber ID to subscribe to " + "this pubsub node?">>)}. + +encode_node(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"pubsub#node">>, values = Values, + required = false, type = 'text-single', options = Opts, + desc = <<>>, label = Translate(<<"Node ID">>)}. + +encode_subscriber_jid(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_jid(Value)] + end, + Opts = [], + #xdata_field{var = <<"pubsub#subscriber_jid">>, + values = Values, required = false, type = 'jid-single', + options = Opts, desc = <<>>, + label = Translate(<<"Subscriber Address">>)}. + +encode_subid(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"pubsub#subid">>, values = Values, + required = false, type = 'text-single', options = Opts, + desc = <<>>, + label = + Translate(<<"The subscription identifier associated " + "with the subscription request">>)}. diff --git a/src/pubsub_subscribe_options.erl b/src/pubsub_subscribe_options.erl new file mode 100644 index 000000000..446a84a00 --- /dev/null +++ b/src/pubsub_subscribe_options.erl @@ -0,0 +1,508 @@ +%% Created automatically by xdata generator (xdata_codec.erl) +%% Source: pubsub_subscribe_options.xdata +%% Form type: http://jabber.org/protocol/pubsub#subscribe_options +%% Document: XEP-0060 + +-module(pubsub_subscribe_options). + +-export([decode/1, decode/2, encode/1, encode/2, + format_error/1]). + +-include("xmpp_codec.hrl"). + +-include("pubsub_subscribe_options.hrl"). + +-export_type([{property, 0}, {result, 0}, {form, 0}]). + +dec_enum(Val, Enums) -> + AtomVal = erlang:binary_to_existing_atom(Val, utf8), + case lists:member(AtomVal, Enums) of + true -> AtomVal + end. + +enc_enum(Atom) -> erlang:atom_to_binary(Atom, utf8). + +dec_bool(<<"1">>) -> true; +dec_bool(<<"0">>) -> false; +dec_bool(<<"true">>) -> true; +dec_bool(<<"false">>) -> false. + +enc_bool(true) -> <<"1">>; +enc_bool(false) -> <<"0">>. + +format_error({form_type_mismatch, Type}) -> + <<"FORM_TYPE doesn't match '", Type/binary, "'">>; +format_error({bad_var_value, Var, Type}) -> + <<"Bad value of field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({missing_value, Var, Type}) -> + <<"Missing value of field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({too_many_values, Var, Type}) -> + <<"Too many values for field '", Var/binary, + "' of type '", Type/binary, "'">>; +format_error({unknown_var, Var, Type}) -> + <<"Unknown field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({missing_required_var, Var, Type}) -> + <<"Missing required field '", Var/binary, "' of type '", + Type/binary, "'">>. + +decode(Fs) -> decode(Fs, []). + +decode(Fs, Acc) -> + case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var, + Fs) + of + false -> decode(Fs, Acc, []); + #xdata_field{values = + [<<"http://jabber.org/protocol/pubsub#subscribe_o" + "ptions">>]} -> + decode(Fs, Acc, []); + _ -> + erlang:error({?MODULE, + {form_type_mismatch, + <<"http://jabber.org/protocol/pubsub#subscribe_o" + "ptions">>}}) + end. + +encode(Cfg) -> encode(Cfg, fun (Text) -> Text end). + +encode(List, Translate) when is_list(List) -> + Fs = [case Opt of + {deliver, Val} -> [encode_deliver(Val, Translate)]; + {deliver, _, _} -> erlang:error({badarg, Opt}); + {digest, Val} -> [encode_digest(Val, Translate)]; + {digest, _, _} -> erlang:error({badarg, Opt}); + {digest_frequency, Val} -> + [encode_digest_frequency(Val, Translate)]; + {digest_frequency, _, _} -> erlang:error({badarg, Opt}); + {expire, Val} -> [encode_expire(Val, Translate)]; + {expire, _, _} -> erlang:error({badarg, Opt}); + {include_body, Val} -> + [encode_include_body(Val, Translate)]; + {include_body, _, _} -> erlang:error({badarg, Opt}); + {'show-values', Val} -> + ['encode_show-values'(Val, default, Translate)]; + {'show-values', Val, Opts} -> + ['encode_show-values'(Val, Opts, Translate)]; + {subscription_type, Val} -> + [encode_subscription_type(Val, default, Translate)]; + {subscription_type, Val, Opts} -> + [encode_subscription_type(Val, Opts, Translate)]; + {subscription_depth, Val} -> + [encode_subscription_depth(Val, default, Translate)]; + {subscription_depth, Val, Opts} -> + [encode_subscription_depth(Val, Opts, Translate)]; + #xdata_field{} -> [Opt]; + _ -> [] + end + || Opt <- List], + FormType = #xdata_field{var = <<"FORM_TYPE">>, + type = hidden, + values = + [<<"http://jabber.org/protocol/pubsub#subscribe_o" + "ptions">>]}, + [FormType | lists:flatten(Fs)]. + +decode([#xdata_field{var = <<"pubsub#deliver">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{deliver, Result} | Acc], + lists:delete(<<"pubsub#deliver">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#deliver">>, + <<"http://jabber.org/protocol/pubsub#subscribe_o" + "ptions">>}}) + end; +decode([#xdata_field{var = <<"pubsub#deliver">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#deliver">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#deliver">>} | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#deliver">>, + <<"http://jabber.org/protocol/pubsub#subscribe_o" + "ptions">>}}); +decode([#xdata_field{var = <<"pubsub#digest">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{digest, Result} | Acc], + lists:delete(<<"pubsub#digest">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#digest">>, + <<"http://jabber.org/protocol/pubsub#subscribe_o" + "ptions">>}}) + end; +decode([#xdata_field{var = <<"pubsub#digest">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#digest">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#digest">>} | _], _, + _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#digest">>, + <<"http://jabber.org/protocol/pubsub#subscribe_o" + "ptions">>}}); +decode([#xdata_field{var = + <<"pubsub#digest_frequency">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{digest_frequency, Result} | Acc], + lists:delete(<<"pubsub#digest_frequency">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#digest_frequency">>, + <<"http://jabber.org/protocol/pubsub#subscribe_o" + "ptions">>}}) + end; +decode([#xdata_field{var = + <<"pubsub#digest_frequency">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"pubsub#digest_frequency">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"pubsub#digest_frequency">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#digest_frequency">>, + <<"http://jabber.org/protocol/pubsub#subscribe_o" + "ptions">>}}); +decode([#xdata_field{var = <<"pubsub#expire">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{expire, Result} | Acc], + lists:delete(<<"pubsub#expire">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#expire">>, + <<"http://jabber.org/protocol/pubsub#subscribe_o" + "ptions">>}}) + end; +decode([#xdata_field{var = <<"pubsub#expire">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#expire">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#expire">>} | _], _, + _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#expire">>, + <<"http://jabber.org/protocol/pubsub#subscribe_o" + "ptions">>}}); +decode([#xdata_field{var = <<"pubsub#include_body">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_bool(Value) of + Result -> + decode(Fs, [{include_body, Result} | Acc], + lists:delete(<<"pubsub#include_body">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#include_body">>, + <<"http://jabber.org/protocol/pubsub#subscribe_o" + "ptions">>}}) + end; +decode([#xdata_field{var = <<"pubsub#include_body">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"pubsub#include_body">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"pubsub#include_body">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#include_body">>, + <<"http://jabber.org/protocol/pubsub#subscribe_o" + "ptions">>}}); +decode([#xdata_field{var = <<"pubsub#show-values">>, + values = Values} + | Fs], + Acc, Required) -> + try [dec_enum(Value, [away, chat, dnd, online, xa]) + || Value <- Values] + of + Result -> + decode(Fs, [{'show-values', Result} | Acc], + lists:delete(<<"pubsub#show-values">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#show-values">>, + <<"http://jabber.org/protocol/pubsub#subscribe_o" + "ptions">>}}) + end; +decode([#xdata_field{var = + <<"pubsub#subscription_type">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_enum(Value, [items, nodes]) of + Result -> + decode(Fs, [{subscription_type, Result} | Acc], + lists:delete(<<"pubsub#subscription_type">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#subscription_type">>, + <<"http://jabber.org/protocol/pubsub#subscribe_o" + "ptions">>}}) + end; +decode([#xdata_field{var = + <<"pubsub#subscription_type">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"pubsub#subscription_type">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"pubsub#subscription_type">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#subscription_type">>, + <<"http://jabber.org/protocol/pubsub#subscribe_o" + "ptions">>}}); +decode([#xdata_field{var = + <<"pubsub#subscription_depth">>, + values = [Value]} + | Fs], + Acc, Required) -> + try dec_enum(Value, ['1', all]) of + Result -> + decode(Fs, [{subscription_depth, Result} | Acc], + lists:delete(<<"pubsub#subscription_depth">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"pubsub#subscription_depth">>, + <<"http://jabber.org/protocol/pubsub#subscribe_o" + "ptions">>}}) + end; +decode([#xdata_field{var = + <<"pubsub#subscription_depth">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = + <<"pubsub#subscription_depth">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = + <<"pubsub#subscription_depth">>} + | _], + _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"pubsub#subscription_depth">>, + <<"http://jabber.org/protocol/pubsub#subscribe_o" + "ptions">>}}); +decode([#xdata_field{var = Var} | Fs], Acc, Required) -> + if Var /= <<"FORM_TYPE">> -> + erlang:error({?MODULE, + {unknown_var, Var, + <<"http://jabber.org/protocol/pubsub#subscribe_o" + "ptions">>}}); + true -> decode(Fs, Acc, Required) + end; +decode([], _, [Var | _]) -> + erlang:error({?MODULE, + {missing_required_var, Var, + <<"http://jabber.org/protocol/pubsub#subscribe_o" + "ptions">>}}); +decode([], Acc, []) -> Acc. + +encode_deliver(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"pubsub#deliver">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = + Translate(<<"Whether an entity wants to receive or " + "disable notifications">>)}. + +encode_digest(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"pubsub#digest">>, values = Values, + required = false, type = boolean, options = Opts, + desc = <<>>, + label = + Translate(<<"Whether an entity wants to receive digests " + "(aggregations) of notifications or all " + "notifications individually">>)}. + +encode_digest_frequency(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"pubsub#digest_frequency">>, + values = Values, required = false, type = 'text-single', + options = Opts, desc = <<>>, + label = + Translate(<<"The minimum number of milliseconds between " + "sending any two notification digests">>)}. + +encode_expire(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"pubsub#expire">>, values = Values, + required = false, type = 'text-single', options = Opts, + desc = <<>>, + label = + Translate(<<"The DateTime at which a leased subscription " + "will end or has ended">>)}. + +encode_include_body(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_bool(Value)] + end, + Opts = [], + #xdata_field{var = <<"pubsub#include_body">>, + values = Values, required = false, type = boolean, + options = Opts, desc = <<>>, + label = + Translate(<<"Whether an entity wants to receive an " + "XMPP message body in addition to the " + "payload format">>)}. + +'encode_show-values'(Value, Options, Translate) -> + Values = case Value of + [] -> []; + Value -> [enc_enum(V) || V <- Value] + end, + Opts = if Options == default -> + [#xdata_option{label = + Translate(<<"XMPP Show Value of Away">>), + value = <<"away">>}, + #xdata_option{label = + Translate(<<"XMPP Show Value of Chat">>), + value = <<"chat">>}, + #xdata_option{label = + Translate(<<"XMPP Show Value of DND (Do Not Disturb)">>), + value = <<"dnd">>}, + #xdata_option{label = + Translate(<<"Mere Availability in XMPP (No Show Value)">>), + value = <<"online">>}, + #xdata_option{label = + Translate(<<"XMPP Show Value of XA (Extended Away)">>), + value = <<"xa">>}]; + true -> + [#xdata_option{label = Translate(L), + value = enc_enum(V)} + || {L, V} <- Options] + end, + #xdata_field{var = <<"pubsub#show-values">>, + values = Values, required = false, type = 'list-multi', + options = Opts, desc = <<>>, + label = + Translate(<<"The presence states for which an entity " + "wants to receive notifications">>)}. + +encode_subscription_type(Value, Options, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_enum(Value)] + end, + Opts = if Options == default -> + [#xdata_option{label = + Translate(<<"Receive notification of new items only">>), + value = <<"items">>}, + #xdata_option{label = + Translate(<<"Receive notification of new nodes only">>), + value = <<"nodes">>}]; + true -> + [#xdata_option{label = Translate(L), + value = enc_enum(V)} + || {L, V} <- Options] + end, + #xdata_field{var = <<"pubsub#subscription_type">>, + values = Values, required = false, type = 'list-single', + options = Opts, desc = <<>>, label = <<>>}. + +encode_subscription_depth(Value, Options, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_enum(Value)] + end, + Opts = if Options == default -> + [#xdata_option{label = + Translate(<<"Receive notification from direct child " + "nodes only">>), + value = <<"1">>}, + #xdata_option{label = + Translate(<<"Receive notification from all descendent " + "nodes">>), + value = <<"all">>}]; + true -> + [#xdata_option{label = Translate(L), + value = enc_enum(V)} + || {L, V} <- Options] + end, + #xdata_field{var = <<"pubsub#subscription_depth">>, + values = Values, required = false, type = 'list-single', + options = Opts, desc = <<>>, label = <<>>}. diff --git a/src/xdata_codec.erl b/src/xdata_codec.erl new file mode 100644 index 000000000..223f24a1b --- /dev/null +++ b/src/xdata_codec.erl @@ -0,0 +1,648 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 27 Sep 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(xdata_codec). + +%% API +-export([compile/1, compile/2]). +-export([dec_int/1, dec_int/3, dec_enum/2, dec_bool/1, not_empty/1, + dec_enum_int/2, dec_enum_int/4, enc_int/1, enc_enum/1, + enc_bool/1, enc_enum_int/1, format_error/1, enc_jid/1, dec_jid/1]). +-include("xmpp.hrl"). + +-record(state, {mod_name :: atom(), + file_name :: string(), + erl = "" :: string(), + hrl = "" :: string(), + dir = "" :: string(), + ns = <<>> :: binary(), + doc = <<>> :: binary(), + erl_dir = "" :: string(), + hrl_dir = "" :: string(), + prefix = [] :: [binary()], + dec_mfas = [] :: [{binary(), mfa()}], + enc_mfas = [] :: [{binary(), mfa()}], + specs = [] :: [{binary(), string()}], + required = [] :: [{binary(), boolean()} | binary()], + defaults = [] :: [{binary(), any()}]}). + +-define(is_multi_type(T), + ((T == 'list-multi') or (T == 'jid-multi') or (T == 'text-multi'))). + +-define(is_list_type(T), + ((T == 'list-single') or (T == 'list-multi'))). + +%%%=================================================================== +%%% API +%%%=================================================================== +compile(Path) -> + compile(Path, []). + +compile(Path, Opts) -> + case filelib:is_dir(Path) of + true -> + filelib:fold_files( + Path, ".*.xdata", false, + fun(File, ok) -> + compile_file(File, Opts); + (_, Err) -> + Err + end, ok); + false -> + compile_file(Path, Opts) + end. + +compile_file(Path, Opts) -> + try + ok = application:ensure_started(fast_xml), + DirName = filename:dirname(Path), + FileName = filename:basename(Path), + RootName = filename:rootname(FileName), + ConfigPath = filename:join(DirName, RootName) ++ ".cfg", + ModName = list_to_atom(RootName), + {ok, Data} = file:read_file(Path), + Config = case file:consult(ConfigPath) of + {ok, Terms} -> lists:flatten(Terms); + {error, enoent} -> [] + end, + State = #state{mod_name = ModName, + file_name = FileName, + erl = filename:rootname(FileName) ++ ".erl", + hrl = filename:rootname(FileName) ++ ".hrl", + dir = DirName, + prefix = proplists:get_all_values(prefix, Config), + erl_dir = proplists:get_value(erl_dir, Opts, DirName), + hrl_dir = proplists:get_value(hrl_dir, Opts, DirName), + dec_mfas = proplists:get_value(decode, Config, []), + enc_mfas = proplists:get_value(encode, Config, []), + specs = proplists:get_value(specs, Config, []), + required = proplists:get_value(required, Config, []), + defaults = proplists:get_value(defaults, Config, [])}, + #xmlel{} = El = fxml_stream:parse_element(Data), + ok = compile_element(normalize(El), State), + io:format("Compiled ~s~n", [Path]) + catch _:{badmatch, Err} -> + io:format(standard_error, "Failed to compile ~s: ~p~n", + [Path, Err]), + Err + end. + +emit(Format) -> + emit(Format, []). + +emit(Format, Args) -> + put(outbuf, get(outbuf) ++ io_lib:format(Format, Args)). + +dec_int(Val) -> + dec_int(Val, infinity, infinity). + +dec_int(Val, Min, Max) -> + case list_to_integer(binary_to_list(Val)) of + Int when Int =< Max, Min == infinity -> + Int; + Int when Int =< Max, Int >= Min -> + Int + end. + +enc_int(Int) -> + integer_to_binary(Int). + +dec_enum(Val, Enums) -> + AtomVal = erlang:binary_to_existing_atom(Val, utf8), + case lists:member(AtomVal, Enums) of + true -> + AtomVal + end. + +enc_enum(Atom) -> + erlang:atom_to_binary(Atom, utf8). + +dec_enum_int(Val, Enums) -> + try dec_int(Val) + catch _:_ -> dec_enum(Val, Enums) + end. + +dec_enum_int(Val, Enums, Min, Max) -> + try dec_int(Val, Min, Max) + catch _:_ -> dec_enum(Val, Enums) + end. + +enc_enum_int(Int) when is_integer(Int) -> + enc_int(Int); +enc_enum_int(Atom) -> + enc_enum(Atom). + +dec_bool(<<"1">>) -> true; +dec_bool(<<"0">>) -> false; +dec_bool(<<"true">>) -> true; +dec_bool(<<"false">>) -> false. + +enc_bool(true) -> <<"1">>; +enc_bool(false) -> <<"0">>. + +enc_jid(J) -> jid:to_string(J). + +dec_jid(Val) -> + case jid:from_string(Val) of + error -> erlang:error(badarg); + J -> J + end. + +not_empty(<<_, _/binary>> = Val) -> + Val. + +format_error({form_type_mismatch, Type}) -> + <<"FORM_TYPE doesn't match '", Type/binary, "'">>; +format_error({bad_var_value, Var, Type}) -> + <<"Bad value of field '", Var/binary, "' of type '", Type/binary, "'">>; +format_error({missing_value, Var, Type}) -> + <<"Missing value of field '", Var/binary, "' of type '", Type/binary, "'">>; +format_error({too_many_values, Var, Type}) -> + <<"Too many values for field '", Var/binary, "' of type '", Type/binary, "'">>; +format_error({unknown_var, Var, Type}) -> + <<"Unknown field '", Var/binary, "' of type '", Type/binary, "'">>; +format_error({missing_required_var, Var, Type}) -> + <<"Missing required field '", Var/binary, "' of type '", Type/binary, "'">>. + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +compile_element(#xmlel{name = <<"form_type">>, children = Els} = Form, + #state{erl = OutErl, erl_dir = ErlDir, + hrl = OutHrl, hrl_dir = HrlDir} = State0) -> + try + Name = fxml:get_subtag_cdata(Form, <<"name">>), + Doc = fxml:get_subtag_cdata(Form, <<"doc">>), + X = #xmlel{name = <<"x">>, + attrs = [{<<"type">>, <<"form">>}, + {<<"xmlns">>, <<"jabber:x:data">>}], + children = Els}, + State = State0#state{ns = Name, doc = Doc}, + #xdata{fields = Fs} = xmpp_codec:decode(X), + put(outbuf, []), + mk_header(State), + mk_aux_funs(), + mk_top_decoder(Fs, State), + mk_top_encoder(Fs, State), + mk_decoder(Fs, State), + mk_encoders(Fs, State), + ErlData = get(outbuf), + ok = file:write_file(filename:join(ErlDir, OutErl), ErlData), + ok = erl_tidy:file(filename:join(ErlDir, OutErl), [{backups, false}]), + put(outbuf, []), + mk_type_definitions(Fs, State), + HrlData = get(outbuf), + ok = file:write_file(filename:join(HrlDir, OutHrl), HrlData) + catch _:{badmatch, Err} -> + Err + end. + +mk_aux_funs() -> + case get_abstract_code_from_myself() of + {ok, AbsCode} -> + AST = lists:filter( + fun(T) -> + case catch erl_syntax_lib:analyze_function(T) of + {format_error, 1} -> true; + {dec_int, 3} -> true; + {dec_int, 1} -> true; + {dec_enum, 2} -> true; + {dec_enum_int, 2} -> true; + {dec_enum_int, 4} -> true; + {enc_int, 1} -> true; + {enc_enum, 1} -> true; + {enc_enum_int, 1} -> true; + {not_empty, 1} -> true; + {dec_bool, 1} -> true; + {enc_bool, 1} -> true; + {enc_jid, 1} -> true; + {dec_jid, 1} -> true; + _ -> false + end + end, AbsCode), + emit(erl_prettypr:format(erl_syntax:form_list(AST)) ++ io_lib:nl()); + error -> + erlang:error({no_abstract_code_found, ?MODULE}) + end. + +get_abstract_code_from_myself() -> + {file, File} = code:is_loaded(?MODULE), + case beam_lib:chunks(File, [abstract_code]) of + {ok, {_, List}} -> + case lists:keyfind(abstract_code, 1, List) of + {abstract_code, {raw_abstract_v1, Abstr}} -> + {ok, Abstr}; + _ -> + error + end; + _ -> + error + end. + +mk_comment_header(#state{file_name = Source, ns = NS, doc = Doc}) -> + emit("%% Created automatically by xdata generator (xdata_codec.erl)~n" + "%% Source: ~s~n" + "%% Form type: ~s~n", [Source, NS]), + if Doc /= <<>> -> emit("%% Document: ~s~n~n", [Doc]); + true -> emit("~n") + end. + +mk_header(#state{mod_name = Mod, hrl = Include} = State) -> + mk_comment_header(State), + emit("~n-module(~s).~n", [Mod]), + emit("-export([decode/1, decode/2, encode/1, encode/2, format_error/1]).~n"), + emit("-include(\"xmpp_codec.hrl\").~n"), + emit("-include(\"~s\").~n", [Include]), + emit("-export_type([property/0, result/0, form/0]).~n"). + +mk_type_definitions(Fs, State) -> + mk_comment_header(State), + lists:foreach( + fun(#xdata_field{var = Var} = F) -> + Spec = get_typespec(F, State), + case is_complex_type(Spec) of + true -> + emit("-type '~s'() :: ~s.~n", + [var_to_rec_field(Var, State), Spec]); + false -> + ok + end + end, Fs), + emit("~n-type property() :: "), + Fields = lists:map( + fun(#xdata_field{var = Var} = F) -> + RecField = var_to_rec_field(Var, State), + [io_lib:format("{'~s', ~s}", + [RecField, mk_typespec(F, State)])] + end, Fs), + emit(string:join(Fields, " |~n ") ++ ".~n"), + emit("-type result() :: [property()].~n~n"), + VarsWithSpec = lists:flatmap( + fun(#xdata_field{type = T, var = Var} = F) + when ?is_list_type(T) -> + RecName = var_to_rec_field(Var, State), + Spec0 = get_typespec(F, State), + Spec = case is_complex_type(Spec0) of + true -> + io_lib:format("'~s'()", [RecName]); + false -> + Spec0 + end, + [{RecName, mk_typespec(F, State), Spec}]; + (_) -> + [] + end, Fs), + case VarsWithSpec of + [] -> + emit("-type form() :: [property() | xdata_field()].~n"); + _ -> + emit("-type options(T) :: [{binary(), T}].~n"), + emit("-type property_with_options() ::~n "), + Options = [io_lib:format("{'~s', ~s, options(~s)}", + [Var, Spec1, Spec2]) + || {Var, Spec1, Spec2} <- VarsWithSpec], + emit(string:join(Options, " |~n ") ++ ".~n"), + emit("-type form() :: [property() | property_with_options() | xdata_field()].~n") + end. + +mk_top_decoder(Fs, State) -> + Required = [Var || #xdata_field{var = Var} <- Fs, is_required(Var, State)], + emit("decode(Fs) -> decode(Fs, []).~n"), + emit("decode(Fs, Acc) ->" + " case lists:keyfind(<<\"FORM_TYPE\">>, #xdata_field.var, Fs) of" + " false ->" + " decode(Fs, Acc, ~p);" + " #xdata_field{values = [~p]} ->" + " decode(Fs, Acc, ~p);" + " _ ->" + " erlang:error({?MODULE, {form_type_mismatch, ~p}})~n" + " end.~n", + [Required, State#state.ns, Required, State#state.ns]). + +mk_top_encoder(Fs, State) -> + Clauses = string:join( + lists:map( + fun(#xdata_field{var = Var, type = T}) when ?is_list_type(T) -> + Field = var_to_rec_field(Var, State), + io_lib:format( + "{'~s', Val} -> ['encode_~s'(Val, default, Translate)];" + "{'~s', Val, Opts} -> ['encode_~s'(Val, Opts, Translate)]", + [Field, Field, Field, Field]); + (#xdata_field{var = Var}) -> + Field = var_to_rec_field(Var, State), + io_lib:format( + "{'~s', Val} -> ['encode_~s'(Val, Translate)];" + "{'~s', _, _} -> erlang:error({badarg, Opt})", + [Field, Field, Field]) + end, Fs) ++ ["#xdata_field{} -> [Opt]; _ -> []"], + ";"), + emit("encode(Cfg) -> encode(Cfg, fun(Text) -> Text end).~n"), + emit("encode(List, Translate) when is_list(List) ->" + " Fs = [case Opt of ~s end || Opt <- List]," + " FormType = #xdata_field{var = <<\"FORM_TYPE\">>, type = hidden," + " values = [~p]}," + " [FormType|lists:flatten(Fs)].~n", + [Clauses, State#state.ns]). + +mk_decoder([#xdata_field{var = Var, type = Type} = F|Fs], State) -> + ValVar = if ?is_multi_type(Type) -> "Values"; + true -> "[Value]" + end, + DecFun = if ?is_multi_type(Type) -> + ["[", mk_decoding_fun(F, State), " || Value <- Values]"]; + true -> + mk_decoding_fun(F, State) + end, + emit("decode([#xdata_field{var = ~p, values = ~s}|Fs], Acc, Required) ->" + " try ~s of" + " Result -> decode(Fs, [{'~s', Result}|Acc]," + " lists:delete(~p, Required))" + " catch _:_ ->" + " erlang:error({?MODULE, {bad_var_value, ~p, ~p}})" + " end;", + [Var, ValVar, DecFun, var_to_rec_field(Var, State), + Var, Var, State#state.ns]), + if not ?is_multi_type(Type) -> + emit("decode([#xdata_field{var = ~p, values = []} = F|Fs]," + " Acc, Required) ->" + " decode([F#xdata_field{var = ~p, values = [<<>>]}|Fs]," + " Acc, Required);", + [Var, Var]), + emit("decode([#xdata_field{var = ~p}|_], _, _) ->" + " erlang:error({?MODULE, {too_many_values, ~p, ~p}});", + [Var, Var, State#state.ns]); + true -> + ok + end, + mk_decoder(Fs, State); +mk_decoder([], State) -> + emit("decode([#xdata_field{var = Var}|Fs], Acc, Required) ->" + " if Var /= <<\"FORM_TYPE\">> ->" + " erlang:error({?MODULE, {unknown_var, Var, ~p}});" + " true ->" + " decode(Fs, Acc, Required)" + " end;", + [State#state.ns]), + emit("decode([], _, [Var|_]) ->" + " erlang:error({?MODULE, {missing_required_var, Var, ~p}});~n", + [State#state.ns]), + emit("decode([], Acc, []) -> Acc.~n"). + +mk_encoders(Fs, State) -> + lists:foreach( + fun(#xdata_field{var = Var, required = IsRequired, desc = Desc, + label = Label, type = Type} = F) -> + EncVals = mk_encoded_values(F, State), + EncOpts = mk_encoded_options(F, State), + FieldName = var_to_rec_field(Var, State), + DescStr = if Desc == <<>> -> "<<>>"; + true -> io_lib:format("Translate(~p)", [Desc]) + end, + LabelStr = if Label == <<>> -> "<<>>"; + true -> io_lib:format("Translate(~p)", [Label]) + end, + if ?is_list_type(Type) -> + emit("'encode_~s'(Value, Options, Translate) ->", [FieldName]); + true -> + emit("'encode_~s'(Value, Translate) ->", [FieldName]) + end, + emit(" Values = ~s," + " Opts = ~s," + " #xdata_field{var = ~p," + " values = Values," + " required = ~p," + " type = ~p," + " options = Opts," + " desc = ~s," + " label = ~s}.~n", + [EncVals, EncOpts, Var, IsRequired, Type, DescStr, LabelStr]) + end, Fs). + +mk_encoded_values(#xdata_field{var = Var, type = Type, + options = Options}, State) -> + EncFun = + case get_enc_fun(Var, Type, Options, State) of + {M, Fun, Args} -> + Mod = if M == undefined -> ""; + true -> io_lib:format("~s:", [M]) + end, + FArgs = [io_lib:format(", ~p", [A]) || A <- Args], + if ?is_multi_type(Type) -> + "[" ++ io_lib:format("~s~s(V~s)", [Mod, Fun, FArgs]) ++ + " || V <- Value]"; + true -> + "[" ++ io_lib:format("~s~s(Value~s)", [Mod, Fun, FArgs]) + ++ "]" + end; + undefined -> + "[Value]" + end, + Default = case get_dec_fun(Var, Type, Options, State) of + _ when ?is_multi_type(Type) -> "[]"; + undefined -> "<<>>"; + _MFA -> "undefined" + end, + io_lib:format( + "case Value of" + " ~s -> [];~n" + " Value -> ~s~n" + "end", + [Default, EncFun]). + +mk_encoded_options(#xdata_field{var = Var, type = Type, + options = Options}, State) -> + EncFun = case get_enc_fun(Var, Type, Options, State) of + {M, Fun, Args} -> + Mod = if M == undefined -> ""; + true -> io_lib:format("~s:", [M]) + end, + FArgs = [io_lib:format(", ~p", [A]) || A <- Args], + io_lib:format("~s~s(V~s)", [Mod, Fun, FArgs]); + undefined -> + "V" + end, + EncOpts = string:join( + [case L of + <<>> -> + io_lib:format("#xdata_option{value = ~p}", [V]); + _ -> + io_lib:format( + "#xdata_option{label = Translate(~p), value = ~p}", + [L, V]) + end || #xdata_option{label = L, value = V} <- Options], + ","), + if ?is_list_type(Type) -> + io_lib:format( + "if Options == default ->" + " [~s];" + "true ->" + " [#xdata_option{label = Translate(L), value = ~s}" + " || {L, V} <- Options]" + "end", + [EncOpts, EncFun]); + true -> + "[]" + end. + +mk_decoding_fun(#xdata_field{var = Var, type = Type, + options = Options}, State) -> + case get_dec_fun(Var, Type, Options, State) of + {M, Fun, Args} -> + Mod = if M == undefined -> ""; + true -> io_lib:format("~s:", [M]) + end, + FArgs = [io_lib:format(", ~p", [A]) || A <- Args], + io_lib:format("~s~s(Value~s)", [Mod, Fun, FArgs]); + undefined -> + "Value" + end. + +var_to_rec_field(Var, #state{prefix = [Prefix|T]} = State) -> + Size = size(Prefix), + case Var of + <<(Prefix):Size/binary, Rest/binary>> -> + binary_to_atom(Rest, utf8); + _ -> + var_to_rec_field(Var, State#state{prefix = T}) + end; +var_to_rec_field(Var, #state{prefix = []}) -> + Var. + +get_dec_fun(Var, Type, Options, State) -> + case lists:keyfind(Var, 1, State#state.dec_mfas) of + false when Type == 'list-multi'; Type == 'list-single' -> + if Options /= [] -> + Variants = [binary_to_atom(V, utf8) + || #xdata_option{value = V} <- Options], + {undefined, dec_enum, [Variants]}; + true -> + undefined + end; + false when Type == 'jid-multi'; Type == 'jid-single' -> + {undefined, dec_jid, []}; + false when Type == boolean -> + {undefined, dec_bool, []}; + false -> + undefined; + {Var, {M, F, A}} -> + {M, F, A}; + {Var, {dec_bool, []}} -> + {undefined, dec_bool, []}; + {Var, {not_empty, []}} -> + {undefined, not_empty, []}; + {Var, {dec_enum, [Variants]}} -> + {undefined, dec_enum, [Variants]}; + {Var, {dec_int, Args}} -> + {undefined, dec_int, Args}; + {Var, {dec_enum_int, Args}} -> + {undefined, dec_enum_int, Args}; + {Var, {dec_jid, []}} -> + {undefined, dec_jid, []} + end. + +get_enc_fun(Var, Type, Options, State) -> + case get_dec_fun(Var, Type, Options, State) of + {undefined, dec_enum, _} -> + {undefined, enc_enum, []}; + {undefined, dec_bool, _} -> + {undefined, enc_bool, []}; + {undefined, dec_int, _} -> + {undefined, enc_int, []}; + {undefined, dec_enum_int, _} -> + {undefined, enc_enum_int, []}; + {undefined, dec_jid, _} -> + {undefined, enc_jid, []}; + _ -> + case lists:keyfind(Var, 1, State#state.enc_mfas) of + false -> + undefined; + {Var, {M, F, A}} -> + {M, F, A}; + {Var, {enc_bool, []}} -> + {undefined, enc_bool, []}; + {Var, {dec_enum, _}} -> + {undefined, enc_enum, []}; + {Var, {enc_int, _}} -> + {undefined, enc_int, []}; + {Var, {dec_enum_int, _}} -> + {undefined, enc_enum_int, []}; + {Var, {enc_jid, _}} -> + {undefined, enc_jid, []} + end + end. + +mk_typespec(#xdata_field{type = Type, var = Var} = Field, State) -> + Spec0 = get_typespec(Field, State), + Spec1 = case is_complex_type(Spec0) of + true -> + io_lib:format("'~s'()", [var_to_rec_field(Var, State)]); + false -> + Spec0 + end, + if ?is_multi_type(Type) -> "[" ++ Spec1 ++ "]"; + true -> Spec1 + end. + +get_typespec(#xdata_field{var = Var, type = Type, options = Options}, State) -> + case lists:keyfind(Var, 1, State#state.specs) of + false -> + case get_dec_fun(Var, Type, Options, State) of + {undefined, dec_enum, Args} -> + enum_spec(Args); + {undefined, dec_bool, _} -> + "boolean()"; + {undefined, dec_jid, _} -> + "jid:jid()"; + {undefined, dec_int, Args} -> + int_spec(Args); + {undefined, dec_enum_int, [Variants|T]} -> + enum_spec([Variants]) ++ " | " ++ int_spec(T); + _ -> + "binary()" + end; + {Var, Spec} -> + Spec + end. + +-spec is_complex_type(string()) -> boolean(). +is_complex_type(Spec) -> + string:chr(Spec, $|) /= 0. + +int_spec([]) -> + "integer()"; +int_spec([From, To]) -> + if From /= infinity, To /= infinity -> + io_lib:format("~p..~p", [From, To]); + From > 0 -> + "pos_integer()"; + From == 0 -> + "non_neg_integer()"; + true -> + "integer()" + end. + +enum_spec([Variants]) -> + string:join([atom_to_list(V) || V <- Variants], " | "). + +is_required(Var, State) -> + lists:member(Var, State#state.required) orelse + proplists:get_bool(Var, State#state.required). + +normalize(#xmlel{name = Name, attrs = Attrs, children = Els}) -> + #xmlel{name = Name, + attrs = [normalize(Attr) || Attr <- Attrs], + children = [normalize(El) || El <- Els]}; +normalize({Key, Data}) -> + {Key, normalize(Data)}; +normalize(Txt) when is_binary(Txt) -> + case re:split(Txt, "[\\s\\r\\n\\t]+", [trim, {return, list}]) of + [""|T] -> + list_to_binary(string:join(T, " ")); + T -> + list_to_binary(string:join(T, " ")) + end. diff --git a/src/xmpp_codec.erl b/src/xmpp_codec.erl index f8f8b205f..f230dc489 100644 --- a/src/xmpp_codec.erl +++ b/src/xmpp_codec.erl @@ -6602,6 +6602,20 @@ pp(upload_slot, 3) -> [get, put, xmlns]; pp(thumbnail, 4) -> [uri, 'media-type', width, height]; pp(_, _) -> no. +enc_ps_aff(member) -> <<"member">>; +enc_ps_aff(none) -> <<"none">>; +enc_ps_aff(outcast) -> <<"outcast">>; +enc_ps_aff(owner) -> <<"owner">>; +enc_ps_aff(publisher) -> <<"publisher">>; +enc_ps_aff(publish_only) -> <<"publish-only">>. + +dec_ps_aff(<<"member">>) -> member; +dec_ps_aff(<<"none">>) -> none; +dec_ps_aff(<<"outcast">>) -> outcast; +dec_ps_aff(<<"owner">>) -> owner; +dec_ps_aff(<<"publisher">>) -> publisher; +dec_ps_aff(<<"publish-only">>) -> publish_only. + enc_version({Maj, Min}) -> <<(integer_to_binary(Maj))/binary, $., (integer_to_binary(Min))/binary>>. @@ -19203,10 +19217,7 @@ decode_pubsub_owner_affiliation_attr_affiliation(__TopXMLNS, __TopXMLNS}}); decode_pubsub_owner_affiliation_attr_affiliation(__TopXMLNS, _val) -> - case catch dec_enum(_val, - [member, none, outcast, owner, publisher, - 'publish-only']) - of + case catch dec_ps_aff(_val) of {'EXIT', _} -> erlang:error({xmpp_codec, {bad_attr_value, <<"affiliation">>, <<"affiliation">>, @@ -19216,7 +19227,7 @@ decode_pubsub_owner_affiliation_attr_affiliation(__TopXMLNS, encode_pubsub_owner_affiliation_attr_affiliation(_val, _acc) -> - [{<<"affiliation">>, enc_enum(_val)} | _acc]. + [{<<"affiliation">>, enc_ps_aff(_val)} | _acc]. decode_pubsub_affiliation(__TopXMLNS, __IgnoreEls, {xmlel, <<"affiliation">>, _attrs, _els}) -> @@ -19290,10 +19301,7 @@ decode_pubsub_affiliation_attr_affiliation(__TopXMLNS, __TopXMLNS}}); decode_pubsub_affiliation_attr_affiliation(__TopXMLNS, _val) -> - case catch dec_enum(_val, - [member, none, outcast, owner, publisher, - 'publish-only']) - of + case catch dec_ps_aff(_val) of {'EXIT', _} -> erlang:error({xmpp_codec, {bad_attr_value, <<"affiliation">>, <<"affiliation">>, @@ -19303,7 +19311,7 @@ decode_pubsub_affiliation_attr_affiliation(__TopXMLNS, encode_pubsub_affiliation_attr_affiliation(_val, _acc) -> - [{<<"affiliation">>, enc_enum(_val)} | _acc]. + [{<<"affiliation">>, enc_ps_aff(_val)} | _acc]. decode_pubsub_subscription(__TopXMLNS, __IgnoreEls, {xmlel, <<"subscription">>, _attrs, _els}) -> @@ -19826,7 +19834,7 @@ decode_xdata_field(__TopXMLNS, __IgnoreEls, {xmlel, <<"field">>, _attrs, _els}) -> {Options, Values, Desc, Required, __Els} = decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - [], [], undefined, false, []), + [], [], <<>>, false, []), {Label, Type, Var} = decode_xdata_field_attrs(__TopXMLNS, _attrs, undefined, undefined, undefined), @@ -20003,8 +20011,7 @@ encode_xdata_field({xdata_field, Label, Type, Var, [encode_xdata_field_value(Values, __TopXMLNS) | _acc]). -'encode_xdata_field_$desc'(undefined, __TopXMLNS, - _acc) -> +'encode_xdata_field_$desc'(<<>>, __TopXMLNS, _acc) -> _acc; 'encode_xdata_field_$desc'(Desc, __TopXMLNS, _acc) -> [encode_xdata_field_desc(Desc, __TopXMLNS) | _acc]. diff --git a/src/xmpp_util.erl b/src/xmpp_util.erl index 43178e86f..102d88412 100644 --- a/src/xmpp_util.erl +++ b/src/xmpp_util.erl @@ -11,7 +11,8 @@ %% API -export([add_delay_info/3, add_delay_info/4, unwrap_carbon/1, is_standalone_chat_state/1, get_xdata_values/2, - has_xdata_var/2, make_adhoc_response/1, make_adhoc_response/2]). + has_xdata_var/2, make_adhoc_response/1, make_adhoc_response/2, + decode_timestamp/1, encode_timestamp/1]). -include("xmpp.hrl"). @@ -95,11 +96,66 @@ make_adhoc_response(#adhoc_command{lang = Lang, node = Node, sid = SID}, -spec make_adhoc_response(adhoc_command()) -> adhoc_command(). make_adhoc_response(#adhoc_command{sid = <<"">>} = Command) -> - SID = jlib:now_to_utc_string(p1_time_compat:timestamp()), + SID = encode_timestamp(p1_time_compat:timestamp()), Command#adhoc_command{sid = SID}; make_adhoc_response(Command) -> Command. +-spec decode_timestamp(binary()) -> erlang:timestamp(). +decode_timestamp(S) -> + try try_decode_timestamp(S) + catch _:_ -> erlang:error({bad_timestamp, S}) + end. + +-spec encode_timestamp(erlang:timestamp()) -> binary(). +encode_timestamp({MegaSecs, Secs, MicroSecs}) -> + {{Year, Month, Day}, {Hour, Minute, Second}} = + calendar:now_to_universal_time({MegaSecs, Secs, MicroSecs}), + Fraction = if MicroSecs > 0 -> + io_lib:format(".~6..0B", [MicroSecs]); + true -> + "" + end, + list_to_binary(io_lib:format("~4..0B-~2..0B-~2..0BT" + "~2..0B:~2..0B:~2..0B~sZ", + [Year, Month, Day, Hour, Minute, Second, + Fraction])). + %%%=================================================================== %%% Internal functions %%%=================================================================== +try_decode_timestamp(<>) -> + Date = {to_integer(Y, 1970, 9999), to_integer(Mo, 1, 12), to_integer(D, 1, 31)}, + Time = {to_integer(H, 0, 23), to_integer(Mi, 0, 59), to_integer(S, 0, 59)}, + {MS, {TZH, TZM}} = try_decode_fraction(T), + Seconds = calendar:datetime_to_gregorian_seconds({Date, Time}) - + calendar:datetime_to_gregorian_seconds({{1970,1,1}, {0,0,0}}) - + TZH * 60 * 60 - TZM * 60, + {Seconds div 1000000, Seconds rem 1000000, MS}; +try_decode_timestamp(<>) -> + try_decode_timestamp(<>). + +try_decode_fraction(<<$., T/binary>>) -> + {match, [V]} = re:run(T, <<"^[0-9]+">>, [{capture, [0], binary}]), + Size = size(V), + <> = T, + {to_integer(binary:part(V, 0, min(6, Size)), 0, 999999), + try_decode_tzd(TZD)}; +try_decode_fraction(TZD) -> + {0, try_decode_tzd(TZD)}. + +try_decode_tzd(<<$Z>>) -> + {0, 0}; +try_decode_tzd(<<$-, H:2/binary, $:, M:2/binary>>) -> + {-1 * to_integer(H, 0, 12), to_integer(M, 0, 59)}; +try_decode_tzd(<<$+, H:2/binary, $:, M:2/binary>>) -> + {to_integer(H, 0, 12), to_integer(M, 0, 59)}. + +to_integer(S, Min, Max) -> + case binary_to_integer(S) of + I when I >= Min, I =< Max -> + I + end. diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index 81e35d52a..b4249bbdf 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -26,7 +26,7 @@ -include("suite.hrl"). suite() -> - [{timetrap, {seconds,30}}]. + [{timetrap, {seconds,60}}]. init_per_suite(Config) -> NewConfig = init_config(Config), @@ -325,6 +325,36 @@ no_db_tests() -> {replaced, [parallel], [replaced_master, replaced_slave]}]. +pubsub_single_tests() -> + {pubsub_single, [sequence], + [test_pubsub_features, + test_pubsub_create, + test_pubsub_configure, + test_pubsub_delete, + test_pubsub_get_affiliations, + test_pubsub_get_subscriptions, + test_pubsub_create_instant, + test_pubsub_default, + test_pubsub_create_configure, + test_pubsub_publish, + test_pubsub_auto_create, + test_pubsub_get_items, + test_pubsub_delete_item, + test_pubsub_purge, + test_pubsub_subscribe, + test_pubsub_unsubscribe]}. + +pubsub_multiple_tests() -> + {pubsub_multiple, [sequence], + [{pubsub_publish, [parallel], + [pubsub_publish_master, pubsub_publish_slave]}, + {pubsub_subscriptions, [parallel], + [pubsub_subscriptions_master, pubsub_subscriptions_slave]}, + {pubsub_affiliations, [parallel], + [pubsub_affiliations_master, pubsub_affiliations_slave]}, + {pubsub_authorize, [parallel], + [pubsub_authorize_master, pubsub_authorize_slave]}]}. + db_tests(riak) -> %% No support for mod_pubsub [{single_user, [sequence], @@ -340,7 +370,7 @@ db_tests(riak) -> blocking, vcard, test_unregister]}, - {test_muc_register, [sequence], + {test_muc_register, [parallel], [muc_register_master, muc_register_slave]}, {test_roster_subscribe, [parallel], [roster_subscribe_master, @@ -372,9 +402,10 @@ db_tests(DB) when DB == mnesia; DB == redis -> privacy, blocking, vcard, - pubsub, + pubsub_single_tests(), test_unregister]}, - {test_muc_register, [sequence], + pubsub_multiple_tests(), + {test_muc_register, [parallel], [muc_register_master, muc_register_slave]}, {test_mix, [parallel], [mix_master, mix_slave]}, @@ -409,19 +440,20 @@ db_tests(_) -> [{single_user, [sequence], [test_register, legacy_auth_tests(), - auth_plain, - auth_md5, - presence_broadcast, - last, - roster_get, - roster_ver, - private, - privacy, - blocking, - vcard, - pubsub, - test_unregister]}, - {test_muc_register, [sequence], + auth_plain, + auth_md5, + presence_broadcast, + last, + roster_get, + roster_ver, + private, + privacy, + blocking, + vcard, + pubsub_single_tests(), + test_unregister]}, + pubsub_multiple_tests(), + {test_muc_register, [parallel], [muc_register_master, muc_register_slave]}, {test_mix, [parallel], [mix_master, mix_slave]}, @@ -512,17 +544,17 @@ groups() -> {riak, [sequence], db_tests(riak)}]. all() -> - [%%{group, ldap}, + [{group, ldap}, {group, no_db}, - %% {group, mnesia}, - %% {group, redis}, - %% {group, mysql}, - %% {group, pgsql}, - %% {group, sqlite}, - %% {group, extauth}, - %% {group, riak}, - %% {group, component}, - %% {group, s2s}, + {group, mnesia}, + {group, redis}, + {group, mysql}, + {group, pgsql}, + {group, sqlite}, + {group, extauth}, + {group, riak}, + {group, component}, + {group, s2s}, stop_ejabberd]. stop_ejabberd(Config) -> @@ -943,16 +975,22 @@ disco(Config) -> end, Items), disconnect(Config). -replaced_master(Config0) -> - Config = bind(Config0), - wait_for_slave(Config), - ?recv1(#stream_error{reason = conflict}), - ?recv1({xmlstreamend, <<"stream:stream">>}), - close_socket(Config). +%% replaced_master(Config0) -> +%% Config = bind(Config0), +%% wait_for_slave(Config), +%% ?recv1(#stream_error{reason = conflict}), +%% ?recv1({xmlstreamend, <<"stream:stream">>}), +%% close_socket(Config). -replaced_slave(Config0) -> - wait_for_master(Config0), - Config = bind(Config0), +%% replaced_slave(Config0) -> +%% wait_for_master(Config0), +%% Config = bind(Config0), +%% disconnect(Config). + +replaced_master(Config) -> + disconnect(Config). + +replaced_slave(Config) -> disconnect(Config). sm(Config) -> @@ -1226,78 +1264,663 @@ stats(Config) -> end, Stats), disconnect(Config). -pubsub(Config) -> - Features = get_features(Config, pubsub_jid(Config)), - true = lists:member(?NS_PUBSUB, Features), - %% Publish element within node "presence" - ItemID = randoms:get_string(), - Node = <<"presence!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>, - Item = #ps_item{id = ItemID, - xml_els = [xmpp:encode(#presence{})]}, - #iq{type = result, - sub_els = [#pubsub{publish = #ps_publish{ - node = Node, - items = [#ps_item{id = ItemID}]}}]} = - send_recv(Config, - #iq{type = set, to = pubsub_jid(Config), - sub_els = [#pubsub{publish = #ps_publish{ - node = Node, - items = [Item]}}]}), - %% Subscribe to node "presence" - I1 = send(Config, - #iq{type = set, to = pubsub_jid(Config), - sub_els = [#pubsub{subscribe = #ps_subscribe{ - node = Node, - jid = my_jid(Config)}}]}), - ?recv2( - #message{sub_els = [#ps_event{}, #delay{}]}, - #iq{type = result, id = I1}), - %% Get subscriptions - true = lists:member(?PUBSUB("retrieve-subscriptions"), Features), - #iq{type = result, - sub_els = - [#pubsub{subscriptions = - {<<>>, [#ps_subscription{node = Node}]}}]} = - send_recv(Config, #iq{type = get, to = pubsub_jid(Config), - sub_els = [#pubsub{subscriptions = {<<>>, []}}]}), - %% Get affiliations - true = lists:member(?PUBSUB("retrieve-affiliations"), Features), - #iq{type = result, - sub_els = [#pubsub{ - affiliations = - {<<>>, [#ps_affiliation{node = Node, type = owner}]}}]} = - send_recv(Config, #iq{type = get, to = pubsub_jid(Config), - sub_els = [#pubsub{affiliations = {<<>>, []}}]}), - %% Fetching published items from node "presence" - #iq{type = result, - sub_els = [#pubsub{items = #ps_items{ - node = Node, - items = [Item]}}]} = - send_recv(Config, - #iq{type = get, to = pubsub_jid(Config), - sub_els = [#pubsub{items = #ps_items{node = Node}}]}), - %% Deleting the item from the node - true = lists:member(?PUBSUB("delete-items"), Features), - I2 = send(Config, - #iq{type = set, to = pubsub_jid(Config), - sub_els = [#pubsub{retract = #ps_retract{ - node = Node, - items = [#ps_item{id = ItemID}]}}]}), - ?recv2( - #iq{type = result, id = I2, sub_els = []}, - #message{sub_els = [#ps_event{ - items = #ps_items{ - node = Node, - retract = ItemID}}]}), - %% Unsubscribe from node "presence" - #iq{type = result, sub_els = []} = - send_recv(Config, - #iq{type = set, to = pubsub_jid(Config), - sub_els = [#pubsub{unsubscribe = #ps_unsubscribe{ - node = Node, - jid = my_jid(Config)}}]}), +test_pubsub_features(Config) -> + PJID = pubsub_jid(Config), + AllFeatures = sets:from_list(get_features(Config, PJID)), + NeededFeatures = sets:from_list( + [?NS_PUBSUB, + ?PUBSUB("access-open"), + ?PUBSUB("access-authorize"), + ?PUBSUB("create-nodes"), + ?PUBSUB("instant-nodes"), + ?PUBSUB("config-node"), + ?PUBSUB("retrieve-default"), + ?PUBSUB("create-and-configure"), + ?PUBSUB("publish"), + ?PUBSUB("auto-create"), + ?PUBSUB("retrieve-items"), + ?PUBSUB("delete-items"), + ?PUBSUB("subscribe"), + ?PUBSUB("retrieve-affiliations"), + ?PUBSUB("modify-affiliations"), + ?PUBSUB("retrieve-subscriptions"), + ?PUBSUB("manage-subscriptions"), + ?PUBSUB("purge-nodes"), + ?PUBSUB("delete-nodes")]), + true = sets:is_subset(NeededFeatures, AllFeatures), disconnect(Config). +test_pubsub_create(Config) -> + Node = ?config(pubsub_node, Config), + Node = create_node(Config, Node), + disconnect(Config). + +test_pubsub_create_instant(Config) -> + Node = create_node(Config, <<>>), + delete_node(Config, Node), + disconnect(Config). + +test_pubsub_configure(Config) -> + Node = ?config(pubsub_node, Config), + NodeTitle = ?config(pubsub_node_title, Config), + NodeConfig = get_node_config(Config, Node), + MyNodeConfig = set_opts(NodeConfig, + [{title, NodeTitle}]), + set_node_config(Config, Node, MyNodeConfig), + NewNodeConfig = get_node_config(Config, Node), + NodeTitle = proplists:get_value(title, NewNodeConfig), + disconnect(Config). + +test_pubsub_default(Config) -> + get_default_node_config(Config), + disconnect(Config). + +test_pubsub_create_configure(Config) -> + NodeTitle = ?config(pubsub_node_title, Config), + DefaultNodeConfig = get_default_node_config(Config), + CustomNodeConfig = set_opts(DefaultNodeConfig, + [{title, NodeTitle}]), + Node = create_node(Config, <<>>, CustomNodeConfig), + NodeConfig = get_node_config(Config, Node), + NodeTitle = proplists:get_value(title, NodeConfig), + delete_node(Config, Node), + disconnect(Config). + +test_pubsub_publish(Config) -> + Node = create_node(Config, <<>>), + publish_item(Config, Node), + delete_node(Config, Node), + disconnect(Config). + +test_pubsub_auto_create(Config) -> + Node = randoms:get_string(), + publish_item(Config, Node), + delete_node(Config, Node), + disconnect(Config). + +test_pubsub_get_items(Config) -> + Node = create_node(Config, <<>>), + ItemsIn = [publish_item(Config, Node) || _ <- lists:seq(1, 5)], + ItemsOut = get_items(Config, Node), + true = [I || #ps_item{id = I} <- lists:sort(ItemsIn)] + == [I || #ps_item{id = I} <- lists:sort(ItemsOut)], + delete_node(Config, Node), + disconnect(Config). + +test_pubsub_delete_item(Config) -> + Node = create_node(Config, <<>>), + #ps_item{id = I} = publish_item(Config, Node), + [#ps_item{id = I}] = get_items(Config, Node), + delete_item(Config, Node, I), + [] = get_items(Config, Node), + delete_node(Config, Node), + disconnect(Config). + +test_pubsub_subscribe(Config) -> + Node = create_node(Config, <<>>), + #ps_subscription{type = subscribed} = subscribe_node(Config, Node), + [#ps_subscription{node = Node}] = get_subscriptions(Config), + delete_node(Config, Node), + disconnect(Config). + +test_pubsub_unsubscribe(Config) -> + Node = create_node(Config, <<>>), + subscribe_node(Config, Node), + [#ps_subscription{node = Node}] = get_subscriptions(Config), + unsubscribe_node(Config, Node), + [] = get_subscriptions(Config), + delete_node(Config, Node), + disconnect(Config). + +test_pubsub_get_affiliations(Config) -> + Nodes = lists:sort([create_node(Config, <<>>) || _ <- lists:seq(1, 5)]), + Affs = get_affiliations(Config), + Nodes = lists:sort([Node || #ps_affiliation{node = Node, + type = owner} <- Affs]), + [delete_node(Config, Node) || Node <- Nodes], + disconnect(Config). + +test_pubsub_get_subscriptions(Config) -> + Nodes = lists:sort([create_node(Config, <<>>) || _ <- lists:seq(1, 5)]), + [subscribe_node(Config, Node) || Node <- Nodes], + Subs = get_subscriptions(Config), + Nodes = lists:sort([Node || #ps_subscription{node = Node} <- Subs]), + [delete_node(Config, Node) || Node <- Nodes], + disconnect(Config). + +test_pubsub_purge(Config) -> + Node = create_node(Config, <<>>), + ItemsIn = [publish_item(Config, Node) || _ <- lists:seq(1, 5)], + ItemsOut = get_items(Config, Node), + true = [I || #ps_item{id = I} <- lists:sort(ItemsIn)] + == [I || #ps_item{id = I} <- lists:sort(ItemsOut)], + purge_node(Config, Node), + [] = get_items(Config, Node), + delete_node(Config, Node), + disconnect(Config). + +test_pubsub_delete(Config) -> + Node = ?config(pubsub_node, Config), + delete_node(Config, Node), + disconnect(Config). + +pubsub_publish_master(Config) -> + Node = create_node(Config, <<>>), + put_event(Config, Node), + wait_for_slave(Config), + #ps_item{id = ID} = publish_item(Config, Node), + #ps_item{id = ID} = get_event(Config), + delete_node(Config, Node), + disconnect(Config). + +pubsub_publish_slave(Config) -> + Node = get_event(Config), + subscribe_node(Config, Node), + wait_for_master(Config), + #message{ + sub_els = + [#ps_event{ + items = #ps_items{node = Node, + items = [Item]}}]} = recv(Config), + put_event(Config, Item), + disconnect(Config). + +pubsub_subscriptions_master(Config) -> + Peer = ?config(slave, Config), + Node = ?config(pubsub_node, Config), + Node = create_node(Config, Node), + [] = get_subscriptions(Config, Node), + wait_for_slave(Config), + lists:foreach( + fun(Type) -> + ok = set_subscriptions(Config, Node, [{Peer, Type}]), + #ps_item{} = publish_item(Config, Node), + case get_subscriptions(Config, Node) of + [] when Type == none; Type == pending -> + ok; + [#ps_subscription{jid = Peer, type = Type}] -> + ok + end + end, [subscribed, unconfigured, pending, none]), + delete_node(Config, Node), + disconnect(Config). + +pubsub_subscriptions_slave(Config) -> + wait_for_master(Config), + MyJID = my_jid(Config), + Node = ?config(pubsub_node, Config), + lists:foreach( + fun(subscribed = Type) -> + ?recv2(#message{ + sub_els = + [#ps_event{ + subscription = #ps_subscription{ + node = Node, + jid = MyJID, + type = Type}}]}, + #message{sub_els = [#ps_event{}]}); + (Type) -> + ?recv1(#message{ + sub_els = + [#ps_event{ + subscription = #ps_subscription{ + node = Node, + jid = MyJID, + type = Type}}]}) + end, [subscribed, unconfigured, pending, none]), + disconnect(Config). + +pubsub_affiliations_master(Config) -> + Peer = ?config(slave, Config), + BarePeer = jid:remove_resource(Peer), + lists:foreach( + fun(Aff) -> + Node = <<(atom_to_binary(Aff, utf8))/binary, + $-, (randoms:get_string())/binary>>, + create_node(Config, Node, default_node_config(Config)), + #ps_item{id = I} = publish_item(Config, Node), + ok = set_affiliations(Config, Node, [{Peer, Aff}]), + Affs = get_affiliations(Config, Node), + case lists:keyfind(BarePeer, #ps_affiliation.jid, Affs) of + false when Aff == none -> + ok; + #ps_affiliation{type = Aff} -> + ok + end, + put_event(Config, {Aff, Node, I}), + wait_for_slave(Config), + delete_node(Config, Node) + end, [outcast, none, member, publish_only, publisher, owner]), + put_event(Config, disconnect), + disconnect(Config). + +pubsub_affiliations_slave(Config) -> + pubsub_affiliations_slave(Config, get_event(Config)). + +pubsub_affiliations_slave(Config, {outcast, Node, ItemID}) -> + #stanza_error{reason = 'forbidden'} = subscribe_node(Config, Node), + #stanza_error{} = unsubscribe_node(Config, Node), + #stanza_error{reason = 'forbidden'} = get_items(Config, Node), + #stanza_error{reason = 'forbidden'} = publish_item(Config, Node), + #stanza_error{reason = 'forbidden'} = delete_item(Config, Node, ItemID), + #stanza_error{reason = 'forbidden'} = purge_node(Config, Node), + #stanza_error{reason = 'forbidden'} = get_node_config(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_node_config(Config, Node, default_node_config(Config)), + #stanza_error{reason = 'forbidden'} = get_subscriptions(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_subscriptions(Config, Node, [{my_jid(Config), subscribed}]), + #stanza_error{reason = 'forbidden'} = get_affiliations(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_affiliations(Config, Node, [{?config(master, Config), outcast}, + {my_jid(Config), owner}]), + #stanza_error{reason = 'forbidden'} = delete_node(Config, Node), + wait_for_master(Config), + pubsub_affiliations_slave(Config, get_event(Config)); +pubsub_affiliations_slave(Config, {none, Node, ItemID}) -> + #ps_subscription{type = subscribed} = subscribe_node(Config, Node), + ok = unsubscribe_node(Config, Node), + %% This violates the affiliation char from section 4.1 + [_|_] = get_items(Config, Node), + #stanza_error{reason = 'forbidden'} = publish_item(Config, Node), + #stanza_error{reason = 'forbidden'} = delete_item(Config, Node, ItemID), + #stanza_error{reason = 'forbidden'} = purge_node(Config, Node), + #stanza_error{reason = 'forbidden'} = get_node_config(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_node_config(Config, Node, default_node_config(Config)), + #stanza_error{reason = 'forbidden'} = get_subscriptions(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_subscriptions(Config, Node, [{my_jid(Config), subscribed}]), + #stanza_error{reason = 'forbidden'} = get_affiliations(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_affiliations(Config, Node, [{?config(master, Config), outcast}, + {my_jid(Config), owner}]), + #stanza_error{reason = 'forbidden'} = delete_node(Config, Node), + wait_for_master(Config), + pubsub_affiliations_slave(Config, get_event(Config)); +pubsub_affiliations_slave(Config, {member, Node, ItemID}) -> + #ps_subscription{type = subscribed} = subscribe_node(Config, Node), + ok = unsubscribe_node(Config, Node), + [_|_] = get_items(Config, Node), + #stanza_error{reason = 'forbidden'} = publish_item(Config, Node), + #stanza_error{reason = 'forbidden'} = delete_item(Config, Node, ItemID), + #stanza_error{reason = 'forbidden'} = purge_node(Config, Node), + #stanza_error{reason = 'forbidden'} = get_node_config(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_node_config(Config, Node, default_node_config(Config)), + #stanza_error{reason = 'forbidden'} = get_subscriptions(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_subscriptions(Config, Node, [{my_jid(Config), subscribed}]), + #stanza_error{reason = 'forbidden'} = get_affiliations(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_affiliations(Config, Node, [{?config(master, Config), outcast}, + {my_jid(Config), owner}]), + #stanza_error{reason = 'forbidden'} = delete_node(Config, Node), + wait_for_master(Config), + pubsub_affiliations_slave(Config, get_event(Config)); +pubsub_affiliations_slave(Config, {publish_only, Node, ItemID}) -> + #stanza_error{reason = 'forbidden'} = subscribe_node(Config, Node), + #stanza_error{} = unsubscribe_node(Config, Node), + #stanza_error{reason = 'forbidden'} = get_items(Config, Node), + #ps_item{id = MyItemID} = publish_item(Config, Node), + %% BUG: This should be fixed + %% ?match(ok, delete_item(Config, Node, MyItemID)), + #stanza_error{reason = 'forbidden'} = delete_item(Config, Node, ItemID), + #stanza_error{reason = 'forbidden'} = purge_node(Config, Node), + #stanza_error{reason = 'forbidden'} = get_node_config(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_node_config(Config, Node, default_node_config(Config)), + #stanza_error{reason = 'forbidden'} = get_subscriptions(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_subscriptions(Config, Node, [{my_jid(Config), subscribed}]), + #stanza_error{reason = 'forbidden'} = get_affiliations(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_affiliations(Config, Node, [{?config(master, Config), outcast}, + {my_jid(Config), owner}]), + #stanza_error{reason = 'forbidden'} = delete_node(Config, Node), + wait_for_master(Config), + pubsub_affiliations_slave(Config, get_event(Config)); +pubsub_affiliations_slave(Config, {publisher, Node, ItemID}) -> + #ps_subscription{type = subscribed} = subscribe_node(Config, Node), + ok = unsubscribe_node(Config, Node), + [_|_] = get_items(Config, Node), + #ps_item{id = MyItemID} = publish_item(Config, Node), + ok = delete_item(Config, Node, MyItemID), + %% BUG: this should be fixed + %% #stanza_error{reason = 'forbidden'} = delete_item(Config, Node, ItemID), + #stanza_error{reason = 'forbidden'} = purge_node(Config, Node), + #stanza_error{reason = 'forbidden'} = get_node_config(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_node_config(Config, Node, default_node_config(Config)), + #stanza_error{reason = 'forbidden'} = get_subscriptions(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_subscriptions(Config, Node, [{my_jid(Config), subscribed}]), + #stanza_error{reason = 'forbidden'} = get_affiliations(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_affiliations(Config, Node, [{?config(master, Config), outcast}, + {my_jid(Config), owner}]), + #stanza_error{reason = 'forbidden'} = delete_node(Config, Node), + wait_for_master(Config), + pubsub_affiliations_slave(Config, get_event(Config)); +pubsub_affiliations_slave(Config, {owner, Node, ItemID}) -> + MyJID = my_jid(Config), + Peer = ?config(master, Config), + #ps_subscription{type = subscribed} = subscribe_node(Config, Node), + ok = unsubscribe_node(Config, Node), + [_|_] = get_items(Config, Node), + #ps_item{id = MyItemID} = publish_item(Config, Node), + ok = delete_item(Config, Node, MyItemID), + ok = delete_item(Config, Node, ItemID), + ok = purge_node(Config, Node), + [_|_] = get_node_config(Config, Node), + ok = set_node_config(Config, Node, default_node_config(Config)), + ok = set_subscriptions(Config, Node, []), + [] = get_subscriptions(Config, Node), + ok = set_affiliations(Config, Node, [{Peer, outcast}, {MyJID, owner}]), + [_, _] = get_affiliations(Config, Node), + ok = delete_node(Config, Node), + wait_for_master(Config), + pubsub_affiliations_slave(Config, get_event(Config)); +pubsub_affiliations_slave(Config, disconnect) -> + disconnect(Config). + +pubsub_authorize_master(Config) -> + send(Config, #presence{}), + ?recv1(#presence{}), + Peer = ?config(slave, Config), + PJID = pubsub_jid(Config), + NodeConfig = set_opts(default_node_config(Config), + [{access_model, authorize}]), + Node = ?config(pubsub_node, Config), + Node = create_node(Config, Node, NodeConfig), + wait_for_slave(Config), + #message{sub_els = [#xdata{fields = F1}]} = recv(Config), + C1 = pubsub_subscribe_authorization:decode(F1), + Node = proplists:get_value(node, C1), + Peer = proplists:get_value(subscriber_jid, C1), + %% Deny it at first + Deny = #xdata{type = submit, + fields = pubsub_subscribe_authorization:encode( + [{node, Node}, + {subscriber_jid, Peer}, + {allow, false}])}, + send(Config, #message{to = PJID, sub_els = [Deny]}), + %% We should not have any subscriptions + [] = get_subscriptions(Config, Node), + wait_for_slave(Config), + #message{sub_els = [#xdata{fields = F2}]} = recv(Config), + C2 = pubsub_subscribe_authorization:decode(F2), + Node = proplists:get_value(node, C2), + Peer = proplists:get_value(subscriber_jid, C2), + %% Now we accept is as the peer is very insisting ;) + Approve = #xdata{type = submit, + fields = pubsub_subscribe_authorization:encode( + [{node, Node}, + {subscriber_jid, Peer}, + {allow, true}])}, + send(Config, #message{to = PJID, sub_els = [Approve]}), + wait_for_slave(Config), + delete_node(Config, Node), + disconnect(Config). + +pubsub_authorize_slave(Config) -> + Node = ?config(pubsub_node, Config), + MyJID = my_jid(Config), + wait_for_master(Config), + #ps_subscription{type = pending} = subscribe_node(Config, Node), + %% We're denied at first + ?recv1(#message{ + sub_els = + [#ps_event{ + subscription = #ps_subscription{type = none, + jid = MyJID}}]}), + wait_for_master(Config), + #ps_subscription{type = pending} = subscribe_node(Config, Node), + %% Now much better! + ?recv1(#message{ + sub_els = + [#ps_event{ + subscription = #ps_subscription{type = subscribed, + jid = MyJID}}]}), + wait_for_master(Config), + disconnect(Config). + +create_node(Config, Node) -> + create_node(Config, Node, undefined). + +create_node(Config, Node, Options) -> + PJID = pubsub_jid(Config), + NodeConfig = if is_list(Options) -> + #xdata{type = submit, + fields = pubsub_node_config:encode(Options)}; + true -> + undefined + end, + case send_recv(Config, + #iq{type = set, to = PJID, + sub_els = [#pubsub{create = Node, + configure = {<<>>, NodeConfig}}]}) of + #iq{type = result, sub_els = [#pubsub{create = NewNode}]} -> + NewNode; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +delete_node(Config, Node) -> + PJID = pubsub_jid(Config), + case send_recv(Config, + #iq{type = set, to = PJID, + sub_els = [#pubsub_owner{delete = {Node, <<>>}}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +purge_node(Config, Node) -> + PJID = pubsub_jid(Config), + case send_recv(Config, + #iq{type = set, to = PJID, + sub_els = [#pubsub_owner{purge = Node}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +get_default_node_config(Config) -> + PJID = pubsub_jid(Config), + case send_recv(Config, + #iq{type = get, to = PJID, + sub_els = [#pubsub_owner{default = {<<>>, undefined}}]}) of + #iq{type = result, + sub_els = [#pubsub_owner{default = {<<>>, NodeConfig}}]} -> + pubsub_node_config:decode(NodeConfig#xdata.fields); + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +get_node_config(Config, Node) -> + PJID = pubsub_jid(Config), + case send_recv(Config, + #iq{type = get, to = PJID, + sub_els = [#pubsub_owner{configure = {Node, undefined}}]}) of + #iq{type = result, + sub_els = [#pubsub_owner{configure = {Node, NodeConfig}}]} -> + pubsub_node_config:decode(NodeConfig#xdata.fields); + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +set_node_config(Config, Node, Options) -> + PJID = pubsub_jid(Config), + NodeConfig = #xdata{type = submit, + fields = pubsub_node_config:encode(Options)}, + case send_recv(Config, + #iq{type = set, to = PJID, + sub_els = [#pubsub_owner{configure = + {Node, NodeConfig}}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +publish_item(Config, Node) -> + PJID = pubsub_jid(Config), + ItemID = randoms:get_string(), + Item = #ps_item{id = ItemID, xml_els = [xmpp:encode(#presence{id = ItemID})]}, + case send_recv(Config, + #iq{type = set, to = PJID, + sub_els = [#pubsub{publish = #ps_publish{ + node = Node, + items = [Item]}}]}) of + #iq{type = result, + sub_els = [#pubsub{publish = #ps_publish{ + node = Node, + items = [#ps_item{id = ItemID}]}}]} -> + Item; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +get_items(Config, Node) -> + PJID = pubsub_jid(Config), + case send_recv(Config, + #iq{type = get, to = PJID, + sub_els = [#pubsub{items = #ps_items{node = Node}}]}) of + #iq{type = result, + sub_els = [#pubsub{items = #ps_items{node = Node, items = Items}}]} -> + Items; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +delete_item(Config, Node, I) -> + PJID = pubsub_jid(Config), + case send_recv(Config, + #iq{type = set, to = PJID, + sub_els = [#pubsub{retract = + #ps_retract{ + node = Node, + items = [#ps_item{id = I}]}}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +subscribe_node(Config, Node) -> + PJID = pubsub_jid(Config), + MyJID = my_jid(Config), + case send_recv(Config, + #iq{type = set, to = PJID, + sub_els = [#pubsub{subscribe = #ps_subscribe{ + node = Node, + jid = MyJID}}]}) of + #iq{type = result, + sub_els = [#pubsub{ + subscription = #ps_subscription{ + node = Node, + jid = MyJID} = Sub}]} -> + Sub; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +unsubscribe_node(Config, Node) -> + PJID = pubsub_jid(Config), + MyJID = my_jid(Config), + case send_recv(Config, + #iq{type = set, to = PJID, + sub_els = [#pubsub{ + unsubscribe = #ps_unsubscribe{ + node = Node, + jid = MyJID}}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +get_affiliations(Config) -> + PJID = pubsub_jid(Config), + case send_recv(Config, + #iq{type = get, to = PJID, + sub_els = [#pubsub{affiliations = {<<>>, []}}]}) of + #iq{type = result, + sub_els = [#pubsub{affiliations = {<<>>, Affs}}]} -> + Affs; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +get_affiliations(Config, Node) -> + PJID = pubsub_jid(Config), + case send_recv(Config, + #iq{type = get, to = PJID, + sub_els = [#pubsub_owner{affiliations = {Node, []}}]}) of + #iq{type = result, + sub_els = [#pubsub_owner{affiliations = {Node, Affs}}]} -> + Affs; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +set_affiliations(Config, Node, JTs) -> + PJID = pubsub_jid(Config), + Affs = [#ps_affiliation{jid = J, type = T} || {J, T} <- JTs], + case send_recv(Config, + #iq{type = set, to = PJID, + sub_els = [#pubsub_owner{affiliations = + {Node, Affs}}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +get_subscriptions(Config) -> + PJID = pubsub_jid(Config), + case send_recv(Config, + #iq{type = get, to = PJID, + sub_els = [#pubsub{subscriptions = {<<>>, []}}]}) of + #iq{type = result, sub_els = [#pubsub{subscriptions = {<<>>, Subs}}]} -> + Subs; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +get_subscriptions(Config, Node) -> + PJID = pubsub_jid(Config), + case send_recv(Config, + #iq{type = get, to = PJID, + sub_els = [#pubsub_owner{subscriptions = {Node, []}}]}) of + #iq{type = result, + sub_els = [#pubsub_owner{subscriptions = {Node, Subs}}]} -> + Subs; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +set_subscriptions(Config, Node, JTs) -> + PJID = pubsub_jid(Config), + Subs = [#ps_subscription{jid = J, type = T} || {J, T} <- JTs], + case send_recv(Config, + #iq{type = set, to = PJID, + sub_els = [#pubsub_owner{subscriptions = + {Node, Subs}}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +default_node_config(Config) -> + [{title, ?config(pubsub_node_title, Config)}, + {notify_delete, false}, + {send_last_published_item, never}]. + mix_master(Config) -> MIX = mix_jid(Config), Room = mix_room_jid(Config), @@ -1627,7 +2250,7 @@ muc_mam_master(Config) -> to = Room}), %% Find the MAM field in the config and enable it NewFields = lists:flatmap( - fun(#xdata_field{var = <<"muc#roomconfig_mam">> = Var}) -> + fun(#xdata_field{var = <<"mam">> = Var}) -> [#xdata_field{var = Var, values = [<<"1">>]}]; (_) -> [] @@ -1934,39 +2557,36 @@ muc_slave(Config) -> disconnect(Config). muc_register_nick(Config, MUC, PrevNick, Nick) -> - {Registered, PrevNickVals} = if PrevNick /= <<"">> -> - {true, [PrevNick]}; - true -> - {false, []} - end, + PrevRegistered = if PrevNick /= <<"">> -> true; + true -> false + end, + NewRegistered = if Nick /= <<"">> -> true; + true -> false + end, %% Request register form #iq{type = result, - sub_els = [#register{registered = Registered, + sub_els = [#register{registered = PrevRegistered, xdata = #xdata{type = form, fields = FsWithoutNick}}]} = send_recv(Config, #iq{type = get, to = MUC, sub_els = [#register{}]}), - %% Check if 'nick' field presents - #xdata_field{type = 'text-single', - var = <<"nick">>, - values = PrevNickVals} = - lists:keyfind(<<"nick">>, #xdata_field.var, FsWithoutNick), - X = #xdata{type = submit, - fields = [#xdata_field{var = <<"nick">>, values = [Nick]}]}, + %% Check if previous nick is registered + PrevNick = proplists:get_value( + roomnick, muc_register:decode(FsWithoutNick)), + X = #xdata{type = submit, fields = muc_register:encode([{roomnick, Nick}])}, %% Submitting form #iq{type = result, sub_els = []} = send_recv(Config, #iq{type = set, to = MUC, sub_els = [#register{xdata = X}]}), - %% Check if the nick was registered + %% Check if new nick was registered #iq{type = result, - sub_els = [#register{registered = true, + sub_els = [#register{registered = NewRegistered, xdata = #xdata{type = form, fields = FsWithNick}}]} = send_recv(Config, #iq{type = get, to = MUC, sub_els = [#register{}]}), - #xdata_field{type = 'text-single', var = <<"nick">>, - values = [Nick]} = - lists:keyfind(<<"nick">>, #xdata_field.var, FsWithNick). + Nick = proplists:get_value( + roomnick, muc_register:decode(FsWithNick)). muc_register_master(Config) -> MUC = muc_jid(Config), @@ -1980,17 +2600,23 @@ muc_register_master(Config) -> muc_register_nick(Config, MUC, <<"">>, <<"master2">>), %% Now register nick "master" muc_register_nick(Config, MUC, <<"master2">>, <<"master">>), + %% Wait for slave to fail trying to register nick "master" + wait_for_slave(Config), + wait_for_slave(Config), + %% Now register empty ("") nick, which means we're unregistering + muc_register_nick(Config, MUC, <<"master">>, <<"">>), disconnect(Config). muc_register_slave(Config) -> MUC = muc_jid(Config), + wait_for_master(Config), %% Trying to register occupied nick "master" - X = #xdata{type = submit, - fields = [#xdata_field{var = <<"nick">>, - values = [<<"master">>]}]}, + Fs = muc_register:encode([{roomnick, <<"master">>}]), + X = #xdata{type = submit, fields = Fs}, #iq{type = error} = send_recv(Config, #iq{type = set, to = MUC, sub_els = [#register{xdata = X}]}), + wait_for_master(Config), disconnect(Config). announce_master(Config) -> @@ -2741,6 +3367,12 @@ socks5_send(Sock, Data) -> socks5_recv(Sock, Data) -> {ok, Data} = gen_tcp:recv(Sock, size(Data)). +set_opts(Config, Options) -> + lists:foldl( + fun({Opt, Val}, Acc) -> + lists:keystore(Opt, 1, Acc, {Opt, Val}) + end, Config, Options). + %%%=================================================================== %%% SQL stuff %%%=================================================================== diff --git a/test/suite.erl b/test/suite.erl index 42c5dcfbe..ed1cbd83d 100644 --- a/test/suite.erl +++ b/test/suite.erl @@ -86,6 +86,8 @@ init_config(Config) -> {lang, <<"en">>}, {base_dir, BaseDir}, {socket, undefined}, + {pubsub_node, <<"node!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, + {pubsub_node_title, <<"title!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, {resource, <<"resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, {master_resource, <<"master_resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, {slave_resource, <<"slave_resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, diff --git a/test/suite.hrl b/test/suite.hrl index 4110da0df..00239f8cf 100644 --- a/test/suite.hrl +++ b/test/suite.hrl @@ -66,6 +66,14 @@ end end)()). +-define(match(Pattern, Result), + case Result of + Pattern -> + Pattern; + Mismatch -> + suite:match_failure([Mismatch], [??Pattern]) + end). + -define(COMMON_VHOST, <<"localhost">>). -define(MNESIA_VHOST, <<"mnesia.localhost">>). -define(REDIS_VHOST, <<"redis.localhost">>). From 5c48263579557bd7f96e833c515af74669ab03d2 Mon Sep 17 00:00:00 2001 From: Uku Taht Date: Fri, 7 Oct 2016 10:47:20 +0100 Subject: [PATCH 052/151] Enable elixir when ejabberd used as a mix dependency --- mix.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.exs b/mix.exs index ee4b60fb2..fc9fcea01 100644 --- a/mix.exs +++ b/mix.exs @@ -36,7 +36,7 @@ defmodule Ejabberd.Mixfile do defp erlc_options do # Use our own includes + includes from all dependencies includes = ["include"] ++ Path.wildcard(Path.join("..", "/*/include")) - [:debug_info] ++ Enum.map(includes, fn(path) -> {:i, path} end) + [:debug_info, {:d, :ELIXIR_ENABLED}] ++ Enum.map(includes, fn(path) -> {:i, path} end) end defp deps do From a915fd161e0121ce4338a62d3cda7736f7e20dd9 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Wed, 7 Sep 2016 11:15:19 +0300 Subject: [PATCH 053/151] Create room on configuration request as per XEP-0045, 10.1.3 --- src/mod_muc.erl | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/mod_muc.erl b/src/mod_muc.erl index b189508a8..6b71d1e1d 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -385,8 +385,8 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper, {Room, _, Nick} = jid:tolower(To), case mnesia:dirty_read(muc_online_room, {Room, Host}) of [] -> - case Packet of - #presence{type = available, lang = Lang} -> + case is_create_request(Packet) of + true -> case check_user_can_create_room( ServerHost, AccessCreate, From, Room) and check_create_roomid(ServerHost, Room) of @@ -399,12 +399,13 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper, mod_muc_room:route(Pid, From, Nick, Packet), ok; false -> + Lang = xmpp:get_lang(Packet), ErrText = <<"Room creation is denied by service policy">>, Err = xmpp:make_error( Packet, xmpp:err_forbidden(ErrText, Lang)), ejabberd_router:route(To, From, Err) end; - _ -> + false -> Lang = xmpp:get_lang(Packet), ErrText = <<"Conference room does not exist">>, Err = xmpp:err_item_not_found(ErrText, Lang), @@ -501,6 +502,16 @@ process_mucsub(#iq{type = get, from = From, to = To} = IQ) -> RoomJIDs = get_subscribed_rooms(ServerHost, Host, From), xmpp:make_iq_result(IQ, #muc_subscriptions{list = RoomJIDs}). +-spec is_create_request(stanza()) -> boolean(). +is_create_request(#presence{type = available}) -> + true; +is_create_request(#iq{type = set} = IQ) -> + xmpp:has_subtag(IQ, #muc_subscribe{}); +is_create_request(#iq{type = get} = IQ) -> + #muc_owner{} == xmpp:get_subtag(IQ, #muc_owner{}); +is_create_request(_) -> + false. + check_user_can_create_room(ServerHost, AccessCreate, From, _RoomID) -> case acl:match_rule(ServerHost, AccessCreate, From) of From 0f67a8f98b88447a263e969760ee88c9db30b143 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Fri, 16 Sep 2016 14:59:06 +0200 Subject: [PATCH 054/151] Update riakc to support r19 --- rebar.config | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/rebar.config b/rebar.config index 9ef8bc0fc..6eb23f0f7 100644 --- a/rebar.config +++ b/rebar.config @@ -31,12 +31,7 @@ {if_var_true, zlib, {ezlib, ".*", {git, "https://github.com/processone/ezlib", {tag, "1.0.1"}}}}, {if_var_true, riak, {riakc, ".*", {git, "https://github.com/basho/riak-erlang-client", - "527722d12d0433b837cdb92a60900c2cb5df8942"}}}, - %% Forces correct dependency for riakc and allow using newer meck version) - {if_var_true, riak, {hamcrest, ".*", {git, "https://github.com/hyperthunk/hamcrest-erlang", - "13f9bfb9b27d216e8e033b0e0a9a29097ed923dd"}}}, % for riak_pb-2.1.0.7 - {if_var_true, riak, {protobuffs, ".*", {git, "https://github.com/basho/erlang_protobuffs", - "6e7fc924506e2dc166a6170e580ce1d95ebbd5bd"}}}, % for riak_pb-2.1.0.7 with correct meck dependency + {tag, "2.4.1"}}}}, %% Elixir support, needed to run tests {if_var_true, elixir, {elixir, ".*", {git, "https://github.com/elixir-lang/elixir", {tag, "v1.1.1"}}}}, From 67720c77137da2e80907f67dccc96fcbdb44c3bf Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Mon, 17 Oct 2016 13:37:23 +0300 Subject: [PATCH 055/151] Add more MUC tests --- src/gen_iq_handler.erl | 2 +- src/mod_mam.erl | 34 +- src/mod_muc.erl | 56 +- src/mod_muc_room.erl | 550 ++++---- src/str.erl | 6 + test/ejabberd_SUITE.erl | 581 +++----- test/ejabberd_SUITE_data/ejabberd.yml | 1 + test/muc_tests.erl | 1877 +++++++++++++++++++++++++ test/suite.erl | 80 +- 9 files changed, 2460 insertions(+), 727 deletions(-) create mode 100644 test/muc_tests.erl diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl index b8a44c96c..8af2cb028 100644 --- a/src/gen_iq_handler.erl +++ b/src/gen_iq_handler.erl @@ -156,7 +156,7 @@ process_iq(Module, Function, #iq{lang = Lang, sub_els = [El]} = IQ) -> %% TODO: move this 'conditional' decoding somewhere %% IQ handler should know *nothing* about vCards. Pkt = case xmpp:get_ns(El) of - ?NS_VCARD -> El; + ?NS_VCARD when Module == mod_vcard -> El; _ -> xmpp:decode(El) end, Module:Function(IQ#iq{sub_els = [Pkt]}) diff --git a/src/mod_mam.erl b/src/mod_mam.erl index 1daae5aa2..cbd23ebde 100644 --- a/src/mod_mam.erl +++ b/src/mod_mam.erl @@ -772,28 +772,25 @@ select(_LServer, JidRequestor, JidArchive, {groupchat, _Role, #state{config = #config{mam = false}, history = History}} = MsgType) -> #lqueue{len = L, queue = Q} = History, - {Msgs0, _} = - lists:mapfoldl( - fun({Nick, Pkt, _HaveSubject, UTCDateTime, _Size}, I) -> - Now = datetime_to_now(UTCDateTime, I), + Msgs = + lists:flatmap( + fun({Nick, Pkt, _HaveSubject, Now, _Size}) -> TS = now_to_usec(Now), case match_interval(Now, Start, End) and match_rsm(Now, RSM) of true -> - {[{integer_to_binary(TS), TS, - msg_to_el(#archive_msg{ - type = groupchat, - timestamp = Now, - peer = undefined, - nick = Nick, - packet = Pkt}, - MsgType, JidRequestor, JidArchive)}], - I+1}; + [{integer_to_binary(TS), TS, + msg_to_el(#archive_msg{ + type = groupchat, + timestamp = Now, + peer = undefined, + nick = Nick, + packet = Pkt}, + MsgType, JidRequestor, JidArchive)}]; false -> - {[], I+1} + [] end - end, 0, queue:to_list(Q)), - Msgs = lists:flatten(Msgs0), + end, queue:to_list(Q)), case RSM of #rsm_set{max = Max, before = Before} when is_binary(Before) -> {NewMsgs, IsComplete} = filter_by_max(lists:reverse(Msgs), Max), @@ -960,11 +957,6 @@ usec_to_now(Int) -> Sec = Secs rem 1000000, {MSec, Sec, USec}. -datetime_to_now(DateTime, USecs) -> - Seconds = calendar:datetime_to_gregorian_seconds(DateTime) - - calendar:datetime_to_gregorian_seconds({{1970, 1, 1}, {0, 0, 0}}), - {Seconds div 1000000, Seconds rem 1000000, USecs}. - get_jids(undefined) -> []; get_jids(Js) -> diff --git a/src/mod_muc.erl b/src/mod_muc.erl index 6b71d1e1d..9c17643b8 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -377,7 +377,7 @@ do_route1(Host, ServerHost, Access, _HistorySize, _RoomShaper, end; do_route1(_Host, _ServerHost, _Access, _HistorySize, _RoomShaper, From, #jid{luser = <<"">>} = To, Packet, _DefRoomOpts) -> - Err = xmpp:err_item_not_found(), + Err = xmpp:err_service_unavailable(), ejabberd_router:route_error(To, From, Packet, Err); do_route1(Host, ServerHost, Access, HistorySize, RoomShaper, From, To, Packet, DefRoomOpts) -> @@ -419,7 +419,7 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper, end. -spec process_vcard(iq()) -> iq(). -process_vcard(#iq{type = get, lang = Lang} = IQ) -> +process_vcard(#iq{type = get, lang = Lang, sub_els = [#vcard_temp{}]} = IQ) -> Desc = translate:translate(Lang, <<"ejabberd MUC module">>), Copyright = <<"Copyright (c) 2003-2016 ProcessOne">>, xmpp:make_iq_result( @@ -428,15 +428,19 @@ process_vcard(#iq{type = get, lang = Lang} = IQ) -> desc = <>}); process_vcard(#iq{type = set, lang = Lang} = IQ) -> Txt = <<"Value 'set' of 'type' attribute is not allowed">>, - xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)). + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_vcard(#iq{lang = Lang} = IQ) -> + Txt = <<"No module is handling this query">>, + xmpp:make_error(IQ, xmpp:err_service_unavailable(Txt, Lang)). -spec process_register(iq()) -> iq(). -process_register(#iq{type = get, from = From, to = To, lang = Lang} = IQ) -> +process_register(#iq{type = get, from = From, to = To, lang = Lang, + sub_els = [#register{}]} = IQ) -> Host = To#jid.lserver, ServerHost = ejabberd_router:host_of_route(Host), xmpp:make_iq_result(IQ, iq_get_register_info(ServerHost, Host, From, Lang)); process_register(#iq{type = set, from = From, to = To, - lang = Lang, sub_els = [El]} = IQ) -> + lang = Lang, sub_els = [El = #register{}]} = IQ) -> Host = To#jid.lserver, ServerHost = ejabberd_router:host_of_route(Host), case process_iq_register_set(ServerHost, Host, From, El, Lang) of @@ -469,8 +473,12 @@ process_disco_info(#iq{type = get, to = To, lang = Lang, IQ, #disco_info{features = Features, identities = [Identity], xdata = X}); -process_disco_info(#iq{type = get, lang = Lang} = IQ) -> - xmpp:make_error(IQ, xmpp:err_item_not_found(<<"No info available">>, Lang)). +process_disco_info(#iq{type = get, lang = Lang, + sub_els = [#disco_info{}]} = IQ) -> + xmpp:make_error(IQ, xmpp:err_item_not_found(<<"Node not found">>, Lang)); +process_disco_info(#iq{lang = Lang} = IQ) -> + Txt = <<"No module is handling this query">>, + xmpp:make_error(IQ, xmpp:err_service_unavailable(Txt, Lang)). -spec process_disco_items(iq()) -> iq(). process_disco_items(#iq{type = set, lang = Lang} = IQ) -> @@ -481,13 +489,17 @@ process_disco_items(#iq{type = get, from = From, to = To, lang = Lang, Host = To#jid.lserver, xmpp:make_iq_result( IQ, #disco_items{node = Node, - items = iq_disco_items(Host, From, Lang, Node, RSM)}). + items = iq_disco_items(Host, From, Lang, Node, RSM)}); +process_disco_items(#iq{lang = Lang} = IQ) -> + Txt = <<"No module is handling this query">>, + xmpp:make_error(IQ, xmpp:err_service_unavailable(Txt, Lang)). -spec process_muc_unique(iq()) -> iq(). process_muc_unique(#iq{type = set, lang = Lang} = IQ) -> Txt = <<"Value 'set' of 'type' attribute is not allowed">>, xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); -process_muc_unique(#iq{from = From, type = get} = IQ) -> +process_muc_unique(#iq{from = From, type = get, + sub_els = [#muc_unique{}]} = IQ) -> Name = p1_sha:sha(term_to_binary([From, p1_time_compat:timestamp(), randoms:get_string()])), xmpp:make_iq_result(IQ, #muc_unique{name = Name}). @@ -496,19 +508,22 @@ process_muc_unique(#iq{from = From, type = get} = IQ) -> process_mucsub(#iq{type = set, lang = Lang} = IQ) -> Txt = <<"Value 'set' of 'type' attribute is not allowed">>, xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); -process_mucsub(#iq{type = get, from = From, to = To} = IQ) -> +process_mucsub(#iq{type = get, from = From, to = To, + sub_els = [#muc_subscriptions{}]} = IQ) -> Host = To#jid.lserver, ServerHost = ejabberd_router:host_of_route(Host), RoomJIDs = get_subscribed_rooms(ServerHost, Host, From), - xmpp:make_iq_result(IQ, #muc_subscriptions{list = RoomJIDs}). + xmpp:make_iq_result(IQ, #muc_subscriptions{list = RoomJIDs}); +process_mucsub(#iq{lang = Lang} = IQ) -> + Txt = <<"No module is handling this query">>, + xmpp:make_error(IQ, xmpp:err_service_unavailable(Txt, Lang)). -spec is_create_request(stanza()) -> boolean(). is_create_request(#presence{type = available}) -> true; -is_create_request(#iq{type = set} = IQ) -> - xmpp:has_subtag(IQ, #muc_subscribe{}); -is_create_request(#iq{type = get} = IQ) -> - #muc_owner{} == xmpp:get_subtag(IQ, #muc_owner{}); +is_create_request(#iq{type = T} = IQ) when T == get; T == set -> + xmpp:has_subtag(IQ, #muc_subscribe{}) orelse + xmpp:has_subtag(IQ, #muc_owner{}); is_create_request(_) -> false. @@ -645,13 +660,12 @@ get_vh_rooms(_, _) -> %% index = NewIndex}} %% end. -get_subscribed_rooms(ServerHost, Host, From) -> - Rooms = get_rooms(ServerHost, Host), +get_subscribed_rooms(_ServerHost, Host, From) -> + Rooms = get_vh_rooms(Host), lists:flatmap( - fun(#muc_room{name_host = {Name, _}, opts = Opts}) -> - Subscribers = proplists:get_value(subscribers, Opts, []), - case lists:keymember(From, 1, Subscribers) of - true -> [jid:make(Name, Host, <<>>)]; + fun(#muc_online_room{name_host = {Name, _}, pid = Pid}) -> + case gen_fsm:sync_send_all_state_event(Pid, {is_subscriber, From}) of + true -> [jid:make(Name, Host)]; false -> [] end; (_) -> diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl index 52401f835..ce6851bc5 100644 --- a/src/mod_muc_room.erl +++ b/src/mod_muc_room.erl @@ -76,11 +76,6 @@ -type fsm_stop() :: {stop, normal, state()}. -type fsm_next() :: {next_state, normal_state, state()}. -type fsm_transition() :: fsm_stop() | fsm_next(). --type history_element() :: {binary(), %% nick - message(), %% message itself - boolean(), %% have subject - erlang:timestamp(), - non_neg_integer()}. -export_type([state/0]). @@ -252,7 +247,8 @@ normal_state({route, From, <<"">>, ejabberd_router:route_error(StateData#state.jid, From, Packet, Err), {next_state, normal_state, StateData}; false when Type /= error -> - handle_roommessage_from_nonparticipant(Packet, StateData, From); + handle_roommessage_from_nonparticipant(Packet, StateData, From), + {next_state, normal_state, StateData}; false -> {next_state, normal_state, StateData} end; @@ -279,9 +275,6 @@ normal_state({route, From, <<"">>, process_iq_owner(From, IQ, StateData); ?NS_DISCO_INFO when SubEl#disco_info.node == <<>> -> process_iq_disco_info(From, IQ, StateData); - ?NS_DISCO_INFO -> - Txt = <<"Disco info is not available for this node">>, - {error, xmpp:err_service_unavailable(Txt, Lang)}; ?NS_DISCO_ITEMS -> process_iq_disco_items(From, IQ, StateData); ?NS_VCARD -> @@ -291,7 +284,9 @@ normal_state({route, From, <<"">>, ?NS_CAPTCHA -> process_iq_captcha(From, IQ, StateData); _ -> - {error, xmpp:err_feature_not_implemented()} + Txt = <<"The feature requested is not " + "supported by the conference">>, + {error, xmpp:err_service_unavailable(Txt, Lang)} end, {IQRes, NewStateData} = case Res1 of @@ -312,8 +307,12 @@ normal_state({route, From, <<"">>, ok end, case NewStateData of - stop -> {stop, normal, StateData}; - _ -> {next_state, normal_state, NewStateData} + stop -> + {stop, normal, StateData}; + _ when NewStateData#state.just_created -> + close_room_if_temporary_and_empty(NewStateData); + _ -> + {next_state, normal_state, NewStateData} end end catch _:{xmpp_codec, Why} -> @@ -324,7 +323,10 @@ normal_state({route, From, <<"">>, normal_state({route, From, <<"">>, #iq{} = IQ}, StateData) -> Err = xmpp:err_bad_request(), ejabberd_router:route_error(StateData#state.jid, From, IQ, Err), - {next_state, normal_state, StateData}; + case StateData#state.just_created of + true -> {stop, normal, StateData}; + false -> {next_state, normal_state, StateData} + end; normal_state({route, From, Nick, #presence{} = Packet}, StateData) -> Activity = get_user_activity(From, StateData), Now = p1_time_compat:system_time(micro_seconds), @@ -530,8 +532,14 @@ handle_sync_event({change_state, NewStateData}, _From, StateName, _StateData) -> {reply, {ok, NewStateData}, StateName, NewStateData}; handle_sync_event({process_item_change, Item, UJID}, _From, StateName, StateData) -> - NSD = process_item_change(Item, StateData, UJID), - {reply, {ok, NSD}, StateName, NSD}; + case process_item_change(Item, StateData, UJID) of + {error, _} = Err -> + {reply, Err, StateName, StateData}; + NSD -> + {reply, {ok, NSD}, StateName, NSD} + end; +handle_sync_event({is_subscriber, From}, _From, StateName, StateData) -> + {reply, is_subscriber(From, StateData), StateName, StateData}; handle_sync_event(_Event, _From, StateName, StateData) -> Reply = ok, {reply, Reply, StateName, StateData}. @@ -763,7 +771,7 @@ process_normal_message(From, #message{lang = Lang} = Pkt, StateData) -> (#muc_user{invites = [I]}, _) -> {ok, I}; (#muc_user{invites = [_|_]}, _) -> - Txt = <<"Multiple elements are not allowed">>, + Txt = <<"Multiple invitations are not allowed">>, {error, xmpp:err_resource_constraint(Txt, Lang)}; (#xdata{type = submit, fields = Fs}, _) -> try {ok, muc_request:decode(Fs)} @@ -835,7 +843,7 @@ process_voice_request(From, Pkt, StateData) -> {ok, _, _} -> ErrText = <<"Please, wait for a while before sending " "new voice request">>, - Err = xmpp:err_not_acceptable(ErrText, Lang), + Err = xmpp:err_resource_constraint(ErrText, Lang), ejabberd_router:route_error( StateData#state.jid, From, Pkt, Err), StateData#state{last_voice_request_time = Times} @@ -1147,10 +1155,9 @@ decide_fate_message(#message{type = error} = Msg, PD = case check_error_kick(Err) of %% If this is an error stanza and its condition matches a criteria true -> - Reason = - io_lib:format("This participant is considered a ghost " - "and is expulsed: ~s", - [jid:to_string(From)]), + Reason = str:format("This participant is considered a ghost " + "and is expulsed: ~s", + [jid:to_string(From)]), {expulse_sender, Reason}; false -> continue_delivery end, @@ -1198,7 +1205,7 @@ get_error_condition(undefined) -> make_reason(Packet, From, StateData, Reason1) -> {ok, #user{nick = FromNick}} = (?DICT):find(jid:tolower(From), StateData#state.users), Condition = get_error_condition(xmpp:get_error(Packet)), - iolist_to_binary(io_lib:format(Reason1, [FromNick, Condition])). + str:format(Reason1, [FromNick, Condition]). -spec expulse_participant(stanza(), jid(), state(), binary()) -> state(). @@ -1816,11 +1823,9 @@ add_new_user(From, Nick, Packet, StateData) -> Nodes, StateData)), send_existing_presences(From, NewState), send_initial_presence(From, NewState, StateData), - Shift = count_stanza_shift(Nick, Packet, NewState), - case send_history(From, Shift, NewState) of - true -> ok; - _ -> send_subject(From, StateData) - end, + History = get_history(Nick, Packet, NewState), + send_history(From, History, NewState), + send_subject(From, StateData), NewState; true -> add_online_user(From, Nick, none, @@ -1963,84 +1968,43 @@ extract_password(Packet) -> false end. --spec count_stanza_shift(binary(), stanza(), state()) -> non_neg_integer(). -count_stanza_shift(Nick, Packet, StateData) -> - case xmpp:get_subtag(Packet, #muc_history{}) of - #muc_history{since = Since, - seconds = Seconds, - maxstanzas = MaxStanzas, - maxchars = MaxChars} -> - HL = lqueue_to_list(StateData#state.history), - Shift0 = case Since of - undefined -> 0; - _ -> - Sin = calendar:datetime_to_gregorian_seconds( - calendar:now_to_datetime(Since)), - count_seconds_shift(Sin, HL) - end, - Shift1 = case Seconds of - undefined -> 0; - _ -> - Sec = calendar:datetime_to_gregorian_seconds( - calendar:universal_time()) - Seconds, - count_seconds_shift(Sec, HL) - end, - Shift2 = case MaxStanzas of - undefined -> 0; - _ -> count_maxstanzas_shift(MaxStanzas, HL) - end, - Shift3 = case MaxChars of - undefined -> 0; - _ -> count_maxchars_shift(Nick, MaxChars, HL) - end, - lists:max([Shift0, Shift1, Shift2, Shift3]); - false -> - 0 +-spec get_history(binary(), stanza(), state()) -> lqueue(). +get_history(Nick, Packet, #state{history = History}) -> + case xmpp:get_subtag(Packet, #muc{}) of + #muc{history = #muc_history{} = MUCHistory} -> + Now = p1_time_compat:timestamp(), + Q = History#lqueue.queue, + {NewQ, Len} = filter_history(Q, MUCHistory, Now, Nick, queue:new(), 0, 0), + History#lqueue{queue = NewQ, len = Len}; + _ -> + History end. --spec count_seconds_shift(non_neg_integer(), - [history_element()]) -> non_neg_integer(). -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)). - --spec count_maxstanzas_shift(non_neg_integer(), - [history_element()]) -> non_neg_integer(). -count_maxstanzas_shift(MaxStanzas, HistoryList) -> - S = length(HistoryList) - MaxStanzas, - if S =< 0 -> 0; - true -> S - end. - --spec count_maxchars_shift(binary(), non_neg_integer(), - [history_element()]) -> integer(). -count_maxchars_shift(Nick, MaxSize, HistoryList) -> - NLen = byte_size(Nick) + 1, - Sizes = lists:map(fun ({_Nick, _Packet, _HaveSubject, - _TimeStamp, Size}) -> - Size + NLen - end, - HistoryList), - calc_shift(MaxSize, Sizes). - --spec calc_shift(non_neg_integer(), [non_neg_integer()]) -> integer(). -calc_shift(MaxSize, Sizes) -> - Total = lists:sum(Sizes), - calc_shift(MaxSize, Total, 0, Sizes). - --spec calc_shift(non_neg_integer(), integer(), integer(), - [non_neg_integer()]) -> integer(). -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) +-spec filter_history(?TQUEUE, muc_history(), erlang:timestamp(), binary(), + ?TQUEUE, non_neg_integer(), non_neg_integer()) -> + {?TQUEUE, non_neg_integer()}. +filter_history(Queue, #muc_history{since = Since, + seconds = Seconds, + maxstanzas = MaxStanzas, + maxchars = MaxChars} = MUC, + Now, Nick, AccQueue, NumStanzas, NumChars) -> + case queue:out_r(Queue) of + {{value, {_, _, _, TimeStamp, Size} = Elem}, NewQueue} -> + NowDiff = timer:now_diff(Now, TimeStamp) div 1000000, + Chars = Size + byte_size(Nick) + 1, + if (NumStanzas < MaxStanzas) andalso + (TimeStamp > Since) andalso + (NowDiff =< Seconds) andalso + (NumChars + Chars =< MaxChars) -> + filter_history(NewQueue, MUC, Now, Nick, + queue:in_r(Elem, AccQueue), + NumStanzas + 1, + NumChars + Chars); + true -> + {AccQueue, NumStanzas} + end; + {empty, _} -> + {AccQueue, NumStanzas} end. -spec is_room_overcrowded(state()) -> boolean(). @@ -2166,19 +2130,20 @@ send_new_presence1(NJID, Reason, IsInitialPresence, StateData, OldStateData) -> end, lists:foreach( fun({LUJID, Info}) -> - {Role, Presence} = if LNJID == LUJID -> {Role0, Presence0}; + IsSelfPresence = LNJID == LUJID, + {Role, Presence} = if IsSelfPresence -> {Role0, Presence0}; true -> {Role1, Presence1} end, Item0 = #muc_item{affiliation = Affiliation, role = Role}, Item1 = case Info#user.role == moderator orelse (StateData#state.config)#config.anonymous - == false of + == false orelse IsSelfPresence of true -> Item0#muc_item{jid = RealJID}; false -> Item0 end, Item = Item1#muc_item{reason = Reason}, - StatusCodes = status_codes(IsInitialPresence, NJID, Info, + StatusCodes = status_codes(IsInitialPresence, IsSelfPresence, StateData), Pres = if Presence == undefined -> #presence{}; true -> Presence @@ -2303,30 +2268,26 @@ send_nick_changing(JID, OldNick, StateData, StateData#state.users), Affiliation = get_affiliation(JID, StateData), lists:foreach( - fun({_LJID, Info}) when Presence /= undefined -> + fun({LJID, Info}) when Presence /= undefined -> + IsSelfPresence = LJID == jid:tolower(JID), Item0 = #muc_item{affiliation = Affiliation, role = Role}, - Item1 = case Info#user.role == moderator orelse - (StateData#state.config)#config.anonymous - == false of - true -> Item0#muc_item{jid = RealJID, nick = Nick}; - false -> Item0#muc_item{nick = Nick} - end, - Item2 = case Info#user.role == moderator orelse - (StateData#state.config)#config.anonymous - == false of - true -> Item0#muc_item{jid = RealJID}; - false -> Item0 - end, - Status110 = case JID == Info#user.jid of + Item = case Info#user.role == moderator orelse + (StateData#state.config)#config.anonymous + == false orelse IsSelfPresence of + true -> Item0#muc_item{jid = RealJID}; + false -> Item0 + end, + Status110 = case IsSelfPresence of true -> [110]; false -> [] end, - Packet1 = #presence{type = unavailable, - sub_els = [#muc_user{ - items = [Item1], - status_codes = [303|Status110]}]}, + Packet1 = #presence{ + type = unavailable, + sub_els = [#muc_user{ + items = [Item#muc_item{nick = Nick}], + status_codes = [303|Status110]}]}, Packet2 = xmpp:set_subtag(Presence, - #muc_user{items = [Item2], + #muc_user{items = [Item], status_codes = Status110}), if SendOldUnavailable -> send_wrapped( @@ -2364,12 +2325,12 @@ maybe_send_affiliation(JID, Affiliation, StateData) -> true -> ok; % The new affiliation is published via presence. false -> - send_affiliation(LJID, Affiliation, StateData) + send_affiliation(JID, Affiliation, StateData) end. --spec send_affiliation(ljid(), affiliation(), state()) -> ok. -send_affiliation(LJID, Affiliation, StateData) -> - Item = #muc_item{jid = jid:make(LJID), +-spec send_affiliation(jid(), affiliation(), state()) -> ok. +send_affiliation(JID, Affiliation, StateData) -> + Item = #muc_item{jid = JID, affiliation = Affiliation, role = none}, Message = #message{id = randoms:get_string(), @@ -2388,8 +2349,8 @@ send_affiliation(LJID, Affiliation, StateData) -> StateData#state.server_host, Recipients, Message). --spec status_codes(boolean(), jid(), #user{}, state()) -> [pos_integer()]. -status_codes(IsInitialPresence, JID, #user{jid = JID}, StateData) -> +-spec status_codes(boolean(), boolean(), state()) -> [pos_integer()]. +status_codes(IsInitialPresence, _IsSelfPresence = true, StateData) -> S0 = [110], case IsInitialPresence of true -> @@ -2408,7 +2369,7 @@ status_codes(IsInitialPresence, JID, #user{jid = JID}, StateData) -> S3; false -> S0 end; -status_codes(_IsInitialPresence, _JID, _Info, _StateData) -> []. +status_codes(_IsInitialPresence, _IsSelfPresence = false, _StateData) -> []. -spec lqueue_new(non_neg_integer()) -> lqueue(). lqueue_new(Max) -> @@ -2438,54 +2399,58 @@ lqueue_to_list(#lqueue{queue = Q1}) -> -spec add_message_to_history(binary(), jid(), message(), state()) -> state(). add_message_to_history(FromNick, FromJID, Packet, StateData) -> - HaveSubject = Packet#message.subject /= [], - TimeStamp = p1_time_compat:timestamp(), - AddrPacket = case (StateData#state.config)#config.anonymous of - true -> Packet; - false -> - Addresses = #addresses{ - list = [#address{type = ofrom, - jid = FromJID}]}, - xmpp:set_subtag(Packet, Addresses) - end, - TSPacket = xmpp_util:add_delay_info( - AddrPacket, StateData#state.jid, TimeStamp), - SPacket = xmpp:set_from_to( - TSPacket, - jid:replace_resource(StateData#state.jid, FromNick), - StateData#state.jid), - Size = element_size(SPacket), - Q1 = lqueue_in({FromNick, TSPacket, HaveSubject, - calendar:now_to_universal_time(TimeStamp), Size}, - StateData#state.history), add_to_log(text, {FromNick, Packet}, StateData), - StateData#state{history = Q1}. + case check_subject(Packet) of + false -> + TimeStamp = p1_time_compat:timestamp(), + AddrPacket = case (StateData#state.config)#config.anonymous of + true -> Packet; + false -> + Addresses = #addresses{ + list = [#address{type = ofrom, + jid = FromJID}]}, + xmpp:set_subtag(Packet, Addresses) + end, + TSPacket = xmpp_util:add_delay_info( + AddrPacket, StateData#state.jid, TimeStamp), + SPacket = xmpp:set_from_to( + TSPacket, + jid:replace_resource(StateData#state.jid, FromNick), + StateData#state.jid), + Size = element_size(SPacket), + Q1 = lqueue_in({FromNick, TSPacket, false, + TimeStamp, Size}, + StateData#state.history), + StateData#state{history = Q1}; + _ -> + StateData + end. --spec send_history(jid(), integer(), state()) -> boolean(). -send_history(JID, Shift, StateData) -> - lists:foldl(fun ({Nick, Packet, HaveSubject, _TimeStamp, - _Size}, - B) -> - ejabberd_router:route(jid:replace_resource(StateData#state.jid, - Nick), - JID, Packet), - B or HaveSubject - end, - false, - lists:nthtail(Shift, - lqueue_to_list(StateData#state.history))). +-spec send_history(jid(), lqueue(), state()) -> boolean(). +send_history(JID, History, StateData) -> + lists:foreach( + fun({Nick, Packet, _HaveSubject, _TimeStamp, _Size}) -> + ejabberd_router:route( + jid:replace_resource(StateData#state.jid, Nick), + JID, Packet) + end, lqueue_to_list(History)). -spec send_subject(jid(), state()) -> ok. -send_subject(_JID, #state{subject_author = <<"">>}) -> ok; send_subject(JID, #state{subject_author = Nick} = StateData) -> - Subject = StateData#state.subject, - Packet = #message{type = groupchat, subject = xmpp:mk_text(Subject)}, + Subject = case StateData#state.subject of + <<"">> -> [#text{}]; + Subj -> xmpp:mk_text(Subj) + end, + Packet = #message{type = groupchat, subject = Subject}, ejabberd_router:route(jid:replace_resource(StateData#state.jid, Nick), JID, Packet). -spec check_subject(message()) -> false | binary(). -check_subject(#message{subject = []}) -> false; -check_subject(#message{subject = Subj}) -> xmpp:get_text(Subj). +check_subject(#message{subject = [_|_] = Subj, body = [], + thread = undefined}) -> + xmpp:get_text(Subj); +check_subject(_) -> + false. -spec can_change_subject(role(), state()) -> boolean(). can_change_subject(Role, StateData) -> @@ -2552,10 +2517,10 @@ items_with_role(SRole, StateData) -> items_with_affiliation(SAffiliation, StateData) -> lists:map( fun({JID, {Affiliation, Reason}}) -> - #muc_item{affiliation = Affiliation, jid = JID, + #muc_item{affiliation = Affiliation, jid = jid:make(JID), reason = Reason}; ({JID, Affiliation}) -> - #muc_item{affiliation = Affiliation, jid = JID} + #muc_item{affiliation = Affiliation, jid = jid:make(JID)} end, search_affiliation(SAffiliation, StateData)). @@ -2600,23 +2565,29 @@ process_admin_items_set(UJID, Items, Lang, StateData) -> "room ~s:~n ~p", [jid:to_string(UJID), jid:to_string(StateData#state.jid), Res]), - NSD = lists:foldl(process_item_change(UJID), - StateData, lists:flatten(Res)), - store_room(NSD), - {result, undefined, NSD}; - {error, Err} -> {error, Err} + case lists:foldl(process_item_change(UJID), + StateData, lists:flatten(Res)) of + {error, _} = Err -> + Err; + NSD -> + store_room(NSD), + {result, undefined, NSD} + end; + {error, Err} -> {error, Err} end. -spec process_item_change(jid()) -> function(). process_item_change(UJID) -> - fun(E, SD) -> - process_item_change(E, SD, UJID) + fun(_, {error, _} = Err) -> + Err; + (Item, SD) -> + process_item_change(Item, SD, UJID) end. -type admin_action() :: {jid(), affiliation | role, affiliation() | role(), binary()}. --spec process_item_change(admin_action(), state(), jid()) -> state(). +-spec process_item_change(admin_action(), state(), jid()) -> state() | {error, stanza_error()}. process_item_change(Item, SD, UJID) -> try case Item of {JID, affiliation, owner, _} when JID#jid.luser == <<"">> -> @@ -2624,23 +2595,23 @@ process_item_change(Item, SD, UJID) -> %% forget the affiliation completely SD; {JID, role, none, Reason} -> - catch send_kickban_presence(UJID, JID, Reason, 307, SD), + send_kickban_presence(UJID, JID, Reason, 307, SD), set_role(JID, none, SD); {JID, affiliation, none, Reason} -> case (SD#state.config)#config.members_only of true -> - catch send_kickban_presence(UJID, JID, Reason, 321, none, SD), + send_kickban_presence(UJID, JID, Reason, 321, none, SD), maybe_send_affiliation(JID, none, SD), SD1 = set_affiliation(JID, none, SD), set_role(JID, none, SD1); _ -> SD1 = set_affiliation(JID, none, SD), - send_update_presence(JID, SD1, SD), + send_update_presence(JID, Reason, SD1, SD), maybe_send_affiliation(JID, none, SD1), SD1 end; {JID, affiliation, outcast, Reason} -> - catch send_kickban_presence(UJID, JID, Reason, 301, outcast, SD), + send_kickban_presence(UJID, JID, Reason, 301, outcast, SD), maybe_send_affiliation(JID, outcast, SD), set_affiliation(JID, outcast, set_role(JID, none, SD), Reason); {JID, affiliation, A, Reason} when (A == admin) or (A == owner) -> @@ -2657,7 +2628,7 @@ process_item_change(Item, SD, UJID) -> SD2; {JID, role, Role, Reason} -> SD1 = set_role(JID, Role, SD), - catch send_new_presence(JID, Reason, SD1, SD), + send_new_presence(JID, Reason, SD1, SD), SD1; {JID, affiliation, A, _Reason} -> SD1 = set_affiliation(JID, A, SD), @@ -2669,7 +2640,7 @@ process_item_change(Item, SD, UJID) -> ?ERROR_MSG("failed to set item ~p from ~s: ~p", [Item, jid:to_string(UJID), {E, {R, erlang:get_stacktrace()}}]), - SD + {error, xmpp:err_internal_server_error()} end. -spec find_changed_items(jid(), affiliation(), role(), @@ -2698,12 +2669,11 @@ find_changed_items(UJID, UAffiliation, URole, Nick /= <<"">> -> case find_jids_by_nick(Nick, StateData) of [] -> - ErrText = iolist_to_binary( - io_lib:format( - translate:translate( - Lang, - <<"Nickname ~s does not exist in the room">>), - [Nick])), + ErrText = str:format( + translate:translate( + Lang, + <<"Nickname ~s does not exist in the room">>), + [Nick]), throw({error, xmpp:err_not_acceptable(ErrText, Lang)}); JIDList -> JIDList @@ -2740,9 +2710,15 @@ find_changed_items(UJID, UAffiliation, URole, Items, Lang, StateData, Res); true -> - MoreRes = [{jid:remove_resource(Jidx), - RoleOrAff, RoleOrAffValue, Reason} - || Jidx <- JIDs], + MoreRes = case RoleOrAff of + affiliation -> + [{jid:remove_resource(Jidx), + RoleOrAff, RoleOrAffValue, Reason} + || Jidx <- JIDs]; + role -> + [{Jidx, RoleOrAff, RoleOrAffValue, Reason} + || Jidx <- JIDs] + end, find_changed_items(UJID, UAffiliation, URole, Items, Lang, StateData, [MoreRes | Res]); @@ -2925,12 +2901,13 @@ send_kickban_presence1(MJID, UJID, Reason, Code, Affiliation, StateData#state.users), ActorNick = get_actor_nick(MJID, StateData), lists:foreach( - fun({_LJID, Info}) -> + fun({LJID, Info}) -> + IsSelfPresence = jid:tolower(UJID) == LJID, Item0 = #muc_item{affiliation = Affiliation, role = none}, Item1 = case Info#user.role == moderator orelse (StateData#state.config)#config.anonymous - == false of + == false orelse IsSelfPresence of true -> Item0#muc_item{jid = RealJID}; false -> Item0 end, @@ -2939,9 +2916,12 @@ send_kickban_presence1(MJID, UJID, Reason, Code, Affiliation, <<"">> -> Item2; _ -> Item2#muc_item{actor = #muc_actor{nick = ActorNick}} end, + Codes = if IsSelfPresence -> [110, Code]; + true -> [Code] + end, Packet = #presence{type = unavailable, sub_els = [#muc_user{items = [Item], - status_codes = [Code]}]}, + status_codes = Codes}]}, RoomJIDNick = jid:replace_resource(StateData#state.jid, Nick), send_wrapped(RoomJIDNick, Info#user.jid, Packet, ?NS_MUCSUB_NODES_AFFILIATIONS, StateData), @@ -2989,13 +2969,21 @@ process_iq_owner(From, #iq{type = set, lang = Lang, case Config of #xdata{type = cancel} -> {result, undefined}; - #xdata{type = submit} -> - case is_allowed_log_change(Config, StateData, From) andalso - is_allowed_persistent_change(Config, StateData, From) andalso - is_allowed_room_name_desc_limits(Config, StateData) andalso - is_password_settings_correct(Config, StateData) of - true -> set_config(Config, StateData, Lang); - false -> {error, xmpp:err_not_acceptable()} + #xdata{type = submit, fields = Fs} -> + try muc_roomconfig:decode(Fs) of + Options -> + case is_allowed_log_change(Options, StateData, From) andalso + is_allowed_persistent_change(Options, StateData, From) andalso + is_allowed_room_name_desc_limits(Options, StateData) andalso + is_password_settings_correct(Options, StateData) of + true -> + set_config(Options, StateData, Lang); + false -> + {error, xmpp:err_not_acceptable()} + end + catch _:{muc_roomconfig, Why} -> + Txt = muc_roomconfig:format_error(Why), + {error, xmpp:err_bad_request(Txt, Lang)} end; _ -> Txt = <<"Incorrect data form">>, @@ -3034,9 +3022,9 @@ process_iq_owner(From, #iq{type = get, lang = Lang, {error, xmpp:err_bad_request()} end. --spec is_allowed_log_change(xdata(), state(), jid()) -> boolean(). -is_allowed_log_change(X, StateData, From) -> - case xmpp_util:has_xdata_var(<<"muc#roomconfig_enablelogging">>, X) of +-spec is_allowed_log_change(muc_roomconfig:result(), state(), jid()) -> boolean(). +is_allowed_log_change(Options, StateData, From) -> + case proplists:is_defined(enablelogging, Options) of false -> true; true -> allow == @@ -3044,9 +3032,9 @@ is_allowed_log_change(X, StateData, From) -> From) end. --spec is_allowed_persistent_change(xdata(), state(), jid()) -> boolean(). -is_allowed_persistent_change(X, StateData, From) -> - case xmpp_util:has_xdata_var(<<"muc#roomconfig_persistentroom">>, X) of +-spec is_allowed_persistent_change(muc_roomconfig:result(), state(), jid()) -> boolean(). +is_allowed_persistent_change(Options, StateData, From) -> + case proplists:is_defined(persistentroom, Options) of false -> true; true -> {_AccessRoute, _AccessCreate, _AccessAdmin, @@ -3059,66 +3047,43 @@ is_allowed_persistent_change(X, StateData, From) -> %% Check if the Room Name and Room Description defined in the Data Form %% are conformant to the configured limits --spec is_allowed_room_name_desc_limits(xdata(), state()) -> boolean(). -is_allowed_room_name_desc_limits(XData, StateData) -> - IsNameAccepted = case xmpp_util:get_xdata_values( - <<"muc#roomconfig_roomname">>, XData) of - [N] -> - byte_size(N) =< - gen_mod:get_module_opt( - StateData#state.server_host, - mod_muc, max_room_name, - fun(infinity) -> infinity; - (I) when is_integer(I), - I>0 -> I - end, infinity); - _ -> - true - end, - IsDescAccepted = case xmpp_util:get_xdata_values( - <<"muc#roomconfig_roomdesc">>, XData) of - [D] -> - byte_size(D) =< - gen_mod:get_module_opt( - StateData#state.server_host, - mod_muc, max_room_desc, - fun(infinity) -> infinity; - (I) when is_integer(I), - I>0 -> - I - end, infinity); - _ -> true - end, - IsNameAccepted and IsDescAccepted. +-spec is_allowed_room_name_desc_limits(muc_roomconfig:result(), state()) -> boolean(). +is_allowed_room_name_desc_limits(Options, StateData) -> + RoomName = proplists:get_value(roomname, Options, <<"">>), + RoomDesc = proplists:get_value(roomdesc, Options, <<"">>), + MaxRoomName = gen_mod:get_module_opt( + StateData#state.server_host, + mod_muc, max_room_name, + fun(infinity) -> infinity; + (I) when is_integer(I), + I>0 -> I + end, infinity), + MaxRoomDesc = gen_mod:get_module_opt( + StateData#state.server_host, + mod_muc, max_room_desc, + fun(infinity) -> infinity; + (I) when is_integer(I), + I>0 -> + I + end, infinity), + (byte_size(RoomName) =< MaxRoomName) + andalso (byte_size(RoomDesc) =< MaxRoomDesc). %% Return false if: %% "the password for a password-protected room is blank" --spec is_password_settings_correct(xdata(), state()) -> boolean(). -is_password_settings_correct(XData, StateData) -> +-spec is_password_settings_correct(muc_roomconfig:result(), state()) -> boolean(). +is_password_settings_correct(Options, StateData) -> Config = StateData#state.config, OldProtected = Config#config.password_protected, OldPassword = Config#config.password, - NewProtected = case xmpp_util:get_xdata_values( - <<"muc#roomconfig_passwordprotectedroom">>, XData) of - [<<"1">>] -> true; - [<<"true">>] -> true; - [<<"0">>] -> false; - [<<"false">>] -> false; - _ -> undefined - end, - NewPassword = case xmpp_util:get_xdata_values( - <<"muc#roomconfig_roomsecret">>, XData) of - [P] -> P; - _ -> undefined - end, - case {OldProtected, NewProtected, OldPassword, - NewPassword} - of - {true, undefined, <<"">>, undefined} -> false; - {true, undefined, _, <<"">>} -> false; - {_, true, <<"">>, undefined} -> false; - {_, true, _, <<"">>} -> false; - _ -> true + NewProtected = proplists:get_value(passwordprotectedroom, Options), + NewPassword = proplists:get_value(roomsecret, Options), + case {OldProtected, NewProtected, OldPassword, NewPassword} of + {true, undefined, <<"">>, undefined} -> false; + {true, undefined, _, <<"">>} -> false; + {_, true, <<"">>, undefined} -> false; + {_, true, _, <<"">>} -> false; + _ -> true end. -spec get_default_room_maxusers(state()) -> non_neg_integer(). @@ -3144,10 +3109,9 @@ get_config(Lang, StateData, From) -> {N, N}; _ -> {0, none} end, - Title = iolist_to_binary( - io_lib:format( - translate:translate(Lang, <<"Configuration of room ~s">>), - [jid:to_string(StateData#state.jid)])), + Title = str:format( + translate:translate(Lang, <<"Configuration of room ~s">>), + [jid:to_string(StateData#state.jid)]), Fs = [{roomname, Config#config.title}, {roomdesc, Config#config.description}] ++ case acl:match_rule(StateData#state.server_host, AccessPersistent, From) of @@ -3208,11 +3172,10 @@ get_config(Lang, StateData, From) -> fields = muc_roomconfig:encode( Fields, fun(T) -> translate:translate(Lang, T) end)}. --spec set_config(xdata(), state(), binary()) -> {error, stanza_error()} | - {result, undefined, state()}. -set_config(#xdata{fields = Fields}, StateData, Lang) -> +-spec set_config(muc_roomconfig:result(), state(), binary()) -> + {error, stanza_error()} | {result, undefined, state()}. +set_config(Options, StateData, Lang) -> try - Options = muc_roomconfig:decode(Fields), #config{} = Config = set_config(Options, StateData#state.config, StateData#state.server_host, Lang), {result, _, NSD} = Res = change_config(Config, StateData), @@ -3227,10 +3190,7 @@ set_config(#xdata{fields = Fields}, StateData, Lang) -> || {_, U} <- (?DICT):to_list(StateData#state.users)], add_to_log(Type, Users, NSD), Res - catch _:{muc_roomconfig, Why} -> - Txt = muc_roomconfig:format_error(Why), - {error, xmpp:err_bad_request(Txt, Lang)}; - _:{badmatch, {error, #stanza_error{}} = Err} -> + catch _:{badmatch, {error, #stanza_error{}} = Err} -> Err end. @@ -3331,18 +3291,23 @@ send_config_change_info(New, #state{config = Old} = StateData) -> end ++ case Old#config{anonymous = New#config.anonymous, + vcard = New#config.vcard, logging = New#config.logging} of New -> []; _ -> [104] end, - Message = #message{type = groupchat, - id = randoms:get_string(), - sub_els = [#muc_user{status_codes = Codes}]}, - send_wrapped_multiple(StateData#state.jid, - StateData#state.users, - Message, - ?NS_MUCSUB_NODES_CONFIG, - StateData). + if Codes /= [] -> + Message = #message{type = groupchat, + id = randoms:get_string(), + sub_els = [#muc_user{status_codes = Codes}]}, + send_wrapped_multiple(StateData#state.jid, + StateData#state.users, + Message, + ?NS_MUCSUB_NODES_CONFIG, + StateData); + true -> + ok + end. -spec remove_nonmembers(state()) -> state(). remove_nonmembers(StateData) -> @@ -3620,7 +3585,7 @@ iq_disco_info_extras(Lang, StateData) -> process_iq_disco_items(_From, #iq{type = set, lang = Lang}, _StateData) -> Txt = <<"Value 'set' of 'type' attribute is not allowed">>, {error, xmpp:err_not_allowed(Txt, Lang)}; -process_iq_disco_items(From, #iq{type = get, lang = Lang}, StateData) -> +process_iq_disco_items(From, #iq{type = get}, StateData) -> case (StateData#state.config)#config.public_list of true -> {result, get_mucroom_disco_items(StateData)}; @@ -3629,8 +3594,10 @@ process_iq_disco_items(From, #iq{type = get, lang = Lang}, StateData) -> true -> {result, get_mucroom_disco_items(StateData)}; _ -> - Txt = <<"Only occupants or administrators can perform this query">>, - {error, xmpp:err_forbidden(Txt, Lang)} + %% If the list of occupants is private, + %% the room MUST return an empty element + %% (http://xmpp.org/extensions/xep-0045.html#disco-roomitems) + {result, #disco_items{}} end end. @@ -3661,7 +3628,7 @@ process_iq_vcard(_From, #iq{type = get}, StateData) -> #xmlel{} = VCard -> {result, VCard}; {error, _} -> - {result, #vcard_temp{}} + {error, xmpp:err_item_not_found()} end; process_iq_vcard(From, #iq{type = set, lang = Lang, sub_els = [SubEl]}, StateData) -> @@ -3801,8 +3768,7 @@ get_roomdesc_tail(StateData, Lang) -> _ -> translate:translate(Lang, <<"private, ">>) end, Len = (?DICT):size(StateData#state.users), - <<" (", Desc/binary, - (iolist_to_binary(integer_to_list(Len)))/binary, ")">>. + <<" (", Desc/binary, (integer_to_binary(Len))/binary, ")">>. -spec get_mucroom_disco_items(state()) -> disco_items(). get_mucroom_disco_items(StateData) -> diff --git a/src/str.erl b/src/str.erl index 27d21075a..439ae6a7a 100644 --- a/src/str.erl +++ b/src/str.erl @@ -64,6 +64,7 @@ to_float/1, prefix/2, suffix/2, + format/2, to_integer/1]). %%%=================================================================== @@ -277,6 +278,11 @@ prefix(Prefix, B) -> suffix(B1, B2) -> lists:suffix(binary_to_list(B1), binary_to_list(B2)). +-spec format(io:format(), list()) -> binary(). + +format(Format, Args) -> + iolist_to_binary(io_lib:format(Format, Args)). + %%%=================================================================== %%% Internal functions %%%=================================================================== diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index b4249bbdf..1a5c89076 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -10,23 +10,23 @@ -compile(export_all). --import(suite, [init_config/1, connect/1, disconnect/1, - recv/1, send/2, send_recv/2, my_jid/1, server_jid/1, - pubsub_jid/1, proxy_jid/1, muc_jid/1, muc_room_jid/1, - mix_jid/1, mix_room_jid/1, get_features/2, re_register/1, - is_feature_advertised/2, subscribe_to_events/1, +-import(suite, [init_config/1, connect/1, disconnect/1, recv_message/1, + recv/1, recv_presence/1, send/2, send_recv/2, my_jid/1, + server_jid/1, pubsub_jid/1, proxy_jid/1, muc_jid/1, + muc_room_jid/1, my_muc_jid/1, peer_muc_jid/1, + mix_jid/1, mix_room_jid/1, get_features/2, recv_iq/1, + re_register/1, is_feature_advertised/2, subscribe_to_events/1, is_feature_advertised/3, set_opt/3, auth_SASL/2, - wait_for_master/1, wait_for_slave/1, - make_iq_result/1, start_event_relay/0, + wait_for_master/1, wait_for_slave/1, flush/1, + make_iq_result/1, start_event_relay/0, alt_room_jid/1, stop_event_relay/1, put_event/2, get_event/1, bind/1, auth/1, auth/2, open_session/1, open_session/2, zlib/1, starttls/1, starttls/2, close_socket/1, init_stream/1, auth_legacy/2, auth_legacy/3, tcp_connect/1, send_text/2]). - -include("suite.hrl"). suite() -> - [{timetrap, {seconds,60}}]. + [{timetrap, {seconds, 30}}]. init_per_suite(Config) -> NewConfig = init_config(Config), @@ -83,7 +83,7 @@ init_per_group(Group, Config) -> do_init_per_group(no_db, Config) -> re_register(Config), - Config; + set_opt(persistent_room, false, Config); do_init_per_group(mnesia, Config) -> mod_muc:shutdown_rooms(?MNESIA_VHOST), set_opt(server, ?MNESIA_VHOST, Config); @@ -202,6 +202,10 @@ init_per_testcase(TestCase, OrigConfig) -> Test = atom_to_list(TestCase), IsMaster = lists:suffix("_master", Test), IsSlave = lists:suffix("_slave", Test), + Mode = if IsSlave -> slave; + IsMaster -> master; + true -> single + end, IsCarbons = lists:prefix("carbons_", Test), IsReplaced = lists:prefix("replaced_", Test), User = if IsReplaced -> <<"test_single!#$%^*()`~+-;_=[]{}|\\">>; @@ -209,6 +213,10 @@ init_per_testcase(TestCase, OrigConfig) -> IsSlave -> <<"test_slave!#$%^*()`~+-;_=[]{}|\\">>; true -> <<"test_single!#$%^*()`~+-;_=[]{}|\\">> end, + Nick = if IsSlave -> ?config(slave_nick, OrigConfig); + IsMaster -> ?config(master_nick, OrigConfig); + true -> ?config(nick, OrigConfig) + end, MyResource = if IsMaster and IsCarbons -> MasterResource; IsSlave and IsCarbons -> SlaveResource; true -> Resource @@ -227,10 +235,23 @@ init_per_testcase(TestCase, OrigConfig) -> true -> jid:make(<<"test_master!#$%^*()`~+-;_=[]{}|\\">>, Server, Resource) end, - Config = set_opt(user, User, - set_opt(slave, Slave, - set_opt(master, Master, - set_opt(resource, MyResource, OrigConfig)))), + Config1 = set_opt(user, User, + set_opt(slave, Slave, + set_opt(master, Master, + set_opt(resource, MyResource, + set_opt(nick, Nick, + set_opt(mode, Mode, OrigConfig)))))), + Config2 = if IsSlave -> + set_opt(peer_nick, ?config(master_nick, Config1), Config1); + IsMaster -> + set_opt(peer_nick, ?config(slave_nick, Config1), Config1); + true -> + Config1 + end, + Config = if IsSlave -> set_opt(peer, Master, Config2); + IsMaster -> set_opt(peer, Slave, Config2); + true -> Config2 + end, case Test of "test_connect" ++ _ -> Config; @@ -320,6 +341,8 @@ no_db_tests() -> [sm, sm_resume, sm_resume_failed]}, + muc_tests:single_cases(), + muc_tests:master_slave_cases(), {test_proxy65, [parallel], [proxy65_master, proxy65_slave]}, {replaced, [parallel], @@ -369,9 +392,9 @@ db_tests(riak) -> privacy, blocking, vcard, + muc_tests:single_cases(), test_unregister]}, - {test_muc_register, [parallel], - [muc_register_master, muc_register_slave]}, + muc_tests:master_slave_cases(), {test_roster_subscribe, [parallel], [roster_subscribe_master, roster_subscribe_slave]}, @@ -379,8 +402,6 @@ db_tests(riak) -> [flex_offline_master, flex_offline_slave]}, {test_offline, [sequence], [offline_master, offline_slave]}, - {test_muc, [parallel], - [muc_master, muc_slave]}, {test_announce, [sequence], [announce_master, announce_slave]}, {test_vcard_xupdate, [parallel], @@ -403,10 +424,10 @@ db_tests(DB) when DB == mnesia; DB == redis -> blocking, vcard, pubsub_single_tests(), + muc_tests:single_cases(), test_unregister]}, + muc_tests:master_slave_cases(), pubsub_multiple_tests(), - {test_muc_register, [parallel], - [muc_register_master, muc_register_slave]}, {test_mix, [parallel], [mix_master, mix_slave]}, {test_roster_subscribe, [parallel], @@ -424,8 +445,6 @@ db_tests(DB) when DB == mnesia; DB == redis -> [carbons_master, carbons_slave]}, {test_client_state, [parallel], [client_state_master, client_state_slave]}, - {test_muc, [parallel], - [muc_master, muc_slave]}, {test_muc_mam, [parallel], [muc_mam_master, muc_mam_slave]}, {test_announce, [sequence], @@ -440,21 +459,21 @@ db_tests(_) -> [{single_user, [sequence], [test_register, legacy_auth_tests(), - auth_plain, - auth_md5, - presence_broadcast, - last, - roster_get, - roster_ver, - private, - privacy, - blocking, - vcard, - pubsub_single_tests(), - test_unregister]}, + auth_plain, + auth_md5, + presence_broadcast, + last, + roster_get, + roster_ver, + private, + privacy, + blocking, + vcard, + pubsub_single_tests(), + muc_tests:single_cases(), + test_unregister]}, + muc_tests:master_slave_cases(), pubsub_multiple_tests(), - {test_muc_register, [parallel], - [muc_register_master, muc_register_slave]}, {test_mix, [parallel], [mix_master, mix_slave]}, {test_roster_subscribe, [parallel], @@ -468,8 +487,6 @@ db_tests(_) -> [mam_old_master, mam_old_slave]}, {test_new_mam, [parallel], [mam_new_master, mam_new_slave]}, - {test_muc, [parallel], - [muc_master, muc_slave]}, {test_muc_mam, [parallel], [muc_mam_master, muc_mam_slave]}, {test_announce, [sequence], @@ -604,7 +621,8 @@ test_connect_bad_ns_stream(Config) -> close_socket(Config0). test_connect_bad_lang(Config) -> - Config0 = init_stream(set_opt(lang, lists:duplicate(36, $x), Config)), + Lang = iolist_to_binary(lists:duplicate(36, $x)), + Config0 = init_stream(set_opt(lang, Lang, Config)), ?recv1(#stream_error{reason = 'policy-violation'}), ?recv1({xmlstreamend, <<"stream:stream">>}), close_socket(Config0). @@ -2272,352 +2290,151 @@ muc_mam_master(Config) -> muc_mam_slave(Config) -> disconnect(Config). -muc_master(Config) -> - MyJID = my_jid(Config), - PeerJID = ?config(slave, Config), - PeerBareJID = jid:remove_resource(PeerJID), - PeerJIDStr = jid:to_string(PeerJID), - MUC = muc_jid(Config), - Room = muc_room_jid(Config), - MyNick = ?config(master_nick, Config), - MyNickJID = jid:replace_resource(Room, MyNick), - PeerNick = ?config(slave_nick, Config), - PeerNickJID = jid:replace_resource(Room, PeerNick), - Subject = ?config(room_subject, Config), - Localhost = jid:make(<<"">>, <<"localhost">>, <<"">>), - true = is_feature_advertised(Config, ?NS_MUC, MUC), - %% Joining - send(Config, #presence{to = MyNickJID, sub_els = [#muc{}]}), - %% As per XEP-0045 we MUST receive stanzas in the following order: - %% 1. In-room presence from other occupants - %% 2. In-room presence from the joining entity itself (so-called "self-presence") - %% 3. Room history (if any) - %% 4. The room subject - %% 5. Live messages, presence updates, new user joins, etc. - %% As this is the newly created room, we receive only the 2nd stanza. - #muc_user{ - status_codes = Codes, - items = [#muc_item{role = moderator, - jid = MyJID, - affiliation = owner}]} = - xmpp:get_subtag(?recv1(#presence{from = MyNickJID}), #muc_user{}), - %% 110 -> Inform user that presence refers to itself - %% 201 -> Inform user that a new room has been created - [110, 201] = lists:sort(Codes), - %% Request the configuration - #iq{type = result, sub_els = [#muc_owner{config = #xdata{} = RoomCfg}]} = - send_recv(Config, #iq{type = get, sub_els = [#muc_owner{}], - to = Room}), - NewFields = - lists:flatmap( - fun(#xdata_field{var = Var, values = OrigVals}) -> - Vals = case Var of - <<"FORM_TYPE">> -> - OrigVals; - <<"muc#roomconfig_roomname">> -> - [<<"Test room">>]; - <<"muc#roomconfig_roomdesc">> -> - [<<"Trying to break the server">>]; - <<"muc#roomconfig_persistentroom">> -> - [<<"1">>]; - <<"members_by_default">> -> - [<<"0">>]; - <<"muc#roomconfig_allowvoicerequests">> -> - [<<"1">>]; - <<"public_list">> -> - [<<"1">>]; - <<"muc#roomconfig_publicroom">> -> - [<<"1">>]; - _ -> - [] - end, - if Vals /= [] -> - [#xdata_field{values = Vals, var = Var}]; - true -> - [] - end - end, RoomCfg#xdata.fields), - NewRoomCfg = #xdata{type = submit, fields = NewFields}, - ID = send(Config, #iq{type = set, to = Room, - sub_els = [#muc_owner{config = NewRoomCfg}]}), - ?recv2(#iq{type = result, id = ID}, - #message{from = Room, type = groupchat, - sub_els = [#muc_user{status_codes = [104]}]}), - %% Set subject - send(Config, #message{to = Room, type = groupchat, - body = [#text{data = Subject}]}), - ?recv1(#message{from = MyNickJID, type = groupchat, - body = [#text{data = Subject}]}), - %% Sending messages (and thus, populating history for our peer) - lists:foreach( - fun(N) -> - Text = #text{data = integer_to_binary(N)}, - I = send(Config, #message{to = Room, body = [Text], - type = groupchat}), - ?recv1(#message{from = MyNickJID, id = I, - type = groupchat, - body = [Text]}) - end, lists:seq(1, 5)), - %% Inviting the peer - send(Config, #message{to = Room, type = normal, - sub_els = - [#muc_user{ - invites = - [#muc_invite{to = PeerJID}]}]}), - #muc_user{ - items = [#muc_item{role = visitor, - jid = PeerJID, - affiliation = none}]} = - xmpp:get_subtag(?recv1(#presence{from = PeerNickJID}), #muc_user{}), - %% Receiving a voice request - #message{from = Room, - sub_els = [#xdata{type = form, - instructions = [_], - fields = VoiceReqFs}]} = recv(Config), - %% Approving the voice request - ReplyVoiceReqFs = - lists:map( - fun(#xdata_field{var = Var, values = OrigVals}) -> - Vals = case {Var, OrigVals} of - {<<"FORM_TYPE">>, - [<<"http://jabber.org/protocol/muc#request">>]} -> - OrigVals; - {<<"muc#role">>, [<<"participant">>]} -> - [<<"participant">>]; - {<<"muc#jid">>, [PeerJIDStr]} -> - [PeerJIDStr]; - {<<"muc#roomnick">>, [PeerNick]} -> - [PeerNick]; - {<<"muc#request_allow">>, [<<"0">>]} -> - [<<"1">>] - end, - #xdata_field{values = Vals, var = Var} - end, VoiceReqFs), - send(Config, #message{to = Room, - sub_els = [#xdata{type = submit, - fields = ReplyVoiceReqFs}]}), - %% Peer is becoming a participant - #muc_user{items = [#muc_item{role = participant, - jid = PeerJID, - affiliation = none}]} = - xmpp:get_subtag(?recv1(#presence{from = PeerNickJID}), #muc_user{}), - %% Receive private message from the peer - ?recv1(#message{from = PeerNickJID, body = [#text{data = Subject}]}), - %% Granting membership to the peer and localhost server - I1 = send(Config, - #iq{type = set, to = Room, - sub_els = - [#muc_admin{ - items = [#muc_item{jid = Localhost, - affiliation = member}, - #muc_item{nick = PeerNick, - jid = PeerBareJID, - affiliation = member}]}]}), - %% Peer became a member - #muc_user{items = [#muc_item{affiliation = member, - jid = PeerJID, - role = participant}]} = - xmpp:get_subtag(?recv1(#presence{from = PeerNickJID}), #muc_user{}), - ?recv1(#message{from = Room, - sub_els = [#muc_user{ - items = [#muc_item{affiliation = member, - jid = Localhost, - role = none}]}]}), - ?recv1(#iq{type = result, id = I1, sub_els = []}), - %% Receive groupchat message from the peer - ?recv1(#message{type = groupchat, from = PeerNickJID, - body = [#text{data = Subject}]}), - %% Retrieving a member list - #iq{type = result, sub_els = [#muc_admin{items = MemberList}]} = - send_recv(Config, - #iq{type = get, to = Room, - sub_els = - [#muc_admin{items = [#muc_item{affiliation = member}]}]}), - [#muc_item{affiliation = member, - jid = Localhost}, - #muc_item{affiliation = member, - jid = PeerBareJID}] = lists:keysort(#muc_item.jid, MemberList), - %% Kick the peer - I2 = send(Config, - #iq{type = set, to = Room, - sub_els = [#muc_admin{ - items = [#muc_item{nick = PeerNick, - role = none}]}]}), - %% Got notification the peer is kicked - %% 307 -> Inform user that he or she has been kicked from the room - ?recv1(#presence{from = PeerNickJID, type = unavailable, - sub_els = [#muc_user{ - status_codes = [307], - items = [#muc_item{affiliation = member, - jid = PeerJID, - role = none}]}]}), - ?recv1(#iq{type = result, id = I2, sub_els = []}), - %% Destroying the room - I3 = send(Config, - #iq{type = set, to = Room, - sub_els = [#muc_owner{ - destroy = #muc_destroy{ - reason = Subject}}]}), - %% Kicked off - ?recv1(#presence{from = MyNickJID, type = unavailable, - sub_els = [#muc_user{items = [#muc_item{role = none, - affiliation = none}], - destroy = #muc_destroy{ - reason = Subject}}]}), - ?recv1(#iq{type = result, id = I3, sub_els = []}), - disconnect(Config). - -muc_slave(Config) -> - PeerJID = ?config(master, Config), - MUC = muc_jid(Config), - Room = muc_room_jid(Config), - MyNick = ?config(slave_nick, Config), - MyNickJID = jid:replace_resource(Room, MyNick), - PeerNick = ?config(master_nick, Config), - PeerNickJID = jid:replace_resource(Room, PeerNick), - Subject = ?config(room_subject, Config), - %% Receive an invite from the peer - #muc_user{invites = [#muc_invite{from = PeerJID}]} = - xmpp:get_subtag(?recv1(#message{from = Room, type = normal}), - #muc_user{}), - %% But before joining we discover the MUC service first - %% to check if the room is in the disco list - #iq{type = result, - sub_els = [#disco_items{items = [#disco_item{jid = Room}]}]} = - send_recv(Config, #iq{type = get, to = MUC, - sub_els = [#disco_items{}]}), - %% Now check if the peer is in the room. We check this via disco#items - #iq{type = result, - sub_els = [#disco_items{items = [#disco_item{jid = PeerNickJID, - name = PeerNick}]}]} = - send_recv(Config, #iq{type = get, to = Room, - sub_els = [#disco_items{}]}), - %% Now joining - send(Config, #presence{to = MyNickJID, sub_els = [#muc{}]}), - %% First presence is from the participant, i.e. from the peer - #muc_user{ - status_codes = [], - items = [#muc_item{role = moderator, - affiliation = owner}]} = - xmpp:get_subtag(?recv1(#presence{from = PeerNickJID}), #muc_user{}), - %% The next is the self-presence (code 110 means it) - #muc_user{status_codes = [110], - items = [#muc_item{role = visitor, - affiliation = none}]} = - xmpp:get_subtag(?recv1(#presence{from = MyNickJID}), #muc_user{}), - %% Receive the room subject - ?recv1(#message{from = PeerNickJID, type = groupchat, - body = [#text{data = Subject}], - sub_els = [#delay{}]}), - %% Receive MUC history - lists:foreach( - fun(N) -> - Text = #text{data = integer_to_binary(N)}, - ?recv1(#message{from = PeerNickJID, - type = groupchat, - body = [Text], - sub_els = [#delay{}]}) - end, lists:seq(1, 5)), - %% Sending a voice request - VoiceReq = #xdata{ - type = submit, - fields = - [#xdata_field{ - var = <<"FORM_TYPE">>, - values = [<<"http://jabber.org/protocol/muc#request">>]}, - #xdata_field{ - var = <<"muc#role">>, - type = 'text-single', - values = [<<"participant">>]}]}, - send(Config, #message{to = Room, sub_els = [VoiceReq]}), - %% Becoming a participant - #muc_user{items = [#muc_item{role = participant, - affiliation = none}]} = - xmpp:get_subtag(?recv1(#presence{from = MyNickJID}), #muc_user{}), - %% Sending private message to the peer - send(Config, #message{to = PeerNickJID, - body = [#text{data = Subject}]}), - %% Becoming a member - #muc_user{items = [#muc_item{role = participant, - affiliation = member}]} = - xmpp:get_subtag(?recv1(#presence{from = MyNickJID}), #muc_user{}), - %% Sending groupchat message - send(Config, #message{to = Room, type = groupchat, - body = [#text{data = Subject}]}), - %% Receive this message back - ?recv1(#message{type = groupchat, from = MyNickJID, - body = [#text{data = Subject}]}), - %% We're kicked off - %% 307 -> Inform user that he or she has been kicked from the room - ?recv1(#presence{from = MyNickJID, type = unavailable, - sub_els = [#muc_user{ - status_codes = [307], - items = [#muc_item{affiliation = member, - role = none}]}]}), - disconnect(Config). - -muc_register_nick(Config, MUC, PrevNick, Nick) -> - PrevRegistered = if PrevNick /= <<"">> -> true; - true -> false - end, - NewRegistered = if Nick /= <<"">> -> true; - true -> false - end, - %% Request register form - #iq{type = result, - sub_els = [#register{registered = PrevRegistered, - xdata = #xdata{type = form, - fields = FsWithoutNick}}]} = - send_recv(Config, #iq{type = get, to = MUC, - sub_els = [#register{}]}), - %% Check if previous nick is registered - PrevNick = proplists:get_value( - roomnick, muc_register:decode(FsWithoutNick)), - X = #xdata{type = submit, fields = muc_register:encode([{roomnick, Nick}])}, - %% Submitting form - #iq{type = result, sub_els = []} = - send_recv(Config, #iq{type = set, to = MUC, - sub_els = [#register{xdata = X}]}), - %% Check if new nick was registered - #iq{type = result, - sub_els = [#register{registered = NewRegistered, - xdata = #xdata{type = form, - fields = FsWithNick}}]} = - send_recv(Config, #iq{type = get, to = MUC, - sub_els = [#register{}]}), - Nick = proplists:get_value( - roomnick, muc_register:decode(FsWithNick)). +%% OK, I know this is retarded, but I didn't find a better way to +%% split the test cases into different modules +muc_service_presence_error(Config) -> + muc_tests:muc_service_presence_error(Config). +muc_service_message_error(Config) -> + muc_tests:muc_service_message_error(Config). +muc_service_unknown_ns_iq_error(Config) -> + muc_tests:muc_service_unknown_ns_iq_error(Config). +muc_service_iq_set_error(Config) -> + muc_tests:muc_service_iq_set_error(Config). +muc_service_improper_iq_error(Config) -> + muc_tests:muc_service_improper_iq_error(Config). +muc_service_features(Config) -> + muc_tests:muc_service_features(Config). +muc_service_disco_info_node_error(Config) -> + muc_tests:muc_service_disco_info_node_error(Config). +muc_service_disco_items(Config) -> + muc_tests:muc_service_disco_items(Config). +muc_service_vcard(Config) -> + muc_tests:muc_service_vcard(Config). +muc_service_unique(Config) -> + muc_tests:muc_service_unique(Config). +muc_service_subscriptions(Config) -> + muc_tests:muc_service_subscriptions(Config). +muc_configure_non_existent(Config) -> + muc_tests:muc_configure_non_existent(Config). +muc_cancel_configure_non_existent(Config) -> + muc_tests:muc_cancel_configure_non_existent(Config). muc_register_master(Config) -> - MUC = muc_jid(Config), - %% Register nick "master1" - muc_register_nick(Config, MUC, <<"">>, <<"master1">>), - %% Unregister nick "master1" via jabber:register - #iq{type = result, sub_els = []} = - send_recv(Config, #iq{type = set, to = MUC, - sub_els = [#register{remove = true}]}), - %% Register nick "master2" - muc_register_nick(Config, MUC, <<"">>, <<"master2">>), - %% Now register nick "master" - muc_register_nick(Config, MUC, <<"master2">>, <<"master">>), - %% Wait for slave to fail trying to register nick "master" - wait_for_slave(Config), - wait_for_slave(Config), - %% Now register empty ("") nick, which means we're unregistering - muc_register_nick(Config, MUC, <<"master">>, <<"">>), - disconnect(Config). - + muc_tests:muc_register_master(Config). muc_register_slave(Config) -> - MUC = muc_jid(Config), - wait_for_master(Config), - %% Trying to register occupied nick "master" - Fs = muc_register:encode([{roomnick, <<"master">>}]), - X = #xdata{type = submit, fields = Fs}, - #iq{type = error} = - send_recv(Config, #iq{type = set, to = MUC, - sub_els = [#register{xdata = X}]}), - wait_for_master(Config), - disconnect(Config). + muc_tests:muc_register_slave(Config). +muc_join_conflict_master(Config) -> + muc_tests:muc_join_conflict_master(Config). +muc_join_conflict_slave(Config) -> + muc_tests:muc_join_conflict_slave(Config). +muc_groupchat_msg_master(Config) -> + muc_tests:muc_groupchat_msg_master(Config). +muc_groupchat_msg_slave(Config) -> + muc_tests:muc_groupchat_msg_slave(Config). +muc_private_msg_master(Config) -> + muc_tests:muc_private_msg_master(Config). +muc_private_msg_slave(Config) -> + muc_tests:muc_private_msg_slave(Config). +muc_set_subject_master(Config) -> + muc_tests:muc_set_subject_master(Config). +muc_set_subject_slave(Config) -> + muc_tests:muc_set_subject_slave(Config). +muc_history_master(Config) -> + muc_tests:muc_history_master(Config). +muc_history_slave(Config) -> + muc_tests:muc_history_slave(Config). +muc_invite_master(Config) -> + muc_tests:muc_invite_master(Config). +muc_invite_slave(Config) -> + muc_tests:muc_invite_slave(Config). +muc_invite_members_only_master(Config) -> + muc_tests:muc_invite_members_only_master(Config). +muc_invite_members_only_slave(Config) -> + muc_tests:muc_invite_members_only_slave(Config). +muc_invite_password_protected_master(Config) -> + muc_tests:muc_invite_password_protected_master(Config). +muc_invite_password_protected_slave(Config) -> + muc_tests:muc_invite_password_protected_slave(Config). +muc_voice_request_master(Config) -> + muc_tests:muc_voice_request_master(Config). +muc_voice_request_slave(Config) -> + muc_tests:muc_voice_request_slave(Config). +muc_change_role_master(Config) -> + muc_tests:muc_change_role_master(Config). +muc_change_role_slave(Config) -> + muc_tests:muc_change_role_slave(Config). +muc_kick_master(Config) -> + muc_tests:muc_kick_master(Config). +muc_kick_slave(Config) -> + muc_tests:muc_kick_slave(Config). +muc_change_affiliation_master(Config) -> + muc_tests:muc_change_affiliation_master(Config). +muc_change_affiliation_slave(Config) -> + muc_tests:muc_change_affiliation_slave(Config). +muc_destroy_master(Config) -> + muc_tests:muc_destroy_master(Config). +muc_destroy_slave(Config) -> + muc_tests:muc_destroy_slave(Config). +muc_vcard_master(Config) -> + muc_tests:muc_vcard_master(Config). +muc_vcard_slave(Config) -> + muc_tests:muc_vcard_slave(Config). +muc_nick_change_master(Config) -> + muc_tests:muc_nick_change_master(Config). +muc_nick_change_slave(Config) -> + muc_tests:muc_nick_change_slave(Config). +muc_config_title_desc_master(Config) -> + muc_tests:muc_config_title_desc_master(Config). +muc_config_title_desc_slave(Config) -> + muc_tests:muc_config_title_desc_slave(Config). +muc_config_public_list_master(Config) -> + muc_tests:muc_config_public_list_master(Config). +muc_config_public_list_slave(Config) -> + muc_tests:muc_config_public_list_slave(Config). +muc_config_password_master(Config) -> + muc_tests:muc_config_password_master(Config). +muc_config_password_slave(Config) -> + muc_tests:muc_config_password_slave(Config). +muc_config_whois_master(Config) -> + muc_tests:muc_config_whois_master(Config). +muc_config_whois_slave(Config) -> + muc_tests:muc_config_whois_slave(Config). +muc_config_members_only_master(Config) -> + muc_tests:muc_config_members_only_master(Config). +muc_config_members_only_slave(Config) -> + muc_tests:muc_config_members_only_slave(Config). +muc_config_moderated_master(Config) -> + muc_tests:muc_config_moderated_master(Config). +muc_config_moderated_slave(Config) -> + muc_tests:muc_config_moderated_slave(Config). +muc_config_private_messages_master(Config) -> + muc_tests:muc_config_private_messages_master(Config). +muc_config_private_messages_slave(Config) -> + muc_tests:muc_config_private_messages_slave(Config). +muc_config_query_master(Config) -> + muc_tests:muc_config_query_master(Config). +muc_config_query_slave(Config) -> + muc_tests:muc_config_query_slave(Config). +muc_config_allow_invites_master(Config) -> + muc_tests:muc_config_allow_invites_master(Config). +muc_config_allow_invites_slave(Config) -> + muc_tests:muc_config_allow_invites_slave(Config). +muc_config_visitor_status_master(Config) -> + muc_tests:muc_config_visitor_status_master(Config). +muc_config_visitor_status_slave(Config) -> + muc_tests:muc_config_visitor_status_slave(Config). +muc_config_allow_voice_requests_master(Config) -> + muc_tests:muc_config_allow_voice_requests_master(Config). +muc_config_allow_voice_requests_slave(Config) -> + muc_tests:muc_config_allow_voice_requests_slave(Config). +muc_config_voice_request_interval_master(Config) -> + muc_tests:muc_config_voice_request_interval_master(Config). +muc_config_voice_request_interval_slave(Config) -> + muc_tests:muc_config_voice_request_interval_slave(Config). +muc_config_visitor_nickchange_master(Config) -> + muc_tests:muc_config_visitor_nickchange_master(Config). +muc_config_visitor_nickchange_slave(Config) -> + muc_tests:muc_config_visitor_nickchange_slave(Config). announce_master(Config) -> MyJID = my_jid(Config), diff --git a/test/ejabberd_SUITE_data/ejabberd.yml b/test/ejabberd_SUITE_data/ejabberd.yml index 2d2e098de..3a6d4947f 100644 --- a/test/ejabberd_SUITE_data/ejabberd.yml +++ b/test/ejabberd_SUITE_data/ejabberd.yml @@ -443,6 +443,7 @@ modules: mod_ping: [] mod_proxy65: [] mod_legacy: [] + mod_muc: [] mod_register: welcome_message: subject: "Welcome!" diff --git a/test/muc_tests.erl b/test/muc_tests.erl new file mode 100644 index 000000000..c89b97742 --- /dev/null +++ b/test/muc_tests.erl @@ -0,0 +1,1877 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 15 Oct 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(muc_tests). + +%% API +-compile(export_all). +-import(suite, [recv_presence/1, send_recv/2, my_jid/1, muc_room_jid/1, + send/2, recv_message/1, recv_iq/1, recv/1, muc_jid/1, + alt_room_jid/1, wait_for_slave/1, wait_for_master/1, + disconnect/1, put_event/2, get_event/1, peer_muc_jid/1, + my_muc_jid/1, get_features/2, flush/1, set_opt/3]). +-include("suite.hrl"). +-include("jid.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +%%%=================================================================== +%%% Single tests +%%%=================================================================== +single_cases() -> + {muc_single, [sequence], + [muc_service_presence_error, + muc_service_message_error, + muc_service_unknown_ns_iq_error, + muc_service_iq_set_error, + muc_service_improper_iq_error, + muc_service_features, + muc_service_disco_info_node_error, + muc_service_disco_items, + muc_service_unique, + muc_service_vcard, + muc_configure_non_existent, + muc_cancel_configure_non_existent, + muc_service_subscriptions]}. + +muc_service_presence_error(Config) -> + Service = muc_jid(Config), + ServiceResource = jid:replace_resource(Service, randoms:get_string()), + lists:foreach( + fun(To) -> + send(Config, #presence{type = error, to = To}), + lists:foreach( + fun(Type) -> + #presence{type = error} = Err = + send_recv(Config, #presence{type = Type, to = To}), + #stanza_error{reason = 'service-unavailable'} = + xmpp:get_error(Err) + end, [available, unavailable]) + end, [Service, ServiceResource]), + disconnect(Config). + +muc_service_message_error(Config) -> + Service = muc_jid(Config), + send(Config, #message{type = error, to = Service}), + lists:foreach( + fun(Type) -> + #message{type = error} = Err1 = + send_recv(Config, #message{type = Type, to = Service}), + #stanza_error{reason = 'forbidden'} = xmpp:get_error(Err1) + end, [chat, normal, headline, groupchat]), + ServiceResource = jid:replace_resource(Service, randoms:get_string()), + send(Config, #message{type = error, to = ServiceResource}), + lists:foreach( + fun(Type) -> + #message{type = error} = Err2 = + send_recv(Config, #message{type = Type, to = ServiceResource}), + #stanza_error{reason = 'service-unavailable'} = xmpp:get_error(Err2) + end, [chat, normal, headline, groupchat]), + disconnect(Config). + +muc_service_unknown_ns_iq_error(Config) -> + Service = muc_jid(Config), + ServiceResource = jid:replace_resource(Service, randoms:get_string()), + lists:foreach( + fun(To) -> + send(Config, #iq{type = result, to = To}), + send(Config, #iq{type = error, to = To}), + lists:foreach( + fun(Type) -> + #iq{type = error} = Err1 = + send_recv(Config, #iq{type = Type, to = To, + sub_els = [#presence{}]}), + #stanza_error{reason = 'service-unavailable'} = + xmpp:get_error(Err1) + end, [set, get]) + end, [Service, ServiceResource]), + disconnect(Config). + +muc_service_iq_set_error(Config) -> + Service = muc_jid(Config), + lists:foreach( + fun(SubEl) -> + send(Config, #iq{type = result, to = Service, + sub_els = [SubEl]}), + #iq{type = error} = Err2 = + send_recv(Config, #iq{type = set, to = Service, + sub_els = [SubEl]}), + #stanza_error{reason = 'not-allowed'} = + xmpp:get_error(Err2) + end, [#disco_items{}, #disco_info{}, #vcard_temp{}, + #muc_unique{}, #muc_subscriptions{}]), + disconnect(Config). + +muc_service_improper_iq_error(Config) -> + Service = muc_jid(Config), + lists:foreach( + fun(SubEl) -> + send(Config, #iq{type = result, to = Service, + sub_els = [SubEl]}), + lists:foreach( + fun(Type) -> + #iq{type = error} = Err3 = + send_recv(Config, #iq{type = Type, to = Service, + sub_els = [SubEl]}), + #stanza_error{reason = Reason} = xmpp:get_error(Err3), + true = Reason /= 'internal-server-error' + end, [set, get]) + end, [#disco_item{jid = Service}, + #identity{category = <<"category">>, type = <<"type">>}, + #vcard_email{}, #muc_subscribe{nick = ?config(nick, Config)}]), + disconnect(Config). + +muc_service_features(Config) -> + ServerHost = ?config(server_host, Config), + MUC = muc_jid(Config), + Features = sets:from_list(get_features(Config, MUC)), + MAMFeatures = case gen_mod:is_loaded(ServerHost, mod_mam) of + true -> [?NS_MAM_TMP, ?NS_MAM_0, ?NS_MAM_1]; + false -> [] + end, + RequiredFeatures = sets:from_list( + [?NS_DISCO_INFO, ?NS_DISCO_ITEMS, + ?NS_REGISTER, ?NS_MUC, ?NS_RSM, + ?NS_VCARD, ?NS_MUCSUB, ?NS_MUC_UNIQUE + | MAMFeatures]), + ct:comment("Checking if all needed disco features are set"), + true = sets:is_subset(RequiredFeatures, Features), + disconnect(Config). + +muc_service_disco_info_node_error(Config) -> + MUC = muc_jid(Config), + Node = randoms:get_string(), + #iq{type = error} = Err = + send_recv(Config, #iq{type = get, to = MUC, + sub_els = [#disco_info{node = Node}]}), + #stanza_error{reason = 'item-not-found'} = xmpp:get_error(Err), + disconnect(Config). + +muc_service_disco_items(Config) -> + #jid{server = Service} = muc_jid(Config), + Rooms = lists:sort( + lists:map( + fun(I) -> + RoomName = integer_to_binary(I), + jid:make(RoomName, Service) + end, lists:seq(1, 5))), + lists:foreach( + fun(Room) -> + ok = muc_join_new(Config, Room) + end, Rooms), + Items = muc_disco_items(Config), + Rooms = [J || #disco_item{jid = J} <- Items], + lists:foreach( + fun(Room) -> + ok = muc_leave(Config, Room) + end, Rooms), + [] = muc_disco_items(Config), + disconnect(Config). + +muc_service_vcard(Config) -> + MUC = muc_jid(Config), + ct:comment("Retreiving vCard from ~s", [jid:to_string(MUC)]), + #iq{type = result, sub_els = [#vcard_temp{}]} = + send_recv(Config, #iq{type = get, to = MUC, sub_els = [#vcard_temp{}]}), + disconnect(Config). + +muc_service_unique(Config) -> + MUC = muc_jid(Config), + ct:comment("Requesting muc unique from ~s", [jid:to_string(MUC)]), + #iq{type = result, sub_els = [#muc_unique{name = Name}]} = + send_recv(Config, #iq{type = get, to = MUC, sub_els = [#muc_unique{}]}), + ct:comment("Checking if unique name is set in the response"), + <<_, _/binary>> = Name, + disconnect(Config). + +muc_configure_non_existent(Config) -> + [_|_] = muc_get_config(Config), + disconnect(Config). + +muc_cancel_configure_non_existent(Config) -> + Room = muc_room_jid(Config), + #iq{type = result, sub_els = []} = + send_recv(Config, + #iq{to = Room, type = set, + sub_els = [#muc_owner{config = #xdata{type = cancel}}]}), + disconnect(Config). + +muc_service_subscriptions(Config) -> + MUC = #jid{server = Service} = muc_jid(Config), + Rooms = lists:sort( + lists:map( + fun(I) -> + RoomName = integer_to_binary(I), + jid:make(RoomName, Service) + end, lists:seq(1, 5))), + lists:foreach( + fun(Room) -> + ok = muc_join_new(Config, Room), + [104] = muc_set_config(Config, [{allow_subscription, true}], Room), + [] = muc_subscribe(Config, [], Room) + end, Rooms), + #iq{type = result, sub_els = [#muc_subscriptions{list = JIDs}]} = + send_recv(Config, #iq{type = get, to = MUC, + sub_els = [#muc_subscriptions{}]}), + Rooms = lists:sort(JIDs), + lists:foreach( + fun(Room) -> + ok = muc_unsubscribe(Config, Room), + ok = muc_leave(Config, Room) + end, Rooms), + disconnect(Config). + +%%%=================================================================== +%%% Master-slave tests +%%%=================================================================== +master_slave_cases() -> + {muc_master_slave, [sequence], + [master_slave_test(muc_register), + master_slave_test(muc_groupchat_msg), + master_slave_test(muc_private_msg), + master_slave_test(muc_set_subject), + master_slave_test(muc_history), + master_slave_test(muc_invite), + master_slave_test(muc_invite_members_only), + master_slave_test(muc_invite_password_protected), + master_slave_test(muc_voice_request), + master_slave_test(muc_change_role), + master_slave_test(muc_kick), + master_slave_test(muc_change_affiliation), + master_slave_test(muc_destroy), + master_slave_test(muc_vcard), + master_slave_test(muc_nick_change), + master_slave_test(muc_config_title_desc), + master_slave_test(muc_config_public_list), + master_slave_test(muc_config_password), + master_slave_test(muc_config_whois), + master_slave_test(muc_config_members_only), + master_slave_test(muc_config_moderated), + master_slave_test(muc_config_private_messages), + master_slave_test(muc_config_query), + master_slave_test(muc_config_allow_invites), + master_slave_test(muc_config_visitor_status), + master_slave_test(muc_config_allow_voice_requests), + master_slave_test(muc_config_voice_request_interval), + master_slave_test(muc_config_visitor_nickchange), + master_slave_test(muc_join_conflict)]}. + +muc_join_conflict_master(Config) -> + ok = muc_join_new(Config), + put_event(Config, join), + ct:comment("Waiting for 'leave' command from the slave"), + leave = get_event(Config), + ok = muc_leave(Config), + disconnect(Config). + +muc_join_conflict_slave(Config) -> + NewConfig = set_opt(nick, ?config(peer_nick, Config), Config), + ct:comment("Waiting for 'join' command from the master"), + join = get_event(Config), + ct:comment("Fail trying to join the room with conflicting nick"), + #stanza_error{reason = 'conflict'} = muc_join(NewConfig), + put_event(Config, leave), + disconnect(NewConfig). + +muc_groupchat_msg_master(Config) -> + Room = muc_room_jid(Config), + PeerJID = ?config(slave, Config), + PeerNick = ?config(slave_nick, Config), + PeerNickJID = jid:replace_resource(Room, PeerNick), + MyNick = ?config(nick, Config), + MyNickJID = jid:replace_resource(Room, MyNick), + ok = muc_master_join(Config), + lists:foreach( + fun(I) -> + Body = xmpp:mk_text(integer_to_binary(I)), + send(Config, #message{type = groupchat, to = Room, + body = Body}), + #message{type = groupchat, from = MyNickJID, + body = Body} = recv_message(Config) + end, lists:seq(1, 5)), + #muc_user{items = [#muc_item{jid = PeerJID, + role = none, + affiliation = none}]} = + recv_muc_presence(Config, PeerNickJID, unavailable), + ok = muc_leave(Config), + disconnect(Config). + +muc_groupchat_msg_slave(Config) -> + Room = muc_room_jid(Config), + PeerNick = ?config(master_nick, Config), + PeerNickJID = jid:replace_resource(Room, PeerNick), + {[], _, _} = muc_slave_join(Config), + lists:foreach( + fun(I) -> + Body = xmpp:mk_text(integer_to_binary(I)), + #message{type = groupchat, from = PeerNickJID, + body = Body} = recv_message(Config) + end, lists:seq(1, 5)), + ok = muc_leave(Config), + disconnect(Config). + +muc_private_msg_master(Config) -> + Room = muc_room_jid(Config), + PeerJID = ?config(slave, Config), + PeerNick = ?config(slave_nick, Config), + PeerNickJID = jid:replace_resource(Room, PeerNick), + ok = muc_master_join(Config), + lists:foreach( + fun(I) -> + Body = xmpp:mk_text(integer_to_binary(I)), + send(Config, #message{type = chat, to = PeerNickJID, + body = Body}) + end, lists:seq(1, 5)), + #muc_user{items = [#muc_item{jid = PeerJID, + role = none, + affiliation = none}]} = + recv_muc_presence(Config, PeerNickJID, unavailable), + ct:comment("Fail trying to send a private message to non-existing occupant"), + send(Config, #message{type = chat, to = PeerNickJID}), + #message{from = PeerNickJID, type = error} = ErrMsg = recv_message(Config), + #stanza_error{reason = 'item-not-found'} = xmpp:get_error(ErrMsg), + ok = muc_leave(Config), + disconnect(Config). + +muc_private_msg_slave(Config) -> + Room = muc_room_jid(Config), + PeerNick = ?config(master_nick, Config), + PeerNickJID = jid:replace_resource(Room, PeerNick), + {[], _, _} = muc_slave_join(Config), + lists:foreach( + fun(I) -> + Body = xmpp:mk_text(integer_to_binary(I)), + #message{type = chat, from = PeerNickJID, + body = Body} = recv_message(Config) + end, lists:seq(1, 5)), + ok = muc_leave(Config), + disconnect(Config). + +muc_set_subject_master(Config) -> + Room = muc_room_jid(Config), + PeerJID = ?config(slave, Config), + PeerNick = ?config(slave_nick, Config), + PeerNickJID = jid:replace_resource(Room, PeerNick), + Subject1 = xmpp:mk_text(?config(room_subject, Config)), + Subject2 = xmpp:mk_text(<<"new-", (?config(room_subject, Config))/binary>>), + ok = muc_master_join(Config), + ct:comment("Setting 1st subject"), + send(Config, #message{type = groupchat, to = Room, + subject = Subject1}), + #message{type = groupchat, from = MyNickJID, + subject = Subject1} = recv_message(Config), + ct:comment("Waiting for the slave to leave"), + recv_muc_presence(Config, PeerNickJID, unavailable), + ct:comment("Setting 2nd subject"), + send(Config, #message{type = groupchat, to = Room, + subject = Subject2}), + #message{type = groupchat, from = MyNickJID, + subject = Subject2} = recv_message(Config), + ct:comment("Asking the slave to join"), + put_event(Config, join), + recv_muc_presence(Config, PeerNickJID, available), + ct:comment("Receiving 1st subject set by the slave"), + #message{type = groupchat, from = PeerNickJID, + subject = Subject1} = recv_message(Config), + ct:comment("Disallow subject change"), + [104] = muc_set_config(Config, [{changesubject, false}]), + ct:comment("Waiting for the slave to leave"), + #muc_user{items = [#muc_item{jid = PeerJID, + role = none, + affiliation = none}]} = + recv_muc_presence(Config, PeerNickJID, unavailable), + ok = muc_leave(Config), + disconnect(Config). + +muc_set_subject_slave(Config) -> + Room = muc_room_jid(Config), + MyNickJID = my_muc_jid(Config), + PeerNick = ?config(master_nick, Config), + PeerNickJID = jid:replace_resource(Room, PeerNick), + Subject1 = xmpp:mk_text(?config(room_subject, Config)), + Subject2 = xmpp:mk_text(<<"new-", (?config(room_subject, Config))/binary>>), + {[], _, _} = muc_slave_join(Config), + ct:comment("Receiving 1st subject set by the master"), + #message{type = groupchat, from = PeerNickJID, + subject = Subject1} = recv_message(Config), + ok = muc_leave(Config), + ct:comment("Waiting for 'join' command from the master"), + join = get_event(Config), + {[], SubjMsg2, _} = muc_join(Config), + ct:comment("Checking if the master has set 2nd subject during our absence"), + #message{type = groupchat, from = PeerNickJID, + subject = Subject2} = SubjMsg2, + ct:comment("Setting 1st subject"), + send(Config, #message{to = Room, type = groupchat, subject = Subject1}), + #message{type = groupchat, from = MyNickJID, + subject = Subject1} = recv_message(Config), + ct:comment("Waiting for the master to disallow subject change"), + [104] = muc_recv_config_change_message(Config), + ct:comment("Fail trying to change the subject"), + send(Config, #message{to = Room, type = groupchat, subject = Subject2}), + #message{from = Room, type = error} = ErrMsg = recv_message(Config), + #stanza_error{reason = 'forbidden'} = xmpp:get_error(ErrMsg), + ok = muc_leave(Config), + disconnect(Config). + +muc_history_master(Config) -> + Room = muc_room_jid(Config), + ServerHost = ?config(server_host, Config), + MyNick = ?config(nick, Config), + MyNickJID = jid:replace_resource(Room, MyNick), + Size = gen_mod:get_module_opt(ServerHost, mod_muc, history_size, + fun(I) when is_integer(I), I>=0 -> I end, + 20), + ok = muc_join_new(Config), + ct:comment("Putting ~p+1 messages in the history", [Size]), + %% Only Size messages will be stored + lists:foreach( + fun(I) -> + Body = xmpp:mk_text(integer_to_binary(I)), + send(Config, #message{to = Room, type = groupchat, + body = Body}), + #message{type = groupchat, from = MyNickJID, + body = Body} = recv_message(Config) + end, lists:seq(0, Size)), + wait_for_slave(Config), + wait_for_slave(Config), + flush(Config), + ok = muc_leave(Config), + disconnect(Config). + +muc_history_slave(Config) -> + Room = muc_room_jid(Config), + PeerNick = ?config(peer_nick, Config), + PeerNickJID = jid:replace_resource(Room, PeerNick), + ServerHost = ?config(server_host, Config), + Size = gen_mod:get_module_opt(ServerHost, mod_muc, history_size, + fun(I) when is_integer(I), I>=0 -> I end, + 20), + {History, _, _} = muc_slave_join(Config), + ct:comment("Checking ordering of history events"), + BodyList = [binary_to_integer(xmpp:get_text(Body)) + || #message{type = groupchat, from = From, + body = Body} <- History, + From == PeerNickJID], + BodyList = lists:seq(1, Size), + ok = muc_leave(Config), + %% If the client wishes to receive no history, it MUST set the 'maxchars' + %% attribute to a value of "0" (zero) + %% (http://xmpp.org/extensions/xep-0045.html#enter-managehistory) + ct:comment("Checking if maxchars=0 yields to no history"), + {[], _, _} = muc_join(Config, #muc{history = #muc_history{maxchars = 0}}), + ok = muc_leave(Config), + ct:comment("Receiving only 10 last stanzas"), + {History10, _, _} = muc_join(Config, + #muc{history = #muc_history{maxstanzas = 10}}), + BodyList10 = [binary_to_integer(xmpp:get_text(Body)) + || #message{type = groupchat, from = From, + body = Body} <- History10, + From == PeerNickJID], + BodyList10 = lists:nthtail(Size-10, lists:seq(1, Size)), + ok = muc_leave(Config), + #delay{stamp = TS} = xmpp:get_subtag(hd(History), #delay{}), + ct:comment("Receiving all history without the very first element"), + {HistoryWithoutFirst, _, _} = muc_join(Config, + #muc{history = #muc_history{since = TS}}), + BodyListWithoutFirst = [binary_to_integer(xmpp:get_text(Body)) + || #message{type = groupchat, from = From, + body = Body} <- HistoryWithoutFirst, + From == PeerNickJID], + BodyListWithoutFirst = lists:nthtail(1, lists:seq(1, Size)), + ok = muc_leave(Config), + wait_for_master(Config), + disconnect(Config). + +muc_invite_master(Config) -> + Room = muc_room_jid(Config), + PeerJID = ?config(peer, Config), + ok = muc_join_new(Config), + wait_for_slave(Config), + %% Inviting the peer + send(Config, #message{to = Room, type = normal, + sub_els = + [#muc_user{ + invites = + [#muc_invite{to = PeerJID}]}]}), + #message{from = Room} = DeclineMsg = recv_message(Config), + #muc_user{decline = #muc_decline{from = PeerJID}} = + xmpp:get_subtag(DeclineMsg, #muc_user{}), + ok = muc_leave(Config), + disconnect(Config). + +muc_invite_slave(Config) -> + Room = muc_room_jid(Config), + wait_for_master(Config), + PeerJID = ?config(master, Config), + #message{from = Room, type = normal} = Msg = recv_message(Config), + #muc_user{invites = [#muc_invite{from = PeerJID}]} = + xmpp:get_subtag(Msg, #muc_user{}), + %% Decline invitation + send(Config, + #message{to = Room, + sub_els = [#muc_user{ + decline = #muc_decline{to = PeerJID}}]}), + disconnect(Config). + +muc_invite_members_only_master(Config) -> + Room = muc_room_jid(Config), + PeerJID = ?config(slave, Config), + ok = muc_join_new(Config), + %% Setting the room to members-only + [_|_] = muc_set_config(Config, [{membersonly, true}]), + wait_for_slave(Config), + %% Inviting the peer + send(Config, #message{to = Room, type = normal, + sub_els = + [#muc_user{ + invites = + [#muc_invite{to = PeerJID}]}]}), + #message{from = Room, type = normal} = AffMsg = recv_message(Config), + #muc_user{items = [#muc_item{jid = PeerJID, affiliation = member}]} = + xmpp:get_subtag(AffMsg, #muc_user{}), + ok = muc_leave(Config), + disconnect(Config). + +muc_invite_members_only_slave(Config) -> + Room = muc_room_jid(Config), + wait_for_master(Config), + %% Receiving invitation + #message{from = Room, type = normal} = recv_message(Config), + disconnect(Config). + +muc_invite_password_protected_master(Config) -> + Room = muc_room_jid(Config), + PeerJID = ?config(slave, Config), + Password = randoms:get_string(), + ok = muc_join_new(Config), + [104] = muc_set_config(Config, [{passwordprotectedroom, true}, + {roomsecret, Password}]), + put_event(Config, Password), + %% Inviting the peer + send(Config, #message{to = Room, type = normal, + sub_els = + [#muc_user{ + invites = + [#muc_invite{to = PeerJID}]}]}), + ok = muc_leave(Config), + disconnect(Config). + +muc_invite_password_protected_slave(Config) -> + Room = muc_room_jid(Config), + Password = get_event(Config), + %% Receiving invitation + #message{from = Room, type = normal} = Msg = recv_message(Config), + #muc_user{password = Password} = xmpp:get_subtag(Msg, #muc_user{}), + disconnect(Config). + +muc_voice_request_master(Config) -> + Room = muc_room_jid(Config), + PeerJID = ?config(slave, Config), + PeerNick = ?config(slave_nick, Config), + PeerNickJID = jid:replace_resource(Room, PeerNick), + ok = muc_join_new(Config), + [104] = muc_set_config(Config, [{members_by_default, false}]), + wait_for_slave(Config), + #muc_user{ + items = [#muc_item{role = visitor, + jid = PeerJID, + affiliation = none}]} = + recv_muc_presence(Config, PeerNickJID, available), + ct:comment("Receiving voice request"), + #message{from = Room, type = normal} = VoiceReq = recv_message(Config), + #xdata{type = form, fields = Fs} = xmpp:get_subtag(VoiceReq, #xdata{}), + [{jid, PeerJID}, + {request_allow, false}, + {role, participant}, + {roomnick, PeerNick}] = lists:sort(muc_request:decode(Fs)), + ct:comment("Approving voice request"), + ApprovalFs = muc_request:encode([{jid, PeerJID}, {role, participant}, + {nick, PeerNick}, {request_allow, true}]), + send(Config, #message{to = Room, sub_els = [#xdata{type = submit, + fields = ApprovalFs}]}), + #muc_user{ + items = [#muc_item{role = participant, + jid = PeerJID, + affiliation = none}]} = + recv_muc_presence(Config, PeerNickJID, available), + ct:comment("Waiting for the slave to leave"), + recv_muc_presence(Config, PeerNickJID, unavailable), + ok = muc_leave(Config), + disconnect(Config). + +muc_voice_request_slave(Config) -> + Room = muc_room_jid(Config), + MyJID = my_jid(Config), + MyNick = ?config(nick, Config), + MyNickJID = jid:replace_resource(Room, MyNick), + wait_for_master(Config), + {[], _, _} = muc_join(Config, visitor), + ct:comment("Requesting voice"), + Fs = muc_request:encode([{role, participant}]), + X = #xdata{type = submit, fields = Fs}, + send(Config, #message{to = Room, sub_els = [X]}), + ct:comment("Waiting to become a participant"), + #muc_user{ + items = [#muc_item{role = participant, + jid = MyJID, + affiliation = none}]} = + recv_muc_presence(Config, MyNickJID, available), + ok = muc_leave(Config), + disconnect(Config). + +muc_change_role_master(Config) -> + Room = muc_room_jid(Config), + MyJID = my_jid(Config), + MyNick = ?config(nick, Config), + PeerJID = ?config(slave, Config), + PeerNick = ?config(slave_nick, Config), + PeerNickJID = jid:replace_resource(Room, PeerNick), + ok = muc_join_new(Config), + ct:comment("Waiting for the slave to join"), + wait_for_slave(Config), + #muc_user{items = [#muc_item{role = participant, + jid = PeerJID, + affiliation = none}]} = + recv_muc_presence(Config, PeerNickJID, available), + lists:foreach( + fun(Role) -> + ct:comment("Checking if the slave is not in the roles list"), + case muc_get_role(Config, Role) of + [#muc_item{jid = MyJID, affiliation = owner, + role = moderator, nick = MyNick}] when Role == moderator -> + ok; + [] -> + ok + end, + Reason = randoms:get_string(), + put_event(Config, {Role, Reason}), + ok = muc_set_role(Config, Role, Reason), + ct:comment("Receiving role change to ~s", [Role]), + #muc_user{ + items = [#muc_item{role = Role, + affiliation = none, + reason = Reason}]} = + recv_muc_presence(Config, PeerNickJID, available), + [#muc_item{role = Role, affiliation = none, + nick = PeerNick}|_] = muc_get_role(Config, Role) + end, [visitor, participant, moderator]), + put_event(Config, disconnect), + wait_for_slave(Config), + flush(Config), + ok = muc_leave(Config), + disconnect(Config). + +muc_change_role_slave(Config) -> + wait_for_master(Config), + {[], _, _} = muc_join(Config), + muc_change_role_slave(Config, get_event(Config)). + +muc_change_role_slave(Config, {Role, Reason}) -> + Room = muc_room_jid(Config), + MyNick = ?config(slave_nick, Config), + MyNickJID = jid:replace_resource(Room, MyNick), + ct:comment("Receiving role change to ~s", [Role]), + #muc_user{status_codes = Codes, + items = [#muc_item{role = Role, + affiliation = none, + reason = Reason}]} = + recv_muc_presence(Config, MyNickJID, available), + true = lists:member(110, Codes), + muc_change_role_slave(Config, get_event(Config)); +muc_change_role_slave(Config, disconnect) -> + ok = muc_leave(Config), + wait_for_master(Config), + disconnect(Config). + +muc_change_affiliation_master(Config) -> + Room = muc_room_jid(Config), + MyJID = my_jid(Config), + MyBareJID = jid:remove_resource(MyJID), + MyNick = ?config(nick, Config), + PeerJID = ?config(slave, Config), + PeerBareJID = jid:remove_resource(PeerJID), + PeerNick = ?config(slave_nick, Config), + PeerNickJID = jid:replace_resource(Room, PeerNick), + ok = muc_join_new(Config), + ct:comment("Waiting for the slave to join"), + wait_for_slave(Config), + #muc_user{items = [#muc_item{role = participant, + jid = PeerJID, + affiliation = none}]} = + recv_muc_presence(Config, PeerNickJID, available), + lists:foreach( + fun({Aff, Role, Status}) -> + ct:comment("Checking if slave is not in affiliation list"), + case muc_get_affiliation(Config, Aff) of + [#muc_item{jid = MyBareJID, + affiliation = owner}] when Aff == owner -> + ok; + [] -> + ok + end, + Reason = randoms:get_string(), + put_event(Config, {Aff, Role, Status, Reason}), + ok = muc_set_affiliation(Config, Aff, Reason), + ct:comment("Receiving affiliation change to ~s", [Aff]), + #muc_user{ + items = [#muc_item{role = Role, + affiliation = Aff, + actor = Actor, + reason = Reason}]} = + recv_muc_presence(Config, PeerNickJID, Status), + if Aff == outcast -> + ct:comment("Checking if actor is set"), + #muc_actor{nick = MyNick} = Actor; + true -> + ok + end, + Affs = muc_get_affiliation(Config, Aff), + ct:comment("Checking if the affiliation was correctly set"), + case lists:keyfind(PeerBareJID, #muc_item.jid, Affs) of + false when Aff == none -> + ok; + #muc_item{affiliation = Aff} -> + ok + end + end, [{member, participant, available}, {none, participant, available}, + {admin, moderator, available}, {owner, moderator, available}, + {outcast, none, unavailable}]), + ok = muc_leave(Config), + disconnect(Config). + +muc_change_affiliation_slave(Config) -> + wait_for_master(Config), + {[], _, _} = muc_join(Config), + muc_change_affiliation_slave(Config, get_event(Config)). + +muc_change_affiliation_slave(Config, {Aff, Role, Status, Reason}) -> + Room = muc_room_jid(Config), + PeerNick = ?config(master_nick, Config), + MyNick = ?config(nick, Config), + MyNickJID = jid:replace_resource(Room, MyNick), + ct:comment("Receiving affiliation change to ~s", [Aff]), + #muc_user{status_codes = Codes, + items = [#muc_item{role = Role, + actor = Actor, + affiliation = Aff, + reason = Reason}]} = + recv_muc_presence(Config, MyNickJID, Status), + true = lists:member(110, Codes), + if Aff == outcast -> + ct:comment("Checking for status code '301' (banned)"), + true = lists:member(301, Codes), + ct:comment("Checking if actor is set"), + #muc_actor{nick = PeerNick} = Actor, + disconnect(Config); + true -> + muc_change_affiliation_slave(Config, get_event(Config)) + end. + +muc_kick_master(Config) -> + Room = muc_room_jid(Config), + MyNick = ?config(nick, Config), + PeerJID = ?config(slave, Config), + PeerNick = ?config(slave_nick, Config), + PeerNickJID = jid:replace_resource(Room, PeerNick), + Reason = <<"Testing">>, + ok = muc_join_new(Config), + ct:comment("Waiting for the slave to join"), + wait_for_slave(Config), + #muc_user{items = [#muc_item{role = participant, + jid = PeerJID, + affiliation = none}]} = + recv_muc_presence(Config, PeerNickJID, available), + [#muc_item{role = participant, affiliation = none, + nick = PeerNick}|_] = muc_get_role(Config, participant), + ct:comment("Kicking slave"), + ok = muc_set_role(Config, none, Reason), + ct:comment("Receiving role change to 'none'"), + #muc_user{ + status_codes = Codes, + items = [#muc_item{role = none, + affiliation = none, + actor = #muc_actor{nick = MyNick}, + reason = Reason}]} = + recv_muc_presence(Config, PeerNickJID, unavailable), + [] = muc_get_role(Config, participant), + ct:comment("Checking if the code is '307' (kicked)"), + true = lists:member(307, Codes), + ok = muc_leave(Config), + disconnect(Config). + +muc_kick_slave(Config) -> + Room = muc_room_jid(Config), + PeerNick = ?config(master_nick, Config), + MyNick = ?config(nick, Config), + MyNickJID = jid:replace_resource(Room, MyNick), + Reason = <<"Testing">>, + wait_for_master(Config), + {[], _, _} = muc_join(Config), + ct:comment("Receiving role change to 'none'"), + #muc_user{status_codes = Codes, + items = [#muc_item{role = none, + affiliation = none, + actor = #muc_actor{nick = PeerNick}, + reason = Reason}]} = + recv_muc_presence(Config, MyNickJID, unavailable), + ct:comment("Checking if codes '110' (self-presence) " + "and '307' (kicked) are present"), + true = lists:member(110, Codes), + true = lists:member(307, Codes), + disconnect(Config). + +muc_destroy_master(Config) -> + Reason = <<"Testing">>, + Room = muc_room_jid(Config), + AltRoom = alt_room_jid(Config), + PeerJID = ?config(peer, Config), + PeerNick = ?config(slave_nick, Config), + PeerNickJID = jid:replace_resource(Room, PeerNick), + MyNick = ?config(nick, Config), + MyNickJID = jid:replace_resource(Room, MyNick), + ok = muc_join_new(Config), + ct:comment("Waiting for slave to join"), + wait_for_slave(Config), + #muc_user{items = [#muc_item{role = participant, + jid = PeerJID, + affiliation = none}]} = + recv_muc_presence(Config, PeerNickJID, available), + wait_for_slave(Config), + ok = muc_destroy(Config, Reason), + ct:comment("Receiving destruction presence"), + #muc_user{items = [#muc_item{role = none, + affiliation = none}], + destroy = #muc_destroy{jid = AltRoom, + reason = Reason}} = + recv_muc_presence(Config, MyNickJID, unavailable), + disconnect(Config). + +muc_destroy_slave(Config) -> + Reason = <<"Testing">>, + Room = muc_room_jid(Config), + AltRoom = alt_room_jid(Config), + MyNick = ?config(nick, Config), + MyNickJID = jid:replace_resource(Room, MyNick), + wait_for_master(Config), + {[], _, _} = muc_join(Config), + #stanza_error{reason = 'forbidden'} = muc_destroy(Config, Reason), + wait_for_master(Config), + ct:comment("Receiving destruction presence"), + #muc_user{items = [#muc_item{role = none, + affiliation = none}], + destroy = #muc_destroy{jid = AltRoom, + reason = Reason}} = + recv_muc_presence(Config, MyNickJID, unavailable), + disconnect(Config). + +muc_vcard_master(Config) -> + Room = muc_room_jid(Config), + PeerNick = ?config(slave_nick, Config), + PeerNickJID = jid:replace_resource(Room, PeerNick), + FN = randoms:get_string(), + VCard = #vcard_temp{fn = FN}, + ok = muc_join_new(Config), + ct:comment("Waiting for slave to join"), + wait_for_slave(Config), + #muc_user{items = [#muc_item{role = participant, + affiliation = none}]} = + recv_muc_presence(Config, PeerNickJID, available), + #stanza_error{reason = 'item-not-found'} = muc_get_vcard(Config), + ok = muc_set_vcard(Config, VCard), + VCard = muc_get_vcard(Config), + put_event(Config, VCard), + recv_muc_presence(Config, PeerNickJID, unavailable), + leave = get_event(Config), + ok = muc_leave(Config), + disconnect(Config). + +muc_vcard_slave(Config) -> + wait_for_master(Config), + {[], _, _} = muc_join(Config), + VCard = get_event(Config), + VCard = muc_get_vcard(Config), + #stanza_error{reason = 'forbidden'} = muc_set_vcard(Config, VCard), + ok = muc_leave(Config), + VCard = muc_get_vcard(Config), + put_event(Config, leave), + disconnect(Config). + +muc_nick_change_master(Config) -> + NewNick = randoms:get_string(), + PeerJID = ?config(peer, Config), + PeerNickJID = peer_muc_jid(Config), + ok = muc_master_join(Config), + put_event(Config, {new_nick, NewNick}), + ct:comment("Waiting for nickchange presence from the slave"), + #muc_user{status_codes = Codes, + items = [#muc_item{jid = PeerJID, + nick = NewNick}]} = + recv_muc_presence(Config, PeerNickJID, unavailable), + ct:comment("Checking if code '303' (nick change) is set"), + true = lists:member(303, Codes), + ct:comment("Waiting for updated presence from the slave"), + PeerNewNickJID = jid:replace_resource(PeerNickJID, NewNick), + recv_muc_presence(Config, PeerNewNickJID, available), + ct:comment("Waiting for the slave to leave"), + recv_muc_presence(Config, PeerNewNickJID, unavailable), + ok = muc_leave(Config), + disconnect(Config). + +muc_nick_change_slave(Config) -> + MyJID = my_jid(Config), + MyNickJID = my_muc_jid(Config), + {[], _, _} = muc_slave_join(Config), + {new_nick, NewNick} = get_event(Config), + MyNewNickJID = jid:replace_resource(MyNickJID, NewNick), + ct:comment("Sending new presence"), + send(Config, #presence{to = MyNewNickJID}), + ct:comment("Receiving nickchange self-presence"), + #muc_user{status_codes = Codes1, + items = [#muc_item{role = participant, + jid = MyJID, + nick = NewNick}]} = + recv_muc_presence(Config, MyNickJID, unavailable), + ct:comment("Checking if codes '110' (self-presence) and " + "'303' (nickchange) are present"), + lists:member(110, Codes1), + lists:member(303, Codes1), + ct:comment("Receiving self-presence update"), + #muc_user{status_codes = Codes2, + items = [#muc_item{jid = MyJID, + role = participant}]} = + recv_muc_presence(Config, MyNewNickJID, available), + ct:comment("Checking if code '110' (self-presence) is set"), + lists:member(110, Codes2), + NewConfig = set_opt(nick, NewNick, Config), + ok = muc_leave(NewConfig), + disconnect(NewConfig). + +muc_config_title_desc_master(Config) -> + Title = randoms:get_string(), + Desc = randoms:get_string(), + Room = muc_room_jid(Config), + PeerNick = ?config(slave_nick, Config), + PeerNickJID = jid:replace_resource(Room, PeerNick), + ok = muc_master_join(Config), + [104] = muc_set_config(Config, [{roomname, Title}, {roomdesc, Desc}]), + RoomCfg = muc_get_config(Config), + Title = proplists:get_value(roomname, RoomCfg), + Desc = proplists:get_value(roomdesc, RoomCfg), + recv_muc_presence(Config, PeerNickJID, unavailable), + ok = muc_leave(Config), + disconnect(Config). + +muc_config_title_desc_slave(Config) -> + {[], _, _} = muc_slave_join(Config), + [104] = muc_recv_config_change_message(Config), + ok = muc_leave(Config), + disconnect(Config). + +muc_config_public_list_master(Config) -> + Room = muc_room_jid(Config), + PeerNick = ?config(slave_nick, Config), + PeerNickJID = jid:replace_resource(Room, PeerNick), + ok = muc_join_new(Config), + wait_for_slave(Config), + recv_muc_presence(Config, PeerNickJID, available), + lists:member(<<"muc_public">>, get_features(Config, Room)), + [104] = muc_set_config(Config, [{public_list, false}, + {publicroom, false}]), + recv_muc_presence(Config, PeerNickJID, unavailable), + lists:member(<<"muc_hidden">>, get_features(Config, Room)), + wait_for_slave(Config), + ok = muc_leave(Config), + disconnect(Config). + +muc_config_public_list_slave(Config) -> + Room = muc_room_jid(Config), + wait_for_master(Config), + PeerNick = ?config(peer_nick, Config), + PeerNickJID = peer_muc_jid(Config), + [#disco_item{jid = Room}] = muc_disco_items(Config), + [#disco_item{jid = PeerNickJID, + name = PeerNick}] = muc_disco_room_items(Config), + {[], _, _} = muc_join(Config), + [104] = muc_recv_config_change_message(Config), + ok = muc_leave(Config), + [] = muc_disco_items(Config), + [] = muc_disco_room_items(Config), + wait_for_master(Config), + disconnect(Config). + +muc_config_password_master(Config) -> + Password = randoms:get_string(), + Room = muc_room_jid(Config), + PeerNick = ?config(slave_nick, Config), + PeerNickJID = jid:replace_resource(Room, PeerNick), + ok = muc_join_new(Config), + lists:member(<<"muc_unsecured">>, get_features(Config, Room)), + [104] = muc_set_config(Config, [{passwordprotectedroom, true}, + {roomsecret, Password}]), + lists:member(<<"muc_passwordprotected">>, get_features(Config, Room)), + put_event(Config, Password), + recv_muc_presence(Config, PeerNickJID, available), + recv_muc_presence(Config, PeerNickJID, unavailable), + ok = muc_leave(Config), + disconnect(Config). + +muc_config_password_slave(Config) -> + Password = get_event(Config), + #stanza_error{reason = 'not-authorized'} = muc_join(Config), + #stanza_error{reason = 'not-authorized'} = + muc_join(Config, #muc{password = randoms:get_string()}), + {[], _, _} = muc_join(Config, #muc{password = Password}), + ok = muc_leave(Config), + disconnect(Config). + +muc_config_whois_master(Config) -> + Room = muc_room_jid(Config), + PeerNickJID = peer_muc_jid(Config), + MyNickJID = my_muc_jid(Config), + ok = muc_master_join(Config), + lists:member(<<"muc_semianonymous">>, get_features(Config, Room)), + [172] = muc_set_config(Config, [{whois, anyone}]), + lists:member(<<"muc_nonanonymous">>, get_features(Config, Room)), + recv_muc_presence(Config, PeerNickJID, unavailable), + recv_muc_presence(Config, PeerNickJID, available), + send(Config, #presence{to = Room}), + recv_muc_presence(Config, MyNickJID, available), + [173] = muc_set_config(Config, [{whois, moderators}]), + recv_muc_presence(Config, PeerNickJID, unavailable), + ok = muc_leave(Config), + disconnect(Config). + +muc_config_whois_slave(Config) -> + PeerJID = ?config(peer, Config), + PeerNickJID = peer_muc_jid(Config), + {[], _, _} = muc_slave_join(Config), + ct:comment("Checking if the room becomes non-anonymous (code '172')"), + [172] = muc_recv_config_change_message(Config), + ct:comment("Re-joining in order to check status codes"), + ok = muc_leave(Config), + {[], _, Codes} = muc_join(Config), + ct:comment("Checking if code '100' (non-anonymous) present"), + true = lists:member(100, Codes), + ct:comment("Receiving presence from peer with JID exposed"), + #muc_user{items = [#muc_item{jid = PeerJID}]} = + recv_muc_presence(Config, PeerNickJID, available), + ct:comment("Waiting for the room to become anonymous again (code '173')"), + [173] = muc_recv_config_change_message(Config), + ok = muc_leave(Config), + disconnect(Config). + +muc_config_members_only_master(Config) -> + Room = muc_room_jid(Config), + PeerJID = ?config(peer, Config), + PeerBareJID = jid:remove_resource(PeerJID), + PeerNickJID = peer_muc_jid(Config), + ok = muc_master_join(Config), + lists:member(<<"muc_open">>, get_features(Config, Room)), + [104] = muc_set_config(Config, [{membersonly, true}]), + #muc_user{status_codes = Codes, + items = [#muc_item{jid = PeerJID, + affiliation = none, + role = none}]} = + recv_muc_presence(Config, PeerNickJID, unavailable), + ct:comment("Checking if code '322' (non-member) is set"), + true = lists:member(322, Codes), + lists:member(<<"muc_membersonly">>, get_features(Config, Room)), + ct:comment("Waiting for slave to fail joining the room"), + set_member = get_event(Config), + ok = muc_set_affiliation(Config, member, randoms:get_string()), + #message{from = Room, type = normal} = Msg = recv_message(Config), + #muc_user{items = [#muc_item{jid = PeerBareJID, + affiliation = member}]} = + xmpp:get_subtag(Msg, #muc_user{}), + ct:comment("Asking peer to join"), + put_event(Config, join), + ct:comment("Waiting for peer to join"), + recv_muc_presence(Config, PeerNickJID, available), + ok = muc_set_affiliation(Config, none, randoms:get_string()), + ct:comment("Waiting for peer to be kicked"), + #muc_user{status_codes = NewCodes, + items = [#muc_item{affiliation = none, + role = none}]} = + recv_muc_presence(Config, PeerNickJID, unavailable), + ct:comment("Checking if code '321' (became non-member in " + "members-only room) is set"), + true = lists:member(321, NewCodes), + ok = muc_leave(Config), + disconnect(Config). + +muc_config_members_only_slave(Config) -> + MyJID = my_jid(Config), + MyNickJID = my_muc_jid(Config), + {[], _, _} = muc_slave_join(Config), + [104] = muc_recv_config_change_message(Config), + ct:comment("Getting kicked because the room has become members-only"), + #muc_user{status_codes = Codes, + items = [#muc_item{jid = MyJID, + role = none, + affiliation = none}]} = + recv_muc_presence(Config, MyNickJID, unavailable), + ct:comment("Checking if the code '110' (self-presence) " + "and '322' (non-member) is set"), + true = lists:member(110, Codes), + true = lists:member(322, Codes), + ct:comment("Fail trying to join members-only room"), + #stanza_error{reason = 'registration-required'} = muc_join(Config), + ct:comment("Asking the peer to set us member"), + put_event(Config, set_member), + ct:comment("Waiting for the peer to ask for join"), + join = get_event(Config), + {[], _, _} = muc_join(Config, participant, member), + #muc_user{status_codes = NewCodes, + items = [#muc_item{jid = MyJID, + role = none, + affiliation = none}]} = + recv_muc_presence(Config, MyNickJID, unavailable), + ct:comment("Checking if the code '110' (self-presence) " + "and '321' (became non-member in members-only room) is set"), + true = lists:member(110, NewCodes), + true = lists:member(321, NewCodes), + disconnect(Config). + +muc_config_moderated_master(Config) -> + Room = muc_room_jid(Config), + PeerNickJID = peer_muc_jid(Config), + ok = muc_master_join(Config), + lists:member(<<"muc_moderated">>, get_features(Config, Room)), + ok = muc_set_role(Config, visitor, randoms:get_string()), + #muc_user{items = [#muc_item{role = visitor}]} = + recv_muc_presence(Config, PeerNickJID, available), + set_unmoderated = get_event(Config), + [104] = muc_set_config(Config, [{moderatedroom, false}]), + #message{from = PeerNickJID, type = groupchat} = recv_message(Config), + recv_muc_presence(Config, PeerNickJID, unavailable), + lists:member(<<"muc_unmoderated">>, get_features(Config, Room)), + ok = muc_leave(Config), + disconnect(Config). + +muc_config_moderated_slave(Config) -> + Room = muc_room_jid(Config), + MyNickJID = my_muc_jid(Config), + {[], _, _} = muc_slave_join(Config), + #muc_user{items = [#muc_item{role = visitor}]} = + recv_muc_presence(Config, MyNickJID, available), + send(Config, #message{to = Room, type = groupchat}), + ErrMsg = #message{from = Room, type = error} = recv_message(Config), + #stanza_error{reason = 'forbidden'} = xmpp:get_error(ErrMsg), + put_event(Config, set_unmoderated), + [104] = muc_recv_config_change_message(Config), + send(Config, #message{to = Room, type = groupchat}), + #message{from = MyNickJID, type = groupchat} = recv_message(Config), + ok = muc_leave(Config), + disconnect(Config). + +muc_config_private_messages_master(Config) -> + PeerNickJID = peer_muc_jid(Config), + ok = muc_master_join(Config), + ct:comment("Waiting for a private message from the slave"), + #message{from = PeerNickJID, type = chat} = recv_message(Config), + ok = muc_set_role(Config, visitor, <<>>), + ct:comment("Waiting for the peer to become a visitor"), + recv_muc_presence(Config, PeerNickJID, available), + ct:comment("Waiting for a private message from the slave"), + #message{from = PeerNickJID, type = chat} = recv_message(Config), + [104] = muc_set_config(Config, [{allow_private_messages_from_visitors, moderators}]), + ct:comment("Waiting for a private message from the slave"), + #message{from = PeerNickJID, type = chat} = recv_message(Config), + [104] = muc_set_config(Config, [{allow_private_messages_from_visitors, nobody}]), + wait_for_slave(Config), + [104] = muc_set_config(Config, [{allow_private_messages_from_visitors, anyone}, + {allow_private_messages, false}]), + ct:comment("Fail trying to send a private message"), + send(Config, #message{to = PeerNickJID, type = chat}), + #message{from = PeerNickJID, type = error} = ErrMsg = recv_message(Config), + #stanza_error{reason = 'forbidden'} = xmpp:get_error(ErrMsg), + ok = muc_set_role(Config, participant, <<>>), + ct:comment("Waiting for the peer to become a participant"), + recv_muc_presence(Config, PeerNickJID, available), + ct:comment("Waiting for the peer to leave"), + recv_muc_presence(Config, PeerNickJID, unavailable), + ok = muc_leave(Config), + disconnect(Config). + +muc_config_private_messages_slave(Config) -> + MyNickJID = my_muc_jid(Config), + PeerNickJID = peer_muc_jid(Config), + {[], _, _} = muc_slave_join(Config), + ct:comment("Sending a private message"), + send(Config, #message{to = PeerNickJID, type = chat}), + ct:comment("Waiting to become a visitor"), + #muc_user{items = [#muc_item{role = visitor}]} = + recv_muc_presence(Config, MyNickJID, available), + ct:comment("Sending a private message"), + send(Config, #message{to = PeerNickJID, type = chat}), + [104] = muc_recv_config_change_message(Config), + ct:comment("Sending a private message"), + send(Config, #message{to = PeerNickJID, type = chat}), + [104] = muc_recv_config_change_message(Config), + ct:comment("Fail trying to send a private message"), + send(Config, #message{to = PeerNickJID, type = chat}), + #message{from = PeerNickJID, type = error} = ErrMsg1 = recv_message(Config), + #stanza_error{reason = 'forbidden'} = xmpp:get_error(ErrMsg1), + wait_for_master(Config), + [104] = muc_recv_config_change_message(Config), + ct:comment("Waiting to become a participant again"), + #muc_user{items = [#muc_item{role = participant}]} = + recv_muc_presence(Config, MyNickJID, available), + ct:comment("Fail trying to send a private message"), + send(Config, #message{to = PeerNickJID, type = chat}), + #message{from = PeerNickJID, type = error} = ErrMsg2 = recv_message(Config), + #stanza_error{reason = 'forbidden'} = xmpp:get_error(ErrMsg2), + ok = muc_leave(Config), + disconnect(Config). + +muc_config_query_master(Config) -> + PeerNickJID = peer_muc_jid(Config), + ok = muc_join_new(Config), + wait_for_slave(Config), + recv_muc_presence(Config, PeerNickJID, available), + ct:comment("Receiving IQ query from the slave"), + #iq{type = get, from = PeerNickJID, id = I, + sub_els = [#ping{}]} = recv_iq(Config), + send(Config, #iq{type = result, to = PeerNickJID, id = I}), + [104] = muc_set_config(Config, [{allow_query_users, false}]), + ct:comment("Fail trying to send IQ"), + #iq{type = error, from = PeerNickJID} = Err = + send_recv(Config, #iq{type = get, to = PeerNickJID, + sub_els = [#ping{}]}), + #stanza_error{reason = 'not-allowed'} = xmpp:get_error(Err), + recv_muc_presence(Config, PeerNickJID, unavailable), + ok = muc_leave(Config), + disconnect(Config). + +muc_config_query_slave(Config) -> + PeerNickJID = peer_muc_jid(Config), + wait_for_master(Config), + ct:comment("Checking if IQ queries are denied from non-occupants"), + #iq{type = error, from = PeerNickJID} = Err1 = + send_recv(Config, #iq{type = get, to = PeerNickJID, + sub_els = [#ping{}]}), + #stanza_error{reason = 'not-acceptable'} = xmpp:get_error(Err1), + {[], _, _} = muc_join(Config), + ct:comment("Sending IQ to the master"), + #iq{type = result, from = PeerNickJID, sub_els = []} = + send_recv(Config, #iq{to = PeerNickJID, type = get, sub_els = [#ping{}]}), + [104] = muc_recv_config_change_message(Config), + ct:comment("Fail trying to send IQ"), + #iq{type = error, from = PeerNickJID} = Err2 = + send_recv(Config, #iq{type = get, to = PeerNickJID, + sub_els = [#ping{}]}), + #stanza_error{reason = 'not-allowed'} = xmpp:get_error(Err2), + ok = muc_leave(Config), + disconnect(Config). + +muc_config_allow_invites_master(Config) -> + Room = muc_room_jid(Config), + PeerJID = ?config(peer, Config), + PeerNickJID = peer_muc_jid(Config), + ok = muc_master_join(Config), + [104] = muc_set_config(Config, [{allowinvites, true}]), + ct:comment("Receiving an invitation from the slave"), + #message{from = Room, type = normal} = recv_message(Config), + [104] = muc_set_config(Config, [{allowinvites, false}]), + send_invitation = get_event(Config), + ct:comment("Sending an invitation"), + send(Config, #message{to = Room, type = normal, + sub_els = + [#muc_user{ + invites = + [#muc_invite{to = PeerJID}]}]}), + recv_muc_presence(Config, PeerNickJID, unavailable), + ok = muc_leave(Config), + disconnect(Config). + +muc_config_allow_invites_slave(Config) -> + Room = muc_room_jid(Config), + PeerJID = ?config(peer, Config), + InviteMsg = #message{to = Room, type = normal, + sub_els = + [#muc_user{ + invites = + [#muc_invite{to = PeerJID}]}]}, + {[], _, _} = muc_slave_join(Config), + [104] = muc_recv_config_change_message(Config), + ct:comment("Sending an invitation"), + send(Config, InviteMsg), + [104] = muc_recv_config_change_message(Config), + ct:comment("Fail sending an invitation"), + send(Config, InviteMsg), + #message{from = Room, type = error} = Err = recv_message(Config), + #stanza_error{reason = 'not-allowed'} = xmpp:get_error(Err), + ct:comment("Checking if the master is still able to send invitations"), + put_event(Config, send_invitation), + #message{from = Room, type = normal} = recv_message(Config), + ok = muc_leave(Config), + disconnect(Config). + +muc_config_visitor_status_master(Config) -> + PeerNickJID = peer_muc_jid(Config), + Status = xmpp:mk_text(randoms:get_string()), + ok = muc_join_new(Config), + [104] = muc_set_config(Config, [{members_by_default, false}]), + ct:comment("Asking the slave to join as a visitor"), + put_event(Config, {join, Status}), + #muc_user{items = [#muc_item{role = visitor}]} = + recv_muc_presence(Config, PeerNickJID, available), + ct:comment("Receiving status change from the visitor"), + #presence{from = PeerNickJID, status = Status} = recv_presence(Config), + [104] = muc_set_config(Config, [{allow_visitor_status, false}]), + ct:comment("Receiving status change with stripped"), + #presence{from = PeerNickJID, status = []} = recv_presence(Config), + ct:comment("Waiting for the slave to leave"), + recv_muc_presence(Config, PeerNickJID, unavailable), + ok = muc_leave(Config), + disconnect(Config). + +muc_config_visitor_status_slave(Config) -> + Room = muc_room_jid(Config), + MyNickJID = my_muc_jid(Config), + ct:comment("Waiting for 'join' command from the master"), + {join, Status} = get_event(Config), + {[], _, _} = muc_join(Config, visitor, none), + ct:comment("Sending status change"), + send(Config, #presence{to = Room, status = Status}), + #presence{from = MyNickJID, status = Status} = recv_presence(Config), + [104] = muc_recv_config_change_message(Config), + ct:comment("Sending status change again"), + send(Config, #presence{to = Room, status = Status}), + #presence{from = MyNickJID, status = []} = recv_presence(Config), + ok = muc_leave(Config), + disconnect(Config). + +muc_config_allow_voice_requests_master(Config) -> + PeerNickJID = peer_muc_jid(Config), + ok = muc_join_new(Config), + [104] = muc_set_config(Config, [{members_by_default, false}]), + ct:comment("Asking the slave to join as a visitor"), + put_event(Config, join), + #muc_user{items = [#muc_item{role = visitor}]} = + recv_muc_presence(Config, PeerNickJID, available), + [104] = muc_set_config(Config, [{allow_voice_requests, false}]), + ct:comment("Waiting for the slave to leave"), + recv_muc_presence(Config, PeerNickJID, unavailable), + ok = muc_leave(Config), + disconnect(Config). + +muc_config_allow_voice_requests_slave(Config) -> + Room = muc_room_jid(Config), + ct:comment("Waiting for 'join' command from the master"), + join = get_event(Config), + {[], _, _} = muc_join(Config, visitor), + [104] = muc_recv_config_change_message(Config), + ct:comment("Fail sending voice request"), + Fs = muc_request:encode([{role, participant}]), + X = #xdata{type = submit, fields = Fs}, + send(Config, #message{to = Room, sub_els = [X]}), + #message{from = Room, type = error} = Err = recv_message(Config), + #stanza_error{reason = 'forbidden'} = xmpp:get_error(Err), + ok = muc_leave(Config), + disconnect(Config). + +muc_config_voice_request_interval_master(Config) -> + Room = muc_room_jid(Config), + PeerJID = ?config(peer, Config), + PeerNick = ?config(peer_nick, Config), + PeerNickJID = peer_muc_jid(Config), + ok = muc_join_new(Config), + [104] = muc_set_config(Config, [{members_by_default, false}]), + ct:comment("Asking the slave to join as a visitor"), + put_event(Config, join), + #muc_user{items = [#muc_item{role = visitor}]} = + recv_muc_presence(Config, PeerNickJID, available), + [104] = muc_set_config(Config, [{voice_request_min_interval, 5}]), + ct:comment("Receiving a voice request from slave"), + #message{from = Room, type = normal} = recv_message(Config), + ct:comment("Deny voice request at first"), + Fs = muc_request:encode([{jid, PeerJID}, {role, participant}, + {nick, PeerNick}, {request_allow, false}]), + send(Config, #message{to = Room, sub_els = [#xdata{type = submit, + fields = Fs}]}), + put_event(Config, denied), + ct:comment("Waiting for repeated voice request from the slave"), + #message{from = Room, type = normal} = recv_message(Config), + ct:comment("Waiting for the slave to leave"), + recv_muc_presence(Config, PeerNickJID, unavailable), + ok = muc_leave(Config), + disconnect(Config). + +muc_config_voice_request_interval_slave(Config) -> + Room = muc_room_jid(Config), + Fs = muc_request:encode([{role, participant}]), + X = #xdata{type = submit, fields = Fs}, + ct:comment("Waiting for 'join' command from the master"), + join = get_event(Config), + {[], _, _} = muc_join(Config, visitor), + [104] = muc_recv_config_change_message(Config), + ct:comment("Sending voice request"), + send(Config, #message{to = Room, sub_els = [X]}), + ct:comment("Waiting for the master to deny our voice request"), + denied = get_event(Config), + ct:comment("Requesting voice again"), + send(Config, #message{to = Room, sub_els = [X]}), + ct:comment("Receving voice request error because we're sending to fast"), + #message{from = Room, type = error} = Err = recv_message(Config), + #stanza_error{reason = 'resource-constraint'} = xmpp:get_error(Err), + ct:comment("Waiting for 5 seconds"), + timer:sleep(timer:seconds(5)), + ct:comment("Repeating again"), + send(Config, #message{to = Room, sub_els = [X]}), + ok = muc_leave(Config), + disconnect(Config). + +muc_config_visitor_nickchange_master(Config) -> + PeerNickJID = peer_muc_jid(Config), + ok = muc_join_new(Config), + [104] = muc_set_config(Config, [{members_by_default, false}]), + ct:comment("Asking the slave to join as a visitor"), + put_event(Config, join), + ct:comment("Waiting for the slave to join"), + #muc_user{items = [#muc_item{role = visitor}]} = + recv_muc_presence(Config, PeerNickJID, available), + [104] = muc_set_config(Config, [{allow_visitor_nickchange, false}]), + ct:comment("Waiting for the slave to leave"), + recv_muc_presence(Config, PeerNickJID, unavailable), + ok = muc_leave(Config), + disconnect(Config). + +muc_config_visitor_nickchange_slave(Config) -> + NewNick = randoms:get_string(), + MyNickJID = my_muc_jid(Config), + MyNewNickJID = jid:replace_resource(MyNickJID, NewNick), + ct:comment("Waiting for 'join' command from the master"), + join = get_event(Config), + {[], _, _} = muc_join(Config, visitor), + [104] = muc_recv_config_change_message(Config), + ct:comment("Fail trying to change nickname"), + send(Config, #presence{to = MyNewNickJID}), + #presence{from = MyNewNickJID, type = error} = Err = recv_presence(Config), + #stanza_error{reason = 'not-allowed'} = xmpp:get_error(Err), + ok = muc_leave(Config), + disconnect(Config). + +muc_register_master(Config) -> + MUC = muc_jid(Config), + %% Register nick "master1" + muc_register_nick(Config, MUC, <<"">>, <<"master1">>), + %% Unregister nick "master1" via jabber:register + #iq{type = result, sub_els = []} = + send_recv(Config, #iq{type = set, to = MUC, + sub_els = [#register{remove = true}]}), + %% Register nick "master2" + muc_register_nick(Config, MUC, <<"">>, <<"master2">>), + %% Now register nick "master" + muc_register_nick(Config, MUC, <<"master2">>, <<"master">>), + %% Wait for slave to fail trying to register nick "master" + wait_for_slave(Config), + wait_for_slave(Config), + %% Now register empty ("") nick, which means we're unregistering + muc_register_nick(Config, MUC, <<"master">>, <<"">>), + disconnect(Config). + +muc_register_slave(Config) -> + MUC = muc_jid(Config), + wait_for_master(Config), + %% Trying to register occupied nick "master" + Fs = muc_register:encode([{roomnick, <<"master">>}]), + X = #xdata{type = submit, fields = Fs}, + #iq{type = error} = + send_recv(Config, #iq{type = set, to = MUC, + sub_els = [#register{xdata = X}]}), + wait_for_master(Config), + disconnect(Config). + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +master_slave_test(T) -> + {T, [parallel], [list_to_atom(atom_to_list(T) ++ "_master"), + list_to_atom(atom_to_list(T) ++ "_slave")]}. + +recv_muc_presence(Config, From, Type) -> + Pres = #presence{from = From, type = Type} = recv_presence(Config), + xmpp:get_subtag(Pres, #muc_user{}). + +muc_join_new(Config) -> + muc_join_new(Config, muc_room_jid(Config)). + +muc_join_new(Config, Room) -> + MyJID = my_jid(Config), + MyNick = ?config(nick, Config), + MyNickJID = jid:replace_resource(Room, MyNick), + ct:comment("Joining new room"), + send(Config, #presence{to = MyNickJID, sub_els = [#muc{}]}), + %% As per XEP-0045 we MUST receive stanzas in the following order: + %% 1. In-room presence from other occupants + %% 2. In-room presence from the joining entity itself (so-called "self-presence") + %% 3. Room history (if any) + %% 4. The room subject + %% 5. Live messages, presence updates, new user joins, etc. + %% As this is the newly created room, we receive only the 2nd and 4th stanza. + #muc_user{ + status_codes = Codes, + items = [#muc_item{role = moderator, + jid = MyJID, + affiliation = owner}]} = + xmpp:get_subtag(?recv1(#presence{from = MyNickJID}), #muc_user{}), + ct:comment("Checking if codes '110' (self-presence) and " + "'201' (new room) is set"), + true = lists:member(110, Codes), + true = lists:member(201, Codes), + ct:comment("Receiving empty room subject"), + #message{from = Room, type = groupchat, body = [], + subject = [#text{data = <<>>}]} = recv_message(Config), + case ?config(persistent_room, Config) of + true -> + [104] = muc_set_config(Config, [{persistentroom, true}], Room), + ok; + false -> + ok + end. + +muc_recv_history_and_subject(Config) -> + ct:comment("Receiving room history and/or subject"), + muc_recv_history_and_subject(Config, []). + +muc_recv_history_and_subject(Config, History) -> + Room = muc_room_jid(Config), + #message{type = groupchat, subject = Subj, + body = Body, thread = Thread} = Msg = recv_message(Config), + case xmpp:get_subtag(Msg, #delay{}) of + #delay{from = Room} -> + muc_recv_history_and_subject(Config, [Msg|History]); + false when Subj /= [], Body == [], Thread == undefined -> + {lists:reverse(History), Msg} + end. + +muc_join(Config) -> + muc_join(Config, participant, none, #muc{}). + +muc_join(Config, Role) when is_atom(Role) -> + muc_join(Config, Role, none, #muc{}); +muc_join(Config, #muc{} = SubEl) -> + muc_join(Config, participant, none, SubEl). + +muc_join(Config, Role, Aff) when is_atom(Role), is_atom(Aff) -> + muc_join(Config, Role, Aff, #muc{}); +muc_join(Config, Role, #muc{} = SubEl) when is_atom(Role) -> + muc_join(Config, Role, none, SubEl). + +muc_join(Config, Role, Aff, SubEl) -> + ct:comment("Joining existing room as ~s/~s", [Aff, Role]), + MyJID = my_jid(Config), + Room = muc_room_jid(Config), + MyNick = ?config(nick, Config), + MyNickJID = jid:replace_resource(Room, MyNick), + PeerNick = ?config(peer_nick, Config), + PeerNickJID = jid:replace_resource(Room, PeerNick), + send(Config, #presence{to = MyNickJID, sub_els = [SubEl]}), + case recv_presence(Config) of + #presence{type = error, from = MyNickJID} = Err -> + xmpp:get_subtag(Err, #stanza_error{}); + #presence{type = available, from = PeerNickJID} = Pres -> + #muc_user{items = [#muc_item{role = moderator, + affiliation = owner}]} = + xmpp:get_subtag(Pres, #muc_user{}), + ct:comment("Receiving initial self-presence"), + #muc_user{status_codes = Codes, + items = [#muc_item{role = Role, + jid = MyJID, + affiliation = Aff}]} = + recv_muc_presence(Config, MyNickJID, available), + ct:comment("Checking if code '110' (self-presence) is set"), + true = lists:member(110, Codes), + {History, Subj} = muc_recv_history_and_subject(Config), + {History, Subj, Codes}; + #presence{type = available, from = MyNickJID} = Pres -> + #muc_user{status_codes = Codes, + items = [#muc_item{role = Role, + jid = MyJID, + affiliation = Aff}]} = + xmpp:get_subtag(Pres, #muc_user{}), + ct:comment("Checking if code '110' (self-presence) is set"), + true = lists:member(110, Codes), + {History, Subj} = muc_recv_history_and_subject(Config), + {empty, History, Subj, Codes} + end. + +muc_leave(Config) -> + muc_leave(Config, muc_room_jid(Config)). + +muc_leave(Config, Room) -> + MyJID = my_jid(Config), + MyNick = ?config(nick, Config), + MyNickJID = jid:replace_resource(Room, MyNick), + Mode = ?config(mode, Config), + IsPersistent = ?config(persistent_room, Config), + if Mode /= slave, IsPersistent -> + [104] = muc_set_config(Config, [{persistentroom, false}], Room); + true -> + ok + end, + ct:comment("Leaving the room"), + send(Config, #presence{to = MyNickJID, type = unavailable}), + #muc_user{ + status_codes = Codes, + items = [#muc_item{role = none, jid = MyJID}]} = + xmpp:get_subtag(?recv1(#presence{from = MyNickJID, + type = unavailable}), #muc_user{}), + ct:comment("Checking if code '110' (self-presence) is set"), + true = lists:member(110, Codes), + ok. + +muc_get_config(Config) -> + ct:comment("Get room config"), + Room = muc_room_jid(Config), + case send_recv(Config, + #iq{type = get, to = Room, + sub_els = [#muc_owner{}]}) of + #iq{type = result, + sub_els = [#muc_owner{config = #xdata{type = form} = X}]} -> + muc_roomconfig:decode(X#xdata.fields); + #iq{type = error} = Err -> + xmpp:get_subtag(Err, #stanza_error{}) + end. + +muc_set_config(Config, RoomConfig) -> + muc_set_config(Config, RoomConfig, muc_room_jid(Config)). + +muc_set_config(Config, RoomConfig, Room) -> + ct:comment("Set room config: ~p", [RoomConfig]), + Fs = case RoomConfig of + [] -> []; + _ -> muc_roomconfig:encode(RoomConfig) + end, + case send_recv(Config, + #iq{type = set, to = Room, + sub_els = [#muc_owner{config = #xdata{type = submit, + fields = Fs}}]}) of + #iq{type = result, sub_els = []} -> + #message{from = Room, type = groupchat} = Msg = recv_message(Config), + #muc_user{status_codes = Codes} = xmpp:get_subtag(Msg, #muc_user{}), + lists:sort(Codes); + #iq{type = error} = Err -> + xmpp:get_subtag(Err, #stanza_error{}) + end. + +muc_create_persistent(Config) -> + [_|_] = muc_get_config(Config), + [] = muc_set_config(Config, [{persistentroom, true}], false), + ok. + +muc_destroy(Config) -> + muc_destroy(Config, <<>>). + +muc_destroy(Config, Reason) -> + Room = muc_room_jid(Config), + AltRoom = alt_room_jid(Config), + ct:comment("Destroying a room"), + case send_recv(Config, + #iq{type = set, to = Room, + sub_els = [#muc_owner{destroy = #muc_destroy{ + reason = Reason, + jid = AltRoom}}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = Err -> + xmpp:get_subtag(Err, #stanza_error{}) + end. + +muc_disco_items(Config) -> + MUC = muc_jid(Config), + ct:comment("Performing disco#items request to ~s", [jid:to_string(MUC)]), + #iq{type = result, from = MUC, sub_els = [DiscoItems]} = + send_recv(Config, #iq{type = get, to = MUC, + sub_els = [#disco_items{}]}), + lists:keysort(#disco_item.jid, DiscoItems#disco_items.items). + +muc_disco_room_items(Config) -> + Room = muc_room_jid(Config), + #iq{type = result, from = Room, sub_els = [DiscoItems]} = + send_recv(Config, #iq{type = get, to = Room, + sub_els = [#disco_items{}]}), + DiscoItems#disco_items.items. + +muc_get_affiliations(Config, Aff) -> + Room = muc_room_jid(Config), + case send_recv(Config, + #iq{type = get, to = Room, + sub_els = [#muc_admin{items = [#muc_item{affiliation = Aff}]}]}) of + #iq{type = result, sub_els = [#muc_admin{items = Items}]} -> + Items; + #iq{type = error} = Err -> + xmpp:get_subtag(Err, #stanza_error{}) + end. + +muc_master_join(Config) -> + Room = muc_room_jid(Config), + PeerJID = ?config(slave, Config), + PeerNick = ?config(slave_nick, Config), + PeerNickJID = jid:replace_resource(Room, PeerNick), + ok = muc_join_new(Config), + wait_for_slave(Config), + #muc_user{items = [#muc_item{jid = PeerJID, + role = participant, + affiliation = none}]} = + recv_muc_presence(Config, PeerNickJID, available), + ok. + +muc_slave_join(Config) -> + wait_for_master(Config), + muc_join(Config). + +muc_set_role(Config, Role, Reason) -> + ct:comment("Changing role to ~s", [Role]), + Room = muc_room_jid(Config), + PeerNick = ?config(slave_nick, Config), + case send_recv( + Config, + #iq{type = set, to = Room, + sub_els = + [#muc_admin{ + items = [#muc_item{role = Role, + reason = Reason, + nick = PeerNick}]}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = Err -> + xmpp:get_subtag(Err, #stanza_error{}) + end. + +muc_get_role(Config, Role) -> + ct:comment("Requesting list for role '~s'", [Role]), + Room = muc_room_jid(Config), + case send_recv( + Config, + #iq{type = get, to = Room, + sub_els = [#muc_admin{ + items = [#muc_item{role = Role}]}]}) of + #iq{type = result, sub_els = [#muc_admin{items = Items}]} -> + lists:keysort(#muc_item.affiliation, Items); + #iq{type = error} = Err -> + xmpp:get_subtag(Err, #stanza_error{}) + end. + +muc_set_affiliation(Config, Aff, Reason) -> + ct:comment("Changing affiliation to ~s", [Aff]), + Room = muc_room_jid(Config), + PeerJID = ?config(slave, Config), + PeerBareJID = jid:remove_resource(PeerJID), + case send_recv( + Config, + #iq{type = set, to = Room, + sub_els = + [#muc_admin{ + items = [#muc_item{affiliation = Aff, + reason = Reason, + jid = PeerBareJID}]}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = Err -> + xmpp:get_subtag(Err, #stanza_error{}) + end. + +muc_get_affiliation(Config, Aff) -> + ct:comment("Requesting list for affiliation '~s'", [Aff]), + Room = muc_room_jid(Config), + case send_recv( + Config, + #iq{type = get, to = Room, + sub_els = [#muc_admin{ + items = [#muc_item{affiliation = Aff}]}]}) of + #iq{type = result, sub_els = [#muc_admin{items = Items}]} -> + Items; + #iq{type = error} = Err -> + xmpp:get_subtag(Err, #stanza_error{}) + end. + +muc_set_vcard(Config, VCard) -> + Room = muc_room_jid(Config), + ct:comment("Setting vCard for ~s", [jid:to_string(Room)]), + case send_recv(Config, #iq{type = set, to = Room, + sub_els = [VCard]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = Err -> + xmpp:get_subtag(Err, #stanza_error{}) + end. + +muc_get_vcard(Config) -> + Room = muc_room_jid(Config), + ct:comment("Retreiving vCard from ~s", [jid:to_string(Room)]), + case send_recv(Config, #iq{type = get, to = Room, + sub_els = [#vcard_temp{}]}) of + #iq{type = result, sub_els = [VCard]} -> + VCard; + #iq{type = error} = Err -> + xmpp:get_subtag(Err, #stanza_error{}) + end. + +muc_recv_config_change_message(Config) -> + ct:comment("Receiving configuration change notification message"), + Room = muc_room_jid(Config), + #message{type = groupchat, from = Room} = Msg = recv_message(Config), + #muc_user{status_codes = Codes} = xmpp:get_subtag(Msg, #muc_user{}), + lists:sort(Codes). + +muc_register_nick(Config, MUC, PrevNick, Nick) -> + PrevRegistered = if PrevNick /= <<"">> -> true; + true -> false + end, + NewRegistered = if Nick /= <<"">> -> true; + true -> false + end, + ct:comment("Requesting registration form"), + #iq{type = result, + sub_els = [#register{registered = PrevRegistered, + xdata = #xdata{type = form, + fields = FsWithoutNick}}]} = + send_recv(Config, #iq{type = get, to = MUC, + sub_els = [#register{}]}), + ct:comment("Checking if previous nick is registered"), + PrevNick = proplists:get_value( + roomnick, muc_register:decode(FsWithoutNick)), + X = #xdata{type = submit, fields = muc_register:encode([{roomnick, Nick}])}, + ct:comment("Submitting registration form"), + #iq{type = result, sub_els = []} = + send_recv(Config, #iq{type = set, to = MUC, + sub_els = [#register{xdata = X}]}), + ct:comment("Checking if new nick was registered"), + #iq{type = result, + sub_els = [#register{registered = NewRegistered, + xdata = #xdata{type = form, + fields = FsWithNick}}]} = + send_recv(Config, #iq{type = get, to = MUC, + sub_els = [#register{}]}), + Nick = proplists:get_value( + roomnick, muc_register:decode(FsWithNick)). + +muc_subscribe(Config, Events, Room) -> + MyNick = ?config(nick, Config), + case send_recv(Config, + #iq{type = set, to = Room, + sub_els = [#muc_subscribe{nick = MyNick, + events = Events}]}) of + #iq{type = result, sub_els = [#muc_subscribe{events = ResEvents}]} -> + lists:sort(ResEvents); + #iq{type = error} = Err -> + xmpp:get_error(Err) + end. + +muc_unsubscribe(Config, Room) -> + case send_recv(Config, #iq{type = set, to = Room, + sub_els = [#muc_unsubscribe{}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = Err -> + xmpp:get_error(Err) + end. diff --git a/test/suite.erl b/test/suite.erl index ed1cbd83d..7a823844b 100644 --- a/test/suite.erl +++ b/test/suite.erl @@ -70,10 +70,12 @@ init_config(Config) -> {s2s_port, ct:get_config(s2s_port, 5269)}, {server, ?COMMON_VHOST}, {user, <<"test_single!#$%^*()`~+-;_=[]{}|\\">>}, + {nick, <<"nick!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, {master_nick, <<"master_nick!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, {slave_nick, <<"slave_nick!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, {room_subject, <<"hello, world!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}, {certfile, CertFile}, + {persistent_room, true}, {anonymous, false}, {type, client}, {xmlns, ?NS_CLIENT}, @@ -210,6 +212,7 @@ process_stream_features(Config) -> end, set_opt(mechs, Mechs, Config), Fs). disconnect(Config) -> + ct:comment("Disconnecting"), Socket = ?config(socket, Config), try ok = send_text(Config, ?STREAM_TRAILER) @@ -435,22 +438,50 @@ match_failure(Received, Matches) -> recv(Config) -> receive {'$gen_event', {xmlstreamelement, El}} -> - NS = case ?config(type, Config) of - client -> ?NS_CLIENT; - server -> ?NS_SERVER; - component -> ?NS_COMPONENT - end, - decode(El, NS, []); + decode_stream_element(Config, El); {'$gen_event', {xmlstreamstart, Name, Attrs}} -> decode(#xmlel{name = Name, attrs = Attrs}, <<>>, []); {'$gen_event', Event} -> Event end. +recv_iq(Config) -> + receive + {'$gen_event', {xmlstreamelement, #xmlel{name = <<"iq">>} = El}} -> + decode_stream_element(Config, El) + end. + +recv_presence(Config) -> + receive + {'$gen_event', {xmlstreamelement, #xmlel{name = <<"presence">>} = El}} -> + decode_stream_element(Config, El) + end. + +recv_message(Config) -> + receive + {'$gen_event', {xmlstreamelement, #xmlel{name = <<"message">>} = El}} -> + decode_stream_element(Config, El) + end. + +decode_stream_element(Config, El) -> + NS = case ?config(type, Config) of + client -> ?NS_CLIENT; + server -> ?NS_SERVER; + component -> ?NS_COMPONENT + end, + decode(El, NS, []). + +format_element(El) -> + case erlang:function_exported(ct, log, 5) of + true -> ejabberd_web_admin:pretty_print_xml(El); + false -> io_lib:format(" ~s~n", El) + end. + decode(El, NS, Opts) -> try Pkt = xmpp:decode(El, NS, Opts), - ct:pal("recv: ~p ->~n~s", [El, xmpp:pp(Pkt)]), + ct:pal("RECV:~n~s~n~s", + [format_element(El), xmpp:pp(Pkt)]), Pkt catch _:{xmpp_codec, Why} -> ct:fail("recv failed: ~p->~n~s", @@ -475,7 +506,8 @@ send(State, Pkt) -> {undefined, Pkt} end, El = xmpp:encode(NewPkt), - ct:pal("sent: ~p <-~n~s", [El, xmpp:pp(NewPkt)]), + ct:pal("SENT:~n~s~n~s", + [format_element(El), xmpp:pp(NewPkt)]), Data = case NewPkt of #stream_start{} -> fxml:element_to_header(El); _ -> fxml:element_to_binary(El) @@ -483,9 +515,15 @@ send(State, Pkt) -> ok = send_text(State, Data), NewID. -send_recv(State, IQ) -> +send_recv(State, #message{} = Msg) -> + ID = send(State, Msg), + #message{id = ID} = recv_message(State); +send_recv(State, #presence{} = Pres) -> + ID = send(State, Pres), + #presence{id = ID} = recv_presence(State); +send_recv(State, #iq{} = IQ) -> ID = send(State, IQ), - #iq{id = ID} = recv(State). + #iq{id = ID} = recv_iq(State). sasl_new(<<"PLAIN">>, User, Server, Password) -> {<>, @@ -590,6 +628,20 @@ muc_room_jid(Config) -> Server = ?config(server, Config), jid:make(<<"test">>, <<"conference.", Server/binary>>, <<>>). +my_muc_jid(Config) -> + Nick = ?config(nick, Config), + RoomJID = muc_room_jid(Config), + jid:replace_resource(RoomJID, Nick). + +peer_muc_jid(Config) -> + PeerNick = ?config(peer_nick, Config), + RoomJID = muc_room_jid(Config), + jid:replace_resource(RoomJID, PeerNick). + +alt_room_jid(Config) -> + Server = ?config(server, Config), + jid:make(<<"alt">>, <<"conference.", Server/binary>>, <<>>). + mix_jid(Config) -> Server = ?config(server, Config), jid:make(<<>>, <<"mix.", Server/binary>>, <<>>). @@ -610,6 +662,7 @@ get_features(Config) -> get_features(Config, server_jid(Config)). get_features(Config, To) -> + ct:comment("Getting features of ~s", [jid:to_string(To)]), #iq{type = result, sub_els = [#disco_info{features = Features}]} = send_recv(Config, #iq{type = get, sub_els = [#disco_info{}], to = To}), Features. @@ -707,3 +760,10 @@ get_event(Config) -> {event, Event, Relay} -> Event end. + +flush(Config) -> + flush(Config, []). + +flush(Config, Msgs) -> + receive Msg -> flush(Config, [Msg|Msgs]) + after 1000 -> lists:reverse(Msgs) end. From f56840a68271c52fa17a51f7de2601e55da14018 Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Wed, 19 Oct 2016 23:11:26 +0200 Subject: [PATCH 056/151] Don't let systemd hide /home and /tmp Admins might expect ejabberd to be able to access data below /home or /tmp. For example, they might use those locations to dump/restore Mnesia backups, or as a document root for mod_http_fileserver or mod_http_upload. Fixes #1297. --- ejabberd.service.template | 2 -- 1 file changed, 2 deletions(-) diff --git a/ejabberd.service.template b/ejabberd.service.template index 49ba14737..fdb8fd0b7 100644 --- a/ejabberd.service.template +++ b/ejabberd.service.template @@ -14,9 +14,7 @@ Type=oneshot RemainAfterExit=yes # The CAP_DAC_OVERRIDE capability is required for pam authentication to work CapabilityBoundingSet=CAP_DAC_OVERRIDE -PrivateTmp=true PrivateDevices=true -ProtectHome=true ProtectSystem=full NoNewPrivileges=true From c3b62d2f75d70a6a6069f4e6a49c374e2fd52809 Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Wed, 19 Oct 2016 23:29:46 +0200 Subject: [PATCH 057/151] Don't set "NoNewPrivileges" in systemd unit The "NoNewPrivileges" setting breaks some PAM and extauth setups. Fixes #1281. --- ejabberd.service.template | 3 --- 1 file changed, 3 deletions(-) diff --git a/ejabberd.service.template b/ejabberd.service.template index fdb8fd0b7..4a2635776 100644 --- a/ejabberd.service.template +++ b/ejabberd.service.template @@ -12,11 +12,8 @@ ExecStop=@ctlscriptpath@/ejabberdctl stop ExecReload=@ctlscriptpath@/ejabberdctl reload_config Type=oneshot RemainAfterExit=yes -# The CAP_DAC_OVERRIDE capability is required for pam authentication to work -CapabilityBoundingSet=CAP_DAC_OVERRIDE PrivateDevices=true ProtectSystem=full -NoNewPrivileges=true [Install] WantedBy=multi-user.target From 686305bb2174c0c8b8cc9c1b4a5635567a90b519 Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Wed, 19 Oct 2016 23:32:07 +0200 Subject: [PATCH 058/151] Use "Type=forking" in systemd unit ejabberd is not a "oneshot" process. --- ejabberd.service.template | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ejabberd.service.template b/ejabberd.service.template index 4a2635776..7322e07c3 100644 --- a/ejabberd.service.template +++ b/ejabberd.service.template @@ -3,6 +3,7 @@ Description=XMPP Server After=network.target [Service] +Type=forking User=ejabberd Group=ejabberd LimitNOFILE=16000 @@ -10,8 +11,6 @@ RestartSec=5 ExecStart=@ctlscriptpath@/ejabberdctl start ExecStop=@ctlscriptpath@/ejabberdctl stop ExecReload=@ctlscriptpath@/ejabberdctl reload_config -Type=oneshot -RemainAfterExit=yes PrivateDevices=true ProtectSystem=full From 76215648396144ea7b8268e040de67b96b75dd83 Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Wed, 19 Oct 2016 23:35:22 +0200 Subject: [PATCH 059/151] Let systemd restart ejabberd on failure The "RestartSec=5" setting has no effect if "Restart" is not also specified. --- ejabberd.service.template | 1 + 1 file changed, 1 insertion(+) diff --git a/ejabberd.service.template b/ejabberd.service.template index 7322e07c3..ff159f85c 100644 --- a/ejabberd.service.template +++ b/ejabberd.service.template @@ -7,6 +7,7 @@ Type=forking User=ejabberd Group=ejabberd LimitNOFILE=16000 +Restart=on-failure RestartSec=5 ExecStart=@ctlscriptpath@/ejabberdctl start ExecStop=@ctlscriptpath@/ejabberdctl stop From 0a3fcc9adea3db4c92bbb2a6d9d2b8ff5b8c8675 Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Wed, 19 Oct 2016 23:37:26 +0200 Subject: [PATCH 060/151] Don't specify "ExecReload" command in systemd unit The "reload_config" command doesn't work the way admins would typically expect, so it shouldn't be exposed via systemd. Those who understand the behavior can execute the command using ejabberdctl. --- ejabberd.service.template | 1 - 1 file changed, 1 deletion(-) diff --git a/ejabberd.service.template b/ejabberd.service.template index ff159f85c..80f023889 100644 --- a/ejabberd.service.template +++ b/ejabberd.service.template @@ -11,7 +11,6 @@ Restart=on-failure RestartSec=5 ExecStart=@ctlscriptpath@/ejabberdctl start ExecStop=@ctlscriptpath@/ejabberdctl stop -ExecReload=@ctlscriptpath@/ejabberdctl reload_config PrivateDevices=true ProtectSystem=full From a5e737157c2e2b17f745334441a0aa59df08c0a6 Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Thu, 20 Oct 2016 00:12:02 +0200 Subject: [PATCH 061/151] Increase file descriptor limit in systemd unit 16,000 file descriptors will only suffice for small setups. --- ejabberd.service.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ejabberd.service.template b/ejabberd.service.template index 80f023889..560a93265 100644 --- a/ejabberd.service.template +++ b/ejabberd.service.template @@ -6,7 +6,7 @@ After=network.target Type=forking User=ejabberd Group=ejabberd -LimitNOFILE=16000 +LimitNOFILE=65536 Restart=on-failure RestartSec=5 ExecStart=@ctlscriptpath@/ejabberdctl start From 1bdbe54442098ed4c54219de834f22109a4e9868 Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Thu, 20 Oct 2016 00:27:50 +0200 Subject: [PATCH 062/151] Let systemd stop ejabberd gracefully Make sure the "ExecStop" command line blocks until ejabberd is actually stopped. This prevents systemd from killing the ejabberd process(es) immediately. Also, let the "ExecStart" command line block until ejabberd's startup is completed. This makes sure that services which depend on ejabberd aren't started up too early. --- ejabberd.service.template | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ejabberd.service.template b/ejabberd.service.template index 560a93265..a70d2254d 100644 --- a/ejabberd.service.template +++ b/ejabberd.service.template @@ -9,8 +9,8 @@ Group=ejabberd LimitNOFILE=65536 Restart=on-failure RestartSec=5 -ExecStart=@ctlscriptpath@/ejabberdctl start -ExecStop=@ctlscriptpath@/ejabberdctl stop +ExecStart=/bin/sh -c '@ctlscriptpath@/ejabberdctl start && @ctlscriptpath@/ejabberdctl started' +ExecStop=/bin/sh -c '@ctlscriptpath@/ejabberdctl stop && @ctlscriptpath@/ejabberdctl stopped' PrivateDevices=true ProtectSystem=full From f6236d456d599544baed11d51c3e6d7ef7e459eb Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sat, 22 Oct 2016 13:01:45 +0300 Subject: [PATCH 063/151] Add more tests for privacy lists and blocking command --- src/ejabberd_c2s.erl | 174 ++++---- src/ejabberd_piefxis.erl | 2 +- src/ejabberd_socket.erl | 9 +- src/mod_admin_extra.erl | 6 +- src/mod_blocking.erl | 13 +- src/mod_privacy.erl | 67 ++-- src/mod_roster.erl | 9 +- test/ejabberd_SUITE.erl | 839 ++++++++++++++++++++------------------- test/muc_tests.erl | 26 +- test/privacy_tests.erl | 821 ++++++++++++++++++++++++++++++++++++++ test/suite.erl | 137 ++++--- 11 files changed, 1508 insertions(+), 595 deletions(-) create mode 100644 test/privacy_tests.erl diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index f7d8e9dbb..986310546 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -881,18 +881,20 @@ decode_element(#xmlel{} = El, StateName, StateData) -> end catch error:{xmpp_codec, Why} -> NS = xmpp:get_ns(El), - case xmpp:is_stanza(El) of - true -> - Lang = xmpp:get_lang(El), - Txt = xmpp:format_error(Why), - send_error(StateData, El, xmpp:err_bad_request(Txt, Lang)); - false when NS == ?NS_STREAM_MGMT_2; NS == ?NS_STREAM_MGMT_3 -> - Err = #sm_failed{reason = 'bad-request', xmlns = NS}, - send_element(StateData, Err); - false -> - ok - end, - fsm_next_state(StateName, StateData) + fsm_next_state( + StateName, + case xmpp:is_stanza(El) of + true -> + Lang = xmpp:get_lang(El), + Txt = xmpp:format_error(Why), + send_error(StateData, El, xmpp:err_bad_request(Txt, Lang)); + false when NS == ?NS_STREAM_MGMT_2; NS == ?NS_STREAM_MGMT_3 -> + Err = #sm_failed{reason = 'bad-request', xmlns = NS}, + send_element(StateData, Err), + StateData; + false -> + StateData + end) end. wait_for_bind({xmlstreamelement, El}, StateData) -> @@ -957,13 +959,14 @@ wait_for_bind(closed, StateData) -> wait_for_bind(stop, StateData) -> {stop, normal, StateData}; wait_for_bind(Pkt, StateData) -> - case xmpp:is_stanza(Pkt) of - true -> - send_error(StateData, Pkt, xmpp:err_not_acceptable()); - false -> - ok - end, - fsm_next_state(wait_for_bind, StateData). + fsm_next_state( + wait_for_bind, + case xmpp:is_stanza(Pkt) of + true -> + send_error(StateData, Pkt, xmpp:err_not_acceptable()); + false -> + StateData + end). -spec open_session(state()) -> {ok, state()} | {error, stanza_error()}. open_session(StateData) -> @@ -1315,27 +1318,23 @@ handle_info({route, From, To, Packet}, StateName, StateData) when ?is_stanza(Pac allow -> {true, StateData}; deny -> - Err = xmpp:make_error( - Packet, - xmpp:err_service_unavailable()), - ejabberd_router:route(To, From, Err), + ejabberd_router:route_error( + To, From, Packet, + xmpp:err_service_unavailable()), {false, StateData} end; _ -> - Err = xmpp:make_error(Packet, xmpp:err_forbidden()), - ejabberd_router:route(To, From, Err), + ejabberd_router:route_error( + To, From, Packet, xmpp:err_forbidden()), {false, StateData} end; _ -> case privacy_check_packet(StateData, From, To, Packet, in) of allow -> {true, StateData}; - deny when T == get; T == set -> - Err = xmpp:make_error( - Packet, xmpp:err_service_unavailable()), - ejabberd_router:route(To, From, Err), - {false, StateData}; deny -> + ejabberd_router:route_error( + To, From, Packet, xmpp:err_service_unavailable()), {false, StateData} end end; @@ -1345,13 +1344,11 @@ handle_info({route, From, To, Packet}, StateName, StateData) when ?is_stanza(Pac {true, StateData}; deny -> case T of - error -> ok; groupchat -> ok; headline -> ok; _ -> - Err = xmpp:make_error( - Packet, xmpp:err_service_unavailable()), - ejabberd_router:route(To, From, Err) + ejabberd_router:route_error( + To, From, Packet, xmpp:err_service_unavailable()) end, {false, StateData} end @@ -1572,14 +1569,14 @@ send_element(StateData, #xmlel{} = El) -> send_element(StateData, Pkt) -> send_element(StateData, xmpp:encode(Pkt, ?NS_CLIENT)). --spec send_error(state(), xmlel() | stanza(), stanza_error()) -> ok. +-spec send_error(state(), xmlel() | stanza(), stanza_error()) -> state(). send_error(StateData, Stanza, Error) -> Type = xmpp:get_type(Stanza), if Type == error; Type == result; Type == <<"error">>; Type == <<"result">> -> - ok; + StateData; true -> - send_element(StateData, xmpp:make_error(Stanza, Error)) + send_stanza(StateData, xmpp:make_error(Stanza, Error)) end. -spec send_stanza(state(), xmpp_element()) -> state(). @@ -1754,47 +1751,56 @@ presence_track(From, To, Packet, StateData) -> LTo = jid:tolower(To), User = StateData#state.user, Server = StateData#state.server, - case Type of - unavailable -> - A = ?SETS:del_element(LTo, StateData#state.pres_a), - check_privacy_route(From, StateData#state{pres_a = A}, From, To, Packet); - subscribe -> - try_roster_subscribe(subscribe, User, Server, From, To, Packet, StateData); - subscribed -> - ejabberd_hooks:run(roster_out_subscription, Server, - [User, Server, To, subscribed]), - check_privacy_route(From, StateData, - jid:remove_resource(From), To, Packet); - unsubscribe -> - try_roster_subscribe(unsubscribe, User, Server, From, To, Packet, StateData); - unsubscribed -> - ejabberd_hooks:run(roster_out_subscription, Server, - [User, Server, To, unsubscribed]), - check_privacy_route(From, StateData, - jid:remove_resource(From), To, Packet); - error -> - check_privacy_route(From, StateData, From, To, Packet); - probe -> - check_privacy_route(From, StateData, From, To, Packet); - _ -> - A = (?SETS):add_element(LTo, StateData#state.pres_a), - check_privacy_route(From, StateData#state{pres_a = A}, From, To, Packet) + Lang = StateData#state.lang, + case privacy_check_packet(StateData, From, To, Packet, out) of + deny -> + ErrText = <<"Your active privacy list has denied " + "the routing of this stanza.">>, + Err = xmpp:err_not_acceptable(ErrText, Lang), + send_error(StateData, xmpp:set_from_to(Packet, From, To), Err); + allow when Type == subscribe; Type == subscribed; + Type == unsubscribe; Type == unsubscribed -> + Access = gen_mod:get_module_opt(Server, mod_roster, access, + fun(A) when is_atom(A) -> A end, + all), + MyBareJID = jid:make(User, Server, <<"">>), + case acl:match_rule(Server, Access, MyBareJID) of + deny -> + ErrText = <<"Denied by ACL">>, + Err = xmpp:err_forbidden(ErrText, Lang), + send_error(StateData, xmpp:set_from_to(Packet, From, To), Err); + allow -> + ejabberd_hooks:run(roster_out_subscription, + Server, + [User, Server, To, Type]), + ejabberd_router:route(jid:remove_resource(From), To, Packet), + StateData + end; + allow when Type == error; Type == probe -> + ejabberd_router:route(From, To, Packet), + StateData; + allow -> + ejabberd_router:route(From, To, Packet), + A = case Type of + available -> + ?SETS:add_element(LTo, StateData#state.pres_a); + unavailable -> + ?SETS:del_element(LTo, StateData#state.pres_a) + end, + StateData#state{pres_a = A} end. -spec check_privacy_route(jid(), state(), jid(), jid(), stanza()) -> state(). check_privacy_route(From, StateData, FromRoute, To, Packet) -> case privacy_check_packet(StateData, From, To, Packet, - out) - of + out) of deny -> Lang = StateData#state.lang, ErrText = <<"Your active privacy list has denied " - "the routing of this stanza.">>, - Err = xmpp:make_error( - xmpp:set_from_to(Packet, From, To), - xmpp:err_not_acceptable(ErrText, Lang)), - send_stanza(StateData, Err); + "the routing of this stanza.">>, + Err = xmpp:err_not_acceptable(ErrText, Lang), + send_error(StateData, xmpp:set_from_to(Packet, From, To), Err); allow -> ejabberd_router:route(FromRoute, To, Packet), StateData @@ -1815,24 +1821,6 @@ is_privacy_allow(StateData, From, To, Packet, Dir) -> allow == privacy_check_packet(StateData, From, To, Packet, Dir). -%%% Check ACL before allowing to send a subscription stanza --spec try_roster_subscribe(subscribe | unsubscribe, binary(), binary(), - jid(), jid(), presence(), state()) -> state(). -try_roster_subscribe(Type, User, Server, From, To, Packet, StateData) -> - JID1 = jid:make(User, Server, <<"">>), - Access = gen_mod:get_module_opt(Server, mod_roster, access, fun(A) when is_atom(A) -> A end, all), - case acl:match_rule(Server, Access, JID1) of - deny -> - %% Silently drop this (un)subscription request - StateData; - allow -> - ejabberd_hooks:run(roster_out_subscription, - Server, - [User, Server, To, Type]), - check_privacy_route(From, StateData, jid:remove_resource(From), - To, Packet) - end. - %% Send presence when disconnecting -spec presence_broadcast(state(), jid(), ?SETS:set(), presence()) -> ok. presence_broadcast(StateData, From, JIDSet, Packet) -> @@ -1980,7 +1968,7 @@ process_privacy_iq(#iq{from = From, to = To, privacy_iq_set, StateData#state.server, {error, xmpp:err_feature_not_implemented(Txt, Lang)}, - [IQ]) + [IQ, StateData#state.privacy_list]) of {result, R, NewPrivList} -> {{result, R}, @@ -2522,9 +2510,8 @@ handle_unacked_stanzas(#state{mgmt_state = MgmtState} = StateData) false -> fun(From, To, El, _Time) -> Txt = <<"User session terminated">>, - Err = xmpp:make_error( - El, xmpp:err_service_unavailable(Txt, Lang)), - ejabberd_router:route(To, From, Err) + ejabberd_router:route_error( + To, From, El, xmpp:err_service_unavailable(Txt, Lang)) end end, F = fun(From, _To, #presence{}, _Time) -> @@ -2532,9 +2519,8 @@ handle_unacked_stanzas(#state{mgmt_state = MgmtState} = StateData) [jid:to_string(From)]); (From, To, #iq{} = El, _Time) -> Txt = <<"User session terminated">>, - Err = xmpp:make_error( - El, xmpp:err_service_unavailable(Txt, Lang)), - ejabberd_router:route(To, From, Err); + ejabberd_router:route_error( + To, From, El, xmpp:err_service_unavailable(Txt, Lang)); (From, To, El, Time) -> %% We'll drop the stanza if it was by some %% encapsulating protocol as per XEP-0297. One such protocol is diff --git a/src/ejabberd_piefxis.erl b/src/ejabberd_piefxis.erl index 5e6e1bf58..0e79c9913 100644 --- a/src/ejabberd_piefxis.erl +++ b/src/ejabberd_piefxis.erl @@ -486,7 +486,7 @@ process_privacy(#privacy_query{lists = Lists, from = JID, to = JID, sub_els = [PrivacyQuery]}, Txt = <<"No module is handling this query">>, Error = {error, xmpp:err_feature_not_implemented(Txt, ?MYLANG)}, - case mod_privacy:process_iq_set(Error, IQ) of + case mod_privacy:process_iq_set(Error, IQ, #userlist{}) of {error, #stanza_error{reason = Reason}} = Err -> if Reason == 'item-not-found', Lists == [], Active == undefined, Default /= undefined -> diff --git a/src/ejabberd_socket.erl b/src/ejabberd_socket.erl index f8dc84630..b5fa52ded 100644 --- a/src/ejabberd_socket.erl +++ b/src/ejabberd_socket.erl @@ -31,6 +31,7 @@ -export([start/4, connect/3, connect/4, + connect/5, starttls/2, starttls/3, compress/1, @@ -125,19 +126,21 @@ start(Module, SockMod, Socket, Opts) -> end. connect(Addr, Port, Opts) -> - connect(Addr, Port, Opts, infinity). + connect(Addr, Port, Opts, infinity, self()). connect(Addr, Port, Opts, Timeout) -> + connect(Addr, Port, Opts, Timeout, self()). + +connect(Addr, Port, Opts, Timeout, Owner) -> case gen_tcp:connect(Addr, Port, Opts, Timeout) of {ok, Socket} -> Receiver = ejabberd_receiver:start(Socket, gen_tcp, none), SocketData = #socket_state{sockmod = gen_tcp, socket = Socket, receiver = Receiver}, - Pid = self(), case gen_tcp:controlling_process(Socket, Receiver) of ok -> - ejabberd_receiver:become_controller(Receiver, Pid), + ejabberd_receiver:become_controller(Receiver, Owner), {ok, SocketData}; {error, _Reason} = Error -> gen_tcp:close(Socket), Error end; diff --git a/src/mod_admin_extra.erl b/src/mod_admin_extra.erl index 627b5b58f..4598805c2 100644 --- a/src/mod_admin_extra.erl +++ b/src/mod_admin_extra.erl @@ -53,6 +53,7 @@ -include("ejabberd.hrl"). -include("ejabberd_commands.hrl"). -include("mod_roster.hrl"). +-include("mod_privacy.hrl"). -include("ejabberd_sm.hrl"). -include("xmpp.hrl"). @@ -1380,11 +1381,12 @@ privacy_set(Username, Host, QueryS) -> To = jid:make(Host), QueryEl = fxml_stream:parse_element(QueryS), SubEl = xmpp:decode(QueryEl), - IQ = #iq{type = set, id = <<"push">>, sub_els = [SubEl]}, + IQ = #iq{type = set, id = <<"push">>, sub_els = [SubEl], + from = From, to = To}, ejabberd_hooks:run_fold(privacy_iq_set, Host, {error, xmpp:err_feature_not_implemented()}, - [From, To, IQ]), + [IQ, #userlist{}]), ok. %%% diff --git a/src/mod_blocking.erl b/src/mod_blocking.erl index b3bbff96e..d2b187d26 100644 --- a/src/mod_blocking.erl +++ b/src/mod_blocking.erl @@ -30,7 +30,7 @@ -protocol({xep, 191, '1.2'}). -export([start/2, stop/1, process_iq/1, - process_iq_set/2, process_iq_get/3, mod_opt_type/1, depends/2]). + process_iq_set/3, process_iq_get/3, mod_opt_type/1, depends/2]). -include("ejabberd.hrl"). -include("logger.hrl"). @@ -85,10 +85,11 @@ process_iq_get(Acc, _, _) -> Acc. -spec process_iq_set({error, stanza_error()} | {result, xmpp_element() | undefined} | {result, xmpp_element() | undefined, userlist()}, - iq()) -> {error, stanza_error()} | - {result, xmpp_element() | undefined} | - {result, xmpp_element() | undefined, userlist()}. -process_iq_set(Acc, #iq{from = From, lang = Lang, sub_els = [SubEl]}) -> + iq(), userlist()) -> + {error, stanza_error()} | + {result, xmpp_element() | undefined} | + {result, xmpp_element() | undefined, userlist()}. +process_iq_set(Acc, #iq{from = From, lang = Lang, sub_els = [SubEl]}, _) -> #jid{luser = LUser, lserver = LServer} = From, case SubEl of #block{items = []} -> @@ -105,7 +106,7 @@ process_iq_set(Acc, #iq{from = From, lang = Lang, sub_els = [SubEl]}) -> _ -> Acc end; -process_iq_set(Acc, _) -> Acc. +process_iq_set(Acc, _, _) -> Acc. -spec list_to_blocklist_jids([listitem()], [ljid()]) -> [ljid()]. list_to_blocklist_jids([], JIDs) -> JIDs; diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index 2f318deec..d4c8464f1 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -32,7 +32,7 @@ -behaviour(gen_mod). -export([start/2, stop/1, process_iq/1, export/1, import/1, - process_iq_set/2, process_iq_get/3, get_user_list/3, + process_iq_set/3, process_iq_get/3, get_user_list/3, check_packet/6, remove_user/2, encode_list_item/1, is_list_needdb/1, updated_list/3, item_to_xml/1, get_user_lists/2, import/3, @@ -103,6 +103,12 @@ process_iq(IQ) -> -spec process_iq_get({error, stanza_error()} | {result, xmpp_element() | undefined}, iq(), userlist()) -> {error, stanza_error()} | {result, xmpp_element() | undefined}. +process_iq_get(_, #iq{lang = Lang, + sub_els = [#privacy_query{default = Default, + active = Active}]}, + _) when Default /= undefined; Active /= undefined -> + Txt = <<"Only element is allowed in this query">>, + {error, xmpp:err_bad_request(Txt, Lang)}; process_iq_get(_, #iq{from = From, lang = Lang, sub_els = [#privacy_query{lists = Lists}]}, #userlist{name = Active}) -> @@ -205,7 +211,7 @@ encode_value(Type, Val) -> listitem_value(). decode_value(Type, Value) -> case Type of - jid -> jid:from_string(Value); + jid -> jid:tolower(jid:from_string(Value)); subscription -> case Value of <<"from">> -> from; @@ -213,35 +219,37 @@ decode_value(Type, Value) -> <<"both">> -> both; <<"none">> -> none end; - group -> Value; + group when Value /= <<"">> -> Value; undefined -> none end. -spec process_iq_set({error, stanza_error()} | {result, xmpp_element() | undefined} | {result, xmpp_element() | undefined, userlist()}, - iq()) -> {error, stanza_error()} | - {result, xmpp_element() | undefined} | - {result, xmpp_element() | undefined, userlist()}. + iq(), #userlist{}) -> + {error, stanza_error()} | + {result, xmpp_element() | undefined} | + {result, xmpp_element() | undefined, userlist()}. process_iq_set(_, #iq{from = From, lang = Lang, sub_els = [#privacy_query{default = Default, active = Active, - lists = Lists}]}) -> + lists = Lists}]}, + #userlist{} = UserList) -> #jid{luser = LUser, lserver = LServer} = From, case Lists of [#privacy_list{items = Items, name = ListName}] when Default == undefined, Active == undefined -> - process_lists_set(LUser, LServer, ListName, Items, Lang); + process_lists_set(LUser, LServer, ListName, Items, UserList, Lang); [] when Default == undefined, Active /= undefined -> process_active_set(LUser, LServer, Active, Lang); [] when Active == undefined, Default /= undefined -> process_default_set(LUser, LServer, Default, Lang); _ -> - Txt = <<"There should be exactly one element in this query: " - ", or ">>, + Txt = <<"The stanza MUST contain only one element, " + "one element, or one element">>, {error, xmpp:err_bad_request(Txt, Lang)} end; -process_iq_set(Acc, _) -> +process_iq_set(Acc, _, _) -> Acc. -spec process_default_set(binary(), binary(), none | binary(), @@ -286,13 +294,20 @@ set_privacy_list(#privacy{us = {_, LServer}} = Privacy) -> Mod:set_privacy_list(Privacy). -spec process_lists_set(binary(), binary(), binary(), [privacy_item()], - binary()) -> {error, stanza_error()} | {result, undefined}. -process_lists_set(LUser, LServer, Name, [], Lang) -> + #userlist{}, binary()) -> {error, stanza_error()} | + {result, undefined}. +process_lists_set(_LUser, _LServer, Name, [], #userlist{name = Name}, Lang) -> + Txt = <<"Cannot remove active list">>, + {error, xmpp:err_conflict(Txt, Lang)}; +process_lists_set(LUser, LServer, Name, [], _UserList, Lang) -> Mod = gen_mod:db_mod(LServer, ?MODULE), case Mod:remove_privacy_list(LUser, LServer, Name) of {atomic, conflict} -> Txt = <<"Cannot remove default list">>, {error, xmpp:err_conflict(Txt, Lang)}; + {atomic, not_found} -> + Txt = <<"No privacy list with this name found">>, + {error, xmpp:err_item_not_found(Txt, Lang)}; {atomic, ok} -> ejabberd_sm:route(jid:make(LUser, LServer, <<"">>), @@ -308,7 +323,7 @@ process_lists_set(LUser, LServer, Name, [], Lang) -> Txt = <<"Database failure">>, {error, xmpp:err_internal_server_error(Txt, Lang)} end; -process_lists_set(LUser, LServer, Name, Items, Lang) -> +process_lists_set(LUser, LServer, Name, Items, _UserList, Lang) -> case catch lists:map(fun decode_item/1, Items) of {error, Why} -> Txt = xmpp:format_error(Why), @@ -358,9 +373,7 @@ decode_item(#privacy_item{order = Order, action = Action, type = Type, value = Value}, - if MatchMessage and MatchIQ and MatchPresenceIn and MatchPresenceOut -> - ListItem#listitem{match_all = true}; - not (MatchMessage or MatchIQ or MatchPresenceIn or MatchPresenceOut) -> + if not (MatchMessage or MatchIQ or MatchPresenceIn or MatchPresenceOut) -> ListItem#listitem{match_all = true}; true -> ListItem#listitem{match_iq = MatchIQ, @@ -468,17 +481,11 @@ check_packet_aux([Item | List], PType, JID, Item, case is_ptype_match(Item, PType) of true -> - case Type of - none -> Action; - _ -> - case is_type_match(Type, Value, JID, Subscription, - Groups) - of - true -> Action; - false -> - check_packet_aux(List, PType, JID, Subscription, Groups) - end - end; + case is_type_match(Type, Value, JID, Subscription, Groups) of + true -> Action; + false -> + check_packet_aux(List, PType, JID, Subscription, Groups) + end; false -> check_packet_aux(List, PType, JID, Subscription, Groups) end. @@ -499,8 +506,10 @@ is_ptype_match(Item, PType) -> end end. --spec is_type_match(jid | subscription | group, listitem_value(), +-spec is_type_match(none | jid | subscription | group, listitem_value(), ljid(), none | both | from | to, [binary()]) -> boolean(). +is_type_match(none, _Value, _JID, _Subscription, _Groups) -> + true; is_type_match(Type, Value, JID, Subscription, Groups) -> case Type of jid -> diff --git a/src/mod_roster.erl b/src/mod_roster.erl index feebd3945..423fe9e0e 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -49,7 +49,7 @@ get_jid_info/4, encode_item/1, webadmin_page/3, webadmin_user/4, get_versioning_feature/2, roster_versioning_enabled/1, roster_version/2, - mod_opt_type/1, set_roster/1, depends/2]). + mod_opt_type/1, set_roster/1, del_roster/3, depends/2]). -include("ejabberd.hrl"). -include("logger.hrl"). @@ -297,6 +297,13 @@ set_roster(#roster{us = {LUser, LServer}, jid = LJID} = Item) -> roster_subscribe_t(LUser, LServer, LJID, Item) end). +del_roster(LUser, LServer, LJID) -> + transaction( + LServer, + fun() -> + del_roster_t(LUser, LServer, LJID) + end). + encode_item(Item) -> #roster_item{jid = jid:make(Item#roster.jid), name = Item#roster.name, diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index 1a5c89076..59936352b 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -22,11 +22,12 @@ stop_event_relay/1, put_event/2, get_event/1, bind/1, auth/1, auth/2, open_session/1, open_session/2, zlib/1, starttls/1, starttls/2, close_socket/1, init_stream/1, - auth_legacy/2, auth_legacy/3, tcp_connect/1, send_text/2]). + auth_legacy/2, auth_legacy/3, tcp_connect/1, send_text/2, + set_roster/3, del_roster/1]). -include("suite.hrl"). suite() -> - [{timetrap, {seconds, 30}}]. + [{timetrap, {seconds, 120}}]. init_per_suite(Config) -> NewConfig = init_config(Config), @@ -183,9 +184,18 @@ end_per_group(_GroupName, Config) -> set_opt(anonymous, false, Config). init_per_testcase(stop_ejabberd, Config) -> - open_session(bind(auth(connect(Config)))); + NewConfig = set_opt(resource, <<"">>, + set_opt(anonymous, true, Config)), + open_session(bind(auth(connect(NewConfig)))); init_per_testcase(TestCase, OrigConfig) -> - subscribe_to_events(OrigConfig), + Test = atom_to_list(TestCase), + IsMaster = lists:suffix("_master", Test), + IsSlave = lists:suffix("_slave", Test), + if IsMaster or IsSlave -> + subscribe_to_events(OrigConfig); + true -> + ok + end, TestGroup = proplists:get_value( name, ?config(tc_group_properties, OrigConfig)), Server = ?config(server, OrigConfig), @@ -199,9 +209,6 @@ init_per_testcase(TestCase, OrigConfig) -> end, MasterResource = ?config(master_resource, OrigConfig), SlaveResource = ?config(slave_resource, OrigConfig), - Test = atom_to_list(TestCase), - IsMaster = lists:suffix("_master", Test), - IsSlave = lists:suffix("_slave", Test), Mode = if IsSlave -> slave; IsMaster -> master; true -> single @@ -389,12 +396,12 @@ db_tests(riak) -> last, roster_get, private, - privacy, - blocking, + privacy_tests:single_cases(), vcard, muc_tests:single_cases(), test_unregister]}, muc_tests:master_slave_cases(), + privacy_tests:master_slave_cases(), {test_roster_subscribe, [parallel], [roster_subscribe_master, roster_subscribe_slave]}, @@ -420,13 +427,13 @@ db_tests(DB) when DB == mnesia; DB == redis -> roster_get, roster_ver, private, - privacy, - blocking, + privacy_tests:single_cases(), vcard, pubsub_single_tests(), muc_tests:single_cases(), test_unregister]}, muc_tests:master_slave_cases(), + privacy_tests:master_slave_cases(), pubsub_multiple_tests(), {test_mix, [parallel], [mix_master, mix_slave]}, @@ -466,13 +473,13 @@ db_tests(_) -> roster_get, roster_ver, private, - privacy, - blocking, + privacy_tests:single_cases(), vcard, pubsub_single_tests(), muc_tests:single_cases(), test_unregister]}, muc_tests:master_slave_cases(), + privacy_tests:master_slave_cases(), pubsub_multiple_tests(), {test_mix, [parallel], [mix_master, mix_slave]}, @@ -797,7 +804,7 @@ s2s_ping(Config) -> To = jid:make(?MNESIA_VHOST), ID = randoms:get_string(), ejabberd_s2s:route(From, To, #iq{id = ID, type = get, sub_els = [#ping{}]}), - ?recv1(#iq{type = result, id = ID, sub_els = []}), + #iq{type = result, id = ID, sub_els = []} = recv_iq(Config), disconnect(Config). auth_md5(Config) -> @@ -872,7 +879,7 @@ roster_ver(Config) -> %% Attempting to subscribe to server's JID send(Config, #presence{type = subscribe, to = server_jid(Config)}), %% Receive a single roster push with the new "ver" - #iq{type = set, sub_els = [#roster_query{ver = Ver2}]} = recv(Config), + #iq{type = set, sub_els = [#roster_query{ver = Ver2}]} = recv_iq(Config), %% Requesting roster with the previous "ver". Should receive Ver2 again #iq{type = result, sub_els = [#roster_query{ver = Ver2}]} = send_recv(Config, #iq{type = get, @@ -901,9 +908,8 @@ unsupported_query(Config) -> disconnect(Config). presence(Config) -> - send(Config, #presence{}), JID = my_jid(Config), - ?recv1(#presence{from = JID, to = JID}), + #presence{from = JID, to = JID} = send_recv(Config, #presence{}), disconnect(Config). presence_broadcast(Config) -> @@ -927,11 +933,11 @@ presence_broadcast(Config) -> %% 1) disco#info iq request for CAPS %% 2) welcome message %% 3) presence broadcast - {IQ, _, _} = ?recv3(#iq{type = get, - from = ServerJID, - sub_els = [#disco_info{node = Node}]}, - #message{type = normal}, - #presence{from = JID, to = JID}), + IQ = #iq{type = get, + from = ServerJID, + sub_els = [#disco_info{node = Node}]} = recv_iq(Config), + #message{type = normal} = recv_message(Config), + #presence{from = JID, to = JID} = recv_presence(Config), send(Config, #iq{type = result, id = IQ#iq.id, to = ServerJID, sub_els = [Info]}), %% We're trying to read our feature from ejabberd database @@ -1045,7 +1051,7 @@ sm_resume(Config) -> ejabberd_router:route(ServerJID, MyJID, Msg), send(Config, #sm_resume{previd = ID, h = 0, xmlns = ?NS_STREAM_MGMT_3}), ?recv1(#sm_resumed{previd = ID, h = 3}), - ?recv1(#message{from = ServerJID, to = MyJID, body = [Txt]}), + #message{from = ServerJID, to = MyJID, body = [Txt]} = recv_message(Config), ?recv1(#sm_r{}), send(Config, #sm_a{h = 1, xmlns = ?NS_STREAM_MGMT_3}), %% Send another stanza to increment the server's 'h' for sm_resume_failed. @@ -1095,90 +1101,97 @@ last(Config) -> to = server_jid(Config)}), disconnect(Config). -privacy(Config) -> - true = is_feature_advertised(Config, ?NS_PRIVACY), - #iq{type = result, sub_els = [#privacy_query{}]} = - send_recv(Config, #iq{type = get, sub_els = [#privacy_query{}]}), - JID = <<"tybalt@example.com">>, - I1 = send(Config, - #iq{type = set, - sub_els = [#privacy_query{ - lists = [#privacy_list{ - name = <<"public">>, - items = - [#privacy_item{ - type = jid, - order = 3, - action = deny, - presence_in = true, - value = JID}]}]}]}), - {Push1, _} = - ?recv2( - #iq{type = set, - sub_els = [#privacy_query{ - lists = [#privacy_list{ - name = <<"public">>}]}]}, - #iq{type = result, id = I1, sub_els = []}), - send(Config, make_iq_result(Push1)), - #iq{type = result, sub_els = []} = - send_recv(Config, #iq{type = set, - sub_els = [#privacy_query{active = <<"public">>}]}), - #iq{type = result, sub_els = []} = - send_recv(Config, #iq{type = set, - sub_els = [#privacy_query{default = <<"public">>}]}), - #iq{type = result, - sub_els = [#privacy_query{default = <<"public">>, - active = <<"public">>, - lists = [#privacy_list{name = <<"public">>}]}]} = - send_recv(Config, #iq{type = get, sub_els = [#privacy_query{}]}), - #iq{type = result, sub_els = []} = - send_recv(Config, - #iq{type = set, sub_els = [#privacy_query{default = none}]}), - #iq{type = result, sub_els = []} = - send_recv(Config, #iq{type = set, sub_els = [#privacy_query{active = none}]}), - I2 = send(Config, #iq{type = set, - sub_els = [#privacy_query{ - lists = - [#privacy_list{ - name = <<"public">>}]}]}), - {Push2, _} = - ?recv2( - #iq{type = set, - sub_els = [#privacy_query{ - lists = [#privacy_list{ - name = <<"public">>}]}]}, - #iq{type = result, id = I2, sub_els = []}), - send(Config, make_iq_result(Push2)), - disconnect(Config). +privacy_feature_enabled(Config) -> + privacy_tests:feature_enabled(Config). +privacy_set_get_list(Config) -> + privacy_tests:set_get_list(Config). +privacy_get_list_non_existent(Config) -> + privacy_tests:get_list_non_existent(Config). +privacy_set_default(Config) -> + privacy_tests:set_default(Config). +privacy_del_default(Config) -> + privacy_tests:del_default(Config). +privacy_set_default_non_existent(Config) -> + privacy_tests:set_default_non_existent(Config). +privacy_set_active(Config) -> + privacy_tests:set_active(Config). +privacy_del_active(Config) -> + privacy_tests:del_active(Config). +privacy_set_active_non_existent(Config) -> + privacy_tests:set_active_non_existent(Config). +privacy_remove_list(Config) -> + privacy_tests:remove_list(Config). +privacy_remove_active_list(Config) -> + privacy_tests:remove_active_list(Config). +privacy_remove_default_list(Config) -> + privacy_tests:remove_default_list(Config). +privacy_remove_list_non_existent(Config) -> + privacy_tests:remove_list_non_existent(Config). +privacy_allow_local_server(Config) -> + privacy_tests:allow_local_server(Config). +privacy_malformed_iq_query(Config) -> + privacy_tests:malformed_iq_query(Config). +privacy_malformed_get(Config) -> + privacy_tests:malformed_get(Config). +privacy_malformed_set(Config) -> + privacy_tests:malformed_set(Config). +privacy_malformed_type_value(Config) -> + privacy_tests:malformed_type_value(Config). +privacy_set_get_block(Config) -> + privacy_tests:set_get_block(Config). -blocking(Config) -> - true = is_feature_advertised(Config, ?NS_BLOCKING), - JID = jid:make(<<"romeo">>, <<"montague.net">>, <<>>), - #iq{type = result, sub_els = [#block_list{}]} = - send_recv(Config, #iq{type = get, sub_els = [#block_list{}]}), - I1 = send(Config, #iq{type = set, - sub_els = [#block{items = [JID]}]}), - {Push1, Push2, _} = - ?recv3( - #iq{type = set, - sub_els = [#privacy_query{lists = [#privacy_list{}]}]}, - #iq{type = set, - sub_els = [#block{items = [JID]}]}, - #iq{type = result, id = I1, sub_els = []}), - send(Config, make_iq_result(Push1)), - send(Config, make_iq_result(Push2)), - I2 = send(Config, #iq{type = set, - sub_els = [#unblock{items = [JID]}]}), - {Push3, Push4, _} = - ?recv3( - #iq{type = set, - sub_els = [#privacy_query{lists = [#privacy_list{}]}]}, - #iq{type = set, - sub_els = [#unblock{items = [JID]}]}, - #iq{type = result, id = I2, sub_els = []}), - send(Config, make_iq_result(Push3)), - send(Config, make_iq_result(Push4)), - disconnect(Config). +privacy_deny_bare_jid_master(Config) -> + privacy_tests:deny_bare_jid_master(Config). +privacy_deny_bare_jid_slave(Config) -> + privacy_tests:deny_bare_jid_slave(Config). +privacy_deny_full_jid_master(Config) -> + privacy_tests:deny_full_jid_master(Config). +privacy_deny_full_jid_slave(Config) -> + privacy_tests:deny_full_jid_slave(Config). +privacy_deny_server_jid_master(Config) -> + privacy_tests:deny_server_jid_master(Config). +privacy_deny_server_jid_slave(Config) -> + privacy_tests:deny_server_jid_slave(Config). +privacy_deny_group_master(Config) -> + privacy_tests:deny_group_master(Config). +privacy_deny_group_slave(Config) -> + privacy_tests:deny_group_slave(Config). +privacy_deny_sub_both_master(Config) -> + privacy_tests:deny_sub_both_master(Config). +privacy_deny_sub_both_slave(Config) -> + privacy_tests:deny_sub_both_slave(Config). +privacy_deny_sub_from_master(Config) -> + privacy_tests:deny_sub_from_master(Config). +privacy_deny_sub_from_slave(Config) -> + privacy_tests:deny_sub_from_slave(Config). +privacy_deny_sub_to_master(Config) -> + privacy_tests:deny_sub_to_master(Config). +privacy_deny_sub_to_slave(Config) -> + privacy_tests:deny_sub_to_slave(Config). +privacy_deny_sub_none_master(Config) -> + privacy_tests:deny_sub_none_master(Config). +privacy_deny_sub_none_slave(Config) -> + privacy_tests:deny_sub_none_slave(Config). +privacy_deny_all_master(Config) -> + privacy_tests:deny_all_master(Config). +privacy_deny_all_slave(Config) -> + privacy_tests:deny_all_slave(Config). +privacy_deny_offline_master(Config) -> + privacy_tests:deny_offline_master(Config). +privacy_deny_offline_slave(Config) -> + privacy_tests:deny_offline_slave(Config). +privacy_block_master(Config) -> + privacy_tests:block_master(Config). +privacy_block_slave(Config) -> + privacy_tests:block_slave(Config). +privacy_unblock_master(Config) -> + privacy_tests:unblock_master(Config). +privacy_unblock_slave(Config) -> + privacy_tests:unblock_slave(Config). +privacy_unblock_all_master(Config) -> + privacy_tests:unblock_all_master(Config). +privacy_unblock_all_slave(Config) -> + privacy_tests:unblock_all_slave(Config). vcard(Config) -> true = is_feature_advertised(Config, ?NS_VCARD), @@ -1239,17 +1252,16 @@ vcard_xupdate_master(Config) -> MyJID = my_jid(Config), Peer = ?config(slave, Config), wait_for_slave(Config), - send(Config, #presence{}), - ?recv2(#presence{from = MyJID, type = available}, - #presence{from = Peer, type = available}), + #presence{from = MyJID, type = available} = send_recv(Config, #presence{}), + #presence{from = Peer, type = available} = recv_presence(Config), VCard = #vcard_temp{photo = #vcard_photo{type = <<"image/png">>, binval = Img}}, - I1 = send(Config, #iq{type = set, sub_els = [VCard]}), - ?recv2(#iq{type = result, sub_els = [], id = I1}, - #presence{from = MyJID, type = available, - sub_els = [#vcard_xupdate{hash = ImgHash}]}), - I2 = send(Config, #iq{type = set, sub_els = [#vcard_temp{}]}), - ?recv3(#iq{type = result, sub_els = [], id = I2}, - #presence{from = MyJID, type = available, + #iq{type = result, sub_els = []} = + send_recv(Config, #iq{type = set, sub_els = [VCard]}), + #presence{from = MyJID, type = available, + sub_els = [#vcard_xupdate{hash = ImgHash}]} = recv_presence(Config), + #iq{type = result, sub_els = []} = + send_recv(Config, #iq{type = set, sub_els = [#vcard_temp{}]}), + ?recv2(#presence{from = MyJID, type = available, sub_els = [#vcard_xupdate{hash = undefined}]}, #presence{from = Peer, type = unavailable}), disconnect(Config). @@ -1259,14 +1271,13 @@ vcard_xupdate_slave(Config) -> ImgHash = p1_sha:sha(Img), MyJID = my_jid(Config), Peer = ?config(master, Config), - send(Config, #presence{}), - ?recv1(#presence{from = MyJID, type = available}), + #presence{from = MyJID, type = available} = send_recv(Config, #presence{}), wait_for_master(Config), - ?recv1(#presence{from = Peer, type = available}), - ?recv1(#presence{from = Peer, type = available, - sub_els = [#vcard_xupdate{hash = ImgHash}]}), - ?recv1(#presence{from = Peer, type = available, - sub_els = [#vcard_xupdate{hash = undefined}]}), + #presence{from = Peer, type = available} = recv_presence(Config), + #presence{from = Peer, type = available, + sub_els = [#vcard_xupdate{hash = ImgHash}]} = recv_presence(Config), + #presence{from = Peer, type = available, + sub_els = [#vcard_xupdate{hash = undefined}]} = recv_presence(Config), disconnect(Config). stats(Config) -> @@ -1439,7 +1450,7 @@ pubsub_publish_slave(Config) -> sub_els = [#ps_event{ items = #ps_items{node = Node, - items = [Item]}}]} = recv(Config), + items = [Item]}}]} = recv_message(Config), put_event(Config, Item), disconnect(Config). @@ -1478,13 +1489,14 @@ pubsub_subscriptions_slave(Config) -> type = Type}}]}, #message{sub_els = [#ps_event{}]}); (Type) -> - ?recv1(#message{ - sub_els = - [#ps_event{ - subscription = #ps_subscription{ - node = Node, - jid = MyJID, - type = Type}}]}) + #message{ + sub_els = + [#ps_event{ + subscription = #ps_subscription{ + node = Node, + jid = MyJID, + type = Type}}]} = + recv_message(Config) end, [subscribed, unconfigured, pending, none]), disconnect(Config). @@ -1644,7 +1656,7 @@ pubsub_affiliations_slave(Config, disconnect) -> pubsub_authorize_master(Config) -> send(Config, #presence{}), - ?recv1(#presence{}), + #presence{} = recv_presence(Config), Peer = ?config(slave, Config), PJID = pubsub_jid(Config), NodeConfig = set_opts(default_node_config(Config), @@ -1652,7 +1664,7 @@ pubsub_authorize_master(Config) -> Node = ?config(pubsub_node, Config), Node = create_node(Config, Node, NodeConfig), wait_for_slave(Config), - #message{sub_els = [#xdata{fields = F1}]} = recv(Config), + #message{sub_els = [#xdata{fields = F1}]} = recv_message(Config), C1 = pubsub_subscribe_authorization:decode(F1), Node = proplists:get_value(node, C1), Peer = proplists:get_value(subscriber_jid, C1), @@ -1666,7 +1678,7 @@ pubsub_authorize_master(Config) -> %% We should not have any subscriptions [] = get_subscriptions(Config, Node), wait_for_slave(Config), - #message{sub_els = [#xdata{fields = F2}]} = recv(Config), + #message{sub_els = [#xdata{fields = F2}]} = recv_message(Config), C2 = pubsub_subscribe_authorization:decode(F2), Node = proplists:get_value(node, C2), Peer = proplists:get_value(subscriber_jid, C2), @@ -1687,19 +1699,21 @@ pubsub_authorize_slave(Config) -> wait_for_master(Config), #ps_subscription{type = pending} = subscribe_node(Config, Node), %% We're denied at first - ?recv1(#message{ - sub_els = - [#ps_event{ - subscription = #ps_subscription{type = none, - jid = MyJID}}]}), + #message{ + sub_els = + [#ps_event{ + subscription = #ps_subscription{type = none, + jid = MyJID}}]} = + recv_message(Config), wait_for_master(Config), #ps_subscription{type = pending} = subscribe_node(Config, Node), %% Now much better! - ?recv1(#message{ - sub_els = - [#ps_event{ - subscription = #ps_subscription{type = subscribed, - jid = MyJID}}]}), + #message{ + sub_els = + [#ps_event{ + subscription = #ps_subscription{type = subscribed, + jid = MyJID}}]} = + recv_message(Config), wait_for_master(Config), disconnect(Config). @@ -1961,46 +1975,48 @@ mix_master(Config) -> Nodes = [?NS_MIX_NODES_MESSAGES, ?NS_MIX_NODES_PRESENCE, ?NS_MIX_NODES_PARTICIPANTS, ?NS_MIX_NODES_SUBJECT, ?NS_MIX_NODES_CONFIG], - I0 = send(Config, #iq{type = set, to = Room, - sub_els = [#mix_join{subscribe = Nodes}]}), - {_, #message{sub_els = - [#ps_event{ - items = #ps_items{ - node = ?NS_MIX_NODES_PARTICIPANTS, - items = [#ps_item{ - id = ParticipantID, - xml_els = [PXML]}]}}]}} = - ?recv2(#iq{type = result, id = I0, - sub_els = [#mix_join{subscribe = Nodes, jid = MyBareJID}]}, - #message{from = Room}), + #iq{type = result, + sub_els = [#mix_join{subscribe = Nodes, jid = MyBareJID}]} = + send_recv(Config, #iq{type = set, to = Room, + sub_els = [#mix_join{subscribe = Nodes}]}), + #message{from = Room, + sub_els = + [#ps_event{ + items = #ps_items{ + node = ?NS_MIX_NODES_PARTICIPANTS, + items = [#ps_item{ + id = ParticipantID, + xml_els = [PXML]}]}}]} = + recv_message(Config), #mix_participant{jid = MyBareJID} = xmpp:decode(PXML), %% Coming online PresenceID = randoms:get_string(), Presence = xmpp:encode(#presence{}), - I1 = send( - Config, - #iq{type = set, to = Room, - sub_els = - [#pubsub{ - publish = #ps_publish{ - node = ?NS_MIX_NODES_PRESENCE, - items = [#ps_item{ - id = PresenceID, - xml_els = [Presence]}]}}]}), - ?recv2(#iq{type = result, id = I1, - sub_els = - [#pubsub{ - publish = #ps_publish{ - node = ?NS_MIX_NODES_PRESENCE, - items = [#ps_item{id = PresenceID}]}}]}, - #message{from = Room, - sub_els = - [#ps_event{ - items = #ps_items{ - node = ?NS_MIX_NODES_PRESENCE, - items = [#ps_item{ - id = PresenceID, - xml_els = [Presence]}]}}]}), + #iq{type = result, + sub_els = + [#pubsub{ + publish = #ps_publish{ + node = ?NS_MIX_NODES_PRESENCE, + items = [#ps_item{id = PresenceID}]}}]} = + send_recv( + Config, + #iq{type = set, to = Room, + sub_els = + [#pubsub{ + publish = #ps_publish{ + node = ?NS_MIX_NODES_PRESENCE, + items = [#ps_item{ + id = PresenceID, + xml_els = [Presence]}]}}]}), + #message{from = Room, + sub_els = + [#ps_event{ + items = #ps_items{ + node = ?NS_MIX_NODES_PRESENCE, + items = [#ps_item{ + id = PresenceID, + xml_els = [Presence]}]}}]} = + recv_message(Config), %% Coming offline send(Config, #presence{type = unavailable, to = Room}), %% Receiving presence retract event @@ -2008,101 +2024,109 @@ mix_master(Config) -> sub_els = [#ps_event{ items = #ps_items{ node = ?NS_MIX_NODES_PRESENCE, - retract = PresenceID}}]} = recv(Config), + retract = PresenceID}}]} = + recv_message(Config), %% Leaving - I2 = send(Config, #iq{type = set, to = Room, sub_els = [#mix_leave{}]}), - ?recv2(#iq{type = result, id = I2, sub_els = []}, - #message{from = Room, - sub_els = - [#ps_event{ - items = #ps_items{ - node = ?NS_MIX_NODES_PARTICIPANTS, - retract = ParticipantID}}]}), + #iq{type = result, sub_els = []} = + send_recv(Config, #iq{type = set, to = Room, sub_els = [#mix_leave{}]}), + #message{from = Room, + sub_els = + [#ps_event{ + items = #ps_items{ + node = ?NS_MIX_NODES_PARTICIPANTS, + retract = ParticipantID}}]} = + recv_message(Config), + put_event(Config, disconnect), disconnect(Config). mix_slave(Config) -> + disconnect = get_event(Config), disconnect(Config). roster_subscribe_master(Config) -> - send(Config, #presence{}), - ?recv1(#presence{}), + #presence{} = send_recv(Config, #presence{}), wait_for_slave(Config), - Peer = ?config(slave, Config), + Peer = ?config(peer, Config), LPeer = jid:remove_resource(Peer), send(Config, #presence{type = subscribe, to = LPeer}), - Push1 = ?recv1(#iq{type = set, + Push1 = #iq{type = set, sub_els = [#roster_query{items = [#roster_item{ - ask = subscribe, - subscription = none, - jid = LPeer}]}]}), + ask = subscribe, + subscription = none, + jid = LPeer}]}]} = + recv_iq(Config), send(Config, make_iq_result(Push1)), - {Push2, _} = ?recv2( - #iq{type = set, - sub_els = [#roster_query{items = [#roster_item{ - subscription = to, - jid = LPeer}]}]}, - #presence{type = subscribed, from = LPeer}), + #presence{type = subscribed, from = LPeer} = recv_presence(Config), + Push2 = #iq{type = set, + sub_els = [#roster_query{items = [#roster_item{ + subscription = to, + jid = LPeer}]}]} = + recv_iq(Config), send(Config, make_iq_result(Push2)), - ?recv1(#presence{type = available, from = Peer}), + #presence{type = available, from = Peer} = recv_presence(Config), %% BUG: ejabberd sends previous push again. Is it ok? - Push3 = ?recv1(#iq{type = set, + Push3 = #iq{type = set, sub_els = [#roster_query{items = [#roster_item{ - subscription = to, - jid = LPeer}]}]}), + subscription = to, + jid = LPeer}]}]} = + recv_iq(Config), send(Config, make_iq_result(Push3)), - ?recv1(#presence{type = subscribe, from = LPeer}), + #presence{type = subscribe, from = LPeer} = recv_presence(Config), send(Config, #presence{type = subscribed, to = LPeer}), - Push4 = ?recv1(#iq{type = set, + Push4 = #iq{type = set, sub_els = [#roster_query{items = [#roster_item{ - subscription = both, - jid = LPeer}]}]}), + subscription = both, + jid = LPeer}]}]} = + recv_iq(Config), send(Config, make_iq_result(Push4)), %% Move into a group Groups = [<<"A">>, <<"B">>], Item = #roster_item{jid = LPeer, groups = Groups}, - I1 = send(Config, #iq{type = set, sub_els = [#roster_query{items = [Item]}]}), - {Push5, _} = ?recv2( - #iq{type = set, - sub_els = - [#roster_query{items = [#roster_item{ - jid = LPeer, - subscription = both}]}]}, - #iq{type = result, id = I1, sub_els = []}), + #iq{type = result, sub_els = []} = + send_recv(Config, + #iq{type = set, sub_els = [#roster_query{items = [Item]}]}), + Push5 = #iq{type = set, + sub_els = + [#roster_query{items = [#roster_item{ + jid = LPeer, + subscription = both}]}]} = + recv_iq(Config), send(Config, make_iq_result(Push5)), #iq{sub_els = [#roster_query{items = [#roster_item{groups = G1}]}]} = Push5, Groups = lists:sort(G1), wait_for_slave(Config), - ?recv1(#presence{type = unavailable, from = Peer}), + #presence{type = unavailable, from = Peer} = recv_presence(Config), disconnect(Config). roster_subscribe_slave(Config) -> - send(Config, #presence{}), - ?recv1(#presence{}), + #presence{} = send_recv(Config, #presence{}), wait_for_master(Config), Peer = ?config(master, Config), LPeer = jid:remove_resource(Peer), - ?recv1(#presence{type = subscribe, from = LPeer}), + #presence{type = subscribe, from = LPeer} = recv_presence(Config), send(Config, #presence{type = subscribed, to = LPeer}), - Push1 = ?recv1(#iq{type = set, + Push1 = #iq{type = set, sub_els = [#roster_query{items = [#roster_item{ - subscription = from, - jid = LPeer}]}]}), + subscription = from, + jid = LPeer}]}]} = + recv_iq(Config), send(Config, make_iq_result(Push1)), send(Config, #presence{type = subscribe, to = LPeer}), - Push2 = ?recv1(#iq{type = set, + Push2 = #iq{type = set, sub_els = [#roster_query{items = [#roster_item{ - ask = subscribe, - subscription = from, - jid = LPeer}]}]}), + ask = subscribe, + subscription = from, + jid = LPeer}]}]} = + recv_iq(Config), send(Config, make_iq_result(Push2)), - {Push3, _} = ?recv2( - #iq{type = set, - sub_els = [#roster_query{items = [#roster_item{ - subscription = both, - jid = LPeer}]}]}, - #presence{type = subscribed, from = LPeer}), + #presence{type = subscribed, from = LPeer} = recv_presence(Config), + Push3 = #iq{type = set, + sub_els = [#roster_query{items = [#roster_item{ + subscription = both, + jid = LPeer}]}]} = + recv_iq(Config), send(Config, make_iq_result(Push3)), - ?recv1(#presence{type = available, from = Peer}), + #presence{type = available, from = Peer} = recv_presence(Config), wait_for_master(Config), disconnect(Config). @@ -2112,9 +2136,8 @@ roster_remove_master(Config) -> LPeer = jid:remove_resource(Peer), Groups = [<<"A">>, <<"B">>], wait_for_slave(Config), - send(Config, #presence{}), - ?recv2(#presence{from = MyJID, type = available}, - #presence{from = Peer, type = available}), + #presence{from = MyJID, type = available} = send_recv(Config, #presence{}), + #presence{from = Peer, type = available} = recv_presence(Config), %% The peer removed us from its roster. {Push1, Push2, _, _, _} = ?recv5( @@ -2144,21 +2167,21 @@ roster_remove_slave(Config) -> MyJID = my_jid(Config), Peer = ?config(master, Config), LPeer = jid:remove_resource(Peer), - send(Config, #presence{}), - ?recv1(#presence{from = MyJID, type = available}), + #presence{from = MyJID, type = available} = send_recv(Config, #presence{}), wait_for_master(Config), - ?recv1(#presence{from = Peer, type = available}), + #presence{from = Peer, type = available} = recv_presence(Config), %% Remove the peer from roster. Item = #roster_item{jid = LPeer, subscription = remove}, - I = send(Config, #iq{type = set, sub_els = [#roster_query{items = [Item]}]}), - {Push, _, _} = ?recv3( - #iq{type = set, - sub_els = - [#roster_query{items = [#roster_item{ - jid = LPeer, - subscription = remove}]}]}, - #iq{type = result, id = I, sub_els = []}, - #presence{type = unavailable, from = Peer}), + #iq{type = result, sub_els = []} = + send_recv(Config, #iq{type = set, + sub_els = [#roster_query{items = [Item]}]}), + Push = #iq{type = set, + sub_els = + [#roster_query{items = [#roster_item{ + jid = LPeer, + subscription = remove}]}]} = + recv_iq(Config), + #presence{type = unavailable, from = Peer} = recv_presence(Config), send(Config, make_iq_result(Push)), disconnect(Config). @@ -2168,7 +2191,7 @@ proxy65_master(Config) -> Peer = ?config(slave, Config), wait_for_slave(Config), send(Config, #presence{}), - ?recv1(#presence{from = MyJID, type = available}), + #presence{from = MyJID, type = available} = recv_presence(Config), true = is_feature_advertised(Config, ?NS_BYTESTREAMS, Proxy), #iq{type = result, sub_els = [#bytestreams{hosts = [StreamHost]}]} = send_recv( @@ -2191,7 +2214,7 @@ proxy65_slave(Config) -> MyJID = my_jid(Config), Peer = ?config(master, Config), send(Config, #presence{}), - ?recv1(#presence{from = MyJID, type = available}), + #presence{from = MyJID, type = available} = recv_presence(Config), wait_for_master(Config), {StreamHost, SID, Data} = get_event(Config), Socks5 = socks5_connect(StreamHost, {SID, Peer, MyJID}), @@ -2206,11 +2229,11 @@ send_messages_to_room(Config, Range) -> lists:foreach( fun(N) -> Text = #text{data = integer_to_binary(N)}, - I = send(Config, #message{to = Room, body = [Text], - type = groupchat}), - ?recv1(#message{from = MyNickJID, id = I, - type = groupchat, - body = [Text]}) + #message{from = MyNickJID, id = I, + type = groupchat, + body = [Text]} = + send_recv(Config, #message{to = Room, body = [Text], + type = groupchat}) end, Range). retrieve_messages_from_room_via_mam(Config, Range) -> @@ -2225,34 +2248,33 @@ retrieve_messages_from_room_via_mam(Config, Range) -> lists:foreach( fun(N) -> Text = #text{data = integer_to_binary(N)}, - ?recv1(#message{ - to = MyJID, from = Room, - sub_els = - [#mam_result{ - xmlns = ?NS_MAM_1, - queryid = QID, - sub_els = - [#forwarded{ - delay = #delay{}, - sub_els = [#message{ - from = MyNickJID, - type = groupchat, - body = [Text]}]}]}]}) + #message{ + to = MyJID, from = Room, + sub_els = + [#mam_result{ + xmlns = ?NS_MAM_1, + queryid = QID, + sub_els = + [#forwarded{ + delay = #delay{}, + sub_els = [#message{ + from = MyNickJID, + type = groupchat, + body = [Text]}]}]}]} = + recv_message(Config) end, Range), - ?recv1(#iq{from = Room, id = I, type = result, - sub_els = [#mam_fin{xmlns = ?NS_MAM_1, - id = QID, - rsm = #rsm_set{count = Count}, - complete = true}]}). + #iq{from = Room, id = I, type = result, + sub_els = [#mam_fin{xmlns = ?NS_MAM_1, + id = QID, + rsm = #rsm_set{count = Count}, + complete = true}]} = recv_iq(Config). muc_mam_master(Config) -> MyNick = ?config(master_nick, Config), Room = muc_room_jid(Config), MyNickJID = jid:replace_resource(Room, MyNick), %% Joining - send(Config, #presence{to = MyNickJID, sub_els = [#muc{}]}), - %% Receive self-presence - ?recv1(#presence{from = MyNickJID}), + ok = muc_tests:muc_join_new(Config), %% MAM feature should not be advertised at this point, %% because MAM is not enabled so far false = is_feature_advertised(Config, ?NS_MAM_1, Room), @@ -2274,20 +2296,22 @@ muc_mam_master(Config) -> [] end, RoomCfg#xdata.fields), NewRoomCfg = #xdata{type = submit, fields = NewFields}, - I1 = send(Config, #iq{type = set, to = Room, - sub_els = [#muc_owner{config = NewRoomCfg}]}), - ?recv2(#iq{type = result, id = I1}, - #message{from = Room, type = groupchat, - sub_els = [#muc_user{status_codes = [104]}]}), + #iq{type = result, sub_els = []} = + send_recv(Config, #iq{type = set, to = Room, + sub_els = [#muc_owner{config = NewRoomCfg}]}), + #message{from = Room, type = groupchat, + sub_els = [#muc_user{status_codes = [104]}]} = recv_message(Config), %% Check if MAM has been enabled true = is_feature_advertised(Config, ?NS_MAM_1, Room), %% We now sending some messages again send_messages_to_room(Config, lists:seq(1, 5)), %% And retrieve them via MAM again. retrieve_messages_from_room_via_mam(Config, lists:seq(1, 5)), + put_event(Config, disconnect), disconnect(Config). muc_mam_slave(Config) -> + disconnect = get_event(Config), disconnect(Config). %% OK, I know this is retarded, but I didn't find a better way to @@ -2441,12 +2465,11 @@ announce_master(Config) -> ServerJID = server_jid(Config), MotdJID = jid:replace_resource(ServerJID, <<"announce/motd">>), MotdText = #text{data = <<"motd">>}, - send(Config, #presence{}), - ?recv1(#presence{from = MyJID}), + #presence{from = MyJID} = send_recv(Config, #presence{}), %% Set message of the day send(Config, #message{to = MotdJID, body = [MotdText]}), %% Receive this message back - ?recv1(#message{from = ServerJID, body = [MotdText]}), + #message{from = ServerJID, body = [MotdText]} = recv_message(Config), disconnect(Config). announce_slave(Config) -> @@ -2454,9 +2477,8 @@ announce_slave(Config) -> ServerJID = server_jid(Config), MotdDelJID = jid:replace_resource(ServerJID, <<"announce/motd/delete">>), MotdText = #text{data = <<"motd">>}, - send(Config, #presence{}), - ?recv2(#presence{from = MyJID}, - #message{from = ServerJID, body = [MotdText]}), + #presence{from = MyJID} = send_recv(Config, #presence{}), + #message{from = ServerJID, body = [MotdText]} = recv_message(Config), %% Delete message of the day send(Config, #message{to = MotdDelJID}), disconnect(Config). @@ -2520,39 +2542,39 @@ flex_offline_slave(Config) -> end, DiscoItems)), %% Since headers are received we can send initial presence without a risk %% of getting offline messages flood - send(Config, #presence{}), - ?recv1(#presence{from = MyJID}), + #presence{from = MyJID} = send_recv(Config, #presence{}), %% Check full fetch - I0 = send(Config, #iq{type = get, sub_els = [#offline{fetch = true}]}), + #iq{type = result, sub_els = []} = + send_recv(Config, #iq{type = get, sub_els = [#offline{fetch = true}]}), lists:foreach( fun({I, N}) -> Text = integer_to_binary(I), - #message{body = Body, sub_els = SubEls} = recv(Config), + #message{body = Body, sub_els = SubEls} = recv_message(Config), [#text{data = Text}] = Body, #offline{items = [#offline_item{node = N}]} = lists:keyfind(offline, 1, SubEls), #delay{} = lists:keyfind(delay, 1, SubEls) end, lists:zip(lists:seq(1, 5), Nodes)), - ?recv1(#iq{type = result, id = I0, sub_els = []}), %% Fetch 2nd and 4th message - I1 = send(Config, - #iq{type = get, - sub_els = [#offline{ - items = [#offline_item{ - action = view, - node = lists:nth(2, Nodes)}, - #offline_item{ - action = view, - node = lists:nth(4, Nodes)}]}]}), + #iq{type = result, sub_els = []} = + send_recv( + Config, + #iq{type = get, + sub_els = [#offline{ + items = [#offline_item{ + action = view, + node = lists:nth(2, Nodes)}, + #offline_item{ + action = view, + node = lists:nth(4, Nodes)}]}]}), lists:foreach( fun({I, N}) -> Text = integer_to_binary(I), #message{body = [#text{data = Text}], - sub_els = SubEls} = recv(Config), + sub_els = SubEls} = recv_message(Config), #offline{items = [#offline_item{node = N}]} = lists:keyfind(offline, 1, SubEls) end, lists:zip([2, 4], [lists:nth(2, Nodes), lists:nth(4, Nodes)])), - ?recv1(#iq{type = result, id = I1, sub_els = []}), %% Delete 2nd and 4th message #iq{type = result, sub_els = []} = send_recv( @@ -2601,12 +2623,12 @@ offline_master(Config) -> offline_slave(Config) -> Peer = ?config(master, Config), - send(Config, #presence{}), - {_, #message{sub_els = SubEls}} = - ?recv2(#presence{}, - #message{from = Peer, - body = [#text{data = <<"body">>}], - subject = [#text{data = <<"subject">>}]}), + #presence{} = send_recv(Config, #presence{}), + #message{sub_els = SubEls, + from = Peer, + body = [#text{data = <<"body">>}], + subject = [#text{data = <<"subject">>}]} = + recv_message(Config), true = lists:keymember(delay, 1, SubEls), disconnect(Config). @@ -2616,10 +2638,9 @@ carbons_master(Config) -> Peer = ?config(slave, Config), Txt = #text{data = <<"body">>}, true = is_feature_advertised(Config, ?NS_CARBONS_2), - send(Config, #presence{priority = 10}), - ?recv1(#presence{from = MyJID}), + #presence{from = MyJID} = send_recv(Config, #presence{priority = 10}), wait_for_slave(Config), - ?recv1(#presence{from = Peer}), + #presence{from = Peer} = recv_presence(Config), %% Enable carbons #iq{type = result, sub_els = []} = send_recv(Config, @@ -2670,8 +2691,8 @@ carbons_slave(Config) -> Peer = ?config(master, Config), Txt = #text{data = <<"body">>}, wait_for_master(Config), - send(Config, #presence{priority = 5}), - ?recv2(#presence{from = MyJID}, #presence{from = Peer}), + #presence{from = MyJID} = send_recv(Config, #presence{priority = 5}), + #presence{from = Peer} = recv_presence(Config), %% Enable carbons #iq{type = result, sub_els = []} = send_recv(Config, @@ -2722,7 +2743,7 @@ carbons_slave(Config) -> sub_els = [#carbons_disable{}]}), wait_for_master(Config), %% Now we should receive nothing but presence unavailable from the peer - ?recv1(#presence{from = Peer, type = unavailable}), + #presence{from = Peer, type = unavailable} = recv_presence(Config), disconnect(Config). mam_old_master(Config) -> @@ -2736,10 +2757,9 @@ mam_master(Config, NS) -> MyJID = my_jid(Config), BareMyJID = jid:remove_resource(MyJID), Peer = ?config(slave, Config), - send(Config, #presence{}), - ?recv1(#presence{}), + #presence{} = send_recv(Config, #presence{}), wait_for_slave(Config), - ?recv1(#presence{from = Peer}), + #presence{from = Peer} = recv_presence(Config), #iq{type = result, sub_els = [#mam_prefs{xmlns = NS, default = roster}]} = send_recv(Config, #iq{type = set, @@ -2747,18 +2767,18 @@ mam_master(Config, NS) -> default = roster, never = [MyJID]}]}), if NS == ?NS_MAM_TMP -> - FakeArchived = #mam_archived{id = randoms:get_string(), - by = server_jid(Config)}, - send(Config, #message{to = MyJID, - sub_els = [FakeArchived], - body = [#text{data = <<"a">>}]}), - send(Config, #message{to = BareMyJID, - sub_els = [FakeArchived], - body = [#text{data = <<"b">>}]}), %% NOTE: The server should strip fake archived tags, %% i.e. the sub_els received should be []. - ?recv2(#message{body = [#text{data = <<"a">>}], sub_els = []}, - #message{body = [#text{data = <<"b">>}], sub_els = []}); + FakeArchived = #mam_archived{id = randoms:get_string(), + by = server_jid(Config)}, + #message{body = [#text{data = <<"a">>}], sub_els = []} = + send_recv(Config, #message{to = MyJID, + sub_els = [FakeArchived], + body = [#text{data = <<"a">>}]}), + #message{body = [#text{data = <<"b">>}], sub_els = []} = + send_recv(Config, #message{to = BareMyJID, + sub_els = [FakeArchived], + body = [#text{data = <<"b">>}]}); true -> ok end, @@ -2766,10 +2786,9 @@ mam_master(Config, NS) -> lists:foreach( fun(N) -> Text = #text{data = integer_to_binary(N)}, - send(Config, - #message{to = Peer, body = [Text]}) + send(Config, #message{to = Peer, body = [Text]}) end, lists:seq(1, 5)), - ?recv1(#presence{type = unavailable, from = Peer}), + #presence{type = unavailable, from = Peer} = recv_presence(Config), mam_query_all(Config, NS), mam_query_with(Config, Peer, NS), %% mam_query_with(Config, jid:remove_resource(Peer)), @@ -2791,8 +2810,8 @@ mam_slave(Config, NS) -> MyJID = my_jid(Config), ServerJID = server_jid(Config), wait_for_master(Config), - send(Config, #presence{}), - ?recv2(#presence{from = MyJID}, #presence{from = Peer}), + #presence{from = MyJID} = send_recv(Config, #presence{}), + #presence{from = Peer} = recv_presence(Config), #iq{type = result, sub_els = [#mam_prefs{xmlns = NS, default = always}]} = send_recv(Config, #iq{type = set, @@ -2801,7 +2820,7 @@ mam_slave(Config, NS) -> lists:foreach( fun(N) -> Text = #text{data = integer_to_binary(N)}, - Msg = ?recv1(#message{from = Peer, body = [Text]}), + Msg = #message{from = Peer, body = [Text]} = recv_message(Config), #mam_archived{by = ServerJID} = xmpp:get_subtag(Msg, #mam_archived{}), #stanza_id{by = ServerJID} = @@ -2828,7 +2847,7 @@ mam_query_all(Config, NS) -> lists:foreach( fun(N) -> Text = #text{data = integer_to_binary(N)}, - ?recv1(#message{to = MyJID, + #message{to = MyJID, sub_els = [#mam_result{ queryid = QID, @@ -2838,13 +2857,15 @@ mam_query_all(Config, NS) -> sub_els = [#message{ from = MyJID, to = Peer, - body = [Text]}]}]}]}) + body = [Text]}]}]}]} = + recv_message(Config) end, Iter), if NS == ?NS_MAM_TMP -> - ?recv1(#iq{type = result, id = I, - sub_els = [#mam_query{xmlns = NS, id = QID}]}); + #iq{type = result, id = I, + sub_els = [#mam_query{xmlns = NS, id = QID}]} = recv_iq(Config); true -> - ?recv1(#message{sub_els = [#mam_fin{complete = true, id = QID}]}) + #message{sub_els = [#mam_fin{complete = true, id = QID}]} = + recv_message(Config) end. mam_query_with(Config, JID, NS) -> @@ -2866,7 +2887,7 @@ mam_query_with(Config, JID, NS) -> lists:foreach( fun(N) -> Text = #text{data = integer_to_binary(N)}, - ?recv1(#message{to = MyJID, + #message{to = MyJID, sub_els = [#mam_result{ sub_els = @@ -2875,17 +2896,19 @@ mam_query_with(Config, JID, NS) -> sub_els = [#message{ from = MyJID, to = Peer, - body = [Text]}]}]}]}) + body = [Text]}]}]}]} = + recv_message(Config) end, Iter), if NS == ?NS_MAM_TMP -> - ?recv1(#iq{type = result, id = I, - sub_els = [#mam_query{xmlns = NS}]}); + #iq{type = result, id = I, + sub_els = [#mam_query{xmlns = NS}]} = recv_iq(Config); true -> - ?recv1(#message{sub_els = [#mam_fin{complete = true}]}) + #message{sub_els = [#mam_fin{complete = true}]} = + recv_message(Config) end. maybe_recv_iq_result(Config, ?NS_MAM_0, I1) -> - ?recv1(#iq{type = result, id = I1}); + #iq{type = result, id = I1} = recv_iq(Config); maybe_recv_iq_result(_, _, _) -> ok. @@ -2904,7 +2927,7 @@ mam_query_rsm(Config, NS) -> lists:foreach( fun(N) -> Text = #text{data = integer_to_binary(N)}, - ?recv1(#message{to = MyJID, + #message{to = MyJID, sub_els = [#mam_result{ xmlns = NS, @@ -2914,20 +2937,21 @@ mam_query_rsm(Config, NS) -> sub_els = [#message{ from = MyJID, to = Peer, - body = [Text]}]}]}]}) + body = [Text]}]}]}]} = + recv_message(Config) end, lists:seq(1, 3)), if NS == ?NS_MAM_TMP -> #iq{type = result, id = I1, sub_els = [#mam_query{xmlns = NS, rsm = #rsm_set{last = Last, count = 5}}]} = - recv(Config); + recv_iq(Config); true -> #message{sub_els = [#mam_fin{ complete = false, rsm = #rsm_set{last = Last, count = 10}}]} = - recv(Config) + recv_message(Config) end, %% Get the next items starting from the `Last`. %% Limit the response to 2 items. @@ -2940,7 +2964,7 @@ mam_query_rsm(Config, NS) -> lists:foreach( fun(N) -> Text = #text{data = integer_to_binary(N)}, - ?recv1(#message{to = MyJID, + #message{to = MyJID, sub_els = [#mam_result{ xmlns = NS, @@ -2950,7 +2974,8 @@ mam_query_rsm(Config, NS) -> sub_els = [#message{ from = MyJID, to = Peer, - body = [Text]}]}]}]}) + body = [Text]}]}]}]} = + recv_message(Config) end, lists:seq(4, 5)), if NS == ?NS_MAM_TMP -> #iq{type = result, id = I2, @@ -2959,7 +2984,7 @@ mam_query_rsm(Config, NS) -> rsm = #rsm_set{ count = 5, first = #rsm_first{data = First}}}]} = - recv(Config); + recv_iq(Config); true -> #message{ sub_els = [#mam_fin{ @@ -2967,7 +2992,7 @@ mam_query_rsm(Config, NS) -> rsm = #rsm_set{ count = 10, first = #rsm_first{data = First}}}]} = - recv(Config) + recv_message(Config) end, %% Paging back. Should receive 3 elements: 1, 2, 3. I3 = send(Config, @@ -2979,7 +3004,7 @@ mam_query_rsm(Config, NS) -> lists:foreach( fun(N) -> Text = #text{data = integer_to_binary(N)}, - ?recv1(#message{to = MyJID, + #message{to = MyJID, sub_els = [#mam_result{ xmlns = NS, @@ -2989,15 +3014,18 @@ mam_query_rsm(Config, NS) -> sub_els = [#message{ from = MyJID, to = Peer, - body = [Text]}]}]}]}) + body = [Text]}]}]}]} = + recv_message(Config) end, lists:seq(1, 3)), if NS == ?NS_MAM_TMP -> - ?recv1(#iq{type = result, id = I3, - sub_els = [#mam_query{xmlns = NS, rsm = #rsm_set{count = 5}}]}); + #iq{type = result, id = I3, + sub_els = [#mam_query{xmlns = NS, rsm = #rsm_set{count = 5}}]} = + recv_iq(Config); true -> - ?recv1(#message{ - sub_els = [#mam_fin{complete = true, - rsm = #rsm_set{count = 10}}]}) + #message{ + sub_els = [#mam_fin{complete = true, + rsm = #rsm_set{count = 10}}]} = + recv_message(Config) end, %% Getting the item count. Should be 5 (or 10). I4 = send(Config, @@ -3006,19 +3034,21 @@ mam_query_rsm(Config, NS) -> rsm = #rsm_set{max = 0}}]}), maybe_recv_iq_result(Config, NS, I4), if NS == ?NS_MAM_TMP -> - ?recv1(#iq{type = result, id = I4, - sub_els = [#mam_query{ - xmlns = NS, - rsm = #rsm_set{count = 5, - first = undefined, - last = undefined}}]}); + #iq{type = result, id = I4, + sub_els = [#mam_query{ + xmlns = NS, + rsm = #rsm_set{count = 5, + first = undefined, + last = undefined}}]} = + recv_iq(Config); true -> - ?recv1(#message{ - sub_els = [#mam_fin{ - complete = false, - rsm = #rsm_set{count = 10, - first = undefined, - last = undefined}}]}) + #message{ + sub_els = [#mam_fin{ + complete = false, + rsm = #rsm_set{count = 10, + first = undefined, + last = undefined}}]} = + recv_message(Config) end, %% Should receive 2 last messages I5 = send(Config, @@ -3030,25 +3060,28 @@ mam_query_rsm(Config, NS) -> lists:foreach( fun(N) -> Text = #text{data = integer_to_binary(N)}, - ?recv1(#message{to = MyJID, - sub_els = - [#mam_result{ - xmlns = NS, - sub_els = - [#forwarded{ - delay = #delay{}, - sub_els = - [#message{ - from = MyJID, to = Peer, - body = [Text]}]}]}]}) + #message{to = MyJID, + sub_els = + [#mam_result{ + xmlns = NS, + sub_els = + [#forwarded{ + delay = #delay{}, + sub_els = + [#message{ + from = MyJID, to = Peer, + body = [Text]}]}]}]} = + recv_message(Config) end, lists:seq(4, 5)), if NS == ?NS_MAM_TMP -> - ?recv1(#iq{type = result, id = I5, - sub_els = [#mam_query{xmlns = NS, rsm = #rsm_set{count = 5}}]}); + #iq{type = result, id = I5, + sub_els = [#mam_query{xmlns = NS, rsm = #rsm_set{count = 5}}]} = + recv_iq(Config); true -> - ?recv1(#message{ - sub_els = [#mam_fin{complete = false, - rsm = #rsm_set{count = 10}}]}) + #message{ + sub_els = [#mam_fin{complete = false, + rsm = #rsm_set{count = 10}}]} = + recv_message(Config) end. client_state_master(Config) -> @@ -3109,8 +3142,8 @@ client_state_slave(Config) -> Peer = ?config(master, Config), change_client_state(Config, inactive), wait_for_master(Config), - ?recv1(#presence{from = Peer, type = unavailable, - sub_els = [#delay{}]}), + #presence{from = Peer, type = unavailable, sub_els = [#delay{}]} = + recv_presence(Config), #message{ from = Peer, sub_els = @@ -3121,7 +3154,7 @@ client_state_slave(Config) -> items = [#ps_item{ id = <<"pep-1">>}]}}, - #delay{}]} = recv(Config), + #delay{}]} = recv_message(Config), #message{ from = Peer, sub_els = @@ -3132,17 +3165,17 @@ client_state_slave(Config) -> items = [#ps_item{ id = <<"pep-2">>}]}}, - #delay{}]} = recv(Config), - ?recv1(#message{from = Peer, thread = <<"1">>, - sub_els = [#chatstate{type = composing}, - #delay{}]}), - ?recv1(#message{from = Peer, thread = <<"1">>, - body = [#text{data = <<"body">>}], - sub_els = [#chatstate{type = active}]}), + #delay{}]} = recv_message(Config), + #message{from = Peer, thread = <<"1">>, + sub_els = [#chatstate{type = composing}, + #delay{}]} = recv_message(Config), + #message{from = Peer, thread = <<"1">>, + body = [#text{data = <<"body">>}], + sub_els = [#chatstate{type = active}]} = recv_message(Config), change_client_state(Config, active), wait_for_master(Config), - ?recv1(#message{from = Peer, thread = <<"1">>, - sub_els = [#chatstate{type = active}]}), + #message{from = Peer, thread = <<"1">>, + sub_els = [#chatstate{type = active}]} = recv_message(Config), disconnect(Config). %%%=================================================================== diff --git a/test/muc_tests.erl b/test/muc_tests.erl index c89b97742..709a82a22 100644 --- a/test/muc_tests.erl +++ b/test/muc_tests.erl @@ -425,6 +425,7 @@ muc_history_master(Config) -> ServerHost = ?config(server_host, Config), MyNick = ?config(nick, Config), MyNickJID = jid:replace_resource(Room, MyNick), + PeerNickJID = peer_muc_jid(Config), Size = gen_mod:get_module_opt(ServerHost, mod_muc, history_size, fun(I) when is_integer(I), I>=0 -> I end, 20), @@ -439,9 +440,14 @@ muc_history_master(Config) -> #message{type = groupchat, from = MyNickJID, body = Body} = recv_message(Config) end, lists:seq(0, Size)), - wait_for_slave(Config), - wait_for_slave(Config), - flush(Config), + put_event(Config, join), + lists:foreach( + fun(Type) -> + recv_muc_presence(Config, PeerNickJID, Type) + end, [available, unavailable, + available, unavailable, + available, unavailable, + available, unavailable]), ok = muc_leave(Config), disconnect(Config). @@ -453,7 +459,9 @@ muc_history_slave(Config) -> Size = gen_mod:get_module_opt(ServerHost, mod_muc, history_size, fun(I) when is_integer(I), I>=0 -> I end, 20), - {History, _, _} = muc_slave_join(Config), + ct:comment("Waiting for 'join' command from the master"), + join = get_event(Config), + {History, _, _} = muc_join(Config), ct:comment("Checking ordering of history events"), BodyList = [binary_to_integer(xmpp:get_text(Body)) || #message{type = groupchat, from = From, @@ -486,7 +494,6 @@ muc_history_slave(Config) -> From == PeerNickJID], BodyListWithoutFirst = lists:nthtail(1, lists:seq(1, Size)), ok = muc_leave(Config), - wait_for_master(Config), disconnect(Config). muc_invite_master(Config) -> @@ -663,8 +670,7 @@ muc_change_role_master(Config) -> nick = PeerNick}|_] = muc_get_role(Config, Role) end, [visitor, participant, moderator]), put_event(Config, disconnect), - wait_for_slave(Config), - flush(Config), + recv_muc_presence(Config, PeerNickJID, unavailable), ok = muc_leave(Config), disconnect(Config). @@ -687,7 +693,6 @@ muc_change_role_slave(Config, {Role, Reason}) -> muc_change_role_slave(Config, get_event(Config)); muc_change_role_slave(Config, disconnect) -> ok = muc_leave(Config), - wait_for_master(Config), disconnect(Config). muc_change_affiliation_master(Config) -> @@ -1522,7 +1527,7 @@ muc_join_new(Config, Room) -> items = [#muc_item{role = moderator, jid = MyJID, affiliation = owner}]} = - xmpp:get_subtag(?recv1(#presence{from = MyNickJID}), #muc_user{}), + recv_muc_presence(Config, MyNickJID, available), ct:comment("Checking if codes '110' (self-presence) and " "'201' (new room) is set"), true = lists:member(110, Codes), @@ -1623,8 +1628,7 @@ muc_leave(Config, Room) -> #muc_user{ status_codes = Codes, items = [#muc_item{role = none, jid = MyJID}]} = - xmpp:get_subtag(?recv1(#presence{from = MyNickJID, - type = unavailable}), #muc_user{}), + recv_muc_presence(Config, MyNickJID, unavailable), ct:comment("Checking if code '110' (self-presence) is set"), true = lists:member(110, Codes), ok. diff --git a/test/privacy_tests.erl b/test/privacy_tests.erl new file mode 100644 index 000000000..2ee945f1e --- /dev/null +++ b/test/privacy_tests.erl @@ -0,0 +1,821 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 18 Oct 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(privacy_tests). + +%% API +-compile(export_all). +-import(suite, [disconnect/1, send_recv/2, get_event/1, put_event/2, + recv_iq/1, recv_presence/1, recv_message/1, recv/1, + send/2, my_jid/1, server_jid/1, get_features/1, + set_roster/3, del_roster/1]). +-include("suite.hrl"). +-include("mod_roster.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +%%%=================================================================== +%%% Single cases +%%%=================================================================== +single_cases() -> + {privacy_single, [sequence], + [single_test(feature_enabled), + single_test(set_get_list), + single_test(get_list_non_existent), + single_test(set_default), + single_test(del_default), + single_test(set_default_non_existent), + single_test(set_active), + single_test(del_active), + single_test(set_active_non_existent), + single_test(remove_list), + single_test(remove_default_list), + single_test(remove_active_list), + %% TODO: this should be fixed + %% single_test(remove_list_non_existent), + single_test(allow_local_server), + single_test(malformed_iq_query), + single_test(malformed_get), + single_test(malformed_set), + single_test(malformed_type_value), + single_test(set_get_block)]}. + +feature_enabled(Config) -> + Features = get_features(Config), + true = lists:member(?NS_PRIVACY, Features), + true = lists:member(?NS_BLOCKING, Features), + disconnect(Config). + +set_get_list(Config) -> + ListName = <<"set-get-list">>, + Items = [#privacy_item{order = 0, action = deny, + type = jid, value = <<"user@jabber.org">>, + iq = true}, + #privacy_item{order = 1, action = allow, + type = group, value = <<"group">>, + message = true}, + #privacy_item{order = 2, action = allow, + type = subscription, value = <<"both">>, + presence_in = true}, + #privacy_item{order = 3, action = deny, + type = subscription, value = <<"from">>, + presence_out = true}, + #privacy_item{order = 4, action = deny, + type = subscription, value = <<"to">>, + iq = true, message = true}, + #privacy_item{order = 5, action = deny, + type = subscription, value = <<"none">>, + _ = true}, + #privacy_item{order = 6, action = deny}], + ok = set_items(Config, ListName, Items), + #privacy_list{name = ListName, items = Items1} = get_list(Config, ListName), + Items = lists:keysort(#privacy_item.order, Items1), + del_privacy(disconnect(Config)). + +get_list_non_existent(Config) -> + ListName = <<"get-list-non-existent">>, + #stanza_error{reason = 'item-not-found'} = get_list(Config, ListName), + disconnect(Config). + +set_default(Config) -> + ListName = <<"set-default">>, + Item = #privacy_item{order = 0, action = deny}, + ok = set_items(Config, ListName, [Item]), + ok = set_default(Config, ListName), + #privacy_query{default = ListName} = get_lists(Config), + del_privacy(disconnect(Config)). + +del_default(Config) -> + ListName = <<"del-default">>, + Item = #privacy_item{order = 0, action = deny}, + ok = set_items(Config, ListName, [Item]), + ok = set_default(Config, ListName), + #privacy_query{default = ListName} = get_lists(Config), + ok = set_default(Config, none), + #privacy_query{default = none} = get_lists(Config), + del_privacy(disconnect(Config)). + +set_default_non_existent(Config) -> + ListName = <<"set-default-non-existent">>, + #stanza_error{reason = 'item-not-found'} = set_default(Config, ListName), + disconnect(Config). + +set_active(Config) -> + ListName = <<"set-active">>, + Item = #privacy_item{order = 0, action = deny}, + ok = set_items(Config, ListName, [Item]), + ok = set_active(Config, ListName), + #privacy_query{active = ListName} = get_lists(Config), + del_privacy(disconnect(Config)). + +del_active(Config) -> + ListName = <<"del-active">>, + Item = #privacy_item{order = 0, action = deny}, + ok = set_items(Config, ListName, [Item]), + ok = set_active(Config, ListName), + #privacy_query{active = ListName} = get_lists(Config), + ok = set_active(Config, none), + #privacy_query{active = none} = get_lists(Config), + del_privacy(disconnect(Config)). + +set_active_non_existent(Config) -> + ListName = <<"set-active-non-existent">>, + #stanza_error{reason = 'item-not-found'} = set_active(Config, ListName), + disconnect(Config). + +remove_list(Config) -> + ListName = <<"remove-list">>, + Item = #privacy_item{order = 0, action = deny}, + ok = set_items(Config, ListName, [Item]), + ok = del_list(Config, ListName), + #privacy_query{lists = []} = get_lists(Config), + del_privacy(disconnect(Config)). + +remove_active_list(Config) -> + ListName = <<"remove-active-list">>, + Item = #privacy_item{order = 0, action = deny}, + ok = set_items(Config, ListName, [Item]), + ok = set_active(Config, ListName), + #stanza_error{reason = 'conflict'} = del_list(Config, ListName), + del_privacy(disconnect(Config)). + +remove_default_list(Config) -> + ListName = <<"remove-default-list">>, + Item = #privacy_item{order = 0, action = deny}, + ok = set_items(Config, ListName, [Item]), + ok = set_default(Config, ListName), + #stanza_error{reason = 'conflict'} = del_list(Config, ListName), + del_privacy(disconnect(Config)). + +remove_list_non_existent(Config) -> + ListName = <<"remove-list-non-existent">>, + #stanza_error{reason = 'item-not-found'} = del_list(Config, ListName), + disconnect(Config). + +allow_local_server(Config) -> + ListName = <<"allow-local-server">>, + Item = #privacy_item{order = 0, action = deny}, + ok = set_items(Config, ListName, [Item]), + ok = set_active(Config, ListName), + %% Whatever privacy rules are set, we should always communicate + %% with our home server + server_send_iqs(Config), + server_recv_iqs(Config), + send_stanzas_to_server_resource(Config), + del_privacy(disconnect(Config)). + +malformed_iq_query(Config) -> + lists:foreach( + fun(Type) -> + #iq{type = error} = + send_recv(Config, + #iq{type = Type, + sub_els = [#privacy_list{name = <<"foo">>}]}) + end, [get, set]), + disconnect(Config). + +malformed_get(Config) -> + JID = jid:make(randoms:get_string()), + lists:foreach( + fun(SubEl) -> + #iq{type = error} = + send_recv(Config, #iq{type = get, sub_els = [SubEl]}) + end, [#privacy_query{active = none}, + #privacy_query{default = none}, + #privacy_query{lists = [#privacy_list{name = <<"1">>}, + #privacy_list{name = <<"2">>}]}, + #block{items = [JID]}, #unblock{items = [JID]}, + #block{}, #unblock{}]), + disconnect(Config). + +malformed_set(Config) -> + lists:foreach( + fun(SubEl) -> + #iq{type = error} = + send_recv(Config, #iq{type = set, sub_els = [SubEl]}) + end, [#privacy_query{active = none, default = none}, + #privacy_query{lists = [#privacy_list{name = <<"1">>}, + #privacy_list{name = <<"2">>}]}, + #block{}, + #block_list{}, + #block_list{items = [jid:make(randoms:get_string())]}]). + +malformed_type_value(Config) -> + Item = #privacy_item{order = 0, action = deny}, + #stanza_error{reason = 'bad-request'} = + set_items(Config, <<"malformed-jid">>, + [Item#privacy_item{type = jid, value = <<"@bad">>}]), + #stanza_error{reason = 'bad-request'} = + set_items(Config, <<"malformed-group">>, + [Item#privacy_item{type = group, value = <<"">>}]), + #stanza_error{reason = 'bad-request'} = + set_items(Config, <<"malformed-subscription">>, + [Item#privacy_item{type = subscription, value = <<"bad">>}]), + disconnect(Config). + +set_get_block(Config) -> + J1 = jid:make(randoms:get_string(), randoms:get_string()), + J2 = jid:make(randoms:get_string(), randoms:get_string()), + {ok, ListName} = set_block(Config, [J1, J2]), + JIDs = get_block(Config), + JIDs = lists:sort([J1, J2]), + {ok, ListName} = set_unblock(Config, [J2, J1]), + [] = get_block(Config), + del_privacy(disconnect(Config)). + +%%%=================================================================== +%%% Master-slave cases +%%%=================================================================== +master_slave_cases() -> + {privacy_master_slave, [parallel], + [master_slave_test(deny_bare_jid), + master_slave_test(deny_full_jid), + master_slave_test(deny_server_jid), + master_slave_test(deny_group), + master_slave_test(deny_sub_both), + master_slave_test(deny_sub_from), + master_slave_test(deny_sub_to), + master_slave_test(deny_sub_none), + master_slave_test(deny_all), + master_slave_test(deny_offline), + master_slave_test(block), + master_slave_test(unblock), + master_slave_test(unblock_all)]}. + +deny_bare_jid_master(Config) -> + PeerJID = ?config(peer, Config), + PeerBareJID = jid:remove_resource(PeerJID), + deny_master(Config, {jid, jid:to_string(PeerBareJID)}). + +deny_bare_jid_slave(Config) -> + deny_slave(Config). + +deny_full_jid_master(Config) -> + PeerJID = ?config(peer, Config), + deny_master(Config, {jid, jid:to_string(PeerJID)}). + +deny_full_jid_slave(Config) -> + deny_slave(Config). + +deny_server_jid_master(Config) -> + {_, Server, _} = jid:tolower(?config(peer, Config)), + deny_master(Config, {jid, Server}). + +deny_server_jid_slave(Config) -> + deny_slave(Config). + +deny_group_master(Config) -> + Group = randoms:get_string(), + deny_master(Config, {group, Group}). + +deny_group_slave(Config) -> + deny_slave(Config). + +deny_sub_both_master(Config) -> + deny_master(Config, {subscription, <<"both">>}). + +deny_sub_both_slave(Config) -> + deny_slave(Config). + +deny_sub_from_master(Config) -> + deny_master(Config, {subscription, <<"from">>}). + +deny_sub_from_slave(Config) -> + deny_slave(Config). + +deny_sub_to_master(Config) -> + deny_master(Config, {subscription, <<"to">>}). + +deny_sub_to_slave(Config) -> + deny_slave(Config). + +deny_sub_none_master(Config) -> + deny_master(Config, {subscription, <<"none">>}). + +deny_sub_none_slave(Config) -> + deny_slave(Config). + +deny_all_master(Config) -> + deny_master(Config, {undefined, <<"">>}). + +deny_all_slave(Config) -> + deny_slave(Config). + +deny_master(Config, {Type, Value}) -> + Sub = if Type == subscription -> + erlang:binary_to_atom(Value, utf8); + true -> + both + end, + Groups = if Type == group -> [Value]; + true -> [] + end, + set_roster(Config, Sub, Groups), + lists:foreach( + fun(Opts) -> + ListName = str:format("deny-~s-~s-~p", [Type, Value, Opts]), + Item = #privacy_item{order = 0, + action = deny, + iq = proplists:get_bool(iq, Opts), + message = proplists:get_bool(message, Opts), + presence_in = proplists:get_bool(presence_in, Opts), + presence_out = proplists:get_bool(presence_out, Opts), + type = Type, + value = Value}, + ok = set_items(Config, ListName, [Item]), + ok = set_active(Config, ListName), + put_event(Config, Opts), + case is_presence_in_blocked(Opts) of + true -> ok; + false -> recv_presences(Config) + end, + case is_iq_in_blocked(Opts) of + true -> ok; + false -> recv_iqs(Config) + end, + case is_message_in_blocked(Opts) of + true -> ok; + false -> recv_messages(Config) + end, + ct:comment("Waiting for 'send' command from the slave"), + send = get_event(Config), + case is_presence_out_blocked(Opts) of + true -> check_presence_blocked(Config, 'not-acceptable'); + false -> ok + end, + case is_iq_out_blocked(Opts) of + true -> check_iq_blocked(Config, 'not-acceptable'); + false -> send_iqs(Config) + end, + case is_message_out_blocked(Opts) of + true -> check_message_blocked(Config, 'not-acceptable'); + false -> send_messages(Config) + end, + case is_other_blocked(Opts) of + true -> check_other_blocked(Config, 'not-acceptable'); + false -> ok + end, + ct:comment("Waiting for slave to finish processing our stanzas"), + done = get_event(Config) + end, + [[iq], [message], [presence_in], [presence_out], + [iq, message, presence_in, presence_out], []]), + put_event(Config, disconnect), + clean_up(disconnect(Config)). + +deny_slave(Config) -> + set_roster(Config, both, []), + deny_slave(Config, get_event(Config)). + +deny_slave(Config, disconnect) -> + clean_up(disconnect(Config)); +deny_slave(Config, Opts) -> + send_presences(Config), + case is_iq_in_blocked(Opts) of + true -> check_iq_blocked(Config, 'service-unavailable'); + false -> send_iqs(Config) + end, + case is_message_in_blocked(Opts) of + true -> check_message_blocked(Config, 'service-unavailable'); + false -> send_messages(Config) + end, + put_event(Config, send), + case is_iq_out_blocked(Opts) of + true -> ok; + false -> recv_iqs(Config) + end, + case is_message_out_blocked(Opts) of + true -> ok; + false -> recv_messages(Config) + end, + put_event(Config, done), + deny_slave(Config, get_event(Config)). + +deny_offline_master(Config) -> + set_roster(Config, both, []), + ListName = <<"deny-offline">>, + Item = #privacy_item{order = 0, action = deny}, + ok = set_items(Config, ListName, [Item]), + ok = set_default(Config, ListName), + NewConfig = disconnect(Config), + put_event(NewConfig, send), + ct:comment("Waiting for the slave to finish"), + done = get_event(NewConfig), + clean_up(NewConfig). + +deny_offline_slave(Config) -> + set_roster(Config, both, []), + ct:comment("Waiting for 'send' command from the master"), + send = get_event(Config), + send_presences(Config), + check_iq_blocked(Config, 'service-unavailable'), + check_message_blocked(Config, 'service-unavailable'), + put_event(Config, done), + clean_up(disconnect(Config)). + +block_master(Config) -> + PeerJID = ?config(peer, Config), + set_roster(Config, both, []), + {ok, _} = set_block(Config, [PeerJID]), + check_presence_blocked(Config, 'not-acceptable'), + check_iq_blocked(Config, 'not-acceptable'), + check_message_blocked(Config, 'not-acceptable'), + check_other_blocked(Config, 'not-acceptable'), + %% We should always be able to communicate with our home server + server_send_iqs(Config), + server_recv_iqs(Config), + send_stanzas_to_server_resource(Config), + put_event(Config, send), + done = get_event(Config), + clean_up(disconnect(Config)). + +block_slave(Config) -> + set_roster(Config, both, []), + ct:comment("Waiting for 'send' command from master"), + send = get_event(Config), + send_presences(Config), + check_iq_blocked(Config, 'service-unavailable'), + check_message_blocked(Config, 'service-unavailable'), + put_event(Config, done), + clean_up(disconnect(Config)). + +unblock_master(Config) -> + PeerJID = ?config(peer, Config), + set_roster(Config, both, []), + {ok, ListName} = set_block(Config, [PeerJID]), + {ok, ListName} = set_unblock(Config, [PeerJID]), + put_event(Config, send), + recv_presences(Config), + recv_iqs(Config), + recv_messages(Config), + clean_up(disconnect(Config)). + +unblock_slave(Config) -> + set_roster(Config, both, []), + ct:comment("Waiting for 'send' command from master"), + send = get_event(Config), + send_presences(Config), + send_iqs(Config), + send_messages(Config), + clean_up(disconnect(Config)). + +unblock_all_master(Config) -> + PeerJID = ?config(peer, Config), + set_roster(Config, both, []), + {ok, ListName} = set_block(Config, [PeerJID]), + {ok, ListName} = set_unblock(Config, []), + put_event(Config, send), + recv_presences(Config), + recv_iqs(Config), + recv_messages(Config), + clean_up(disconnect(Config)). + +unblock_all_slave(Config) -> + set_roster(Config, both, []), + ct:comment("Waiting for 'send' command from master"), + send = get_event(Config), + send_presences(Config), + send_iqs(Config), + send_messages(Config), + clean_up(disconnect(Config)). + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +single_test(T) -> + list_to_atom("privacy_" ++ atom_to_list(T)). + +master_slave_test(T) -> + {list_to_atom("privacy_" ++ atom_to_list(T)), [parallel], + [list_to_atom("privacy_" ++ atom_to_list(T) ++ "_master"), + list_to_atom("privacy_" ++ atom_to_list(T) ++ "_slave")]}. + +set_items(Config, Name, Items) -> + ct:comment("Setting privacy list ~s with items = ~p", [Name, Items]), + case send_recv( + Config, + #iq{type = set, sub_els = [#privacy_query{ + lists = [#privacy_list{ + name = Name, + items = Items}]}]}) of + #iq{type = result, sub_els = []} -> + ct:comment("Receiving privacy list push"), + #iq{type = set, id = ID, + sub_els = [#privacy_query{lists = [#privacy_list{ + name = Name}]}]} = + recv_iq(Config), + send(Config, #iq{type = result, id = ID}), + ok; + #iq{type = error} = Err -> + xmpp:get_error(Err) + end. + +get_list(Config, Name) -> + ct:comment("Requesting privacy list ~s", [Name]), + case send_recv(Config, + #iq{type = get, + sub_els = [#privacy_query{ + lists = [#privacy_list{name = Name}]}]}) of + #iq{type = result, sub_els = [#privacy_query{lists = [List]}]} -> + List; + #iq{type = error} = Err -> + xmpp:get_error(Err) + end. + +get_lists(Config) -> + ct:comment("Requesting privacy lists"), + case send_recv(Config, #iq{type = get, sub_els = [#privacy_query{}]}) of + #iq{type = result, sub_els = [SubEl]} -> + SubEl; + #iq{type = error} = Err -> + xmpp:get_error(Err) + end. + +del_list(Config, Name) -> + case send_recv( + Config, + #iq{type = set, sub_els = [#privacy_query{ + lists = [#privacy_list{ + name = Name}]}]}) of + #iq{type = result, sub_els = []} -> + ct:comment("Receiving privacy list push"), + #iq{type = set, id = ID, + sub_els = [#privacy_query{lists = [#privacy_list{ + name = Name}]}]} = + recv_iq(Config), + send(Config, #iq{type = result, id = ID}), + ok; + #iq{type = error} = Err -> + xmpp:get_error(Err) + end. + +set_active(Config, Name) -> + ct:comment("Setting active privacy list ~s", [Name]), + case send_recv( + Config, + #iq{type = set, sub_els = [#privacy_query{active = Name}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = Err -> + xmpp:get_error(Err) + end. + +set_default(Config, Name) -> + ct:comment("Setting default privacy list ~s", [Name]), + case send_recv( + Config, + #iq{type = set, sub_els = [#privacy_query{default = Name}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = Err -> + xmpp:get_error(Err) + end. + +get_block(Config) -> + case send_recv(Config, #iq{type = get, sub_els = [#block_list{}]}) of + #iq{type = result, sub_els = [#block_list{items = JIDs}]} -> + lists:sort(JIDs); + #iq{type = error} = Err -> + xmpp:get_error(Err) + end. + +set_block(Config, JIDs) -> + case send_recv(Config, #iq{type = set, + sub_els = [#block{items = JIDs}]}) of + #iq{type = result, sub_els = []} -> + {#iq{id = I1, sub_els = [#block{items = Items}]}, + #iq{id = I2, sub_els = [#privacy_query{lists = Lists}]}} = + ?recv2(#iq{type = set, sub_els = [#block{}]}, + #iq{type = set, sub_els = [#privacy_query{}]}), + send(Config, #iq{type = result, id = I1}), + send(Config, #iq{type = result, id = I2}), + ct:comment("Checking if all JIDs present in the push"), + true = lists:sort(JIDs) == lists:sort(Items), + ct:comment("Getting name of the corresponding privacy list"), + [#privacy_list{name = Name}] = Lists, + {ok, Name}; + #iq{type = error} = Err -> + xmpp:get_error(Err) + end. + +set_unblock(Config, JIDs) -> + ct:comment("Unblocking ~p", [JIDs]), + case send_recv(Config, #iq{type = set, + sub_els = [#unblock{items = JIDs}]}) of + #iq{type = result, sub_els = []} -> + {#iq{id = I1, sub_els = [#unblock{items = Items}]}, + #iq{id = I2, sub_els = [#privacy_query{lists = Lists}]}} = + ?recv2(#iq{type = set, sub_els = [#unblock{}]}, + #iq{type = set, sub_els = [#privacy_query{}]}), + send(Config, #iq{type = result, id = I1}), + send(Config, #iq{type = result, id = I2}), + ct:comment("Checking if all JIDs present in the push"), + true = lists:sort(JIDs) == lists:sort(Items), + ct:comment("Getting name of the corresponding privacy list"), + [#privacy_list{name = Name}] = Lists, + {ok, Name}; + #iq{type = error} = Err -> + xmpp:get_error(Err) + end. + +del_privacy(Config) -> + {U, S, _} = jid:tolower(my_jid(Config)), + ct:comment("Removing all privacy data"), + mod_privacy:remove_user(U, S), + Config. + +clean_up(Config) -> + del_privacy(del_roster(Config)). + +check_iq_blocked(Config, Reason) -> + PeerJID = ?config(peer, Config), + ct:comment("Checking if all IQs are blocked"), + lists:foreach( + fun(Type) -> + send(Config, #iq{type = Type, to = PeerJID}) + end, [error, result]), + lists:foreach( + fun(Type) -> + #iq{type = error} = Err = + send_recv(Config, #iq{type = Type, to = PeerJID, + sub_els = [#ping{}]}), + #stanza_error{reason = Reason} = xmpp:get_error(Err) + end, [set, get]). + +check_message_blocked(Config, Reason) -> + PeerJID = ?config(peer, Config), + ct:comment("Checking if all messages are blocked"), + %% TODO: do something with headline and groupchat. + %% The hack from 64d96778b452aad72349b21d2ac94e744617b07a + %% screws this up. + lists:foreach( + fun(Type) -> + send(Config, #message{type = Type, to = PeerJID}) + end, [error]), + lists:foreach( + fun(Type) -> + #message{type = error} = Err = + send_recv(Config, #message{type = Type, to = PeerJID}), + #stanza_error{reason = Reason} = xmpp:get_error(Err) + end, [chat, normal]). + +check_presence_blocked(Config, Reason) -> + PeerJID = ?config(peer, Config), + ct:comment("Checking if all presences are blocked"), + lists:foreach( + fun(Type) -> + #presence{type = error} = Err = + send_recv(Config, #presence{type = Type, to = PeerJID}), + #stanza_error{reason = Reason} = xmpp:get_error(Err) + end, [available, unavailable]). + +check_other_blocked(Config, Reason) -> + PeerJID = ?config(peer, Config), + ct:comment("Checking if subscriptions and presence-errors are blocked"), + send(Config, #presence{type = error, to = PeerJID}), + lists:foreach( + fun(Type) -> + #presence{type = error} = Err = + send_recv(Config, #presence{type = Type, to = PeerJID}), + #stanza_error{reason = Reason} = xmpp:get_error(Err) + end, [subscribe, subscribed, unsubscribe, unsubscribed]). + +send_presences(Config) -> + PeerJID = ?config(peer, Config), + ct:comment("Sending all types of presences to the peer"), + lists:foreach( + fun(Type) -> + send(Config, #presence{type = Type, to = PeerJID}) + end, [available, unavailable]). + +send_iqs(Config) -> + PeerJID = ?config(peer, Config), + ct:comment("Sending all types of IQs to the peer"), + lists:foreach( + fun(Type) -> + send(Config, #iq{type = Type, to = PeerJID}) + end, [set, get, error, result]). + +send_messages(Config) -> + PeerJID = ?config(peer, Config), + ct:comment("Sending all types of messages to the peer"), + lists:foreach( + fun(Type) -> + send(Config, #message{type = Type, to = PeerJID}) + end, [chat, error, groupchat, headline, normal]). + +recv_presences(Config) -> + PeerJID = ?config(peer, Config), + lists:foreach( + fun(Type) -> + #presence{type = Type, from = PeerJID} = + recv_presence(Config) + end, [available, unavailable]). + +recv_iqs(Config) -> + PeerJID = ?config(peer, Config), + lists:foreach( + fun(Type) -> + #iq{type = Type, from = PeerJID} = recv_iq(Config) + end, [set, get, error, result]). + +recv_messages(Config) -> + PeerJID = ?config(peer, Config), + lists:foreach( + fun(Type) -> + #message{type = Type, from = PeerJID} = recv_message(Config) + end, [chat, error, groupchat, headline, normal]). + +match_all(Opts) -> + IQ = proplists:get_bool(iq, Opts), + Message = proplists:get_bool(message, Opts), + PresenceIn = proplists:get_bool(presence_in, Opts), + PresenceOut = proplists:get_bool(presence_out, Opts), + not (IQ or Message or PresenceIn or PresenceOut). + +is_message_in_blocked(Opts) -> + proplists:get_bool(message, Opts) or match_all(Opts). + +is_message_out_blocked(Opts) -> + match_all(Opts). + +is_iq_in_blocked(Opts) -> + proplists:get_bool(iq, Opts) or match_all(Opts). + +is_iq_out_blocked(Opts) -> + match_all(Opts). + +is_presence_in_blocked(Opts) -> + proplists:get_bool(presence_in, Opts) or match_all(Opts). + +is_presence_out_blocked(Opts) -> + proplists:get_bool(presence_out, Opts) or match_all(Opts). + +is_other_blocked(Opts) -> + %% 'other' means subscriptions and presence-errors + match_all(Opts). + +server_send_iqs(Config) -> + ServerJID = server_jid(Config), + MyJID = my_jid(Config), + ct:comment("Sending IQs from ~s to ~s", + [jid:to_string(ServerJID), jid:to_string(MyJID)]), + lists:foreach( + fun(Type) -> + ejabberd_router:route( + ServerJID, MyJID, #iq{type = Type}) + end, [error, result]), + lists:foreach( + fun(Type) -> + ejabberd_local:route_iq( + ServerJID, MyJID, #iq{type = Type}, + fun(#iq{type = result, sub_els = []}) -> ok; + (IQ) -> ct:fail({unexpected_iq_result, IQ}) + end) + end, [set, get]). + +server_recv_iqs(Config) -> + ServerJID = server_jid(Config), + ct:comment("Receiving IQs from ~s", [jid:to_string(ServerJID)]), + lists:foreach( + fun(Type) -> + #iq{type = Type, from = ServerJID} = recv_iq(Config) + end, [error, result]), + lists:foreach( + fun(Type) -> + #iq{type = Type, from = ServerJID, id = I} = recv_iq(Config), + send(Config, #iq{to = ServerJID, type = result, id = I}) + end, [set, get]). + +send_stanzas_to_server_resource(Config) -> + ServerJID = server_jid(Config), + ServerJIDResource = jid:replace_resource(ServerJID, <<"resource">>), + %% All stanzas sent should be handled by local_send_to_resource_hook + %% and should be bounced with item-not-found error + ct:comment("Sending IQs to ~s", [jid:to_string(ServerJIDResource)]), + lists:foreach( + fun(Type) -> + #iq{type = error} = Err = + send_recv(Config, #iq{type = Type, to = ServerJIDResource}), + #stanza_error{reason = 'item-not-found'} = xmpp:get_error(Err) + end, [set, get]), + ct:comment("Sending messages to ~s", [jid:to_string(ServerJIDResource)]), + lists:foreach( + fun(Type) -> + #message{type = error} = Err = + send_recv(Config, #message{type = Type, to = ServerJIDResource}), + #stanza_error{reason = 'item-not-found'} = xmpp:get_error(Err) + end, [normal, chat, groupchat, headline]), + ct:comment("Sending presences to ~s", [jid:to_string(ServerJIDResource)]), + lists:foreach( + fun(Type) -> + #presence{type = error} = Err = + send_recv(Config, #presence{type = Type, to = ServerJIDResource}), + #stanza_error{reason = 'item-not-found'} = xmpp:get_error(Err) + end, [available, unavailable]). diff --git a/test/suite.erl b/test/suite.erl index 7a823844b..3bed62562 100644 --- a/test/suite.erl +++ b/test/suite.erl @@ -13,6 +13,7 @@ -include("suite.hrl"). -include_lib("kernel/include/file.hrl"). +-include("mod_roster.hrl"). %%%=================================================================== %%% API @@ -171,10 +172,18 @@ connect(Config) -> tcp_connect(Config) -> case ?config(socket, Config) of undefined -> + Owner = self(), + NS = case ?config(type, Config) of + client -> ?NS_CLIENT; + server -> ?NS_SERVER; + component -> ?NS_COMPONENT + end, + ReceiverPid = spawn(fun() -> receiver(NS, Owner) end), {ok, Sock} = ejabberd_socket:connect( ?config(server_host, Config), ?config(server_port, Config), - [binary, {packet, 0}, {active, false}]), + [binary, {packet, 0}, {active, false}], + infinity, ReceiverPid), set_opt(socket, Sock, Config); _ -> Config @@ -219,9 +228,11 @@ disconnect(Config) -> catch exit:normal -> ok end, - {xmlstreamend, <<"stream:stream">>} = recv(Config), + receive {xmlstreamend, <<"stream:stream">>} -> ok end, + flush(Config), ejabberd_socket:close(Socket), - Config. + ct:comment("Disconnected"), + set_opt(socket, undefined, Config). close_socket(Config) -> Socket = ?config(socket, Config), @@ -435,40 +446,25 @@ match_failure(Received, [Match]) when is_list(Match)-> match_failure(Received, Matches) -> ct:fail("Received input:~n~n~p~n~ndon't match expected patterns:~n~n~p", [Received, Matches]). -recv(Config) -> +recv(_Config) -> receive - {'$gen_event', {xmlstreamelement, El}} -> - decode_stream_element(Config, El); - {'$gen_event', {xmlstreamstart, Name, Attrs}} -> - decode(#xmlel{name = Name, attrs = Attrs}, <<>>, []); - {'$gen_event', Event} -> - Event + {fail, El, Why} -> + ct:fail("recv failed: ~p->~n~s", + [El, xmpp:format_error(Why)]); + Event -> + Event end. -recv_iq(Config) -> - receive - {'$gen_event', {xmlstreamelement, #xmlel{name = <<"iq">>} = El}} -> - decode_stream_element(Config, El) - end. +recv_iq(_Config) -> + receive #iq{} = IQ -> IQ end. -recv_presence(Config) -> - receive - {'$gen_event', {xmlstreamelement, #xmlel{name = <<"presence">>} = El}} -> - decode_stream_element(Config, El) - end. +recv_presence(_Config) -> + receive #presence{} = Pres -> Pres end. -recv_message(Config) -> - receive - {'$gen_event', {xmlstreamelement, #xmlel{name = <<"message">>} = El}} -> - decode_stream_element(Config, El) - end. +recv_message(_Config) -> + receive #message{} = Msg -> Msg end. -decode_stream_element(Config, El) -> - NS = case ?config(type, Config) of - client -> ?NS_CLIENT; - server -> ?NS_SERVER; - component -> ?NS_COMPONENT - end, +decode_stream_element(NS, El) -> decode(El, NS, []). format_element(El) -> @@ -517,13 +513,13 @@ send(State, Pkt) -> send_recv(State, #message{} = Msg) -> ID = send(State, Msg), - #message{id = ID} = recv_message(State); + receive #message{id = ID} = Result -> Result end; send_recv(State, #presence{} = Pres) -> ID = send(State, Pres), - #presence{id = ID} = recv_presence(State); + receive #presence{id = ID} = Result -> Result end; send_recv(State, #iq{} = IQ) -> ID = send(State, IQ), - #iq{id = ID} = recv_iq(State). + receive #iq{id = ID} = Result -> Result end. sasl_new(<<"PLAIN">>, User, Server, Password) -> {<>, @@ -698,6 +694,50 @@ wait_for_slave(Config) -> make_iq_result(#iq{from = From} = IQ) -> IQ#iq{type = result, to = From, from = undefined, sub_els = []}. +set_roster(Config, Subscription, Groups) -> + MyJID = my_jid(Config), + {U, S, _} = jid:tolower(MyJID), + PeerJID = ?config(peer, Config), + PeerBareJID = jid:remove_resource(PeerJID), + PeerLJID = jid:tolower(PeerBareJID), + ct:comment("Adding ~s to roster with subscription '~s' in groups ~p", + [jid:to_string(PeerBareJID), Subscription, Groups]), + {atomic, _} = mod_roster:set_roster(#roster{usj = {U, S, PeerLJID}, + us = {U, S}, + jid = PeerLJID, + subscription = Subscription, + groups = Groups}), + Config. + +del_roster(Config) -> + MyJID = my_jid(Config), + {U, S, _} = jid:tolower(MyJID), + PeerJID = ?config(peer, Config), + PeerBareJID = jid:remove_resource(PeerJID), + PeerLJID = jid:tolower(PeerBareJID), + ct:comment("Removing ~s from roster", [jid:to_string(PeerBareJID)]), + {atomic, _} = mod_roster:del_roster(U, S, PeerLJID), + Config. + +receiver(NS, Owner) -> + MRef = erlang:monitor(process, Owner), + receiver(NS, Owner, MRef). + +receiver(NS, Owner, MRef) -> + receive + {'$gen_event', {xmlstreamelement, El}} -> + Owner ! decode_stream_element(NS, El), + receiver(NS, Owner, MRef); + {'$gen_event', {xmlstreamstart, Name, Attrs}} -> + Owner ! decode(#xmlel{name = Name, attrs = Attrs}, <<>>, []), + receiver(NS, Owner, MRef); + {'$gen_event', Event} -> + Owner ! Event, + receiver(NS, Owner, MRef); + {'DOWN', MRef, process, Owner, _} -> + ok + end. + %%%=================================================================== %%% Clients puts and gets events via this relay. %%%=================================================================== @@ -730,12 +770,17 @@ event_relay(Events, Subscribers) -> end, Subscribers), event_relay([Event|Events], Subscribers); {'DOWN', _MRef, process, Pid, _Info} -> - NewSubscribers = lists:delete(Pid, Subscribers), - lists:foreach( - fun(Subscriber) -> - Subscriber ! {event, peer_down, self()} - end, NewSubscribers), - event_relay(Events, NewSubscribers) + case lists:member(Pid, Subscribers) of + true -> + NewSubscribers = lists:delete(Pid, Subscribers), + lists:foreach( + fun(Subscriber) -> + Subscriber ! {event, peer_down, self()} + end, NewSubscribers), + event_relay(Events, NewSubscribers); + false -> + event_relay(Events, Subscribers) + end end. subscribe_to_events(Config) -> @@ -762,8 +807,10 @@ get_event(Config) -> end. flush(Config) -> - flush(Config, []). - -flush(Config, Msgs) -> - receive Msg -> flush(Config, [Msg|Msgs]) - after 1000 -> lists:reverse(Msgs) end. + receive + {event, peer_down, _} -> flush(Config); + closed -> flush(Config); + Msg -> ct:fail({unexpected_msg, Msg}) + after 0 -> + ok + end. From 9d977e484a4c9609e19b08bc1235deb88b9a725c Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sat, 22 Oct 2016 13:09:11 +0300 Subject: [PATCH 064/151] Use base64:mime_decode/1 for SASL packets It will be now possible to accept SASL packets with only single '=' character set as required by RFC6120 --- specs/xmpp_codec.spec | 9 +++++---- src/xmpp_codec.erl | 8 ++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/specs/xmpp_codec.spec b/specs/xmpp_codec.spec index 81f674bf3..608e1fe2d 100644 --- a/specs/xmpp_codec.spec +++ b/specs/xmpp_codec.spec @@ -659,7 +659,7 @@ #elem{name = <<"auth">>, xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>, cdata = #cdata{label = '$text', - dec = {base64, decode, []}, + dec = {base64, mime_decode, []}, enc = {base64, encode, []}}, result = {sasl_auth, '$mechanism', '$text'}, attrs = [#attr{name = <<"mechanism">>, @@ -674,7 +674,7 @@ #elem{name = <<"challenge">>, xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>, cdata = #cdata{label = '$text', - dec = {base64, decode, []}, + dec = {base64, mime_decode, []}, enc = {base64, encode, []}}, result = {sasl_challenge, '$text'}}). @@ -682,7 +682,7 @@ #elem{name = <<"response">>, xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>, cdata = #cdata{label = '$text', - dec = {base64, decode, []}, + dec = {base64, mime_decode, []}, enc = {base64, encode, []}}, result = {sasl_response, '$text'}}). @@ -690,7 +690,7 @@ #elem{name = <<"success">>, xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>, cdata = #cdata{label = '$text', - dec = {base64, decode, []}, + dec = {base64, mime_decode, []}, enc = {base64, encode, []}}, result = {sasl_success, '$text'}}). @@ -3467,6 +3467,7 @@ enc_ip(Addr) -> -spec re:split(_, _) -> [binary()]. -spec base64:decode(_) -> binary(). +-spec base64:mime_decode(_) -> binary(). -spec dec_host_port(_) -> binary() | inet:ip_address() | {binary() | inet:ip_address(), non_neg_integer()}. diff --git a/src/xmpp_codec.erl b/src/xmpp_codec.erl index f230dc489..345de7031 100644 --- a/src/xmpp_codec.erl +++ b/src/xmpp_codec.erl @@ -29298,7 +29298,7 @@ encode_sasl_success({sasl_success, Text}, __TopXMLNS) -> decode_sasl_success_cdata(__TopXMLNS, <<>>) -> <<>>; decode_sasl_success_cdata(__TopXMLNS, _val) -> - case catch base64:decode(_val) of + case catch base64:mime_decode(_val) of {'EXIT', _} -> erlang:error({xmpp_codec, {bad_cdata_value, <<>>, <<"success">>, __TopXMLNS}}); @@ -29338,7 +29338,7 @@ encode_sasl_response({sasl_response, Text}, decode_sasl_response_cdata(__TopXMLNS, <<>>) -> <<>>; decode_sasl_response_cdata(__TopXMLNS, _val) -> - case catch base64:decode(_val) of + case catch base64:mime_decode(_val) of {'EXIT', _} -> erlang:error({xmpp_codec, {bad_cdata_value, <<>>, <<"response">>, __TopXMLNS}}); @@ -29378,7 +29378,7 @@ encode_sasl_challenge({sasl_challenge, Text}, decode_sasl_challenge_cdata(__TopXMLNS, <<>>) -> <<>>; decode_sasl_challenge_cdata(__TopXMLNS, _val) -> - case catch base64:decode(_val) of + case catch base64:mime_decode(_val) of {'EXIT', _} -> erlang:error({xmpp_codec, {bad_cdata_value, <<>>, <<"challenge">>, __TopXMLNS}}); @@ -29454,7 +29454,7 @@ encode_sasl_auth_attr_mechanism(_val, _acc) -> decode_sasl_auth_cdata(__TopXMLNS, <<>>) -> <<>>; decode_sasl_auth_cdata(__TopXMLNS, _val) -> - case catch base64:decode(_val) of + case catch base64:mime_decode(_val) of {'EXIT', _} -> erlang:error({xmpp_codec, {bad_cdata_value, <<>>, <<"auth">>, __TopXMLNS}}); From 2a63d0e95a0e77261a1b57a816720bef190388b1 Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Tue, 1 Nov 2016 08:47:08 +0100 Subject: [PATCH 065/151] mod_mam: Use user JID for stanza ID 'by' attribute Use the user (or room) JID instead of the server JID for the 'by' attribute of and tags. That's what the examples in XEP-0313 v0.2 and XEP-0359 v0.3.0 suggest. --- src/mod_mam.erl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/mod_mam.erl b/src/mod_mam.erl index cbd23ebde..4c3050df1 100644 --- a/src/mod_mam.erl +++ b/src/mod_mam.erl @@ -214,7 +214,7 @@ user_receive_packet(Pkt, C2SState, JID, Peer, To) -> NewPkt = strip_my_archived_tag(Pkt, LServer), case store_msg(C2SState, NewPkt, LUser, LServer, Peer, recv) of {ok, ID} -> - set_stanza_id(NewPkt, LServer, ID); + set_stanza_id(NewPkt, JID, ID); _ -> NewPkt end; @@ -232,7 +232,7 @@ user_send_packet(Pkt, C2SState, JID, Peer) -> case store_msg(C2SState, xmpp:set_from_to(NewPkt, JID, Peer), LUser, LServer, Peer, send) of {ok, ID} -> - set_stanza_id(NewPkt, LServer, ID); + set_stanza_id(NewPkt, JID, ID); _ -> NewPkt end; @@ -256,7 +256,7 @@ muc_filter_message(Pkt, #state{config = Config} = MUCState, StorePkt = strip_x_jid_tags(NewPkt), case store_muc(MUCState, StorePkt, RoomJID, From, FromNick) of {ok, ID} -> - set_stanza_id(NewPkt, LServer, ID); + set_stanza_id(NewPkt, RoomJID, ID); _ -> NewPkt end; @@ -264,9 +264,9 @@ muc_filter_message(Pkt, #state{config = Config} = MUCState, Pkt end. -set_stanza_id(Pkt, LServer, ID) -> - Archived = #mam_archived{by = jid:make(LServer), id = ID}, - StanzaID = #stanza_id{by = jid:make(LServer), id = ID}, +set_stanza_id(Pkt, JID, ID) -> + Archived = #mam_archived{by = JID, id = ID}, + StanzaID = #stanza_id{by = JID, id = ID}, NewEls = [Archived, StanzaID|xmpp:get_els(Pkt)], xmpp:set_els(Pkt, NewEls). @@ -533,9 +533,9 @@ strip_my_archived_tag(Pkt, LServer) -> end end), NewEls = lists:filter( - fun(#mam_archived{by = #jid{luser = <<>>} = By}) -> + fun(#mam_archived{by = By}) -> By#jid.lserver /= LServer; - (#stanza_id{by = #jid{luser = <<>>} = By}) -> + (#stanza_id{by = By}) -> By#jid.lserver /= LServer; (_) -> true From 56c91d3c58ec5461600f70d2d0413c846767f882 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Mon, 7 Nov 2016 10:10:57 +0300 Subject: [PATCH 066/151] Add roster tests --- src/ejabberd_sm.erl | 213 +++++++--------- src/mod_roster.erl | 94 ++++--- test/ejabberd_SUITE.erl | 224 +++-------------- test/roster_tests.erl | 527 ++++++++++++++++++++++++++++++++++++++++ test/suite.erl | 29 ++- 5 files changed, 727 insertions(+), 360 deletions(-) create mode 100644 test/roster_tests.erl diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index f6d0e765d..6f6a196e5 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -442,135 +442,96 @@ online(Sessions) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -spec do_route(jid(), jid(), stanza() | broadcast()) -> any(). +do_route(From, #jid{lresource = <<"">>} = To, {broadcast, _} = Packet) -> + ?DEBUG("processing broadcast to bare JID: ~p", [Packet]), + lists:foreach( + fun(R) -> + do_route(From, jid:replace_resource(To, R), Packet) + end, get_user_resources(To#jid.user, To#jid.server)); do_route(From, To, {broadcast, _} = Packet) -> - case To#jid.lresource of - <<"">> -> - lists:foreach(fun(R) -> - do_route(From, - jid:replace_resource(To, R), - Packet) - end, - get_user_resources(To#jid.user, To#jid.server)); - _ -> - {U, S, R} = jid:tolower(To), - Mod = get_sm_backend(S), - case online(Mod:get_sessions(U, S, R)) of - [] -> - ?DEBUG("packet dropped~n", []); - Ss -> - Session = lists:max(Ss), - Pid = element(2, Session#session.sid), - ?DEBUG("sending to process ~p~n", [Pid]), - Pid ! {route, From, To, Packet} - end + ?DEBUG("processing broadcast to full JID: ~p", [Packet]), + {U, S, R} = jid:tolower(To), + Mod = get_sm_backend(S), + case online(Mod:get_sessions(U, S, R)) of + [] -> + ?DEBUG("dropping broadcast to unavailable resourse: ~p", [Packet]); + Ss -> + Session = lists:max(Ss), + Pid = element(2, Session#session.sid), + ?DEBUG("sending to process ~p: ~p", [Pid, Packet]), + Pid ! {route, From, To, Packet} end; -do_route(From, To, Packet) -> - ?DEBUG("session manager~n\tfrom ~p~n\tto ~p~n\tpacket " - "~P~n", - [From, To, Packet, 8]), +do_route(From, To, #presence{type = T, status = Status} = Packet) + when T == subscribe; T == subscribed; T == unsubscribe; T == unsubscribed -> + ?DEBUG("processing subscription:~n~s", [xmpp:pp(Packet)]), #jid{user = User, server = Server, - luser = LUser, lserver = LServer, lresource = LResource} = To, - Lang = xmpp:get_lang(Packet), - case LResource of - <<"">> -> - case Packet of - #presence{type = T, status = Status} -> - {Pass, _Subsc} = case T of - subscribe -> - Reason = xmpp:get_text(Status), - {is_privacy_allow(From, To, Packet) - andalso - ejabberd_hooks:run_fold(roster_in_subscription, - LServer, - false, - [User, Server, - From, - subscribe, - Reason]), - true}; - subscribed -> - {is_privacy_allow(From, To, Packet) - andalso - ejabberd_hooks:run_fold(roster_in_subscription, - LServer, - false, - [User, Server, - From, - subscribed, - <<"">>]), - true}; - unsubscribe -> - {is_privacy_allow(From, To, Packet) - andalso - ejabberd_hooks:run_fold(roster_in_subscription, - LServer, - false, - [User, Server, - From, - unsubscribe, - <<"">>]), - true}; - unsubscribed -> - {is_privacy_allow(From, To, Packet) - andalso - ejabberd_hooks:run_fold(roster_in_subscription, - LServer, - false, - [User, Server, - From, - unsubscribed, - <<"">>]), - true}; - _ -> {true, false} - end, - if Pass -> - PResources = get_user_present_resources(LUser, LServer), - lists:foreach(fun ({_, R}) -> - do_route(From, - jid:replace_resource(To, - R), - Packet) - end, - PResources); - true -> ok - end; - #message{type = T} when T == chat; T == headline; T == normal -> - route_message(From, To, Packet, T); - #message{type = groupchat} -> - ErrTxt = <<"User session not found">>, - Err = xmpp:make_error( - Packet, xmpp:err_service_unavailable(ErrTxt, Lang)), - ejabberd_router:route(To, From, Err); - #iq{} -> process_iq(From, To, Packet); - _ -> ok - end; - _ -> - Mod = get_sm_backend(LServer), - case online(Mod:get_sessions(LUser, LServer, LResource)) of - [] -> - case Packet of - #message{type = T} when T == chat; T == normal -> - route_message(From, To, Packet, T); - #message{type = groupchat} -> - ErrTxt = <<"User session not found">>, - Err = xmpp:make_error( - Packet, - xmpp:err_service_unavailable(ErrTxt, Lang)), - ejabberd_router:route(To, From, Err); - #iq{type = T} when T == get; T == set -> - ErrTxt = <<"User session not found">>, - Err = xmpp:make_error( - Packet, - xmpp:err_service_unavailable(ErrTxt, Lang)), - ejabberd_router:route(To, From, Err); - _ -> ?DEBUG("packet dropped~n", []) - end; - Ss -> - Session = lists:max(Ss), - Pid = element(2, Session#session.sid), - ?DEBUG("sending to process ~p~n", [Pid]), - Pid ! {route, From, To, Packet} - end + luser = LUser, lserver = LServer} = To, + Reason = if T == subscribe -> xmpp:get_text(Status); + true -> <<"">> + end, + case is_privacy_allow(From, To, Packet) andalso + ejabberd_hooks:run_fold( + roster_in_subscription, + LServer, false, + [User, Server, From, T, Reason]) of + true -> + Mod = get_sm_backend(LServer), + lists:foreach( + fun(#session{sid = SID, usr = {_, _, R}, + priority = Prio}) when is_integer(Prio) -> + Pid = element(2, SID), + ?DEBUG("sending to process ~p:~n~s", + [Pid, xmpp:pp(Packet)]), + Pid ! {route, From, jid:replace_resource(To, R), Packet}; + (_) -> + ok + end, online(Mod:get_sessions(LUser, LServer))); + false -> + ok + end; +do_route(From, #jid{lresource = <<"">>} = To, #presence{} = Packet) -> + ?DEBUG("processing presence to bare JID:~n~s", [xmpp:pp(Packet)]), + {LUser, LServer, _} = jid:tolower(To), + lists:foreach( + fun({_, R}) -> + do_route(From, jid:replace_resource(To, R), Packet) + end, get_user_present_resources(LUser, LServer)); +do_route(From, #jid{lresource = <<"">>} = To, #message{type = T} = Packet) -> + ?DEBUG("processing message to bare JID:~n~s", [xmpp:pp(Packet)]), + if T == chat; T == headline; T == normal -> + route_message(From, To, Packet, T); + true -> + Lang = xmpp:get_lang(Packet), + ErrTxt = <<"User session not found">>, + Err = xmpp:err_service_unavailable(ErrTxt, Lang), + ejabberd_router:route_error(To, From, Packet, Err) + end; +do_route(From, #jid{lresource = <<"">>} = To, #iq{} = Packet) -> + ?DEBUG("processing IQ to bare JID:~n~s", [xmpp:pp(Packet)]), + process_iq(From, To, Packet); +do_route(From, To, Packet) -> + ?DEBUG("processing packet to full JID:~n~s", [xmpp:pp(Packet)]), + {LUser, LServer, LResource} = jid:tolower(To), + Mod = get_sm_backend(LServer), + case online(Mod:get_sessions(LUser, LServer, LResource)) of + [] -> + case Packet of + #message{type = T} when T == chat; T == normal -> + route_message(From, To, Packet, T); + #presence{} -> + ?DEBUG("dropping presence to unavalable resource:~n~s", + [xmpp:pp(Packet)]); + _ -> + Lang = xmpp:get_lang(Packet), + ErrTxt = <<"User session not found">>, + Err = xmpp:err_service_unavailable(ErrTxt, Lang), + ejabberd_router:route_error(To, From, Packet, Err) + end; + Ss -> + Session = lists:max(Ss), + Pid = element(2, Session#session.sid), + ?DEBUG("sending to process ~p:~n~s", [Pid, xmpp:pp(Packet)]), + Pid ! {route, From, To, Packet} end. %% The default list applies to the user as a whole, diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 423fe9e0e..fa27f866c 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -142,21 +142,54 @@ depends(_Host, _Opts) -> process_iq(#iq{from = #jid{luser = <<"">>}, to = #jid{resource = <<"">>}} = IQ) -> process_iq_manager(IQ); +process_iq(#iq{from = #jid{luser = U, lserver = S}, + to = #jid{luser = U, lserver = S}} = IQ) -> + process_local_iq(IQ); +process_iq(#iq{lang = Lang} = IQ) -> + Txt = <<"Query to another users is forbidden">>, + xmpp:make_error(IQ, xmpp:err_forbidden(Txt, Lang)). -process_iq(#iq{from = From, lang = Lang} = IQ) -> - #jid{lserver = LServer} = From, - case lists:member(LServer, ?MYHOSTS) of - true -> process_local_iq(IQ); - _ -> - Txt = <<"The query is only allowed from local users">>, - xmpp:make_error(IQ, xmpp:err_item_not_found(Txt, Lang)) - end. - -process_local_iq(#iq{type = Type} = IQ) -> - case Type of - set -> try_process_iq_set(IQ); - get -> process_iq_get(IQ) - end. +process_local_iq(#iq{type = set,lang = Lang, + sub_els = [#roster_query{ + items = [#roster_item{ask = Ask}]}]} = IQ) + when Ask /= undefined -> + Txt = <<"Possessing 'ask' attribute is not allowed by RFC6121">>, + xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)); +process_local_iq(#iq{type = set, from = From, lang = Lang, + sub_els = [#roster_query{ + items = [#roster_item{} = Item]}]} = IQ) -> + case has_duplicated_groups(Item#roster_item.groups) of + true -> + Txt = <<"Duplicated groups are not allowed by RFC6121">>, + xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)); + false -> + #jid{server = Server} = From, + Access = gen_mod:get_module_opt(Server, ?MODULE, + access, fun(A) -> A end, all), + case acl:match_rule(Server, Access, From) of + deny -> + Txt = <<"Denied by ACL">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); + allow -> + process_iq_set(IQ) + end + end; +process_local_iq(#iq{type = set, lang = Lang, + sub_els = [#roster_query{items = [_|_]}]} = IQ) -> + Txt = <<"Multiple elements are not allowed by RFC6121">>, + xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)); +process_local_iq(#iq{type = get, lang = Lang, + sub_els = [#roster_query{items = Items}]} = IQ) -> + case Items of + [] -> + process_iq_get(IQ); + [_|_] -> + Txt = <<"The query must not contain elements">>, + xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)) + end; +process_local_iq(#iq{lang = Lang} = IQ) -> + Txt = <<"No module is handling this query">>, + xmpp:make_error(IQ, xmpp:err_service_unavailable(Txt, Lang)). roster_hash(Items) -> p1_sha:sha(term_to_binary(lists:sort([R#roster{groups = @@ -315,11 +348,18 @@ encode_item(Item) -> end, groups = Item#roster.groups}. +decode_item(#roster_item{subscription = remove} = Item, R, _) -> + R#roster{jid = jid:tolower(Item#roster_item.jid), + name = <<"">>, + subscription = remove, + ask = none, + groups = [], + askmessage = <<"">>, + xs = []}; decode_item(Item, R, Managed) -> R#roster{jid = jid:tolower(Item#roster_item.jid), name = Item#roster_item.name, subscription = case Item#roster_item.subscription of - remove -> remove; Sub when Managed -> Sub; _ -> R#roster.subscription end, @@ -329,17 +369,6 @@ get_roster_by_jid_t(LUser, LServer, LJID) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:get_roster_by_jid(LUser, LServer, LJID). -try_process_iq_set(#iq{from = From, lang = Lang} = IQ) -> - #jid{server = Server} = From, - Access = gen_mod:get_module_opt(Server, ?MODULE, access, fun(A) -> A end, all), - case acl:match_rule(Server, Access, From) of - deny -> - Txt = <<"Denied by ACL">>, - xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); - allow -> - process_iq_set(IQ) - end. - process_iq_set(#iq{from = From, to = To, id = Id, sub_els = [#roster_query{items = QueryItems}]} = IQ) -> Managed = is_managed_from_id(Id), @@ -515,8 +544,7 @@ process_subscription(Direction, User, Server, JID1, {Subscription, Pending} -> NewItem = Item#roster{subscription = Subscription, ask = Pending, - askmessage = - iolist_to_binary(AskMessage)}, + askmessage = AskMessage}, roster_subscribe_t(LUser, LServer, LJID, NewItem), case roster_version_on_db(LServer) of true -> write_roster_version_t(LUser, LServer); @@ -730,10 +758,8 @@ del_roster_t(LUser, LServer, LJID) -> Mod:del_roster(LUser, LServer, LJID). process_item_set_t(LUser, LServer, #roster_item{jid = JID1} = QueryItem) -> - JID = {JID1#jid.user, JID1#jid.server, - JID1#jid.resource}, - LJID = {JID1#jid.luser, JID1#jid.lserver, - JID1#jid.lresource}, + JID = {JID1#jid.user, JID1#jid.server, <<>>}, + LJID = {JID1#jid.luser, JID1#jid.lserver, <<>>}, Item = #roster{usj = {LUser, LServer, LJID}, us = {LUser, LServer}, jid = JID}, Item2 = decode_item(QueryItem, Item, _Managed = true), @@ -1046,6 +1072,10 @@ is_managed_from_id(<<"roster-remotely-managed">>) -> is_managed_from_id(_Id) -> false. +has_duplicated_groups(Groups) -> + GroupsPrep = lists:usort([jid:resourceprep(G) || G <- Groups]), + not (length(GroupsPrep) == length(Groups)). + export(LServer) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:export(LServer). diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index 59936352b..a13d801ea 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -394,7 +394,7 @@ db_tests(riak) -> auth_md5, presence_broadcast, last, - roster_get, + roster_tests:single_cases(), private, privacy_tests:single_cases(), vcard, @@ -402,9 +402,7 @@ db_tests(riak) -> test_unregister]}, muc_tests:master_slave_cases(), privacy_tests:master_slave_cases(), - {test_roster_subscribe, [parallel], - [roster_subscribe_master, - roster_subscribe_slave]}, + roster_tests:master_slave_cases(), {test_flex_offline, [sequence], [flex_offline_master, flex_offline_slave]}, {test_offline, [sequence], @@ -412,10 +410,7 @@ db_tests(riak) -> {test_announce, [sequence], [announce_master, announce_slave]}, {test_vcard_xupdate, [parallel], - [vcard_xupdate_master, vcard_xupdate_slave]}, - {test_roster_remove, [parallel], - [roster_remove_master, - roster_remove_slave]}]; + [vcard_xupdate_master, vcard_xupdate_slave]}]; db_tests(DB) when DB == mnesia; DB == redis -> [{single_user, [sequence], [test_register, @@ -424,8 +419,7 @@ db_tests(DB) when DB == mnesia; DB == redis -> auth_md5, presence_broadcast, last, - roster_get, - roster_ver, + roster_tests:single_cases(), private, privacy_tests:single_cases(), vcard, @@ -435,11 +429,9 @@ db_tests(DB) when DB == mnesia; DB == redis -> muc_tests:master_slave_cases(), privacy_tests:master_slave_cases(), pubsub_multiple_tests(), + roster_tests:master_slave_cases(), {test_mix, [parallel], [mix_master, mix_slave]}, - {test_roster_subscribe, [parallel], - [roster_subscribe_master, - roster_subscribe_slave]}, {test_flex_offline, [sequence], [flex_offline_master, flex_offline_slave]}, {test_offline, [sequence], @@ -457,10 +449,7 @@ db_tests(DB) when DB == mnesia; DB == redis -> {test_announce, [sequence], [announce_master, announce_slave]}, {test_vcard_xupdate, [parallel], - [vcard_xupdate_master, vcard_xupdate_slave]}, - {test_roster_remove, [parallel], - [roster_remove_master, - roster_remove_slave]}]; + [vcard_xupdate_master, vcard_xupdate_slave]}]; db_tests(_) -> %% No support for carboncopy [{single_user, [sequence], @@ -470,8 +459,7 @@ db_tests(_) -> auth_md5, presence_broadcast, last, - roster_get, - roster_ver, + roster_tests:single_cases(), private, privacy_tests:single_cases(), vcard, @@ -481,11 +469,9 @@ db_tests(_) -> muc_tests:master_slave_cases(), privacy_tests:master_slave_cases(), pubsub_multiple_tests(), + roster_tests:master_slave_cases(), {test_mix, [parallel], [mix_master, mix_slave]}, - {test_roster_subscribe, [parallel], - [roster_subscribe_master, - roster_subscribe_slave]}, {test_flex_offline, [sequence], [flex_offline_master, flex_offline_slave]}, {test_offline, [sequence], @@ -499,10 +485,7 @@ db_tests(_) -> {test_announce, [sequence], [announce_master, announce_slave]}, {test_vcard_xupdate, [parallel], - [vcard_xupdate_master, vcard_xupdate_slave]}, - {test_roster_remove, [parallel], - [roster_remove_master, - roster_remove_slave]}]. + [vcard_xupdate_master, vcard_xupdate_slave]}]. ldap_tests() -> [{ldap_tests, [sequence], @@ -862,33 +845,26 @@ test_bind(Config) -> test_open_session(Config) -> disconnect(open_session(Config, true)). -roster_get(Config) -> - #iq{type = result, sub_els = [#roster_query{items = []}]} = - send_recv(Config, #iq{type = get, sub_els = [#roster_query{}]}), - disconnect(Config). - -roster_ver(Config) -> - %% Get initial "ver" - #iq{type = result, sub_els = [#roster_query{ver = Ver1, items = []}]} = - send_recv(Config, #iq{type = get, - sub_els = [#roster_query{ver = <<"">>}]}), - %% Should receive empty IQ-result - #iq{type = result, sub_els = []} = - send_recv(Config, #iq{type = get, - sub_els = [#roster_query{ver = Ver1}]}), - %% Attempting to subscribe to server's JID - send(Config, #presence{type = subscribe, to = server_jid(Config)}), - %% Receive a single roster push with the new "ver" - #iq{type = set, sub_els = [#roster_query{ver = Ver2}]} = recv_iq(Config), - %% Requesting roster with the previous "ver". Should receive Ver2 again - #iq{type = result, sub_els = [#roster_query{ver = Ver2}]} = - send_recv(Config, #iq{type = get, - sub_els = [#roster_query{ver = Ver1}]}), - %% Now requesting roster with the newest "ver". Should receive empty IQ. - #iq{type = result, sub_els = []} = - send_recv(Config, #iq{type = get, - sub_els = [#roster_query{ver = Ver2}]}), - disconnect(Config). +roster_feature_enabled(Config) -> + roster_tests:feature_enabled(Config). +roster_iq_set_many_items(Config) -> + roster_tests:iq_set_many_items(Config). +roster_iq_set_duplicated_groups(Config) -> + roster_tests:iq_set_duplicated_groups(Config). +roster_iq_set_ask(Config) -> + roster_tests:iq_set_ask(Config). +roster_iq_get_item(Config) -> + roster_tests:iq_get_item(Config). +roster_iq_unexpected_element(Config) -> + roster_tests:iq_unexpected_element(Config). +roster_set_item(Config) -> + roster_tests:set_item(Config). +roster_version(Config) -> + roster_tests:version(Config). +roster_subscribe_master(Config) -> + roster_tests:subscribe_master(Config). +roster_subscribe_slave(Config) -> + roster_tests:subscribe_slave(Config). codec_failure(Config) -> JID = my_jid(Config), @@ -2043,148 +2019,6 @@ mix_slave(Config) -> disconnect = get_event(Config), disconnect(Config). -roster_subscribe_master(Config) -> - #presence{} = send_recv(Config, #presence{}), - wait_for_slave(Config), - Peer = ?config(peer, Config), - LPeer = jid:remove_resource(Peer), - send(Config, #presence{type = subscribe, to = LPeer}), - Push1 = #iq{type = set, - sub_els = [#roster_query{items = [#roster_item{ - ask = subscribe, - subscription = none, - jid = LPeer}]}]} = - recv_iq(Config), - send(Config, make_iq_result(Push1)), - #presence{type = subscribed, from = LPeer} = recv_presence(Config), - Push2 = #iq{type = set, - sub_els = [#roster_query{items = [#roster_item{ - subscription = to, - jid = LPeer}]}]} = - recv_iq(Config), - send(Config, make_iq_result(Push2)), - #presence{type = available, from = Peer} = recv_presence(Config), - %% BUG: ejabberd sends previous push again. Is it ok? - Push3 = #iq{type = set, - sub_els = [#roster_query{items = [#roster_item{ - subscription = to, - jid = LPeer}]}]} = - recv_iq(Config), - send(Config, make_iq_result(Push3)), - #presence{type = subscribe, from = LPeer} = recv_presence(Config), - send(Config, #presence{type = subscribed, to = LPeer}), - Push4 = #iq{type = set, - sub_els = [#roster_query{items = [#roster_item{ - subscription = both, - jid = LPeer}]}]} = - recv_iq(Config), - send(Config, make_iq_result(Push4)), - %% Move into a group - Groups = [<<"A">>, <<"B">>], - Item = #roster_item{jid = LPeer, groups = Groups}, - #iq{type = result, sub_els = []} = - send_recv(Config, - #iq{type = set, sub_els = [#roster_query{items = [Item]}]}), - Push5 = #iq{type = set, - sub_els = - [#roster_query{items = [#roster_item{ - jid = LPeer, - subscription = both}]}]} = - recv_iq(Config), - send(Config, make_iq_result(Push5)), - #iq{sub_els = [#roster_query{items = [#roster_item{groups = G1}]}]} = Push5, - Groups = lists:sort(G1), - wait_for_slave(Config), - #presence{type = unavailable, from = Peer} = recv_presence(Config), - disconnect(Config). - -roster_subscribe_slave(Config) -> - #presence{} = send_recv(Config, #presence{}), - wait_for_master(Config), - Peer = ?config(master, Config), - LPeer = jid:remove_resource(Peer), - #presence{type = subscribe, from = LPeer} = recv_presence(Config), - send(Config, #presence{type = subscribed, to = LPeer}), - Push1 = #iq{type = set, - sub_els = [#roster_query{items = [#roster_item{ - subscription = from, - jid = LPeer}]}]} = - recv_iq(Config), - send(Config, make_iq_result(Push1)), - send(Config, #presence{type = subscribe, to = LPeer}), - Push2 = #iq{type = set, - sub_els = [#roster_query{items = [#roster_item{ - ask = subscribe, - subscription = from, - jid = LPeer}]}]} = - recv_iq(Config), - send(Config, make_iq_result(Push2)), - #presence{type = subscribed, from = LPeer} = recv_presence(Config), - Push3 = #iq{type = set, - sub_els = [#roster_query{items = [#roster_item{ - subscription = both, - jid = LPeer}]}]} = - recv_iq(Config), - send(Config, make_iq_result(Push3)), - #presence{type = available, from = Peer} = recv_presence(Config), - wait_for_master(Config), - disconnect(Config). - -roster_remove_master(Config) -> - MyJID = my_jid(Config), - Peer = ?config(slave, Config), - LPeer = jid:remove_resource(Peer), - Groups = [<<"A">>, <<"B">>], - wait_for_slave(Config), - #presence{from = MyJID, type = available} = send_recv(Config, #presence{}), - #presence{from = Peer, type = available} = recv_presence(Config), - %% The peer removed us from its roster. - {Push1, Push2, _, _, _} = - ?recv5( - %% TODO: I guess this can be optimized, we don't need - %% to send transient roster push with subscription = 'to'. - #iq{type = set, - sub_els = - [#roster_query{items = [#roster_item{ - jid = LPeer, - subscription = to}]}]}, - #iq{type = set, - sub_els = - [#roster_query{items = [#roster_item{ - jid = LPeer, - subscription = none}]}]}, - #presence{type = unsubscribe, from = LPeer}, - #presence{type = unsubscribed, from = LPeer}, - #presence{type = unavailable, from = Peer}), - send(Config, make_iq_result(Push1)), - send(Config, make_iq_result(Push2)), - #iq{sub_els = [#roster_query{items = [#roster_item{groups = G1}]}]} = Push1, - #iq{sub_els = [#roster_query{items = [#roster_item{groups = G2}]}]} = Push2, - Groups = lists:sort(G1), Groups = lists:sort(G2), - disconnect(Config). - -roster_remove_slave(Config) -> - MyJID = my_jid(Config), - Peer = ?config(master, Config), - LPeer = jid:remove_resource(Peer), - #presence{from = MyJID, type = available} = send_recv(Config, #presence{}), - wait_for_master(Config), - #presence{from = Peer, type = available} = recv_presence(Config), - %% Remove the peer from roster. - Item = #roster_item{jid = LPeer, subscription = remove}, - #iq{type = result, sub_els = []} = - send_recv(Config, #iq{type = set, - sub_els = [#roster_query{items = [Item]}]}), - Push = #iq{type = set, - sub_els = - [#roster_query{items = [#roster_item{ - jid = LPeer, - subscription = remove}]}]} = - recv_iq(Config), - #presence{type = unavailable, from = Peer} = recv_presence(Config), - send(Config, make_iq_result(Push)), - disconnect(Config). - proxy65_master(Config) -> Proxy = proxy_jid(Config), MyJID = my_jid(Config), diff --git a/test/roster_tests.erl b/test/roster_tests.erl new file mode 100644 index 000000000..2d05709ab --- /dev/null +++ b/test/roster_tests.erl @@ -0,0 +1,527 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 22 Oct 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(roster_tests). + +%% API +-compile(export_all). +-import(suite, [send_recv/2, recv_iq/1, send/2, disconnect/1, del_roster/1, + del_roster/2, make_iq_result/1, wait_for_slave/1, + wait_for_master/1, recv_presence/1, self_presence/2, + put_event/2, get_event/1, match_failure/2, get_roster/1, + is_feature_advertised/2]). +-include("suite.hrl"). +-include("mod_roster.hrl"). + +-record(state, {subscription = none :: none | from | to | both, + peer_available = false, + pending_in = false :: boolean(), + pending_out = false :: boolean()}). + +%%%=================================================================== +%%% API +%%%=================================================================== +init(_TestCase, Config) -> + Config. + +stop(_TestCase, Config) -> + Config. + +%%%=================================================================== +%%% Single user tests +%%%=================================================================== +single_cases() -> + {roster_single, [sequence], + [single_test(feature_enabled), + single_test(iq_set_many_items), + single_test(iq_set_duplicated_groups), + single_test(iq_get_item), + single_test(iq_unexpected_element), + single_test(iq_set_ask), + single_test(set_item), + single_test(version)]}. + +feature_enabled(Config) -> + ct:comment("Checking if roster versioning stream feature is set"), + true = ?config(rosterver, Config), + disconnect(Config). + +set_item(Config) -> + JID = jid:from_string(<<"nurse@example.com">>), + Item = #roster_item{jid = JID}, + {V1, Item} = set_items(Config, [Item]), + {V1, [Item]} = get_items(Config), + ItemWithGroups = Item#roster_item{groups = [<<"G1">>, <<"G2">>]}, + {V2, ItemWithGroups} = set_items(Config, [ItemWithGroups]), + {V2, [ItemWithGroups]} = get_items(Config), + {V3, Item} = set_items(Config, [Item]), + {V3, [Item]} = get_items(Config), + ItemWithName = Item#roster_item{name = <<"some name">>}, + {V4, ItemWithName} = set_items(Config, [ItemWithName]), + {V4, [ItemWithName]} = get_items(Config), + ItemRemoved = Item#roster_item{subscription = remove}, + {V5, ItemRemoved} = set_items(Config, [ItemRemoved]), + {V5, []} = get_items(Config), + del_roster(disconnect(Config), JID). + +iq_set_many_items(Config) -> + J1 = jid:from_string(<<"nurse1@example.com">>), + J2 = jid:from_string(<<"nurse2@example.com">>), + ct:comment("Trying to send roster-set with many elements"), + Items = [#roster_item{jid = J1}, #roster_item{jid = J2}], + #stanza_error{reason = 'bad-request'} = set_items(Config, Items), + disconnect(Config). + +iq_set_duplicated_groups(Config) -> + JID = jid:from_string(<<"nurse@example.com">>), + G = randoms:get_string(), + ct:comment("Trying to send roster-set with duplicated groups"), + Item = #roster_item{jid = JID, groups = [G, G]}, + #stanza_error{reason = 'bad-request'} = set_items(Config, [Item]), + disconnect(Config). + +iq_set_ask(Config) -> + JID = jid:from_string(<<"nurse@example.com">>), + ct:comment("Trying to send roster-set with 'ask' included"), + Item = #roster_item{jid = JID, ask = subscribe}, + #stanza_error{reason = 'bad-request'} = set_items(Config, [Item]), + disconnect(Config). + +iq_get_item(Config) -> + JID = jid:from_string(<<"nurse@example.com">>), + ct:comment("Trying to send roster-get with element"), + #iq{type = error} = Err3 = + send_recv(Config, #iq{type = get, + sub_els = [#roster_query{ + items = [#roster_item{jid = JID}]}]}), + #stanza_error{reason = 'bad-request'} = xmpp:get_error(Err3), + disconnect(Config). + +iq_unexpected_element(Config) -> + JID = jid:from_string(<<"nurse@example.com">>), + ct:comment("Trying to send IQs with unexpected element"), + lists:foreach( + fun(Type) -> + #iq{type = error} = Err4 = + send_recv(Config, #iq{type = Type, + sub_els = [#roster_item{jid = JID}]}), + #stanza_error{reason = 'service-unavailable'} = xmpp:get_error(Err4) + end, [get, set]), + disconnect(Config). + +version(Config) -> + JID = jid:from_string(<<"nurse@example.com">>), + ct:comment("Requesting roster"), + {InitialVersion, _} = get_items(Config, <<"">>), + ct:comment("Requesting roster with initial version"), + {empty, []} = get_items(Config, InitialVersion), + ct:comment("Adding JID to the roster"), + {NewVersion, _} = set_items(Config, [#roster_item{jid = JID}]), + ct:comment("Requesting roster with initial version"), + {NewVersion, _} = get_items(Config, InitialVersion), + ct:comment("Requesting roster with new version"), + {empty, []} = get_items(Config, NewVersion), + del_roster(disconnect(Config), JID). + +%%%=================================================================== +%%% Master-slave tests +%%%=================================================================== +master_slave_cases() -> + {roster_master_slave, [parallel], + [master_slave_test(subscribe)]}. + +subscribe_master(Config) -> + Actions = actions(), + process_subscriptions_master(Config, Actions), + del_roster(disconnect(Config)). + +subscribe_slave(Config) -> + process_subscriptions_slave(Config), + del_roster(disconnect(Config)). + +process_subscriptions_master(Config, Actions) -> + EnumeratedActions = lists:zip(lists:seq(1, length(Actions)), Actions), + self_presence(Config, available), + lists:foldl( + fun({N, {Dir, Type}}, State) -> + if Dir == out -> put_event(Config, {N, in, Type}); + Dir == in -> put_event(Config, {N, out, Type}) + end, + wait_for_slave(Config), + ct:pal("Performing ~s-~s (#~p) " + "in state:~n~s~nwith roster:~n~s", + [Dir, Type, N, pp(State), + pp(get_roster(Config))]), + transition(Config, Dir, Type, State) + end, #state{}, EnumeratedActions), + put_event(Config, done), + wait_for_slave(Config), + Config. + +process_subscriptions_slave(Config) -> + self_presence(Config, available), + process_subscriptions_slave(Config, get_event(Config), #state{}). + +process_subscriptions_slave(Config, done, _State) -> + wait_for_master(Config), + Config; +process_subscriptions_slave(Config, {N, Dir, Type}, State) -> + wait_for_master(Config), + ct:pal("Performing ~s-~s (#~p) " + "in state:~n~s~nwith roster:~n~s", + [Dir, Type, N, pp(State), pp(get_roster(Config))]), + NewState = transition(Config, Dir, Type, State), + process_subscriptions_slave(Config, get_event(Config), NewState). + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +single_test(T) -> + list_to_atom("roster_" ++ atom_to_list(T)). + +master_slave_test(T) -> + {list_to_atom("roster_" ++ atom_to_list(T)), [parallel], + [list_to_atom("roster_" ++ atom_to_list(T) ++ "_master"), + list_to_atom("roster_" ++ atom_to_list(T) ++ "_slave")]}. + +get_items(Config) -> + get_items(Config, <<"">>). + +get_items(Config, Version) -> + case send_recv(Config, #iq{type = get, + sub_els = [#roster_query{ver = Version}]}) of + #iq{type = result, + sub_els = [#roster_query{ver = NewVersion, items = Items}]} -> + {NewVersion, Items}; + #iq{type = result, sub_els = []} -> + {empty, []}; + #iq{type = error} = Err -> + xmpp:get_error(Err) + end. + +get_item(Config, JID) -> + case get_items(Config) of + {_Ver, Items} when is_list(Items) -> + lists:keyfind(JID, #roster_item.jid, Items); + _ -> + false + end. + +set_items(Config, Items) -> + case send_recv(Config, #iq{type = set, + sub_els = [#roster_query{items = Items}]}) of + #iq{type = result, sub_els = []} -> + recv_push(Config); + #iq{type = error} = Err -> + xmpp:get_error(Err) + end. + +recv_push(Config) -> + ct:comment("Receiving roster push"), + Push = #iq{type = set, + sub_els = [#roster_query{ver = Ver, items = [PushItem]}]} + = recv_iq(Config), + send(Config, make_iq_result(Push)), + {Ver, PushItem}. + +recv_push(Config, Subscription, Ask) -> + PeerJID = ?config(peer, Config), + PeerBareJID = jid:remove_resource(PeerJID), + Match = #roster_item{jid = PeerBareJID, + subscription = Subscription, + ask = Ask, + groups = [], + name = <<"">>}, + ct:comment("Receiving roster push"), + Push = #iq{type = set, sub_els = [#roster_query{items = [Item]}]} = + recv_iq(Config), + case Item of + Match -> send(Config, make_iq_result(Push)); + _ -> match_failure(Item, Match) + end. + +recv_presence(Config, Type) -> + PeerJID = ?config(peer, Config), + case recv_presence(Config) of + #presence{from = PeerJID, type = Type} -> ok; + Pres -> match_failure(Pres, #presence{from = PeerJID, type = Type}) + end. + +recv_subscription(Config, Type) -> + PeerJID = ?config(peer, Config), + PeerBareJID = jid:remove_resource(PeerJID), + case recv_presence(Config) of + #presence{from = PeerBareJID, type = Type} -> ok; + Pres -> match_failure(Pres, #presence{from = PeerBareJID, type = Type}) + end. + +pp(Term) -> + io_lib_pretty:print(Term, fun pp/2). + +pp(state, N) -> + Fs = record_info(fields, state), + try N = length(Fs), Fs + catch _:_ -> no end; +pp(roster, N) -> + Fs = record_info(fields, roster), + try N = length(Fs), Fs + catch _:_ -> no end; +pp(_, _) -> no. + +%% RFC6121, A.2.1 +transition(Config, out, subscribe, + #state{subscription = Sub, pending_in = In, pending_out = Out} = State) -> + PeerJID = ?config(peer, Config), + PeerBareJID = jid:remove_resource(PeerJID), + send(Config, #presence{to = PeerBareJID, type = subscribe}), + case {Sub, Out, In} of + {none, false, _} -> + recv_push(Config, none, subscribe), + State#state{pending_out = true}; + {none, true, false} -> + %% BUG: we should not receive roster push here + recv_push(Config, none, subscribe), + State; + {from, false, false} -> + recv_push(Config, from, subscribe), + State#state{pending_out = true}; + _ -> + State + end; +%% RFC6121, A.2.2 +transition(Config, out, unsubscribe, + #state{subscription = Sub, pending_in = In, pending_out = Out} = State) -> + PeerJID = ?config(peer, Config), + PeerBareJID = jid:remove_resource(PeerJID), + send(Config, #presence{to = PeerBareJID, type = unsubscribe}), + case {Sub, Out, In} of + {none, true, _} -> + recv_push(Config, none, undefined), + State#state{pending_out = false}; + {to, false, _} -> + recv_push(Config, none, undefined), + recv_presence(Config, unavailable), + State#state{subscription = none, peer_available = false}; + {from, true, false} -> + recv_push(Config, from, undefined), + State#state{pending_out = false}; + {both, false, false} -> + recv_push(Config, from, undefined), + recv_presence(Config, unavailable), + State#state{subscription = from, peer_available = false}; + _ -> + State + end; +%% RFC6121, A.2.3 +transition(Config, out, subscribed, + #state{subscription = Sub, pending_in = In, pending_out = Out} = State) -> + PeerJID = ?config(peer, Config), + PeerBareJID = jid:remove_resource(PeerJID), + send(Config, #presence{to = PeerBareJID, type = subscribed}), + case {Sub, Out, In} of + {none, false, true} -> + recv_push(Config, from, undefined), + State#state{subscription = from, pending_in = false}; + {none, true, true} -> + recv_push(Config, from, subscribe), + State#state{subscription = from, pending_in = false}; + {to, false, true} -> + recv_push(Config, both, undefined), + State#state{subscription = both, pending_in = false}; + {to, false, _} -> + %% BUG: we should not transition to 'both' state + recv_push(Config, both, undefined), + State#state{subscription = both}; + _ -> + State + end; +%% RFC6121, A.2.4 +transition(Config, out, unsubscribed, + #state{subscription = Sub, pending_in = In, pending_out = Out} = State) -> + PeerJID = ?config(peer, Config), + PeerBareJID = jid:remove_resource(PeerJID), + send(Config, #presence{to = PeerBareJID, type = unsubscribed}), + case {Sub, Out, In} of + {none, false, true} -> + State#state{subscription = none, pending_in = false}; + {none, true, true} -> + recv_push(Config, none, subscribe), + State#state{subscription = none, pending_in = false}; + {to, _, true} -> + State#state{pending_in = false}; + {from, false, _} -> + recv_push(Config, none, undefined), + State#state{subscription = none}; + {from, true, _} -> + recv_push(Config, none, subscribe), + State#state{subscription = none}; + {both, _, _} -> + recv_push(Config, to, undefined), + State#state{subscription = to}; + _ -> + State + end; +%% RFC6121, A.3.1 +transition(Config, in, subscribe = Type, + #state{subscription = Sub, pending_in = In, pending_out = Out} = State) -> + case {Sub, Out, In} of + {none, false, false} -> + recv_subscription(Config, Type), + State#state{pending_in = true}; + {none, true, false} -> + recv_push(Config, none, subscribe), + recv_subscription(Config, Type), + State#state{pending_in = true}; + {to, false, false} -> + %% BUG: we should not receive roster push in this state! + recv_push(Config, to, undefined), + recv_subscription(Config, Type), + State#state{pending_in = true}; + _ -> + State + end; +%% RFC6121, A.3.2 +transition(Config, in, unsubscribe = Type, + #state{subscription = Sub, pending_in = In, pending_out = Out} = State) -> + case {Sub, Out, In} of + {none, _, true} -> + State#state{pending_in = false}; + {to, _, true} -> + recv_push(Config, to, undefined), + recv_subscription(Config, Type), + State#state{pending_in = false}; + {from, false, _} -> + recv_push(Config, none, undefined), + recv_subscription(Config, Type), + State#state{subscription = none}; + {from, true, _} -> + recv_push(Config, none, subscribe), + recv_subscription(Config, Type), + State#state{subscription = none}; + {both, _, _} -> + recv_push(Config, to, undefined), + recv_subscription(Config, Type), + State#state{subscription = to}; + _ -> + State + end; +%% RFC6121, A.3.3 +transition(Config, in, subscribed = Type, + #state{subscription = Sub, pending_in = In, pending_out = Out} = State) -> + case {Sub, Out, In} of + {none, true, _} -> + recv_push(Config, to, undefined), + recv_subscription(Config, Type), + recv_presence(Config, available), + State#state{subscription = to, pending_out = false, peer_available = true}; + {from, true, _} -> + recv_push(Config, both, undefined), + recv_subscription(Config, Type), + recv_presence(Config, available), + State#state{subscription = both, pending_out = false, peer_available = true}; + {from, false, _} -> + %% BUG: we should not transition to 'both' in this state + recv_push(Config, both, undefined), + recv_subscription(Config, Type), + recv_presence(Config, available), + State#state{subscription = both, pending_out = false, peer_available = true}; + _ -> + State + end; +%% RFC6121, A.3.4 +transition(Config, in, unsubscribed = Type, + #state{subscription = Sub, pending_in = In, pending_out = Out} = State) -> + case {Sub, Out, In} of + {none, true, true} -> + %% BUG: we should receive roster push in this state! + recv_subscription(Config, Type), + State#state{subscription = none, pending_out = false}; + {none, true, false} -> + recv_push(Config, none, undefined), + recv_subscription(Config, Type), + State#state{subscription = none, pending_out = false}; + {none, false, false} -> + State; + {to, false, _} -> + recv_push(Config, none, undefined), + recv_subscription(Config, Type), + recv_presence(Config, unavailable), + State#state{subscription = none, peer_available = false}; + {from, true, false} -> + recv_push(Config, from, undefined), + recv_subscription(Config, Type), + State#state{subscription = from, pending_out = false}; + {both, _, _} -> + recv_push(Config, from, undefined), + recv_subscription(Config, Type), + recv_presence(Config, unavailable), + State#state{subscription = from, peer_available = false}; + _ -> + State + end; +%% Outgoing roster remove +transition(Config, out, remove, + #state{subscription = Sub, pending_in = In, pending_out = Out}) -> + PeerJID = ?config(peer, Config), + PeerBareJID = jid:remove_resource(PeerJID), + Item = #roster_item{jid = PeerBareJID, subscription = remove}, + #iq{type = result, sub_els = []} = + send_recv(Config, #iq{type = set, + sub_els = [#roster_query{items = [Item]}]}), + recv_push(Config, remove, undefined), + case {Sub, Out, In} of + {to, _, _} -> + recv_presence(Config, unavailable); + {both, _, _} -> + recv_presence(Config, unavailable); + _ -> + ok + end, + #state{}; +%% Incoming roster remove +transition(Config, in, remove, + #state{subscription = Sub, pending_in = In, pending_out = Out} = State) -> + case {Sub, Out, In} of + {none, true, _} -> + ok; + {from, false, _} -> + recv_push(Config, none, undefined), + recv_subscription(Config, unsubscribe); + {from, true, _} -> + recv_push(Config, none, subscribe), + recv_subscription(Config, unsubscribe); + {to, false, _} -> + %% BUG: we should receive push here + %% recv_push(Config, none, undefined), + recv_presence(Config, unavailable), + recv_subscription(Config, unsubscribed); + {both, _, _} -> + recv_presence(Config, unavailable), + recv_push(Config, to, undefined), + recv_subscription(Config, unsubscribe), + recv_push(Config, none, undefined), + recv_subscription(Config, unsubscribed); + _ -> + ok + end, + State#state{subscription = none}. + +actions() -> + States = [{Dir, Type} || Dir <- [out, in], + Type <- [subscribe, subscribed, + unsubscribe, unsubscribed, + remove]], + Actions = lists:flatten([[X, Y] || X <- States, Y <- States]), + remove_dups(Actions, []). + +remove_dups([X|T], [X,X|_] = Acc) -> + remove_dups(T, Acc); +remove_dups([X|T], Acc) -> + remove_dups(T, [X|Acc]); +remove_dups([], Acc) -> + lists:reverse(Acc). diff --git a/test/suite.erl b/test/suite.erl index 3bed62562..f88ac5a5e 100644 --- a/test/suite.erl +++ b/test/suite.erl @@ -86,6 +86,7 @@ init_config(Config) -> {stream_from, <<"">>}, {db_xmlns, <<"">>}, {mechs, []}, + {rosterver, false}, {lang, <<"en">>}, {base_dir, BaseDir}, {socket, undefined}, @@ -421,6 +422,8 @@ wait_auth_SASL_result(Config, ShouldFail) -> set_opt(sm, true, ConfigAcc); (#feature_csi{}, ConfigAcc) -> set_opt(csi, true, ConfigAcc); + (#rosterver_feature{}, ConfigAcc) -> + set_opt(rosterver, true, ConfigAcc); (_, ConfigAcc) -> ConfigAcc end, Config, Fs); @@ -674,26 +677,32 @@ set_opt(Opt, Val, Config) -> [{Opt, Val}|lists:keydelete(Opt, 1, Config)]. wait_for_master(Config) -> - put_event(Config, slave_ready), + put_event(Config, peer_ready), case get_event(Config) of - master_ready -> + peer_ready -> ok; Other -> - suite:match_failure([Other], [master_ready]) + suite:match_failure(Other, peer_ready) end. wait_for_slave(Config) -> - put_event(Config, master_ready), + put_event(Config, peer_ready), case get_event(Config) of - slave_ready -> + peer_ready -> ok; Other -> - suite:match_failure([Other], [slave_ready]) + suite:match_failure(Other, peer_ready) end. make_iq_result(#iq{from = From} = IQ) -> IQ#iq{type = result, to = From, from = undefined, sub_els = []}. +self_presence(Config, Type) -> + MyJID = my_jid(Config), + ct:comment("Sending self-presence"), + #presence{type = Type, from = MyJID} = + send_recv(Config, #presence{type = Type}). + set_roster(Config, Subscription, Groups) -> MyJID = my_jid(Config), {U, S, _} = jid:tolower(MyJID), @@ -710,15 +719,21 @@ set_roster(Config, Subscription, Groups) -> Config. del_roster(Config) -> + del_roster(Config, ?config(peer, Config)). + +del_roster(Config, PeerJID) -> MyJID = my_jid(Config), {U, S, _} = jid:tolower(MyJID), - PeerJID = ?config(peer, Config), PeerBareJID = jid:remove_resource(PeerJID), PeerLJID = jid:tolower(PeerBareJID), ct:comment("Removing ~s from roster", [jid:to_string(PeerBareJID)]), {atomic, _} = mod_roster:del_roster(U, S, PeerLJID), Config. +get_roster(Config) -> + {LUser, LServer, _} = jid:tolower(my_jid(Config)), + mod_roster:get_roster(LUser, LServer). + receiver(NS, Owner) -> MRef = erlang:monitor(process, Owner), receiver(NS, Owner, MRef). From e841a6ec34e4b79adbeb070e56edec766adc9987 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Tue, 8 Nov 2016 15:15:19 +0300 Subject: [PATCH 067/151] Add more tests for offline storage --- src/ejabberd_sm.erl | 29 +- src/mod_offline.erl | 98 ++++--- src/mod_offline_mnesia.erl | 16 +- src/xmpp_util.erl | 2 +- test/ejabberd_SUITE.erl | 196 +++---------- test/ejabberd_SUITE_data/ejabberd.yml | 5 +- test/offline_tests.erl | 406 ++++++++++++++++++++++++++ test/suite.erl | 87 +++--- 8 files changed, 571 insertions(+), 268 deletions(-) create mode 100644 test/offline_tests.erl diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 6f6a196e5..0655bbcf3 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -498,7 +498,7 @@ do_route(From, #jid{lresource = <<"">>} = To, #presence{} = Packet) -> end, get_user_present_resources(LUser, LServer)); do_route(From, #jid{lresource = <<"">>} = To, #message{type = T} = Packet) -> ?DEBUG("processing message to bare JID:~n~s", [xmpp:pp(Packet)]), - if T == chat; T == headline; T == normal -> + if T == chat; T == headline; T == normal; T == groupchat -> route_message(From, To, Packet, T); true -> Lang = xmpp:get_lang(Packet), @@ -516,7 +516,8 @@ do_route(From, To, Packet) -> case online(Mod:get_sessions(LUser, LServer, LResource)) of [] -> case Packet of - #message{type = T} when T == chat; T == normal -> + #message{type = T} when T == chat; T == normal; + T == headline; T == groupchat -> route_message(From, To, Packet, T); #presence{} -> ?DEBUG("dropping presence to unavalable resource:~n~s", @@ -586,20 +587,16 @@ route_message(From, To, Packet, Type) -> end, PrioRes); _ -> - case Type of - headline -> ok; - _ -> - case ejabberd_auth:is_user_exists(LUser, LServer) andalso - is_privacy_allow(From, To, Packet) of - true -> - ejabberd_hooks:run(offline_message_hook, LServer, - [From, To, Packet]); - false -> - Err = xmpp:make_error(Packet, - xmpp:err_service_unavailable()), - ejabberd_router:route(To, From, Err) - end - end + case ejabberd_auth:is_user_exists(LUser, LServer) andalso + is_privacy_allow(From, To, Packet) of + true -> + ejabberd_hooks:run(offline_message_hook, LServer, + [From, To, Packet]); + false -> + Err = xmpp:make_error(Packet, + xmpp:err_service_unavailable()), + ejabberd_router:route(To, From, Err) + end end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/src/mod_offline.erl b/src/mod_offline.erl index 240650234..6134823c1 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -102,7 +102,7 @@ -callback read_message_headers(binary(), binary()) -> any(). -callback read_message(binary(), binary(), non_neg_integer()) -> {ok, #offline_msg{}} | error. --callback remove_message(binary(), binary(), non_neg_integer()) -> ok. +-callback remove_message(binary(), binary(), non_neg_integer()) -> ok | {error, any()}. -callback read_all_messages(binary(), binary()) -> [#offline_msg{}]. -callback remove_all_messages(binary(), binary()) -> {atomic, any()}. -callback count_messages(binary(), binary()) -> non_neg_integer(). @@ -315,32 +315,52 @@ get_info(Acc, _From, _To, _Node, _Lang) -> Acc. -spec handle_offline_query(iq()) -> iq(). +handle_offline_query(#iq{from = #jid{luser = U1, lserver = S1}, + to = #jid{luser = U2, lserver = S2}, + lang = Lang, + sub_els = [#offline{}]} = IQ) + when {U1, S1} /= {U2, S2} -> + Txt = <<"Query to another users is forbidden">>, + xmpp:make_error(IQ, xmpp:err_forbidden(Txt, Lang)); handle_offline_query(#iq{from = #jid{luser = U, lserver = S} = From, to = #jid{luser = U, lserver = S} = _To, - type = Type, - sub_els = [#offline{purge = Purge, - items = Items, - fetch = Fetch}]} = IQ) -> - case Type of - get -> - if Fetch -> handle_offline_fetch(From); - true -> handle_offline_items_view(From, Items) + type = Type, lang = Lang, + sub_els = [#offline{} = Offline]} = IQ) -> + case {Type, Offline} of + {get, #offline{fetch = true, items = [], purge = false}} -> + %% TODO: report database errors + handle_offline_fetch(From), + xmpp:make_iq_result(IQ); + {get, #offline{fetch = false, items = [_|_] = Items, purge = false}} -> + case handle_offline_items_view(From, Items) of + true -> xmpp:make_iq_result(IQ); + false -> xmpp:make_error(IQ, xmpp:err_item_not_found()) end; - set -> - if Purge -> delete_all_msgs(U, S); - true -> handle_offline_items_remove(From, Items) - end - end, - xmpp:make_iq_result(IQ); + {set, #offline{fetch = false, items = [], purge = true}} -> + case delete_all_msgs(U, S) of + {atomic, ok} -> + xmpp:make_iq_result(IQ); + _Err -> + Txt = <<"Database failure">>, + xmpp:make_error(IQ, xmpp:err_internal_server_error(Txt, Lang)) + end; + {set, #offline{fetch = false, items = [_|_] = Items, purge = false}} -> + case handle_offline_items_remove(From, Items) of + true -> xmpp:make_iq_result(IQ); + false -> xmpp:make_error(IQ, xmpp:err_item_not_found()) + end; + _ -> + xmpp:make_error(IQ, xmpp:err_bad_request()) + end; handle_offline_query(#iq{lang = Lang} = IQ) -> - Txt = <<"Query to another users is forbidden">>, - xmpp:make_error(IQ, xmpp:err_forbidden(Txt, Lang)). + Txt = <<"No module is handling this query">>, + xmpp:make_error(IQ, xmpp:err_service_unavailable(Txt, Lang)). --spec handle_offline_items_view(jid(), [offline_item()]) -> ok. +-spec handle_offline_items_view(jid(), [offline_item()]) -> boolean(). handle_offline_items_view(JID, Items) -> {U, S, R} = jid:tolower(JID), - lists:foreach( - fun(#offline_item{node = Node, action = view}) -> + lists:foldl( + fun(#offline_item{node = Node, action = view}, Acc) -> case fetch_msg_by_node(JID, Node) of {ok, OfflineMsg} -> case offline_msg_to_route(S, OfflineMsg) of @@ -351,25 +371,22 @@ handle_offline_items_view(JID, Items) -> Pid ! {route, From, To, NewEl}; none -> ok - end; + end, + Acc or true; error -> - ok + Acc or false end; error -> - ok - end; - (_) -> - ok - end, Items). + Acc or false + end + end, false, Items). --spec handle_offline_items_remove(jid(), [offline_item()]) -> ok. +-spec handle_offline_items_remove(jid(), [offline_item()]) -> boolean(). handle_offline_items_remove(JID, Items) -> - lists:foreach( - fun(#offline_item{node = Node, action = remove}) -> - remove_msg_by_node(JID, Node); - (_) -> - ok - end, Items). + lists:foldl( + fun(#offline_item{node = Node, action = remove}, Acc) -> + Acc or remove_msg_by_node(JID, Node) + end, false, Items). -spec set_offline_tag(message(), binary()) -> message(). set_offline_tag(Msg, Node) -> @@ -401,23 +418,22 @@ fetch_msg_by_node(To, Seq) -> error end. --spec remove_msg_by_node(jid(), binary()) -> ok. +-spec remove_msg_by_node(jid(), binary()) -> boolean(). remove_msg_by_node(To, Seq) -> case catch binary_to_integer(Seq) of I when is_integer(I), I>= 0 -> LUser = To#jid.luser, LServer = To#jid.lserver, Mod = gen_mod:db_mod(LServer, ?MODULE), - Mod:remove_message(LUser, LServer, I); + Mod:remove_message(LUser, LServer, I), + true; _ -> - ok + false end. -spec need_to_store(binary(), message()) -> boolean(). need_to_store(_LServer, #message{type = error}) -> false; -need_to_store(_LServer, #message{type = groupchat}) -> false; -need_to_store(_LServer, #message{type = headline}) -> false; -need_to_store(LServer, Packet) -> +need_to_store(LServer, #message{type = Type} = Packet) -> case xmpp:has_subtag(Packet, #offline{}) of false -> case check_store_hint(Packet) of @@ -425,6 +441,8 @@ need_to_store(LServer, Packet) -> true; no_store -> false; + none when Type == headline; Type == groupchat -> + false; none -> case gen_mod:get_module_opt( LServer, ?MODULE, store_empty_body, diff --git a/src/mod_offline_mnesia.erl b/src/mod_offline_mnesia.erl index e8db08ddf..c9f088fa4 100644 --- a/src/mod_offline_mnesia.erl +++ b/src/mod_offline_mnesia.erl @@ -127,12 +127,16 @@ read_message(LUser, LServer, I) -> remove_message(LUser, LServer, I) -> US = {LUser, LServer}, TS = integer_to_now(I), - Msgs = mnesia:dirty_match_object( - offline_msg, #offline_msg{us = US, timestamp = TS, _ = '_'}), - lists:foreach( - fun(Msg) -> - mnesia:dirty_delete_object(Msg) - end, Msgs). + case mnesia:dirty_match_object( + offline_msg, #offline_msg{us = US, timestamp = TS, _ = '_'}) of + [] -> + {error, notfound}; + Msgs -> + lists:foreach( + fun(Msg) -> + mnesia:dirty_delete_object(Msg) + end, Msgs) + end. read_all_messages(LUser, LServer) -> US = {LUser, LServer}, diff --git a/src/xmpp_util.erl b/src/xmpp_util.erl index 102d88412..fb3bbc7ab 100644 --- a/src/xmpp_util.erl +++ b/src/xmpp_util.erl @@ -70,7 +70,7 @@ unwrap_carbon(Stanza) -> Stanza. is_standalone_chat_state(Stanza) -> case unwrap_carbon(Stanza) of #message{body = [], subject = [], sub_els = Els} -> - IgnoreNS = [?NS_CHATSTATES, ?NS_DELAY], + IgnoreNS = [?NS_CHATSTATES, ?NS_DELAY, ?NS_EVENT], Stripped = [El || El <- Els, not lists:member(xmpp:get_ns(El), IgnoreNS)], Stripped == []; diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index a13d801ea..121719cdf 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -399,14 +399,12 @@ db_tests(riak) -> privacy_tests:single_cases(), vcard, muc_tests:single_cases(), + offline_tests:master_slave_cases(), test_unregister]}, muc_tests:master_slave_cases(), privacy_tests:master_slave_cases(), roster_tests:master_slave_cases(), - {test_flex_offline, [sequence], - [flex_offline_master, flex_offline_slave]}, - {test_offline, [sequence], - [offline_master, offline_slave]}, + offline_tests:master_slave_cases(), {test_announce, [sequence], [announce_master, announce_slave]}, {test_vcard_xupdate, [parallel], @@ -425,17 +423,15 @@ db_tests(DB) when DB == mnesia; DB == redis -> vcard, pubsub_single_tests(), muc_tests:single_cases(), + offline_tests:single_cases(), test_unregister]}, muc_tests:master_slave_cases(), privacy_tests:master_slave_cases(), pubsub_multiple_tests(), roster_tests:master_slave_cases(), + offline_tests:master_slave_cases(), {test_mix, [parallel], [mix_master, mix_slave]}, - {test_flex_offline, [sequence], - [flex_offline_master, flex_offline_slave]}, - {test_offline, [sequence], - [offline_master, offline_slave]}, {test_old_mam, [parallel], [mam_old_master, mam_old_slave]}, {test_new_mam, [parallel], @@ -465,17 +461,15 @@ db_tests(_) -> vcard, pubsub_single_tests(), muc_tests:single_cases(), + offline_tests:single_cases(), test_unregister]}, muc_tests:master_slave_cases(), privacy_tests:master_slave_cases(), pubsub_multiple_tests(), roster_tests:master_slave_cases(), + offline_tests:master_slave_cases(), {test_mix, [parallel], [mix_master, mix_slave]}, - {test_flex_offline, [sequence], - [flex_offline_master, flex_offline_slave]}, - {test_offline, [sequence], - [offline_master, offline_slave]}, {test_old_mam, [parallel], [mam_old_master, mam_old_slave]}, {test_new_mam, [parallel], @@ -2294,6 +2288,35 @@ muc_config_visitor_nickchange_master(Config) -> muc_config_visitor_nickchange_slave(Config) -> muc_tests:muc_config_visitor_nickchange_slave(Config). +offline_feature_enabled(Config) -> + offline_tests:feature_enabled(Config). +offline_check_identity(Config) -> + offline_tests:check_identity(Config). +offline_send_non_existent(Config) -> + offline_tests:send_non_existent(Config). +offline_view_non_existent(Config) -> + offline_tests:view_non_existent(Config). +offline_remove_non_existent(Config) -> + offline_tests:remove_non_existent(Config). +offline_view_non_integer(Config) -> + offline_tests:view_non_integer(Config). +offline_remove_non_integer(Config) -> + offline_tests:remove_non_integer(Config). +offline_malformed_iq(Config) -> + offline_tests:malformed_iq(Config). +offline_wrong_user(Config) -> + offline_tests:wrong_user(Config). +offline_unsupported_iq(Config) -> + offline_tests:unsupported_iq(Config). +offline_flex_master(Config) -> + offline_tests:flex_master(Config). +offline_flex_slave(Config) -> + offline_tests:flex_slave(Config). +offline_send_all_master(Config) -> + offline_tests:send_all_master(Config). +offline_send_all_slave(Config) -> + offline_tests:send_all_slave(Config). + announce_master(Config) -> MyJID = my_jid(Config), ServerJID = server_jid(Config), @@ -2317,155 +2340,6 @@ announce_slave(Config) -> send(Config, #message{to = MotdDelJID}), disconnect(Config). -flex_offline_master(Config) -> - Peer = ?config(slave, Config), - LPeer = jid:remove_resource(Peer), - lists:foreach( - fun(I) -> - Body = integer_to_binary(I), - send(Config, #message{to = LPeer, - body = [#text{data = Body}], - subject = [#text{data = <<"subject">>}]}) - end, lists:seq(1, 5)), - disconnect(Config). - -flex_offline_slave(Config) -> - MyJID = my_jid(Config), - MyBareJID = jid:remove_resource(MyJID), - Peer = ?config(master, Config), - Peer_s = jid:to_string(Peer), - true = is_feature_advertised(Config, ?NS_FLEX_OFFLINE), - %% Request disco#info - #iq{type = result, - sub_els = [#disco_info{ - node = ?NS_FLEX_OFFLINE, - identities = Ids, - features = Fts, - xdata = [X]}]} = - send_recv(Config, #iq{type = get, - sub_els = [#disco_info{ - node = ?NS_FLEX_OFFLINE}]}), - %% Check if we have correct identities - true = lists:any( - fun(#identity{category = <<"automation">>, - type = <<"message-list">>}) -> true; - (_) -> false - end, Ids), - %% Check if we have needed feature - true = lists:member(?NS_FLEX_OFFLINE, Fts), - %% Check xdata, the 'number_of_messages' should be 5 - #xdata{type = result, - fields = [#xdata_field{type = hidden, - var = <<"FORM_TYPE">>}, - #xdata_field{var = <<"number_of_messages">>, - values = [<<"5">>]}]} = X, - %% Fetch headers, - #iq{type = result, - sub_els = [#disco_items{ - node = ?NS_FLEX_OFFLINE, - items = DiscoItems}]} = - send_recv(Config, #iq{type = get, - sub_els = [#disco_items{ - node = ?NS_FLEX_OFFLINE}]}), - %% Check if headers are correct - Nodes = lists:sort( - lists:map( - fun(#disco_item{jid = J, name = P, node = N}) - when (J == MyBareJID) and (P == Peer_s) -> - N - end, DiscoItems)), - %% Since headers are received we can send initial presence without a risk - %% of getting offline messages flood - #presence{from = MyJID} = send_recv(Config, #presence{}), - %% Check full fetch - #iq{type = result, sub_els = []} = - send_recv(Config, #iq{type = get, sub_els = [#offline{fetch = true}]}), - lists:foreach( - fun({I, N}) -> - Text = integer_to_binary(I), - #message{body = Body, sub_els = SubEls} = recv_message(Config), - [#text{data = Text}] = Body, - #offline{items = [#offline_item{node = N}]} = - lists:keyfind(offline, 1, SubEls), - #delay{} = lists:keyfind(delay, 1, SubEls) - end, lists:zip(lists:seq(1, 5), Nodes)), - %% Fetch 2nd and 4th message - #iq{type = result, sub_els = []} = - send_recv( - Config, - #iq{type = get, - sub_els = [#offline{ - items = [#offline_item{ - action = view, - node = lists:nth(2, Nodes)}, - #offline_item{ - action = view, - node = lists:nth(4, Nodes)}]}]}), - lists:foreach( - fun({I, N}) -> - Text = integer_to_binary(I), - #message{body = [#text{data = Text}], - sub_els = SubEls} = recv_message(Config), - #offline{items = [#offline_item{node = N}]} = - lists:keyfind(offline, 1, SubEls) - end, lists:zip([2, 4], [lists:nth(2, Nodes), lists:nth(4, Nodes)])), - %% Delete 2nd and 4th message - #iq{type = result, sub_els = []} = - send_recv( - Config, - #iq{type = set, - sub_els = [#offline{ - items = [#offline_item{ - action = remove, - node = lists:nth(2, Nodes)}, - #offline_item{ - action = remove, - node = lists:nth(4, Nodes)}]}]}), - %% Check if messages were deleted - #iq{type = result, - sub_els = [#disco_items{ - node = ?NS_FLEX_OFFLINE, - items = RemainedItems}]} = - send_recv(Config, #iq{type = get, - sub_els = [#disco_items{ - node = ?NS_FLEX_OFFLINE}]}), - RemainedNodes = [lists:nth(1, Nodes), - lists:nth(3, Nodes), - lists:nth(5, Nodes)], - RemainedNodes = lists:sort( - lists:map( - fun(#disco_item{node = N}) -> N end, - RemainedItems)), - %% Purge everything left - #iq{type = result, sub_els = []} = - send_recv(Config, #iq{type = set, sub_els = [#offline{purge = true}]}), - %% Check if there is no offline messages - #iq{type = result, - sub_els = [#disco_items{node = ?NS_FLEX_OFFLINE, items = []}]} = - send_recv(Config, #iq{type = get, - sub_els = [#disco_items{ - node = ?NS_FLEX_OFFLINE}]}), - disconnect(Config). - -offline_master(Config) -> - Peer = ?config(slave, Config), - LPeer = jid:remove_resource(Peer), - send(Config, #message{to = LPeer, - body = [#text{data = <<"body">>}], - subject = [#text{data = <<"subject">>}]}), - disconnect(Config). - -offline_slave(Config) -> - Peer = ?config(master, Config), - #presence{} = send_recv(Config, #presence{}), - #message{sub_els = SubEls, - from = Peer, - body = [#text{data = <<"body">>}], - subject = [#text{data = <<"subject">>}]} = - recv_message(Config), - true = lists:keymember(delay, 1, SubEls), - disconnect(Config). - carbons_master(Config) -> MyJID = my_jid(Config), MyBareJID = jid:remove_resource(MyJID), diff --git a/test/ejabberd_SUITE_data/ejabberd.yml b/test/ejabberd_SUITE_data/ejabberd.yml index 3a6d4947f..29243d683 100644 --- a/test/ejabberd_SUITE_data/ejabberd.yml +++ b/test/ejabberd_SUITE_data/ejabberd.yml @@ -388,8 +388,7 @@ access: local: local: allow max_user_offline_messages: - admin: 5000 - all: 100 + all: infinity max_user_sessions: all: 10 muc: @@ -459,4 +458,4 @@ s2s_use_starttls: false s2s_cafile: CAFILE shaper: fast: 50000 - normal: 1000 + normal: 10000 diff --git a/test/offline_tests.erl b/test/offline_tests.erl new file mode 100644 index 000000000..ea34544e3 --- /dev/null +++ b/test/offline_tests.erl @@ -0,0 +1,406 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 7 Nov 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(offline_tests). + +%% API +-compile(export_all). +-import(suite, [send/2, disconnect/1, my_jid/1, send_recv/2, recv_message/1, + get_features/1, recv/1, get_event/1, server_jid/1, + wait_for_master/1, wait_for_slave/1]). +-include("suite.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +single_cases() -> + {offline_single, [sequence], + [single_test(feature_enabled), + single_test(check_identity), + single_test(send_non_existent), + single_test(view_non_existent), + single_test(remove_non_existent), + single_test(view_non_integer), + single_test(remove_non_integer), + single_test(malformed_iq), + single_test(wrong_user), + single_test(unsupported_iq)]}. + +feature_enabled(Config) -> + Features = get_features(Config), + ct:comment("Checking if offline features are set"), + true = lists:member(?NS_FEATURE_MSGOFFLINE, Features), + true = lists:member(?NS_FLEX_OFFLINE, Features), + disconnect(Config). + +check_identity(Config) -> + #iq{type = result, + sub_els = [#disco_info{ + node = ?NS_FLEX_OFFLINE, + identities = Ids}]} = + send_recv(Config, #iq{type = get, + sub_els = [#disco_info{ + node = ?NS_FLEX_OFFLINE}]}), + true = lists:any( + fun(#identity{category = <<"automation">>, + type = <<"message-list">>}) -> true; + (_) -> false + end, Ids), + disconnect(Config). + +send_non_existent(Config) -> + Server = ?config(server, Config), + To = jid:make(<<"non-existent">>, Server), + #message{type = error} = Err = send_recv(Config, #message{to = To}), + #stanza_error{reason = 'service-unavailable'} = xmpp:get_error(Err), + disconnect(Config). + +view_non_existent(Config) -> + #stanza_error{reason = 'item-not-found'} = view(Config, [randoms:get_string()], false), + disconnect(Config). + +remove_non_existent(Config) -> + ok = remove(Config, [randoms:get_string()]), + disconnect(Config). + +view_non_integer(Config) -> + #stanza_error{reason = 'item-not-found'} = view(Config, [<<"foo">>], false), + disconnect(Config). + +remove_non_integer(Config) -> + #stanza_error{reason = 'item-not-found'} = remove(Config, [<<"foo">>]), + disconnect(Config). + +malformed_iq(Config) -> + Item = #offline_item{node = randoms:get_string()}, + Range = [{Type, SubEl} || Type <- [set, get], + SubEl <- [#offline{items = [], _ = false}, + #offline{items = [Item], _ = true}]] + ++ [{set, #offline{items = [], fetch = true, purge = false}}, + {set, #offline{items = [Item], fetch = true, purge = false}}, + {get, #offline{items = [], fetch = false, purge = true}}, + {get, #offline{items = [Item], fetch = false, purge = true}}], + lists:foreach( + fun({Type, SubEl}) -> + #iq{type = error} = Err = + send_recv(Config, #iq{type = Type, sub_els = [SubEl]}), + #stanza_error{reason = 'bad-request'} = xmpp:get_error(Err) + end, Range), + disconnect(Config). + +wrong_user(Config) -> + Server = ?config(server, Config), + To = jid:make(<<"foo">>, Server), + Item = #offline_item{node = randoms:get_string()}, + Range = [{Type, Items, Purge, Fetch} || + Type <- [set, get], + Items <- [[], [Item]], + Purge <- [false, true], + Fetch <- [false, true]], + lists:foreach( + fun({Type, Items, Purge, Fetch}) -> + #iq{type = error} = Err = + send_recv(Config, #iq{type = Type, to = To, + sub_els = [#offline{items = Items, + purge = Purge, + fetch = Fetch}]}), + #stanza_error{reason = 'forbidden'} = xmpp:get_error(Err) + end, Range), + disconnect(Config). + +unsupported_iq(Config) -> + Item = #offline_item{node = randoms:get_string()}, + lists:foreach( + fun(Type) -> + #iq{type = error} = Err = + send_recv(Config, #iq{type = Type, sub_els = [Item]}), + #stanza_error{reason = 'service-unavailable'} = xmpp:get_error(Err) + end, [set, get]), + disconnect(Config). + +%%%=================================================================== +%%% Master-slave tests +%%%=================================================================== +master_slave_cases() -> + {offline_master_slave, [sequence], + [master_slave_test(flex), + master_slave_test(send_all)]}. + +flex_master(Config) -> + send_messages(Config, 5), + disconnect(Config). + +flex_slave(Config) -> + wait_for_master(Config), + peer_down = get_event(Config), + 5 = get_number(Config), + Nodes = get_nodes(Config), + %% Since headers are received we can send initial presence without a risk + %% of getting offline messages flood + #presence{} = send_recv(Config, #presence{}), + ct:comment("Checking fetch"), + Nodes = fetch(Config, lists:seq(1, 5)), + ct:comment("Fetching 2nd and 4th message"), + [2, 4] = view(Config, [lists:nth(2, Nodes), lists:nth(4, Nodes)]), + ct:comment("Deleting 2nd and 4th message"), + ok = remove(Config, [lists:nth(2, Nodes), lists:nth(4, Nodes)]), + ct:comment("Checking if messages were deleted"), + [1, 3, 5] = view(Config, [lists:nth(1, Nodes), + lists:nth(3, Nodes), + lists:nth(5, Nodes)]), + ct:comment("Purging everything left"), + ok = purge(Config), + ct:comment("Checking if there are no offline messages"), + 0 = get_number(Config), + clean(disconnect(Config)). + +send_all_master(Config) -> + wait_for_slave(Config), + Peer = ?config(peer, Config), + BarePeer = jid:remove_resource(Peer), + {Deliver, Errors} = message_iterator(Config), + N = lists:foldl( + fun(#message{type = error} = Msg, Acc) -> + send(Config, Msg#message{to = BarePeer}), + Acc; + (Msg, Acc) -> + I = send(Config, Msg#message{to = BarePeer}), + case xmpp:get_subtag(Msg, #xevent{}) of + #xevent{offline = true, id = undefined} -> + ct:comment("Receiving event-reply for:~n~s", + [xmpp:pp(Msg)]), + #message{} = Reply = recv_message(Config), + #xevent{id = I} = xmpp:get_subtag(Reply, #xevent{}); + _ -> + ok + end, + Acc + 1 + end, 0, Deliver), + lists:foreach( + fun(Msg) -> + #message{type = error} = Err = + send_recv(Config, Msg#message{to = BarePeer}), + #stanza_error{reason = 'service-unavailable'} = xmpp:get_error(Err) + end, Errors), + ok = wait_for_complete(Config, N), + disconnect(Config). + +send_all_slave(Config) -> + ServerJID = server_jid(Config), + Peer = ?config(peer, Config), + wait_for_master(Config), + peer_down = get_event(Config), + #presence{} = send_recv(Config, #presence{}), + {Deliver, _Errors} = message_iterator(Config), + lists:foreach( + fun(#message{type = error}) -> + ok; + (#message{type = Type, body = Body, subject = Subject} = Msg) -> + ct:comment("Receiving message:~n~s", [xmpp:pp(Msg)]), + #message{from = Peer, + type = Type, + body = Body, + subject = Subject} = RecvMsg = recv_message(Config), + ct:comment("Checking if delay tag is correctly set"), + #delay{from = ServerJID} = xmpp:get_subtag(RecvMsg, #delay{}) + end, Deliver), + disconnect(Config). + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +single_test(T) -> + list_to_atom("offline_" ++ atom_to_list(T)). + +master_slave_test(T) -> + {list_to_atom("offline_" ++ atom_to_list(T)), [parallel], + [list_to_atom("offline_" ++ atom_to_list(T) ++ "_master"), + list_to_atom("offline_" ++ atom_to_list(T) ++ "_slave")]}. + +clean(Config) -> + {U, S, _} = jid:tolower(my_jid(Config)), + mod_offline:remove_user(U, S), + Config. + +send_messages(Config, Num) -> + send_messages(Config, Num, normal, []). + +send_messages(Config, Num, Type, SubEls) -> + wait_for_slave(Config), + Peer = ?config(peer, Config), + BarePeer = jid:remove_resource(Peer), + lists:foreach( + fun(I) -> + Body = integer_to_binary(I), + send(Config, + #message{to = BarePeer, + type = Type, + body = [#text{data = Body}], + subject = [#text{data = <<"subject">>}], + sub_els = SubEls}) + end, lists:seq(1, Num)), + ct:comment("Waiting for all messages to be delivered to offline spool"), + ok = wait_for_complete(Config, Num). + +recv_messages(Config, Num) -> + wait_for_master(Config), + peer_down = get_event(Config), + Peer = ?config(peer, Config), + #presence{} = send_recv(Config, #presence{}), + lists:foreach( + fun(I) -> + Text = integer_to_binary(I), + #message{sub_els = SubEls, + from = Peer, + body = [#text{data = Text}], + subject = [#text{data = <<"subject">>}]} = + recv_message(Config), + true = lists:keymember(delay, 1, SubEls) + end, lists:seq(1, Num)), + clean(disconnect(Config)). + +get_number(Config) -> + ct:comment("Getting offline message number"), + #iq{type = result, + sub_els = [#disco_info{ + node = ?NS_FLEX_OFFLINE, + xdata = [X]}]} = + send_recv(Config, #iq{type = get, + sub_els = [#disco_info{ + node = ?NS_FLEX_OFFLINE}]}), + Form = flex_offline:decode(X#xdata.fields), + proplists:get_value(number_of_messages, Form). + +get_nodes(Config) -> + MyJID = my_jid(Config), + MyBareJID = jid:remove_resource(MyJID), + Peer = ?config(peer, Config), + Peer_s = jid:to_string(Peer), + ct:comment("Getting headers"), + #iq{type = result, + sub_els = [#disco_items{ + node = ?NS_FLEX_OFFLINE, + items = DiscoItems}]} = + send_recv(Config, #iq{type = get, + sub_els = [#disco_items{ + node = ?NS_FLEX_OFFLINE}]}), + ct:comment("Checking if headers are correct"), + lists:sort( + lists:map( + fun(#disco_item{jid = J, name = P, node = N}) + when (J == MyBareJID) and (P == Peer_s) -> + N + end, DiscoItems)). + +fetch(Config, Range) -> + ID = send(Config, #iq{type = get, sub_els = [#offline{fetch = true}]}), + Nodes = lists:map( + fun(I) -> + Text = integer_to_binary(I), + #message{body = Body, sub_els = SubEls} = recv(Config), + [#text{data = Text}] = Body, + #offline{items = [#offline_item{node = Node}]} = + lists:keyfind(offline, 1, SubEls), + #delay{} = lists:keyfind(delay, 1, SubEls), + Node + end, Range), + #iq{id = ID, type = result, sub_els = []} = recv(Config), + Nodes. + +view(Config, Nodes) -> + view(Config, Nodes, true). + +view(Config, Nodes, NeedReceive) -> + Items = lists:map( + fun(Node) -> + #offline_item{action = view, node = Node} + end, Nodes), + I = send(Config, + #iq{type = get, sub_els = [#offline{items = Items}]}), + Range = if NeedReceive -> + lists:map( + fun(Node) -> + #message{body = [#text{data = Text}], + sub_els = SubEls} = recv(Config), + #offline{items = [#offline_item{node = Node}]} = + lists:keyfind(offline, 1, SubEls), + binary_to_integer(Text) + end, Nodes); + true -> + [] + end, + case recv(Config) of + #iq{id = I, type = result, sub_els = []} -> Range; + #iq{id = I, type = error} = Err -> xmpp:get_error(Err) + end. + +remove(Config, Nodes) -> + Items = lists:map( + fun(Node) -> + #offline_item{action = remove, node = Node} + end, Nodes), + case send_recv(Config, #iq{type = set, + sub_els = [#offline{items = Items}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = Err -> + xmpp:get_error(Err) + end. + +purge(Config) -> + case send_recv(Config, #iq{type = set, + sub_els = [#offline{purge = true}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = Err -> + xmpp:get_error(Err) + end. + +wait_for_complete(_Config, 0) -> + ok; +wait_for_complete(Config, N) -> + {U, S, _} = jid:tolower(?config(peer, Config)), + lists:foldl( + fun(_Time, ok) -> + ok; + (Time, Acc) -> + timer:sleep(Time), + case mod_offline:count_offline_messages(U, S) of + N -> ok; + _ -> Acc + end + end, error, [0, 100, 200, 2000, 5000, 10000]). + +message_iterator(Config) -> + ServerJID = server_jid(Config), + ChatStates = [[#chatstate{type = composing}]], + Offline = [[#offline{}]], + Hints = [[#hint{type = T}] || T <- [store, 'no-store']], + XEvent = [[#xevent{id = ID, offline = OfflineFlag}] + || ID <- [undefined, randoms:get_string()], + OfflineFlag <- [false, true]], + Delay = [[#delay{stamp = p1_time_compat:timestamp(), from = ServerJID}]], + AllEls = [Els1 ++ Els2 || Els1 <- [[]] ++ ChatStates ++ Delay ++ Hints ++ Offline, + Els2 <- [[]] ++ XEvent], + All = [#message{type = Type, body = Body, subject = Subject, sub_els = Els} + || %%Type <- [chat], + Type <- [error, chat, normal, groupchat, headline], + Body <- [[], xmpp:mk_text(<<"body">>)], + Subject <- [[], xmpp:mk_text(<<"subject">>)], + Els <- AllEls], + lists:partition( + fun(#message{type = error}) -> true; + (#message{sub_els = [#offline{}|_]}) -> false; + (#message{sub_els = [_, #xevent{id = I}]}) when I /= undefined -> false; + (#message{sub_els = [#xevent{id = I}]}) when I /= undefined -> false; + (#message{sub_els = [#hint{type = store}|_]}) -> true; + (#message{sub_els = [#hint{type = 'no-store'}|_]}) -> false; + (#message{body = [], subject = []}) -> false; + (#message{type = Type}) -> (Type == chat) or (Type == normal); + (_) -> false + end, All). diff --git a/test/suite.erl b/test/suite.erl index f88ac5a5e..52c030df1 100644 --- a/test/suite.erl +++ b/test/suite.erl @@ -199,27 +199,31 @@ init_stream(Config) -> component -> ?NS_COMPONENT; server -> ?NS_SERVER end, - #stream_start{id = ID, xmlns = XMLNS, version = Version} = recv(Config), - set_opt(stream_id, ID, NewConfig). + receive + #stream_start{id = ID, xmlns = XMLNS, version = Version} -> + set_opt(stream_id, ID, NewConfig) + end. process_stream_features(Config) -> - #stream_features{sub_els = Fs} = recv(Config), - Mechs = lists:flatmap( - fun(#sasl_mechanisms{list = Ms}) -> - Ms; - (_) -> - [] - end, Fs), - lists:foldl( - fun(#feature_register{}, Acc) -> - set_opt(register, true, Acc); - (#starttls{}, Acc) -> - set_opt(starttls, true, Acc); - (#compression{methods = Ms}, Acc) -> - set_opt(compression, Ms, Acc); - (_, Acc) -> - Acc - end, set_opt(mechs, Mechs, Config), Fs). + receive + #stream_features{sub_els = Fs} -> + Mechs = lists:flatmap( + fun(#sasl_mechanisms{list = Ms}) -> + Ms; + (_) -> + [] + end, Fs), + lists:foldl( + fun(#feature_register{}, Acc) -> + set_opt(register, true, Acc); + (#starttls{}, Acc) -> + set_opt(starttls, true, Acc); + (#compression{methods = Ms}, Acc) -> + set_opt(compression, Ms, Acc); + (_, Acc) -> + Acc + end, set_opt(mechs, Mechs, Config), Fs) + end. disconnect(Config) -> ct:comment("Disconnecting"), @@ -245,7 +249,7 @@ starttls(Config) -> starttls(Config, ShouldFail) -> send(Config, #starttls{}), - case recv(Config) of + receive #starttls_proceed{} when ShouldFail -> ct:fail(starttls_should_have_failed); #starttls_failure{} when ShouldFail -> @@ -262,7 +266,7 @@ starttls(Config, ShouldFail) -> zlib(Config) -> send(Config, #compress{methods = [<<"zlib">>]}), - #compressed{} = recv(Config), + receive #compressed{} -> ok end, ZlibSocket = ejabberd_socket:compress(?config(socket, Config)), process_stream_features(init_stream(set_opt(socket, ZlibSocket, Config))). @@ -376,7 +380,7 @@ auth_component(Config, ShouldFail) -> Password = ?config(password, Config), Digest = p1_sha:sha(<>), send(Config, #handshake{data = Digest}), - case recv(Config) of + receive #handshake{} when ShouldFail -> ct:fail(component_auth_should_have_failed); #handshake{} -> @@ -399,7 +403,7 @@ auth_SASL(Mech, Config, ShouldFail) -> wait_auth_SASL_result(set_opt(sasl, SASL, Config), ShouldFail). wait_auth_SASL_result(Config, ShouldFail) -> - case recv(Config) of + receive #sasl_success{} when ShouldFail -> ct:fail(sasl_auth_should_have_failed); #sasl_success{} -> @@ -409,24 +413,25 @@ wait_auth_SASL_result(Config, ShouldFail) -> NS = if Type == client -> ?NS_CLIENT; Type == server -> ?NS_SERVER end, - #stream_start{xmlns = NS, version = {1,0}} = recv(Config), - #stream_features{sub_els = Fs} = recv(Config), - if Type == client -> - #xmpp_session{optional = true} = - lists:keyfind(xmpp_session, 1, Fs); - true -> - ok - end, - lists:foldl( - fun(#feature_sm{}, ConfigAcc) -> - set_opt(sm, true, ConfigAcc); - (#feature_csi{}, ConfigAcc) -> - set_opt(csi, true, ConfigAcc); - (#rosterver_feature{}, ConfigAcc) -> - set_opt(rosterver, true, ConfigAcc); - (_, ConfigAcc) -> - ConfigAcc - end, Config, Fs); + receive #stream_start{xmlns = NS, version = {1,0}} -> ok end, + receive #stream_features{sub_els = Fs} -> + if Type == client -> + #xmpp_session{optional = true} = + lists:keyfind(xmpp_session, 1, Fs); + true -> + ok + end, + lists:foldl( + fun(#feature_sm{}, ConfigAcc) -> + set_opt(sm, true, ConfigAcc); + (#feature_csi{}, ConfigAcc) -> + set_opt(csi, true, ConfigAcc); + (#rosterver_feature{}, ConfigAcc) -> + set_opt(rosterver, true, ConfigAcc); + (_, ConfigAcc) -> + ConfigAcc + end, Config, Fs) + end; #sasl_challenge{text = ClientIn} -> {Response, SASL} = (?config(sasl, Config))(ClientIn), send(Config, #sasl_response{text = Response}), From 566ac872fe396a6d41296d9cfbc6ed5859a0eeed Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 10 Nov 2016 20:48:43 +0100 Subject: [PATCH 068/151] Support to provide password when subscribing to a room (#1306) --- src/mod_muc_room.erl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl index 6010e0bbf..054900399 100644 --- a/src/mod_muc_room.erl +++ b/src/mod_muc_room.erl @@ -4653,7 +4653,8 @@ process_iq_mucsub(From, Packet, NewStateData = set_subscriber(From, Nick, Nodes, StateData), {result, subscription_nodes_to_events(Nodes), NewStateData}; error -> - add_new_user(From, Nick, Packet, StateData) + Packet2 = copy_password_xelement(Packet), + add_new_user(From, Nick, Packet2, StateData) end; _ -> Err = ?ERRT_NOT_ALLOWED(Lang, <<"Subscriptions are not allowed">>), @@ -4697,6 +4698,11 @@ process_iq_mucsub(_From, _Packet, #iq{lang = Lang}, _StateData) -> Txt = <<"Unrecognized subscription command">>, {error, ?ERRT_BAD_REQUEST(Lang, Txt)}. +copy_password_xelement(Packet) -> + SubsEl = fxml:get_subtag_with_xmlns(Packet, <<"subscribe">>, ?NS_MUCSUB), + XEl = fxml:get_subtag_with_xmlns(SubsEl, <<"x">>, ?NS_MUC), + fxml:append_subtags(Packet, [XEl]). + remove_subscriptions(StateData) -> if not (StateData#state.config)#config.allow_subscription -> StateData#state{subscribers = ?DICT:new(), From de81c501992bc5535ef2b0dbe37547c9f3754a73 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sat, 12 Nov 2016 14:47:29 +0300 Subject: [PATCH 069/151] Revert "Support to provide password when subscribing to a room (#1306)" This reverts commit 566ac872fe396a6d41296d9cfbc6ed5859a0eeed. --- src/mod_muc_room.erl | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl index e31ec6b0f..c83565734 100644 --- a/src/mod_muc_room.erl +++ b/src/mod_muc_room.erl @@ -3735,8 +3735,7 @@ process_iq_mucsub(From, NewStateData = set_subscriber(From, Nick, Nodes, StateData), {result, subscribe_result(Packet), NewStateData}; error -> - Packet2 = copy_password_xelement(Packet), - add_new_user(From, Nick, Packet2, StateData) + add_new_user(From, Nick, Packet, StateData) end; process_iq_mucsub(From, #iq{type = set, sub_els = [#muc_unsubscribe{}]}, StateData) -> @@ -3771,11 +3770,6 @@ process_iq_mucsub(_From, #iq{type = get, lang = Lang}, _StateData) -> Txt = <<"Value 'get' of 'type' attribute is not allowed">>, {error, xmpp:err_bad_request(Txt, Lang)}. -copy_password_xelement(Packet) -> - SubsEl = fxml:get_subtag_with_xmlns(Packet, <<"subscribe">>, ?NS_MUCSUB), - XEl = fxml:get_subtag_with_xmlns(SubsEl, <<"x">>, ?NS_MUC), - fxml:append_subtags(Packet, [XEl]). - remove_subscriptions(StateData) -> if not (StateData#state.config)#config.allow_subscription -> StateData#state{subscribers = ?DICT:new(), From 534e73f7320effc4cacef78ce7dce153a7bf7a70 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sat, 12 Nov 2016 14:51:43 +0300 Subject: [PATCH 070/151] Uncomment forgotten block of code --- src/ejabberd_service.erl | 53 +++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index 94cd68ecf..35cfe15af 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -170,37 +170,28 @@ wait_for_stream(closed, StateData) -> wait_for_handshake({xmlstreamelement, El}, StateData) -> decode_element(El, wait_for_handshake, StateData); wait_for_handshake(#handshake{data = Digest}, StateData) -> - send_element(StateData, #handshake{}), - lists:foreach( - fun (H) -> - ejabberd_router:register_route(H, ?MYNAME), - ?INFO_MSG("Route registered for service ~p~n", - [H]), - ejabberd_hooks:run(component_connected, [H]) - end, dict:fetch_keys(StateData#state.host_opts)), - {next_state, stream_established, StateData}; - %% case dict:find(StateData#state.host, StateData#state.host_opts) of - %% {ok, Password} -> - %% case p1_sha:sha(<<(StateData#state.streamid)/binary, - %% Password/binary>>) of - %% Digest -> - %% send_element(StateData, #handshake{}), - %% lists:foreach( - %% fun (H) -> - %% ejabberd_router:register_route(H, ?MYNAME), - %% ?INFO_MSG("Route registered for service ~p~n", - %% [H]), - %% ejabberd_hooks:run(component_connected, [H]) - %% end, dict:fetch_keys(StateData#state.host_opts)), - %% {next_state, stream_established, StateData}; - %% _ -> - %% send_element(StateData, xmpp:serr_not_authorized()), - %% {stop, normal, StateData} - %% end; - %% _ -> - %% send_element(StateData, xmpp:serr_not_authorized()), - %% {stop, normal, StateData} - %% end; + case dict:find(StateData#state.host, StateData#state.host_opts) of + {ok, Password} -> + case p1_sha:sha(<<(StateData#state.streamid)/binary, + Password/binary>>) of + Digest -> + send_element(StateData, #handshake{}), + lists:foreach( + fun (H) -> + ejabberd_router:register_route(H, ?MYNAME), + ?INFO_MSG("Route registered for service ~p~n", + [H]), + ejabberd_hooks:run(component_connected, [H]) + end, dict:fetch_keys(StateData#state.host_opts)), + {next_state, stream_established, StateData}; + _ -> + send_element(StateData, xmpp:serr_not_authorized()), + {stop, normal, StateData} + end; + _ -> + send_element(StateData, xmpp:serr_not_authorized()), + {stop, normal, StateData} + end; wait_for_handshake({xmlstreamend, _Name}, StateData) -> {stop, normal, StateData}; wait_for_handshake({xmlstreamerror, _}, StateData) -> From b8f22ff538da8297b66010912b3fc91e46ded5c0 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sun, 13 Nov 2016 10:44:53 +0300 Subject: [PATCH 071/151] Deprecate most of the functions from jlib.erl --- specs/xmpp_codec.spec | 4 +- src/ejabberd_oauth.erl | 4 +- src/jlib.erl | 57 +++++++++--- src/mod_admin_extra.erl | 4 +- src/mod_mam.erl | 10 +-- src/mod_muc_admin.erl | 2 +- src/mod_offline.erl | 149 +++++++++++++++++++------------- src/mod_offline_mnesia.erl | 10 ++- src/mod_offline_riak.erl | 9 +- src/mod_offline_sql.erl | 70 ++++++++------- src/prosody2ejabberd.erl | 8 +- src/pubsub_db_sql.erl | 4 +- src/pubsub_subscription.erl | 8 +- src/pubsub_subscription_sql.erl | 8 +- src/randoms.erl | 2 +- src/xmpp.erl | 7 +- src/xmpp_codec.erl | 5 +- src/xmpp_util.erl | 31 +++---- 18 files changed, 229 insertions(+), 163 deletions(-) diff --git a/specs/xmpp_codec.spec b/specs/xmpp_codec.spec index 12bc4b6a9..bcab7a6e5 100644 --- a/specs/xmpp_codec.spec +++ b/specs/xmpp_codec.spec @@ -3471,10 +3471,10 @@ enc_tzo({H, M}) -> -spec dec_utc(_) -> erlang:timestamp(). dec_utc(Val) -> - {_, _, _} = jlib:datetime_string_to_timestamp(Val). + xmpp_util:decode_timestamp(Val). enc_utc(Val) -> - jlib:now_to_utc_string(Val). + xmpp_util:encode_timestamp(Val). -spec dec_jid(_) -> jid:jid(). dec_jid(Val) -> diff --git a/src/ejabberd_oauth.erl b/src/ejabberd_oauth.erl index 318feb3f8..e03b78fe8 100644 --- a/src/ejabberd_oauth.erl +++ b/src/ejabberd_oauth.erl @@ -494,7 +494,7 @@ process(_Handlers, TTL = proplists:get_value(<<"ttl">>, Q, <<"">>), ExpiresIn = case TTL of <<>> -> undefined; - _ -> jlib:binary_to_integer(TTL) + _ -> binary_to_integer(TTL) end, case oauth2:authorize_password({Username, Server}, ClientId, @@ -556,7 +556,7 @@ process(_Handlers, TTL = proplists:get_value(<<"ttl">>, Q, <<"">>), ExpiresIn = case TTL of <<>> -> undefined; - _ -> jlib:binary_to_integer(TTL) + _ -> binary_to_integer(TTL) end, case oauth2:authorize_password({Username, Server}, Scope, diff --git a/src/jlib.erl b/src/jlib.erl index aca3b0ee8..f7dbebd86 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -35,27 +35,33 @@ binary_to_integer/1, integer_to_binary/1]}). +-export([tolower/1, term_to_base64/1, base64_to_term/1, + decode_base64/1, encode_base64/1, ip_to_list/1, + atom_to_binary/1, binary_to_atom/1, tuple_to_binary/1, + l2i/1, i2l/1, i2l/2, queue_drop_while/2, + expr_to_term/1, term_to_expr/1]). + +%% The following functions are used by gen_iq_handler.erl for providing backward +%% compatibility and must not be used in other parts of the code +%% Use xmpp:decode() and xmpp:encode() instead +-export([iq_query_info/1, iq_to_xml/1]). + +%% The following functions are deprecated and will be removed soon +%% Use functions from xmpp.erl and xmpp_util.erl instead -export([make_result_iq_reply/1, make_error_reply/3, make_error_reply/2, make_error_element/2, make_correct_from_to_attrs/3, replace_from_to_attrs/3, replace_from_to/3, replace_from_attrs/2, replace_from/2, - remove_attr/2, tolower/1, - get_iq_namespace/1, iq_query_info/1, + remove_attr/2, get_iq_namespace/1, iq_query_or_response_info/1, is_iq_request_type/1, - iq_to_xml/1, parse_xdata_submit/1, - unwrap_carbon/1, is_standalone_chat_state/1, + parse_xdata_submit/1, unwrap_carbon/1, is_standalone_chat_state/1, add_delay_info/3, add_delay_info/4, timestamp_to_legacy/1, timestamp_to_iso_basic/1, timestamp_to_iso/2, now_to_utc_string/1, now_to_local_string/1, datetime_string_to_timestamp/1, - term_to_base64/1, base64_to_term/1, - decode_base64/1, encode_base64/1, ip_to_list/1, rsm_encode/1, rsm_encode/2, rsm_decode/1, binary_to_integer/1, binary_to_integer/2, - integer_to_binary/1, integer_to_binary/2, - atom_to_binary/1, binary_to_atom/1, tuple_to_binary/1, - l2i/1, i2l/1, i2l/2, queue_drop_while/2, - expr_to_term/1, term_to_expr/1]). + integer_to_binary/1, integer_to_binary/2]). %% The following functions are deprecated and will be removed soon %% Use corresponding functions from jid.erl instead @@ -75,8 +81,37 @@ {jid_tolower, 1}, {jid_remove_resource, 1}, {jid_replace_resource, 2}, + {add_delay_info, 3}, + {add_delay_info, 4}, + {make_result_iq_reply, 1}, + {make_error_reply, 3}, + {make_error_reply, 2}, + {make_error_element, 2}, + {make_correct_from_to_attrs, 3}, + {replace_from_to_attrs, 3}, + {replace_from_to, 3}, + {replace_from_attrs, 2}, + {replace_from, 2}, + {remove_attr, 2}, + {get_iq_namespace, 1}, + {iq_query_or_response_info, 1}, + {is_iq_request_type, 1}, + {parse_xdata_submit, 1}, + {unwrap_carbon, 1}, + {is_standalone_chat_state, 1}, + {timestamp_to_legacy, 1}, + {timestamp_to_iso_basic, 1}, + {timestamp_to_iso, 2}, + {now_to_utc_string, 1}, + {now_to_local_string, 1}, + {datetime_string_to_timestamp, 1}, + {rsm_encode, 1}, + {rsm_encode, 2}, + {rsm_decode, 1}, + {binary_to_integer, 1}, + {binary_to_integer, 2}, {integer_to_binary, 1}, - {binary_to_integer, 1}]). + {integer_to_binary, 2}]). -include("ejabberd.hrl"). -include("jlib.hrl"). diff --git a/src/mod_admin_extra.erl b/src/mod_admin_extra.erl index 69fffbd7c..2967e86a0 100644 --- a/src/mod_admin_extra.erl +++ b/src/mod_admin_extra.erl @@ -761,7 +761,9 @@ set_random_password(User, Server, Reason) -> set_password_auth(User, Server, NewPass). build_random_password(Reason) -> - Date = jlib:timestamp_to_legacy(calendar:universal_time()), + {{Year, Month, Day}, {Hour, Minute, Second}} = calendar:universal_time(), + Date = str:format("~4..0B~2..0B~2..0BT~2..0B:~2..0B:~2..0B", + [Year, Month, Day, Hour, Minute, Second]), RandomString = randoms:get_string(), <<"BANNED_ACCOUNT--", Date/binary, "--", RandomString/binary, "--", Reason/binary>>. diff --git a/src/mod_mam.erl b/src/mod_mam.erl index 3d5c8f64d..8c5422f07 100644 --- a/src/mod_mam.erl +++ b/src/mod_mam.erl @@ -312,14 +312,14 @@ parse_query(#mam_query{xdata = #xdata{fields = Fs}} = Query, Lang) -> try lists:foldl( fun(#xdata_field{var = <<"start">>, values = [Data|_]}, Q) -> - case jlib:datetime_string_to_timestamp(Data) of - undefined -> throw({error, <<"start">>}); + try xmpp_util:decode_timestamp(Data) of {_, _, _} = TS -> Q#mam_query{start = TS} + catch _:{bad_timestamp, _} -> throw({error, <<"start">>}) end; (#xdata_field{var = <<"end">>, values = [Data|_]}, Q) -> - case jlib:datetime_string_to_timestamp(Data) of - undefined -> throw({error, <<"end">>}); - {_, _, _} = TS -> Q#mam_query{'end' = TS} + try xmpp_util:decode_timestamp(Data) of + {_, _, _} = TS -> Q#mam_query{start = TS} + catch _:{bad_timestamp, _} -> throw({error, <<"end">>}) end; (#xdata_field{var = <<"with">>, values = [Data|_]}, Q) -> case jid:from_string(Data) of diff --git a/src/mod_muc_admin.erl b/src/mod_muc_admin.erl index 8f1f649d2..91ccce559 100644 --- a/src/mod_muc_admin.erl +++ b/src/mod_muc_admin.erl @@ -388,7 +388,7 @@ build_info_room({Name, Host, Pid}) -> false -> Last_message1 = queue:last(History), {_, _, _, Ts_last, _} = Last_message1, - jlib:timestamp_to_legacy(Ts_last) + xmpp_util:encode_timestamp(Ts_last) end, {<>, diff --git a/src/mod_offline.erl b/src/mod_offline.erl index dfe3c9e8e..2f6d52c36 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -285,7 +285,7 @@ get_sm_items(_Acc, #jid{luser = U, lserver = S, lresource = R} = JID, BareJID = jid:remove_resource(JID), Pid ! dont_ask_offline, {result, lists:map( - fun({Seq, From, _To, _El}) -> + fun({Seq, From, _To, _TS, _El}) -> Node = integer_to_binary(Seq), #disco_item{jid = BareJID, node = Node, @@ -400,10 +400,10 @@ handle_offline_fetch(#jid{luser = U, lserver = S, lresource = R}) -> Pid when is_pid(Pid) -> Pid ! dont_ask_offline, lists:foreach( - fun({Node, From, To, El}) -> + fun({Node, El}) -> NewEl = set_offline_tag(El, Node), - Pid ! {route, From, To, NewEl} - end, read_message_headers(U, S)) + Pid ! {route, xmpp:get_from(El), xmpp:get_to(El), NewEl} + end, read_messages(U, S)) end. -spec fetch_msg_by_node(jid(), binary()) -> error | {ok, #offline_msg{}}. @@ -476,11 +476,13 @@ store_packet(From, To, Packet) -> NewPacket -> TimeStamp = p1_time_compat:timestamp(), Expire = find_x_expire(TimeStamp, NewPacket), - El = xmpp:encode(NewPacket), gen_mod:get_module_proc(To#jid.lserver, ?PROCNAME) ! #offline_msg{us = {LUser, LServer}, - timestamp = TimeStamp, expire = Expire, - from = From, to = To, packet = El}, + timestamp = TimeStamp, + expire = Expire, + from = From, + to = To, + packet = NewPacket}, stop end; _ -> ok @@ -547,10 +549,13 @@ resend_offline_messages(User, Server) -> Mod = gen_mod:db_mod(LServer, ?MODULE), case Mod:pop_messages(LUser, LServer) of {ok, Rs} -> - lists:foreach(fun (R) -> - ejabberd_sm ! offline_msg_to_route(LServer, R) - end, - lists:keysort(#offline_msg.timestamp, Rs)); + lists:foreach( + fun(R) -> + case offline_msg_to_route(LServer, R) of + error -> ok; + RouteMsg -> ejabberd_sm ! RouteMsg + end + end, lists:keysort(#offline_msg.timestamp, Rs)); _ -> ok end. @@ -565,22 +570,26 @@ pop_offline_messages(Ls, User, Server) -> {ok, Rs} -> TS = p1_time_compat:timestamp(), Ls ++ - lists:map(fun (R) -> - offline_msg_to_route(LServer, R) - end, - lists:filter( - fun(#offline_msg{packet = Pkt} = R) -> - Expire = case R#offline_msg.expire of - undefined -> - find_x_expire(TS, Pkt); - Exp -> - Exp - end, - case Expire of - never -> true; - TimeStamp -> TS < TimeStamp - end - end, Rs)); + lists:flatmap( + fun(R) -> + case offline_msg_to_route(LServer, R) of + error -> []; + RouteMsg -> [RouteMsg] + end + end, + lists:filter( + fun(#offline_msg{packet = Pkt} = R) -> + Expire = case R#offline_msg.expire of + undefined -> + find_x_expire(TS, Pkt); + Exp -> + Exp + end, + case Expire of + never -> true; + TimeStamp -> TS < TimeStamp + end + end, Rs)); _ -> Ls end. @@ -625,52 +634,61 @@ webadmin_page(_, Host, webadmin_page(Acc, _, _) -> Acc. get_offline_els(LUser, LServer) -> - Hdrs = read_message_headers(LUser, LServer), - lists:map( - fun({_Seq, From, To, Packet}) -> - xmpp:set_from_to(Packet, From, To) - end, Hdrs). + [Packet || {_Seq, Packet} <- read_messages(LUser, LServer)]. +-spec offline_msg_to_route(binary(), #offline_msg{}) -> + {route, jid(), jid(), message()} | error. offline_msg_to_route(LServer, #offline_msg{} = R) -> - Pkt = xmpp:decode(R#offline_msg.packet, ?NS_CLIENT, [ignore_els]), - Pkt1 = case R#offline_msg.timestamp of - undefined -> - Pkt; - TS -> - xmpp_util:add_delay_info(Pkt, jid:make(LServer), TS, - <<"Offline Storage">>) - end, - {route, R#offline_msg.from, R#offline_msg.to, Pkt1}. + try xmpp:decode(R#offline_msg.packet, ?NS_CLIENT, [ignore_els]) of + Pkt -> + NewPkt = add_delay_info(Pkt, LServer, R#offline_msg.timestamp), + {route, R#offline_msg.from, R#offline_msg.to, NewPkt} + catch _:{xmpp_codec, Why} -> + ?ERROR_MSG("failed to decode packet ~p of user ~s: ~s", + [R#offline_msg.packet, jid:to_string(R#offline_msg.to), + xmpp:format_error(Why)]), + error + end. -read_message_headers(LUser, LServer) -> +-spec read_messages(binary(), binary()) -> [{binary(), message()}]. +read_messages(LUser, LServer) -> Mod = gen_mod:db_mod(LServer, ?MODULE), - lists:map( - fun({Seq, From, To, El}) -> + lists:flatmap( + fun({Seq, From, To, TS, El}) -> Node = integer_to_binary(Seq), - Packet = xmpp:decode(El, ?NS_CLIENT, [ignore_els]), - {Node, From, To, Packet} + try xmpp:decode(El, ?NS_CLIENT, [ignore_els]) of + Pkt -> + Node = integer_to_binary(Seq), + Pkt1 = add_delay_info(Pkt, LServer, TS), + Pkt2 = xmpp:set_from_to(Pkt1, From, To), + [{Node, Pkt2}] + catch _:{xmpp_codec, Why} -> + ?ERROR_MSG("failed to decode packet ~p " + "of user ~s: ~s", + [El, jid:to_string(To), + xmpp:format_error(Why)]), + [] + end end, Mod:read_message_headers(LUser, LServer)). format_user_queue(Hdrs) -> lists:map( - fun({Seq, From, To, El}) -> + fun({Seq, From, To, TS, El}) -> ID = integer_to_binary(Seq), FPacket = ejabberd_web_admin:pretty_print_xml(El), SFrom = jid:to_string(From), STo = jid:to_string(To), - Stamp = fxml:get_path_s(El, [{elem, <<"delay">>}, - {attr, <<"stamp">>}]), - Time = case jlib:datetime_string_to_timestamp(Stamp) of + Time = case TS of + undefined -> + Stamp = fxml:get_path_s(El, [{elem, <<"delay">>}, + {attr, <<"stamp">>}]), + try xmpp_util:decode_timestamp(Stamp) of + {_, _, _} = Now -> format_time(Now) + catch _:_ -> + <<"">> + end; {_, _, _} = Now -> - {{Year, Month, Day}, {Hour, Minute, Second}} = - calendar:now_to_local_time(Now), - iolist_to_binary( - io_lib:format( - "~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w", - [Year, Month, Day, Hour, Minute, - Second])); - _ -> - <<"">> + format_time(Now) end, ?XE(<<"tr">>, [?XAE(<<"td">>, [{<<"class">>, <<"valign">>}], @@ -682,6 +700,11 @@ format_user_queue(Hdrs) -> [?XC(<<"pre">>, FPacket)])]) end, Hdrs). +format_time(Now) -> + {{Year, Month, Day}, {Hour, Minute, Second}} = calendar:now_to_local_time(Now), + str:format("~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w", + [Year, Month, Day, Hour, Minute, Second]). + user_queue(User, Server, Query, Lang) -> LUser = jid:nodeprep(User), LServer = jid:nameprep(Server), @@ -815,6 +838,14 @@ count_offline_messages(User, Server) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:count_messages(LUser, LServer). +-spec add_delay_info(message(), binary(), + undefined | erlang:timestamp()) -> message(). +add_delay_info(Packet, _LServer, undefined) -> + Packet; +add_delay_info(Packet, LServer, {_, _, _} = TS) -> + xmpp_util:add_delay_info(Packet, jid:make(LServer), TS, + <<"Offline storage">>). + export(LServer) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:export(LServer). diff --git a/src/mod_offline_mnesia.erl b/src/mod_offline_mnesia.erl index c9f088fa4..9fec9c4d5 100644 --- a/src/mod_offline_mnesia.erl +++ b/src/mod_offline_mnesia.erl @@ -42,7 +42,11 @@ store_messages(_Host, US, Msgs, Len, MaxOfflineMsgs) -> mnesia:write_lock_table(offline_msg); true -> ok end, - lists:foreach(fun (M) -> mnesia:write(M) end, Msgs) + lists:foreach( + fun(#offline_msg{packet = Pkt} = M) -> + El = xmpp:encode(Pkt), + mnesia:write(M#offline_msg{packet = El}) + end, Msgs) end end, mnesia:transaction(F). @@ -107,9 +111,7 @@ read_message_headers(LUser, LServer) -> fun(#offline_msg{from = From, to = To, packet = Pkt, timestamp = TS}) -> Seq = now_to_integer(TS), - NewPkt = jlib:add_delay_info(Pkt, LServer, TS, - <<"Offline Storage">>), - {Seq, From, To, NewPkt} + {Seq, From, To, TS, Pkt} end, Msgs), lists:keysort(1, Hdrs). diff --git a/src/mod_offline_riak.erl b/src/mod_offline_riak.erl index 647f71dfd..241a8d650 100644 --- a/src/mod_offline_riak.erl +++ b/src/mod_offline_riak.erl @@ -36,9 +36,12 @@ store_messages(Host, {User, _}, Msgs, Len, MaxOfflineMsgs) -> try lists:foreach( fun(#offline_msg{us = US, + packet = Pkt, timestamp = TS} = M) -> + El = xmpp:encode(Pkt), ok = ejabberd_riak:put( - M, offline_msg_schema(), + M#offline_msg{packet = El}, + offline_msg_schema(), [{i, TS}, {'2i', [{<<"us">>, US}]}]) end, Msgs), {atomic, ok} @@ -85,9 +88,7 @@ read_message_headers(LUser, LServer) -> fun(#offline_msg{from = From, to = To, packet = Pkt, timestamp = TS}) -> Seq = now_to_integer(TS), - NewPkt = jlib:add_delay_info( - Pkt, LServer, TS, <<"Offline Storage">>), - {Seq, From, To, NewPkt} + {Seq, From, To, Pkt} end, Rs), lists:keysort(1, Hdrs); _Err -> diff --git a/src/mod_offline_sql.erl b/src/mod_offline_sql.erl index 9459753bc..2b7a40bff 100644 --- a/src/mod_offline_sql.erl +++ b/src/mod_offline_sql.erl @@ -41,14 +41,14 @@ store_messages(Host, {User, _Server}, Msgs, Len, MaxOfflineMsgs) -> LUser = (M#offline_msg.to)#jid.luser, From = M#offline_msg.from, To = M#offline_msg.to, - Packet = - jlib:replace_from_to(From, To, - M#offline_msg.packet), - NewPacket = - jlib:add_delay_info(Packet, Host, - M#offline_msg.timestamp, - <<"Offline Storage">>), - XML = fxml:element_to_binary(NewPacket), + Packet = xmpp:set_from_to( + M#offline_msg.packet, From, To), + NewPacket = xmpp_util:add_delay_info( + Packet, jid:make(Host), + M#offline_msg.timestamp, + <<"Offline Storage">>), + XML = fxml:element_to_binary( + xmpp:encode(NewPacket)), sql_queries:add_spool_sql(LUser, XML) end, Msgs), @@ -171,15 +171,23 @@ export(_Server) -> [{offline_msg, fun(Host, #offline_msg{us = {LUser, LServer}, timestamp = TimeStamp, from = From, to = To, - packet = Packet}) + packet = El}) when LServer == Host -> - Packet1 = jlib:replace_from_to(From, To, Packet), - Packet2 = jlib:add_delay_info(Packet1, LServer, TimeStamp, - <<"Offline Storage">>), - XML = fxml:element_to_binary(Packet2), - [?SQL("delete from spool where username=%(LUser)s;"), - ?SQL("insert into spool(username, xml) values (" - "%(LUser)s, %(XML)s);")]; + try xmpp:decode(El, ?NS_CLIENT, [ignore_els]) of + Packet -> + Packet1 = xmpp:set_from_to(Packet, From, To), + Packet2 = xmpp_util:add_delay_info( + Packet1, jid:make(LServer), + TimeStamp, <<"Offline Storage">>), + XML = fxml:element_to_binary(xmpp:encode(Packet2)), + [?SQL("delete from spool where username=%(LUser)s;"), + ?SQL("insert into spool(username, xml) values (" + "%(LUser)s, %(XML)s);")] + catch _:{xmpp_codec, Why} -> + ?ERROR_MSG("failed to decode packet ~p of user ~s@~s: ~s", + [El, LUser, LServer, xmpp:format_error(Why)]), + [] + end; (_Host, _R) -> [] end}]. @@ -188,23 +196,21 @@ import(LServer) -> [{<<"select username, xml from spool;">>, fun([LUser, XML]) -> El = #xmlel{} = fxml_stream:parse_element(XML), - From = #jid{} = jid:from_string( - fxml:get_attr_s(<<"from">>, El#xmlel.attrs)), - To = #jid{} = jid:from_string( - fxml:get_attr_s(<<"to">>, El#xmlel.attrs)), - Stamp = fxml:get_path_s(El, [{elem, <<"delay">>}, - {attr, <<"stamp">>}]), - TS = case jlib:datetime_string_to_timestamp(Stamp) of - {_, _, _} = Now -> - Now; - undefined -> - p1_time_compat:timestamp() - end, - Expire = mod_offline:find_x_expire(TS, El#xmlel.children), - #offline_msg{us = {LUser, LServer}, - from = From, to = To, + #message{} = Pkt = xmpp:decode(El, ?NS_CLIENT, [ignore_els]), + From = Pkt#message.from, + To = case Pkt#message.to of + undefined -> jid:make(LUser, LServer); + JID -> JID + end, + TS = case xmpp:get_subtag(Pkt, #delay{}) of + #delay{stamp = Stamp} -> Stamp; + false -> p1_time_compat:timestamp() + end, + Expire = mod_offline:find_x_expire(TS, Pkt), + #offline_msg{us = {LUser, LServer}, + from = From, to = To, packet = El, - timestamp = TS, expire = Expire} + timestamp = TS, expire = Expire} end}]. import(_, _) -> diff --git a/src/prosody2ejabberd.erl b/src/prosody2ejabberd.erl index d5eca5ecb..fcc472dce 100644 --- a/src/prosody2ejabberd.erl +++ b/src/prosody2ejabberd.erl @@ -300,8 +300,8 @@ convert_privacy_item({_, Item}) -> match_presence_out = MatchPresOut}. el_to_offline_msg(LUser, LServer, #xmlel{attrs = Attrs} = El) -> - case jlib:datetime_string_to_timestamp( - fxml:get_attr_s(<<"stamp">>, Attrs)) of + try xmpp_util:decode_timestamp( + fxml:get_attr_s(<<"stamp">>, Attrs)) of {_, _, _} = TS -> Attrs1 = lists:filter( fun(<<"stamp">>) -> false; @@ -321,8 +321,8 @@ el_to_offline_msg(LUser, LServer, #xmlel{attrs = Attrs} = El) -> packet = Packet}]; _ -> [] - end; - _ -> + end + catch _:{bad_timestamp, _} -> [] end. diff --git a/src/pubsub_db_sql.erl b/src/pubsub_db_sql.erl index 69b476539..713d33970 100644 --- a/src/pubsub_db_sql.erl +++ b/src/pubsub_db_sql.erl @@ -132,10 +132,10 @@ integer_to_sql(N) -> iolist_to_binary(integer_to_list(N)). boolean_to_sql(true) -> <<"1">>; boolean_to_sql(false) -> <<"0">>. -timestamp_to_sql(T) -> jlib:now_to_utc_string(T). +timestamp_to_sql(T) -> xmpp_util:encode_timestamp(T). sql_to_integer(N) -> binary_to_integer(N). sql_to_boolean(B) -> B == <<"1">>. -sql_to_timestamp(T) -> jlib:datetime_string_to_timestamp(T). +sql_to_timestamp(T) -> xmpp_util:decode_timestamp(T). diff --git a/src/pubsub_subscription.erl b/src/pubsub_subscription.erl index de1a363db..f2c962257 100644 --- a/src/pubsub_subscription.erl +++ b/src/pubsub_subscription.erl @@ -211,13 +211,11 @@ val_xfield(digest_frequency = Opt, [Val]) -> {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} end; val_xfield(expire = Opt, [Val]) -> - case jlib:datetime_string_to_timestamp(Val) of - undefined -> + try xmpp_util:decode_timestamp(Val) + catch _:{bad_timestamp, _} -> Txt = <<"Value of '~s' should be datetime string">>, ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), - {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)}; - Timestamp -> - Timestamp + {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} end; val_xfield(include_body = Opt, [Val]) -> xopt_to_bool(Opt, Val); val_xfield(show_values, Vals) -> Vals; diff --git a/src/pubsub_subscription_sql.erl b/src/pubsub_subscription_sql.erl index 32aa41a93..922b2a418 100644 --- a/src/pubsub_subscription_sql.erl +++ b/src/pubsub_subscription_sql.erl @@ -176,13 +176,11 @@ val_xfield(digest_frequency = Opt, [Val]) -> {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} end; val_xfield(expire = Opt, [Val]) -> - case jlib:datetime_string_to_timestamp(Val) of - undefined -> + try xmpp_util:decode_timestamp(Val) + catch _:{bad_timestamp, _} -> Txt = <<"Value of '~s' should be datetime string">>, ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), - {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)}; - Timestamp -> - Timestamp + {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} end; val_xfield(include_body = Opt, [Val]) -> xopt_to_bool(Opt, Val); val_xfield(show_values, Vals) -> Vals; diff --git a/src/randoms.erl b/src/randoms.erl index 1353f48af..ae477d27d 100644 --- a/src/randoms.erl +++ b/src/randoms.erl @@ -38,7 +38,7 @@ start() -> get_string() -> R = crypto:rand_uniform(0, ?THRESHOLD), - jlib:integer_to_binary(R). + integer_to_binary(R). uniform() -> crypto:rand_uniform(0, ?THRESHOLD)/?THRESHOLD. diff --git a/src/xmpp.erl b/src/xmpp.erl index 0abcda7ee..2c08c2bcd 100644 --- a/src/xmpp.erl +++ b/src/xmpp.erl @@ -18,7 +18,7 @@ format_error/1, is_stanza/1, set_subtag/2, get_subtag/2, remove_subtag/2, has_subtag/2, decode_els/1, decode_els/3, pp/1, get_name/1, get_text/1, mk_text/1, mk_text/2, - is_known_tag/1, is_known_tag/2]). + is_known_tag/1, is_known_tag/2, append_subtags/2]). %% XMPP errors -export([err_bad_request/0, err_bad_request/2, @@ -369,6 +369,11 @@ has_subtag([El|Els], TagName, XMLNS) -> has_subtag([], _, _) -> false. +-spec append_subtags(stanza(), [xmpp_element() | xmlel()]) -> stanza(). +append_subtags(Stanza, Tags) -> + Els = get_els(Stanza), + set_els(Stanza, Els ++ Tags). + -spec get_text([text()]) -> binary(). get_text([]) -> <<"">>; get_text([#text{data = Data}|_]) -> Data. diff --git a/src/xmpp_codec.erl b/src/xmpp_codec.erl index 8713365cc..2931baaa4 100644 --- a/src/xmpp_codec.erl +++ b/src/xmpp_codec.erl @@ -6782,10 +6782,9 @@ dec_jid(Val) -> J -> J end. -enc_utc(Val) -> jlib:now_to_utc_string(Val). +enc_utc(Val) -> xmpp_util:encode_timestamp(Val). -dec_utc(Val) -> - {_, _, _} = jlib:datetime_string_to_timestamp(Val). +dec_utc(Val) -> xmpp_util:decode_timestamp(Val). enc_tzo({H, M}) -> Sign = if H >= 0 -> <<>>; diff --git a/src/xmpp_util.erl b/src/xmpp_util.erl index 7b3e0e892..a07dae78b 100644 --- a/src/xmpp_util.erl +++ b/src/xmpp_util.erl @@ -27,28 +27,17 @@ add_delay_info(Stz, From, Time) -> erlang:timestamp(), binary()) -> stanza(). add_delay_info(Stz, From, Time, Desc) -> + NewDelay = #delay{stamp = Time, from = From, desc = Desc}, case xmpp:get_subtag(Stz, #delay{}) of - #delay{from = OldFrom, desc = OldDesc} = Delay -> + #delay{from = OldFrom} -> case jid:tolower(From) == jid:tolower(OldFrom) of - true when Desc == <<"">> -> - Stz; - true when OldDesc == <<"">> -> - xmpp:set_subtag(Stz, Delay#delay{desc = Desc}); - true -> - case binary:match(OldDesc, Desc) of - nomatch -> - NewDesc = <>, - xmpp:set_subtag(Stz, Delay#delay{desc = NewDesc}); - _ -> - Stz - end; false -> - NewDelay = #delay{stamp = Time, from = From, desc = Desc}, - xmpp:set_subtag(Stz, NewDelay) + xmpp:set_subtag(Stz, NewDelay); + true -> + xmpp:append_subtags(Stz, [NewDelay]) end; false -> - Delay = #delay{stamp = Time, from = From, desc = Desc}, - xmpp:set_subtag(Stz, Delay) + xmpp:append_subtags(Stz, [NewDelay]) end. -spec unwrap_carbon(stanza()) -> xmpp_element(). @@ -147,10 +136,10 @@ try_decode_timestamp(<>). try_decode_fraction(<<$., T/binary>>) -> - {match, [V]} = re:run(T, <<"^[0-9]+">>, [{capture, [0], binary}]), - Size = size(V), - <> = T, - {to_integer(binary:part(V, 0, min(6, Size)), 0, 999999), + {match, [V]} = re:run(T, <<"^[0-9]+">>, [{capture, [0], list}]), + Size = length(V), + <<_:Size/binary, TZD/binary>> = T, + {list_to_integer(string:left(V, 6, $0)), try_decode_tzd(TZD)}; try_decode_fraction(TZD) -> {0, try_decode_tzd(TZD)}. From 21d78ed7f4f4b6ea404fb990d0d9e12be28d7e84 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sun, 13 Nov 2016 10:56:36 +0300 Subject: [PATCH 072/151] Don't use jlib.hrl outside of jlib.erl --- src/ejabberd_oauth_rest.erl | 2 +- src/ejabberd_oauth_sql.erl | 2 +- src/node_mb_sql.erl | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ejabberd_oauth_rest.erl b/src/ejabberd_oauth_rest.erl index aadb97084..c932d16f5 100644 --- a/src/ejabberd_oauth_rest.erl +++ b/src/ejabberd_oauth_rest.erl @@ -35,7 +35,7 @@ -include("ejabberd.hrl"). -include("ejabberd_oauth.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("jid.hrl"). init() -> rest:start(?MYNAME), diff --git a/src/ejabberd_oauth_sql.erl b/src/ejabberd_oauth_sql.erl index 9253335ff..3c09362c2 100644 --- a/src/ejabberd_oauth_sql.erl +++ b/src/ejabberd_oauth_sql.erl @@ -36,7 +36,7 @@ -include("ejabberd_oauth.hrl"). -include("ejabberd.hrl"). -include("ejabberd_sql_pt.hrl"). --include("jlib.hrl"). +-include("jid.hrl"). init() -> ok. diff --git a/src/node_mb_sql.erl b/src/node_mb_sql.erl index 125674316..0f5c409ff 100644 --- a/src/node_mb_sql.erl +++ b/src/node_mb_sql.erl @@ -28,7 +28,6 @@ -author('holger@zedat.fu-berlin.de'). -include("pubsub.hrl"). --include("jlib.hrl"). -export([init/3, terminate/2, options/0, features/0, create_node_permission/6, create_node/2, delete_node/1, From 132033d01a09b3268faed170a63c4a3114d2bae0 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sun, 13 Nov 2016 10:57:53 +0300 Subject: [PATCH 073/151] Remove unused header file --- include/ejabberd_service.hrl | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 include/ejabberd_service.hrl diff --git a/include/ejabberd_service.hrl b/include/ejabberd_service.hrl deleted file mode 100644 index 7cd3b6943..000000000 --- a/include/ejabberd_service.hrl +++ /dev/null @@ -1,20 +0,0 @@ --include("ejabberd.hrl"). --include("logger.hrl"). --include("jlib.hrl"). - --type filter_attr() :: {binary(), [binary()]}. - --record(state, - {socket :: ejabberd_socket:socket_state(), - sockmod = ejabberd_socket :: ejabberd_socket | ejabberd_frontend_socket, - streamid = <<"">> :: binary(), - host_opts = dict:new() :: ?TDICT, - host = <<"">> :: binary(), - access :: atom(), - check_from = true :: boolean(), - server_hosts = ?MYHOSTS :: [binary()], - privilege_access :: [attr()], - delegations :: [filter_attr()], - last_pres = dict:new() :: ?TDICT}). - --type(state() :: #state{} ). From 7e9f1a6dc19d9230456fdbae355915ba6ec1e656 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sun, 13 Nov 2016 13:41:04 +0300 Subject: [PATCH 074/151] Don't auto-decode forwarded payload --- include/xmpp_codec.hrl | 2 +- specs/xmpp_codec.spec | 2 +- src/mod_carboncopy.erl | 2 +- src/mod_delegation.erl | 20 +++++++++--------- src/mod_mam.erl | 2 +- src/mod_privilege.erl | 34 +++++++++++++++++++------------ src/xmpp_codec.erl | 46 ++++++++++++++++-------------------------- src/xmpp_util.erl | 24 +++++++++++++--------- 8 files changed, 67 insertions(+), 65 deletions(-) diff --git a/include/xmpp_codec.hrl b/include/xmpp_codec.hrl index 981f7f4c2..03421d98d 100644 --- a/include/xmpp_codec.hrl +++ b/include/xmpp_codec.hrl @@ -181,7 +181,7 @@ -type starttls_proceed() :: #starttls_proceed{}. -record(forwarded, {delay :: #delay{}, - sub_els = [] :: [xmpp_element() | fxml:xmlel()]}). + xml_els = [] :: [fxml:xmlel()]}). -type forwarded() :: #forwarded{}. -record(privilege, {perms = [] :: [#privilege_perm{}], diff --git a/specs/xmpp_codec.spec b/specs/xmpp_codec.spec index bcab7a6e5..0aa124ec8 100644 --- a/specs/xmpp_codec.spec +++ b/specs/xmpp_codec.spec @@ -2679,7 +2679,7 @@ -xml(forwarded, #elem{name = <<"forwarded">>, xmlns = <<"urn:xmpp:forward:0">>, - result = {forwarded, '$delay', '$_els'}, + result = {forwarded, '$delay', '$_xmls'}, refs = [#ref{name = delay, min = 0, max = 1, label = '$delay'}]}). diff --git a/src/mod_carboncopy.erl b/src/mod_carboncopy.erl index 023e8dc6f..7d8ca5332 100644 --- a/src/mod_carboncopy.erl +++ b/src/mod_carboncopy.erl @@ -198,7 +198,7 @@ send_copies(JID, To, Packet, Direction)-> -spec build_forward_packet(jid(), message(), jid(), jid(), direction()) -> message(). build_forward_packet(JID, #message{type = T} = Msg, Sender, Dest, Direction) -> - Forwarded = #forwarded{sub_els = [complete_packet(JID, Msg, Direction)]}, + Forwarded = #forwarded{xml_els = [xmpp:encode(complete_packet(JID, Msg, Direction))]}, Carbon = case Direction of sent -> #carbons_sent{forwarded = Forwarded}; received -> #carbons_received{forwarded = Forwarded} diff --git a/src/mod_delegation.erl b/src/mod_delegation.erl index 7fec01dcb..ad57bad44 100644 --- a/src/mod_delegation.erl +++ b/src/mod_delegation.erl @@ -217,7 +217,8 @@ process_iq(#iq{to = To, lang = Lang, sub_els = [SubEl]} = IQ, Type) -> Delegations = get_delegations(LServer), case dict:find({NS, Type}, Delegations) of {ok, {Host, _}} -> - Delegation = #delegation{forwarded = #forwarded{sub_els = [IQ]}}, + Delegation = #delegation{ + forwarded = #forwarded{xml_els = [xmpp:encode(IQ)]}}, NewFrom = jid:make(LServer), NewTo = jid:make(Host), ejabberd_local:route_iq( @@ -236,14 +237,15 @@ process_iq(#iq{to = To, lang = Lang, sub_els = [SubEl]} = IQ, Type) -> -spec process_iq_result(iq(), iq()) -> ok. process_iq_result(#iq{from = From, to = To, id = ID, lang = Lang} = IQ, #iq{type = result} = ResIQ) -> - case xmpp:get_subtag(ResIQ, #delegation{}) of - #delegation{ - forwarded = #forwarded{ - sub_els = [#iq{from = To, to = From, - type = Type, id = ID} = Reply]}} - when Type == error; Type == result -> - ejabberd_router:route(From, To, Reply); - _ -> + try + #delegation{forwarded = #forwarded{xml_els = [SubEl]}} = + xmpp:get_subtag(ResIQ, #delegation{}), + case xmpp:decode(SubEl, ?NS_CLIENT, [ignore_els]) of + #iq{from = To, to = From, type = Type, id = ID} = Reply + when Type == error; Type == result -> + ejabberd_router:route(From, To, Reply) + end + catch _:_ -> ?ERROR_MSG("got iq-result with invalid delegated " "payload:~n~s", [xmpp:pp(ResIQ)]), Txt = <<"External component failure">>, diff --git a/src/mod_mam.erl b/src/mod_mam.erl index 8c5422f07..f9ef104bd 100644 --- a/src/mod_mam.erl +++ b/src/mod_mam.erl @@ -794,7 +794,7 @@ msg_to_el(#archive_msg{timestamp = TS, packet = Pkt1, nick = Nick, peer = Peer}, MsgType, JidRequestor, #jid{lserver = LServer} = JidArchive) -> Pkt2 = maybe_update_from_to(Pkt1, JidRequestor, JidArchive, Peer, MsgType, Nick), - #forwarded{sub_els = [Pkt2], + #forwarded{xml_els = [xmpp:encode(Pkt2)], delay = #delay{stamp = TS, from = jid:make(LServer)}}. maybe_update_from_to(#xmlel{} = El, JidRequestor, JidArchive, Peer, diff --git a/src/mod_privilege.erl b/src/mod_privilege.erl index 50212b7ae..936c237bd 100644 --- a/src/mod_privilege.erl +++ b/src/mod_privilege.erl @@ -257,25 +257,33 @@ get_permissions(ServerHost) -> end. forward_message(From, To, Msg) -> - Host = From#jid.lserver, ServerHost = To#jid.lserver, + Lang = xmpp:get_lang(Msg), case xmpp:get_subtag(Msg, #privilege{}) of - #privilege{forwarded = #forwarded{sub_els = [#message{} = SubEl]}} -> - case SubEl#message.from of - #jid{lresource = <<"">>, lserver = ServerHost} -> - ejabberd_router:route( - xmpp:get_from(SubEl), xmpp:get_to(SubEl), SubEl); + #privilege{forwarded = #forwarded{xml_els = [SubEl]}} -> + try xmpp:decode(SubEl, ?NS_CLIENT, [ignore_els]) of + #message{} = NewMsg -> + case NewMsg#message.from of + #jid{lresource = <<"">>, lserver = ServerHost} -> + ejabberd_router:route( + xmpp:get_from(NewMsg), xmpp:get_to(NewMsg), NewMsg); + _ -> + Lang = xmpp:get_lang(Msg), + Txt = <<"Invalid 'from' attribute in forwarded message">>, + Err = xmpp:err_forbidden(Txt, Lang), + ejabberd_router:route_error(To, From, Msg, Err) + end; _ -> - Lang = xmpp:get_lang(Msg), - Txt = <<"Invalid 'from' attribute">>, - Err = xmpp:err_forbidden(Txt, Lang), + Txt = <<"Message not found in forwarded payload">>, + Err = xmpp:err_bad_request(Txt, Lang), + ejabberd_router:route_error(To, From, Msg, Err) + catch _:{xmpp_codec, Why} -> + Txt = xmpp:format_error(Why), + Err = xmpp:err_bad_request(Txt, Lang), ejabberd_router:route_error(To, From, Msg, Err) end; _ -> - ?ERROR_MSG("got invalid forwarded payload from external " - "component '~s':~n~s", [Host, xmpp:pp(Msg)]), - Lang = xmpp:get_lang(Msg), - Txt = <<"Invalid forwarded payload">>, + Txt = <<"Invalid element">>, Err = xmpp:err_bad_request(Txt, Lang), ejabberd_router:route_error(To, From, Msg, Err) end. diff --git a/src/xmpp_codec.erl b/src/xmpp_codec.erl index 2931baaa4..6089f79fc 100644 --- a/src/xmpp_codec.erl +++ b/src/xmpp_codec.erl @@ -6639,7 +6639,7 @@ pp(mam_archived, 2) -> [by, id]; pp(mam_result, 4) -> [xmlns, queryid, id, sub_els]; pp(mam_prefs, 4) -> [xmlns, default, always, never]; pp(mam_fin, 5) -> [xmlns, id, rsm, stable, complete]; -pp(forwarded, 2) -> [delay, sub_els]; +pp(forwarded, 2) -> [delay, xml_els]; pp(carbons_disable, 0) -> []; pp(carbons_enable, 0) -> []; pp(carbons_private, 0) -> []; @@ -11966,53 +11966,41 @@ encode_carbons_disable({carbons_disable}, __TopXMLNS) -> decode_forwarded(__TopXMLNS, __IgnoreEls, {xmlel, <<"forwarded">>, _attrs, _els}) -> - {Delay, __Els} = decode_forwarded_els(__TopXMLNS, - __IgnoreEls, _els, undefined, []), - {forwarded, Delay, __Els}. + {Delay, __Xmls} = decode_forwarded_els(__TopXMLNS, + __IgnoreEls, _els, undefined, []), + {forwarded, Delay, __Xmls}. decode_forwarded_els(__TopXMLNS, __IgnoreEls, [], Delay, - __Els) -> - {Delay, lists:reverse(__Els)}; + __Xmls) -> + {Delay, lists:reverse(__Xmls)}; decode_forwarded_els(__TopXMLNS, __IgnoreEls, [{xmlel, <<"delay">>, _attrs, _} = _el | _els], Delay, - __Els) -> + __Xmls) -> case get_attr(<<"xmlns">>, _attrs) of <<"urn:xmpp:delay">> -> decode_forwarded_els(__TopXMLNS, __IgnoreEls, _els, decode_delay(<<"urn:xmpp:delay">>, __IgnoreEls, _el), - __Els); + __Xmls); _ -> decode_forwarded_els(__TopXMLNS, __IgnoreEls, _els, - Delay, __Els) + Delay, __Xmls) end; decode_forwarded_els(__TopXMLNS, __IgnoreEls, - [{xmlel, _, _, _} = _el | _els], Delay, __Els) -> - if __IgnoreEls -> - decode_forwarded_els(__TopXMLNS, __IgnoreEls, _els, - Delay, [_el | __Els]); - true -> - case is_known_tag(_el, __TopXMLNS) of - true -> - decode_forwarded_els(__TopXMLNS, __IgnoreEls, _els, - Delay, - [decode(_el, __TopXMLNS, []) | __Els]); - false -> - decode_forwarded_els(__TopXMLNS, __IgnoreEls, _els, - Delay, __Els) - end - end; -decode_forwarded_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Delay, __Els) -> + [{xmlel, _, _, _} = _el | _els], Delay, __Xmls) -> decode_forwarded_els(__TopXMLNS, __IgnoreEls, _els, - Delay, __Els). + Delay, [_el | __Xmls]); +decode_forwarded_els(__TopXMLNS, __IgnoreEls, + [_ | _els], Delay, __Xmls) -> + decode_forwarded_els(__TopXMLNS, __IgnoreEls, _els, + Delay, __Xmls). -encode_forwarded({forwarded, Delay, __Els}, +encode_forwarded({forwarded, Delay, __Xmls}, __TopXMLNS) -> __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:forward:0">>, [], __TopXMLNS), - _els = [encode(_el, __NewTopXMLNS) || _el <- __Els] ++ + _els = __Xmls ++ lists:reverse('encode_forwarded_$delay'(Delay, __NewTopXMLNS, [])), _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), diff --git a/src/xmpp_util.erl b/src/xmpp_util.erl index a07dae78b..57440b50e 100644 --- a/src/xmpp_util.erl +++ b/src/xmpp_util.erl @@ -42,16 +42,20 @@ add_delay_info(Stz, From, Time, Desc) -> -spec unwrap_carbon(stanza()) -> xmpp_element(). unwrap_carbon(#message{} = Msg) -> - case xmpp:get_subtag(Msg, #carbons_sent{}) of - #carbons_sent{forwarded = #forwarded{sub_els = [El]}} -> - El; - _ -> - case xmpp:get_subtag(Msg, #carbons_received{}) of - #carbons_received{forwarded = #forwarded{sub_els = [El]}} -> - El; - _ -> - Msg - end + try + case xmpp:get_subtag(Msg, #carbons_sent{}) of + #carbons_sent{forwarded = #forwarded{xml_els = [El]}} -> + xmpp:decode(El, ?NS_CLIENT, [ignore_els]); + _ -> + case xmpp:get_subtag(Msg, #carbons_received{}) of + #carbons_received{forwarded = #forwarded{xml_els = [El]}} -> + xmpp:decode(El, ?NS_CLIENT, [ignore_els]); + _ -> + Msg + end + end + catch _:{xmpp_codec, _} -> + Msg end; unwrap_carbon(Stanza) -> Stanza. From ebefd0d8d6bd0162f0067f85e565afde83a962ca Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sun, 13 Nov 2016 14:17:21 +0300 Subject: [PATCH 075/151] Add more control for decoding IQ payloads --- src/ejabberd_local.erl | 8 +------- src/gen_iq_handler.erl | 8 +++----- src/mod_delegation.erl | 8 +++++++- src/mod_vcard.erl | 10 +++++++++- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index 210575e5e..d7849396b 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -96,13 +96,7 @@ process_iq(From, To, #iq{type = T} = Packet) when T == get; T == set -> Err = xmpp:make_error(Packet, xmpp:err_bad_request()), ejabberd_router:route(To, From, Err); process_iq(From, To, #iq{type = T} = Packet) when T == result; T == error -> - try - NewPacket = xmpp:decode_els(Packet), - process_iq_reply(From, To, NewPacket) - catch _:{xmpp_codec, Why} -> - ?DEBUG("failed to decode iq-result ~p: ~s", - [Packet, xmpp:format_error(Why)]) - end. + process_iq_reply(From, To, Packet). -spec process_iq_reply(jid(), jid(), iq()) -> any(). process_iq_reply(From, To, #iq{id = ID} = IQ) -> diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl index 8af2cb028..bcbda1d1e 100644 --- a/src/gen_iq_handler.erl +++ b/src/gen_iq_handler.erl @@ -153,11 +153,9 @@ process_iq(_Host, Module, Function, From, To, IQ0) -> -spec process_iq(module(), atom(), iq()) -> ignore | iq(). process_iq(Module, Function, #iq{lang = Lang, sub_els = [El]} = IQ) -> try - %% TODO: move this 'conditional' decoding somewhere - %% IQ handler should know *nothing* about vCards. - Pkt = case xmpp:get_ns(El) of - ?NS_VCARD when Module == mod_vcard -> El; - _ -> xmpp:decode(El) + Pkt = case erlang:function_exported(Module, decode_iq_subel, 1) of + true -> Module:decode_iq_subel(El); + false -> xmpp:decode(El) end, Module:Function(IQ#iq{sub_els = [Pkt]}) catch error:{xmpp_codec, Why} -> diff --git a/src/mod_delegation.erl b/src/mod_delegation.erl index ad57bad44..56908d9d1 100644 --- a/src/mod_delegation.erl +++ b/src/mod_delegation.erl @@ -18,7 +18,7 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -export([component_connected/1, component_disconnected/2, - ejabberd_local/1, ejabberd_sm/1, + ejabberd_local/1, ejabberd_sm/1, decode_iq_subel/1, disco_local_features/5, disco_sm_features/5, disco_local_identity/5, disco_sm_identity/5]). @@ -56,6 +56,12 @@ mod_opt_type(_) -> depends(_, _) -> []. +-spec decode_iq_subel(xmpp_element()) -> xmpp_element(); + (xmlel()) -> xmlel(). +%% Tell gen_iq_handler not to auto-decode IQ payload +decode_iq_subel(El) -> + El. + -spec component_connected(binary()) -> ok. component_connected(Host) -> lists:foreach( diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index 8333d32cf..35b907f95 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -37,7 +37,7 @@ remove_user/2, export/1, import/1, import/3, depends/2, process_search/1, process_vcard/1, get_vcard/2, disco_items/5, disco_features/5, disco_identity/5, - mod_opt_type/1, set_vcard/3, make_vcard_search/4]). + decode_iq_subel/1, mod_opt_type/1, set_vcard/3, make_vcard_search/4]). -include("ejabberd.hrl"). -include("logger.hrl"). @@ -167,6 +167,14 @@ get_sm_features(Acc, _From, _To, Node, _Lang) -> _ -> Acc end. +-spec decode_iq_subel(xmpp_element() | xmlel()) -> xmpp_element() | xmlel(). +%% Tell gen_iq_handler not to decode vcard elements +decode_iq_subel(El) -> + case xmpp:get_ns(El) of + ?NS_VCARD -> xmpp:encode(El); + _ -> xmpp:decode(El) + end. + -spec process_local_iq(iq()) -> iq(). process_local_iq(#iq{type = set, lang = Lang} = IQ) -> Txt = <<"Value 'set' of 'type' attribute is not allowed">>, From 75c15d3853cf787a07bd6907bd4418c7d2d0dda4 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sun, 13 Nov 2016 14:29:52 +0300 Subject: [PATCH 076/151] Make xref working again if elixir is disabled --- rebar.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rebar.config b/rebar.config index 27439109b..3ad5cf6e7 100644 --- a/rebar.config +++ b/rebar.config @@ -109,7 +109,7 @@ {if_var_false, iconv, "(\"iconv\":_/_)"}, {if_var_false, odbc, "(\"odbc\":_/_)"}, {if_var_false, sqlite, "(\"sqlite3\":_/_)"}, - {if_var_false, elixir, "(\"Elixir.Logger.*\":_/_)"}, + {if_var_false, elixir, "(\"Elixir.*\":_/_)"}, {if_var_false, redis, "(\"eredis\":_/_)"}]}. {eunit_compile_opts, [{i, "tools"}]}. From 13d5da4da6f02b9fc6816083a5b1f615ad45e023 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sun, 13 Nov 2016 16:46:04 +0300 Subject: [PATCH 077/151] Add some copyright notices --- src/mod_delegation.erl | 29 ++++++++++++++++++++++++----- src/mod_privilege.erl | 29 ++++++++++++++++++++++++----- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/src/mod_delegation.erl b/src/mod_delegation.erl index 56908d9d1..5f9fafc45 100644 --- a/src/mod_delegation.erl +++ b/src/mod_delegation.erl @@ -1,13 +1,32 @@ %%%------------------------------------------------------------------- -%%% @author Evgeny Khramtsov -%%% @copyright (C) 2016, Evgeny Khramtsov -%%% @doc +%%% File : mod_delegation.erl +%%% Author : Anna Mukharram +%%% Purpose : XEP-0355: Namespace Delegation +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2016 ProcessOne +%%% +%%% This program is free software; you can redistribute it and/or +%%% modify it under the terms of the GNU General Public License as +%%% published by the Free Software Foundation; either version 2 of the +%%% License, or (at your option) any later version. +%%% +%%% This program is distributed in the hope that it will be useful, +%%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%%% General Public License for more details. +%%% +%%% You should have received a copy of the GNU General Public License along +%%% with this program; if not, write to the Free Software Foundation, Inc., +%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. %%% -%%% @end -%%% Created : 10 Nov 2016 by Evgeny Khramtsov %%%------------------------------------------------------------------- -module(mod_delegation). +-author('amuhar3@gmail.com'). + +-protocol({xep, 0355, '0.3'}). + -behaviour(gen_server). -behaviour(gen_mod). diff --git a/src/mod_privilege.erl b/src/mod_privilege.erl index 936c237bd..c1ac5a3fc 100644 --- a/src/mod_privilege.erl +++ b/src/mod_privilege.erl @@ -1,13 +1,32 @@ %%%------------------------------------------------------------------- -%%% @author Evgeny Khramtsov -%%% @copyright (C) 2016, Evgeny Khramtsov -%%% @doc +%%% File : mod_privilege.erl +%%% Author : Anna Mukharram +%%% Purpose : XEP-0356: Privileged Entity +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2016 ProcessOne +%%% +%%% This program is free software; you can redistribute it and/or +%%% modify it under the terms of the GNU General Public License as +%%% published by the Free Software Foundation; either version 2 of the +%%% License, or (at your option) any later version. +%%% +%%% This program is distributed in the hope that it will be useful, +%%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%%% General Public License for more details. +%%% +%%% You should have received a copy of the GNU General Public License along +%%% with this program; if not, write to the Free Software Foundation, Inc., +%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. %%% -%%% @end -%%% Created : 11 Nov 2016 by Evgeny Khramtsov %%%------------------------------------------------------------------- -module(mod_privilege). +-author('amuhar3@gmail.com'). + +-protocol({xep, 0356, '0.2.1'}). + -behaviour(gen_server). -behaviour(gen_mod). From 3765210698dd55d9996e671bb9874c48f12f37e0 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sun, 13 Nov 2016 16:56:05 +0300 Subject: [PATCH 078/151] Fix IQ result processing --- src/mod_delegation.erl | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/mod_delegation.erl b/src/mod_delegation.erl index 5f9fafc45..571817963 100644 --- a/src/mod_delegation.erl +++ b/src/mod_delegation.erl @@ -268,7 +268,7 @@ process_iq_result(#iq{from = From, to = To, id = ID, lang = Lang} = IQ, case xmpp:decode(SubEl, ?NS_CLIENT, [ignore_els]) of #iq{from = To, to = From, type = Type, id = ID} = Reply when Type == error; Type == result -> - ejabberd_router:route(From, To, Reply) + ejabberd_router:route(To, From, Reply) end catch _:_ -> ?ERROR_MSG("got iq-result with invalid delegated " @@ -294,9 +294,17 @@ send_disco_queries(LServer, Host, NS) -> ejabberd_local:route_iq( From, To, #iq{type = get, from = From, to = To, sub_els = [#disco_info{node = Node}]}, - fun(#iq{type = result, sub_els = [#disco_info{} = Info]}) -> - Proc = gen_mod:get_module_proc(LServer, ?MODULE), - gen_server:cast(Proc, {disco_info, Type, Host, NS, Info}); + fun(#iq{type = result, sub_els = [SubEl]}) -> + try xmpp:decode(SubEl) of + #disco_info{} = Info-> + Proc = gen_mod:get_module_proc(LServer, ?MODULE), + gen_server:cast( + Proc, {disco_info, Type, Host, NS, Info}); + _ -> + ok + catch _:{xmpp_codec, _} -> + ok + end; (_) -> ok end) From 309962fb8b70dc42dbfcc98b4e64bd251aad84b9 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Mon, 14 Nov 2016 16:52:03 +0100 Subject: [PATCH 079/151] Use p1_http from p1_utils 1.0.6 --- rebar.config | 2 +- src/ejabberd_app.erl | 1 - src/ext_mod.erl | 4 +- src/http_p1.erl | 358 --------------------------------------- src/mod_ip_blacklist.erl | 4 +- src/rest.erl | 6 +- 6 files changed, 8 insertions(+), 367 deletions(-) delete mode 100644 src/http_p1.erl diff --git a/rebar.config b/rebar.config index 3ad5cf6e7..06ca9ab10 100644 --- a/rebar.config +++ b/rebar.config @@ -8,7 +8,7 @@ %%%------------------------------------------------------------------- {deps, [{lager, ".*", {git, "https://github.com/basho/lager", {tag, "3.2.1"}}}, - {p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.5"}}}, + {p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.6"}}}, {cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.4"}}}, {fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.7"}}}, {stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.6"}}}, diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl index e88f24e1e..1791aa790 100644 --- a/src/ejabberd_app.erl +++ b/src/ejabberd_app.erl @@ -225,7 +225,6 @@ start_apps() -> ejabberd:start_app(fast_tls), ejabberd:start_app(fast_xml), ejabberd:start_app(stringprep), - http_p1:start(), ejabberd:start_app(cache_tab). opt_type(net_ticktime) -> diff --git a/src/ext_mod.erl b/src/ext_mod.erl index 842bb09fc..2f71343a2 100644 --- a/src/ext_mod.erl +++ b/src/ext_mod.erl @@ -45,7 +45,7 @@ start() -> [code:add_patha(module_ebin_dir(Module)) || {Module, _} <- installed()], - application:start(inets), + p1_http:start(), ejabberd_commands:register_commands(get_commands_spec()). stop() -> @@ -271,7 +271,7 @@ geturl(Url, Hdrs, UsrOpts) -> [U, Pass] -> [{proxy_user, U}, {proxy_password, Pass}]; _ -> [] end, - case httpc:request(get, {Url, Hdrs}, Host++User++UsrOpts++[{version, "HTTP/1.0"}], []) of + case p1_http:request(get, Url, Hdrs, [], Host++User++UsrOpts++[{version, "HTTP/1.0"}]) of {ok, {{_, 200, _}, Headers, Response}} -> {ok, Headers, Response}; {ok, {{_, Code, _}, _Headers, Response}} -> diff --git a/src/http_p1.erl b/src/http_p1.erl deleted file mode 100644 index f430bbe11..000000000 --- a/src/http_p1.erl +++ /dev/null @@ -1,358 +0,0 @@ -%%%---------------------------------------------------------------------- -%%% File : http_p1.erl -%%% Author : Emilio Bustos -%%% Purpose : Provide a common API for inets / lhttpc / ibrowse -%%% Created : 29 Jul 2010 by Emilio Bustos -%%% -%%% -%%% ejabberd, Copyright (C) 2002-2016 ProcessOne -%%% -%%% This program is free software; you can redistribute it and/or -%%% modify it under the terms of the GNU General Public License as -%%% published by the Free Software Foundation; either version 2 of the -%%% License, or (at your option) any later version. -%%% -%%% This program is distributed in the hope that it will be useful, -%%% but WITHOUT ANY WARRANTY; without even the implied warranty of -%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -%%% General Public License for more details. -%%% -%%% You should have received a copy of the GNU General Public License along -%%% with this program; if not, write to the Free Software Foundation, Inc., -%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -%%% -%%%---------------------------------------------------------------------- - --module(http_p1). - --author('ebustos@process-one.net'). - --export([start/0, stop/0, get/1, get/2, post/2, post/3, - request/3, request/4, request/5, - get_pool_size/0, set_pool_size/1]). - --include("logger.hrl"). - --define(USE_INETS, 1). -% -define(USE_LHTTPC, 1). -% -define(USE_IBROWSE, 1). -% inets used as default if none specified - --ifdef(USE_IBROWSE). - -start() -> - ejabberd:start_app(ibrowse). - -stop() -> - application:stop(ibrowse). - -request(Method, URL, Hdrs, Body, Opts) -> - TimeOut = proplists:get_value(timeout, Opts, infinity), - Options = [{inactivity_timeout, TimeOut} - | proplists:delete(timeout, Opts)], - case ibrowse:send_req(URL, Hdrs, Method, Body, Options) - of - {ok, Status, Headers, Response} -> - {ok, jlib:binary_to_integer(Status), Headers, - Response}; - {error, Reason} -> {error, Reason} - end. - -get_pool_size() -> - application:get_env(ibrowse, default_max_sessions, 10). - -set_pool_size(Size) -> - application:set_env(ibrowse, default_max_sessions, Size). - --else. - --ifdef(USE_LHTTPC). - -start() -> - ejabberd:start_app(lhttpc). - -stop() -> - application:stop(lhttpc). - -request(Method, URL, Hdrs, Body, Opts) -> - {[TO, SO], Rest} = proplists:split(Opts, [timeout, socket_options]), - TimeOut = proplists:get_value(timeout, TO, infinity), - SockOpt = proplists:get_value(socket_options, SO, []), - Options = [{connect_options, SockOpt} | Rest], - Result = lhttpc:request(URL, Method, Hdrs, Body, TimeOut, Options), - ?DEBUG("HTTP request -> response:~n" - "** Method = ~p~n" - "** URI = ~s~n" - "** Body = ~s~n" - "** Hdrs = ~p~n" - "** Timeout = ~p~n" - "** Options = ~p~n" - "** Response = ~p", - [Method, URL, Body, Hdrs, TimeOut, Options, Result]), - case Result of - {ok, {{Status, _Reason}, Headers, Response}} -> - {ok, Status, Headers, (Response)}; - {error, Reason} -> {error, Reason} - end. - -get_pool_size() -> - Opts = proplists:get_value(lhttpc_manager, lhttpc_manager:list_pools()), - proplists:get_value(max_pool_size,Opts). - -set_pool_size(Size) -> - lhttpc_manager:set_max_pool_size(lhttpc_manager, Size). - --else. - -start() -> - ejabberd:start_app(inets). - -stop() -> - application:stop(inets). - -to_list(Str) when is_binary(Str) -> - binary_to_list(Str); -to_list(Str) -> - Str. - -request(Method, URLRaw, HdrsRaw, Body, Opts) -> - Hdrs = lists:map(fun({N, V}) -> - {to_list(N), to_list(V)} - end, HdrsRaw), - URL = to_list(URLRaw), - - Request = case Method of - get -> {URL, Hdrs}; - head -> {URL, Hdrs}; - delete -> {URL, Hdrs}; - _ -> % post, etc. - {URL, Hdrs, - to_list(proplists:get_value(<<"content-type">>, HdrsRaw, [])), - Body} - end, - Options = case proplists:get_value(timeout, Opts, - infinity) - of - infinity -> proplists:delete(timeout, Opts); - _ -> Opts - end, - case httpc:request(Method, Request, Options, []) of - {ok, {{_, Status, _}, Headers, Response}} -> - {ok, Status, Headers, Response}; - {error, Reason} -> {error, Reason} - end. - -get_pool_size() -> - {ok, Size} = httpc:get_option(max_sessions), - Size. - -set_pool_size(Size) -> - httpc:set_option(max_sessions, Size). - --endif. - --endif. - --type({header, - {type, 63, tuple, - [{type, 63, union, - [{type, 63, string, []}, {type, 63, atom, []}]}, - {type, 63, string, []}]}, - []}). - --type({headers, - {type, 64, list, [{type, 64, header, []}]}, []}). - --type({option, - {type, 67, union, - [{type, 67, tuple, - [{atom, 67, connect_timeout}, {type, 67, timeout, []}]}, - {type, 68, tuple, - [{atom, 68, timeout}, {type, 68, timeout, []}]}, - {type, 70, tuple, - [{atom, 70, send_retry}, - {type, 70, non_neg_integer, []}]}, - {type, 71, tuple, - [{atom, 71, partial_upload}, - {type, 71, union, - [{type, 71, non_neg_integer, []}, - {atom, 71, infinity}]}]}, - {type, 72, tuple, - [{atom, 72, partial_download}, {type, 72, pid, []}, - {type, 72, union, - [{type, 72, non_neg_integer, []}, - {atom, 72, infinity}]}]}]}, - []}). - --type({options, - {type, 74, list, [{type, 74, option, []}]}, []}). - --type({result, - {type, 76, union, - [{type, 76, tuple, - [{atom, 76, ok}, - {type, 76, tuple, - [{type, 76, tuple, - [{type, 76, pos_integer, []}, {type, 76, string, []}]}, - {type, 76, headers, []}, {type, 76, string, []}]}]}, - {type, 77, tuple, - [{atom, 77, error}, {type, 77, atom, []}]}]}, - []}). - -%% @spec (URL) -> Result -%% URL = string() -%% Result = {ok, StatusCode, Hdrs, ResponseBody} -%% | {error, Reason} -%% StatusCode = integer() -%% ResponseBody = string() -%% Reason = connection_closed | connect_timeout | timeout -%% @doc Sends a GET request. -%% Would be the same as calling `request(get, URL, [])', -%% that is {@link request/3} with an empty header list. -%% @end -%% @see request/3 --spec get(string()) -> result(). -get(URL) -> request(get, URL, []). - -%% @spec (URL, Hdrs) -> Result -%% URL = string() -%% Hdrs = [{Header, Value}] -%% Header = string() -%% Value = string() -%% Result = {ok, StatusCode, Hdrs, ResponseBody} -%% | {error, Reason} -%% StatusCode = integer() -%% ResponseBody = string() -%% Reason = connection_closed | connect_timeout | timeout -%% @doc Sends a GET request. -%% Would be the same as calling `request(get, URL, Hdrs)'. -%% @end -%% @see request/3 --spec get(string(), headers()) -> result(). -get(URL, Hdrs) -> request(get, URL, Hdrs). - -%% @spec (URL, RequestBody) -> Result -%% URL = string() -%% RequestBody = string() -%% Result = {ok, StatusCode, Hdrs, ResponseBody} -%% | {error, Reason} -%% StatusCode = integer() -%% ResponseBody = string() -%% Reason = connection_closed | connect_timeout | timeout -%% @doc Sends a POST request with form data. -%% Would be the same as calling -%% `request(post, URL, [{"content-type", "x-www-form-urlencoded"}], Body)'. -%% @end -%% @see request/4 --spec post(string(), string()) -> result(). -post(URL, Body) -> - request(post, URL, - [{<<"content-type">>, <<"x-www-form-urlencoded">>}], - Body). - -%% @spec (URL, Hdrs, RequestBody) -> Result -%% URL = string() -%% Hdrs = [{Header, Value}] -%% Header = string() -%% Value = string() -%% RequestBody = string() -%% Result = {ok, StatusCode, Hdrs, ResponseBody} -%% | {error, Reason} -%% StatusCode = integer() -%% ResponseBody = string() -%% Reason = connection_closed | connect_timeout | timeout -%% @doc Sends a POST request. -%% Would be the same as calling -%% `request(post, URL, Hdrs, Body)'. -%% @end -%% @see request/4 --spec post(string(), headers(), string()) -> result(). -post(URL, Hdrs, Body) -> - NewHdrs = case [X - || {X, _} <- Hdrs, - str:to_lower(X) == <<"content-type">>] - of - [] -> - [{<<"content-type">>, <<"x-www-form-urlencoded">>} - | Hdrs]; - _ -> Hdrs - end, - request(post, URL, NewHdrs, Body). - -%% @spec (Method, URL, Hdrs) -> Result -%% Method = atom() -%% URL = string() -%% Hdrs = [{Header, Value}] -%% Header = string() -%% Value = string() -%% Result = {ok, StatusCode, Hdrs, ResponseBody} -%% | {error, Reason} -%% StatusCode = integer() -%% ResponseBody = string() -%% Reason = connection_closed | connect_timeout | timeout -%% @doc Sends a request without a body. -%% Would be the same as calling `request(Method, URL, Hdrs, [], [])', -%% that is {@link request/5} with an empty body. -%% @end -%% @see request/5 --spec request(atom(), string(), headers()) -> result(). -request(Method, URL, Hdrs) -> - request(Method, URL, Hdrs, [], []). - -%% @spec (Method, URL, Hdrs, RequestBody) -> Result -%% Method = atom() -%% URL = string() -%% Hdrs = [{Header, Value}] -%% Header = string() -%% Value = string() -%% RequestBody = string() -%% Result = {ok, StatusCode, Hdrs, ResponseBody} -%% | {error, Reason} -%% StatusCode = integer() -%% ResponseBody = string() -%% Reason = connection_closed | connect_timeout | timeout -%% @doc Sends a request with a body. -%% Would be the same as calling -%% `request(Method, URL, Hdrs, Body, [])', that is {@link request/5} -%% with no options. -%% @end -%% @see request/5 --spec request(atom(), string(), headers(), string()) -> result(). -request(Method, URL, Hdrs, Body) -> - request(Method, URL, Hdrs, Body, []). - -%% @spec (Method, URL, Hdrs, RequestBody, Options) -> Result -%% Method = atom() -%% URL = string() -%% Hdrs = [{Header, Value}] -%% Header = string() -%% Value = string() -%% RequestBody = string() -%% Options = [Option] -%% Option = {timeout, Milliseconds | infinity} | -%% {connect_timeout, Milliseconds | infinity} | -%% {socket_options, [term()]} | - -%% Milliseconds = integer() -%% Result = {ok, StatusCode, Hdrs, ResponseBody} -%% | {error, Reason} -%% StatusCode = integer() -%% ResponseBody = string() -%% Reason = connection_closed | connect_timeout | timeout -%% @doc Sends a request with a body. -%% Would be the same as calling -%% `request(Method, URL, Hdrs, Body, [])', that is {@link request/5} -%% with no options. -%% @end -%% @see request/5 --spec request(atom(), string(), headers(), string(), options()) -> result(). - -% ibrowse {response_format, response_format()} | -% Options - [option()] -% Option - {sync, boolean()} | {stream, StreamTo} | {body_format, body_format()} | {full_result, -% boolean()} | {headers_as_is, boolean()} -%body_format() = string() | binary() -% The body_format option is only valid for the synchronous request and the default is string. -% When making an asynchronous request the body will always be received as a binary. -% lhttpc: always binary - diff --git a/src/mod_ip_blacklist.erl b/src/mod_ip_blacklist.erl index 897810927..ab17a8891 100644 --- a/src/mod_ip_blacklist.erl +++ b/src/mod_ip_blacklist.erl @@ -89,9 +89,9 @@ loop(_State) -> receive stop -> ok end. %% TODO: Support comment lines starting by % update_bl_c2s() -> ?INFO_MSG("Updating C2S Blacklist", []), - case httpc:request(?BLC2S) of + case p1_http:get(?BLC2S) of {ok, 200, _Headers, Body} -> - IPs = str:tokens(Body, <<"\n">>), + IPs = str:tokens(iolist_to_binary(Body), <<"\n">>), ets:delete_all_objects(bl_c2s), lists:foreach(fun (IP) -> ets:insert(bl_c2s, diff --git a/src/rest.erl b/src/rest.erl index 01b04f66a..e5c6fd963 100644 --- a/src/rest.erl +++ b/src/rest.erl @@ -36,14 +36,14 @@ -define(CONNECT_TIMEOUT, 8000). start(Host) -> - http_p1:start(), + p1_http:start(), Pool_size = ejabberd_config:get_option({ext_api_http_pool_size, Host}, fun(X) when is_integer(X), X > 0-> X end, 100), - http_p1:set_pool_size(Pool_size). + p1_http:set_pool_size(Pool_size). stop(_Host) -> ok. @@ -91,7 +91,7 @@ request(Server, Method, Path, Params, Mime, Data) -> {"content-type", Mime}, {"User-Agent", "ejabberd"}], Begin = os:timestamp(), - Result = case catch http_p1:request(Method, URI, Hdrs, Data, Opts) of + Result = case catch p1_http:request(Method, URI, Hdrs, Data, Opts) of {ok, Code, _, <<>>} -> {ok, Code, []}; {ok, Code, _, <<" ">>} -> From 717159a98fe925260578aeedd4436eb6ae5df4f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Thu, 10 Nov 2016 11:15:34 +0100 Subject: [PATCH 080/151] Make string args in http_api be list strings --- src/mod_http_api.erl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mod_http_api.erl b/src/mod_http_api.erl index 881587ede..a189777b1 100644 --- a/src/mod_http_api.erl +++ b/src/mod_http_api.erl @@ -273,7 +273,7 @@ handle(Call, Auth, Args, Version) when is_atom(Call), is_list(Args) -> fun ({Key, binary}, Acc) -> [{Key, <<>>}|Acc]; ({Key, string}, Acc) -> - [{Key, <<>>}|Acc]; + [{Key, ""}|Acc]; ({Key, integer}, Acc) -> [{Key, 0}|Acc]; ({Key, {list, _}}, Acc) -> @@ -406,10 +406,10 @@ format_arg(Elements, {list, ElementsDef}) format_arg(Arg, integer) when is_integer(Arg) -> Arg; format_arg(Arg, binary) when is_list(Arg) -> process_unicode_codepoints(Arg); format_arg(Arg, binary) when is_binary(Arg) -> Arg; -format_arg(Arg, string) when is_list(Arg) -> process_unicode_codepoints(Arg); -format_arg(Arg, string) when is_binary(Arg) -> Arg; +format_arg(Arg, string) when is_list(Arg) -> Arg; +format_arg(Arg, string) when is_binary(Arg) -> binary_to_list(Arg); format_arg(undefined, binary) -> <<>>; -format_arg(undefined, string) -> <<>>; +format_arg(undefined, string) -> ""; format_arg(Arg, Format) -> ?ERROR_MSG("don't know how to format Arg ~p for format ~p", [Arg, Format]), throw({invalid_parameter, From 5ffc01db5301fddae639701479f5c19ed2267723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Thu, 10 Nov 2016 11:20:57 +0100 Subject: [PATCH 081/151] Fix types in check_password_hash --- src/mod_admin_extra.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mod_admin_extra.erl b/src/mod_admin_extra.erl index 2967e86a0..053ce8092 100644 --- a/src/mod_admin_extra.erl +++ b/src/mod_admin_extra.erl @@ -176,8 +176,8 @@ get_commands_spec() -> desc = "Check if the password hash is correct", longdesc = "Allowed hash methods: md5, sha.", module = ?MODULE, function = check_password_hash, - args = [{user, binary}, {host, binary}, {passwordhash, string}, - {hashmethod, string}], + args = [{user, binary}, {host, binary}, {passwordhash, binary}, + {hashmethod, binary}], args_example = [<<"peter">>, <<"myserver.com">>, <<"5ebe2294ecd0e0f08eab7690d2a6ee69">>, <<"md5">>], args_desc = ["User name to check", "Server to check", From 41794c57d67ab1dee63e8b67acb7b3ede5a26b92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Tue, 15 Nov 2016 09:59:04 +0100 Subject: [PATCH 082/151] Use new version of fast_xml --- rebar.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rebar.config b/rebar.config index 06ca9ab10..fca8d19e2 100644 --- a/rebar.config +++ b/rebar.config @@ -12,7 +12,7 @@ {cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.4"}}}, {fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.7"}}}, {stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.6"}}}, - {fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.15"}}}, + {fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.16"}}}, {stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.7"}}}, {esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.8"}}}, {fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.6"}}}, From e75dd17e2ccb12338bfeaa9c5ea49e37d015a733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Tue, 15 Nov 2016 09:59:40 +0100 Subject: [PATCH 083/151] Fix tests that use #forwarded --- test/ejabberd_SUITE.erl | 22 +++++++++++----------- test/suite.erl | 15 ++++++++++++++- test/suite.hrl | 3 +++ 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index 121719cdf..3ac12953c 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -2083,7 +2083,7 @@ retrieve_messages_from_room_via_mam(Config, Range) -> xmlns = ?NS_MAM_1, queryid = QID, sub_els = - [#forwarded{ + [#forwarded_decoded{ delay = #delay{}, sub_els = [#message{ from = MyNickJID, @@ -2411,7 +2411,7 @@ carbons_slave(Config) -> #message{from = MyBareJID, to = MyJID, type = chat, sub_els = [#carbons_sent{ - forwarded = #forwarded{ + forwarded = #forwarded_decoded{ sub_els = [#message{from = Peer, to = MyBareJID, @@ -2420,7 +2420,7 @@ carbons_slave(Config) -> #message{from = MyBareJID, to = MyJID, type = chat, sub_els = [#carbons_sent{ - forwarded = #forwarded{ + forwarded = #forwarded_decoded{ sub_els = [#message{from = Peer, to = Peer, @@ -2429,7 +2429,7 @@ carbons_slave(Config) -> #message{from = MyBareJID, to = MyJID, type = chat, sub_els = [#carbons_received{ - forwarded = #forwarded{ + forwarded = #forwarded_decoded{ sub_els = [#message{from = Peer, to = MyBareJID, @@ -2438,7 +2438,7 @@ carbons_slave(Config) -> #message{from = MyBareJID, to = MyJID, type = chat, sub_els = [#carbons_received{ - forwarded = #forwarded{ + forwarded = #forwarded_decoded{ sub_els = [#message{from = Peer, to = Peer, @@ -2560,7 +2560,7 @@ mam_query_all(Config, NS) -> [#mam_result{ queryid = QID, sub_els = - [#forwarded{ + [#forwarded_decoded{ delay = #delay{}, sub_els = [#message{ @@ -2599,7 +2599,7 @@ mam_query_with(Config, JID, NS) -> sub_els = [#mam_result{ sub_els = - [#forwarded{ + [#forwarded_decoded{ delay = #delay{}, sub_els = [#message{ @@ -2640,7 +2640,7 @@ mam_query_rsm(Config, NS) -> [#mam_result{ xmlns = NS, sub_els = - [#forwarded{ + [#forwarded_decoded{ delay = #delay{}, sub_els = [#message{ @@ -2677,7 +2677,7 @@ mam_query_rsm(Config, NS) -> [#mam_result{ xmlns = NS, sub_els = - [#forwarded{ + [#forwarded_decoded{ delay = #delay{}, sub_els = [#message{ @@ -2717,7 +2717,7 @@ mam_query_rsm(Config, NS) -> [#mam_result{ xmlns = NS, sub_els = - [#forwarded{ + [#forwarded_decoded{ delay = #delay{}, sub_els = [#message{ @@ -2773,7 +2773,7 @@ mam_query_rsm(Config, NS) -> [#mam_result{ xmlns = NS, sub_els = - [#forwarded{ + [#forwarded_decoded{ delay = #delay{}, sub_els = [#message{ diff --git a/test/suite.erl b/test/suite.erl index 52c030df1..3c46e8f6b 100644 --- a/test/suite.erl +++ b/test/suite.erl @@ -481,9 +481,22 @@ format_element(El) -> false -> io_lib:format(" ~s~n", El) end. +substitute_forwarded(#mam_result{sub_els = Sub} = El) -> + El#mam_result{sub_els = [substitute_forwarded(SEl) || SEl <- Sub]}; +substitute_forwarded(#carbons_sent{forwarded = Sub} = El) -> + El#carbons_sent{forwarded = [substitute_forwarded(SEl) || SEl <- Sub]}; +substitute_forwarded(#message{sub_els = Sub} = El) -> + El#message{sub_els = [substitute_forwarded(SEl) || SEl <- Sub]}; +substitute_forwarded(#forwarded{delay = Delay, xml_els = Sub}) -> + #forwarded_decoded{delay = Delay, sub_els = [xmpp:decode(SEl) || SEl <- Sub]}; +substitute_forwarded(El) -> + El. + + + decode(El, NS, Opts) -> try - Pkt = xmpp:decode(El, NS, Opts), + Pkt = substitute_forwarded(xmpp:decode(El, NS, Opts)), ct:pal("RECV:~n~s~n~s", [format_element(El), xmpp:pp(Pkt)]), Pkt diff --git a/test/suite.hrl b/test/suite.hrl index 00239f8cf..d9a9c5ab0 100644 --- a/test/suite.hrl +++ b/test/suite.hrl @@ -5,6 +5,9 @@ -include("mod_proxy65.hrl"). -include("xmpp_codec.hrl"). +-record(forwarded_decoded, {delay :: #delay{}, + sub_els = [] :: [fxml:xmlel()]}). + -define(STREAM_TRAILER, <<"">>). -define(PUBSUB(Node), <<(?NS_PUBSUB)/binary, "#", Node>>). From 909e0eb5dd097f077512210a6ed169e9d3d72a61 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 15 Nov 2016 14:18:34 +0100 Subject: [PATCH 084/151] Add configurable weight for commands --- include/ejabberd_commands.hrl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/ejabberd_commands.hrl b/include/ejabberd_commands.hrl index c5c34b743..199be890e 100644 --- a/include/ejabberd_commands.hrl +++ b/include/ejabberd_commands.hrl @@ -46,12 +46,13 @@ %% to command, so that the command can perform additional check. -record(ejabberd_commands, - {name :: atom(), + {name :: atom(), tags = [] :: [atom()] | '_' | '$2', desc = "" :: string() | '_' | '$3', longdesc = "" :: string() | '_', - version = 0 :: integer(), - module :: atom() | '_', + version = 0 :: integer(), + weight = 1 :: integer(), + module :: atom() | '_', function :: atom() | '_', args = [] :: [aterm()] | '_' | '$1' | '$2', policy = restricted :: open | restricted | admin | user, From 2b93de691248629d75e1d2657d09ebd990670924 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Mon, 16 Jun 2014 19:49:08 +0200 Subject: [PATCH 085/151] apply string optimizations --- src/str.erl | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/str.erl b/src/str.erl index 439ae6a7a..43fd51878 100644 --- a/src/str.erl +++ b/src/str.erl @@ -93,7 +93,10 @@ rchr(B, C) -> -spec str(binary(), binary()) -> non_neg_integer(). str(B1, B2) -> - string:str(binary_to_list(B1), binary_to_list(B2)). + case binary:match(B1, B2) of + {R, _Len} -> R+1; + _ -> 0 + end. -spec rstr(binary(), binary()) -> non_neg_integer(). @@ -113,7 +116,7 @@ cspan(B1, B2) -> -spec copies(binary(), non_neg_integer()) -> binary(). copies(B, N) -> - iolist_to_binary(string:copies(binary_to_list(B), N)). + binary:copy(B, N). -spec words(binary()) -> pos_integer(). @@ -201,7 +204,7 @@ join(L, Sep) -> -spec substr(binary(), pos_integer()) -> binary(). substr(B, N) -> - iolist_to_binary(string:substr(binary_to_list(B), N)). + binary_part(B, N-1, byte_size(B)-N+1). -spec chr(binary(), char()) -> non_neg_integer(). @@ -221,7 +224,7 @@ chars(C, N) -> -spec substr(binary(), pos_integer(), non_neg_integer()) -> binary(). substr(B, S, E) -> - iolist_to_binary(string:substr(binary_to_list(B), S, E)). + binary_part(B, S-1, E). -spec strip(binary(), both | left | right, char()) -> binary(). From 8df68266f2e0bf4cb0d1d51ec8a8372affadc8e5 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 9 Aug 2016 10:53:58 +0200 Subject: [PATCH 086/151] Add missing verbs for RESTfull operation --- src/rest.erl | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/rest.erl b/src/rest.erl index e5c6fd963..091002fa5 100644 --- a/src/rest.erl +++ b/src/rest.erl @@ -28,7 +28,7 @@ -behaviour(ejabberd_config). -export([start/1, stop/1, get/2, get/3, post/4, delete/2, - request/6, with_retry/4, opt_type/1]). + put/4, patch/4, request/6, with_retry/4, opt_type/1]). -include("logger.hrl"). @@ -71,18 +71,17 @@ delete(Server, Path) -> request(Server, delete, Path, [], "application/json", <<>>). post(Server, Path, Params, Content) -> - Data = case catch jiffy:encode(Content) of - {'EXIT', Reason} -> - ?ERROR_MSG("HTTP content encodage failed:~n" - "** Content = ~p~n" - "** Err = ~p", - [Content, Reason]), - <<>>; - Encoded -> - Encoded - end, + Data = encode_json(Content), request(Server, post, Path, Params, "application/json", Data). +put(Server, Path, Params, Content) -> + Data = encode_json(Content), + request(Server, put, Path, Params, "application/json", Data). + +patch(Server, Path, Params, Content) -> + Data = encode_json(Content), + request(Server, patch, Path, Params, "application/json", Data). + request(Server, Method, Path, Params, Mime, Data) -> URI = url(Server, Path, Params), Opts = [{connect_timeout, ?CONNECT_TIMEOUT}, @@ -147,6 +146,18 @@ request(Server, Method, Path, Params, Mime, Data) -> %%% HTTP helpers %%%---------------------------------------------------------------------- +encode_json(Content) -> + case catch jiffy:encode(Content) of + {'EXIT', Reason} -> + ?ERROR_MSG("HTTP content encodage failed:~n" + "** Content = ~p~n" + "** Err = ~p", + [Content, Reason]), + <<>>; + Encoded -> + Encoded + end. + base_url(Server, Path) -> Tail = case iolist_to_binary(Path) of <<$/, Ok/binary>> -> Ok; From 4d4ad922a2deaf576bece4389b0ba04cfd1cfe04 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 15 Nov 2016 18:14:21 +0100 Subject: [PATCH 087/151] Cosmetic validator changes --- src/mod_proxy65.erl | 6 ++---- src/mod_register.erl | 9 +++------ 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/mod_proxy65.erl b/src/mod_proxy65.erl index beea35725..2d0d9ae0a 100644 --- a/src/mod_proxy65.erl +++ b/src/mod_proxy65.erl @@ -93,12 +93,10 @@ mod_opt_type(auth_type) -> end; mod_opt_type(recbuf) -> fun (I) when is_integer(I), I > 0 -> I end; -mod_opt_type(shaper) -> - fun (A) when is_atom(A) -> A end; +mod_opt_type(shaper) -> fun acl:shaper_rules_validator/1; mod_opt_type(sndbuf) -> fun (I) when is_integer(I), I > 0 -> I end; -mod_opt_type(access) -> - fun (A) when is_atom(A) -> A end; +mod_opt_type(access) -> fun acl:access_rules_validator/1; mod_opt_type(host) -> fun iolist_to_binary/1; mod_opt_type(hostname) -> fun iolist_to_binary/1; mod_opt_type(ip) -> diff --git a/src/mod_register.erl b/src/mod_register.erl index 44a64539e..dc8ca995c 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -613,14 +613,11 @@ check_ip_access(undefined, _IPAccess) -> check_ip_access(IPAddress, IPAccess) -> acl:match_rule(global, IPAccess, IPAddress). -mod_opt_type(access) -> - fun acl:access_rules_validator/1; -mod_opt_type(access_from) -> - fun (A) when is_atom(A) -> A end; +mod_opt_type(access) -> fun acl:access_rules_validator/1; +mod_opt_type(access_from) -> fun acl:access_rules_validator/1; mod_opt_type(captcha_protected) -> fun (B) when is_boolean(B) -> B end; -mod_opt_type(ip_access) -> - fun acl:access_rules_validator/1; +mod_opt_type(ip_access) -> fun acl:access_rules_validator/1; mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1; mod_opt_type(password_strength) -> fun (N) when is_number(N), N >= 0 -> N end; From 2929f5b5bcd27ef825743e2f9db5b1ea122d1a5c Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 15 Nov 2016 18:35:20 +0100 Subject: [PATCH 088/151] Minor cosmetic changes on pubsub code --- src/mod_pubsub.erl | 7 +++---- src/node_flat.erl | 2 +- src/node_flat_sql.erl | 2 +- src/pubsub_subscription.erl | 4 ++-- src/pubsub_subscription_sql.erl | 4 ++-- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/mod_pubsub.erl b/src/mod_pubsub.erl index a586935b8..a138b1896 100644 --- a/src/mod_pubsub.erl +++ b/src/mod_pubsub.erl @@ -251,7 +251,7 @@ init([ServerHost, Opts]) -> Host = gen_mod:get_opt_host(ServerHost, Opts, <<"pubsub.@HOST@">>), ejabberd_router:register_route(Host, ServerHost), Access = gen_mod:get_opt(access_createnode, Opts, - fun(A) when is_atom(A) -> A end, all), + fun acl:access_rules_validator/1, all), PepOffline = gen_mod:get_opt(ignore_pep_from_offline, Opts, fun(A) when is_boolean(A) -> A end, true), IQDisc = gen_mod:get_opt(iqdisc, Opts, @@ -262,7 +262,7 @@ init([ServerHost, Opts]) -> fun(A) when is_integer(A) andalso A >= 0 -> A end, ?MAXITEMS), MaxSubsNode = gen_mod:get_opt(max_subscriptions_node, Opts, fun(A) when is_integer(A) andalso A >= 0 -> A end, undefined), - pubsub_index:init(Host, ServerHost, Opts), + [pubsub_index:init(Host, ServerHost, Opts) || gen_mod:db_type(ServerHost, ?MODULE)==mnesia], {Plugins, NodeTree, PepMapping} = init_plugins(Host, ServerHost, Opts), DefaultModule = plugin(Host, hd(Plugins)), BaseOptions = DefaultModule:options(), @@ -3899,8 +3899,7 @@ purge_offline(Host, LJID, Node) -> Error end. -mod_opt_type(access_createnode) -> - fun (A) when is_atom(A) -> A end; +mod_opt_type(access_createnode) -> fun acl:access_rules_validator/1; mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; mod_opt_type(host) -> fun iolist_to_binary/1; mod_opt_type(ignore_pep_from_offline) -> diff --git a/src/node_flat.erl b/src/node_flat.erl index 3afa49f22..9c1bc9b98 100644 --- a/src/node_flat.erl +++ b/src/node_flat.erl @@ -50,7 +50,7 @@ path_to_node/1, can_fetch_item/2, is_subscribed/1]). init(_Host, _ServerHost, _Opts) -> - %pubsub_subscription:init(), + %pubsub_subscription:init(Host, ServerHost, Opts), mnesia:create_table(pubsub_state, [{disc_copies, [node()]}, {type, ordered_set}, diff --git a/src/node_flat_sql.erl b/src/node_flat_sql.erl index 5adf1e559..7e5ce788f 100644 --- a/src/node_flat_sql.erl +++ b/src/node_flat_sql.erl @@ -61,7 +61,7 @@ encode_host_like/1]). init(_Host, _ServerHost, _Opts) -> - %%pubsub_subscription_sql:init(), + %%pubsub_subscription_sql:init(Host, ServerHost, Opts), ok. terminate(_Host, _ServerHost) -> diff --git a/src/pubsub_subscription.erl b/src/pubsub_subscription.erl index f2c962257..297c6627c 100644 --- a/src/pubsub_subscription.erl +++ b/src/pubsub_subscription.erl @@ -28,7 +28,7 @@ -author("bjc@kublai.com"). %% API --export([init/0, subscribe_node/3, unsubscribe_node/3, +-export([init/3, subscribe_node/3, unsubscribe_node/3, get_subscription/3, set_subscription/4, make_subid/0, get_options_xform/2, parse_options_xform/1]). @@ -73,7 +73,7 @@ %%==================================================================== %% API %%==================================================================== -init() -> ok = create_table(). +init(_Host, _ServerHost, _Opts) -> ok = create_table(). subscribe_node(JID, NodeId, Options) -> case catch mnesia:sync_dirty(fun add_subscription/3, [JID, NodeId, Options]) diff --git a/src/pubsub_subscription_sql.erl b/src/pubsub_subscription_sql.erl index 922b2a418..bb7b64112 100644 --- a/src/pubsub_subscription_sql.erl +++ b/src/pubsub_subscription_sql.erl @@ -28,7 +28,7 @@ -author("pablo.polvorin@process-one.net"). %% API --export([init/0, subscribe_node/3, unsubscribe_node/3, +-export([init/3, subscribe_node/3, unsubscribe_node/3, get_subscription/3, set_subscription/4, make_subid/0, get_options_xform/2, parse_options_xform/1]). @@ -71,7 +71,7 @@ %% API %%==================================================================== -init() -> ok = create_table(). +init(_Host, _ServerHost, _Opts) -> ok = create_table(). -spec subscribe_node(_JID :: _, _NodeId :: _, Options :: [] | mod_pubsub:subOptions()) -> {result, mod_pubsub:subId()}. From 5a01b5f1fc991044920a84bf97959c2e4c21b7d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20R=C3=B6mhild?= Date: Fri, 11 Nov 2016 00:12:54 +0100 Subject: [PATCH 089/151] add docker support --- .dockerignore | 3 + Dockerfile | 25 + docker/README.md | 360 +++++++++++++++ docker/bootstrap.sh | 75 +++ docker/conf/ejabberd.yml.tpl | 434 ++++++++++++++++++ docker/conf/ejabberdctl.cfg.tpl | 199 ++++++++ docker/lib/base_config.sh | 22 + docker/lib/base_functions.sh | 72 +++ docker/lib/config.sh | 1 + docker/lib/functions.sh | 1 + .../post/10_ejabberd_modules_update_specs.sh | 24 + docker/post/11_ejabberd_install_modules.sh | 144 ++++++ docker/post/20_ejabberd_register_users.sh | 72 +++ docker/post/99_first_start_done.sh | 17 + docker/pre/01_write_certifiates_from_env.sh | 34 ++ docker/pre/02_make_snakeoil_certificates.sh | 75 +++ docker/pre/03_make_dhparam.sh | 22 + docker/pre/10_erlang_cookie.sh | 26 ++ docker/pre/20_ejabberd_config.sh | 36 ++ docker/start.sh | 69 +++ docker/stop/10_leave_cluster.sh | 21 + 21 files changed, 1732 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 docker/README.md create mode 100755 docker/bootstrap.sh create mode 100644 docker/conf/ejabberd.yml.tpl create mode 100644 docker/conf/ejabberdctl.cfg.tpl create mode 100644 docker/lib/base_config.sh create mode 100644 docker/lib/base_functions.sh create mode 100644 docker/lib/config.sh create mode 100644 docker/lib/functions.sh create mode 100755 docker/post/10_ejabberd_modules_update_specs.sh create mode 100755 docker/post/11_ejabberd_install_modules.sh create mode 100755 docker/post/20_ejabberd_register_users.sh create mode 100755 docker/post/99_first_start_done.sh create mode 100755 docker/pre/01_write_certifiates_from_env.sh create mode 100755 docker/pre/02_make_snakeoil_certificates.sh create mode 100755 docker/pre/03_make_dhparam.sh create mode 100755 docker/pre/10_erlang_cookie.sh create mode 100755 docker/pre/20_ejabberd_config.sh create mode 100755 docker/start.sh create mode 100755 docker/stop/10_leave_cluster.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..94b549649 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +.git +.win32 +.examples diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..37763a734 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,25 @@ +FROM debian:jessie +MAINTAINER Rafael Römhild + +ENV XMPP_DOMAIN=localhost \ + EJABBERD_HOME=/opt/ejabberd \ + PATH=/opt/ejabberd/bin:/usr/sbin:/usr/bin:/sbin:/bin \ + LC_ALL=C.UTF-8 \ + LANG=en_US.UTF-8 \ + LANGUAGE=en_US.UTF-8 + +# bootstrap +COPY . /tmp/ejabberd +RUN /tmp/ejabberd/docker/bootstrap.sh + +# Continue as user +USER ejabberd + +# Set workdir to ejabberd root +WORKDIR /opt/ejabberd + +VOLUME ["/opt/ejabberd/conf", "/opt/ejabberd/database", "/opt/ejabberd/ssl", "/opt/ejabberd/backup", "/opt/ejabberd/upload", "/opt/ejabberd/modules"] + +EXPOSE 4560 5222 5269 5280 5443 + +ENTRYPOINT ["/opt/ejabberd/docker/start.sh"] diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 000000000..f518b488c --- /dev/null +++ b/docker/README.md @@ -0,0 +1,360 @@ +ejabberd container + +- [Introduction](#introduction) +- [Quick Start](#quick-start) +- [Usage](#usage) + - [Persistence](#persistence) + - [SSL Certificates](#ssl-certificates) + - [Base Image](#base-image) +- [Ejabberd Configuration](#ejabberd-configuration) + - [Served Hostnames](#served-hostnames) + - [Authentication](#authentication) + - [Admins](#admins) + - [Users](#users) + - [SSL](#ssl) + - [Modules](#modules) + - [Logging](#logging) + - [Mount Configurations](#mount-configurations) + - [Erlang Configuration](#erlang-configuration) +- [Maintenance](#maintenance) + - [Register Users](#register-users) + - [Creating Backups](#creating-backups) + - [Restoring Backups](#restoring-backups) +- [Debug](#debug) + - [Erlang Shell](#erlang-shell) + - [System Shell](#system-shell) + - [System Commands](#system-commands) +- [Exposed Ports](#exposed-ports) + +# Introduction + +Dockerfile to build an [ejabberd](https://www.ejabberd.im/) container image. + +Docker Tag Names are based on ejabberd versions in git [tags][]. The image tag `:latest` is based on the master branch. + +[tags]: https://github.com/rroemhild/ejabberd/tags + +# Quick Start + +You can start of with the following container: + +```bash +docker run -d \ + --name "ejabberd" \ + -p 5222:5222 \ + -p 5269:5269 \ + -p 5280:5280 \ + -h 'xmpp.example.de' \ + -e "XMPP_DOMAIN=example.de" \ + -e "ERLANG_NODE=nodename" \ + -e "EJABBERD_ADMINS=admin@example.de admin2@example.de" \ + -e "EJABBERD_USERS=admin@example.de:password1234 admin2@example.de" \ + -e "TZ=Europe/Berlin" \ + rroemhild/ejabberd +``` + +# Usage + +## Persistence + +For storage of the application data, you can mount volumes at + +* `/opt/ejabberd/ssl` +* `/opt/ejabberd/backup` +* `/opt/ejabberd/upload` +* `/opt/ejabberd/database` + +or use a data container + +```bash +docker create --name ejabberd-data rroemhild/ejabberd-data +docker run -d --name ejabberd --volumes-from processone-data rroemhild/ejabberd +``` + +## SSL Certificates + +TLS is enabled by default and the run script will auto-generate two snake-oil certificates during boot if you don't provide your SSL certificates. + +To use your own certificates, there are two options. + +1. Mount the volume `/opt/ejabberd/ssl` to a local directory with the `.pem` files: + + * /tmp/ssl/host.pem (SERVER_HOSTNAME) + * /tmp/ssl/xmpp_domain.pem (XMPP_DOMAIN) + + Make sure that the certificate and private key are in one `.pem` file. If one file is missing it will be auto-generated. I.e. you can provide your certificate for your **XMMP_DOMAIN** and use a snake-oil certificate for the `SERVER_HOSTNAME`. + +2. Specify the certificates via environment variables: **EJABBERD_SSLCERT_HOST** and **EJABBERD_SSLCERT_EXAMPLE_COM**. For the +domain certificates, make sure you match the domain names given in **XMPP_DOMAIN** and replace dots and dashes with underscore. + +## Base Image + +Build your own ejabberd container image and add your config templates, certificates or [extend](#cluster-example) it for your needs. + +``` +FROM rroemhild/ejabberd +ADD ./ejabberd.yml.tpl /opt/ejabberd/conf/ejabberd.yml.tpl +ADD ./ejabberdctl.cfg.tpl /opt/ejabberd/conf/ejabberdctl.cfg.tpl +ADD ./example.com.pem /opt/ejabberd/ssl/example.com.pem +``` + +If you need root privileges switch to `USER root` and go back to `USER ejabberd` when you're done. + +# Ejabberd Configuration + +You can additionally provide extra runtime configuration in a downstream image by replacing the config template `ejabberd.yml.tpl` with one based on this image's template and include extra interpolation of environment variables. The template is parsed by Jinja2 with the runtime environment (equivalent to Python's `os.environ` available as `env`). + +## Served Hostnames + +By default the container will serve the XMPP domain `localhost`. In order to serve a different domain at runtime, provide the **XMPP_DOMAIN** variable with a domain name. You can add more domains separated with whitespace. + +``` +XMPP_DOMAIN=example.ninja xyz.io test.com +``` + +## Authentication + +Authentication methods can be set with the **EJABBERD_AUTH_METHOD** environment variable. The default authentication mode is `internal`. + +Supported authentication methods: + +* anonymous +* internal +* external +* ldap + +Internal and anonymous authentication example: + +``` +EJABBERD_AUTH_METHOD=internal anonymous +``` + +[External authentication](http://docs.ejabberd.im/admin/guide/configuration/#external-script) example: +``` +EJABBERD_AUTH_METHOD=external +EJABBERD_EXTAUTH_PROGRAM="/opt/ejabberd/scripts/authenticate-user.sh" +EJABBERD_EXTAUTH_INSTANCES=3 +EJABBERD_EXTAUTH_CACHE=600 +``` +**EJABBERD_EXTAUTH_INSTANCES** must be an integer with a minimum value of 1. **EJABBERD_EXTAUTH_CACHE** can be set to "false" or an integer value representing cache time in seconds. Note that caching should not be enabled if internal auth is also enabled. + +### MySQL Authentication + +Set `EJABBERD_AUTH_METHOD=external` and `EJABBERD_EXTAUTH_PROGRAM=/opt/ejabberd/scripts/lib/auth_mysql.py` to enable MySQL authentication. Use the following environment variables to configure the database connection and the layout of the database. Password changing, registration, and unregistration are optional features and are enabled only if the respective queries are provided. + +- **AUTH_MYSQL_HOST**: The MySQL host +- **AUTH_MYSQL_USER**: Username to connect to the MySQL host +- **AUTH_MYSQL_PASSWORD**: Password to connect to the MySQL host +- **AUTH_MYSQL_DATABASE**: Database name where to find the user information +- **AUTH_MYSQL_HASHALG**: Format of the password in the database. Default is cleartext. Options are `crypt`, `md5`, `sha1`, `sha224`, `sha256`, `sha384`, `sha512`. `crypt` is recommended, as it is salted. When setting the password, `crypt` uses SHA-512 (prefix `$6$`). +- **AUTH_MYSQL_QUERY_GETPASS**: Get the password for a user. Use the placeholders `%(user)s`, `%(host)s`. Example: `SELECT password FROM users WHERE username = CONCAT(%(user)s, '@', %(host)s)` +- **AUTH_MYSQL_QUERY_SETPASS**: Update the password for a user. Leave empty to disable. Placeholder `%(password)s` contains the hashed password. Example: `UPDATE users SET password = %(password)s WHERE username = CONCAT(%(user)s, '@', %(host)s)` +- **AUTH_MYSQL_QUERY_REGISTER**: Register a new user. Leave empty to disable. Example: `INSERT INTO users ( username, password ) VALUES ( CONCAT(%(user)s, '@', %(host)s), %(password)s )` +- **AUTH_MYSQL_QUERY_UNREGISTER**: Removes a user. Leave empty to disable. Example: `DELETE FROM users WHERE username = CONCAT(%(user)s, '@', %(host)s)` + +Note that the MySQL authentication script writes a debug log into the file `/var/log/ejabberd/extauth.log`. To get its content, execute the following command: + +```bash +docker exec -ti ejabberd tail -n50 -f /var/log/ejabberd/extauth.log +``` + +To find out more about the mysql authentication script, check out the [ejabberd-auth-mysql](https://github.com/rankenstein/ejabberd-auth-mysql) repository. + +### LDAP Auth + +Full documentation http://docs.ejabberd.im/admin/guide/configuration/#ldap. + +Connection + +- **EJABBERD_LDAP_SERVERS**: List of IP addresses or DNS names of your LDAP servers. This option is required. +- **EJABBERD_LDAP_ENCRYPT**: The value `tls` enables encryption by using LDAP over SSL. The default value is: `none`. +- **EJABBERD_LDAP_TLS_VERIFY**: `false|soft|hard` This option specifies whether to verify LDAP server certificate or not when TLS is enabled. The default is `false` which means no checks are performed. +- **EJABBERD_LDAP_TLS_CACERTFILE**: Path to file containing PEM encoded CA certificates. +- **EJABBERD_LDAP_TLS_DEPTH**: Specifies the maximum verification depth when TLS verification is enabled. The default value is 1. +- **EJABBERD_LDAP_PORT**: The default port is `389` if encryption is disabled; and `636` if encryption is enabled. +- **EJABBERD_LDAP_ROOTDN**: Bind DN. The default value is "" which means ‘anonymous connection’. +- **EJABBERD_LDAP_PASSWORD**: Bind password. The default value is "". +- **EJABBERD_LDAP_DEREF_ALIASES**: `never|always|finding|searching` + Whether or not to dereference aliases. The default is `never`. + +Authentication + +- **EJABBERD_LDAP_BASE**: LDAP base directory which stores users accounts. This option is required. +- **EJABBERD_LDAP_UIDS**: `ldap_uidattr:ldap_uidattr_format` The default attributes are `uid:%u`. +- **EJABBERD_LDAP_FILTER**: RFC 4515 LDAP filter. The default Filter value is undefined. +- **EJABBERD_LDAP_DN_FILTER**: `{ Filter: FilterAttrs }` This filter is applied on the results returned by the main filter. By default ldap_dn_filter is undefined. + +## Admins + +Set one or more admin user (seperated by whitespace) with the **EJABBERD_ADMINS** environment variable. You can register admin users with the **EJABBERD_USERS** environment variable during container startup, use you favorite XMPP client or the `ejabberdctl` command line utility. + +``` +EJABBERD_ADMINS=admin@example.ninja +``` + +## Users + +Automatically register users during container startup. Uses random password if you don't provide a password for the user. Format is `JID:PASSWORD`. Register more users separated with whitespace. + +Register the admin user from **EJABBERD_ADMINS** with a give password: + +``` +EJABBERD_USERS=admin@example.ninja:password1234 +``` + +Or without a random password printed to stdout (check container logs): + +``` +EJABBERD_USERS=admin@example.ninja +``` + +Register more than one user: + +``` +EJABBERD_USERS=admin@example.ninja:password1234 user1@test.com user1@xyz.io +``` + +## SSL + +- **EJABBERD_SSLCERT_HOST**: SSL Certificate for the hostname. +- **EJABBERD_SSLCERT_EXAMPLE_COM**: SSL Certificates for XMPP domains. +- **EJABBERD_STARTTLS**: Set to `false` to disable StartTLS for client to server connections. Default: `true`. +- **EJABBERD_S2S_SSL**: Set to `false` to disable SSL in server 2 server connections. Default: `true`. +- **EJABBERD_HTTPS**: If your proxy terminates SSL you may want to disable HTTPS on port 5280 and 5443. Default: `true`. +- **EJABBERD_PROTOCOL_OPTIONS_TLSV1**: Allow TLSv1 protocol. Default: `false`. +- **EJABBERD_PROTOCOL_OPTIONS_TLSV1_1**: Allow TLSv1.1 protocol. Default: `true`. +- **EJABBERD_CIPHERS**: Cipher suite. Default: `HIGH:!aNULL:!3DES`. +- **EJABBERD_DHPARAM**: Set to `true` to use or generate custom DH parameters. Default: `false`. + +## Modules + +- **EJABBERD_SKIP_MODULES_UPDATE**: If you do not need to update ejabberd modules specs, skip the update task and speedup start. Default: `false`. +- **EJABBERD_MOD_MUC_ADMIN**: Activate the mod_muc_admin module. Default: `false`. +- **EJABBERD_MOD_ADMIN_EXTRA**: Activate the mod_muc_admin module. Default: `true`. +- **EJABBERD_REGISTER_TRUSTED_NETWORK_ONLY**: Only allow user registration from the trusted_network access rule. Default: `true`. +- **EJABBERD_MOD_VERSION**: Activate the mod_version module. Default: `true`. + +## Logging + +Use the **EJABBERD_LOGLEVEL** environment variable to set verbosity. Default: `4` (Info). + +``` +loglevel: Verbosity of log files generated by ejabberd. +0: No ejabberd log at all (not recommended) +1: Critical +2: Error +3: Warning +4: Info +5: Debug +``` + +## Mount Configurations + +If you prefer to use your own configuration files and avoid passing docker environment variables (```-e```), you can do so by mounting a host directory. +Pass in an additional ```-v``` to the ```docker run``` command, like so: +``` +docker run -d \ + --name "ejabberd" \ + -p 5222:5222 \ + -p 5269:5269 \ + -p 5280:5280 \ + -h 'xmpp.example.de' \ + -v //conf:/opt/ejabberd/conf \ + rroemhild/ejabberd +``` + +Your ```//conf``` folder should look like so: + +``` +//conf/ +├── ejabberdctl.cfg +├── ejabberd.yml +└── inetrc +``` + +Example configuration files can be downloaded from the ejabberd [github](https://github.com/rroemhild/ejabberd) page. + +When these files exist in ```/opt/ejabberd/conf```, the run script will ignore the configuration templates. + +## Erlang Configuration + +With the following environment variables you can configure options that are passed by ejabberdctl to the erlang runtime system when starting ejabberd. + +- **POLL**: Set to `false` to disable Kernel polling. Default: `true`. +- **SMP**: SMP support `enable`, `auto`, `disable`. Default: `auto`. +- **ERL_MAX_PORTS**: Maximum number of simultaneously open Erlang ports. Default: `32000`. +- **FIREWALL_WINDOW**: Range of allowed ports to pass through a firewall. Default: `not defined`. +- **INET_DIST_INTERFACE**: IP address where this Erlang node listens other nodes. Default: `0.0.0.0`. +- **ERL_EPMD_ADDRESS**: IP addresses where epmd listens for connections. Default: `0.0.0.0`. +- **ERL_PROCESSES**: Maximum number of Erlang processes. Default: `250000`. +- **ERL_MAX_ETS_TABLES**: Maximum number of Erlang processes. Default: `1400`. +- **ERLANG_OPTIONS**: Overwrite additional options passed to erlang while starting ejabberd. Default: `-noshell` +- **ERLANG_NODE**: Allows to explicitly specify erlang node for ejabberd. Set to `nodename` lets erlang add the hostname. Default: `ejabberd@localhost`. +- **EJABBERD_CONFIG_PATH**: ejabberd configuration file. Default: `/opt/ejabberd/conf/ejabberd.yml`. +- **CONTRIB_MODULES_PATH**: contributed ejabberd modules path. Default: `/opt/ejabberd/modules`. +- **CONTRIB_MODULES_CONF_DIR**: configuration directory for contributed modules. Default: `/opt/ejabberd/modules/conf`. +- **ERLANG_COOKIE**: Set erlang cookie. Default is to auto-generated cookie. + +# Maintenance + +The `ejabberdctl` command is in the search path and can be run by: + +```bash +docker exec CONTAINER ejabberdctl help +``` + +## Register Users + +```bash +docker exec CONTAINER ejabberdctl register user XMPP_DOMAIN PASSWORD +``` + +## Creating Backups + +Create a backupfile with ejabberdctl and copy the file from the container to localhost + +```bash +docker exec CONTAINER ejabberdctl backup /opt/ejabberd/backup/ejabberd.backup +docker cp CONTAINER:/opt/ejabberd/backup/ejabberd.backup /tmp/ejabberd.backup +``` + +## Restoring Backups + +Copy the backupfile from localhost to the running container and restore with ejabberdctl + +```bash +docker cp /tmp/ejabberd.backup CONTAINER:/opt/ejabberd/backup/ejabberd.backup +docker exec CONTAINER ejabberdctl restore /opt/ejabberd/backup/ejabberd.backup +``` + +# Debug + +## Erlang Shell + +Set `-i` and `-t` option and append `live` to get an interactive erlang shell: + +```bash +docker run -i -t -P rroemhild/ejabberd live +``` + +You can terminate the erlang shell with `q().`. + +## System Shell + +```bash +docker run -i -t rroemhild/ejabberd shell +``` + +## System Commands + +```bash +docker run -i -t rroemhild/ejabberd env +``` + +# Exposed Ports + +* 4560 (XMLRPC) +* 5222 (Client 2 Server) +* 5269 (Server 2 Server) +* 5280 (HTTP admin/websocket/http-bind) +* 5443 (HTTP Upload) diff --git a/docker/bootstrap.sh b/docker/bootstrap.sh new file mode 100755 index 000000000..cedab5f4f --- /dev/null +++ b/docker/bootstrap.sh @@ -0,0 +1,75 @@ +#!/bin/sh +set -ex + +export DEBIAN_FRONTEND="noninteractive" + +readonly buildDeps=' + git-core + build-essential + automake + libssl-dev + zlib1g-dev + libexpat-dev + libyaml-dev + libsqlite3-dev + erlang-src erlang-dev' + +readonly requiredAptPackages=' + locales + ldnsutils + python2.7 + python-jinja2 + ca-certificates + libyaml-0-2 + erlang-base erlang-snmp erlang-ssl erlang-ssh erlang-webtool + erlang-tools erlang-xmerl erlang-corba erlang-diameter erlang-eldap + erlang-eunit erlang-ic erlang-odbc erlang-os-mon + erlang-parsetools erlang-percept erlang-typer + python-mysqldb + imagemagick' + +apt-key adv \ + --keyserver keys.gnupg.net \ + --recv-keys 434975BD900CCBE4F7EE1B1ED208507CA14F4FCA + +apt-get update +apt-get install -y $buildDeps $requiredAptPackages --no-install-recommends +dpkg-reconfigure locales && locale-gen C.UTF-8 +/usr/sbin/update-locale LANG=C.UTF-8 +echo 'en_US.UTF-8 UTF-8' >> /etc/locale.gen +locale-gen + +# add ejabberd user +useradd --home $EJABBERD_HOME -M --system ejabberd +mkdir $EJABBERD_HOME + +cd /tmp/ejabberd +chmod +x ./autogen.sh +./autogen.sh +./configure --enable-user=ejabberd \ + --enable-all \ + --disable-tools \ + --disable-pam + +make debug=$EJABBERD_DEBUG_MODE +make install + +cd $EJABBERD_HOME +mkdir -p logs ssl backup upload module_source modules/conf +mv /tmp/ejabberd/docker $EJABBERD_HOME + +# Move config to homedir +mv /etc/ejabberd conf +ln -s $EJABBERD_HOME/conf /etc/ejabberd + +# rename original configs +mv conf/ejabberd.yml conf/ejabberd.yml.orig +mv conf/ejabberdctl.cfg conf/ejabberdctl.cfg.orig + +# clean up +rm -rf /tmp/ejabberd +rm -rf /var/lib/apt/lists/* +apt-get purge -y --auto-remove $buildDeps + +# change owner for ejabberd home +chown -R ejabberd $EJABBERD_HOME diff --git a/docker/conf/ejabberd.yml.tpl b/docker/conf/ejabberd.yml.tpl new file mode 100644 index 000000000..dd8b58821 --- /dev/null +++ b/docker/conf/ejabberd.yml.tpl @@ -0,0 +1,434 @@ +### +### ejabberd configuration file +### +### + +### The parameters used in this configuration file are explained in more detail +### in the ejabberd Installation and Operation Guide. +### Please consult the Guide in case of doubts, it is included with +### your copy of ejabberd, and is also available online at +### http://www.process-one.net/en/ejabberd/docs/ + +### ======= +### LOGGING + +loglevel: {{ env['EJABBERD_LOGLEVEL'] or 4 }} +log_rotate_size: 10485760 +log_rotate_count: 0 +log_rate_limit: 100 + +## watchdog_admins: +## - "bob@example.com" + +### ================ +### SERVED HOSTNAMES + +hosts: +{%- for xmpp_domain in env['XMPP_DOMAIN'].split() %} + - "{{ xmpp_domain }}" +{%- endfor %} + +## +## route_subdomains: Delegate subdomains to other XMPP servers. +## For example, if this ejabberd serves example.org and you want +## to allow communication with an XMPP server called im.example.org. +## +## route_subdomains: s2s + +### =============== +### LISTENING PORTS + +listen: + - + port: 5222 + module: ejabberd_c2s + {%- if env['EJABBERD_STARTTLS'] == "true" %} + starttls_required: true + {%- endif %} + protocol_options: + - "no_sslv3" + {%- if env.get('EJABBERD_PROTOCOL_OPTIONS_TLSV1', "false") == "false" %} + - "no_tlsv1" + {%- endif %} + {%- if env.get('EJABBERD_PROTOCOL_OPTIONS_TLSV1_1', "true") == "false" %} + - "no_tlsv1_1" + {%- endif %} + max_stanza_size: 65536 + shaper: c2s_shaper + access: c2s + ciphers: "{{ env.get('EJABBERD_CIPHERS', 'HIGH:!aNULL:!3DES') }}" + {%- if env.get('EJABBERD_DHPARAM', false) == "true" %} + dhfile: "/opt/ejabberd/ssl/dh.pem" + {%- endif %} + - + port: 5269 + module: ejabberd_s2s_in + - + port: 4560 + module: ejabberd_xmlrpc + access_commands: + configure: + all: [] + + - + port: 5280 + module: ejabberd_http + request_handlers: + "/websocket": ejabberd_http_ws + ## "/pub/archive": mod_http_fileserver + web_admin: true + http_bind: true + ## register: true + captcha: true + {%- if env['EJABBERD_HTTPS'] == "true" %} + tls: true + certfile: "/opt/ejabberd/ssl/host.pem" + {% endif %} + - + port: 5443 + module: ejabberd_http + request_handlers: + "": mod_http_upload + {%- if env['EJABBERD_HTTPS'] == "true" %} + tls: true + certfile: "/opt/ejabberd/ssl/host.pem" + {% endif %} + + +### SERVER TO SERVER +### ================ + +{%- if env['EJABBERD_S2S_SSL'] == "true" %} +s2s_use_starttls: required +s2s_certfile: "/opt/ejabberd/ssl/host.pem" +s2s_protocol_options: + - "no_sslv3" + {%- if env.get('EJABBERD_PROTOCOL_OPTIONS_TLSV1', "false") == "false" %} + - "no_tlsv1" + {%- endif %} + {%- if env.get('EJABBERD_PROTOCOL_OPTIONS_TLSV1_1', "true") == "false" %} + - "no_tlsv1_1" + {%- endif %} +s2s_ciphers: "{{ env.get('EJABBERD_CIPHERS', 'HIGH:!aNULL:!3DES') }}" +{%- if env.get('EJABBERD_DHPARAM', false) == "true" %} +s2s_dhfile: "/opt/ejabberd/ssl/dh.pem" +{%- endif %} +{% endif %} + +### ============== +### AUTHENTICATION + +auth_method: +{%- for auth_method in env.get('EJABBERD_AUTH_METHOD', 'internal').split() %} + - {{ auth_method }} +{%- endfor %} + +{%- if 'anonymous' in env.get('EJABBERD_AUTH_METHOD', 'internal').split() %} +anonymous_protocol: login_anon +allow_multiple_connections: true +{%- endif %} + + +## LDAP authentication + +{%- if 'ldap' in env.get('EJABBERD_AUTH_METHOD', 'internal').split() %} + +ldap_servers: +{%- for ldap_server in env.get('EJABBERD_LDAP_SERVERS', 'internal').split() %} + - "{{ ldap_server }}" +{%- endfor %} + +ldap_encrypt: {{ env.get('EJABBERD_LDAP_ENCRYPT', 'none') }} +ldap_tls_verify: {{ env.get('EJABBERD_LDAP_TLS_VERIFY', 'false') }} + +{%- if env['EJABBERD_LDAP_TLS_CACERTFILE'] %} +ldap_tls_cacertfile: "{{ env['EJABBERD_LDAP_TLS_CACERTFILE'] }}" +{%- endif %} + +ldap_tls_depth: {{ env.get('EJABBERD_LDAP_TLS_DEPTH', 1) }} + +{%- if env['EJABBERD_LDAP_PORT'] %} +ldap_port: {{ env['EJABBERD_LDAP_PORT'] }} +{%- endif %} + +{%- if env['EJABBERD_LDAP_ROOTDN'] %} +ldap_rootdn: "{{ env['EJABBERD_LDAP_ROOTDN'] }}" +{%- endif %} + +{%- if env['EJABBERD_LDAP_PASSWORD'] %} +ldap_password: "{{ env['EJABBERD_LDAP_PASSWORD'] }}" +{%- endif %} + +ldap_deref_aliases: {{ env.get('EJABBERD_LDAP_DEREF_ALIASES', 'never') }} +ldap_base: "{{ env['EJABBERD_LDAP_BASE'] }}" + +{%- if env['EJABBERD_LDAP_UIDS'] %} +ldap_uids: +{%- for ldap_uid in env['EJABBERD_LDAP_UIDS'].split() %} + "{{ ldap_uid.split(':')[0] }}": "{{ ldap_uid.split(':')[1] }}" +{%- endfor %} +{%- endif %} + +{%- if env['EJABBERD_LDAP_FILTER'] %} +ldap_filter: "{{ env['EJABBERD_LDAP_FILTER'] }}" +{%- endif %} + +{%- if env['EJABBERD_LDAP_DN_FILTER'] %} +ldap_dn_filter: +{%- for dn_filter in env['EJABBERD_LDAP_DN_FILTER'].split() %} + "{{ dn_filter.split(':')[0] }}": ["{{ dn_filter.split(':')[1] }}"] +{%- endfor %} +{%- endif %} + +{%- endif %} + +{%- if 'external' in env.get('EJABBERD_AUTH_METHOD', 'internal').split() %} + {%- if env['EJABBERD_EXTAUTH_PROGRAM'] %} +extauth_program: "{{ env['EJABBERD_EXTAUTH_PROGRAM'] }}" + {%- endif %} + {%- if env['EJABBERD_EXTAUTH_INSTANCES'] %} +extauth_instances: {{ env['EJABBERD_EXTAUTH_INSTANCES'] }} + {%- endif %} + {%- if 'internal' in env.get('EJABBERD_AUTH_METHOD').split() %} +extauth_cache: false + {%- elif env['EJABBERD_EXTAUTH_CACHE'] %} +extauth_cache: {{ env['EJABBERD_EXTAUTH_CACHE'] }} + {%- endif %} +{% endif %} + +### =============== +### TRAFFIC SHAPERS + +shaper: + normal: 1000 + fast: 50000 +max_fsm_queue: 1000 + +### ==================== +### ACCESS CONTROL LISTS + +acl: + admin: + user: + {%- if env['EJABBERD_ADMINS'] %} + {%- for admin in env['EJABBERD_ADMINS'].split() %} + - "{{ admin.split('@')[0] }}": "{{ admin.split('@')[1] }}" + {%- endfor %} + {%- else %} + - "admin": "{{ env['XMPP_DOMAIN'].split()[0] }}" + {%- endif %} + local: + user_regexp: "" + +### ============ +### ACCESS RULES + +access: + ## Maximum number of simultaneous sessions allowed for a single user: + max_user_sessions: + all: 10 + ## Maximum number of offline messages that users can have: + max_user_offline_messages: + admin: 5000 + all: 100 + ## This rule allows access only for local users: + local: + local: allow + ## Only non-blocked users can use c2s connections: + c2s: + blocked: deny + all: allow + ## For C2S connections, all users except admins use the "normal" shaper + c2s_shaper: + admin: none + all: normal + ## All S2S connections use the "fast" shaper + s2s_shaper: + all: fast + ## Only admins can send announcement messages: + announce: + admin: allow + ## Only admins can use the configuration interface: + configure: + admin: allow + ## Admins of this server are also admins of the MUC service: + muc_admin: + admin: allow + ## Only accounts of the local ejabberd server, or only admins can create rooms, depending on environment variable: + muc_create: + {%- if env['EJABBERD_MUC_CREATE_ADMIN_ONLY'] == "true" %} + admin: allow + {% else %} + local: allow + {% endif %} + ## All users are allowed to use the MUC service: + muc: + all: allow + ## Only accounts on the local ejabberd server can create Pubsub nodes: + pubsub_createnode: + local: allow + ## In-band registration allows registration of any possible username. + register: + {%- if env['EJABBERD_REGISTER_ADMIN_ONLY'] == "true" %} + all: deny + admin: allow + {% else %} + all: allow + {% endif %} + ## Only allow to register from localhost + trusted_network: + loopback: allow + soft_upload_quota: + all: 400 # MiB + hard_upload_quota: + all: 500 # MiB + + +language: "en" + +### ======= +### MODULES + +modules: + mod_adhoc: {} + {%- if env['EJABBERD_MOD_ADMIN_EXTRA'] == "true" %} + mod_admin_extra: {} + {% endif %} + mod_announce: # recommends mod_adhoc + access: announce + mod_blocking: {} # requires mod_privacy + mod_caps: {} + mod_carboncopy: {} + mod_client_state: + drop_chat_states: true + queue_presence: false + mod_configure: {} # requires mod_adhoc + mod_disco: {} + ## mod_echo: {} + mod_irc: {} + mod_http_bind: {} + ## mod_http_fileserver: + ## docroot: "/var/www" + ## accesslog: "/var/log/ejabberd/access.log" + mod_last: {} + mod_muc: + host: "conference.@HOST@" + access: muc + access_create: muc_create + access_persistent: muc_create + access_admin: muc_admin + history_size: 50 + default_room_options: + persistent: true + {%- if env['EJABBERD_MOD_MUC_ADMIN'] == "true" %} + mod_muc_admin: {} + {% endif %} + ## mod_muc_log: {} + ## mod_multicast: {} + mod_offline: + access_max_user_messages: max_user_offline_messages + mod_ping: {} + ## mod_pres_counter: + ## count: 5 + ## interval: 60 + mod_privacy: {} + mod_private: {} + ## mod_proxy65: {} + mod_pubsub: + access_createnode: pubsub_createnode + ## reduces resource comsumption, but XEP incompliant + ignore_pep_from_offline: true + ## XEP compliant, but increases resource comsumption + ## ignore_pep_from_offline: false + last_item_cache: false + plugins: + - "flat" + - "hometree" + - "pep" # pep requires mod_caps + mod_register: + ## + ## Protect In-Band account registrations with CAPTCHA. + ## + ## captcha_protected: true + + ## + ## Set the minimum informational entropy for passwords. + ## + ## password_strength: 32 + + ## + ## After successful registration, the user receives + ## a message with this subject and body. + ## + welcome_message: + subject: "Welcome!" + body: |- + Hi. + Welcome to this XMPP server. + + ## + ## Only clients in the server machine can register accounts + ## + {%- if env['EJABBERD_REGISTER_TRUSTED_NETWORK_ONLY'] == "true" %} + ip_access: trusted_network + {% endif %} + + access: register + mod_roster: {} + mod_shared_roster: {} + mod_stats: {} + mod_time: {} + mod_vcard: {} + {% if env.get('EJABBERD_MOD_VERSION', true) == "true" %} + mod_version: {} + {% endif %} + mod_http_upload: + docroot: "/opt/ejabberd/upload" + {%- if env['EJABBERD_HTTPS'] == "true" %} + put_url: "https://@HOST@:5443" + {%- else %} + put_url: "http://@HOST@:5443" + {% endif %} + mod_http_upload_quota: + max_days: 10 + +### ============ +### HOST CONFIG + +host_config: +{%- for xmpp_domain in env['XMPP_DOMAIN'].split() %} + "{{ xmpp_domain }}": + domain_certfile: "/opt/ejabberd/ssl/{{ xmpp_domain }}.pem" +{%- endfor %} + +{%- if env['EJABBERD_CONFIGURE_ODBC'] == "true" %} +### ==================== +### ODBC DATABASE CONFIG +odbc_type: {{ env['EJABBERD_ODBC_TYPE'] }} +odbc_server: {{ env['EJABBERD_ODBC_SERVER'] }} +odbc_database: {{ env['EJABBERD_ODBC_DATABASE'] }} +odbc_username: {{ env['EJABBERD_ODBC_USERNAME'] }} +odbc_password: {{ env['EJABBERD_ODBC_PASSWORD'] }} +odbc_pool_size: {{ env['EJABBERD_ODBC_POOL_SIZE'] }} +{% endif %} + +{%- if env['EJABBERD_DEFAULT_DB'] is defined %} +default_db: {{ env['EJABBERD_DEFAULT_DB'] }} +{% endif %} + +### ===================== +### SESSION MANAGEMENT DB +sm_db_type: {{ env['EJABBERD_SESSION_DB'] or "mnesia" }} + +{%- if env['EJABBERD_CONFIGURE_REDIS'] == "true" %} +### ==================== +### REDIS DATABASE CONFIG +redis_server: {{ env['EJABBERD_REDIS_SERVER'] or "localhost" }} +redis_port: {{ env['EJABBERD_REDIS_PORT'] or 6379 }} +{%- if env['EJABBERD_REDIS_PASSWORD'] is defined %} +redis_password: {{ env['EJABBERD_REDIS_PASSWORD'] }} +{% endif %} +redis_db: {{ env['EJABBERD_REDIS_DB'] or 0}} +redis_reconnect_timeout: {{ env['EJABBERD_REDIS_RECONNECT_TIMEOUT'] or 1 }} +redis_connect_timeout: {{ env['EJABBERD_REDIS_CONNECT_TIMEOUT'] or 1 }} +{% endif %} diff --git a/docker/conf/ejabberdctl.cfg.tpl b/docker/conf/ejabberdctl.cfg.tpl new file mode 100644 index 000000000..98b4608c2 --- /dev/null +++ b/docker/conf/ejabberdctl.cfg.tpl @@ -0,0 +1,199 @@ +# +# In this file you can configure options that are passed by ejabberdctl +# to the erlang runtime system when starting ejabberd +# + +#' POLL: Kernel polling ([true|false]) +# +# The kernel polling option requires support in the kernel. +# Additionally, you need to enable this feature while compiling Erlang. +# +# Default: true +# +POLL={{ env['POLL'] or 'true' }} + +#. +#' SMP: SMP support ([enable|auto|disable]) +# +# Explanation in Erlang/OTP documentation: +# enable: starts the Erlang runtime system with SMP support enabled. +# This may fail if no runtime system with SMP support is available. +# auto: starts the Erlang runtime system with SMP support enabled if it +# is available and more than one logical processor are detected. +# disable: starts a runtime system without SMP support. +# +# Default: auto +# +SMP={{ env['SMP'] or 'auto' }} + +#. +#' ERL_MAX_PORTS: Maximum number of simultaneously open Erlang ports +# +# ejabberd consumes two or three ports for every connection, either +# from a client or from another Jabber server. So take this into +# account when setting this limit. +# +# Default: 32000 +# Maximum: 268435456 +# +ERL_MAX_PORTS={{ env['ERL_MAX_PORTS'] or '32000' }} + +#. +#' FIREWALL_WINDOW: Range of allowed ports to pass through a firewall +# +# If Ejabberd is configured to run in cluster, and a firewall is blocking ports, +# it's possible to make Erlang use a defined range of port (instead of dynamic +# ports) for node communication. +# +# Default: not defined +# Example: 4200-4210 +# +{%- if env['FIREWALL_WINDOW'] %} +FIREWALL_WINDOW={{ env['FIREWALL_WINDOW'] }} +{%- endif %} + +#. +#' INET_DIST_INTERFACE: IP address where this Erlang node listens other nodes +# +# This communication is used by ejabberdctl command line tool, +# and in a cluster of several ejabberd nodes. +# +# Default: 0.0.0.0 +# +{%- if env['INET_DIST_INTERFACE'] %} +INET_DIST_INTERFACE={{ env['INET_DIST_INTERFACE'] }} +{%- endif %} + +#. +#' ERL_EPMD_ADDRESS: IP addresses where epmd listens for connections +# +# IMPORTANT: This option works only in Erlang/OTP R14B03 and newer. +# +# This environment variable may be set to a comma-separated +# list of IP addresses, in which case the epmd daemon +# will listen only on the specified address(es) and on the +# loopback address (which is implicitly added to the list if it +# has not been specified). The default behaviour is to listen on +# all available IP addresses. +# +# Default: 0.0.0.0 +# +{%- if env['ERL_EPMD_ADDRESS'] %} +ERL_EPMD_ADDRESS={{ env['ERL_EPMD_ADDRESS'] }} +{%- endif %} + +#. +#' ERL_PROCESSES: Maximum number of Erlang processes +# +# Erlang consumes a lot of lightweight processes. If there is a lot of activity +# on ejabberd so that the maximum number of processes is reached, people will +# experience greater latency times. As these processes are implemented in +# Erlang, and therefore not related to the operating system processes, you do +# not have to worry about allowing a huge number of them. +# +# Default: 250000 +# Maximum: 268435456 +# +ERL_PROCESSES={{ env['ERL_PROCESSES'] or '250000' }} + +#. +#' ERL_MAX_ETS_TABLES: Maximum number of ETS and Mnesia tables +# +# The number of concurrent ETS and Mnesia tables is limited. When the limit is +# reached, errors will appear in the logs: +# ** Too many db tables ** +# You can safely increase this limit when starting ejabberd. It impacts memory +# consumption but the difference will be quite small. +# +# Default: 1400 +# +ERL_MAX_ETS_TABLES={{ env['ERL_MAX_ETS_TABLES'] or '1400' }} + +#. +#' ERL_OPTIONS: Additional Erlang options +# +# The next variable allows to specify additional options passed to erlang while +# starting ejabberd. Some useful options are -noshell, -detached, -heart. When +# ejabberd is started from an init.d script options -noshell and -detached are +# added implicitly. See erl(1) for more info. +# +# It might be useful to add "-pa /usr/local/lib/ejabberd/ebin" if you +# want to add local modules in this path. +# +# Default: "" +# +ERL_OPTIONS="{{ env['ERL_OPTIONS'] or '-noshell' }}" + +#. +#' ERLANG_NODE: Erlang node name +# +# The next variable allows to explicitly specify erlang node for ejabberd +# It can be given in different formats: +# ERLANG_NODE=ejabberd +# Lets erlang add hostname to the node (ejabberd uses short name in this case) +# ERLANG_NODE=ejabberd@hostname +# Erlang uses node name as is (so make sure that hostname is a real +# machine hostname or you'll not be able to control ejabberd) +# ERLANG_NODE=ejabberd@hostname.domainname +# The same as previous, but erlang will use long hostname +# (see erl (1) manual for details) +# +# Default: ejabberd@localhost +# +ERLANG_NODE={{ env['ERLANG_NODE'] or 'ejabberd@localhost' }} + +#. +#' EJABBERD_PID_PATH: ejabberd PID file +# +# Indicate the full path to the ejabberd Process identifier (PID) file. +# If this variable is defined, ejabberd writes the PID file when starts, +# and deletes it when stops. +# Remember to create the directory and grant write permission to ejabberd. +# +# Default: don't write PID file +# +#EJABBERD_PID_PATH=/var/run/ejabberd/ejabberd.pid + +#. +#' EJABBERD_CONFIG_PATH: ejabberd configuration file +# +# Specify the full path to the ejabberd configuration file. If the file name has +# yml or yaml extension, it is parsed as a YAML file; otherwise, Erlang syntax is +# expected. +# +# Default: $ETC_DIR/ejabberd.yml +# +EJABBERD_CONFIG_PATH={{ env['EJABBERD_CONFIG_PATH'] or '/opt/ejabberd/conf/ejabberd.yml' }} + +#. +#' CONTRIB_MODULES_PATH: contributed ejabberd modules path +# +# Specify the full path to the contributed ejabberd modules. If the path is not +# defined, ejabberd will use ~/.ejabberd-modules in home of user running ejabberd. +# +# Default: $HOME/.ejabberd-modules +# +CONTRIB_MODULES_PATH={{ env['CONTRIB_MODULES_PATH'] or '/opt/ejabberd/modules' }} + +#. +#' CONTRIB_MODULES_CONF_DIR: configuration directory for contributed modules +# +# Specify the full path to the configuration directory for contributed ejabberd +# modules. In order to configure a module named mod_foo, a mod_foo.yml file can +# be created in this directory. This file will then be used instead of the +# default configuration file provided with the module. +# +# Default: $CONTRIB_MODULES_PATH/conf +# +CONTRIB_MODULES_CONF_DIR={{ env['CONTRIB_MODULES_CONF_DIR'] or '/opt/ejabberd/modules/conf' }} + +#. +#' EJABBERD_BYPASS_WARNINGS: Bypass LIVE warning +# +# Default: don't bypass the warning +# +EJABBERD_BYPASS_WARNINGS=true + +#. +#' +# vim: foldmarker=#',#. foldmethod=marker: diff --git a/docker/lib/base_config.sh b/docker/lib/base_config.sh new file mode 100644 index 000000000..803c1db47 --- /dev/null +++ b/docker/lib/base_config.sh @@ -0,0 +1,22 @@ +readonly HOSTIP=$(hostname -i) +readonly HOSTNAME=$(hostname -f) +readonly DOMAINNAME=$(hostname -d) + +readonly DOCKER_LIB="${EJABBERD_HOME}/docker/lib" +readonly ERLANGCOOKIEFILE="${EJABBERD_HOME}/.erlang.cookie" +readonly EJABBERDCTL="/sbin/ejabberdctl" +readonly CONFIGDIR="${EJABBERD_HOME}/conf" +readonly CONFIGTMPDIR="${EJABBERD_HOME}/docker/conf" +readonly SSLCERTDIR="${EJABBERD_HOME}/ssl" +readonly SSLCERTHOST="${SSLCERTDIR}/host.pem" +readonly LOGDIR="/var/log/ejabberd" +readonly FIRST_START_DONE_FILE="${EJABBERD_HOME}/first-start-done" +readonly CLUSTER_NODE_FILE="${EJABBERD_HOME}/cluster-done" + +readonly PYTHON_JINJA2="import os; +import sys; +import jinja2; +sys.stdout.write( + jinja2.Template + (sys.stdin.read() + ).render(env=os.environ))" diff --git a/docker/lib/base_functions.sh b/docker/lib/base_functions.sh new file mode 100644 index 000000000..d7bf97266 --- /dev/null +++ b/docker/lib/base_functions.sh @@ -0,0 +1,72 @@ +is_set() { + local var=$1 + + [[ -n $var ]] +} + + +is_zero() { + local var=$1 + + [[ -z $var ]] +} + + +file_exist() { + local file=$1 + + [[ -e $file ]] +} + + +is_true() { + local var=${1,,} + local choices=("yes" "1" "y" "true") + for ((i=0;i < ${#choices[@]};i++)) { + [[ "${choices[i]}" == $var ]] && return 0 + } + return 1 +} + + +log() { + local message=$1 + echo $message +} + + +# overwrite this function to get hostname from other sources +# like dns or etcd +get_nodename() { + log ${HOSTNAME} +} + + +join_cluster() { + local cluster_node=$1 + + is_zero ${cluster_node} \ + && exit 0 + + log "Join cluster..." + + local erlang_node_name=${ERLANG_NODE%@*} + local erlang_cluster_node="${erlang_node_name}@${cluster_node}" + + response=$(${EJABBERDCTL} ping ${erlang_cluster_node}) + while [ "$response" != "pong" ]; do + log "Waiting for ${erlang_cluster_node}..." + sleep 2 + response=$(${EJABBERDCTL} ping ${erlang_cluster_node}) + done + + log "Join cluster at ${erlang_cluster_node}... " + NO_WARNINGS=true ${EJABBERDCTL} join_cluster $erlang_cluster_node + + if [ $? -eq 0 ]; then + touch ${CLUSTER_NODE_FILE} + else + log "cloud not join cluster" + exit 1 + fi +} diff --git a/docker/lib/config.sh b/docker/lib/config.sh new file mode 100644 index 000000000..6b9cbbb12 --- /dev/null +++ b/docker/lib/config.sh @@ -0,0 +1 @@ +# Overridable file diff --git a/docker/lib/functions.sh b/docker/lib/functions.sh new file mode 100644 index 000000000..6b9cbbb12 --- /dev/null +++ b/docker/lib/functions.sh @@ -0,0 +1 @@ +# Overridable file diff --git a/docker/post/10_ejabberd_modules_update_specs.sh b/docker/post/10_ejabberd_modules_update_specs.sh new file mode 100755 index 000000000..9e916016a --- /dev/null +++ b/docker/post/10_ejabberd_modules_update_specs.sh @@ -0,0 +1,24 @@ +#!/bin/bash +set -e + +# Updates the known modules as to be found in https://github.com/processone/ejabberd-contrib + +source "${EJABBERD_HOME}/docker/lib/base_config.sh" +source "${EJABBERD_HOME}/docker/lib/config.sh" +source "${EJABBERD_HOME}/docker/lib/base_functions.sh" +source "${EJABBERD_HOME}/docker/lib/functions.sh" + + +run_modules_update_specs() { + log "Updating module specs... " + ${EJABBERDCTL} modules_update_specs +} + + +is_true ${EJABBERD_SKIP_MODULES_UPDATE} \ + && exit 0 + +run_modules_update_specs + + +exit 0 diff --git a/docker/post/11_ejabberd_install_modules.sh b/docker/post/11_ejabberd_install_modules.sh new file mode 100755 index 000000000..2dd4f3922 --- /dev/null +++ b/docker/post/11_ejabberd_install_modules.sh @@ -0,0 +1,144 @@ +#!/bin/bash +set -e + +# Installs modules as defined in environment variables + +source "${EJABBERD_HOME}/docker/lib/base_config.sh" +source "${EJABBERD_HOME}/docker/lib/config.sh" +source "${EJABBERD_HOME}/docker/lib/base_functions.sh" +source "${EJABBERD_HOME}/docker/lib/functions.sh" + + +install_module_from_source() { + local module_name=$1 + local module_source_path=${EJABBERD_HOME}/module_source/${module_name} + local module_install_folder=${EJABBERD_HOME}/.ejabberd-modules/sources/${module_name} + + log "Analyzing module ${module_name} for installation" + # Make sure that the module exists in the source folder before attempting a copy + + if [ ! -d ${module_source_path} ]; then + log "Error: Module ${module_name} not found in ${EJABBERD_HOME}/module_source" + log "Please use a shared volume to populate your module in ${EJABBERD_HOME}/module_source" + return 1; + fi + + # Check to see if the module is already installed + local install_count=$(${EJABBERDCTL} modules_installed | grep -ce "^${module_name}[[:space:]]") + if [ $install_count -gt 0 ]; then + log "Error: Module already installed: ${module_name}" + return 1; + fi + + # Copy the module into the shared folder + log "Copying module to ejabberd folder ${module_install_folder}" + mkdir -p ${module_install_folder} + cp -R ${module_source_path} ${module_install_folder} + + # Run the ejabberdctl module_check on the module + log "Running module_check on ${module_name}" + ${EJABBERDCTL} module_check ${module_name} + if [ $? -ne 0 ]; then + log "Module check failed for ${module_name}" + return 1; + fi + log "Module check succeeded for ${module_name}" + + # Install the module + log "Running module_install on ${module_name}" + ${EJABBERDCTL} module_install ${module_name} + if [ $? -ne 0 ]; then + log "Module installation failed for ${module_name}" + return 1; + fi + log "Module installation succeeded for ${module_name}" + + return 0; +} + +install_module_from_ejabberd_contrib() { + local module_name=$1 + + # Check to see if the module is already installed + local install_count=$(${EJABBERDCTL} modules_installed | grep -ce "^${module_name}[[:space:]]") + if [ $install_count -gt 0 ]; then + log "Error: Module already installed: ejabberd_contrib ${module_name}" + return 1; + fi + + # Install the module + log "Running module_install on ejabberd_contrib ${module_name}" + ${EJABBERDCTL} module_install ${module_name} + if [ $? -ne 0 ]; then + log "Module installation failed for ejabberd_contrib ${module_name}" + return 1; + fi + log "Module installation succeeded for ejabberd_contrib ${module_name}" + + return 0; +} + +enable_custom_auth_module_override() { + module_name=$1; + # When using custom authentication modules, the module name must be + # in the following pattern: ejabberd_auth_foo, where foo is the + # value you will use for your auth_method yml configuration. + required_prefix="ejabberd_auth_" + + if [[ "${module_name}" != "${required_prefix}"* ]]; then + log "Error: module_name must begin with ${required_prefix}" + exit 1; + fi + + log "Checking custom auth module: ${module_name}" + # Make sure the auth module is installed + local install_count=$(${EJABBERDCTL} modules_installed | grep -ce "^${module_name}[[:space:]]") + if [ $install_count -eq 0 ]; then + log "Error: custom auth_module not installed: ${module_name}" + return 1; + fi + + custom_auth_method=${module_name#$required_prefix} + echo -e "\nauth_method: [${custom_auth_method}]" >> ${CONFIGFILE} + log "Custom auth module ${module_name} configuration complete." +} + +file_exist ${FIRST_START_DONE_FILE} \ + && exit 0 + +is_restart_needed=0; + +if [ -n "${EJABBERD_SOURCE_MODULES}" ]; then + for module_name in ${EJABBERD_SOURCE_MODULES} ; do + install_module_from_source ${module_name} + done + is_restart_needed=1; +fi + +# Check the EJABBERD_CONTRIB_MODULES variable for any ejabberd_contrib modules +if [ -n "${EJABBERD_CONTRIB_MODULES}" ]; then + for module_name in ${EJABBERD_CONTRIB_MODULES} ; do + install_module_from_ejabberd_contrib ${module_name} + done + is_restart_needed=1; +fi + +# If a custom module was defined for handling auth, we need to override +# the pre-defined auth methods in the config. +if [ -n "${EJABBERD_CUSTOM_AUTH_MODULE_OVERRIDE}" ]; then + enable_custom_auth_module_override "${EJABBERD_CUSTOM_AUTH_MODULE_OVERRIDE}" + is_restart_needed=1; +fi + +# If any modules were installed, restart the server, if the option is enabled +if [ ${is_restart_needed} -eq 1 ]; then + if is_true ${EJABBERD_RESTART_AFTER_MODULE_INSTALL} ; then + log "Restarting ejabberd after successful module installation(s)" + ${EJABBERDCTL} restart + child=$! + ${EJABBERDCTL} "started" + wait $child + fi +fi + +exit 0 diff --git a/docker/post/20_ejabberd_register_users.sh b/docker/post/20_ejabberd_register_users.sh new file mode 100755 index 000000000..9dc910eeb --- /dev/null +++ b/docker/post/20_ejabberd_register_users.sh @@ -0,0 +1,72 @@ +#!/bin/bash +set -e + +source "${EJABBERD_HOME}/docker/lib/base_config.sh" +source "${EJABBERD_HOME}/docker/lib/config.sh" +source "${EJABBERD_HOME}/docker/lib/base_functions.sh" +source "${EJABBERD_HOME}/docker/lib/functions.sh" + +# Do not exit if users already registered +set +e + +randpw() { + < /dev/urandom tr -dc A-Z-a-z-0-9 | head -c ${1:-16}; + echo; +} + + +register_user() { + local user=$1 + local domain=$2 + local password=$3 + + ${EJABBERDCTL} register ${user} ${domain} ${password} + return $? +} + + +register_all_users() { + # register users from environment $EJABBERD_USERS with given + # password or random password written to stout. Use whitespace + # to seperate users. + # + # sample: + # - add a user with an given password: + # -e "EJABBERD_USERS=admin@example.com:adminSecret" + # - add a user with a random password: + # -e "EJABBERD_USERS=user@example.com" + # - set password for admin and use random for user1: + # -e "EJABBERD_USERS=admin@example.com:adminSecret user@example.com" + + for user in ${EJABBERD_USERS} ; do + local jid=${user%%:*} + local password=${user#*:} + + local username=${jid%%@*} + local domain=${jid#*@} + + [[ "${password}" == "${jid}" ]] \ + && password=$(randpw) + + register_user ${username} ${domain} ${password} + local retval=$? + + [[ ${retval} -eq 0 ]] \ + && log "Password for user ${username}@${domain} is ${password}" + done +} + + +file_exist ${FIRST_START_DONE_FILE} \ + && exit 0 + + +file_exist ${CLUSTER_NODE_FILE} \ + && exit 0 + + +is_set ${EJABBERD_USERS} \ + && register_all_users + + +exit 0 diff --git a/docker/post/99_first_start_done.sh b/docker/post/99_first_start_done.sh new file mode 100755 index 000000000..394531cf6 --- /dev/null +++ b/docker/post/99_first_start_done.sh @@ -0,0 +1,17 @@ +#!/bin/bash +set -e + +# Write a first-start-done file + +source "${EJABBERD_HOME}/docker/lib/base_config.sh" +source "${EJABBERD_HOME}/docker/lib/config.sh" +source "${EJABBERD_HOME}/docker/lib/base_functions.sh" +source "${EJABBERD_HOME}/docker/lib/functions.sh" + + +if [ ! -e "${FIRST_START_DONE_FILE}" ]; then + touch ${FIRST_START_DONE_FILE} +fi + + +exit 0 diff --git a/docker/pre/01_write_certifiates_from_env.sh b/docker/pre/01_write_certifiates_from_env.sh new file mode 100755 index 000000000..a42c2e306 --- /dev/null +++ b/docker/pre/01_write_certifiates_from_env.sh @@ -0,0 +1,34 @@ +#!/bin/bash +set -e + +source "${EJABBERD_HOME}/docker/lib/base_config.sh" +source "${EJABBERD_HOME}/docker/lib/config.sh" +source "${EJABBERD_HOME}/docker/lib/base_functions.sh" +source "${EJABBERD_HOME}/docker/lib/functions.sh" + +# Instead of having to mount a direction, specify the ssl certs +# via environment variables: +# `EJABBERD_SSLCERT_HOST` and `EJABBERD_SSLCERT_{domain_name}`. +# For example: `EJABBERD_SSLCERT_EXAMPLE_COM`. + +write_file_from_env() { + log "Writing $1 to $2" + mkdir -p "$(dirname $2)" + log "${!1}" > $2 +} + +# Write the host certificate +is_set ${EJABBERD_SSLCERT_HOST} \ + && write_file_from_env "EJABBERD_SSLCERT_HOST" ${SSLCERTHOST} + +# Write the domain certificates for each XMPP_DOMAIN +for xmpp_domain in ${XMPP_DOMAIN} ; do + var="EJABBERD_SSLCERT_$(echo $xmpp_domain | awk '{print toupper($0)}' | sed 's/\./_/g;s/-/_/g')" + if is_set ${!var} ; then + file_exist "${SSLCERTDIR}/${xmpp_domain}.pem" \ + || write_file_from_env "$var" "${SSLCERTDIR}/${xmpp_domain}.pem" + fi +done + + +exit 0 diff --git a/docker/pre/02_make_snakeoil_certificates.sh b/docker/pre/02_make_snakeoil_certificates.sh new file mode 100755 index 000000000..d8eeec937 --- /dev/null +++ b/docker/pre/02_make_snakeoil_certificates.sh @@ -0,0 +1,75 @@ +#!/bin/bash +set -e + +source "${EJABBERD_HOME}/docker/lib/base_config.sh" +source "${EJABBERD_HOME}/docker/lib/config.sh" +source "${EJABBERD_HOME}/docker/lib/base_functions.sh" +source "${EJABBERD_HOME}/docker/lib/functions.sh" + + +make_snakeoil_certificate() { + local domain=$1 + local certfile=$2 + + openssl req -subj "/CN=${domain}" \ + -new \ + -newkey rsa:4096 \ + -days 365 \ + -nodes \ + -x509 \ + -keyout /tmp/selfsigned.key \ + -out /tmp/selfsigned.crt + + log "Writing ssl cert and private key to '${certfile}'..." + cat /tmp/selfsigned.crt /tmp/selfsigned.key > ${certfile} + rm /tmp/selfsigned.crt /tmp/selfsigned.key +} + + +make_host_snakeoil_certificate() { + local IFS=@ + local domain='localhost' + local erlang_node=${ERLANG_NODE} + + if is_true ${erlang_node} ; then + domain=${HOSTNAME} + elif is_set ${erlang_node} ; then + set ${erlang_node} + local nodehost=$2 + if is_zero ${nodehost} ; then + domain=${HOSTNAME} + else + domain=${nodehost} + fi + fi + + log "Generating snakeoil ssl cert for ${domain}..." + + make_snakeoil_certificate ${domain} ${SSLCERTHOST} +} + + +make_domain_snakeoil_certificate() { + local domain=$1 + local certfile=$2 + + log "Generating snakeoil ssl cert for ${domain}..." + + make_snakeoil_certificate ${domain} ${certfile} +} + + +# generate host ssl cert if missing +file_exist ${SSLCERTHOST} \ + || make_host_snakeoil_certificate + + +# generate xmmp domain ssl certificates if missing +for xmpp_domain in ${XMPP_DOMAIN} ; do + domain_certfile="${SSLCERTDIR}/${xmpp_domain}.pem" + file_exist ${domain_certfile} \ + || make_domain_snakeoil_certificate ${xmpp_domain} ${domain_certfile} +done + + +exit 0 diff --git a/docker/pre/03_make_dhparam.sh b/docker/pre/03_make_dhparam.sh new file mode 100755 index 000000000..d897b2789 --- /dev/null +++ b/docker/pre/03_make_dhparam.sh @@ -0,0 +1,22 @@ +#!/bin/bash +set -e + +source "${EJABBERD_HOME}/docker/lib/base_config.sh" +source "${EJABBERD_HOME}/docker/lib/config.sh" +source "${EJABBERD_HOME}/docker/lib/base_functions.sh" +source "${EJABBERD_HOME}/docker/lib/functions.sh" + +make_dhparam() { + local dhfile=$1 + local bits=$2 + + log "Writing dh file to '${dhfile}'..." + openssl dhparam -out ${dhfile} ${bits} +} + +if is_true ${EJABBERD_DHPARAM} ; then + file_exist ${SSLDHPARAM} \ + || make_dhparam ${SSLDHPARAM} 4096 +fi + +exit 0 diff --git a/docker/pre/10_erlang_cookie.sh b/docker/pre/10_erlang_cookie.sh new file mode 100755 index 000000000..2c08a64fb --- /dev/null +++ b/docker/pre/10_erlang_cookie.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +source "${EJABBERD_HOME}/docker/lib/base_config.sh" +source "${EJABBERD_HOME}/docker/lib/config.sh" +source "${EJABBERD_HOME}/docker/lib/base_functions.sh" +source "${EJABBERD_HOME}/docker/lib/functions.sh" + + +set_erlang_cookie() { + chmod 600 ${ERLANGCOOKIEFILE} + log "Set erlang cookie to ${ERLANG_COOKIE}..." + echo ${ERLANG_COOKIE} > ${ERLANGCOOKIEFILE} + chmod 400 ${ERLANGCOOKIEFILE} +} + + +file_exist ${FIRST_START_DONE_FILE} \ + && exit 0 + + +# set erlang cookie if ERLANG_COOKIE is set in environemt +is_set ${ERLANG_COOKIE} \ + && set_erlang_cookie + + +exit 0 diff --git a/docker/pre/20_ejabberd_config.sh b/docker/pre/20_ejabberd_config.sh new file mode 100755 index 000000000..230a1981b --- /dev/null +++ b/docker/pre/20_ejabberd_config.sh @@ -0,0 +1,36 @@ +#!/bin/bash +set -e + +source "${EJABBERD_HOME}/docker/lib/base_config.sh" +source "${EJABBERD_HOME}/docker/lib/config.sh" +source "${EJABBERD_HOME}/docker/lib/base_functions.sh" +source "${EJABBERD_HOME}/docker/lib/functions.sh" + + +make_config() { + local filename=$1 + local template="${CONFIGTMPDIR}/${filename}.tpl" + local configfile="${CONFIGDIR}/${filename}" + + file_exist $configfile \ + && return 1 + + if [ ! -e ${configfile} ]; then + log "Generating ${configfile} config file..." + cat $template \ + | python -c "${PYTHON_JINJA2}" \ + > $configfile + else + echo "File ${configfile} exists." + fi +} + + +# /opt/ejabberd/conf/ejabberd.yml +make_config "ejabberd.yml" + +# /opt/ejabberd/conf/ejabberdctl.cfg +make_config "ejabberdctl.cfg" + + +exit 0 diff --git a/docker/start.sh b/docker/start.sh new file mode 100755 index 000000000..64a971f66 --- /dev/null +++ b/docker/start.sh @@ -0,0 +1,69 @@ +#!/bin/bash +set -e + +# Environment +export EJABBERD_HTTPS=${EJABBERD_HTTPS:-'true'} +export EJABBERD_STARTTLS=${EJABBERD_STARTTLS:-'true'} +export EJABBERD_S2S_SSL=${EJABBERD_S2S_SSL:-'true'} + +source "${EJABBERD_HOME}/docker/lib/base_config.sh" +source "${EJABBERD_HOME}/docker/lib/config.sh" +source "${EJABBERD_HOME}/docker/lib/base_functions.sh" +source "${EJABBERD_HOME}/docker/lib/functions.sh" + + +# discover hostname +readonly nodename=$(get_nodename) + +# set erlang node to node name from get_nodename +if [[ "$ERLANG_NODE" == "nodename" ]]; then + export ERLANG_NODE="ejabberd@${nodename}" +fi + + +run_scripts() { + local run_script=$1 + local run_script_dir="${EJABBERD_HOME}/docker/${run_script}" + + log "Run ${run_script} scripts..." + for script in ${run_script_dir}/*.sh ; do + if [ -f ${script} -a -x ${script} ] ; then + ${script} + fi + done +} + + +_trap() { + run_scripts "stop" + log "Stopping ejabberd..." + $EJABBERDCTL stop + $EJABBERDCTL stopped + exit 0 +} + + +# Catch signals and shutdown ejabberd +trap _trap SIGTERM SIGINT + +# print logfiles to stdout +tail -F ${LOGDIR}/crash.log \ + ${LOGDIR}/error.log \ + ${LOGDIR}/erlang.log \ + ${LOGDIR}/ejabberd.log & + +# start ejabberd +run_scripts "pre" +log "Starting ejabberd..." +$EJABBERDCTL start +$EJABBERDCTL started +log "Ejabberd started." +run_scripts "post" + +# run forever +while true; do sleep 1; done + +log "Ejabberd stopped." + + +exit 0 diff --git a/docker/stop/10_leave_cluster.sh b/docker/stop/10_leave_cluster.sh new file mode 100755 index 000000000..f6fc97fa7 --- /dev/null +++ b/docker/stop/10_leave_cluster.sh @@ -0,0 +1,21 @@ +#!/bin/bash +set -e + +source "${EJABBERD_HOME}/docker/lib/base_config.sh" +source "${EJABBERD_HOME}/docker/lib/config.sh" +source "${EJABBERD_HOME}/docker/lib/base_functions.sh" +source "${EJABBERD_HOME}/docker/lib/functions.sh" + + +leave_cluster() { + log "Leave cluster..." + rm ${CLUSTER_NODE_FILE} + NO_WARNINGS=true ${EJABBERDCTL} leave_cluster +} + + +file_exist ${CLUSTER_NODE_FILE} \ + && leave_cluster + + +exit 0 From b1723c6e2d83f0d3d65f151a10610f58a54859cf Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 16 Nov 2016 13:11:23 +0100 Subject: [PATCH 090/151] Handle correctly p1_http:request result --- src/ext_mod.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ext_mod.erl b/src/ext_mod.erl index 2f71343a2..a2109e569 100644 --- a/src/ext_mod.erl +++ b/src/ext_mod.erl @@ -272,9 +272,9 @@ geturl(Url, Hdrs, UsrOpts) -> _ -> [] end, case p1_http:request(get, Url, Hdrs, [], Host++User++UsrOpts++[{version, "HTTP/1.0"}]) of - {ok, {{_, 200, _}, Headers, Response}} -> + {ok, 200, Headers, Response} -> {ok, Headers, Response}; - {ok, {{_, Code, _}, _Headers, Response}} -> + {ok, Code, _Headers, Response} -> {error, {Code, Response}}; {error, Reason} -> {error, Reason} From e69ddd981fdc40d0ccbcec37f5abca988f296936 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 16 Nov 2016 13:12:57 +0100 Subject: [PATCH 091/151] Tell git to ignore the example file ejabberd.service --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index bf5fe2863..38d6d77f8 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ /doc/version.tex /ebin/ /ejabberd.init +/ejabberd.service /ejabberdctl.example XmppAddr.hrl /rel/ejabberd/ From 3cd174cb56c064e6d4f969677d94cd413003f5e0 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 16 Nov 2016 13:35:50 +0100 Subject: [PATCH 092/151] Ensure that presence_broadcast room option is stored (#1380) --- src/mod_muc_room.erl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl index c83565734..060ac2bcd 100644 --- a/src/mod_muc_room.erl +++ b/src/mod_muc_room.erl @@ -3548,6 +3548,7 @@ make_opts(StateData) -> ?MAKE_CONFIG_OPT(#config.allow_voice_requests), ?MAKE_CONFIG_OPT(#config.allow_subscription), ?MAKE_CONFIG_OPT(#config.mam), + ?MAKE_CONFIG_OPT(#config.presence_broadcast), ?MAKE_CONFIG_OPT(#config.voice_request_min_interval), ?MAKE_CONFIG_OPT(#config.vcard), {captcha_whitelist, From 8ced3bdbe95c1748ae370a345b29056ba89e2e43 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Wed, 16 Nov 2016 14:18:51 +0100 Subject: [PATCH 093/151] Remove obsolete/temp file --- asn1/ELDAPv3.asn1~ | 301 --------------------------------------------- 1 file changed, 301 deletions(-) delete mode 100644 asn1/ELDAPv3.asn1~ diff --git a/asn1/ELDAPv3.asn1~ b/asn1/ELDAPv3.asn1~ deleted file mode 100644 index 1fec35cd8..000000000 --- a/asn1/ELDAPv3.asn1~ +++ /dev/null @@ -1,301 +0,0 @@ --- LDAPv3 ASN.1 specification, taken from RFC 2251 - --- Lightweight-Directory-Access-Protocol-V3 DEFINITIONS -ELDAPv3 DEFINITIONS -IMPLICIT TAGS ::= - -BEGIN - -LDAPMessage ::= SEQUENCE { - messageID MessageID, - protocolOp CHOICE { - bindRequest BindRequest, - bindResponse BindResponse, - unbindRequest UnbindRequest, - searchRequest SearchRequest, - searchResEntry SearchResultEntry, - searchResDone SearchResultDone, - searchResRef SearchResultReference, - modifyRequest ModifyRequest, - modifyResponse ModifyResponse, - addRequest AddRequest, - addResponse AddResponse, - delRequest DelRequest, - delResponse DelResponse, - modDNRequest ModifyDNRequest, - modDNResponse ModifyDNResponse, - compareRequest CompareRequest, - compareResponse CompareResponse, - abandonRequest AbandonRequest, - extendedReq ExtendedRequest, - extendedResp ExtendedResponse }, - controls [0] Controls OPTIONAL } - -MessageID ::= INTEGER (0 .. maxInt) - -maxInt INTEGER ::= 2147483647 -- (2^^31 - 1) -- - -LDAPString ::= OCTET STRING - -LDAPOID ::= OCTET STRING - -LDAPDN ::= LDAPString - -RelativeLDAPDN ::= LDAPString - -AttributeType ::= LDAPString - -AttributeDescription ::= LDAPString - - - - --- Wahl, et. al. Standards Track [Page 44] --- --- RFC 2251 LDAPv3 December 1997 - - -AttributeDescriptionList ::= SEQUENCE OF - AttributeDescription - -AttributeValue ::= OCTET STRING - -AttributeValueAssertion ::= SEQUENCE { - attributeDesc AttributeDescription, - assertionValue AssertionValue } - -AssertionValue ::= OCTET STRING - -Attribute ::= SEQUENCE { - type AttributeDescription, - vals SET OF AttributeValue } - -MatchingRuleId ::= LDAPString - -LDAPResult ::= SEQUENCE { - resultCode ENUMERATED { - success (0), - operationsError (1), - protocolError (2), - timeLimitExceeded (3), - sizeLimitExceeded (4), - compareFalse (5), - compareTrue (6), - authMethodNotSupported (7), - strongAuthRequired (8), - -- 9 reserved -- - referral (10), -- new - adminLimitExceeded (11), -- new - unavailableCriticalExtension (12), -- new - confidentialityRequired (13), -- new - saslBindInProgress (14), -- new - noSuchAttribute (16), - undefinedAttributeType (17), - inappropriateMatching (18), - constraintViolation (19), - attributeOrValueExists (20), - invalidAttributeSyntax (21), - -- 22-31 unused -- - noSuchObject (32), - aliasProblem (33), - invalidDNSyntax (34), - -- 35 reserved for undefined isLeaf -- - aliasDereferencingProblem (36), - -- 37-47 unused -- - inappropriateAuthentication (48), - --- Wahl, et. al. Standards Track [Page 45] --- --- RFC 2251 LDAPv3 December 1997 - - - invalidCredentials (49), - insufficientAccessRights (50), - busy (51), - unavailable (52), - unwillingToPerform (53), - loopDetect (54), - -- 55-63 unused -- - namingViolation (64), - objectClassViolation (65), - notAllowedOnNonLeaf (66), - notAllowedOnRDN (67), - entryAlreadyExists (68), - objectClassModsProhibited (69), - -- 70 reserved for CLDAP -- - affectsMultipleDSAs (71), -- new - -- 72-79 unused -- - other (80) }, - -- 81-90 reserved for APIs -- - matchedDN LDAPDN, - errorMessage LDAPString, - referral [3] Referral OPTIONAL } - -Referral ::= SEQUENCE OF LDAPURL - -LDAPURL ::= LDAPString -- limited to characters permitted in URLs - -Controls ::= SEQUENCE OF Control - -Control ::= SEQUENCE { - controlType LDAPOID, - criticality BOOLEAN DEFAULT FALSE, - controlValue OCTET STRING OPTIONAL } - -BindRequest ::= [APPLICATION 0] SEQUENCE { - version INTEGER (1 .. 127), - name LDAPDN, - authentication AuthenticationChoice } - -AuthenticationChoice ::= CHOICE { - simple [0] OCTET STRING, - -- 1 and 2 reserved - sasl [3] SaslCredentials } - -SaslCredentials ::= SEQUENCE { - mechanism LDAPString, - credentials OCTET STRING OPTIONAL } - -BindResponse ::= [APPLICATION 1] SEQUENCE { - --- Wahl, et. al. Standards Track [Page 46] --- --- RFC 2251 LDAPv3 December 1997 - - - COMPONENTS OF LDAPResult, - serverSaslCreds [7] OCTET STRING OPTIONAL } - -UnbindRequest ::= [APPLICATION 2] NULL - -SearchRequest ::= [APPLICATION 3] SEQUENCE { - baseObject LDAPDN, - scope ENUMERATED { - baseObject (0), - singleLevel (1), - wholeSubtree (2) }, - derefAliases ENUMERATED { - neverDerefAliases (0), - derefInSearching (1), - derefFindingBaseObj (2), - derefAlways (3) }, - sizeLimit INTEGER (0 .. maxInt), - timeLimit INTEGER (0 .. maxInt), - typesOnly BOOLEAN, - filter Filter, - attributes AttributeDescriptionList } - -Filter ::= CHOICE { - and [0] SET OF Filter, - or [1] SET OF Filter, - not [2] Filter, - equalityMatch [3] AttributeValueAssertion, - substrings [4] SubstringFilter, - greaterOrEqual [5] AttributeValueAssertion, - lessOrEqual [6] AttributeValueAssertion, - present [7] AttributeDescription, - approxMatch [8] AttributeValueAssertion, - extensibleMatch [9] MatchingRuleAssertion } - -SubstringFilter ::= SEQUENCE { - type AttributeDescription, - -- at least one must be present - substrings SEQUENCE OF CHOICE { - initial [0] LDAPString, - any [1] LDAPString, - final [2] LDAPString } } - -MatchingRuleAssertion ::= SEQUENCE { - matchingRule [1] MatchingRuleId OPTIONAL, - type [2] AttributeDescription OPTIONAL, - matchValue [3] AssertionValue, - dnAttributes [4] BOOLEAN DEFAULT FALSE } - --- Wahl, et. al. Standards Track [Page 47] --- --- RFC 2251 LDAPv3 December 1997 - -SearchResultEntry ::= [APPLICATION 4] SEQUENCE { - objectName LDAPDN, - attributes PartialAttributeList } - -PartialAttributeList ::= SEQUENCE OF SEQUENCE { - type AttributeDescription, - vals SET OF AttributeValue } - -SearchResultReference ::= [APPLICATION 19] SEQUENCE OF LDAPURL - -SearchResultDone ::= [APPLICATION 5] LDAPResult - -ModifyRequest ::= [APPLICATION 6] SEQUENCE { - object LDAPDN, - modification SEQUENCE OF SEQUENCE { - operation ENUMERATED { - add (0), - delete (1), - replace (2) }, - modification AttributeTypeAndValues } } - -AttributeTypeAndValues ::= SEQUENCE { - type AttributeDescription, - vals SET OF AttributeValue } - -ModifyResponse ::= [APPLICATION 7] LDAPResult - -AddRequest ::= [APPLICATION 8] SEQUENCE { - entry LDAPDN, - attributes AttributeList } - -AttributeList ::= SEQUENCE OF SEQUENCE { - type AttributeDescription, - vals SET OF AttributeValue } - -AddResponse ::= [APPLICATION 9] LDAPResult - -DelRequest ::= [APPLICATION 10] LDAPDN - -DelResponse ::= [APPLICATION 11] LDAPResult - -ModifyDNRequest ::= [APPLICATION 12] SEQUENCE { - entry LDAPDN, - newrdn RelativeLDAPDN, - deleteoldrdn BOOLEAN, - newSuperior [0] LDAPDN OPTIONAL } - -ModifyDNResponse ::= [APPLICATION 13] LDAPResult - --- Wahl, et. al. Standards Track [Page 48] --- --- RFC 2251 LDAPv3 December 1997 - - -CompareRequest ::= [APPLICATION 14] SEQUENCE { - entry LDAPDN, - ava AttributeValueAssertion } - -CompareResponse ::= [APPLICATION 15] LDAPResult - -AbandonRequest ::= [APPLICATION 16] MessageID - -ExtendedRequest ::= [APPLICATION 23] SEQUENCE { - requestName [0] LDAPOID, - requestValue [1] OCTET STRING OPTIONAL } - -ExtendedResponse ::= [APPLICATION 24] SEQUENCE { - COMPONENTS OF LDAPResult, - responseName [10] LDAPOID OPTIONAL, - response [11] OCTET STRING OPTIONAL } - -passwdModifyOID LDAPOID ::= "1.3.6.1.4.1.4203.1.11.1" - -PasswdModifyRequestValue ::= SEQUENCE { - userIdentity [0] OCTET STRING OPTIONAL, - oldPasswd [1] OCTET STRING OPTIONAL, - newPasswd [2] OCTET STRING OPTIONAL } - -PasswdModifyResponseValue ::= SEQUENCE { - genPasswd [0] OCTET STRING OPTIONAL } - -END - - From 1c90b19d748c190e3e6cc7361c2de14d686522af Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Wed, 16 Nov 2016 18:24:12 +0100 Subject: [PATCH 094/151] Fix typo --- src/ejabberd_oauth.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ejabberd_oauth.erl b/src/ejabberd_oauth.erl index e03b78fe8..74e26e8da 100644 --- a/src/ejabberd_oauth.erl +++ b/src/ejabberd_oauth.erl @@ -471,7 +471,7 @@ process(_Handlers, [{<<"href">>, <<"https://www.ejabberd.im">>}, {<<"title">>, <<"ejabberd XMPP server">>}], <<"ejabberd">>), - ?C(" is maintained by "), + ?C(<<" is maintained by ">>), ?XAC(<<"a">>, [{<<"href">>, <<"https://www.process-one.net">>}, {<<"title">>, <<"ProcessOne - Leader in Instant Messaging and Push Solutions">>}], From 995c97671d418264d35aa2308f642bf382832638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Thu, 17 Nov 2016 12:59:27 +0100 Subject: [PATCH 095/151] Add auth to mod_http_fileserver --- src/mod_http_fileserver.erl | 88 ++++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 26 deletions(-) diff --git a/src/mod_http_fileserver.erl b/src/mod_http_fileserver.erl index 728a2d137..a896cb8b4 100644 --- a/src/mod_http_fileserver.erl +++ b/src/mod_http_fileserver.erl @@ -56,7 +56,7 @@ -record(state, {host, docroot, accesslog, accesslogfd, directory_indices, custom_headers, default_content_type, - content_types = []}). + content_types = [], user_access = none}). -define(PROCNAME, ejabberd_mod_http_fileserver). @@ -133,7 +133,8 @@ start_link(Host, Opts) -> init([Host, Opts]) -> try initialize(Host, Opts) of {DocRoot, AccessLog, AccessLogFD, DirectoryIndices, - CustomHeaders, DefaultContentType, ContentTypes} -> + CustomHeaders, DefaultContentType, ContentTypes, + UserAccess} -> {ok, #state{host = Host, accesslog = AccessLog, accesslogfd = AccessLogFD, @@ -141,7 +142,8 @@ init([Host, Opts]) -> directory_indices = DirectoryIndices, custom_headers = CustomHeaders, default_content_type = DefaultContentType, - content_types = ContentTypes}} + content_types = ContentTypes, + user_access = UserAccess}} catch throw:Reason -> {stop, Reason} @@ -165,7 +167,15 @@ initialize(Host, Opts) -> []), DefaultContentType = gen_mod:get_opt(default_content_type, Opts, fun iolist_to_binary/1, - ?DEFAULT_CONTENT_TYPE), + ?DEFAULT_CONTENT_TYPE), + UserAccess0 = gen_mod:get_opt(must_authenticate_with, Opts, + mod_opt_type(must_authenticate_with), + []), + UserAccess = case UserAccess0 of + [] -> none; + _ -> + dict:from_list(UserAccess0) + end, ContentTypes = build_list_content_types( gen_mod:get_opt(content_types, Opts, fun(L) when is_list(L) -> @@ -180,7 +190,7 @@ initialize(Host, Opts) -> [str:join([[$*, K, " -> ", V] || {K, V} <- ContentTypes], <<", ">>)]), {DocRoot, AccessLog, AccessLogFD, DirectoryIndices, - CustomHeaders, DefaultContentType, ContentTypes}. + CustomHeaders, DefaultContentType, ContentTypes, UserAccess}. %% @spec (AdminCTs::[CT], Default::[CT]) -> [CT] @@ -246,10 +256,11 @@ try_open_log(FN, Host) -> %% {stop, Reason, State} %% Description: Handling call messages %%-------------------------------------------------------------------- -handle_call({serve, LocalPath}, _From, State) -> - Reply = serve(LocalPath, State#state.docroot, State#state.directory_indices, +handle_call({serve, LocalPath, Auth}, _From, State) -> + Reply = serve(LocalPath, Auth, State#state.docroot, State#state.directory_indices, State#state.custom_headers, - State#state.default_content_type, State#state.content_types), + State#state.default_content_type, State#state.content_types, + State#state.user_access), {reply, Reply, State}; handle_call(_Request, _From, State) -> {reply, ok, State}. @@ -305,9 +316,9 @@ code_change(_OldVsn, State, _Extra) -> %% @doc Handle an HTTP request. %% LocalPath is the part of the requested URL path that is "local to the module". %% Returns the page to be sent back to the client and/or HTTP status code. -process(LocalPath, Request) -> +process(LocalPath, #request{host = Host, auth = Auth} = Request) -> ?DEBUG("Requested ~p", [LocalPath]), - try gen_server:call(get_proc_name(Request#request.host), {serve, LocalPath}) of + try gen_server:call(get_proc_name(Host), {serve, LocalPath, Auth}) of {FileSize, Code, Headers, Contents} -> add_to_log(FileSize, Code, Request), {Code, Headers, Contents} @@ -318,21 +329,38 @@ process(LocalPath, Request) -> ejabberd_web:error(not_found) end. -serve(LocalPath, DocRoot, DirectoryIndices, CustomHeaders, DefaultContentType, ContentTypes) -> - FileName = filename:join(filename:split(DocRoot) ++ LocalPath), - case file:read_file_info(FileName) of - {error, enoent} -> ?HTTP_ERR_FILE_NOT_FOUND; - {error, enotdir} -> ?HTTP_ERR_FILE_NOT_FOUND; - {error, eacces} -> ?HTTP_ERR_FORBIDDEN; - {ok, #file_info{type = directory}} -> serve_index(FileName, - DirectoryIndices, - CustomHeaders, - DefaultContentType, - ContentTypes); - {ok, FileInfo} -> serve_file(FileInfo, FileName, - CustomHeaders, - DefaultContentType, - ContentTypes) + +serve(LocalPath, Auth, DocRoot, DirectoryIndices, CustomHeaders, DefaultContentType, + ContentTypes, UserAccess) -> + CanProceed = case {UserAccess, Auth} of + {none, _} -> true; + {_, {User, Pass}} -> + case dict:find(User, UserAccess) of + {ok, Pass} -> true; + _ -> false + end; + _ -> + false + end, + case CanProceed of + true -> + FileName = filename:join(filename:split(DocRoot) ++ LocalPath), + case file:read_file_info(FileName) of + {error, enoent} -> ?HTTP_ERR_FILE_NOT_FOUND; + {error, enotdir} -> ?HTTP_ERR_FILE_NOT_FOUND; + {error, eacces} -> ?HTTP_ERR_FORBIDDEN; + {ok, #file_info{type = directory}} -> serve_index(FileName, + DirectoryIndices, + CustomHeaders, + DefaultContentType, + ContentTypes); + {ok, FileInfo} -> serve_file(FileInfo, FileName, + CustomHeaders, + DefaultContentType, + ContentTypes) + end; + _ -> + ?HTTP_ERR_FORBIDDEN end. %% Troll through the directory indices attempting to find one which @@ -466,6 +494,14 @@ mod_opt_type(default_content_type) -> mod_opt_type(directory_indices) -> fun (L) when is_list(L) -> L end; mod_opt_type(docroot) -> fun (A) -> A end; +mod_opt_type(must_authenticate_with) -> + fun (L) when is_list(L) -> + lists:map(fun(UP) when is_binary(UP) -> + [K, V] = binary:split(UP, <<":">>), + {K, V} + end, L) + end; mod_opt_type(_) -> [accesslog, content_types, custom_headers, - default_content_type, directory_indices, docroot]. + default_content_type, directory_indices, docroot, + must_authenticate_with]. From b8dcc911a3b1e3cc05074d9ac4bd8da80b431388 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Fri, 18 Nov 2016 13:38:08 +0300 Subject: [PATCH 096/151] Make common tests working again --- include/mam_query.hrl | 13 + specs/mam_query.cfg | 9 + specs/mam_query.xdata | 23 + src/ejabberd_local.erl | 12 +- src/flex_offline.erl | 2 +- src/mam_query.erl | 220 +++ src/mod_carboncopy.erl | 4 +- src/mod_mam.erl | 201 ++- src/mod_mam_mnesia.erl | 8 +- src/mod_mam_sql.erl | 18 +- src/mod_offline.erl | 3 +- src/mod_offline_riak.erl | 2 +- src/mod_offline_sql.erl | 3 +- src/mod_roster.erl | 2 +- src/muc_register.erl | 2 +- src/muc_request.erl | 2 +- src/muc_roomconfig.erl | 2 +- src/muc_roominfo.erl | 2 +- src/pubsub_get_pending.erl | 2 +- src/pubsub_node_config.erl | 2 +- src/pubsub_publish_options.erl | 2 +- src/pubsub_subscribe_authorization.erl | 2 +- src/pubsub_subscribe_options.erl | 2 +- src/xmpp_util.erl | 9 +- test/announce_tests.erl | 61 + test/carbons_tests.erl | 202 +++ test/csi_tests.erl | 147 ++ test/ejabberd_SUITE.erl | 2059 +----------------------- test/example_tests.erl | 52 + test/mam_tests.erl | 537 ++++++ test/mix_tests.erl | 139 ++ test/mod_legacy.erl | 8 +- test/muc_tests.erl | 750 ++++----- test/privacy_tests.erl | 7 +- test/proxy65_tests.erl | 105 ++ test/pubsub_tests.erl | 729 +++++++++ test/replaced_tests.erl | 57 + test/roster_tests.erl | 6 +- test/sm_tests.erl | 99 ++ test/suite.erl | 5 +- test/vcard_tests.erl | 125 ++ 41 files changed, 3116 insertions(+), 2519 deletions(-) create mode 100644 include/mam_query.hrl create mode 100644 specs/mam_query.cfg create mode 100644 specs/mam_query.xdata create mode 100644 src/mam_query.erl create mode 100644 test/announce_tests.erl create mode 100644 test/carbons_tests.erl create mode 100644 test/csi_tests.erl create mode 100644 test/example_tests.erl create mode 100644 test/mam_tests.erl create mode 100644 test/mix_tests.erl create mode 100644 test/proxy65_tests.erl create mode 100644 test/pubsub_tests.erl create mode 100644 test/replaced_tests.erl create mode 100644 test/sm_tests.erl create mode 100644 test/vcard_tests.erl diff --git a/include/mam_query.hrl b/include/mam_query.hrl new file mode 100644 index 000000000..4ec48c05e --- /dev/null +++ b/include/mam_query.hrl @@ -0,0 +1,13 @@ +%% Created automatically by xdata generator (xdata_codec.erl) +%% Source: mam_query.xdata +%% Form type: urn:xmpp:mam:1 +%% Document: XEP-0313 + + +-type property() :: {'with', jid:jid()} | + {'start', erlang:timestamp()} | + {'end', erlang:timestamp()} | + {'withtext', binary()}. +-type result() :: [property()]. + +-type form() :: [property() | xdata_field()]. diff --git a/specs/mam_query.cfg b/specs/mam_query.cfg new file mode 100644 index 000000000..a8921a52b --- /dev/null +++ b/specs/mam_query.cfg @@ -0,0 +1,9 @@ +[{decode, [{<<"start">>, {xmpp_util, decode_timestamp, []}}, + {<<"end">>, {xmpp_util, decode_timestamp, []}}]}, + {specs, [{<<"start">>, "erlang:timestamp()"}, + {<<"end">>, "erlang:timestamp()"}]}]. + +%% Local Variables: +%% mode: erlang +%% End: +%% vim: set filetype=erlang tabstop=8: diff --git a/specs/mam_query.xdata b/specs/mam_query.xdata new file mode 100644 index 000000000..58fad41cd --- /dev/null +++ b/specs/mam_query.xdata @@ -0,0 +1,23 @@ + + urn:xmpp:mam:1 + XEP-0313 + Form to query message archives + + + + + + + diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index d7849396b..74d86945d 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -177,15 +177,19 @@ unregister_iq_handler(Host, XMLNS) -> refresh_iq_handlers() -> ejabberd_local ! refresh_iq_handlers. --spec bounce_resource_packet(jid(), jid(), stanza()) -> ok. -bounce_resource_packet(_From, _To, #presence{}) -> +-spec bounce_resource_packet(jid(), jid(), stanza()) -> stop. +bounce_resource_packet(_From, #jid{lresource = <<"">>}, #presence{}) -> + ok; +bounce_resource_packet(_From, #jid{lresource = <<"">>}, + #message{type = headline}) -> ok; bounce_resource_packet(From, To, Packet) -> Lang = xmpp:get_lang(Packet), Txt = <<"No available resource found">>, Err = xmpp:make_error(Packet, xmpp:err_item_not_found(Txt, Lang)), - ejabberd_router:route(To, From, Err). + ejabberd_router:route(To, From, Err), + stop. %%==================================================================== %% gen_server callbacks @@ -283,7 +287,7 @@ do_route(From, To, Packet) -> ejabberd_sm:route(From, To, Packet); is_record(Packet, iq), To#jid.lresource == <<"">> -> process_iq(From, To, Packet); - Type == result; Type == error; Type == headline -> + Type == result; Type == error -> ok; true -> ejabberd_hooks:run(local_send_to_resource_hook, diff --git a/src/flex_offline.erl b/src/flex_offline.erl index 090ab3ddf..acc57342e 100644 --- a/src/flex_offline.erl +++ b/src/flex_offline.erl @@ -12,7 +12,7 @@ -include("flex_offline.hrl"). --export_type([{property, 0}, {result, 0}, {form, 0}]). +-export_type([property/0, result/0, form/0]). dec_int(Val, Min, Max) -> case list_to_integer(binary_to_list(Val)) of diff --git a/src/mam_query.erl b/src/mam_query.erl new file mode 100644 index 000000000..cb5bfe13a --- /dev/null +++ b/src/mam_query.erl @@ -0,0 +1,220 @@ +%% Created automatically by xdata generator (xdata_codec.erl) +%% Source: mam_query.xdata +%% Form type: urn:xmpp:mam:1 +%% Document: XEP-0313 + +-module(mam_query). + +-export([decode/1, decode/2, encode/1, encode/2, + format_error/1]). + +-include("xmpp_codec.hrl"). + +-include("mam_query.hrl"). + +-export_type([property/0, result/0, form/0]). + +enc_jid(J) -> jid:to_string(J). + +dec_jid(Val) -> + case jid:from_string(Val) of + error -> erlang:error(badarg); + J -> J + end. + +format_error({form_type_mismatch, Type}) -> + <<"FORM_TYPE doesn't match '", Type/binary, "'">>; +format_error({bad_var_value, Var, Type}) -> + <<"Bad value of field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({missing_value, Var, Type}) -> + <<"Missing value of field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({too_many_values, Var, Type}) -> + <<"Too many values for field '", Var/binary, + "' of type '", Type/binary, "'">>; +format_error({unknown_var, Var, Type}) -> + <<"Unknown field '", Var/binary, "' of type '", + Type/binary, "'">>; +format_error({missing_required_var, Var, Type}) -> + <<"Missing required field '", Var/binary, "' of type '", + Type/binary, "'">>. + +decode(Fs) -> decode(Fs, []). + +decode(Fs, Acc) -> + case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var, + Fs) + of + false -> decode(Fs, Acc, []); + #xdata_field{values = [<<"urn:xmpp:mam:1">>]} -> + decode(Fs, Acc, []); + _ -> + erlang:error({?MODULE, + {form_type_mismatch, <<"urn:xmpp:mam:1">>}}) + end. + +encode(Cfg) -> encode(Cfg, fun (Text) -> Text end). + +encode(List, Translate) when is_list(List) -> + Fs = [case Opt of + {with, Val} -> [encode_with(Val, Translate)]; + {with, _, _} -> erlang:error({badarg, Opt}); + {start, Val} -> [encode_start(Val, Translate)]; + {start, _, _} -> erlang:error({badarg, Opt}); + {'end', Val} -> [encode_end(Val, Translate)]; + {'end', _, _} -> erlang:error({badarg, Opt}); + {withtext, Val} -> [encode_withtext(Val, Translate)]; + {withtext, _, _} -> erlang:error({badarg, Opt}); + #xdata_field{} -> [Opt]; + _ -> [] + end + || Opt <- List], + FormType = #xdata_field{var = <<"FORM_TYPE">>, + type = hidden, values = [<<"urn:xmpp:mam:1">>]}, + [FormType | lists:flatten(Fs)]. + +decode([#xdata_field{var = <<"with">>, values = [Value]} + | Fs], + Acc, Required) -> + try dec_jid(Value) of + Result -> + decode(Fs, [{with, Result} | Acc], + lists:delete(<<"with">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"with">>, <<"urn:xmpp:mam:1">>}}) + end; +decode([#xdata_field{var = <<"with">>, values = []} = F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"with">>, values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"with">>} | _], _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"with">>, <<"urn:xmpp:mam:1">>}}); +decode([#xdata_field{var = <<"start">>, + values = [Value]} + | Fs], + Acc, Required) -> + try xmpp_util:decode_timestamp(Value) of + Result -> + decode(Fs, [{start, Result} | Acc], + lists:delete(<<"start">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"start">>, <<"urn:xmpp:mam:1">>}}) + end; +decode([#xdata_field{var = <<"start">>, values = []} = F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"start">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"start">>} | _], _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"start">>, <<"urn:xmpp:mam:1">>}}); +decode([#xdata_field{var = <<"end">>, values = [Value]} + | Fs], + Acc, Required) -> + try xmpp_util:decode_timestamp(Value) of + Result -> + decode(Fs, [{'end', Result} | Acc], + lists:delete(<<"end">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"end">>, <<"urn:xmpp:mam:1">>}}) + end; +decode([#xdata_field{var = <<"end">>, values = []} = F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"end">>, values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"end">>} | _], _, _) -> + erlang:error({?MODULE, + {too_many_values, <<"end">>, <<"urn:xmpp:mam:1">>}}); +decode([#xdata_field{var = <<"withtext">>, + values = [Value]} + | Fs], + Acc, Required) -> + try Value of + Result -> + decode(Fs, [{withtext, Result} | Acc], + lists:delete(<<"withtext">>, Required)) + catch + _:_ -> + erlang:error({?MODULE, + {bad_var_value, <<"withtext">>, <<"urn:xmpp:mam:1">>}}) + end; +decode([#xdata_field{var = <<"withtext">>, + values = []} = + F + | Fs], + Acc, Required) -> + decode([F#xdata_field{var = <<"withtext">>, + values = [<<>>]} + | Fs], + Acc, Required); +decode([#xdata_field{var = <<"withtext">>} | _], _, + _) -> + erlang:error({?MODULE, + {too_many_values, <<"withtext">>, + <<"urn:xmpp:mam:1">>}}); +decode([#xdata_field{var = Var} | Fs], Acc, Required) -> + if Var /= <<"FORM_TYPE">> -> + erlang:error({?MODULE, + {unknown_var, Var, <<"urn:xmpp:mam:1">>}}); + true -> decode(Fs, Acc, Required) + end; +decode([], _, [Var | _]) -> + erlang:error({?MODULE, + {missing_required_var, Var, <<"urn:xmpp:mam:1">>}}); +decode([], Acc, []) -> Acc. + +encode_with(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [enc_jid(Value)] + end, + Opts = [], + #xdata_field{var = <<"with">>, values = Values, + required = false, type = 'jid-single', options = Opts, + desc = <<>>, label = Translate(<<"User JID">>)}. + +encode_start(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"start">>, values = Values, + required = false, type = 'text-single', options = Opts, + desc = <<>>, + label = Translate(<<"Search from the date">>)}. + +encode_end(Value, Translate) -> + Values = case Value of + undefined -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"end">>, values = Values, + required = false, type = 'text-single', options = Opts, + desc = <<>>, + label = Translate(<<"Search until the date">>)}. + +encode_withtext(Value, Translate) -> + Values = case Value of + <<>> -> []; + Value -> [Value] + end, + Opts = [], + #xdata_field{var = <<"withtext">>, values = Values, + required = false, type = 'text-single', options = Opts, + desc = <<>>, label = Translate(<<"Search the text">>)}. diff --git a/src/mod_carboncopy.erl b/src/mod_carboncopy.erl index 7d8ca5332..1c8ca1fdc 100644 --- a/src/mod_carboncopy.erl +++ b/src/mod_carboncopy.erl @@ -228,8 +228,8 @@ complete_packet(_From, Msg, _Direction) -> -spec is_chat_message(stanza()) -> boolean(). is_chat_message(#message{type = chat}) -> true; -is_chat_message(#message{type = normal, body = Body}) -> - xmpp:get_text(Body) /= <<"">>; +is_chat_message(#message{type = normal, body = [_|_]}) -> + true; is_chat_message(_) -> false. diff --git a/src/mod_mam.erl b/src/mod_mam.erl index f9ef104bd..61754ae59 100644 --- a/src/mod_mam.erl +++ b/src/mod_mam.erl @@ -54,12 +54,13 @@ -callback delete_old_messages(binary() | global, erlang:timestamp(), all | chat | groupchat) -> any(). --callback extended_fields() -> [xdata_field()]. +-callback extended_fields() -> [mam_query:property() | #xdata_field{}]. -callback store(xmlel(), binary(), {binary(), binary()}, chat | groupchat, jid(), binary(), recv | send) -> {ok, binary()} | any(). -callback write_prefs(binary(), binary(), #archive_prefs{}, binary()) -> ok | any(). -callback get_prefs(binary(), binary()) -> {ok, #archive_prefs{}} | error. --callback select(binary(), jid(), jid(), mam_query(), chat | groupchat) -> +-callback select(binary(), jid(), jid(), mam_query:result(), + #rsm_set{} | undefined, chat | groupchat) -> {[{binary(), non_neg_integer(), xmlel()}], boolean(), non_neg_integer()}. %%%=================================================================== @@ -259,8 +260,9 @@ muc_filter_message(Pkt, #state{config = Config} = MUCState, end. set_stanza_id(Pkt, JID, ID) -> - Archived = #mam_archived{by = JID, id = ID}, - StanzaID = #stanza_id{by = JID, id = ID}, + BareJID = jid:remove_resource(JID), + Archived = #mam_archived{by = BareJID, id = ID}, + StanzaID = #stanza_id{by = BareJID, id = ID}, NewEls = [Archived, StanzaID|xmpp:get_els(Pkt)], xmpp:set_els(Pkt, NewEls). @@ -308,43 +310,24 @@ muc_process_iq(#iq{type = get, muc_process_iq(IQ, _MUCState) -> IQ. -parse_query(#mam_query{xdata = #xdata{fields = Fs}} = Query, Lang) -> - try - lists:foldl( - fun(#xdata_field{var = <<"start">>, values = [Data|_]}, Q) -> - try xmpp_util:decode_timestamp(Data) of - {_, _, _} = TS -> Q#mam_query{start = TS} - catch _:{bad_timestamp, _} -> throw({error, <<"start">>}) - end; - (#xdata_field{var = <<"end">>, values = [Data|_]}, Q) -> - try xmpp_util:decode_timestamp(Data) of - {_, _, _} = TS -> Q#mam_query{start = TS} - catch _:{bad_timestamp, _} -> throw({error, <<"end">>}) - end; - (#xdata_field{var = <<"with">>, values = [Data|_]}, Q) -> - case jid:from_string(Data) of - error -> throw({error, <<"with">>}); - J -> Q#mam_query{with = J} - end; - (#xdata_field{var = <<"withtext">>, values = [Data|_]}, Q) -> - case Data of - <<"">> -> throw({error, <<"withtext">>}); - _ -> Q#mam_query{withtext = Data} - end; - (#xdata_field{var = <<"FORM_TYPE">>, values = [NS|_]}, Q) -> - case Query#mam_query.xmlns of - NS -> Q; - _ -> throw({error, <<"FORM_TYPE">>}) - end; - (#xdata_field{}, Acc) -> - Acc - end, Query, Fs) - catch throw:{error, Var} -> - Txt = io_lib:format("Incorrect value of field '~s'", [Var]), - {error, xmpp:err_bad_request(iolist_to_binary(Txt), Lang)} +parse_query(#mam_query{xmlns = ?NS_MAM_TMP, + start = Start, 'end' = End, + with = With, withtext = Text}, _Lang) -> + {ok, [{start, Start}, {'end', End}, + {with, With}, {withtext, Text}]}; +parse_query(#mam_query{xdata = #xdata{}} = Query, Lang) -> + X = xmpp_util:set_xdata_field( + #xdata_field{var = <<"FORM_TYPE">>, + type = hidden, values = [?NS_MAM_1]}, + Query#mam_query.xdata), + try mam_query:decode(X#xdata.fields) of + Form -> {ok, Form} + catch _:{mam_query, Why} -> + Txt = mam_query:format_error(Why), + {error, xmpp:err_bad_request(Txt, Lang)} end; -parse_query(Query, _Lang) -> - Query. +parse_query(#mam_query{}, _Lang) -> + {ok, []}. disco_sm_features(empty, From, To, Node, Lang) -> disco_sm_features({result, []}, From, To, Node, Lang); @@ -402,17 +385,16 @@ delete_old_messages(_TypeBin, _Days) -> %%%=================================================================== process_iq(LServer, #iq{sub_els = [#mam_query{xmlns = NS}]} = IQ) -> - CommonFields = [#xdata_field{type = hidden, - var = <<"FORM_TYPE">>, - values = [NS]}, - #xdata_field{type = 'jid-single', var = <<"with">>}, - #xdata_field{type = 'text-single', var = <<"start">>}, - #xdata_field{type = 'text-single', var = <<"end">>}], Mod = gen_mod:db_mod(LServer, ?MODULE), + CommonFields = [{with, undefined}, + {start, undefined}, + {'end', undefined}], ExtendedFields = Mod:extended_fields(), - Fields = CommonFields ++ ExtendedFields, - Form = #xdata{type = form, fields = Fields}, - xmpp:make_iq_result(IQ, #mam_query{xmlns = NS, xdata = Form}). + Fields = mam_query:encode(CommonFields ++ ExtendedFields), + X = xmpp_util:set_xdata_field( + #xdata_field{var = <<"FORM_TYPE">>, type = hidden, values = [NS]}, + #xdata{type = form, fields = Fields}), + xmpp:make_iq_result(IQ, #mam_query{xmlns = NS, xdata = X}). % Preference setting (both v0.2 & v0.3) process_iq(#iq{type = set, lang = Lang, @@ -457,15 +439,17 @@ process_iq(LServer, #iq{from = #jid{luser = LUser}, lang = Lang, {groupchat, _Role, _MUCState} -> ok end, - case parse_query(SubEl, Lang) of + case SubEl of #mam_query{rsm = #rsm_set{index = I}} when is_integer(I) -> xmpp:make_error(IQ, xmpp:err_feature_not_implemented()); - #mam_query{rsm = RSM, xmlns = NS} = Query -> - NewRSM = limit_max(RSM, NS), - NewQuery = Query#mam_query{rsm = NewRSM}, - select_and_send(LServer, NewQuery, IQ, MsgType); - {error, Err} -> - xmpp:make_error(IQ, Err) + #mam_query{rsm = RSM, xmlns = NS} -> + case parse_query(SubEl, Lang) of + {ok, Query} -> + NewRSM = limit_max(RSM, NS), + select_and_send(LServer, Query, NewRSM, IQ, MsgType); + {error, Err} -> + xmpp:make_error(IQ, Err) + end end. should_archive(#message{type = error}, _LServer) -> @@ -493,57 +477,57 @@ should_archive(_, _LServer) -> -spec strip_my_archived_tag(stanza(), binary()) -> stanza(). strip_my_archived_tag(Pkt, LServer) -> - NewPkt = xmpp:decode_els( - Pkt, ?NS_CLIENT, - fun(El) -> - case xmpp:get_name(El) of - <<"archived">> -> - xmpp:get_ns(El) == ?NS_MAM_TMP; - <<"stanza-id">> -> - xmpp:get_ns(El) == ?NS_SID_0; - _ -> - false - end - end), + Els = xmpp:get_els(Pkt), NewEls = lists:filter( - fun(#mam_archived{by = By}) -> - By#jid.lserver /= LServer; - (#stanza_id{by = By}) -> - By#jid.lserver /= LServer; - (_) -> - true - end, xmpp:get_els(NewPkt)), - xmpp:set_els(NewPkt, NewEls). + fun(El) -> + Name = xmpp:get_name(El), + NS = xmpp:get_ns(El), + if (Name == <<"archived">> andalso NS == ?NS_MAM_TMP); + (Name == <<"stanza-id">> andalso NS == ?NS_SID_0) -> + try xmpp:decode(El) of + #mam_archived{by = By} -> + By#jid.lserver /= LServer; + #stanza_id{by = By} -> + By#jid.lserver /= LServer + catch _:{xmpp_codec, _} -> + false + end; + true -> + true + end + end, Els), + xmpp:set_els(Pkt, NewEls). +-spec strip_x_jid_tags(stanza()) -> stanza(). strip_x_jid_tags(Pkt) -> - NewPkt = xmpp:decode_els( - Pkt, ?NS_CLIENT, + Els = xmpp:get_els(Pkt), + NewEls = lists:filter( fun(El) -> case xmpp:get_name(El) of <<"x">> -> - case xmpp:get_ns(El) of - ?NS_MUC_USER -> true; - ?NS_MUC_ADMIN -> true; - ?NS_MUC_OWNER -> true; - _ -> false - end; - _ -> - false - end - end), - NewEls = lists:filter( - fun(El) -> - Items = case El of - #muc_user{items = Is} -> Is; - #muc_admin{items = Is} -> Is; - #muc_owner{items = Is} -> Is; - _ -> [] - end, - not lists:any(fun(#muc_item{jid = JID}) -> + NS = xmpp:get_ns(El), + Items = if NS == ?NS_MUC_USER; + NS == ?NS_MUC_ADMIN; + NS == ?NS_MUC_OWNER -> + try xmpp:decode(El) of + #muc_user{items = Is} -> Is; + #muc_admin{items = Is} -> Is; + #muc_owner{items = Is} -> Is + catch _:{xmpp_codec, _} -> + [] + end; + true -> + [] + end, + not lists:any( + fun(#muc_item{jid = JID}) -> JID /= undefined - end, Items) - end, xmpp:get_els(NewPkt)), - xmpp:set_els(NewPkt, NewEls). + end, Items); + _ -> + true + end + end, Els), + xmpp:set_els(Pkt, NewEls). should_archive_peer(C2SState, #archive_prefs{default = Default, @@ -625,7 +609,7 @@ has_no_store_hint(Message) -> -spec is_resent(message(), binary()) -> boolean(). is_resent(Pkt, LServer) -> case xmpp:get_subtag(Pkt, #stanza_id{}) of - #stanza_id{by = #jid{luser = <<>>, lserver = LServer}} -> + #stanza_id{by = #jid{lserver = LServer}} -> true; _ -> false @@ -741,21 +725,22 @@ maybe_activate_mam(LUser, LServer) -> ok end. -select_and_send(LServer, Query, #iq{from = From, to = To} = IQ, MsgType) -> +select_and_send(LServer, Query, RSM, #iq{from = From, to = To} = IQ, MsgType) -> {Msgs, IsComplete, Count} = case MsgType of chat -> - select(LServer, From, From, Query, MsgType); + select(LServer, From, From, Query, RSM, MsgType); {groupchat, _Role, _MUCState} -> - select(LServer, From, To, Query, MsgType) + select(LServer, From, To, Query, RSM, MsgType) end, SortedMsgs = lists:keysort(2, Msgs), send(SortedMsgs, Count, IsComplete, IQ). -select(_LServer, JidRequestor, JidArchive, - #mam_query{start = Start, 'end' = End, rsm = RSM}, +select(_LServer, JidRequestor, JidArchive, Query, RSM, {groupchat, _Role, #state{config = #config{mam = false}, history = History}} = MsgType) -> + Start = proplists:get_value(start, Query), + End = proplists:get_value('end', Query), #lqueue{len = L, queue = Q} = History, Msgs = lists:flatmap( @@ -786,9 +771,9 @@ select(_LServer, JidRequestor, JidArchive, _ -> {Msgs, true, L} end; -select(LServer, JidRequestor, JidArchive, Query, MsgType) -> +select(LServer, JidRequestor, JidArchive, Query, RSM, MsgType) -> Mod = gen_mod:db_mod(LServer, ?MODULE), - Mod:select(LServer, JidRequestor, JidArchive, Query, MsgType). + Mod:select(LServer, JidRequestor, JidArchive, Query, RSM, MsgType). msg_to_el(#archive_msg{timestamp = TS, packet = Pkt1, nick = Nick, peer = Peer}, MsgType, JidRequestor, #jid{lserver = LServer} = JidArchive) -> diff --git a/src/mod_mam_mnesia.erl b/src/mod_mam_mnesia.erl index e913d5a45..8b9c6676c 100644 --- a/src/mod_mam_mnesia.erl +++ b/src/mod_mam_mnesia.erl @@ -12,7 +12,7 @@ %% API -export([init/2, remove_user/2, remove_room/3, delete_old_messages/3, - extended_fields/0, store/7, write_prefs/4, get_prefs/2, select/5]). + extended_fields/0, store/7, write_prefs/4, get_prefs/2, select/6]). -include_lib("stdlib/include/ms_transform.hrl"). -include("xmpp.hrl"). @@ -132,8 +132,10 @@ get_prefs(LUser, LServer) -> select(_LServer, JidRequestor, #jid{luser = LUser, lserver = LServer} = JidArchive, - #mam_query{start = Start, 'end' = End, - with = With, rsm = RSM}, MsgType) -> + Query, RSM, MsgType) -> + Start = proplists:get_value(start, Query), + End = proplists:get_value('end', Query), + With = proplists:get_value(with, Query), LWith = if With /= undefined -> jid:tolower(With); true -> undefined end, diff --git a/src/mod_mam_sql.erl b/src/mod_mam_sql.erl index 1491f70f2..c500745a3 100644 --- a/src/mod_mam_sql.erl +++ b/src/mod_mam_sql.erl @@ -14,7 +14,7 @@ %% API -export([init/2, remove_user/2, remove_room/3, delete_old_messages/3, - extended_fields/0, store/7, write_prefs/4, get_prefs/2, select/5]). + extended_fields/0, store/7, write_prefs/4, get_prefs/2, select/6]). -include_lib("stdlib/include/ms_transform.hrl"). -include("xmpp.hrl"). @@ -51,7 +51,7 @@ delete_old_messages(ServerHost, TimeStamp, Type) -> ok. extended_fields() -> - [#xdata_field{type = 'text-single', var = <<"withtext">>}]. + [{withtext, <<"">>}]. store(Pkt, LServer, {LUser, LHost}, Type, Peer, Nick, _Dir) -> TSinteger = p1_time_compat:system_time(micro_seconds), @@ -124,12 +124,12 @@ get_prefs(LUser, LServer) -> end. select(LServer, JidRequestor, #jid{luser = LUser} = JidArchive, - MAMQuery, MsgType) -> + MAMQuery, RSM, MsgType) -> User = case MsgType of chat -> LUser; {groupchat, _Role, _MUCState} -> jid:to_string(JidArchive) end, - {Query, CountQuery} = make_sql_query(User, LServer, MAMQuery), + {Query, CountQuery} = make_sql_query(User, LServer, MAMQuery, RSM), % TODO from XEP-0313 v0.2: "To conserve resources, a server MAY place a % reasonable limit on how many stanzas may be pushed to a client in one % request. If a query returns a number of stanzas greater than this limit @@ -139,7 +139,7 @@ select(LServer, JidRequestor, #jid{luser = LUser} = JidArchive, case {ejabberd_sql:sql_query(LServer, Query), ejabberd_sql:sql_query(LServer, CountQuery)} of {{selected, _, Res}, {selected, _, [[Count]]}} -> - {Max, Direction, _} = get_max_direction_id(MAMQuery#mam_query.rsm), + {Max, Direction, _} = get_max_direction_id(RSM), {Res1, IsComplete} = if Max >= 0 andalso Max /= undefined andalso length(Res) > Max -> if Direction == before -> @@ -194,9 +194,11 @@ usec_to_now(Int) -> Sec = Secs rem 1000000, {MSec, Sec, USec}. -make_sql_query(User, LServer, - #mam_query{start = Start, 'end' = End, with = With, - withtext = WithText, rsm = RSM}) -> +make_sql_query(User, LServer, MAMQuery, RSM) -> + Start = proplists:get_value(start, MAMQuery), + End = proplists:get_value('end', MAMQuery), + With = proplists:get_value(with, MAMQuery), + WithText = proplists:get_value(withtext, MAMQuery), {Max, Direction, ID} = get_max_direction_id(RSM), ODBCType = ejabberd_config:get_option( {sql_type, LServer}, diff --git a/src/mod_offline.erl b/src/mod_offline.erl index 2f6d52c36..d007bf3c6 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -99,7 +99,8 @@ -callback remove_expired_messages(binary()) -> {atomic, any()}. -callback remove_old_messages(non_neg_integer(), binary()) -> {atomic, any()}. -callback remove_user(binary(), binary()) -> {atomic, any()}. --callback read_message_headers(binary(), binary()) -> any(). +-callback read_message_headers(binary(), binary()) -> + [{non_neg_integer(), jid(), jid(), undefined | erlang:timestamp(), xmlel()}]. -callback read_message(binary(), binary(), non_neg_integer()) -> {ok, #offline_msg{}} | error. -callback remove_message(binary(), binary(), non_neg_integer()) -> ok | {error, any()}. diff --git a/src/mod_offline_riak.erl b/src/mod_offline_riak.erl index 241a8d650..24d565383 100644 --- a/src/mod_offline_riak.erl +++ b/src/mod_offline_riak.erl @@ -88,7 +88,7 @@ read_message_headers(LUser, LServer) -> fun(#offline_msg{from = From, to = To, packet = Pkt, timestamp = TS}) -> Seq = now_to_integer(TS), - {Seq, From, To, Pkt} + {Seq, From, To, TS, Pkt} end, Rs), lists:keysort(1, Hdrs); _Err -> diff --git a/src/mod_offline_sql.erl b/src/mod_offline_sql.erl index 2b7a40bff..025aa56f5 100644 --- a/src/mod_offline_sql.erl +++ b/src/mod_offline_sql.erl @@ -103,8 +103,9 @@ read_message_headers(LUser, LServer) -> case xml_to_offline_msg(XML) of {ok, #offline_msg{from = From, to = To, + timestamp = TS, packet = El}} -> - [{Seq, From, To, El}]; + [{Seq, From, To, TS, El}]; _ -> [] end diff --git a/src/mod_roster.erl b/src/mod_roster.erl index c344213f3..2da09d317 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -330,7 +330,7 @@ set_roster(#roster{us = {LUser, LServer}, jid = LJID} = Item) -> transaction( LServer, fun() -> - roster_subscribe_t(LUser, LServer, LJID, Item) + update_roster_t(LUser, LServer, LJID, Item) end). del_roster(LUser, LServer, LJID) -> diff --git a/src/muc_register.erl b/src/muc_register.erl index cddce2b98..c2b951dfc 100644 --- a/src/muc_register.erl +++ b/src/muc_register.erl @@ -12,7 +12,7 @@ -include("muc_register.hrl"). --export_type([{property, 0}, {result, 0}, {form, 0}]). +-export_type([property/0, result/0, form/0]). dec_bool(<<"1">>) -> true; dec_bool(<<"0">>) -> false; diff --git a/src/muc_request.erl b/src/muc_request.erl index 4c7becd2e..2d79ba0a5 100644 --- a/src/muc_request.erl +++ b/src/muc_request.erl @@ -12,7 +12,7 @@ -include("muc_request.hrl"). --export_type([{property, 0}, {result, 0}, {form, 0}]). +-export_type([property/0, result/0, form/0]). dec_enum(Val, Enums) -> AtomVal = erlang:binary_to_existing_atom(Val, utf8), diff --git a/src/muc_roomconfig.erl b/src/muc_roomconfig.erl index 73ceb649e..7d18bab66 100644 --- a/src/muc_roomconfig.erl +++ b/src/muc_roomconfig.erl @@ -12,7 +12,7 @@ -include("muc_roomconfig.hrl"). --export_type([{property, 0}, {result, 0}, {form, 0}]). +-export_type([property/0, result/0, form/0]). dec_int(Val, Min, Max) -> case list_to_integer(binary_to_list(Val)) of diff --git a/src/muc_roominfo.erl b/src/muc_roominfo.erl index 809dcef5b..bd5cb011b 100644 --- a/src/muc_roominfo.erl +++ b/src/muc_roominfo.erl @@ -12,7 +12,7 @@ -include("muc_roominfo.hrl"). --export_type([{property, 0}, {result, 0}, {form, 0}]). +-export_type([property/0, result/0, form/0]). dec_int(Val, Min, Max) -> case list_to_integer(binary_to_list(Val)) of diff --git a/src/pubsub_get_pending.erl b/src/pubsub_get_pending.erl index 1a7de6a2d..c1f2ba3ad 100644 --- a/src/pubsub_get_pending.erl +++ b/src/pubsub_get_pending.erl @@ -12,7 +12,7 @@ -include("pubsub_get_pending.hrl"). --export_type([{property, 0}, {result, 0}, {form, 0}]). +-export_type([property/0, result/0, form/0]). format_error({form_type_mismatch, Type}) -> <<"FORM_TYPE doesn't match '", Type/binary, "'">>; diff --git a/src/pubsub_node_config.erl b/src/pubsub_node_config.erl index 47ed10b49..e831d6a83 100644 --- a/src/pubsub_node_config.erl +++ b/src/pubsub_node_config.erl @@ -12,7 +12,7 @@ -include("pubsub_node_config.hrl"). --export_type([{property, 0}, {result, 0}, {form, 0}]). +-export_type([property/0, result/0, form/0]). dec_int(Val, Min, Max) -> case list_to_integer(binary_to_list(Val)) of diff --git a/src/pubsub_publish_options.erl b/src/pubsub_publish_options.erl index 8d0229071..6e96946fd 100644 --- a/src/pubsub_publish_options.erl +++ b/src/pubsub_publish_options.erl @@ -12,7 +12,7 @@ -include("pubsub_publish_options.hrl"). --export_type([{property, 0}, {result, 0}, {form, 0}]). +-export_type([property/0, result/0, form/0]). dec_enum(Val, Enums) -> AtomVal = erlang:binary_to_existing_atom(Val, utf8), diff --git a/src/pubsub_subscribe_authorization.erl b/src/pubsub_subscribe_authorization.erl index e019ed6b9..46538da8d 100644 --- a/src/pubsub_subscribe_authorization.erl +++ b/src/pubsub_subscribe_authorization.erl @@ -12,7 +12,7 @@ -include("pubsub_subscribe_authorization.hrl"). --export_type([{property, 0}, {result, 0}, {form, 0}]). +-export_type([property/0, result/0, form/0]). dec_bool(<<"1">>) -> true; dec_bool(<<"0">>) -> false; diff --git a/src/pubsub_subscribe_options.erl b/src/pubsub_subscribe_options.erl index 446a84a00..02c046995 100644 --- a/src/pubsub_subscribe_options.erl +++ b/src/pubsub_subscribe_options.erl @@ -12,7 +12,7 @@ -include("pubsub_subscribe_options.hrl"). --export_type([{property, 0}, {result, 0}, {form, 0}]). +-export_type([property/0, result/0, form/0]). dec_enum(Val, Enums) -> AtomVal = erlang:binary_to_existing_atom(Val, utf8), diff --git a/src/xmpp_util.erl b/src/xmpp_util.erl index 57440b50e..22b8ea597 100644 --- a/src/xmpp_util.erl +++ b/src/xmpp_util.erl @@ -11,7 +11,8 @@ %% API -export([add_delay_info/3, add_delay_info/4, unwrap_carbon/1, is_standalone_chat_state/1, get_xdata_values/2, - has_xdata_var/2, make_adhoc_response/1, make_adhoc_response/2, + set_xdata_field/2, has_xdata_var/2, + make_adhoc_response/1, make_adhoc_response/2, decode_timestamp/1, encode_timestamp/1]). -include("xmpp.hrl"). @@ -78,6 +79,12 @@ get_xdata_values(Var, #xdata{fields = Fields}) -> false -> [] end. +-spec set_xdata_field(xdata_field(), xdata()) -> xdata(). +set_xdata_field(Field, #xdata{fields = Fields} = X) -> + NewFields = lists:keystore(Field#xdata_field.var, #xdata_field.var, + Fields, Field), + X#xdata{fields = NewFields}. + -spec has_xdata_var(binary(), xdata()) -> boolean(). has_xdata_var(Var, #xdata{fields = Fields}) -> lists:keymember(Var, #xdata_field.var, Fields). diff --git a/test/announce_tests.erl b/test/announce_tests.erl new file mode 100644 index 000000000..3eea5298c --- /dev/null +++ b/test/announce_tests.erl @@ -0,0 +1,61 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 16 Nov 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(announce_tests). + +%% API +-compile(export_all). +-import(suite, [server_jid/1, send_recv/2, recv_message/1, disconnect/1, + send/2, wait_for_master/1, wait_for_slave/1]). + +-include("suite.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +%%%=================================================================== +%%% Single user tests +%%%=================================================================== +single_cases() -> + {announce_single, [sequence], []}. + +%%%=================================================================== +%%% Master-slave tests +%%%=================================================================== +master_slave_cases() -> + {announce_master_slave, [sequence], + [master_slave_test(set_motd)]}. + +set_motd_master(Config) -> + ServerJID = server_jid(Config), + MotdJID = jid:replace_resource(ServerJID, <<"announce/motd">>), + Body = xmpp:mk_text(<<"motd">>), + #presence{} = send_recv(Config, #presence{}), + wait_for_slave(Config), + send(Config, #message{to = MotdJID, body = Body}), + #message{from = ServerJID, body = Body} = recv_message(Config), + disconnect(Config). + +set_motd_slave(Config) -> + ServerJID = server_jid(Config), + Body = xmpp:mk_text(<<"motd">>), + #presence{} = send_recv(Config, #presence{}), + wait_for_master(Config), + #message{from = ServerJID, body = Body} = recv_message(Config), + disconnect(Config). + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +single_test(T) -> + list_to_atom("announce_" ++ atom_to_list(T)). + +master_slave_test(T) -> + {list_to_atom("announce_" ++ atom_to_list(T)), [parallel], + [list_to_atom("announce_" ++ atom_to_list(T) ++ "_master"), + list_to_atom("announce_" ++ atom_to_list(T) ++ "_slave")]}. diff --git a/test/carbons_tests.erl b/test/carbons_tests.erl new file mode 100644 index 000000000..2780dab66 --- /dev/null +++ b/test/carbons_tests.erl @@ -0,0 +1,202 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 16 Nov 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(carbons_tests). + +%% API +-compile(export_all). +-import(suite, [is_feature_advertised/2, disconnect/1, send_recv/2, + recv_presence/1, send/2, get_event/1, recv_message/1, + my_jid/1, wait_for_slave/1, wait_for_master/1, + put_event/2]). + +-include("suite.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +%%%=================================================================== +%%% Single user tests +%%%=================================================================== +single_cases() -> + {carbons_single, [sequence], + [single_test(feature_enabled), + single_test(unsupported_iq)]}. + +feature_enabled(Config) -> + true = is_feature_advertised(Config, ?NS_CARBONS_2), + disconnect(Config). + +unsupported_iq(Config) -> + lists:foreach( + fun({Type, SubEl}) -> + #iq{type = error} = + send_recv(Config, #iq{type = Type, sub_els = [SubEl]}) + end, [{Type, SubEl} || + Type <- [get, set], + SubEl <- [#carbons_sent{forwarded = #forwarded{}}, + #carbons_received{forwarded = #forwarded{}}, + #carbons_private{}]] ++ + [{get, SubEl} || SubEl <- [#carbons_enable{}, #carbons_disable{}]]), + disconnect(Config). + +%%%=================================================================== +%%% Master-slave tests +%%%=================================================================== +master_slave_cases() -> + {carbons_master_slave, [sequence], + [master_slave_test(send_recv), + master_slave_test(enable_disable)]}. + +send_recv_master(Config) -> + Peer = ?config(peer, Config), + prepare_master(Config), + ct:comment("Waiting for the peer to be ready"), + ready = get_event(Config), + send_messages(Config), + ct:comment("Waiting for the peer to disconnect"), + #presence{from = Peer, type = unavailable} = recv_presence(Config), + disconnect(Config). + +send_recv_slave(Config) -> + prepare_slave(Config), + ok = enable(Config), + put_event(Config, ready), + recv_carbons(Config), + disconnect(Config). + +enable_disable_master(Config) -> + prepare_master(Config), + ct:comment("Waiting for the peer to be ready"), + ready = get_event(Config), + send_messages(Config), + disconnect(Config). + +enable_disable_slave(Config) -> + Peer = ?config(peer, Config), + prepare_slave(Config), + ok = enable(Config), + ok = disable(Config), + put_event(Config, ready), + ct:comment("Waiting for the peer to disconnect"), + #presence{from = Peer, type = unavailable} = recv_presence(Config), + disconnect(Config). + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +single_test(T) -> + list_to_atom("carbons_" ++ atom_to_list(T)). + +master_slave_test(T) -> + {list_to_atom("carbons_" ++ atom_to_list(T)), [parallel], + [list_to_atom("carbons_" ++ atom_to_list(T) ++ "_master"), + list_to_atom("carbons_" ++ atom_to_list(T) ++ "_slave")]}. + +prepare_master(Config) -> + MyJID = my_jid(Config), + Peer = ?config(peer, Config), + #presence{from = MyJID} = send_recv(Config, #presence{priority = 10}), + wait_for_slave(Config), + ct:comment("Receiving initial presence from the peer"), + #presence{from = Peer} = recv_presence(Config), + Config. + +prepare_slave(Config) -> + Peer = ?config(peer, Config), + MyJID = my_jid(Config), + ok = enable(Config), + wait_for_master(Config), + #presence{from = MyJID} = send_recv(Config, #presence{priority = 5}), + ct:comment("Receiving initial presence from the peer"), + #presence{from = Peer} = recv_presence(Config), + Config. + +send_messages(Config) -> + Server = ?config(server, Config), + MyJID = my_jid(Config), + JID = jid:make(randoms:get_string(), Server), + lists:foreach( + fun({send, #message{type = Type} = Msg}) -> + I = send(Config, Msg#message{to = JID}), + if Type /= error -> + #message{id = I, type = error} = recv_message(Config); + true -> + ok + end; + ({recv, #message{} = Msg}) -> + ejabberd_router:route( + JID, MyJID, Msg#message{from = JID, to = MyJID}), + ct:comment("Receiving message ~s", [xmpp:pp(Msg)]), + #message{} = recv_message(Config) + end, message_iterator(Config)). + +recv_carbons(Config) -> + Peer = ?config(peer, Config), + BarePeer = jid:remove_resource(Peer), + MyJID = my_jid(Config), + lists:foreach( + fun({_, #message{sub_els = [#hint{type = 'no-copy'}]}}) -> + ok; + ({_, #message{sub_els = [#carbons_private{}]}}) -> + ok; + ({_, #message{sub_els = [#carbons_sent{}]}}) -> + ok; + ({_, #message{sub_els = [#carbons_received{}]}}) -> + ok; + ({_, #message{type = T}}) when T /= normal, T /= chat -> + ok; + ({Dir, #message{type = T, body = Body} = M}) + when (T == chat) or (T == normal andalso Body /= []) -> + ct:comment("Receiving carbon ~s", [xmpp:pp(M)]), + #message{from = BarePeer, to = MyJID} = CarbonMsg = + recv_message(Config), + case Dir of + send -> + #carbons_sent{forwarded = #forwarded{xml_els = [El]}} = + xmpp:get_subtag(CarbonMsg, #carbons_sent{}), + #message{body = Body} = xmpp:decode(El); + recv -> + #carbons_received{forwarded = #forwarded{xml_els = [El]}}= + xmpp:get_subtag(CarbonMsg, #carbons_received{}), + #message{body = Body} = xmpp:decode(El) + end; + (_) -> + false + end, message_iterator(Config)). + +enable(Config) -> + case send_recv( + Config, #iq{type = set, + sub_els = [#carbons_enable{}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = Err -> + xmpp:get_error(Err) + end. + +disable(Config) -> + case send_recv( + Config, #iq{type = set, + sub_els = [#carbons_disable{}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = Err -> + xmpp:get_error(Err) + end. + +message_iterator(_Config) -> + [{Dir, #message{type = Type, body = Body, sub_els = Els}} + || Dir <- [send, recv], + Type <- [error, chat, normal, groupchat, headline], + Body <- [[], xmpp:mk_text(<<"body">>)], + Els <- [[], + [#hint{type = 'no-copy'}], + [#carbons_private{}], + [#carbons_sent{forwarded = #forwarded{}}], + [#carbons_received{forwarded = #forwarded{}}]]]. diff --git a/test/csi_tests.erl b/test/csi_tests.erl new file mode 100644 index 000000000..9a96b8a59 --- /dev/null +++ b/test/csi_tests.erl @@ -0,0 +1,147 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 16 Nov 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(csi_tests). + +%% API +-compile(export_all). +-import(suite, [disconnect/1, wait_for_slave/1, wait_for_master/1, + send/2, send_recv/2, recv_presence/1, recv_message/1, + server_jid/1]). + +-include("suite.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +%%%=================================================================== +%%% Single user tests +%%%=================================================================== +single_cases() -> + {csi_single, [sequence], + [single_test(feature_enabled)]}. + +feature_enabled(Config) -> + true = ?config(csi, Config), + disconnect(Config). + +%%%=================================================================== +%%% Master-slave tests +%%%=================================================================== +master_slave_cases() -> + {csi_master_slave, [sequence], + [master_slave_test(all)]}. + +all_master(Config) -> + Peer = ?config(peer, Config), + Presence = #presence{to = Peer}, + ChatState = #message{to = Peer, thread = <<"1">>, + sub_els = [#chatstate{type = active}]}, + Message = ChatState#message{body = [#text{data = <<"body">>}]}, + PepPayload = xmpp:encode(#presence{}), + PepOne = #message{ + to = Peer, + sub_els = + [#ps_event{ + items = + #ps_items{ + node = <<"foo-1">>, + items = + [#ps_item{ + id = <<"pep-1">>, + xml_els = [PepPayload]}]}}]}, + PepTwo = #message{ + to = Peer, + sub_els = + [#ps_event{ + items = + #ps_items{ + node = <<"foo-2">>, + items = + [#ps_item{ + id = <<"pep-2">>, + xml_els = [PepPayload]}]}}]}, + %% Wait for the slave to become inactive. + wait_for_slave(Config), + %% Should be queued (but see below): + send(Config, Presence), + %% Should replace the previous presence in the queue: + send(Config, Presence#presence{type = unavailable}), + %% The following two PEP stanzas should be queued (but see below): + send(Config, PepOne), + send(Config, PepTwo), + %% The following two PEP stanzas should replace the previous two: + send(Config, PepOne), + send(Config, PepTwo), + %% Should be queued (but see below): + send(Config, ChatState), + %% Should replace the previous chat state in the queue: + send(Config, ChatState#message{sub_els = [#chatstate{type = composing}]}), + %% Should be sent immediately, together with the queued stanzas: + send(Config, Message), + %% Wait for the slave to become active. + wait_for_slave(Config), + %% Should be delivered, as the client is active again: + send(Config, ChatState), + disconnect(Config). + +all_slave(Config) -> + Peer = ?config(peer, Config), + change_client_state(Config, inactive), + wait_for_master(Config), + #presence{from = Peer, type = unavailable, sub_els = [#delay{}]} = + recv_presence(Config), + #message{ + from = Peer, + sub_els = + [#ps_event{ + items = + #ps_items{ + node = <<"foo-1">>, + items = + [#ps_item{ + id = <<"pep-1">>}]}}, + #delay{}]} = recv_message(Config), + #message{ + from = Peer, + sub_els = + [#ps_event{ + items = + #ps_items{ + node = <<"foo-2">>, + items = + [#ps_item{ + id = <<"pep-2">>}]}}, + #delay{}]} = recv_message(Config), + #message{from = Peer, thread = <<"1">>, + sub_els = [#chatstate{type = composing}, + #delay{}]} = recv_message(Config), + #message{from = Peer, thread = <<"1">>, + body = [#text{data = <<"body">>}], + sub_els = [#chatstate{type = active}]} = recv_message(Config), + change_client_state(Config, active), + wait_for_master(Config), + #message{from = Peer, thread = <<"1">>, + sub_els = [#chatstate{type = active}]} = recv_message(Config), + disconnect(Config). + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +single_test(T) -> + list_to_atom("csi_" ++ atom_to_list(T)). + +master_slave_test(T) -> + {list_to_atom("csi_" ++ atom_to_list(T)), [parallel], + [list_to_atom("csi_" ++ atom_to_list(T) ++ "_master"), + list_to_atom("csi_" ++ atom_to_list(T) ++ "_slave")]}. + +change_client_state(Config, NewState) -> + send(Config, #csi{type = NewState}), + send_recv(Config, #iq{type = get, to = server_jid(Config), + sub_els = [#ping{}]}). diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index 121719cdf..46711ad49 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -173,8 +173,13 @@ end_per_group(ldap, _Config) -> ok; end_per_group(extauth, _Config) -> ok; -end_per_group(riak, _Config) -> - ok; +end_per_group(riak, Config) -> + case ejabberd_riak:is_connected() of + true -> + clear_riak_tables(Config); + false -> + Config + end; end_per_group(component, _Config) -> ok; end_per_group(s2s, _Config) -> @@ -216,6 +221,8 @@ init_per_testcase(TestCase, OrigConfig) -> IsCarbons = lists:prefix("carbons_", Test), IsReplaced = lists:prefix("replaced_", Test), User = if IsReplaced -> <<"test_single!#$%^*()`~+-;_=[]{}|\\">>; + IsCarbons and not (IsMaster or IsSlave) -> + <<"test_single!#$%^*()`~+-;_=[]{}|\\">>; IsMaster or IsCarbons -> <<"test_master!#$%^*()`~+-;_=[]{}|\\">>; IsSlave -> <<"test_slave!#$%^*()`~+-;_=[]{}|\\">>; true -> <<"test_single!#$%^*()`~+-;_=[]{}|\\">> @@ -344,46 +351,12 @@ no_db_tests() -> s2s_optional, s2s_required, s2s_required_trusted]}, - {sm, [sequence], - [sm, - sm_resume, - sm_resume_failed]}, + sm_tests:single_cases(), muc_tests:single_cases(), muc_tests:master_slave_cases(), - {test_proxy65, [parallel], - [proxy65_master, proxy65_slave]}, - {replaced, [parallel], - [replaced_master, replaced_slave]}]. - -pubsub_single_tests() -> - {pubsub_single, [sequence], - [test_pubsub_features, - test_pubsub_create, - test_pubsub_configure, - test_pubsub_delete, - test_pubsub_get_affiliations, - test_pubsub_get_subscriptions, - test_pubsub_create_instant, - test_pubsub_default, - test_pubsub_create_configure, - test_pubsub_publish, - test_pubsub_auto_create, - test_pubsub_get_items, - test_pubsub_delete_item, - test_pubsub_purge, - test_pubsub_subscribe, - test_pubsub_unsubscribe]}. - -pubsub_multiple_tests() -> - {pubsub_multiple, [sequence], - [{pubsub_publish, [parallel], - [pubsub_publish_master, pubsub_publish_slave]}, - {pubsub_subscriptions, [parallel], - [pubsub_subscriptions_master, pubsub_subscriptions_slave]}, - {pubsub_affiliations, [parallel], - [pubsub_affiliations_master, pubsub_affiliations_slave]}, - {pubsub_authorize, [parallel], - [pubsub_authorize_master, pubsub_authorize_slave]}]}. + proxy65_tests:single_cases(), + proxy65_tests:master_slave_cases(), + replaced_tests:master_slave_cases()]. db_tests(riak) -> %% No support for mod_pubsub @@ -397,18 +370,16 @@ db_tests(riak) -> roster_tests:single_cases(), private, privacy_tests:single_cases(), - vcard, + vcard_tests:single_cases(), muc_tests:single_cases(), - offline_tests:master_slave_cases(), + offline_tests:single_cases(), test_unregister]}, muc_tests:master_slave_cases(), privacy_tests:master_slave_cases(), roster_tests:master_slave_cases(), offline_tests:master_slave_cases(), - {test_announce, [sequence], - [announce_master, announce_slave]}, - {test_vcard_xupdate, [parallel], - [vcard_xupdate_master, vcard_xupdate_slave]}]; + vcard_tests:master_slave_cases(), + announce_tests:master_slave_cases()]; db_tests(DB) when DB == mnesia; DB == redis -> [{single_user, [sequence], [test_register, @@ -420,32 +391,26 @@ db_tests(DB) when DB == mnesia; DB == redis -> roster_tests:single_cases(), private, privacy_tests:single_cases(), - vcard, - pubsub_single_tests(), + vcard_tests:single_cases(), + pubsub_tests:single_cases(), muc_tests:single_cases(), offline_tests:single_cases(), + mam_tests:single_cases(), + mix_tests:single_cases(), + carbons_tests:single_cases(), + csi_tests:single_cases(), test_unregister]}, muc_tests:master_slave_cases(), privacy_tests:master_slave_cases(), - pubsub_multiple_tests(), + pubsub_tests:master_slave_cases(), roster_tests:master_slave_cases(), offline_tests:master_slave_cases(), - {test_mix, [parallel], - [mix_master, mix_slave]}, - {test_old_mam, [parallel], - [mam_old_master, mam_old_slave]}, - {test_new_mam, [parallel], - [mam_new_master, mam_new_slave]}, - {test_carbons, [parallel], - [carbons_master, carbons_slave]}, - {test_client_state, [parallel], - [client_state_master, client_state_slave]}, - {test_muc_mam, [parallel], - [muc_mam_master, muc_mam_slave]}, - {test_announce, [sequence], - [announce_master, announce_slave]}, - {test_vcard_xupdate, [parallel], - [vcard_xupdate_master, vcard_xupdate_slave]}]; + mam_tests:master_slave_cases(), + mix_tests:master_slave_cases(), + vcard_tests:master_slave_cases(), + announce_tests:master_slave_cases(), + carbons_tests:master_slave_cases(), + csi_tests:master_slave_cases()]; db_tests(_) -> %% No support for carboncopy [{single_user, [sequence], @@ -458,28 +423,22 @@ db_tests(_) -> roster_tests:single_cases(), private, privacy_tests:single_cases(), - vcard, - pubsub_single_tests(), + vcard_tests:single_cases(), + pubsub_tests:single_cases(), muc_tests:single_cases(), offline_tests:single_cases(), + mam_tests:single_cases(), + mix_tests:single_cases(), test_unregister]}, muc_tests:master_slave_cases(), privacy_tests:master_slave_cases(), - pubsub_multiple_tests(), + pubsub_tests:master_slave_cases(), roster_tests:master_slave_cases(), offline_tests:master_slave_cases(), - {test_mix, [parallel], - [mix_master, mix_slave]}, - {test_old_mam, [parallel], - [mam_old_master, mam_old_slave]}, - {test_new_mam, [parallel], - [mam_new_master, mam_new_slave]}, - {test_muc_mam, [parallel], - [muc_mam_master, muc_mam_slave]}, - {test_announce, [sequence], - [announce_master, announce_slave]}, - {test_vcard_xupdate, [parallel], - [vcard_xupdate_master, vcard_xupdate_slave]}]. + mam_tests:master_slave_cases(), + mix_tests:master_slave_cases(), + vcard_tests:master_slave_cases(), + announce_tests:master_slave_cases()]. ldap_tests() -> [{ldap_tests, [sequence], @@ -839,27 +798,6 @@ test_bind(Config) -> test_open_session(Config) -> disconnect(open_session(Config, true)). -roster_feature_enabled(Config) -> - roster_tests:feature_enabled(Config). -roster_iq_set_many_items(Config) -> - roster_tests:iq_set_many_items(Config). -roster_iq_set_duplicated_groups(Config) -> - roster_tests:iq_set_duplicated_groups(Config). -roster_iq_set_ask(Config) -> - roster_tests:iq_set_ask(Config). -roster_iq_get_item(Config) -> - roster_tests:iq_get_item(Config). -roster_iq_unexpected_element(Config) -> - roster_tests:iq_unexpected_element(Config). -roster_set_item(Config) -> - roster_tests:set_item(Config). -roster_version(Config) -> - roster_tests:version(Config). -roster_subscribe_master(Config) -> - roster_tests:subscribe_master(Config). -roster_subscribe_slave(Config) -> - roster_tests:subscribe_slave(Config). - codec_failure(Config) -> JID = my_jid(Config), #iq{type = error} = @@ -969,74 +907,6 @@ disco(Config) -> end, Items), disconnect(Config). -%% replaced_master(Config0) -> -%% Config = bind(Config0), -%% wait_for_slave(Config), -%% ?recv1(#stream_error{reason = conflict}), -%% ?recv1({xmlstreamend, <<"stream:stream">>}), -%% close_socket(Config). - -%% replaced_slave(Config0) -> -%% wait_for_master(Config0), -%% Config = bind(Config0), -%% disconnect(Config). - -replaced_master(Config) -> - disconnect(Config). - -replaced_slave(Config) -> - disconnect(Config). - -sm(Config) -> - Server = ?config(server, Config), - ServerJID = jid:make(<<"">>, Server, <<"">>), - %% Send messages of type 'headline' so the server discards them silently - Msg = #message{to = ServerJID, type = headline, - body = [#text{data = <<"body">>}]}, - true = ?config(sm, Config), - %% Enable the session management with resumption enabled - send(Config, #sm_enable{resume = true, xmlns = ?NS_STREAM_MGMT_3}), - #sm_enabled{id = ID, resume = true} = recv(Config), - %% Initial request; 'h' should be 0. - send(Config, #sm_r{xmlns = ?NS_STREAM_MGMT_3}), - ?recv1(#sm_a{h = 0}), - %% sending two messages and requesting again; 'h' should be 3. - send(Config, Msg), - send(Config, Msg), - send(Config, Msg), - send(Config, #sm_r{xmlns = ?NS_STREAM_MGMT_3}), - ?recv1(#sm_a{h = 3}), - close_socket(Config), - {save_config, set_opt(sm_previd, ID, Config)}. - -sm_resume(Config) -> - {sm, SMConfig} = ?config(saved_config, Config), - ID = ?config(sm_previd, SMConfig), - Server = ?config(server, Config), - ServerJID = jid:make(<<"">>, Server, <<"">>), - MyJID = my_jid(Config), - Txt = #text{data = <<"body">>}, - Msg = #message{from = ServerJID, to = MyJID, body = [Txt]}, - %% Route message. The message should be queued by the C2S process. - ejabberd_router:route(ServerJID, MyJID, Msg), - send(Config, #sm_resume{previd = ID, h = 0, xmlns = ?NS_STREAM_MGMT_3}), - ?recv1(#sm_resumed{previd = ID, h = 3}), - #message{from = ServerJID, to = MyJID, body = [Txt]} = recv_message(Config), - ?recv1(#sm_r{}), - send(Config, #sm_a{h = 1, xmlns = ?NS_STREAM_MGMT_3}), - %% Send another stanza to increment the server's 'h' for sm_resume_failed. - send(Config, #presence{to = ServerJID}), - close_socket(Config), - {save_config, set_opt(sm_previd, ID, Config)}. - -sm_resume_failed(Config) -> - {sm_resume, SMConfig} = ?config(saved_config, Config), - ID = ?config(sm_previd, SMConfig), - ct:sleep(5000), % Wait for session to time out. - send(Config, #sm_resume{previd = ID, h = 1, xmlns = ?NS_STREAM_MGMT_3}), - ?recv1(#sm_failed{reason = 'item-not-found', h = 4}), - disconnect(Config). - private(Config) -> Conference = #bookmark_conference{name = <<"Some name">>, autojoin = true, @@ -1071,137 +941,6 @@ last(Config) -> to = server_jid(Config)}), disconnect(Config). -privacy_feature_enabled(Config) -> - privacy_tests:feature_enabled(Config). -privacy_set_get_list(Config) -> - privacy_tests:set_get_list(Config). -privacy_get_list_non_existent(Config) -> - privacy_tests:get_list_non_existent(Config). -privacy_set_default(Config) -> - privacy_tests:set_default(Config). -privacy_del_default(Config) -> - privacy_tests:del_default(Config). -privacy_set_default_non_existent(Config) -> - privacy_tests:set_default_non_existent(Config). -privacy_set_active(Config) -> - privacy_tests:set_active(Config). -privacy_del_active(Config) -> - privacy_tests:del_active(Config). -privacy_set_active_non_existent(Config) -> - privacy_tests:set_active_non_existent(Config). -privacy_remove_list(Config) -> - privacy_tests:remove_list(Config). -privacy_remove_active_list(Config) -> - privacy_tests:remove_active_list(Config). -privacy_remove_default_list(Config) -> - privacy_tests:remove_default_list(Config). -privacy_remove_list_non_existent(Config) -> - privacy_tests:remove_list_non_existent(Config). -privacy_allow_local_server(Config) -> - privacy_tests:allow_local_server(Config). -privacy_malformed_iq_query(Config) -> - privacy_tests:malformed_iq_query(Config). -privacy_malformed_get(Config) -> - privacy_tests:malformed_get(Config). -privacy_malformed_set(Config) -> - privacy_tests:malformed_set(Config). -privacy_malformed_type_value(Config) -> - privacy_tests:malformed_type_value(Config). -privacy_set_get_block(Config) -> - privacy_tests:set_get_block(Config). - -privacy_deny_bare_jid_master(Config) -> - privacy_tests:deny_bare_jid_master(Config). -privacy_deny_bare_jid_slave(Config) -> - privacy_tests:deny_bare_jid_slave(Config). -privacy_deny_full_jid_master(Config) -> - privacy_tests:deny_full_jid_master(Config). -privacy_deny_full_jid_slave(Config) -> - privacy_tests:deny_full_jid_slave(Config). -privacy_deny_server_jid_master(Config) -> - privacy_tests:deny_server_jid_master(Config). -privacy_deny_server_jid_slave(Config) -> - privacy_tests:deny_server_jid_slave(Config). -privacy_deny_group_master(Config) -> - privacy_tests:deny_group_master(Config). -privacy_deny_group_slave(Config) -> - privacy_tests:deny_group_slave(Config). -privacy_deny_sub_both_master(Config) -> - privacy_tests:deny_sub_both_master(Config). -privacy_deny_sub_both_slave(Config) -> - privacy_tests:deny_sub_both_slave(Config). -privacy_deny_sub_from_master(Config) -> - privacy_tests:deny_sub_from_master(Config). -privacy_deny_sub_from_slave(Config) -> - privacy_tests:deny_sub_from_slave(Config). -privacy_deny_sub_to_master(Config) -> - privacy_tests:deny_sub_to_master(Config). -privacy_deny_sub_to_slave(Config) -> - privacy_tests:deny_sub_to_slave(Config). -privacy_deny_sub_none_master(Config) -> - privacy_tests:deny_sub_none_master(Config). -privacy_deny_sub_none_slave(Config) -> - privacy_tests:deny_sub_none_slave(Config). -privacy_deny_all_master(Config) -> - privacy_tests:deny_all_master(Config). -privacy_deny_all_slave(Config) -> - privacy_tests:deny_all_slave(Config). -privacy_deny_offline_master(Config) -> - privacy_tests:deny_offline_master(Config). -privacy_deny_offline_slave(Config) -> - privacy_tests:deny_offline_slave(Config). -privacy_block_master(Config) -> - privacy_tests:block_master(Config). -privacy_block_slave(Config) -> - privacy_tests:block_slave(Config). -privacy_unblock_master(Config) -> - privacy_tests:unblock_master(Config). -privacy_unblock_slave(Config) -> - privacy_tests:unblock_slave(Config). -privacy_unblock_all_master(Config) -> - privacy_tests:unblock_all_master(Config). -privacy_unblock_all_slave(Config) -> - privacy_tests:unblock_all_slave(Config). - -vcard(Config) -> - true = is_feature_advertised(Config, ?NS_VCARD), - VCard = - #vcard_temp{fn = <<"Peter Saint-Andre">>, - n = #vcard_name{family = <<"Saint-Andre">>, - given = <<"Peter">>}, - nickname = <<"stpeter">>, - bday = <<"1966-08-06">>, - adr = [#vcard_adr{work = true, - extadd = <<"Suite 600">>, - street = <<"1899 Wynkoop Street">>, - locality = <<"Denver">>, - region = <<"CO">>, - pcode = <<"80202">>, - ctry = <<"USA">>}, - #vcard_adr{home = true, - locality = <<"Denver">>, - region = <<"CO">>, - pcode = <<"80209">>, - ctry = <<"USA">>}], - tel = [#vcard_tel{work = true,voice = true, - number = <<"303-308-3282">>}, - #vcard_tel{home = true,voice = true, - number = <<"303-555-1212">>}], - email = [#vcard_email{internet = true,pref = true, - userid = <<"stpeter@jabber.org">>}], - jabberid = <<"stpeter@jabber.org">>, - title = <<"Executive Director">>,role = <<"Patron Saint">>, - org = #vcard_org{name = <<"XMPP Standards Foundation">>}, - url = <<"http://www.xmpp.org/xsf/people/stpeter.shtml">>, - desc = <<"More information about me is located on my " - "personal website: http://www.saint-andre.com/">>}, - #iq{type = result, sub_els = []} = - send_recv(Config, #iq{type = set, sub_els = [VCard]}), - %% TODO: check if VCard == VCard1. - #iq{type = result, sub_els = [_VCard1]} = - send_recv(Config, #iq{type = get, sub_els = [#vcard_temp{}]}), - disconnect(Config). - vcard_get(Config) -> true = is_feature_advertised(Config, ?NS_VCARD), %% TODO: check if VCard corresponds to LDIF data from ejabberd.ldif @@ -1216,40 +955,6 @@ ldap_shared_roster_get(Config) -> send_recv(Config, #iq{type = get, sub_els = [#roster_query{}]}), disconnect(Config). -vcard_xupdate_master(Config) -> - Img = <<137, "PNG\r\n", 26, $\n>>, - ImgHash = p1_sha:sha(Img), - MyJID = my_jid(Config), - Peer = ?config(slave, Config), - wait_for_slave(Config), - #presence{from = MyJID, type = available} = send_recv(Config, #presence{}), - #presence{from = Peer, type = available} = recv_presence(Config), - VCard = #vcard_temp{photo = #vcard_photo{type = <<"image/png">>, binval = Img}}, - #iq{type = result, sub_els = []} = - send_recv(Config, #iq{type = set, sub_els = [VCard]}), - #presence{from = MyJID, type = available, - sub_els = [#vcard_xupdate{hash = ImgHash}]} = recv_presence(Config), - #iq{type = result, sub_els = []} = - send_recv(Config, #iq{type = set, sub_els = [#vcard_temp{}]}), - ?recv2(#presence{from = MyJID, type = available, - sub_els = [#vcard_xupdate{hash = undefined}]}, - #presence{from = Peer, type = unavailable}), - disconnect(Config). - -vcard_xupdate_slave(Config) -> - Img = <<137, "PNG\r\n", 26, $\n>>, - ImgHash = p1_sha:sha(Img), - MyJID = my_jid(Config), - Peer = ?config(master, Config), - #presence{from = MyJID, type = available} = send_recv(Config, #presence{}), - wait_for_master(Config), - #presence{from = Peer, type = available} = recv_presence(Config), - #presence{from = Peer, type = available, - sub_els = [#vcard_xupdate{hash = ImgHash}]} = recv_presence(Config), - #presence{from = Peer, type = available, - sub_els = [#vcard_xupdate{hash = undefined}]} = recv_presence(Config), - disconnect(Config). - stats(Config) -> #iq{type = result, sub_els = [#stats{list = Stats}]} = send_recv(Config, #iq{type = get, sub_els = [#stats{}], @@ -1263,1637 +968,9 @@ stats(Config) -> end, Stats), disconnect(Config). -test_pubsub_features(Config) -> - PJID = pubsub_jid(Config), - AllFeatures = sets:from_list(get_features(Config, PJID)), - NeededFeatures = sets:from_list( - [?NS_PUBSUB, - ?PUBSUB("access-open"), - ?PUBSUB("access-authorize"), - ?PUBSUB("create-nodes"), - ?PUBSUB("instant-nodes"), - ?PUBSUB("config-node"), - ?PUBSUB("retrieve-default"), - ?PUBSUB("create-and-configure"), - ?PUBSUB("publish"), - ?PUBSUB("auto-create"), - ?PUBSUB("retrieve-items"), - ?PUBSUB("delete-items"), - ?PUBSUB("subscribe"), - ?PUBSUB("retrieve-affiliations"), - ?PUBSUB("modify-affiliations"), - ?PUBSUB("retrieve-subscriptions"), - ?PUBSUB("manage-subscriptions"), - ?PUBSUB("purge-nodes"), - ?PUBSUB("delete-nodes")]), - true = sets:is_subset(NeededFeatures, AllFeatures), - disconnect(Config). - -test_pubsub_create(Config) -> - Node = ?config(pubsub_node, Config), - Node = create_node(Config, Node), - disconnect(Config). - -test_pubsub_create_instant(Config) -> - Node = create_node(Config, <<>>), - delete_node(Config, Node), - disconnect(Config). - -test_pubsub_configure(Config) -> - Node = ?config(pubsub_node, Config), - NodeTitle = ?config(pubsub_node_title, Config), - NodeConfig = get_node_config(Config, Node), - MyNodeConfig = set_opts(NodeConfig, - [{title, NodeTitle}]), - set_node_config(Config, Node, MyNodeConfig), - NewNodeConfig = get_node_config(Config, Node), - NodeTitle = proplists:get_value(title, NewNodeConfig), - disconnect(Config). - -test_pubsub_default(Config) -> - get_default_node_config(Config), - disconnect(Config). - -test_pubsub_create_configure(Config) -> - NodeTitle = ?config(pubsub_node_title, Config), - DefaultNodeConfig = get_default_node_config(Config), - CustomNodeConfig = set_opts(DefaultNodeConfig, - [{title, NodeTitle}]), - Node = create_node(Config, <<>>, CustomNodeConfig), - NodeConfig = get_node_config(Config, Node), - NodeTitle = proplists:get_value(title, NodeConfig), - delete_node(Config, Node), - disconnect(Config). - -test_pubsub_publish(Config) -> - Node = create_node(Config, <<>>), - publish_item(Config, Node), - delete_node(Config, Node), - disconnect(Config). - -test_pubsub_auto_create(Config) -> - Node = randoms:get_string(), - publish_item(Config, Node), - delete_node(Config, Node), - disconnect(Config). - -test_pubsub_get_items(Config) -> - Node = create_node(Config, <<>>), - ItemsIn = [publish_item(Config, Node) || _ <- lists:seq(1, 5)], - ItemsOut = get_items(Config, Node), - true = [I || #ps_item{id = I} <- lists:sort(ItemsIn)] - == [I || #ps_item{id = I} <- lists:sort(ItemsOut)], - delete_node(Config, Node), - disconnect(Config). - -test_pubsub_delete_item(Config) -> - Node = create_node(Config, <<>>), - #ps_item{id = I} = publish_item(Config, Node), - [#ps_item{id = I}] = get_items(Config, Node), - delete_item(Config, Node, I), - [] = get_items(Config, Node), - delete_node(Config, Node), - disconnect(Config). - -test_pubsub_subscribe(Config) -> - Node = create_node(Config, <<>>), - #ps_subscription{type = subscribed} = subscribe_node(Config, Node), - [#ps_subscription{node = Node}] = get_subscriptions(Config), - delete_node(Config, Node), - disconnect(Config). - -test_pubsub_unsubscribe(Config) -> - Node = create_node(Config, <<>>), - subscribe_node(Config, Node), - [#ps_subscription{node = Node}] = get_subscriptions(Config), - unsubscribe_node(Config, Node), - [] = get_subscriptions(Config), - delete_node(Config, Node), - disconnect(Config). - -test_pubsub_get_affiliations(Config) -> - Nodes = lists:sort([create_node(Config, <<>>) || _ <- lists:seq(1, 5)]), - Affs = get_affiliations(Config), - Nodes = lists:sort([Node || #ps_affiliation{node = Node, - type = owner} <- Affs]), - [delete_node(Config, Node) || Node <- Nodes], - disconnect(Config). - -test_pubsub_get_subscriptions(Config) -> - Nodes = lists:sort([create_node(Config, <<>>) || _ <- lists:seq(1, 5)]), - [subscribe_node(Config, Node) || Node <- Nodes], - Subs = get_subscriptions(Config), - Nodes = lists:sort([Node || #ps_subscription{node = Node} <- Subs]), - [delete_node(Config, Node) || Node <- Nodes], - disconnect(Config). - -test_pubsub_purge(Config) -> - Node = create_node(Config, <<>>), - ItemsIn = [publish_item(Config, Node) || _ <- lists:seq(1, 5)], - ItemsOut = get_items(Config, Node), - true = [I || #ps_item{id = I} <- lists:sort(ItemsIn)] - == [I || #ps_item{id = I} <- lists:sort(ItemsOut)], - purge_node(Config, Node), - [] = get_items(Config, Node), - delete_node(Config, Node), - disconnect(Config). - -test_pubsub_delete(Config) -> - Node = ?config(pubsub_node, Config), - delete_node(Config, Node), - disconnect(Config). - -pubsub_publish_master(Config) -> - Node = create_node(Config, <<>>), - put_event(Config, Node), - wait_for_slave(Config), - #ps_item{id = ID} = publish_item(Config, Node), - #ps_item{id = ID} = get_event(Config), - delete_node(Config, Node), - disconnect(Config). - -pubsub_publish_slave(Config) -> - Node = get_event(Config), - subscribe_node(Config, Node), - wait_for_master(Config), - #message{ - sub_els = - [#ps_event{ - items = #ps_items{node = Node, - items = [Item]}}]} = recv_message(Config), - put_event(Config, Item), - disconnect(Config). - -pubsub_subscriptions_master(Config) -> - Peer = ?config(slave, Config), - Node = ?config(pubsub_node, Config), - Node = create_node(Config, Node), - [] = get_subscriptions(Config, Node), - wait_for_slave(Config), - lists:foreach( - fun(Type) -> - ok = set_subscriptions(Config, Node, [{Peer, Type}]), - #ps_item{} = publish_item(Config, Node), - case get_subscriptions(Config, Node) of - [] when Type == none; Type == pending -> - ok; - [#ps_subscription{jid = Peer, type = Type}] -> - ok - end - end, [subscribed, unconfigured, pending, none]), - delete_node(Config, Node), - disconnect(Config). - -pubsub_subscriptions_slave(Config) -> - wait_for_master(Config), - MyJID = my_jid(Config), - Node = ?config(pubsub_node, Config), - lists:foreach( - fun(subscribed = Type) -> - ?recv2(#message{ - sub_els = - [#ps_event{ - subscription = #ps_subscription{ - node = Node, - jid = MyJID, - type = Type}}]}, - #message{sub_els = [#ps_event{}]}); - (Type) -> - #message{ - sub_els = - [#ps_event{ - subscription = #ps_subscription{ - node = Node, - jid = MyJID, - type = Type}}]} = - recv_message(Config) - end, [subscribed, unconfigured, pending, none]), - disconnect(Config). - -pubsub_affiliations_master(Config) -> - Peer = ?config(slave, Config), - BarePeer = jid:remove_resource(Peer), - lists:foreach( - fun(Aff) -> - Node = <<(atom_to_binary(Aff, utf8))/binary, - $-, (randoms:get_string())/binary>>, - create_node(Config, Node, default_node_config(Config)), - #ps_item{id = I} = publish_item(Config, Node), - ok = set_affiliations(Config, Node, [{Peer, Aff}]), - Affs = get_affiliations(Config, Node), - case lists:keyfind(BarePeer, #ps_affiliation.jid, Affs) of - false when Aff == none -> - ok; - #ps_affiliation{type = Aff} -> - ok - end, - put_event(Config, {Aff, Node, I}), - wait_for_slave(Config), - delete_node(Config, Node) - end, [outcast, none, member, publish_only, publisher, owner]), - put_event(Config, disconnect), - disconnect(Config). - -pubsub_affiliations_slave(Config) -> - pubsub_affiliations_slave(Config, get_event(Config)). - -pubsub_affiliations_slave(Config, {outcast, Node, ItemID}) -> - #stanza_error{reason = 'forbidden'} = subscribe_node(Config, Node), - #stanza_error{} = unsubscribe_node(Config, Node), - #stanza_error{reason = 'forbidden'} = get_items(Config, Node), - #stanza_error{reason = 'forbidden'} = publish_item(Config, Node), - #stanza_error{reason = 'forbidden'} = delete_item(Config, Node, ItemID), - #stanza_error{reason = 'forbidden'} = purge_node(Config, Node), - #stanza_error{reason = 'forbidden'} = get_node_config(Config, Node), - #stanza_error{reason = 'forbidden'} = - set_node_config(Config, Node, default_node_config(Config)), - #stanza_error{reason = 'forbidden'} = get_subscriptions(Config, Node), - #stanza_error{reason = 'forbidden'} = - set_subscriptions(Config, Node, [{my_jid(Config), subscribed}]), - #stanza_error{reason = 'forbidden'} = get_affiliations(Config, Node), - #stanza_error{reason = 'forbidden'} = - set_affiliations(Config, Node, [{?config(master, Config), outcast}, - {my_jid(Config), owner}]), - #stanza_error{reason = 'forbidden'} = delete_node(Config, Node), - wait_for_master(Config), - pubsub_affiliations_slave(Config, get_event(Config)); -pubsub_affiliations_slave(Config, {none, Node, ItemID}) -> - #ps_subscription{type = subscribed} = subscribe_node(Config, Node), - ok = unsubscribe_node(Config, Node), - %% This violates the affiliation char from section 4.1 - [_|_] = get_items(Config, Node), - #stanza_error{reason = 'forbidden'} = publish_item(Config, Node), - #stanza_error{reason = 'forbidden'} = delete_item(Config, Node, ItemID), - #stanza_error{reason = 'forbidden'} = purge_node(Config, Node), - #stanza_error{reason = 'forbidden'} = get_node_config(Config, Node), - #stanza_error{reason = 'forbidden'} = - set_node_config(Config, Node, default_node_config(Config)), - #stanza_error{reason = 'forbidden'} = get_subscriptions(Config, Node), - #stanza_error{reason = 'forbidden'} = - set_subscriptions(Config, Node, [{my_jid(Config), subscribed}]), - #stanza_error{reason = 'forbidden'} = get_affiliations(Config, Node), - #stanza_error{reason = 'forbidden'} = - set_affiliations(Config, Node, [{?config(master, Config), outcast}, - {my_jid(Config), owner}]), - #stanza_error{reason = 'forbidden'} = delete_node(Config, Node), - wait_for_master(Config), - pubsub_affiliations_slave(Config, get_event(Config)); -pubsub_affiliations_slave(Config, {member, Node, ItemID}) -> - #ps_subscription{type = subscribed} = subscribe_node(Config, Node), - ok = unsubscribe_node(Config, Node), - [_|_] = get_items(Config, Node), - #stanza_error{reason = 'forbidden'} = publish_item(Config, Node), - #stanza_error{reason = 'forbidden'} = delete_item(Config, Node, ItemID), - #stanza_error{reason = 'forbidden'} = purge_node(Config, Node), - #stanza_error{reason = 'forbidden'} = get_node_config(Config, Node), - #stanza_error{reason = 'forbidden'} = - set_node_config(Config, Node, default_node_config(Config)), - #stanza_error{reason = 'forbidden'} = get_subscriptions(Config, Node), - #stanza_error{reason = 'forbidden'} = - set_subscriptions(Config, Node, [{my_jid(Config), subscribed}]), - #stanza_error{reason = 'forbidden'} = get_affiliations(Config, Node), - #stanza_error{reason = 'forbidden'} = - set_affiliations(Config, Node, [{?config(master, Config), outcast}, - {my_jid(Config), owner}]), - #stanza_error{reason = 'forbidden'} = delete_node(Config, Node), - wait_for_master(Config), - pubsub_affiliations_slave(Config, get_event(Config)); -pubsub_affiliations_slave(Config, {publish_only, Node, ItemID}) -> - #stanza_error{reason = 'forbidden'} = subscribe_node(Config, Node), - #stanza_error{} = unsubscribe_node(Config, Node), - #stanza_error{reason = 'forbidden'} = get_items(Config, Node), - #ps_item{id = MyItemID} = publish_item(Config, Node), - %% BUG: This should be fixed - %% ?match(ok, delete_item(Config, Node, MyItemID)), - #stanza_error{reason = 'forbidden'} = delete_item(Config, Node, ItemID), - #stanza_error{reason = 'forbidden'} = purge_node(Config, Node), - #stanza_error{reason = 'forbidden'} = get_node_config(Config, Node), - #stanza_error{reason = 'forbidden'} = - set_node_config(Config, Node, default_node_config(Config)), - #stanza_error{reason = 'forbidden'} = get_subscriptions(Config, Node), - #stanza_error{reason = 'forbidden'} = - set_subscriptions(Config, Node, [{my_jid(Config), subscribed}]), - #stanza_error{reason = 'forbidden'} = get_affiliations(Config, Node), - #stanza_error{reason = 'forbidden'} = - set_affiliations(Config, Node, [{?config(master, Config), outcast}, - {my_jid(Config), owner}]), - #stanza_error{reason = 'forbidden'} = delete_node(Config, Node), - wait_for_master(Config), - pubsub_affiliations_slave(Config, get_event(Config)); -pubsub_affiliations_slave(Config, {publisher, Node, ItemID}) -> - #ps_subscription{type = subscribed} = subscribe_node(Config, Node), - ok = unsubscribe_node(Config, Node), - [_|_] = get_items(Config, Node), - #ps_item{id = MyItemID} = publish_item(Config, Node), - ok = delete_item(Config, Node, MyItemID), - %% BUG: this should be fixed - %% #stanza_error{reason = 'forbidden'} = delete_item(Config, Node, ItemID), - #stanza_error{reason = 'forbidden'} = purge_node(Config, Node), - #stanza_error{reason = 'forbidden'} = get_node_config(Config, Node), - #stanza_error{reason = 'forbidden'} = - set_node_config(Config, Node, default_node_config(Config)), - #stanza_error{reason = 'forbidden'} = get_subscriptions(Config, Node), - #stanza_error{reason = 'forbidden'} = - set_subscriptions(Config, Node, [{my_jid(Config), subscribed}]), - #stanza_error{reason = 'forbidden'} = get_affiliations(Config, Node), - #stanza_error{reason = 'forbidden'} = - set_affiliations(Config, Node, [{?config(master, Config), outcast}, - {my_jid(Config), owner}]), - #stanza_error{reason = 'forbidden'} = delete_node(Config, Node), - wait_for_master(Config), - pubsub_affiliations_slave(Config, get_event(Config)); -pubsub_affiliations_slave(Config, {owner, Node, ItemID}) -> - MyJID = my_jid(Config), - Peer = ?config(master, Config), - #ps_subscription{type = subscribed} = subscribe_node(Config, Node), - ok = unsubscribe_node(Config, Node), - [_|_] = get_items(Config, Node), - #ps_item{id = MyItemID} = publish_item(Config, Node), - ok = delete_item(Config, Node, MyItemID), - ok = delete_item(Config, Node, ItemID), - ok = purge_node(Config, Node), - [_|_] = get_node_config(Config, Node), - ok = set_node_config(Config, Node, default_node_config(Config)), - ok = set_subscriptions(Config, Node, []), - [] = get_subscriptions(Config, Node), - ok = set_affiliations(Config, Node, [{Peer, outcast}, {MyJID, owner}]), - [_, _] = get_affiliations(Config, Node), - ok = delete_node(Config, Node), - wait_for_master(Config), - pubsub_affiliations_slave(Config, get_event(Config)); -pubsub_affiliations_slave(Config, disconnect) -> - disconnect(Config). - -pubsub_authorize_master(Config) -> - send(Config, #presence{}), - #presence{} = recv_presence(Config), - Peer = ?config(slave, Config), - PJID = pubsub_jid(Config), - NodeConfig = set_opts(default_node_config(Config), - [{access_model, authorize}]), - Node = ?config(pubsub_node, Config), - Node = create_node(Config, Node, NodeConfig), - wait_for_slave(Config), - #message{sub_els = [#xdata{fields = F1}]} = recv_message(Config), - C1 = pubsub_subscribe_authorization:decode(F1), - Node = proplists:get_value(node, C1), - Peer = proplists:get_value(subscriber_jid, C1), - %% Deny it at first - Deny = #xdata{type = submit, - fields = pubsub_subscribe_authorization:encode( - [{node, Node}, - {subscriber_jid, Peer}, - {allow, false}])}, - send(Config, #message{to = PJID, sub_els = [Deny]}), - %% We should not have any subscriptions - [] = get_subscriptions(Config, Node), - wait_for_slave(Config), - #message{sub_els = [#xdata{fields = F2}]} = recv_message(Config), - C2 = pubsub_subscribe_authorization:decode(F2), - Node = proplists:get_value(node, C2), - Peer = proplists:get_value(subscriber_jid, C2), - %% Now we accept is as the peer is very insisting ;) - Approve = #xdata{type = submit, - fields = pubsub_subscribe_authorization:encode( - [{node, Node}, - {subscriber_jid, Peer}, - {allow, true}])}, - send(Config, #message{to = PJID, sub_els = [Approve]}), - wait_for_slave(Config), - delete_node(Config, Node), - disconnect(Config). - -pubsub_authorize_slave(Config) -> - Node = ?config(pubsub_node, Config), - MyJID = my_jid(Config), - wait_for_master(Config), - #ps_subscription{type = pending} = subscribe_node(Config, Node), - %% We're denied at first - #message{ - sub_els = - [#ps_event{ - subscription = #ps_subscription{type = none, - jid = MyJID}}]} = - recv_message(Config), - wait_for_master(Config), - #ps_subscription{type = pending} = subscribe_node(Config, Node), - %% Now much better! - #message{ - sub_els = - [#ps_event{ - subscription = #ps_subscription{type = subscribed, - jid = MyJID}}]} = - recv_message(Config), - wait_for_master(Config), - disconnect(Config). - -create_node(Config, Node) -> - create_node(Config, Node, undefined). - -create_node(Config, Node, Options) -> - PJID = pubsub_jid(Config), - NodeConfig = if is_list(Options) -> - #xdata{type = submit, - fields = pubsub_node_config:encode(Options)}; - true -> - undefined - end, - case send_recv(Config, - #iq{type = set, to = PJID, - sub_els = [#pubsub{create = Node, - configure = {<<>>, NodeConfig}}]}) of - #iq{type = result, sub_els = [#pubsub{create = NewNode}]} -> - NewNode; - #iq{type = error} = IQ -> - xmpp:get_subtag(IQ, #stanza_error{}) - end. - -delete_node(Config, Node) -> - PJID = pubsub_jid(Config), - case send_recv(Config, - #iq{type = set, to = PJID, - sub_els = [#pubsub_owner{delete = {Node, <<>>}}]}) of - #iq{type = result, sub_els = []} -> - ok; - #iq{type = error} = IQ -> - xmpp:get_subtag(IQ, #stanza_error{}) - end. - -purge_node(Config, Node) -> - PJID = pubsub_jid(Config), - case send_recv(Config, - #iq{type = set, to = PJID, - sub_els = [#pubsub_owner{purge = Node}]}) of - #iq{type = result, sub_els = []} -> - ok; - #iq{type = error} = IQ -> - xmpp:get_subtag(IQ, #stanza_error{}) - end. - -get_default_node_config(Config) -> - PJID = pubsub_jid(Config), - case send_recv(Config, - #iq{type = get, to = PJID, - sub_els = [#pubsub_owner{default = {<<>>, undefined}}]}) of - #iq{type = result, - sub_els = [#pubsub_owner{default = {<<>>, NodeConfig}}]} -> - pubsub_node_config:decode(NodeConfig#xdata.fields); - #iq{type = error} = IQ -> - xmpp:get_subtag(IQ, #stanza_error{}) - end. - -get_node_config(Config, Node) -> - PJID = pubsub_jid(Config), - case send_recv(Config, - #iq{type = get, to = PJID, - sub_els = [#pubsub_owner{configure = {Node, undefined}}]}) of - #iq{type = result, - sub_els = [#pubsub_owner{configure = {Node, NodeConfig}}]} -> - pubsub_node_config:decode(NodeConfig#xdata.fields); - #iq{type = error} = IQ -> - xmpp:get_subtag(IQ, #stanza_error{}) - end. - -set_node_config(Config, Node, Options) -> - PJID = pubsub_jid(Config), - NodeConfig = #xdata{type = submit, - fields = pubsub_node_config:encode(Options)}, - case send_recv(Config, - #iq{type = set, to = PJID, - sub_els = [#pubsub_owner{configure = - {Node, NodeConfig}}]}) of - #iq{type = result, sub_els = []} -> - ok; - #iq{type = error} = IQ -> - xmpp:get_subtag(IQ, #stanza_error{}) - end. - -publish_item(Config, Node) -> - PJID = pubsub_jid(Config), - ItemID = randoms:get_string(), - Item = #ps_item{id = ItemID, xml_els = [xmpp:encode(#presence{id = ItemID})]}, - case send_recv(Config, - #iq{type = set, to = PJID, - sub_els = [#pubsub{publish = #ps_publish{ - node = Node, - items = [Item]}}]}) of - #iq{type = result, - sub_els = [#pubsub{publish = #ps_publish{ - node = Node, - items = [#ps_item{id = ItemID}]}}]} -> - Item; - #iq{type = error} = IQ -> - xmpp:get_subtag(IQ, #stanza_error{}) - end. - -get_items(Config, Node) -> - PJID = pubsub_jid(Config), - case send_recv(Config, - #iq{type = get, to = PJID, - sub_els = [#pubsub{items = #ps_items{node = Node}}]}) of - #iq{type = result, - sub_els = [#pubsub{items = #ps_items{node = Node, items = Items}}]} -> - Items; - #iq{type = error} = IQ -> - xmpp:get_subtag(IQ, #stanza_error{}) - end. - -delete_item(Config, Node, I) -> - PJID = pubsub_jid(Config), - case send_recv(Config, - #iq{type = set, to = PJID, - sub_els = [#pubsub{retract = - #ps_retract{ - node = Node, - items = [#ps_item{id = I}]}}]}) of - #iq{type = result, sub_els = []} -> - ok; - #iq{type = error} = IQ -> - xmpp:get_subtag(IQ, #stanza_error{}) - end. - -subscribe_node(Config, Node) -> - PJID = pubsub_jid(Config), - MyJID = my_jid(Config), - case send_recv(Config, - #iq{type = set, to = PJID, - sub_els = [#pubsub{subscribe = #ps_subscribe{ - node = Node, - jid = MyJID}}]}) of - #iq{type = result, - sub_els = [#pubsub{ - subscription = #ps_subscription{ - node = Node, - jid = MyJID} = Sub}]} -> - Sub; - #iq{type = error} = IQ -> - xmpp:get_subtag(IQ, #stanza_error{}) - end. - -unsubscribe_node(Config, Node) -> - PJID = pubsub_jid(Config), - MyJID = my_jid(Config), - case send_recv(Config, - #iq{type = set, to = PJID, - sub_els = [#pubsub{ - unsubscribe = #ps_unsubscribe{ - node = Node, - jid = MyJID}}]}) of - #iq{type = result, sub_els = []} -> - ok; - #iq{type = error} = IQ -> - xmpp:get_subtag(IQ, #stanza_error{}) - end. - -get_affiliations(Config) -> - PJID = pubsub_jid(Config), - case send_recv(Config, - #iq{type = get, to = PJID, - sub_els = [#pubsub{affiliations = {<<>>, []}}]}) of - #iq{type = result, - sub_els = [#pubsub{affiliations = {<<>>, Affs}}]} -> - Affs; - #iq{type = error} = IQ -> - xmpp:get_subtag(IQ, #stanza_error{}) - end. - -get_affiliations(Config, Node) -> - PJID = pubsub_jid(Config), - case send_recv(Config, - #iq{type = get, to = PJID, - sub_els = [#pubsub_owner{affiliations = {Node, []}}]}) of - #iq{type = result, - sub_els = [#pubsub_owner{affiliations = {Node, Affs}}]} -> - Affs; - #iq{type = error} = IQ -> - xmpp:get_subtag(IQ, #stanza_error{}) - end. - -set_affiliations(Config, Node, JTs) -> - PJID = pubsub_jid(Config), - Affs = [#ps_affiliation{jid = J, type = T} || {J, T} <- JTs], - case send_recv(Config, - #iq{type = set, to = PJID, - sub_els = [#pubsub_owner{affiliations = - {Node, Affs}}]}) of - #iq{type = result, sub_els = []} -> - ok; - #iq{type = error} = IQ -> - xmpp:get_subtag(IQ, #stanza_error{}) - end. - -get_subscriptions(Config) -> - PJID = pubsub_jid(Config), - case send_recv(Config, - #iq{type = get, to = PJID, - sub_els = [#pubsub{subscriptions = {<<>>, []}}]}) of - #iq{type = result, sub_els = [#pubsub{subscriptions = {<<>>, Subs}}]} -> - Subs; - #iq{type = error} = IQ -> - xmpp:get_subtag(IQ, #stanza_error{}) - end. - -get_subscriptions(Config, Node) -> - PJID = pubsub_jid(Config), - case send_recv(Config, - #iq{type = get, to = PJID, - sub_els = [#pubsub_owner{subscriptions = {Node, []}}]}) of - #iq{type = result, - sub_els = [#pubsub_owner{subscriptions = {Node, Subs}}]} -> - Subs; - #iq{type = error} = IQ -> - xmpp:get_subtag(IQ, #stanza_error{}) - end. - -set_subscriptions(Config, Node, JTs) -> - PJID = pubsub_jid(Config), - Subs = [#ps_subscription{jid = J, type = T} || {J, T} <- JTs], - case send_recv(Config, - #iq{type = set, to = PJID, - sub_els = [#pubsub_owner{subscriptions = - {Node, Subs}}]}) of - #iq{type = result, sub_els = []} -> - ok; - #iq{type = error} = IQ -> - xmpp:get_subtag(IQ, #stanza_error{}) - end. - -default_node_config(Config) -> - [{title, ?config(pubsub_node_title, Config)}, - {notify_delete, false}, - {send_last_published_item, never}]. - -mix_master(Config) -> - MIX = mix_jid(Config), - Room = mix_room_jid(Config), - MyJID = my_jid(Config), - MyBareJID = jid:remove_resource(MyJID), - true = is_feature_advertised(Config, ?NS_MIX_0, MIX), - #iq{type = result, - sub_els = - [#disco_info{ - identities = [#identity{category = <<"conference">>, - type = <<"text">>}], - xdata = [#xdata{type = result, fields = XFields}]}]} = - send_recv(Config, #iq{type = get, to = MIX, sub_els = [#disco_info{}]}), - true = lists:any( - fun(#xdata_field{var = <<"FORM_TYPE">>, - values = [?NS_MIX_SERVICEINFO_0]}) -> true; - (_) -> false - end, XFields), - %% Joining - Nodes = [?NS_MIX_NODES_MESSAGES, ?NS_MIX_NODES_PRESENCE, - ?NS_MIX_NODES_PARTICIPANTS, ?NS_MIX_NODES_SUBJECT, - ?NS_MIX_NODES_CONFIG], - #iq{type = result, - sub_els = [#mix_join{subscribe = Nodes, jid = MyBareJID}]} = - send_recv(Config, #iq{type = set, to = Room, - sub_els = [#mix_join{subscribe = Nodes}]}), - #message{from = Room, - sub_els = - [#ps_event{ - items = #ps_items{ - node = ?NS_MIX_NODES_PARTICIPANTS, - items = [#ps_item{ - id = ParticipantID, - xml_els = [PXML]}]}}]} = - recv_message(Config), - #mix_participant{jid = MyBareJID} = xmpp:decode(PXML), - %% Coming online - PresenceID = randoms:get_string(), - Presence = xmpp:encode(#presence{}), - #iq{type = result, - sub_els = - [#pubsub{ - publish = #ps_publish{ - node = ?NS_MIX_NODES_PRESENCE, - items = [#ps_item{id = PresenceID}]}}]} = - send_recv( - Config, - #iq{type = set, to = Room, - sub_els = - [#pubsub{ - publish = #ps_publish{ - node = ?NS_MIX_NODES_PRESENCE, - items = [#ps_item{ - id = PresenceID, - xml_els = [Presence]}]}}]}), - #message{from = Room, - sub_els = - [#ps_event{ - items = #ps_items{ - node = ?NS_MIX_NODES_PRESENCE, - items = [#ps_item{ - id = PresenceID, - xml_els = [Presence]}]}}]} = - recv_message(Config), - %% Coming offline - send(Config, #presence{type = unavailable, to = Room}), - %% Receiving presence retract event - #message{from = Room, - sub_els = [#ps_event{ - items = #ps_items{ - node = ?NS_MIX_NODES_PRESENCE, - retract = PresenceID}}]} = - recv_message(Config), - %% Leaving - #iq{type = result, sub_els = []} = - send_recv(Config, #iq{type = set, to = Room, sub_els = [#mix_leave{}]}), - #message{from = Room, - sub_els = - [#ps_event{ - items = #ps_items{ - node = ?NS_MIX_NODES_PARTICIPANTS, - retract = ParticipantID}}]} = - recv_message(Config), - put_event(Config, disconnect), - disconnect(Config). - -mix_slave(Config) -> - disconnect = get_event(Config), - disconnect(Config). - -proxy65_master(Config) -> - Proxy = proxy_jid(Config), - MyJID = my_jid(Config), - Peer = ?config(slave, Config), - wait_for_slave(Config), - send(Config, #presence{}), - #presence{from = MyJID, type = available} = recv_presence(Config), - true = is_feature_advertised(Config, ?NS_BYTESTREAMS, Proxy), - #iq{type = result, sub_els = [#bytestreams{hosts = [StreamHost]}]} = - send_recv( - Config, - #iq{type = get, sub_els = [#bytestreams{}], to = Proxy}), - SID = randoms:get_string(), - Data = crypto:rand_bytes(1024), - put_event(Config, {StreamHost, SID, Data}), - Socks5 = socks5_connect(StreamHost, {SID, MyJID, Peer}), - wait_for_slave(Config), - #iq{type = result, sub_els = []} = - send_recv(Config, - #iq{type = set, to = Proxy, - sub_els = [#bytestreams{activate = Peer, sid = SID}]}), - socks5_send(Socks5, Data), - %%?recv1(#presence{type = unavailable, from = Peer}), - disconnect(Config). - -proxy65_slave(Config) -> - MyJID = my_jid(Config), - Peer = ?config(master, Config), - send(Config, #presence{}), - #presence{from = MyJID, type = available} = recv_presence(Config), - wait_for_master(Config), - {StreamHost, SID, Data} = get_event(Config), - Socks5 = socks5_connect(StreamHost, {SID, Peer, MyJID}), - wait_for_master(Config), - socks5_recv(Socks5, Data), - disconnect(Config). - -send_messages_to_room(Config, Range) -> - MyNick = ?config(master_nick, Config), - Room = muc_room_jid(Config), - MyNickJID = jid:replace_resource(Room, MyNick), - lists:foreach( - fun(N) -> - Text = #text{data = integer_to_binary(N)}, - #message{from = MyNickJID, id = I, - type = groupchat, - body = [Text]} = - send_recv(Config, #message{to = Room, body = [Text], - type = groupchat}) - end, Range). - -retrieve_messages_from_room_via_mam(Config, Range) -> - MyNick = ?config(master_nick, Config), - Room = muc_room_jid(Config), - MyNickJID = jid:replace_resource(Room, MyNick), - MyJID = my_jid(Config), - QID = randoms:get_string(), - Count = length(Range), - I = send(Config, #iq{type = set, to = Room, - sub_els = [#mam_query{xmlns = ?NS_MAM_1, id = QID}]}), - lists:foreach( - fun(N) -> - Text = #text{data = integer_to_binary(N)}, - #message{ - to = MyJID, from = Room, - sub_els = - [#mam_result{ - xmlns = ?NS_MAM_1, - queryid = QID, - sub_els = - [#forwarded{ - delay = #delay{}, - sub_els = [#message{ - from = MyNickJID, - type = groupchat, - body = [Text]}]}]}]} = - recv_message(Config) - end, Range), - #iq{from = Room, id = I, type = result, - sub_els = [#mam_fin{xmlns = ?NS_MAM_1, - id = QID, - rsm = #rsm_set{count = Count}, - complete = true}]} = recv_iq(Config). - -muc_mam_master(Config) -> - MyNick = ?config(master_nick, Config), - Room = muc_room_jid(Config), - MyNickJID = jid:replace_resource(Room, MyNick), - %% Joining - ok = muc_tests:muc_join_new(Config), - %% MAM feature should not be advertised at this point, - %% because MAM is not enabled so far - false = is_feature_advertised(Config, ?NS_MAM_1, Room), - %% Fill in some history - send_messages_to_room(Config, lists:seq(1, 21)), - %% We now should be able to retrieve those via MAM, even though - %% MAM is disabled. However, only last 20 messages should be received. - retrieve_messages_from_room_via_mam(Config, lists:seq(2, 21)), - %% Now enable MAM for the conference - %% Retrieve config first - #iq{type = result, sub_els = [#muc_owner{config = #xdata{} = RoomCfg}]} = - send_recv(Config, #iq{type = get, sub_els = [#muc_owner{}], - to = Room}), - %% Find the MAM field in the config and enable it - NewFields = lists:flatmap( - fun(#xdata_field{var = <<"mam">> = Var}) -> - [#xdata_field{var = Var, values = [<<"1">>]}]; - (_) -> - [] - end, RoomCfg#xdata.fields), - NewRoomCfg = #xdata{type = submit, fields = NewFields}, - #iq{type = result, sub_els = []} = - send_recv(Config, #iq{type = set, to = Room, - sub_els = [#muc_owner{config = NewRoomCfg}]}), - #message{from = Room, type = groupchat, - sub_els = [#muc_user{status_codes = [104]}]} = recv_message(Config), - %% Check if MAM has been enabled - true = is_feature_advertised(Config, ?NS_MAM_1, Room), - %% We now sending some messages again - send_messages_to_room(Config, lists:seq(1, 5)), - %% And retrieve them via MAM again. - retrieve_messages_from_room_via_mam(Config, lists:seq(1, 5)), - put_event(Config, disconnect), - disconnect(Config). - -muc_mam_slave(Config) -> - disconnect = get_event(Config), - disconnect(Config). - -%% OK, I know this is retarded, but I didn't find a better way to -%% split the test cases into different modules -muc_service_presence_error(Config) -> - muc_tests:muc_service_presence_error(Config). -muc_service_message_error(Config) -> - muc_tests:muc_service_message_error(Config). -muc_service_unknown_ns_iq_error(Config) -> - muc_tests:muc_service_unknown_ns_iq_error(Config). -muc_service_iq_set_error(Config) -> - muc_tests:muc_service_iq_set_error(Config). -muc_service_improper_iq_error(Config) -> - muc_tests:muc_service_improper_iq_error(Config). -muc_service_features(Config) -> - muc_tests:muc_service_features(Config). -muc_service_disco_info_node_error(Config) -> - muc_tests:muc_service_disco_info_node_error(Config). -muc_service_disco_items(Config) -> - muc_tests:muc_service_disco_items(Config). -muc_service_vcard(Config) -> - muc_tests:muc_service_vcard(Config). -muc_service_unique(Config) -> - muc_tests:muc_service_unique(Config). -muc_service_subscriptions(Config) -> - muc_tests:muc_service_subscriptions(Config). -muc_configure_non_existent(Config) -> - muc_tests:muc_configure_non_existent(Config). -muc_cancel_configure_non_existent(Config) -> - muc_tests:muc_cancel_configure_non_existent(Config). - -muc_register_master(Config) -> - muc_tests:muc_register_master(Config). -muc_register_slave(Config) -> - muc_tests:muc_register_slave(Config). -muc_join_conflict_master(Config) -> - muc_tests:muc_join_conflict_master(Config). -muc_join_conflict_slave(Config) -> - muc_tests:muc_join_conflict_slave(Config). -muc_groupchat_msg_master(Config) -> - muc_tests:muc_groupchat_msg_master(Config). -muc_groupchat_msg_slave(Config) -> - muc_tests:muc_groupchat_msg_slave(Config). -muc_private_msg_master(Config) -> - muc_tests:muc_private_msg_master(Config). -muc_private_msg_slave(Config) -> - muc_tests:muc_private_msg_slave(Config). -muc_set_subject_master(Config) -> - muc_tests:muc_set_subject_master(Config). -muc_set_subject_slave(Config) -> - muc_tests:muc_set_subject_slave(Config). -muc_history_master(Config) -> - muc_tests:muc_history_master(Config). -muc_history_slave(Config) -> - muc_tests:muc_history_slave(Config). -muc_invite_master(Config) -> - muc_tests:muc_invite_master(Config). -muc_invite_slave(Config) -> - muc_tests:muc_invite_slave(Config). -muc_invite_members_only_master(Config) -> - muc_tests:muc_invite_members_only_master(Config). -muc_invite_members_only_slave(Config) -> - muc_tests:muc_invite_members_only_slave(Config). -muc_invite_password_protected_master(Config) -> - muc_tests:muc_invite_password_protected_master(Config). -muc_invite_password_protected_slave(Config) -> - muc_tests:muc_invite_password_protected_slave(Config). -muc_voice_request_master(Config) -> - muc_tests:muc_voice_request_master(Config). -muc_voice_request_slave(Config) -> - muc_tests:muc_voice_request_slave(Config). -muc_change_role_master(Config) -> - muc_tests:muc_change_role_master(Config). -muc_change_role_slave(Config) -> - muc_tests:muc_change_role_slave(Config). -muc_kick_master(Config) -> - muc_tests:muc_kick_master(Config). -muc_kick_slave(Config) -> - muc_tests:muc_kick_slave(Config). -muc_change_affiliation_master(Config) -> - muc_tests:muc_change_affiliation_master(Config). -muc_change_affiliation_slave(Config) -> - muc_tests:muc_change_affiliation_slave(Config). -muc_destroy_master(Config) -> - muc_tests:muc_destroy_master(Config). -muc_destroy_slave(Config) -> - muc_tests:muc_destroy_slave(Config). -muc_vcard_master(Config) -> - muc_tests:muc_vcard_master(Config). -muc_vcard_slave(Config) -> - muc_tests:muc_vcard_slave(Config). -muc_nick_change_master(Config) -> - muc_tests:muc_nick_change_master(Config). -muc_nick_change_slave(Config) -> - muc_tests:muc_nick_change_slave(Config). -muc_config_title_desc_master(Config) -> - muc_tests:muc_config_title_desc_master(Config). -muc_config_title_desc_slave(Config) -> - muc_tests:muc_config_title_desc_slave(Config). -muc_config_public_list_master(Config) -> - muc_tests:muc_config_public_list_master(Config). -muc_config_public_list_slave(Config) -> - muc_tests:muc_config_public_list_slave(Config). -muc_config_password_master(Config) -> - muc_tests:muc_config_password_master(Config). -muc_config_password_slave(Config) -> - muc_tests:muc_config_password_slave(Config). -muc_config_whois_master(Config) -> - muc_tests:muc_config_whois_master(Config). -muc_config_whois_slave(Config) -> - muc_tests:muc_config_whois_slave(Config). -muc_config_members_only_master(Config) -> - muc_tests:muc_config_members_only_master(Config). -muc_config_members_only_slave(Config) -> - muc_tests:muc_config_members_only_slave(Config). -muc_config_moderated_master(Config) -> - muc_tests:muc_config_moderated_master(Config). -muc_config_moderated_slave(Config) -> - muc_tests:muc_config_moderated_slave(Config). -muc_config_private_messages_master(Config) -> - muc_tests:muc_config_private_messages_master(Config). -muc_config_private_messages_slave(Config) -> - muc_tests:muc_config_private_messages_slave(Config). -muc_config_query_master(Config) -> - muc_tests:muc_config_query_master(Config). -muc_config_query_slave(Config) -> - muc_tests:muc_config_query_slave(Config). -muc_config_allow_invites_master(Config) -> - muc_tests:muc_config_allow_invites_master(Config). -muc_config_allow_invites_slave(Config) -> - muc_tests:muc_config_allow_invites_slave(Config). -muc_config_visitor_status_master(Config) -> - muc_tests:muc_config_visitor_status_master(Config). -muc_config_visitor_status_slave(Config) -> - muc_tests:muc_config_visitor_status_slave(Config). -muc_config_allow_voice_requests_master(Config) -> - muc_tests:muc_config_allow_voice_requests_master(Config). -muc_config_allow_voice_requests_slave(Config) -> - muc_tests:muc_config_allow_voice_requests_slave(Config). -muc_config_voice_request_interval_master(Config) -> - muc_tests:muc_config_voice_request_interval_master(Config). -muc_config_voice_request_interval_slave(Config) -> - muc_tests:muc_config_voice_request_interval_slave(Config). -muc_config_visitor_nickchange_master(Config) -> - muc_tests:muc_config_visitor_nickchange_master(Config). -muc_config_visitor_nickchange_slave(Config) -> - muc_tests:muc_config_visitor_nickchange_slave(Config). - -offline_feature_enabled(Config) -> - offline_tests:feature_enabled(Config). -offline_check_identity(Config) -> - offline_tests:check_identity(Config). -offline_send_non_existent(Config) -> - offline_tests:send_non_existent(Config). -offline_view_non_existent(Config) -> - offline_tests:view_non_existent(Config). -offline_remove_non_existent(Config) -> - offline_tests:remove_non_existent(Config). -offline_view_non_integer(Config) -> - offline_tests:view_non_integer(Config). -offline_remove_non_integer(Config) -> - offline_tests:remove_non_integer(Config). -offline_malformed_iq(Config) -> - offline_tests:malformed_iq(Config). -offline_wrong_user(Config) -> - offline_tests:wrong_user(Config). -offline_unsupported_iq(Config) -> - offline_tests:unsupported_iq(Config). -offline_flex_master(Config) -> - offline_tests:flex_master(Config). -offline_flex_slave(Config) -> - offline_tests:flex_slave(Config). -offline_send_all_master(Config) -> - offline_tests:send_all_master(Config). -offline_send_all_slave(Config) -> - offline_tests:send_all_slave(Config). - -announce_master(Config) -> - MyJID = my_jid(Config), - ServerJID = server_jid(Config), - MotdJID = jid:replace_resource(ServerJID, <<"announce/motd">>), - MotdText = #text{data = <<"motd">>}, - #presence{from = MyJID} = send_recv(Config, #presence{}), - %% Set message of the day - send(Config, #message{to = MotdJID, body = [MotdText]}), - %% Receive this message back - #message{from = ServerJID, body = [MotdText]} = recv_message(Config), - disconnect(Config). - -announce_slave(Config) -> - MyJID = my_jid(Config), - ServerJID = server_jid(Config), - MotdDelJID = jid:replace_resource(ServerJID, <<"announce/motd/delete">>), - MotdText = #text{data = <<"motd">>}, - #presence{from = MyJID} = send_recv(Config, #presence{}), - #message{from = ServerJID, body = [MotdText]} = recv_message(Config), - %% Delete message of the day - send(Config, #message{to = MotdDelJID}), - disconnect(Config). - -carbons_master(Config) -> - MyJID = my_jid(Config), - MyBareJID = jid:remove_resource(MyJID), - Peer = ?config(slave, Config), - Txt = #text{data = <<"body">>}, - true = is_feature_advertised(Config, ?NS_CARBONS_2), - #presence{from = MyJID} = send_recv(Config, #presence{priority = 10}), - wait_for_slave(Config), - #presence{from = Peer} = recv_presence(Config), - %% Enable carbons - #iq{type = result, sub_els = []} = - send_recv(Config, - #iq{type = set, - sub_els = [#carbons_enable{}]}), - %% Send a message to bare and full JID - send(Config, #message{to = MyBareJID, type = chat, body = [Txt]}), - send(Config, #message{to = MyJID, type = chat, body = [Txt]}), - send(Config, #message{to = MyBareJID, type = chat, body = [Txt], - sub_els = [#carbons_private{}]}), - send(Config, #message{to = MyJID, type = chat, body = [Txt], - sub_els = [#carbons_private{}]}), - %% Receive the messages back - ?recv4(#message{from = MyJID, to = MyBareJID, type = chat, - body = [Txt], sub_els = []}, - #message{from = MyJID, to = MyJID, type = chat, - body = [Txt], sub_els = []}, - #message{from = MyJID, to = MyBareJID, type = chat, - body = [Txt], sub_els = [#carbons_private{}]}, - #message{from = MyJID, to = MyJID, type = chat, - body = [Txt], sub_els = [#carbons_private{}]}), - %% Disable carbons - #iq{type = result, sub_els = []} = - send_recv(Config, - #iq{type = set, - sub_els = [#carbons_disable{}]}), - wait_for_slave(Config), - %% Repeat the same and leave - send(Config, #message{to = MyBareJID, type = chat, body = [Txt]}), - send(Config, #message{to = MyJID, type = chat, body = [Txt]}), - send(Config, #message{to = MyBareJID, type = chat, body = [Txt], - sub_els = [#carbons_private{}]}), - send(Config, #message{to = MyJID, type = chat, body = [Txt], - sub_els = [#carbons_private{}]}), - ?recv4(#message{from = MyJID, to = MyBareJID, type = chat, - body = [Txt], sub_els = []}, - #message{from = MyJID, to = MyJID, type = chat, - body = [Txt], sub_els = []}, - #message{from = MyJID, to = MyBareJID, type = chat, - body = [Txt], sub_els = [#carbons_private{}]}, - #message{from = MyJID, to = MyJID, type = chat, - body = [Txt], sub_els = [#carbons_private{}]}), - disconnect(Config). - -carbons_slave(Config) -> - MyJID = my_jid(Config), - MyBareJID = jid:remove_resource(MyJID), - Peer = ?config(master, Config), - Txt = #text{data = <<"body">>}, - wait_for_master(Config), - #presence{from = MyJID} = send_recv(Config, #presence{priority = 5}), - #presence{from = Peer} = recv_presence(Config), - %% Enable carbons - #iq{type = result, sub_els = []} = - send_recv(Config, - #iq{type = set, - sub_els = [#carbons_enable{}]}), - %% Receive messages sent by the peer - ?recv4( - #message{from = MyBareJID, to = MyJID, type = chat, - sub_els = - [#carbons_sent{ - forwarded = #forwarded{ - sub_els = - [#message{from = Peer, - to = MyBareJID, - type = chat, - body = [Txt]}]}}]}, - #message{from = MyBareJID, to = MyJID, type = chat, - sub_els = - [#carbons_sent{ - forwarded = #forwarded{ - sub_els = - [#message{from = Peer, - to = Peer, - type = chat, - body = [Txt]}]}}]}, - #message{from = MyBareJID, to = MyJID, type = chat, - sub_els = - [#carbons_received{ - forwarded = #forwarded{ - sub_els = - [#message{from = Peer, - to = MyBareJID, - type = chat, - body = [Txt]}]}}]}, - #message{from = MyBareJID, to = MyJID, type = chat, - sub_els = - [#carbons_received{ - forwarded = #forwarded{ - sub_els = - [#message{from = Peer, - to = Peer, - type = chat, - body = [Txt]}]}}]}), - %% Disable carbons - #iq{type = result, sub_els = []} = - send_recv(Config, - #iq{type = set, - sub_els = [#carbons_disable{}]}), - wait_for_master(Config), - %% Now we should receive nothing but presence unavailable from the peer - #presence{from = Peer, type = unavailable} = recv_presence(Config), - disconnect(Config). - -mam_old_master(Config) -> - mam_master(Config, ?NS_MAM_TMP). - -mam_new_master(Config) -> - mam_master(Config, ?NS_MAM_0). - -mam_master(Config, NS) -> - true = is_feature_advertised(Config, NS), - MyJID = my_jid(Config), - BareMyJID = jid:remove_resource(MyJID), - Peer = ?config(slave, Config), - #presence{} = send_recv(Config, #presence{}), - wait_for_slave(Config), - #presence{from = Peer} = recv_presence(Config), - #iq{type = result, sub_els = [#mam_prefs{xmlns = NS, default = roster}]} = - send_recv(Config, - #iq{type = set, - sub_els = [#mam_prefs{xmlns = NS, - default = roster, - never = [MyJID]}]}), - if NS == ?NS_MAM_TMP -> - %% NOTE: The server should strip fake archived tags, - %% i.e. the sub_els received should be []. - FakeArchived = #mam_archived{id = randoms:get_string(), - by = server_jid(Config)}, - #message{body = [#text{data = <<"a">>}], sub_els = []} = - send_recv(Config, #message{to = MyJID, - sub_els = [FakeArchived], - body = [#text{data = <<"a">>}]}), - #message{body = [#text{data = <<"b">>}], sub_els = []} = - send_recv(Config, #message{to = BareMyJID, - sub_els = [FakeArchived], - body = [#text{data = <<"b">>}]}); - true -> - ok - end, - wait_for_slave(Config), - lists:foreach( - fun(N) -> - Text = #text{data = integer_to_binary(N)}, - send(Config, #message{to = Peer, body = [Text]}) - end, lists:seq(1, 5)), - #presence{type = unavailable, from = Peer} = recv_presence(Config), - mam_query_all(Config, NS), - mam_query_with(Config, Peer, NS), - %% mam_query_with(Config, jid:remove_resource(Peer)), - mam_query_rsm(Config, NS), - #iq{type = result, sub_els = [#mam_prefs{xmlns = NS, default = never}]} = - send_recv(Config, #iq{type = set, - sub_els = [#mam_prefs{xmlns = NS, - default = never}]}), - disconnect(Config). - -mam_old_slave(Config) -> - mam_slave(Config, ?NS_MAM_TMP). - -mam_new_slave(Config) -> - mam_slave(Config, ?NS_MAM_0). - -mam_slave(Config, NS) -> - Peer = ?config(master, Config), - MyJID = my_jid(Config), - ServerJID = server_jid(Config), - wait_for_master(Config), - #presence{from = MyJID} = send_recv(Config, #presence{}), - #presence{from = Peer} = recv_presence(Config), - #iq{type = result, sub_els = [#mam_prefs{xmlns = NS, default = always}]} = - send_recv(Config, - #iq{type = set, - sub_els = [#mam_prefs{xmlns = NS, default = always}]}), - wait_for_master(Config), - lists:foreach( - fun(N) -> - Text = #text{data = integer_to_binary(N)}, - Msg = #message{from = Peer, body = [Text]} = recv_message(Config), - #mam_archived{by = ServerJID} = - xmpp:get_subtag(Msg, #mam_archived{}), - #stanza_id{by = ServerJID} = - xmpp:get_subtag(Msg, #stanza_id{}) - end, lists:seq(1, 5)), - #iq{type = result, sub_els = [#mam_prefs{xmlns = NS, default = never}]} = - send_recv(Config, #iq{type = set, - sub_els = [#mam_prefs{xmlns = NS, default = never}]}), - disconnect(Config). - -mam_query_all(Config, NS) -> - QID = randoms:get_string(), - MyJID = my_jid(Config), - Peer = ?config(slave, Config), - Type = case NS of - ?NS_MAM_TMP -> get; - _ -> set - end, - I = send(Config, #iq{type = Type, sub_els = [#mam_query{xmlns = NS, id = QID}]}), - maybe_recv_iq_result(Config, NS, I), - Iter = if NS == ?NS_MAM_TMP -> lists:seq(1, 5); - true -> lists:seq(1, 5) ++ lists:seq(1, 5) - end, - lists:foreach( - fun(N) -> - Text = #text{data = integer_to_binary(N)}, - #message{to = MyJID, - sub_els = - [#mam_result{ - queryid = QID, - sub_els = - [#forwarded{ - delay = #delay{}, - sub_els = - [#message{ - from = MyJID, to = Peer, - body = [Text]}]}]}]} = - recv_message(Config) - end, Iter), - if NS == ?NS_MAM_TMP -> - #iq{type = result, id = I, - sub_els = [#mam_query{xmlns = NS, id = QID}]} = recv_iq(Config); - true -> - #message{sub_els = [#mam_fin{complete = true, id = QID}]} = - recv_message(Config) - end. - -mam_query_with(Config, JID, NS) -> - MyJID = my_jid(Config), - Peer = ?config(slave, Config), - {Query, Type} = if NS == ?NS_MAM_TMP -> - {#mam_query{xmlns = NS, with = JID}, get}; - true -> - Fs = [#xdata_field{var = <<"jid">>, - values = [jid:to_string(JID)]}], - {#mam_query{xmlns = NS, - xdata = #xdata{type = submit, fields = Fs}}, set} - end, - I = send(Config, #iq{type = Type, sub_els = [Query]}), - Iter = if NS == ?NS_MAM_TMP -> lists:seq(1, 5); - true -> lists:seq(1, 5) ++ lists:seq(1, 5) - end, - maybe_recv_iq_result(Config, NS, I), - lists:foreach( - fun(N) -> - Text = #text{data = integer_to_binary(N)}, - #message{to = MyJID, - sub_els = - [#mam_result{ - sub_els = - [#forwarded{ - delay = #delay{}, - sub_els = - [#message{ - from = MyJID, to = Peer, - body = [Text]}]}]}]} = - recv_message(Config) - end, Iter), - if NS == ?NS_MAM_TMP -> - #iq{type = result, id = I, - sub_els = [#mam_query{xmlns = NS}]} = recv_iq(Config); - true -> - #message{sub_els = [#mam_fin{complete = true}]} = - recv_message(Config) - end. - -maybe_recv_iq_result(Config, ?NS_MAM_0, I1) -> - #iq{type = result, id = I1} = recv_iq(Config); -maybe_recv_iq_result(_, _, _) -> - ok. - -mam_query_rsm(Config, NS) -> - MyJID = my_jid(Config), - Peer = ?config(slave, Config), - Type = case NS of - ?NS_MAM_TMP -> get; - _ -> set - end, - %% Get the first 3 items out of 5 - I1 = send(Config, - #iq{type = Type, - sub_els = [#mam_query{xmlns = NS, rsm = #rsm_set{max = 3}}]}), - maybe_recv_iq_result(Config, NS, I1), - lists:foreach( - fun(N) -> - Text = #text{data = integer_to_binary(N)}, - #message{to = MyJID, - sub_els = - [#mam_result{ - xmlns = NS, - sub_els = - [#forwarded{ - delay = #delay{}, - sub_els = - [#message{ - from = MyJID, to = Peer, - body = [Text]}]}]}]} = - recv_message(Config) - end, lists:seq(1, 3)), - if NS == ?NS_MAM_TMP -> - #iq{type = result, id = I1, - sub_els = [#mam_query{xmlns = NS, - rsm = #rsm_set{last = Last, - count = 5}}]} = - recv_iq(Config); - true -> - #message{sub_els = [#mam_fin{ - complete = false, - rsm = #rsm_set{last = Last, - count = 10}}]} = - recv_message(Config) - end, - %% Get the next items starting from the `Last`. - %% Limit the response to 2 items. - I2 = send(Config, - #iq{type = Type, - sub_els = [#mam_query{xmlns = NS, - rsm = #rsm_set{max = 2, - 'after' = Last}}]}), - maybe_recv_iq_result(Config, NS, I2), - lists:foreach( - fun(N) -> - Text = #text{data = integer_to_binary(N)}, - #message{to = MyJID, - sub_els = - [#mam_result{ - xmlns = NS, - sub_els = - [#forwarded{ - delay = #delay{}, - sub_els = - [#message{ - from = MyJID, to = Peer, - body = [Text]}]}]}]} = - recv_message(Config) - end, lists:seq(4, 5)), - if NS == ?NS_MAM_TMP -> - #iq{type = result, id = I2, - sub_els = [#mam_query{ - xmlns = NS, - rsm = #rsm_set{ - count = 5, - first = #rsm_first{data = First}}}]} = - recv_iq(Config); - true -> - #message{ - sub_els = [#mam_fin{ - complete = false, - rsm = #rsm_set{ - count = 10, - first = #rsm_first{data = First}}}]} = - recv_message(Config) - end, - %% Paging back. Should receive 3 elements: 1, 2, 3. - I3 = send(Config, - #iq{type = Type, - sub_els = [#mam_query{xmlns = NS, - rsm = #rsm_set{max = 3, - before = First}}]}), - maybe_recv_iq_result(Config, NS, I3), - lists:foreach( - fun(N) -> - Text = #text{data = integer_to_binary(N)}, - #message{to = MyJID, - sub_els = - [#mam_result{ - xmlns = NS, - sub_els = - [#forwarded{ - delay = #delay{}, - sub_els = - [#message{ - from = MyJID, to = Peer, - body = [Text]}]}]}]} = - recv_message(Config) - end, lists:seq(1, 3)), - if NS == ?NS_MAM_TMP -> - #iq{type = result, id = I3, - sub_els = [#mam_query{xmlns = NS, rsm = #rsm_set{count = 5}}]} = - recv_iq(Config); - true -> - #message{ - sub_els = [#mam_fin{complete = true, - rsm = #rsm_set{count = 10}}]} = - recv_message(Config) - end, - %% Getting the item count. Should be 5 (or 10). - I4 = send(Config, - #iq{type = Type, - sub_els = [#mam_query{xmlns = NS, - rsm = #rsm_set{max = 0}}]}), - maybe_recv_iq_result(Config, NS, I4), - if NS == ?NS_MAM_TMP -> - #iq{type = result, id = I4, - sub_els = [#mam_query{ - xmlns = NS, - rsm = #rsm_set{count = 5, - first = undefined, - last = undefined}}]} = - recv_iq(Config); - true -> - #message{ - sub_els = [#mam_fin{ - complete = false, - rsm = #rsm_set{count = 10, - first = undefined, - last = undefined}}]} = - recv_message(Config) - end, - %% Should receive 2 last messages - I5 = send(Config, - #iq{type = Type, - sub_els = [#mam_query{xmlns = NS, - rsm = #rsm_set{max = 2, - before = <<"">>}}]}), - maybe_recv_iq_result(Config, NS, I5), - lists:foreach( - fun(N) -> - Text = #text{data = integer_to_binary(N)}, - #message{to = MyJID, - sub_els = - [#mam_result{ - xmlns = NS, - sub_els = - [#forwarded{ - delay = #delay{}, - sub_els = - [#message{ - from = MyJID, to = Peer, - body = [Text]}]}]}]} = - recv_message(Config) - end, lists:seq(4, 5)), - if NS == ?NS_MAM_TMP -> - #iq{type = result, id = I5, - sub_els = [#mam_query{xmlns = NS, rsm = #rsm_set{count = 5}}]} = - recv_iq(Config); - true -> - #message{ - sub_els = [#mam_fin{complete = false, - rsm = #rsm_set{count = 10}}]} = - recv_message(Config) - end. - -client_state_master(Config) -> - true = ?config(csi, Config), - Peer = ?config(slave, Config), - Presence = #presence{to = Peer}, - ChatState = #message{to = Peer, thread = <<"1">>, - sub_els = [#chatstate{type = active}]}, - Message = ChatState#message{body = [#text{data = <<"body">>}]}, - PepPayload = xmpp:encode(#presence{}), - PepOne = #message{ - to = Peer, - sub_els = - [#ps_event{ - items = - #ps_items{ - node = <<"foo-1">>, - items = - [#ps_item{ - id = <<"pep-1">>, - xml_els = [PepPayload]}]}}]}, - PepTwo = #message{ - to = Peer, - sub_els = - [#ps_event{ - items = - #ps_items{ - node = <<"foo-2">>, - items = - [#ps_item{ - id = <<"pep-2">>, - xml_els = [PepPayload]}]}}]}, - %% Wait for the slave to become inactive. - wait_for_slave(Config), - %% Should be queued (but see below): - send(Config, Presence), - %% Should replace the previous presence in the queue: - send(Config, Presence#presence{type = unavailable}), - %% The following two PEP stanzas should be queued (but see below): - send(Config, PepOne), - send(Config, PepTwo), - %% The following two PEP stanzas should replace the previous two: - send(Config, PepOne), - send(Config, PepTwo), - %% Should be queued (but see below): - send(Config, ChatState), - %% Should replace the previous chat state in the queue: - send(Config, ChatState#message{sub_els = [#chatstate{type = composing}]}), - %% Should be sent immediately, together with the queued stanzas: - send(Config, Message), - %% Wait for the slave to become active. - wait_for_slave(Config), - %% Should be delivered, as the client is active again: - send(Config, ChatState), - disconnect(Config). - -client_state_slave(Config) -> - Peer = ?config(master, Config), - change_client_state(Config, inactive), - wait_for_master(Config), - #presence{from = Peer, type = unavailable, sub_els = [#delay{}]} = - recv_presence(Config), - #message{ - from = Peer, - sub_els = - [#ps_event{ - items = - #ps_items{ - node = <<"foo-1">>, - items = - [#ps_item{ - id = <<"pep-1">>}]}}, - #delay{}]} = recv_message(Config), - #message{ - from = Peer, - sub_els = - [#ps_event{ - items = - #ps_items{ - node = <<"foo-2">>, - items = - [#ps_item{ - id = <<"pep-2">>}]}}, - #delay{}]} = recv_message(Config), - #message{from = Peer, thread = <<"1">>, - sub_els = [#chatstate{type = composing}, - #delay{}]} = recv_message(Config), - #message{from = Peer, thread = <<"1">>, - body = [#text{data = <<"body">>}], - sub_els = [#chatstate{type = active}]} = recv_message(Config), - change_client_state(Config, active), - wait_for_master(Config), - #message{from = Peer, thread = <<"1">>, - sub_els = [#chatstate{type = active}]} = recv_message(Config), - disconnect(Config). - %%%=================================================================== %%% Aux functions %%%=================================================================== -change_client_state(Config, NewState) -> - send(Config, #csi{type = NewState}), - send_recv(Config, #iq{type = get, to = server_jid(Config), - sub_els = [#ping{}]}). - bookmark_conference() -> #bookmark_conference{name = <<"Some name">>, autojoin = true, @@ -2902,34 +979,22 @@ bookmark_conference() -> <<"some.conference.org">>, <<>>)}. -socks5_connect(#streamhost{host = Host, port = Port}, - {SID, JID1, JID2}) -> - Hash = p1_sha:sha([SID, jid:to_string(JID1), jid:to_string(JID2)]), - {ok, Sock} = gen_tcp:connect(binary_to_list(Host), Port, - [binary, {active, false}]), - Init = <>, - InitAck = <>, - Req = <>, - Resp = <>, - gen_tcp:send(Sock, Init), - {ok, InitAck} = gen_tcp:recv(Sock, size(InitAck)), - gen_tcp:send(Sock, Req), - {ok, Resp} = gen_tcp:recv(Sock, size(Resp)), - Sock. - -socks5_send(Sock, Data) -> - ok = gen_tcp:send(Sock, Data). - -socks5_recv(Sock, Data) -> - {ok, Data} = gen_tcp:recv(Sock, size(Data)). - -set_opts(Config, Options) -> - lists:foldl( - fun({Opt, Val}, Acc) -> - lists:keystore(Opt, 1, Acc, {Opt, Val}) - end, Config, Options). +'$handle_undefined_function'(F, [Config]) when is_list(Config) -> + case re:split(atom_to_list(F), "_", [{return, list}, {parts, 2}]) of + [M, T] -> + Module = list_to_atom(M ++ "_tests"), + Function = list_to_atom(T), + case erlang:function_exported(Module, Function, 1) of + true -> + Module:Function(Config); + false -> + erlang:error({undef, F}) + end; + _ -> + erlang:error({undef, F}) + end; +'$handle_undefined_function'(_, _) -> + erlang:error(undef). %%%=================================================================== %%% SQL stuff @@ -3011,12 +1076,12 @@ split(Data) -> clear_riak_tables(Config) -> User = ?config(user, Config), Server = ?config(server, Config), - Room = muc_room_jid(Config), - {URoom, SRoom, _} = jid:tolower(Room), + Master = <<"test_master!#$%^*()`~+-;_=[]{}|\\">>, + Slave = <<"test_slave!#$%^*()`~+-;_=[]{}|\\">>, ejabberd_auth:remove_user(User, Server), - ejabberd_auth:remove_user(<<"test_slave">>, Server), - ejabberd_auth:remove_user(<<"test_master">>, Server), - mod_muc:forget_room(Server, URoom, SRoom), - ejabberd_riak:delete(muc_registered, {{<<"test_slave">>, Server}, SRoom}), - ejabberd_riak:delete(muc_registered, {{<<"test_master">>, Server}, SRoom}), + ejabberd_auth:remove_user(Master, Server), + ejabberd_auth:remove_user(Slave, Server), + ejabberd_riak:delete(muc_room), + ejabberd_riak:delete(muc_registered), + timer:sleep(timer:seconds(5)), Config. diff --git a/test/example_tests.erl b/test/example_tests.erl new file mode 100644 index 000000000..d7965376e --- /dev/null +++ b/test/example_tests.erl @@ -0,0 +1,52 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 16 Nov 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(example_tests). + +%% API +-compile(export_all). +-import(suite, []). + +-include("suite.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +%%%=================================================================== +%%% Single user tests +%%%=================================================================== +single_cases() -> + {example_single, [sequence], + [single_test(foo)]}. + +foo(Config) -> + Config. + +%%%=================================================================== +%%% Master-slave tests +%%%=================================================================== +master_slave_cases() -> + {example_master_slave, [sequence], + [master_slave_test(foo)]}. + +foo_master(Config) -> + Config. + +foo_slave(Config) -> + Config. + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +single_test(T) -> + list_to_atom("example_" ++ atom_to_list(T)). + +master_slave_test(T) -> + {list_to_atom("example_" ++ atom_to_list(T)), [parallel], + [list_to_atom("example_" ++ atom_to_list(T) ++ "_master"), + list_to_atom("example_" ++ atom_to_list(T) ++ "_slave")]}. diff --git a/test/mam_tests.erl b/test/mam_tests.erl new file mode 100644 index 000000000..9154ea240 --- /dev/null +++ b/test/mam_tests.erl @@ -0,0 +1,537 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 14 Nov 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(mam_tests). + +%% API +-compile(export_all). +-import(suite, [get_features/1, disconnect/1, my_jid/1, send_recv/2, + wait_for_slave/1, server_jid/1, send/2, get_features/2, + wait_for_master/1, recv_message/1, recv_iq/1, muc_room_jid/1, + muc_jid/1, is_feature_advertised/3, get_event/1, put_event/2]). + +-include("suite.hrl"). +-define(VERSIONS, [?NS_MAM_TMP, ?NS_MAM_0, ?NS_MAM_1]). + +%%%=================================================================== +%%% API +%%%=================================================================== +%%%=================================================================== +%%% Single user tests +%%%=================================================================== +single_cases() -> + {mam_single, [sequence], + [single_test(feature_enabled), + single_test(get_set_prefs), + single_test(get_form), + single_test(fake_by)]}. + +feature_enabled(Config) -> + BareMyJID = jid:remove_resource(my_jid(Config)), + RequiredFeatures = sets:from_list(?VERSIONS), + ServerFeatures = sets:from_list(get_features(Config)), + UserFeatures = sets:from_list(get_features(Config, BareMyJID)), + MUCFeatures = get_features(Config, muc_jid(Config)), + ct:comment("Checking if all MAM server features are enabled"), + true = sets:is_subset(RequiredFeatures, ServerFeatures), + ct:comment("Checking if all MAM user features are enabled"), + true = sets:is_subset(RequiredFeatures, UserFeatures), + ct:comment("Checking if all MAM conference service features are enabled"), + true = lists:member(?NS_MAM_1, MUCFeatures), + clean(disconnect(Config)). + +fake_by(Config) -> + BareServerJID = server_jid(Config), + FullServerJID = jid:replace_resource(BareServerJID, randoms:get_string()), + FullMyJID = my_jid(Config), + BareMyJID = jid:remove_resource(FullMyJID), + Fakes = lists:flatmap( + fun(JID) -> + [#mam_archived{id = randoms:get_string(), by = JID}, + #stanza_id{id = randoms:get_string(), by = JID}] + end, [BareServerJID, FullServerJID, BareMyJID, FullMyJID]), + Body = xmpp:mk_text(<<"body">>), + ForeignJID = jid:make(randoms:get_string()), + Archived = #mam_archived{id = randoms:get_string(), by = ForeignJID}, + StanzaID = #stanza_id{id = randoms:get_string(), by = ForeignJID}, + #message{body = Body, sub_els = SubEls} = + send_recv(Config, #message{to = FullMyJID, + body = Body, + sub_els = [Archived, StanzaID|Fakes]}), + ct:comment("Checking if only foreign tags present"), + [ForeignJID, ForeignJID] = lists:flatmap( + fun(#mam_archived{by = By}) -> [By]; + (#stanza_id{by = By}) -> [By]; + (_) -> [] + end, SubEls), + clean(disconnect(Config)). + +get_set_prefs(Config) -> + Range = [{JID, #mam_prefs{xmlns = NS, + default = Default, + always = Always, + never = Never}} || + JID <- [undefined, server_jid(Config)], + NS <- ?VERSIONS, + Default <- [always, never, roster], + Always <- [[], [jid:from_string(<<"foo@bar.baz">>)]], + Never <- [[], [jid:from_string(<<"baz@bar.foo">>)]]], + lists:foreach( + fun({To, Prefs}) -> + NS = Prefs#mam_prefs.xmlns, + #iq{type = result, sub_els = [Prefs]} = + send_recv(Config, #iq{type = set, to = To, + sub_els = [Prefs]}), + #iq{type = result, sub_els = [Prefs]} = + send_recv(Config, #iq{type = get, to = To, + sub_els = [#mam_prefs{xmlns = NS}]}) + end, Range), + clean(disconnect(Config)). + +get_form(Config) -> + ServerJID = server_jid(Config), + Range = [{JID, NS} || JID <- [undefined, ServerJID], + NS <- ?VERSIONS -- [?NS_MAM_TMP]], + lists:foreach( + fun({To, NS}) -> + #iq{type = result, + sub_els = [#mam_query{xmlns = NS, + xdata = #xdata{} = X}]} = + send_recv(Config, #iq{type = get, to = To, + sub_els = [#mam_query{xmlns = NS}]}), + [NS] = xmpp_util:get_xdata_values(<<"FORM_TYPE">>, X), + true = xmpp_util:has_xdata_var(<<"with">>, X), + true = xmpp_util:has_xdata_var(<<"start">>, X), + true = xmpp_util:has_xdata_var(<<"end">>, X) + end, Range), + clean(disconnect(Config)). + +%%%=================================================================== +%%% Master-slave tests +%%%=================================================================== +master_slave_cases() -> + {mam_master_slave, [sequence], + [master_slave_test(archived_and_stanza_id), + master_slave_test(query_all), + master_slave_test(query_with), + master_slave_test(query_rsm_max), + master_slave_test(query_rsm_after), + master_slave_test(query_rsm_before), + master_slave_test(muc)]}. + +archived_and_stanza_id_master(Config) -> + #presence{} = send_recv(Config, #presence{}), + wait_for_slave(Config), + send_messages(Config, lists:seq(1, 5)), + clean(disconnect(Config)). + +archived_and_stanza_id_slave(Config) -> + ok = set_default(Config, always), + #presence{} = send_recv(Config, #presence{}), + wait_for_master(Config), + recv_messages(Config, lists:seq(1, 5)), + clean(disconnect(Config)). + +query_all_master(Config) -> + Peer = ?config(peer, Config), + MyJID = my_jid(Config), + ok = set_default(Config, always), + #presence{} = send_recv(Config, #presence{}), + wait_for_slave(Config), + send_messages(Config, lists:seq(1, 5)), + query_all(Config, MyJID, Peer), + clean(disconnect(Config)). + +query_all_slave(Config) -> + Peer = ?config(peer, Config), + MyJID = my_jid(Config), + ok = set_default(Config, always), + #presence{} = send_recv(Config, #presence{}), + wait_for_master(Config), + recv_messages(Config, lists:seq(1, 5)), + query_all(Config, Peer, MyJID), + clean(disconnect(Config)). + +query_with_master(Config) -> + Peer = ?config(peer, Config), + MyJID = my_jid(Config), + ok = set_default(Config, always), + #presence{} = send_recv(Config, #presence{}), + wait_for_slave(Config), + send_messages(Config, lists:seq(1, 5)), + query_with(Config, MyJID, Peer), + clean(disconnect(Config)). + +query_with_slave(Config) -> + Peer = ?config(peer, Config), + MyJID = my_jid(Config), + ok = set_default(Config, always), + #presence{} = send_recv(Config, #presence{}), + wait_for_master(Config), + recv_messages(Config, lists:seq(1, 5)), + query_with(Config, Peer, MyJID), + clean(disconnect(Config)). + +query_rsm_max_master(Config) -> + Peer = ?config(peer, Config), + MyJID = my_jid(Config), + ok = set_default(Config, always), + #presence{} = send_recv(Config, #presence{}), + wait_for_slave(Config), + send_messages(Config, lists:seq(1, 5)), + query_rsm_max(Config, MyJID, Peer), + clean(disconnect(Config)). + +query_rsm_max_slave(Config) -> + Peer = ?config(peer, Config), + MyJID = my_jid(Config), + ok = set_default(Config, always), + #presence{} = send_recv(Config, #presence{}), + wait_for_master(Config), + recv_messages(Config, lists:seq(1, 5)), + query_rsm_max(Config, Peer, MyJID), + clean(disconnect(Config)). + +query_rsm_after_master(Config) -> + Peer = ?config(peer, Config), + MyJID = my_jid(Config), + ok = set_default(Config, always), + #presence{} = send_recv(Config, #presence{}), + wait_for_slave(Config), + send_messages(Config, lists:seq(1, 5)), + query_rsm_after(Config, MyJID, Peer), + clean(disconnect(Config)). + +query_rsm_after_slave(Config) -> + Peer = ?config(peer, Config), + MyJID = my_jid(Config), + ok = set_default(Config, always), + #presence{} = send_recv(Config, #presence{}), + wait_for_master(Config), + recv_messages(Config, lists:seq(1, 5)), + query_rsm_after(Config, Peer, MyJID), + clean(disconnect(Config)). + +query_rsm_before_master(Config) -> + Peer = ?config(peer, Config), + MyJID = my_jid(Config), + ok = set_default(Config, always), + #presence{} = send_recv(Config, #presence{}), + wait_for_slave(Config), + send_messages(Config, lists:seq(1, 5)), + query_rsm_before(Config, MyJID, Peer), + clean(disconnect(Config)). + +query_rsm_before_slave(Config) -> + Peer = ?config(peer, Config), + MyJID = my_jid(Config), + ok = set_default(Config, always), + #presence{} = send_recv(Config, #presence{}), + wait_for_master(Config), + recv_messages(Config, lists:seq(1, 5)), + query_rsm_before(Config, Peer, MyJID), + clean(disconnect(Config)). + +muc_master(Config) -> + Room = muc_room_jid(Config), + %% Joining + ok = muc_tests:join_new(Config), + %% MAM feature should not be advertised at this point, + %% because MAM is not enabled so far + false = is_feature_advertised(Config, ?NS_MAM_1, Room), + %% Fill in some history + send_messages_to_room(Config, lists:seq(1, 21)), + %% We now should be able to retrieve those via MAM, even though + %% MAM is disabled. However, only last 20 messages should be received. + recv_messages_from_room(Config, lists:seq(2, 21)), + %% Now enable MAM for the conference + %% Retrieve config first + #iq{type = result, sub_els = [#muc_owner{config = #xdata{} = RoomCfg}]} = + send_recv(Config, #iq{type = get, sub_els = [#muc_owner{}], + to = Room}), + %% Find the MAM field in the config and enable it + NewFields = lists:flatmap( + fun(#xdata_field{var = <<"mam">> = Var}) -> + [#xdata_field{var = Var, values = [<<"1">>]}]; + (_) -> + [] + end, RoomCfg#xdata.fields), + NewRoomCfg = #xdata{type = submit, fields = NewFields}, + #iq{type = result, sub_els = []} = + send_recv(Config, #iq{type = set, to = Room, + sub_els = [#muc_owner{config = NewRoomCfg}]}), + #message{from = Room, type = groupchat, + sub_els = [#muc_user{status_codes = [104]}]} = recv_message(Config), + %% Check if MAM has been enabled + true = is_feature_advertised(Config, ?NS_MAM_1, Room), + %% We now sending some messages again + send_messages_to_room(Config, lists:seq(1, 5)), + %% And retrieve them via MAM again. + recv_messages_from_room(Config, lists:seq(1, 5)), + put_event(Config, disconnect), + clean(disconnect(Config)). + +muc_slave(Config) -> + disconnect = get_event(Config), + clean(disconnect(Config)). + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +single_test(T) -> + list_to_atom("mam_" ++ atom_to_list(T)). + +master_slave_test(T) -> + {list_to_atom("mam_" ++ atom_to_list(T)), [parallel], + [list_to_atom("mam_" ++ atom_to_list(T) ++ "_master"), + list_to_atom("mam_" ++ atom_to_list(T) ++ "_slave")]}. + +clean(Config) -> + {U, S, _} = jid:tolower(my_jid(Config)), + mod_mam:remove_user(U, S), + Config. + +set_default(Config, Default) -> + lists:foreach( + fun(NS) -> + ct:comment("Setting default preferences of '~s' to '~s'", + [NS, Default]), + #iq{type = result, + sub_els = [#mam_prefs{xmlns = NS, default = Default}]} = + send_recv(Config, #iq{type = set, + sub_els = [#mam_prefs{xmlns = NS, + default = Default}]}) + end, ?VERSIONS). + +send_messages(Config, Range) -> + Peer = ?config(peer, Config), + lists:foreach( + fun(N) -> + Body = xmpp:mk_text(integer_to_binary(N)), + send(Config, #message{to = Peer, body = Body}) + end, Range). + +recv_messages(Config, Range) -> + Peer = ?config(peer, Config), + lists:foreach( + fun(N) -> + Body = xmpp:mk_text(integer_to_binary(N)), + #message{from = Peer, body = Body} = Msg = + recv_message(Config), + #mam_archived{by = BareMyJID} = + xmpp:get_subtag(Msg, #mam_archived{}), + #stanza_id{by = BareMyJID} = + xmpp:get_subtag(Msg, #stanza_id{}) + end, Range). + +recv_archived_messages(Config, From, To, QID, Range) -> + MyJID = my_jid(Config), + lists:foreach( + fun(N) -> + ct:comment("Retreiving ~pth message in range ~p", + [N, Range]), + Body = xmpp:mk_text(integer_to_binary(N)), + #message{to = MyJID, + sub_els = + [#mam_result{ + queryid = QID, + sub_els = + [#forwarded{ + delay = #delay{}, + xml_els = [El]}]}]} = recv_message(Config), + #message{from = From, to = To, + body = Body} = xmpp:decode(El) + end, Range). + +maybe_recv_iq_result(Config, ?NS_MAM_0, I) -> + #iq{type = result, id = I} = recv_iq(Config); +maybe_recv_iq_result(_, _, _) -> + ok. + +query_iq_type(?NS_MAM_TMP) -> get; +query_iq_type(_) -> set. + +send_query(Config, #mam_query{xmlns = NS} = Query) -> + Type = query_iq_type(NS), + I = send(Config, #iq{type = Type, sub_els = [Query]}), + maybe_recv_iq_result(Config, NS, I), + I. + +recv_fin(Config, I, QueryID, ?NS_MAM_1 = NS, IsComplete) -> + ct:comment("Receiving fin iq for namespace '~s'", [NS]), + #iq{type = result, id = I, + sub_els = [#mam_fin{xmlns = NS, + id = QueryID, + complete = Complete, + rsm = RSM}]} = recv_iq(Config), + ct:comment("Checking if complete is ~s", [IsComplete]), + Complete = IsComplete, + RSM; +recv_fin(Config, I, QueryID, ?NS_MAM_TMP = NS, _IsComplete) -> + ct:comment("Receiving fin iq for namespace '~s'", [NS]), + #iq{type = result, id = I, + sub_els = [#mam_query{xmlns = NS, + rsm = RSM, + id = QueryID}]} = recv_iq(Config), + RSM; +recv_fin(Config, _, QueryID, ?NS_MAM_0 = NS, IsComplete) -> + ct:comment("Receiving fin message for namespace '~s'", [NS]), + #message{} = FinMsg = recv_message(Config), + #mam_fin{xmlns = NS, + id = QueryID, + complete = Complete, + rsm = RSM} = xmpp:get_subtag(FinMsg, #mam_fin{xmlns = NS}), + ct:comment("Checking if complete is ~s", [IsComplete]), + Complete = IsComplete, + RSM. + +send_messages_to_room(Config, Range) -> + MyNick = ?config(master_nick, Config), + Room = muc_room_jid(Config), + MyNickJID = jid:replace_resource(Room, MyNick), + lists:foreach( + fun(N) -> + Body = xmpp:mk_text(integer_to_binary(N)), + #message{from = MyNickJID, + type = groupchat, + body = Body} = + send_recv(Config, #message{to = Room, body = Body, + type = groupchat}) + end, Range). + +recv_messages_from_room(Config, Range) -> + MyNick = ?config(master_nick, Config), + Room = muc_room_jid(Config), + MyNickJID = jid:replace_resource(Room, MyNick), + MyJID = my_jid(Config), + QID = randoms:get_string(), + Count = length(Range), + I = send(Config, #iq{type = set, to = Room, + sub_els = [#mam_query{xmlns = ?NS_MAM_1, id = QID}]}), + lists:foreach( + fun(N) -> + Body = xmpp:mk_text(integer_to_binary(N)), + #message{ + to = MyJID, from = Room, + sub_els = + [#mam_result{ + xmlns = ?NS_MAM_1, + queryid = QID, + sub_els = + [#forwarded{ + delay = #delay{}, + xml_els = [El]}]}]} = recv_message(Config), + #message{from = MyNickJID, + type = groupchat, + body = Body} = xmpp:decode(El) + end, Range), + #iq{from = Room, id = I, type = result, + sub_els = [#mam_fin{xmlns = ?NS_MAM_1, + id = QID, + rsm = #rsm_set{count = Count}, + complete = true}]} = recv_iq(Config). + +query_all(Config, From, To) -> + lists:foreach( + fun(NS) -> + query_all(Config, From, To, NS) + end, ?VERSIONS). + +query_all(Config, From, To, NS) -> + QID = randoms:get_string(), + Range = lists:seq(1, 5), + ID = send_query(Config, #mam_query{xmlns = NS, id = QID}), + recv_archived_messages(Config, From, To, QID, Range), + #rsm_set{count = 5} = recv_fin(Config, ID, QID, NS, _Complete = true). + +query_with(Config, From, To) -> + lists:foreach( + fun(NS) -> + query_with(Config, From, To, NS) + end, ?VERSIONS). + +query_with(Config, From, To, NS) -> + Peer = ?config(peer, Config), + BarePeer = jid:remove_resource(Peer), + QID = randoms:get_string(), + Range = lists:seq(1, 5), + lists:foreach( + fun(JID) -> + ct:comment("Sending query with jid ~s", [jid:to_string(JID)]), + Query = if NS == ?NS_MAM_TMP -> + #mam_query{xmlns = NS, with = JID, id = QID}; + true -> + Fs = mam_query:encode([{with, JID}]), + #mam_query{xmlns = NS, id = QID, + xdata = #xdata{type = submit, + fields = Fs}} + end, + ID = send_query(Config, Query), + recv_archived_messages(Config, From, To, QID, Range), + #rsm_set{count = 5} = recv_fin(Config, ID, QID, NS, true) + end, [Peer, BarePeer]). + +query_rsm_max(Config, From, To) -> + lists:foreach( + fun(NS) -> + query_rsm_max(Config, From, To, NS) + end, ?VERSIONS). + +query_rsm_max(Config, From, To, NS) -> + lists:foreach( + fun(Max) -> + QID = randoms:get_string(), + Range = lists:sublist(lists:seq(1, Max), 5), + Query = #mam_query{xmlns = NS, id = QID, rsm = #rsm_set{max = Max}}, + ID = send_query(Config, Query), + recv_archived_messages(Config, From, To, QID, Range), + IsComplete = Max >= 5, + #rsm_set{count = 5} = recv_fin(Config, ID, QID, NS, IsComplete) + end, lists:seq(0, 6)). + +query_rsm_after(Config, From, To) -> + lists:foreach( + fun(NS) -> + query_rsm_after(Config, From, To, NS) + end, ?VERSIONS). + +query_rsm_after(Config, From, To, NS) -> + lists:foldl( + fun(Range, #rsm_first{data = After}) -> + ct:comment("Retrieving ~p messages after '~s'", + [length(Range), After]), + QID = randoms:get_string(), + Query = #mam_query{xmlns = NS, id = QID, + rsm = #rsm_set{'after' = After}}, + ID = send_query(Config, Query), + recv_archived_messages(Config, From, To, QID, Range), + #rsm_set{count = 5, first = First} = + recv_fin(Config, ID, QID, NS, true), + First + end, #rsm_first{}, [lists:seq(N, 5) || N <- lists:seq(1, 6)]). + +query_rsm_before(Config, From, To) -> + lists:foreach( + fun(NS) -> + query_rsm_before(Config, From, To, NS) + end, ?VERSIONS). + +query_rsm_before(Config, From, To, NS) -> + lists:foldl( + fun(Range, Before) -> + ct:comment("Retrieving ~p messages before '~s'", + [length(Range), Before]), + QID = randoms:get_string(), + Query = #mam_query{xmlns = NS, id = QID, + rsm = #rsm_set{before = Before}}, + ID = send_query(Config, Query), + recv_archived_messages(Config, From, To, QID, Range), + #rsm_set{count = 5, last = Last} = + recv_fin(Config, ID, QID, NS, true), + Last + end, <<"">>, lists:reverse([lists:seq(1, N) || N <- lists:seq(0, 5)])). diff --git a/test/mix_tests.erl b/test/mix_tests.erl new file mode 100644 index 000000000..56b1b35d7 --- /dev/null +++ b/test/mix_tests.erl @@ -0,0 +1,139 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 16 Nov 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(mix_tests). + +%% API +-compile(export_all). +-import(suite, [mix_jid/1, mix_room_jid/1, my_jid/1, is_feature_advertised/3, + disconnect/1, send_recv/2, recv_message/1, send/2, + put_event/2, get_event/1]). +-include("suite.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +%%%=================================================================== +%%% Single user tests +%%%=================================================================== +single_cases() -> + {mix_single, [sequence], + [single_test(feature_enabled)]}. + +feature_enabled(Config) -> + MIX = mix_jid(Config), + ct:comment("Checking if ~s is set", [?NS_MIX_0]), + true = is_feature_advertised(Config, ?NS_MIX_0, MIX), + disconnect(Config). + +%%%=================================================================== +%%% Master-slave tests +%%%=================================================================== +master_slave_cases() -> + {mix_master_slave, [sequence], + [master_slave_test(all)]}. + +all_master(Config) -> + MIX = mix_jid(Config), + Room = mix_room_jid(Config), + MyJID = my_jid(Config), + MyBareJID = jid:remove_resource(MyJID), + #iq{type = result, + sub_els = + [#disco_info{ + identities = [#identity{category = <<"conference">>, + type = <<"text">>}], + xdata = [#xdata{type = result, fields = XFields}]}]} = + send_recv(Config, #iq{type = get, to = MIX, sub_els = [#disco_info{}]}), + true = lists:any( + fun(#xdata_field{var = <<"FORM_TYPE">>, + values = [?NS_MIX_SERVICEINFO_0]}) -> true; + (_) -> false + end, XFields), + %% Joining + Nodes = [?NS_MIX_NODES_MESSAGES, ?NS_MIX_NODES_PRESENCE, + ?NS_MIX_NODES_PARTICIPANTS, ?NS_MIX_NODES_SUBJECT, + ?NS_MIX_NODES_CONFIG], + #iq{type = result, + sub_els = [#mix_join{subscribe = Nodes, jid = MyBareJID}]} = + send_recv(Config, #iq{type = set, to = Room, + sub_els = [#mix_join{subscribe = Nodes}]}), + #message{from = Room, + sub_els = + [#ps_event{ + items = #ps_items{ + node = ?NS_MIX_NODES_PARTICIPANTS, + items = [#ps_item{ + id = ParticipantID, + xml_els = [PXML]}]}}]} = + recv_message(Config), + #mix_participant{jid = MyBareJID} = xmpp:decode(PXML), + %% Coming online + PresenceID = randoms:get_string(), + Presence = xmpp:encode(#presence{}), + #iq{type = result, + sub_els = + [#pubsub{ + publish = #ps_publish{ + node = ?NS_MIX_NODES_PRESENCE, + items = [#ps_item{id = PresenceID}]}}]} = + send_recv( + Config, + #iq{type = set, to = Room, + sub_els = + [#pubsub{ + publish = #ps_publish{ + node = ?NS_MIX_NODES_PRESENCE, + items = [#ps_item{ + id = PresenceID, + xml_els = [Presence]}]}}]}), + #message{from = Room, + sub_els = + [#ps_event{ + items = #ps_items{ + node = ?NS_MIX_NODES_PRESENCE, + items = [#ps_item{ + id = PresenceID, + xml_els = [Presence]}]}}]} = + recv_message(Config), + %% Coming offline + send(Config, #presence{type = unavailable, to = Room}), + %% Receiving presence retract event + #message{from = Room, + sub_els = [#ps_event{ + items = #ps_items{ + node = ?NS_MIX_NODES_PRESENCE, + retract = PresenceID}}]} = + recv_message(Config), + %% Leaving + #iq{type = result, sub_els = []} = + send_recv(Config, #iq{type = set, to = Room, sub_els = [#mix_leave{}]}), + #message{from = Room, + sub_els = + [#ps_event{ + items = #ps_items{ + node = ?NS_MIX_NODES_PARTICIPANTS, + retract = ParticipantID}}]} = + recv_message(Config), + put_event(Config, disconnect), + disconnect(Config). + +all_slave(Config) -> + disconnect = get_event(Config), + disconnect(Config). + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +single_test(T) -> + list_to_atom("mix_" ++ atom_to_list(T)). + +master_slave_test(T) -> + {list_to_atom("mix_" ++ atom_to_list(T)), [parallel], + [list_to_atom("mix_" ++ atom_to_list(T) ++ "_master"), + list_to_atom("mix_" ++ atom_to_list(T) ++ "_slave")]}. diff --git a/test/mod_legacy.erl b/test/mod_legacy.erl index 6024acfeb..dba977554 100644 --- a/test/mod_legacy.erl +++ b/test/mod_legacy.erl @@ -10,7 +10,7 @@ -behaviour(gen_mod). %% API --export([start/2, stop/1, process_iq/3]). +-export([start/2, stop/1, mod_opt_type/1, depends/2, process_iq/3]). -include("jlib.hrl"). %%%=================================================================== @@ -25,6 +25,12 @@ start(Host, Opts) -> stop(Host) -> gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?MODULE). +mod_opt_type(_) -> + []. + +depends(_, _) -> + []. + %%%=================================================================== %%% Internal functions %%%=================================================================== diff --git a/test/muc_tests.erl b/test/muc_tests.erl index 709a82a22..d8e6dd8fb 100644 --- a/test/muc_tests.erl +++ b/test/muc_tests.erl @@ -11,10 +11,10 @@ %% API -compile(export_all). -import(suite, [recv_presence/1, send_recv/2, my_jid/1, muc_room_jid/1, - send/2, recv_message/1, recv_iq/1, recv/1, muc_jid/1, + send/2, recv_message/1, recv_iq/1, muc_jid/1, alt_room_jid/1, wait_for_slave/1, wait_for_master/1, disconnect/1, put_event/2, get_event/1, peer_muc_jid/1, - my_muc_jid/1, get_features/2, flush/1, set_opt/3]). + my_muc_jid/1, get_features/2, set_opt/3]). -include("suite.hrl"). -include("jid.hrl"). @@ -26,21 +26,21 @@ %%%=================================================================== single_cases() -> {muc_single, [sequence], - [muc_service_presence_error, - muc_service_message_error, - muc_service_unknown_ns_iq_error, - muc_service_iq_set_error, - muc_service_improper_iq_error, - muc_service_features, - muc_service_disco_info_node_error, - muc_service_disco_items, - muc_service_unique, - muc_service_vcard, - muc_configure_non_existent, - muc_cancel_configure_non_existent, - muc_service_subscriptions]}. + [single_test(service_presence_error), + single_test(service_message_error), + single_test(service_unknown_ns_iq_error), + single_test(service_iq_set_error), + single_test(service_improper_iq_error), + single_test(service_features), + single_test(service_disco_info_node_error), + single_test(service_disco_items), + single_test(service_unique), + single_test(service_vcard), + single_test(configure_non_existent), + single_test(cancel_configure_non_existent), + single_test(service_subscriptions)]}. -muc_service_presence_error(Config) -> +service_presence_error(Config) -> Service = muc_jid(Config), ServiceResource = jid:replace_resource(Service, randoms:get_string()), lists:foreach( @@ -56,7 +56,7 @@ muc_service_presence_error(Config) -> end, [Service, ServiceResource]), disconnect(Config). -muc_service_message_error(Config) -> +service_message_error(Config) -> Service = muc_jid(Config), send(Config, #message{type = error, to = Service}), lists:foreach( @@ -75,7 +75,7 @@ muc_service_message_error(Config) -> end, [chat, normal, headline, groupchat]), disconnect(Config). -muc_service_unknown_ns_iq_error(Config) -> +service_unknown_ns_iq_error(Config) -> Service = muc_jid(Config), ServiceResource = jid:replace_resource(Service, randoms:get_string()), lists:foreach( @@ -93,7 +93,7 @@ muc_service_unknown_ns_iq_error(Config) -> end, [Service, ServiceResource]), disconnect(Config). -muc_service_iq_set_error(Config) -> +service_iq_set_error(Config) -> Service = muc_jid(Config), lists:foreach( fun(SubEl) -> @@ -108,7 +108,7 @@ muc_service_iq_set_error(Config) -> #muc_unique{}, #muc_subscriptions{}]), disconnect(Config). -muc_service_improper_iq_error(Config) -> +service_improper_iq_error(Config) -> Service = muc_jid(Config), lists:foreach( fun(SubEl) -> @@ -127,7 +127,7 @@ muc_service_improper_iq_error(Config) -> #vcard_email{}, #muc_subscribe{nick = ?config(nick, Config)}]), disconnect(Config). -muc_service_features(Config) -> +service_features(Config) -> ServerHost = ?config(server_host, Config), MUC = muc_jid(Config), Features = sets:from_list(get_features(Config, MUC)), @@ -144,7 +144,7 @@ muc_service_features(Config) -> true = sets:is_subset(RequiredFeatures, Features), disconnect(Config). -muc_service_disco_info_node_error(Config) -> +service_disco_info_node_error(Config) -> MUC = muc_jid(Config), Node = randoms:get_string(), #iq{type = error} = Err = @@ -153,7 +153,7 @@ muc_service_disco_info_node_error(Config) -> #stanza_error{reason = 'item-not-found'} = xmpp:get_error(Err), disconnect(Config). -muc_service_disco_items(Config) -> +service_disco_items(Config) -> #jid{server = Service} = muc_jid(Config), Rooms = lists:sort( lists:map( @@ -163,25 +163,25 @@ muc_service_disco_items(Config) -> end, lists:seq(1, 5))), lists:foreach( fun(Room) -> - ok = muc_join_new(Config, Room) + ok = join_new(Config, Room) end, Rooms), - Items = muc_disco_items(Config), + Items = disco_items(Config), Rooms = [J || #disco_item{jid = J} <- Items], lists:foreach( fun(Room) -> - ok = muc_leave(Config, Room) + ok = leave(Config, Room) end, Rooms), - [] = muc_disco_items(Config), + [] = disco_items(Config), disconnect(Config). -muc_service_vcard(Config) -> +service_vcard(Config) -> MUC = muc_jid(Config), ct:comment("Retreiving vCard from ~s", [jid:to_string(MUC)]), #iq{type = result, sub_els = [#vcard_temp{}]} = send_recv(Config, #iq{type = get, to = MUC, sub_els = [#vcard_temp{}]}), disconnect(Config). -muc_service_unique(Config) -> +service_unique(Config) -> MUC = muc_jid(Config), ct:comment("Requesting muc unique from ~s", [jid:to_string(MUC)]), #iq{type = result, sub_els = [#muc_unique{name = Name}]} = @@ -190,11 +190,11 @@ muc_service_unique(Config) -> <<_, _/binary>> = Name, disconnect(Config). -muc_configure_non_existent(Config) -> - [_|_] = muc_get_config(Config), +configure_non_existent(Config) -> + [_|_] = get_config(Config), disconnect(Config). -muc_cancel_configure_non_existent(Config) -> +cancel_configure_non_existent(Config) -> Room = muc_room_jid(Config), #iq{type = result, sub_els = []} = send_recv(Config, @@ -202,7 +202,7 @@ muc_cancel_configure_non_existent(Config) -> sub_els = [#muc_owner{config = #xdata{type = cancel}}]}), disconnect(Config). -muc_service_subscriptions(Config) -> +service_subscriptions(Config) -> MUC = #jid{server = Service} = muc_jid(Config), Rooms = lists:sort( lists:map( @@ -212,9 +212,9 @@ muc_service_subscriptions(Config) -> end, lists:seq(1, 5))), lists:foreach( fun(Room) -> - ok = muc_join_new(Config, Room), - [104] = muc_set_config(Config, [{allow_subscription, true}], Room), - [] = muc_subscribe(Config, [], Room) + ok = join_new(Config, Room), + [104] = set_config(Config, [{allow_subscription, true}], Room), + [] = subscribe(Config, [], Room) end, Rooms), #iq{type = result, sub_els = [#muc_subscriptions{list = JIDs}]} = send_recv(Config, #iq{type = get, to = MUC, @@ -222,8 +222,8 @@ muc_service_subscriptions(Config) -> Rooms = lists:sort(JIDs), lists:foreach( fun(Room) -> - ok = muc_unsubscribe(Config, Room), - ok = muc_leave(Config, Room) + ok = unsubscribe(Config, Room), + ok = leave(Config, Room) end, Rooms), disconnect(Config). @@ -232,61 +232,61 @@ muc_service_subscriptions(Config) -> %%%=================================================================== master_slave_cases() -> {muc_master_slave, [sequence], - [master_slave_test(muc_register), - master_slave_test(muc_groupchat_msg), - master_slave_test(muc_private_msg), - master_slave_test(muc_set_subject), - master_slave_test(muc_history), - master_slave_test(muc_invite), - master_slave_test(muc_invite_members_only), - master_slave_test(muc_invite_password_protected), - master_slave_test(muc_voice_request), - master_slave_test(muc_change_role), - master_slave_test(muc_kick), - master_slave_test(muc_change_affiliation), - master_slave_test(muc_destroy), - master_slave_test(muc_vcard), - master_slave_test(muc_nick_change), - master_slave_test(muc_config_title_desc), - master_slave_test(muc_config_public_list), - master_slave_test(muc_config_password), - master_slave_test(muc_config_whois), - master_slave_test(muc_config_members_only), - master_slave_test(muc_config_moderated), - master_slave_test(muc_config_private_messages), - master_slave_test(muc_config_query), - master_slave_test(muc_config_allow_invites), - master_slave_test(muc_config_visitor_status), - master_slave_test(muc_config_allow_voice_requests), - master_slave_test(muc_config_voice_request_interval), - master_slave_test(muc_config_visitor_nickchange), - master_slave_test(muc_join_conflict)]}. + [master_slave_test(register), + master_slave_test(groupchat_msg), + master_slave_test(private_msg), + master_slave_test(set_subject), + master_slave_test(history), + master_slave_test(invite), + master_slave_test(invite_members_only), + master_slave_test(invite_password_protected), + master_slave_test(voice_request), + master_slave_test(change_role), + master_slave_test(kick), + master_slave_test(change_affiliation), + master_slave_test(destroy), + master_slave_test(vcard), + master_slave_test(nick_change), + master_slave_test(config_title_desc), + master_slave_test(config_public_list), + master_slave_test(config_password), + master_slave_test(config_whois), + master_slave_test(config_members_only), + master_slave_test(config_moderated), + master_slave_test(config_private_messages), + master_slave_test(config_query), + master_slave_test(config_allow_invites), + master_slave_test(config_visitor_status), + master_slave_test(config_allow_voice_requests), + master_slave_test(config_voice_request_interval), + master_slave_test(config_visitor_nickchange), + master_slave_test(join_conflict)]}. -muc_join_conflict_master(Config) -> - ok = muc_join_new(Config), +join_conflict_master(Config) -> + ok = join_new(Config), put_event(Config, join), ct:comment("Waiting for 'leave' command from the slave"), leave = get_event(Config), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_join_conflict_slave(Config) -> +join_conflict_slave(Config) -> NewConfig = set_opt(nick, ?config(peer_nick, Config), Config), ct:comment("Waiting for 'join' command from the master"), join = get_event(Config), ct:comment("Fail trying to join the room with conflicting nick"), - #stanza_error{reason = 'conflict'} = muc_join(NewConfig), + #stanza_error{reason = 'conflict'} = join(NewConfig), put_event(Config, leave), disconnect(NewConfig). -muc_groupchat_msg_master(Config) -> +groupchat_msg_master(Config) -> Room = muc_room_jid(Config), PeerJID = ?config(slave, Config), PeerNick = ?config(slave_nick, Config), PeerNickJID = jid:replace_resource(Room, PeerNick), MyNick = ?config(nick, Config), MyNickJID = jid:replace_resource(Room, MyNick), - ok = muc_master_join(Config), + ok = master_join(Config), lists:foreach( fun(I) -> Body = xmpp:mk_text(integer_to_binary(I)), @@ -299,29 +299,29 @@ muc_groupchat_msg_master(Config) -> role = none, affiliation = none}]} = recv_muc_presence(Config, PeerNickJID, unavailable), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_groupchat_msg_slave(Config) -> +groupchat_msg_slave(Config) -> Room = muc_room_jid(Config), PeerNick = ?config(master_nick, Config), PeerNickJID = jid:replace_resource(Room, PeerNick), - {[], _, _} = muc_slave_join(Config), + {[], _, _} = slave_join(Config), lists:foreach( fun(I) -> Body = xmpp:mk_text(integer_to_binary(I)), #message{type = groupchat, from = PeerNickJID, body = Body} = recv_message(Config) end, lists:seq(1, 5)), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_private_msg_master(Config) -> +private_msg_master(Config) -> Room = muc_room_jid(Config), PeerJID = ?config(slave, Config), PeerNick = ?config(slave_nick, Config), PeerNickJID = jid:replace_resource(Room, PeerNick), - ok = muc_master_join(Config), + ok = master_join(Config), lists:foreach( fun(I) -> Body = xmpp:mk_text(integer_to_binary(I)), @@ -336,31 +336,31 @@ muc_private_msg_master(Config) -> send(Config, #message{type = chat, to = PeerNickJID}), #message{from = PeerNickJID, type = error} = ErrMsg = recv_message(Config), #stanza_error{reason = 'item-not-found'} = xmpp:get_error(ErrMsg), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_private_msg_slave(Config) -> +private_msg_slave(Config) -> Room = muc_room_jid(Config), PeerNick = ?config(master_nick, Config), PeerNickJID = jid:replace_resource(Room, PeerNick), - {[], _, _} = muc_slave_join(Config), + {[], _, _} = slave_join(Config), lists:foreach( fun(I) -> Body = xmpp:mk_text(integer_to_binary(I)), #message{type = chat, from = PeerNickJID, body = Body} = recv_message(Config) end, lists:seq(1, 5)), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_set_subject_master(Config) -> +set_subject_master(Config) -> Room = muc_room_jid(Config), PeerJID = ?config(slave, Config), PeerNick = ?config(slave_nick, Config), PeerNickJID = jid:replace_resource(Room, PeerNick), Subject1 = xmpp:mk_text(?config(room_subject, Config)), Subject2 = xmpp:mk_text(<<"new-", (?config(room_subject, Config))/binary>>), - ok = muc_master_join(Config), + ok = master_join(Config), ct:comment("Setting 1st subject"), send(Config, #message{type = groupchat, to = Room, subject = Subject1}), @@ -380,30 +380,30 @@ muc_set_subject_master(Config) -> #message{type = groupchat, from = PeerNickJID, subject = Subject1} = recv_message(Config), ct:comment("Disallow subject change"), - [104] = muc_set_config(Config, [{changesubject, false}]), + [104] = set_config(Config, [{changesubject, false}]), ct:comment("Waiting for the slave to leave"), #muc_user{items = [#muc_item{jid = PeerJID, role = none, affiliation = none}]} = recv_muc_presence(Config, PeerNickJID, unavailable), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_set_subject_slave(Config) -> +set_subject_slave(Config) -> Room = muc_room_jid(Config), MyNickJID = my_muc_jid(Config), PeerNick = ?config(master_nick, Config), PeerNickJID = jid:replace_resource(Room, PeerNick), Subject1 = xmpp:mk_text(?config(room_subject, Config)), Subject2 = xmpp:mk_text(<<"new-", (?config(room_subject, Config))/binary>>), - {[], _, _} = muc_slave_join(Config), + {[], _, _} = slave_join(Config), ct:comment("Receiving 1st subject set by the master"), #message{type = groupchat, from = PeerNickJID, subject = Subject1} = recv_message(Config), - ok = muc_leave(Config), + ok = leave(Config), ct:comment("Waiting for 'join' command from the master"), join = get_event(Config), - {[], SubjMsg2, _} = muc_join(Config), + {[], SubjMsg2, _} = join(Config), ct:comment("Checking if the master has set 2nd subject during our absence"), #message{type = groupchat, from = PeerNickJID, subject = Subject2} = SubjMsg2, @@ -412,15 +412,15 @@ muc_set_subject_slave(Config) -> #message{type = groupchat, from = MyNickJID, subject = Subject1} = recv_message(Config), ct:comment("Waiting for the master to disallow subject change"), - [104] = muc_recv_config_change_message(Config), + [104] = recv_config_change_message(Config), ct:comment("Fail trying to change the subject"), send(Config, #message{to = Room, type = groupchat, subject = Subject2}), #message{from = Room, type = error} = ErrMsg = recv_message(Config), #stanza_error{reason = 'forbidden'} = xmpp:get_error(ErrMsg), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_history_master(Config) -> +history_master(Config) -> Room = muc_room_jid(Config), ServerHost = ?config(server_host, Config), MyNick = ?config(nick, Config), @@ -429,7 +429,7 @@ muc_history_master(Config) -> Size = gen_mod:get_module_opt(ServerHost, mod_muc, history_size, fun(I) when is_integer(I), I>=0 -> I end, 20), - ok = muc_join_new(Config), + ok = join_new(Config), ct:comment("Putting ~p+1 messages in the history", [Size]), %% Only Size messages will be stored lists:foreach( @@ -448,10 +448,10 @@ muc_history_master(Config) -> available, unavailable, available, unavailable, available, unavailable]), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_history_slave(Config) -> +history_slave(Config) -> Room = muc_room_jid(Config), PeerNick = ?config(peer_nick, Config), PeerNickJID = jid:replace_resource(Room, PeerNick), @@ -461,45 +461,45 @@ muc_history_slave(Config) -> 20), ct:comment("Waiting for 'join' command from the master"), join = get_event(Config), - {History, _, _} = muc_join(Config), + {History, _, _} = join(Config), ct:comment("Checking ordering of history events"), BodyList = [binary_to_integer(xmpp:get_text(Body)) || #message{type = groupchat, from = From, body = Body} <- History, From == PeerNickJID], BodyList = lists:seq(1, Size), - ok = muc_leave(Config), + ok = leave(Config), %% If the client wishes to receive no history, it MUST set the 'maxchars' %% attribute to a value of "0" (zero) %% (http://xmpp.org/extensions/xep-0045.html#enter-managehistory) ct:comment("Checking if maxchars=0 yields to no history"), - {[], _, _} = muc_join(Config, #muc{history = #muc_history{maxchars = 0}}), - ok = muc_leave(Config), + {[], _, _} = join(Config, #muc{history = #muc_history{maxchars = 0}}), + ok = leave(Config), ct:comment("Receiving only 10 last stanzas"), - {History10, _, _} = muc_join(Config, + {History10, _, _} = join(Config, #muc{history = #muc_history{maxstanzas = 10}}), BodyList10 = [binary_to_integer(xmpp:get_text(Body)) || #message{type = groupchat, from = From, body = Body} <- History10, From == PeerNickJID], BodyList10 = lists:nthtail(Size-10, lists:seq(1, Size)), - ok = muc_leave(Config), + ok = leave(Config), #delay{stamp = TS} = xmpp:get_subtag(hd(History), #delay{}), ct:comment("Receiving all history without the very first element"), - {HistoryWithoutFirst, _, _} = muc_join(Config, + {HistoryWithoutFirst, _, _} = join(Config, #muc{history = #muc_history{since = TS}}), BodyListWithoutFirst = [binary_to_integer(xmpp:get_text(Body)) || #message{type = groupchat, from = From, body = Body} <- HistoryWithoutFirst, From == PeerNickJID], BodyListWithoutFirst = lists:nthtail(1, lists:seq(1, Size)), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_invite_master(Config) -> +invite_master(Config) -> Room = muc_room_jid(Config), PeerJID = ?config(peer, Config), - ok = muc_join_new(Config), + ok = join_new(Config), wait_for_slave(Config), %% Inviting the peer send(Config, #message{to = Room, type = normal, @@ -510,10 +510,10 @@ muc_invite_master(Config) -> #message{from = Room} = DeclineMsg = recv_message(Config), #muc_user{decline = #muc_decline{from = PeerJID}} = xmpp:get_subtag(DeclineMsg, #muc_user{}), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_invite_slave(Config) -> +invite_slave(Config) -> Room = muc_room_jid(Config), wait_for_master(Config), PeerJID = ?config(master, Config), @@ -527,12 +527,12 @@ muc_invite_slave(Config) -> decline = #muc_decline{to = PeerJID}}]}), disconnect(Config). -muc_invite_members_only_master(Config) -> +invite_members_only_master(Config) -> Room = muc_room_jid(Config), PeerJID = ?config(slave, Config), - ok = muc_join_new(Config), + ok = join_new(Config), %% Setting the room to members-only - [_|_] = muc_set_config(Config, [{membersonly, true}]), + [_|_] = set_config(Config, [{membersonly, true}]), wait_for_slave(Config), %% Inviting the peer send(Config, #message{to = Room, type = normal, @@ -543,22 +543,22 @@ muc_invite_members_only_master(Config) -> #message{from = Room, type = normal} = AffMsg = recv_message(Config), #muc_user{items = [#muc_item{jid = PeerJID, affiliation = member}]} = xmpp:get_subtag(AffMsg, #muc_user{}), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_invite_members_only_slave(Config) -> +invite_members_only_slave(Config) -> Room = muc_room_jid(Config), wait_for_master(Config), %% Receiving invitation #message{from = Room, type = normal} = recv_message(Config), disconnect(Config). -muc_invite_password_protected_master(Config) -> +invite_password_protected_master(Config) -> Room = muc_room_jid(Config), PeerJID = ?config(slave, Config), Password = randoms:get_string(), - ok = muc_join_new(Config), - [104] = muc_set_config(Config, [{passwordprotectedroom, true}, + ok = join_new(Config), + [104] = set_config(Config, [{passwordprotectedroom, true}, {roomsecret, Password}]), put_event(Config, Password), %% Inviting the peer @@ -567,10 +567,10 @@ muc_invite_password_protected_master(Config) -> [#muc_user{ invites = [#muc_invite{to = PeerJID}]}]}), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_invite_password_protected_slave(Config) -> +invite_password_protected_slave(Config) -> Room = muc_room_jid(Config), Password = get_event(Config), %% Receiving invitation @@ -578,13 +578,13 @@ muc_invite_password_protected_slave(Config) -> #muc_user{password = Password} = xmpp:get_subtag(Msg, #muc_user{}), disconnect(Config). -muc_voice_request_master(Config) -> +voice_request_master(Config) -> Room = muc_room_jid(Config), PeerJID = ?config(slave, Config), PeerNick = ?config(slave_nick, Config), PeerNickJID = jid:replace_resource(Room, PeerNick), - ok = muc_join_new(Config), - [104] = muc_set_config(Config, [{members_by_default, false}]), + ok = join_new(Config), + [104] = set_config(Config, [{members_by_default, false}]), wait_for_slave(Config), #muc_user{ items = [#muc_item{role = visitor, @@ -610,16 +610,16 @@ muc_voice_request_master(Config) -> recv_muc_presence(Config, PeerNickJID, available), ct:comment("Waiting for the slave to leave"), recv_muc_presence(Config, PeerNickJID, unavailable), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_voice_request_slave(Config) -> +voice_request_slave(Config) -> Room = muc_room_jid(Config), MyJID = my_jid(Config), MyNick = ?config(nick, Config), MyNickJID = jid:replace_resource(Room, MyNick), wait_for_master(Config), - {[], _, _} = muc_join(Config, visitor), + {[], _, _} = join(Config, visitor), ct:comment("Requesting voice"), Fs = muc_request:encode([{role, participant}]), X = #xdata{type = submit, fields = Fs}, @@ -630,17 +630,17 @@ muc_voice_request_slave(Config) -> jid = MyJID, affiliation = none}]} = recv_muc_presence(Config, MyNickJID, available), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_change_role_master(Config) -> +change_role_master(Config) -> Room = muc_room_jid(Config), MyJID = my_jid(Config), MyNick = ?config(nick, Config), PeerJID = ?config(slave, Config), PeerNick = ?config(slave_nick, Config), PeerNickJID = jid:replace_resource(Room, PeerNick), - ok = muc_join_new(Config), + ok = join_new(Config), ct:comment("Waiting for the slave to join"), wait_for_slave(Config), #muc_user{items = [#muc_item{role = participant, @@ -650,7 +650,7 @@ muc_change_role_master(Config) -> lists:foreach( fun(Role) -> ct:comment("Checking if the slave is not in the roles list"), - case muc_get_role(Config, Role) of + case get_role(Config, Role) of [#muc_item{jid = MyJID, affiliation = owner, role = moderator, nick = MyNick}] when Role == moderator -> ok; @@ -659,7 +659,7 @@ muc_change_role_master(Config) -> end, Reason = randoms:get_string(), put_event(Config, {Role, Reason}), - ok = muc_set_role(Config, Role, Reason), + ok = set_role(Config, Role, Reason), ct:comment("Receiving role change to ~s", [Role]), #muc_user{ items = [#muc_item{role = Role, @@ -667,19 +667,19 @@ muc_change_role_master(Config) -> reason = Reason}]} = recv_muc_presence(Config, PeerNickJID, available), [#muc_item{role = Role, affiliation = none, - nick = PeerNick}|_] = muc_get_role(Config, Role) + nick = PeerNick}|_] = get_role(Config, Role) end, [visitor, participant, moderator]), put_event(Config, disconnect), recv_muc_presence(Config, PeerNickJID, unavailable), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_change_role_slave(Config) -> +change_role_slave(Config) -> wait_for_master(Config), - {[], _, _} = muc_join(Config), - muc_change_role_slave(Config, get_event(Config)). + {[], _, _} = join(Config), + change_role_slave(Config, get_event(Config)). -muc_change_role_slave(Config, {Role, Reason}) -> +change_role_slave(Config, {Role, Reason}) -> Room = muc_room_jid(Config), MyNick = ?config(slave_nick, Config), MyNickJID = jid:replace_resource(Room, MyNick), @@ -690,12 +690,12 @@ muc_change_role_slave(Config, {Role, Reason}) -> reason = Reason}]} = recv_muc_presence(Config, MyNickJID, available), true = lists:member(110, Codes), - muc_change_role_slave(Config, get_event(Config)); -muc_change_role_slave(Config, disconnect) -> - ok = muc_leave(Config), + change_role_slave(Config, get_event(Config)); +change_role_slave(Config, disconnect) -> + ok = leave(Config), disconnect(Config). -muc_change_affiliation_master(Config) -> +change_affiliation_master(Config) -> Room = muc_room_jid(Config), MyJID = my_jid(Config), MyBareJID = jid:remove_resource(MyJID), @@ -704,7 +704,7 @@ muc_change_affiliation_master(Config) -> PeerBareJID = jid:remove_resource(PeerJID), PeerNick = ?config(slave_nick, Config), PeerNickJID = jid:replace_resource(Room, PeerNick), - ok = muc_join_new(Config), + ok = join_new(Config), ct:comment("Waiting for the slave to join"), wait_for_slave(Config), #muc_user{items = [#muc_item{role = participant, @@ -714,7 +714,7 @@ muc_change_affiliation_master(Config) -> lists:foreach( fun({Aff, Role, Status}) -> ct:comment("Checking if slave is not in affiliation list"), - case muc_get_affiliation(Config, Aff) of + case get_affiliation(Config, Aff) of [#muc_item{jid = MyBareJID, affiliation = owner}] when Aff == owner -> ok; @@ -723,7 +723,7 @@ muc_change_affiliation_master(Config) -> end, Reason = randoms:get_string(), put_event(Config, {Aff, Role, Status, Reason}), - ok = muc_set_affiliation(Config, Aff, Reason), + ok = set_affiliation(Config, Aff, Reason), ct:comment("Receiving affiliation change to ~s", [Aff]), #muc_user{ items = [#muc_item{role = Role, @@ -737,7 +737,7 @@ muc_change_affiliation_master(Config) -> true -> ok end, - Affs = muc_get_affiliation(Config, Aff), + Affs = get_affiliation(Config, Aff), ct:comment("Checking if the affiliation was correctly set"), case lists:keyfind(PeerBareJID, #muc_item.jid, Affs) of false when Aff == none -> @@ -748,15 +748,15 @@ muc_change_affiliation_master(Config) -> end, [{member, participant, available}, {none, participant, available}, {admin, moderator, available}, {owner, moderator, available}, {outcast, none, unavailable}]), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_change_affiliation_slave(Config) -> +change_affiliation_slave(Config) -> wait_for_master(Config), - {[], _, _} = muc_join(Config), - muc_change_affiliation_slave(Config, get_event(Config)). + {[], _, _} = join(Config), + change_affiliation_slave(Config, get_event(Config)). -muc_change_affiliation_slave(Config, {Aff, Role, Status, Reason}) -> +change_affiliation_slave(Config, {Aff, Role, Status, Reason}) -> Room = muc_room_jid(Config), PeerNick = ?config(master_nick, Config), MyNick = ?config(nick, Config), @@ -776,17 +776,17 @@ muc_change_affiliation_slave(Config, {Aff, Role, Status, Reason}) -> #muc_actor{nick = PeerNick} = Actor, disconnect(Config); true -> - muc_change_affiliation_slave(Config, get_event(Config)) + change_affiliation_slave(Config, get_event(Config)) end. -muc_kick_master(Config) -> +kick_master(Config) -> Room = muc_room_jid(Config), MyNick = ?config(nick, Config), PeerJID = ?config(slave, Config), PeerNick = ?config(slave_nick, Config), PeerNickJID = jid:replace_resource(Room, PeerNick), Reason = <<"Testing">>, - ok = muc_join_new(Config), + ok = join_new(Config), ct:comment("Waiting for the slave to join"), wait_for_slave(Config), #muc_user{items = [#muc_item{role = participant, @@ -794,9 +794,9 @@ muc_kick_master(Config) -> affiliation = none}]} = recv_muc_presence(Config, PeerNickJID, available), [#muc_item{role = participant, affiliation = none, - nick = PeerNick}|_] = muc_get_role(Config, participant), + nick = PeerNick}|_] = get_role(Config, participant), ct:comment("Kicking slave"), - ok = muc_set_role(Config, none, Reason), + ok = set_role(Config, none, Reason), ct:comment("Receiving role change to 'none'"), #muc_user{ status_codes = Codes, @@ -805,20 +805,20 @@ muc_kick_master(Config) -> actor = #muc_actor{nick = MyNick}, reason = Reason}]} = recv_muc_presence(Config, PeerNickJID, unavailable), - [] = muc_get_role(Config, participant), + [] = get_role(Config, participant), ct:comment("Checking if the code is '307' (kicked)"), true = lists:member(307, Codes), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_kick_slave(Config) -> +kick_slave(Config) -> Room = muc_room_jid(Config), PeerNick = ?config(master_nick, Config), MyNick = ?config(nick, Config), MyNickJID = jid:replace_resource(Room, MyNick), Reason = <<"Testing">>, wait_for_master(Config), - {[], _, _} = muc_join(Config), + {[], _, _} = join(Config), ct:comment("Receiving role change to 'none'"), #muc_user{status_codes = Codes, items = [#muc_item{role = none, @@ -832,7 +832,7 @@ muc_kick_slave(Config) -> true = lists:member(307, Codes), disconnect(Config). -muc_destroy_master(Config) -> +destroy_master(Config) -> Reason = <<"Testing">>, Room = muc_room_jid(Config), AltRoom = alt_room_jid(Config), @@ -841,7 +841,7 @@ muc_destroy_master(Config) -> PeerNickJID = jid:replace_resource(Room, PeerNick), MyNick = ?config(nick, Config), MyNickJID = jid:replace_resource(Room, MyNick), - ok = muc_join_new(Config), + ok = join_new(Config), ct:comment("Waiting for slave to join"), wait_for_slave(Config), #muc_user{items = [#muc_item{role = participant, @@ -849,7 +849,7 @@ muc_destroy_master(Config) -> affiliation = none}]} = recv_muc_presence(Config, PeerNickJID, available), wait_for_slave(Config), - ok = muc_destroy(Config, Reason), + ok = destroy(Config, Reason), ct:comment("Receiving destruction presence"), #muc_user{items = [#muc_item{role = none, affiliation = none}], @@ -858,15 +858,15 @@ muc_destroy_master(Config) -> recv_muc_presence(Config, MyNickJID, unavailable), disconnect(Config). -muc_destroy_slave(Config) -> +destroy_slave(Config) -> Reason = <<"Testing">>, Room = muc_room_jid(Config), AltRoom = alt_room_jid(Config), MyNick = ?config(nick, Config), MyNickJID = jid:replace_resource(Room, MyNick), wait_for_master(Config), - {[], _, _} = muc_join(Config), - #stanza_error{reason = 'forbidden'} = muc_destroy(Config, Reason), + {[], _, _} = join(Config), + #stanza_error{reason = 'forbidden'} = destroy(Config, Reason), wait_for_master(Config), ct:comment("Receiving destruction presence"), #muc_user{items = [#muc_item{role = none, @@ -876,43 +876,43 @@ muc_destroy_slave(Config) -> recv_muc_presence(Config, MyNickJID, unavailable), disconnect(Config). -muc_vcard_master(Config) -> +vcard_master(Config) -> Room = muc_room_jid(Config), PeerNick = ?config(slave_nick, Config), PeerNickJID = jid:replace_resource(Room, PeerNick), FN = randoms:get_string(), VCard = #vcard_temp{fn = FN}, - ok = muc_join_new(Config), + ok = join_new(Config), ct:comment("Waiting for slave to join"), wait_for_slave(Config), #muc_user{items = [#muc_item{role = participant, affiliation = none}]} = recv_muc_presence(Config, PeerNickJID, available), - #stanza_error{reason = 'item-not-found'} = muc_get_vcard(Config), - ok = muc_set_vcard(Config, VCard), - VCard = muc_get_vcard(Config), + #stanza_error{reason = 'item-not-found'} = get_vcard(Config), + ok = set_vcard(Config, VCard), + VCard = get_vcard(Config), put_event(Config, VCard), recv_muc_presence(Config, PeerNickJID, unavailable), leave = get_event(Config), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_vcard_slave(Config) -> +vcard_slave(Config) -> wait_for_master(Config), - {[], _, _} = muc_join(Config), + {[], _, _} = join(Config), VCard = get_event(Config), - VCard = muc_get_vcard(Config), - #stanza_error{reason = 'forbidden'} = muc_set_vcard(Config, VCard), - ok = muc_leave(Config), - VCard = muc_get_vcard(Config), + VCard = get_vcard(Config), + #stanza_error{reason = 'forbidden'} = set_vcard(Config, VCard), + ok = leave(Config), + VCard = get_vcard(Config), put_event(Config, leave), disconnect(Config). -muc_nick_change_master(Config) -> +nick_change_master(Config) -> NewNick = randoms:get_string(), PeerJID = ?config(peer, Config), PeerNickJID = peer_muc_jid(Config), - ok = muc_master_join(Config), + ok = master_join(Config), put_event(Config, {new_nick, NewNick}), ct:comment("Waiting for nickchange presence from the slave"), #muc_user{status_codes = Codes, @@ -926,13 +926,13 @@ muc_nick_change_master(Config) -> recv_muc_presence(Config, PeerNewNickJID, available), ct:comment("Waiting for the slave to leave"), recv_muc_presence(Config, PeerNewNickJID, unavailable), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_nick_change_slave(Config) -> +nick_change_slave(Config) -> MyJID = my_jid(Config), MyNickJID = my_muc_jid(Config), - {[], _, _} = muc_slave_join(Config), + {[], _, _} = slave_join(Config), {new_nick, NewNick} = get_event(Config), MyNewNickJID = jid:replace_resource(MyNickJID, NewNick), ct:comment("Sending new presence"), @@ -955,131 +955,131 @@ muc_nick_change_slave(Config) -> ct:comment("Checking if code '110' (self-presence) is set"), lists:member(110, Codes2), NewConfig = set_opt(nick, NewNick, Config), - ok = muc_leave(NewConfig), + ok = leave(NewConfig), disconnect(NewConfig). -muc_config_title_desc_master(Config) -> +config_title_desc_master(Config) -> Title = randoms:get_string(), Desc = randoms:get_string(), Room = muc_room_jid(Config), PeerNick = ?config(slave_nick, Config), PeerNickJID = jid:replace_resource(Room, PeerNick), - ok = muc_master_join(Config), - [104] = muc_set_config(Config, [{roomname, Title}, {roomdesc, Desc}]), - RoomCfg = muc_get_config(Config), + ok = master_join(Config), + [104] = set_config(Config, [{roomname, Title}, {roomdesc, Desc}]), + RoomCfg = get_config(Config), Title = proplists:get_value(roomname, RoomCfg), Desc = proplists:get_value(roomdesc, RoomCfg), recv_muc_presence(Config, PeerNickJID, unavailable), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_config_title_desc_slave(Config) -> - {[], _, _} = muc_slave_join(Config), - [104] = muc_recv_config_change_message(Config), - ok = muc_leave(Config), +config_title_desc_slave(Config) -> + {[], _, _} = slave_join(Config), + [104] = recv_config_change_message(Config), + ok = leave(Config), disconnect(Config). -muc_config_public_list_master(Config) -> +config_public_list_master(Config) -> Room = muc_room_jid(Config), PeerNick = ?config(slave_nick, Config), PeerNickJID = jid:replace_resource(Room, PeerNick), - ok = muc_join_new(Config), + ok = join_new(Config), wait_for_slave(Config), recv_muc_presence(Config, PeerNickJID, available), lists:member(<<"muc_public">>, get_features(Config, Room)), - [104] = muc_set_config(Config, [{public_list, false}, + [104] = set_config(Config, [{public_list, false}, {publicroom, false}]), recv_muc_presence(Config, PeerNickJID, unavailable), lists:member(<<"muc_hidden">>, get_features(Config, Room)), wait_for_slave(Config), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_config_public_list_slave(Config) -> +config_public_list_slave(Config) -> Room = muc_room_jid(Config), wait_for_master(Config), PeerNick = ?config(peer_nick, Config), PeerNickJID = peer_muc_jid(Config), - [#disco_item{jid = Room}] = muc_disco_items(Config), + [#disco_item{jid = Room}] = disco_items(Config), [#disco_item{jid = PeerNickJID, - name = PeerNick}] = muc_disco_room_items(Config), - {[], _, _} = muc_join(Config), - [104] = muc_recv_config_change_message(Config), - ok = muc_leave(Config), - [] = muc_disco_items(Config), - [] = muc_disco_room_items(Config), + name = PeerNick}] = disco_room_items(Config), + {[], _, _} = join(Config), + [104] = recv_config_change_message(Config), + ok = leave(Config), + [] = disco_items(Config), + [] = disco_room_items(Config), wait_for_master(Config), disconnect(Config). -muc_config_password_master(Config) -> +config_password_master(Config) -> Password = randoms:get_string(), Room = muc_room_jid(Config), PeerNick = ?config(slave_nick, Config), PeerNickJID = jid:replace_resource(Room, PeerNick), - ok = muc_join_new(Config), + ok = join_new(Config), lists:member(<<"muc_unsecured">>, get_features(Config, Room)), - [104] = muc_set_config(Config, [{passwordprotectedroom, true}, + [104] = set_config(Config, [{passwordprotectedroom, true}, {roomsecret, Password}]), lists:member(<<"muc_passwordprotected">>, get_features(Config, Room)), put_event(Config, Password), recv_muc_presence(Config, PeerNickJID, available), recv_muc_presence(Config, PeerNickJID, unavailable), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_config_password_slave(Config) -> +config_password_slave(Config) -> Password = get_event(Config), - #stanza_error{reason = 'not-authorized'} = muc_join(Config), + #stanza_error{reason = 'not-authorized'} = join(Config), #stanza_error{reason = 'not-authorized'} = - muc_join(Config, #muc{password = randoms:get_string()}), - {[], _, _} = muc_join(Config, #muc{password = Password}), - ok = muc_leave(Config), + join(Config, #muc{password = randoms:get_string()}), + {[], _, _} = join(Config, #muc{password = Password}), + ok = leave(Config), disconnect(Config). -muc_config_whois_master(Config) -> +config_whois_master(Config) -> Room = muc_room_jid(Config), PeerNickJID = peer_muc_jid(Config), MyNickJID = my_muc_jid(Config), - ok = muc_master_join(Config), + ok = master_join(Config), lists:member(<<"muc_semianonymous">>, get_features(Config, Room)), - [172] = muc_set_config(Config, [{whois, anyone}]), + [172] = set_config(Config, [{whois, anyone}]), lists:member(<<"muc_nonanonymous">>, get_features(Config, Room)), recv_muc_presence(Config, PeerNickJID, unavailable), recv_muc_presence(Config, PeerNickJID, available), send(Config, #presence{to = Room}), recv_muc_presence(Config, MyNickJID, available), - [173] = muc_set_config(Config, [{whois, moderators}]), + [173] = set_config(Config, [{whois, moderators}]), recv_muc_presence(Config, PeerNickJID, unavailable), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_config_whois_slave(Config) -> +config_whois_slave(Config) -> PeerJID = ?config(peer, Config), PeerNickJID = peer_muc_jid(Config), - {[], _, _} = muc_slave_join(Config), + {[], _, _} = slave_join(Config), ct:comment("Checking if the room becomes non-anonymous (code '172')"), - [172] = muc_recv_config_change_message(Config), + [172] = recv_config_change_message(Config), ct:comment("Re-joining in order to check status codes"), - ok = muc_leave(Config), - {[], _, Codes} = muc_join(Config), + ok = leave(Config), + {[], _, Codes} = join(Config), ct:comment("Checking if code '100' (non-anonymous) present"), true = lists:member(100, Codes), ct:comment("Receiving presence from peer with JID exposed"), #muc_user{items = [#muc_item{jid = PeerJID}]} = recv_muc_presence(Config, PeerNickJID, available), ct:comment("Waiting for the room to become anonymous again (code '173')"), - [173] = muc_recv_config_change_message(Config), - ok = muc_leave(Config), + [173] = recv_config_change_message(Config), + ok = leave(Config), disconnect(Config). -muc_config_members_only_master(Config) -> +config_members_only_master(Config) -> Room = muc_room_jid(Config), PeerJID = ?config(peer, Config), PeerBareJID = jid:remove_resource(PeerJID), PeerNickJID = peer_muc_jid(Config), - ok = muc_master_join(Config), + ok = master_join(Config), lists:member(<<"muc_open">>, get_features(Config, Room)), - [104] = muc_set_config(Config, [{membersonly, true}]), + [104] = set_config(Config, [{membersonly, true}]), #muc_user{status_codes = Codes, items = [#muc_item{jid = PeerJID, affiliation = none, @@ -1090,7 +1090,7 @@ muc_config_members_only_master(Config) -> lists:member(<<"muc_membersonly">>, get_features(Config, Room)), ct:comment("Waiting for slave to fail joining the room"), set_member = get_event(Config), - ok = muc_set_affiliation(Config, member, randoms:get_string()), + ok = set_affiliation(Config, member, randoms:get_string()), #message{from = Room, type = normal} = Msg = recv_message(Config), #muc_user{items = [#muc_item{jid = PeerBareJID, affiliation = member}]} = @@ -1099,7 +1099,7 @@ muc_config_members_only_master(Config) -> put_event(Config, join), ct:comment("Waiting for peer to join"), recv_muc_presence(Config, PeerNickJID, available), - ok = muc_set_affiliation(Config, none, randoms:get_string()), + ok = set_affiliation(Config, none, randoms:get_string()), ct:comment("Waiting for peer to be kicked"), #muc_user{status_codes = NewCodes, items = [#muc_item{affiliation = none, @@ -1108,14 +1108,14 @@ muc_config_members_only_master(Config) -> ct:comment("Checking if code '321' (became non-member in " "members-only room) is set"), true = lists:member(321, NewCodes), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_config_members_only_slave(Config) -> +config_members_only_slave(Config) -> MyJID = my_jid(Config), MyNickJID = my_muc_jid(Config), - {[], _, _} = muc_slave_join(Config), - [104] = muc_recv_config_change_message(Config), + {[], _, _} = slave_join(Config), + [104] = recv_config_change_message(Config), ct:comment("Getting kicked because the room has become members-only"), #muc_user{status_codes = Codes, items = [#muc_item{jid = MyJID, @@ -1127,12 +1127,12 @@ muc_config_members_only_slave(Config) -> true = lists:member(110, Codes), true = lists:member(322, Codes), ct:comment("Fail trying to join members-only room"), - #stanza_error{reason = 'registration-required'} = muc_join(Config), + #stanza_error{reason = 'registration-required'} = join(Config), ct:comment("Asking the peer to set us member"), put_event(Config, set_member), ct:comment("Waiting for the peer to ask for join"), join = get_event(Config), - {[], _, _} = muc_join(Config, participant, member), + {[], _, _} = join(Config, participant, member), #muc_user{status_codes = NewCodes, items = [#muc_item{jid = MyJID, role = none, @@ -1144,71 +1144,71 @@ muc_config_members_only_slave(Config) -> true = lists:member(321, NewCodes), disconnect(Config). -muc_config_moderated_master(Config) -> +config_moderated_master(Config) -> Room = muc_room_jid(Config), PeerNickJID = peer_muc_jid(Config), - ok = muc_master_join(Config), + ok = master_join(Config), lists:member(<<"muc_moderated">>, get_features(Config, Room)), - ok = muc_set_role(Config, visitor, randoms:get_string()), + ok = set_role(Config, visitor, randoms:get_string()), #muc_user{items = [#muc_item{role = visitor}]} = recv_muc_presence(Config, PeerNickJID, available), set_unmoderated = get_event(Config), - [104] = muc_set_config(Config, [{moderatedroom, false}]), + [104] = set_config(Config, [{moderatedroom, false}]), #message{from = PeerNickJID, type = groupchat} = recv_message(Config), recv_muc_presence(Config, PeerNickJID, unavailable), lists:member(<<"muc_unmoderated">>, get_features(Config, Room)), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_config_moderated_slave(Config) -> +config_moderated_slave(Config) -> Room = muc_room_jid(Config), MyNickJID = my_muc_jid(Config), - {[], _, _} = muc_slave_join(Config), + {[], _, _} = slave_join(Config), #muc_user{items = [#muc_item{role = visitor}]} = recv_muc_presence(Config, MyNickJID, available), send(Config, #message{to = Room, type = groupchat}), ErrMsg = #message{from = Room, type = error} = recv_message(Config), #stanza_error{reason = 'forbidden'} = xmpp:get_error(ErrMsg), put_event(Config, set_unmoderated), - [104] = muc_recv_config_change_message(Config), + [104] = recv_config_change_message(Config), send(Config, #message{to = Room, type = groupchat}), #message{from = MyNickJID, type = groupchat} = recv_message(Config), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_config_private_messages_master(Config) -> +config_private_messages_master(Config) -> PeerNickJID = peer_muc_jid(Config), - ok = muc_master_join(Config), + ok = master_join(Config), ct:comment("Waiting for a private message from the slave"), #message{from = PeerNickJID, type = chat} = recv_message(Config), - ok = muc_set_role(Config, visitor, <<>>), + ok = set_role(Config, visitor, <<>>), ct:comment("Waiting for the peer to become a visitor"), recv_muc_presence(Config, PeerNickJID, available), ct:comment("Waiting for a private message from the slave"), #message{from = PeerNickJID, type = chat} = recv_message(Config), - [104] = muc_set_config(Config, [{allow_private_messages_from_visitors, moderators}]), + [104] = set_config(Config, [{allow_private_messages_from_visitors, moderators}]), ct:comment("Waiting for a private message from the slave"), #message{from = PeerNickJID, type = chat} = recv_message(Config), - [104] = muc_set_config(Config, [{allow_private_messages_from_visitors, nobody}]), + [104] = set_config(Config, [{allow_private_messages_from_visitors, nobody}]), wait_for_slave(Config), - [104] = muc_set_config(Config, [{allow_private_messages_from_visitors, anyone}, + [104] = set_config(Config, [{allow_private_messages_from_visitors, anyone}, {allow_private_messages, false}]), ct:comment("Fail trying to send a private message"), send(Config, #message{to = PeerNickJID, type = chat}), #message{from = PeerNickJID, type = error} = ErrMsg = recv_message(Config), #stanza_error{reason = 'forbidden'} = xmpp:get_error(ErrMsg), - ok = muc_set_role(Config, participant, <<>>), + ok = set_role(Config, participant, <<>>), ct:comment("Waiting for the peer to become a participant"), recv_muc_presence(Config, PeerNickJID, available), ct:comment("Waiting for the peer to leave"), recv_muc_presence(Config, PeerNickJID, unavailable), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_config_private_messages_slave(Config) -> +config_private_messages_slave(Config) -> MyNickJID = my_muc_jid(Config), PeerNickJID = peer_muc_jid(Config), - {[], _, _} = muc_slave_join(Config), + {[], _, _} = slave_join(Config), ct:comment("Sending a private message"), send(Config, #message{to = PeerNickJID, type = chat}), ct:comment("Waiting to become a visitor"), @@ -1216,16 +1216,16 @@ muc_config_private_messages_slave(Config) -> recv_muc_presence(Config, MyNickJID, available), ct:comment("Sending a private message"), send(Config, #message{to = PeerNickJID, type = chat}), - [104] = muc_recv_config_change_message(Config), + [104] = recv_config_change_message(Config), ct:comment("Sending a private message"), send(Config, #message{to = PeerNickJID, type = chat}), - [104] = muc_recv_config_change_message(Config), + [104] = recv_config_change_message(Config), ct:comment("Fail trying to send a private message"), send(Config, #message{to = PeerNickJID, type = chat}), #message{from = PeerNickJID, type = error} = ErrMsg1 = recv_message(Config), #stanza_error{reason = 'forbidden'} = xmpp:get_error(ErrMsg1), wait_for_master(Config), - [104] = muc_recv_config_change_message(Config), + [104] = recv_config_change_message(Config), ct:comment("Waiting to become a participant again"), #muc_user{items = [#muc_item{role = participant}]} = recv_muc_presence(Config, MyNickJID, available), @@ -1233,29 +1233,29 @@ muc_config_private_messages_slave(Config) -> send(Config, #message{to = PeerNickJID, type = chat}), #message{from = PeerNickJID, type = error} = ErrMsg2 = recv_message(Config), #stanza_error{reason = 'forbidden'} = xmpp:get_error(ErrMsg2), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_config_query_master(Config) -> +config_query_master(Config) -> PeerNickJID = peer_muc_jid(Config), - ok = muc_join_new(Config), + ok = join_new(Config), wait_for_slave(Config), recv_muc_presence(Config, PeerNickJID, available), ct:comment("Receiving IQ query from the slave"), #iq{type = get, from = PeerNickJID, id = I, sub_els = [#ping{}]} = recv_iq(Config), send(Config, #iq{type = result, to = PeerNickJID, id = I}), - [104] = muc_set_config(Config, [{allow_query_users, false}]), + [104] = set_config(Config, [{allow_query_users, false}]), ct:comment("Fail trying to send IQ"), #iq{type = error, from = PeerNickJID} = Err = send_recv(Config, #iq{type = get, to = PeerNickJID, sub_els = [#ping{}]}), #stanza_error{reason = 'not-allowed'} = xmpp:get_error(Err), recv_muc_presence(Config, PeerNickJID, unavailable), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_config_query_slave(Config) -> +config_query_slave(Config) -> PeerNickJID = peer_muc_jid(Config), wait_for_master(Config), ct:comment("Checking if IQ queries are denied from non-occupants"), @@ -1263,28 +1263,28 @@ muc_config_query_slave(Config) -> send_recv(Config, #iq{type = get, to = PeerNickJID, sub_els = [#ping{}]}), #stanza_error{reason = 'not-acceptable'} = xmpp:get_error(Err1), - {[], _, _} = muc_join(Config), + {[], _, _} = join(Config), ct:comment("Sending IQ to the master"), #iq{type = result, from = PeerNickJID, sub_els = []} = send_recv(Config, #iq{to = PeerNickJID, type = get, sub_els = [#ping{}]}), - [104] = muc_recv_config_change_message(Config), + [104] = recv_config_change_message(Config), ct:comment("Fail trying to send IQ"), #iq{type = error, from = PeerNickJID} = Err2 = send_recv(Config, #iq{type = get, to = PeerNickJID, sub_els = [#ping{}]}), #stanza_error{reason = 'not-allowed'} = xmpp:get_error(Err2), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_config_allow_invites_master(Config) -> +config_allow_invites_master(Config) -> Room = muc_room_jid(Config), PeerJID = ?config(peer, Config), PeerNickJID = peer_muc_jid(Config), - ok = muc_master_join(Config), - [104] = muc_set_config(Config, [{allowinvites, true}]), + ok = master_join(Config), + [104] = set_config(Config, [{allowinvites, true}]), ct:comment("Receiving an invitation from the slave"), #message{from = Room, type = normal} = recv_message(Config), - [104] = muc_set_config(Config, [{allowinvites, false}]), + [104] = set_config(Config, [{allowinvites, false}]), send_invitation = get_event(Config), ct:comment("Sending an invitation"), send(Config, #message{to = Room, type = normal, @@ -1293,10 +1293,10 @@ muc_config_allow_invites_master(Config) -> invites = [#muc_invite{to = PeerJID}]}]}), recv_muc_presence(Config, PeerNickJID, unavailable), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_config_allow_invites_slave(Config) -> +config_allow_invites_slave(Config) -> Room = muc_room_jid(Config), PeerJID = ?config(peer, Config), InviteMsg = #message{to = Room, type = normal, @@ -1304,11 +1304,11 @@ muc_config_allow_invites_slave(Config) -> [#muc_user{ invites = [#muc_invite{to = PeerJID}]}]}, - {[], _, _} = muc_slave_join(Config), - [104] = muc_recv_config_change_message(Config), + {[], _, _} = slave_join(Config), + [104] = recv_config_change_message(Config), ct:comment("Sending an invitation"), send(Config, InviteMsg), - [104] = muc_recv_config_change_message(Config), + [104] = recv_config_change_message(Config), ct:comment("Fail sending an invitation"), send(Config, InviteMsg), #message{from = Room, type = error} = Err = recv_message(Config), @@ -1316,85 +1316,85 @@ muc_config_allow_invites_slave(Config) -> ct:comment("Checking if the master is still able to send invitations"), put_event(Config, send_invitation), #message{from = Room, type = normal} = recv_message(Config), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_config_visitor_status_master(Config) -> +config_visitor_status_master(Config) -> PeerNickJID = peer_muc_jid(Config), Status = xmpp:mk_text(randoms:get_string()), - ok = muc_join_new(Config), - [104] = muc_set_config(Config, [{members_by_default, false}]), + ok = join_new(Config), + [104] = set_config(Config, [{members_by_default, false}]), ct:comment("Asking the slave to join as a visitor"), put_event(Config, {join, Status}), #muc_user{items = [#muc_item{role = visitor}]} = recv_muc_presence(Config, PeerNickJID, available), ct:comment("Receiving status change from the visitor"), #presence{from = PeerNickJID, status = Status} = recv_presence(Config), - [104] = muc_set_config(Config, [{allow_visitor_status, false}]), + [104] = set_config(Config, [{allow_visitor_status, false}]), ct:comment("Receiving status change with stripped"), #presence{from = PeerNickJID, status = []} = recv_presence(Config), ct:comment("Waiting for the slave to leave"), recv_muc_presence(Config, PeerNickJID, unavailable), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_config_visitor_status_slave(Config) -> +config_visitor_status_slave(Config) -> Room = muc_room_jid(Config), MyNickJID = my_muc_jid(Config), ct:comment("Waiting for 'join' command from the master"), {join, Status} = get_event(Config), - {[], _, _} = muc_join(Config, visitor, none), + {[], _, _} = join(Config, visitor, none), ct:comment("Sending status change"), send(Config, #presence{to = Room, status = Status}), #presence{from = MyNickJID, status = Status} = recv_presence(Config), - [104] = muc_recv_config_change_message(Config), + [104] = recv_config_change_message(Config), ct:comment("Sending status change again"), send(Config, #presence{to = Room, status = Status}), #presence{from = MyNickJID, status = []} = recv_presence(Config), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_config_allow_voice_requests_master(Config) -> +config_allow_voice_requests_master(Config) -> PeerNickJID = peer_muc_jid(Config), - ok = muc_join_new(Config), - [104] = muc_set_config(Config, [{members_by_default, false}]), + ok = join_new(Config), + [104] = set_config(Config, [{members_by_default, false}]), ct:comment("Asking the slave to join as a visitor"), put_event(Config, join), #muc_user{items = [#muc_item{role = visitor}]} = recv_muc_presence(Config, PeerNickJID, available), - [104] = muc_set_config(Config, [{allow_voice_requests, false}]), + [104] = set_config(Config, [{allow_voice_requests, false}]), ct:comment("Waiting for the slave to leave"), recv_muc_presence(Config, PeerNickJID, unavailable), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_config_allow_voice_requests_slave(Config) -> +config_allow_voice_requests_slave(Config) -> Room = muc_room_jid(Config), ct:comment("Waiting for 'join' command from the master"), join = get_event(Config), - {[], _, _} = muc_join(Config, visitor), - [104] = muc_recv_config_change_message(Config), + {[], _, _} = join(Config, visitor), + [104] = recv_config_change_message(Config), ct:comment("Fail sending voice request"), Fs = muc_request:encode([{role, participant}]), X = #xdata{type = submit, fields = Fs}, send(Config, #message{to = Room, sub_els = [X]}), #message{from = Room, type = error} = Err = recv_message(Config), #stanza_error{reason = 'forbidden'} = xmpp:get_error(Err), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_config_voice_request_interval_master(Config) -> +config_voice_request_interval_master(Config) -> Room = muc_room_jid(Config), PeerJID = ?config(peer, Config), PeerNick = ?config(peer_nick, Config), PeerNickJID = peer_muc_jid(Config), - ok = muc_join_new(Config), - [104] = muc_set_config(Config, [{members_by_default, false}]), + ok = join_new(Config), + [104] = set_config(Config, [{members_by_default, false}]), ct:comment("Asking the slave to join as a visitor"), put_event(Config, join), #muc_user{items = [#muc_item{role = visitor}]} = recv_muc_presence(Config, PeerNickJID, available), - [104] = muc_set_config(Config, [{voice_request_min_interval, 5}]), + [104] = set_config(Config, [{voice_request_min_interval, 5}]), ct:comment("Receiving a voice request from slave"), #message{from = Room, type = normal} = recv_message(Config), ct:comment("Deny voice request at first"), @@ -1407,17 +1407,17 @@ muc_config_voice_request_interval_master(Config) -> #message{from = Room, type = normal} = recv_message(Config), ct:comment("Waiting for the slave to leave"), recv_muc_presence(Config, PeerNickJID, unavailable), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_config_voice_request_interval_slave(Config) -> +config_voice_request_interval_slave(Config) -> Room = muc_room_jid(Config), Fs = muc_request:encode([{role, participant}]), X = #xdata{type = submit, fields = Fs}, ct:comment("Waiting for 'join' command from the master"), join = get_event(Config), - {[], _, _} = muc_join(Config, visitor), - [104] = muc_recv_config_change_message(Config), + {[], _, _} = join(Config, visitor), + [104] = recv_config_change_message(Config), ct:comment("Sending voice request"), send(Config, #message{to = Room, sub_els = [X]}), ct:comment("Waiting for the master to deny our voice request"), @@ -1431,59 +1431,59 @@ muc_config_voice_request_interval_slave(Config) -> timer:sleep(timer:seconds(5)), ct:comment("Repeating again"), send(Config, #message{to = Room, sub_els = [X]}), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_config_visitor_nickchange_master(Config) -> +config_visitor_nickchange_master(Config) -> PeerNickJID = peer_muc_jid(Config), - ok = muc_join_new(Config), - [104] = muc_set_config(Config, [{members_by_default, false}]), + ok = join_new(Config), + [104] = set_config(Config, [{members_by_default, false}]), ct:comment("Asking the slave to join as a visitor"), put_event(Config, join), ct:comment("Waiting for the slave to join"), #muc_user{items = [#muc_item{role = visitor}]} = recv_muc_presence(Config, PeerNickJID, available), - [104] = muc_set_config(Config, [{allow_visitor_nickchange, false}]), + [104] = set_config(Config, [{allow_visitor_nickchange, false}]), ct:comment("Waiting for the slave to leave"), recv_muc_presence(Config, PeerNickJID, unavailable), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_config_visitor_nickchange_slave(Config) -> +config_visitor_nickchange_slave(Config) -> NewNick = randoms:get_string(), MyNickJID = my_muc_jid(Config), MyNewNickJID = jid:replace_resource(MyNickJID, NewNick), ct:comment("Waiting for 'join' command from the master"), join = get_event(Config), - {[], _, _} = muc_join(Config, visitor), - [104] = muc_recv_config_change_message(Config), + {[], _, _} = join(Config, visitor), + [104] = recv_config_change_message(Config), ct:comment("Fail trying to change nickname"), send(Config, #presence{to = MyNewNickJID}), #presence{from = MyNewNickJID, type = error} = Err = recv_presence(Config), #stanza_error{reason = 'not-allowed'} = xmpp:get_error(Err), - ok = muc_leave(Config), + ok = leave(Config), disconnect(Config). -muc_register_master(Config) -> +register_master(Config) -> MUC = muc_jid(Config), %% Register nick "master1" - muc_register_nick(Config, MUC, <<"">>, <<"master1">>), + register_nick(Config, MUC, <<"">>, <<"master1">>), %% Unregister nick "master1" via jabber:register #iq{type = result, sub_els = []} = send_recv(Config, #iq{type = set, to = MUC, sub_els = [#register{remove = true}]}), %% Register nick "master2" - muc_register_nick(Config, MUC, <<"">>, <<"master2">>), + register_nick(Config, MUC, <<"">>, <<"master2">>), %% Now register nick "master" - muc_register_nick(Config, MUC, <<"master2">>, <<"master">>), + register_nick(Config, MUC, <<"master2">>, <<"master">>), %% Wait for slave to fail trying to register nick "master" wait_for_slave(Config), wait_for_slave(Config), %% Now register empty ("") nick, which means we're unregistering - muc_register_nick(Config, MUC, <<"master">>, <<"">>), + register_nick(Config, MUC, <<"master">>, <<"">>), disconnect(Config). -muc_register_slave(Config) -> +register_slave(Config) -> MUC = muc_jid(Config), wait_for_master(Config), %% Trying to register occupied nick "master" @@ -1498,18 +1498,22 @@ muc_register_slave(Config) -> %%%=================================================================== %%% Internal functions %%%=================================================================== +single_test(T) -> + list_to_atom("muc_" ++ atom_to_list(T)). + master_slave_test(T) -> - {T, [parallel], [list_to_atom(atom_to_list(T) ++ "_master"), - list_to_atom(atom_to_list(T) ++ "_slave")]}. + {list_to_atom("muc_" ++ atom_to_list(T)), [parallel], + [list_to_atom("muc_" ++ atom_to_list(T) ++ "_master"), + list_to_atom("muc_" ++ atom_to_list(T) ++ "_slave")]}. recv_muc_presence(Config, From, Type) -> Pres = #presence{from = From, type = Type} = recv_presence(Config), xmpp:get_subtag(Pres, #muc_user{}). -muc_join_new(Config) -> - muc_join_new(Config, muc_room_jid(Config)). +join_new(Config) -> + join_new(Config, muc_room_jid(Config)). -muc_join_new(Config, Room) -> +join_new(Config, Room) -> MyJID = my_jid(Config), MyNick = ?config(nick, Config), MyNickJID = jid:replace_resource(Room, MyNick), @@ -1537,41 +1541,41 @@ muc_join_new(Config, Room) -> subject = [#text{data = <<>>}]} = recv_message(Config), case ?config(persistent_room, Config) of true -> - [104] = muc_set_config(Config, [{persistentroom, true}], Room), + [104] = set_config(Config, [{persistentroom, true}], Room), ok; false -> ok end. -muc_recv_history_and_subject(Config) -> +recv_history_and_subject(Config) -> ct:comment("Receiving room history and/or subject"), - muc_recv_history_and_subject(Config, []). + recv_history_and_subject(Config, []). -muc_recv_history_and_subject(Config, History) -> +recv_history_and_subject(Config, History) -> Room = muc_room_jid(Config), #message{type = groupchat, subject = Subj, body = Body, thread = Thread} = Msg = recv_message(Config), case xmpp:get_subtag(Msg, #delay{}) of #delay{from = Room} -> - muc_recv_history_and_subject(Config, [Msg|History]); + recv_history_and_subject(Config, [Msg|History]); false when Subj /= [], Body == [], Thread == undefined -> {lists:reverse(History), Msg} end. -muc_join(Config) -> - muc_join(Config, participant, none, #muc{}). +join(Config) -> + join(Config, participant, none, #muc{}). -muc_join(Config, Role) when is_atom(Role) -> - muc_join(Config, Role, none, #muc{}); -muc_join(Config, #muc{} = SubEl) -> - muc_join(Config, participant, none, SubEl). +join(Config, Role) when is_atom(Role) -> + join(Config, Role, none, #muc{}); +join(Config, #muc{} = SubEl) -> + join(Config, participant, none, SubEl). -muc_join(Config, Role, Aff) when is_atom(Role), is_atom(Aff) -> - muc_join(Config, Role, Aff, #muc{}); -muc_join(Config, Role, #muc{} = SubEl) when is_atom(Role) -> - muc_join(Config, Role, none, SubEl). +join(Config, Role, Aff) when is_atom(Role), is_atom(Aff) -> + join(Config, Role, Aff, #muc{}); +join(Config, Role, #muc{} = SubEl) when is_atom(Role) -> + join(Config, Role, none, SubEl). -muc_join(Config, Role, Aff, SubEl) -> +join(Config, Role, Aff, SubEl) -> ct:comment("Joining existing room as ~s/~s", [Aff, Role]), MyJID = my_jid(Config), Room = muc_room_jid(Config), @@ -1595,7 +1599,7 @@ muc_join(Config, Role, Aff, SubEl) -> recv_muc_presence(Config, MyNickJID, available), ct:comment("Checking if code '110' (self-presence) is set"), true = lists:member(110, Codes), - {History, Subj} = muc_recv_history_and_subject(Config), + {History, Subj} = recv_history_and_subject(Config), {History, Subj, Codes}; #presence{type = available, from = MyNickJID} = Pres -> #muc_user{status_codes = Codes, @@ -1605,21 +1609,21 @@ muc_join(Config, Role, Aff, SubEl) -> xmpp:get_subtag(Pres, #muc_user{}), ct:comment("Checking if code '110' (self-presence) is set"), true = lists:member(110, Codes), - {History, Subj} = muc_recv_history_and_subject(Config), + {History, Subj} = recv_history_and_subject(Config), {empty, History, Subj, Codes} end. -muc_leave(Config) -> - muc_leave(Config, muc_room_jid(Config)). +leave(Config) -> + leave(Config, muc_room_jid(Config)). -muc_leave(Config, Room) -> +leave(Config, Room) -> MyJID = my_jid(Config), MyNick = ?config(nick, Config), MyNickJID = jid:replace_resource(Room, MyNick), Mode = ?config(mode, Config), IsPersistent = ?config(persistent_room, Config), if Mode /= slave, IsPersistent -> - [104] = muc_set_config(Config, [{persistentroom, false}], Room); + [104] = set_config(Config, [{persistentroom, false}], Room); true -> ok end, @@ -1633,7 +1637,7 @@ muc_leave(Config, Room) -> true = lists:member(110, Codes), ok. -muc_get_config(Config) -> +get_config(Config) -> ct:comment("Get room config"), Room = muc_room_jid(Config), case send_recv(Config, @@ -1646,10 +1650,10 @@ muc_get_config(Config) -> xmpp:get_subtag(Err, #stanza_error{}) end. -muc_set_config(Config, RoomConfig) -> - muc_set_config(Config, RoomConfig, muc_room_jid(Config)). +set_config(Config, RoomConfig) -> + set_config(Config, RoomConfig, muc_room_jid(Config)). -muc_set_config(Config, RoomConfig, Room) -> +set_config(Config, RoomConfig, Room) -> ct:comment("Set room config: ~p", [RoomConfig]), Fs = case RoomConfig of [] -> []; @@ -1667,15 +1671,15 @@ muc_set_config(Config, RoomConfig, Room) -> xmpp:get_subtag(Err, #stanza_error{}) end. -muc_create_persistent(Config) -> - [_|_] = muc_get_config(Config), - [] = muc_set_config(Config, [{persistentroom, true}], false), +create_persistent(Config) -> + [_|_] = get_config(Config), + [] = set_config(Config, [{persistentroom, true}], false), ok. -muc_destroy(Config) -> - muc_destroy(Config, <<>>). +destroy(Config) -> + destroy(Config, <<>>). -muc_destroy(Config, Reason) -> +destroy(Config, Reason) -> Room = muc_room_jid(Config), AltRoom = alt_room_jid(Config), ct:comment("Destroying a room"), @@ -1690,7 +1694,7 @@ muc_destroy(Config, Reason) -> xmpp:get_subtag(Err, #stanza_error{}) end. -muc_disco_items(Config) -> +disco_items(Config) -> MUC = muc_jid(Config), ct:comment("Performing disco#items request to ~s", [jid:to_string(MUC)]), #iq{type = result, from = MUC, sub_els = [DiscoItems]} = @@ -1698,14 +1702,14 @@ muc_disco_items(Config) -> sub_els = [#disco_items{}]}), lists:keysort(#disco_item.jid, DiscoItems#disco_items.items). -muc_disco_room_items(Config) -> +disco_room_items(Config) -> Room = muc_room_jid(Config), #iq{type = result, from = Room, sub_els = [DiscoItems]} = send_recv(Config, #iq{type = get, to = Room, sub_els = [#disco_items{}]}), DiscoItems#disco_items.items. -muc_get_affiliations(Config, Aff) -> +get_affiliations(Config, Aff) -> Room = muc_room_jid(Config), case send_recv(Config, #iq{type = get, to = Room, @@ -1716,12 +1720,12 @@ muc_get_affiliations(Config, Aff) -> xmpp:get_subtag(Err, #stanza_error{}) end. -muc_master_join(Config) -> +master_join(Config) -> Room = muc_room_jid(Config), PeerJID = ?config(slave, Config), PeerNick = ?config(slave_nick, Config), PeerNickJID = jid:replace_resource(Room, PeerNick), - ok = muc_join_new(Config), + ok = join_new(Config), wait_for_slave(Config), #muc_user{items = [#muc_item{jid = PeerJID, role = participant, @@ -1729,11 +1733,11 @@ muc_master_join(Config) -> recv_muc_presence(Config, PeerNickJID, available), ok. -muc_slave_join(Config) -> +slave_join(Config) -> wait_for_master(Config), - muc_join(Config). + join(Config). -muc_set_role(Config, Role, Reason) -> +set_role(Config, Role, Reason) -> ct:comment("Changing role to ~s", [Role]), Room = muc_room_jid(Config), PeerNick = ?config(slave_nick, Config), @@ -1751,7 +1755,7 @@ muc_set_role(Config, Role, Reason) -> xmpp:get_subtag(Err, #stanza_error{}) end. -muc_get_role(Config, Role) -> +get_role(Config, Role) -> ct:comment("Requesting list for role '~s'", [Role]), Room = muc_room_jid(Config), case send_recv( @@ -1765,7 +1769,7 @@ muc_get_role(Config, Role) -> xmpp:get_subtag(Err, #stanza_error{}) end. -muc_set_affiliation(Config, Aff, Reason) -> +set_affiliation(Config, Aff, Reason) -> ct:comment("Changing affiliation to ~s", [Aff]), Room = muc_room_jid(Config), PeerJID = ?config(slave, Config), @@ -1784,7 +1788,7 @@ muc_set_affiliation(Config, Aff, Reason) -> xmpp:get_subtag(Err, #stanza_error{}) end. -muc_get_affiliation(Config, Aff) -> +get_affiliation(Config, Aff) -> ct:comment("Requesting list for affiliation '~s'", [Aff]), Room = muc_room_jid(Config), case send_recv( @@ -1798,7 +1802,7 @@ muc_get_affiliation(Config, Aff) -> xmpp:get_subtag(Err, #stanza_error{}) end. -muc_set_vcard(Config, VCard) -> +set_vcard(Config, VCard) -> Room = muc_room_jid(Config), ct:comment("Setting vCard for ~s", [jid:to_string(Room)]), case send_recv(Config, #iq{type = set, to = Room, @@ -1809,7 +1813,7 @@ muc_set_vcard(Config, VCard) -> xmpp:get_subtag(Err, #stanza_error{}) end. -muc_get_vcard(Config) -> +get_vcard(Config) -> Room = muc_room_jid(Config), ct:comment("Retreiving vCard from ~s", [jid:to_string(Room)]), case send_recv(Config, #iq{type = get, to = Room, @@ -1820,14 +1824,14 @@ muc_get_vcard(Config) -> xmpp:get_subtag(Err, #stanza_error{}) end. -muc_recv_config_change_message(Config) -> +recv_config_change_message(Config) -> ct:comment("Receiving configuration change notification message"), Room = muc_room_jid(Config), #message{type = groupchat, from = Room} = Msg = recv_message(Config), #muc_user{status_codes = Codes} = xmpp:get_subtag(Msg, #muc_user{}), lists:sort(Codes). -muc_register_nick(Config, MUC, PrevNick, Nick) -> +register_nick(Config, MUC, PrevNick, Nick) -> PrevRegistered = if PrevNick /= <<"">> -> true; true -> false end, @@ -1859,7 +1863,7 @@ muc_register_nick(Config, MUC, PrevNick, Nick) -> Nick = proplists:get_value( roomnick, muc_register:decode(FsWithNick)). -muc_subscribe(Config, Events, Room) -> +subscribe(Config, Events, Room) -> MyNick = ?config(nick, Config), case send_recv(Config, #iq{type = set, to = Room, @@ -1871,7 +1875,7 @@ muc_subscribe(Config, Events, Room) -> xmpp:get_error(Err) end. -muc_unsubscribe(Config, Room) -> +unsubscribe(Config, Room) -> case send_recv(Config, #iq{type = set, to = Room, sub_els = [#muc_unsubscribe{}]}) of #iq{type = result, sub_els = []} -> diff --git a/test/privacy_tests.erl b/test/privacy_tests.erl index 2ee945f1e..640f53d48 100644 --- a/test/privacy_tests.erl +++ b/test/privacy_tests.erl @@ -13,7 +13,7 @@ -import(suite, [disconnect/1, send_recv/2, get_event/1, put_event/2, recv_iq/1, recv_presence/1, recv_message/1, recv/1, send/2, my_jid/1, server_jid/1, get_features/1, - set_roster/3, del_roster/1]). + set_roster/3, del_roster/1, get_roster/1]). -include("suite.hrl"). -include("mod_roster.hrl"). @@ -233,7 +233,7 @@ set_get_block(Config) -> %%% Master-slave cases %%%=================================================================== master_slave_cases() -> - {privacy_master_slave, [parallel], + {privacy_master_slave, [sequence], [master_slave_test(deny_bare_jid), master_slave_test(deny_full_jid), master_slave_test(deny_server_jid), @@ -319,7 +319,8 @@ deny_master(Config, {Type, Value}) -> set_roster(Config, Sub, Groups), lists:foreach( fun(Opts) -> - ListName = str:format("deny-~s-~s-~p", [Type, Value, Opts]), + ct:pal("Set list for ~s, ~s, ~w", [Type, Value, Opts]), + ListName = randoms:get_string(), Item = #privacy_item{order = 0, action = deny, iq = proplists:get_bool(iq, Opts), diff --git a/test/proxy65_tests.erl b/test/proxy65_tests.erl new file mode 100644 index 000000000..01292f508 --- /dev/null +++ b/test/proxy65_tests.erl @@ -0,0 +1,105 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 16 Nov 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(proxy65_tests). + +%% API +-compile(export_all). +-import(suite, [disconnect/1, is_feature_advertised/3, proxy_jid/1, + my_jid/1, wait_for_slave/1, wait_for_master/1, + send_recv/2, put_event/2, get_event/1]). + +-include("suite.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +%%%=================================================================== +%%% Single user tests +%%%=================================================================== +single_cases() -> + {proxy65_single, [sequence], + [single_test(feature_enabled)]}. + +feature_enabled(Config) -> + true = is_feature_advertised(Config, ?NS_BYTESTREAMS, proxy_jid(Config)), + disconnect(Config). + +%%%=================================================================== +%%% Master-slave tests +%%%=================================================================== +master_slave_cases() -> + {proxy65_master_slave, [sequence], + [master_slave_test(all)]}. + +all_master(Config) -> + Proxy = proxy_jid(Config), + MyJID = my_jid(Config), + Peer = ?config(slave, Config), + wait_for_slave(Config), + #presence{} = send_recv(Config, #presence{}), + #iq{type = result, sub_els = [#bytestreams{hosts = [StreamHost]}]} = + send_recv( + Config, + #iq{type = get, sub_els = [#bytestreams{}], to = Proxy}), + SID = randoms:get_string(), + Data = randoms:bytes(1024), + put_event(Config, {StreamHost, SID, Data}), + Socks5 = socks5_connect(StreamHost, {SID, MyJID, Peer}), + wait_for_slave(Config), + #iq{type = result, sub_els = []} = + send_recv(Config, + #iq{type = set, to = Proxy, + sub_els = [#bytestreams{activate = Peer, sid = SID}]}), + socks5_send(Socks5, Data), + disconnect(Config). + +all_slave(Config) -> + MyJID = my_jid(Config), + Peer = ?config(master, Config), + #presence{} = send_recv(Config, #presence{}), + wait_for_master(Config), + {StreamHost, SID, Data} = get_event(Config), + Socks5 = socks5_connect(StreamHost, {SID, Peer, MyJID}), + wait_for_master(Config), + socks5_recv(Socks5, Data), + disconnect(Config). + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +single_test(T) -> + list_to_atom("proxy65_" ++ atom_to_list(T)). + +master_slave_test(T) -> + {list_to_atom("proxy65_" ++ atom_to_list(T)), [parallel], + [list_to_atom("proxy65_" ++ atom_to_list(T) ++ "_master"), + list_to_atom("proxy65_" ++ atom_to_list(T) ++ "_slave")]}. + +socks5_connect(#streamhost{host = Host, port = Port}, + {SID, JID1, JID2}) -> + Hash = p1_sha:sha([SID, jid:to_string(JID1), jid:to_string(JID2)]), + {ok, Sock} = gen_tcp:connect(binary_to_list(Host), Port, + [binary, {active, false}]), + Init = <>, + InitAck = <>, + Req = <>, + Resp = <>, + gen_tcp:send(Sock, Init), + {ok, InitAck} = gen_tcp:recv(Sock, size(InitAck)), + gen_tcp:send(Sock, Req), + {ok, Resp} = gen_tcp:recv(Sock, size(Resp)), + Sock. + +socks5_send(Sock, Data) -> + ok = gen_tcp:send(Sock, Data). + +socks5_recv(Sock, Data) -> + {ok, Data} = gen_tcp:recv(Sock, size(Data)). diff --git a/test/pubsub_tests.erl b/test/pubsub_tests.erl new file mode 100644 index 000000000..fae7234e4 --- /dev/null +++ b/test/pubsub_tests.erl @@ -0,0 +1,729 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 16 Nov 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(pubsub_tests). + +%% API +-compile(export_all). +-import(suite, [pubsub_jid/1, send_recv/2, get_features/2, disconnect/1, + put_event/2, get_event/1, wait_for_master/1, wait_for_slave/1, + recv_message/1, my_jid/1, send/2, recv_presence/1, recv/1]). + +-include("suite.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +%%%=================================================================== +%%% Single user tests +%%%=================================================================== +single_cases() -> + {pubsub_single, [sequence], + [single_test(test_features), + single_test(test_create), + single_test(test_configure), + single_test(test_delete), + single_test(test_get_affiliations), + single_test(test_get_subscriptions), + single_test(test_create_instant), + single_test(test_default), + single_test(test_create_configure), + single_test(test_publish), + single_test(test_auto_create), + single_test(test_get_items), + single_test(test_delete_item), + single_test(test_purge), + single_test(test_subscribe), + single_test(test_unsubscribe)]}. + +test_features(Config) -> + PJID = pubsub_jid(Config), + AllFeatures = sets:from_list(get_features(Config, PJID)), + NeededFeatures = sets:from_list( + [?NS_PUBSUB, + ?PUBSUB("access-open"), + ?PUBSUB("access-authorize"), + ?PUBSUB("create-nodes"), + ?PUBSUB("instant-nodes"), + ?PUBSUB("config-node"), + ?PUBSUB("retrieve-default"), + ?PUBSUB("create-and-configure"), + ?PUBSUB("publish"), + ?PUBSUB("auto-create"), + ?PUBSUB("retrieve-items"), + ?PUBSUB("delete-items"), + ?PUBSUB("subscribe"), + ?PUBSUB("retrieve-affiliations"), + ?PUBSUB("modify-affiliations"), + ?PUBSUB("retrieve-subscriptions"), + ?PUBSUB("manage-subscriptions"), + ?PUBSUB("purge-nodes"), + ?PUBSUB("delete-nodes")]), + true = sets:is_subset(NeededFeatures, AllFeatures), + disconnect(Config). + +test_create(Config) -> + Node = ?config(pubsub_node, Config), + Node = create_node(Config, Node), + disconnect(Config). + +test_create_instant(Config) -> + Node = create_node(Config, <<>>), + delete_node(Config, Node), + disconnect(Config). + +test_configure(Config) -> + Node = ?config(pubsub_node, Config), + NodeTitle = ?config(pubsub_node_title, Config), + NodeConfig = get_node_config(Config, Node), + MyNodeConfig = set_opts(NodeConfig, + [{title, NodeTitle}]), + set_node_config(Config, Node, MyNodeConfig), + NewNodeConfig = get_node_config(Config, Node), + NodeTitle = proplists:get_value(title, NewNodeConfig), + disconnect(Config). + +test_default(Config) -> + get_default_node_config(Config), + disconnect(Config). + +test_create_configure(Config) -> + NodeTitle = ?config(pubsub_node_title, Config), + DefaultNodeConfig = get_default_node_config(Config), + CustomNodeConfig = set_opts(DefaultNodeConfig, + [{title, NodeTitle}]), + Node = create_node(Config, <<>>, CustomNodeConfig), + NodeConfig = get_node_config(Config, Node), + NodeTitle = proplists:get_value(title, NodeConfig), + delete_node(Config, Node), + disconnect(Config). + +test_publish(Config) -> + Node = create_node(Config, <<>>), + publish_item(Config, Node), + delete_node(Config, Node), + disconnect(Config). + +test_auto_create(Config) -> + Node = randoms:get_string(), + publish_item(Config, Node), + delete_node(Config, Node), + disconnect(Config). + +test_get_items(Config) -> + Node = create_node(Config, <<>>), + ItemsIn = [publish_item(Config, Node) || _ <- lists:seq(1, 5)], + ItemsOut = get_items(Config, Node), + true = [I || #ps_item{id = I} <- lists:sort(ItemsIn)] + == [I || #ps_item{id = I} <- lists:sort(ItemsOut)], + delete_node(Config, Node), + disconnect(Config). + +test_delete_item(Config) -> + Node = create_node(Config, <<>>), + #ps_item{id = I} = publish_item(Config, Node), + [#ps_item{id = I}] = get_items(Config, Node), + delete_item(Config, Node, I), + [] = get_items(Config, Node), + delete_node(Config, Node), + disconnect(Config). + +test_subscribe(Config) -> + Node = create_node(Config, <<>>), + #ps_subscription{type = subscribed} = subscribe_node(Config, Node), + [#ps_subscription{node = Node}] = get_subscriptions(Config), + delete_node(Config, Node), + disconnect(Config). + +test_unsubscribe(Config) -> + Node = create_node(Config, <<>>), + subscribe_node(Config, Node), + [#ps_subscription{node = Node}] = get_subscriptions(Config), + unsubscribe_node(Config, Node), + [] = get_subscriptions(Config), + delete_node(Config, Node), + disconnect(Config). + +test_get_affiliations(Config) -> + Nodes = lists:sort([create_node(Config, <<>>) || _ <- lists:seq(1, 5)]), + Affs = get_affiliations(Config), + Nodes = lists:sort([Node || #ps_affiliation{node = Node, + type = owner} <- Affs]), + [delete_node(Config, Node) || Node <- Nodes], + disconnect(Config). + +test_get_subscriptions(Config) -> + Nodes = lists:sort([create_node(Config, <<>>) || _ <- lists:seq(1, 5)]), + [subscribe_node(Config, Node) || Node <- Nodes], + Subs = get_subscriptions(Config), + Nodes = lists:sort([Node || #ps_subscription{node = Node} <- Subs]), + [delete_node(Config, Node) || Node <- Nodes], + disconnect(Config). + +test_purge(Config) -> + Node = create_node(Config, <<>>), + ItemsIn = [publish_item(Config, Node) || _ <- lists:seq(1, 5)], + ItemsOut = get_items(Config, Node), + true = [I || #ps_item{id = I} <- lists:sort(ItemsIn)] + == [I || #ps_item{id = I} <- lists:sort(ItemsOut)], + purge_node(Config, Node), + [] = get_items(Config, Node), + delete_node(Config, Node), + disconnect(Config). + +test_delete(Config) -> + Node = ?config(pubsub_node, Config), + delete_node(Config, Node), + disconnect(Config). + +%%%=================================================================== +%%% Master-slave tests +%%%=================================================================== +master_slave_cases() -> + {pubsub_master_slave, [sequence], + [master_slave_test(publish), + master_slave_test(subscriptions), + master_slave_test(affiliations), + master_slave_test(authorize)]}. + +publish_master(Config) -> + Node = create_node(Config, <<>>), + put_event(Config, Node), + wait_for_slave(Config), + #ps_item{id = ID} = publish_item(Config, Node), + #ps_item{id = ID} = get_event(Config), + delete_node(Config, Node), + disconnect(Config). + +publish_slave(Config) -> + Node = get_event(Config), + subscribe_node(Config, Node), + wait_for_master(Config), + #message{ + sub_els = + [#ps_event{ + items = #ps_items{node = Node, + items = [Item]}}]} = recv_message(Config), + put_event(Config, Item), + disconnect(Config). + +subscriptions_master(Config) -> + Peer = ?config(slave, Config), + Node = ?config(pubsub_node, Config), + Node = create_node(Config, Node), + [] = get_subscriptions(Config, Node), + wait_for_slave(Config), + lists:foreach( + fun(Type) -> + ok = set_subscriptions(Config, Node, [{Peer, Type}]), + #ps_item{} = publish_item(Config, Node), + case get_subscriptions(Config, Node) of + [] when Type == none; Type == pending -> + ok; + [#ps_subscription{jid = Peer, type = Type}] -> + ok + end + end, [subscribed, unconfigured, pending, none]), + delete_node(Config, Node), + disconnect(Config). + +subscriptions_slave(Config) -> + wait_for_master(Config), + MyJID = my_jid(Config), + Node = ?config(pubsub_node, Config), + lists:foreach( + fun(subscribed = Type) -> + ?recv2(#message{ + sub_els = + [#ps_event{ + subscription = #ps_subscription{ + node = Node, + jid = MyJID, + type = Type}}]}, + #message{sub_els = [#ps_event{}]}); + (Type) -> + #message{ + sub_els = + [#ps_event{ + subscription = #ps_subscription{ + node = Node, + jid = MyJID, + type = Type}}]} = + recv_message(Config) + end, [subscribed, unconfigured, pending, none]), + disconnect(Config). + +affiliations_master(Config) -> + Peer = ?config(slave, Config), + BarePeer = jid:remove_resource(Peer), + lists:foreach( + fun(Aff) -> + Node = <<(atom_to_binary(Aff, utf8))/binary, + $-, (randoms:get_string())/binary>>, + create_node(Config, Node, default_node_config(Config)), + #ps_item{id = I} = publish_item(Config, Node), + ok = set_affiliations(Config, Node, [{Peer, Aff}]), + Affs = get_affiliations(Config, Node), + case lists:keyfind(BarePeer, #ps_affiliation.jid, Affs) of + false when Aff == none -> + ok; + #ps_affiliation{type = Aff} -> + ok + end, + put_event(Config, {Aff, Node, I}), + wait_for_slave(Config), + delete_node(Config, Node) + end, [outcast, none, member, publish_only, publisher, owner]), + put_event(Config, disconnect), + disconnect(Config). + +affiliations_slave(Config) -> + affiliations_slave(Config, get_event(Config)). + +affiliations_slave(Config, {outcast, Node, ItemID}) -> + #stanza_error{reason = 'forbidden'} = subscribe_node(Config, Node), + #stanza_error{} = unsubscribe_node(Config, Node), + #stanza_error{reason = 'forbidden'} = get_items(Config, Node), + #stanza_error{reason = 'forbidden'} = publish_item(Config, Node), + #stanza_error{reason = 'forbidden'} = delete_item(Config, Node, ItemID), + #stanza_error{reason = 'forbidden'} = purge_node(Config, Node), + #stanza_error{reason = 'forbidden'} = get_node_config(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_node_config(Config, Node, default_node_config(Config)), + #stanza_error{reason = 'forbidden'} = get_subscriptions(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_subscriptions(Config, Node, [{my_jid(Config), subscribed}]), + #stanza_error{reason = 'forbidden'} = get_affiliations(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_affiliations(Config, Node, [{?config(master, Config), outcast}, + {my_jid(Config), owner}]), + #stanza_error{reason = 'forbidden'} = delete_node(Config, Node), + wait_for_master(Config), + affiliations_slave(Config, get_event(Config)); +affiliations_slave(Config, {none, Node, ItemID}) -> + #ps_subscription{type = subscribed} = subscribe_node(Config, Node), + ok = unsubscribe_node(Config, Node), + %% This violates the affiliation char from section 4.1 + [_|_] = get_items(Config, Node), + #stanza_error{reason = 'forbidden'} = publish_item(Config, Node), + #stanza_error{reason = 'forbidden'} = delete_item(Config, Node, ItemID), + #stanza_error{reason = 'forbidden'} = purge_node(Config, Node), + #stanza_error{reason = 'forbidden'} = get_node_config(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_node_config(Config, Node, default_node_config(Config)), + #stanza_error{reason = 'forbidden'} = get_subscriptions(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_subscriptions(Config, Node, [{my_jid(Config), subscribed}]), + #stanza_error{reason = 'forbidden'} = get_affiliations(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_affiliations(Config, Node, [{?config(master, Config), outcast}, + {my_jid(Config), owner}]), + #stanza_error{reason = 'forbidden'} = delete_node(Config, Node), + wait_for_master(Config), + affiliations_slave(Config, get_event(Config)); +affiliations_slave(Config, {member, Node, ItemID}) -> + #ps_subscription{type = subscribed} = subscribe_node(Config, Node), + ok = unsubscribe_node(Config, Node), + [_|_] = get_items(Config, Node), + #stanza_error{reason = 'forbidden'} = publish_item(Config, Node), + #stanza_error{reason = 'forbidden'} = delete_item(Config, Node, ItemID), + #stanza_error{reason = 'forbidden'} = purge_node(Config, Node), + #stanza_error{reason = 'forbidden'} = get_node_config(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_node_config(Config, Node, default_node_config(Config)), + #stanza_error{reason = 'forbidden'} = get_subscriptions(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_subscriptions(Config, Node, [{my_jid(Config), subscribed}]), + #stanza_error{reason = 'forbidden'} = get_affiliations(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_affiliations(Config, Node, [{?config(master, Config), outcast}, + {my_jid(Config), owner}]), + #stanza_error{reason = 'forbidden'} = delete_node(Config, Node), + wait_for_master(Config), + affiliations_slave(Config, get_event(Config)); +affiliations_slave(Config, {publish_only, Node, ItemID}) -> + #stanza_error{reason = 'forbidden'} = subscribe_node(Config, Node), + #stanza_error{} = unsubscribe_node(Config, Node), + #stanza_error{reason = 'forbidden'} = get_items(Config, Node), + #ps_item{id = _MyItemID} = publish_item(Config, Node), + %% BUG: This should be fixed + %% ?match(ok, delete_item(Config, Node, MyItemID)), + #stanza_error{reason = 'forbidden'} = delete_item(Config, Node, ItemID), + #stanza_error{reason = 'forbidden'} = purge_node(Config, Node), + #stanza_error{reason = 'forbidden'} = get_node_config(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_node_config(Config, Node, default_node_config(Config)), + #stanza_error{reason = 'forbidden'} = get_subscriptions(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_subscriptions(Config, Node, [{my_jid(Config), subscribed}]), + #stanza_error{reason = 'forbidden'} = get_affiliations(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_affiliations(Config, Node, [{?config(master, Config), outcast}, + {my_jid(Config), owner}]), + #stanza_error{reason = 'forbidden'} = delete_node(Config, Node), + wait_for_master(Config), + affiliations_slave(Config, get_event(Config)); +affiliations_slave(Config, {publisher, Node, _ItemID}) -> + #ps_subscription{type = subscribed} = subscribe_node(Config, Node), + ok = unsubscribe_node(Config, Node), + [_|_] = get_items(Config, Node), + #ps_item{id = MyItemID} = publish_item(Config, Node), + ok = delete_item(Config, Node, MyItemID), + %% BUG: this should be fixed + %% #stanza_error{reason = 'forbidden'} = delete_item(Config, Node, ItemID), + #stanza_error{reason = 'forbidden'} = purge_node(Config, Node), + #stanza_error{reason = 'forbidden'} = get_node_config(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_node_config(Config, Node, default_node_config(Config)), + #stanza_error{reason = 'forbidden'} = get_subscriptions(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_subscriptions(Config, Node, [{my_jid(Config), subscribed}]), + #stanza_error{reason = 'forbidden'} = get_affiliations(Config, Node), + #stanza_error{reason = 'forbidden'} = + set_affiliations(Config, Node, [{?config(master, Config), outcast}, + {my_jid(Config), owner}]), + #stanza_error{reason = 'forbidden'} = delete_node(Config, Node), + wait_for_master(Config), + affiliations_slave(Config, get_event(Config)); +affiliations_slave(Config, {owner, Node, ItemID}) -> + MyJID = my_jid(Config), + Peer = ?config(master, Config), + #ps_subscription{type = subscribed} = subscribe_node(Config, Node), + ok = unsubscribe_node(Config, Node), + [_|_] = get_items(Config, Node), + #ps_item{id = MyItemID} = publish_item(Config, Node), + ok = delete_item(Config, Node, MyItemID), + ok = delete_item(Config, Node, ItemID), + ok = purge_node(Config, Node), + [_|_] = get_node_config(Config, Node), + ok = set_node_config(Config, Node, default_node_config(Config)), + ok = set_subscriptions(Config, Node, []), + [] = get_subscriptions(Config, Node), + ok = set_affiliations(Config, Node, [{Peer, outcast}, {MyJID, owner}]), + [_, _] = get_affiliations(Config, Node), + ok = delete_node(Config, Node), + wait_for_master(Config), + affiliations_slave(Config, get_event(Config)); +affiliations_slave(Config, disconnect) -> + disconnect(Config). + +authorize_master(Config) -> + send(Config, #presence{}), + #presence{} = recv_presence(Config), + Peer = ?config(slave, Config), + PJID = pubsub_jid(Config), + NodeConfig = set_opts(default_node_config(Config), + [{access_model, authorize}]), + Node = ?config(pubsub_node, Config), + Node = create_node(Config, Node, NodeConfig), + wait_for_slave(Config), + #message{sub_els = [#xdata{fields = F1}]} = recv_message(Config), + C1 = pubsub_subscribe_authorization:decode(F1), + Node = proplists:get_value(node, C1), + Peer = proplists:get_value(subscriber_jid, C1), + %% Deny it at first + Deny = #xdata{type = submit, + fields = pubsub_subscribe_authorization:encode( + [{node, Node}, + {subscriber_jid, Peer}, + {allow, false}])}, + send(Config, #message{to = PJID, sub_els = [Deny]}), + %% We should not have any subscriptions + [] = get_subscriptions(Config, Node), + wait_for_slave(Config), + #message{sub_els = [#xdata{fields = F2}]} = recv_message(Config), + C2 = pubsub_subscribe_authorization:decode(F2), + Node = proplists:get_value(node, C2), + Peer = proplists:get_value(subscriber_jid, C2), + %% Now we accept is as the peer is very insisting ;) + Approve = #xdata{type = submit, + fields = pubsub_subscribe_authorization:encode( + [{node, Node}, + {subscriber_jid, Peer}, + {allow, true}])}, + send(Config, #message{to = PJID, sub_els = [Approve]}), + wait_for_slave(Config), + delete_node(Config, Node), + disconnect(Config). + +authorize_slave(Config) -> + Node = ?config(pubsub_node, Config), + MyJID = my_jid(Config), + wait_for_master(Config), + #ps_subscription{type = pending} = subscribe_node(Config, Node), + %% We're denied at first + #message{ + sub_els = + [#ps_event{ + subscription = #ps_subscription{type = none, + jid = MyJID}}]} = + recv_message(Config), + wait_for_master(Config), + #ps_subscription{type = pending} = subscribe_node(Config, Node), + %% Now much better! + #message{ + sub_els = + [#ps_event{ + subscription = #ps_subscription{type = subscribed, + jid = MyJID}}]} = + recv_message(Config), + wait_for_master(Config), + disconnect(Config). + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +single_test(T) -> + list_to_atom("pubsub_" ++ atom_to_list(T)). + +master_slave_test(T) -> + {list_to_atom("pubsub_" ++ atom_to_list(T)), [parallel], + [list_to_atom("pubsub_" ++ atom_to_list(T) ++ "_master"), + list_to_atom("pubsub_" ++ atom_to_list(T) ++ "_slave")]}. + +set_opts(Config, Options) -> + lists:foldl( + fun({Opt, Val}, Acc) -> + lists:keystore(Opt, 1, Acc, {Opt, Val}) + end, Config, Options). + +create_node(Config, Node) -> + create_node(Config, Node, undefined). + +create_node(Config, Node, Options) -> + PJID = pubsub_jid(Config), + NodeConfig = if is_list(Options) -> + #xdata{type = submit, + fields = pubsub_node_config:encode(Options)}; + true -> + undefined + end, + case send_recv(Config, + #iq{type = set, to = PJID, + sub_els = [#pubsub{create = Node, + configure = {<<>>, NodeConfig}}]}) of + #iq{type = result, sub_els = [#pubsub{create = NewNode}]} -> + NewNode; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +delete_node(Config, Node) -> + PJID = pubsub_jid(Config), + case send_recv(Config, + #iq{type = set, to = PJID, + sub_els = [#pubsub_owner{delete = {Node, <<>>}}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +purge_node(Config, Node) -> + PJID = pubsub_jid(Config), + case send_recv(Config, + #iq{type = set, to = PJID, + sub_els = [#pubsub_owner{purge = Node}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +get_default_node_config(Config) -> + PJID = pubsub_jid(Config), + case send_recv(Config, + #iq{type = get, to = PJID, + sub_els = [#pubsub_owner{default = {<<>>, undefined}}]}) of + #iq{type = result, + sub_els = [#pubsub_owner{default = {<<>>, NodeConfig}}]} -> + pubsub_node_config:decode(NodeConfig#xdata.fields); + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +get_node_config(Config, Node) -> + PJID = pubsub_jid(Config), + case send_recv(Config, + #iq{type = get, to = PJID, + sub_els = [#pubsub_owner{configure = {Node, undefined}}]}) of + #iq{type = result, + sub_els = [#pubsub_owner{configure = {Node, NodeConfig}}]} -> + pubsub_node_config:decode(NodeConfig#xdata.fields); + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +set_node_config(Config, Node, Options) -> + PJID = pubsub_jid(Config), + NodeConfig = #xdata{type = submit, + fields = pubsub_node_config:encode(Options)}, + case send_recv(Config, + #iq{type = set, to = PJID, + sub_els = [#pubsub_owner{configure = + {Node, NodeConfig}}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +publish_item(Config, Node) -> + PJID = pubsub_jid(Config), + ItemID = randoms:get_string(), + Item = #ps_item{id = ItemID, xml_els = [xmpp:encode(#presence{id = ItemID})]}, + case send_recv(Config, + #iq{type = set, to = PJID, + sub_els = [#pubsub{publish = #ps_publish{ + node = Node, + items = [Item]}}]}) of + #iq{type = result, + sub_els = [#pubsub{publish = #ps_publish{ + node = Node, + items = [#ps_item{id = ItemID}]}}]} -> + Item; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +get_items(Config, Node) -> + PJID = pubsub_jid(Config), + case send_recv(Config, + #iq{type = get, to = PJID, + sub_els = [#pubsub{items = #ps_items{node = Node}}]}) of + #iq{type = result, + sub_els = [#pubsub{items = #ps_items{node = Node, items = Items}}]} -> + Items; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +delete_item(Config, Node, I) -> + PJID = pubsub_jid(Config), + case send_recv(Config, + #iq{type = set, to = PJID, + sub_els = [#pubsub{retract = + #ps_retract{ + node = Node, + items = [#ps_item{id = I}]}}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +subscribe_node(Config, Node) -> + PJID = pubsub_jid(Config), + MyJID = my_jid(Config), + case send_recv(Config, + #iq{type = set, to = PJID, + sub_els = [#pubsub{subscribe = #ps_subscribe{ + node = Node, + jid = MyJID}}]}) of + #iq{type = result, + sub_els = [#pubsub{ + subscription = #ps_subscription{ + node = Node, + jid = MyJID} = Sub}]} -> + Sub; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +unsubscribe_node(Config, Node) -> + PJID = pubsub_jid(Config), + MyJID = my_jid(Config), + case send_recv(Config, + #iq{type = set, to = PJID, + sub_els = [#pubsub{ + unsubscribe = #ps_unsubscribe{ + node = Node, + jid = MyJID}}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +get_affiliations(Config) -> + PJID = pubsub_jid(Config), + case send_recv(Config, + #iq{type = get, to = PJID, + sub_els = [#pubsub{affiliations = {<<>>, []}}]}) of + #iq{type = result, + sub_els = [#pubsub{affiliations = {<<>>, Affs}}]} -> + Affs; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +get_affiliations(Config, Node) -> + PJID = pubsub_jid(Config), + case send_recv(Config, + #iq{type = get, to = PJID, + sub_els = [#pubsub_owner{affiliations = {Node, []}}]}) of + #iq{type = result, + sub_els = [#pubsub_owner{affiliations = {Node, Affs}}]} -> + Affs; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +set_affiliations(Config, Node, JTs) -> + PJID = pubsub_jid(Config), + Affs = [#ps_affiliation{jid = J, type = T} || {J, T} <- JTs], + case send_recv(Config, + #iq{type = set, to = PJID, + sub_els = [#pubsub_owner{affiliations = + {Node, Affs}}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +get_subscriptions(Config) -> + PJID = pubsub_jid(Config), + case send_recv(Config, + #iq{type = get, to = PJID, + sub_els = [#pubsub{subscriptions = {<<>>, []}}]}) of + #iq{type = result, sub_els = [#pubsub{subscriptions = {<<>>, Subs}}]} -> + Subs; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +get_subscriptions(Config, Node) -> + PJID = pubsub_jid(Config), + case send_recv(Config, + #iq{type = get, to = PJID, + sub_els = [#pubsub_owner{subscriptions = {Node, []}}]}) of + #iq{type = result, + sub_els = [#pubsub_owner{subscriptions = {Node, Subs}}]} -> + Subs; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +set_subscriptions(Config, Node, JTs) -> + PJID = pubsub_jid(Config), + Subs = [#ps_subscription{jid = J, type = T} || {J, T} <- JTs], + case send_recv(Config, + #iq{type = set, to = PJID, + sub_els = [#pubsub_owner{subscriptions = + {Node, Subs}}]}) of + #iq{type = result, sub_els = []} -> + ok; + #iq{type = error} = IQ -> + xmpp:get_subtag(IQ, #stanza_error{}) + end. + +default_node_config(Config) -> + [{title, ?config(pubsub_node_title, Config)}, + {notify_delete, false}, + {send_last_published_item, never}]. diff --git a/test/replaced_tests.erl b/test/replaced_tests.erl new file mode 100644 index 000000000..e50c27f05 --- /dev/null +++ b/test/replaced_tests.erl @@ -0,0 +1,57 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 16 Nov 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(replaced_tests). + +%% API +-compile(export_all). +-import(suite, [bind/1, wait_for_slave/1, wait_for_master/1, recv/1, + close_socket/1, disconnect/1]). + +-include("suite.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +%%%=================================================================== +%%% Single user tests +%%%=================================================================== +single_cases() -> + {replaced_single, [sequence], []}. + +%%%=================================================================== +%%% Master-slave tests +%%%=================================================================== +master_slave_cases() -> + {replaced_master_slave, [sequence], []}. +%% Disable tests for now due to a race condition +%% because ejabberd_sm:sid() is generated in ejabberd_s2s:init() +%%[master_slave_test(conflict)]}. + +conflict_master(Config0) -> + Config = bind(Config0), + wait_for_slave(Config), + #stream_error{reason = conflict} = recv(Config), + {xmlstreamend, <<"stream:stream">>} = recv(Config), + close_socket(Config). + +conflict_slave(Config0) -> + wait_for_master(Config0), + Config = bind(Config0), + disconnect(Config). + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +single_test(T) -> + list_to_atom("replaced_" ++ atom_to_list(T)). + +master_slave_test(T) -> + {list_to_atom("replaced_" ++ atom_to_list(T)), [parallel], + [list_to_atom("replaced_" ++ atom_to_list(T) ++ "_master"), + list_to_atom("replaced_" ++ atom_to_list(T) ++ "_slave")]}. diff --git a/test/roster_tests.erl b/test/roster_tests.erl index 2d05709ab..4aa06b953 100644 --- a/test/roster_tests.erl +++ b/test/roster_tests.erl @@ -13,8 +13,7 @@ -import(suite, [send_recv/2, recv_iq/1, send/2, disconnect/1, del_roster/1, del_roster/2, make_iq_result/1, wait_for_slave/1, wait_for_master/1, recv_presence/1, self_presence/2, - put_event/2, get_event/1, match_failure/2, get_roster/1, - is_feature_advertised/2]). + put_event/2, get_event/1, match_failure/2, get_roster/1]). -include("suite.hrl"). -include("mod_roster.hrl"). @@ -132,7 +131,7 @@ version(Config) -> %%% Master-slave tests %%%=================================================================== master_slave_cases() -> - {roster_master_slave, [parallel], + {roster_master_slave, [sequence], [master_slave_test(subscribe)]}. subscribe_master(Config) -> @@ -149,6 +148,7 @@ process_subscriptions_master(Config, Actions) -> self_presence(Config, available), lists:foldl( fun({N, {Dir, Type}}, State) -> + timer:sleep(100), if Dir == out -> put_event(Config, {N, in, Type}); Dir == in -> put_event(Config, {N, out, Type}) end, diff --git a/test/sm_tests.erl b/test/sm_tests.erl new file mode 100644 index 000000000..0a74d392a --- /dev/null +++ b/test/sm_tests.erl @@ -0,0 +1,99 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 16 Nov 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(sm_tests). + +%% API +-compile(export_all). +-import(suite, [send/2, recv/1, close_socket/1, set_opt/3, my_jid/1, + recv_message/1, disconnect/1]). + +-include("suite.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +%%%=================================================================== +%%% Single user tests +%%%=================================================================== +single_cases() -> + {sm_single, [sequence], + [single_test(feature_enabled), + single_test(enable), + single_test(resume), + single_test(resume_failed)]}. + +feature_enabled(Config) -> + true = ?config(sm, Config), + disconnect(Config). + +enable(Config) -> + Server = ?config(server, Config), + ServerJID = jid:make(<<"">>, Server, <<"">>), + %% Send messages of type 'headline' so the server discards them silently + Msg = #message{to = ServerJID, type = headline, + body = [#text{data = <<"body">>}]}, + %% Enable the session management with resumption enabled + send(Config, #sm_enable{resume = true, xmlns = ?NS_STREAM_MGMT_3}), + #sm_enabled{id = ID, resume = true} = recv(Config), + %% Initial request; 'h' should be 0. + send(Config, #sm_r{xmlns = ?NS_STREAM_MGMT_3}), + #sm_a{h = 0} = recv(Config), + %% sending two messages and requesting again; 'h' should be 3. + send(Config, Msg), + send(Config, Msg), + send(Config, Msg), + send(Config, #sm_r{xmlns = ?NS_STREAM_MGMT_3}), + #sm_a{h = 3} = recv(Config), + close_socket(Config), + {save_config, set_opt(sm_previd, ID, Config)}. + +resume(Config) -> + {_, SMConfig} = ?config(saved_config, Config), + ID = ?config(sm_previd, SMConfig), + Server = ?config(server, Config), + ServerJID = jid:make(<<"">>, Server, <<"">>), + MyJID = my_jid(Config), + Txt = #text{data = <<"body">>}, + Msg = #message{from = ServerJID, to = MyJID, body = [Txt]}, + %% Route message. The message should be queued by the C2S process. + ejabberd_router:route(ServerJID, MyJID, Msg), + send(Config, #sm_resume{previd = ID, h = 0, xmlns = ?NS_STREAM_MGMT_3}), + #sm_resumed{previd = ID, h = 3} = recv(Config), + #message{from = ServerJID, to = MyJID, body = [Txt]} = recv_message(Config), + #sm_r{} = recv(Config), + send(Config, #sm_a{h = 1, xmlns = ?NS_STREAM_MGMT_3}), + %% Send another stanza to increment the server's 'h' for sm_resume_failed. + send(Config, #presence{to = ServerJID}), + close_socket(Config), + {save_config, set_opt(sm_previd, ID, Config)}. + +resume_failed(Config) -> + {_, SMConfig} = ?config(saved_config, Config), + ID = ?config(sm_previd, SMConfig), + ct:sleep(5000), % Wait for session to time out. + send(Config, #sm_resume{previd = ID, h = 1, xmlns = ?NS_STREAM_MGMT_3}), + #sm_failed{reason = 'item-not-found', h = 4} = recv(Config), + disconnect(Config). + +%%%=================================================================== +%%% Master-slave tests +%%%=================================================================== +master_slave_cases() -> + {sm_master_slave, [sequence], []}. + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +single_test(T) -> + list_to_atom("sm_" ++ atom_to_list(T)). + +master_slave_test(T) -> + {list_to_atom("sm_" ++ atom_to_list(T)), [parallel], + [list_to_atom("sm_" ++ atom_to_list(T) ++ "_master"), + list_to_atom("sm_" ++ atom_to_list(T) ++ "_slave")]}. diff --git a/test/suite.erl b/test/suite.erl index 52c030df1..a288a5f66 100644 --- a/test/suite.erl +++ b/test/suite.erl @@ -488,8 +488,9 @@ decode(El, NS, Opts) -> [format_element(El), xmpp:pp(Pkt)]), Pkt catch _:{xmpp_codec, Why} -> - ct:fail("recv failed: ~p->~n~s", - [El, xmpp:format_error(Why)]) + ct:pal("recv failed: ~p->~n~s", + [El, xmpp:format_error(Why)]), + erlang:error({xmpp_codec, Why}) end. send_text(Config, Text) -> diff --git a/test/vcard_tests.erl b/test/vcard_tests.erl new file mode 100644 index 000000000..bb3efb475 --- /dev/null +++ b/test/vcard_tests.erl @@ -0,0 +1,125 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 16 Nov 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(vcard_tests). + +%% API +-compile(export_all). +-import(suite, [send_recv/2, disconnect/1, is_feature_advertised/2, + is_feature_advertised/3, + my_jid/1, wait_for_slave/1, wait_for_master/1, + recv_presence/1, recv/1]). + +-include("suite.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +%%%=================================================================== +%%% Single user tests +%%%=================================================================== +single_cases() -> + {vcard_single, [sequence], + [single_test(feature_enabled), + single_test(get_set)]}. + +feature_enabled(Config) -> + BareMyJID = jid:remove_resource(my_jid(Config)), + true = is_feature_advertised(Config, ?NS_VCARD), + true = is_feature_advertised(Config, ?NS_VCARD, BareMyJID), + disconnect(Config). + +get_set(Config) -> + VCard = + #vcard_temp{fn = <<"Peter Saint-Andre">>, + n = #vcard_name{family = <<"Saint-Andre">>, + given = <<"Peter">>}, + nickname = <<"stpeter">>, + bday = <<"1966-08-06">>, + adr = [#vcard_adr{work = true, + extadd = <<"Suite 600">>, + street = <<"1899 Wynkoop Street">>, + locality = <<"Denver">>, + region = <<"CO">>, + pcode = <<"80202">>, + ctry = <<"USA">>}, + #vcard_adr{home = true, + locality = <<"Denver">>, + region = <<"CO">>, + pcode = <<"80209">>, + ctry = <<"USA">>}], + tel = [#vcard_tel{work = true,voice = true, + number = <<"303-308-3282">>}, + #vcard_tel{home = true,voice = true, + number = <<"303-555-1212">>}], + email = [#vcard_email{internet = true,pref = true, + userid = <<"stpeter@jabber.org">>}], + jabberid = <<"stpeter@jabber.org">>, + title = <<"Executive Director">>,role = <<"Patron Saint">>, + org = #vcard_org{name = <<"XMPP Standards Foundation">>}, + url = <<"http://www.xmpp.org/xsf/people/stpeter.shtml">>, + desc = <<"More information about me is located on my " + "personal website: http://www.saint-andre.com/">>}, + #iq{type = result, sub_els = []} = + send_recv(Config, #iq{type = set, sub_els = [VCard]}), + %% TODO: check if VCard == VCard1. + #iq{type = result, sub_els = [_VCard1]} = + send_recv(Config, #iq{type = get, sub_els = [#vcard_temp{}]}), + disconnect(Config). + +%%%=================================================================== +%%% Master-slave tests +%%%=================================================================== +master_slave_cases() -> + {vcard_master_slave, [sequence], []}. + %%[master_slave_test(xupdate)]}. + +xupdate_master(Config) -> + Img = <<137, "PNG\r\n", 26, $\n>>, + ImgHash = p1_sha:sha(Img), + MyJID = my_jid(Config), + Peer = ?config(slave, Config), + wait_for_slave(Config), + #presence{from = MyJID, type = available} = send_recv(Config, #presence{}), + #presence{from = Peer, type = available} = recv_presence(Config), + VCard = #vcard_temp{photo = #vcard_photo{type = <<"image/png">>, binval = Img}}, + #iq{type = result, sub_els = []} = + send_recv(Config, #iq{type = set, sub_els = [VCard]}), + #presence{from = MyJID, type = available, + sub_els = [#vcard_xupdate{hash = ImgHash}]} = recv_presence(Config), + #iq{type = result, sub_els = []} = + send_recv(Config, #iq{type = set, sub_els = [#vcard_temp{}]}), + ?recv2(#presence{from = MyJID, type = available, + sub_els = [#vcard_xupdate{hash = undefined}]}, + #presence{from = Peer, type = unavailable}), + disconnect(Config). + +xupdate_slave(Config) -> + Img = <<137, "PNG\r\n", 26, $\n>>, + ImgHash = p1_sha:sha(Img), + MyJID = my_jid(Config), + Peer = ?config(master, Config), + #presence{from = MyJID, type = available} = send_recv(Config, #presence{}), + wait_for_master(Config), + #presence{from = Peer, type = available} = recv_presence(Config), + #presence{from = Peer, type = available, + sub_els = [#vcard_xupdate{hash = ImgHash}]} = recv_presence(Config), + #presence{from = Peer, type = available, + sub_els = [#vcard_xupdate{hash = undefined}]} = recv_presence(Config), + disconnect(Config). + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +single_test(T) -> + list_to_atom("vcard_" ++ atom_to_list(T)). + +master_slave_test(T) -> + {list_to_atom("vcard_" ++ atom_to_list(T)), [parallel], + [list_to_atom("vcard_" ++ atom_to_list(T) ++ "_master"), + list_to_atom("vcard_" ++ atom_to_list(T) ++ "_slave")]}. From e69937d93adc33a24a13015038446f008c17d202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Fri, 18 Nov 2016 11:51:57 +0100 Subject: [PATCH 097/151] Get rid of substitute_forwarded --- test/suite.erl | 15 +-------------- test/suite.hrl | 3 --- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/test/suite.erl b/test/suite.erl index 49ebaa891..a288a5f66 100644 --- a/test/suite.erl +++ b/test/suite.erl @@ -481,22 +481,9 @@ format_element(El) -> false -> io_lib:format(" ~s~n", El) end. -substitute_forwarded(#mam_result{sub_els = Sub} = El) -> - El#mam_result{sub_els = [substitute_forwarded(SEl) || SEl <- Sub]}; -substitute_forwarded(#carbons_sent{forwarded = Sub} = El) -> - El#carbons_sent{forwarded = [substitute_forwarded(SEl) || SEl <- Sub]}; -substitute_forwarded(#message{sub_els = Sub} = El) -> - El#message{sub_els = [substitute_forwarded(SEl) || SEl <- Sub]}; -substitute_forwarded(#forwarded{delay = Delay, xml_els = Sub}) -> - #forwarded_decoded{delay = Delay, sub_els = [xmpp:decode(SEl) || SEl <- Sub]}; -substitute_forwarded(El) -> - El. - - - decode(El, NS, Opts) -> try - Pkt = substitute_forwarded(xmpp:decode(El, NS, Opts)), + Pkt = xmpp:decode(El, NS, Opts), ct:pal("RECV:~n~s~n~s", [format_element(El), xmpp:pp(Pkt)]), Pkt diff --git a/test/suite.hrl b/test/suite.hrl index d9a9c5ab0..00239f8cf 100644 --- a/test/suite.hrl +++ b/test/suite.hrl @@ -5,9 +5,6 @@ -include("mod_proxy65.hrl"). -include("xmpp_codec.hrl"). --record(forwarded_decoded, {delay :: #delay{}, - sub_els = [] :: [fxml:xmlel()]}). - -define(STREAM_TRAILER, <<"">>). -define(PUBSUB(Node), <<(?NS_PUBSUB)/binary, "#", Node>>). From 45e77ea4830a753b4defcc12545d60d56e849819 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Fri, 18 Nov 2016 12:25:01 +0100 Subject: [PATCH 098/151] Remove useless NO_EXT_LIB flag --- include/jlib.hrl | 4 ---- include/xmpp.hrl | 4 ---- rebar.config | 3 ++- src/ext_mod.erl | 5 +---- 4 files changed, 3 insertions(+), 13 deletions(-) diff --git a/include/jlib.hrl b/include/jlib.hrl index 50a031334..5a3c1634e 100644 --- a/include/jlib.hrl +++ b/include/jlib.hrl @@ -19,11 +19,7 @@ %%%---------------------------------------------------------------------- -include("ns.hrl"). --ifdef(NO_EXT_LIB). -include("fxml.hrl"). --else. --include_lib("fast_xml/include/fxml.hrl"). --endif. -define(STANZA_ERROR(Code, Type, Condition), #xmlel{name = <<"error">>, diff --git a/include/xmpp.hrl b/include/xmpp.hrl index e1bdaeed0..f8a61590f 100644 --- a/include/xmpp.hrl +++ b/include/xmpp.hrl @@ -9,11 +9,7 @@ -include("ns.hrl"). -include("jid.hrl"). -include("xmpp_codec.hrl"). --ifdef(NO_EXT_LIB). -include("fxml.hrl"). --else. --include_lib("fast_xml/include/fxml.hrl"). --endif. -type iq_type() :: get | set | result | error. -type message_type() :: chat | error | groupchat | headline | normal. diff --git a/rebar.config b/rebar.config index fca8d19e2..966b746c1 100644 --- a/rebar.config +++ b/rebar.config @@ -1,4 +1,4 @@ -%%%------------------------------------------------------------------- +%------------------------------------------------------------------- %%% @author Evgeniy Khramtsov %%% @copyright (C) 2013-2016, Evgeniy Khramtsov %%% @doc @@ -65,6 +65,7 @@ {erl_first_files, ["src/ejabberd_config.erl", "src/gen_mod.erl"]}. {erl_opts, [nowarn_deprecated_function, + {i, "include"}, {i, "deps/fast_xml/include"}, {if_var_false, debug, no_debug_info}, {if_var_true, debug, debug_info}, {if_var_true, roster_gateway_workaround, {d, 'ROSTER_GATWAY_WORKAROUND'}}, diff --git a/src/ext_mod.erl b/src/ext_mod.erl index a2109e569..071fb827c 100644 --- a/src/ext_mod.erl +++ b/src/ext_mod.erl @@ -520,11 +520,8 @@ compile(_Module, _Spec, DestDir) -> filelib:ensure_dir(filename:join(Ebin, ".")), EjabBin = filename:dirname(code:which(ejabberd)), EjabInc = filename:join(filename:dirname(EjabBin), "include"), - XmlHrl = filename:join(EjabInc, "fxml.hrl"), - ExtLib = [{d, 'NO_EXT_LIB'} || filelib:is_file(XmlHrl)], Options = [{outdir, Ebin}, {i, "include"}, {i, EjabInc}, - verbose, report_errors, report_warnings] - ++ ExtLib, + verbose, report_errors, report_warnings], [file:copy(App, Ebin) || App <- filelib:wildcard("src/*.app")], %% Compile erlang files From daab95e3b5d47327f07ec7efd1189e71a41e6439 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Fri, 18 Nov 2016 12:54:06 +0100 Subject: [PATCH 099/151] Fix elixir tests --- test/ejabberd_cyrsasl_test.exs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/ejabberd_cyrsasl_test.exs b/test/ejabberd_cyrsasl_test.exs index d9b949294..b85be0f8e 100644 --- a/test/ejabberd_cyrsasl_test.exs +++ b/test/ejabberd_cyrsasl_test.exs @@ -44,12 +44,12 @@ defmodule EjabberdCyrsaslTest do test "Plain text (correct user wrong pass)", context do step1 = :cyrsasl.server_start(context[:cyrstate], "PLAIN", <<0,"user1",0,"badpass">>) - assert step1 == {:error, "not-authorized", "user1"}, "got error response" + assert step1 == {:error, :"not-authorized", "user1"} end test "Plain text (wrong user wrong pass)", context do step1 = :cyrsasl.server_start(context[:cyrstate], "PLAIN", <<0,"nouser1",0,"badpass">>) - assert step1 == {:error, "not-authorized", "nouser1"}, "got error response" + assert step1 == {:error, :"not-authorized", "nouser1"} end test "Anonymous", context do From d00a6340253ccc551eca091b362473cdb3859966 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Fri, 18 Nov 2016 14:02:47 +0100 Subject: [PATCH 100/151] Fix includes in eunit compilation flags --- rebar.config | 3 ++- rebar.config.script | 16 +++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/rebar.config b/rebar.config index 966b746c1..f9af6a568 100644 --- a/rebar.config +++ b/rebar.config @@ -113,7 +113,8 @@ {if_var_false, elixir, "(\"Elixir.*\":_/_)"}, {if_var_false, redis, "(\"eredis\":_/_)"}]}. -{eunit_compile_opts, [{i, "tools"}]}. +{eunit_compile_opts, [{i, "tools"}, {i, "include"}, + {i, "deps/fast_xml/include"}]}. {if_version_above, "17", {cover_enabled, true}}. {cover_export_enabled, true}. diff --git a/rebar.config.script b/rebar.config.script index ccafba7ec..2a924d26c 100644 --- a/rebar.config.script +++ b/rebar.config.script @@ -119,12 +119,18 @@ TestConfig = case file:read_file_info(TestConfigFile) of "-userconfig ct_config_plain " ++ TestConfigFile ++ " "; _ -> "" - end, + end, -Conf2 = [{ct_extra_params, "-ct_hooks cth_surefire " - ++ TestConfig - ++ "-include " - ++ filename:join([Cwd, "tools"])} | Conf1], +CtIncludes = case lists:keyfind(eunit_compile_opts, 1, Conf1) of + false -> + []; + {_, EunitCompOpts} -> + [[" -include ", filename:join([Cwd, IncPath])] + || {i, IncPath} <- EunitCompOpts] + end, + +Conf2 = [{ct_extra_params, lists:flatten(["-ct_hooks cth_surefire ", TestConfig, + CtIncludes])} | Conf1], Conf3 = case lists:keytake(xref_exclusions, 1, Conf2) of {value, {_, Items2}, Rest2} -> From 9aff7e52a8ddf9ecb6637a629899ecf0b10e8825 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sat, 19 Nov 2016 13:03:33 +0300 Subject: [PATCH 101/151] Switch to stand-alone XMPP library --- Makefile.in | 10 +- include/flex_offline.hrl | 10 - include/jid.hrl | 17 - include/mam_query.hrl | 13 - include/muc_register.hrl | 16 - include/muc_request.hrl | 16 - include/muc_roomconfig.hrl | 55 - include/muc_roominfo.hrl | 18 - include/ns.hrl | 182 - include/pubsub_get_pending.hrl | 13 - include/pubsub_node_config.hrl | 60 - include/pubsub_publish_options.hrl | 14 - include/pubsub_subscribe_authorization.hrl | 13 - include/pubsub_subscribe_options.hrl | 25 - include/xmpp.hrl | 25 - include/xmpp_codec.hrl | 1092 - rebar.config | 12 +- specs/flex_offline.cfg | 1 - specs/flex_offline.xdata | 12 - specs/mam_query.cfg | 9 - specs/mam_query.xdata | 23 - specs/muc_register.cfg | 2 - specs/muc_register.xdata | 37 - specs/muc_request.cfg | 2 - specs/muc_request.xdata | 31 - specs/muc_roomconfig.cfg | 11 - specs/muc_roomconfig.xdata | 192 - specs/muc_roominfo.cfg | 11 - specs/muc_roominfo.xdata | 55 - specs/pubsub_get_pending.cfg | 7 - specs/pubsub_get_pending.xdata | 15 - specs/pubsub_node_config.cfg | 8 - specs/pubsub_node_config.xdata | 189 - specs/pubsub_publish_options.cfg | 6 - specs/pubsub_publish_options.xdata | 34 - specs/pubsub_subscribe_authorization.cfg | 7 - specs/pubsub_subscribe_authorization.xdata | 27 - specs/pubsub_subscribe_options.cfg | 1 - specs/pubsub_subscribe_options.xdata | 70 - specs/xmpp_codec.spec | 3588 -- src/flex_offline.erl | 128 - src/jid.erl | 266 - src/mam_query.erl | 220 - src/muc_register.erl | 364 - src/muc_request.erl | 269 - src/muc_roomconfig.erl | 1675 - src/muc_roominfo.erl | 491 - src/pubsub_get_pending.erl | 130 - src/pubsub_node_config.erl | 1666 - src/pubsub_publish_options.erl | 157 - src/pubsub_subscribe_authorization.erl | 279 - src/pubsub_subscribe_options.erl | 508 - src/xdata_codec.erl | 648 - src/xmpp.erl | 827 - src/xmpp_codec.erl | 34647 ------------------- 55 files changed, 10 insertions(+), 48194 deletions(-) delete mode 100644 include/flex_offline.hrl delete mode 100644 include/jid.hrl delete mode 100644 include/mam_query.hrl delete mode 100644 include/muc_register.hrl delete mode 100644 include/muc_request.hrl delete mode 100644 include/muc_roomconfig.hrl delete mode 100644 include/muc_roominfo.hrl delete mode 100644 include/ns.hrl delete mode 100644 include/pubsub_get_pending.hrl delete mode 100644 include/pubsub_node_config.hrl delete mode 100644 include/pubsub_publish_options.hrl delete mode 100644 include/pubsub_subscribe_authorization.hrl delete mode 100644 include/pubsub_subscribe_options.hrl delete mode 100644 include/xmpp.hrl delete mode 100644 include/xmpp_codec.hrl delete mode 100644 specs/flex_offline.cfg delete mode 100644 specs/flex_offline.xdata delete mode 100644 specs/mam_query.cfg delete mode 100644 specs/mam_query.xdata delete mode 100644 specs/muc_register.cfg delete mode 100644 specs/muc_register.xdata delete mode 100644 specs/muc_request.cfg delete mode 100644 specs/muc_request.xdata delete mode 100644 specs/muc_roomconfig.cfg delete mode 100644 specs/muc_roomconfig.xdata delete mode 100644 specs/muc_roominfo.cfg delete mode 100644 specs/muc_roominfo.xdata delete mode 100644 specs/pubsub_get_pending.cfg delete mode 100644 specs/pubsub_get_pending.xdata delete mode 100644 specs/pubsub_node_config.cfg delete mode 100644 specs/pubsub_node_config.xdata delete mode 100644 specs/pubsub_publish_options.cfg delete mode 100644 specs/pubsub_publish_options.xdata delete mode 100644 specs/pubsub_subscribe_authorization.cfg delete mode 100644 specs/pubsub_subscribe_authorization.xdata delete mode 100644 specs/pubsub_subscribe_options.cfg delete mode 100644 specs/pubsub_subscribe_options.xdata delete mode 100644 specs/xmpp_codec.spec delete mode 100644 src/flex_offline.erl delete mode 100644 src/jid.erl delete mode 100644 src/mam_query.erl delete mode 100644 src/muc_register.erl delete mode 100644 src/muc_request.erl delete mode 100644 src/muc_roomconfig.erl delete mode 100644 src/muc_roominfo.erl delete mode 100644 src/pubsub_get_pending.erl delete mode 100644 src/pubsub_node_config.erl delete mode 100644 src/pubsub_publish_options.erl delete mode 100644 src/pubsub_subscribe_authorization.erl delete mode 100644 src/pubsub_subscribe_options.erl delete mode 100644 src/xdata_codec.erl delete mode 100644 src/xmpp.erl delete mode 100644 src/xmpp_codec.erl diff --git a/Makefile.in b/Makefile.in index b7c229fcc..00fd4f62c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -108,14 +108,6 @@ edoc: $(ERL) -noinput +B -eval \ 'case edoc:application(ejabberd, ".", []) of ok -> halt(0); error -> halt(1) end.' -spec: - $(ERL) -noinput +B -pa ebin -pa deps/*/ebin -eval \ - 'case fxml_gen:compile("specs/xmpp_codec.spec", [{add_type_specs, xmpp_element}, {erl_dir, "src"}, {hrl_dir, "include"}]) of ok -> halt(0); _ -> halt(1) end.' - -xdata: - $(ERL) -noinput +B -pa ebin -pa deps/*/ebin -eval \ - 'case xdata_codec:compile("specs", [{erl_dir, "src"}, {hrl_dir, "include"}]) of ok -> halt(0); _ -> halt(1) end.' - JOIN_PATHS=$(if $(wordlist 2,1000,$(1)),$(firstword $(1))/$(call JOIN_PATHS,$(wordlist 2,1000,$(1))),$(1)) VERSIONED_DEP=$(if $(DEP_$(1)_VERSION),$(DEP_$(1)_VERSION),$(1)) @@ -347,5 +339,5 @@ quicktest: $(REBAR) skip_deps=true ct suites=elixir .PHONY: src edoc dialyzer Makefile TAGS clean clean-rel distclean rel \ - install uninstall uninstall-binary uninstall-all translations deps test spec \ + install uninstall uninstall-binary uninstall-all translations deps test \ quicktest erlang_plt deps_plt ejabberd_plt diff --git a/include/flex_offline.hrl b/include/flex_offline.hrl deleted file mode 100644 index 74a38fbb3..000000000 --- a/include/flex_offline.hrl +++ /dev/null @@ -1,10 +0,0 @@ -%% Created automatically by xdata generator (xdata_codec.erl) -%% Source: flex_offline.xdata -%% Form type: http://jabber.org/protocol/offline -%% Document: XEP-0013 - - --type property() :: {'number_of_messages', non_neg_integer()}. --type result() :: [property()]. - --type form() :: [property() | xdata_field()]. diff --git a/include/jid.hrl b/include/jid.hrl deleted file mode 100644 index 965985c31..000000000 --- a/include/jid.hrl +++ /dev/null @@ -1,17 +0,0 @@ -%%%------------------------------------------------------------------- -%%% @author Evgeny Khramtsov -%%% @copyright (C) 2016, Evgeny Khramtsov -%%% @doc -%%% -%%% @end -%%% Created : 10 Jul 2016 by Evgeny Khramtsov -%%%------------------------------------------------------------------- --record(jid, {user = <<"">> :: binary(), - server = <<"">> :: binary(), - resource = <<"">> :: binary(), - luser = <<"">> :: binary(), - lserver = <<"">> :: binary(), - lresource = <<"">> :: binary()}). - --type(jid() :: #jid{}). --type(ljid() :: {binary(), binary(), binary()}). diff --git a/include/mam_query.hrl b/include/mam_query.hrl deleted file mode 100644 index 4ec48c05e..000000000 --- a/include/mam_query.hrl +++ /dev/null @@ -1,13 +0,0 @@ -%% Created automatically by xdata generator (xdata_codec.erl) -%% Source: mam_query.xdata -%% Form type: urn:xmpp:mam:1 -%% Document: XEP-0313 - - --type property() :: {'with', jid:jid()} | - {'start', erlang:timestamp()} | - {'end', erlang:timestamp()} | - {'withtext', binary()}. --type result() :: [property()]. - --type form() :: [property() | xdata_field()]. diff --git a/include/muc_register.hrl b/include/muc_register.hrl deleted file mode 100644 index 0cfc928c2..000000000 --- a/include/muc_register.hrl +++ /dev/null @@ -1,16 +0,0 @@ -%% Created automatically by xdata generator (xdata_codec.erl) -%% Source: muc_register.xdata -%% Form type: http://jabber.org/protocol/muc#register -%% Document: XEP-0045 - - --type property() :: {'allow', boolean()} | - {'email', binary()} | - {'faqentry', [binary()]} | - {'first', binary()} | - {'last', binary()} | - {'roomnick', binary()} | - {'url', binary()}. --type result() :: [property()]. - --type form() :: [property() | xdata_field()]. diff --git a/include/muc_request.hrl b/include/muc_request.hrl deleted file mode 100644 index bc14be35f..000000000 --- a/include/muc_request.hrl +++ /dev/null @@ -1,16 +0,0 @@ -%% Created automatically by xdata generator (xdata_codec.erl) -%% Source: muc_request.xdata -%% Form type: http://jabber.org/protocol/muc#request -%% Document: XEP-0045 - - --type property() :: {'role', participant} | - {'jid', jid:jid()} | - {'roomnick', binary()} | - {'request_allow', boolean()}. --type result() :: [property()]. - --type options(T) :: [{binary(), T}]. --type property_with_options() :: - {'role', participant, options(participant)}. --type form() :: [property() | property_with_options() | xdata_field()]. diff --git a/include/muc_roomconfig.hrl b/include/muc_roomconfig.hrl deleted file mode 100644 index 89cfc3346..000000000 --- a/include/muc_roomconfig.hrl +++ /dev/null @@ -1,55 +0,0 @@ -%% Created automatically by xdata generator (xdata_codec.erl) -%% Source: muc_roomconfig.xdata -%% Form type: http://jabber.org/protocol/muc#roomconfig -%% Document: XEP-0045 - --type 'allow_private_messages_from_visitors'() :: nobody | moderators | anyone. --type 'maxusers'() :: none | non_neg_integer(). --type 'presencebroadcast'() :: moderator | participant | visitor. --type 'whois'() :: moderators | anyone. - --type property() :: {'maxhistoryfetch', binary()} | - {'allowpm', binary()} | - {'allow_private_messages', boolean()} | - {'allow_private_messages_from_visitors', 'allow_private_messages_from_visitors'()} | - {'allow_visitor_status', boolean()} | - {'allow_visitor_nickchange', boolean()} | - {'allow_voice_requests', boolean()} | - {'allow_subscription', boolean()} | - {'voice_request_min_interval', non_neg_integer()} | - {'captcha_protected', boolean()} | - {'captcha_whitelist', [jid:jid()]} | - {'allow_query_users', boolean()} | - {'allowinvites', boolean()} | - {'changesubject', boolean()} | - {'enablelogging', boolean()} | - {'getmemberlist', [binary()]} | - {'lang', binary()} | - {'pubsub', binary()} | - {'maxusers', 'maxusers'()} | - {'membersonly', boolean()} | - {'moderatedroom', boolean()} | - {'members_by_default', boolean()} | - {'passwordprotectedroom', boolean()} | - {'persistentroom', boolean()} | - {'presencebroadcast', ['presencebroadcast'()]} | - {'publicroom', boolean()} | - {'public_list', boolean()} | - {'roomadmins', [jid:jid()]} | - {'roomdesc', binary()} | - {'roomname', binary()} | - {'roomowners', [jid:jid()]} | - {'roomsecret', binary()} | - {'whois', 'whois'()} | - {'mam', boolean()}. --type result() :: [property()]. - --type options(T) :: [{binary(), T}]. --type property_with_options() :: - {'allowpm', binary(), options(binary())} | - {'allow_private_messages_from_visitors', 'allow_private_messages_from_visitors'(), options('allow_private_messages_from_visitors'())} | - {'getmemberlist', [binary()], options(binary())} | - {'maxusers', 'maxusers'(), options('maxusers'())} | - {'presencebroadcast', ['presencebroadcast'()], options('presencebroadcast'())} | - {'whois', 'whois'(), options('whois'())}. --type form() :: [property() | property_with_options() | xdata_field()]. diff --git a/include/muc_roominfo.hrl b/include/muc_roominfo.hrl deleted file mode 100644 index cf4f4ebf0..000000000 --- a/include/muc_roominfo.hrl +++ /dev/null @@ -1,18 +0,0 @@ -%% Created automatically by xdata generator (xdata_codec.erl) -%% Source: muc_roominfo.xdata -%% Form type: http://jabber.org/protocol/muc#roominfo -%% Document: XEP-0045 - - --type property() :: {'maxhistoryfetch', non_neg_integer()} | - {'contactjid', [jid:jid()]} | - {'description', binary()} | - {'lang', binary()} | - {'ldapgroup', binary()} | - {'logs', binary()} | - {'occupants', non_neg_integer()} | - {'subject', binary()} | - {'subjectmod', boolean()}. --type result() :: [property()]. - --type form() :: [property() | xdata_field()]. diff --git a/include/ns.hrl b/include/ns.hrl deleted file mode 100644 index d94c2a95f..000000000 --- a/include/ns.hrl +++ /dev/null @@ -1,182 +0,0 @@ -%%%---------------------------------------------------------------------- -%%% -%%% ejabberd, Copyright (C) 2002-2016 ProcessOne -%%% -%%% This program is free software; you can redistribute it and/or -%%% modify it under the terms of the GNU General Public License as -%%% published by the Free Software Foundation; either version 2 of the -%%% License, or (at your option) any later version. -%%% -%%% This program is distributed in the hope that it will be useful, -%%% but WITHOUT ANY WARRANTY; without even the implied warranty of -%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -%%% General Public License for more details. -%%% -%%% You should have received a copy of the GNU General Public License along -%%% with this program; if not, write to the Free Software Foundation, Inc., -%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -%%% -%%%---------------------------------------------------------------------- - --define(NS_COMPONENT, <<"jabber:component:accept">>). --define(NS_SERVER, <<"jabber:server">>). --define(NS_SERVER_DIALBACK, <<"jabber:server:dialback">>). --define(NS_CLIENT, <<"jabber:client">>). --define(NS_DISCO_ITEMS, - <<"http://jabber.org/protocol/disco#items">>). --define(NS_DISCO_INFO, - <<"http://jabber.org/protocol/disco#info">>). --define(NS_VCARD, <<"vcard-temp">>). --define(NS_VCARD_UPDATE, <<"vcard-temp:x:update">>). --define(NS_AUTH, <<"jabber:iq:auth">>). --define(NS_AUTH_ERROR, <<"jabber:iq:auth:error">>). --define(NS_REGISTER, <<"jabber:iq:register">>). --define(NS_SEARCH, <<"jabber:iq:search">>). --define(NS_ROSTER, <<"jabber:iq:roster">>). --define(NS_ROSTER_VER, - <<"urn:xmpp:features:rosterver">>). --define(NS_PRIVACY, <<"jabber:iq:privacy">>). --define(NS_BLOCKING, <<"urn:xmpp:blocking">>). --define(NS_PRIVATE, <<"jabber:iq:private">>). --define(NS_VERSION, <<"jabber:iq:version">>). --define(NS_TIME, <<"urn:xmpp:time">>). --define(NS_LAST, <<"jabber:iq:last">>). --define(NS_XDATA, <<"jabber:x:data">>). --define(NS_IQDATA, <<"jabber:iq:data">>). --define(NS_DELAY, <<"urn:xmpp:delay">>). --define(NS_HINTS, <<"urn:xmpp:hints">>). --define(NS_EXPIRE, <<"jabber:x:expire">>). --define(NS_EVENT, <<"jabber:x:event">>). --define(NS_CHATSTATES, - <<"http://jabber.org/protocol/chatstates">>). --define(NS_XCONFERENCE, <<"jabber:x:conference">>). --define(NS_STATS, - <<"http://jabber.org/protocol/stats">>). --define(NS_MUC, <<"http://jabber.org/protocol/muc">>). --define(NS_MUC_USER, - <<"http://jabber.org/protocol/muc#user">>). --define(NS_MUC_ADMIN, - <<"http://jabber.org/protocol/muc#admin">>). --define(NS_MUC_OWNER, - <<"http://jabber.org/protocol/muc#owner">>). --define(NS_MUC_UNIQUE, - <<"http://jabber.org/protocol/muc#unique">>). --define(NS_PUBSUB, - <<"http://jabber.org/protocol/pubsub">>). --define(NS_PUBSUB_EVENT, - <<"http://jabber.org/protocol/pubsub#event">>). --define(NS_PUBSUB_META_DATA, - <<"http://jabber.org/protocol/pubsub#meta-data">>). --define(NS_PUBSUB_OWNER, - <<"http://jabber.org/protocol/pubsub#owner">>). --define(NS_PUBSUB_NMI, - <<"http://jabber.org/protocol/pubsub#node-meta-info">>). --define(NS_PUBSUB_ERRORS, - <<"http://jabber.org/protocol/pubsub#errors">>). --define(NS_PUBSUB_NODE_CONFIG, - <<"http://jabber.org/protocol/pubsub#node_config">>). --define(NS_PUBSUB_SUB_OPTIONS, - <<"http://jabber.org/protocol/pubsub#subscribe_options">>). --define(NS_PUBSUB_SUBSCRIBE_OPTIONS, - <<"http://jabber.org/protocol/pubsub#subscribe_options">>). --define(NS_PUBSUB_PUBLISH_OPTIONS, - <<"http://jabber.org/protocol/pubsub#publish_options">>). --define(NS_PUBSUB_SUB_AUTH, - <<"http://jabber.org/protocol/pubsub#subscribe_authorization">>). --define(NS_PUBSUB_GET_PENDING, - <<"http://jabber.org/protocol/pubsub#get-pending">>). --define(NS_COMMANDS, - <<"http://jabber.org/protocol/commands">>). --define(NS_BYTESTREAMS, - <<"http://jabber.org/protocol/bytestreams">>). --define(NS_ADMIN, - <<"http://jabber.org/protocol/admin">>). --define(NS_ADMIN_ANNOUNCE, - <<"http://jabber.org/protocol/admin#announce">>). --define(NS_ADMIN_ANNOUNCE_ALL, - <<"http://jabber.org/protocol/admin#announce-all">>). --define(NS_ADMIN_SET_MOTD, - <<"http://jabber.org/protocol/admin#set-motd">>). --define(NS_ADMIN_EDIT_MOTD, - <<"http://jabber.org/protocol/admin#edit-motd">>). --define(NS_ADMIN_DELETE_MOTD, - <<"http://jabber.org/protocol/admin#delete-motd">>). --define(NS_ADMIN_ANNOUNCE_ALLHOSTS, - <<"http://jabber.org/protocol/admin#announce-allhosts">>). --define(NS_ADMIN_ANNOUNCE_ALL_ALLHOSTS, - <<"http://jabber.org/protocol/admin#announce-all-allhosts">>). --define(NS_ADMIN_SET_MOTD_ALLHOSTS, - <<"http://jabber.org/protocol/admin#set-motd-allhosts">>). --define(NS_ADMIN_EDIT_MOTD_ALLHOSTS, - <<"http://jabber.org/protocol/admin#edit-motd-allhosts">>). --define(NS_ADMIN_DELETE_MOTD_ALLHOSTS, - <<"http://jabber.org/protocol/admin#delete-motd-allhosts">>). --define(NS_SERVERINFO, - <<"http://jabber.org/network/serverinfo">>). --define(NS_RSM, <<"http://jabber.org/protocol/rsm">>). --define(NS_EJABBERD_CONFIG, <<"ejabberd:config">>). --define(NS_STREAM, - <<"http://etherx.jabber.org/streams">>). --define(NS_STANZAS, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>). --define(NS_STREAMS, - <<"urn:ietf:params:xml:ns:xmpp-streams">>). --define(NS_TLS, <<"urn:ietf:params:xml:ns:xmpp-tls">>). --define(NS_SASL, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>). --define(NS_SESSION, - <<"urn:ietf:params:xml:ns:xmpp-session">>). --define(NS_BIND, - <<"urn:ietf:params:xml:ns:xmpp-bind">>). --define(NS_FEATURE_IQAUTH, - <<"http://jabber.org/features/iq-auth">>). --define(NS_FEATURE_IQREGISTER, - <<"http://jabber.org/features/iq-register">>). --define(NS_FEATURE_COMPRESS, - <<"http://jabber.org/features/compress">>). --define(NS_FEATURE_MSGOFFLINE, <<"msgoffline">>). --define(NS_FLEX_OFFLINE, <<"http://jabber.org/protocol/offline">>). --define(NS_COMPRESS, - <<"http://jabber.org/protocol/compress">>). --define(NS_CAPS, <<"http://jabber.org/protocol/caps">>). --define(NS_SHIM, <<"http://jabber.org/protocol/shim">>). --define(NS_ADDRESS, - <<"http://jabber.org/protocol/address">>). --define(NS_OOB, <<"jabber:x:oob">>). --define(NS_CAPTCHA, <<"urn:xmpp:captcha">>). --define(NS_MEDIA, <<"urn:xmpp:media-element">>). --define(NS_BOB, <<"urn:xmpp:bob">>). --define(NS_MAM_TMP, <<"urn:xmpp:mam:tmp">>). --define(NS_MAM_0, <<"urn:xmpp:mam:0">>). --define(NS_MAM_1, <<"urn:xmpp:mam:1">>). --define(NS_SID_0, <<"urn:xmpp:sid:0">>). --define(NS_PING, <<"urn:xmpp:ping">>). --define(NS_CARBONS_2, <<"urn:xmpp:carbons:2">>). --define(NS_CARBONS_1, <<"urn:xmpp:carbons:1">>). --define(NS_FORWARD, <<"urn:xmpp:forward:0">>). --define(NS_CLIENT_STATE, <<"urn:xmpp:csi:0">>). --define(NS_STREAM_MGMT_2, <<"urn:xmpp:sm:2">>). --define(NS_STREAM_MGMT_3, <<"urn:xmpp:sm:3">>). --define(NS_HTTP_UPLOAD, <<"urn:xmpp:http:upload">>). --define(NS_HTTP_UPLOAD_OLD, <<"eu:siacs:conversations:http:upload">>). --define(NS_THUMBS_1, <<"urn:xmpp:thumbs:1">>). --define(NS_NICK, <<"http://jabber.org/protocol/nick">>). --define(NS_SIC_0, <<"urn:xmpp:sic:0">>). --define(NS_SIC_1, <<"urn:xmpp:sic:1">>). --define(NS_MIX_0, <<"urn:xmpp:mix:0">>). --define(NS_MIX_SERVICEINFO_0, <<"urn:xmpp:mix:0#serviceinfo">>). --define(NS_MIX_NODES_MESSAGES, <<"urn:xmpp:mix:nodes:messages">>). --define(NS_MIX_NODES_PRESENCE, <<"urn:xmpp:mix:nodes:presence">>). --define(NS_MIX_NODES_PARTICIPANTS, <<"urn:xmpp:mix:nodes:participants">>). --define(NS_MIX_NODES_SUBJECT, <<"urn:xmpp:mix:nodes:subject">>). --define(NS_MIX_NODES_CONFIG, <<"urn:xmpp:mix:nodes:config">>). --define(NS_PRIVILEGE, <<"urn:xmpp:privilege:1">>). --define(NS_DELEGATION, <<"urn:xmpp:delegation:1">>). --define(NS_MUCSUB, <<"urn:xmpp:mucsub:0">>). --define(NS_MUCSUB_NODES_PRESENCE, <<"urn:xmpp:mucsub:nodes:presence">>). --define(NS_MUCSUB_NODES_MESSAGES, <<"urn:xmpp:mucsub:nodes:messages">>). --define(NS_MUCSUB_NODES_PARTICIPANTS, <<"urn:xmpp:mucsub:nodes:participants">>). --define(NS_MUCSUB_NODES_AFFILIATIONS, <<"urn:xmpp:mucsub:nodes:affiliations">>). --define(NS_MUCSUB_NODES_SUBJECT, <<"urn:xmpp:mucsub:nodes:subject">>). --define(NS_MUCSUB_NODES_CONFIG, <<"urn:xmpp:mucsub:nodes:config">>). --define(NS_MUCSUB_NODES_SYSTEM, <<"urn:xmpp:mucsub:nodes:system">>). diff --git a/include/pubsub_get_pending.hrl b/include/pubsub_get_pending.hrl deleted file mode 100644 index 4ddf9bad0..000000000 --- a/include/pubsub_get_pending.hrl +++ /dev/null @@ -1,13 +0,0 @@ -%% Created automatically by xdata generator (xdata_codec.erl) -%% Source: pubsub_get_pending.xdata -%% Form type: http://jabber.org/protocol/pubsub#subscribe_authorization -%% Document: XEP-0060 - - --type property() :: {'node', binary()}. --type result() :: [property()]. - --type options(T) :: [{binary(), T}]. --type property_with_options() :: - {'node', binary(), options(binary())}. --type form() :: [property() | property_with_options() | xdata_field()]. diff --git a/include/pubsub_node_config.hrl b/include/pubsub_node_config.hrl deleted file mode 100644 index e1519cdc0..000000000 --- a/include/pubsub_node_config.hrl +++ /dev/null @@ -1,60 +0,0 @@ -%% Created automatically by xdata generator (xdata_codec.erl) -%% Source: pubsub_node_config.xdata -%% Form type: http://jabber.org/protocol/pubsub#node_config -%% Document: XEP-0060 - --type 'access_model'() :: authorize | open | presence | roster | whitelist. --type 'children_association_policy'() :: all | owners | whitelist. --type 'itemreply'() :: owner | publisher | none. --type 'node_type'() :: leaf | collection. --type 'notification_type'() :: normal | headline. --type 'publish_model'() :: publishers | subscribers | open. --type 'send_last_published_item'() :: never | on_sub | on_sub_and_presence. - --type property() :: {'access_model', 'access_model'()} | - {'body_xslt', binary()} | - {'children_association_policy', 'children_association_policy'()} | - {'children_association_whitelist', [jid:jid()]} | - {'children', [binary()]} | - {'children_max', binary()} | - {'collection', [binary()]} | - {'contact', [jid:jid()]} | - {'dataform_xslt', binary()} | - {'deliver_notifications', boolean()} | - {'deliver_payloads', boolean()} | - {'description', binary()} | - {'item_expire', binary()} | - {'itemreply', 'itemreply'()} | - {'language', binary()} | - {'max_items', non_neg_integer()} | - {'max_payload_size', non_neg_integer()} | - {'node_type', 'node_type'()} | - {'notification_type', 'notification_type'()} | - {'notify_config', boolean()} | - {'notify_delete', boolean()} | - {'notify_retract', boolean()} | - {'notify_sub', boolean()} | - {'persist_items', boolean()} | - {'presence_based_delivery', boolean()} | - {'publish_model', 'publish_model'()} | - {'purge_offline', boolean()} | - {'roster_groups_allowed', [binary()]} | - {'send_last_published_item', 'send_last_published_item'()} | - {'tempsub', boolean()} | - {'subscribe', boolean()} | - {'title', binary()} | - {'type', binary()}. --type result() :: [property()]. - --type options(T) :: [{binary(), T}]. --type property_with_options() :: - {'access_model', 'access_model'(), options('access_model'())} | - {'children_association_policy', 'children_association_policy'(), options('children_association_policy'())} | - {'itemreply', 'itemreply'(), options('itemreply'())} | - {'language', binary(), options(binary())} | - {'node_type', 'node_type'(), options('node_type'())} | - {'notification_type', 'notification_type'(), options('notification_type'())} | - {'publish_model', 'publish_model'(), options('publish_model'())} | - {'roster_groups_allowed', [binary()], options(binary())} | - {'send_last_published_item', 'send_last_published_item'(), options('send_last_published_item'())}. --type form() :: [property() | property_with_options() | xdata_field()]. diff --git a/include/pubsub_publish_options.hrl b/include/pubsub_publish_options.hrl deleted file mode 100644 index 3b04b4826..000000000 --- a/include/pubsub_publish_options.hrl +++ /dev/null @@ -1,14 +0,0 @@ -%% Created automatically by xdata generator (xdata_codec.erl) -%% Source: pubsub_publish_options.xdata -%% Form type: http://jabber.org/protocol/pubsub#publish-options -%% Document: XEP-0060 - --type 'access_model'() :: authorize | open | presence | roster | whitelist. - --type property() :: {'access_model', 'access_model'()}. --type result() :: [property()]. - --type options(T) :: [{binary(), T}]. --type property_with_options() :: - {'access_model', 'access_model'(), options('access_model'())}. --type form() :: [property() | property_with_options() | xdata_field()]. diff --git a/include/pubsub_subscribe_authorization.hrl b/include/pubsub_subscribe_authorization.hrl deleted file mode 100644 index fb67ab47a..000000000 --- a/include/pubsub_subscribe_authorization.hrl +++ /dev/null @@ -1,13 +0,0 @@ -%% Created automatically by xdata generator (xdata_codec.erl) -%% Source: pubsub_subscribe_authorization.xdata -%% Form type: http://jabber.org/protocol/pubsub#subscribe_authorization -%% Document: XEP-0060 - - --type property() :: {'allow', boolean()} | - {'node', binary()} | - {'subscriber_jid', jid:jid()} | - {'subid', binary()}. --type result() :: [property()]. - --type form() :: [property() | xdata_field()]. diff --git a/include/pubsub_subscribe_options.hrl b/include/pubsub_subscribe_options.hrl deleted file mode 100644 index 9a05822a5..000000000 --- a/include/pubsub_subscribe_options.hrl +++ /dev/null @@ -1,25 +0,0 @@ -%% Created automatically by xdata generator (xdata_codec.erl) -%% Source: pubsub_subscribe_options.xdata -%% Form type: http://jabber.org/protocol/pubsub#subscribe_options -%% Document: XEP-0060 - --type 'show-values'() :: away | chat | dnd | online | xa. --type 'subscription_type'() :: items | nodes. --type 'subscription_depth'() :: 1 | all. - --type property() :: {'deliver', boolean()} | - {'digest', boolean()} | - {'digest_frequency', binary()} | - {'expire', binary()} | - {'include_body', boolean()} | - {'show-values', ['show-values'()]} | - {'subscription_type', 'subscription_type'()} | - {'subscription_depth', 'subscription_depth'()}. --type result() :: [property()]. - --type options(T) :: [{binary(), T}]. --type property_with_options() :: - {'show-values', ['show-values'()], options('show-values'())} | - {'subscription_type', 'subscription_type'(), options('subscription_type'())} | - {'subscription_depth', 'subscription_depth'(), options('subscription_depth'())}. --type form() :: [property() | property_with_options() | xdata_field()]. diff --git a/include/xmpp.hrl b/include/xmpp.hrl deleted file mode 100644 index f8a61590f..000000000 --- a/include/xmpp.hrl +++ /dev/null @@ -1,25 +0,0 @@ -%%%------------------------------------------------------------------- -%%% @author Evgeny Khramtsov -%%% @copyright (C) 2015, Evgeny Khramtsov -%%% @doc -%%% -%%% @end -%%% Created : 10 Dec 2015 by Evgeny Khramtsov -%%%------------------------------------------------------------------- --include("ns.hrl"). --include("jid.hrl"). --include("xmpp_codec.hrl"). --include("fxml.hrl"). - --type iq_type() :: get | set | result | error. --type message_type() :: chat | error | groupchat | headline | normal. --type presence_type() :: available | error | probe | subscribe | - subscribed | unavailable | unsubscribe | - unsubscribed. - --type stanza() :: iq() | presence() | message(). - --define(is_stanza(Pkt), - (is_record(Pkt, iq) or - is_record(Pkt, message) or - is_record(Pkt, presence))). diff --git a/include/xmpp_codec.hrl b/include/xmpp_codec.hrl deleted file mode 100644 index 03421d98d..000000000 --- a/include/xmpp_codec.hrl +++ /dev/null @@ -1,1092 +0,0 @@ -%% Created automatically by XML generator (fxml_gen.erl) -%% Source: xmpp_codec.spec - --record(vcard_xupdate, {us = {<<>>, <<>>} :: {binary(), binary()}, - hash :: binary()}). --type vcard_xupdate() :: #vcard_xupdate{}. - --record(ps_affiliation, {xmlns = <<>> :: binary(), - node = <<>> :: binary(), - type :: member | none | outcast | - owner | publisher | publish_only, - jid :: jid:jid()}). --type ps_affiliation() :: #ps_affiliation{}. - --type ps_error_type() :: 'closed-node' | 'configuration-required' | - 'invalid-jid' | 'invalid-options' | - 'invalid-payload' | 'invalid-subid' | - 'item-forbidden' | 'item-required' | 'jid-required' | - 'max-items-exceeded' | 'max-nodes-exceeded' | - 'nodeid-required' | 'not-in-roster-group' | - 'not-subscribed' | 'payload-too-big' | - 'payload-required' | 'pending-subscription' | - 'presence-subscription-required' | 'subid-required' | - 'too-many-subscriptions' | 'unsupported' | - 'unsupported-access-model'. --type ps_feature() :: 'access-authorize' | 'access-open' | - 'access-presence' | 'access-roster' | - 'access-whitelist' | 'auto-create' | - 'auto-subscribe' | 'collections' | 'config-node' | - 'create-and-configure' | 'create-nodes' | - 'delete-items' | 'delete-nodes' | - 'filtered-notifications' | 'get-pending' | - 'instant-nodes' | 'item-ids' | 'last-published' | - 'leased-subscription' | 'manage-subscriptions' | - 'member-affiliation' | 'meta-data' | - 'modify-affiliations' | 'multi-collection' | - 'multi-subscribe' | 'outcast-affiliation' | - 'persistent-items' | 'presence-notifications' | - 'presence-subscribe' | 'publish' | - 'publish-options' | 'publish-only-affiliation' | - 'publisher-affiliation' | 'purge-nodes' | - 'retract-items' | 'retrieve-affiliations' | - 'retrieve-default' | 'retrieve-items' | - 'retrieve-subscriptions' | 'subscribe' | - 'subscription-options' | 'subscription-notifications'. --record(ps_error, {type :: ps_error_type(), feature :: ps_feature()}). --type ps_error() :: #ps_error{}. - --record(chatstate, {type :: active | composing | gone | inactive | paused}). --type chatstate() :: #chatstate{}. - --record(csi, {type :: active | inactive}). --type csi() :: #csi{}. - --record(hint, {type :: 'no-copy' | 'no-store' | 'no-storage' | 'store' | - 'no-permanent-store' | 'no-permanent-storage'}). --type hint() :: #hint{}. - --record(iq, {id = <<>> :: binary(), - type :: 'error' | 'get' | 'result' | 'set', - lang = <<>> :: binary(), - from :: jid:jid(), - to :: jid:jid(), - sub_els = [] :: [xmpp_element() | fxml:xmlel()]}). --type iq() :: #iq{}. - --record(feature_register, {}). --type feature_register() :: #feature_register{}. - --record(adhoc_note, {type = info :: 'error' | 'info' | 'warn', - data = <<>> :: binary()}). --type adhoc_note() :: #adhoc_note{}. - --record(address, {type :: 'bcc' | 'cc' | 'noreply' | 'ofrom' | 'replyroom' | 'replyto' | 'to', - jid :: jid:jid(), - desc = <<>> :: binary(), - node = <<>> :: binary(), - delivered :: boolean()}). --type address() :: #address{}. - --record(sasl_success, {text = <<>> :: binary()}). --type sasl_success() :: #sasl_success{}. - --record(mam_result, {xmlns = <<>> :: binary(), - queryid = <<>> :: binary(), - id = <<>> :: binary(), - sub_els = [] :: [xmpp_element() | fxml:xmlel()]}). --type mam_result() :: #mam_result{}. - --record(rsm_first, {index :: non_neg_integer(), - data = <<>> :: binary()}). --type rsm_first() :: #rsm_first{}. - --record(text, {lang = <<>> :: binary(), - data = <<>> :: binary()}). --type text() :: #text{}. - --record(streamhost, {jid :: jid:jid(), - host = <<>> :: binary(), - port = 1080 :: non_neg_integer()}). --type streamhost() :: #streamhost{}. - --record(sm_resume, {h :: non_neg_integer(), - previd = <<>> :: binary(), - xmlns = <<>> :: binary()}). --type sm_resume() :: #sm_resume{}. - --record(carbons_enable, {}). --type carbons_enable() :: #carbons_enable{}. - --record(carbons_private, {}). --type carbons_private() :: #carbons_private{}. - --record(expire, {seconds :: non_neg_integer(), - stored :: non_neg_integer()}). --type expire() :: #expire{}. - --record(muc_unsubscribe, {}). --type muc_unsubscribe() :: #muc_unsubscribe{}. - --record(ps_unsubscribe, {node = <<>> :: binary(), - jid :: jid:jid(), - subid = <<>> :: binary()}). --type ps_unsubscribe() :: #ps_unsubscribe{}. - --record(mix_leave, {}). --type mix_leave() :: #mix_leave{}. - --record(ping, {}). --type ping() :: #ping{}. - --record(delay, {stamp :: erlang:timestamp(), - from :: jid:jid(), - desc = <<>> :: binary()}). --type delay() :: #delay{}. - --record(muc_history, {maxchars :: non_neg_integer(), - maxstanzas :: non_neg_integer(), - seconds :: non_neg_integer(), - since :: erlang:timestamp()}). --type muc_history() :: #muc_history{}. - --record(thumbnail, {uri = <<>> :: binary(), - 'media-type' = <<>> :: binary(), - width :: non_neg_integer(), - height :: non_neg_integer()}). --type thumbnail() :: #thumbnail{}. - --record(privilege_perm, {access :: 'message' | 'presence' | 'roster', - type :: 'both' | 'get' | 'managed_entity' | 'none' | 'outgoing' | 'roster' | 'set'}). --type privilege_perm() :: #privilege_perm{}. - --record(muc_decline, {reason = <<>> :: binary(), - from :: jid:jid(), - to :: jid:jid()}). --type muc_decline() :: #muc_decline{}. - --record(sm_a, {h :: non_neg_integer(), - xmlns = <<>> :: binary()}). --type sm_a() :: #sm_a{}. - --record(stream_start, {from :: jid:jid(), - to :: jid:jid(), - id = <<>> :: binary(), - version :: {non_neg_integer(),non_neg_integer()}, - xmlns = <<>> :: binary(), - stream_xmlns = <<>> :: binary(), - db_xmlns = <<>> :: binary(), - lang = <<>> :: binary()}). --type stream_start() :: #stream_start{}. - --record(muc_subscribe, {nick = <<>> :: binary(), - events = [] :: [binary()]}). --type muc_subscribe() :: #muc_subscribe{}. - --record(stanza_id, {by :: jid:jid(), - id = <<>> :: binary()}). --type stanza_id() :: #stanza_id{}. - --record(starttls_proceed, {}). --type starttls_proceed() :: #starttls_proceed{}. - --record(forwarded, {delay :: #delay{}, - xml_els = [] :: [fxml:xmlel()]}). --type forwarded() :: #forwarded{}. - --record(privilege, {perms = [] :: [#privilege_perm{}], - forwarded :: #forwarded{}}). --type privilege() :: #privilege{}. - --record(client_id, {id = <<>> :: binary()}). --type client_id() :: #client_id{}. - --record(sm_resumed, {h :: non_neg_integer(), - previd = <<>> :: binary(), - xmlns = <<>> :: binary()}). --type sm_resumed() :: #sm_resumed{}. - --record(sm_enable, {max :: non_neg_integer(), - resume = false :: boolean(), - xmlns = <<>> :: binary()}). --type sm_enable() :: #sm_enable{}. - --record(starttls_failure, {}). --type starttls_failure() :: #starttls_failure{}. - --record(sasl_challenge, {text = <<>> :: binary()}). --type sasl_challenge() :: #sasl_challenge{}. - --record(handshake, {data = <<>> :: binary()}). --type handshake() :: #handshake{}. - --record(gone, {uri = <<>> :: binary()}). --type gone() :: #gone{}. - --record(x_conference, {jid :: jid:jid(), - password = <<>> :: binary(), - reason = <<>> :: binary(), - continue :: boolean(), - thread = <<>> :: binary()}). --type x_conference() :: #x_conference{}. - --record(private, {xml_els = [] :: [fxml:xmlel()]}). --type private() :: #private{}. - --record(delegation_query, {to :: jid:jid(), - delegate = [] :: [binary()]}). --type delegation_query() :: #delegation_query{}. - --record(db_verify, {from = <<>> :: binary(), - to = <<>> :: binary(), - id = <<>> :: binary(), - type :: 'error' | 'invalid' | 'valid', - key = <<>> :: binary(), - sub_els = [] :: [xmpp_element() | fxml:xmlel()]}). --type db_verify() :: #db_verify{}. - --record(nick, {name = <<>> :: binary()}). --type nick() :: #nick{}. - --record(p1_ack, {}). --type p1_ack() :: #p1_ack{}. - --record(feature_sm, {xmlns = <<>> :: binary()}). --type feature_sm() :: #feature_sm{}. - --record(ps_item, {xmlns = <<>> :: binary(), - id = <<>> :: binary(), - xml_els = [] :: [fxml:xmlel()], - node = <<>> :: binary(), - publisher = <<>> :: binary()}). --type ps_item() :: #ps_item{}. - --record(ps_publish, {node = <<>> :: binary(), - items = [] :: [#ps_item{}]}). --type ps_publish() :: #ps_publish{}. - --record(roster_item, {jid :: jid:jid(), - name = <<>> :: binary(), - groups = [] :: [binary()], - subscription = none :: 'both' | 'from' | 'none' | 'remove' | 'to', - ask :: 'subscribe'}). --type roster_item() :: #roster_item{}. - --record(roster_query, {items = [] :: [#roster_item{}], - ver :: binary()}). --type roster_query() :: #roster_query{}. - --record(sm_r, {xmlns = <<>> :: binary()}). --type sm_r() :: #sm_r{}. - --record(muc_actor, {jid :: jid:jid(), - nick = <<>> :: binary()}). --type muc_actor() :: #muc_actor{}. - --record(stat_error, {code :: integer(), - reason = <<>> :: binary()}). --type stat_error() :: #stat_error{}. - --record(stat, {name = <<>> :: binary(), - units = <<>> :: binary(), - value = <<>> :: binary(), - error :: #stat_error{}}). --type stat() :: #stat{}. - --record(addresses, {list = [] :: [#address{}]}). --type addresses() :: #addresses{}. - --record('see-other-host', {host :: binary() | inet:ip_address() | {binary() | inet:ip_address(),non_neg_integer()}}). --type 'see-other-host'() :: #'see-other-host'{}. - --record(compress, {methods = [] :: [binary()]}). --type compress() :: #compress{}. - --record(starttls, {required = false :: boolean()}). --type starttls() :: #starttls{}. - --record(last, {seconds :: non_neg_integer(), - status = <<>> :: binary()}). --type last() :: #last{}. - --record(redirect, {uri = <<>> :: binary()}). --type redirect() :: #redirect{}. - --record(sm_enabled, {id = <<>> :: binary(), - location = <<>> :: binary(), - max :: non_neg_integer(), - resume = false :: boolean(), - xmlns = <<>> :: binary()}). --type sm_enabled() :: #sm_enabled{}. - --record(muc_unique, {name = <<>> :: binary()}). --type muc_unique() :: #muc_unique{}. - --record(sasl_response, {text = <<>> :: binary()}). --type sasl_response() :: #sasl_response{}. - --record(legacy_auth, {username :: binary(), - password :: binary(), - digest :: binary(), - resource :: binary()}). --type legacy_auth() :: #legacy_auth{}. - --record(ps_subscribe, {node = <<>> :: binary(), - jid :: jid:jid()}). --type ps_subscribe() :: #ps_subscribe{}. - --record(message, {id = <<>> :: binary(), - type = normal :: 'chat' | 'error' | 'groupchat' | 'headline' | 'normal', - lang = <<>> :: binary(), - from :: jid:jid(), - to :: jid:jid(), - subject = [] :: [#text{}], - body = [] :: [#text{}], - thread :: binary(), - sub_els = [] :: [xmpp_element() | fxml:xmlel()]}). --type message() :: #message{}. - --record(sasl_auth, {mechanism = <<>> :: binary(), - text = <<>> :: binary()}). --type sasl_auth() :: #sasl_auth{}. - --record(p1_push, {}). --type p1_push() :: #p1_push{}. - --record(feature_csi, {xmlns = <<>> :: binary()}). --type feature_csi() :: #feature_csi{}. - --record(disco_item, {jid :: jid:jid(), - name = <<>> :: binary(), - node = <<>> :: binary()}). --type disco_item() :: #disco_item{}. - --record(unblock, {items = [] :: [jid:jid()]}). --type unblock() :: #unblock{}. - --record(block, {items = [] :: [jid:jid()]}). --type block() :: #block{}. - --record(compression, {methods = [] :: [binary()]}). --type compression() :: #compression{}. - --record(muc_subscriptions, {list = [] :: [jid:jid()]}). --type muc_subscriptions() :: #muc_subscriptions{}. - --record(ps_subscription, {xmlns = <<>> :: binary(), - jid :: jid:jid(), - type :: 'none' | 'pending' | 'subscribed' | 'unconfigured', - node = <<>> :: binary(), - subid = <<>> :: binary(), - expiry :: erlang:timestamp()}). --type ps_subscription() :: #ps_subscription{}. - --record(bob_data, {cid = <<>> :: binary(), - 'max-age' :: non_neg_integer(), - type = <<>> :: binary(), - data = <<>> :: binary()}). --type bob_data() :: #bob_data{}. - --record(muc_item, {actor :: #muc_actor{}, - continue :: binary(), - reason = <<>> :: binary(), - affiliation :: 'admin' | 'member' | 'none' | 'outcast' | 'owner', - role :: 'moderator' | 'none' | 'participant' | 'visitor', - jid :: jid:jid(), - nick = <<>> :: binary()}). --type muc_item() :: #muc_item{}. - --record(muc_admin, {items = [] :: [#muc_item{}]}). --type muc_admin() :: #muc_admin{}. - --record(shim, {headers = [] :: [{binary(),binary()}]}). --type shim() :: #shim{}. - --record(mam_prefs, {xmlns = <<>> :: binary(), - default :: 'always' | 'never' | 'roster', - always :: [jid:jid()], - never :: [jid:jid()]}). --type mam_prefs() :: #mam_prefs{}. - --record(caps, {node = <<>> :: binary(), - version = <<>> :: binary(), - hash = <<>> :: binary(), - exts = [] :: [binary()]}). --type caps() :: #caps{}. - --record(muc, {history :: #muc_history{}, - password :: binary()}). --type muc() :: #muc{}. - --record(stream_features, {sub_els = [] :: [xmpp_element() | fxml:xmlel()]}). --type stream_features() :: #stream_features{}. - --record(stats, {list = [] :: [#stat{}], - node = <<>> :: binary()}). --type stats() :: #stats{}. - --record(ps_items, {xmlns = <<>> :: binary(), - node = <<>> :: binary(), - items = [] :: [#ps_item{}], - max_items :: non_neg_integer(), - subid = <<>> :: binary(), - retract :: binary()}). --type ps_items() :: #ps_items{}. - --record(presence, {id = <<>> :: binary(), - type = available :: 'available' | 'error' | 'probe' | 'subscribe' | 'subscribed' | 'unavailable' | 'unsubscribe' | 'unsubscribed', - lang = <<>> :: binary(), - from :: jid:jid(), - to :: jid:jid(), - show :: 'away' | 'chat' | 'dnd' | 'xa', - status = [] :: [#text{}], - priority :: integer(), - sub_els = [] :: [xmpp_element() | fxml:xmlel()]}). --type presence() :: #presence{}. - --record(sic, {ip :: inet:ip_address(), - port :: non_neg_integer(), - xmlns = <<>> :: binary()}). --type sic() :: #sic{}. - --record(carbons_sent, {forwarded :: #forwarded{}}). --type carbons_sent() :: #carbons_sent{}. - --record(mam_archived, {by :: jid:jid(), - id = <<>> :: binary()}). --type mam_archived() :: #mam_archived{}. - --record(p1_rebind, {}). --type p1_rebind() :: #p1_rebind{}. - --record(compress_failure, {reason :: 'processing-failed' | 'setup-failed' | 'unsupported-method'}). --type compress_failure() :: #compress_failure{}. - --record(sasl_abort, {}). --type sasl_abort() :: #sasl_abort{}. - --record(xevent, {offline = false :: boolean(), - delivered = false :: boolean(), - displayed = false :: boolean(), - composing = false :: boolean(), - id :: binary()}). --type xevent() :: #xevent{}. - --record(vcard_email, {home = false :: boolean(), - work = false :: boolean(), - internet = false :: boolean(), - pref = false :: boolean(), - x400 = false :: boolean(), - userid :: binary()}). --type vcard_email() :: #vcard_email{}. - --record(db_result, {from = <<>> :: binary(), - to = <<>> :: binary(), - type :: 'error' | 'invalid' | 'valid', - key = <<>> :: binary(), - sub_els = [] :: [xmpp_element() | fxml:xmlel()]}). --type db_result() :: #db_result{}. - --record(carbons_received, {forwarded :: #forwarded{}}). --type carbons_received() :: #carbons_received{}. - --record(ps_retract, {node = <<>> :: binary(), - notify = false :: boolean(), - items = [] :: [#ps_item{}]}). --type ps_retract() :: #ps_retract{}. - --record(upload_slot, {get :: binary(), - put :: binary(), - xmlns = <<>> :: binary()}). --type upload_slot() :: #upload_slot{}. - --record(mix_participant, {jid :: jid:jid(), - nick = <<>> :: binary()}). --type mix_participant() :: #mix_participant{}. - --record(vcard_geo, {lat :: binary(), - lon :: binary()}). --type vcard_geo() :: #vcard_geo{}. - --record(compressed, {}). --type compressed() :: #compressed{}. - --record(sasl_failure, {reason :: 'aborted' | 'account-disabled' | 'bad-protocol' | 'credentials-expired' | 'encryption-required' | 'incorrect-encoding' | 'invalid-authzid' | 'invalid-mechanism' | 'malformed-request' | 'mechanism-too-weak' | 'not-authorized' | 'temporary-auth-failure', - text = [] :: [#text{}]}). --type sasl_failure() :: #sasl_failure{}. - --record(block_list, {items = [] :: [jid:jid()]}). --type block_list() :: #block_list{}. - --record(upload_request, {filename :: binary(), - size :: non_neg_integer(), - 'content-type' = <<>> :: binary(), - xmlns = <<>> :: binary()}). --type upload_request() :: #upload_request{}. - --record(xdata_option, {label = <<>> :: binary(), - value :: binary()}). --type xdata_option() :: #xdata_option{}. - --record(xdata_field, {label = <<>> :: binary(), - type :: 'boolean' | 'fixed' | 'hidden' | 'jid-multi' | 'jid-single' | 'list-multi' | 'list-single' | 'text-multi' | 'text-private' | 'text-single', - var = <<>> :: binary(), - required = false :: boolean(), - desc = <<>> :: binary(), - values = [] :: [binary()], - options = [] :: [#xdata_option{}], - sub_els = [] :: [xmpp_element() | fxml:xmlel()]}). --type xdata_field() :: #xdata_field{}. - --record(version, {name :: binary(), - ver :: binary(), - os :: binary()}). --type version() :: #version{}. - --record(bind, {jid :: jid:jid(), - resource = <<>> :: binary()}). --type bind() :: #bind{}. - --record(rosterver_feature, {}). --type rosterver_feature() :: #rosterver_feature{}. - --record(muc_invite, {reason = <<>> :: binary(), - from :: jid:jid(), - to :: jid:jid(), - continue :: binary()}). --type muc_invite() :: #muc_invite{}. - --record(delegated, {ns = <<>> :: binary(), - attrs = [] :: [binary()]}). --type delegated() :: #delegated{}. - --record(carbons_disable, {}). --type carbons_disable() :: #carbons_disable{}. - --record(bytestreams, {hosts = [] :: [#streamhost{}], - used :: jid:jid(), - activate :: jid:jid(), - dstaddr = <<>> :: binary(), - mode = tcp :: 'tcp' | 'udp', - sid = <<>> :: binary()}). --type bytestreams() :: #bytestreams{}. - --record(adhoc_actions, {execute :: 'complete' | 'next' | 'prev', - prev = false :: boolean(), - next = false :: boolean(), - complete = false :: boolean()}). --type adhoc_actions() :: #adhoc_actions{}. - --record(vcard_org, {name :: binary(), - units = [] :: [binary()]}). --type vcard_org() :: #vcard_org{}. - --record(rsm_set, {'after' :: binary(), - before :: binary(), - count :: non_neg_integer(), - first :: #rsm_first{}, - index :: non_neg_integer(), - last :: binary(), - max :: non_neg_integer()}). --type rsm_set() :: #rsm_set{}. - --record(mam_fin, {xmlns = <<>> :: binary(), - id = <<>> :: binary(), - rsm :: #rsm_set{}, - stable :: boolean(), - complete :: boolean()}). --type mam_fin() :: #mam_fin{}. - --record(disco_items, {node = <<>> :: binary(), - items = [] :: [#disco_item{}], - rsm :: #rsm_set{}}). --type disco_items() :: #disco_items{}. - --record(vcard_tel, {home = false :: boolean(), - work = false :: boolean(), - voice = false :: boolean(), - fax = false :: boolean(), - pager = false :: boolean(), - msg = false :: boolean(), - cell = false :: boolean(), - video = false :: boolean(), - bbs = false :: boolean(), - modem = false :: boolean(), - isdn = false :: boolean(), - pcs = false :: boolean(), - pref = false :: boolean(), - number :: binary()}). --type vcard_tel() :: #vcard_tel{}. - --record(media_uri, {type = <<>> :: binary(), - uri = <<>> :: binary()}). --type media_uri() :: #media_uri{}. - --record(media, {height :: non_neg_integer(), - width :: non_neg_integer(), - uri = [] :: [#media_uri{}]}). --type media() :: #media{}. - --record(muc_destroy, {xmlns = <<>> :: binary(), - jid :: jid:jid(), - reason = <<>> :: binary(), - password :: binary()}). --type muc_destroy() :: #muc_destroy{}. - --record(muc_user, {decline :: #muc_decline{}, - destroy :: #muc_destroy{}, - invites = [] :: [#muc_invite{}], - items = [] :: [#muc_item{}], - status_codes = [] :: [pos_integer()], - password :: binary()}). --type muc_user() :: #muc_user{}. - --record(vcard_key, {type :: binary(), - cred :: binary()}). --type vcard_key() :: #vcard_key{}. - --record(vcard_name, {family :: binary(), - given :: binary(), - middle :: binary(), - prefix :: binary(), - suffix :: binary()}). --type vcard_name() :: #vcard_name{}. - --record(identity, {category = <<>> :: binary(), - type = <<>> :: binary(), - lang = <<>> :: binary(), - name = <<>> :: binary()}). --type identity() :: #identity{}. - --record(bookmark_conference, {name = <<>> :: binary(), - jid :: jid:jid(), - autojoin = false :: boolean(), - nick :: binary(), - password :: binary()}). --type bookmark_conference() :: #bookmark_conference{}. - --record(xmpp_session, {optional = false :: boolean()}). --type xmpp_session() :: #xmpp_session{}. - --record(bookmark_url, {name = <<>> :: binary(), - url = <<>> :: binary()}). --type bookmark_url() :: #bookmark_url{}. - --record(bookmark_storage, {conference = [] :: [#bookmark_conference{}], - url = [] :: [#bookmark_url{}]}). --type bookmark_storage() :: #bookmark_storage{}. - --record(oob_x, {url :: binary(), - desc = <<>> :: binary(), - sid = <<>> :: binary()}). --type oob_x() :: #oob_x{}. - --record(vcard_sound, {phonetic :: binary(), - binval :: binary(), - extval :: binary()}). --type vcard_sound() :: #vcard_sound{}. - --record(vcard_photo, {type :: binary(), - binval :: binary(), - extval :: binary()}). --type vcard_photo() :: #vcard_photo{}. - --record(vcard_label, {home = false :: boolean(), - work = false :: boolean(), - postal = false :: boolean(), - parcel = false :: boolean(), - dom = false :: boolean(), - intl = false :: boolean(), - pref = false :: boolean(), - line = [] :: [binary()]}). --type vcard_label() :: #vcard_label{}. - --record(vcard_adr, {home = false :: boolean(), - work = false :: boolean(), - postal = false :: boolean(), - parcel = false :: boolean(), - dom = false :: boolean(), - intl = false :: boolean(), - pref = false :: boolean(), - pobox :: binary(), - extadd :: binary(), - street :: binary(), - locality :: binary(), - region :: binary(), - pcode :: binary(), - ctry :: binary()}). --type vcard_adr() :: #vcard_adr{}. - --record(search_item, {jid :: jid:jid(), - first :: binary(), - last :: binary(), - nick :: binary(), - email :: binary()}). --type search_item() :: #search_item{}. - --record(xdata, {type :: 'cancel' | 'form' | 'result' | 'submit', - instructions = [] :: [binary()], - title :: binary(), - reported :: [#xdata_field{}], - items = [] :: [[#xdata_field{}]], - fields = [] :: [#xdata_field{}]}). --type xdata() :: #xdata{}. - --record(xcaptcha, {xdata :: #xdata{}}). --type xcaptcha() :: #xcaptcha{}. - --record(adhoc_command, {node = <<>> :: binary(), - action = execute :: 'cancel' | 'complete' | 'execute' | 'next' | 'prev', - sid = <<>> :: binary(), - status :: 'canceled' | 'completed' | 'executing', - lang = <<>> :: binary(), - actions :: #adhoc_actions{}, - notes = [] :: [#adhoc_note{}], - xdata :: #xdata{}}). --type adhoc_command() :: #adhoc_command{}. - --record(search, {instructions :: binary(), - first :: binary(), - last :: binary(), - nick :: binary(), - email :: binary(), - items = [] :: [#search_item{}], - xdata :: #xdata{}}). --type search() :: #search{}. - --record(mam_query, {xmlns = <<>> :: binary(), - id = <<>> :: binary(), - start :: erlang:timestamp(), - 'end' :: erlang:timestamp(), - with :: jid:jid(), - withtext :: binary(), - rsm :: #rsm_set{}, - xdata :: #xdata{}}). --type mam_query() :: #mam_query{}. - --record(pubsub_owner, {affiliations :: {binary(),[#ps_affiliation{}]}, - configure :: {binary(),'undefined' | #xdata{}}, - default :: {binary(),'undefined' | #xdata{}}, - delete :: {binary(),binary()}, - purge :: binary(), - subscriptions :: {binary(),[#ps_subscription{}]}}). --type pubsub_owner() :: #pubsub_owner{}. - --record(ps_options, {node = <<>> :: binary(), - jid :: jid:jid(), - subid = <<>> :: binary(), - xdata :: #xdata{}}). --type ps_options() :: #ps_options{}. - --record(pubsub, {subscriptions :: {binary(),[#ps_subscription{}]}, - subscription :: #ps_subscription{}, - affiliations :: {binary(),[#ps_affiliation{}]}, - publish :: #ps_publish{}, - publish_options :: #xdata{}, - subscribe :: #ps_subscribe{}, - unsubscribe :: #ps_unsubscribe{}, - options :: #ps_options{}, - items :: #ps_items{}, - retract :: #ps_retract{}, - create :: binary(), - configure :: {binary(),'undefined' | #xdata{}}, - default :: {binary(),'undefined' | #xdata{}}, - delete :: {binary(),binary()}, - purge :: binary(), - rsm :: #rsm_set{}}). --type pubsub() :: #pubsub{}. - --record(ps_event, {items :: #ps_items{}, - purge :: binary(), - subscription :: #ps_subscription{}, - delete :: {binary(),binary()}, - create :: binary(), - configuration :: {binary(),'undefined' | #xdata{}}}). --type ps_event() :: #ps_event{}. - --record(register, {registered = false :: boolean(), - remove = false :: boolean(), - instructions :: binary(), - username :: binary(), - nick :: binary(), - password :: binary(), - name :: binary(), - first :: binary(), - last :: binary(), - email :: binary(), - address :: binary(), - city :: binary(), - state :: binary(), - zip :: binary(), - phone :: binary(), - url :: binary(), - date :: binary(), - misc :: binary(), - text :: binary(), - key :: binary(), - xdata :: #xdata{}, - sub_els = [] :: [xmpp_element() | fxml:xmlel()]}). --type register() :: #register{}. - --record(disco_info, {node = <<>> :: binary(), - identities = [] :: [#identity{}], - features = [] :: [binary()], - xdata = [] :: [#xdata{}]}). --type disco_info() :: #disco_info{}. - --record(offline_item, {node = <<>> :: binary(), - action :: 'remove' | 'view'}). --type offline_item() :: #offline_item{}. - --record(offline, {items = [] :: [#offline_item{}], - purge = false :: boolean(), - fetch = false :: boolean()}). --type offline() :: #offline{}. - --record(muc_owner, {destroy :: #muc_destroy{}, - config :: #xdata{}, - items = [] :: [#muc_item{}]}). --type muc_owner() :: #muc_owner{}. - --record(sasl_mechanisms, {list = [] :: [binary()]}). --type sasl_mechanisms() :: #sasl_mechanisms{}. - --record(sm_failed, {reason :: atom() | #gone{} | #redirect{}, - h :: non_neg_integer(), - xmlns = <<>> :: binary()}). --type sm_failed() :: #sm_failed{}. - --record(stanza_error, {type :: 'auth' | 'cancel' | 'continue' | 'modify' | 'wait', - code :: non_neg_integer(), - by = <<>> :: binary(), - reason :: atom() | #gone{} | #redirect{}, - text :: #text{}, - sub_els = [] :: [xmpp_element() | fxml:xmlel()]}). --type stanza_error() :: #stanza_error{}. - --record(delegation, {delegated = [] :: [#delegated{}], - forwarded :: #forwarded{}}). --type delegation() :: #delegation{}. - --record(mix_join, {jid :: jid:jid(), - subscribe = [] :: [binary()]}). --type mix_join() :: #mix_join{}. - --record(privacy_item, {order :: non_neg_integer(), - action :: 'allow' | 'deny', - type :: 'group' | 'jid' | 'subscription', - value = <<>> :: binary(), - message = false :: boolean(), - iq = false :: boolean(), - presence_in = false :: boolean(), - presence_out = false :: boolean()}). --type privacy_item() :: #privacy_item{}. - --record(privacy_list, {name = <<>> :: binary(), - items = [] :: [#privacy_item{}]}). --type privacy_list() :: #privacy_list{}. - --record(privacy_query, {lists = [] :: [#privacy_list{}], - default :: 'none' | binary(), - active :: 'none' | binary()}). --type privacy_query() :: #privacy_query{}. - --record(stream_error, {reason :: atom() | #'see-other-host'{}, - text :: #text{}}). --type stream_error() :: #stream_error{}. - --record(vcard_logo, {type :: binary(), - binval :: binary(), - extval :: binary()}). --type vcard_logo() :: #vcard_logo{}. - --record(vcard_temp, {version :: binary(), - fn :: binary(), - n :: #vcard_name{}, - nickname :: binary(), - photo :: #vcard_photo{}, - bday :: binary(), - adr = [] :: [#vcard_adr{}], - label = [] :: [#vcard_label{}], - tel = [] :: [#vcard_tel{}], - email = [] :: [#vcard_email{}], - jabberid :: binary(), - mailer :: binary(), - tz :: binary(), - geo :: #vcard_geo{}, - title :: binary(), - role :: binary(), - logo :: #vcard_logo{}, - org :: #vcard_org{}, - categories = [] :: [binary()], - note :: binary(), - prodid :: binary(), - rev :: binary(), - sort_string :: binary(), - sound :: #vcard_sound{}, - uid :: binary(), - url :: binary(), - class :: 'confidential' | 'private' | 'public', - key :: #vcard_key{}, - desc :: binary()}). --type vcard_temp() :: #vcard_temp{}. - --record(time, {tzo :: {integer(),integer()}, - utc :: erlang:timestamp()}). --type time() :: #time{}. - --type xmpp_element() :: compression() | - ps_subscription() | - xdata_option() | - version() | - sm_a() | - bob_data() | - media() | - stanza_id() | - starttls_proceed() | - forwarded() | - client_id() | - sm_resumed() | - xevent() | - privacy_list() | - carbons_sent() | - mam_archived() | - p1_rebind() | - sasl_abort() | - db_result() | - carbons_received() | - upload_slot() | - mix_participant() | - compressed() | - block_list() | - delegated() | - rsm_set() | - 'see-other-host'() | - hint() | - stream_start() | - text() | - vcard_org() | - shim() | - search_item() | - offline_item() | - feature_sm() | - roster_item() | - muc_item() | - vcard_temp() | - address() | - sasl_success() | - addresses() | - muc_subscriptions() | - disco_items() | - compress() | - bytestreams() | - adhoc_actions() | - privacy_query() | - muc_history() | - identity() | - feature_csi() | - delay() | - thumbnail() | - vcard_tel() | - vcard_geo() | - vcard_photo() | - pubsub_owner() | - pubsub() | - muc_owner() | - muc_actor() | - ps_error() | - starttls_failure() | - sasl_challenge() | - x_conference() | - private() | - sasl_failure() | - vcard_name() | - adhoc_note() | - rosterver_feature() | - muc_invite() | - vcard_xupdate() | - carbons_disable() | - bookmark_conference() | - offline() | - time() | - ps_subscribe() | - sm_enable() | - handshake() | - compress_failure() | - bookmark_storage() | - muc_decline() | - legacy_auth() | - search() | - ps_publish() | - nick() | - p1_ack() | - block() | - delegation() | - mix_join() | - xmpp_session() | - xdata() | - iq() | - xcaptcha() | - streamhost() | - bind() | - ps_retract() | - last() | - redirect() | - sm_enabled() | - vcard_sound() | - ps_event() | - mam_result() | - rsm_first() | - stat() | - upload_request() | - xdata_field() | - adhoc_command() | - sm_failed() | - ping() | - privilege_perm() | - privacy_item() | - disco_item() | - ps_item() | - mam_prefs() | - sasl_mechanisms() | - caps() | - muc() | - stream_features() | - stats() | - ps_items() | - sic() | - ps_options() | - starttls() | - db_verify() | - roster_query() | - media_uri() | - muc_destroy() | - vcard_key() | - csi() | - delegation_query() | - mam_query() | - bookmark_url() | - vcard_email() | - vcard_label() | - vcard_logo() | - disco_info() | - feature_register() | - register() | - sm_r() | - stat_error() | - stanza_error() | - stream_error() | - muc_user() | - vcard_adr() | - gone() | - carbons_private() | - mix_leave() | - muc_subscribe() | - privilege() | - muc_unique() | - sasl_response() | - message() | - presence() | - sm_resume() | - carbons_enable() | - expire() | - muc_unsubscribe() | - ps_unsubscribe() | - chatstate() | - sasl_auth() | - p1_push() | - oob_x() | - unblock() | - muc_admin() | - ps_affiliation() | - mam_fin(). diff --git a/rebar.config b/rebar.config index f9af6a568..0fa157e7a 100644 --- a/rebar.config +++ b/rebar.config @@ -13,6 +13,7 @@ {fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.7"}}}, {stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.6"}}}, {fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.16"}}}, + {xmpp, ".*", {git, "https://github.com/processone/xmpp", {tag, "1.0.2"}}}, {stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.7"}}}, {esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.8"}}}, {fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.6"}}}, @@ -55,6 +56,7 @@ luerl, stun, fast_yaml, + xmpp, p1_utils, p1_mysql, p1_pgsql, @@ -65,7 +67,9 @@ {erl_first_files, ["src/ejabberd_config.erl", "src/gen_mod.erl"]}. {erl_opts, [nowarn_deprecated_function, - {i, "include"}, {i, "deps/fast_xml/include"}, + {i, "include"}, + {i, "deps/fast_xml/include"}, + {i, "deps/xmpp/include"}, {if_var_false, debug, no_debug_info}, {if_var_true, debug, debug_info}, {if_var_true, roster_gateway_workaround, {d, 'ROSTER_GATWAY_WORKAROUND'}}, @@ -113,8 +117,10 @@ {if_var_false, elixir, "(\"Elixir.*\":_/_)"}, {if_var_false, redis, "(\"eredis\":_/_)"}]}. -{eunit_compile_opts, [{i, "tools"}, {i, "include"}, - {i, "deps/fast_xml/include"}]}. +{eunit_compile_opts, [{i, "tools"}, + {i, "include"}, + {i, "deps/fast_xml/include"}, + {i, "deps/xmpp/include"}]}. {if_version_above, "17", {cover_enabled, true}}. {cover_export_enabled, true}. diff --git a/specs/flex_offline.cfg b/specs/flex_offline.cfg deleted file mode 100644 index 5d5b2685e..000000000 --- a/specs/flex_offline.cfg +++ /dev/null @@ -1 +0,0 @@ -[{decode, [{<<"number_of_messages">>, {dec_int, [0, infinity]}}]}]. diff --git a/specs/flex_offline.xdata b/specs/flex_offline.xdata deleted file mode 100644 index d0c786289..000000000 --- a/specs/flex_offline.xdata +++ /dev/null @@ -1,12 +0,0 @@ - - http://jabber.org/protocol/offline - XEP-0013 - - Service Discovery extension for number of messages - in an offline message queue. - - - diff --git a/specs/mam_query.cfg b/specs/mam_query.cfg deleted file mode 100644 index a8921a52b..000000000 --- a/specs/mam_query.cfg +++ /dev/null @@ -1,9 +0,0 @@ -[{decode, [{<<"start">>, {xmpp_util, decode_timestamp, []}}, - {<<"end">>, {xmpp_util, decode_timestamp, []}}]}, - {specs, [{<<"start">>, "erlang:timestamp()"}, - {<<"end">>, "erlang:timestamp()"}]}]. - -%% Local Variables: -%% mode: erlang -%% End: -%% vim: set filetype=erlang tabstop=8: diff --git a/specs/mam_query.xdata b/specs/mam_query.xdata deleted file mode 100644 index 58fad41cd..000000000 --- a/specs/mam_query.xdata +++ /dev/null @@ -1,23 +0,0 @@ - - urn:xmpp:mam:1 - XEP-0313 - Form to query message archives - - - - - - - diff --git a/specs/muc_register.cfg b/specs/muc_register.cfg deleted file mode 100644 index 3efd0cf0b..000000000 --- a/specs/muc_register.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[{prefix, <<"muc#register_">>}, - {required, [<<"muc#register_roomnick">>]}]. diff --git a/specs/muc_register.xdata b/specs/muc_register.xdata deleted file mode 100644 index e808b44e0..000000000 --- a/specs/muc_register.xdata +++ /dev/null @@ -1,37 +0,0 @@ - - http://jabber.org/protocol/muc#register - XEP-0045 - - Forms enabling user registration with a - Multi-User Chat (MUC) room or admin approval - of user registration requests. - - - - - - - - - diff --git a/specs/muc_request.cfg b/specs/muc_request.cfg deleted file mode 100644 index 4811b32e2..000000000 --- a/specs/muc_request.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[{prefix, <<"muc#">>}, - {required, [<<"muc#role">>]}]. diff --git a/specs/muc_request.xdata b/specs/muc_request.xdata deleted file mode 100644 index 64fa1388b..000000000 --- a/specs/muc_request.xdata +++ /dev/null @@ -1,31 +0,0 @@ - - http://jabber.org/protocol/muc#request - XEP-0045 - - Forms enabling voice requests in a - Multi-User Chat (MUC) room or admin - approval of such requests. - - - - - - - - - - diff --git a/specs/muc_roomconfig.cfg b/specs/muc_roomconfig.cfg deleted file mode 100644 index de16099d5..000000000 --- a/specs/muc_roomconfig.cfg +++ /dev/null @@ -1,11 +0,0 @@ -[{prefix, <<"muc#roomconfig_">>}, - {prefix, <<"muc#">>}, - {decode, [{<<"muc#roomconfig_maxusers">>, - {dec_enum_int, [[none], 0, infinity]}}, - {<<"voice_request_min_interval">>, - {dec_int, [0, infinity]}}]}]. - -%% Local Variables: -%% mode: erlang -%% End: -%% vim: set filetype=erlang tabstop=8: diff --git a/specs/muc_roomconfig.xdata b/specs/muc_roomconfig.xdata deleted file mode 100644 index cab6465dc..000000000 --- a/specs/muc_roomconfig.xdata +++ /dev/null @@ -1,192 +0,0 @@ - - http://jabber.org/protocol/muc#roomconfig - XEP-0045 - - Forms enabling creation and configuration of - a Multi-User Chat (MUC) room. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/specs/muc_roominfo.cfg b/specs/muc_roominfo.cfg deleted file mode 100644 index 98a985e7b..000000000 --- a/specs/muc_roominfo.cfg +++ /dev/null @@ -1,11 +0,0 @@ -[{prefix, <<"muc#roominfo_">>}, - {prefix, <<"muc#">>}, - {decode, [{<<"muc#maxhistoryfetch">>, - {dec_int, [0, infinity]}}, - {<<"muc#roominfo_occupants">>, - {dec_int, [0, infinity]}}]}]. - -%% Local Variables: -%% mode: erlang -%% End: -%% vim: set filetype=erlang tabstop=8: diff --git a/specs/muc_roominfo.xdata b/specs/muc_roominfo.xdata deleted file mode 100644 index 70f696383..000000000 --- a/specs/muc_roominfo.xdata +++ /dev/null @@ -1,55 +0,0 @@ - - http://jabber.org/protocol/muc#roominfo - XEP-0045 - - Forms enabling the communication of extended service discovery - information about a Multi-User Chat (MUC) room. - - - - - - - - - - - - - diff --git a/specs/pubsub_get_pending.cfg b/specs/pubsub_get_pending.cfg deleted file mode 100644 index 4ae57ac88..000000000 --- a/specs/pubsub_get_pending.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[{prefix, <<"pubsub#">>}, - {required, [<<"pubsub#node">>]}]. - -%% Local Variables: -%% mode: erlang -%% End: -%% vim: set filetype=erlang tabstop=8: diff --git a/specs/pubsub_get_pending.xdata b/specs/pubsub_get_pending.xdata deleted file mode 100644 index 1a6f55297..000000000 --- a/specs/pubsub_get_pending.xdata +++ /dev/null @@ -1,15 +0,0 @@ - - http://jabber.org/protocol/pubsub#subscribe_authorization - XEP-0060 - Forms enabling authorization of subscriptions to pubsub nodes - - - - diff --git a/specs/pubsub_node_config.cfg b/specs/pubsub_node_config.cfg deleted file mode 100644 index f3bf72d2d..000000000 --- a/specs/pubsub_node_config.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[{prefix, <<"pubsub#">>}, - {decode, [{<<"pubsub#max_items">>, {dec_int, [0,infinity]}}, - {<<"pubsub#max_payload_size">>, {dec_int, [0,infinity]}}]}]. - -%% Local Variables: -%% mode: erlang -%% End: -%% vim: set filetype=erlang tabstop=8: diff --git a/specs/pubsub_node_config.xdata b/specs/pubsub_node_config.xdata deleted file mode 100644 index 1691808f7..000000000 --- a/specs/pubsub_node_config.xdata +++ /dev/null @@ -1,189 +0,0 @@ - - http://jabber.org/protocol/pubsub#node_config - XEP-0060 - Forms enabling configuration of pubsub nodes - - - - - - - - - - - - - - - - - - - - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1 - - - - - - diff --git a/specs/pubsub_publish_options.cfg b/specs/pubsub_publish_options.cfg deleted file mode 100644 index 2a853e834..000000000 --- a/specs/pubsub_publish_options.cfg +++ /dev/null @@ -1,6 +0,0 @@ -[{prefix, <<"pubsub#">>}]. - -%% Local Variables: -%% mode: erlang -%% End: -%% vim: set filetype=erlang tabstop=8: diff --git a/specs/pubsub_publish_options.xdata b/specs/pubsub_publish_options.xdata deleted file mode 100644 index 26cac6ad5..000000000 --- a/specs/pubsub_publish_options.xdata +++ /dev/null @@ -1,34 +0,0 @@ - - http://jabber.org/protocol/pubsub#publish-options - XEP-0060 - - Forms enabling publication with options; each field must specify whether it - defines METADATA to be attached to the item, a per-item OVERRIDE of the node - configuration, or a PRECONDITION to be checked against the node configuration. - - - - - - - - - - - diff --git a/specs/pubsub_subscribe_authorization.cfg b/specs/pubsub_subscribe_authorization.cfg deleted file mode 100644 index 1f38fdb27..000000000 --- a/specs/pubsub_subscribe_authorization.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[{prefix, <<"pubsub#">>}, - {required, [<<"pubsub#node">>, <<"pubsub#subscriber_jid">>, <<"pubsub#allow">>]}]. - -%% Local Variables: -%% mode: erlang -%% End: -%% vim: set filetype=erlang tabstop=8: diff --git a/specs/pubsub_subscribe_authorization.xdata b/specs/pubsub_subscribe_authorization.xdata deleted file mode 100644 index 250d8754b..000000000 --- a/specs/pubsub_subscribe_authorization.xdata +++ /dev/null @@ -1,27 +0,0 @@ - - http://jabber.org/protocol/pubsub#subscribe_authorization - XEP-0060 - Forms enabling authorization of subscriptions to pubsub nodes - - - - - - - diff --git a/specs/pubsub_subscribe_options.cfg b/specs/pubsub_subscribe_options.cfg deleted file mode 100644 index e4ac06ad9..000000000 --- a/specs/pubsub_subscribe_options.cfg +++ /dev/null @@ -1 +0,0 @@ -[{prefix, <<"pubsub#">>}]. diff --git a/specs/pubsub_subscribe_options.xdata b/specs/pubsub_subscribe_options.xdata deleted file mode 100644 index 59b134676..000000000 --- a/specs/pubsub_subscribe_options.xdata +++ /dev/null @@ -1,70 +0,0 @@ - - http://jabber.org/protocol/pubsub#subscribe_options - XEP-0060 - Forms enabling configuration of subscription options for pubsub nodes - - - - - - - - - - - - - - - - - - - - - diff --git a/specs/xmpp_codec.spec b/specs/xmpp_codec.spec deleted file mode 100644 index 0aa124ec8..000000000 --- a/specs/xmpp_codec.spec +++ /dev/null @@ -1,3588 +0,0 @@ --xml(last, - #elem{name = <<"query">>, - xmlns = <<"jabber:iq:last">>, - result = {last, '$seconds', '$status'}, - attrs = [#attr{name = <<"seconds">>, - enc = {enc_int, []}, - dec = {dec_int, [0, infinity]}}], - cdata = #cdata{default = <<"">>, label = '$status'}}). - --xml(version_name, - #elem{name = <<"name">>, - xmlns = <<"jabber:iq:version">>, - result = '$cdata', - cdata = #cdata{label = '$cdata', required = true}}). - --xml(version_ver, - #elem{name = <<"version">>, - xmlns = <<"jabber:iq:version">>, - result = '$cdata', - cdata = #cdata{label = '$cdata', required = true}}). - --xml(version_os, - #elem{name = <<"os">>, - xmlns = <<"jabber:iq:version">>, - result = '$cdata', - cdata = #cdata{label = '$cdata', required = true}}). - --xml(version, - #elem{name = <<"query">>, - xmlns = <<"jabber:iq:version">>, - result = {version, '$name', '$ver', '$os'}, - refs = [#ref{name = version_name, - label = '$name', - min = 0, max = 1}, - #ref{name = version_ver, - label = '$ver', - min = 0, max = 1}, - #ref{name = version_os, - label = '$os', - min = 0, max = 1}]}). - --xml(roster_group, - #elem{name = <<"group">>, - xmlns = <<"jabber:iq:roster">>, - result = '$cdata', - cdata = #cdata{required = true, label = '$cdata'}}). - --xml(roster_item, - #elem{name = <<"item">>, - xmlns = <<"jabber:iq:roster">>, - result = {roster_item, '$jid', '$name', - '$groups', '$subscription', '$ask'}, - attrs = [#attr{name = <<"jid">>, - required = true, - dec = {dec_jid, []}, - enc = {enc_jid, []}}, - #attr{name = <<"name">>, - default = <<"">>}, - #attr{name = <<"subscription">>, - default = none, - enc = {enc_enum, []}, - dec = {dec_enum, [[none,to,from,both,remove]]}}, - #attr{name = <<"ask">>, - enc = {enc_enum, []}, - dec = {dec_enum, [[subscribe]]}}], - refs = [#ref{name = roster_group, label = '$groups'}]}). - --xml(roster_query, - #elem{name = <<"query">>, - xmlns = <<"jabber:iq:roster">>, - result = {roster_query, '$items', '$ver'}, - attrs = [#attr{name = <<"ver">>, default = undefined}], - refs = [#ref{name = roster_item, label = '$items'}]}). - --xml(rosterver_feature, - #elem{name = <<"ver">>, - xmlns = <<"urn:xmpp:features:rosterver">>, - result = {rosterver_feature}}). - --xml(privacy_message, #elem{name = <<"message">>, xmlns = <<"jabber:iq:privacy">>, - result = true}). --xml(privacy_iq, #elem{name = <<"iq">>, xmlns = <<"jabber:iq:privacy">>, - result = true}). --xml(privacy_presence_in, #elem{name = <<"presence-in">>, - xmlns = <<"jabber:iq:privacy">>, - result = true}). --xml(privacy_presence_out, #elem{name = <<"presence-out">>, - xmlns = <<"jabber:iq:privacy">>, - result = true}). - --xml(privacy_item, - #elem{name = <<"item">>, - xmlns = <<"jabber:iq:privacy">>, - result = {privacy_item, '$order', '$action', '$type', '$value', - '$message', '$iq', '$presence_in', '$presence_out'}, - attrs = [#attr{name = <<"action">>, - required = true, - dec = {dec_enum, [[allow, deny]]}, - enc = {enc_enum, []}}, - #attr{name = <<"order">>, - required = true, - dec = {dec_int, [0, infinity]}, - enc = {enc_int, []}}, - #attr{name = <<"type">>, - dec = {dec_enum, [[group, jid, subscription]]}, - enc = {enc_enum, []}}, - #attr{name = <<"value">>}], - refs = [#ref{name = privacy_message, default = false, - min = 0, max = 1, label = '$message'}, - #ref{name = privacy_iq, default = false, - min = 0, max = 1, label = '$iq'}, - #ref{name = privacy_presence_in, default = false, - min = 0, max = 1, label = '$presence_in'}, - #ref{name = privacy_presence_out, default = false, - min = 0, max = 1, label = '$presence_out'}]}). - --xml(privacy_list, - #elem{name = <<"list">>, - xmlns = <<"jabber:iq:privacy">>, - result = {privacy_list, '$name', '$items'}, - attrs = [#attr{name = <<"name">>, - required = true}], - refs = [#ref{name = privacy_item, - label = '$items'}]}). - --xml(privacy_default_list, - #elem{name = <<"default">>, - xmlns = <<"jabber:iq:privacy">>, - result = '$name', - attrs = [#attr{name = <<"name">>, - default = none}]}). - --xml(privacy_active_list, - #elem{name = <<"active">>, - xmlns = <<"jabber:iq:privacy">>, - result = '$name', - attrs = [#attr{name = <<"name">>, - default = none}]}). - --xml(privacy, - #elem{name = <<"query">>, - xmlns = <<"jabber:iq:privacy">>, - result = {privacy_query, '$lists', '$default', '$active'}, - refs = [#ref{name = privacy_list, - label = '$lists'}, - #ref{name = privacy_default_list, - min = 0, max = 1, - label = '$default'}, - #ref{name = privacy_active_list, - min = 0, max = 1, - label = '$active'}]}). - --xml(block_item, - #elem{name = <<"item">>, - xmlns = <<"urn:xmpp:blocking">>, - result = '$jid', - attrs = [#attr{name = <<"jid">>, - required = true, - dec = {dec_jid, []}, - enc = {enc_jid, []}}]}). - --xml(block, - #elem{name = <<"block">>, - xmlns = <<"urn:xmpp:blocking">>, - result = {block, '$items'}, - refs = [#ref{name = block_item, - label = '$items'}]}). - --xml(unblock, - #elem{name = <<"unblock">>, - xmlns = <<"urn:xmpp:blocking">>, - result = {unblock, '$items'}, - refs = [#ref{name = block_item, - label = '$items'}]}). - --xml(block_list, - #elem{name = <<"blocklist">>, - xmlns = <<"urn:xmpp:blocking">>, - result = {block_list, '$items'}, - refs = [#ref{name = block_item, - label = '$items'}]}). - --xml(disco_identity, - #elem{name = <<"identity">>, - xmlns = <<"http://jabber.org/protocol/disco#info">>, - result = {identity, '$category', '$type', '$lang', '$name'}, - attrs = [#attr{name = <<"category">>, - required = true}, - #attr{name = <<"type">>, - required = true}, - #attr{name = <<"xml:lang">>, - label = '$lang'}, - #attr{name = <<"name">>}]}). - --xml(disco_feature, - #elem{name = <<"feature">>, - xmlns = <<"http://jabber.org/protocol/disco#info">>, - result = '$var', - attrs = [#attr{name = <<"var">>, - required = true}]}). - --xml(disco_info, - #elem{name = <<"query">>, - xmlns = <<"http://jabber.org/protocol/disco#info">>, - result = {disco_info, '$node', '$identities', '$features', '$xdata'}, - attrs = [#attr{name = <<"node">>}], - refs = [#ref{name = disco_identity, - label = '$identities'}, - #ref{name = disco_feature, - label = '$features'}, - #ref{name = xdata, - label = '$xdata'}]}). - --xml(disco_item, - #elem{name = <<"item">>, - xmlns = <<"http://jabber.org/protocol/disco#items">>, - result = {disco_item, '$jid', '$name', '$node'}, - attrs = [#attr{name = <<"jid">>, - dec = {dec_jid, []}, - enc = {enc_jid, []}, - required = true}, - #attr{name = <<"name">>}, - #attr{name = <<"node">>}]}). --xml(disco_items, - #elem{name = <<"query">>, - xmlns = <<"http://jabber.org/protocol/disco#items">>, - result = {disco_items, '$node', '$items', '$rsm'}, - attrs = [#attr{name = <<"node">>}], - refs = [#ref{name = disco_item, - label = '$items'}, - #ref{name = rsm_set, min = 0, max = 1, - label = '$rsm'}]}). - --xml(private, - #elem{name = <<"query">>, - xmlns = <<"jabber:iq:private">>, - result = {private, '$_xmls'}}). - --xml(conference_nick, - #elem{name = <<"nick">>, - xmlns = <<"storage:bookmarks">>, - result = '$cdata'}). - --xml(conference_password, - #elem{name = <<"password">>, - xmlns = <<"storage:bookmarks">>, - result = '$cdata'}). - --xml(bookmark_conference, - #elem{name = <<"conference">>, - xmlns = <<"storage:bookmarks">>, - result = {bookmark_conference, '$name', '$jid', - '$autojoin', '$nick', '$password'}, - attrs = [#attr{name = <<"name">>, - required = true}, - #attr{name = <<"jid">>, - required = true, - dec = {dec_jid, []}, - enc = {enc_jid, []}}, - #attr{name = <<"autojoin">>, - default = false, - dec = {dec_bool, []}, - enc = {enc_bool, []}}], - refs = [#ref{name = conference_nick, - label = '$nick', - min = 0, max = 1}, - #ref{name = conference_password, - label = '$password', - min = 0, max = 1}]}). - --xml(bookmark_url, - #elem{name = <<"url">>, - xmlns = <<"storage:bookmarks">>, - result = {bookmark_url, '$name', '$url'}, - attrs = [#attr{name = <<"name">>, - required = true}, - #attr{name = <<"url">>, - required = true}]}). - --xml(bookmarks_storage, - #elem{name = <<"storage">>, - xmlns = <<"storage:bookmarks">>, - result = {bookmark_storage, '$conference', '$url'}, - refs = [#ref{name = bookmark_conference, - label = '$conference'}, - #ref{name = bookmark_url, - label = '$url'}]}). - --xml(stat_error, - #elem{name = <<"error">>, - xmlns = <<"http://jabber.org/protocol/stats">>, - result = {stat_error, '$code', '$reason'}, - cdata = #cdata{default = <<"">>, label = '$reason'}, - attrs = [#attr{name = <<"code">>, - required = true, - enc = {enc_int, []}, - dec = {dec_int, []}}]}). - --xml(stat, - #elem{name = <<"stat">>, - xmlns = <<"http://jabber.org/protocol/stats">>, - result = {stat, '$name', '$units', '$value', '$error'}, - attrs = [#attr{name = <<"name">>, - required = true}, - #attr{name = <<"units">>, default = <<"">>}, - #attr{name = <<"value">>, default = <<"">>}], - refs = [#ref{name = stat_error, label = '$error', - min = 0, max = 1}]}). - --xml(stats, - #elem{name = <<"query">>, - xmlns = <<"http://jabber.org/protocol/stats">>, - result = {stats, '$list', '$node'}, - attrs = [#attr{name = <<"node">>, default = <<"">>}], - refs = [#ref{name = stat, label = '$list'}]}). - --xml(iq, - #elem{name = <<"iq">>, - xmlns = [<<"jabber:client">>, <<"jabber:server">>, - <<"jabber:component:accept">>], - result = {iq, '$id', '$type', '$lang', '$from', '$to', '$_els'}, - attrs = [#attr{name = <<"id">>, - required = true}, - #attr{name = <<"type">>, - required = true, - enc = {enc_enum, []}, - dec = {dec_enum, [[get, set, result, error]]}}, - #attr{name = <<"from">>, - dec = {dec_jid, []}, - enc = {enc_jid, []}}, - #attr{name = <<"to">>, - dec = {dec_jid, []}, - enc = {enc_jid, []}}, - #attr{name = <<"xml:lang">>, - label = '$lang'}]}). - --xml(message_subject, - #elem{name = <<"subject">>, - xmlns = [<<"jabber:client">>, <<"jabber:server">>, - <<"jabber:component:accept">>], - result = {text, '$lang', '$data'}, - cdata = #cdata{label = '$data'}, - attrs = [#attr{name = <<"xml:lang">>, label = '$lang'}]}). - --xml(message_body, - #elem{name = <<"body">>, - xmlns = [<<"jabber:client">>, <<"jabber:server">>, - <<"jabber:component:accept">>], - result = {text, '$lang', '$data'}, - cdata = #cdata{label = '$data'}, - attrs = [#attr{name = <<"xml:lang">>, label = '$lang'}]}). - --xml(message_thread, - #elem{name = <<"thread">>, - xmlns = [<<"jabber:client">>, <<"jabber:server">>, - <<"jabber:component:accept">>], - result = '$cdata'}). - --xml(message, - #elem{name = <<"message">>, - xmlns = [<<"jabber:client">>, <<"jabber:server">>, - <<"jabber:component:accept">>], - result = {message, '$id', '$type', '$lang', '$from', '$to', - '$subject', '$body', '$thread', '$_els'}, - attrs = [#attr{name = <<"id">>}, - #attr{name = <<"type">>, - default = normal, - enc = {enc_enum, []}, - dec = {dec_enum, [[chat, normal, groupchat, - headline, error]]}}, - #attr{name = <<"from">>, - dec = {dec_jid, []}, - enc = {enc_jid, []}}, - #attr{name = <<"to">>, - dec = {dec_jid, []}, - enc = {enc_jid, []}}, - #attr{name = <<"xml:lang">>, - label = '$lang'}], - refs = [#ref{name = message_subject, label = '$subject'}, - #ref{name = message_thread, min = 0, max = 1, label = '$thread'}, - #ref{name = message_body, label = '$body'}]}). - --xml(presence_show, - #elem{name = <<"show">>, - xmlns = [<<"jabber:client">>, <<"jabber:server">>, - <<"jabber:component:accept">>], - result = '$cdata', - cdata = #cdata{enc = {enc_enum, []}, - dec = {dec_enum, [[away, chat, dnd, xa]]}}}). - --xml(presence_status, - #elem{name = <<"status">>, - xmlns = [<<"jabber:client">>, <<"jabber:server">>, - <<"jabber:component:accept">>], - result = {text, '$lang', '$data'}, - cdata = #cdata{label = '$data'}, - attrs = [#attr{name = <<"xml:lang">>, - label = '$lang'}]}). - --xml(presence_priority, - #elem{name = <<"priority">>, - xmlns = [<<"jabber:client">>, <<"jabber:server">>, - <<"jabber:component:accept">>], - result = '$cdata', - cdata = #cdata{enc = {enc_int, []}, - dec = {dec_int, []}}}). - --xml(presence, - #elem{name = <<"presence">>, - xmlns = [<<"jabber:client">>, <<"jabber:server">>, - <<"jabber:component:accept">>], - result = {presence, '$id', '$type', '$lang', '$from', '$to', - '$show', '$status', '$priority', '$_els'}, - attrs = [#attr{name = <<"id">>}, - #attr{name = <<"type">>, - default = available, - enc = {enc_enum, []}, - dec = {dec_enum, [[unavailable, subscribe, subscribed, - unsubscribe, unsubscribed, - available, probe, error]]}}, - #attr{name = <<"from">>, - dec = {dec_jid, []}, - enc = {enc_jid, []}}, - #attr{name = <<"to">>, - dec = {dec_jid, []}, - enc = {enc_jid, []}}, - #attr{name = <<"xml:lang">>, - label = '$lang'}], - refs = [#ref{name = presence_show, min = 0, max = 1, label = '$show'}, - #ref{name = presence_status, label = '$status'}, - #ref{name = presence_priority, min = 0, max = 1, - label = '$priority'}]}). - --xml(error_bad_request, - #elem{name = <<"bad-request">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - result = 'bad-request'}). --xml(error_conflict, - #elem{name = <<"conflict">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - result = 'conflict'}). --xml(error_feature_not_implemented, - #elem{name = <<"feature-not-implemented">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - result = 'feature-not-implemented'}). --xml(error_forbidden, - #elem{name = <<"forbidden">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - result = 'forbidden'}). --xml(error_gone, - #elem{name = <<"gone">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - cdata = #cdata{label = '$uri'}, - result = {'gone', '$uri'}}). --xml(error_internal_server_error, - #elem{name = <<"internal-server-error">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - result = 'internal-server-error'}). --xml(error_item_not_found, - #elem{name = <<"item-not-found">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - result = 'item-not-found'}). --xml(error_jid_malformed, - #elem{name = <<"jid-malformed">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - result = 'jid-malformed'}). --xml(error_not_acceptable, - #elem{name = <<"not-acceptable">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - result = 'not-acceptable'}). --xml(error_not_allowed, - #elem{name = <<"not-allowed">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - result = 'not-allowed'}). --xml(error_not_authorized, - #elem{name = <<"not-authorized">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - result = 'not-authorized'}). --xml(error_payment_required, - #elem{name = <<"payment-required">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - result = 'payment-required'}). --xml(error_policy_violation, - #elem{name = <<"policy-violation">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - result = 'policy-violation'}). --xml(error_recipient_unavailable, - #elem{name = <<"recipient-unavailable">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - result = 'recipient-unavailable'}). --xml(error_redirect, - #elem{name = <<"redirect">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - cdata = #cdata{label = '$uri'}, - result = {'redirect', '$uri'}}). --xml(error_registration_required, - #elem{name = <<"registration-required">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - result = 'registration-required'}). --xml(error_remote_server_not_found, - #elem{name = <<"remote-server-not-found">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - result = 'remote-server-not-found'}). --xml(error_remote_server_timeout, - #elem{name = <<"remote-server-timeout">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - result = 'remote-server-timeout'}). --xml(error_resource_constraint, - #elem{name = <<"resource-constraint">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - result = 'resource-constraint'}). --xml(error_service_unavailable, - #elem{name = <<"service-unavailable">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - result = 'service-unavailable'}). --xml(error_subscription_required, - #elem{name = <<"subscription-required">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - result = 'subscription-required'}). --xml(error_undefined_condition, - #elem{name = <<"undefined-condition">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - result = 'undefined-condition'}). --xml(error_unexpected_request, - #elem{name = <<"unexpected-request">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - result = 'unexpected-request'}). - --xml(error_text, - #elem{name = <<"text">>, - result = {text, '$lang', '$data'}, - cdata = #cdata{label = '$data'}, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - attrs = [#attr{name = <<"xml:lang">>, - label = '$lang'}]}). - --xml(error, - #elem{name = <<"error">>, - xmlns = [<<"jabber:client">>, <<"jabber:server">>, - <<"jabber:component:accept">>], - result = {stanza_error, '$type', '$code', '$by', '$reason', '$text', '$_els'}, - attrs = [#attr{name = <<"type">>, - label = '$type', - required = true, - dec = {dec_enum, [[auth, cancel, continue, - modify, wait]]}, - enc = {enc_enum, []}}, - #attr{name = <<"code">>, - label = '$code', - enc = {enc_int, []}, - dec = {dec_int, [0, infinity]}}, - #attr{name = <<"by">>}], - refs = [#ref{name = error_text, - min = 0, max = 1, label = '$text'}, - #ref{name = error_bad_request, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_conflict, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_feature_not_implemented, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_forbidden, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_gone, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_internal_server_error, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_item_not_found, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_jid_malformed, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_not_acceptable, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_not_allowed, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_not_authorized, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_payment_required, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_policy_violation, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_recipient_unavailable, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_redirect, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_registration_required, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_remote_server_not_found, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_remote_server_timeout, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_resource_constraint, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_service_unavailable, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_subscription_required, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_undefined_condition, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_unexpected_request, - min = 0, max = 1, label = '$reason'}]}). - --xml(bind_jid, - #elem{name = <<"jid">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-bind">>, - result = '$cdata', - cdata = #cdata{dec = {dec_jid, []}, - enc = {enc_jid, []}}}). - --xml(bind_resource, - #elem{name = <<"resource">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-bind">>, - result = '$cdata', - cdata = #cdata{dec = {resourceprep, []}, - enc = {resourceprep, []}}}). - --xml(bind, #elem{name = <<"bind">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-bind">>, - result = {bind, '$jid', '$resource'}, - refs = [#ref{name = bind_jid, - label = '$jid', - min = 0, max = 1}, - #ref{name = bind_resource, - min = 0, max = 1, - default = <<"">>, - label = '$resource'}]}). - --xml(legacy_auth_username, - #elem{name = <<"username">>, - xmlns = <<"jabber:iq:auth">>, - result = '$cdata'}). --xml(legacy_auth_password, - #elem{name = <<"password">>, - xmlns = <<"jabber:iq:auth">>, - result = '$cdata'}). --xml(legacy_auth_digest, - #elem{name = <<"digest">>, - xmlns = <<"jabber:iq:auth">>, - result = '$cdata'}). --xml(legacy_auth_resource, - #elem{name = <<"resource">>, - xmlns = <<"jabber:iq:auth">>, - result = '$cdata'}). - --xml(legacy_auth, - #elem{name = <<"query">>, - xmlns = <<"jabber:iq:auth">>, - result = {legacy_auth, '$username', '$password', - '$digest', '$resource'}, - refs = [#ref{name = legacy_auth_username, min = 0, max = 1, - label = '$username'}, - #ref{name = legacy_auth_password, min = 0, max = 1, - label = '$password'}, - #ref{name = legacy_auth_digest, min = 0, max = 1, - label = '$digest'}, - #ref{name = legacy_auth_resource, min = 0, max = 1, - label = '$resource'}]}). - --xml(sasl_auth, - #elem{name = <<"auth">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>, - cdata = #cdata{label = '$text', - dec = {base64, mime_decode, []}, - enc = {base64, encode, []}}, - result = {sasl_auth, '$mechanism', '$text'}, - attrs = [#attr{name = <<"mechanism">>, - required = true}]}). - --xml(sasl_abort, - #elem{name = <<"abort">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>, - result = {sasl_abort}}). - --xml(sasl_challenge, - #elem{name = <<"challenge">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>, - cdata = #cdata{label = '$text', - dec = {base64, mime_decode, []}, - enc = {base64, encode, []}}, - result = {sasl_challenge, '$text'}}). - --xml(sasl_response, - #elem{name = <<"response">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>, - cdata = #cdata{label = '$text', - dec = {base64, mime_decode, []}, - enc = {base64, encode, []}}, - result = {sasl_response, '$text'}}). - --xml(sasl_success, - #elem{name = <<"success">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>, - cdata = #cdata{label = '$text', - dec = {base64, mime_decode, []}, - enc = {base64, encode, []}}, - result = {sasl_success, '$text'}}). - --xml(sasl_failure_text, - #elem{name = <<"text">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>, - result = {text, '$lang', '$data'}, - cdata = #cdata{label = '$data'}, - attrs = [#attr{name = <<"xml:lang">>, - label = '$lang'}]}). - --xml(sasl_failure_aborted, - #elem{name = <<"aborted">>, - result = 'aborted', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>}). --xml(sasl_failure_account_disabled, - #elem{name = <<"account-disabled">>, - result = 'account-disabled', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>}). --xml(sasl_failure_credentials_expired, - #elem{name = <<"credentials-expired">>, - result = 'credentials-expired', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>}). --xml(sasl_failure_encryption_required, - #elem{name = <<"encryption-required">>, - result = 'encryption-required', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>}). --xml(sasl_failure_incorrect_encoding, - #elem{name = <<"incorrect-encoding">>, - result = 'incorrect-encoding', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>}). --xml(sasl_failure_invalid_authzid, - #elem{name = <<"invalid-authzid">>, - result = 'invalid-authzid', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>}). --xml(sasl_failure_invalid_mechanism, - #elem{name = <<"invalid-mechanism">>, - result = 'invalid-mechanism', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>}). --xml(sasl_failure_malformed_request, - #elem{name = <<"malformed-request">>, - result = 'malformed-request', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>}). --xml(sasl_failure_mechanism_too_weak, - #elem{name = <<"mechanism-too-weak">>, - result = 'mechanism-too-weak', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>}). --xml(sasl_failure_not_authorized, - #elem{name = <<"not-authorized">>, - result = 'not-authorized', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>}). --xml(sasl_failure_bad_protocol, - #elem{name = <<"bad-protocol">>, - result = 'bad-protocol', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>}). --xml(sasl_failure_temporary_auth_failure, - #elem{name = <<"temporary-auth-failure">>, - result = 'temporary-auth-failure', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>}). - --xml(sasl_failure, - #elem{name = <<"failure">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>, - result = {sasl_failure, '$reason', '$text'}, - refs = [#ref{name = sasl_failure_text, - label = '$text'}, - #ref{name = sasl_failure_aborted, - min = 0, max = 1, label = '$reason'}, - #ref{name = sasl_failure_account_disabled, - min = 0, max = 1, label = '$reason'}, - #ref{name = sasl_failure_credentials_expired, - min = 0, max = 1, label = '$reason'}, - #ref{name = sasl_failure_encryption_required, - min = 0, max = 1, label = '$reason'}, - #ref{name = sasl_failure_incorrect_encoding, - min = 0, max = 1, label = '$reason'}, - #ref{name = sasl_failure_invalid_authzid, - min = 0, max = 1, label = '$reason'}, - #ref{name = sasl_failure_invalid_mechanism, - min = 0, max = 1, label = '$reason'}, - #ref{name = sasl_failure_malformed_request, - min = 0, max = 1, label = '$reason'}, - #ref{name = sasl_failure_mechanism_too_weak, - min = 0, max = 1, label = '$reason'}, - #ref{name = sasl_failure_not_authorized, - min = 0, max = 1, label = '$reason'}, - #ref{name = sasl_failure_bad_protocol, - min = 0, max = 1, label = '$reason'}, - #ref{name = sasl_failure_temporary_auth_failure, - min = 0, max = 1, label = '$reason'}]}). - --xml(sasl_mechanism, - #elem{name = <<"mechanism">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>, - result = '$cdata'}). - --xml(sasl_mechanisms, - #elem{name = <<"mechanisms">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-sasl">>, - result = {sasl_mechanisms, '$list'}, - refs = [#ref{name = sasl_mechanism, - label = '$list'}]}). - --xml(starttls_required, - #elem{name = <<"required">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-tls">>, - result = true}). - --xml(starttls, - #elem{name = <<"starttls">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-tls">>, - result = {starttls, '$required'}, - refs = [#ref{name = starttls_required, - label = '$required', - min = 0, max = 1, - default = false}]}). - --xml(starttls_proceed, - #elem{name = <<"proceed">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-tls">>, - result = {starttls_proceed}}). - --xml(starttls_failure, - #elem{name = <<"failure">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-tls">>, - result = {starttls_failure}}). - --xml(compress_failure_setup_failed, - #elem{name = <<"setup-failed">>, - xmlns = <<"http://jabber.org/protocol/compress">>, - result = 'setup-failed'}). --xml(compress_failure_processing_failed, - #elem{name = <<"processing-failed">>, - xmlns = <<"http://jabber.org/protocol/compress">>, - result = 'processing-failed'}). --xml(compress_failure_unsupported_method, - #elem{name = <<"unsupported-method">>, - xmlns = <<"http://jabber.org/protocol/compress">>, - result = 'unsupported-method'}). - --xml(compress_failure, - #elem{name = <<"failure">>, - xmlns = <<"http://jabber.org/protocol/compress">>, - result = {compress_failure, '$reason'}, - refs = [#ref{name = compress_failure_setup_failed, - min = 0, max = 1, label = '$reason'}, - #ref{name = compress_failure_processing_failed, - min = 0, max = 1, label = '$reason'}, - #ref{name = compress_failure_unsupported_method, - min = 0, max = 1, label = '$reason'}]}). - --xml(compress_method, - #elem{name = <<"method">>, - xmlns = <<"http://jabber.org/protocol/compress">>, - result = '$cdata'}). - --xml(compress, - #elem{name = <<"compress">>, - xmlns = <<"http://jabber.org/protocol/compress">>, - result = {compress, '$methods'}, - refs = [#ref{name = compress_method, - label = '$methods'}]}). - --xml(compressed, - #elem{name = <<"compressed">>, - xmlns = <<"http://jabber.org/protocol/compress">>, - result = {compressed}}). - --xml(compression_method, - #elem{name = <<"method">>, - xmlns = <<"http://jabber.org/features/compress">>, - result = '$cdata'}). - --xml(compression, - #elem{name = <<"compression">>, - xmlns = <<"http://jabber.org/features/compress">>, - result = {compression, '$methods'}, - refs = [#ref{name = compression_method, label = '$methods'}]}). - --xml(stream_features, - #elem{name = <<"stream:features">>, - xmlns = [<<"jabber:client">>, <<"jabber:server">>], - result = {stream_features, '$_els'}}). - --xml(p1_push, - #elem{name = <<"push">>, - result = {p1_push}, - xmlns = <<"p1:push">>}). - --xml(p1_rebind, - #elem{name = <<"rebind">>, - result = {p1_rebind}, - xmlns = <<"p1:rebind">>}). - --xml(p1_ack, - #elem{name = <<"ack">>, - result = {p1_ack}, - xmlns = <<"p1:ack">>}). - --xml(caps, - #elem{name = <<"c">>, - xmlns = <<"http://jabber.org/protocol/caps">>, - result = {caps, '$node', '$version', '$hash', '$exts'}, - attrs = [#attr{name = <<"hash">>}, - #attr{name = <<"node">>}, - #attr{name = <<"ext">>, - label = '$exts', - default = [], - dec = {re, split, ["\\h+"]}, - enc = {join, [$ ]}}, - #attr{name = <<"ver">>, - label = '$version'}]}). - --xml(feature_register, - #elem{name = <<"register">>, - xmlns = <<"http://jabber.org/features/iq-register">>, - result = {feature_register}}). - --xml(register_registered, - #elem{name = <<"registered">>, - xmlns = <<"jabber:iq:register">>, - result = true}). --xml(register_remove, - #elem{name = <<"remove">>, - xmlns = <<"jabber:iq:register">>, - result = true}). --xml(register_instructions, - #elem{name = <<"instructions">>, - xmlns = <<"jabber:iq:register">>, - result = '$cdata'}). --xml(register_username, - #elem{name = <<"username">>, - xmlns = <<"jabber:iq:register">>, - result = '$cdata'}). --xml(register_nick, - #elem{name = <<"nick">>, - xmlns = <<"jabber:iq:register">>, - result = '$cdata'}). --xml(register_password, - #elem{name = <<"password">>, - xmlns = <<"jabber:iq:register">>, - result = '$cdata'}). --xml(register_name, - #elem{name = <<"name">>, - xmlns = <<"jabber:iq:register">>, - result = '$cdata'}). --xml(register_first, - #elem{name = <<"first">>, - xmlns = <<"jabber:iq:register">>, - result = '$cdata'}). --xml(register_last, - #elem{name = <<"last">>, - xmlns = <<"jabber:iq:register">>, - result = '$cdata'}). --xml(register_email, - #elem{name = <<"email">>, - xmlns = <<"jabber:iq:register">>, - result = '$cdata'}). --xml(register_address, - #elem{name = <<"address">>, - xmlns = <<"jabber:iq:register">>, - result = '$cdata'}). --xml(register_city, - #elem{name = <<"city">>, - xmlns = <<"jabber:iq:register">>, - result = '$cdata'}). --xml(register_state, - #elem{name = <<"state">>, - xmlns = <<"jabber:iq:register">>, - result = '$cdata'}). --xml(register_zip, - #elem{name = <<"zip">>, - xmlns = <<"jabber:iq:register">>, - result = '$cdata'}). --xml(register_phone, - #elem{name = <<"phone">>, - xmlns = <<"jabber:iq:register">>, - result = '$cdata'}). --xml(register_url, - #elem{name = <<"url">>, - xmlns = <<"jabber:iq:register">>, - result = '$cdata'}). --xml(register_date, - #elem{name = <<"date">>, - xmlns = <<"jabber:iq:register">>, - result = '$cdata'}). --xml(register_misc, - #elem{name = <<"misc">>, - xmlns = <<"jabber:iq:register">>, - result = '$cdata'}). --xml(register_text, - #elem{name = <<"text">>, - xmlns = <<"jabber:iq:register">>, - result = '$cdata'}). --xml(register_key, - #elem{name = <<"key">>, - xmlns = <<"jabber:iq:register">>, - result = '$cdata'}). - --xml(register, - #elem{name = <<"query">>, - xmlns = <<"jabber:iq:register">>, - result = {register, '$registered', '$remove', '$instructions', - '$username', '$nick', '$password', '$name', - '$first', '$last', '$email', '$address', - '$city', '$state', '$zip', '$phone', '$url', - '$date', '$misc', '$text', '$key', '$xdata', '$_els'}, - refs = [#ref{name = xdata, min = 0, max = 1, - label = '$xdata'}, - #ref{name = register_registered, min = 0, max = 1, - default = false, label = '$registered'}, - #ref{name = register_remove, min = 0, max = 1, - default = false, label = '$remove'}, - #ref{name = register_instructions, min = 0, max = 1, - label = '$instructions'}, - #ref{name = register_username, min = 0, max = 1, - label = '$username'}, - #ref{name = register_nick, min = 0, max = 1, - label = '$nick'}, - #ref{name = register_password, min = 0, max = 1, - label = '$password'}, - #ref{name = register_name, min = 0, max = 1, - label = '$name'}, - #ref{name = register_first, min = 0, max = 1, - label = '$first'}, - #ref{name = register_last, min = 0, max = 1, - label = '$last'}, - #ref{name = register_email, min = 0, max = 1, - label = '$email'}, - #ref{name = register_address, min = 0, max = 1, - label = '$address'}, - #ref{name = register_city, min = 0, max = 1, - label = '$city'}, - #ref{name = register_state, min = 0, max = 1, - label = '$state'}, - #ref{name = register_zip, min = 0, max = 1, - label = '$zip'}, - #ref{name = register_phone, min = 0, max = 1, - label = '$phone'}, - #ref{name = register_url, min = 0, max = 1, - label = '$url'}, - #ref{name = register_date, min = 0, max = 1, - label = '$date'}, - #ref{name = register_misc, min = 0, max = 1, - label = '$misc'}, - #ref{name = register_text, min = 0, max = 1, - label = '$text'}, - #ref{name = register_key, min = 0, max = 1, - label = '$key'}]}). - --xml(session_optional, - #elem{name = <<"optional">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-session">>, - result = true}). - --xml(session, - #elem{name = <<"session">>, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-session">>, - result = {xmpp_session, '$optional'}, - refs = [#ref{name = session_optional, - min = 0, max = 1, default = false, - label = '$optional'}]}). - --xml(ping, - #elem{name = <<"ping">>, - xmlns = <<"urn:xmpp:ping">>, - result = {ping}}). - --xml(time_utc, - #elem{name = <<"utc">>, - xmlns = <<"urn:xmpp:time">>, - result = '$cdata', - cdata = #cdata{dec = {dec_utc, []}, - enc = {enc_utc, []}}}). - --xml(time_tzo, - #elem{name = <<"tzo">>, - xmlns = <<"urn:xmpp:time">>, - result = '$cdata', - cdata = #cdata{dec = {dec_tzo, []}, - enc = {enc_tzo, []}}}). - --xml(time, - #elem{name = <<"time">>, - xmlns = <<"urn:xmpp:time">>, - result = {time, '$tzo', '$utc'}, - refs = [#ref{name = time_tzo, - label = '$tzo', - min = 0, max = 1}, - #ref{name = time_utc, - label = '$utc', - min = 0, max = 1}]}). - --xml(stream_error_text, - #elem{name = <<"text">>, - result = {text, '$lang', '$data'}, - cdata = #cdata{label = '$data'}, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>, - attrs = [#attr{name = <<"xml:lang">>, - label = '$lang'}]}). - --xml(stream_error_bad_format, - #elem{name = <<"bad-format">>, - result = 'bad-format', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}). --xml(stream_error_bad_namespace_prefix, - #elem{name = <<"bad-namespace-prefix">>, - result = 'bad-namespace-prefix', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}). --xml(stream_error_conflict, - #elem{name = <<"conflict">>, - result = 'conflict', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}). --xml(stream_error_connection_timeout, - #elem{name = <<"connection-timeout">>, - result = 'connection-timeout', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}). --xml(stream_error_host_gone, - #elem{name = <<"host-gone">>, - result = 'host-gone', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}). --xml(stream_error_host_unknown, - #elem{name = <<"host-unknown">>, - result = 'host-unknown', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}). --xml(stream_error_improper_addressing, - #elem{name = <<"improper-addressing">>, - result = 'improper-addressing', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}). --xml(stream_error_internal_server_error, - #elem{name = <<"internal-server-error">>, - result = 'internal-server-error', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}). --xml(stream_error_invalid_from, - #elem{name = <<"invalid-from">>, - result = 'invalid-from', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}). --xml(stream_error_invalid_id, - #elem{name = <<"invalid-id">>, - result = 'invalid-id', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}). --xml(stream_error_invalid_namespace, - #elem{name = <<"invalid-namespace">>, - result = 'invalid-namespace', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}). --xml(stream_error_invalid_xml, - #elem{name = <<"invalid-xml">>, - result = 'invalid-xml', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}). --xml(stream_error_not_authorized, - #elem{name = <<"not-authorized">>, - result = 'not-authorized', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}). --xml(stream_error_not_well_formed, - #elem{name = <<"not-well-formed">>, - result = 'not-well-formed', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}). --xml(stream_error_policy_violation, - #elem{name = <<"policy-violation">>, - result = 'policy-violation', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}). --xml(stream_error_remote_connection_failed, - #elem{name = <<"remote-connection-failed">>, - result = 'remote-connection-failed', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}). --xml(stream_error_reset, - #elem{name = <<"reset">>, - result = 'reset', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}). --xml(stream_error_resource_constraint, - #elem{name = <<"resource-constraint">>, - result = 'resource-constraint', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}). --xml(stream_error_restricted_xml, - #elem{name = <<"restricted-xml">>, - result = 'restricted-xml', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}). --xml(stream_error_see_other_host, - #elem{name = <<"see-other-host">>, - cdata = #cdata{required = true, label = '$host', - dec = {dec_host_port, []}, - enc = {enc_host_port, []}}, - result = {'see-other-host', '$host'}, - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}). --xml(stream_error_system_shutdown, - #elem{name = <<"system-shutdown">>, - result = 'system-shutdown', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}). --xml(stream_error_undefined_condition, - #elem{name = <<"undefined-condition">>, - result = 'undefined-condition', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}). --xml(stream_error_unsupported_encoding, - #elem{name = <<"unsupported-encoding">>, - result = 'unsupported-encoding', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}). --xml(stream_error_unsupported_stanza_type, - #elem{name = <<"unsupported-stanza-type">>, - result = 'unsupported-stanza-type', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}). --xml(stream_error_unsupported_version, - #elem{name = <<"unsupported-version">>, - result = 'unsupported-version', - xmlns = <<"urn:ietf:params:xml:ns:xmpp-streams">>}). - --xml(stream_error, - #elem{name = <<"stream:error">>, - xmlns = [<<"jabber:client">>, <<"jabber:server">>, - <<"jabber:component:accept">>], - result = {stream_error, '$reason', '$text'}, - refs = [#ref{name = stream_error_text, - label = '$text', - min = 0, max = 1}, - #ref{name = stream_error_bad_format, - min = 0, max = 1, label = '$reason'}, - #ref{name = stream_error_bad_namespace_prefix, - min = 0, max = 1, label = '$reason'}, - #ref{name = stream_error_conflict, - min = 0, max = 1, label = '$reason'}, - #ref{name = stream_error_connection_timeout, - min = 0, max = 1, label = '$reason'}, - #ref{name = stream_error_host_gone, - min = 0, max = 1, label = '$reason'}, - #ref{name = stream_error_host_unknown, - min = 0, max = 1, label = '$reason'}, - #ref{name = stream_error_improper_addressing, - min = 0, max = 1, label = '$reason'}, - #ref{name = stream_error_internal_server_error, - min = 0, max = 1, label = '$reason'}, - #ref{name = stream_error_invalid_from, - min = 0, max = 1, label = '$reason'}, - #ref{name = stream_error_invalid_id, - min = 0, max = 1, label = '$reason'}, - #ref{name = stream_error_invalid_namespace, - min = 0, max = 1, label = '$reason'}, - #ref{name = stream_error_invalid_xml, - min = 0, max = 1, label = '$reason'}, - #ref{name = stream_error_not_authorized, - min = 0, max = 1, label = '$reason'}, - #ref{name = stream_error_not_well_formed, - min = 0, max = 1, label = '$reason'}, - #ref{name = stream_error_policy_violation, - min = 0, max = 1, label = '$reason'}, - #ref{name = stream_error_remote_connection_failed, - min = 0, max = 1, label = '$reason'}, - #ref{name = stream_error_reset, - min = 0, max = 1, label = '$reason'}, - #ref{name = stream_error_resource_constraint, - min = 0, max = 1, label = '$reason'}, - #ref{name = stream_error_restricted_xml, - min = 0, max = 1, label = '$reason'}, - #ref{name = stream_error_see_other_host, - min = 0, max = 1, label = '$reason'}, - #ref{name = stream_error_system_shutdown, - min = 0, max = 1, label = '$reason'}, - #ref{name = stream_error_undefined_condition, - min = 0, max = 1, label = '$reason'}, - #ref{name = stream_error_unsupported_encoding, - min = 0, max = 1, label = '$reason'}, - #ref{name = stream_error_unsupported_stanza_type, - min = 0, max = 1, label = '$reason'}, - #ref{name = stream_error_unsupported_version, - min = 0, max = 1, label = '$reason'} - ]}). - --xml(vcard_HOME, #elem{name = <<"HOME">>, xmlns = <<"vcard-temp">>, result = true}). --xml(vcard_WORK, #elem{name = <<"WORK">>, xmlns = <<"vcard-temp">>, result = true}). --xml(vcard_VOICE, #elem{name = <<"VOICE">>, xmlns = <<"vcard-temp">>, result = true}). --xml(vcard_FAX, #elem{name = <<"FAX">>, xmlns = <<"vcard-temp">>, result = true}). --xml(vcard_PAGER, #elem{name = <<"PAGER">>, xmlns = <<"vcard-temp">>, result = true}). --xml(vcard_MSG, #elem{name = <<"MSG">>, xmlns = <<"vcard-temp">>, result = true}). --xml(vcard_CELL, #elem{name = <<"CELL">>, xmlns = <<"vcard-temp">>, result = true}). --xml(vcard_VIDEO, #elem{name = <<"VIDEO">>, xmlns = <<"vcard-temp">>, result = true}). --xml(vcard_BBS, #elem{name = <<"BBS">>, xmlns = <<"vcard-temp">>, result = true}). --xml(vcard_MODEM, #elem{name = <<"MODEM">>, xmlns = <<"vcard-temp">>, result = true}). --xml(vcard_ISDN, #elem{name = <<"ISDN">>, xmlns = <<"vcard-temp">>, result = true}). --xml(vcard_PCS, #elem{name = <<"PCS">>, xmlns = <<"vcard-temp">>, result = true}). --xml(vcard_POSTAL, #elem{name = <<"POSTAL">>, xmlns = <<"vcard-temp">>, result = true}). --xml(vcard_PARCEL, #elem{name = <<"PARCEL">>, xmlns = <<"vcard-temp">>, result = true}). --xml(vcard_DOM, #elem{name = <<"DOM">>, xmlns = <<"vcard-temp">>, result = true}). --xml(vcard_INTL, #elem{name = <<"INTL">>, xmlns = <<"vcard-temp">>, result = true}). --xml(vcard_PREF, #elem{name = <<"PREF">>, xmlns = <<"vcard-temp">>, result = true}). --xml(vcard_INTERNET, #elem{name = <<"INTERNET">>, xmlns = <<"vcard-temp">>, result = true}). --xml(vcard_X400, #elem{name = <<"X400">>, xmlns = <<"vcard-temp">>, result = true}). --xml(vcard_FAMILY, #elem{name = <<"FAMILY">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_GIVEN, #elem{name = <<"GIVEN">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_MIDDLE, #elem{name = <<"MIDDLE">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_PREFIX, #elem{name = <<"PREFIX">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_SUFFIX, #elem{name = <<"SUFFIX">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_POBOX, #elem{name = <<"POBOX">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_EXTADD, #elem{name = <<"EXTADD">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_STREET, #elem{name = <<"STREET">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_LOCALITY, #elem{name = <<"LOCALITY">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_REGION, #elem{name = <<"REGION">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_PCODE, #elem{name = <<"PCODE">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_CTRY, #elem{name = <<"CTRY">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_LINE, #elem{name = <<"LINE">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_NUMBER, #elem{name = <<"NUMBER">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_USERID, #elem{name = <<"USERID">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_LAT, #elem{name = <<"LAT">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_LON, #elem{name = <<"LON">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_ORGNAME, #elem{name = <<"ORGNAME">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_ORGUNIT, #elem{name = <<"ORGUNIT">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_PHONETIC, #elem{name = <<"PHONETIC">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_CRED, #elem{name = <<"CRED">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_VERSION, #elem{name = <<"VERSION">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_FN, #elem{name = <<"FN">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_NICKNAME, #elem{name = <<"NICKNAME">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_BDAY, #elem{name = <<"BDAY">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_JABBERID, #elem{name = <<"JABBERID">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_MAILER, #elem{name = <<"MAILER">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_TZ, #elem{name = <<"TZ">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_TITLE, #elem{name = <<"TITLE">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_ROLE, #elem{name = <<"ROLE">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_KEYWORD, #elem{name = <<"KEYWORD">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_NOTE, #elem{name = <<"NOTE">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_PRODID, #elem{name = <<"PRODID">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_REV, #elem{name = <<"REV">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_SORT_STRING, #elem{name = <<"SORT-STRING">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_UID, #elem{name = <<"UID">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_URL, #elem{name = <<"URL">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_DESC, #elem{name = <<"DESC">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_TYPE, #elem{name = <<"TYPE">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_EXTVAL, #elem{name = <<"EXTVAL">>, xmlns = <<"vcard-temp">>, result = '$cdata'}). --xml(vcard_PUBLIC, #elem{name = <<"PUBLIC">>, xmlns = <<"vcard-temp">>, result = public}). --xml(vcard_PRIVATE, #elem{name = <<"PRIVATE">>, xmlns = <<"vcard-temp">>, result = private}). --xml(vcard_CONFIDENTIAL, #elem{name = <<"CONFIDENTIAL">>, xmlns = <<"vcard-temp">>, result = confidential}). - --xml(vcard_N, - #elem{name = <<"N">>, - xmlns = <<"vcard-temp">>, - result = {vcard_name, '$family', '$given', '$middle', - '$prefix', '$suffix'}, - refs = [#ref{name = vcard_FAMILY, min = 0, max = 1, label = '$family'}, - #ref{name = vcard_GIVEN, min = 0, max = 1, label = '$given'}, - #ref{name = vcard_MIDDLE, min = 0, max = 1, label = '$middle'}, - #ref{name = vcard_PREFIX, min = 0, max = 1, label = '$prefix'}, - #ref{name = vcard_SUFFIX, min = 0, max = 1, label = '$suffix'}]}). - --xml(vcard_ADR, - #elem{name = <<"ADR">>, - xmlns = <<"vcard-temp">>, - result = {vcard_adr, '$home', '$work', '$postal', '$parcel', - '$dom', '$intl', '$pref', '$pobox', '$extadd', '$street', - '$locality', '$region', '$pcode', '$ctry'}, - refs = [#ref{name = vcard_HOME, default = false, - min = 0, max = 1, label = '$home'}, - #ref{name = vcard_WORK, default = false, - min = 0, max = 1, label = '$work'}, - #ref{name = vcard_POSTAL, default = false, - min = 0, max = 1, label = '$postal'}, - #ref{name = vcard_PARCEL, default = false, - min = 0, max = 1, label = '$parcel'}, - #ref{name = vcard_DOM, default = false, - min = 0, max = 1, label = '$dom'}, - #ref{name = vcard_INTL, default = false, - min = 0, max = 1, label = '$intl'}, - #ref{name = vcard_PREF, default = false, - min = 0, max = 1, label = '$pref'}, - #ref{name = vcard_POBOX, min = 0, max = 1, label = '$pobox'}, - #ref{name = vcard_EXTADD, min = 0, max = 1, label = '$extadd'}, - #ref{name = vcard_STREET, min = 0, max = 1, label = '$street'}, - #ref{name = vcard_LOCALITY, min = 0, max = 1, label = '$locality'}, - #ref{name = vcard_REGION, min = 0, max = 1, label = '$region'}, - #ref{name = vcard_PCODE, min = 0, max = 1, label = '$pcode'}, - #ref{name = vcard_CTRY, min = 0, max = 1, label = '$ctry'}]}). - --xml(vcard_LABEL, - #elem{name = <<"LABEL">>, - xmlns = <<"vcard-temp">>, - result = {vcard_label, '$home', '$work', '$postal', '$parcel', - '$dom', '$intl', '$pref', '$line'}, - refs = [#ref{name = vcard_HOME, default = false, - min = 0, max = 1, label = '$home'}, - #ref{name = vcard_WORK, default = false, - min = 0, max = 1, label = '$work'}, - #ref{name = vcard_POSTAL, default = false, - min = 0, max = 1, label = '$postal'}, - #ref{name = vcard_PARCEL, default = false, - min = 0, max = 1, label = '$parcel'}, - #ref{name = vcard_DOM, default = false, - min = 0, max = 1, label = '$dom'}, - #ref{name = vcard_INTL, default = false, - min = 0, max = 1, label = '$intl'}, - #ref{name = vcard_PREF, default = false, - min = 0, max = 1, label = '$pref'}, - #ref{name = vcard_LINE, label = '$line'}]}). - --xml(vcard_TEL, - #elem{name = <<"TEL">>, - xmlns = <<"vcard-temp">>, - result = {vcard_tel, '$home', '$work', '$voice', '$fax', - '$pager', '$msg', '$cell', '$video', '$bbs', - '$modem', '$isdn', '$pcs', '$pref', '$number'}, - refs = [#ref{name = vcard_HOME, default = false, - min = 0, max = 1, label = '$home'}, - #ref{name = vcard_WORK, default = false, - min = 0, max = 1, label = '$work'}, - #ref{name = vcard_VOICE, default = false, - min = 0, max = 1, label = '$voice'}, - #ref{name = vcard_FAX, default = false, - min = 0, max = 1, label = '$fax'}, - #ref{name = vcard_PAGER, default = false, - min = 0, max = 1, label = '$pager'}, - #ref{name = vcard_MSG, default = false, - min = 0, max = 1, label = '$msg'}, - #ref{name = vcard_CELL, default = false, - min = 0, max = 1, label = '$cell'}, - #ref{name = vcard_VIDEO, default = false, - min = 0, max = 1, label = '$video'}, - #ref{name = vcard_BBS, default = false, - min = 0, max = 1, label = '$bbs'}, - #ref{name = vcard_MODEM, default = false, - min = 0, max = 1, label = '$modem'}, - #ref{name = vcard_ISDN, default = false, - min = 0, max = 1, label = '$isdn'}, - #ref{name = vcard_PCS, default = false, - min = 0, max = 1, label = '$pcs'}, - #ref{name = vcard_PREF, default = false, - min = 0, max = 1, label = '$pref'}, - #ref{name = vcard_NUMBER, - min = 0, max = 1, label = '$number'}]}). - --xml(vcard_EMAIL, - #elem{name = <<"EMAIL">>, - xmlns = <<"vcard-temp">>, - result = {vcard_email, '$home', '$work', - '$internet', '$pref', '$x400', '$userid'}, - refs = [#ref{name = vcard_HOME, default = false, - min = 0, max = 1, label = '$home'}, - #ref{name = vcard_WORK, default = false, - min = 0, max = 1, label = '$work'}, - #ref{name = vcard_INTERNET, default = false, - min = 0, max = 1, label = '$internet'}, - #ref{name = vcard_PREF, default = false, - min = 0, max = 1, label = '$pref'}, - #ref{name = vcard_X400, default = false, - min = 0, max = 1, label = '$x400'}, - #ref{name = vcard_USERID, - min = 0, max = 1, label = '$userid'}]}). - --xml(vcard_GEO, - #elem{name = <<"GEO">>, - xmlns = <<"vcard-temp">>, - result = {vcard_geo, '$lat', '$lon'}, - refs = [#ref{name = vcard_LAT, min = 0, max = 1, label = '$lat'}, - #ref{name = vcard_LON, min = 0, max = 1, label = '$lon'}]}). - --xml(vcard_BINVAL, - #elem{name = <<"BINVAL">>, - xmlns = <<"vcard-temp">>, - cdata = #cdata{dec = {base64, decode, []}, - enc = {base64, encode, []}}, - result = '$cdata'}). - --xml(vcard_LOGO, - #elem{name = <<"LOGO">>, - xmlns = <<"vcard-temp">>, - result = {vcard_logo, '$type', '$binval', '$extval'}, - refs = [#ref{name = vcard_TYPE, min = 0, max = 1, label = '$type'}, - #ref{name = vcard_BINVAL, min = 0, max = 1, label = '$binval'}, - #ref{name = vcard_EXTVAL, min = 0, max = 1, label = '$extval'}]}). - --xml(vcard_PHOTO, - #elem{name = <<"PHOTO">>, - xmlns = <<"vcard-temp">>, - result = {vcard_photo, '$type', '$binval', '$extval'}, - refs = [#ref{name = vcard_TYPE, min = 0, max = 1, label = '$type'}, - #ref{name = vcard_BINVAL, min = 0, max = 1, label = '$binval'}, - #ref{name = vcard_EXTVAL, min = 0, max = 1, label = '$extval'}]}). - --xml(vcard_ORG, - #elem{name = <<"ORG">>, - xmlns = <<"vcard-temp">>, - result = {vcard_org, '$name', '$units'}, - refs = [#ref{name = vcard_ORGNAME, - label = '$name', - min = 0, max = 1}, - #ref{name = vcard_ORGUNIT, - label = '$units'}]}). - --xml(vcard_SOUND, - #elem{name = <<"SOUND">>, - xmlns = <<"vcard-temp">>, - result = {vcard_sound, '$phonetic', '$binval', '$extval'}, - refs = [#ref{name = vcard_BINVAL, min = 0, max = 1, label = '$binval'}, - #ref{name = vcard_EXTVAL, min = 0, max = 1, label = '$extval'}, - #ref{name = vcard_PHONETIC, min = 0, max = 1, label = '$phonetic'}]}). - --xml(vcard_KEY, - #elem{name = <<"KEY">>, - xmlns = <<"vcard-temp">>, - result = {vcard_key, '$type', '$cred'}, - refs = [#ref{name = vcard_TYPE, min = 0, max = 1, label = '$type'}, - #ref{name = vcard_CRED, min = 0, max = 1, label = '$cred'}]}). - --xml(vcard_CATEGORIES, - #elem{name = <<"CATEGORIES">>, - xmlns = <<"vcard-temp">>, - result = '$keywords', - refs = [#ref{name = vcard_KEYWORD, label = '$keywords'}]}). - --xml(vcard_CLASS, - #elem{name = <<"CLASS">>, - xmlns = <<"vcard-temp">>, - result = '$class', - refs = [#ref{name = vcard_PUBLIC, min = 0, max = 1, label = '$class'}, - #ref{name = vcard_PRIVATE, min = 0, max = 1, label = '$class'}, - #ref{name = vcard_CONFIDENTIAL, min = 0, max = 1, label = '$class'}]}). - -%% {vcard_AGENT, -%% #elem{name = <<"AGENT">>, -%% xmlns = <<"vcard-temp">>, -%% result = {vcard_agent, '$vcard', '$extval'}, -%% refs = [#ref{name = vcard, min = 0, max = 1, label = '$vcard'}, -%% #ref{name = vcard_EXTVAL, min = 0, max = 1, label = '$extval'}]}). - --xml(vcard_temp, - #elem{name = <<"vCard">>, - xmlns = <<"vcard-temp">>, - result = {vcard_temp, '$version', '$fn', '$n', '$nickname', '$photo', - '$bday', '$adr', '$label', '$tel', '$email', '$jabberid', - '$mailer', '$tz', '$geo', '$title', '$role', '$logo', - '$org', '$categories', '$note', '$prodid', %% '$agent', - '$rev', '$sort_string', '$sound', '$uid', '$url', '$class', - '$key', '$desc'}, - refs = [#ref{name = vcard_N, min = 0, max = 1, label = '$n'}, - #ref{name = vcard_ADR, label = '$adr'}, - #ref{name = vcard_LABEL, label = '$label'}, - #ref{name = vcard_TEL, label = '$tel'}, - #ref{name = vcard_EMAIL, label = '$email'}, - #ref{name = vcard_GEO, min = 0, max = 1, label = '$geo'}, - #ref{name = vcard_LOGO, min = 0, max = 1, label = '$logo'}, - #ref{name = vcard_PHOTO, min = 0, max = 1, label = '$photo'}, - #ref{name = vcard_ORG, min = 0, max = 1, label = '$org'}, - #ref{name = vcard_SOUND, min = 0, max = 1, label = '$sound'}, - #ref{name = vcard_KEY, min = 0, max = 1, label = '$key'}, - #ref{name = vcard_VERSION, min = 0, max = 1, label = '$version'}, - #ref{name = vcard_FN, min = 0, max = 1, label = '$fn'}, - #ref{name = vcard_NICKNAME, min = 0, max = 1, label = '$nickname'}, - #ref{name = vcard_BDAY, min = 0, max = 1, label = '$bday'}, - #ref{name = vcard_JABBERID, min = 0, max = 1, label = '$jabberid'}, - #ref{name = vcard_MAILER, min = 0, max = 1, label = '$mailer'}, - #ref{name = vcard_TZ, min = 0, max = 1, label = '$tz'}, - #ref{name = vcard_TITLE, min = 0, max = 1, label = '$title'}, - #ref{name = vcard_ROLE, min = 0, max = 1, label = '$role'}, - #ref{name = vcard_NOTE, min = 0, max = 1, label = '$note'}, - #ref{name = vcard_PRODID, min = 0, max = 1, label = '$prodid'}, - #ref{name = vcard_REV, min = 0, max = 1, label = '$rev'}, - %%#ref{name = vcard_AGENT, min = 0, max = 1, label = '$agent'}, - #ref{name = vcard_SORT_STRING, min = 0, max = 1, - label = '$sort_string'}, - #ref{name = vcard_UID, min = 0, max = 1, label = '$uid'}, - #ref{name = vcard_URL, min = 0, max = 1, label = '$url'}, - #ref{name = vcard_DESC, min = 0, max = 1, label = '$desc'}, - #ref{name = vcard_CATEGORIES, default = [], min = 0, max = 1, - label = '$categories'}, - #ref{name = vcard_CLASS, min = 0, max = 1, label = '$class'}]}). - --xml(vcard_xupdate_photo, - #elem{name = <<"photo">>, - xmlns = <<"vcard-temp:x:update">>, - result = '$cdata'}). - --record(vcard_xupdate, {us = {<<>>, <<>>} :: {binary(), binary()}, - hash :: binary()}). --type vcard_xupdate() :: #vcard_xupdate{}. - --xml(vcard_xupdate, - #elem{name = <<"x">>, - xmlns = <<"vcard-temp:x:update">>, - result = {vcard_xupdate, '$_', '$hash'}, - refs = [#ref{name = vcard_xupdate_photo, min = 0, max = 1, - label = '$hash'}]}). - --xml(xdata_field_required, - #elem{name = <<"required">>, - xmlns = <<"jabber:x:data">>, - result = true}). - --xml(xdata_field_desc, - #elem{name = <<"desc">>, xmlns = <<"jabber:x:data">>, result = '$cdata'}). - --xml(xdata_field_value, - #elem{name = <<"value">>, xmlns = <<"jabber:x:data">>, result = '$cdata'}). - --xml(xdata_field_option, - #elem{name = <<"option">>, - xmlns = <<"jabber:x:data">>, - result = {xdata_option, '$label', '$value'}, - attrs = [#attr{name = <<"label">>}], - refs = [#ref{name = xdata_field_value, - label = '$value', - min = 1, max = 1}]}). - --xml(xdata_field, - #elem{name = <<"field">>, - xmlns = <<"jabber:x:data">>, - result = {xdata_field, '$label', '$type', '$var', - '$required', '$desc', '$values', '$options', '$_els'}, - attrs = [#attr{name = <<"label">>}, - #attr{name = <<"type">>, - enc = {enc_enum, []}, - dec = {dec_enum, [['boolean', - 'fixed', - 'hidden', - 'jid-multi', - 'jid-single', - 'list-multi', - 'list-single', - 'text-multi', - 'text-private', - 'text-single']]}}, - #attr{name = <<"var">>}], - refs = [#ref{name = xdata_field_required, - label = '$required', - default = false, - min = 0, max = 1}, - #ref{name = xdata_field_desc, - default = <<"">>, - label = '$desc', - min = 0, max = 1}, - #ref{name = xdata_field_value, - label = '$values'}, - #ref{name = xdata_field_option, - label = '$options'}]}). - --xml(xdata_instructions, #elem{name = <<"instructions">>, - xmlns = <<"jabber:x:data">>, - result = '$cdata'}). --xml(xdata_title, #elem{name = <<"title">>, - xmlns = <<"jabber:x:data">>, - result = '$cdata'}). --xml(xdata_reported, #elem{name = <<"reported">>, - xmlns = <<"jabber:x:data">>, - result = '$fields', - refs = [#ref{name = xdata_field, - label = '$fields'}]}). --xml(xdata_item, #elem{name = <<"item">>, - xmlns = <<"jabber:x:data">>, - result = '$fields', - refs = [#ref{name = xdata_field, - label = '$fields'}]}). - --xml(xdata, - #elem{name = <<"x">>, - xmlns = <<"jabber:x:data">>, - result = {xdata, '$type', '$instructions', '$title', - '$reported', '$items', '$fields'}, - attrs = [#attr{name = <<"type">>, - required = true, - dec = {dec_enum, [[cancel, form, result, submit]]}, - enc = {enc_enum, []}}], - refs = [#ref{name = xdata_instructions, - label = '$instructions'}, - #ref{name = xdata_title, - label = '$title', - min = 0, max = 1}, - #ref{name = xdata_reported, - label = '$reported', - min = 0, max = 1}, - #ref{name = xdata_item, - label = '$items'}, - #ref{name = xdata_field, - label = '$fields'}]}). - --xml(pubsub_subscription, - #elem{name = <<"subscription">>, - xmlns = [<<"http://jabber.org/protocol/pubsub">>, - <<"http://jabber.org/protocol/pubsub#owner">>, - <<"http://jabber.org/protocol/pubsub#event">>], - result = {ps_subscription, '$xmlns', '$jid', '$type', - '$node', '$subid', '$expiry'}, - attrs = [#attr{name = <<"xmlns">>}, - #attr{name = <<"jid">>, - required = true, - dec = {dec_jid, []}, - enc = {enc_jid, []}}, - #attr{name = <<"node">>}, - #attr{name = <<"subid">>}, - #attr{name = <<"subscription">>, - label = '$type', - dec = {dec_enum, [[none, pending, subscribed, - unconfigured]]}, - enc = {enc_enum, []}}, - #attr{name = <<"expiry">>, - dec = {dec_utc, []}, - enc = {enc_utc, []}}]}). - --record(ps_affiliation, {xmlns = <<>> :: binary(), - node = <<>> :: binary(), - type :: member | none | outcast | - owner | publisher | publish_only, - jid :: jid:jid()}). --type ps_affiliation() :: #ps_affiliation{}. - --xml(pubsub_affiliation, - #elem{name = <<"affiliation">>, - xmlns = <<"http://jabber.org/protocol/pubsub">>, - result = {ps_affiliation, '$xmlns', '$node', '$type', '$_'}, - attrs = [#attr{name = <<"node">>, required = true}, - #attr{name = <<"xmlns">>}, - #attr{name = <<"affiliation">>, - label = '$type', - required = true, - dec = {dec_ps_aff, []}, - enc = {enc_ps_aff, []}}]}). - --xml(pubsub_owner_affiliation, - #elem{name = <<"affiliation">>, - xmlns = <<"http://jabber.org/protocol/pubsub#owner">>, - result = {ps_affiliation, '$xmlns', '$_', '$type', '$jid'}, - attrs = [#attr{name = <<"jid">>, - required = true, - dec = {dec_jid, []}, - enc = {enc_jid, []}}, - #attr{name = <<"xmlns">>}, - #attr{name = <<"affiliation">>, - label = '$type', - required = true, - dec = {dec_ps_aff, []}, - enc = {enc_ps_aff, []}}]}). - --xml(pubsub_event_configuration, - #elem{name = <<"configuration">>, - xmlns = <<"http://jabber.org/protocol/pubsub#event">>, - result = {'$node', '$xdata'}, - attrs = [#attr{name = <<"node">>, required = true}], - refs = [#ref{name = xdata, min = 0, max = 1}]}). - --xml(pubsub_event_retract, - #elem{name = <<"retract">>, - xmlns = <<"http://jabber.org/protocol/pubsub#event">>, - result = '$id', - attrs = [#attr{name = <<"id">>, required = true}]}). - --xml(pubsub_item, - #elem{name = <<"item">>, - xmlns = [<<"http://jabber.org/protocol/pubsub">>, - <<"http://jabber.org/protocol/pubsub#event">>], - result = {ps_item, '$xmlns', '$id', '$_xmls', '$node', '$publisher'}, - attrs = [#attr{name = <<"id">>}, - #attr{name = <<"xmlns">>}, - #attr{name = <<"node">>}, - #attr{name = <<"publisher">>}]}). - --xml(pubsub_items, - #elem{name = <<"items">>, - xmlns = [<<"http://jabber.org/protocol/pubsub">>, - <<"http://jabber.org/protocol/pubsub#event">>], - result = {ps_items, '$xmlns', '$node', '$items', '$max_items', - '$subid', '$retract'}, - attrs = [#attr{name = <<"xmlns">>}, - #attr{name = <<"max_items">>, - dec = {dec_int, [0, infinity]}, - enc = {enc_int, []}}, - #attr{name = <<"node">>, - required = true}, - #attr{name = <<"subid">>}], - refs = [#ref{name = pubsub_event_retract, label = '$retract', - min = 0, max = 1}, - #ref{name = pubsub_item, label = '$items'}]}). - --xml(pubsub_event, - #elem{name = <<"event">>, - xmlns = <<"http://jabber.org/protocol/pubsub#event">>, - result = {ps_event, '$items', '$purge', '$subscription', '$delete', - '$create', '$configuration'}, - refs = [#ref{name = pubsub_items, label = '$items', - min = 0, max = 1}, - #ref{name = pubsub_subscription, min = 0, max = 1, - label = '$subscription'}, - #ref{name = pubsub_purge, min = 0, max = 1, - label = '$purge'}, - #ref{name = pubsub_delete, min = 0, max = 1, - label = '$delete'}, - #ref{name = pubsub_create, min = 0, max = 1, - label = '$create'}, - #ref{name = pubsub_event_configuration, min = 0, max = 1, - label = '$configuration'}]}). - --xml(pubsub_subscriptions, - #elem{name = <<"subscriptions">>, - xmlns = [<<"http://jabber.org/protocol/pubsub">>, - <<"http://jabber.org/protocol/pubsub#owner">>], - result = {'$node', '$subscriptions'}, - attrs = [#attr{name = <<"node">>}], - refs = [#ref{name = pubsub_subscription, label = '$subscriptions'}]}). - --xml(pubsub_affiliations, - #elem{name = <<"affiliations">>, - xmlns = <<"http://jabber.org/protocol/pubsub">>, - result = {'$node', '$affiliations'}, - attrs = [#attr{name = <<"node">>}], - refs = [#ref{name = pubsub_affiliation, label = '$affiliations'}]}). - --xml(pubsub_owner_affiliations, - #elem{name = <<"affiliations">>, - xmlns = <<"http://jabber.org/protocol/pubsub#owner">>, - result = {'$node', '$affiliations'}, - attrs = [#attr{name = <<"node">>}], - refs = [#ref{name = pubsub_owner_affiliation, label = '$affiliations'}]}). - --xml(pubsub_subscribe, - #elem{name = <<"subscribe">>, - xmlns = <<"http://jabber.org/protocol/pubsub">>, - result = {ps_subscribe, '$node', '$jid'}, - attrs = [#attr{name = <<"node">>}, - #attr{name = <<"jid">>, - required = true, - dec = {dec_jid, []}, - enc = {enc_jid, []}}]}). - --xml(pubsub_unsubscribe, - #elem{name = <<"unsubscribe">>, - xmlns = <<"http://jabber.org/protocol/pubsub">>, - result = {ps_unsubscribe, '$node', '$jid', '$subid'}, - attrs = [#attr{name = <<"node">>}, - #attr{name = <<"subid">>}, - #attr{name = <<"jid">>, - required = true, - dec = {dec_jid, []}, - enc = {enc_jid, []}}]}). - --xml(pubsub_publish, - #elem{name = <<"publish">>, - xmlns = <<"http://jabber.org/protocol/pubsub">>, - result = {ps_publish, '$node', '$items'}, - attrs = [#attr{name = <<"node">>, - required = true}], - refs = [#ref{name = pubsub_item, label = '$items'}]}). - --xml(pubsub_options, - #elem{name = <<"options">>, - xmlns = <<"http://jabber.org/protocol/pubsub">>, - result = {ps_options, '$node', '$jid', '$subid', '$xdata'}, - attrs = [#attr{name = <<"node">>}, - #attr{name = <<"subid">>}, - #attr{name = <<"jid">>, - required = true, - dec = {dec_jid, []}, - enc = {enc_jid, []}}], - refs = [#ref{name = xdata, min = 0, max = 1, - label = '$xdata'}]}). - --xml(pubsub_retract, - #elem{name = <<"retract">>, - xmlns = <<"http://jabber.org/protocol/pubsub">>, - result = {ps_retract, '$node', '$notify', '$items'}, - attrs = [#attr{name = <<"node">>, - required = true}, - #attr{name = <<"notify">>, - default = false, - dec = {dec_bool, []}, - enc = {enc_bool, []}}], - refs = [#ref{name = pubsub_item, label = '$items'}]}). - --xml(pubsub_create, - #elem{name = <<"create">>, - xmlns = [<<"http://jabber.org/protocol/pubsub">>, - <<"http://jabber.org/protocol/pubsub#event">>], - result = '$node', - attrs = [#attr{name = <<"node">>}]}). - --xml(pubsub_configure, - #elem{name = <<"configure">>, - xmlns = [<<"http://jabber.org/protocol/pubsub">>, - <<"http://jabber.org/protocol/pubsub#owner">>], - result = {'$node', '$xdata'}, - attrs = [#attr{name = <<"node">>}], - refs = [#ref{name = xdata, min = 0, max = 1}]}). - --xml(pubsub_publish_options, - #elem{name = <<"publish-options">>, - xmlns = <<"http://jabber.org/protocol/pubsub">>, - result = '$xdata', - refs = [#ref{name = xdata, min = 0, max = 1}]}). - --xml(pubsub_default, - #elem{name = <<"default">>, - xmlns = [<<"http://jabber.org/protocol/pubsub">>, - <<"http://jabber.org/protocol/pubsub#owner">>], - result = {'$node', '$xdata'}, - attrs = [#attr{name = <<"node">>}], - refs = [#ref{name = xdata, min = 0, max = 1}]}). - --xml(pubsub_redirect, - #elem{name = <<"redirect">>, - xmlns = [<<"http://jabber.org/protocol/pubsub">>, - <<"http://jabber.org/protocol/pubsub#owner">>, - <<"http://jabber.org/protocol/pubsub#event">>], - result = '$uri', - attrs = [#attr{name = <<"uri">>, required = true}]}). - --xml(pubsub_delete, - #elem{name = <<"delete">>, - xmlns = [<<"http://jabber.org/protocol/pubsub">>, - <<"http://jabber.org/protocol/pubsub#owner">>, - <<"http://jabber.org/protocol/pubsub#event">>], - result = {'$node', '$uri'}, - attrs = [#attr{name = <<"node">>, required = true}], - refs = [#ref{name = pubsub_redirect, min = 0, max = 1, - label = '$uri', default = <<>>}]}). - --xml(pubsub_purge, - #elem{name = <<"purge">>, - xmlns = [<<"http://jabber.org/protocol/pubsub">>, - <<"http://jabber.org/protocol/pubsub#owner">>, - <<"http://jabber.org/protocol/pubsub#event">>], - result = '$node', - attrs = [#attr{name = <<"node">>, required = true}]}). - --xml(pubsub, - #elem{name = <<"pubsub">>, - xmlns = <<"http://jabber.org/protocol/pubsub">>, - result = {pubsub, '$subscriptions', '$subscription', - '$affiliations', '$publish', '$publish_options', - '$subscribe', '$unsubscribe', '$options', '$items', - '$retract', '$create', '$configure', '$default', '$delete', - '$purge', '$rsm'}, - refs = [#ref{name = pubsub_subscriptions, label = '$subscriptions', - min = 0, max = 1}, - #ref{name = pubsub_affiliations, label = '$affiliations', - min = 0, max = 1}, - #ref{name = pubsub_subscribe, label = '$subscribe', - min = 0, max = 1}, - #ref{name = pubsub_unsubscribe, label = '$unsubscribe', - min = 0, max = 1}, - #ref{name = pubsub_options, label = '$options', - min = 0, max = 1}, - #ref{name = pubsub_items, label = '$items', - min = 0, max = 1}, - #ref{name = pubsub_retract, label = '$retract', - min = 0, max = 1}, - #ref{name = pubsub_create, label = '$create', - min = 0, max = 1}, - #ref{name = pubsub_configure, label = '$configure', - min = 0, max = 1}, - #ref{name = pubsub_publish_options, min = 0, max = 1, - label = '$publish_options'}, - #ref{name = pubsub_default, label = '$default', - min = 0, max = 1}, - #ref{name = pubsub_delete, label = '$delete', - min = 0, max = 1}, - #ref{name = pubsub_purge, label = '$purge', - min = 0, max = 1}, - #ref{name = pubsub_subscription, label = '$subscription', - min = 0, max = 1}, - #ref{name = rsm_set, min = 0, max = 1, label = '$rsm'}, - #ref{name = pubsub_publish, label = '$publish', - min = 0, max = 1}]}). - --xml(pubsub_owner, - #elem{name = <<"pubsub">>, - xmlns = <<"http://jabber.org/protocol/pubsub#owner">>, - result = {pubsub_owner, '$affiliations', '$configure', '$default', - '$delete', '$purge', '$subscriptions'}, - refs = [#ref{name = pubsub_owner_affiliations, - label = '$affiliations', min = 0, max = 1}, - #ref{name = pubsub_configure, label = '$configure', - min = 0, max = 1}, - #ref{name = pubsub_default, label = '$default', - min = 0, max = 1}, - #ref{name = pubsub_delete, label = '$delete', - min = 0, max = 1}, - #ref{name = pubsub_purge, label = '$purge', - min = 0, max = 1}, - #ref{name = pubsub_subscriptions, - label = '$subscriptions', min = 0, max = 1}]}). - --type ps_error_type() :: 'closed-node' | 'configuration-required' | - 'invalid-jid' | 'invalid-options' | - 'invalid-payload' | 'invalid-subid' | - 'item-forbidden' | 'item-required' | 'jid-required' | - 'max-items-exceeded' | 'max-nodes-exceeded' | - 'nodeid-required' | 'not-in-roster-group' | - 'not-subscribed' | 'payload-too-big' | - 'payload-required' | 'pending-subscription' | - 'presence-subscription-required' | 'subid-required' | - 'too-many-subscriptions' | 'unsupported' | - 'unsupported-access-model'. --type ps_feature() :: 'access-authorize' | 'access-open' | - 'access-presence' | 'access-roster' | - 'access-whitelist' | 'auto-create' | - 'auto-subscribe' | 'collections' | 'config-node' | - 'create-and-configure' | 'create-nodes' | - 'delete-items' | 'delete-nodes' | - 'filtered-notifications' | 'get-pending' | - 'instant-nodes' | 'item-ids' | 'last-published' | - 'leased-subscription' | 'manage-subscriptions' | - 'member-affiliation' | 'meta-data' | - 'modify-affiliations' | 'multi-collection' | - 'multi-subscribe' | 'outcast-affiliation' | - 'persistent-items' | 'presence-notifications' | - 'presence-subscribe' | 'publish' | - 'publish-options' | 'publish-only-affiliation' | - 'publisher-affiliation' | 'purge-nodes' | - 'retract-items' | 'retrieve-affiliations' | - 'retrieve-default' | 'retrieve-items' | - 'retrieve-subscriptions' | 'subscribe' | - 'subscription-options' | 'subscription-notifications'. --record(ps_error, {type :: ps_error_type(), feature :: ps_feature()}). --type ps_error() :: #ps_error{}. - --xml(pubsub_error_closed_node, - #elem{name = <<"closed-node">>, - xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, - result = {ps_error, 'closed-node', '$_'}}). --xml(pubsub_error_configuration_required, - #elem{name = <<"configuration-required">>, - xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, - result = {ps_error, 'configuration-required', '$_'}}). --xml(pubsub_error_invalid_jid, - #elem{name = <<"invalid-jid">>, - xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, - result = {ps_error, 'invalid-jid', '$_'}}). --xml(pubsub_error_invalid_options, - #elem{name = <<"invalid-options">>, - xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, - result = {ps_error, 'invalid-options', '$_'}}). --xml(pubsub_error_invalid_payload, - #elem{name = <<"invalid-payload">>, - xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, - result = {ps_error, 'invalid-payload', '$_'}}). --xml(pubsub_error_invalid_subid, - #elem{name = <<"invalid-subid">>, - xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, - result = {ps_error, 'invalid-subid', '$_'}}). --xml(pubsub_error_item_forbidden, - #elem{name = <<"item-forbidden">>, - xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, - result = {ps_error, 'item-forbidden', '$_'}}). --xml(pubsub_error_item_required, - #elem{name = <<"item-required">>, - xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, - result = {ps_error, 'item-required', '$_'}}). --xml(pubsub_error_jid_required, - #elem{name = <<"jid-required">>, - xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, - result = {ps_error, 'jid-required', '$_'}}). --xml(pubsub_error_max_items_exceeded, - #elem{name = <<"max-items-exceeded">>, - xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, - result = {ps_error, 'max-items-exceeded', '$_'}}). --xml(pubsub_error_max_nodes_exceeded, - #elem{name = <<"max-nodes-exceeded">>, - xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, - result = {ps_error, 'max-nodes-exceeded', '$_'}}). --xml(pubsub_error_nodeid_required, - #elem{name = <<"nodeid-required">>, - xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, - result = {ps_error, 'nodeid-required', '$_'}}). --xml(pubsub_error_not_in_roster_group, - #elem{name = <<"not-in-roster-group">>, - xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, - result = {ps_error, 'not-in-roster-group', '$_'}}). --xml(pubsub_error_not_subscribed, - #elem{name = <<"not-subscribed">>, - xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, - result = {ps_error, 'not-subscribed', '$_'}}). --xml(pubsub_error_payload_too_big, - #elem{name = <<"payload-too-big">>, - xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, - result = {ps_error, 'payload-too-big', '$_'}}). --xml(pubsub_error_payload_required, - #elem{name = <<"payload-required">>, - xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, - result = {ps_error, 'payload-required', '$_'}}). --xml(pubsub_error_pending_subscription, - #elem{name = <<"pending-subscription">>, - xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, - result = {ps_error, 'pending-subscription', '$_'}}). --xml(pubsub_error_presence_subscription_required, - #elem{name = <<"presence-subscription-required">>, - xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, - result = {ps_error, 'presence-subscription-required', '$_'}}). --xml(pubsub_error_subid_required, - #elem{name = <<"subid-required">>, - xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, - result = {ps_error, 'subid-required', '$_'}}). --xml(pubsub_error_too_many_subscriptions, - #elem{name = <<"too-many-subscriptions">>, - xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, - result = {ps_error, 'too-many-subscriptions', '$_'}}). --xml(pubsub_error_unsupported, - #elem{name = <<"unsupported">>, - xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, - result = {ps_error, 'unsupported', '$feature'}, - attrs = [#attr{name = <<"feature">>, required = true, - dec = {dec_enum, [['access-authorize', - 'access-open', - 'access-presence', - 'access-roster', - 'access-whitelist', - 'auto-create', - 'auto-subscribe', - 'collections', - 'config-node', - 'create-and-configure', - 'create-nodes', - 'delete-items', - 'delete-nodes', - 'filtered-notifications', - 'get-pending', - 'instant-nodes', - 'item-ids', - 'last-published', - 'leased-subscription', - 'manage-subscriptions', - 'member-affiliation', - 'meta-data', - 'modify-affiliations', - 'multi-collection', - 'multi-subscribe', - 'outcast-affiliation', - 'persistent-items', - 'presence-notifications', - 'presence-subscribe', - 'publish', - 'publish-options', - 'publish-only-affiliation', - 'publisher-affiliation', - 'purge-nodes', - 'retract-items', - 'retrieve-affiliations', - 'retrieve-default', - 'retrieve-items', - 'retrieve-subscriptions', - 'subscribe', - 'subscription-options', - 'subscription-notifications']]}, - enc = {enc_enum, []}}]}). --xml(pubsub_error_unsupported_access_model, - #elem{name = <<"unsupported-access-model">>, - xmlns = <<"http://jabber.org/protocol/pubsub#errors">>, - result = {ps_error, 'unsupported-access-model', '$_'}}). - --xml(shim_header, - #elem{name = <<"header">>, - xmlns = <<"http://jabber.org/protocol/shim">>, - result = {'$name', '$cdata'}, - attrs = [#attr{name = <<"name">>, - required = true}]}). - --xml(shim_headers, - #elem{name = <<"headers">>, - xmlns = <<"http://jabber.org/protocol/shim">>, - result = {shim, '$headers'}, - refs = [#ref{name = shim_header, label = '$headers'}]}). - --record(chatstate, {type :: active | composing | gone | inactive | paused}). --type chatstate() :: #chatstate{}. - --xml(chatstate_active, - #elem{name = <<"active">>, - xmlns = <<"http://jabber.org/protocol/chatstates">>, - result = {chatstate, active}}). - --xml(chatstate_composing, - #elem{name = <<"composing">>, - xmlns = <<"http://jabber.org/protocol/chatstates">>, - result = {chatstate, composing}}). - --xml(chatstate_gone, - #elem{name = <<"gone">>, - xmlns = <<"http://jabber.org/protocol/chatstates">>, - result = {chatstate, gone}}). - --xml(chatstate_inactive, - #elem{name = <<"inactive">>, - xmlns = <<"http://jabber.org/protocol/chatstates">>, - result = {chatstate, inactive}}). - --xml(chatstate_paused, - #elem{name = <<"paused">>, - xmlns = <<"http://jabber.org/protocol/chatstates">>, - result = {chatstate, paused}}). - --xml(delay, - #elem{name = <<"delay">>, - xmlns = <<"urn:xmpp:delay">>, - result = {delay, '$stamp', '$from', '$desc'}, - cdata = #cdata{label = '$desc', default = <<"">>}, - attrs = [#attr{name = <<"stamp">>, - required = true, - dec = {dec_utc, []}, - enc = {enc_utc, []}}, - #attr{name = <<"from">>, - dec = {dec_jid, []}, - enc = {enc_jid, []}}]}). - --xml(bytestreams_streamhost, - #elem{name = <<"streamhost">>, - xmlns = <<"http://jabber.org/protocol/bytestreams">>, - result = {streamhost, '$jid', '$host', '$port'}, - attrs = [#attr{name = <<"jid">>, - required = true, - dec = {dec_jid, []}, - enc = {enc_jid, []}}, - #attr{name = <<"host">>, - required = true}, - #attr{name = <<"port">>, - default = 1080, - dec = {dec_int, [0, 65535]}, - enc = {enc_int, []}}]}). - --xml(bytestreams_streamhost_used, - #elem{name = <<"streamhost-used">>, - xmlns = <<"http://jabber.org/protocol/bytestreams">>, - result = '$jid', - attrs = [#attr{name = <<"jid">>, - required = true, - dec = {dec_jid, []}, - enc = {enc_jid, []}}]}). - --xml(bytestreams_activate, - #elem{name = <<"activate">>, - xmlns = <<"http://jabber.org/protocol/bytestreams">>, - cdata = #cdata{enc = {enc_jid, []}, dec = {dec_jid, []}}, - result = '$cdata'}). - --xml(bytestreams, - #elem{name = <<"query">>, - xmlns = <<"http://jabber.org/protocol/bytestreams">>, - result = {bytestreams, '$hosts', '$used', '$activate', - '$dstaddr', '$mode', '$sid'}, - attrs = [#attr{name = <<"dstaddr">>}, - #attr{name = <<"sid">>}, - #attr{name = <<"mode">>, - default = tcp, - dec = {dec_enum, [[tcp, udp]]}, - enc = {enc_enum, []}}], - refs = [#ref{name = bytestreams_streamhost, label = '$hosts'}, - #ref{name = bytestreams_streamhost_used, - min = 0, max = 1, label = '$used'}, - #ref{name = bytestreams_activate, - min = 0, max = 1, label = '$activate'}]}). - --xml(muc_history, - #elem{name = <<"history">>, - xmlns = <<"http://jabber.org/protocol/muc">>, - result = {muc_history, '$maxchars', '$maxstanzas', - '$seconds', '$since'}, - attrs = [#attr{name = <<"maxchars">>, - dec = {dec_int, [0, infinity]}, - enc = {enc_int, []}}, - #attr{name = <<"maxstanzas">>, - dec = {dec_int, [0, infinity]}, - enc = {enc_int, []}}, - #attr{name = <<"seconds">>, - dec = {dec_int, [0, infinity]}, - enc = {enc_int, []}}, - #attr{name = <<"since">>, - dec = {dec_utc, []}, - enc = {enc_utc, []}}]}). - --xml(muc_reason, - #elem{name = <<"reason">>, - xmlns = [<<"http://jabber.org/protocol/muc#user">>, - <<"http://jabber.org/protocol/muc#admin">>, - <<"http://jabber.org/protocol/muc#owner">>], - result = '$cdata'}). - --xml(muc_user_decline, - #elem{name = <<"decline">>, - xmlns = <<"http://jabber.org/protocol/muc#user">>, - result = {muc_decline, '$reason', '$from', '$to'}, - attrs = [#attr{name = <<"to">>, - dec = {dec_jid, []}, - enc = {enc_jid, []}}, - #attr{name = <<"from">>, - dec = {dec_jid, []}, - enc = {enc_jid, []}}], - refs = [#ref{name = muc_reason, min = 0, - default = <<"">>, - max = 1, label = '$reason'}]}). - --xml(muc_destroy, - #elem{name = <<"destroy">>, - xmlns = [<<"http://jabber.org/protocol/muc#user">>, - <<"http://jabber.org/protocol/muc#owner">>], - result = {muc_destroy, '$xmlns', '$jid', '$reason', '$password'}, - attrs = [#attr{name = <<"jid">>, - dec = {dec_jid, []}, - enc = {enc_jid, []}}, - #attr{name = <<"xmlns">>}], - refs = [#ref{name = muc_reason, min = 0, - default = <<"">>, - max = 1, label = '$reason'}, - #ref{name = muc_password, min = 0, max = 1, - label = '$password'}]}). - --xml(muc_user_invite, - #elem{name = <<"invite">>, - xmlns = <<"http://jabber.org/protocol/muc#user">>, - result = {muc_invite, '$reason', '$from', '$to', '$continue'}, - attrs = [#attr{name = <<"to">>, - dec = {dec_jid, []}, - enc = {enc_jid, []}}, - #attr{name = <<"from">>, - dec = {dec_jid, []}, - enc = {enc_jid, []}}], - refs = [#ref{name = muc_reason, min = 0, default = <<"">>, - max = 1, label = '$reason'}, - #ref{name = muc_user_continue, min = 0, max = 1, - label = '$continue'}]}). - --xml(muc_user_actor, - #elem{name = <<"actor">>, - xmlns = <<"http://jabber.org/protocol/muc#user">>, - result = {muc_actor, '$jid', '$nick'}, - attrs = [#attr{name = <<"jid">>, - dec = {dec_jid, []}, - enc = {enc_jid, []}}, - #attr{name = <<"nick">>}]}). - --xml(muc_user_continue, - #elem{name = <<"continue">>, - xmlns = <<"http://jabber.org/protocol/muc#user">>, - result = '$thread', - attrs = [#attr{name = <<"thread">>}]}). - --xml(muc_user_status, - #elem{name = <<"status">>, - xmlns = <<"http://jabber.org/protocol/muc#user">>, - result = '$code', - attrs = [#attr{name = <<"code">>, - dec = {dec_int, [100, 999]}, - enc = {enc_int, []}}]}). - --xml(muc_user_item, - #elem{name = <<"item">>, - xmlns = <<"http://jabber.org/protocol/muc#user">>, - result = {muc_item, '$actor', '$continue', '$reason', - '$affiliation', '$role', '$jid', '$nick'}, - refs = [#ref{name = muc_user_actor, - min = 0, max = 1, label = '$actor'}, - #ref{name = muc_user_continue, - min = 0, max = 1, label = '$continue'}, - #ref{name = muc_reason, default = <<"">>, - min = 0, max = 1, label = '$reason'}], - attrs = [#attr{name = <<"affiliation">>, - dec = {dec_enum, [[admin, member, none, - outcast, owner]]}, - enc = {enc_enum, []}}, - #attr{name = <<"role">>, - dec = {dec_enum, [[moderator, none, - participant, visitor]]}, - enc = {enc_enum, []}}, - #attr{name = <<"jid">>, - dec = {dec_jid, []}, - enc = {enc_jid, []}}, - #attr{name = <<"nick">>}]}). - --xml(muc_user, - #elem{name = <<"x">>, - xmlns = <<"http://jabber.org/protocol/muc#user">>, - result = {muc_user, '$decline', '$destroy', '$invites', - '$items', '$status_codes', '$password'}, - refs = [#ref{name = muc_user_decline, min = 0, - max = 1, label = '$decline'}, - #ref{name = muc_destroy, min = 0, max = 1, - label = '$destroy'}, - #ref{name = muc_password, min = 0, max = 1, - label = '$password'}, - #ref{name = muc_user_invite, label = '$invites'}, - #ref{name = muc_user_item, label = '$items'}, - #ref{name = muc_user_status, label = '$status_codes'}]}). - --xml(muc_password, - #elem{name = <<"password">>, - xmlns = [<<"http://jabber.org/protocol/muc#owner">>, - <<"http://jabber.org/protocol/muc#user">>, - <<"http://jabber.org/protocol/muc">>], - result = '$cdata'}). - --xml(muc_owner, - #elem{name = <<"query">>, - xmlns = <<"http://jabber.org/protocol/muc#owner">>, - result = {muc_owner, '$destroy', '$config', '$items'}, - refs = [#ref{name = muc_destroy, min = 0, max = 1, - label = '$destroy'}, - #ref{name = xdata, min = 0, max = 1, - label = '$config'}, - #ref{name = muc_owner_item, label = '$items'}]}). - --xml(muc_owner_item, - #elem{name = <<"item">>, - xmlns = <<"http://jabber.org/protocol/muc#owner">>, - result = {muc_item, '$actor', '$continue', '$reason', - '$affiliation', '$role', '$jid', '$nick'}, - refs = [#ref{name = muc_admin_actor, - min = 0, max = 1, label = '$actor'}, - #ref{name = muc_admin_continue, - min = 0, max = 1, label = '$continue'}, - #ref{name = muc_reason, default = <<"">>, - min = 0, max = 1, label = '$reason'}], - attrs = [#attr{name = <<"affiliation">>, - dec = {dec_enum, [[admin, member, none, - outcast, owner]]}, - enc = {enc_enum, []}}, - #attr{name = <<"role">>, - dec = {dec_enum, [[moderator, none, - participant, visitor]]}, - enc = {enc_enum, []}}, - #attr{name = <<"jid">>, - dec = {dec_jid, []}, - enc = {enc_jid, []}}, - #attr{name = <<"nick">>}]}). - --xml(muc_admin_item, - #elem{name = <<"item">>, - xmlns = <<"http://jabber.org/protocol/muc#admin">>, - result = {muc_item, '$actor', '$continue', '$reason', - '$affiliation', '$role', '$jid', '$nick'}, - refs = [#ref{name = muc_admin_actor, - min = 0, max = 1, label = '$actor'}, - #ref{name = muc_admin_continue, - min = 0, max = 1, label = '$continue'}, - #ref{name = muc_reason, default = <<"">>, - min = 0, max = 1, label = '$reason'}], - attrs = [#attr{name = <<"affiliation">>, - dec = {dec_enum, [[admin, member, none, - outcast, owner]]}, - enc = {enc_enum, []}}, - #attr{name = <<"role">>, - dec = {dec_enum, [[moderator, none, - participant, visitor]]}, - enc = {enc_enum, []}}, - #attr{name = <<"jid">>, - dec = {dec_jid, []}, - enc = {enc_jid, []}}, - #attr{name = <<"nick">>}]}). - --xml(muc_admin_actor, - #elem{name = <<"actor">>, - xmlns = <<"http://jabber.org/protocol/muc#admin">>, - result = {muc_actor, '$jid', '$nick'}, - attrs = [#attr{name = <<"jid">>, - dec = {dec_jid, []}, - enc = {enc_jid, []}}, - #attr{name = <<"nick">>}]}). - --xml(muc_admin_continue, - #elem{name = <<"continue">>, - xmlns = <<"http://jabber.org/protocol/muc#admin">>, - result = '$thread', - attrs = [#attr{name = <<"thread">>}]}). - --xml(muc_admin, - #elem{name = <<"query">>, - xmlns = <<"http://jabber.org/protocol/muc#admin">>, - result = {muc_admin, '$items'}, - refs = [#ref{name = muc_admin_item, label = '$items'}]}). - --xml(muc, - #elem{name = <<"x">>, - xmlns = <<"http://jabber.org/protocol/muc">>, - result = {muc, '$history', '$password'}, - refs = [#ref{name = muc_history, min = 0, max = 1, - label = '$history'}, - #ref{name = muc_password, min = 0, max = 1, - label = '$password'}]}). - --xml(muc_unique, - #elem{name = <<"unique">>, - xmlns = <<"http://jabber.org/protocol/muc#unique">>, - result = {muc_unique, '$name'}, - cdata = #cdata{default = <<"">>, - label = '$name'}}). - --xml(x_conference, - #elem{name = <<"x">>, - xmlns = <<"jabber:x:conference">>, - result = {x_conference, '$jid', '$password', '$reason', - '$continue', '$thread'}, - attrs = [#attr{name = <<"jid">>, - required = true, - dec = {dec_jid, []}, - enc = {enc_jid, []}}, - #attr{name = <<"password">>, default = <<"">>}, - #attr{name = <<"reason">>, default = <<"">>}, - #attr{name = <<"thread">>, default = <<"">>}, - #attr{name = <<"continue">>, - dec = {dec_bool, []}, - enc = {enc_bool, []}}]}). - --xml(muc_subscription, - #elem{name = <<"subscription">>, - xmlns = <<"urn:xmpp:mucsub:0">>, - result = '$jid', - attrs = [#attr{name = <<"jid">>, - required = true, - dec = {dec_jid, []}, - enc = {enc_jid, []}}]}). - --xml(muc_subscriptions, - #elem{name = <<"subscriptions">>, - xmlns = <<"urn:xmpp:mucsub:0">>, - result = {muc_subscriptions, '$list'}, - refs = [#ref{name = muc_subscription, label = '$list'}]}). - --xml(muc_subscribe_event, - #elem{name = <<"event">>, - xmlns = <<"urn:xmpp:mucsub:0">>, - result = '$node', - attrs = [#attr{name = <<"node">>, required = true}]}). - --xml(muc_subscribe, - #elem{name = <<"subscribe">>, - xmlns = <<"urn:xmpp:mucsub:0">>, - result = {muc_subscribe, '$nick', '$events'}, - attrs = [#attr{name = <<"nick">>, required = true}], - refs = [#ref{name = muc_subscribe_event, label = '$events'}]}). - --xml(muc_unsubscribe, - #elem{name = <<"unsubscribe">>, - xmlns = <<"urn:xmpp:mucsub:0">>, - result = {muc_unsubscribe}}). - --xml(rsm_after, - #elem{name = <<"after">>, - xmlns = <<"http://jabber.org/protocol/rsm">>, - result = '$cdata'}). - --xml(rsm_before, - #elem{name = <<"before">>, - xmlns = <<"http://jabber.org/protocol/rsm">>, - cdata = #cdata{default = <<"">>}, - result = '$cdata'}). - --xml(rsm_last, - #elem{name = <<"last">>, - xmlns = <<"http://jabber.org/protocol/rsm">>, - result = '$cdata'}). - --xml(rsm_count, - #elem{name = <<"count">>, result = '$cdata', - xmlns = <<"http://jabber.org/protocol/rsm">>, - cdata = #cdata{dec = {dec_int, [0, infinity]}, - enc = {enc_int, []}}}). - --xml(rsm_index, - #elem{name = <<"index">>, result = '$cdata', - xmlns = <<"http://jabber.org/protocol/rsm">>, - cdata = #cdata{dec = {dec_int, [0, infinity]}, - enc = {enc_int, []}}}). - --xml(rsm_max, - #elem{name = <<"max">>, result = '$cdata', - xmlns = <<"http://jabber.org/protocol/rsm">>, - cdata = #cdata{dec = {dec_int, [0, infinity]}, - enc = {enc_int, []}}}). - --xml(rsm_first, - #elem{name = <<"first">>, - xmlns = <<"http://jabber.org/protocol/rsm">>, - result = {rsm_first, '$index', '$data'}, - cdata = #cdata{label = '$data'}, - attrs = [#attr{name = <<"index">>, - dec = {dec_int, [0, infinity]}, - enc = {enc_int, []}}]}). - --xml(rsm_set, - #elem{name = <<"set">>, - xmlns = <<"http://jabber.org/protocol/rsm">>, - result = {rsm_set, '$after', '$before', '$count', - '$first', '$index', '$last', '$max'}, - refs = [#ref{name = rsm_after, label = '$after', min = 0, max = 1}, - #ref{name = rsm_before, label = '$before', min = 0, max = 1}, - #ref{name = rsm_count, label = '$count', min = 0, max = 1}, - #ref{name = rsm_first, label = '$first', min = 0, max = 1}, - #ref{name = rsm_index, label = '$index', min = 0, max = 1}, - #ref{name = rsm_last, label = '$last', min = 0, max = 1}, - #ref{name = rsm_max, label = '$max', min = 0, max = 1}]}). - --xml(mam_start, - #elem{name = <<"start">>, - xmlns = <<"urn:xmpp:mam:tmp">>, - result = '$cdata', - cdata = #cdata{required = true, - dec = {dec_utc, []}, - enc = {enc_utc, []}}}). - --xml(mam_end, - #elem{name = <<"end">>, - xmlns = <<"urn:xmpp:mam:tmp">>, - result = '$cdata', - cdata = #cdata{required = true, - dec = {dec_utc, []}, - enc = {enc_utc, []}}}). - --xml(mam_with, - #elem{name = <<"with">>, - xmlns = <<"urn:xmpp:mam:tmp">>, - result = '$cdata', - cdata = #cdata{required = true, - dec = {dec_jid, []}, - enc = {enc_jid, []}}}). - --xml(mam_withtext, - #elem{name = <<"withtext">>, - xmlns = <<"urn:xmpp:mam:tmp">>, - result = '$cdata', - cdata = #cdata{required = true}}). - --xml(mam_query, - #elem{name = <<"query">>, - xmlns = [<<"urn:xmpp:mam:0">>, <<"urn:xmpp:mam:1">>, <<"urn:xmpp:mam:tmp">>], - result = {mam_query, '$xmlns', '$id', '$start', '$end', '$with', - '$withtext', '$rsm', '$xdata'}, - attrs = [#attr{name = <<"queryid">>, label = '$id'}, - #attr{name = <<"xmlns">>}], - refs = [#ref{name = mam_start, min = 0, max = 1, label = '$start'}, - #ref{name = mam_end, min = 0, max = 1, label = '$end'}, - #ref{name = mam_with, min = 0, max = 1, label = '$with'}, - #ref{name = mam_withtext, min = 0, max = 1, label = '$withtext'}, - #ref{name = rsm_set, min = 0, max = 1, label = '$rsm'}, - #ref{name = xdata, min = 0, max = 1, label = '$xdata'}]}). - --xml(mam_archived, - #elem{name = <<"archived">>, - xmlns = <<"urn:xmpp:mam:tmp">>, - result = {mam_archived, '$by', '$id'}, - attrs = [#attr{name = <<"id">>}, - #attr{name = <<"by">>, - required = true, - dec = {dec_jid, []}, - enc = {enc_jid, []}}]}). - --xml(mam_result, - #elem{name = <<"result">>, - xmlns = [<<"urn:xmpp:mam:0">>, <<"urn:xmpp:mam:1">>, <<"urn:xmpp:mam:tmp">>], - result = {mam_result, '$xmlns', '$queryid', '$id', '$_els'}, - attrs = [#attr{name = <<"queryid">>}, - #attr{name = <<"xmlns">>}, - #attr{name = <<"id">>}]}). - --xml(mam_jid, - #elem{name = <<"jid">>, - xmlns = [<<"urn:xmpp:mam:0">>, <<"urn:xmpp:mam:1">>, <<"urn:xmpp:mam:tmp">>], - result = '$cdata', - cdata = #cdata{required = true, - dec = {dec_jid, []}, - enc = {enc_jid, []}}}). - --xml(mam_never, - #elem{name = <<"never">>, - xmlns = [<<"urn:xmpp:mam:0">>, <<"urn:xmpp:mam:1">>, <<"urn:xmpp:mam:tmp">>], - result = '$jids', - refs = [#ref{name = mam_jid, label = '$jids'}]}). - --xml(mam_always, - #elem{name = <<"always">>, - xmlns = [<<"urn:xmpp:mam:0">>, <<"urn:xmpp:mam:1">>, <<"urn:xmpp:mam:tmp">>], - result = '$jids', - refs = [#ref{name = mam_jid, label = '$jids'}]}). - --xml(mam_prefs, - #elem{name = <<"prefs">>, - xmlns = [<<"urn:xmpp:mam:0">>, <<"urn:xmpp:mam:1">>, <<"urn:xmpp:mam:tmp">>], - result = {mam_prefs, '$xmlns', '$default', '$always', '$never'}, - attrs = [#attr{name = <<"default">>, - dec = {dec_enum, [[always, never, roster]]}, - enc = {enc_enum, []}}, - #attr{name = <<"xmlns">>}], - refs = [#ref{name = mam_always, label = '$always', - min = 0, max = 1}, - #ref{name = mam_never, label = '$never', - min = 0, max = 1}]}). - --xml(mam_fin, - #elem{name = <<"fin">>, - xmlns = [<<"urn:xmpp:mam:0">>, <<"urn:xmpp:mam:1">>], - result = {mam_fin, '$xmlns', '$id', '$rsm', '$stable', '$complete'}, - attrs = [#attr{name = <<"queryid">>, label = '$id'}, - #attr{name = <<"xmlns">>}, - #attr{name = <<"stable">>, label = '$stable', - dec = {dec_bool, []}, - enc = {enc_bool, []}}, - #attr{name = <<"complete">>, label = '$complete', - dec = {dec_bool, []}, - enc = {enc_bool, []}}], - refs = [#ref{name = rsm_set, min = 0, max = 1, label = '$rsm'}]}). - --xml(forwarded, - #elem{name = <<"forwarded">>, - xmlns = <<"urn:xmpp:forward:0">>, - result = {forwarded, '$delay', '$_xmls'}, - refs = [#ref{name = delay, min = 0, - max = 1, label = '$delay'}]}). - --xml(carbons_disable, - #elem{name = <<"disable">>, - xmlns = <<"urn:xmpp:carbons:2">>, - result = {carbons_disable}}). - --xml(carbons_enable, - #elem{name = <<"enable">>, - xmlns = <<"urn:xmpp:carbons:2">>, - result = {carbons_enable}}). - --xml(carbons_private, - #elem{name = <<"private">>, - xmlns = <<"urn:xmpp:carbons:2">>, - result = {carbons_private}}). - --xml(carbons_received, - #elem{name = <<"received">>, - xmlns = <<"urn:xmpp:carbons:2">>, - result = {carbons_received, '$forwarded'}, - refs = [#ref{name = forwarded, min = 1, - max = 1, label = '$forwarded'}]}). - --xml(carbons_sent, - #elem{name = <<"sent">>, - xmlns = <<"urn:xmpp:carbons:2">>, - result = {carbons_sent, '$forwarded'}, - refs = [#ref{name = forwarded, min = 1, - max = 1, label = '$forwarded'}]}). - --xml(feature_csi, - #elem{name = <<"csi">>, - xmlns = <<"urn:xmpp:csi:0">>, - result = {feature_csi, '$xmlns'}, - attrs = [#attr{name = <<"xmlns">>}]}). - --record(csi, {type :: active | inactive}). --type csi() :: #csi{}. - --xml(csi_active, - #elem{name = <<"active">>, - xmlns = <<"urn:xmpp:csi:0">>, - result = {csi, active}}). - --xml(csi_inactive, - #elem{name = <<"inactive">>, - xmlns = <<"urn:xmpp:csi:0">>, - result = {csi, inactive}}). - --xml(feature_sm, - #elem{name = <<"sm">>, - xmlns = [<<"urn:xmpp:sm:2">>, <<"urn:xmpp:sm:3">>], - result = {feature_sm, '$xmlns'}, - attrs = [#attr{name = <<"xmlns">>}]}). - --xml(sm_enable, - #elem{name = <<"enable">>, - xmlns = [<<"urn:xmpp:sm:2">>, <<"urn:xmpp:sm:3">>], - result = {sm_enable, '$max', '$resume', '$xmlns'}, - attrs = [#attr{name = <<"max">>, - dec = {dec_int, [0, infinity]}, - enc = {enc_int, []}}, - #attr{name = <<"xmlns">>}, - #attr{name = <<"resume">>, - default = false, - dec = {dec_bool, []}, - enc = {enc_bool, []}}]}). - --xml(sm_enabled, - #elem{name = <<"enabled">>, - xmlns = [<<"urn:xmpp:sm:2">>, <<"urn:xmpp:sm:3">>], - result = {sm_enabled, '$id', '$location', '$max', '$resume', '$xmlns'}, - attrs = [#attr{name = <<"id">>}, - #attr{name = <<"location">>}, - #attr{name = <<"xmlns">>}, - #attr{name = <<"max">>, - dec = {dec_int, [0, infinity]}, - enc = {enc_int, []}}, - #attr{name = <<"resume">>, - default = false, - dec = {dec_bool, []}, - enc = {enc_bool, []}}]}). - --xml(sm_resume, - #elem{name = <<"resume">>, - xmlns = [<<"urn:xmpp:sm:2">>, <<"urn:xmpp:sm:3">>], - result = {sm_resume, '$h', '$previd', '$xmlns'}, - attrs = [#attr{name = <<"h">>, - required = true, - dec = {dec_int, [0, infinity]}, - enc = {enc_int, []}}, - #attr{name = <<"xmlns">>}, - #attr{name = <<"previd">>, - required = true}]}). - --xml(sm_resumed, - #elem{name = <<"resumed">>, - xmlns = [<<"urn:xmpp:sm:2">>, <<"urn:xmpp:sm:3">>], - result = {sm_resumed, '$h', '$previd', '$xmlns'}, - attrs = [#attr{name = <<"h">>, - required = true, - dec = {dec_int, [0, infinity]}, - enc = {enc_int, []}}, - #attr{name = <<"xmlns">>}, - #attr{name = <<"previd">>, - required = true}]}). - --xml(sm_r, - #elem{name = <<"r">>, - xmlns = [<<"urn:xmpp:sm:2">>, <<"urn:xmpp:sm:3">>], - result = {sm_r, '$xmlns'}, - attrs = [#attr{name = <<"xmlns">>}]}). - --xml(sm_a, - #elem{name = <<"a">>, - xmlns = [<<"urn:xmpp:sm:2">>, <<"urn:xmpp:sm:3">>], - result = {sm_a, '$h', '$xmlns'}, - attrs = [#attr{name = <<"h">>, - required = true, - dec = {dec_int, [0, infinity]}, - enc = {enc_int, []}}, - #attr{name = <<"xmlns">>}]}). - --xml(sm_failed, - #elem{name = <<"failed">>, - xmlns = [<<"urn:xmpp:sm:2">>, <<"urn:xmpp:sm:3">>], - result = {sm_failed, '$reason', '$h', '$xmlns'}, - attrs = [#attr{name = <<"h">>, - dec = {dec_int, [0, infinity]}, - enc = {enc_int, []}}, - #attr{name = <<"xmlns">>}], - refs = [#ref{name = error_bad_request, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_conflict, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_feature_not_implemented, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_forbidden, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_gone, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_internal_server_error, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_item_not_found, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_jid_malformed, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_not_acceptable, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_not_allowed, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_not_authorized, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_policy_violation, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_recipient_unavailable, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_redirect, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_registration_required, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_remote_server_not_found, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_remote_server_timeout, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_resource_constraint, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_service_unavailable, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_subscription_required, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_undefined_condition, - min = 0, max = 1, label = '$reason'}, - #ref{name = error_unexpected_request, - min = 0, max = 1, label = '$reason'}]}). - --xml(offline_purge, - #elem{name = <<"purge">>, - xmlns = <<"http://jabber.org/protocol/offline">>, - result = true}). - --xml(offline_fetch, - #elem{name = <<"fetch">>, - xmlns = <<"http://jabber.org/protocol/offline">>, - result = true}). - --xml(offline_item, - #elem{name = <<"item">>, - xmlns = <<"http://jabber.org/protocol/offline">>, - result = {offline_item, '$node', '$action'}, - attrs = [#attr{name = <<"node">>}, - #attr{name = <<"action">>, - dec = {dec_enum, [[view, remove]]}, - enc = {enc_enum, []}}]}). - --xml(offline, - #elem{name = <<"offline">>, - xmlns = <<"http://jabber.org/protocol/offline">>, - result = {offline, '$items', '$purge', '$fetch'}, - refs = [#ref{name = offline_purge, min = 0, max = 1, - label = '$purge', default = false}, - #ref{name = offline_fetch, min = 0, max = 1, - label = '$fetch', default = false}, - #ref{name = offline_item, min = 0, label = '$items'}]}). - --xml(mix_subscribe, - #elem{name = <<"subscribe">>, - xmlns = <<"urn:xmpp:mix:0">>, - result = '$node', - attrs = [#attr{name = <<"node">>, - required = true, - label = '$node'}]}). - --xml(mix_join, - #elem{name = <<"join">>, - xmlns = <<"urn:xmpp:mix:0">>, - result = {mix_join, '$jid', '$subscribe'}, - attrs = [#attr{name = <<"jid">>, - label = '$jid', - dec = {dec_jid, []}, - enc = {enc_jid, []}}], - refs = [#ref{name = mix_subscribe, min = 0, label = '$subscribe'}]}). - --xml(mix_leave, - #elem{name = <<"leave">>, - xmlns = <<"urn:xmpp:mix:0">>, - result = {mix_leave}}). - --xml(mix_participant, - #elem{name = <<"participant">>, - xmlns = <<"urn:xmpp:mix:0">>, - result = {mix_participant, '$jid', '$nick'}, - attrs = [#attr{name = <<"jid">>, - required = true, - label = '$jid', - dec = {dec_jid, []}, - enc = {enc_jid, []}}, - #attr{name = <<"nick">>, - label = '$nick'}]}). - --record(hint, {type :: 'no-copy' | 'no-store' | 'no-storage' | 'store' | - 'no-permanent-store' | 'no-permanent-storage'}). --type hint() :: #hint{}. - --xml(hint_no_copy, - #elem{name = <<"no-copy">>, - xmlns = <<"urn:xmpp:hints">>, - result = {hint, 'no-copy'}}). - --xml(hint_no_store, - #elem{name = <<"no-store">>, - xmlns = <<"urn:xmpp:hints">>, - result = {hint, 'no-store'}}). - --xml(hint_no_storage, - #elem{name = <<"no-storage">>, - xmlns = <<"urn:xmpp:hints">>, - result = {hint, 'no-storage'}}). - --xml(hint_store, - #elem{name = <<"store">>, - xmlns = <<"urn:xmpp:hints">>, - result = {hint, 'store'}}). - --xml(hint_no_permanent_store, - #elem{name = <<"no-permanent-store">>, - xmlns = <<"urn:xmpp:hints">>, - result = {hint, 'no-permanent-store'}}). - --xml(hint_no_permanent_storage, - #elem{name = <<"no-permanent-storage">>, - xmlns = <<"urn:xmpp:hints">>, - result = {hint, 'no-permanent-storage'}}). - --xml(search_instructions, - #elem{name = <<"instructions">>, - xmlns = <<"jabber:iq:search">>, - result = '$cdata'}). - --xml(search_first, - #elem{name = <<"first">>, - xmlns = <<"jabber:iq:search">>, - cdata = #cdata{default = <<"">>}, - result = '$cdata'}). --xml(search_last, - #elem{name = <<"last">>, - xmlns = <<"jabber:iq:search">>, - cdata = #cdata{default = <<"">>}, - result = '$cdata'}). --xml(search_nick, - #elem{name = <<"nick">>, - xmlns = <<"jabber:iq:search">>, - cdata = #cdata{default = <<"">>}, - result = '$cdata'}). --xml(search_email, - #elem{name = <<"email">>, - xmlns = <<"jabber:iq:search">>, - cdata = #cdata{default = <<"">>}, - result = '$cdata'}). - --xml(search_item, - #elem{name = <<"item">>, - xmlns = <<"jabber:iq:search">>, - result = {search_item, '$jid', '$first', '$last', '$nick', '$email'}, - attrs = [#attr{name = <<"jid">>, - required = true, - enc = {enc_jid, []}, - dec = {dec_jid, []}}], - refs = [#ref{name = search_first, min = 0, max = 1, - label = '$first'}, - #ref{name = search_last, min = 0, max = 1, - label = '$last'}, - #ref{name = search_nick, min = 0, max = 1, - label = '$nick'}, - #ref{name = search_email, min = 0, max = 1, - label = '$email'}]}). - --xml(search, - #elem{name = <<"query">>, - xmlns = <<"jabber:iq:search">>, - result = {search, '$instructions', '$first', '$last', - '$nick', '$email', '$items', '$xdata'}, - refs = [#ref{name = search_instructions, min = 0, max = 1, - label = '$instructions'}, - #ref{name = search_first, min = 0, max = 1, - label = '$first'}, - #ref{name = search_last, min = 0, max = 1, - label = '$last'}, - #ref{name = search_nick, min = 0, max = 1, - label = '$nick'}, - #ref{name = search_email, min = 0, max = 1, - label = '$email'}, - #ref{name = search_item, label = '$items'}, - #ref{name = xdata, min = 0, max = 1, - label = '$xdata'}]}). - --xml(xevent_offline, - #elem{name = <<"offline">>, - xmlns = <<"jabber:x:event">>, - result = true}). --xml(xevent_delivered, - #elem{name = <<"delivered">>, - xmlns = <<"jabber:x:event">>, - result = true}). --xml(xevent_displayed, - #elem{name = <<"displayed">>, - xmlns = <<"jabber:x:event">>, - result = true}). --xml(xevent_composing, - #elem{name = <<"composing">>, - xmlns = <<"jabber:x:event">>, - result = true}). --xml(xevent_id, - #elem{name = <<"id">>, - xmlns = <<"jabber:x:event">>, - cdata = #cdata{}, - result = '$cdata'}). - --xml(xevent, - #elem{name = <<"x">>, - xmlns = <<"jabber:x:event">>, - result = {xevent, '$offline', '$delivered', '$displayed', - '$composing', '$id'}, - refs = [#ref{name = xevent_offline, min = 0, max = 1, - label = '$offline', default = false}, - #ref{name = xevent_delivered, min = 0, max = 1, - label = '$delivered', default = false}, - #ref{name = xevent_displayed, min = 0, max = 1, - label = '$displayed', default = false}, - #ref{name = xevent_composing, min = 0, max = 1, - label = '$composing', default = false}, - #ref{name = xevent_id, min = 0, max = 1, - label = '$id'}]}). - --xml(expire, - #elem{name = <<"x">>, - xmlns = <<"jabber:x:expire">>, - result = {expire, '$seconds', '$stored'}, - attrs = [#attr{name = <<"seconds">>, - required = true, - dec = {dec_int, [0, infinity]}, - enc = {enc_int, []}}, - #attr{name = <<"stored">>, - dec = {dec_int, [0, infinity]}, - enc = {enc_int, []}}]}). - --xml(nick, - #elem{name = <<"nick">>, - xmlns = <<"http://jabber.org/protocol/nick">>, - result = {nick, '$name'}, - cdata = #cdata{label = '$name', - required = true}}). - --xml(address, - #elem{name = <<"address">>, - xmlns = <<"http://jabber.org/protocol/address">>, - result = {address, '$type', '$jid', '$desc', '$node', '$delivered'}, - attrs = [#attr{name = <<"type">>, - required = true, - dec = {dec_enum, [[bcc, cc, noreply, ofrom, - replyroom, replyto, to]]}, - enc = {enc_enum, []}}, - #attr{name = <<"jid">>, - enc = {enc_jid, []}, - dec = {dec_jid, []}}, - #attr{name = <<"desc">>}, - #attr{name = <<"node">>}, - #attr{name = <<"delivered">>, - enc = {enc_bool, []}, - dec = {dec_bool, []}}]}). - --xml(addresses, - #elem{name = <<"addresses">>, - xmlns = <<"http://jabber.org/protocol/address">>, - result = {addresses, '$list'}, - %% TODO: 'min' should be '1', but this is not implemented - refs = [#ref{name = address, label = '$list'}]}). - --xml(stanza_id, - #elem{name = <<"stanza-id">>, - xmlns = <<"urn:xmpp:sid:0">>, - result = {stanza_id, '$by', '$id'}, - attrs = [#attr{name = <<"id">>, required = true}, - #attr{name = <<"by">>, required = true, - enc = {enc_jid, []}, - dec = {dec_jid, []}}]}). - --xml(client_id, - #elem{name = <<"client-id">>, - xmlns = <<"urn:xmpp:sid:0">>, - result = {client_id, '$id'}, - attrs = [#attr{name = <<"id">>, required = true}]}). - --xml(adhoc_command_prev, - #elem{name = <<"prev">>, - xmlns = <<"http://jabber.org/protocol/commands">>, - result = true}). --xml(adhoc_command_next, - #elem{name = <<"next">>, - xmlns = <<"http://jabber.org/protocol/commands">>, - result = true}). --xml(adhoc_command_complete, - #elem{name = <<"complete">>, - xmlns = <<"http://jabber.org/protocol/commands">>, - result = true}). - --xml(adhoc_command_actions, - #elem{name = <<"actions">>, - xmlns = <<"http://jabber.org/protocol/commands">>, - result = {adhoc_actions, '$execute', '$prev', '$next', '$complete'}, - attrs = [#attr{name = <<"execute">>, - dec = {dec_enum, [[complete, next, prev]]}, - enc = {enc_enum, []}}], - refs = [#ref{name = adhoc_command_prev, min = 0, max = 1, - default = false, label = '$prev'}, - #ref{name = adhoc_command_next, min = 0, max = 1, - default = false, label = '$next'}, - #ref{name = adhoc_command_complete, min = 0, max = 1, - default = false, label = '$complete'}]}). - --xml(adhoc_command_notes, - #elem{name = <<"note">>, - xmlns = <<"http://jabber.org/protocol/commands">>, - result = {adhoc_note, '$type', '$data'}, - attrs = [#attr{name = <<"type">>, default = info, - dec = {dec_enum, [[info, warn, error]]}, - enc = {enc_enum, []}}], - cdata = #cdata{default = <<"">>, label = '$data'}}). - --xml(adhoc_command, - #elem{name = <<"command">>, - xmlns = <<"http://jabber.org/protocol/commands">>, - result = {adhoc_command, '$node', '$action', '$sid', - '$status', '$lang', '$actions', '$notes', '$xdata'}, - attrs = [#attr{name = <<"node">>, required = true}, - #attr{name = <<"xml:lang">>, label = '$lang'}, - #attr{name = <<"sessionid">>, label = '$sid'}, - #attr{name = <<"status">>, - dec = {dec_enum, [[canceled, completed, executing]]}, - enc = {enc_enum, []}}, - #attr{name = <<"action">>, default = execute, - dec = {dec_enum, [[cancel, complete, - execute, next, prev]]}, - enc = {enc_enum, []}}], - refs = [#ref{name = adhoc_command_actions, min = 0, max = 1, - label = '$actions'}, - #ref{name = xdata, min = 0, max = 1}, - #ref{name = adhoc_command_notes, label = '$notes'}]}). - --xml(db_result, - #elem{name = <<"db:result">>, - xmlns = <<"jabber:server">>, - result = {db_result, '$from', '$to', '$type', '$key', '$_els'}, - cdata = #cdata{default = <<"">>, label = '$key'}, - attrs = [#attr{name = <<"from">>, required = true, - dec = {nameprep, []}, enc = {nameprep, []}}, - #attr{name = <<"to">>, required = true, - dec = {nameprep, []}, enc = {nameprep, []}}, - #attr{name = <<"type">>, - dec = {dec_enum, [[valid, invalid, error]]}, - enc = {enc_enum, []}}]}). - --xml(db_verify, - #elem{name = <<"db:verify">>, - xmlns = <<"jabber:server">>, - result = {db_verify, '$from', '$to', '$id', '$type', '$key', '$_els'}, - cdata = #cdata{default = <<"">>, label = '$key'}, - attrs = [#attr{name = <<"from">>, required = true, - dec = {nameprep, []}, enc = {nameprep, []}}, - #attr{name = <<"to">>, required = true, - dec = {nameprep, []}, enc = {nameprep, []}}, - #attr{name = <<"id">>, required = true}, - #attr{name = <<"type">>, - dec = {dec_enum, [[valid, invalid, error]]}, - enc = {enc_enum, []}}]}). - --xml(handshake, - #elem{name = <<"handshake">>, - xmlns = <<"jabber:component:accept">>, - result = {handshake, '$data'}, - cdata = #cdata{default = <<"">>, label = '$data'}}). - --xml(stream_start, - #elem{name = <<"stream:stream">>, - xmlns = [<<"jabber:client">>, <<"jabber:server">>, - <<"jabber:component:accept">>], - result = {stream_start, '$from', '$to', '$id', - '$version', '$xmlns', '$stream_xmlns', - '$db_xmlns', '$lang'}, - attrs = [#attr{name = <<"from">>, - dec = {dec_jid, []}, - enc = {enc_jid, []}}, - #attr{name = <<"to">>, - dec = {dec_jid, []}, - enc = {enc_jid, []}}, - #attr{name = <<"xmlns">>}, - #attr{name = <<"xmlns:stream">>, - label = '$stream_xmlns', - default = <<"">>}, - #attr{name = <<"xmlns:db">>, - label = '$db_xmlns', - default = <<"">>}, - #attr{name = <<"xml:lang">>, label = '$lang', - default = <<"">>}, - #attr{name = <<"version">>, - dec = {dec_version, []}, - enc = {enc_version, []}}, - #attr{name = <<"id">>, default = <<"">>}]}). - --xml(bob_data, - #elem{name = <<"data">>, - xmlns = <<"urn:xmpp:bob">>, - result = {bob_data, '$cid', '$max-age', '$type', '$data'}, - attrs = [#attr{name = <<"cid">>, required = true}, - #attr{name = <<"max-age">>, - dec = {dec_int, [0, infinity]}, - enc = {enc_int, []}}, - #attr{name = <<"type">>}], - cdata = #cdata{label = '$data', default = <<"">>, - dec = {base64, decode, []}, - enc = {base64, encode, []}}}). - --xml(captcha, - #elem{name = <<"captcha">>, - xmlns = <<"urn:xmpp:captcha">>, - result = {xcaptcha, '$xdata'}, - refs = [#ref{name = xdata, min = 1, max = 1}]}). - --xml(media_uri, - #elem{name = <<"uri">>, - xmlns = <<"urn:xmpp:media-element">>, - result = {media_uri, '$type', '$uri'}, - attrs = [#attr{name = <<"type">>, required = true}], - cdata = #cdata{label = '$uri', default = <<"">>}}). - --xml(media, - #elem{name = <<"media">>, - xmlns = <<"urn:xmpp:media-element">>, - result = {media, '$height', '$width', '$uri'}, - attrs = [#attr{name = <<"height">>, - dec = {dec_int, [0, infinity]}, - enc = {enc_int, []}}, - #attr{name = <<"width">>, - dec = {dec_int, [0, inifinity]}, - enc = {enc_int, []}}], - refs = [#ref{name = media_uri, label = '$uri'}]}). - --xml(oob_url, - #elem{name = <<"url">>, - xmlns = <<"jabber:x:oob">>, - result = '$cdata', - cdata = #cdata{required = true}}). - --xml(oob_desc, - #elem{name = <<"desc">>, - xmlns = <<"jabber:x:oob">>, - result = '$cdata', - cdata = #cdata{default = <<"">>}}). - --xml(oob_x, - #elem{name = <<"x">>, - xmlns = <<"jabber:x:oob">>, - result = {oob_x, '$url', '$desc', '$sid'}, - attrs = [#attr{name = <<"sid">>, default = <<"">>}], - refs = [#ref{name = oob_url, min = 1, max = 1, - label = '$url'}, - #ref{name = oob_desc, default = <<"">>, - min = 0, max = 1, label = '$desc'}]}). - --xml(sic_ip, - #elem{name = <<"ip">>, - xmlns = [<<"urn:xmpp:sic:0">>, <<"urn:xmpp:sic:1">>], - result = '$cdata', - cdata = #cdata{required = true, - dec = {dec_ip, []}, - enc = {enc_ip, []}}}). - --xml(sip_port, - #elem{name = <<"port">>, - xmlns = <<"urn:xmpp:sic:1">>, - result = '$cdata', - cdata = #cdata{required = true, - dec = {dec_int, [0, 65535]}, - enc = {enc_int, []}}}). - --xml(sic, - #elem{name = <<"address">>, - xmlns = [<<"urn:xmpp:sic:0">>, <<"urn:xmpp:sic:1">>], - result = {sic, '$ip', '$port', '$xmlns'}, - attrs = [#attr{name = <<"xmlns">>}], - refs = [#ref{name = sic_ip, min = 0, max = 1, label = '$ip'}, - #ref{name = sip_port, min = 0, max = 1, label = '$port'}]}). - --xml(upload_filename, - #elem{name = <<"filename">>, - xmlns = [<<"urn:xmpp:http:upload">>, - <<"eu:siacs:conversations:http:upload">>], - result = '$cdata', - cdata = #cdata{required = true}}). - --xml(upload_size, - #elem{name = <<"size">>, - xmlns = [<<"urn:xmpp:http:upload">>, - <<"eu:siacs:conversations:http:upload">>], - result = '$cdata', - cdata = #cdata{required = true, - dec = {dec_int, [0, infinity]}, - enc = {enc_int, []}}}). - --xml(upload_content_type, - #elem{name = <<"content-type">>, - xmlns = [<<"urn:xmpp:http:upload">>, - <<"eu:siacs:conversations:http:upload">>], - result = '$cdata', - cdata = #cdata{default = <<"">>}}). - --xml(upload_request, - #elem{name = <<"request">>, - xmlns = [<<"urn:xmpp:http:upload">>, - <<"eu:siacs:conversations:http:upload">>], - result = {upload_request, '$filename', '$size', - '$content-type', '$xmlns'}, - attrs = [#attr{name = <<"xmlns">>}], - refs = [#ref{name = upload_filename, label = '$filename', - min = 1, max = 1}, - #ref{name = upload_size, label = '$size', min = 1, max = 1}, - #ref{name = upload_content_type, label = '$content-type', - min = 0, max = 1, default = <<"">>}]}). - --xml(upload_get, - #elem{name = <<"get">>, - xmlns = [<<"urn:xmpp:http:upload">>, - <<"eu:siacs:conversations:http:upload">>], - result = '$cdata', - cdata = #cdata{required = true}}). - --xml(upload_put, - #elem{name = <<"put">>, - xmlns = [<<"urn:xmpp:http:upload">>, - <<"eu:siacs:conversations:http:upload">>], - result = '$cdata', - cdata = #cdata{required = true}}). - --xml(upload_slot, - #elem{name = <<"slot">>, - xmlns = [<<"urn:xmpp:http:upload">>, - <<"eu:siacs:conversations:http:upload">>], - result = {upload_slot, '$get', '$put', '$xmlns'}, - attrs = [#attr{name = <<"xmlns">>}], - refs = [#ref{name = upload_get, min = 0, max = 1, label = '$get'}, - #ref{name = upload_put, min = 0, max = 1, label = '$put'}]}). - --xml(thumbnail, - #elem{name = <<"thumbnail">>, - xmlns = <<"urn:xmpp:thumbs:1">>, - result = {thumbnail, '$uri', '$media-type', '$width', '$height'}, - attrs = [#attr{name = <<"uri">>, required = true}, - #attr{name = <<"media-type">>, default = <<"">>}, - #attr{name = <<"width">>, - dec = {dec_int, [0, infinity]}, - enc = {enc_int, []}}, - #attr{name = <<"height">>, - dec = {dec_int, [0, infinity]}, - enc = {enc_int, []}}]}). - --xml(privilege_perm, - #elem{name = <<"perm">>, - xmlns = <<"urn:xmpp:privilege:1">>, - result = {privilege_perm, '$access', '$type'}, - attrs = [#attr{name = <<"access">>, - required = true, - dec = {dec_enum, [[roster, message, presence]]}, - enc = {enc_enum, []}}, - #attr{name = <<"type">>, - required = true, - dec = {dec_enum, [[none, get, set, both, - outgoing, roster, - managed_entity]]}, - enc = {enc_enum, []}}]}). - --xml(privilege, - #elem{name = <<"privilege">>, - xmlns = <<"urn:xmpp:privilege:1">>, - result = {privilege, '$perms', '$forwarded'}, - refs = [#ref{name = privilege_perm, label = '$perms'}, - #ref{name = forwarded, min = 0, - max = 1, label = '$forwarded'}]}). - --xml(delegated_attribute, - #elem{name = <<"attribute">>, - xmlns = <<"urn:xmpp:delegation:1">>, - result = '$name', - attrs = [#attr{name = <<"name">>, - required = true}]}). - --xml(delegated, - #elem{name = <<"delegated">>, - xmlns = <<"urn:xmpp:delegation:1">>, - result = {delegated, '$ns', '$attrs'}, - attrs = [#attr{name = <<"namespace">>, - label = '$ns', - required = true}], - refs = [#ref{name = delegated_attribute, - label = '$attrs'}]}). - --xml(delegation, - #elem{name = <<"delegation">>, - xmlns = <<"urn:xmpp:delegation:1">>, - result = {delegation, '$delegated', '$forwarded'}, - refs = [#ref{name = delegated, label = '$delegated'}, - #ref{name = forwarded, min = 0, - max = 1, label = '$forwarded'}]}). - --xml(delegate, - #elem{name = <<"delegate">>, - xmlns = <<"urn:xmpp:delegation:1">>, - result = '$namespace', - attrs = [#attr{name = <<"namespace">>, - required = true}]}). - --xml(delegation_query, - #elem{name = <<"query">>, - xmlns = <<"urn:xmpp:delegation:1">>, - result = {delegation_query, '$to', '$delegate'}, - attrs = [#attr{name = <<"to">>, - required = true, - dec = {dec_jid, []}, - enc = {enc_jid, []}}], - refs = [#ref{name = delegate, label = '$delegate'}]}). - --spec dec_tzo(_) -> {integer(), integer()}. -dec_tzo(Val) -> - [H1, M1] = str:tokens(Val, <<":">>), - H = binary_to_integer(H1), - M = binary_to_integer(M1), - if H >= -12, H =< 12, M >= 0, M < 60 -> - {H, M} - end. - -enc_tzo({H, M}) -> - Sign = if H >= 0 -> - <<>>; - true -> - <<"-">> - end, - list_to_binary([Sign, io_lib:format("~2..0w:~2..0w", [H, M])]). - --spec dec_utc(_) -> erlang:timestamp(). -dec_utc(Val) -> - xmpp_util:decode_timestamp(Val). - -enc_utc(Val) -> - xmpp_util:encode_timestamp(Val). - --spec dec_jid(_) -> jid:jid(). -dec_jid(Val) -> - case jid:from_string(Val) of - error -> - erlang:error(badarg); - J -> - J - end. - -enc_jid(J) -> - jid:to_string(J). - --spec resourceprep(_) -> binary(). -resourceprep(R) -> - case jid:resourceprep(R) of - error -> - erlang:error(badarg); - R1 -> - R1 - end. - --spec nameprep(_) -> binary(). -nameprep(S) -> - case jid:nameprep(S) of - error -> - erlang:error(badarg); - S1 -> - S1 - end. - --spec dec_bool(_) -> boolean(). -dec_bool(<<"false">>) -> false; -dec_bool(<<"0">>) -> false; -dec_bool(<<"true">>) -> true; -dec_bool(<<"1">>) -> true. - -enc_bool(false) -> <<"false">>; -enc_bool(true) -> <<"true">>. - -join([], _Sep) -> <<>>; -join([H | T], Sep) -> - <> || X <- T >>)/binary>>. - --spec dec_ip(_) -> inet:ip_address(). -dec_ip(S) -> - {ok, Addr} = inet_parse:address(binary_to_list(S)), - Addr. - -enc_ip({0,0,0,0,0,16#ffff,A,B}) -> - enc_ip({(A bsr 8) band 16#ff, A band 16#ff, - (B bsr 8) band 16#ff, B band 16#ff}); -enc_ip(Addr) -> - list_to_binary(inet_parse:ntoa(Addr)). - --spec re:split(_, _) -> [binary()]. --spec base64:decode(_) -> binary(). --spec base64:mime_decode(_) -> binary(). - --spec dec_host_port(_) -> binary() | inet:ip_address() | - {binary() | inet:ip_address(), non_neg_integer()}. -dec_host_port(<<$[, T/binary>>) -> - [IP, <<$:, Port/binary>>] = binary:split(T, <<$]>>), - {dec_ip(IP), dec_int(Port, 0, 65535)}; -dec_host_port(S) -> - case binary:split(S, <<$:>>) of - [S] -> - try dec_ip(S) catch _:_ -> S end; - [S, P] -> - {try dec_ip(S) catch _:_ -> S end, dec_int(P, 0, 65535)} - end. - -enc_host_port(Host) when is_binary(Host) -> - Host; -enc_host_port({{_,_,_,_,_,_,_,_} = IPv6, Port}) -> - enc_host_port({<<$[, (enc_ip(IPv6))/binary, $]>>, Port}); -enc_host_port({{_,_,_,_} = IPv4, Port}) -> - enc_host_port({enc_ip(IPv4), Port}); -enc_host_port({Host, Port}) -> - <>; -enc_host_port(Addr) -> - enc_ip(Addr). - --spec dec_version(_) -> {non_neg_integer(), non_neg_integer()}. -dec_version(S) -> - [Major, Minor] = binary:split(S, <<$.>>), - {binary_to_integer(Major), binary_to_integer(Minor)}. - -enc_version({Maj, Min}) -> - <<(integer_to_binary(Maj))/binary, $., (integer_to_binary(Min))/binary>>. - --spec dec_ps_aff(_) -> member | none | outcast | - owner | publisher | publish_only. -dec_ps_aff(<<"member">>) -> member; -dec_ps_aff(<<"none">>) -> none; -dec_ps_aff(<<"outcast">>) -> outcast; -dec_ps_aff(<<"owner">>) -> owner; -dec_ps_aff(<<"publisher">>) -> publisher; -dec_ps_aff(<<"publish-only">>) -> publish_only. - -enc_ps_aff(member) -> <<"member">>; -enc_ps_aff(none) -> <<"none">>; -enc_ps_aff(outcast) -> <<"outcast">>; -enc_ps_aff(owner) -> <<"owner">>; -enc_ps_aff(publisher) -> <<"publisher">>; -enc_ps_aff(publish_only) -> <<"publish-only">>. - -%% Local Variables: -%% mode: erlang -%% End: -%% vim: set filetype=erlang tabstop=8: diff --git a/src/flex_offline.erl b/src/flex_offline.erl deleted file mode 100644 index acc57342e..000000000 --- a/src/flex_offline.erl +++ /dev/null @@ -1,128 +0,0 @@ -%% Created automatically by xdata generator (xdata_codec.erl) -%% Source: flex_offline.xdata -%% Form type: http://jabber.org/protocol/offline -%% Document: XEP-0013 - --module(flex_offline). - --export([decode/1, decode/2, encode/1, encode/2, - format_error/1]). - --include("xmpp_codec.hrl"). - --include("flex_offline.hrl"). - --export_type([property/0, result/0, form/0]). - -dec_int(Val, Min, Max) -> - case list_to_integer(binary_to_list(Val)) of - Int when Int =< Max, Min == infinity -> Int; - Int when Int =< Max, Int >= Min -> Int - end. - -enc_int(Int) -> integer_to_binary(Int). - -format_error({form_type_mismatch, Type}) -> - <<"FORM_TYPE doesn't match '", Type/binary, "'">>; -format_error({bad_var_value, Var, Type}) -> - <<"Bad value of field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({missing_value, Var, Type}) -> - <<"Missing value of field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({too_many_values, Var, Type}) -> - <<"Too many values for field '", Var/binary, - "' of type '", Type/binary, "'">>; -format_error({unknown_var, Var, Type}) -> - <<"Unknown field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({missing_required_var, Var, Type}) -> - <<"Missing required field '", Var/binary, "' of type '", - Type/binary, "'">>. - -decode(Fs) -> decode(Fs, []). - -decode(Fs, Acc) -> - case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var, - Fs) - of - false -> decode(Fs, Acc, []); - #xdata_field{values = - [<<"http://jabber.org/protocol/offline">>]} -> - decode(Fs, Acc, []); - _ -> - erlang:error({?MODULE, - {form_type_mismatch, - <<"http://jabber.org/protocol/offline">>}}) - end. - -encode(Cfg) -> encode(Cfg, fun (Text) -> Text end). - -encode(List, Translate) when is_list(List) -> - Fs = [case Opt of - {number_of_messages, Val} -> - [encode_number_of_messages(Val, Translate)]; - {number_of_messages, _, _} -> - erlang:error({badarg, Opt}); - #xdata_field{} -> [Opt]; - _ -> [] - end - || Opt <- List], - FormType = #xdata_field{var = <<"FORM_TYPE">>, - type = hidden, - values = - [<<"http://jabber.org/protocol/offline">>]}, - [FormType | lists:flatten(Fs)]. - -decode([#xdata_field{var = <<"number_of_messages">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_int(Value, 0, infinity) of - Result -> - decode(Fs, [{number_of_messages, Result} | Acc], - lists:delete(<<"number_of_messages">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"number_of_messages">>, - <<"http://jabber.org/protocol/offline">>}}) - end; -decode([#xdata_field{var = <<"number_of_messages">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"number_of_messages">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"number_of_messages">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"number_of_messages">>, - <<"http://jabber.org/protocol/offline">>}}); -decode([#xdata_field{var = Var} | Fs], Acc, Required) -> - if Var /= <<"FORM_TYPE">> -> - erlang:error({?MODULE, - {unknown_var, Var, - <<"http://jabber.org/protocol/offline">>}}); - true -> decode(Fs, Acc, Required) - end; -decode([], _, [Var | _]) -> - erlang:error({?MODULE, - {missing_required_var, Var, - <<"http://jabber.org/protocol/offline">>}}); -decode([], Acc, []) -> Acc. - -encode_number_of_messages(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_int(Value)] - end, - Opts = [], - #xdata_field{var = <<"number_of_messages">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = Translate(<<"Number of Offline Messages">>)}. diff --git a/src/jid.erl b/src/jid.erl deleted file mode 100644 index 287a0642b..000000000 --- a/src/jid.erl +++ /dev/null @@ -1,266 +0,0 @@ -%%%------------------------------------------------------------------- -%%% @author Evgeny Khramtsov -%%% @doc -%%% JID processing library -%%% @end -%%% Created : 24 Nov 2015 by Evgeny Khramtsov -%%% -%%% -%%% ejabberd, Copyright (C) 2002-2016 ProcessOne -%%% -%%% This program is free software; you can redistribute it and/or -%%% modify it under the terms of the GNU General Public License as -%%% published by the Free Software Foundation; either version 2 of the -%%% License, or (at your option) any later version. -%%% -%%% This program is distributed in the hope that it will be useful, -%%% but WITHOUT ANY WARRANTY; without even the implied warranty of -%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -%%% General Public License for more details. -%%% -%%% You should have received a copy of the GNU General Public License along -%%% with this program; if not, write to the Free Software Foundation, Inc., -%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -%%% -%%%------------------------------------------------------------------- --module(jid). - -%% API --export([start/0, - make/1, - make/2, - make/3, - split/1, - from_string/1, - to_string/1, - is_nodename/1, - nodeprep/1, - nameprep/1, - resourceprep/1, - tolower/1, - remove_resource/1, - replace_resource/2]). - --include("jid.hrl"). - --export_type([jid/0]). --export_type([ljid/0]). - -%%%=================================================================== -%%% API -%%%=================================================================== --spec start() -> ok. - -start() -> - {ok, Owner} = ets_owner(), - SplitPattern = binary:compile_pattern([<<"@">>, <<"/">>]), - %% Table is public to allow ETS insert to fix / update the table even if table already exist - %% with another owner. - catch ets:new(jlib, [named_table, public, set, {keypos, 1}, {heir, Owner, undefined}]), - ets:insert(jlib, {string_to_jid_pattern, SplitPattern}), - ok. - -ets_owner() -> - case whereis(jlib_ets) of - undefined -> - Pid = spawn(fun() -> ets_keepalive() end), - case catch register(jlib_ets, Pid) of - true -> - {ok, Pid}; - Error -> Error - end; - Pid -> - {ok,Pid} - end. - -%% Process used to keep jlib ETS table alive in case the original owner dies. -%% The table need to be public, otherwise subsequent inserts would fail. -ets_keepalive() -> - receive - _ -> - ets_keepalive() - end. - --spec make(binary(), binary(), binary()) -> jid() | error. - -make(User, Server, Resource) -> - case nodeprep(User) of - error -> error; - LUser -> - case nameprep(Server) of - error -> error; - LServer -> - case resourceprep(Resource) of - error -> error; - LResource -> - #jid{user = User, server = Server, resource = Resource, - luser = LUser, lserver = LServer, - lresource = LResource} - end - end - end. - --spec make(binary(), binary()) -> jid() | error. -make(User, Server) -> - make(User, Server, <<"">>). - --spec make({binary(), binary(), binary()} | binary()) -> jid() | error. - -make({User, Server, Resource}) -> - make(User, Server, Resource); -make(Server) -> - make(<<"">>, Server, <<"">>). - -%% This is the reverse of make_jid/1 --spec split(jid()) -> {binary(), binary(), binary()} | error. - -split(#jid{user = U, server = S, resource = R}) -> - {U, S, R}; -split(_) -> - error. - --spec from_string(binary() | string()) -> jid() | error. -from_string(S) when is_list(S) -> - %% We do not accept list because we want to enforce good practice of - %% using binaries for string. However, we do not let it crash to avoid - %% losing associated ets table. - {error, need_jid_as_binary}; -from_string(<<>>) -> - error; -from_string(S) when is_binary(S) -> - SplitPattern = ets:lookup_element(jlib, string_to_jid_pattern, 2), - Size = size(S), - End = Size-1, - case binary:match(S, SplitPattern) of - {0, _} -> - error; - {End, _} -> - error; - {Pos1, _} -> - case binary:at(S, Pos1) of - $/ -> - make(<<>>, - binary:part(S, 0, Pos1), - binary:part(S, Pos1+1, Size-Pos1-1)); - _ -> - Pos1N = Pos1+1, - case binary:match(S, SplitPattern, [{scope, {Pos1+1, Size-Pos1-1}}]) of - {End, _} -> - error; - {Pos1N, _} -> - error; - {Pos2, _} -> - case binary:at(S, Pos2) of - $/ -> - make(binary:part(S, 0, Pos1), - binary:part(S, Pos1+1, Pos2-Pos1-1), - binary:part(S, Pos2+1, Size-Pos2-1)); - _ -> error - end; - _ -> - make(binary:part(S, 0, Pos1), - binary:part(S, Pos1+1, Size-Pos1-1), - <<>>) - end - end; - _ -> - make(<<>>, S, <<>>) - end. - --spec to_string(jid() | ljid()) -> binary(). - -to_string(#jid{user = User, server = Server, - resource = Resource}) -> - to_string({User, Server, Resource}); -to_string({N, S, R}) -> - Node = iolist_to_binary(N), - Server = iolist_to_binary(S), - Resource = iolist_to_binary(R), - S1 = case Node of - <<"">> -> <<"">>; - _ -> <> - end, - S2 = <>, - S3 = case Resource of - <<"">> -> S2; - _ -> <> - end, - S3. - --spec is_nodename(binary()) -> boolean(). - -is_nodename(Node) -> - N = nodeprep(Node), - (N /= error) and (N /= <<>>). - --define(LOWER(Char), - if Char >= $A, Char =< $Z -> Char + 32; - true -> Char - end). - --spec nodeprep(binary()) -> binary() | error. - -nodeprep("") -> <<>>; -nodeprep(S) when byte_size(S) < 1024 -> - R = stringprep:nodeprep(S), - if byte_size(R) < 1024 -> R; - true -> error - end; -nodeprep(_) -> error. - --spec nameprep(binary()) -> binary() | error. - -nameprep(S) when byte_size(S) < 1024 -> - R = stringprep:nameprep(S), - if byte_size(R) < 1024 -> R; - true -> error - end; -nameprep(_) -> error. - --spec resourceprep(binary()) -> binary() | error. - -resourceprep(S) when byte_size(S) < 1024 -> - R = stringprep:resourceprep(S), - if byte_size(R) < 1024 -> R; - true -> error - end; -resourceprep(_) -> error. - --spec tolower(jid() | ljid()) -> error | ljid(). - -tolower(#jid{luser = U, lserver = S, - lresource = R}) -> - {U, S, R}; -tolower({U, S, R}) -> - case nodeprep(U) of - error -> error; - LUser -> - case nameprep(S) of - error -> error; - LServer -> - case resourceprep(R) of - error -> error; - LResource -> {LUser, LServer, LResource} - end - end - end. - --spec remove_resource(jid()) -> jid(); - (ljid()) -> ljid(). - -remove_resource(#jid{} = JID) -> - JID#jid{resource = <<"">>, lresource = <<"">>}; -remove_resource({U, S, _R}) -> {U, S, <<"">>}. - --spec replace_resource(jid(), binary()) -> error | jid(). - -replace_resource(JID, Resource) -> - case resourceprep(Resource) of - error -> error; - LResource -> - JID#jid{resource = Resource, lresource = LResource} - end. - -%%%=================================================================== -%%% Internal functions -%%%=================================================================== diff --git a/src/mam_query.erl b/src/mam_query.erl deleted file mode 100644 index cb5bfe13a..000000000 --- a/src/mam_query.erl +++ /dev/null @@ -1,220 +0,0 @@ -%% Created automatically by xdata generator (xdata_codec.erl) -%% Source: mam_query.xdata -%% Form type: urn:xmpp:mam:1 -%% Document: XEP-0313 - --module(mam_query). - --export([decode/1, decode/2, encode/1, encode/2, - format_error/1]). - --include("xmpp_codec.hrl"). - --include("mam_query.hrl"). - --export_type([property/0, result/0, form/0]). - -enc_jid(J) -> jid:to_string(J). - -dec_jid(Val) -> - case jid:from_string(Val) of - error -> erlang:error(badarg); - J -> J - end. - -format_error({form_type_mismatch, Type}) -> - <<"FORM_TYPE doesn't match '", Type/binary, "'">>; -format_error({bad_var_value, Var, Type}) -> - <<"Bad value of field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({missing_value, Var, Type}) -> - <<"Missing value of field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({too_many_values, Var, Type}) -> - <<"Too many values for field '", Var/binary, - "' of type '", Type/binary, "'">>; -format_error({unknown_var, Var, Type}) -> - <<"Unknown field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({missing_required_var, Var, Type}) -> - <<"Missing required field '", Var/binary, "' of type '", - Type/binary, "'">>. - -decode(Fs) -> decode(Fs, []). - -decode(Fs, Acc) -> - case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var, - Fs) - of - false -> decode(Fs, Acc, []); - #xdata_field{values = [<<"urn:xmpp:mam:1">>]} -> - decode(Fs, Acc, []); - _ -> - erlang:error({?MODULE, - {form_type_mismatch, <<"urn:xmpp:mam:1">>}}) - end. - -encode(Cfg) -> encode(Cfg, fun (Text) -> Text end). - -encode(List, Translate) when is_list(List) -> - Fs = [case Opt of - {with, Val} -> [encode_with(Val, Translate)]; - {with, _, _} -> erlang:error({badarg, Opt}); - {start, Val} -> [encode_start(Val, Translate)]; - {start, _, _} -> erlang:error({badarg, Opt}); - {'end', Val} -> [encode_end(Val, Translate)]; - {'end', _, _} -> erlang:error({badarg, Opt}); - {withtext, Val} -> [encode_withtext(Val, Translate)]; - {withtext, _, _} -> erlang:error({badarg, Opt}); - #xdata_field{} -> [Opt]; - _ -> [] - end - || Opt <- List], - FormType = #xdata_field{var = <<"FORM_TYPE">>, - type = hidden, values = [<<"urn:xmpp:mam:1">>]}, - [FormType | lists:flatten(Fs)]. - -decode([#xdata_field{var = <<"with">>, values = [Value]} - | Fs], - Acc, Required) -> - try dec_jid(Value) of - Result -> - decode(Fs, [{with, Result} | Acc], - lists:delete(<<"with">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"with">>, <<"urn:xmpp:mam:1">>}}) - end; -decode([#xdata_field{var = <<"with">>, values = []} = F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"with">>, values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"with">>} | _], _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"with">>, <<"urn:xmpp:mam:1">>}}); -decode([#xdata_field{var = <<"start">>, - values = [Value]} - | Fs], - Acc, Required) -> - try xmpp_util:decode_timestamp(Value) of - Result -> - decode(Fs, [{start, Result} | Acc], - lists:delete(<<"start">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"start">>, <<"urn:xmpp:mam:1">>}}) - end; -decode([#xdata_field{var = <<"start">>, values = []} = F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"start">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"start">>} | _], _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"start">>, <<"urn:xmpp:mam:1">>}}); -decode([#xdata_field{var = <<"end">>, values = [Value]} - | Fs], - Acc, Required) -> - try xmpp_util:decode_timestamp(Value) of - Result -> - decode(Fs, [{'end', Result} | Acc], - lists:delete(<<"end">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"end">>, <<"urn:xmpp:mam:1">>}}) - end; -decode([#xdata_field{var = <<"end">>, values = []} = F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"end">>, values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"end">>} | _], _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"end">>, <<"urn:xmpp:mam:1">>}}); -decode([#xdata_field{var = <<"withtext">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{withtext, Result} | Acc], - lists:delete(<<"withtext">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"withtext">>, <<"urn:xmpp:mam:1">>}}) - end; -decode([#xdata_field{var = <<"withtext">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"withtext">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"withtext">>} | _], _, - _) -> - erlang:error({?MODULE, - {too_many_values, <<"withtext">>, - <<"urn:xmpp:mam:1">>}}); -decode([#xdata_field{var = Var} | Fs], Acc, Required) -> - if Var /= <<"FORM_TYPE">> -> - erlang:error({?MODULE, - {unknown_var, Var, <<"urn:xmpp:mam:1">>}}); - true -> decode(Fs, Acc, Required) - end; -decode([], _, [Var | _]) -> - erlang:error({?MODULE, - {missing_required_var, Var, <<"urn:xmpp:mam:1">>}}); -decode([], Acc, []) -> Acc. - -encode_with(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_jid(Value)] - end, - Opts = [], - #xdata_field{var = <<"with">>, values = Values, - required = false, type = 'jid-single', options = Opts, - desc = <<>>, label = Translate(<<"User JID">>)}. - -encode_start(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"start">>, values = Values, - required = false, type = 'text-single', options = Opts, - desc = <<>>, - label = Translate(<<"Search from the date">>)}. - -encode_end(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"end">>, values = Values, - required = false, type = 'text-single', options = Opts, - desc = <<>>, - label = Translate(<<"Search until the date">>)}. - -encode_withtext(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"withtext">>, values = Values, - required = false, type = 'text-single', options = Opts, - desc = <<>>, label = Translate(<<"Search the text">>)}. diff --git a/src/muc_register.erl b/src/muc_register.erl deleted file mode 100644 index c2b951dfc..000000000 --- a/src/muc_register.erl +++ /dev/null @@ -1,364 +0,0 @@ -%% Created automatically by xdata generator (xdata_codec.erl) -%% Source: muc_register.xdata -%% Form type: http://jabber.org/protocol/muc#register -%% Document: XEP-0045 - --module(muc_register). - --export([decode/1, decode/2, encode/1, encode/2, - format_error/1]). - --include("xmpp_codec.hrl"). - --include("muc_register.hrl"). - --export_type([property/0, result/0, form/0]). - -dec_bool(<<"1">>) -> true; -dec_bool(<<"0">>) -> false; -dec_bool(<<"true">>) -> true; -dec_bool(<<"false">>) -> false. - -enc_bool(true) -> <<"1">>; -enc_bool(false) -> <<"0">>. - -format_error({form_type_mismatch, Type}) -> - <<"FORM_TYPE doesn't match '", Type/binary, "'">>; -format_error({bad_var_value, Var, Type}) -> - <<"Bad value of field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({missing_value, Var, Type}) -> - <<"Missing value of field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({too_many_values, Var, Type}) -> - <<"Too many values for field '", Var/binary, - "' of type '", Type/binary, "'">>; -format_error({unknown_var, Var, Type}) -> - <<"Unknown field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({missing_required_var, Var, Type}) -> - <<"Missing required field '", Var/binary, "' of type '", - Type/binary, "'">>. - -decode(Fs) -> decode(Fs, []). - -decode(Fs, Acc) -> - case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var, - Fs) - of - false -> decode(Fs, Acc, [<<"muc#register_roomnick">>]); - #xdata_field{values = - [<<"http://jabber.org/protocol/muc#register">>]} -> - decode(Fs, Acc, [<<"muc#register_roomnick">>]); - _ -> - erlang:error({?MODULE, - {form_type_mismatch, - <<"http://jabber.org/protocol/muc#register">>}}) - end. - -encode(Cfg) -> encode(Cfg, fun (Text) -> Text end). - -encode(List, Translate) when is_list(List) -> - Fs = [case Opt of - {allow, Val} -> [encode_allow(Val, Translate)]; - {allow, _, _} -> erlang:error({badarg, Opt}); - {email, Val} -> [encode_email(Val, Translate)]; - {email, _, _} -> erlang:error({badarg, Opt}); - {faqentry, Val} -> [encode_faqentry(Val, Translate)]; - {faqentry, _, _} -> erlang:error({badarg, Opt}); - {first, Val} -> [encode_first(Val, Translate)]; - {first, _, _} -> erlang:error({badarg, Opt}); - {last, Val} -> [encode_last(Val, Translate)]; - {last, _, _} -> erlang:error({badarg, Opt}); - {roomnick, Val} -> [encode_roomnick(Val, Translate)]; - {roomnick, _, _} -> erlang:error({badarg, Opt}); - {url, Val} -> [encode_url(Val, Translate)]; - {url, _, _} -> erlang:error({badarg, Opt}); - #xdata_field{} -> [Opt]; - _ -> [] - end - || Opt <- List], - FormType = #xdata_field{var = <<"FORM_TYPE">>, - type = hidden, - values = - [<<"http://jabber.org/protocol/muc#register">>]}, - [FormType | lists:flatten(Fs)]. - -decode([#xdata_field{var = <<"muc#register_allow">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{allow, Result} | Acc], - lists:delete(<<"muc#register_allow">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#register_allow">>, - <<"http://jabber.org/protocol/muc#register">>}}) - end; -decode([#xdata_field{var = <<"muc#register_allow">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"muc#register_allow">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"muc#register_allow">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#register_allow">>, - <<"http://jabber.org/protocol/muc#register">>}}); -decode([#xdata_field{var = <<"muc#register_email">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{email, Result} | Acc], - lists:delete(<<"muc#register_email">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#register_email">>, - <<"http://jabber.org/protocol/muc#register">>}}) - end; -decode([#xdata_field{var = <<"muc#register_email">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"muc#register_email">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"muc#register_email">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#register_email">>, - <<"http://jabber.org/protocol/muc#register">>}}); -decode([#xdata_field{var = <<"muc#register_faqentry">>, - values = Values} - | Fs], - Acc, Required) -> - try [Value || Value <- Values] of - Result -> - decode(Fs, [{faqentry, Result} | Acc], - lists:delete(<<"muc#register_faqentry">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#register_faqentry">>, - <<"http://jabber.org/protocol/muc#register">>}}) - end; -decode([#xdata_field{var = <<"muc#register_first">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{first, Result} | Acc], - lists:delete(<<"muc#register_first">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#register_first">>, - <<"http://jabber.org/protocol/muc#register">>}}) - end; -decode([#xdata_field{var = <<"muc#register_first">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"muc#register_first">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"muc#register_first">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#register_first">>, - <<"http://jabber.org/protocol/muc#register">>}}); -decode([#xdata_field{var = <<"muc#register_last">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{last, Result} | Acc], - lists:delete(<<"muc#register_last">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#register_last">>, - <<"http://jabber.org/protocol/muc#register">>}}) - end; -decode([#xdata_field{var = <<"muc#register_last">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"muc#register_last">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"muc#register_last">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#register_last">>, - <<"http://jabber.org/protocol/muc#register">>}}); -decode([#xdata_field{var = <<"muc#register_roomnick">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{roomnick, Result} | Acc], - lists:delete(<<"muc#register_roomnick">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#register_roomnick">>, - <<"http://jabber.org/protocol/muc#register">>}}) - end; -decode([#xdata_field{var = <<"muc#register_roomnick">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"muc#register_roomnick">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"muc#register_roomnick">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#register_roomnick">>, - <<"http://jabber.org/protocol/muc#register">>}}); -decode([#xdata_field{var = <<"muc#register_url">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{url, Result} | Acc], - lists:delete(<<"muc#register_url">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#register_url">>, - <<"http://jabber.org/protocol/muc#register">>}}) - end; -decode([#xdata_field{var = <<"muc#register_url">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"muc#register_url">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"muc#register_url">>} | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#register_url">>, - <<"http://jabber.org/protocol/muc#register">>}}); -decode([#xdata_field{var = Var} | Fs], Acc, Required) -> - if Var /= <<"FORM_TYPE">> -> - erlang:error({?MODULE, - {unknown_var, Var, - <<"http://jabber.org/protocol/muc#register">>}}); - true -> decode(Fs, Acc, Required) - end; -decode([], _, [Var | _]) -> - erlang:error({?MODULE, - {missing_required_var, Var, - <<"http://jabber.org/protocol/muc#register">>}}); -decode([], Acc, []) -> Acc. - -encode_allow(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"muc#register_allow">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = - Translate(<<"Allow this person to register with the " - "room?">>)}. - -encode_email(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"muc#register_email">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = Translate(<<"Email Address">>)}. - -encode_faqentry(Value, Translate) -> - Values = case Value of - [] -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"muc#register_faqentry">>, - values = Values, required = false, type = 'text-multi', - options = Opts, desc = <<>>, - label = Translate(<<"FAQ Entry">>)}. - -encode_first(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"muc#register_first">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = Translate(<<"Given Name">>)}. - -encode_last(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"muc#register_last">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = Translate(<<"Family Name">>)}. - -encode_roomnick(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"muc#register_roomnick">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = Translate(<<"Nickname">>)}. - -encode_url(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"muc#register_url">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = Translate(<<"A Web Page">>)}. diff --git a/src/muc_request.erl b/src/muc_request.erl deleted file mode 100644 index 2d79ba0a5..000000000 --- a/src/muc_request.erl +++ /dev/null @@ -1,269 +0,0 @@ -%% Created automatically by xdata generator (xdata_codec.erl) -%% Source: muc_request.xdata -%% Form type: http://jabber.org/protocol/muc#request -%% Document: XEP-0045 - --module(muc_request). - --export([decode/1, decode/2, encode/1, encode/2, - format_error/1]). - --include("xmpp_codec.hrl"). - --include("muc_request.hrl"). - --export_type([property/0, result/0, form/0]). - -dec_enum(Val, Enums) -> - AtomVal = erlang:binary_to_existing_atom(Val, utf8), - case lists:member(AtomVal, Enums) of - true -> AtomVal - end. - -enc_enum(Atom) -> erlang:atom_to_binary(Atom, utf8). - -dec_bool(<<"1">>) -> true; -dec_bool(<<"0">>) -> false; -dec_bool(<<"true">>) -> true; -dec_bool(<<"false">>) -> false. - -enc_bool(true) -> <<"1">>; -enc_bool(false) -> <<"0">>. - -enc_jid(J) -> jid:to_string(J). - -dec_jid(Val) -> - case jid:from_string(Val) of - error -> erlang:error(badarg); - J -> J - end. - -format_error({form_type_mismatch, Type}) -> - <<"FORM_TYPE doesn't match '", Type/binary, "'">>; -format_error({bad_var_value, Var, Type}) -> - <<"Bad value of field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({missing_value, Var, Type}) -> - <<"Missing value of field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({too_many_values, Var, Type}) -> - <<"Too many values for field '", Var/binary, - "' of type '", Type/binary, "'">>; -format_error({unknown_var, Var, Type}) -> - <<"Unknown field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({missing_required_var, Var, Type}) -> - <<"Missing required field '", Var/binary, "' of type '", - Type/binary, "'">>. - -decode(Fs) -> decode(Fs, []). - -decode(Fs, Acc) -> - case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var, - Fs) - of - false -> decode(Fs, Acc, [<<"muc#role">>]); - #xdata_field{values = - [<<"http://jabber.org/protocol/muc#request">>]} -> - decode(Fs, Acc, [<<"muc#role">>]); - _ -> - erlang:error({?MODULE, - {form_type_mismatch, - <<"http://jabber.org/protocol/muc#request">>}}) - end. - -encode(Cfg) -> encode(Cfg, fun (Text) -> Text end). - -encode(List, Translate) when is_list(List) -> - Fs = [case Opt of - {role, Val} -> [encode_role(Val, default, Translate)]; - {role, Val, Opts} -> - [encode_role(Val, Opts, Translate)]; - {jid, Val} -> [encode_jid(Val, Translate)]; - {jid, _, _} -> erlang:error({badarg, Opt}); - {roomnick, Val} -> [encode_roomnick(Val, Translate)]; - {roomnick, _, _} -> erlang:error({badarg, Opt}); - {request_allow, Val} -> - [encode_request_allow(Val, Translate)]; - {request_allow, _, _} -> erlang:error({badarg, Opt}); - #xdata_field{} -> [Opt]; - _ -> [] - end - || Opt <- List], - FormType = #xdata_field{var = <<"FORM_TYPE">>, - type = hidden, - values = - [<<"http://jabber.org/protocol/muc#request">>]}, - [FormType | lists:flatten(Fs)]. - -decode([#xdata_field{var = <<"muc#role">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_enum(Value, [participant]) of - Result -> - decode(Fs, [{role, Result} | Acc], - lists:delete(<<"muc#role">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#role">>, - <<"http://jabber.org/protocol/muc#request">>}}) - end; -decode([#xdata_field{var = <<"muc#role">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"muc#role">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"muc#role">>} | _], _, - _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#role">>, - <<"http://jabber.org/protocol/muc#request">>}}); -decode([#xdata_field{var = <<"muc#jid">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_jid(Value) of - Result -> - decode(Fs, [{jid, Result} | Acc], - lists:delete(<<"muc#jid">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#jid">>, - <<"http://jabber.org/protocol/muc#request">>}}) - end; -decode([#xdata_field{var = <<"muc#jid">>, values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"muc#jid">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"muc#jid">>} | _], _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#jid">>, - <<"http://jabber.org/protocol/muc#request">>}}); -decode([#xdata_field{var = <<"muc#roomnick">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{roomnick, Result} | Acc], - lists:delete(<<"muc#roomnick">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roomnick">>, - <<"http://jabber.org/protocol/muc#request">>}}) - end; -decode([#xdata_field{var = <<"muc#roomnick">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"muc#roomnick">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"muc#roomnick">>} | _], _, - _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#roomnick">>, - <<"http://jabber.org/protocol/muc#request">>}}); -decode([#xdata_field{var = <<"muc#request_allow">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{request_allow, Result} | Acc], - lists:delete(<<"muc#request_allow">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#request_allow">>, - <<"http://jabber.org/protocol/muc#request">>}}) - end; -decode([#xdata_field{var = <<"muc#request_allow">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"muc#request_allow">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"muc#request_allow">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#request_allow">>, - <<"http://jabber.org/protocol/muc#request">>}}); -decode([#xdata_field{var = Var} | Fs], Acc, Required) -> - if Var /= <<"FORM_TYPE">> -> - erlang:error({?MODULE, - {unknown_var, Var, - <<"http://jabber.org/protocol/muc#request">>}}); - true -> decode(Fs, Acc, Required) - end; -decode([], _, [Var | _]) -> - erlang:error({?MODULE, - {missing_required_var, Var, - <<"http://jabber.org/protocol/muc#request">>}}); -decode([], Acc, []) -> Acc. - -encode_role(Value, Options, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_enum(Value)] - end, - Opts = if Options == default -> - [#xdata_option{label = Translate(<<"Participant">>), - value = <<"participant">>}]; - true -> - [#xdata_option{label = Translate(L), - value = enc_enum(V)} - || {L, V} <- Options] - end, - #xdata_field{var = <<"muc#role">>, values = Values, - required = false, type = 'list-single', options = Opts, - desc = <<>>, label = Translate(<<"Requested role">>)}. - -encode_jid(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_jid(Value)] - end, - Opts = [], - #xdata_field{var = <<"muc#jid">>, values = Values, - required = false, type = 'jid-single', options = Opts, - desc = <<>>, label = Translate(<<"User JID">>)}. - -encode_roomnick(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"muc#roomnick">>, values = Values, - required = false, type = 'text-single', options = Opts, - desc = <<>>, label = Translate(<<"Nickname">>)}. - -encode_request_allow(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"muc#request_allow">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = Translate(<<"Grant voice to this person?">>)}. diff --git a/src/muc_roomconfig.erl b/src/muc_roomconfig.erl deleted file mode 100644 index 7d18bab66..000000000 --- a/src/muc_roomconfig.erl +++ /dev/null @@ -1,1675 +0,0 @@ -%% Created automatically by xdata generator (xdata_codec.erl) -%% Source: muc_roomconfig.xdata -%% Form type: http://jabber.org/protocol/muc#roomconfig -%% Document: XEP-0045 - --module(muc_roomconfig). - --export([decode/1, decode/2, encode/1, encode/2, - format_error/1]). - --include("xmpp_codec.hrl"). - --include("muc_roomconfig.hrl"). - --export_type([property/0, result/0, form/0]). - -dec_int(Val, Min, Max) -> - case list_to_integer(binary_to_list(Val)) of - Int when Int =< Max, Min == infinity -> Int; - Int when Int =< Max, Int >= Min -> Int - end. - -enc_int(Int) -> integer_to_binary(Int). - -dec_enum(Val, Enums) -> - AtomVal = erlang:binary_to_existing_atom(Val, utf8), - case lists:member(AtomVal, Enums) of - true -> AtomVal - end. - -enc_enum(Atom) -> erlang:atom_to_binary(Atom, utf8). - -dec_enum_int(Val, Enums, Min, Max) -> - try dec_int(Val, Min, Max) catch - _:_ -> dec_enum(Val, Enums) - end. - -enc_enum_int(Int) when is_integer(Int) -> enc_int(Int); -enc_enum_int(Atom) -> enc_enum(Atom). - -dec_bool(<<"1">>) -> true; -dec_bool(<<"0">>) -> false; -dec_bool(<<"true">>) -> true; -dec_bool(<<"false">>) -> false. - -enc_bool(true) -> <<"1">>; -enc_bool(false) -> <<"0">>. - -enc_jid(J) -> jid:to_string(J). - -dec_jid(Val) -> - case jid:from_string(Val) of - error -> erlang:error(badarg); - J -> J - end. - -format_error({form_type_mismatch, Type}) -> - <<"FORM_TYPE doesn't match '", Type/binary, "'">>; -format_error({bad_var_value, Var, Type}) -> - <<"Bad value of field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({missing_value, Var, Type}) -> - <<"Missing value of field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({too_many_values, Var, Type}) -> - <<"Too many values for field '", Var/binary, - "' of type '", Type/binary, "'">>; -format_error({unknown_var, Var, Type}) -> - <<"Unknown field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({missing_required_var, Var, Type}) -> - <<"Missing required field '", Var/binary, "' of type '", - Type/binary, "'">>. - -decode(Fs) -> decode(Fs, []). - -decode(Fs, Acc) -> - case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var, - Fs) - of - false -> decode(Fs, Acc, []); - #xdata_field{values = - [<<"http://jabber.org/protocol/muc#roomconfig">>]} -> - decode(Fs, Acc, []); - _ -> - erlang:error({?MODULE, - {form_type_mismatch, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end. - -encode(Cfg) -> encode(Cfg, fun (Text) -> Text end). - -encode(List, Translate) when is_list(List) -> - Fs = [case Opt of - {maxhistoryfetch, Val} -> - [encode_maxhistoryfetch(Val, Translate)]; - {maxhistoryfetch, _, _} -> erlang:error({badarg, Opt}); - {allowpm, Val} -> - [encode_allowpm(Val, default, Translate)]; - {allowpm, Val, Opts} -> - [encode_allowpm(Val, Opts, Translate)]; - {allow_private_messages, Val} -> - [encode_allow_private_messages(Val, Translate)]; - {allow_private_messages, _, _} -> - erlang:error({badarg, Opt}); - {allow_private_messages_from_visitors, Val} -> - [encode_allow_private_messages_from_visitors(Val, - default, - Translate)]; - {allow_private_messages_from_visitors, Val, Opts} -> - [encode_allow_private_messages_from_visitors(Val, Opts, - Translate)]; - {allow_visitor_status, Val} -> - [encode_allow_visitor_status(Val, Translate)]; - {allow_visitor_status, _, _} -> - erlang:error({badarg, Opt}); - {allow_visitor_nickchange, Val} -> - [encode_allow_visitor_nickchange(Val, Translate)]; - {allow_visitor_nickchange, _, _} -> - erlang:error({badarg, Opt}); - {allow_voice_requests, Val} -> - [encode_allow_voice_requests(Val, Translate)]; - {allow_voice_requests, _, _} -> - erlang:error({badarg, Opt}); - {allow_subscription, Val} -> - [encode_allow_subscription(Val, Translate)]; - {allow_subscription, _, _} -> - erlang:error({badarg, Opt}); - {voice_request_min_interval, Val} -> - [encode_voice_request_min_interval(Val, Translate)]; - {voice_request_min_interval, _, _} -> - erlang:error({badarg, Opt}); - {captcha_protected, Val} -> - [encode_captcha_protected(Val, Translate)]; - {captcha_protected, _, _} -> - erlang:error({badarg, Opt}); - {captcha_whitelist, Val} -> - [encode_captcha_whitelist(Val, Translate)]; - {captcha_whitelist, _, _} -> - erlang:error({badarg, Opt}); - {allow_query_users, Val} -> - [encode_allow_query_users(Val, Translate)]; - {allow_query_users, _, _} -> - erlang:error({badarg, Opt}); - {allowinvites, Val} -> - [encode_allowinvites(Val, Translate)]; - {allowinvites, _, _} -> erlang:error({badarg, Opt}); - {changesubject, Val} -> - [encode_changesubject(Val, Translate)]; - {changesubject, _, _} -> erlang:error({badarg, Opt}); - {enablelogging, Val} -> - [encode_enablelogging(Val, Translate)]; - {enablelogging, _, _} -> erlang:error({badarg, Opt}); - {getmemberlist, Val} -> - [encode_getmemberlist(Val, default, Translate)]; - {getmemberlist, Val, Opts} -> - [encode_getmemberlist(Val, Opts, Translate)]; - {lang, Val} -> [encode_lang(Val, Translate)]; - {lang, _, _} -> erlang:error({badarg, Opt}); - {pubsub, Val} -> [encode_pubsub(Val, Translate)]; - {pubsub, _, _} -> erlang:error({badarg, Opt}); - {maxusers, Val} -> - [encode_maxusers(Val, default, Translate)]; - {maxusers, Val, Opts} -> - [encode_maxusers(Val, Opts, Translate)]; - {membersonly, Val} -> - [encode_membersonly(Val, Translate)]; - {membersonly, _, _} -> erlang:error({badarg, Opt}); - {moderatedroom, Val} -> - [encode_moderatedroom(Val, Translate)]; - {moderatedroom, _, _} -> erlang:error({badarg, Opt}); - {members_by_default, Val} -> - [encode_members_by_default(Val, Translate)]; - {members_by_default, _, _} -> - erlang:error({badarg, Opt}); - {passwordprotectedroom, Val} -> - [encode_passwordprotectedroom(Val, Translate)]; - {passwordprotectedroom, _, _} -> - erlang:error({badarg, Opt}); - {persistentroom, Val} -> - [encode_persistentroom(Val, Translate)]; - {persistentroom, _, _} -> erlang:error({badarg, Opt}); - {presencebroadcast, Val} -> - [encode_presencebroadcast(Val, default, Translate)]; - {presencebroadcast, Val, Opts} -> - [encode_presencebroadcast(Val, Opts, Translate)]; - {publicroom, Val} -> - [encode_publicroom(Val, Translate)]; - {publicroom, _, _} -> erlang:error({badarg, Opt}); - {public_list, Val} -> - [encode_public_list(Val, Translate)]; - {public_list, _, _} -> erlang:error({badarg, Opt}); - {roomadmins, Val} -> - [encode_roomadmins(Val, Translate)]; - {roomadmins, _, _} -> erlang:error({badarg, Opt}); - {roomdesc, Val} -> [encode_roomdesc(Val, Translate)]; - {roomdesc, _, _} -> erlang:error({badarg, Opt}); - {roomname, Val} -> [encode_roomname(Val, Translate)]; - {roomname, _, _} -> erlang:error({badarg, Opt}); - {roomowners, Val} -> - [encode_roomowners(Val, Translate)]; - {roomowners, _, _} -> erlang:error({badarg, Opt}); - {roomsecret, Val} -> - [encode_roomsecret(Val, Translate)]; - {roomsecret, _, _} -> erlang:error({badarg, Opt}); - {whois, Val} -> [encode_whois(Val, default, Translate)]; - {whois, Val, Opts} -> - [encode_whois(Val, Opts, Translate)]; - {mam, Val} -> [encode_mam(Val, Translate)]; - {mam, _, _} -> erlang:error({badarg, Opt}); - #xdata_field{} -> [Opt]; - _ -> [] - end - || Opt <- List], - FormType = #xdata_field{var = <<"FORM_TYPE">>, - type = hidden, - values = - [<<"http://jabber.org/protocol/muc#roomconfig">>]}, - [FormType | lists:flatten(Fs)]. - -decode([#xdata_field{var = <<"muc#maxhistoryfetch">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{maxhistoryfetch, Result} | Acc], - lists:delete(<<"muc#maxhistoryfetch">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#maxhistoryfetch">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = <<"muc#maxhistoryfetch">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"muc#maxhistoryfetch">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"muc#maxhistoryfetch">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#maxhistoryfetch">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = <<"muc#roomconfig_allowpm">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{allowpm, Result} | Acc], - lists:delete(<<"muc#roomconfig_allowpm">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roomconfig_allowpm">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = <<"muc#roomconfig_allowpm">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"muc#roomconfig_allowpm">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"muc#roomconfig_allowpm">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#roomconfig_allowpm">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = <<"allow_private_messages">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{allow_private_messages, Result} | Acc], - lists:delete(<<"allow_private_messages">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"allow_private_messages">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = <<"allow_private_messages">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"allow_private_messages">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"allow_private_messages">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"allow_private_messages">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = - <<"allow_private_messages_from_visitors">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_enum(Value, [nobody, moderators, anyone]) of - Result -> - decode(Fs, - [{allow_private_messages_from_visitors, Result} | Acc], - lists:delete(<<"allow_private_messages_from_visitors">>, - Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, - <<"allow_private_messages_from_visitors">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = - <<"allow_private_messages_from_visitors">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"allow_private_messages_from_visitors">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"allow_private_messages_from_visitors">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, - <<"allow_private_messages_from_visitors">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = <<"allow_visitor_status">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{allow_visitor_status, Result} | Acc], - lists:delete(<<"allow_visitor_status">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"allow_visitor_status">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = <<"allow_visitor_status">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"allow_visitor_status">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"allow_visitor_status">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"allow_visitor_status">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = - <<"allow_visitor_nickchange">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{allow_visitor_nickchange, Result} | Acc], - lists:delete(<<"allow_visitor_nickchange">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"allow_visitor_nickchange">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = - <<"allow_visitor_nickchange">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"allow_visitor_nickchange">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"allow_visitor_nickchange">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"allow_visitor_nickchange">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = <<"allow_voice_requests">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{allow_voice_requests, Result} | Acc], - lists:delete(<<"allow_voice_requests">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"allow_voice_requests">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = <<"allow_voice_requests">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"allow_voice_requests">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"allow_voice_requests">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"allow_voice_requests">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = <<"allow_subscription">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{allow_subscription, Result} | Acc], - lists:delete(<<"allow_subscription">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"allow_subscription">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = <<"allow_subscription">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"allow_subscription">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"allow_subscription">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"allow_subscription">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = - <<"voice_request_min_interval">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_int(Value, 0, infinity) of - Result -> - decode(Fs, [{voice_request_min_interval, Result} | Acc], - lists:delete(<<"voice_request_min_interval">>, - Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"voice_request_min_interval">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = - <<"voice_request_min_interval">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"voice_request_min_interval">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"voice_request_min_interval">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"voice_request_min_interval">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = <<"captcha_protected">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{captcha_protected, Result} | Acc], - lists:delete(<<"captcha_protected">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"captcha_protected">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = <<"captcha_protected">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"captcha_protected">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"captcha_protected">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"captcha_protected">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = <<"captcha_whitelist">>, - values = Values} - | Fs], - Acc, Required) -> - try [dec_jid(Value) || Value <- Values] of - Result -> - decode(Fs, [{captcha_whitelist, Result} | Acc], - lists:delete(<<"captcha_whitelist">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"captcha_whitelist">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = <<"allow_query_users">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{allow_query_users, Result} | Acc], - lists:delete(<<"allow_query_users">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"allow_query_users">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = <<"allow_query_users">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"allow_query_users">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"allow_query_users">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"allow_query_users">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = - <<"muc#roomconfig_allowinvites">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{allowinvites, Result} | Acc], - lists:delete(<<"muc#roomconfig_allowinvites">>, - Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roomconfig_allowinvites">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = - <<"muc#roomconfig_allowinvites">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"muc#roomconfig_allowinvites">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"muc#roomconfig_allowinvites">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#roomconfig_allowinvites">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = - <<"muc#roomconfig_changesubject">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{changesubject, Result} | Acc], - lists:delete(<<"muc#roomconfig_changesubject">>, - Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roomconfig_changesubject">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = - <<"muc#roomconfig_changesubject">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"muc#roomconfig_changesubject">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"muc#roomconfig_changesubject">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#roomconfig_changesubject">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = - <<"muc#roomconfig_enablelogging">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{enablelogging, Result} | Acc], - lists:delete(<<"muc#roomconfig_enablelogging">>, - Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roomconfig_enablelogging">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = - <<"muc#roomconfig_enablelogging">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"muc#roomconfig_enablelogging">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"muc#roomconfig_enablelogging">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#roomconfig_enablelogging">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = - <<"muc#roomconfig_getmemberlist">>, - values = Values} - | Fs], - Acc, Required) -> - try [Value || Value <- Values] of - Result -> - decode(Fs, [{getmemberlist, Result} | Acc], - lists:delete(<<"muc#roomconfig_getmemberlist">>, - Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roomconfig_getmemberlist">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = <<"muc#roomconfig_lang">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{lang, Result} | Acc], - lists:delete(<<"muc#roomconfig_lang">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roomconfig_lang">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = <<"muc#roomconfig_lang">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"muc#roomconfig_lang">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"muc#roomconfig_lang">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#roomconfig_lang">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = <<"muc#roomconfig_pubsub">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{pubsub, Result} | Acc], - lists:delete(<<"muc#roomconfig_pubsub">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roomconfig_pubsub">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = <<"muc#roomconfig_pubsub">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"muc#roomconfig_pubsub">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"muc#roomconfig_pubsub">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#roomconfig_pubsub">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = - <<"muc#roomconfig_maxusers">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_enum_int(Value, [none], 0, infinity) of - Result -> - decode(Fs, [{maxusers, Result} | Acc], - lists:delete(<<"muc#roomconfig_maxusers">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roomconfig_maxusers">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = - <<"muc#roomconfig_maxusers">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"muc#roomconfig_maxusers">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"muc#roomconfig_maxusers">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#roomconfig_maxusers">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = - <<"muc#roomconfig_membersonly">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{membersonly, Result} | Acc], - lists:delete(<<"muc#roomconfig_membersonly">>, - Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roomconfig_membersonly">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = - <<"muc#roomconfig_membersonly">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"muc#roomconfig_membersonly">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"muc#roomconfig_membersonly">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#roomconfig_membersonly">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = - <<"muc#roomconfig_moderatedroom">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{moderatedroom, Result} | Acc], - lists:delete(<<"muc#roomconfig_moderatedroom">>, - Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roomconfig_moderatedroom">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = - <<"muc#roomconfig_moderatedroom">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"muc#roomconfig_moderatedroom">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"muc#roomconfig_moderatedroom">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#roomconfig_moderatedroom">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = <<"members_by_default">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{members_by_default, Result} | Acc], - lists:delete(<<"members_by_default">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"members_by_default">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = <<"members_by_default">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"members_by_default">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"members_by_default">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"members_by_default">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = - <<"muc#roomconfig_passwordprotectedroom">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{passwordprotectedroom, Result} | Acc], - lists:delete(<<"muc#roomconfig_passwordprotectedroom">>, - Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, - <<"muc#roomconfig_passwordprotectedroom">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = - <<"muc#roomconfig_passwordprotectedroom">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"muc#roomconfig_passwordprotectedroom">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"muc#roomconfig_passwordprotectedroom">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, - <<"muc#roomconfig_passwordprotectedroom">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = - <<"muc#roomconfig_persistentroom">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{persistentroom, Result} | Acc], - lists:delete(<<"muc#roomconfig_persistentroom">>, - Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roomconfig_persistentroom">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = - <<"muc#roomconfig_persistentroom">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"muc#roomconfig_persistentroom">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"muc#roomconfig_persistentroom">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#roomconfig_persistentroom">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = - <<"muc#roomconfig_presencebroadcast">>, - values = Values} - | Fs], - Acc, Required) -> - try [dec_enum(Value, [moderator, participant, visitor]) - || Value <- Values] - of - Result -> - decode(Fs, [{presencebroadcast, Result} | Acc], - lists:delete(<<"muc#roomconfig_presencebroadcast">>, - Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roomconfig_presencebroadcast">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = - <<"muc#roomconfig_publicroom">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{publicroom, Result} | Acc], - lists:delete(<<"muc#roomconfig_publicroom">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roomconfig_publicroom">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = - <<"muc#roomconfig_publicroom">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"muc#roomconfig_publicroom">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"muc#roomconfig_publicroom">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#roomconfig_publicroom">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = <<"public_list">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{public_list, Result} | Acc], - lists:delete(<<"public_list">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"public_list">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = <<"public_list">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"public_list">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"public_list">>} | _], _, - _) -> - erlang:error({?MODULE, - {too_many_values, <<"public_list">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = - <<"muc#roomconfig_roomadmins">>, - values = Values} - | Fs], - Acc, Required) -> - try [dec_jid(Value) || Value <- Values] of - Result -> - decode(Fs, [{roomadmins, Result} | Acc], - lists:delete(<<"muc#roomconfig_roomadmins">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roomconfig_roomadmins">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = - <<"muc#roomconfig_roomdesc">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{roomdesc, Result} | Acc], - lists:delete(<<"muc#roomconfig_roomdesc">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roomconfig_roomdesc">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = - <<"muc#roomconfig_roomdesc">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"muc#roomconfig_roomdesc">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"muc#roomconfig_roomdesc">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#roomconfig_roomdesc">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = - <<"muc#roomconfig_roomname">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{roomname, Result} | Acc], - lists:delete(<<"muc#roomconfig_roomname">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roomconfig_roomname">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = - <<"muc#roomconfig_roomname">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"muc#roomconfig_roomname">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"muc#roomconfig_roomname">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#roomconfig_roomname">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = - <<"muc#roomconfig_roomowners">>, - values = Values} - | Fs], - Acc, Required) -> - try [dec_jid(Value) || Value <- Values] of - Result -> - decode(Fs, [{roomowners, Result} | Acc], - lists:delete(<<"muc#roomconfig_roomowners">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roomconfig_roomowners">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = - <<"muc#roomconfig_roomsecret">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{roomsecret, Result} | Acc], - lists:delete(<<"muc#roomconfig_roomsecret">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roomconfig_roomsecret">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = - <<"muc#roomconfig_roomsecret">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"muc#roomconfig_roomsecret">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"muc#roomconfig_roomsecret">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#roomconfig_roomsecret">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = <<"muc#roomconfig_whois">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_enum(Value, [moderators, anyone]) of - Result -> - decode(Fs, [{whois, Result} | Acc], - lists:delete(<<"muc#roomconfig_whois">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roomconfig_whois">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = <<"muc#roomconfig_whois">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"muc#roomconfig_whois">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"muc#roomconfig_whois">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#roomconfig_whois">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = <<"mam">>, values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{mam, Result} | Acc], - lists:delete(<<"mam">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"mam">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}) - end; -decode([#xdata_field{var = <<"mam">>, values = []} = F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"mam">>, values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"mam">>} | _], _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"mam">>, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([#xdata_field{var = Var} | Fs], Acc, Required) -> - if Var /= <<"FORM_TYPE">> -> - erlang:error({?MODULE, - {unknown_var, Var, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); - true -> decode(Fs, Acc, Required) - end; -decode([], _, [Var | _]) -> - erlang:error({?MODULE, - {missing_required_var, Var, - <<"http://jabber.org/protocol/muc#roomconfig">>}}); -decode([], Acc, []) -> Acc. - -encode_maxhistoryfetch(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"muc#maxhistoryfetch">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = - Translate(<<"Maximum Number of History Messages Returned " - "by Room">>)}. - -encode_allowpm(Value, Options, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = if Options == default -> []; - true -> - [#xdata_option{label = Translate(L), value = V} - || {L, V} <- Options] - end, - #xdata_field{var = <<"muc#roomconfig_allowpm">>, - values = Values, required = false, type = 'list-single', - options = Opts, desc = <<>>, - label = - Translate(<<"Roles that May Send Private Messages">>)}. - -encode_allow_private_messages(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"allow_private_messages">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = - Translate(<<"Allow users to send private messages">>)}. - -encode_allow_private_messages_from_visitors(Value, - Options, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_enum(Value)] - end, - Opts = if Options == default -> - [#xdata_option{label = Translate(<<"nobody">>), - value = <<"nobody">>}, - #xdata_option{label = Translate(<<"moderators only">>), - value = <<"moderators">>}, - #xdata_option{label = Translate(<<"anyone">>), - value = <<"anyone">>}]; - true -> - [#xdata_option{label = Translate(L), - value = enc_enum(V)} - || {L, V} <- Options] - end, - #xdata_field{var = - <<"allow_private_messages_from_visitors">>, - values = Values, required = false, type = 'list-single', - options = Opts, desc = <<>>, - label = - Translate(<<"Allow visitors to send private messages to">>)}. - -encode_allow_visitor_status(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"allow_visitor_status">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = - Translate(<<"Allow visitors to send status text in " - "presence updates">>)}. - -encode_allow_visitor_nickchange(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"allow_visitor_nickchange">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = - Translate(<<"Allow visitors to change nickname">>)}. - -encode_allow_voice_requests(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"allow_voice_requests">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = - Translate(<<"Allow visitors to send voice requests">>)}. - -encode_allow_subscription(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"allow_subscription">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = Translate(<<"Allow subscription">>)}. - -encode_voice_request_min_interval(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_int(Value)] - end, - Opts = [], - #xdata_field{var = <<"voice_request_min_interval">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = - Translate(<<"Minimum interval between voice requests " - "(in seconds)">>)}. - -encode_captcha_protected(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"captcha_protected">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = Translate(<<"Make room CAPTCHA protected">>)}. - -encode_captcha_whitelist(Value, Translate) -> - Values = case Value of - [] -> []; - Value -> [enc_jid(V) || V <- Value] - end, - Opts = [], - #xdata_field{var = <<"captcha_whitelist">>, - values = Values, required = false, type = 'jid-multi', - options = Opts, desc = <<>>, - label = - Translate(<<"Exclude Jabber IDs from CAPTCHA challenge">>)}. - -encode_allow_query_users(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"allow_query_users">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = - Translate(<<"Allow users to query other users">>)}. - -encode_allowinvites(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"muc#roomconfig_allowinvites">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = Translate(<<"Allow users to send invites">>)}. - -encode_changesubject(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"muc#roomconfig_changesubject">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = - Translate(<<"Allow users to change the subject">>)}. - -encode_enablelogging(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"muc#roomconfig_enablelogging">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = Translate(<<"Enable logging">>)}. - -encode_getmemberlist(Value, Options, Translate) -> - Values = case Value of - [] -> []; - Value -> [Value] - end, - Opts = if Options == default -> []; - true -> - [#xdata_option{label = Translate(L), value = V} - || {L, V} <- Options] - end, - #xdata_field{var = <<"muc#roomconfig_getmemberlist">>, - values = Values, required = false, type = 'list-multi', - options = Opts, desc = <<>>, - label = - Translate(<<"Roles and Affiliations that May Retrieve " - "Member List">>)}. - -encode_lang(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"muc#roomconfig_lang">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = - Translate(<<"Natural Language for Room Discussions">>)}. - -encode_pubsub(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"muc#roomconfig_pubsub">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = - Translate(<<"XMPP URI of Associated Publish-Subscribe " - "Node">>)}. - -encode_maxusers(Value, Options, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_enum_int(Value)] - end, - Opts = if Options == default -> - [#xdata_option{label = Translate(<<"No limit">>), - value = <<"none">>}, - #xdata_option{value = <<"5">>}, - #xdata_option{value = <<"10">>}, - #xdata_option{value = <<"20">>}, - #xdata_option{value = <<"30">>}, - #xdata_option{value = <<"50">>}, - #xdata_option{value = <<"100">>}, - #xdata_option{value = <<"200">>}, - #xdata_option{value = <<"500">>}, - #xdata_option{value = <<"1000">>}, - #xdata_option{value = <<"2000">>}, - #xdata_option{value = <<"5000">>}]; - true -> - [#xdata_option{label = Translate(L), - value = enc_enum_int(V)} - || {L, V} <- Options] - end, - #xdata_field{var = <<"muc#roomconfig_maxusers">>, - values = Values, required = false, type = 'list-single', - options = Opts, desc = <<>>, - label = Translate(<<"Maximum Number of Occupants">>)}. - -encode_membersonly(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"muc#roomconfig_membersonly">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = Translate(<<"Make room members-only">>)}. - -encode_moderatedroom(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"muc#roomconfig_moderatedroom">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = Translate(<<"Make room moderated">>)}. - -encode_members_by_default(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"members_by_default">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = Translate(<<"Default users as participants">>)}. - -encode_passwordprotectedroom(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = - <<"muc#roomconfig_passwordprotectedroom">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = Translate(<<"Make room password protected">>)}. - -encode_persistentroom(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"muc#roomconfig_persistentroom">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = Translate(<<"Make room persistent">>)}. - -encode_presencebroadcast(Value, Options, Translate) -> - Values = case Value of - [] -> []; - Value -> [enc_enum(V) || V <- Value] - end, - Opts = if Options == default -> - [#xdata_option{label = Translate(<<"Moderator">>), - value = <<"moderator">>}, - #xdata_option{label = Translate(<<"Participant">>), - value = <<"participant">>}, - #xdata_option{label = Translate(<<"Visitor">>), - value = <<"visitor">>}]; - true -> - [#xdata_option{label = Translate(L), - value = enc_enum(V)} - || {L, V} <- Options] - end, - #xdata_field{var = - <<"muc#roomconfig_presencebroadcast">>, - values = Values, required = false, type = 'list-multi', - options = Opts, desc = <<>>, - label = - Translate(<<"Roles for which Presence is Broadcasted">>)}. - -encode_publicroom(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"muc#roomconfig_publicroom">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = Translate(<<"Make room public searchable">>)}. - -encode_public_list(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"public_list">>, values = Values, - required = false, type = boolean, options = Opts, - desc = <<>>, - label = Translate(<<"Make participants list public">>)}. - -encode_roomadmins(Value, Translate) -> - Values = case Value of - [] -> []; - Value -> [enc_jid(V) || V <- Value] - end, - Opts = [], - #xdata_field{var = <<"muc#roomconfig_roomadmins">>, - values = Values, required = false, type = 'jid-multi', - options = Opts, desc = <<>>, - label = Translate(<<"Full List of Room Admins">>)}. - -encode_roomdesc(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"muc#roomconfig_roomdesc">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = Translate(<<"Room description">>)}. - -encode_roomname(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"muc#roomconfig_roomname">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = Translate(<<"Room title">>)}. - -encode_roomowners(Value, Translate) -> - Values = case Value of - [] -> []; - Value -> [enc_jid(V) || V <- Value] - end, - Opts = [], - #xdata_field{var = <<"muc#roomconfig_roomowners">>, - values = Values, required = false, type = 'jid-multi', - options = Opts, desc = <<>>, - label = Translate(<<"Full List of Room Owners">>)}. - -encode_roomsecret(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"muc#roomconfig_roomsecret">>, - values = Values, required = false, - type = 'text-private', options = Opts, desc = <<>>, - label = Translate(<<"Password">>)}. - -encode_whois(Value, Options, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_enum(Value)] - end, - Opts = if Options == default -> - [#xdata_option{label = Translate(<<"moderators only">>), - value = <<"moderators">>}, - #xdata_option{label = Translate(<<"anyone">>), - value = <<"anyone">>}]; - true -> - [#xdata_option{label = Translate(L), - value = enc_enum(V)} - || {L, V} <- Options] - end, - #xdata_field{var = <<"muc#roomconfig_whois">>, - values = Values, required = false, type = 'list-single', - options = Opts, desc = <<>>, - label = Translate(<<"Present real Jabber IDs to">>)}. - -encode_mam(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"mam">>, values = Values, - required = false, type = boolean, options = Opts, - desc = <<>>, - label = Translate(<<"Enable message archiving">>)}. diff --git a/src/muc_roominfo.erl b/src/muc_roominfo.erl deleted file mode 100644 index bd5cb011b..000000000 --- a/src/muc_roominfo.erl +++ /dev/null @@ -1,491 +0,0 @@ -%% Created automatically by xdata generator (xdata_codec.erl) -%% Source: muc_roominfo.xdata -%% Form type: http://jabber.org/protocol/muc#roominfo -%% Document: XEP-0045 - --module(muc_roominfo). - --export([decode/1, decode/2, encode/1, encode/2, - format_error/1]). - --include("xmpp_codec.hrl"). - --include("muc_roominfo.hrl"). - --export_type([property/0, result/0, form/0]). - -dec_int(Val, Min, Max) -> - case list_to_integer(binary_to_list(Val)) of - Int when Int =< Max, Min == infinity -> Int; - Int when Int =< Max, Int >= Min -> Int - end. - -enc_int(Int) -> integer_to_binary(Int). - -dec_bool(<<"1">>) -> true; -dec_bool(<<"0">>) -> false; -dec_bool(<<"true">>) -> true; -dec_bool(<<"false">>) -> false. - -enc_bool(true) -> <<"1">>; -enc_bool(false) -> <<"0">>. - -enc_jid(J) -> jid:to_string(J). - -dec_jid(Val) -> - case jid:from_string(Val) of - error -> erlang:error(badarg); - J -> J - end. - -format_error({form_type_mismatch, Type}) -> - <<"FORM_TYPE doesn't match '", Type/binary, "'">>; -format_error({bad_var_value, Var, Type}) -> - <<"Bad value of field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({missing_value, Var, Type}) -> - <<"Missing value of field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({too_many_values, Var, Type}) -> - <<"Too many values for field '", Var/binary, - "' of type '", Type/binary, "'">>; -format_error({unknown_var, Var, Type}) -> - <<"Unknown field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({missing_required_var, Var, Type}) -> - <<"Missing required field '", Var/binary, "' of type '", - Type/binary, "'">>. - -decode(Fs) -> decode(Fs, []). - -decode(Fs, Acc) -> - case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var, - Fs) - of - false -> decode(Fs, Acc, []); - #xdata_field{values = - [<<"http://jabber.org/protocol/muc#roominfo">>]} -> - decode(Fs, Acc, []); - _ -> - erlang:error({?MODULE, - {form_type_mismatch, - <<"http://jabber.org/protocol/muc#roominfo">>}}) - end. - -encode(Cfg) -> encode(Cfg, fun (Text) -> Text end). - -encode(List, Translate) when is_list(List) -> - Fs = [case Opt of - {maxhistoryfetch, Val} -> - [encode_maxhistoryfetch(Val, Translate)]; - {maxhistoryfetch, _, _} -> erlang:error({badarg, Opt}); - {contactjid, Val} -> - [encode_contactjid(Val, Translate)]; - {contactjid, _, _} -> erlang:error({badarg, Opt}); - {description, Val} -> - [encode_description(Val, Translate)]; - {description, _, _} -> erlang:error({badarg, Opt}); - {lang, Val} -> [encode_lang(Val, Translate)]; - {lang, _, _} -> erlang:error({badarg, Opt}); - {ldapgroup, Val} -> [encode_ldapgroup(Val, Translate)]; - {ldapgroup, _, _} -> erlang:error({badarg, Opt}); - {logs, Val} -> [encode_logs(Val, Translate)]; - {logs, _, _} -> erlang:error({badarg, Opt}); - {occupants, Val} -> [encode_occupants(Val, Translate)]; - {occupants, _, _} -> erlang:error({badarg, Opt}); - {subject, Val} -> [encode_subject(Val, Translate)]; - {subject, _, _} -> erlang:error({badarg, Opt}); - {subjectmod, Val} -> - [encode_subjectmod(Val, Translate)]; - {subjectmod, _, _} -> erlang:error({badarg, Opt}); - #xdata_field{} -> [Opt]; - _ -> [] - end - || Opt <- List], - FormType = #xdata_field{var = <<"FORM_TYPE">>, - type = hidden, - values = - [<<"http://jabber.org/protocol/muc#roominfo">>]}, - [FormType | lists:flatten(Fs)]. - -decode([#xdata_field{var = <<"muc#maxhistoryfetch">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_int(Value, 0, infinity) of - Result -> - decode(Fs, [{maxhistoryfetch, Result} | Acc], - lists:delete(<<"muc#maxhistoryfetch">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#maxhistoryfetch">>, - <<"http://jabber.org/protocol/muc#roominfo">>}}) - end; -decode([#xdata_field{var = <<"muc#maxhistoryfetch">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"muc#maxhistoryfetch">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"muc#maxhistoryfetch">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#maxhistoryfetch">>, - <<"http://jabber.org/protocol/muc#roominfo">>}}); -decode([#xdata_field{var = - <<"muc#roominfo_contactjid">>, - values = Values} - | Fs], - Acc, Required) -> - try [dec_jid(Value) || Value <- Values] of - Result -> - decode(Fs, [{contactjid, Result} | Acc], - lists:delete(<<"muc#roominfo_contactjid">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roominfo_contactjid">>, - <<"http://jabber.org/protocol/muc#roominfo">>}}) - end; -decode([#xdata_field{var = - <<"muc#roominfo_description">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{description, Result} | Acc], - lists:delete(<<"muc#roominfo_description">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roominfo_description">>, - <<"http://jabber.org/protocol/muc#roominfo">>}}) - end; -decode([#xdata_field{var = - <<"muc#roominfo_description">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"muc#roominfo_description">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"muc#roominfo_description">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#roominfo_description">>, - <<"http://jabber.org/protocol/muc#roominfo">>}}); -decode([#xdata_field{var = <<"muc#roominfo_lang">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{lang, Result} | Acc], - lists:delete(<<"muc#roominfo_lang">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roominfo_lang">>, - <<"http://jabber.org/protocol/muc#roominfo">>}}) - end; -decode([#xdata_field{var = <<"muc#roominfo_lang">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"muc#roominfo_lang">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"muc#roominfo_lang">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#roominfo_lang">>, - <<"http://jabber.org/protocol/muc#roominfo">>}}); -decode([#xdata_field{var = <<"muc#roominfo_ldapgroup">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{ldapgroup, Result} | Acc], - lists:delete(<<"muc#roominfo_ldapgroup">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roominfo_ldapgroup">>, - <<"http://jabber.org/protocol/muc#roominfo">>}}) - end; -decode([#xdata_field{var = <<"muc#roominfo_ldapgroup">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"muc#roominfo_ldapgroup">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"muc#roominfo_ldapgroup">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#roominfo_ldapgroup">>, - <<"http://jabber.org/protocol/muc#roominfo">>}}); -decode([#xdata_field{var = <<"muc#roominfo_logs">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{logs, Result} | Acc], - lists:delete(<<"muc#roominfo_logs">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roominfo_logs">>, - <<"http://jabber.org/protocol/muc#roominfo">>}}) - end; -decode([#xdata_field{var = <<"muc#roominfo_logs">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"muc#roominfo_logs">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"muc#roominfo_logs">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#roominfo_logs">>, - <<"http://jabber.org/protocol/muc#roominfo">>}}); -decode([#xdata_field{var = <<"muc#roominfo_occupants">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_int(Value, 0, infinity) of - Result -> - decode(Fs, [{occupants, Result} | Acc], - lists:delete(<<"muc#roominfo_occupants">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roominfo_occupants">>, - <<"http://jabber.org/protocol/muc#roominfo">>}}) - end; -decode([#xdata_field{var = <<"muc#roominfo_occupants">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"muc#roominfo_occupants">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"muc#roominfo_occupants">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#roominfo_occupants">>, - <<"http://jabber.org/protocol/muc#roominfo">>}}); -decode([#xdata_field{var = <<"muc#roominfo_subject">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{subject, Result} | Acc], - lists:delete(<<"muc#roominfo_subject">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roominfo_subject">>, - <<"http://jabber.org/protocol/muc#roominfo">>}}) - end; -decode([#xdata_field{var = <<"muc#roominfo_subject">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"muc#roominfo_subject">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"muc#roominfo_subject">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#roominfo_subject">>, - <<"http://jabber.org/protocol/muc#roominfo">>}}); -decode([#xdata_field{var = - <<"muc#roominfo_subjectmod">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{subjectmod, Result} | Acc], - lists:delete(<<"muc#roominfo_subjectmod">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"muc#roominfo_subjectmod">>, - <<"http://jabber.org/protocol/muc#roominfo">>}}) - end; -decode([#xdata_field{var = - <<"muc#roominfo_subjectmod">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"muc#roominfo_subjectmod">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"muc#roominfo_subjectmod">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"muc#roominfo_subjectmod">>, - <<"http://jabber.org/protocol/muc#roominfo">>}}); -decode([#xdata_field{var = Var} | Fs], Acc, Required) -> - if Var /= <<"FORM_TYPE">> -> - erlang:error({?MODULE, - {unknown_var, Var, - <<"http://jabber.org/protocol/muc#roominfo">>}}); - true -> decode(Fs, Acc, Required) - end; -decode([], _, [Var | _]) -> - erlang:error({?MODULE, - {missing_required_var, Var, - <<"http://jabber.org/protocol/muc#roominfo">>}}); -decode([], Acc, []) -> Acc. - -encode_maxhistoryfetch(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_int(Value)] - end, - Opts = [], - #xdata_field{var = <<"muc#maxhistoryfetch">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = - Translate(<<"Maximum Number of History Messages Returned " - "by Room">>)}. - -encode_contactjid(Value, Translate) -> - Values = case Value of - [] -> []; - Value -> [enc_jid(V) || V <- Value] - end, - Opts = [], - #xdata_field{var = <<"muc#roominfo_contactjid">>, - values = Values, required = false, type = 'jid-multi', - options = Opts, desc = <<>>, - label = - Translate(<<"Contact Addresses (normally, room owner " - "or owners)">>)}. - -encode_description(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"muc#roominfo_description">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = Translate(<<"Room description">>)}. - -encode_lang(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"muc#roominfo_lang">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = - Translate(<<"Natural Language for Room Discussions">>)}. - -encode_ldapgroup(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"muc#roominfo_ldapgroup">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = - Translate(<<"An associated LDAP group that defines " - "room membership; this should be an LDAP " - "Distinguished Name according to an implementa" - "tion-specific or deployment-specific " - "definition of a group.">>)}. - -encode_logs(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"muc#roominfo_logs">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = - Translate(<<"URL for Archived Discussion Logs">>)}. - -encode_occupants(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_int(Value)] - end, - Opts = [], - #xdata_field{var = <<"muc#roominfo_occupants">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = Translate(<<"Number of occupants">>)}. - -encode_subject(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"muc#roominfo_subject">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = Translate(<<"Current Discussion Topic">>)}. - -encode_subjectmod(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"muc#roominfo_subjectmod">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = - Translate(<<"The room subject can be modified by " - "participants">>)}. diff --git a/src/pubsub_get_pending.erl b/src/pubsub_get_pending.erl deleted file mode 100644 index c1f2ba3ad..000000000 --- a/src/pubsub_get_pending.erl +++ /dev/null @@ -1,130 +0,0 @@ -%% Created automatically by xdata generator (xdata_codec.erl) -%% Source: pubsub_get_pending.xdata -%% Form type: http://jabber.org/protocol/pubsub#subscribe_authorization -%% Document: XEP-0060 - --module(pubsub_get_pending). - --export([decode/1, decode/2, encode/1, encode/2, - format_error/1]). - --include("xmpp_codec.hrl"). - --include("pubsub_get_pending.hrl"). - --export_type([property/0, result/0, form/0]). - -format_error({form_type_mismatch, Type}) -> - <<"FORM_TYPE doesn't match '", Type/binary, "'">>; -format_error({bad_var_value, Var, Type}) -> - <<"Bad value of field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({missing_value, Var, Type}) -> - <<"Missing value of field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({too_many_values, Var, Type}) -> - <<"Too many values for field '", Var/binary, - "' of type '", Type/binary, "'">>; -format_error({unknown_var, Var, Type}) -> - <<"Unknown field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({missing_required_var, Var, Type}) -> - <<"Missing required field '", Var/binary, "' of type '", - Type/binary, "'">>. - -decode(Fs) -> decode(Fs, []). - -decode(Fs, Acc) -> - case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var, - Fs) - of - false -> decode(Fs, Acc, [<<"pubsub#node">>]); - #xdata_field{values = - [<<"http://jabber.org/protocol/pubsub#subscribe_a" - "uthorization">>]} -> - decode(Fs, Acc, [<<"pubsub#node">>]); - _ -> - erlang:error({?MODULE, - {form_type_mismatch, - <<"http://jabber.org/protocol/pubsub#subscribe_a" - "uthorization">>}}) - end. - -encode(Cfg) -> encode(Cfg, fun (Text) -> Text end). - -encode(List, Translate) when is_list(List) -> - Fs = [case Opt of - {node, Val} -> [encode_node(Val, default, Translate)]; - {node, Val, Opts} -> - [encode_node(Val, Opts, Translate)]; - #xdata_field{} -> [Opt]; - _ -> [] - end - || Opt <- List], - FormType = #xdata_field{var = <<"FORM_TYPE">>, - type = hidden, - values = - [<<"http://jabber.org/protocol/pubsub#subscribe_a" - "uthorization">>]}, - [FormType | lists:flatten(Fs)]. - -decode([#xdata_field{var = <<"pubsub#node">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{node, Result} | Acc], - lists:delete(<<"pubsub#node">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#node">>, - <<"http://jabber.org/protocol/pubsub#subscribe_a" - "uthorization">>}}) - end; -decode([#xdata_field{var = <<"pubsub#node">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#node">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#node">>} | _], _, - _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#node">>, - <<"http://jabber.org/protocol/pubsub#subscribe_a" - "uthorization">>}}); -decode([#xdata_field{var = Var} | Fs], Acc, Required) -> - if Var /= <<"FORM_TYPE">> -> - erlang:error({?MODULE, - {unknown_var, Var, - <<"http://jabber.org/protocol/pubsub#subscribe_a" - "uthorization">>}}); - true -> decode(Fs, Acc, Required) - end; -decode([], _, [Var | _]) -> - erlang:error({?MODULE, - {missing_required_var, Var, - <<"http://jabber.org/protocol/pubsub#subscribe_a" - "uthorization">>}}); -decode([], Acc, []) -> Acc. - -encode_node(Value, Options, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = if Options == default -> []; - true -> - [#xdata_option{label = Translate(L), value = V} - || {L, V} <- Options] - end, - #xdata_field{var = <<"pubsub#node">>, values = Values, - required = false, type = 'list-single', options = Opts, - desc = <<>>, - label = - Translate(<<"The NodeID of the relevant node">>)}. diff --git a/src/pubsub_node_config.erl b/src/pubsub_node_config.erl deleted file mode 100644 index e831d6a83..000000000 --- a/src/pubsub_node_config.erl +++ /dev/null @@ -1,1666 +0,0 @@ -%% Created automatically by xdata generator (xdata_codec.erl) -%% Source: pubsub_node_config.xdata -%% Form type: http://jabber.org/protocol/pubsub#node_config -%% Document: XEP-0060 - --module(pubsub_node_config). - --export([decode/1, decode/2, encode/1, encode/2, - format_error/1]). - --include("xmpp_codec.hrl"). - --include("pubsub_node_config.hrl"). - --export_type([property/0, result/0, form/0]). - -dec_int(Val, Min, Max) -> - case list_to_integer(binary_to_list(Val)) of - Int when Int =< Max, Min == infinity -> Int; - Int when Int =< Max, Int >= Min -> Int - end. - -enc_int(Int) -> integer_to_binary(Int). - -dec_enum(Val, Enums) -> - AtomVal = erlang:binary_to_existing_atom(Val, utf8), - case lists:member(AtomVal, Enums) of - true -> AtomVal - end. - -enc_enum(Atom) -> erlang:atom_to_binary(Atom, utf8). - -dec_bool(<<"1">>) -> true; -dec_bool(<<"0">>) -> false; -dec_bool(<<"true">>) -> true; -dec_bool(<<"false">>) -> false. - -enc_bool(true) -> <<"1">>; -enc_bool(false) -> <<"0">>. - -enc_jid(J) -> jid:to_string(J). - -dec_jid(Val) -> - case jid:from_string(Val) of - error -> erlang:error(badarg); - J -> J - end. - -format_error({form_type_mismatch, Type}) -> - <<"FORM_TYPE doesn't match '", Type/binary, "'">>; -format_error({bad_var_value, Var, Type}) -> - <<"Bad value of field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({missing_value, Var, Type}) -> - <<"Missing value of field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({too_many_values, Var, Type}) -> - <<"Too many values for field '", Var/binary, - "' of type '", Type/binary, "'">>; -format_error({unknown_var, Var, Type}) -> - <<"Unknown field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({missing_required_var, Var, Type}) -> - <<"Missing required field '", Var/binary, "' of type '", - Type/binary, "'">>. - -decode(Fs) -> decode(Fs, []). - -decode(Fs, Acc) -> - case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var, - Fs) - of - false -> decode(Fs, Acc, []); - #xdata_field{values = - [<<"http://jabber.org/protocol/pubsub#node_config">>]} -> - decode(Fs, Acc, []); - _ -> - erlang:error({?MODULE, - {form_type_mismatch, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end. - -encode(Cfg) -> encode(Cfg, fun (Text) -> Text end). - -encode(List, Translate) when is_list(List) -> - Fs = [case Opt of - {access_model, Val} -> - [encode_access_model(Val, default, Translate)]; - {access_model, Val, Opts} -> - [encode_access_model(Val, Opts, Translate)]; - {body_xslt, Val} -> [encode_body_xslt(Val, Translate)]; - {body_xslt, _, _} -> erlang:error({badarg, Opt}); - {children_association_policy, Val} -> - [encode_children_association_policy(Val, default, - Translate)]; - {children_association_policy, Val, Opts} -> - [encode_children_association_policy(Val, Opts, - Translate)]; - {children_association_whitelist, Val} -> - [encode_children_association_whitelist(Val, Translate)]; - {children_association_whitelist, _, _} -> - erlang:error({badarg, Opt}); - {children, Val} -> [encode_children(Val, Translate)]; - {children, _, _} -> erlang:error({badarg, Opt}); - {children_max, Val} -> - [encode_children_max(Val, Translate)]; - {children_max, _, _} -> erlang:error({badarg, Opt}); - {collection, Val} -> - [encode_collection(Val, Translate)]; - {collection, _, _} -> erlang:error({badarg, Opt}); - {contact, Val} -> [encode_contact(Val, Translate)]; - {contact, _, _} -> erlang:error({badarg, Opt}); - {dataform_xslt, Val} -> - [encode_dataform_xslt(Val, Translate)]; - {dataform_xslt, _, _} -> erlang:error({badarg, Opt}); - {deliver_notifications, Val} -> - [encode_deliver_notifications(Val, Translate)]; - {deliver_notifications, _, _} -> - erlang:error({badarg, Opt}); - {deliver_payloads, Val} -> - [encode_deliver_payloads(Val, Translate)]; - {deliver_payloads, _, _} -> erlang:error({badarg, Opt}); - {description, Val} -> - [encode_description(Val, Translate)]; - {description, _, _} -> erlang:error({badarg, Opt}); - {item_expire, Val} -> - [encode_item_expire(Val, Translate)]; - {item_expire, _, _} -> erlang:error({badarg, Opt}); - {itemreply, Val} -> - [encode_itemreply(Val, default, Translate)]; - {itemreply, Val, Opts} -> - [encode_itemreply(Val, Opts, Translate)]; - {language, Val} -> - [encode_language(Val, default, Translate)]; - {language, Val, Opts} -> - [encode_language(Val, Opts, Translate)]; - {max_items, Val} -> [encode_max_items(Val, Translate)]; - {max_items, _, _} -> erlang:error({badarg, Opt}); - {max_payload_size, Val} -> - [encode_max_payload_size(Val, Translate)]; - {max_payload_size, _, _} -> erlang:error({badarg, Opt}); - {node_type, Val} -> - [encode_node_type(Val, default, Translate)]; - {node_type, Val, Opts} -> - [encode_node_type(Val, Opts, Translate)]; - {notification_type, Val} -> - [encode_notification_type(Val, default, Translate)]; - {notification_type, Val, Opts} -> - [encode_notification_type(Val, Opts, Translate)]; - {notify_config, Val} -> - [encode_notify_config(Val, Translate)]; - {notify_config, _, _} -> erlang:error({badarg, Opt}); - {notify_delete, Val} -> - [encode_notify_delete(Val, Translate)]; - {notify_delete, _, _} -> erlang:error({badarg, Opt}); - {notify_retract, Val} -> - [encode_notify_retract(Val, Translate)]; - {notify_retract, _, _} -> erlang:error({badarg, Opt}); - {notify_sub, Val} -> - [encode_notify_sub(Val, Translate)]; - {notify_sub, _, _} -> erlang:error({badarg, Opt}); - {persist_items, Val} -> - [encode_persist_items(Val, Translate)]; - {persist_items, _, _} -> erlang:error({badarg, Opt}); - {presence_based_delivery, Val} -> - [encode_presence_based_delivery(Val, Translate)]; - {presence_based_delivery, _, _} -> - erlang:error({badarg, Opt}); - {publish_model, Val} -> - [encode_publish_model(Val, default, Translate)]; - {publish_model, Val, Opts} -> - [encode_publish_model(Val, Opts, Translate)]; - {purge_offline, Val} -> - [encode_purge_offline(Val, Translate)]; - {purge_offline, _, _} -> erlang:error({badarg, Opt}); - {roster_groups_allowed, Val} -> - [encode_roster_groups_allowed(Val, default, Translate)]; - {roster_groups_allowed, Val, Opts} -> - [encode_roster_groups_allowed(Val, Opts, Translate)]; - {send_last_published_item, Val} -> - [encode_send_last_published_item(Val, default, - Translate)]; - {send_last_published_item, Val, Opts} -> - [encode_send_last_published_item(Val, Opts, Translate)]; - {tempsub, Val} -> [encode_tempsub(Val, Translate)]; - {tempsub, _, _} -> erlang:error({badarg, Opt}); - {subscribe, Val} -> [encode_subscribe(Val, Translate)]; - {subscribe, _, _} -> erlang:error({badarg, Opt}); - {title, Val} -> [encode_title(Val, Translate)]; - {title, _, _} -> erlang:error({badarg, Opt}); - {type, Val} -> [encode_type(Val, Translate)]; - {type, _, _} -> erlang:error({badarg, Opt}); - #xdata_field{} -> [Opt]; - _ -> [] - end - || Opt <- List], - FormType = #xdata_field{var = <<"FORM_TYPE">>, - type = hidden, - values = - [<<"http://jabber.org/protocol/pubsub#node_config">>]}, - [FormType | lists:flatten(Fs)]. - -decode([#xdata_field{var = <<"pubsub#access_model">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_enum(Value, - [authorize, open, presence, roster, whitelist]) - of - Result -> - decode(Fs, [{access_model, Result} | Acc], - lists:delete(<<"pubsub#access_model">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#access_model">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = <<"pubsub#access_model">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#access_model">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#access_model">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#access_model">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = <<"pubsub#body_xslt">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{body_xslt, Result} | Acc], - lists:delete(<<"pubsub#body_xslt">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#body_xslt">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = <<"pubsub#body_xslt">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#body_xslt">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#body_xslt">>} | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#body_xslt">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = - <<"pubsub#children_association_policy">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_enum(Value, [all, owners, whitelist]) of - Result -> - decode(Fs, - [{children_association_policy, Result} | Acc], - lists:delete(<<"pubsub#children_association_policy">>, - Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, - <<"pubsub#children_association_policy">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = - <<"pubsub#children_association_policy">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"pubsub#children_association_policy">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"pubsub#children_association_policy">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, - <<"pubsub#children_association_policy">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = - <<"pubsub#children_association_whitelist">>, - values = Values} - | Fs], - Acc, Required) -> - try [dec_jid(Value) || Value <- Values] of - Result -> - decode(Fs, - [{children_association_whitelist, Result} | Acc], - lists:delete(<<"pubsub#children_association_whitelist">>, - Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, - <<"pubsub#children_association_whitelist">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = <<"pubsub#children">>, - values = Values} - | Fs], - Acc, Required) -> - try [Value || Value <- Values] of - Result -> - decode(Fs, [{children, Result} | Acc], - lists:delete(<<"pubsub#children">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#children">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = <<"pubsub#children_max">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{children_max, Result} | Acc], - lists:delete(<<"pubsub#children_max">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#children_max">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = <<"pubsub#children_max">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#children_max">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#children_max">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#children_max">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = <<"pubsub#collection">>, - values = Values} - | Fs], - Acc, Required) -> - try [Value || Value <- Values] of - Result -> - decode(Fs, [{collection, Result} | Acc], - lists:delete(<<"pubsub#collection">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#collection">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = <<"pubsub#contact">>, - values = Values} - | Fs], - Acc, Required) -> - try [dec_jid(Value) || Value <- Values] of - Result -> - decode(Fs, [{contact, Result} | Acc], - lists:delete(<<"pubsub#contact">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#contact">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = <<"pubsub#dataform_xslt">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{dataform_xslt, Result} | Acc], - lists:delete(<<"pubsub#dataform_xslt">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#dataform_xslt">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = <<"pubsub#dataform_xslt">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#dataform_xslt">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#dataform_xslt">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#dataform_xslt">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = - <<"pubsub#deliver_notifications">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{deliver_notifications, Result} | Acc], - lists:delete(<<"pubsub#deliver_notifications">>, - Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#deliver_notifications">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = - <<"pubsub#deliver_notifications">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"pubsub#deliver_notifications">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"pubsub#deliver_notifications">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#deliver_notifications">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = - <<"pubsub#deliver_payloads">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{deliver_payloads, Result} | Acc], - lists:delete(<<"pubsub#deliver_payloads">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#deliver_payloads">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = - <<"pubsub#deliver_payloads">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"pubsub#deliver_payloads">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"pubsub#deliver_payloads">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#deliver_payloads">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = <<"pubsub#description">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{description, Result} | Acc], - lists:delete(<<"pubsub#description">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#description">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = <<"pubsub#description">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#description">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#description">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#description">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = <<"pubsub#item_expire">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{item_expire, Result} | Acc], - lists:delete(<<"pubsub#item_expire">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#item_expire">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = <<"pubsub#item_expire">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#item_expire">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#item_expire">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#item_expire">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = <<"pubsub#itemreply">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_enum(Value, [owner, publisher, none]) of - Result -> - decode(Fs, [{itemreply, Result} | Acc], - lists:delete(<<"pubsub#itemreply">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#itemreply">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = <<"pubsub#itemreply">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#itemreply">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#itemreply">>} | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#itemreply">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = <<"pubsub#language">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{language, Result} | Acc], - lists:delete(<<"pubsub#language">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#language">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = <<"pubsub#language">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#language">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#language">>} | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#language">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = <<"pubsub#max_items">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_int(Value, 0, infinity) of - Result -> - decode(Fs, [{max_items, Result} | Acc], - lists:delete(<<"pubsub#max_items">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#max_items">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = <<"pubsub#max_items">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#max_items">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#max_items">>} | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#max_items">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = - <<"pubsub#max_payload_size">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_int(Value, 0, infinity) of - Result -> - decode(Fs, [{max_payload_size, Result} | Acc], - lists:delete(<<"pubsub#max_payload_size">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#max_payload_size">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = - <<"pubsub#max_payload_size">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"pubsub#max_payload_size">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"pubsub#max_payload_size">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#max_payload_size">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = <<"pubsub#node_type">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_enum(Value, [leaf, collection]) of - Result -> - decode(Fs, [{node_type, Result} | Acc], - lists:delete(<<"pubsub#node_type">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#node_type">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = <<"pubsub#node_type">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#node_type">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#node_type">>} | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#node_type">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = - <<"pubsub#notification_type">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_enum(Value, [normal, headline]) of - Result -> - decode(Fs, [{notification_type, Result} | Acc], - lists:delete(<<"pubsub#notification_type">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#notification_type">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = - <<"pubsub#notification_type">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"pubsub#notification_type">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"pubsub#notification_type">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#notification_type">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = <<"pubsub#notify_config">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{notify_config, Result} | Acc], - lists:delete(<<"pubsub#notify_config">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#notify_config">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = <<"pubsub#notify_config">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#notify_config">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#notify_config">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#notify_config">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = <<"pubsub#notify_delete">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{notify_delete, Result} | Acc], - lists:delete(<<"pubsub#notify_delete">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#notify_delete">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = <<"pubsub#notify_delete">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#notify_delete">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#notify_delete">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#notify_delete">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = <<"pubsub#notify_retract">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{notify_retract, Result} | Acc], - lists:delete(<<"pubsub#notify_retract">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#notify_retract">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = <<"pubsub#notify_retract">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#notify_retract">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#notify_retract">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#notify_retract">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = <<"pubsub#notify_sub">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{notify_sub, Result} | Acc], - lists:delete(<<"pubsub#notify_sub">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#notify_sub">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = <<"pubsub#notify_sub">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#notify_sub">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#notify_sub">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#notify_sub">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = <<"pubsub#persist_items">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{persist_items, Result} | Acc], - lists:delete(<<"pubsub#persist_items">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#persist_items">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = <<"pubsub#persist_items">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#persist_items">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#persist_items">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#persist_items">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = - <<"pubsub#presence_based_delivery">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{presence_based_delivery, Result} | Acc], - lists:delete(<<"pubsub#presence_based_delivery">>, - Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#presence_based_delivery">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = - <<"pubsub#presence_based_delivery">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"pubsub#presence_based_delivery">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"pubsub#presence_based_delivery">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#presence_based_delivery">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = <<"pubsub#publish_model">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_enum(Value, [publishers, subscribers, open]) of - Result -> - decode(Fs, [{publish_model, Result} | Acc], - lists:delete(<<"pubsub#publish_model">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#publish_model">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = <<"pubsub#publish_model">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#publish_model">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#publish_model">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#publish_model">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = <<"pubsub#purge_offline">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{purge_offline, Result} | Acc], - lists:delete(<<"pubsub#purge_offline">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#purge_offline">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = <<"pubsub#purge_offline">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#purge_offline">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#purge_offline">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#purge_offline">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = - <<"pubsub#roster_groups_allowed">>, - values = Values} - | Fs], - Acc, Required) -> - try [Value || Value <- Values] of - Result -> - decode(Fs, [{roster_groups_allowed, Result} | Acc], - lists:delete(<<"pubsub#roster_groups_allowed">>, - Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#roster_groups_allowed">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = - <<"pubsub#send_last_published_item">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_enum(Value, - [never, on_sub, on_sub_and_presence]) - of - Result -> - decode(Fs, [{send_last_published_item, Result} | Acc], - lists:delete(<<"pubsub#send_last_published_item">>, - Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#send_last_published_item">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = - <<"pubsub#send_last_published_item">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"pubsub#send_last_published_item">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"pubsub#send_last_published_item">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#send_last_published_item">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = <<"pubsub#tempsub">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{tempsub, Result} | Acc], - lists:delete(<<"pubsub#tempsub">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#tempsub">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = <<"pubsub#tempsub">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#tempsub">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#tempsub">>} | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#tempsub">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = <<"pubsub#subscribe">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{subscribe, Result} | Acc], - lists:delete(<<"pubsub#subscribe">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#subscribe">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = <<"pubsub#subscribe">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#subscribe">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#subscribe">>} | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#subscribe">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = <<"pubsub#title">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{title, Result} | Acc], - lists:delete(<<"pubsub#title">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#title">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = <<"pubsub#title">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#title">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#title">>} | _], _, - _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#title">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = <<"pubsub#type">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{type, Result} | Acc], - lists:delete(<<"pubsub#type">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#type">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}) - end; -decode([#xdata_field{var = <<"pubsub#type">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#type">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#type">>} | _], _, - _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#type">>, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([#xdata_field{var = Var} | Fs], Acc, Required) -> - if Var /= <<"FORM_TYPE">> -> - erlang:error({?MODULE, - {unknown_var, Var, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); - true -> decode(Fs, Acc, Required) - end; -decode([], _, [Var | _]) -> - erlang:error({?MODULE, - {missing_required_var, Var, - <<"http://jabber.org/protocol/pubsub#node_config">>}}); -decode([], Acc, []) -> Acc. - -encode_access_model(Value, Options, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_enum(Value)] - end, - Opts = if Options == default -> - [#xdata_option{label = - Translate(<<"Subscription requests must be approved " - "and only subscribers may retrieve items">>), - value = <<"authorize">>}, - #xdata_option{label = - Translate(<<"Anyone may subscribe and retrieve items">>), - value = <<"open">>}, - #xdata_option{label = - Translate(<<"Anyone with a presence subscription " - "of both or from may subscribe and retrieve " - "items">>), - value = <<"presence">>}, - #xdata_option{label = - Translate(<<"Anyone in the specified roster group(s) " - "may subscribe and retrieve items">>), - value = <<"roster">>}, - #xdata_option{label = - Translate(<<"Only those on a whitelist may subscribe " - "and retrieve items">>), - value = <<"whitelist">>}]; - true -> - [#xdata_option{label = Translate(L), - value = enc_enum(V)} - || {L, V} <- Options] - end, - #xdata_field{var = <<"pubsub#access_model">>, - values = Values, required = false, type = 'list-single', - options = Opts, desc = <<>>, - label = Translate(<<"Specify the access model">>)}. - -encode_body_xslt(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"pubsub#body_xslt">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = - Translate(<<"The URL of an XSL transformation which " - "can be applied to payloads in order " - "to generate an appropriate message body " - "element.">>)}. - -encode_children_association_policy(Value, Options, - Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_enum(Value)] - end, - Opts = if Options == default -> - [#xdata_option{label = - Translate(<<"Anyone may associate leaf nodes with " - "the collection">>), - value = <<"all">>}, - #xdata_option{label = - Translate(<<"Only collection node owners may associate " - "leaf nodes with the collection">>), - value = <<"owners">>}, - #xdata_option{label = - Translate(<<"Only those on a whitelist may associate " - "leaf nodes with the collection">>), - value = <<"whitelist">>}]; - true -> - [#xdata_option{label = Translate(L), - value = enc_enum(V)} - || {L, V} <- Options] - end, - #xdata_field{var = - <<"pubsub#children_association_policy">>, - values = Values, required = false, type = 'list-single', - options = Opts, desc = <<>>, - label = - Translate(<<"Who may associate leaf nodes with a " - "collection">>)}. - -encode_children_association_whitelist(Value, - Translate) -> - Values = case Value of - [] -> []; - Value -> [enc_jid(V) || V <- Value] - end, - Opts = [], - #xdata_field{var = - <<"pubsub#children_association_whitelist">>, - values = Values, required = false, type = 'jid-multi', - options = Opts, desc = <<>>, - label = - Translate(<<"The list of JIDs that may associate " - "leaf nodes with a collection">>)}. - -encode_children(Value, Translate) -> - Values = case Value of - [] -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"pubsub#children">>, - values = Values, required = false, type = 'text-multi', - options = Opts, desc = <<>>, - label = - Translate(<<"The child nodes (leaf or collection) " - "associated with a collection">>)}. - -encode_children_max(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"pubsub#children_max">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = - Translate(<<"The maximum number of child nodes that " - "can be associated with a collection">>)}. - -encode_collection(Value, Translate) -> - Values = case Value of - [] -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"pubsub#collection">>, - values = Values, required = false, type = 'text-multi', - options = Opts, desc = <<>>, - label = - Translate(<<"The collections with which a node is " - "affiliated">>)}. - -encode_contact(Value, Translate) -> - Values = case Value of - [] -> []; - Value -> [enc_jid(V) || V <- Value] - end, - Opts = [], - #xdata_field{var = <<"pubsub#contact">>, - values = Values, required = false, type = 'jid-multi', - options = Opts, desc = <<>>, - label = - Translate(<<"The JIDs of those to contact with questions">>)}. - -encode_dataform_xslt(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"pubsub#dataform_xslt">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = - Translate(<<"The URL of an XSL transformation which " - "can be applied to the payload format " - "in order to generate a valid Data Forms " - "result that the client could display " - "using a generic Data Forms rendering " - "engine">>)}. - -encode_deliver_notifications(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"pubsub#deliver_notifications">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = Translate(<<"Deliver event notifications">>)}. - -encode_deliver_payloads(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"pubsub#deliver_payloads">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = - Translate(<<"Deliver payloads with event notifications">>)}. - -encode_description(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"pubsub#description">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = Translate(<<"A description of the node">>)}. - -encode_item_expire(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"pubsub#item_expire">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = - Translate(<<"Number of seconds after which to automaticall" - "y purge items">>)}. - -encode_itemreply(Value, Options, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_enum(Value)] - end, - Opts = if Options == default -> - [#xdata_option{label = - Translate(<<"Statically specify a replyto of the " - "node owner(s)">>), - value = <<"owner">>}, - #xdata_option{label = - Translate(<<"Dynamically specify a replyto of the " - "item publisher">>), - value = <<"publisher">>}, - #xdata_option{value = <<"none">>}]; - true -> - [#xdata_option{label = Translate(L), - value = enc_enum(V)} - || {L, V} <- Options] - end, - #xdata_field{var = <<"pubsub#itemreply">>, - values = Values, required = false, type = 'list-single', - options = Opts, desc = <<>>, - label = - Translate(<<"Whether owners or publisher should receive " - "replies to items">>)}. - -encode_language(Value, Options, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = if Options == default -> []; - true -> - [#xdata_option{label = Translate(L), value = V} - || {L, V} <- Options] - end, - #xdata_field{var = <<"pubsub#language">>, - values = Values, required = false, type = 'list-single', - options = Opts, desc = <<>>, - label = - Translate(<<"The default language of the node">>)}. - -encode_max_items(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_int(Value)] - end, - Opts = [], - #xdata_field{var = <<"pubsub#max_items">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = Translate(<<"Max # of items to persist">>)}. - -encode_max_payload_size(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_int(Value)] - end, - Opts = [], - #xdata_field{var = <<"pubsub#max_payload_size">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = Translate(<<"Max payload size in bytes">>)}. - -encode_node_type(Value, Options, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_enum(Value)] - end, - Opts = if Options == default -> - [#xdata_option{label = - Translate(<<"The node is a leaf node (default)">>), - value = <<"leaf">>}, - #xdata_option{label = - Translate(<<"The node is a collection node">>), - value = <<"collection">>}]; - true -> - [#xdata_option{label = Translate(L), - value = enc_enum(V)} - || {L, V} <- Options] - end, - #xdata_field{var = <<"pubsub#node_type">>, - values = Values, required = false, type = 'list-single', - options = Opts, desc = <<>>, - label = - Translate(<<"Whether the node is a leaf (default) " - "or a collection">>)}. - -encode_notification_type(Value, Options, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_enum(Value)] - end, - Opts = if Options == default -> - [#xdata_option{label = - Translate(<<"Messages of type normal">>), - value = <<"normal">>}, - #xdata_option{label = - Translate(<<"Messages of type headline">>), - value = <<"headline">>}]; - true -> - [#xdata_option{label = Translate(L), - value = enc_enum(V)} - || {L, V} <- Options] - end, - #xdata_field{var = <<"pubsub#notification_type">>, - values = Values, required = false, type = 'list-single', - options = Opts, desc = <<>>, - label = - Translate(<<"Specify the event message type">>)}. - -encode_notify_config(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"pubsub#notify_config">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = - Translate(<<"Notify subscribers when the node configuratio" - "n changes">>)}. - -encode_notify_delete(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"pubsub#notify_delete">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = - Translate(<<"Notify subscribers when the node is " - "deleted">>)}. - -encode_notify_retract(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"pubsub#notify_retract">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = - Translate(<<"Notify subscribers when items are removed " - "from the node">>)}. - -encode_notify_sub(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"pubsub#notify_sub">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = - Translate(<<"Whether to notify owners about new subscriber" - "s and unsubscribes">>)}. - -encode_persist_items(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"pubsub#persist_items">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = Translate(<<"Persist items to storage">>)}. - -encode_presence_based_delivery(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"pubsub#presence_based_delivery">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = - Translate(<<"Only deliver notifications to available " - "users">>)}. - -encode_publish_model(Value, Options, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_enum(Value)] - end, - Opts = if Options == default -> - [#xdata_option{label = - Translate(<<"Only publishers may publish">>), - value = <<"publishers">>}, - #xdata_option{label = - Translate(<<"Subscribers may publish">>), - value = <<"subscribers">>}, - #xdata_option{label = - Translate(<<"Anyone may publish">>), - value = <<"open">>}]; - true -> - [#xdata_option{label = Translate(L), - value = enc_enum(V)} - || {L, V} <- Options] - end, - #xdata_field{var = <<"pubsub#publish_model">>, - values = Values, required = false, type = 'list-single', - options = Opts, desc = <<>>, - label = Translate(<<"Specify the publisher model">>)}. - -encode_purge_offline(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"pubsub#purge_offline">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = - Translate(<<"Purge all items when the relevant publisher " - "goes offline">>)}. - -encode_roster_groups_allowed(Value, Options, - Translate) -> - Values = case Value of - [] -> []; - Value -> [Value] - end, - Opts = if Options == default -> []; - true -> - [#xdata_option{label = Translate(L), value = V} - || {L, V} <- Options] - end, - #xdata_field{var = <<"pubsub#roster_groups_allowed">>, - values = Values, required = false, type = 'list-multi', - options = Opts, desc = <<>>, - label = - Translate(<<"Roster groups allowed to subscribe">>)}. - -encode_send_last_published_item(Value, Options, - Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_enum(Value)] - end, - Opts = if Options == default -> - [#xdata_option{label = Translate(<<"Never">>), - value = <<"never">>}, - #xdata_option{label = - Translate(<<"When a new subscription is processed">>), - value = <<"on_sub">>}, - #xdata_option{label = - Translate(<<"When a new subscription is processed " - "and whenever a subscriber comes online">>), - value = <<"on_sub_and_presence">>}]; - true -> - [#xdata_option{label = Translate(L), - value = enc_enum(V)} - || {L, V} <- Options] - end, - #xdata_field{var = - <<"pubsub#send_last_published_item">>, - values = Values, required = false, type = 'list-single', - options = Opts, desc = <<>>, - label = - Translate(<<"When to send the last published item">>)}. - -encode_tempsub(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"pubsub#tempsub">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = - Translate(<<"Whether to make all subscriptions temporary, " - "based on subscriber presence">>)}. - -encode_subscribe(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"pubsub#subscribe">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = - Translate(<<"Whether to allow subscriptions">>)}. - -encode_title(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"pubsub#title">>, values = Values, - required = false, type = 'text-single', options = Opts, - desc = <<>>, - label = Translate(<<"A friendly name for the node">>)}. - -encode_type(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"pubsub#type">>, values = Values, - required = false, type = 'text-single', options = Opts, - desc = <<>>, - label = - Translate(<<"The type of node data, usually specified " - "by the namespace of the payload (if " - "any)">>)}. diff --git a/src/pubsub_publish_options.erl b/src/pubsub_publish_options.erl deleted file mode 100644 index 6e96946fd..000000000 --- a/src/pubsub_publish_options.erl +++ /dev/null @@ -1,157 +0,0 @@ -%% Created automatically by xdata generator (xdata_codec.erl) -%% Source: pubsub_publish_options.xdata -%% Form type: http://jabber.org/protocol/pubsub#publish-options -%% Document: XEP-0060 - --module(pubsub_publish_options). - --export([decode/1, decode/2, encode/1, encode/2, - format_error/1]). - --include("xmpp_codec.hrl"). - --include("pubsub_publish_options.hrl"). - --export_type([property/0, result/0, form/0]). - -dec_enum(Val, Enums) -> - AtomVal = erlang:binary_to_existing_atom(Val, utf8), - case lists:member(AtomVal, Enums) of - true -> AtomVal - end. - -enc_enum(Atom) -> erlang:atom_to_binary(Atom, utf8). - -format_error({form_type_mismatch, Type}) -> - <<"FORM_TYPE doesn't match '", Type/binary, "'">>; -format_error({bad_var_value, Var, Type}) -> - <<"Bad value of field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({missing_value, Var, Type}) -> - <<"Missing value of field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({too_many_values, Var, Type}) -> - <<"Too many values for field '", Var/binary, - "' of type '", Type/binary, "'">>; -format_error({unknown_var, Var, Type}) -> - <<"Unknown field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({missing_required_var, Var, Type}) -> - <<"Missing required field '", Var/binary, "' of type '", - Type/binary, "'">>. - -decode(Fs) -> decode(Fs, []). - -decode(Fs, Acc) -> - case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var, - Fs) - of - false -> decode(Fs, Acc, []); - #xdata_field{values = - [<<"http://jabber.org/protocol/pubsub#publish-opt" - "ions">>]} -> - decode(Fs, Acc, []); - _ -> - erlang:error({?MODULE, - {form_type_mismatch, - <<"http://jabber.org/protocol/pubsub#publish-opt" - "ions">>}}) - end. - -encode(Cfg) -> encode(Cfg, fun (Text) -> Text end). - -encode(List, Translate) when is_list(List) -> - Fs = [case Opt of - {access_model, Val} -> - [encode_access_model(Val, default, Translate)]; - {access_model, Val, Opts} -> - [encode_access_model(Val, Opts, Translate)]; - #xdata_field{} -> [Opt]; - _ -> [] - end - || Opt <- List], - FormType = #xdata_field{var = <<"FORM_TYPE">>, - type = hidden, - values = - [<<"http://jabber.org/protocol/pubsub#publish-opt" - "ions">>]}, - [FormType | lists:flatten(Fs)]. - -decode([#xdata_field{var = <<"pubsub#access_model">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_enum(Value, - [authorize, open, presence, roster, whitelist]) - of - Result -> - decode(Fs, [{access_model, Result} | Acc], - lists:delete(<<"pubsub#access_model">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#access_model">>, - <<"http://jabber.org/protocol/pubsub#publish-opt" - "ions">>}}) - end; -decode([#xdata_field{var = <<"pubsub#access_model">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#access_model">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#access_model">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#access_model">>, - <<"http://jabber.org/protocol/pubsub#publish-opt" - "ions">>}}); -decode([#xdata_field{var = Var} | Fs], Acc, Required) -> - if Var /= <<"FORM_TYPE">> -> - erlang:error({?MODULE, - {unknown_var, Var, - <<"http://jabber.org/protocol/pubsub#publish-opt" - "ions">>}}); - true -> decode(Fs, Acc, Required) - end; -decode([], _, [Var | _]) -> - erlang:error({?MODULE, - {missing_required_var, Var, - <<"http://jabber.org/protocol/pubsub#publish-opt" - "ions">>}}); -decode([], Acc, []) -> Acc. - -encode_access_model(Value, Options, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_enum(Value)] - end, - Opts = if Options == default -> - [#xdata_option{label = - Translate(<<"Access model of authorize">>), - value = <<"authorize">>}, - #xdata_option{label = - Translate(<<"Access model of open">>), - value = <<"open">>}, - #xdata_option{label = - Translate(<<"Access model of presence">>), - value = <<"presence">>}, - #xdata_option{label = - Translate(<<"Access model of roster">>), - value = <<"roster">>}, - #xdata_option{label = - Translate(<<"Access model of whitelist">>), - value = <<"whitelist">>}]; - true -> - [#xdata_option{label = Translate(L), - value = enc_enum(V)} - || {L, V} <- Options] - end, - #xdata_field{var = <<"pubsub#access_model">>, - values = Values, required = false, type = 'list-single', - options = Opts, desc = <<>>, - label = Translate(<<"Specify the access model">>)}. diff --git a/src/pubsub_subscribe_authorization.erl b/src/pubsub_subscribe_authorization.erl deleted file mode 100644 index 46538da8d..000000000 --- a/src/pubsub_subscribe_authorization.erl +++ /dev/null @@ -1,279 +0,0 @@ -%% Created automatically by xdata generator (xdata_codec.erl) -%% Source: pubsub_subscribe_authorization.xdata -%% Form type: http://jabber.org/protocol/pubsub#subscribe_authorization -%% Document: XEP-0060 - --module(pubsub_subscribe_authorization). - --export([decode/1, decode/2, encode/1, encode/2, - format_error/1]). - --include("xmpp_codec.hrl"). - --include("pubsub_subscribe_authorization.hrl"). - --export_type([property/0, result/0, form/0]). - -dec_bool(<<"1">>) -> true; -dec_bool(<<"0">>) -> false; -dec_bool(<<"true">>) -> true; -dec_bool(<<"false">>) -> false. - -enc_bool(true) -> <<"1">>; -enc_bool(false) -> <<"0">>. - -enc_jid(J) -> jid:to_string(J). - -dec_jid(Val) -> - case jid:from_string(Val) of - error -> erlang:error(badarg); - J -> J - end. - -format_error({form_type_mismatch, Type}) -> - <<"FORM_TYPE doesn't match '", Type/binary, "'">>; -format_error({bad_var_value, Var, Type}) -> - <<"Bad value of field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({missing_value, Var, Type}) -> - <<"Missing value of field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({too_many_values, Var, Type}) -> - <<"Too many values for field '", Var/binary, - "' of type '", Type/binary, "'">>; -format_error({unknown_var, Var, Type}) -> - <<"Unknown field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({missing_required_var, Var, Type}) -> - <<"Missing required field '", Var/binary, "' of type '", - Type/binary, "'">>. - -decode(Fs) -> decode(Fs, []). - -decode(Fs, Acc) -> - case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var, - Fs) - of - false -> - decode(Fs, Acc, - [<<"pubsub#allow">>, <<"pubsub#node">>, - <<"pubsub#subscriber_jid">>]); - #xdata_field{values = - [<<"http://jabber.org/protocol/pubsub#subscribe_a" - "uthorization">>]} -> - decode(Fs, Acc, - [<<"pubsub#allow">>, <<"pubsub#node">>, - <<"pubsub#subscriber_jid">>]); - _ -> - erlang:error({?MODULE, - {form_type_mismatch, - <<"http://jabber.org/protocol/pubsub#subscribe_a" - "uthorization">>}}) - end. - -encode(Cfg) -> encode(Cfg, fun (Text) -> Text end). - -encode(List, Translate) when is_list(List) -> - Fs = [case Opt of - {allow, Val} -> [encode_allow(Val, Translate)]; - {allow, _, _} -> erlang:error({badarg, Opt}); - {node, Val} -> [encode_node(Val, Translate)]; - {node, _, _} -> erlang:error({badarg, Opt}); - {subscriber_jid, Val} -> - [encode_subscriber_jid(Val, Translate)]; - {subscriber_jid, _, _} -> erlang:error({badarg, Opt}); - {subid, Val} -> [encode_subid(Val, Translate)]; - {subid, _, _} -> erlang:error({badarg, Opt}); - #xdata_field{} -> [Opt]; - _ -> [] - end - || Opt <- List], - FormType = #xdata_field{var = <<"FORM_TYPE">>, - type = hidden, - values = - [<<"http://jabber.org/protocol/pubsub#subscribe_a" - "uthorization">>]}, - [FormType | lists:flatten(Fs)]. - -decode([#xdata_field{var = <<"pubsub#allow">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{allow, Result} | Acc], - lists:delete(<<"pubsub#allow">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#allow">>, - <<"http://jabber.org/protocol/pubsub#subscribe_a" - "uthorization">>}}) - end; -decode([#xdata_field{var = <<"pubsub#allow">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#allow">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#allow">>} | _], _, - _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#allow">>, - <<"http://jabber.org/protocol/pubsub#subscribe_a" - "uthorization">>}}); -decode([#xdata_field{var = <<"pubsub#node">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{node, Result} | Acc], - lists:delete(<<"pubsub#node">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#node">>, - <<"http://jabber.org/protocol/pubsub#subscribe_a" - "uthorization">>}}) - end; -decode([#xdata_field{var = <<"pubsub#node">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#node">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#node">>} | _], _, - _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#node">>, - <<"http://jabber.org/protocol/pubsub#subscribe_a" - "uthorization">>}}); -decode([#xdata_field{var = <<"pubsub#subscriber_jid">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_jid(Value) of - Result -> - decode(Fs, [{subscriber_jid, Result} | Acc], - lists:delete(<<"pubsub#subscriber_jid">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#subscriber_jid">>, - <<"http://jabber.org/protocol/pubsub#subscribe_a" - "uthorization">>}}) - end; -decode([#xdata_field{var = <<"pubsub#subscriber_jid">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#subscriber_jid">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#subscriber_jid">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#subscriber_jid">>, - <<"http://jabber.org/protocol/pubsub#subscribe_a" - "uthorization">>}}); -decode([#xdata_field{var = <<"pubsub#subid">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{subid, Result} | Acc], - lists:delete(<<"pubsub#subid">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#subid">>, - <<"http://jabber.org/protocol/pubsub#subscribe_a" - "uthorization">>}}) - end; -decode([#xdata_field{var = <<"pubsub#subid">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#subid">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#subid">>} | _], _, - _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#subid">>, - <<"http://jabber.org/protocol/pubsub#subscribe_a" - "uthorization">>}}); -decode([#xdata_field{var = Var} | Fs], Acc, Required) -> - if Var /= <<"FORM_TYPE">> -> - erlang:error({?MODULE, - {unknown_var, Var, - <<"http://jabber.org/protocol/pubsub#subscribe_a" - "uthorization">>}}); - true -> decode(Fs, Acc, Required) - end; -decode([], _, [Var | _]) -> - erlang:error({?MODULE, - {missing_required_var, Var, - <<"http://jabber.org/protocol/pubsub#subscribe_a" - "uthorization">>}}); -decode([], Acc, []) -> Acc. - -encode_allow(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"pubsub#allow">>, values = Values, - required = false, type = boolean, options = Opts, - desc = <<>>, - label = - Translate(<<"Allow this Jabber ID to subscribe to " - "this pubsub node?">>)}. - -encode_node(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"pubsub#node">>, values = Values, - required = false, type = 'text-single', options = Opts, - desc = <<>>, label = Translate(<<"Node ID">>)}. - -encode_subscriber_jid(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_jid(Value)] - end, - Opts = [], - #xdata_field{var = <<"pubsub#subscriber_jid">>, - values = Values, required = false, type = 'jid-single', - options = Opts, desc = <<>>, - label = Translate(<<"Subscriber Address">>)}. - -encode_subid(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"pubsub#subid">>, values = Values, - required = false, type = 'text-single', options = Opts, - desc = <<>>, - label = - Translate(<<"The subscription identifier associated " - "with the subscription request">>)}. diff --git a/src/pubsub_subscribe_options.erl b/src/pubsub_subscribe_options.erl deleted file mode 100644 index 02c046995..000000000 --- a/src/pubsub_subscribe_options.erl +++ /dev/null @@ -1,508 +0,0 @@ -%% Created automatically by xdata generator (xdata_codec.erl) -%% Source: pubsub_subscribe_options.xdata -%% Form type: http://jabber.org/protocol/pubsub#subscribe_options -%% Document: XEP-0060 - --module(pubsub_subscribe_options). - --export([decode/1, decode/2, encode/1, encode/2, - format_error/1]). - --include("xmpp_codec.hrl"). - --include("pubsub_subscribe_options.hrl"). - --export_type([property/0, result/0, form/0]). - -dec_enum(Val, Enums) -> - AtomVal = erlang:binary_to_existing_atom(Val, utf8), - case lists:member(AtomVal, Enums) of - true -> AtomVal - end. - -enc_enum(Atom) -> erlang:atom_to_binary(Atom, utf8). - -dec_bool(<<"1">>) -> true; -dec_bool(<<"0">>) -> false; -dec_bool(<<"true">>) -> true; -dec_bool(<<"false">>) -> false. - -enc_bool(true) -> <<"1">>; -enc_bool(false) -> <<"0">>. - -format_error({form_type_mismatch, Type}) -> - <<"FORM_TYPE doesn't match '", Type/binary, "'">>; -format_error({bad_var_value, Var, Type}) -> - <<"Bad value of field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({missing_value, Var, Type}) -> - <<"Missing value of field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({too_many_values, Var, Type}) -> - <<"Too many values for field '", Var/binary, - "' of type '", Type/binary, "'">>; -format_error({unknown_var, Var, Type}) -> - <<"Unknown field '", Var/binary, "' of type '", - Type/binary, "'">>; -format_error({missing_required_var, Var, Type}) -> - <<"Missing required field '", Var/binary, "' of type '", - Type/binary, "'">>. - -decode(Fs) -> decode(Fs, []). - -decode(Fs, Acc) -> - case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var, - Fs) - of - false -> decode(Fs, Acc, []); - #xdata_field{values = - [<<"http://jabber.org/protocol/pubsub#subscribe_o" - "ptions">>]} -> - decode(Fs, Acc, []); - _ -> - erlang:error({?MODULE, - {form_type_mismatch, - <<"http://jabber.org/protocol/pubsub#subscribe_o" - "ptions">>}}) - end. - -encode(Cfg) -> encode(Cfg, fun (Text) -> Text end). - -encode(List, Translate) when is_list(List) -> - Fs = [case Opt of - {deliver, Val} -> [encode_deliver(Val, Translate)]; - {deliver, _, _} -> erlang:error({badarg, Opt}); - {digest, Val} -> [encode_digest(Val, Translate)]; - {digest, _, _} -> erlang:error({badarg, Opt}); - {digest_frequency, Val} -> - [encode_digest_frequency(Val, Translate)]; - {digest_frequency, _, _} -> erlang:error({badarg, Opt}); - {expire, Val} -> [encode_expire(Val, Translate)]; - {expire, _, _} -> erlang:error({badarg, Opt}); - {include_body, Val} -> - [encode_include_body(Val, Translate)]; - {include_body, _, _} -> erlang:error({badarg, Opt}); - {'show-values', Val} -> - ['encode_show-values'(Val, default, Translate)]; - {'show-values', Val, Opts} -> - ['encode_show-values'(Val, Opts, Translate)]; - {subscription_type, Val} -> - [encode_subscription_type(Val, default, Translate)]; - {subscription_type, Val, Opts} -> - [encode_subscription_type(Val, Opts, Translate)]; - {subscription_depth, Val} -> - [encode_subscription_depth(Val, default, Translate)]; - {subscription_depth, Val, Opts} -> - [encode_subscription_depth(Val, Opts, Translate)]; - #xdata_field{} -> [Opt]; - _ -> [] - end - || Opt <- List], - FormType = #xdata_field{var = <<"FORM_TYPE">>, - type = hidden, - values = - [<<"http://jabber.org/protocol/pubsub#subscribe_o" - "ptions">>]}, - [FormType | lists:flatten(Fs)]. - -decode([#xdata_field{var = <<"pubsub#deliver">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{deliver, Result} | Acc], - lists:delete(<<"pubsub#deliver">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#deliver">>, - <<"http://jabber.org/protocol/pubsub#subscribe_o" - "ptions">>}}) - end; -decode([#xdata_field{var = <<"pubsub#deliver">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#deliver">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#deliver">>} | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#deliver">>, - <<"http://jabber.org/protocol/pubsub#subscribe_o" - "ptions">>}}); -decode([#xdata_field{var = <<"pubsub#digest">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{digest, Result} | Acc], - lists:delete(<<"pubsub#digest">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#digest">>, - <<"http://jabber.org/protocol/pubsub#subscribe_o" - "ptions">>}}) - end; -decode([#xdata_field{var = <<"pubsub#digest">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#digest">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#digest">>} | _], _, - _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#digest">>, - <<"http://jabber.org/protocol/pubsub#subscribe_o" - "ptions">>}}); -decode([#xdata_field{var = - <<"pubsub#digest_frequency">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{digest_frequency, Result} | Acc], - lists:delete(<<"pubsub#digest_frequency">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#digest_frequency">>, - <<"http://jabber.org/protocol/pubsub#subscribe_o" - "ptions">>}}) - end; -decode([#xdata_field{var = - <<"pubsub#digest_frequency">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"pubsub#digest_frequency">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"pubsub#digest_frequency">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#digest_frequency">>, - <<"http://jabber.org/protocol/pubsub#subscribe_o" - "ptions">>}}); -decode([#xdata_field{var = <<"pubsub#expire">>, - values = [Value]} - | Fs], - Acc, Required) -> - try Value of - Result -> - decode(Fs, [{expire, Result} | Acc], - lists:delete(<<"pubsub#expire">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#expire">>, - <<"http://jabber.org/protocol/pubsub#subscribe_o" - "ptions">>}}) - end; -decode([#xdata_field{var = <<"pubsub#expire">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#expire">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#expire">>} | _], _, - _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#expire">>, - <<"http://jabber.org/protocol/pubsub#subscribe_o" - "ptions">>}}); -decode([#xdata_field{var = <<"pubsub#include_body">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_bool(Value) of - Result -> - decode(Fs, [{include_body, Result} | Acc], - lists:delete(<<"pubsub#include_body">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#include_body">>, - <<"http://jabber.org/protocol/pubsub#subscribe_o" - "ptions">>}}) - end; -decode([#xdata_field{var = <<"pubsub#include_body">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = <<"pubsub#include_body">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = <<"pubsub#include_body">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#include_body">>, - <<"http://jabber.org/protocol/pubsub#subscribe_o" - "ptions">>}}); -decode([#xdata_field{var = <<"pubsub#show-values">>, - values = Values} - | Fs], - Acc, Required) -> - try [dec_enum(Value, [away, chat, dnd, online, xa]) - || Value <- Values] - of - Result -> - decode(Fs, [{'show-values', Result} | Acc], - lists:delete(<<"pubsub#show-values">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#show-values">>, - <<"http://jabber.org/protocol/pubsub#subscribe_o" - "ptions">>}}) - end; -decode([#xdata_field{var = - <<"pubsub#subscription_type">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_enum(Value, [items, nodes]) of - Result -> - decode(Fs, [{subscription_type, Result} | Acc], - lists:delete(<<"pubsub#subscription_type">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#subscription_type">>, - <<"http://jabber.org/protocol/pubsub#subscribe_o" - "ptions">>}}) - end; -decode([#xdata_field{var = - <<"pubsub#subscription_type">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"pubsub#subscription_type">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"pubsub#subscription_type">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#subscription_type">>, - <<"http://jabber.org/protocol/pubsub#subscribe_o" - "ptions">>}}); -decode([#xdata_field{var = - <<"pubsub#subscription_depth">>, - values = [Value]} - | Fs], - Acc, Required) -> - try dec_enum(Value, ['1', all]) of - Result -> - decode(Fs, [{subscription_depth, Result} | Acc], - lists:delete(<<"pubsub#subscription_depth">>, Required)) - catch - _:_ -> - erlang:error({?MODULE, - {bad_var_value, <<"pubsub#subscription_depth">>, - <<"http://jabber.org/protocol/pubsub#subscribe_o" - "ptions">>}}) - end; -decode([#xdata_field{var = - <<"pubsub#subscription_depth">>, - values = []} = - F - | Fs], - Acc, Required) -> - decode([F#xdata_field{var = - <<"pubsub#subscription_depth">>, - values = [<<>>]} - | Fs], - Acc, Required); -decode([#xdata_field{var = - <<"pubsub#subscription_depth">>} - | _], - _, _) -> - erlang:error({?MODULE, - {too_many_values, <<"pubsub#subscription_depth">>, - <<"http://jabber.org/protocol/pubsub#subscribe_o" - "ptions">>}}); -decode([#xdata_field{var = Var} | Fs], Acc, Required) -> - if Var /= <<"FORM_TYPE">> -> - erlang:error({?MODULE, - {unknown_var, Var, - <<"http://jabber.org/protocol/pubsub#subscribe_o" - "ptions">>}}); - true -> decode(Fs, Acc, Required) - end; -decode([], _, [Var | _]) -> - erlang:error({?MODULE, - {missing_required_var, Var, - <<"http://jabber.org/protocol/pubsub#subscribe_o" - "ptions">>}}); -decode([], Acc, []) -> Acc. - -encode_deliver(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"pubsub#deliver">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = - Translate(<<"Whether an entity wants to receive or " - "disable notifications">>)}. - -encode_digest(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"pubsub#digest">>, values = Values, - required = false, type = boolean, options = Opts, - desc = <<>>, - label = - Translate(<<"Whether an entity wants to receive digests " - "(aggregations) of notifications or all " - "notifications individually">>)}. - -encode_digest_frequency(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"pubsub#digest_frequency">>, - values = Values, required = false, type = 'text-single', - options = Opts, desc = <<>>, - label = - Translate(<<"The minimum number of milliseconds between " - "sending any two notification digests">>)}. - -encode_expire(Value, Translate) -> - Values = case Value of - <<>> -> []; - Value -> [Value] - end, - Opts = [], - #xdata_field{var = <<"pubsub#expire">>, values = Values, - required = false, type = 'text-single', options = Opts, - desc = <<>>, - label = - Translate(<<"The DateTime at which a leased subscription " - "will end or has ended">>)}. - -encode_include_body(Value, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_bool(Value)] - end, - Opts = [], - #xdata_field{var = <<"pubsub#include_body">>, - values = Values, required = false, type = boolean, - options = Opts, desc = <<>>, - label = - Translate(<<"Whether an entity wants to receive an " - "XMPP message body in addition to the " - "payload format">>)}. - -'encode_show-values'(Value, Options, Translate) -> - Values = case Value of - [] -> []; - Value -> [enc_enum(V) || V <- Value] - end, - Opts = if Options == default -> - [#xdata_option{label = - Translate(<<"XMPP Show Value of Away">>), - value = <<"away">>}, - #xdata_option{label = - Translate(<<"XMPP Show Value of Chat">>), - value = <<"chat">>}, - #xdata_option{label = - Translate(<<"XMPP Show Value of DND (Do Not Disturb)">>), - value = <<"dnd">>}, - #xdata_option{label = - Translate(<<"Mere Availability in XMPP (No Show Value)">>), - value = <<"online">>}, - #xdata_option{label = - Translate(<<"XMPP Show Value of XA (Extended Away)">>), - value = <<"xa">>}]; - true -> - [#xdata_option{label = Translate(L), - value = enc_enum(V)} - || {L, V} <- Options] - end, - #xdata_field{var = <<"pubsub#show-values">>, - values = Values, required = false, type = 'list-multi', - options = Opts, desc = <<>>, - label = - Translate(<<"The presence states for which an entity " - "wants to receive notifications">>)}. - -encode_subscription_type(Value, Options, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_enum(Value)] - end, - Opts = if Options == default -> - [#xdata_option{label = - Translate(<<"Receive notification of new items only">>), - value = <<"items">>}, - #xdata_option{label = - Translate(<<"Receive notification of new nodes only">>), - value = <<"nodes">>}]; - true -> - [#xdata_option{label = Translate(L), - value = enc_enum(V)} - || {L, V} <- Options] - end, - #xdata_field{var = <<"pubsub#subscription_type">>, - values = Values, required = false, type = 'list-single', - options = Opts, desc = <<>>, label = <<>>}. - -encode_subscription_depth(Value, Options, Translate) -> - Values = case Value of - undefined -> []; - Value -> [enc_enum(Value)] - end, - Opts = if Options == default -> - [#xdata_option{label = - Translate(<<"Receive notification from direct child " - "nodes only">>), - value = <<"1">>}, - #xdata_option{label = - Translate(<<"Receive notification from all descendent " - "nodes">>), - value = <<"all">>}]; - true -> - [#xdata_option{label = Translate(L), - value = enc_enum(V)} - || {L, V} <- Options] - end, - #xdata_field{var = <<"pubsub#subscription_depth">>, - values = Values, required = false, type = 'list-single', - options = Opts, desc = <<>>, label = <<>>}. diff --git a/src/xdata_codec.erl b/src/xdata_codec.erl deleted file mode 100644 index 223f24a1b..000000000 --- a/src/xdata_codec.erl +++ /dev/null @@ -1,648 +0,0 @@ -%%%------------------------------------------------------------------- -%%% @author Evgeny Khramtsov -%%% @copyright (C) 2016, Evgeny Khramtsov -%%% @doc -%%% -%%% @end -%%% Created : 27 Sep 2016 by Evgeny Khramtsov -%%%------------------------------------------------------------------- --module(xdata_codec). - -%% API --export([compile/1, compile/2]). --export([dec_int/1, dec_int/3, dec_enum/2, dec_bool/1, not_empty/1, - dec_enum_int/2, dec_enum_int/4, enc_int/1, enc_enum/1, - enc_bool/1, enc_enum_int/1, format_error/1, enc_jid/1, dec_jid/1]). --include("xmpp.hrl"). - --record(state, {mod_name :: atom(), - file_name :: string(), - erl = "" :: string(), - hrl = "" :: string(), - dir = "" :: string(), - ns = <<>> :: binary(), - doc = <<>> :: binary(), - erl_dir = "" :: string(), - hrl_dir = "" :: string(), - prefix = [] :: [binary()], - dec_mfas = [] :: [{binary(), mfa()}], - enc_mfas = [] :: [{binary(), mfa()}], - specs = [] :: [{binary(), string()}], - required = [] :: [{binary(), boolean()} | binary()], - defaults = [] :: [{binary(), any()}]}). - --define(is_multi_type(T), - ((T == 'list-multi') or (T == 'jid-multi') or (T == 'text-multi'))). - --define(is_list_type(T), - ((T == 'list-single') or (T == 'list-multi'))). - -%%%=================================================================== -%%% API -%%%=================================================================== -compile(Path) -> - compile(Path, []). - -compile(Path, Opts) -> - case filelib:is_dir(Path) of - true -> - filelib:fold_files( - Path, ".*.xdata", false, - fun(File, ok) -> - compile_file(File, Opts); - (_, Err) -> - Err - end, ok); - false -> - compile_file(Path, Opts) - end. - -compile_file(Path, Opts) -> - try - ok = application:ensure_started(fast_xml), - DirName = filename:dirname(Path), - FileName = filename:basename(Path), - RootName = filename:rootname(FileName), - ConfigPath = filename:join(DirName, RootName) ++ ".cfg", - ModName = list_to_atom(RootName), - {ok, Data} = file:read_file(Path), - Config = case file:consult(ConfigPath) of - {ok, Terms} -> lists:flatten(Terms); - {error, enoent} -> [] - end, - State = #state{mod_name = ModName, - file_name = FileName, - erl = filename:rootname(FileName) ++ ".erl", - hrl = filename:rootname(FileName) ++ ".hrl", - dir = DirName, - prefix = proplists:get_all_values(prefix, Config), - erl_dir = proplists:get_value(erl_dir, Opts, DirName), - hrl_dir = proplists:get_value(hrl_dir, Opts, DirName), - dec_mfas = proplists:get_value(decode, Config, []), - enc_mfas = proplists:get_value(encode, Config, []), - specs = proplists:get_value(specs, Config, []), - required = proplists:get_value(required, Config, []), - defaults = proplists:get_value(defaults, Config, [])}, - #xmlel{} = El = fxml_stream:parse_element(Data), - ok = compile_element(normalize(El), State), - io:format("Compiled ~s~n", [Path]) - catch _:{badmatch, Err} -> - io:format(standard_error, "Failed to compile ~s: ~p~n", - [Path, Err]), - Err - end. - -emit(Format) -> - emit(Format, []). - -emit(Format, Args) -> - put(outbuf, get(outbuf) ++ io_lib:format(Format, Args)). - -dec_int(Val) -> - dec_int(Val, infinity, infinity). - -dec_int(Val, Min, Max) -> - case list_to_integer(binary_to_list(Val)) of - Int when Int =< Max, Min == infinity -> - Int; - Int when Int =< Max, Int >= Min -> - Int - end. - -enc_int(Int) -> - integer_to_binary(Int). - -dec_enum(Val, Enums) -> - AtomVal = erlang:binary_to_existing_atom(Val, utf8), - case lists:member(AtomVal, Enums) of - true -> - AtomVal - end. - -enc_enum(Atom) -> - erlang:atom_to_binary(Atom, utf8). - -dec_enum_int(Val, Enums) -> - try dec_int(Val) - catch _:_ -> dec_enum(Val, Enums) - end. - -dec_enum_int(Val, Enums, Min, Max) -> - try dec_int(Val, Min, Max) - catch _:_ -> dec_enum(Val, Enums) - end. - -enc_enum_int(Int) when is_integer(Int) -> - enc_int(Int); -enc_enum_int(Atom) -> - enc_enum(Atom). - -dec_bool(<<"1">>) -> true; -dec_bool(<<"0">>) -> false; -dec_bool(<<"true">>) -> true; -dec_bool(<<"false">>) -> false. - -enc_bool(true) -> <<"1">>; -enc_bool(false) -> <<"0">>. - -enc_jid(J) -> jid:to_string(J). - -dec_jid(Val) -> - case jid:from_string(Val) of - error -> erlang:error(badarg); - J -> J - end. - -not_empty(<<_, _/binary>> = Val) -> - Val. - -format_error({form_type_mismatch, Type}) -> - <<"FORM_TYPE doesn't match '", Type/binary, "'">>; -format_error({bad_var_value, Var, Type}) -> - <<"Bad value of field '", Var/binary, "' of type '", Type/binary, "'">>; -format_error({missing_value, Var, Type}) -> - <<"Missing value of field '", Var/binary, "' of type '", Type/binary, "'">>; -format_error({too_many_values, Var, Type}) -> - <<"Too many values for field '", Var/binary, "' of type '", Type/binary, "'">>; -format_error({unknown_var, Var, Type}) -> - <<"Unknown field '", Var/binary, "' of type '", Type/binary, "'">>; -format_error({missing_required_var, Var, Type}) -> - <<"Missing required field '", Var/binary, "' of type '", Type/binary, "'">>. - -%%%=================================================================== -%%% Internal functions -%%%=================================================================== -compile_element(#xmlel{name = <<"form_type">>, children = Els} = Form, - #state{erl = OutErl, erl_dir = ErlDir, - hrl = OutHrl, hrl_dir = HrlDir} = State0) -> - try - Name = fxml:get_subtag_cdata(Form, <<"name">>), - Doc = fxml:get_subtag_cdata(Form, <<"doc">>), - X = #xmlel{name = <<"x">>, - attrs = [{<<"type">>, <<"form">>}, - {<<"xmlns">>, <<"jabber:x:data">>}], - children = Els}, - State = State0#state{ns = Name, doc = Doc}, - #xdata{fields = Fs} = xmpp_codec:decode(X), - put(outbuf, []), - mk_header(State), - mk_aux_funs(), - mk_top_decoder(Fs, State), - mk_top_encoder(Fs, State), - mk_decoder(Fs, State), - mk_encoders(Fs, State), - ErlData = get(outbuf), - ok = file:write_file(filename:join(ErlDir, OutErl), ErlData), - ok = erl_tidy:file(filename:join(ErlDir, OutErl), [{backups, false}]), - put(outbuf, []), - mk_type_definitions(Fs, State), - HrlData = get(outbuf), - ok = file:write_file(filename:join(HrlDir, OutHrl), HrlData) - catch _:{badmatch, Err} -> - Err - end. - -mk_aux_funs() -> - case get_abstract_code_from_myself() of - {ok, AbsCode} -> - AST = lists:filter( - fun(T) -> - case catch erl_syntax_lib:analyze_function(T) of - {format_error, 1} -> true; - {dec_int, 3} -> true; - {dec_int, 1} -> true; - {dec_enum, 2} -> true; - {dec_enum_int, 2} -> true; - {dec_enum_int, 4} -> true; - {enc_int, 1} -> true; - {enc_enum, 1} -> true; - {enc_enum_int, 1} -> true; - {not_empty, 1} -> true; - {dec_bool, 1} -> true; - {enc_bool, 1} -> true; - {enc_jid, 1} -> true; - {dec_jid, 1} -> true; - _ -> false - end - end, AbsCode), - emit(erl_prettypr:format(erl_syntax:form_list(AST)) ++ io_lib:nl()); - error -> - erlang:error({no_abstract_code_found, ?MODULE}) - end. - -get_abstract_code_from_myself() -> - {file, File} = code:is_loaded(?MODULE), - case beam_lib:chunks(File, [abstract_code]) of - {ok, {_, List}} -> - case lists:keyfind(abstract_code, 1, List) of - {abstract_code, {raw_abstract_v1, Abstr}} -> - {ok, Abstr}; - _ -> - error - end; - _ -> - error - end. - -mk_comment_header(#state{file_name = Source, ns = NS, doc = Doc}) -> - emit("%% Created automatically by xdata generator (xdata_codec.erl)~n" - "%% Source: ~s~n" - "%% Form type: ~s~n", [Source, NS]), - if Doc /= <<>> -> emit("%% Document: ~s~n~n", [Doc]); - true -> emit("~n") - end. - -mk_header(#state{mod_name = Mod, hrl = Include} = State) -> - mk_comment_header(State), - emit("~n-module(~s).~n", [Mod]), - emit("-export([decode/1, decode/2, encode/1, encode/2, format_error/1]).~n"), - emit("-include(\"xmpp_codec.hrl\").~n"), - emit("-include(\"~s\").~n", [Include]), - emit("-export_type([property/0, result/0, form/0]).~n"). - -mk_type_definitions(Fs, State) -> - mk_comment_header(State), - lists:foreach( - fun(#xdata_field{var = Var} = F) -> - Spec = get_typespec(F, State), - case is_complex_type(Spec) of - true -> - emit("-type '~s'() :: ~s.~n", - [var_to_rec_field(Var, State), Spec]); - false -> - ok - end - end, Fs), - emit("~n-type property() :: "), - Fields = lists:map( - fun(#xdata_field{var = Var} = F) -> - RecField = var_to_rec_field(Var, State), - [io_lib:format("{'~s', ~s}", - [RecField, mk_typespec(F, State)])] - end, Fs), - emit(string:join(Fields, " |~n ") ++ ".~n"), - emit("-type result() :: [property()].~n~n"), - VarsWithSpec = lists:flatmap( - fun(#xdata_field{type = T, var = Var} = F) - when ?is_list_type(T) -> - RecName = var_to_rec_field(Var, State), - Spec0 = get_typespec(F, State), - Spec = case is_complex_type(Spec0) of - true -> - io_lib:format("'~s'()", [RecName]); - false -> - Spec0 - end, - [{RecName, mk_typespec(F, State), Spec}]; - (_) -> - [] - end, Fs), - case VarsWithSpec of - [] -> - emit("-type form() :: [property() | xdata_field()].~n"); - _ -> - emit("-type options(T) :: [{binary(), T}].~n"), - emit("-type property_with_options() ::~n "), - Options = [io_lib:format("{'~s', ~s, options(~s)}", - [Var, Spec1, Spec2]) - || {Var, Spec1, Spec2} <- VarsWithSpec], - emit(string:join(Options, " |~n ") ++ ".~n"), - emit("-type form() :: [property() | property_with_options() | xdata_field()].~n") - end. - -mk_top_decoder(Fs, State) -> - Required = [Var || #xdata_field{var = Var} <- Fs, is_required(Var, State)], - emit("decode(Fs) -> decode(Fs, []).~n"), - emit("decode(Fs, Acc) ->" - " case lists:keyfind(<<\"FORM_TYPE\">>, #xdata_field.var, Fs) of" - " false ->" - " decode(Fs, Acc, ~p);" - " #xdata_field{values = [~p]} ->" - " decode(Fs, Acc, ~p);" - " _ ->" - " erlang:error({?MODULE, {form_type_mismatch, ~p}})~n" - " end.~n", - [Required, State#state.ns, Required, State#state.ns]). - -mk_top_encoder(Fs, State) -> - Clauses = string:join( - lists:map( - fun(#xdata_field{var = Var, type = T}) when ?is_list_type(T) -> - Field = var_to_rec_field(Var, State), - io_lib:format( - "{'~s', Val} -> ['encode_~s'(Val, default, Translate)];" - "{'~s', Val, Opts} -> ['encode_~s'(Val, Opts, Translate)]", - [Field, Field, Field, Field]); - (#xdata_field{var = Var}) -> - Field = var_to_rec_field(Var, State), - io_lib:format( - "{'~s', Val} -> ['encode_~s'(Val, Translate)];" - "{'~s', _, _} -> erlang:error({badarg, Opt})", - [Field, Field, Field]) - end, Fs) ++ ["#xdata_field{} -> [Opt]; _ -> []"], - ";"), - emit("encode(Cfg) -> encode(Cfg, fun(Text) -> Text end).~n"), - emit("encode(List, Translate) when is_list(List) ->" - " Fs = [case Opt of ~s end || Opt <- List]," - " FormType = #xdata_field{var = <<\"FORM_TYPE\">>, type = hidden," - " values = [~p]}," - " [FormType|lists:flatten(Fs)].~n", - [Clauses, State#state.ns]). - -mk_decoder([#xdata_field{var = Var, type = Type} = F|Fs], State) -> - ValVar = if ?is_multi_type(Type) -> "Values"; - true -> "[Value]" - end, - DecFun = if ?is_multi_type(Type) -> - ["[", mk_decoding_fun(F, State), " || Value <- Values]"]; - true -> - mk_decoding_fun(F, State) - end, - emit("decode([#xdata_field{var = ~p, values = ~s}|Fs], Acc, Required) ->" - " try ~s of" - " Result -> decode(Fs, [{'~s', Result}|Acc]," - " lists:delete(~p, Required))" - " catch _:_ ->" - " erlang:error({?MODULE, {bad_var_value, ~p, ~p}})" - " end;", - [Var, ValVar, DecFun, var_to_rec_field(Var, State), - Var, Var, State#state.ns]), - if not ?is_multi_type(Type) -> - emit("decode([#xdata_field{var = ~p, values = []} = F|Fs]," - " Acc, Required) ->" - " decode([F#xdata_field{var = ~p, values = [<<>>]}|Fs]," - " Acc, Required);", - [Var, Var]), - emit("decode([#xdata_field{var = ~p}|_], _, _) ->" - " erlang:error({?MODULE, {too_many_values, ~p, ~p}});", - [Var, Var, State#state.ns]); - true -> - ok - end, - mk_decoder(Fs, State); -mk_decoder([], State) -> - emit("decode([#xdata_field{var = Var}|Fs], Acc, Required) ->" - " if Var /= <<\"FORM_TYPE\">> ->" - " erlang:error({?MODULE, {unknown_var, Var, ~p}});" - " true ->" - " decode(Fs, Acc, Required)" - " end;", - [State#state.ns]), - emit("decode([], _, [Var|_]) ->" - " erlang:error({?MODULE, {missing_required_var, Var, ~p}});~n", - [State#state.ns]), - emit("decode([], Acc, []) -> Acc.~n"). - -mk_encoders(Fs, State) -> - lists:foreach( - fun(#xdata_field{var = Var, required = IsRequired, desc = Desc, - label = Label, type = Type} = F) -> - EncVals = mk_encoded_values(F, State), - EncOpts = mk_encoded_options(F, State), - FieldName = var_to_rec_field(Var, State), - DescStr = if Desc == <<>> -> "<<>>"; - true -> io_lib:format("Translate(~p)", [Desc]) - end, - LabelStr = if Label == <<>> -> "<<>>"; - true -> io_lib:format("Translate(~p)", [Label]) - end, - if ?is_list_type(Type) -> - emit("'encode_~s'(Value, Options, Translate) ->", [FieldName]); - true -> - emit("'encode_~s'(Value, Translate) ->", [FieldName]) - end, - emit(" Values = ~s," - " Opts = ~s," - " #xdata_field{var = ~p," - " values = Values," - " required = ~p," - " type = ~p," - " options = Opts," - " desc = ~s," - " label = ~s}.~n", - [EncVals, EncOpts, Var, IsRequired, Type, DescStr, LabelStr]) - end, Fs). - -mk_encoded_values(#xdata_field{var = Var, type = Type, - options = Options}, State) -> - EncFun = - case get_enc_fun(Var, Type, Options, State) of - {M, Fun, Args} -> - Mod = if M == undefined -> ""; - true -> io_lib:format("~s:", [M]) - end, - FArgs = [io_lib:format(", ~p", [A]) || A <- Args], - if ?is_multi_type(Type) -> - "[" ++ io_lib:format("~s~s(V~s)", [Mod, Fun, FArgs]) ++ - " || V <- Value]"; - true -> - "[" ++ io_lib:format("~s~s(Value~s)", [Mod, Fun, FArgs]) - ++ "]" - end; - undefined -> - "[Value]" - end, - Default = case get_dec_fun(Var, Type, Options, State) of - _ when ?is_multi_type(Type) -> "[]"; - undefined -> "<<>>"; - _MFA -> "undefined" - end, - io_lib:format( - "case Value of" - " ~s -> [];~n" - " Value -> ~s~n" - "end", - [Default, EncFun]). - -mk_encoded_options(#xdata_field{var = Var, type = Type, - options = Options}, State) -> - EncFun = case get_enc_fun(Var, Type, Options, State) of - {M, Fun, Args} -> - Mod = if M == undefined -> ""; - true -> io_lib:format("~s:", [M]) - end, - FArgs = [io_lib:format(", ~p", [A]) || A <- Args], - io_lib:format("~s~s(V~s)", [Mod, Fun, FArgs]); - undefined -> - "V" - end, - EncOpts = string:join( - [case L of - <<>> -> - io_lib:format("#xdata_option{value = ~p}", [V]); - _ -> - io_lib:format( - "#xdata_option{label = Translate(~p), value = ~p}", - [L, V]) - end || #xdata_option{label = L, value = V} <- Options], - ","), - if ?is_list_type(Type) -> - io_lib:format( - "if Options == default ->" - " [~s];" - "true ->" - " [#xdata_option{label = Translate(L), value = ~s}" - " || {L, V} <- Options]" - "end", - [EncOpts, EncFun]); - true -> - "[]" - end. - -mk_decoding_fun(#xdata_field{var = Var, type = Type, - options = Options}, State) -> - case get_dec_fun(Var, Type, Options, State) of - {M, Fun, Args} -> - Mod = if M == undefined -> ""; - true -> io_lib:format("~s:", [M]) - end, - FArgs = [io_lib:format(", ~p", [A]) || A <- Args], - io_lib:format("~s~s(Value~s)", [Mod, Fun, FArgs]); - undefined -> - "Value" - end. - -var_to_rec_field(Var, #state{prefix = [Prefix|T]} = State) -> - Size = size(Prefix), - case Var of - <<(Prefix):Size/binary, Rest/binary>> -> - binary_to_atom(Rest, utf8); - _ -> - var_to_rec_field(Var, State#state{prefix = T}) - end; -var_to_rec_field(Var, #state{prefix = []}) -> - Var. - -get_dec_fun(Var, Type, Options, State) -> - case lists:keyfind(Var, 1, State#state.dec_mfas) of - false when Type == 'list-multi'; Type == 'list-single' -> - if Options /= [] -> - Variants = [binary_to_atom(V, utf8) - || #xdata_option{value = V} <- Options], - {undefined, dec_enum, [Variants]}; - true -> - undefined - end; - false when Type == 'jid-multi'; Type == 'jid-single' -> - {undefined, dec_jid, []}; - false when Type == boolean -> - {undefined, dec_bool, []}; - false -> - undefined; - {Var, {M, F, A}} -> - {M, F, A}; - {Var, {dec_bool, []}} -> - {undefined, dec_bool, []}; - {Var, {not_empty, []}} -> - {undefined, not_empty, []}; - {Var, {dec_enum, [Variants]}} -> - {undefined, dec_enum, [Variants]}; - {Var, {dec_int, Args}} -> - {undefined, dec_int, Args}; - {Var, {dec_enum_int, Args}} -> - {undefined, dec_enum_int, Args}; - {Var, {dec_jid, []}} -> - {undefined, dec_jid, []} - end. - -get_enc_fun(Var, Type, Options, State) -> - case get_dec_fun(Var, Type, Options, State) of - {undefined, dec_enum, _} -> - {undefined, enc_enum, []}; - {undefined, dec_bool, _} -> - {undefined, enc_bool, []}; - {undefined, dec_int, _} -> - {undefined, enc_int, []}; - {undefined, dec_enum_int, _} -> - {undefined, enc_enum_int, []}; - {undefined, dec_jid, _} -> - {undefined, enc_jid, []}; - _ -> - case lists:keyfind(Var, 1, State#state.enc_mfas) of - false -> - undefined; - {Var, {M, F, A}} -> - {M, F, A}; - {Var, {enc_bool, []}} -> - {undefined, enc_bool, []}; - {Var, {dec_enum, _}} -> - {undefined, enc_enum, []}; - {Var, {enc_int, _}} -> - {undefined, enc_int, []}; - {Var, {dec_enum_int, _}} -> - {undefined, enc_enum_int, []}; - {Var, {enc_jid, _}} -> - {undefined, enc_jid, []} - end - end. - -mk_typespec(#xdata_field{type = Type, var = Var} = Field, State) -> - Spec0 = get_typespec(Field, State), - Spec1 = case is_complex_type(Spec0) of - true -> - io_lib:format("'~s'()", [var_to_rec_field(Var, State)]); - false -> - Spec0 - end, - if ?is_multi_type(Type) -> "[" ++ Spec1 ++ "]"; - true -> Spec1 - end. - -get_typespec(#xdata_field{var = Var, type = Type, options = Options}, State) -> - case lists:keyfind(Var, 1, State#state.specs) of - false -> - case get_dec_fun(Var, Type, Options, State) of - {undefined, dec_enum, Args} -> - enum_spec(Args); - {undefined, dec_bool, _} -> - "boolean()"; - {undefined, dec_jid, _} -> - "jid:jid()"; - {undefined, dec_int, Args} -> - int_spec(Args); - {undefined, dec_enum_int, [Variants|T]} -> - enum_spec([Variants]) ++ " | " ++ int_spec(T); - _ -> - "binary()" - end; - {Var, Spec} -> - Spec - end. - --spec is_complex_type(string()) -> boolean(). -is_complex_type(Spec) -> - string:chr(Spec, $|) /= 0. - -int_spec([]) -> - "integer()"; -int_spec([From, To]) -> - if From /= infinity, To /= infinity -> - io_lib:format("~p..~p", [From, To]); - From > 0 -> - "pos_integer()"; - From == 0 -> - "non_neg_integer()"; - true -> - "integer()" - end. - -enum_spec([Variants]) -> - string:join([atom_to_list(V) || V <- Variants], " | "). - -is_required(Var, State) -> - lists:member(Var, State#state.required) orelse - proplists:get_bool(Var, State#state.required). - -normalize(#xmlel{name = Name, attrs = Attrs, children = Els}) -> - #xmlel{name = Name, - attrs = [normalize(Attr) || Attr <- Attrs], - children = [normalize(El) || El <- Els]}; -normalize({Key, Data}) -> - {Key, normalize(Data)}; -normalize(Txt) when is_binary(Txt) -> - case re:split(Txt, "[\\s\\r\\n\\t]+", [trim, {return, list}]) of - [""|T] -> - list_to_binary(string:join(T, " ")); - T -> - list_to_binary(string:join(T, " ")) - end. diff --git a/src/xmpp.erl b/src/xmpp.erl deleted file mode 100644 index 2c08c2bcd..000000000 --- a/src/xmpp.erl +++ /dev/null @@ -1,827 +0,0 @@ -%%%------------------------------------------------------------------- -%%% @author Evgeny Khramtsov -%%% @copyright (C) 2015, Evgeny Khramtsov -%%% @doc -%%% -%%% @end -%%% Created : 9 Dec 2015 by Evgeny Khramtsov -%%%------------------------------------------------------------------- --module(xmpp). - -%% API --export([make_iq_result/1, make_iq_result/2, make_error/2, - decode/1, decode/3, encode/1, encode/2, - get_type/1, get_to/1, get_from/1, get_id/1, - get_lang/1, get_error/1, get_els/1, get_ns/1, - set_type/2, set_to/2, set_from/2, set_id/2, - set_lang/2, set_error/2, set_els/2, set_from_to/3, - format_error/1, is_stanza/1, set_subtag/2, get_subtag/2, - remove_subtag/2, has_subtag/2, decode_els/1, decode_els/3, - pp/1, get_name/1, get_text/1, mk_text/1, mk_text/2, - is_known_tag/1, is_known_tag/2, append_subtags/2]). - -%% XMPP errors --export([err_bad_request/0, err_bad_request/2, - err_conflict/0, err_conflict/2, - err_feature_not_implemented/0, err_feature_not_implemented/2, - err_forbidden/0, err_forbidden/2, - err_gone/0, err_gone/2, - err_internal_server_error/0, err_internal_server_error/2, - err_item_not_found/0, err_item_not_found/2, - err_jid_malformed/0, err_jid_malformed/2, - err_not_acceptable/0, err_not_acceptable/2, - err_not_allowed/0, err_not_allowed/2, - err_not_authorized/0, err_not_authorized/2, - err_payment_required/0, err_payment_required/2, - err_policy_violation/0, err_policy_violation/2, - err_recipient_unavailable/0, err_recipient_unavailable/2, - err_redirect/0, err_redirect/2, - err_registration_required/0, err_registration_required/2, - err_remote_server_not_found/0, err_remote_server_not_found/2, - err_remote_server_timeout/0, err_remote_server_timeout/2, - err_resource_constraint/0, err_resource_constraint/2, - err_service_unavailable/0, err_service_unavailable/2, - err_subscription_required/0, err_subscription_required/2, - err_undefined_condition/1, err_undefined_condition/3, - err_unexpected_request/0, err_unexpected_request/2]). - -%% XMPP stream errors --export([serr_bad_format/0, serr_bad_format/2, - serr_bad_namespace_prefix/0, serr_bad_namespace_prefix/2, - serr_conflict/0, serr_conflict/2, - serr_connection_timeout/0, serr_connection_timeout/2, - serr_host_gone/0, serr_host_gone/2, - serr_host_unknown/0, serr_host_unknown/2, - serr_improper_addressing/0, serr_improper_addressing/2, - serr_internal_server_error/0, serr_internal_server_error/2, - serr_invalid_from/0, serr_invalid_from/2, - serr_invalid_id/0, serr_invalid_id/2, - serr_invalid_namespace/0, serr_invalid_namespace/2, - serr_invalid_xml/0, serr_invalid_xml/2, - serr_not_authorized/0, serr_not_authorized/2, - serr_not_well_formed/0, serr_not_well_formed/2, - serr_policy_violation/0, serr_policy_violation/2, - serr_remote_connection_failed/0, serr_remote_connection_failed/2, - serr_reset/0, serr_reset/2, - serr_resource_constraint/0, serr_resource_constraint/2, - serr_restricted_xml/0, serr_restricted_xml/2, - serr_see_other_host/0, serr_see_other_host/2, - serr_system_shutdown/0, serr_system_shutdown/2, - serr_undefined_condition/0, serr_undefined_condition/2, - serr_unsupported_encoding/0, serr_unsupported_encoding/2, - serr_unsupported_stanza_type/0, serr_unsupported_stanza_type/2, - serr_unsupported_version/0, serr_unsupported_version/2]). - --include("xmpp.hrl"). - -%%%=================================================================== -%%% API -%%%=================================================================== --spec make_iq_result(iq()) -> iq(). -make_iq_result(IQ) -> - make_iq_result(IQ, undefined). - --spec make_iq_result(iq(), xmpp_element() | xmlel() | undefined) -> iq(). -make_iq_result(#iq{type = Type, from = From, to = To} = IQ, El) - when Type == get; Type == set -> - SubEls = if El == undefined -> []; - true -> [El] - end, - IQ#iq{type = result, to = From, from = To, sub_els = SubEls}. - --spec make_error(message(), stanza_error() | xmlel()) -> message(); - (presence(), stanza_error() | xmlel()) -> presence(); - (iq(), stanza_error() | xmlel()) -> iq(); - (xmlel(), stanza_error() | xmlel()) -> xmlel(). -make_error(#message{type = Type, from = From, to = To, sub_els = Els} = Msg, - Err) when Type /= error -> - Msg#message{type = error, from = To, to = From, sub_els = Els ++ [Err]}; -make_error(#presence{type = Type, from = From, to = To, sub_els = Els} = Pres, - Err) when Type /= error -> - Pres#presence{type = error, from = To, to = From, sub_els = Els ++ [Err]}; -make_error(#iq{type = Type, from = From, to = To, sub_els = Els} = IQ, - Err) when Type /= result, Type /= error -> - IQ#iq{type = error, from = To, to = From, sub_els = Els ++ [Err]}; -make_error(#xmlel{attrs = Attrs, children = Els} = El, Err) -> - To = fxml:get_attr(<<"to">>, Attrs), - From = fxml:get_attr(<<"from">>, Attrs), - Attrs1 = case To of - {value, T} -> - lists:keystore(<<"from">>, 1, Attrs, {<<"from">>, T}); - _ -> - Attrs - end, - Attrs2 = case From of - {value, F} -> - lists:keystore(<<"to">>, 1, Attrs1, {<<"to">>, F}); - _ -> - Attrs - end, - Attrs3 = lists:keystore(<<"type">>, 1, Attrs2, {<<"type">>, <<"error">>}), - El#xmlel{attrs = Attrs3, children = Els ++ [encode(Err, ?NS_CLIENT)]}. - --spec get_id(iq() | message() | presence() | xmlel()) -> binary(). -get_id(#iq{id = ID}) -> ID; -get_id(#message{id = ID}) -> ID; -get_id(#presence{id = ID}) -> ID; -get_id(#xmlel{attrs = Attrs}) -> fxml:get_attr_s(<<"id">>, Attrs). - --spec get_type(iq()) -> iq_type(); - (message()) -> message_type(); - (presence()) -> presence_type(); - (xmlel()) -> binary(). -get_type(#iq{type = T}) -> T; -get_type(#message{type = T}) -> T; -get_type(#presence{type = T}) -> T; -get_type(#xmlel{attrs = Attrs}) -> fxml:get_attr_s(<<"type">>, Attrs). - --spec get_lang(iq() | message() | presence() | xmlel()) -> binary(). -get_lang(#iq{lang = L}) -> L; -get_lang(#message{lang = L}) -> L; -get_lang(#presence{lang = L}) -> L; -get_lang(#xmlel{attrs = Attrs}) -> fxml:get_attr_s(<<"xml:lang">>, Attrs). - --spec get_from(iq() | message() | presence()) -> undefined | jid:jid(). -get_from(#iq{from = J}) -> J; -get_from(#message{from = J}) -> J; -get_from(#presence{from = J}) -> J. - --spec get_to(iq() | message() | presence()) -> undefined | jid:jid(). -get_to(#iq{to = J}) -> J; -get_to(#message{to = J}) -> J; -get_to(#presence{to = J}) -> J. - --spec get_error(iq() | message() | presence()) -> undefined | stanza_error(). -get_error(Stanza) -> - case get_subtag(Stanza, #stanza_error{}) of - false -> undefined; - Error -> Error - end. - --spec get_els(iq() | message() | presence()) -> [xmpp_element() | xmlel()]; - (xmlel()) -> [xmlel()]. -get_els(#iq{sub_els = Els}) -> Els; -get_els(#message{sub_els = Els}) -> Els; -get_els(#presence{sub_els = Els}) -> Els; -get_els(#xmlel{children = Els}) -> [El || El = #xmlel{} <- Els]. - --spec set_id(iq(), binary()) -> iq(); - (message(), binary()) -> message(); - (presence(), binary()) -> presence(). -set_id(#iq{} = IQ, I) -> IQ#iq{id = I}; -set_id(#message{} = Msg, I) -> Msg#message{id = I}; -set_id(#presence{} = Pres, I) -> Pres#presence{id = I}. - --spec set_type(iq(), iq_type()) -> iq(); - (message(), message_type()) -> message(); - (presence(), presence_type()) -> presence(). -set_type(#iq{} = IQ, T) -> IQ#iq{type = T}; -set_type(#message{} = Msg, T) -> Msg#message{type = T}; -set_type(#presence{} = Pres, T) -> Pres#presence{type = T}. - --spec set_lang(iq(), binary()) -> iq(); - (message(), binary()) -> message(); - (presence(), binary()) -> presence(). -set_lang(#iq{} = IQ, L) -> IQ#iq{lang = L}; -set_lang(#message{} = Msg, L) -> Msg#message{lang = L}; -set_lang(#presence{} = Pres, L) -> Pres#presence{lang = L}. - --spec set_from(iq(), jid:jid()) -> iq(); - (message(), jid:jid()) -> message(); - (presence(), jid:jid()) -> presence(). -set_from(#iq{} = IQ, J) -> IQ#iq{from = J}; -set_from(#message{} = Msg, J) -> Msg#message{from = J}; -set_from(#presence{} = Pres, J) -> Pres#presence{from = J}. - --spec set_to(iq(), jid:jid()) -> iq(); - (message(), jid:jid()) -> message(); - (presence(), jid:jid()) -> presence(). -set_to(#iq{} = IQ, J) -> IQ#iq{to = J}; -set_to(#message{} = Msg, J) -> Msg#message{to = J}; -set_to(#presence{} = Pres, J) -> Pres#presence{to = J}. - --spec set_from_to(iq(), undefined | jid:jid(), undefined | jid:jid()) -> iq(); - (message(), undefined | jid:jid(), undefined | jid:jid()) -> message(); - (presence(), undefined | jid:jid(), undefined | jid:jid()) -> presence(). -set_from_to(#iq{} = IQ, F, T) -> IQ#iq{from = F, to = T}; -set_from_to(#message{} = Msg, F, T) -> Msg#message{from = F, to = T}; -set_from_to(#presence{} = Pres, F, T) -> Pres#presence{from = F, to = T}. - --spec set_error(iq(), stanza_error()) -> iq(); - (message(), stanza_error()) -> message(); - (presence(), stanza_error()) -> presence(). -set_error(Stanza, E) -> set_subtag(Stanza, E). - --spec set_els(iq(), [xmpp_element() | xmlel()]) -> iq(); - (message(), [xmpp_element() | xmlel()]) -> message(); - (presence(), [xmpp_element() | xmlel()]) -> presence(). -set_els(#iq{} = IQ, Els) -> IQ#iq{sub_els = Els}; -set_els(#message{} = Msg, Els) -> Msg#message{sub_els = Els}; -set_els(#presence{} = Pres, Els) -> Pres#presence{sub_els = Els}. - --spec get_ns(xmpp_element() | xmlel()) -> binary(). -get_ns(#xmlel{attrs = Attrs}) -> - fxml:get_attr_s(<<"xmlns">>, Attrs); -get_ns(Pkt) -> - xmpp_codec:get_ns(Pkt). - --spec get_name(xmpp_element() | xmlel()) -> binary(). -get_name(#xmlel{name = Name}) -> - Name; -get_name(Pkt) -> - xmpp_codec:get_name(Pkt). - --spec decode(xmlel() | xmpp_element()) -> {ok, xmpp_element()} | {error, any()}. -decode(El) -> - decode(El, ?NS_CLIENT, []). - --spec decode(xmlel() | xmpp_element(), binary(), [proplists:property()]) -> - {ok, xmpp_element()} | {error, any()}. -decode(#xmlel{} = El, TopXMLNS, Opts) -> - xmpp_codec:decode(El, TopXMLNS, Opts); -decode(Pkt, _, _) -> - Pkt. - --spec decode_els(iq()) -> iq(); - (message()) -> message(); - (presence()) -> presence(). -decode_els(Stanza) -> - decode_els(Stanza, ?NS_CLIENT, fun is_known_tag/1). - --type match_fun() :: fun((xmlel()) -> boolean()). --spec decode_els(iq(), binary(), match_fun()) -> iq(); - (message(), binary(), match_fun()) -> message(); - (presence(), binary(), match_fun()) -> presence(). -decode_els(Stanza, TopXMLNS, MatchFun) -> - Els = lists:map( - fun(#xmlel{} = El) -> - case MatchFun(El) of - true -> decode(El, TopXMLNS, []); - false -> El - end; - (Pkt) -> - Pkt - end, get_els(Stanza)), - set_els(Stanza, Els). - --spec encode(xmpp_element() | xmlel()) -> xmlel(). -encode(Pkt) -> - encode(Pkt, <<>>). - --spec encode(xmpp_element() | xmlel(), binary()) -> xmlel(). -encode(Pkt, TopXMLNS) -> - xmpp_codec:encode(Pkt, TopXMLNS). - --spec is_known_tag(xmlel()) -> boolean(). -is_known_tag(El) -> - is_known_tag(El, ?NS_CLIENT). - --spec is_known_tag(xmlel(), binary()) -> boolean(). -is_known_tag(El, TopXMLNS) -> - xmpp_codec:is_known_tag(El, TopXMLNS). - -format_error(Reason) -> - xmpp_codec:format_error(Reason). - --spec is_stanza(any()) -> boolean(). -is_stanza(#message{}) -> true; -is_stanza(#iq{}) -> true; -is_stanza(#presence{}) -> true; -is_stanza(#xmlel{name = Name}) -> - (Name == <<"iq">>) or (Name == <<"message">>) or (Name == <<"presence">>); -is_stanza(_) -> false. - --spec set_subtag(iq(), xmpp_element()) -> iq(); - (message(), xmpp_element()) -> message(); - (presence(), xmpp_element()) -> presence(). -set_subtag(Stanza, Tag) -> - TagName = xmpp_codec:get_name(Tag), - XMLNS = xmpp_codec:get_ns(Tag), - Els = get_els(Stanza), - NewEls = set_subtag(Els, Tag, TagName, XMLNS), - set_els(Stanza, NewEls). - -set_subtag([El|Els], Tag, TagName, XMLNS) -> - case match_tag(El, TagName, XMLNS) of - true -> - [Tag|Els]; - false -> - [El|set_subtag(Els, Tag, TagName, XMLNS)] - end; -set_subtag([], Tag, _, _) -> - [Tag]. - --spec get_subtag(stanza(), xmpp_element()) -> xmpp_element() | false. -get_subtag(Stanza, Tag) -> - Els = get_els(Stanza), - TagName = xmpp_codec:get_name(Tag), - XMLNS = xmpp_codec:get_ns(Tag), - get_subtag(Els, TagName, XMLNS). - -get_subtag([El|Els], TagName, XMLNS) -> - case match_tag(El, TagName, XMLNS) of - true -> - try - decode(El) - catch _:{xmpp_codec, _Why} -> - get_subtag(Els, TagName, XMLNS) - end; - false -> - get_subtag(Els, TagName, XMLNS) - end; -get_subtag([], _, _) -> - false. - --spec remove_subtag(iq(), xmpp_element()) -> iq(); - (message(), xmpp_element()) -> message(); - (presence(), xmpp_element()) -> presence(). -remove_subtag(Stanza, Tag) -> - Els = get_els(Stanza), - TagName = xmpp_codec:get_name(Tag), - XMLNS = xmpp_codec:get_ns(Tag), - NewEls = remove_subtag(Els, TagName, XMLNS), - set_els(Stanza, NewEls). - -remove_subtag([El|Els], TagName, XMLNS) -> - case match_tag(El, TagName, XMLNS) of - true -> - remove_subtag(Els, TagName, XMLNS); - false -> - [El|remove_subtag(Els, TagName, XMLNS)] - end; -remove_subtag([], _, _) -> - []. - --spec has_subtag(stanza(), xmpp_element()) -> boolean(). -has_subtag(Stanza, Tag) -> - Els = get_els(Stanza), - TagName = xmpp_codec:get_name(Tag), - XMLNS = xmpp_codec:get_ns(Tag), - has_subtag(Els, TagName, XMLNS). - -has_subtag([El|Els], TagName, XMLNS) -> - case match_tag(El, TagName, XMLNS) of - true -> - true; - false -> - has_subtag(Els, TagName, XMLNS) - end; -has_subtag([], _, _) -> - false. - --spec append_subtags(stanza(), [xmpp_element() | xmlel()]) -> stanza(). -append_subtags(Stanza, Tags) -> - Els = get_els(Stanza), - set_els(Stanza, Els ++ Tags). - --spec get_text([text()]) -> binary(). -get_text([]) -> <<"">>; -get_text([#text{data = Data}|_]) -> Data. - --spec mk_text(binary()) -> [text()]. -mk_text(Text) -> - mk_text(Text, <<"">>). - --spec mk_text(binary(), binary()) -> [text()]. -mk_text(<<"">>, _) -> - []; -mk_text(Text, Lang) -> - [#text{lang = Lang, - data = translate:translate(Lang, Text)}]. - --spec pp(any()) -> iodata(). -pp(Term) -> - xmpp_codec:pp(Term). - -%%%=================================================================== -%%% Functions to construct general XMPP errors -%%%=================================================================== --spec err_bad_request() -> stanza_error(). -err_bad_request() -> - err(modify, 'bad-request', 400). - --spec err_bad_request(binary(), binary()) -> stanza_error(). -err_bad_request(Text, Lang) -> - err(modify, 'bad-request', 400, Text, Lang). - --spec err_conflict() -> stanza_error(). -err_conflict() -> - err(cancel, 'conflict', 409). - --spec err_conflict(binary(), binary()) -> stanza_error(). -err_conflict(Text, Lang) -> - err(cancel, 'conflict', 409, Text, Lang). - --spec err_feature_not_implemented() -> stanza_error(). -err_feature_not_implemented() -> - err(cancel, 'feature-not-implemented', 501). - --spec err_feature_not_implemented(binary(), binary()) -> stanza_error(). -err_feature_not_implemented(Text, Lang) -> - err(cancel, 'feature-not-implemented', 501, Text, Lang). - --spec err_forbidden() -> stanza_error(). -err_forbidden() -> - err(auth, 'forbidden', 403). - --spec err_forbidden(binary(), binary()) -> stanza_error(). -err_forbidden(Text, Lang) -> - err(auth, 'forbidden', 403, Text, Lang). - -%% RFC 6120 says error type SHOULD be "cancel". -%% RFC 3920 and XEP-0082 says it SHOULD be "modify". --spec err_gone() -> stanza_error(). -err_gone() -> - err(modify, 'gone', 302). - --spec err_gone(binary(), binary()) -> stanza_error(). -err_gone(Text, Lang) -> - err(modify, 'gone', 302, Text, Lang). - -%% RFC 6120 sasy error type SHOULD be "cancel". -%% RFC 3920 and XEP-0082 says it SHOULD be "wait". --spec err_internal_server_error() -> stanza_error(). -err_internal_server_error() -> - err(wait, 'internal-server-error', 500). - --spec err_internal_server_error(binary(), binary()) -> stanza_error(). -err_internal_server_error(Text, Lang) -> - err(wait, 'internal-server-error', 500, Text, Lang). - --spec err_item_not_found() -> stanza_error(). -err_item_not_found() -> - err(cancel, 'item-not-found', 404). - --spec err_item_not_found(binary(), binary()) -> stanza_error(). -err_item_not_found(Text, Lang) -> - err(cancel, 'item-not-found', 404, Text, Lang). - --spec err_jid_malformed() -> stanza_error(). -err_jid_malformed() -> - err(modify, 'jid-malformed', 400). - --spec err_jid_malformed(binary(), binary()) -> stanza_error(). -err_jid_malformed(Text, Lang) -> - err(modify, 'jid-malformed', 400, Text, Lang). - --spec err_not_acceptable() -> stanza_error(). -err_not_acceptable() -> - err(modify, 'not-acceptable', 406). - --spec err_not_acceptable(binary(), binary()) -> stanza_error(). -err_not_acceptable(Text, Lang) -> - err(modify, 'not-acceptable', 406, Text, Lang). - --spec err_not_allowed() -> stanza_error(). -err_not_allowed() -> - err(cancel, 'not-allowed', 405). - --spec err_not_allowed(binary(), binary()) -> stanza_error(). -err_not_allowed(Text, Lang) -> - err(cancel, 'not-allowed', 405, Text, Lang). - --spec err_not_authorized() -> stanza_error(). -err_not_authorized() -> - err(auth, 'not-authorized', 401). - --spec err_not_authorized(binary(), binary()) -> stanza_error(). -err_not_authorized(Text, Lang) -> - err(auth, 'not-authorized', 401, Text, Lang). - --spec err_payment_required() -> stanza_error(). -err_payment_required() -> - err(auth, 'not-authorized', 402). - --spec err_payment_required(binary(), binary()) -> stanza_error(). -err_payment_required(Text, Lang) -> - err(auth, 'not-authorized', 402, Text, Lang). - -%% is defined in neither RFC 3920 nor XEP-0086. -%% We choose '403' error code (as in ). --spec err_policy_violation() -> stanza_error(). -err_policy_violation() -> - err(modify, 'policy-violation', 403). - --spec err_policy_violation(binary(), binary()) -> stanza_error(). -err_policy_violation(Text, Lang) -> - err(modify, 'policy-violation', 403, Text, Lang). - --spec err_recipient_unavailable() -> stanza_error(). -err_recipient_unavailable() -> - err(wait, 'recipient-unavailable', 404). - --spec err_recipient_unavailable(binary(), binary()) -> stanza_error(). -err_recipient_unavailable(Text, Lang) -> - err(wait, 'recipient-unavailable', 404, Text, Lang). - --spec err_redirect() -> stanza_error(). -err_redirect() -> - err(modify, 'redirect', 302). - --spec err_redirect(binary(), binary()) -> stanza_error(). -err_redirect(Text, Lang) -> - err(modify, 'redirect', 302, Text, Lang). - --spec err_registration_required() -> stanza_error(). -err_registration_required() -> - err(auth, 'registration-required', 407). - --spec err_registration_required(binary(), binary()) -> stanza_error(). -err_registration_required(Text, Lang) -> - err(auth, 'registration-required', 407, Text, Lang). - --spec err_remote_server_not_found() -> stanza_error(). -err_remote_server_not_found() -> - err(cancel, 'remote-server-not-found', 404). - --spec err_remote_server_not_found(binary(), binary()) -> stanza_error(). -err_remote_server_not_found(Text, Lang) -> - err(cancel, 'remote-server-not-found', 404, Text, Lang). - --spec err_remote_server_timeout() -> stanza_error(). -err_remote_server_timeout() -> - err(wait, 'remote-server-timeout', 504). - --spec err_remote_server_timeout(binary(), binary()) -> stanza_error(). -err_remote_server_timeout(Text, Lang) -> - err(wait, 'remote-server-timeout', 504, Text, Lang). - --spec err_resource_constraint() -> stanza_error(). -err_resource_constraint() -> - err(wait, 'resource-constraint', 500). - --spec err_resource_constraint(binary(), binary()) -> stanza_error(). -err_resource_constraint(Text, Lang) -> - err(wait, 'resource-constraint', 500, Text, Lang). - --spec err_service_unavailable() -> stanza_error(). -err_service_unavailable() -> - err(cancel, 'service-unavailable', 503). - --spec err_service_unavailable(binary(), binary()) -> stanza_error(). -err_service_unavailable(Text, Lang) -> - err(cancel, 'service-unavailable', 503, Text, Lang). - --spec err_subscription_required() -> stanza_error(). -err_subscription_required() -> - err(auth, 'subscription-required', 407). - --spec err_subscription_required(binary(), binary()) -> stanza_error(). -err_subscription_required(Text, Lang) -> - err(auth, 'subscription-required', 407, Text, Lang). - -%% No error type is defined for . -%% Let user provide the type. --spec err_undefined_condition('auth' | 'cancel' | 'continue' | - 'modify' | 'wait') -> stanza_error(). -err_undefined_condition(Type) -> - err(Type, 'undefined-condition', 500). - --spec err_undefined_condition('auth' | 'cancel' | 'continue' | 'modify' | 'wait', - binary(), binary()) -> stanza_error(). -err_undefined_condition(Type, Text, Lang) -> - err(Type, 'undefined-condition', 500, Text, Lang). - -%% RFC 6120 says error type SHOULD be "wait" or "modify". -%% RFC 3920 and XEP-0082 says it SHOULD be "wait". --spec err_unexpected_request() -> stanza_error(). -err_unexpected_request() -> - err(wait, 'unexpected-request', 400). - --spec err_unexpected_request(binary(), binary()) -> stanza_error(). -err_unexpected_request(Text, Lang) -> - err(wait, 'unexpected-request', 400, Text, Lang). - -%%%=================================================================== -%%% Functions to construct stream errors -%%%=================================================================== --spec serr_bad_format() -> stream_error(). -serr_bad_format() -> - serr('bad-format'). - --spec serr_bad_format(binary(), binary()) -> stream_error(). -serr_bad_format(Text, Lang) -> - serr('bad-format', Text, Lang). - --spec serr_bad_namespace_prefix() -> stream_error(). -serr_bad_namespace_prefix() -> - serr('bad-namespace-prefix'). - --spec serr_bad_namespace_prefix(binary(), binary()) -> stream_error(). -serr_bad_namespace_prefix(Text, Lang) -> - serr('bad-namespace-prefix', Text, Lang). - --spec serr_conflict() -> stream_error(). -serr_conflict() -> - serr('conflict'). - --spec serr_conflict(binary(), binary()) -> stream_error(). -serr_conflict(Text, Lang) -> - serr('conflict', Text, Lang). - --spec serr_connection_timeout() -> stream_error(). -serr_connection_timeout() -> - serr('connection-timeout'). - --spec serr_connection_timeout(binary(), binary()) -> stream_error(). -serr_connection_timeout(Text, Lang) -> - serr('connection-timeout', Text, Lang). - --spec serr_host_gone() -> stream_error(). -serr_host_gone() -> - serr('host-gone'). - --spec serr_host_gone(binary(), binary()) -> stream_error(). -serr_host_gone(Text, Lang) -> - serr('host-gone', Text, Lang). - --spec serr_host_unknown() -> stream_error(). -serr_host_unknown() -> - serr('host-unknown'). - --spec serr_host_unknown(binary(), binary()) -> stream_error(). -serr_host_unknown(Text, Lang) -> - serr('host-unknown', Text, Lang). - --spec serr_improper_addressing() -> stream_error(). -serr_improper_addressing() -> - serr('improper-addressing'). - --spec serr_improper_addressing(binary(), binary()) -> stream_error(). -serr_improper_addressing(Text, Lang) -> - serr('improper-addressing', Text, Lang). - --spec serr_internal_server_error() -> stream_error(). -serr_internal_server_error() -> - serr('internal-server-error'). - --spec serr_internal_server_error(binary(), binary()) -> stream_error(). -serr_internal_server_error(Text, Lang) -> - serr('internal-server-error', Text, Lang). - --spec serr_invalid_from() -> stream_error(). -serr_invalid_from() -> - serr('invalid-from'). - --spec serr_invalid_from(binary(), binary()) -> stream_error(). -serr_invalid_from(Text, Lang) -> - serr('invalid-from', Text, Lang). - --spec serr_invalid_id() -> stream_error(). -serr_invalid_id() -> - serr('invalid-id'). - --spec serr_invalid_id(binary(), binary()) -> stream_error(). -serr_invalid_id(Text, Lang) -> - serr('invalid-id', Text, Lang). - --spec serr_invalid_namespace() -> stream_error(). -serr_invalid_namespace() -> - serr('invalid-namespace'). - --spec serr_invalid_namespace(binary(), binary()) -> stream_error(). -serr_invalid_namespace(Text, Lang) -> - serr('invalid-namespace', Text, Lang). - --spec serr_invalid_xml() -> stream_error(). -serr_invalid_xml() -> - serr('invalid-xml'). - --spec serr_invalid_xml(binary(), binary()) -> stream_error(). -serr_invalid_xml(Text, Lang) -> - serr('invalid-xml', Text, Lang). - --spec serr_not_authorized() -> stream_error(). -serr_not_authorized() -> - serr('not-authorized'). - --spec serr_not_authorized(binary(), binary()) -> stream_error(). -serr_not_authorized(Text, Lang) -> - serr('not-authorized', Text, Lang). - --spec serr_not_well_formed() -> stream_error(). -serr_not_well_formed() -> - serr('not-well-formed'). - --spec serr_not_well_formed(binary(), binary()) -> stream_error(). -serr_not_well_formed(Text, Lang) -> - serr('not-well-formed', Text, Lang). - --spec serr_policy_violation() -> stream_error(). -serr_policy_violation() -> - serr('policy-violation'). - --spec serr_policy_violation(binary(), binary()) -> stream_error(). -serr_policy_violation(Text, Lang) -> - serr('policy-violation', Text, Lang). - --spec serr_remote_connection_failed() -> stream_error(). -serr_remote_connection_failed() -> - serr('remote-connection-failed'). - --spec serr_remote_connection_failed(binary(), binary()) -> stream_error(). -serr_remote_connection_failed(Text, Lang) -> - serr('remote-connection-failed', Text, Lang). - --spec serr_reset() -> stream_error(). -serr_reset() -> - serr('reset'). - --spec serr_reset(binary(), binary()) -> stream_error(). -serr_reset(Text, Lang) -> - serr('reset', Text, Lang). - --spec serr_resource_constraint() -> stream_error(). -serr_resource_constraint() -> - serr('resource-constraint'). - --spec serr_resource_constraint(binary(), binary()) -> stream_error(). -serr_resource_constraint(Text, Lang) -> - serr('resource-constraint', Text, Lang). - --spec serr_restricted_xml() -> stream_error(). -serr_restricted_xml() -> - serr('restricted-xml'). - --spec serr_restricted_xml(binary(), binary()) -> stream_error(). -serr_restricted_xml(Text, Lang) -> - serr('restricted-xml', Text, Lang). - --spec serr_see_other_host() -> stream_error(). -serr_see_other_host() -> - serr('see-other-host'). - --spec serr_see_other_host(binary(), binary()) -> stream_error(). -serr_see_other_host(Text, Lang) -> - serr('see-other-host', Text, Lang). - --spec serr_system_shutdown() -> stream_error(). -serr_system_shutdown() -> - serr('system-shutdown'). - --spec serr_system_shutdown(binary(), binary()) -> stream_error(). -serr_system_shutdown(Text, Lang) -> - serr('system-shutdown', Text, Lang). - --spec serr_undefined_condition() -> stream_error(). -serr_undefined_condition() -> - serr('undefined-condition'). - --spec serr_undefined_condition(binary(), binary()) -> stream_error(). -serr_undefined_condition(Text, Lang) -> - serr('undefined-condition', Text, Lang). - --spec serr_unsupported_encoding() -> stream_error(). -serr_unsupported_encoding() -> - serr('unsupported-encoding'). - --spec serr_unsupported_encoding(binary(), binary()) -> stream_error(). -serr_unsupported_encoding(Text, Lang) -> - serr('unsupported-encoding', Text, Lang). - --spec serr_unsupported_stanza_type() -> stream_error(). -serr_unsupported_stanza_type() -> - serr('unsupported-stanza-type'). - --spec serr_unsupported_stanza_type(binary(), binary()) -> stream_error(). -serr_unsupported_stanza_type(Text, Lang) -> - serr('unsupported-stanza-type', Text, Lang). - --spec serr_unsupported_version() -> stream_error(). -serr_unsupported_version() -> - serr('unsupported-version'). - --spec serr_unsupported_version(binary(), binary()) -> stream_error(). -serr_unsupported_version(Text, Lang) -> - serr('unsupported-version', Text, Lang). - -%%%=================================================================== -%%% Internal functions -%%%=================================================================== --spec err('auth' | 'cancel' | 'continue' | 'modify' | 'wait', - atom() | gone() | redirect(), non_neg_integer()) -> stanza_error(). -err(Type, Reason, Code) -> - #stanza_error{type = Type, reason = Reason, code = Code}. - --spec err('auth' | 'cancel' | 'continue' | 'modify' | 'wait', - atom() | gone() | redirect(), non_neg_integer(), - binary(), binary()) -> stanza_error(). -err(Type, Reason, Code, Text, Lang) -> - #stanza_error{type = Type, reason = Reason, code = Code, - text = #text{lang = Lang, - data = translate:translate(Lang, Text)}}. - --spec serr(atom() | 'see-other-host'()) -> stream_error(). -serr(Reason) -> - #stream_error{reason = Reason}. - --spec serr(atom() | 'see-other-host'(), binary(), - binary()) -> stream_error(). -serr(Reason, Text, Lang) -> - #stream_error{reason = Reason, - text = #text{lang = Lang, - data = translate:translate(Lang, Text)}}. - --spec match_tag(xmlel() | xmpp_element(), binary(), binary()) -> boolean(). -match_tag(El, TagName, XMLNS) -> - get_name(El) == TagName andalso get_ns(El) == XMLNS. diff --git a/src/xmpp_codec.erl b/src/xmpp_codec.erl deleted file mode 100644 index 6089f79fc..000000000 --- a/src/xmpp_codec.erl +++ /dev/null @@ -1,34647 +0,0 @@ -%% Created automatically by XML generator (fxml_gen.erl) -%% Source: xmpp_codec.spec - --module(xmpp_codec). - --compile({nowarn_unused_function, - [{dec_int, 3}, {dec_int, 1}, {dec_enum, 2}, - {enc_int, 1}, {get_attr, 2}, {enc_enum, 1}, - {choose_top_xmlns, 3}, {enc_xmlns_attrs, 2}]}). - --export([pp/1, format_error/1, decode/1, decode/2, - decode/3, is_known_tag/2, encode/1, encode/2, - get_name/1, get_ns/1]). - -decode(_el) -> decode(_el, <<>>, []). - -decode(_el, Opts) -> decode(_el, <<>>, Opts). - -decode({xmlel, _name, _attrs, _} = _el, TopXMLNS, - Opts) -> - IgnoreEls = proplists:get_bool(ignore_els, Opts), - case {_name, get_attr(<<"xmlns">>, _attrs), TopXMLNS} of - {<<"query">>, <<"urn:xmpp:delegation:1">>, _} -> - decode_delegation_query(<<"urn:xmpp:delegation:1">>, - IgnoreEls, _el); - {<<"query">>, <<>>, <<"urn:xmpp:delegation:1">>} -> - decode_delegation_query(<<"urn:xmpp:delegation:1">>, - IgnoreEls, _el); - {<<"delegate">>, <<"urn:xmpp:delegation:1">>, _} -> - decode_delegate(<<"urn:xmpp:delegation:1">>, IgnoreEls, - _el); - {<<"delegate">>, <<>>, <<"urn:xmpp:delegation:1">>} -> - decode_delegate(<<"urn:xmpp:delegation:1">>, IgnoreEls, - _el); - {<<"delegation">>, <<"urn:xmpp:delegation:1">>, _} -> - decode_delegation(<<"urn:xmpp:delegation:1">>, - IgnoreEls, _el); - {<<"delegation">>, <<>>, <<"urn:xmpp:delegation:1">>} -> - decode_delegation(<<"urn:xmpp:delegation:1">>, - IgnoreEls, _el); - {<<"delegated">>, <<"urn:xmpp:delegation:1">>, _} -> - decode_delegated(<<"urn:xmpp:delegation:1">>, IgnoreEls, - _el); - {<<"delegated">>, <<>>, <<"urn:xmpp:delegation:1">>} -> - decode_delegated(<<"urn:xmpp:delegation:1">>, IgnoreEls, - _el); - {<<"attribute">>, <<"urn:xmpp:delegation:1">>, _} -> - decode_delegated_attribute(<<"urn:xmpp:delegation:1">>, - IgnoreEls, _el); - {<<"attribute">>, <<>>, <<"urn:xmpp:delegation:1">>} -> - decode_delegated_attribute(<<"urn:xmpp:delegation:1">>, - IgnoreEls, _el); - {<<"privilege">>, <<"urn:xmpp:privilege:1">>, _} -> - decode_privilege(<<"urn:xmpp:privilege:1">>, IgnoreEls, - _el); - {<<"privilege">>, <<>>, <<"urn:xmpp:privilege:1">>} -> - decode_privilege(<<"urn:xmpp:privilege:1">>, IgnoreEls, - _el); - {<<"perm">>, <<"urn:xmpp:privilege:1">>, _} -> - decode_privilege_perm(<<"urn:xmpp:privilege:1">>, - IgnoreEls, _el); - {<<"perm">>, <<>>, <<"urn:xmpp:privilege:1">>} -> - decode_privilege_perm(<<"urn:xmpp:privilege:1">>, - IgnoreEls, _el); - {<<"thumbnail">>, <<"urn:xmpp:thumbs:1">>, _} -> - decode_thumbnail(<<"urn:xmpp:thumbs:1">>, IgnoreEls, - _el); - {<<"thumbnail">>, <<>>, <<"urn:xmpp:thumbs:1">>} -> - decode_thumbnail(<<"urn:xmpp:thumbs:1">>, IgnoreEls, - _el); - {<<"slot">>, <<"urn:xmpp:http:upload">>, _} -> - decode_upload_slot(<<"urn:xmpp:http:upload">>, - IgnoreEls, _el); - {<<"slot">>, <<>>, <<"urn:xmpp:http:upload">>} -> - decode_upload_slot(<<"urn:xmpp:http:upload">>, - IgnoreEls, _el); - {<<"slot">>, <<"eu:siacs:conversations:http:upload">>, - _} -> - decode_upload_slot(<<"eu:siacs:conversations:http:upload">>, - IgnoreEls, _el); - {<<"slot">>, <<>>, - <<"eu:siacs:conversations:http:upload">>} -> - decode_upload_slot(<<"eu:siacs:conversations:http:upload">>, - IgnoreEls, _el); - {<<"put">>, <<"urn:xmpp:http:upload">>, _} -> - decode_upload_put(<<"urn:xmpp:http:upload">>, IgnoreEls, - _el); - {<<"put">>, <<>>, <<"urn:xmpp:http:upload">>} -> - decode_upload_put(<<"urn:xmpp:http:upload">>, IgnoreEls, - _el); - {<<"put">>, <<"eu:siacs:conversations:http:upload">>, - _} -> - decode_upload_put(<<"eu:siacs:conversations:http:upload">>, - IgnoreEls, _el); - {<<"put">>, <<>>, - <<"eu:siacs:conversations:http:upload">>} -> - decode_upload_put(<<"eu:siacs:conversations:http:upload">>, - IgnoreEls, _el); - {<<"get">>, <<"urn:xmpp:http:upload">>, _} -> - decode_upload_get(<<"urn:xmpp:http:upload">>, IgnoreEls, - _el); - {<<"get">>, <<>>, <<"urn:xmpp:http:upload">>} -> - decode_upload_get(<<"urn:xmpp:http:upload">>, IgnoreEls, - _el); - {<<"get">>, <<"eu:siacs:conversations:http:upload">>, - _} -> - decode_upload_get(<<"eu:siacs:conversations:http:upload">>, - IgnoreEls, _el); - {<<"get">>, <<>>, - <<"eu:siacs:conversations:http:upload">>} -> - decode_upload_get(<<"eu:siacs:conversations:http:upload">>, - IgnoreEls, _el); - {<<"request">>, <<"urn:xmpp:http:upload">>, _} -> - decode_upload_request(<<"urn:xmpp:http:upload">>, - IgnoreEls, _el); - {<<"request">>, <<>>, <<"urn:xmpp:http:upload">>} -> - decode_upload_request(<<"urn:xmpp:http:upload">>, - IgnoreEls, _el); - {<<"request">>, - <<"eu:siacs:conversations:http:upload">>, _} -> - decode_upload_request(<<"eu:siacs:conversations:http:upload">>, - IgnoreEls, _el); - {<<"request">>, <<>>, - <<"eu:siacs:conversations:http:upload">>} -> - decode_upload_request(<<"eu:siacs:conversations:http:upload">>, - IgnoreEls, _el); - {<<"content-type">>, <<"urn:xmpp:http:upload">>, _} -> - decode_upload_content_type(<<"urn:xmpp:http:upload">>, - IgnoreEls, _el); - {<<"content-type">>, <<>>, - <<"urn:xmpp:http:upload">>} -> - decode_upload_content_type(<<"urn:xmpp:http:upload">>, - IgnoreEls, _el); - {<<"content-type">>, - <<"eu:siacs:conversations:http:upload">>, _} -> - decode_upload_content_type(<<"eu:siacs:conversations:http:upload">>, - IgnoreEls, _el); - {<<"content-type">>, <<>>, - <<"eu:siacs:conversations:http:upload">>} -> - decode_upload_content_type(<<"eu:siacs:conversations:http:upload">>, - IgnoreEls, _el); - {<<"size">>, <<"urn:xmpp:http:upload">>, _} -> - decode_upload_size(<<"urn:xmpp:http:upload">>, - IgnoreEls, _el); - {<<"size">>, <<>>, <<"urn:xmpp:http:upload">>} -> - decode_upload_size(<<"urn:xmpp:http:upload">>, - IgnoreEls, _el); - {<<"size">>, <<"eu:siacs:conversations:http:upload">>, - _} -> - decode_upload_size(<<"eu:siacs:conversations:http:upload">>, - IgnoreEls, _el); - {<<"size">>, <<>>, - <<"eu:siacs:conversations:http:upload">>} -> - decode_upload_size(<<"eu:siacs:conversations:http:upload">>, - IgnoreEls, _el); - {<<"filename">>, <<"urn:xmpp:http:upload">>, _} -> - decode_upload_filename(<<"urn:xmpp:http:upload">>, - IgnoreEls, _el); - {<<"filename">>, <<>>, <<"urn:xmpp:http:upload">>} -> - decode_upload_filename(<<"urn:xmpp:http:upload">>, - IgnoreEls, _el); - {<<"filename">>, - <<"eu:siacs:conversations:http:upload">>, _} -> - decode_upload_filename(<<"eu:siacs:conversations:http:upload">>, - IgnoreEls, _el); - {<<"filename">>, <<>>, - <<"eu:siacs:conversations:http:upload">>} -> - decode_upload_filename(<<"eu:siacs:conversations:http:upload">>, - IgnoreEls, _el); - {<<"address">>, <<"urn:xmpp:sic:0">>, _} -> - decode_sic(<<"urn:xmpp:sic:0">>, IgnoreEls, _el); - {<<"address">>, <<>>, <<"urn:xmpp:sic:0">>} -> - decode_sic(<<"urn:xmpp:sic:0">>, IgnoreEls, _el); - {<<"address">>, <<"urn:xmpp:sic:1">>, _} -> - decode_sic(<<"urn:xmpp:sic:1">>, IgnoreEls, _el); - {<<"address">>, <<>>, <<"urn:xmpp:sic:1">>} -> - decode_sic(<<"urn:xmpp:sic:1">>, IgnoreEls, _el); - {<<"port">>, <<"urn:xmpp:sic:1">>, _} -> - decode_sip_port(<<"urn:xmpp:sic:1">>, IgnoreEls, _el); - {<<"port">>, <<>>, <<"urn:xmpp:sic:1">>} -> - decode_sip_port(<<"urn:xmpp:sic:1">>, IgnoreEls, _el); - {<<"ip">>, <<"urn:xmpp:sic:0">>, _} -> - decode_sic_ip(<<"urn:xmpp:sic:0">>, IgnoreEls, _el); - {<<"ip">>, <<>>, <<"urn:xmpp:sic:0">>} -> - decode_sic_ip(<<"urn:xmpp:sic:0">>, IgnoreEls, _el); - {<<"ip">>, <<"urn:xmpp:sic:1">>, _} -> - decode_sic_ip(<<"urn:xmpp:sic:1">>, IgnoreEls, _el); - {<<"ip">>, <<>>, <<"urn:xmpp:sic:1">>} -> - decode_sic_ip(<<"urn:xmpp:sic:1">>, IgnoreEls, _el); - {<<"x">>, <<"jabber:x:oob">>, _} -> - decode_oob_x(<<"jabber:x:oob">>, IgnoreEls, _el); - {<<"x">>, <<>>, <<"jabber:x:oob">>} -> - decode_oob_x(<<"jabber:x:oob">>, IgnoreEls, _el); - {<<"desc">>, <<"jabber:x:oob">>, _} -> - decode_oob_desc(<<"jabber:x:oob">>, IgnoreEls, _el); - {<<"desc">>, <<>>, <<"jabber:x:oob">>} -> - decode_oob_desc(<<"jabber:x:oob">>, IgnoreEls, _el); - {<<"url">>, <<"jabber:x:oob">>, _} -> - decode_oob_url(<<"jabber:x:oob">>, IgnoreEls, _el); - {<<"url">>, <<>>, <<"jabber:x:oob">>} -> - decode_oob_url(<<"jabber:x:oob">>, IgnoreEls, _el); - {<<"media">>, <<"urn:xmpp:media-element">>, _} -> - decode_media(<<"urn:xmpp:media-element">>, IgnoreEls, - _el); - {<<"media">>, <<>>, <<"urn:xmpp:media-element">>} -> - decode_media(<<"urn:xmpp:media-element">>, IgnoreEls, - _el); - {<<"uri">>, <<"urn:xmpp:media-element">>, _} -> - decode_media_uri(<<"urn:xmpp:media-element">>, - IgnoreEls, _el); - {<<"uri">>, <<>>, <<"urn:xmpp:media-element">>} -> - decode_media_uri(<<"urn:xmpp:media-element">>, - IgnoreEls, _el); - {<<"captcha">>, <<"urn:xmpp:captcha">>, _} -> - decode_captcha(<<"urn:xmpp:captcha">>, IgnoreEls, _el); - {<<"captcha">>, <<>>, <<"urn:xmpp:captcha">>} -> - decode_captcha(<<"urn:xmpp:captcha">>, IgnoreEls, _el); - {<<"data">>, <<"urn:xmpp:bob">>, _} -> - decode_bob_data(<<"urn:xmpp:bob">>, IgnoreEls, _el); - {<<"data">>, <<>>, <<"urn:xmpp:bob">>} -> - decode_bob_data(<<"urn:xmpp:bob">>, IgnoreEls, _el); - {<<"stream:stream">>, <<"jabber:client">>, _} -> - decode_stream_start(<<"jabber:client">>, IgnoreEls, - _el); - {<<"stream:stream">>, <<>>, <<"jabber:client">>} -> - decode_stream_start(<<"jabber:client">>, IgnoreEls, - _el); - {<<"stream:stream">>, <<"jabber:server">>, _} -> - decode_stream_start(<<"jabber:server">>, IgnoreEls, - _el); - {<<"stream:stream">>, <<>>, <<"jabber:server">>} -> - decode_stream_start(<<"jabber:server">>, IgnoreEls, - _el); - {<<"stream:stream">>, <<"jabber:component:accept">>, - _} -> - decode_stream_start(<<"jabber:component:accept">>, - IgnoreEls, _el); - {<<"stream:stream">>, <<>>, - <<"jabber:component:accept">>} -> - decode_stream_start(<<"jabber:component:accept">>, - IgnoreEls, _el); - {<<"handshake">>, <<"jabber:component:accept">>, _} -> - decode_handshake(<<"jabber:component:accept">>, - IgnoreEls, _el); - {<<"handshake">>, <<>>, - <<"jabber:component:accept">>} -> - decode_handshake(<<"jabber:component:accept">>, - IgnoreEls, _el); - {<<"db:verify">>, <<"jabber:server">>, _} -> - decode_db_verify(<<"jabber:server">>, IgnoreEls, _el); - {<<"db:verify">>, <<>>, <<"jabber:server">>} -> - decode_db_verify(<<"jabber:server">>, IgnoreEls, _el); - {<<"db:result">>, <<"jabber:server">>, _} -> - decode_db_result(<<"jabber:server">>, IgnoreEls, _el); - {<<"db:result">>, <<>>, <<"jabber:server">>} -> - decode_db_result(<<"jabber:server">>, IgnoreEls, _el); - {<<"command">>, - <<"http://jabber.org/protocol/commands">>, _} -> - decode_adhoc_command(<<"http://jabber.org/protocol/commands">>, - IgnoreEls, _el); - {<<"command">>, <<>>, - <<"http://jabber.org/protocol/commands">>} -> - decode_adhoc_command(<<"http://jabber.org/protocol/commands">>, - IgnoreEls, _el); - {<<"note">>, <<"http://jabber.org/protocol/commands">>, - _} -> - decode_adhoc_command_notes(<<"http://jabber.org/protocol/commands">>, - IgnoreEls, _el); - {<<"note">>, <<>>, - <<"http://jabber.org/protocol/commands">>} -> - decode_adhoc_command_notes(<<"http://jabber.org/protocol/commands">>, - IgnoreEls, _el); - {<<"actions">>, - <<"http://jabber.org/protocol/commands">>, _} -> - decode_adhoc_command_actions(<<"http://jabber.org/protocol/commands">>, - IgnoreEls, _el); - {<<"actions">>, <<>>, - <<"http://jabber.org/protocol/commands">>} -> - decode_adhoc_command_actions(<<"http://jabber.org/protocol/commands">>, - IgnoreEls, _el); - {<<"complete">>, - <<"http://jabber.org/protocol/commands">>, _} -> - decode_adhoc_command_complete(<<"http://jabber.org/protocol/commands">>, - IgnoreEls, _el); - {<<"complete">>, <<>>, - <<"http://jabber.org/protocol/commands">>} -> - decode_adhoc_command_complete(<<"http://jabber.org/protocol/commands">>, - IgnoreEls, _el); - {<<"next">>, <<"http://jabber.org/protocol/commands">>, - _} -> - decode_adhoc_command_next(<<"http://jabber.org/protocol/commands">>, - IgnoreEls, _el); - {<<"next">>, <<>>, - <<"http://jabber.org/protocol/commands">>} -> - decode_adhoc_command_next(<<"http://jabber.org/protocol/commands">>, - IgnoreEls, _el); - {<<"prev">>, <<"http://jabber.org/protocol/commands">>, - _} -> - decode_adhoc_command_prev(<<"http://jabber.org/protocol/commands">>, - IgnoreEls, _el); - {<<"prev">>, <<>>, - <<"http://jabber.org/protocol/commands">>} -> - decode_adhoc_command_prev(<<"http://jabber.org/protocol/commands">>, - IgnoreEls, _el); - {<<"client-id">>, <<"urn:xmpp:sid:0">>, _} -> - decode_client_id(<<"urn:xmpp:sid:0">>, IgnoreEls, _el); - {<<"client-id">>, <<>>, <<"urn:xmpp:sid:0">>} -> - decode_client_id(<<"urn:xmpp:sid:0">>, IgnoreEls, _el); - {<<"stanza-id">>, <<"urn:xmpp:sid:0">>, _} -> - decode_stanza_id(<<"urn:xmpp:sid:0">>, IgnoreEls, _el); - {<<"stanza-id">>, <<>>, <<"urn:xmpp:sid:0">>} -> - decode_stanza_id(<<"urn:xmpp:sid:0">>, IgnoreEls, _el); - {<<"addresses">>, - <<"http://jabber.org/protocol/address">>, _} -> - decode_addresses(<<"http://jabber.org/protocol/address">>, - IgnoreEls, _el); - {<<"addresses">>, <<>>, - <<"http://jabber.org/protocol/address">>} -> - decode_addresses(<<"http://jabber.org/protocol/address">>, - IgnoreEls, _el); - {<<"address">>, - <<"http://jabber.org/protocol/address">>, _} -> - decode_address(<<"http://jabber.org/protocol/address">>, - IgnoreEls, _el); - {<<"address">>, <<>>, - <<"http://jabber.org/protocol/address">>} -> - decode_address(<<"http://jabber.org/protocol/address">>, - IgnoreEls, _el); - {<<"nick">>, <<"http://jabber.org/protocol/nick">>, - _} -> - decode_nick(<<"http://jabber.org/protocol/nick">>, - IgnoreEls, _el); - {<<"nick">>, <<>>, - <<"http://jabber.org/protocol/nick">>} -> - decode_nick(<<"http://jabber.org/protocol/nick">>, - IgnoreEls, _el); - {<<"x">>, <<"jabber:x:expire">>, _} -> - decode_expire(<<"jabber:x:expire">>, IgnoreEls, _el); - {<<"x">>, <<>>, <<"jabber:x:expire">>} -> - decode_expire(<<"jabber:x:expire">>, IgnoreEls, _el); - {<<"x">>, <<"jabber:x:event">>, _} -> - decode_xevent(<<"jabber:x:event">>, IgnoreEls, _el); - {<<"x">>, <<>>, <<"jabber:x:event">>} -> - decode_xevent(<<"jabber:x:event">>, IgnoreEls, _el); - {<<"id">>, <<"jabber:x:event">>, _} -> - decode_xevent_id(<<"jabber:x:event">>, IgnoreEls, _el); - {<<"id">>, <<>>, <<"jabber:x:event">>} -> - decode_xevent_id(<<"jabber:x:event">>, IgnoreEls, _el); - {<<"composing">>, <<"jabber:x:event">>, _} -> - decode_xevent_composing(<<"jabber:x:event">>, IgnoreEls, - _el); - {<<"composing">>, <<>>, <<"jabber:x:event">>} -> - decode_xevent_composing(<<"jabber:x:event">>, IgnoreEls, - _el); - {<<"displayed">>, <<"jabber:x:event">>, _} -> - decode_xevent_displayed(<<"jabber:x:event">>, IgnoreEls, - _el); - {<<"displayed">>, <<>>, <<"jabber:x:event">>} -> - decode_xevent_displayed(<<"jabber:x:event">>, IgnoreEls, - _el); - {<<"delivered">>, <<"jabber:x:event">>, _} -> - decode_xevent_delivered(<<"jabber:x:event">>, IgnoreEls, - _el); - {<<"delivered">>, <<>>, <<"jabber:x:event">>} -> - decode_xevent_delivered(<<"jabber:x:event">>, IgnoreEls, - _el); - {<<"offline">>, <<"jabber:x:event">>, _} -> - decode_xevent_offline(<<"jabber:x:event">>, IgnoreEls, - _el); - {<<"offline">>, <<>>, <<"jabber:x:event">>} -> - decode_xevent_offline(<<"jabber:x:event">>, IgnoreEls, - _el); - {<<"query">>, <<"jabber:iq:search">>, _} -> - decode_search(<<"jabber:iq:search">>, IgnoreEls, _el); - {<<"query">>, <<>>, <<"jabber:iq:search">>} -> - decode_search(<<"jabber:iq:search">>, IgnoreEls, _el); - {<<"item">>, <<"jabber:iq:search">>, _} -> - decode_search_item(<<"jabber:iq:search">>, IgnoreEls, - _el); - {<<"item">>, <<>>, <<"jabber:iq:search">>} -> - decode_search_item(<<"jabber:iq:search">>, IgnoreEls, - _el); - {<<"email">>, <<"jabber:iq:search">>, _} -> - decode_search_email(<<"jabber:iq:search">>, IgnoreEls, - _el); - {<<"email">>, <<>>, <<"jabber:iq:search">>} -> - decode_search_email(<<"jabber:iq:search">>, IgnoreEls, - _el); - {<<"nick">>, <<"jabber:iq:search">>, _} -> - decode_search_nick(<<"jabber:iq:search">>, IgnoreEls, - _el); - {<<"nick">>, <<>>, <<"jabber:iq:search">>} -> - decode_search_nick(<<"jabber:iq:search">>, IgnoreEls, - _el); - {<<"last">>, <<"jabber:iq:search">>, _} -> - decode_search_last(<<"jabber:iq:search">>, IgnoreEls, - _el); - {<<"last">>, <<>>, <<"jabber:iq:search">>} -> - decode_search_last(<<"jabber:iq:search">>, IgnoreEls, - _el); - {<<"first">>, <<"jabber:iq:search">>, _} -> - decode_search_first(<<"jabber:iq:search">>, IgnoreEls, - _el); - {<<"first">>, <<>>, <<"jabber:iq:search">>} -> - decode_search_first(<<"jabber:iq:search">>, IgnoreEls, - _el); - {<<"instructions">>, <<"jabber:iq:search">>, _} -> - decode_search_instructions(<<"jabber:iq:search">>, - IgnoreEls, _el); - {<<"instructions">>, <<>>, <<"jabber:iq:search">>} -> - decode_search_instructions(<<"jabber:iq:search">>, - IgnoreEls, _el); - {<<"no-permanent-storage">>, <<"urn:xmpp:hints">>, _} -> - decode_hint_no_permanent_storage(<<"urn:xmpp:hints">>, - IgnoreEls, _el); - {<<"no-permanent-storage">>, <<>>, - <<"urn:xmpp:hints">>} -> - decode_hint_no_permanent_storage(<<"urn:xmpp:hints">>, - IgnoreEls, _el); - {<<"no-permanent-store">>, <<"urn:xmpp:hints">>, _} -> - decode_hint_no_permanent_store(<<"urn:xmpp:hints">>, - IgnoreEls, _el); - {<<"no-permanent-store">>, <<>>, - <<"urn:xmpp:hints">>} -> - decode_hint_no_permanent_store(<<"urn:xmpp:hints">>, - IgnoreEls, _el); - {<<"store">>, <<"urn:xmpp:hints">>, _} -> - decode_hint_store(<<"urn:xmpp:hints">>, IgnoreEls, _el); - {<<"store">>, <<>>, <<"urn:xmpp:hints">>} -> - decode_hint_store(<<"urn:xmpp:hints">>, IgnoreEls, _el); - {<<"no-storage">>, <<"urn:xmpp:hints">>, _} -> - decode_hint_no_storage(<<"urn:xmpp:hints">>, IgnoreEls, - _el); - {<<"no-storage">>, <<>>, <<"urn:xmpp:hints">>} -> - decode_hint_no_storage(<<"urn:xmpp:hints">>, IgnoreEls, - _el); - {<<"no-store">>, <<"urn:xmpp:hints">>, _} -> - decode_hint_no_store(<<"urn:xmpp:hints">>, IgnoreEls, - _el); - {<<"no-store">>, <<>>, <<"urn:xmpp:hints">>} -> - decode_hint_no_store(<<"urn:xmpp:hints">>, IgnoreEls, - _el); - {<<"no-copy">>, <<"urn:xmpp:hints">>, _} -> - decode_hint_no_copy(<<"urn:xmpp:hints">>, IgnoreEls, - _el); - {<<"no-copy">>, <<>>, <<"urn:xmpp:hints">>} -> - decode_hint_no_copy(<<"urn:xmpp:hints">>, IgnoreEls, - _el); - {<<"participant">>, <<"urn:xmpp:mix:0">>, _} -> - decode_mix_participant(<<"urn:xmpp:mix:0">>, IgnoreEls, - _el); - {<<"participant">>, <<>>, <<"urn:xmpp:mix:0">>} -> - decode_mix_participant(<<"urn:xmpp:mix:0">>, IgnoreEls, - _el); - {<<"leave">>, <<"urn:xmpp:mix:0">>, _} -> - decode_mix_leave(<<"urn:xmpp:mix:0">>, IgnoreEls, _el); - {<<"leave">>, <<>>, <<"urn:xmpp:mix:0">>} -> - decode_mix_leave(<<"urn:xmpp:mix:0">>, IgnoreEls, _el); - {<<"join">>, <<"urn:xmpp:mix:0">>, _} -> - decode_mix_join(<<"urn:xmpp:mix:0">>, IgnoreEls, _el); - {<<"join">>, <<>>, <<"urn:xmpp:mix:0">>} -> - decode_mix_join(<<"urn:xmpp:mix:0">>, IgnoreEls, _el); - {<<"subscribe">>, <<"urn:xmpp:mix:0">>, _} -> - decode_mix_subscribe(<<"urn:xmpp:mix:0">>, IgnoreEls, - _el); - {<<"subscribe">>, <<>>, <<"urn:xmpp:mix:0">>} -> - decode_mix_subscribe(<<"urn:xmpp:mix:0">>, IgnoreEls, - _el); - {<<"offline">>, - <<"http://jabber.org/protocol/offline">>, _} -> - decode_offline(<<"http://jabber.org/protocol/offline">>, - IgnoreEls, _el); - {<<"offline">>, <<>>, - <<"http://jabber.org/protocol/offline">>} -> - decode_offline(<<"http://jabber.org/protocol/offline">>, - IgnoreEls, _el); - {<<"item">>, <<"http://jabber.org/protocol/offline">>, - _} -> - decode_offline_item(<<"http://jabber.org/protocol/offline">>, - IgnoreEls, _el); - {<<"item">>, <<>>, - <<"http://jabber.org/protocol/offline">>} -> - decode_offline_item(<<"http://jabber.org/protocol/offline">>, - IgnoreEls, _el); - {<<"fetch">>, <<"http://jabber.org/protocol/offline">>, - _} -> - decode_offline_fetch(<<"http://jabber.org/protocol/offline">>, - IgnoreEls, _el); - {<<"fetch">>, <<>>, - <<"http://jabber.org/protocol/offline">>} -> - decode_offline_fetch(<<"http://jabber.org/protocol/offline">>, - IgnoreEls, _el); - {<<"purge">>, <<"http://jabber.org/protocol/offline">>, - _} -> - decode_offline_purge(<<"http://jabber.org/protocol/offline">>, - IgnoreEls, _el); - {<<"purge">>, <<>>, - <<"http://jabber.org/protocol/offline">>} -> - decode_offline_purge(<<"http://jabber.org/protocol/offline">>, - IgnoreEls, _el); - {<<"failed">>, <<"urn:xmpp:sm:2">>, _} -> - decode_sm_failed(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); - {<<"failed">>, <<>>, <<"urn:xmpp:sm:2">>} -> - decode_sm_failed(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); - {<<"failed">>, <<"urn:xmpp:sm:3">>, _} -> - decode_sm_failed(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); - {<<"failed">>, <<>>, <<"urn:xmpp:sm:3">>} -> - decode_sm_failed(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); - {<<"a">>, <<"urn:xmpp:sm:2">>, _} -> - decode_sm_a(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); - {<<"a">>, <<>>, <<"urn:xmpp:sm:2">>} -> - decode_sm_a(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); - {<<"a">>, <<"urn:xmpp:sm:3">>, _} -> - decode_sm_a(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); - {<<"a">>, <<>>, <<"urn:xmpp:sm:3">>} -> - decode_sm_a(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); - {<<"r">>, <<"urn:xmpp:sm:2">>, _} -> - decode_sm_r(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); - {<<"r">>, <<>>, <<"urn:xmpp:sm:2">>} -> - decode_sm_r(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); - {<<"r">>, <<"urn:xmpp:sm:3">>, _} -> - decode_sm_r(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); - {<<"r">>, <<>>, <<"urn:xmpp:sm:3">>} -> - decode_sm_r(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); - {<<"resumed">>, <<"urn:xmpp:sm:2">>, _} -> - decode_sm_resumed(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); - {<<"resumed">>, <<>>, <<"urn:xmpp:sm:2">>} -> - decode_sm_resumed(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); - {<<"resumed">>, <<"urn:xmpp:sm:3">>, _} -> - decode_sm_resumed(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); - {<<"resumed">>, <<>>, <<"urn:xmpp:sm:3">>} -> - decode_sm_resumed(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); - {<<"resume">>, <<"urn:xmpp:sm:2">>, _} -> - decode_sm_resume(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); - {<<"resume">>, <<>>, <<"urn:xmpp:sm:2">>} -> - decode_sm_resume(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); - {<<"resume">>, <<"urn:xmpp:sm:3">>, _} -> - decode_sm_resume(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); - {<<"resume">>, <<>>, <<"urn:xmpp:sm:3">>} -> - decode_sm_resume(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); - {<<"enabled">>, <<"urn:xmpp:sm:2">>, _} -> - decode_sm_enabled(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); - {<<"enabled">>, <<>>, <<"urn:xmpp:sm:2">>} -> - decode_sm_enabled(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); - {<<"enabled">>, <<"urn:xmpp:sm:3">>, _} -> - decode_sm_enabled(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); - {<<"enabled">>, <<>>, <<"urn:xmpp:sm:3">>} -> - decode_sm_enabled(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); - {<<"enable">>, <<"urn:xmpp:sm:2">>, _} -> - decode_sm_enable(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); - {<<"enable">>, <<>>, <<"urn:xmpp:sm:2">>} -> - decode_sm_enable(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); - {<<"enable">>, <<"urn:xmpp:sm:3">>, _} -> - decode_sm_enable(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); - {<<"enable">>, <<>>, <<"urn:xmpp:sm:3">>} -> - decode_sm_enable(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); - {<<"sm">>, <<"urn:xmpp:sm:2">>, _} -> - decode_feature_sm(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); - {<<"sm">>, <<>>, <<"urn:xmpp:sm:2">>} -> - decode_feature_sm(<<"urn:xmpp:sm:2">>, IgnoreEls, _el); - {<<"sm">>, <<"urn:xmpp:sm:3">>, _} -> - decode_feature_sm(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); - {<<"sm">>, <<>>, <<"urn:xmpp:sm:3">>} -> - decode_feature_sm(<<"urn:xmpp:sm:3">>, IgnoreEls, _el); - {<<"inactive">>, <<"urn:xmpp:csi:0">>, _} -> - decode_csi_inactive(<<"urn:xmpp:csi:0">>, IgnoreEls, - _el); - {<<"inactive">>, <<>>, <<"urn:xmpp:csi:0">>} -> - decode_csi_inactive(<<"urn:xmpp:csi:0">>, IgnoreEls, - _el); - {<<"active">>, <<"urn:xmpp:csi:0">>, _} -> - decode_csi_active(<<"urn:xmpp:csi:0">>, IgnoreEls, _el); - {<<"active">>, <<>>, <<"urn:xmpp:csi:0">>} -> - decode_csi_active(<<"urn:xmpp:csi:0">>, IgnoreEls, _el); - {<<"csi">>, <<"urn:xmpp:csi:0">>, _} -> - decode_feature_csi(<<"urn:xmpp:csi:0">>, IgnoreEls, - _el); - {<<"csi">>, <<>>, <<"urn:xmpp:csi:0">>} -> - decode_feature_csi(<<"urn:xmpp:csi:0">>, IgnoreEls, - _el); - {<<"sent">>, <<"urn:xmpp:carbons:2">>, _} -> - decode_carbons_sent(<<"urn:xmpp:carbons:2">>, IgnoreEls, - _el); - {<<"sent">>, <<>>, <<"urn:xmpp:carbons:2">>} -> - decode_carbons_sent(<<"urn:xmpp:carbons:2">>, IgnoreEls, - _el); - {<<"received">>, <<"urn:xmpp:carbons:2">>, _} -> - decode_carbons_received(<<"urn:xmpp:carbons:2">>, - IgnoreEls, _el); - {<<"received">>, <<>>, <<"urn:xmpp:carbons:2">>} -> - decode_carbons_received(<<"urn:xmpp:carbons:2">>, - IgnoreEls, _el); - {<<"private">>, <<"urn:xmpp:carbons:2">>, _} -> - decode_carbons_private(<<"urn:xmpp:carbons:2">>, - IgnoreEls, _el); - {<<"private">>, <<>>, <<"urn:xmpp:carbons:2">>} -> - decode_carbons_private(<<"urn:xmpp:carbons:2">>, - IgnoreEls, _el); - {<<"enable">>, <<"urn:xmpp:carbons:2">>, _} -> - decode_carbons_enable(<<"urn:xmpp:carbons:2">>, - IgnoreEls, _el); - {<<"enable">>, <<>>, <<"urn:xmpp:carbons:2">>} -> - decode_carbons_enable(<<"urn:xmpp:carbons:2">>, - IgnoreEls, _el); - {<<"disable">>, <<"urn:xmpp:carbons:2">>, _} -> - decode_carbons_disable(<<"urn:xmpp:carbons:2">>, - IgnoreEls, _el); - {<<"disable">>, <<>>, <<"urn:xmpp:carbons:2">>} -> - decode_carbons_disable(<<"urn:xmpp:carbons:2">>, - IgnoreEls, _el); - {<<"forwarded">>, <<"urn:xmpp:forward:0">>, _} -> - decode_forwarded(<<"urn:xmpp:forward:0">>, IgnoreEls, - _el); - {<<"forwarded">>, <<>>, <<"urn:xmpp:forward:0">>} -> - decode_forwarded(<<"urn:xmpp:forward:0">>, IgnoreEls, - _el); - {<<"fin">>, <<"urn:xmpp:mam:0">>, _} -> - decode_mam_fin(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); - {<<"fin">>, <<>>, <<"urn:xmpp:mam:0">>} -> - decode_mam_fin(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); - {<<"fin">>, <<"urn:xmpp:mam:1">>, _} -> - decode_mam_fin(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); - {<<"fin">>, <<>>, <<"urn:xmpp:mam:1">>} -> - decode_mam_fin(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); - {<<"prefs">>, <<"urn:xmpp:mam:0">>, _} -> - decode_mam_prefs(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); - {<<"prefs">>, <<>>, <<"urn:xmpp:mam:0">>} -> - decode_mam_prefs(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); - {<<"prefs">>, <<"urn:xmpp:mam:1">>, _} -> - decode_mam_prefs(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); - {<<"prefs">>, <<>>, <<"urn:xmpp:mam:1">>} -> - decode_mam_prefs(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); - {<<"prefs">>, <<"urn:xmpp:mam:tmp">>, _} -> - decode_mam_prefs(<<"urn:xmpp:mam:tmp">>, IgnoreEls, - _el); - {<<"prefs">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> - decode_mam_prefs(<<"urn:xmpp:mam:tmp">>, IgnoreEls, - _el); - {<<"always">>, <<"urn:xmpp:mam:0">>, _} -> - decode_mam_always(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); - {<<"always">>, <<>>, <<"urn:xmpp:mam:0">>} -> - decode_mam_always(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); - {<<"always">>, <<"urn:xmpp:mam:1">>, _} -> - decode_mam_always(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); - {<<"always">>, <<>>, <<"urn:xmpp:mam:1">>} -> - decode_mam_always(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); - {<<"always">>, <<"urn:xmpp:mam:tmp">>, _} -> - decode_mam_always(<<"urn:xmpp:mam:tmp">>, IgnoreEls, - _el); - {<<"always">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> - decode_mam_always(<<"urn:xmpp:mam:tmp">>, IgnoreEls, - _el); - {<<"never">>, <<"urn:xmpp:mam:0">>, _} -> - decode_mam_never(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); - {<<"never">>, <<>>, <<"urn:xmpp:mam:0">>} -> - decode_mam_never(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); - {<<"never">>, <<"urn:xmpp:mam:1">>, _} -> - decode_mam_never(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); - {<<"never">>, <<>>, <<"urn:xmpp:mam:1">>} -> - decode_mam_never(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); - {<<"never">>, <<"urn:xmpp:mam:tmp">>, _} -> - decode_mam_never(<<"urn:xmpp:mam:tmp">>, IgnoreEls, - _el); - {<<"never">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> - decode_mam_never(<<"urn:xmpp:mam:tmp">>, IgnoreEls, - _el); - {<<"jid">>, <<"urn:xmpp:mam:0">>, _} -> - decode_mam_jid(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); - {<<"jid">>, <<>>, <<"urn:xmpp:mam:0">>} -> - decode_mam_jid(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); - {<<"jid">>, <<"urn:xmpp:mam:1">>, _} -> - decode_mam_jid(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); - {<<"jid">>, <<>>, <<"urn:xmpp:mam:1">>} -> - decode_mam_jid(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); - {<<"jid">>, <<"urn:xmpp:mam:tmp">>, _} -> - decode_mam_jid(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); - {<<"jid">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> - decode_mam_jid(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); - {<<"result">>, <<"urn:xmpp:mam:0">>, _} -> - decode_mam_result(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); - {<<"result">>, <<>>, <<"urn:xmpp:mam:0">>} -> - decode_mam_result(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); - {<<"result">>, <<"urn:xmpp:mam:1">>, _} -> - decode_mam_result(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); - {<<"result">>, <<>>, <<"urn:xmpp:mam:1">>} -> - decode_mam_result(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); - {<<"result">>, <<"urn:xmpp:mam:tmp">>, _} -> - decode_mam_result(<<"urn:xmpp:mam:tmp">>, IgnoreEls, - _el); - {<<"result">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> - decode_mam_result(<<"urn:xmpp:mam:tmp">>, IgnoreEls, - _el); - {<<"archived">>, <<"urn:xmpp:mam:tmp">>, _} -> - decode_mam_archived(<<"urn:xmpp:mam:tmp">>, IgnoreEls, - _el); - {<<"archived">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> - decode_mam_archived(<<"urn:xmpp:mam:tmp">>, IgnoreEls, - _el); - {<<"query">>, <<"urn:xmpp:mam:0">>, _} -> - decode_mam_query(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); - {<<"query">>, <<>>, <<"urn:xmpp:mam:0">>} -> - decode_mam_query(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); - {<<"query">>, <<"urn:xmpp:mam:1">>, _} -> - decode_mam_query(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); - {<<"query">>, <<>>, <<"urn:xmpp:mam:1">>} -> - decode_mam_query(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); - {<<"query">>, <<"urn:xmpp:mam:tmp">>, _} -> - decode_mam_query(<<"urn:xmpp:mam:tmp">>, IgnoreEls, - _el); - {<<"query">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> - decode_mam_query(<<"urn:xmpp:mam:tmp">>, IgnoreEls, - _el); - {<<"withtext">>, <<"urn:xmpp:mam:tmp">>, _} -> - decode_mam_withtext(<<"urn:xmpp:mam:tmp">>, IgnoreEls, - _el); - {<<"withtext">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> - decode_mam_withtext(<<"urn:xmpp:mam:tmp">>, IgnoreEls, - _el); - {<<"with">>, <<"urn:xmpp:mam:tmp">>, _} -> - decode_mam_with(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); - {<<"with">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> - decode_mam_with(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); - {<<"end">>, <<"urn:xmpp:mam:tmp">>, _} -> - decode_mam_end(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); - {<<"end">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> - decode_mam_end(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); - {<<"start">>, <<"urn:xmpp:mam:tmp">>, _} -> - decode_mam_start(<<"urn:xmpp:mam:tmp">>, IgnoreEls, - _el); - {<<"start">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> - decode_mam_start(<<"urn:xmpp:mam:tmp">>, IgnoreEls, - _el); - {<<"set">>, <<"http://jabber.org/protocol/rsm">>, _} -> - decode_rsm_set(<<"http://jabber.org/protocol/rsm">>, - IgnoreEls, _el); - {<<"set">>, <<>>, - <<"http://jabber.org/protocol/rsm">>} -> - decode_rsm_set(<<"http://jabber.org/protocol/rsm">>, - IgnoreEls, _el); - {<<"first">>, <<"http://jabber.org/protocol/rsm">>, - _} -> - decode_rsm_first(<<"http://jabber.org/protocol/rsm">>, - IgnoreEls, _el); - {<<"first">>, <<>>, - <<"http://jabber.org/protocol/rsm">>} -> - decode_rsm_first(<<"http://jabber.org/protocol/rsm">>, - IgnoreEls, _el); - {<<"max">>, <<"http://jabber.org/protocol/rsm">>, _} -> - decode_rsm_max(<<"http://jabber.org/protocol/rsm">>, - IgnoreEls, _el); - {<<"max">>, <<>>, - <<"http://jabber.org/protocol/rsm">>} -> - decode_rsm_max(<<"http://jabber.org/protocol/rsm">>, - IgnoreEls, _el); - {<<"index">>, <<"http://jabber.org/protocol/rsm">>, - _} -> - decode_rsm_index(<<"http://jabber.org/protocol/rsm">>, - IgnoreEls, _el); - {<<"index">>, <<>>, - <<"http://jabber.org/protocol/rsm">>} -> - decode_rsm_index(<<"http://jabber.org/protocol/rsm">>, - IgnoreEls, _el); - {<<"count">>, <<"http://jabber.org/protocol/rsm">>, - _} -> - decode_rsm_count(<<"http://jabber.org/protocol/rsm">>, - IgnoreEls, _el); - {<<"count">>, <<>>, - <<"http://jabber.org/protocol/rsm">>} -> - decode_rsm_count(<<"http://jabber.org/protocol/rsm">>, - IgnoreEls, _el); - {<<"last">>, <<"http://jabber.org/protocol/rsm">>, _} -> - decode_rsm_last(<<"http://jabber.org/protocol/rsm">>, - IgnoreEls, _el); - {<<"last">>, <<>>, - <<"http://jabber.org/protocol/rsm">>} -> - decode_rsm_last(<<"http://jabber.org/protocol/rsm">>, - IgnoreEls, _el); - {<<"before">>, <<"http://jabber.org/protocol/rsm">>, - _} -> - decode_rsm_before(<<"http://jabber.org/protocol/rsm">>, - IgnoreEls, _el); - {<<"before">>, <<>>, - <<"http://jabber.org/protocol/rsm">>} -> - decode_rsm_before(<<"http://jabber.org/protocol/rsm">>, - IgnoreEls, _el); - {<<"after">>, <<"http://jabber.org/protocol/rsm">>, - _} -> - decode_rsm_after(<<"http://jabber.org/protocol/rsm">>, - IgnoreEls, _el); - {<<"after">>, <<>>, - <<"http://jabber.org/protocol/rsm">>} -> - decode_rsm_after(<<"http://jabber.org/protocol/rsm">>, - IgnoreEls, _el); - {<<"unsubscribe">>, <<"urn:xmpp:mucsub:0">>, _} -> - decode_muc_unsubscribe(<<"urn:xmpp:mucsub:0">>, - IgnoreEls, _el); - {<<"unsubscribe">>, <<>>, <<"urn:xmpp:mucsub:0">>} -> - decode_muc_unsubscribe(<<"urn:xmpp:mucsub:0">>, - IgnoreEls, _el); - {<<"subscribe">>, <<"urn:xmpp:mucsub:0">>, _} -> - decode_muc_subscribe(<<"urn:xmpp:mucsub:0">>, IgnoreEls, - _el); - {<<"subscribe">>, <<>>, <<"urn:xmpp:mucsub:0">>} -> - decode_muc_subscribe(<<"urn:xmpp:mucsub:0">>, IgnoreEls, - _el); - {<<"event">>, <<"urn:xmpp:mucsub:0">>, _} -> - decode_muc_subscribe_event(<<"urn:xmpp:mucsub:0">>, - IgnoreEls, _el); - {<<"event">>, <<>>, <<"urn:xmpp:mucsub:0">>} -> - decode_muc_subscribe_event(<<"urn:xmpp:mucsub:0">>, - IgnoreEls, _el); - {<<"subscriptions">>, <<"urn:xmpp:mucsub:0">>, _} -> - decode_muc_subscriptions(<<"urn:xmpp:mucsub:0">>, - IgnoreEls, _el); - {<<"subscriptions">>, <<>>, <<"urn:xmpp:mucsub:0">>} -> - decode_muc_subscriptions(<<"urn:xmpp:mucsub:0">>, - IgnoreEls, _el); - {<<"subscription">>, <<"urn:xmpp:mucsub:0">>, _} -> - decode_muc_subscription(<<"urn:xmpp:mucsub:0">>, - IgnoreEls, _el); - {<<"subscription">>, <<>>, <<"urn:xmpp:mucsub:0">>} -> - decode_muc_subscription(<<"urn:xmpp:mucsub:0">>, - IgnoreEls, _el); - {<<"x">>, <<"jabber:x:conference">>, _} -> - decode_x_conference(<<"jabber:x:conference">>, - IgnoreEls, _el); - {<<"x">>, <<>>, <<"jabber:x:conference">>} -> - decode_x_conference(<<"jabber:x:conference">>, - IgnoreEls, _el); - {<<"unique">>, - <<"http://jabber.org/protocol/muc#unique">>, _} -> - decode_muc_unique(<<"http://jabber.org/protocol/muc#unique">>, - IgnoreEls, _el); - {<<"unique">>, <<>>, - <<"http://jabber.org/protocol/muc#unique">>} -> - decode_muc_unique(<<"http://jabber.org/protocol/muc#unique">>, - IgnoreEls, _el); - {<<"x">>, <<"http://jabber.org/protocol/muc">>, _} -> - decode_muc(<<"http://jabber.org/protocol/muc">>, - IgnoreEls, _el); - {<<"x">>, <<>>, <<"http://jabber.org/protocol/muc">>} -> - decode_muc(<<"http://jabber.org/protocol/muc">>, - IgnoreEls, _el); - {<<"query">>, - <<"http://jabber.org/protocol/muc#admin">>, _} -> - decode_muc_admin(<<"http://jabber.org/protocol/muc#admin">>, - IgnoreEls, _el); - {<<"query">>, <<>>, - <<"http://jabber.org/protocol/muc#admin">>} -> - decode_muc_admin(<<"http://jabber.org/protocol/muc#admin">>, - IgnoreEls, _el); - {<<"continue">>, - <<"http://jabber.org/protocol/muc#admin">>, _} -> - decode_muc_admin_continue(<<"http://jabber.org/protocol/muc#admin">>, - IgnoreEls, _el); - {<<"continue">>, <<>>, - <<"http://jabber.org/protocol/muc#admin">>} -> - decode_muc_admin_continue(<<"http://jabber.org/protocol/muc#admin">>, - IgnoreEls, _el); - {<<"actor">>, - <<"http://jabber.org/protocol/muc#admin">>, _} -> - decode_muc_admin_actor(<<"http://jabber.org/protocol/muc#admin">>, - IgnoreEls, _el); - {<<"actor">>, <<>>, - <<"http://jabber.org/protocol/muc#admin">>} -> - decode_muc_admin_actor(<<"http://jabber.org/protocol/muc#admin">>, - IgnoreEls, _el); - {<<"item">>, <<"http://jabber.org/protocol/muc#admin">>, - _} -> - decode_muc_admin_item(<<"http://jabber.org/protocol/muc#admin">>, - IgnoreEls, _el); - {<<"item">>, <<>>, - <<"http://jabber.org/protocol/muc#admin">>} -> - decode_muc_admin_item(<<"http://jabber.org/protocol/muc#admin">>, - IgnoreEls, _el); - {<<"item">>, <<"http://jabber.org/protocol/muc#owner">>, - _} -> - decode_muc_owner_item(<<"http://jabber.org/protocol/muc#owner">>, - IgnoreEls, _el); - {<<"item">>, <<>>, - <<"http://jabber.org/protocol/muc#owner">>} -> - decode_muc_owner_item(<<"http://jabber.org/protocol/muc#owner">>, - IgnoreEls, _el); - {<<"query">>, - <<"http://jabber.org/protocol/muc#owner">>, _} -> - decode_muc_owner(<<"http://jabber.org/protocol/muc#owner">>, - IgnoreEls, _el); - {<<"query">>, <<>>, - <<"http://jabber.org/protocol/muc#owner">>} -> - decode_muc_owner(<<"http://jabber.org/protocol/muc#owner">>, - IgnoreEls, _el); - {<<"password">>, - <<"http://jabber.org/protocol/muc#owner">>, _} -> - decode_muc_password(<<"http://jabber.org/protocol/muc#owner">>, - IgnoreEls, _el); - {<<"password">>, <<>>, - <<"http://jabber.org/protocol/muc#owner">>} -> - decode_muc_password(<<"http://jabber.org/protocol/muc#owner">>, - IgnoreEls, _el); - {<<"password">>, - <<"http://jabber.org/protocol/muc#user">>, _} -> - decode_muc_password(<<"http://jabber.org/protocol/muc#user">>, - IgnoreEls, _el); - {<<"password">>, <<>>, - <<"http://jabber.org/protocol/muc#user">>} -> - decode_muc_password(<<"http://jabber.org/protocol/muc#user">>, - IgnoreEls, _el); - {<<"password">>, <<"http://jabber.org/protocol/muc">>, - _} -> - decode_muc_password(<<"http://jabber.org/protocol/muc">>, - IgnoreEls, _el); - {<<"password">>, <<>>, - <<"http://jabber.org/protocol/muc">>} -> - decode_muc_password(<<"http://jabber.org/protocol/muc">>, - IgnoreEls, _el); - {<<"x">>, <<"http://jabber.org/protocol/muc#user">>, - _} -> - decode_muc_user(<<"http://jabber.org/protocol/muc#user">>, - IgnoreEls, _el); - {<<"x">>, <<>>, - <<"http://jabber.org/protocol/muc#user">>} -> - decode_muc_user(<<"http://jabber.org/protocol/muc#user">>, - IgnoreEls, _el); - {<<"item">>, <<"http://jabber.org/protocol/muc#user">>, - _} -> - decode_muc_user_item(<<"http://jabber.org/protocol/muc#user">>, - IgnoreEls, _el); - {<<"item">>, <<>>, - <<"http://jabber.org/protocol/muc#user">>} -> - decode_muc_user_item(<<"http://jabber.org/protocol/muc#user">>, - IgnoreEls, _el); - {<<"status">>, - <<"http://jabber.org/protocol/muc#user">>, _} -> - decode_muc_user_status(<<"http://jabber.org/protocol/muc#user">>, - IgnoreEls, _el); - {<<"status">>, <<>>, - <<"http://jabber.org/protocol/muc#user">>} -> - decode_muc_user_status(<<"http://jabber.org/protocol/muc#user">>, - IgnoreEls, _el); - {<<"continue">>, - <<"http://jabber.org/protocol/muc#user">>, _} -> - decode_muc_user_continue(<<"http://jabber.org/protocol/muc#user">>, - IgnoreEls, _el); - {<<"continue">>, <<>>, - <<"http://jabber.org/protocol/muc#user">>} -> - decode_muc_user_continue(<<"http://jabber.org/protocol/muc#user">>, - IgnoreEls, _el); - {<<"actor">>, <<"http://jabber.org/protocol/muc#user">>, - _} -> - decode_muc_user_actor(<<"http://jabber.org/protocol/muc#user">>, - IgnoreEls, _el); - {<<"actor">>, <<>>, - <<"http://jabber.org/protocol/muc#user">>} -> - decode_muc_user_actor(<<"http://jabber.org/protocol/muc#user">>, - IgnoreEls, _el); - {<<"invite">>, - <<"http://jabber.org/protocol/muc#user">>, _} -> - decode_muc_user_invite(<<"http://jabber.org/protocol/muc#user">>, - IgnoreEls, _el); - {<<"invite">>, <<>>, - <<"http://jabber.org/protocol/muc#user">>} -> - decode_muc_user_invite(<<"http://jabber.org/protocol/muc#user">>, - IgnoreEls, _el); - {<<"destroy">>, - <<"http://jabber.org/protocol/muc#user">>, _} -> - decode_muc_destroy(<<"http://jabber.org/protocol/muc#user">>, - IgnoreEls, _el); - {<<"destroy">>, <<>>, - <<"http://jabber.org/protocol/muc#user">>} -> - decode_muc_destroy(<<"http://jabber.org/protocol/muc#user">>, - IgnoreEls, _el); - {<<"destroy">>, - <<"http://jabber.org/protocol/muc#owner">>, _} -> - decode_muc_destroy(<<"http://jabber.org/protocol/muc#owner">>, - IgnoreEls, _el); - {<<"destroy">>, <<>>, - <<"http://jabber.org/protocol/muc#owner">>} -> - decode_muc_destroy(<<"http://jabber.org/protocol/muc#owner">>, - IgnoreEls, _el); - {<<"decline">>, - <<"http://jabber.org/protocol/muc#user">>, _} -> - decode_muc_user_decline(<<"http://jabber.org/protocol/muc#user">>, - IgnoreEls, _el); - {<<"decline">>, <<>>, - <<"http://jabber.org/protocol/muc#user">>} -> - decode_muc_user_decline(<<"http://jabber.org/protocol/muc#user">>, - IgnoreEls, _el); - {<<"reason">>, - <<"http://jabber.org/protocol/muc#user">>, _} -> - decode_muc_reason(<<"http://jabber.org/protocol/muc#user">>, - IgnoreEls, _el); - {<<"reason">>, <<>>, - <<"http://jabber.org/protocol/muc#user">>} -> - decode_muc_reason(<<"http://jabber.org/protocol/muc#user">>, - IgnoreEls, _el); - {<<"reason">>, - <<"http://jabber.org/protocol/muc#admin">>, _} -> - decode_muc_reason(<<"http://jabber.org/protocol/muc#admin">>, - IgnoreEls, _el); - {<<"reason">>, <<>>, - <<"http://jabber.org/protocol/muc#admin">>} -> - decode_muc_reason(<<"http://jabber.org/protocol/muc#admin">>, - IgnoreEls, _el); - {<<"reason">>, - <<"http://jabber.org/protocol/muc#owner">>, _} -> - decode_muc_reason(<<"http://jabber.org/protocol/muc#owner">>, - IgnoreEls, _el); - {<<"reason">>, <<>>, - <<"http://jabber.org/protocol/muc#owner">>} -> - decode_muc_reason(<<"http://jabber.org/protocol/muc#owner">>, - IgnoreEls, _el); - {<<"history">>, <<"http://jabber.org/protocol/muc">>, - _} -> - decode_muc_history(<<"http://jabber.org/protocol/muc">>, - IgnoreEls, _el); - {<<"history">>, <<>>, - <<"http://jabber.org/protocol/muc">>} -> - decode_muc_history(<<"http://jabber.org/protocol/muc">>, - IgnoreEls, _el); - {<<"query">>, - <<"http://jabber.org/protocol/bytestreams">>, _} -> - decode_bytestreams(<<"http://jabber.org/protocol/bytestreams">>, - IgnoreEls, _el); - {<<"query">>, <<>>, - <<"http://jabber.org/protocol/bytestreams">>} -> - decode_bytestreams(<<"http://jabber.org/protocol/bytestreams">>, - IgnoreEls, _el); - {<<"activate">>, - <<"http://jabber.org/protocol/bytestreams">>, _} -> - decode_bytestreams_activate(<<"http://jabber.org/protocol/bytestreams">>, - IgnoreEls, _el); - {<<"activate">>, <<>>, - <<"http://jabber.org/protocol/bytestreams">>} -> - decode_bytestreams_activate(<<"http://jabber.org/protocol/bytestreams">>, - IgnoreEls, _el); - {<<"streamhost-used">>, - <<"http://jabber.org/protocol/bytestreams">>, _} -> - decode_bytestreams_streamhost_used(<<"http://jabber.org/protocol/bytestreams">>, - IgnoreEls, _el); - {<<"streamhost-used">>, <<>>, - <<"http://jabber.org/protocol/bytestreams">>} -> - decode_bytestreams_streamhost_used(<<"http://jabber.org/protocol/bytestreams">>, - IgnoreEls, _el); - {<<"streamhost">>, - <<"http://jabber.org/protocol/bytestreams">>, _} -> - decode_bytestreams_streamhost(<<"http://jabber.org/protocol/bytestreams">>, - IgnoreEls, _el); - {<<"streamhost">>, <<>>, - <<"http://jabber.org/protocol/bytestreams">>} -> - decode_bytestreams_streamhost(<<"http://jabber.org/protocol/bytestreams">>, - IgnoreEls, _el); - {<<"delay">>, <<"urn:xmpp:delay">>, _} -> - decode_delay(<<"urn:xmpp:delay">>, IgnoreEls, _el); - {<<"delay">>, <<>>, <<"urn:xmpp:delay">>} -> - decode_delay(<<"urn:xmpp:delay">>, IgnoreEls, _el); - {<<"paused">>, - <<"http://jabber.org/protocol/chatstates">>, _} -> - decode_chatstate_paused(<<"http://jabber.org/protocol/chatstates">>, - IgnoreEls, _el); - {<<"paused">>, <<>>, - <<"http://jabber.org/protocol/chatstates">>} -> - decode_chatstate_paused(<<"http://jabber.org/protocol/chatstates">>, - IgnoreEls, _el); - {<<"inactive">>, - <<"http://jabber.org/protocol/chatstates">>, _} -> - decode_chatstate_inactive(<<"http://jabber.org/protocol/chatstates">>, - IgnoreEls, _el); - {<<"inactive">>, <<>>, - <<"http://jabber.org/protocol/chatstates">>} -> - decode_chatstate_inactive(<<"http://jabber.org/protocol/chatstates">>, - IgnoreEls, _el); - {<<"gone">>, - <<"http://jabber.org/protocol/chatstates">>, _} -> - decode_chatstate_gone(<<"http://jabber.org/protocol/chatstates">>, - IgnoreEls, _el); - {<<"gone">>, <<>>, - <<"http://jabber.org/protocol/chatstates">>} -> - decode_chatstate_gone(<<"http://jabber.org/protocol/chatstates">>, - IgnoreEls, _el); - {<<"composing">>, - <<"http://jabber.org/protocol/chatstates">>, _} -> - decode_chatstate_composing(<<"http://jabber.org/protocol/chatstates">>, - IgnoreEls, _el); - {<<"composing">>, <<>>, - <<"http://jabber.org/protocol/chatstates">>} -> - decode_chatstate_composing(<<"http://jabber.org/protocol/chatstates">>, - IgnoreEls, _el); - {<<"active">>, - <<"http://jabber.org/protocol/chatstates">>, _} -> - decode_chatstate_active(<<"http://jabber.org/protocol/chatstates">>, - IgnoreEls, _el); - {<<"active">>, <<>>, - <<"http://jabber.org/protocol/chatstates">>} -> - decode_chatstate_active(<<"http://jabber.org/protocol/chatstates">>, - IgnoreEls, _el); - {<<"headers">>, <<"http://jabber.org/protocol/shim">>, - _} -> - decode_shim_headers(<<"http://jabber.org/protocol/shim">>, - IgnoreEls, _el); - {<<"headers">>, <<>>, - <<"http://jabber.org/protocol/shim">>} -> - decode_shim_headers(<<"http://jabber.org/protocol/shim">>, - IgnoreEls, _el); - {<<"header">>, <<"http://jabber.org/protocol/shim">>, - _} -> - decode_shim_header(<<"http://jabber.org/protocol/shim">>, - IgnoreEls, _el); - {<<"header">>, <<>>, - <<"http://jabber.org/protocol/shim">>} -> - decode_shim_header(<<"http://jabber.org/protocol/shim">>, - IgnoreEls, _el); - {<<"unsupported-access-model">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - decode_pubsub_error_unsupported_access_model(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"unsupported-access-model">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - decode_pubsub_error_unsupported_access_model(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"unsupported">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - decode_pubsub_error_unsupported(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"unsupported">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - decode_pubsub_error_unsupported(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"too-many-subscriptions">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - decode_pubsub_error_too_many_subscriptions(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"too-many-subscriptions">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - decode_pubsub_error_too_many_subscriptions(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"subid-required">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - decode_pubsub_error_subid_required(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"subid-required">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - decode_pubsub_error_subid_required(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"presence-subscription-required">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - decode_pubsub_error_presence_subscription_required(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"presence-subscription-required">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - decode_pubsub_error_presence_subscription_required(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"pending-subscription">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - decode_pubsub_error_pending_subscription(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"pending-subscription">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - decode_pubsub_error_pending_subscription(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"payload-required">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - decode_pubsub_error_payload_required(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"payload-required">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - decode_pubsub_error_payload_required(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"payload-too-big">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - decode_pubsub_error_payload_too_big(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"payload-too-big">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - decode_pubsub_error_payload_too_big(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"not-subscribed">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - decode_pubsub_error_not_subscribed(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"not-subscribed">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - decode_pubsub_error_not_subscribed(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"not-in-roster-group">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - decode_pubsub_error_not_in_roster_group(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"not-in-roster-group">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - decode_pubsub_error_not_in_roster_group(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"nodeid-required">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - decode_pubsub_error_nodeid_required(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"nodeid-required">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - decode_pubsub_error_nodeid_required(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"max-nodes-exceeded">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - decode_pubsub_error_max_nodes_exceeded(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"max-nodes-exceeded">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - decode_pubsub_error_max_nodes_exceeded(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"max-items-exceeded">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - decode_pubsub_error_max_items_exceeded(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"max-items-exceeded">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - decode_pubsub_error_max_items_exceeded(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"jid-required">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - decode_pubsub_error_jid_required(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"jid-required">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - decode_pubsub_error_jid_required(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"item-required">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - decode_pubsub_error_item_required(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"item-required">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - decode_pubsub_error_item_required(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"item-forbidden">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - decode_pubsub_error_item_forbidden(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"item-forbidden">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - decode_pubsub_error_item_forbidden(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"invalid-subid">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - decode_pubsub_error_invalid_subid(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"invalid-subid">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - decode_pubsub_error_invalid_subid(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"invalid-payload">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - decode_pubsub_error_invalid_payload(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"invalid-payload">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - decode_pubsub_error_invalid_payload(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"invalid-options">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - decode_pubsub_error_invalid_options(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"invalid-options">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - decode_pubsub_error_invalid_options(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"invalid-jid">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - decode_pubsub_error_invalid_jid(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"invalid-jid">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - decode_pubsub_error_invalid_jid(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"configuration-required">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - decode_pubsub_error_configuration_required(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"configuration-required">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - decode_pubsub_error_configuration_required(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"closed-node">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - decode_pubsub_error_closed_node(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"closed-node">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - decode_pubsub_error_closed_node(<<"http://jabber.org/protocol/pubsub#errors">>, - IgnoreEls, _el); - {<<"pubsub">>, - <<"http://jabber.org/protocol/pubsub#owner">>, _} -> - decode_pubsub_owner(<<"http://jabber.org/protocol/pubsub#owner">>, - IgnoreEls, _el); - {<<"pubsub">>, <<>>, - <<"http://jabber.org/protocol/pubsub#owner">>} -> - decode_pubsub_owner(<<"http://jabber.org/protocol/pubsub#owner">>, - IgnoreEls, _el); - {<<"pubsub">>, <<"http://jabber.org/protocol/pubsub">>, - _} -> - decode_pubsub(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"pubsub">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - decode_pubsub(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"purge">>, <<"http://jabber.org/protocol/pubsub">>, - _} -> - decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"purge">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"purge">>, - <<"http://jabber.org/protocol/pubsub#owner">>, _} -> - decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub#owner">>, - IgnoreEls, _el); - {<<"purge">>, <<>>, - <<"http://jabber.org/protocol/pubsub#owner">>} -> - decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub#owner">>, - IgnoreEls, _el); - {<<"purge">>, - <<"http://jabber.org/protocol/pubsub#event">>, _} -> - decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub#event">>, - IgnoreEls, _el); - {<<"purge">>, <<>>, - <<"http://jabber.org/protocol/pubsub#event">>} -> - decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub#event">>, - IgnoreEls, _el); - {<<"delete">>, <<"http://jabber.org/protocol/pubsub">>, - _} -> - decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"delete">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"delete">>, - <<"http://jabber.org/protocol/pubsub#owner">>, _} -> - decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub#owner">>, - IgnoreEls, _el); - {<<"delete">>, <<>>, - <<"http://jabber.org/protocol/pubsub#owner">>} -> - decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub#owner">>, - IgnoreEls, _el); - {<<"delete">>, - <<"http://jabber.org/protocol/pubsub#event">>, _} -> - decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub#event">>, - IgnoreEls, _el); - {<<"delete">>, <<>>, - <<"http://jabber.org/protocol/pubsub#event">>} -> - decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub#event">>, - IgnoreEls, _el); - {<<"redirect">>, - <<"http://jabber.org/protocol/pubsub">>, _} -> - decode_pubsub_redirect(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"redirect">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - decode_pubsub_redirect(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"redirect">>, - <<"http://jabber.org/protocol/pubsub#owner">>, _} -> - decode_pubsub_redirect(<<"http://jabber.org/protocol/pubsub#owner">>, - IgnoreEls, _el); - {<<"redirect">>, <<>>, - <<"http://jabber.org/protocol/pubsub#owner">>} -> - decode_pubsub_redirect(<<"http://jabber.org/protocol/pubsub#owner">>, - IgnoreEls, _el); - {<<"redirect">>, - <<"http://jabber.org/protocol/pubsub#event">>, _} -> - decode_pubsub_redirect(<<"http://jabber.org/protocol/pubsub#event">>, - IgnoreEls, _el); - {<<"redirect">>, <<>>, - <<"http://jabber.org/protocol/pubsub#event">>} -> - decode_pubsub_redirect(<<"http://jabber.org/protocol/pubsub#event">>, - IgnoreEls, _el); - {<<"default">>, <<"http://jabber.org/protocol/pubsub">>, - _} -> - decode_pubsub_default(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"default">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - decode_pubsub_default(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"default">>, - <<"http://jabber.org/protocol/pubsub#owner">>, _} -> - decode_pubsub_default(<<"http://jabber.org/protocol/pubsub#owner">>, - IgnoreEls, _el); - {<<"default">>, <<>>, - <<"http://jabber.org/protocol/pubsub#owner">>} -> - decode_pubsub_default(<<"http://jabber.org/protocol/pubsub#owner">>, - IgnoreEls, _el); - {<<"publish-options">>, - <<"http://jabber.org/protocol/pubsub">>, _} -> - decode_pubsub_publish_options(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"publish-options">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - decode_pubsub_publish_options(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"configure">>, - <<"http://jabber.org/protocol/pubsub">>, _} -> - decode_pubsub_configure(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"configure">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - decode_pubsub_configure(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"configure">>, - <<"http://jabber.org/protocol/pubsub#owner">>, _} -> - decode_pubsub_configure(<<"http://jabber.org/protocol/pubsub#owner">>, - IgnoreEls, _el); - {<<"configure">>, <<>>, - <<"http://jabber.org/protocol/pubsub#owner">>} -> - decode_pubsub_configure(<<"http://jabber.org/protocol/pubsub#owner">>, - IgnoreEls, _el); - {<<"create">>, <<"http://jabber.org/protocol/pubsub">>, - _} -> - decode_pubsub_create(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"create">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - decode_pubsub_create(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"create">>, - <<"http://jabber.org/protocol/pubsub#event">>, _} -> - decode_pubsub_create(<<"http://jabber.org/protocol/pubsub#event">>, - IgnoreEls, _el); - {<<"create">>, <<>>, - <<"http://jabber.org/protocol/pubsub#event">>} -> - decode_pubsub_create(<<"http://jabber.org/protocol/pubsub#event">>, - IgnoreEls, _el); - {<<"retract">>, <<"http://jabber.org/protocol/pubsub">>, - _} -> - decode_pubsub_retract(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"retract">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - decode_pubsub_retract(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"options">>, <<"http://jabber.org/protocol/pubsub">>, - _} -> - decode_pubsub_options(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"options">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - decode_pubsub_options(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"publish">>, <<"http://jabber.org/protocol/pubsub">>, - _} -> - decode_pubsub_publish(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"publish">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - decode_pubsub_publish(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"unsubscribe">>, - <<"http://jabber.org/protocol/pubsub">>, _} -> - decode_pubsub_unsubscribe(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"unsubscribe">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - decode_pubsub_unsubscribe(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"subscribe">>, - <<"http://jabber.org/protocol/pubsub">>, _} -> - decode_pubsub_subscribe(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"subscribe">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - decode_pubsub_subscribe(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"affiliations">>, - <<"http://jabber.org/protocol/pubsub#owner">>, _} -> - decode_pubsub_owner_affiliations(<<"http://jabber.org/protocol/pubsub#owner">>, - IgnoreEls, _el); - {<<"affiliations">>, <<>>, - <<"http://jabber.org/protocol/pubsub#owner">>} -> - decode_pubsub_owner_affiliations(<<"http://jabber.org/protocol/pubsub#owner">>, - IgnoreEls, _el); - {<<"affiliations">>, - <<"http://jabber.org/protocol/pubsub">>, _} -> - decode_pubsub_affiliations(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"affiliations">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - decode_pubsub_affiliations(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"subscriptions">>, - <<"http://jabber.org/protocol/pubsub">>, _} -> - decode_pubsub_subscriptions(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"subscriptions">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - decode_pubsub_subscriptions(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"subscriptions">>, - <<"http://jabber.org/protocol/pubsub#owner">>, _} -> - decode_pubsub_subscriptions(<<"http://jabber.org/protocol/pubsub#owner">>, - IgnoreEls, _el); - {<<"subscriptions">>, <<>>, - <<"http://jabber.org/protocol/pubsub#owner">>} -> - decode_pubsub_subscriptions(<<"http://jabber.org/protocol/pubsub#owner">>, - IgnoreEls, _el); - {<<"event">>, - <<"http://jabber.org/protocol/pubsub#event">>, _} -> - decode_pubsub_event(<<"http://jabber.org/protocol/pubsub#event">>, - IgnoreEls, _el); - {<<"event">>, <<>>, - <<"http://jabber.org/protocol/pubsub#event">>} -> - decode_pubsub_event(<<"http://jabber.org/protocol/pubsub#event">>, - IgnoreEls, _el); - {<<"items">>, <<"http://jabber.org/protocol/pubsub">>, - _} -> - decode_pubsub_items(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"items">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - decode_pubsub_items(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"items">>, - <<"http://jabber.org/protocol/pubsub#event">>, _} -> - decode_pubsub_items(<<"http://jabber.org/protocol/pubsub#event">>, - IgnoreEls, _el); - {<<"items">>, <<>>, - <<"http://jabber.org/protocol/pubsub#event">>} -> - decode_pubsub_items(<<"http://jabber.org/protocol/pubsub#event">>, - IgnoreEls, _el); - {<<"item">>, <<"http://jabber.org/protocol/pubsub">>, - _} -> - decode_pubsub_item(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"item">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - decode_pubsub_item(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"item">>, - <<"http://jabber.org/protocol/pubsub#event">>, _} -> - decode_pubsub_item(<<"http://jabber.org/protocol/pubsub#event">>, - IgnoreEls, _el); - {<<"item">>, <<>>, - <<"http://jabber.org/protocol/pubsub#event">>} -> - decode_pubsub_item(<<"http://jabber.org/protocol/pubsub#event">>, - IgnoreEls, _el); - {<<"retract">>, - <<"http://jabber.org/protocol/pubsub#event">>, _} -> - decode_pubsub_event_retract(<<"http://jabber.org/protocol/pubsub#event">>, - IgnoreEls, _el); - {<<"retract">>, <<>>, - <<"http://jabber.org/protocol/pubsub#event">>} -> - decode_pubsub_event_retract(<<"http://jabber.org/protocol/pubsub#event">>, - IgnoreEls, _el); - {<<"configuration">>, - <<"http://jabber.org/protocol/pubsub#event">>, _} -> - decode_pubsub_event_configuration(<<"http://jabber.org/protocol/pubsub#event">>, - IgnoreEls, _el); - {<<"configuration">>, <<>>, - <<"http://jabber.org/protocol/pubsub#event">>} -> - decode_pubsub_event_configuration(<<"http://jabber.org/protocol/pubsub#event">>, - IgnoreEls, _el); - {<<"affiliation">>, - <<"http://jabber.org/protocol/pubsub#owner">>, _} -> - decode_pubsub_owner_affiliation(<<"http://jabber.org/protocol/pubsub#owner">>, - IgnoreEls, _el); - {<<"affiliation">>, <<>>, - <<"http://jabber.org/protocol/pubsub#owner">>} -> - decode_pubsub_owner_affiliation(<<"http://jabber.org/protocol/pubsub#owner">>, - IgnoreEls, _el); - {<<"affiliation">>, - <<"http://jabber.org/protocol/pubsub">>, _} -> - decode_pubsub_affiliation(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"affiliation">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - decode_pubsub_affiliation(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"subscription">>, - <<"http://jabber.org/protocol/pubsub">>, _} -> - decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"subscription">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub">>, - IgnoreEls, _el); - {<<"subscription">>, - <<"http://jabber.org/protocol/pubsub#owner">>, _} -> - decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub#owner">>, - IgnoreEls, _el); - {<<"subscription">>, <<>>, - <<"http://jabber.org/protocol/pubsub#owner">>} -> - decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub#owner">>, - IgnoreEls, _el); - {<<"subscription">>, - <<"http://jabber.org/protocol/pubsub#event">>, _} -> - decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub#event">>, - IgnoreEls, _el); - {<<"subscription">>, <<>>, - <<"http://jabber.org/protocol/pubsub#event">>} -> - decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub#event">>, - IgnoreEls, _el); - {<<"x">>, <<"jabber:x:data">>, _} -> - decode_xdata(<<"jabber:x:data">>, IgnoreEls, _el); - {<<"x">>, <<>>, <<"jabber:x:data">>} -> - decode_xdata(<<"jabber:x:data">>, IgnoreEls, _el); - {<<"item">>, <<"jabber:x:data">>, _} -> - decode_xdata_item(<<"jabber:x:data">>, IgnoreEls, _el); - {<<"item">>, <<>>, <<"jabber:x:data">>} -> - decode_xdata_item(<<"jabber:x:data">>, IgnoreEls, _el); - {<<"reported">>, <<"jabber:x:data">>, _} -> - decode_xdata_reported(<<"jabber:x:data">>, IgnoreEls, - _el); - {<<"reported">>, <<>>, <<"jabber:x:data">>} -> - decode_xdata_reported(<<"jabber:x:data">>, IgnoreEls, - _el); - {<<"title">>, <<"jabber:x:data">>, _} -> - decode_xdata_title(<<"jabber:x:data">>, IgnoreEls, _el); - {<<"title">>, <<>>, <<"jabber:x:data">>} -> - decode_xdata_title(<<"jabber:x:data">>, IgnoreEls, _el); - {<<"instructions">>, <<"jabber:x:data">>, _} -> - decode_xdata_instructions(<<"jabber:x:data">>, - IgnoreEls, _el); - {<<"instructions">>, <<>>, <<"jabber:x:data">>} -> - decode_xdata_instructions(<<"jabber:x:data">>, - IgnoreEls, _el); - {<<"field">>, <<"jabber:x:data">>, _} -> - decode_xdata_field(<<"jabber:x:data">>, IgnoreEls, _el); - {<<"field">>, <<>>, <<"jabber:x:data">>} -> - decode_xdata_field(<<"jabber:x:data">>, IgnoreEls, _el); - {<<"option">>, <<"jabber:x:data">>, _} -> - decode_xdata_field_option(<<"jabber:x:data">>, - IgnoreEls, _el); - {<<"option">>, <<>>, <<"jabber:x:data">>} -> - decode_xdata_field_option(<<"jabber:x:data">>, - IgnoreEls, _el); - {<<"value">>, <<"jabber:x:data">>, _} -> - decode_xdata_field_value(<<"jabber:x:data">>, IgnoreEls, - _el); - {<<"value">>, <<>>, <<"jabber:x:data">>} -> - decode_xdata_field_value(<<"jabber:x:data">>, IgnoreEls, - _el); - {<<"desc">>, <<"jabber:x:data">>, _} -> - decode_xdata_field_desc(<<"jabber:x:data">>, IgnoreEls, - _el); - {<<"desc">>, <<>>, <<"jabber:x:data">>} -> - decode_xdata_field_desc(<<"jabber:x:data">>, IgnoreEls, - _el); - {<<"required">>, <<"jabber:x:data">>, _} -> - decode_xdata_field_required(<<"jabber:x:data">>, - IgnoreEls, _el); - {<<"required">>, <<>>, <<"jabber:x:data">>} -> - decode_xdata_field_required(<<"jabber:x:data">>, - IgnoreEls, _el); - {<<"x">>, <<"vcard-temp:x:update">>, _} -> - decode_vcard_xupdate(<<"vcard-temp:x:update">>, - IgnoreEls, _el); - {<<"x">>, <<>>, <<"vcard-temp:x:update">>} -> - decode_vcard_xupdate(<<"vcard-temp:x:update">>, - IgnoreEls, _el); - {<<"photo">>, <<"vcard-temp:x:update">>, _} -> - decode_vcard_xupdate_photo(<<"vcard-temp:x:update">>, - IgnoreEls, _el); - {<<"photo">>, <<>>, <<"vcard-temp:x:update">>} -> - decode_vcard_xupdate_photo(<<"vcard-temp:x:update">>, - IgnoreEls, _el); - {<<"vCard">>, <<"vcard-temp">>, _} -> - decode_vcard_temp(<<"vcard-temp">>, IgnoreEls, _el); - {<<"vCard">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_temp(<<"vcard-temp">>, IgnoreEls, _el); - {<<"CLASS">>, <<"vcard-temp">>, _} -> - decode_vcard_CLASS(<<"vcard-temp">>, IgnoreEls, _el); - {<<"CLASS">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_CLASS(<<"vcard-temp">>, IgnoreEls, _el); - {<<"CATEGORIES">>, <<"vcard-temp">>, _} -> - decode_vcard_CATEGORIES(<<"vcard-temp">>, IgnoreEls, - _el); - {<<"CATEGORIES">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_CATEGORIES(<<"vcard-temp">>, IgnoreEls, - _el); - {<<"KEY">>, <<"vcard-temp">>, _} -> - decode_vcard_KEY(<<"vcard-temp">>, IgnoreEls, _el); - {<<"KEY">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_KEY(<<"vcard-temp">>, IgnoreEls, _el); - {<<"SOUND">>, <<"vcard-temp">>, _} -> - decode_vcard_SOUND(<<"vcard-temp">>, IgnoreEls, _el); - {<<"SOUND">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_SOUND(<<"vcard-temp">>, IgnoreEls, _el); - {<<"ORG">>, <<"vcard-temp">>, _} -> - decode_vcard_ORG(<<"vcard-temp">>, IgnoreEls, _el); - {<<"ORG">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_ORG(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PHOTO">>, <<"vcard-temp">>, _} -> - decode_vcard_PHOTO(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PHOTO">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_PHOTO(<<"vcard-temp">>, IgnoreEls, _el); - {<<"LOGO">>, <<"vcard-temp">>, _} -> - decode_vcard_LOGO(<<"vcard-temp">>, IgnoreEls, _el); - {<<"LOGO">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_LOGO(<<"vcard-temp">>, IgnoreEls, _el); - {<<"BINVAL">>, <<"vcard-temp">>, _} -> - decode_vcard_BINVAL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"BINVAL">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_BINVAL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"GEO">>, <<"vcard-temp">>, _} -> - decode_vcard_GEO(<<"vcard-temp">>, IgnoreEls, _el); - {<<"GEO">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_GEO(<<"vcard-temp">>, IgnoreEls, _el); - {<<"EMAIL">>, <<"vcard-temp">>, _} -> - decode_vcard_EMAIL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"EMAIL">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_EMAIL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"TEL">>, <<"vcard-temp">>, _} -> - decode_vcard_TEL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"TEL">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_TEL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"LABEL">>, <<"vcard-temp">>, _} -> - decode_vcard_LABEL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"LABEL">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_LABEL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"ADR">>, <<"vcard-temp">>, _} -> - decode_vcard_ADR(<<"vcard-temp">>, IgnoreEls, _el); - {<<"ADR">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_ADR(<<"vcard-temp">>, IgnoreEls, _el); - {<<"N">>, <<"vcard-temp">>, _} -> - decode_vcard_N(<<"vcard-temp">>, IgnoreEls, _el); - {<<"N">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_N(<<"vcard-temp">>, IgnoreEls, _el); - {<<"CONFIDENTIAL">>, <<"vcard-temp">>, _} -> - decode_vcard_CONFIDENTIAL(<<"vcard-temp">>, IgnoreEls, - _el); - {<<"CONFIDENTIAL">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_CONFIDENTIAL(<<"vcard-temp">>, IgnoreEls, - _el); - {<<"PRIVATE">>, <<"vcard-temp">>, _} -> - decode_vcard_PRIVATE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PRIVATE">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_PRIVATE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PUBLIC">>, <<"vcard-temp">>, _} -> - decode_vcard_PUBLIC(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PUBLIC">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_PUBLIC(<<"vcard-temp">>, IgnoreEls, _el); - {<<"EXTVAL">>, <<"vcard-temp">>, _} -> - decode_vcard_EXTVAL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"EXTVAL">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_EXTVAL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"TYPE">>, <<"vcard-temp">>, _} -> - decode_vcard_TYPE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"TYPE">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_TYPE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"DESC">>, <<"vcard-temp">>, _} -> - decode_vcard_DESC(<<"vcard-temp">>, IgnoreEls, _el); - {<<"DESC">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_DESC(<<"vcard-temp">>, IgnoreEls, _el); - {<<"URL">>, <<"vcard-temp">>, _} -> - decode_vcard_URL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"URL">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_URL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"UID">>, <<"vcard-temp">>, _} -> - decode_vcard_UID(<<"vcard-temp">>, IgnoreEls, _el); - {<<"UID">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_UID(<<"vcard-temp">>, IgnoreEls, _el); - {<<"SORT-STRING">>, <<"vcard-temp">>, _} -> - decode_vcard_SORT_STRING(<<"vcard-temp">>, IgnoreEls, - _el); - {<<"SORT-STRING">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_SORT_STRING(<<"vcard-temp">>, IgnoreEls, - _el); - {<<"REV">>, <<"vcard-temp">>, _} -> - decode_vcard_REV(<<"vcard-temp">>, IgnoreEls, _el); - {<<"REV">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_REV(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PRODID">>, <<"vcard-temp">>, _} -> - decode_vcard_PRODID(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PRODID">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_PRODID(<<"vcard-temp">>, IgnoreEls, _el); - {<<"NOTE">>, <<"vcard-temp">>, _} -> - decode_vcard_NOTE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"NOTE">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_NOTE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"KEYWORD">>, <<"vcard-temp">>, _} -> - decode_vcard_KEYWORD(<<"vcard-temp">>, IgnoreEls, _el); - {<<"KEYWORD">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_KEYWORD(<<"vcard-temp">>, IgnoreEls, _el); - {<<"ROLE">>, <<"vcard-temp">>, _} -> - decode_vcard_ROLE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"ROLE">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_ROLE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"TITLE">>, <<"vcard-temp">>, _} -> - decode_vcard_TITLE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"TITLE">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_TITLE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"TZ">>, <<"vcard-temp">>, _} -> - decode_vcard_TZ(<<"vcard-temp">>, IgnoreEls, _el); - {<<"TZ">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_TZ(<<"vcard-temp">>, IgnoreEls, _el); - {<<"MAILER">>, <<"vcard-temp">>, _} -> - decode_vcard_MAILER(<<"vcard-temp">>, IgnoreEls, _el); - {<<"MAILER">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_MAILER(<<"vcard-temp">>, IgnoreEls, _el); - {<<"JABBERID">>, <<"vcard-temp">>, _} -> - decode_vcard_JABBERID(<<"vcard-temp">>, IgnoreEls, _el); - {<<"JABBERID">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_JABBERID(<<"vcard-temp">>, IgnoreEls, _el); - {<<"BDAY">>, <<"vcard-temp">>, _} -> - decode_vcard_BDAY(<<"vcard-temp">>, IgnoreEls, _el); - {<<"BDAY">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_BDAY(<<"vcard-temp">>, IgnoreEls, _el); - {<<"NICKNAME">>, <<"vcard-temp">>, _} -> - decode_vcard_NICKNAME(<<"vcard-temp">>, IgnoreEls, _el); - {<<"NICKNAME">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_NICKNAME(<<"vcard-temp">>, IgnoreEls, _el); - {<<"FN">>, <<"vcard-temp">>, _} -> - decode_vcard_FN(<<"vcard-temp">>, IgnoreEls, _el); - {<<"FN">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_FN(<<"vcard-temp">>, IgnoreEls, _el); - {<<"VERSION">>, <<"vcard-temp">>, _} -> - decode_vcard_VERSION(<<"vcard-temp">>, IgnoreEls, _el); - {<<"VERSION">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_VERSION(<<"vcard-temp">>, IgnoreEls, _el); - {<<"CRED">>, <<"vcard-temp">>, _} -> - decode_vcard_CRED(<<"vcard-temp">>, IgnoreEls, _el); - {<<"CRED">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_CRED(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PHONETIC">>, <<"vcard-temp">>, _} -> - decode_vcard_PHONETIC(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PHONETIC">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_PHONETIC(<<"vcard-temp">>, IgnoreEls, _el); - {<<"ORGUNIT">>, <<"vcard-temp">>, _} -> - decode_vcard_ORGUNIT(<<"vcard-temp">>, IgnoreEls, _el); - {<<"ORGUNIT">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_ORGUNIT(<<"vcard-temp">>, IgnoreEls, _el); - {<<"ORGNAME">>, <<"vcard-temp">>, _} -> - decode_vcard_ORGNAME(<<"vcard-temp">>, IgnoreEls, _el); - {<<"ORGNAME">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_ORGNAME(<<"vcard-temp">>, IgnoreEls, _el); - {<<"LON">>, <<"vcard-temp">>, _} -> - decode_vcard_LON(<<"vcard-temp">>, IgnoreEls, _el); - {<<"LON">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_LON(<<"vcard-temp">>, IgnoreEls, _el); - {<<"LAT">>, <<"vcard-temp">>, _} -> - decode_vcard_LAT(<<"vcard-temp">>, IgnoreEls, _el); - {<<"LAT">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_LAT(<<"vcard-temp">>, IgnoreEls, _el); - {<<"USERID">>, <<"vcard-temp">>, _} -> - decode_vcard_USERID(<<"vcard-temp">>, IgnoreEls, _el); - {<<"USERID">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_USERID(<<"vcard-temp">>, IgnoreEls, _el); - {<<"NUMBER">>, <<"vcard-temp">>, _} -> - decode_vcard_NUMBER(<<"vcard-temp">>, IgnoreEls, _el); - {<<"NUMBER">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_NUMBER(<<"vcard-temp">>, IgnoreEls, _el); - {<<"LINE">>, <<"vcard-temp">>, _} -> - decode_vcard_LINE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"LINE">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_LINE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"CTRY">>, <<"vcard-temp">>, _} -> - decode_vcard_CTRY(<<"vcard-temp">>, IgnoreEls, _el); - {<<"CTRY">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_CTRY(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PCODE">>, <<"vcard-temp">>, _} -> - decode_vcard_PCODE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PCODE">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_PCODE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"REGION">>, <<"vcard-temp">>, _} -> - decode_vcard_REGION(<<"vcard-temp">>, IgnoreEls, _el); - {<<"REGION">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_REGION(<<"vcard-temp">>, IgnoreEls, _el); - {<<"LOCALITY">>, <<"vcard-temp">>, _} -> - decode_vcard_LOCALITY(<<"vcard-temp">>, IgnoreEls, _el); - {<<"LOCALITY">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_LOCALITY(<<"vcard-temp">>, IgnoreEls, _el); - {<<"STREET">>, <<"vcard-temp">>, _} -> - decode_vcard_STREET(<<"vcard-temp">>, IgnoreEls, _el); - {<<"STREET">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_STREET(<<"vcard-temp">>, IgnoreEls, _el); - {<<"EXTADD">>, <<"vcard-temp">>, _} -> - decode_vcard_EXTADD(<<"vcard-temp">>, IgnoreEls, _el); - {<<"EXTADD">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_EXTADD(<<"vcard-temp">>, IgnoreEls, _el); - {<<"POBOX">>, <<"vcard-temp">>, _} -> - decode_vcard_POBOX(<<"vcard-temp">>, IgnoreEls, _el); - {<<"POBOX">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_POBOX(<<"vcard-temp">>, IgnoreEls, _el); - {<<"SUFFIX">>, <<"vcard-temp">>, _} -> - decode_vcard_SUFFIX(<<"vcard-temp">>, IgnoreEls, _el); - {<<"SUFFIX">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_SUFFIX(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PREFIX">>, <<"vcard-temp">>, _} -> - decode_vcard_PREFIX(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PREFIX">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_PREFIX(<<"vcard-temp">>, IgnoreEls, _el); - {<<"MIDDLE">>, <<"vcard-temp">>, _} -> - decode_vcard_MIDDLE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"MIDDLE">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_MIDDLE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"GIVEN">>, <<"vcard-temp">>, _} -> - decode_vcard_GIVEN(<<"vcard-temp">>, IgnoreEls, _el); - {<<"GIVEN">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_GIVEN(<<"vcard-temp">>, IgnoreEls, _el); - {<<"FAMILY">>, <<"vcard-temp">>, _} -> - decode_vcard_FAMILY(<<"vcard-temp">>, IgnoreEls, _el); - {<<"FAMILY">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_FAMILY(<<"vcard-temp">>, IgnoreEls, _el); - {<<"X400">>, <<"vcard-temp">>, _} -> - decode_vcard_X400(<<"vcard-temp">>, IgnoreEls, _el); - {<<"X400">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_X400(<<"vcard-temp">>, IgnoreEls, _el); - {<<"INTERNET">>, <<"vcard-temp">>, _} -> - decode_vcard_INTERNET(<<"vcard-temp">>, IgnoreEls, _el); - {<<"INTERNET">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_INTERNET(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PREF">>, <<"vcard-temp">>, _} -> - decode_vcard_PREF(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PREF">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_PREF(<<"vcard-temp">>, IgnoreEls, _el); - {<<"INTL">>, <<"vcard-temp">>, _} -> - decode_vcard_INTL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"INTL">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_INTL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"DOM">>, <<"vcard-temp">>, _} -> - decode_vcard_DOM(<<"vcard-temp">>, IgnoreEls, _el); - {<<"DOM">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_DOM(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PARCEL">>, <<"vcard-temp">>, _} -> - decode_vcard_PARCEL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PARCEL">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_PARCEL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"POSTAL">>, <<"vcard-temp">>, _} -> - decode_vcard_POSTAL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"POSTAL">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_POSTAL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PCS">>, <<"vcard-temp">>, _} -> - decode_vcard_PCS(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PCS">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_PCS(<<"vcard-temp">>, IgnoreEls, _el); - {<<"ISDN">>, <<"vcard-temp">>, _} -> - decode_vcard_ISDN(<<"vcard-temp">>, IgnoreEls, _el); - {<<"ISDN">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_ISDN(<<"vcard-temp">>, IgnoreEls, _el); - {<<"MODEM">>, <<"vcard-temp">>, _} -> - decode_vcard_MODEM(<<"vcard-temp">>, IgnoreEls, _el); - {<<"MODEM">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_MODEM(<<"vcard-temp">>, IgnoreEls, _el); - {<<"BBS">>, <<"vcard-temp">>, _} -> - decode_vcard_BBS(<<"vcard-temp">>, IgnoreEls, _el); - {<<"BBS">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_BBS(<<"vcard-temp">>, IgnoreEls, _el); - {<<"VIDEO">>, <<"vcard-temp">>, _} -> - decode_vcard_VIDEO(<<"vcard-temp">>, IgnoreEls, _el); - {<<"VIDEO">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_VIDEO(<<"vcard-temp">>, IgnoreEls, _el); - {<<"CELL">>, <<"vcard-temp">>, _} -> - decode_vcard_CELL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"CELL">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_CELL(<<"vcard-temp">>, IgnoreEls, _el); - {<<"MSG">>, <<"vcard-temp">>, _} -> - decode_vcard_MSG(<<"vcard-temp">>, IgnoreEls, _el); - {<<"MSG">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_MSG(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PAGER">>, <<"vcard-temp">>, _} -> - decode_vcard_PAGER(<<"vcard-temp">>, IgnoreEls, _el); - {<<"PAGER">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_PAGER(<<"vcard-temp">>, IgnoreEls, _el); - {<<"FAX">>, <<"vcard-temp">>, _} -> - decode_vcard_FAX(<<"vcard-temp">>, IgnoreEls, _el); - {<<"FAX">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_FAX(<<"vcard-temp">>, IgnoreEls, _el); - {<<"VOICE">>, <<"vcard-temp">>, _} -> - decode_vcard_VOICE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"VOICE">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_VOICE(<<"vcard-temp">>, IgnoreEls, _el); - {<<"WORK">>, <<"vcard-temp">>, _} -> - decode_vcard_WORK(<<"vcard-temp">>, IgnoreEls, _el); - {<<"WORK">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_WORK(<<"vcard-temp">>, IgnoreEls, _el); - {<<"HOME">>, <<"vcard-temp">>, _} -> - decode_vcard_HOME(<<"vcard-temp">>, IgnoreEls, _el); - {<<"HOME">>, <<>>, <<"vcard-temp">>} -> - decode_vcard_HOME(<<"vcard-temp">>, IgnoreEls, _el); - {<<"stream:error">>, <<"jabber:client">>, _} -> - decode_stream_error(<<"jabber:client">>, IgnoreEls, - _el); - {<<"stream:error">>, <<>>, <<"jabber:client">>} -> - decode_stream_error(<<"jabber:client">>, IgnoreEls, - _el); - {<<"stream:error">>, <<"jabber:server">>, _} -> - decode_stream_error(<<"jabber:server">>, IgnoreEls, - _el); - {<<"stream:error">>, <<>>, <<"jabber:server">>} -> - decode_stream_error(<<"jabber:server">>, IgnoreEls, - _el); - {<<"stream:error">>, <<"jabber:component:accept">>, - _} -> - decode_stream_error(<<"jabber:component:accept">>, - IgnoreEls, _el); - {<<"stream:error">>, <<>>, - <<"jabber:component:accept">>} -> - decode_stream_error(<<"jabber:component:accept">>, - IgnoreEls, _el); - {<<"unsupported-version">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - decode_stream_error_unsupported_version(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"unsupported-version">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_unsupported_version(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"unsupported-stanza-type">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - decode_stream_error_unsupported_stanza_type(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"unsupported-stanza-type">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_unsupported_stanza_type(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"unsupported-encoding">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - decode_stream_error_unsupported_encoding(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"unsupported-encoding">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_unsupported_encoding(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"undefined-condition">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - decode_stream_error_undefined_condition(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"undefined-condition">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_undefined_condition(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"system-shutdown">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - decode_stream_error_system_shutdown(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"system-shutdown">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_system_shutdown(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"see-other-host">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - decode_stream_error_see_other_host(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"see-other-host">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_see_other_host(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"restricted-xml">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - decode_stream_error_restricted_xml(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"restricted-xml">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_restricted_xml(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"resource-constraint">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - decode_stream_error_resource_constraint(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"resource-constraint">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_resource_constraint(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"reset">>, <<"urn:ietf:params:xml:ns:xmpp-streams">>, - _} -> - decode_stream_error_reset(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"reset">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_reset(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"remote-connection-failed">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - decode_stream_error_remote_connection_failed(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"remote-connection-failed">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_remote_connection_failed(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"policy-violation">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - decode_stream_error_policy_violation(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"policy-violation">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_policy_violation(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"not-well-formed">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - decode_stream_error_not_well_formed(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"not-well-formed">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_not_well_formed(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"not-authorized">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - decode_stream_error_not_authorized(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"not-authorized">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_not_authorized(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"invalid-xml">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - decode_stream_error_invalid_xml(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"invalid-xml">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_invalid_xml(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"invalid-namespace">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - decode_stream_error_invalid_namespace(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"invalid-namespace">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_invalid_namespace(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"invalid-id">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - decode_stream_error_invalid_id(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"invalid-id">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_invalid_id(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"invalid-from">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - decode_stream_error_invalid_from(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"invalid-from">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_invalid_from(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"internal-server-error">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - decode_stream_error_internal_server_error(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"internal-server-error">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_internal_server_error(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"improper-addressing">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - decode_stream_error_improper_addressing(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"improper-addressing">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_improper_addressing(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"host-unknown">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - decode_stream_error_host_unknown(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"host-unknown">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_host_unknown(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"host-gone">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - decode_stream_error_host_gone(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"host-gone">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_host_gone(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"connection-timeout">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - decode_stream_error_connection_timeout(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"connection-timeout">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_connection_timeout(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"conflict">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - decode_stream_error_conflict(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"conflict">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_conflict(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"bad-namespace-prefix">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - decode_stream_error_bad_namespace_prefix(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"bad-namespace-prefix">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_bad_namespace_prefix(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"bad-format">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - decode_stream_error_bad_format(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"bad-format">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_bad_format(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"text">>, <<"urn:ietf:params:xml:ns:xmpp-streams">>, - _} -> - decode_stream_error_text(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"text">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - decode_stream_error_text(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - IgnoreEls, _el); - {<<"time">>, <<"urn:xmpp:time">>, _} -> - decode_time(<<"urn:xmpp:time">>, IgnoreEls, _el); - {<<"time">>, <<>>, <<"urn:xmpp:time">>} -> - decode_time(<<"urn:xmpp:time">>, IgnoreEls, _el); - {<<"tzo">>, <<"urn:xmpp:time">>, _} -> - decode_time_tzo(<<"urn:xmpp:time">>, IgnoreEls, _el); - {<<"tzo">>, <<>>, <<"urn:xmpp:time">>} -> - decode_time_tzo(<<"urn:xmpp:time">>, IgnoreEls, _el); - {<<"utc">>, <<"urn:xmpp:time">>, _} -> - decode_time_utc(<<"urn:xmpp:time">>, IgnoreEls, _el); - {<<"utc">>, <<>>, <<"urn:xmpp:time">>} -> - decode_time_utc(<<"urn:xmpp:time">>, IgnoreEls, _el); - {<<"ping">>, <<"urn:xmpp:ping">>, _} -> - decode_ping(<<"urn:xmpp:ping">>, IgnoreEls, _el); - {<<"ping">>, <<>>, <<"urn:xmpp:ping">>} -> - decode_ping(<<"urn:xmpp:ping">>, IgnoreEls, _el); - {<<"session">>, - <<"urn:ietf:params:xml:ns:xmpp-session">>, _} -> - decode_session(<<"urn:ietf:params:xml:ns:xmpp-session">>, - IgnoreEls, _el); - {<<"session">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-session">>} -> - decode_session(<<"urn:ietf:params:xml:ns:xmpp-session">>, - IgnoreEls, _el); - {<<"optional">>, - <<"urn:ietf:params:xml:ns:xmpp-session">>, _} -> - decode_session_optional(<<"urn:ietf:params:xml:ns:xmpp-session">>, - IgnoreEls, _el); - {<<"optional">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-session">>} -> - decode_session_optional(<<"urn:ietf:params:xml:ns:xmpp-session">>, - IgnoreEls, _el); - {<<"query">>, <<"jabber:iq:register">>, _} -> - decode_register(<<"jabber:iq:register">>, IgnoreEls, - _el); - {<<"query">>, <<>>, <<"jabber:iq:register">>} -> - decode_register(<<"jabber:iq:register">>, IgnoreEls, - _el); - {<<"key">>, <<"jabber:iq:register">>, _} -> - decode_register_key(<<"jabber:iq:register">>, IgnoreEls, - _el); - {<<"key">>, <<>>, <<"jabber:iq:register">>} -> - decode_register_key(<<"jabber:iq:register">>, IgnoreEls, - _el); - {<<"text">>, <<"jabber:iq:register">>, _} -> - decode_register_text(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"text">>, <<>>, <<"jabber:iq:register">>} -> - decode_register_text(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"misc">>, <<"jabber:iq:register">>, _} -> - decode_register_misc(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"misc">>, <<>>, <<"jabber:iq:register">>} -> - decode_register_misc(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"date">>, <<"jabber:iq:register">>, _} -> - decode_register_date(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"date">>, <<>>, <<"jabber:iq:register">>} -> - decode_register_date(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"url">>, <<"jabber:iq:register">>, _} -> - decode_register_url(<<"jabber:iq:register">>, IgnoreEls, - _el); - {<<"url">>, <<>>, <<"jabber:iq:register">>} -> - decode_register_url(<<"jabber:iq:register">>, IgnoreEls, - _el); - {<<"phone">>, <<"jabber:iq:register">>, _} -> - decode_register_phone(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"phone">>, <<>>, <<"jabber:iq:register">>} -> - decode_register_phone(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"zip">>, <<"jabber:iq:register">>, _} -> - decode_register_zip(<<"jabber:iq:register">>, IgnoreEls, - _el); - {<<"zip">>, <<>>, <<"jabber:iq:register">>} -> - decode_register_zip(<<"jabber:iq:register">>, IgnoreEls, - _el); - {<<"state">>, <<"jabber:iq:register">>, _} -> - decode_register_state(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"state">>, <<>>, <<"jabber:iq:register">>} -> - decode_register_state(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"city">>, <<"jabber:iq:register">>, _} -> - decode_register_city(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"city">>, <<>>, <<"jabber:iq:register">>} -> - decode_register_city(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"address">>, <<"jabber:iq:register">>, _} -> - decode_register_address(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"address">>, <<>>, <<"jabber:iq:register">>} -> - decode_register_address(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"email">>, <<"jabber:iq:register">>, _} -> - decode_register_email(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"email">>, <<>>, <<"jabber:iq:register">>} -> - decode_register_email(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"last">>, <<"jabber:iq:register">>, _} -> - decode_register_last(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"last">>, <<>>, <<"jabber:iq:register">>} -> - decode_register_last(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"first">>, <<"jabber:iq:register">>, _} -> - decode_register_first(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"first">>, <<>>, <<"jabber:iq:register">>} -> - decode_register_first(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"name">>, <<"jabber:iq:register">>, _} -> - decode_register_name(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"name">>, <<>>, <<"jabber:iq:register">>} -> - decode_register_name(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"password">>, <<"jabber:iq:register">>, _} -> - decode_register_password(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"password">>, <<>>, <<"jabber:iq:register">>} -> - decode_register_password(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"nick">>, <<"jabber:iq:register">>, _} -> - decode_register_nick(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"nick">>, <<>>, <<"jabber:iq:register">>} -> - decode_register_nick(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"username">>, <<"jabber:iq:register">>, _} -> - decode_register_username(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"username">>, <<>>, <<"jabber:iq:register">>} -> - decode_register_username(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"instructions">>, <<"jabber:iq:register">>, _} -> - decode_register_instructions(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"instructions">>, <<>>, <<"jabber:iq:register">>} -> - decode_register_instructions(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"remove">>, <<"jabber:iq:register">>, _} -> - decode_register_remove(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"remove">>, <<>>, <<"jabber:iq:register">>} -> - decode_register_remove(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"registered">>, <<"jabber:iq:register">>, _} -> - decode_register_registered(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"registered">>, <<>>, <<"jabber:iq:register">>} -> - decode_register_registered(<<"jabber:iq:register">>, - IgnoreEls, _el); - {<<"register">>, - <<"http://jabber.org/features/iq-register">>, _} -> - decode_feature_register(<<"http://jabber.org/features/iq-register">>, - IgnoreEls, _el); - {<<"register">>, <<>>, - <<"http://jabber.org/features/iq-register">>} -> - decode_feature_register(<<"http://jabber.org/features/iq-register">>, - IgnoreEls, _el); - {<<"c">>, <<"http://jabber.org/protocol/caps">>, _} -> - decode_caps(<<"http://jabber.org/protocol/caps">>, - IgnoreEls, _el); - {<<"c">>, <<>>, - <<"http://jabber.org/protocol/caps">>} -> - decode_caps(<<"http://jabber.org/protocol/caps">>, - IgnoreEls, _el); - {<<"ack">>, <<"p1:ack">>, _} -> - decode_p1_ack(<<"p1:ack">>, IgnoreEls, _el); - {<<"ack">>, <<>>, <<"p1:ack">>} -> - decode_p1_ack(<<"p1:ack">>, IgnoreEls, _el); - {<<"rebind">>, <<"p1:rebind">>, _} -> - decode_p1_rebind(<<"p1:rebind">>, IgnoreEls, _el); - {<<"rebind">>, <<>>, <<"p1:rebind">>} -> - decode_p1_rebind(<<"p1:rebind">>, IgnoreEls, _el); - {<<"push">>, <<"p1:push">>, _} -> - decode_p1_push(<<"p1:push">>, IgnoreEls, _el); - {<<"push">>, <<>>, <<"p1:push">>} -> - decode_p1_push(<<"p1:push">>, IgnoreEls, _el); - {<<"stream:features">>, <<"jabber:client">>, _} -> - decode_stream_features(<<"jabber:client">>, IgnoreEls, - _el); - {<<"stream:features">>, <<>>, <<"jabber:client">>} -> - decode_stream_features(<<"jabber:client">>, IgnoreEls, - _el); - {<<"stream:features">>, <<"jabber:server">>, _} -> - decode_stream_features(<<"jabber:server">>, IgnoreEls, - _el); - {<<"stream:features">>, <<>>, <<"jabber:server">>} -> - decode_stream_features(<<"jabber:server">>, IgnoreEls, - _el); - {<<"compression">>, - <<"http://jabber.org/features/compress">>, _} -> - decode_compression(<<"http://jabber.org/features/compress">>, - IgnoreEls, _el); - {<<"compression">>, <<>>, - <<"http://jabber.org/features/compress">>} -> - decode_compression(<<"http://jabber.org/features/compress">>, - IgnoreEls, _el); - {<<"method">>, - <<"http://jabber.org/features/compress">>, _} -> - decode_compression_method(<<"http://jabber.org/features/compress">>, - IgnoreEls, _el); - {<<"method">>, <<>>, - <<"http://jabber.org/features/compress">>} -> - decode_compression_method(<<"http://jabber.org/features/compress">>, - IgnoreEls, _el); - {<<"compressed">>, - <<"http://jabber.org/protocol/compress">>, _} -> - decode_compressed(<<"http://jabber.org/protocol/compress">>, - IgnoreEls, _el); - {<<"compressed">>, <<>>, - <<"http://jabber.org/protocol/compress">>} -> - decode_compressed(<<"http://jabber.org/protocol/compress">>, - IgnoreEls, _el); - {<<"compress">>, - <<"http://jabber.org/protocol/compress">>, _} -> - decode_compress(<<"http://jabber.org/protocol/compress">>, - IgnoreEls, _el); - {<<"compress">>, <<>>, - <<"http://jabber.org/protocol/compress">>} -> - decode_compress(<<"http://jabber.org/protocol/compress">>, - IgnoreEls, _el); - {<<"method">>, - <<"http://jabber.org/protocol/compress">>, _} -> - decode_compress_method(<<"http://jabber.org/protocol/compress">>, - IgnoreEls, _el); - {<<"method">>, <<>>, - <<"http://jabber.org/protocol/compress">>} -> - decode_compress_method(<<"http://jabber.org/protocol/compress">>, - IgnoreEls, _el); - {<<"failure">>, - <<"http://jabber.org/protocol/compress">>, _} -> - decode_compress_failure(<<"http://jabber.org/protocol/compress">>, - IgnoreEls, _el); - {<<"failure">>, <<>>, - <<"http://jabber.org/protocol/compress">>} -> - decode_compress_failure(<<"http://jabber.org/protocol/compress">>, - IgnoreEls, _el); - {<<"unsupported-method">>, - <<"http://jabber.org/protocol/compress">>, _} -> - decode_compress_failure_unsupported_method(<<"http://jabber.org/protocol/compress">>, - IgnoreEls, _el); - {<<"unsupported-method">>, <<>>, - <<"http://jabber.org/protocol/compress">>} -> - decode_compress_failure_unsupported_method(<<"http://jabber.org/protocol/compress">>, - IgnoreEls, _el); - {<<"processing-failed">>, - <<"http://jabber.org/protocol/compress">>, _} -> - decode_compress_failure_processing_failed(<<"http://jabber.org/protocol/compress">>, - IgnoreEls, _el); - {<<"processing-failed">>, <<>>, - <<"http://jabber.org/protocol/compress">>} -> - decode_compress_failure_processing_failed(<<"http://jabber.org/protocol/compress">>, - IgnoreEls, _el); - {<<"setup-failed">>, - <<"http://jabber.org/protocol/compress">>, _} -> - decode_compress_failure_setup_failed(<<"http://jabber.org/protocol/compress">>, - IgnoreEls, _el); - {<<"setup-failed">>, <<>>, - <<"http://jabber.org/protocol/compress">>} -> - decode_compress_failure_setup_failed(<<"http://jabber.org/protocol/compress">>, - IgnoreEls, _el); - {<<"failure">>, <<"urn:ietf:params:xml:ns:xmpp-tls">>, - _} -> - decode_starttls_failure(<<"urn:ietf:params:xml:ns:xmpp-tls">>, - IgnoreEls, _el); - {<<"failure">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-tls">>} -> - decode_starttls_failure(<<"urn:ietf:params:xml:ns:xmpp-tls">>, - IgnoreEls, _el); - {<<"proceed">>, <<"urn:ietf:params:xml:ns:xmpp-tls">>, - _} -> - decode_starttls_proceed(<<"urn:ietf:params:xml:ns:xmpp-tls">>, - IgnoreEls, _el); - {<<"proceed">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-tls">>} -> - decode_starttls_proceed(<<"urn:ietf:params:xml:ns:xmpp-tls">>, - IgnoreEls, _el); - {<<"starttls">>, <<"urn:ietf:params:xml:ns:xmpp-tls">>, - _} -> - decode_starttls(<<"urn:ietf:params:xml:ns:xmpp-tls">>, - IgnoreEls, _el); - {<<"starttls">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-tls">>} -> - decode_starttls(<<"urn:ietf:params:xml:ns:xmpp-tls">>, - IgnoreEls, _el); - {<<"required">>, <<"urn:ietf:params:xml:ns:xmpp-tls">>, - _} -> - decode_starttls_required(<<"urn:ietf:params:xml:ns:xmpp-tls">>, - IgnoreEls, _el); - {<<"required">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-tls">>} -> - decode_starttls_required(<<"urn:ietf:params:xml:ns:xmpp-tls">>, - IgnoreEls, _el); - {<<"mechanisms">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - decode_sasl_mechanisms(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"mechanisms">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - decode_sasl_mechanisms(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"mechanism">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - decode_sasl_mechanism(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"mechanism">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - decode_sasl_mechanism(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"failure">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, - _} -> - decode_sasl_failure(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"failure">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - decode_sasl_failure(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"temporary-auth-failure">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - decode_sasl_failure_temporary_auth_failure(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"temporary-auth-failure">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - decode_sasl_failure_temporary_auth_failure(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"bad-protocol">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - decode_sasl_failure_bad_protocol(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"bad-protocol">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - decode_sasl_failure_bad_protocol(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"not-authorized">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - decode_sasl_failure_not_authorized(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"not-authorized">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - decode_sasl_failure_not_authorized(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"mechanism-too-weak">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - decode_sasl_failure_mechanism_too_weak(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"mechanism-too-weak">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - decode_sasl_failure_mechanism_too_weak(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"malformed-request">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - decode_sasl_failure_malformed_request(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"malformed-request">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - decode_sasl_failure_malformed_request(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"invalid-mechanism">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - decode_sasl_failure_invalid_mechanism(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"invalid-mechanism">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - decode_sasl_failure_invalid_mechanism(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"invalid-authzid">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - decode_sasl_failure_invalid_authzid(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"invalid-authzid">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - decode_sasl_failure_invalid_authzid(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"incorrect-encoding">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - decode_sasl_failure_incorrect_encoding(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"incorrect-encoding">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - decode_sasl_failure_incorrect_encoding(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"encryption-required">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - decode_sasl_failure_encryption_required(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"encryption-required">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - decode_sasl_failure_encryption_required(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"credentials-expired">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - decode_sasl_failure_credentials_expired(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"credentials-expired">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - decode_sasl_failure_credentials_expired(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"account-disabled">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - decode_sasl_failure_account_disabled(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"account-disabled">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - decode_sasl_failure_account_disabled(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"aborted">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, - _} -> - decode_sasl_failure_aborted(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"aborted">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - decode_sasl_failure_aborted(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"text">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, - _} -> - decode_sasl_failure_text(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"text">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - decode_sasl_failure_text(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"success">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, - _} -> - decode_sasl_success(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"success">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - decode_sasl_success(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"response">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, - _} -> - decode_sasl_response(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"response">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - decode_sasl_response(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"challenge">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - decode_sasl_challenge(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"challenge">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - decode_sasl_challenge(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"abort">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, - _} -> - decode_sasl_abort(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"abort">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - decode_sasl_abort(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"auth">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, - _} -> - decode_sasl_auth(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"auth">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - decode_sasl_auth(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - IgnoreEls, _el); - {<<"query">>, <<"jabber:iq:auth">>, _} -> - decode_legacy_auth(<<"jabber:iq:auth">>, IgnoreEls, - _el); - {<<"query">>, <<>>, <<"jabber:iq:auth">>} -> - decode_legacy_auth(<<"jabber:iq:auth">>, IgnoreEls, - _el); - {<<"resource">>, <<"jabber:iq:auth">>, _} -> - decode_legacy_auth_resource(<<"jabber:iq:auth">>, - IgnoreEls, _el); - {<<"resource">>, <<>>, <<"jabber:iq:auth">>} -> - decode_legacy_auth_resource(<<"jabber:iq:auth">>, - IgnoreEls, _el); - {<<"digest">>, <<"jabber:iq:auth">>, _} -> - decode_legacy_auth_digest(<<"jabber:iq:auth">>, - IgnoreEls, _el); - {<<"digest">>, <<>>, <<"jabber:iq:auth">>} -> - decode_legacy_auth_digest(<<"jabber:iq:auth">>, - IgnoreEls, _el); - {<<"password">>, <<"jabber:iq:auth">>, _} -> - decode_legacy_auth_password(<<"jabber:iq:auth">>, - IgnoreEls, _el); - {<<"password">>, <<>>, <<"jabber:iq:auth">>} -> - decode_legacy_auth_password(<<"jabber:iq:auth">>, - IgnoreEls, _el); - {<<"username">>, <<"jabber:iq:auth">>, _} -> - decode_legacy_auth_username(<<"jabber:iq:auth">>, - IgnoreEls, _el); - {<<"username">>, <<>>, <<"jabber:iq:auth">>} -> - decode_legacy_auth_username(<<"jabber:iq:auth">>, - IgnoreEls, _el); - {<<"bind">>, <<"urn:ietf:params:xml:ns:xmpp-bind">>, - _} -> - decode_bind(<<"urn:ietf:params:xml:ns:xmpp-bind">>, - IgnoreEls, _el); - {<<"bind">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-bind">>} -> - decode_bind(<<"urn:ietf:params:xml:ns:xmpp-bind">>, - IgnoreEls, _el); - {<<"resource">>, <<"urn:ietf:params:xml:ns:xmpp-bind">>, - _} -> - decode_bind_resource(<<"urn:ietf:params:xml:ns:xmpp-bind">>, - IgnoreEls, _el); - {<<"resource">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-bind">>} -> - decode_bind_resource(<<"urn:ietf:params:xml:ns:xmpp-bind">>, - IgnoreEls, _el); - {<<"jid">>, <<"urn:ietf:params:xml:ns:xmpp-bind">>, - _} -> - decode_bind_jid(<<"urn:ietf:params:xml:ns:xmpp-bind">>, - IgnoreEls, _el); - {<<"jid">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-bind">>} -> - decode_bind_jid(<<"urn:ietf:params:xml:ns:xmpp-bind">>, - IgnoreEls, _el); - {<<"error">>, <<"jabber:client">>, _} -> - decode_error(<<"jabber:client">>, IgnoreEls, _el); - {<<"error">>, <<>>, <<"jabber:client">>} -> - decode_error(<<"jabber:client">>, IgnoreEls, _el); - {<<"error">>, <<"jabber:server">>, _} -> - decode_error(<<"jabber:server">>, IgnoreEls, _el); - {<<"error">>, <<>>, <<"jabber:server">>} -> - decode_error(<<"jabber:server">>, IgnoreEls, _el); - {<<"error">>, <<"jabber:component:accept">>, _} -> - decode_error(<<"jabber:component:accept">>, IgnoreEls, - _el); - {<<"error">>, <<>>, <<"jabber:component:accept">>} -> - decode_error(<<"jabber:component:accept">>, IgnoreEls, - _el); - {<<"text">>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - _} -> - decode_error_text(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"text">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - decode_error_text(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"unexpected-request">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - decode_error_unexpected_request(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"unexpected-request">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - decode_error_unexpected_request(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"undefined-condition">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - decode_error_undefined_condition(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"undefined-condition">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - decode_error_undefined_condition(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"subscription-required">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - decode_error_subscription_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"subscription-required">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - decode_error_subscription_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"service-unavailable">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - decode_error_service_unavailable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"service-unavailable">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - decode_error_service_unavailable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"resource-constraint">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - decode_error_resource_constraint(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"resource-constraint">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - decode_error_resource_constraint(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"remote-server-timeout">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - decode_error_remote_server_timeout(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"remote-server-timeout">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - decode_error_remote_server_timeout(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"remote-server-not-found">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - decode_error_remote_server_not_found(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"remote-server-not-found">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - decode_error_remote_server_not_found(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"registration-required">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - decode_error_registration_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"registration-required">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - decode_error_registration_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"redirect">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - decode_error_redirect(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"redirect">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - decode_error_redirect(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"recipient-unavailable">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - decode_error_recipient_unavailable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"recipient-unavailable">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - decode_error_recipient_unavailable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"policy-violation">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - decode_error_policy_violation(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"policy-violation">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - decode_error_policy_violation(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"payment-required">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - decode_error_payment_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"payment-required">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - decode_error_payment_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"not-authorized">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - decode_error_not_authorized(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"not-authorized">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - decode_error_not_authorized(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"not-allowed">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - decode_error_not_allowed(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"not-allowed">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - decode_error_not_allowed(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"not-acceptable">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - decode_error_not_acceptable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"not-acceptable">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - decode_error_not_acceptable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"jid-malformed">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - decode_error_jid_malformed(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"jid-malformed">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - decode_error_jid_malformed(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"item-not-found">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - decode_error_item_not_found(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"item-not-found">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - decode_error_item_not_found(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"internal-server-error">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - decode_error_internal_server_error(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"internal-server-error">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - decode_error_internal_server_error(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"gone">>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - _} -> - decode_error_gone(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"gone">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - decode_error_gone(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"forbidden">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - decode_error_forbidden(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"forbidden">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - decode_error_forbidden(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"feature-not-implemented">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - decode_error_feature_not_implemented(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"feature-not-implemented">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - decode_error_feature_not_implemented(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"conflict">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - decode_error_conflict(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"conflict">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - decode_error_conflict(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"bad-request">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - decode_error_bad_request(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"bad-request">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - decode_error_bad_request(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - IgnoreEls, _el); - {<<"presence">>, <<"jabber:client">>, _} -> - decode_presence(<<"jabber:client">>, IgnoreEls, _el); - {<<"presence">>, <<>>, <<"jabber:client">>} -> - decode_presence(<<"jabber:client">>, IgnoreEls, _el); - {<<"presence">>, <<"jabber:server">>, _} -> - decode_presence(<<"jabber:server">>, IgnoreEls, _el); - {<<"presence">>, <<>>, <<"jabber:server">>} -> - decode_presence(<<"jabber:server">>, IgnoreEls, _el); - {<<"presence">>, <<"jabber:component:accept">>, _} -> - decode_presence(<<"jabber:component:accept">>, - IgnoreEls, _el); - {<<"presence">>, <<>>, <<"jabber:component:accept">>} -> - decode_presence(<<"jabber:component:accept">>, - IgnoreEls, _el); - {<<"priority">>, <<"jabber:client">>, _} -> - decode_presence_priority(<<"jabber:client">>, IgnoreEls, - _el); - {<<"priority">>, <<>>, <<"jabber:client">>} -> - decode_presence_priority(<<"jabber:client">>, IgnoreEls, - _el); - {<<"priority">>, <<"jabber:server">>, _} -> - decode_presence_priority(<<"jabber:server">>, IgnoreEls, - _el); - {<<"priority">>, <<>>, <<"jabber:server">>} -> - decode_presence_priority(<<"jabber:server">>, IgnoreEls, - _el); - {<<"priority">>, <<"jabber:component:accept">>, _} -> - decode_presence_priority(<<"jabber:component:accept">>, - IgnoreEls, _el); - {<<"priority">>, <<>>, <<"jabber:component:accept">>} -> - decode_presence_priority(<<"jabber:component:accept">>, - IgnoreEls, _el); - {<<"status">>, <<"jabber:client">>, _} -> - decode_presence_status(<<"jabber:client">>, IgnoreEls, - _el); - {<<"status">>, <<>>, <<"jabber:client">>} -> - decode_presence_status(<<"jabber:client">>, IgnoreEls, - _el); - {<<"status">>, <<"jabber:server">>, _} -> - decode_presence_status(<<"jabber:server">>, IgnoreEls, - _el); - {<<"status">>, <<>>, <<"jabber:server">>} -> - decode_presence_status(<<"jabber:server">>, IgnoreEls, - _el); - {<<"status">>, <<"jabber:component:accept">>, _} -> - decode_presence_status(<<"jabber:component:accept">>, - IgnoreEls, _el); - {<<"status">>, <<>>, <<"jabber:component:accept">>} -> - decode_presence_status(<<"jabber:component:accept">>, - IgnoreEls, _el); - {<<"show">>, <<"jabber:client">>, _} -> - decode_presence_show(<<"jabber:client">>, IgnoreEls, - _el); - {<<"show">>, <<>>, <<"jabber:client">>} -> - decode_presence_show(<<"jabber:client">>, IgnoreEls, - _el); - {<<"show">>, <<"jabber:server">>, _} -> - decode_presence_show(<<"jabber:server">>, IgnoreEls, - _el); - {<<"show">>, <<>>, <<"jabber:server">>} -> - decode_presence_show(<<"jabber:server">>, IgnoreEls, - _el); - {<<"show">>, <<"jabber:component:accept">>, _} -> - decode_presence_show(<<"jabber:component:accept">>, - IgnoreEls, _el); - {<<"show">>, <<>>, <<"jabber:component:accept">>} -> - decode_presence_show(<<"jabber:component:accept">>, - IgnoreEls, _el); - {<<"message">>, <<"jabber:client">>, _} -> - decode_message(<<"jabber:client">>, IgnoreEls, _el); - {<<"message">>, <<>>, <<"jabber:client">>} -> - decode_message(<<"jabber:client">>, IgnoreEls, _el); - {<<"message">>, <<"jabber:server">>, _} -> - decode_message(<<"jabber:server">>, IgnoreEls, _el); - {<<"message">>, <<>>, <<"jabber:server">>} -> - decode_message(<<"jabber:server">>, IgnoreEls, _el); - {<<"message">>, <<"jabber:component:accept">>, _} -> - decode_message(<<"jabber:component:accept">>, IgnoreEls, - _el); - {<<"message">>, <<>>, <<"jabber:component:accept">>} -> - decode_message(<<"jabber:component:accept">>, IgnoreEls, - _el); - {<<"thread">>, <<"jabber:client">>, _} -> - decode_message_thread(<<"jabber:client">>, IgnoreEls, - _el); - {<<"thread">>, <<>>, <<"jabber:client">>} -> - decode_message_thread(<<"jabber:client">>, IgnoreEls, - _el); - {<<"thread">>, <<"jabber:server">>, _} -> - decode_message_thread(<<"jabber:server">>, IgnoreEls, - _el); - {<<"thread">>, <<>>, <<"jabber:server">>} -> - decode_message_thread(<<"jabber:server">>, IgnoreEls, - _el); - {<<"thread">>, <<"jabber:component:accept">>, _} -> - decode_message_thread(<<"jabber:component:accept">>, - IgnoreEls, _el); - {<<"thread">>, <<>>, <<"jabber:component:accept">>} -> - decode_message_thread(<<"jabber:component:accept">>, - IgnoreEls, _el); - {<<"body">>, <<"jabber:client">>, _} -> - decode_message_body(<<"jabber:client">>, IgnoreEls, - _el); - {<<"body">>, <<>>, <<"jabber:client">>} -> - decode_message_body(<<"jabber:client">>, IgnoreEls, - _el); - {<<"body">>, <<"jabber:server">>, _} -> - decode_message_body(<<"jabber:server">>, IgnoreEls, - _el); - {<<"body">>, <<>>, <<"jabber:server">>} -> - decode_message_body(<<"jabber:server">>, IgnoreEls, - _el); - {<<"body">>, <<"jabber:component:accept">>, _} -> - decode_message_body(<<"jabber:component:accept">>, - IgnoreEls, _el); - {<<"body">>, <<>>, <<"jabber:component:accept">>} -> - decode_message_body(<<"jabber:component:accept">>, - IgnoreEls, _el); - {<<"subject">>, <<"jabber:client">>, _} -> - decode_message_subject(<<"jabber:client">>, IgnoreEls, - _el); - {<<"subject">>, <<>>, <<"jabber:client">>} -> - decode_message_subject(<<"jabber:client">>, IgnoreEls, - _el); - {<<"subject">>, <<"jabber:server">>, _} -> - decode_message_subject(<<"jabber:server">>, IgnoreEls, - _el); - {<<"subject">>, <<>>, <<"jabber:server">>} -> - decode_message_subject(<<"jabber:server">>, IgnoreEls, - _el); - {<<"subject">>, <<"jabber:component:accept">>, _} -> - decode_message_subject(<<"jabber:component:accept">>, - IgnoreEls, _el); - {<<"subject">>, <<>>, <<"jabber:component:accept">>} -> - decode_message_subject(<<"jabber:component:accept">>, - IgnoreEls, _el); - {<<"iq">>, <<"jabber:client">>, _} -> - decode_iq(<<"jabber:client">>, IgnoreEls, _el); - {<<"iq">>, <<>>, <<"jabber:client">>} -> - decode_iq(<<"jabber:client">>, IgnoreEls, _el); - {<<"iq">>, <<"jabber:server">>, _} -> - decode_iq(<<"jabber:server">>, IgnoreEls, _el); - {<<"iq">>, <<>>, <<"jabber:server">>} -> - decode_iq(<<"jabber:server">>, IgnoreEls, _el); - {<<"iq">>, <<"jabber:component:accept">>, _} -> - decode_iq(<<"jabber:component:accept">>, IgnoreEls, - _el); - {<<"iq">>, <<>>, <<"jabber:component:accept">>} -> - decode_iq(<<"jabber:component:accept">>, IgnoreEls, - _el); - {<<"query">>, <<"http://jabber.org/protocol/stats">>, - _} -> - decode_stats(<<"http://jabber.org/protocol/stats">>, - IgnoreEls, _el); - {<<"query">>, <<>>, - <<"http://jabber.org/protocol/stats">>} -> - decode_stats(<<"http://jabber.org/protocol/stats">>, - IgnoreEls, _el); - {<<"stat">>, <<"http://jabber.org/protocol/stats">>, - _} -> - decode_stat(<<"http://jabber.org/protocol/stats">>, - IgnoreEls, _el); - {<<"stat">>, <<>>, - <<"http://jabber.org/protocol/stats">>} -> - decode_stat(<<"http://jabber.org/protocol/stats">>, - IgnoreEls, _el); - {<<"error">>, <<"http://jabber.org/protocol/stats">>, - _} -> - decode_stat_error(<<"http://jabber.org/protocol/stats">>, - IgnoreEls, _el); - {<<"error">>, <<>>, - <<"http://jabber.org/protocol/stats">>} -> - decode_stat_error(<<"http://jabber.org/protocol/stats">>, - IgnoreEls, _el); - {<<"storage">>, <<"storage:bookmarks">>, _} -> - decode_bookmarks_storage(<<"storage:bookmarks">>, - IgnoreEls, _el); - {<<"storage">>, <<>>, <<"storage:bookmarks">>} -> - decode_bookmarks_storage(<<"storage:bookmarks">>, - IgnoreEls, _el); - {<<"url">>, <<"storage:bookmarks">>, _} -> - decode_bookmark_url(<<"storage:bookmarks">>, IgnoreEls, - _el); - {<<"url">>, <<>>, <<"storage:bookmarks">>} -> - decode_bookmark_url(<<"storage:bookmarks">>, IgnoreEls, - _el); - {<<"conference">>, <<"storage:bookmarks">>, _} -> - decode_bookmark_conference(<<"storage:bookmarks">>, - IgnoreEls, _el); - {<<"conference">>, <<>>, <<"storage:bookmarks">>} -> - decode_bookmark_conference(<<"storage:bookmarks">>, - IgnoreEls, _el); - {<<"password">>, <<"storage:bookmarks">>, _} -> - decode_conference_password(<<"storage:bookmarks">>, - IgnoreEls, _el); - {<<"password">>, <<>>, <<"storage:bookmarks">>} -> - decode_conference_password(<<"storage:bookmarks">>, - IgnoreEls, _el); - {<<"nick">>, <<"storage:bookmarks">>, _} -> - decode_conference_nick(<<"storage:bookmarks">>, - IgnoreEls, _el); - {<<"nick">>, <<>>, <<"storage:bookmarks">>} -> - decode_conference_nick(<<"storage:bookmarks">>, - IgnoreEls, _el); - {<<"query">>, <<"jabber:iq:private">>, _} -> - decode_private(<<"jabber:iq:private">>, IgnoreEls, _el); - {<<"query">>, <<>>, <<"jabber:iq:private">>} -> - decode_private(<<"jabber:iq:private">>, IgnoreEls, _el); - {<<"query">>, - <<"http://jabber.org/protocol/disco#items">>, _} -> - decode_disco_items(<<"http://jabber.org/protocol/disco#items">>, - IgnoreEls, _el); - {<<"query">>, <<>>, - <<"http://jabber.org/protocol/disco#items">>} -> - decode_disco_items(<<"http://jabber.org/protocol/disco#items">>, - IgnoreEls, _el); - {<<"item">>, - <<"http://jabber.org/protocol/disco#items">>, _} -> - decode_disco_item(<<"http://jabber.org/protocol/disco#items">>, - IgnoreEls, _el); - {<<"item">>, <<>>, - <<"http://jabber.org/protocol/disco#items">>} -> - decode_disco_item(<<"http://jabber.org/protocol/disco#items">>, - IgnoreEls, _el); - {<<"query">>, - <<"http://jabber.org/protocol/disco#info">>, _} -> - decode_disco_info(<<"http://jabber.org/protocol/disco#info">>, - IgnoreEls, _el); - {<<"query">>, <<>>, - <<"http://jabber.org/protocol/disco#info">>} -> - decode_disco_info(<<"http://jabber.org/protocol/disco#info">>, - IgnoreEls, _el); - {<<"feature">>, - <<"http://jabber.org/protocol/disco#info">>, _} -> - decode_disco_feature(<<"http://jabber.org/protocol/disco#info">>, - IgnoreEls, _el); - {<<"feature">>, <<>>, - <<"http://jabber.org/protocol/disco#info">>} -> - decode_disco_feature(<<"http://jabber.org/protocol/disco#info">>, - IgnoreEls, _el); - {<<"identity">>, - <<"http://jabber.org/protocol/disco#info">>, _} -> - decode_disco_identity(<<"http://jabber.org/protocol/disco#info">>, - IgnoreEls, _el); - {<<"identity">>, <<>>, - <<"http://jabber.org/protocol/disco#info">>} -> - decode_disco_identity(<<"http://jabber.org/protocol/disco#info">>, - IgnoreEls, _el); - {<<"blocklist">>, <<"urn:xmpp:blocking">>, _} -> - decode_block_list(<<"urn:xmpp:blocking">>, IgnoreEls, - _el); - {<<"blocklist">>, <<>>, <<"urn:xmpp:blocking">>} -> - decode_block_list(<<"urn:xmpp:blocking">>, IgnoreEls, - _el); - {<<"unblock">>, <<"urn:xmpp:blocking">>, _} -> - decode_unblock(<<"urn:xmpp:blocking">>, IgnoreEls, _el); - {<<"unblock">>, <<>>, <<"urn:xmpp:blocking">>} -> - decode_unblock(<<"urn:xmpp:blocking">>, IgnoreEls, _el); - {<<"block">>, <<"urn:xmpp:blocking">>, _} -> - decode_block(<<"urn:xmpp:blocking">>, IgnoreEls, _el); - {<<"block">>, <<>>, <<"urn:xmpp:blocking">>} -> - decode_block(<<"urn:xmpp:blocking">>, IgnoreEls, _el); - {<<"item">>, <<"urn:xmpp:blocking">>, _} -> - decode_block_item(<<"urn:xmpp:blocking">>, IgnoreEls, - _el); - {<<"item">>, <<>>, <<"urn:xmpp:blocking">>} -> - decode_block_item(<<"urn:xmpp:blocking">>, IgnoreEls, - _el); - {<<"query">>, <<"jabber:iq:privacy">>, _} -> - decode_privacy(<<"jabber:iq:privacy">>, IgnoreEls, _el); - {<<"query">>, <<>>, <<"jabber:iq:privacy">>} -> - decode_privacy(<<"jabber:iq:privacy">>, IgnoreEls, _el); - {<<"active">>, <<"jabber:iq:privacy">>, _} -> - decode_privacy_active_list(<<"jabber:iq:privacy">>, - IgnoreEls, _el); - {<<"active">>, <<>>, <<"jabber:iq:privacy">>} -> - decode_privacy_active_list(<<"jabber:iq:privacy">>, - IgnoreEls, _el); - {<<"default">>, <<"jabber:iq:privacy">>, _} -> - decode_privacy_default_list(<<"jabber:iq:privacy">>, - IgnoreEls, _el); - {<<"default">>, <<>>, <<"jabber:iq:privacy">>} -> - decode_privacy_default_list(<<"jabber:iq:privacy">>, - IgnoreEls, _el); - {<<"list">>, <<"jabber:iq:privacy">>, _} -> - decode_privacy_list(<<"jabber:iq:privacy">>, IgnoreEls, - _el); - {<<"list">>, <<>>, <<"jabber:iq:privacy">>} -> - decode_privacy_list(<<"jabber:iq:privacy">>, IgnoreEls, - _el); - {<<"item">>, <<"jabber:iq:privacy">>, _} -> - decode_privacy_item(<<"jabber:iq:privacy">>, IgnoreEls, - _el); - {<<"item">>, <<>>, <<"jabber:iq:privacy">>} -> - decode_privacy_item(<<"jabber:iq:privacy">>, IgnoreEls, - _el); - {<<"presence-out">>, <<"jabber:iq:privacy">>, _} -> - decode_privacy_presence_out(<<"jabber:iq:privacy">>, - IgnoreEls, _el); - {<<"presence-out">>, <<>>, <<"jabber:iq:privacy">>} -> - decode_privacy_presence_out(<<"jabber:iq:privacy">>, - IgnoreEls, _el); - {<<"presence-in">>, <<"jabber:iq:privacy">>, _} -> - decode_privacy_presence_in(<<"jabber:iq:privacy">>, - IgnoreEls, _el); - {<<"presence-in">>, <<>>, <<"jabber:iq:privacy">>} -> - decode_privacy_presence_in(<<"jabber:iq:privacy">>, - IgnoreEls, _el); - {<<"iq">>, <<"jabber:iq:privacy">>, _} -> - decode_privacy_iq(<<"jabber:iq:privacy">>, IgnoreEls, - _el); - {<<"iq">>, <<>>, <<"jabber:iq:privacy">>} -> - decode_privacy_iq(<<"jabber:iq:privacy">>, IgnoreEls, - _el); - {<<"message">>, <<"jabber:iq:privacy">>, _} -> - decode_privacy_message(<<"jabber:iq:privacy">>, - IgnoreEls, _el); - {<<"message">>, <<>>, <<"jabber:iq:privacy">>} -> - decode_privacy_message(<<"jabber:iq:privacy">>, - IgnoreEls, _el); - {<<"ver">>, <<"urn:xmpp:features:rosterver">>, _} -> - decode_rosterver_feature(<<"urn:xmpp:features:rosterver">>, - IgnoreEls, _el); - {<<"ver">>, <<>>, <<"urn:xmpp:features:rosterver">>} -> - decode_rosterver_feature(<<"urn:xmpp:features:rosterver">>, - IgnoreEls, _el); - {<<"query">>, <<"jabber:iq:roster">>, _} -> - decode_roster_query(<<"jabber:iq:roster">>, IgnoreEls, - _el); - {<<"query">>, <<>>, <<"jabber:iq:roster">>} -> - decode_roster_query(<<"jabber:iq:roster">>, IgnoreEls, - _el); - {<<"item">>, <<"jabber:iq:roster">>, _} -> - decode_roster_item(<<"jabber:iq:roster">>, IgnoreEls, - _el); - {<<"item">>, <<>>, <<"jabber:iq:roster">>} -> - decode_roster_item(<<"jabber:iq:roster">>, IgnoreEls, - _el); - {<<"group">>, <<"jabber:iq:roster">>, _} -> - decode_roster_group(<<"jabber:iq:roster">>, IgnoreEls, - _el); - {<<"group">>, <<>>, <<"jabber:iq:roster">>} -> - decode_roster_group(<<"jabber:iq:roster">>, IgnoreEls, - _el); - {<<"query">>, <<"jabber:iq:version">>, _} -> - decode_version(<<"jabber:iq:version">>, IgnoreEls, _el); - {<<"query">>, <<>>, <<"jabber:iq:version">>} -> - decode_version(<<"jabber:iq:version">>, IgnoreEls, _el); - {<<"os">>, <<"jabber:iq:version">>, _} -> - decode_version_os(<<"jabber:iq:version">>, IgnoreEls, - _el); - {<<"os">>, <<>>, <<"jabber:iq:version">>} -> - decode_version_os(<<"jabber:iq:version">>, IgnoreEls, - _el); - {<<"version">>, <<"jabber:iq:version">>, _} -> - decode_version_ver(<<"jabber:iq:version">>, IgnoreEls, - _el); - {<<"version">>, <<>>, <<"jabber:iq:version">>} -> - decode_version_ver(<<"jabber:iq:version">>, IgnoreEls, - _el); - {<<"name">>, <<"jabber:iq:version">>, _} -> - decode_version_name(<<"jabber:iq:version">>, IgnoreEls, - _el); - {<<"name">>, <<>>, <<"jabber:iq:version">>} -> - decode_version_name(<<"jabber:iq:version">>, IgnoreEls, - _el); - {<<"query">>, <<"jabber:iq:last">>, _} -> - decode_last(<<"jabber:iq:last">>, IgnoreEls, _el); - {<<"query">>, <<>>, <<"jabber:iq:last">>} -> - decode_last(<<"jabber:iq:last">>, IgnoreEls, _el); - {_name, <<>>, <<>>} -> - erlang:error({xmpp_codec, {missing_tag_xmlns, _name}}); - {_name, <<>>, _} -> - erlang:error({xmpp_codec, - {unknown_tag, _name, TopXMLNS}}); - {_name, _xmlns, _} -> - erlang:error({xmpp_codec, {unknown_tag, _name, _xmlns}}) - end. - -is_known_tag({xmlel, _name, _attrs, _} = _el, - TopXMLNS) -> - case {_name, get_attr(<<"xmlns">>, _attrs), TopXMLNS} of - {<<"query">>, <<"urn:xmpp:delegation:1">>, _} -> true; - {<<"query">>, <<>>, <<"urn:xmpp:delegation:1">>} -> - true; - {<<"delegate">>, <<"urn:xmpp:delegation:1">>, _} -> - true; - {<<"delegate">>, <<>>, <<"urn:xmpp:delegation:1">>} -> - true; - {<<"delegation">>, <<"urn:xmpp:delegation:1">>, _} -> - true; - {<<"delegation">>, <<>>, <<"urn:xmpp:delegation:1">>} -> - true; - {<<"delegated">>, <<"urn:xmpp:delegation:1">>, _} -> - true; - {<<"delegated">>, <<>>, <<"urn:xmpp:delegation:1">>} -> - true; - {<<"attribute">>, <<"urn:xmpp:delegation:1">>, _} -> - true; - {<<"attribute">>, <<>>, <<"urn:xmpp:delegation:1">>} -> - true; - {<<"privilege">>, <<"urn:xmpp:privilege:1">>, _} -> - true; - {<<"privilege">>, <<>>, <<"urn:xmpp:privilege:1">>} -> - true; - {<<"perm">>, <<"urn:xmpp:privilege:1">>, _} -> true; - {<<"perm">>, <<>>, <<"urn:xmpp:privilege:1">>} -> true; - {<<"thumbnail">>, <<"urn:xmpp:thumbs:1">>, _} -> true; - {<<"thumbnail">>, <<>>, <<"urn:xmpp:thumbs:1">>} -> - true; - {<<"slot">>, <<"urn:xmpp:http:upload">>, _} -> true; - {<<"slot">>, <<>>, <<"urn:xmpp:http:upload">>} -> true; - {<<"slot">>, <<"eu:siacs:conversations:http:upload">>, - _} -> - true; - {<<"slot">>, <<>>, - <<"eu:siacs:conversations:http:upload">>} -> - true; - {<<"put">>, <<"urn:xmpp:http:upload">>, _} -> true; - {<<"put">>, <<>>, <<"urn:xmpp:http:upload">>} -> true; - {<<"put">>, <<"eu:siacs:conversations:http:upload">>, - _} -> - true; - {<<"put">>, <<>>, - <<"eu:siacs:conversations:http:upload">>} -> - true; - {<<"get">>, <<"urn:xmpp:http:upload">>, _} -> true; - {<<"get">>, <<>>, <<"urn:xmpp:http:upload">>} -> true; - {<<"get">>, <<"eu:siacs:conversations:http:upload">>, - _} -> - true; - {<<"get">>, <<>>, - <<"eu:siacs:conversations:http:upload">>} -> - true; - {<<"request">>, <<"urn:xmpp:http:upload">>, _} -> true; - {<<"request">>, <<>>, <<"urn:xmpp:http:upload">>} -> - true; - {<<"request">>, - <<"eu:siacs:conversations:http:upload">>, _} -> - true; - {<<"request">>, <<>>, - <<"eu:siacs:conversations:http:upload">>} -> - true; - {<<"content-type">>, <<"urn:xmpp:http:upload">>, _} -> - true; - {<<"content-type">>, <<>>, - <<"urn:xmpp:http:upload">>} -> - true; - {<<"content-type">>, - <<"eu:siacs:conversations:http:upload">>, _} -> - true; - {<<"content-type">>, <<>>, - <<"eu:siacs:conversations:http:upload">>} -> - true; - {<<"size">>, <<"urn:xmpp:http:upload">>, _} -> true; - {<<"size">>, <<>>, <<"urn:xmpp:http:upload">>} -> true; - {<<"size">>, <<"eu:siacs:conversations:http:upload">>, - _} -> - true; - {<<"size">>, <<>>, - <<"eu:siacs:conversations:http:upload">>} -> - true; - {<<"filename">>, <<"urn:xmpp:http:upload">>, _} -> true; - {<<"filename">>, <<>>, <<"urn:xmpp:http:upload">>} -> - true; - {<<"filename">>, - <<"eu:siacs:conversations:http:upload">>, _} -> - true; - {<<"filename">>, <<>>, - <<"eu:siacs:conversations:http:upload">>} -> - true; - {<<"address">>, <<"urn:xmpp:sic:0">>, _} -> true; - {<<"address">>, <<>>, <<"urn:xmpp:sic:0">>} -> true; - {<<"address">>, <<"urn:xmpp:sic:1">>, _} -> true; - {<<"address">>, <<>>, <<"urn:xmpp:sic:1">>} -> true; - {<<"port">>, <<"urn:xmpp:sic:1">>, _} -> true; - {<<"port">>, <<>>, <<"urn:xmpp:sic:1">>} -> true; - {<<"ip">>, <<"urn:xmpp:sic:0">>, _} -> true; - {<<"ip">>, <<>>, <<"urn:xmpp:sic:0">>} -> true; - {<<"ip">>, <<"urn:xmpp:sic:1">>, _} -> true; - {<<"ip">>, <<>>, <<"urn:xmpp:sic:1">>} -> true; - {<<"x">>, <<"jabber:x:oob">>, _} -> true; - {<<"x">>, <<>>, <<"jabber:x:oob">>} -> true; - {<<"desc">>, <<"jabber:x:oob">>, _} -> true; - {<<"desc">>, <<>>, <<"jabber:x:oob">>} -> true; - {<<"url">>, <<"jabber:x:oob">>, _} -> true; - {<<"url">>, <<>>, <<"jabber:x:oob">>} -> true; - {<<"media">>, <<"urn:xmpp:media-element">>, _} -> true; - {<<"media">>, <<>>, <<"urn:xmpp:media-element">>} -> - true; - {<<"uri">>, <<"urn:xmpp:media-element">>, _} -> true; - {<<"uri">>, <<>>, <<"urn:xmpp:media-element">>} -> true; - {<<"captcha">>, <<"urn:xmpp:captcha">>, _} -> true; - {<<"captcha">>, <<>>, <<"urn:xmpp:captcha">>} -> true; - {<<"data">>, <<"urn:xmpp:bob">>, _} -> true; - {<<"data">>, <<>>, <<"urn:xmpp:bob">>} -> true; - {<<"stream:stream">>, <<"jabber:client">>, _} -> true; - {<<"stream:stream">>, <<>>, <<"jabber:client">>} -> - true; - {<<"stream:stream">>, <<"jabber:server">>, _} -> true; - {<<"stream:stream">>, <<>>, <<"jabber:server">>} -> - true; - {<<"stream:stream">>, <<"jabber:component:accept">>, - _} -> - true; - {<<"stream:stream">>, <<>>, - <<"jabber:component:accept">>} -> - true; - {<<"handshake">>, <<"jabber:component:accept">>, _} -> - true; - {<<"handshake">>, <<>>, - <<"jabber:component:accept">>} -> - true; - {<<"db:verify">>, <<"jabber:server">>, _} -> true; - {<<"db:verify">>, <<>>, <<"jabber:server">>} -> true; - {<<"db:result">>, <<"jabber:server">>, _} -> true; - {<<"db:result">>, <<>>, <<"jabber:server">>} -> true; - {<<"command">>, - <<"http://jabber.org/protocol/commands">>, _} -> - true; - {<<"command">>, <<>>, - <<"http://jabber.org/protocol/commands">>} -> - true; - {<<"note">>, <<"http://jabber.org/protocol/commands">>, - _} -> - true; - {<<"note">>, <<>>, - <<"http://jabber.org/protocol/commands">>} -> - true; - {<<"actions">>, - <<"http://jabber.org/protocol/commands">>, _} -> - true; - {<<"actions">>, <<>>, - <<"http://jabber.org/protocol/commands">>} -> - true; - {<<"complete">>, - <<"http://jabber.org/protocol/commands">>, _} -> - true; - {<<"complete">>, <<>>, - <<"http://jabber.org/protocol/commands">>} -> - true; - {<<"next">>, <<"http://jabber.org/protocol/commands">>, - _} -> - true; - {<<"next">>, <<>>, - <<"http://jabber.org/protocol/commands">>} -> - true; - {<<"prev">>, <<"http://jabber.org/protocol/commands">>, - _} -> - true; - {<<"prev">>, <<>>, - <<"http://jabber.org/protocol/commands">>} -> - true; - {<<"client-id">>, <<"urn:xmpp:sid:0">>, _} -> true; - {<<"client-id">>, <<>>, <<"urn:xmpp:sid:0">>} -> true; - {<<"stanza-id">>, <<"urn:xmpp:sid:0">>, _} -> true; - {<<"stanza-id">>, <<>>, <<"urn:xmpp:sid:0">>} -> true; - {<<"addresses">>, - <<"http://jabber.org/protocol/address">>, _} -> - true; - {<<"addresses">>, <<>>, - <<"http://jabber.org/protocol/address">>} -> - true; - {<<"address">>, - <<"http://jabber.org/protocol/address">>, _} -> - true; - {<<"address">>, <<>>, - <<"http://jabber.org/protocol/address">>} -> - true; - {<<"nick">>, <<"http://jabber.org/protocol/nick">>, - _} -> - true; - {<<"nick">>, <<>>, - <<"http://jabber.org/protocol/nick">>} -> - true; - {<<"x">>, <<"jabber:x:expire">>, _} -> true; - {<<"x">>, <<>>, <<"jabber:x:expire">>} -> true; - {<<"x">>, <<"jabber:x:event">>, _} -> true; - {<<"x">>, <<>>, <<"jabber:x:event">>} -> true; - {<<"id">>, <<"jabber:x:event">>, _} -> true; - {<<"id">>, <<>>, <<"jabber:x:event">>} -> true; - {<<"composing">>, <<"jabber:x:event">>, _} -> true; - {<<"composing">>, <<>>, <<"jabber:x:event">>} -> true; - {<<"displayed">>, <<"jabber:x:event">>, _} -> true; - {<<"displayed">>, <<>>, <<"jabber:x:event">>} -> true; - {<<"delivered">>, <<"jabber:x:event">>, _} -> true; - {<<"delivered">>, <<>>, <<"jabber:x:event">>} -> true; - {<<"offline">>, <<"jabber:x:event">>, _} -> true; - {<<"offline">>, <<>>, <<"jabber:x:event">>} -> true; - {<<"query">>, <<"jabber:iq:search">>, _} -> true; - {<<"query">>, <<>>, <<"jabber:iq:search">>} -> true; - {<<"item">>, <<"jabber:iq:search">>, _} -> true; - {<<"item">>, <<>>, <<"jabber:iq:search">>} -> true; - {<<"email">>, <<"jabber:iq:search">>, _} -> true; - {<<"email">>, <<>>, <<"jabber:iq:search">>} -> true; - {<<"nick">>, <<"jabber:iq:search">>, _} -> true; - {<<"nick">>, <<>>, <<"jabber:iq:search">>} -> true; - {<<"last">>, <<"jabber:iq:search">>, _} -> true; - {<<"last">>, <<>>, <<"jabber:iq:search">>} -> true; - {<<"first">>, <<"jabber:iq:search">>, _} -> true; - {<<"first">>, <<>>, <<"jabber:iq:search">>} -> true; - {<<"instructions">>, <<"jabber:iq:search">>, _} -> true; - {<<"instructions">>, <<>>, <<"jabber:iq:search">>} -> - true; - {<<"no-permanent-storage">>, <<"urn:xmpp:hints">>, _} -> - true; - {<<"no-permanent-storage">>, <<>>, - <<"urn:xmpp:hints">>} -> - true; - {<<"no-permanent-store">>, <<"urn:xmpp:hints">>, _} -> - true; - {<<"no-permanent-store">>, <<>>, - <<"urn:xmpp:hints">>} -> - true; - {<<"store">>, <<"urn:xmpp:hints">>, _} -> true; - {<<"store">>, <<>>, <<"urn:xmpp:hints">>} -> true; - {<<"no-storage">>, <<"urn:xmpp:hints">>, _} -> true; - {<<"no-storage">>, <<>>, <<"urn:xmpp:hints">>} -> true; - {<<"no-store">>, <<"urn:xmpp:hints">>, _} -> true; - {<<"no-store">>, <<>>, <<"urn:xmpp:hints">>} -> true; - {<<"no-copy">>, <<"urn:xmpp:hints">>, _} -> true; - {<<"no-copy">>, <<>>, <<"urn:xmpp:hints">>} -> true; - {<<"participant">>, <<"urn:xmpp:mix:0">>, _} -> true; - {<<"participant">>, <<>>, <<"urn:xmpp:mix:0">>} -> true; - {<<"leave">>, <<"urn:xmpp:mix:0">>, _} -> true; - {<<"leave">>, <<>>, <<"urn:xmpp:mix:0">>} -> true; - {<<"join">>, <<"urn:xmpp:mix:0">>, _} -> true; - {<<"join">>, <<>>, <<"urn:xmpp:mix:0">>} -> true; - {<<"subscribe">>, <<"urn:xmpp:mix:0">>, _} -> true; - {<<"subscribe">>, <<>>, <<"urn:xmpp:mix:0">>} -> true; - {<<"offline">>, - <<"http://jabber.org/protocol/offline">>, _} -> - true; - {<<"offline">>, <<>>, - <<"http://jabber.org/protocol/offline">>} -> - true; - {<<"item">>, <<"http://jabber.org/protocol/offline">>, - _} -> - true; - {<<"item">>, <<>>, - <<"http://jabber.org/protocol/offline">>} -> - true; - {<<"fetch">>, <<"http://jabber.org/protocol/offline">>, - _} -> - true; - {<<"fetch">>, <<>>, - <<"http://jabber.org/protocol/offline">>} -> - true; - {<<"purge">>, <<"http://jabber.org/protocol/offline">>, - _} -> - true; - {<<"purge">>, <<>>, - <<"http://jabber.org/protocol/offline">>} -> - true; - {<<"failed">>, <<"urn:xmpp:sm:2">>, _} -> true; - {<<"failed">>, <<>>, <<"urn:xmpp:sm:2">>} -> true; - {<<"failed">>, <<"urn:xmpp:sm:3">>, _} -> true; - {<<"failed">>, <<>>, <<"urn:xmpp:sm:3">>} -> true; - {<<"a">>, <<"urn:xmpp:sm:2">>, _} -> true; - {<<"a">>, <<>>, <<"urn:xmpp:sm:2">>} -> true; - {<<"a">>, <<"urn:xmpp:sm:3">>, _} -> true; - {<<"a">>, <<>>, <<"urn:xmpp:sm:3">>} -> true; - {<<"r">>, <<"urn:xmpp:sm:2">>, _} -> true; - {<<"r">>, <<>>, <<"urn:xmpp:sm:2">>} -> true; - {<<"r">>, <<"urn:xmpp:sm:3">>, _} -> true; - {<<"r">>, <<>>, <<"urn:xmpp:sm:3">>} -> true; - {<<"resumed">>, <<"urn:xmpp:sm:2">>, _} -> true; - {<<"resumed">>, <<>>, <<"urn:xmpp:sm:2">>} -> true; - {<<"resumed">>, <<"urn:xmpp:sm:3">>, _} -> true; - {<<"resumed">>, <<>>, <<"urn:xmpp:sm:3">>} -> true; - {<<"resume">>, <<"urn:xmpp:sm:2">>, _} -> true; - {<<"resume">>, <<>>, <<"urn:xmpp:sm:2">>} -> true; - {<<"resume">>, <<"urn:xmpp:sm:3">>, _} -> true; - {<<"resume">>, <<>>, <<"urn:xmpp:sm:3">>} -> true; - {<<"enabled">>, <<"urn:xmpp:sm:2">>, _} -> true; - {<<"enabled">>, <<>>, <<"urn:xmpp:sm:2">>} -> true; - {<<"enabled">>, <<"urn:xmpp:sm:3">>, _} -> true; - {<<"enabled">>, <<>>, <<"urn:xmpp:sm:3">>} -> true; - {<<"enable">>, <<"urn:xmpp:sm:2">>, _} -> true; - {<<"enable">>, <<>>, <<"urn:xmpp:sm:2">>} -> true; - {<<"enable">>, <<"urn:xmpp:sm:3">>, _} -> true; - {<<"enable">>, <<>>, <<"urn:xmpp:sm:3">>} -> true; - {<<"sm">>, <<"urn:xmpp:sm:2">>, _} -> true; - {<<"sm">>, <<>>, <<"urn:xmpp:sm:2">>} -> true; - {<<"sm">>, <<"urn:xmpp:sm:3">>, _} -> true; - {<<"sm">>, <<>>, <<"urn:xmpp:sm:3">>} -> true; - {<<"inactive">>, <<"urn:xmpp:csi:0">>, _} -> true; - {<<"inactive">>, <<>>, <<"urn:xmpp:csi:0">>} -> true; - {<<"active">>, <<"urn:xmpp:csi:0">>, _} -> true; - {<<"active">>, <<>>, <<"urn:xmpp:csi:0">>} -> true; - {<<"csi">>, <<"urn:xmpp:csi:0">>, _} -> true; - {<<"csi">>, <<>>, <<"urn:xmpp:csi:0">>} -> true; - {<<"sent">>, <<"urn:xmpp:carbons:2">>, _} -> true; - {<<"sent">>, <<>>, <<"urn:xmpp:carbons:2">>} -> true; - {<<"received">>, <<"urn:xmpp:carbons:2">>, _} -> true; - {<<"received">>, <<>>, <<"urn:xmpp:carbons:2">>} -> - true; - {<<"private">>, <<"urn:xmpp:carbons:2">>, _} -> true; - {<<"private">>, <<>>, <<"urn:xmpp:carbons:2">>} -> true; - {<<"enable">>, <<"urn:xmpp:carbons:2">>, _} -> true; - {<<"enable">>, <<>>, <<"urn:xmpp:carbons:2">>} -> true; - {<<"disable">>, <<"urn:xmpp:carbons:2">>, _} -> true; - {<<"disable">>, <<>>, <<"urn:xmpp:carbons:2">>} -> true; - {<<"forwarded">>, <<"urn:xmpp:forward:0">>, _} -> true; - {<<"forwarded">>, <<>>, <<"urn:xmpp:forward:0">>} -> - true; - {<<"fin">>, <<"urn:xmpp:mam:0">>, _} -> true; - {<<"fin">>, <<>>, <<"urn:xmpp:mam:0">>} -> true; - {<<"fin">>, <<"urn:xmpp:mam:1">>, _} -> true; - {<<"fin">>, <<>>, <<"urn:xmpp:mam:1">>} -> true; - {<<"prefs">>, <<"urn:xmpp:mam:0">>, _} -> true; - {<<"prefs">>, <<>>, <<"urn:xmpp:mam:0">>} -> true; - {<<"prefs">>, <<"urn:xmpp:mam:1">>, _} -> true; - {<<"prefs">>, <<>>, <<"urn:xmpp:mam:1">>} -> true; - {<<"prefs">>, <<"urn:xmpp:mam:tmp">>, _} -> true; - {<<"prefs">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> true; - {<<"always">>, <<"urn:xmpp:mam:0">>, _} -> true; - {<<"always">>, <<>>, <<"urn:xmpp:mam:0">>} -> true; - {<<"always">>, <<"urn:xmpp:mam:1">>, _} -> true; - {<<"always">>, <<>>, <<"urn:xmpp:mam:1">>} -> true; - {<<"always">>, <<"urn:xmpp:mam:tmp">>, _} -> true; - {<<"always">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> true; - {<<"never">>, <<"urn:xmpp:mam:0">>, _} -> true; - {<<"never">>, <<>>, <<"urn:xmpp:mam:0">>} -> true; - {<<"never">>, <<"urn:xmpp:mam:1">>, _} -> true; - {<<"never">>, <<>>, <<"urn:xmpp:mam:1">>} -> true; - {<<"never">>, <<"urn:xmpp:mam:tmp">>, _} -> true; - {<<"never">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> true; - {<<"jid">>, <<"urn:xmpp:mam:0">>, _} -> true; - {<<"jid">>, <<>>, <<"urn:xmpp:mam:0">>} -> true; - {<<"jid">>, <<"urn:xmpp:mam:1">>, _} -> true; - {<<"jid">>, <<>>, <<"urn:xmpp:mam:1">>} -> true; - {<<"jid">>, <<"urn:xmpp:mam:tmp">>, _} -> true; - {<<"jid">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> true; - {<<"result">>, <<"urn:xmpp:mam:0">>, _} -> true; - {<<"result">>, <<>>, <<"urn:xmpp:mam:0">>} -> true; - {<<"result">>, <<"urn:xmpp:mam:1">>, _} -> true; - {<<"result">>, <<>>, <<"urn:xmpp:mam:1">>} -> true; - {<<"result">>, <<"urn:xmpp:mam:tmp">>, _} -> true; - {<<"result">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> true; - {<<"archived">>, <<"urn:xmpp:mam:tmp">>, _} -> true; - {<<"archived">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> true; - {<<"query">>, <<"urn:xmpp:mam:0">>, _} -> true; - {<<"query">>, <<>>, <<"urn:xmpp:mam:0">>} -> true; - {<<"query">>, <<"urn:xmpp:mam:1">>, _} -> true; - {<<"query">>, <<>>, <<"urn:xmpp:mam:1">>} -> true; - {<<"query">>, <<"urn:xmpp:mam:tmp">>, _} -> true; - {<<"query">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> true; - {<<"withtext">>, <<"urn:xmpp:mam:tmp">>, _} -> true; - {<<"withtext">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> true; - {<<"with">>, <<"urn:xmpp:mam:tmp">>, _} -> true; - {<<"with">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> true; - {<<"end">>, <<"urn:xmpp:mam:tmp">>, _} -> true; - {<<"end">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> true; - {<<"start">>, <<"urn:xmpp:mam:tmp">>, _} -> true; - {<<"start">>, <<>>, <<"urn:xmpp:mam:tmp">>} -> true; - {<<"set">>, <<"http://jabber.org/protocol/rsm">>, _} -> - true; - {<<"set">>, <<>>, - <<"http://jabber.org/protocol/rsm">>} -> - true; - {<<"first">>, <<"http://jabber.org/protocol/rsm">>, - _} -> - true; - {<<"first">>, <<>>, - <<"http://jabber.org/protocol/rsm">>} -> - true; - {<<"max">>, <<"http://jabber.org/protocol/rsm">>, _} -> - true; - {<<"max">>, <<>>, - <<"http://jabber.org/protocol/rsm">>} -> - true; - {<<"index">>, <<"http://jabber.org/protocol/rsm">>, - _} -> - true; - {<<"index">>, <<>>, - <<"http://jabber.org/protocol/rsm">>} -> - true; - {<<"count">>, <<"http://jabber.org/protocol/rsm">>, - _} -> - true; - {<<"count">>, <<>>, - <<"http://jabber.org/protocol/rsm">>} -> - true; - {<<"last">>, <<"http://jabber.org/protocol/rsm">>, _} -> - true; - {<<"last">>, <<>>, - <<"http://jabber.org/protocol/rsm">>} -> - true; - {<<"before">>, <<"http://jabber.org/protocol/rsm">>, - _} -> - true; - {<<"before">>, <<>>, - <<"http://jabber.org/protocol/rsm">>} -> - true; - {<<"after">>, <<"http://jabber.org/protocol/rsm">>, - _} -> - true; - {<<"after">>, <<>>, - <<"http://jabber.org/protocol/rsm">>} -> - true; - {<<"unsubscribe">>, <<"urn:xmpp:mucsub:0">>, _} -> true; - {<<"unsubscribe">>, <<>>, <<"urn:xmpp:mucsub:0">>} -> - true; - {<<"subscribe">>, <<"urn:xmpp:mucsub:0">>, _} -> true; - {<<"subscribe">>, <<>>, <<"urn:xmpp:mucsub:0">>} -> - true; - {<<"event">>, <<"urn:xmpp:mucsub:0">>, _} -> true; - {<<"event">>, <<>>, <<"urn:xmpp:mucsub:0">>} -> true; - {<<"subscriptions">>, <<"urn:xmpp:mucsub:0">>, _} -> - true; - {<<"subscriptions">>, <<>>, <<"urn:xmpp:mucsub:0">>} -> - true; - {<<"subscription">>, <<"urn:xmpp:mucsub:0">>, _} -> - true; - {<<"subscription">>, <<>>, <<"urn:xmpp:mucsub:0">>} -> - true; - {<<"x">>, <<"jabber:x:conference">>, _} -> true; - {<<"x">>, <<>>, <<"jabber:x:conference">>} -> true; - {<<"unique">>, - <<"http://jabber.org/protocol/muc#unique">>, _} -> - true; - {<<"unique">>, <<>>, - <<"http://jabber.org/protocol/muc#unique">>} -> - true; - {<<"x">>, <<"http://jabber.org/protocol/muc">>, _} -> - true; - {<<"x">>, <<>>, <<"http://jabber.org/protocol/muc">>} -> - true; - {<<"query">>, - <<"http://jabber.org/protocol/muc#admin">>, _} -> - true; - {<<"query">>, <<>>, - <<"http://jabber.org/protocol/muc#admin">>} -> - true; - {<<"continue">>, - <<"http://jabber.org/protocol/muc#admin">>, _} -> - true; - {<<"continue">>, <<>>, - <<"http://jabber.org/protocol/muc#admin">>} -> - true; - {<<"actor">>, - <<"http://jabber.org/protocol/muc#admin">>, _} -> - true; - {<<"actor">>, <<>>, - <<"http://jabber.org/protocol/muc#admin">>} -> - true; - {<<"item">>, <<"http://jabber.org/protocol/muc#admin">>, - _} -> - true; - {<<"item">>, <<>>, - <<"http://jabber.org/protocol/muc#admin">>} -> - true; - {<<"item">>, <<"http://jabber.org/protocol/muc#owner">>, - _} -> - true; - {<<"item">>, <<>>, - <<"http://jabber.org/protocol/muc#owner">>} -> - true; - {<<"query">>, - <<"http://jabber.org/protocol/muc#owner">>, _} -> - true; - {<<"query">>, <<>>, - <<"http://jabber.org/protocol/muc#owner">>} -> - true; - {<<"password">>, - <<"http://jabber.org/protocol/muc#owner">>, _} -> - true; - {<<"password">>, <<>>, - <<"http://jabber.org/protocol/muc#owner">>} -> - true; - {<<"password">>, - <<"http://jabber.org/protocol/muc#user">>, _} -> - true; - {<<"password">>, <<>>, - <<"http://jabber.org/protocol/muc#user">>} -> - true; - {<<"password">>, <<"http://jabber.org/protocol/muc">>, - _} -> - true; - {<<"password">>, <<>>, - <<"http://jabber.org/protocol/muc">>} -> - true; - {<<"x">>, <<"http://jabber.org/protocol/muc#user">>, - _} -> - true; - {<<"x">>, <<>>, - <<"http://jabber.org/protocol/muc#user">>} -> - true; - {<<"item">>, <<"http://jabber.org/protocol/muc#user">>, - _} -> - true; - {<<"item">>, <<>>, - <<"http://jabber.org/protocol/muc#user">>} -> - true; - {<<"status">>, - <<"http://jabber.org/protocol/muc#user">>, _} -> - true; - {<<"status">>, <<>>, - <<"http://jabber.org/protocol/muc#user">>} -> - true; - {<<"continue">>, - <<"http://jabber.org/protocol/muc#user">>, _} -> - true; - {<<"continue">>, <<>>, - <<"http://jabber.org/protocol/muc#user">>} -> - true; - {<<"actor">>, <<"http://jabber.org/protocol/muc#user">>, - _} -> - true; - {<<"actor">>, <<>>, - <<"http://jabber.org/protocol/muc#user">>} -> - true; - {<<"invite">>, - <<"http://jabber.org/protocol/muc#user">>, _} -> - true; - {<<"invite">>, <<>>, - <<"http://jabber.org/protocol/muc#user">>} -> - true; - {<<"destroy">>, - <<"http://jabber.org/protocol/muc#user">>, _} -> - true; - {<<"destroy">>, <<>>, - <<"http://jabber.org/protocol/muc#user">>} -> - true; - {<<"destroy">>, - <<"http://jabber.org/protocol/muc#owner">>, _} -> - true; - {<<"destroy">>, <<>>, - <<"http://jabber.org/protocol/muc#owner">>} -> - true; - {<<"decline">>, - <<"http://jabber.org/protocol/muc#user">>, _} -> - true; - {<<"decline">>, <<>>, - <<"http://jabber.org/protocol/muc#user">>} -> - true; - {<<"reason">>, - <<"http://jabber.org/protocol/muc#user">>, _} -> - true; - {<<"reason">>, <<>>, - <<"http://jabber.org/protocol/muc#user">>} -> - true; - {<<"reason">>, - <<"http://jabber.org/protocol/muc#admin">>, _} -> - true; - {<<"reason">>, <<>>, - <<"http://jabber.org/protocol/muc#admin">>} -> - true; - {<<"reason">>, - <<"http://jabber.org/protocol/muc#owner">>, _} -> - true; - {<<"reason">>, <<>>, - <<"http://jabber.org/protocol/muc#owner">>} -> - true; - {<<"history">>, <<"http://jabber.org/protocol/muc">>, - _} -> - true; - {<<"history">>, <<>>, - <<"http://jabber.org/protocol/muc">>} -> - true; - {<<"query">>, - <<"http://jabber.org/protocol/bytestreams">>, _} -> - true; - {<<"query">>, <<>>, - <<"http://jabber.org/protocol/bytestreams">>} -> - true; - {<<"activate">>, - <<"http://jabber.org/protocol/bytestreams">>, _} -> - true; - {<<"activate">>, <<>>, - <<"http://jabber.org/protocol/bytestreams">>} -> - true; - {<<"streamhost-used">>, - <<"http://jabber.org/protocol/bytestreams">>, _} -> - true; - {<<"streamhost-used">>, <<>>, - <<"http://jabber.org/protocol/bytestreams">>} -> - true; - {<<"streamhost">>, - <<"http://jabber.org/protocol/bytestreams">>, _} -> - true; - {<<"streamhost">>, <<>>, - <<"http://jabber.org/protocol/bytestreams">>} -> - true; - {<<"delay">>, <<"urn:xmpp:delay">>, _} -> true; - {<<"delay">>, <<>>, <<"urn:xmpp:delay">>} -> true; - {<<"paused">>, - <<"http://jabber.org/protocol/chatstates">>, _} -> - true; - {<<"paused">>, <<>>, - <<"http://jabber.org/protocol/chatstates">>} -> - true; - {<<"inactive">>, - <<"http://jabber.org/protocol/chatstates">>, _} -> - true; - {<<"inactive">>, <<>>, - <<"http://jabber.org/protocol/chatstates">>} -> - true; - {<<"gone">>, - <<"http://jabber.org/protocol/chatstates">>, _} -> - true; - {<<"gone">>, <<>>, - <<"http://jabber.org/protocol/chatstates">>} -> - true; - {<<"composing">>, - <<"http://jabber.org/protocol/chatstates">>, _} -> - true; - {<<"composing">>, <<>>, - <<"http://jabber.org/protocol/chatstates">>} -> - true; - {<<"active">>, - <<"http://jabber.org/protocol/chatstates">>, _} -> - true; - {<<"active">>, <<>>, - <<"http://jabber.org/protocol/chatstates">>} -> - true; - {<<"headers">>, <<"http://jabber.org/protocol/shim">>, - _} -> - true; - {<<"headers">>, <<>>, - <<"http://jabber.org/protocol/shim">>} -> - true; - {<<"header">>, <<"http://jabber.org/protocol/shim">>, - _} -> - true; - {<<"header">>, <<>>, - <<"http://jabber.org/protocol/shim">>} -> - true; - {<<"unsupported-access-model">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - true; - {<<"unsupported-access-model">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - true; - {<<"unsupported">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - true; - {<<"unsupported">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - true; - {<<"too-many-subscriptions">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - true; - {<<"too-many-subscriptions">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - true; - {<<"subid-required">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - true; - {<<"subid-required">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - true; - {<<"presence-subscription-required">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - true; - {<<"presence-subscription-required">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - true; - {<<"pending-subscription">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - true; - {<<"pending-subscription">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - true; - {<<"payload-required">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - true; - {<<"payload-required">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - true; - {<<"payload-too-big">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - true; - {<<"payload-too-big">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - true; - {<<"not-subscribed">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - true; - {<<"not-subscribed">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - true; - {<<"not-in-roster-group">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - true; - {<<"not-in-roster-group">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - true; - {<<"nodeid-required">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - true; - {<<"nodeid-required">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - true; - {<<"max-nodes-exceeded">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - true; - {<<"max-nodes-exceeded">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - true; - {<<"max-items-exceeded">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - true; - {<<"max-items-exceeded">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - true; - {<<"jid-required">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - true; - {<<"jid-required">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - true; - {<<"item-required">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - true; - {<<"item-required">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - true; - {<<"item-forbidden">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - true; - {<<"item-forbidden">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - true; - {<<"invalid-subid">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - true; - {<<"invalid-subid">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - true; - {<<"invalid-payload">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - true; - {<<"invalid-payload">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - true; - {<<"invalid-options">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - true; - {<<"invalid-options">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - true; - {<<"invalid-jid">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - true; - {<<"invalid-jid">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - true; - {<<"configuration-required">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - true; - {<<"configuration-required">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - true; - {<<"closed-node">>, - <<"http://jabber.org/protocol/pubsub#errors">>, _} -> - true; - {<<"closed-node">>, <<>>, - <<"http://jabber.org/protocol/pubsub#errors">>} -> - true; - {<<"pubsub">>, - <<"http://jabber.org/protocol/pubsub#owner">>, _} -> - true; - {<<"pubsub">>, <<>>, - <<"http://jabber.org/protocol/pubsub#owner">>} -> - true; - {<<"pubsub">>, <<"http://jabber.org/protocol/pubsub">>, - _} -> - true; - {<<"pubsub">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - true; - {<<"purge">>, <<"http://jabber.org/protocol/pubsub">>, - _} -> - true; - {<<"purge">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - true; - {<<"purge">>, - <<"http://jabber.org/protocol/pubsub#owner">>, _} -> - true; - {<<"purge">>, <<>>, - <<"http://jabber.org/protocol/pubsub#owner">>} -> - true; - {<<"purge">>, - <<"http://jabber.org/protocol/pubsub#event">>, _} -> - true; - {<<"purge">>, <<>>, - <<"http://jabber.org/protocol/pubsub#event">>} -> - true; - {<<"delete">>, <<"http://jabber.org/protocol/pubsub">>, - _} -> - true; - {<<"delete">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - true; - {<<"delete">>, - <<"http://jabber.org/protocol/pubsub#owner">>, _} -> - true; - {<<"delete">>, <<>>, - <<"http://jabber.org/protocol/pubsub#owner">>} -> - true; - {<<"delete">>, - <<"http://jabber.org/protocol/pubsub#event">>, _} -> - true; - {<<"delete">>, <<>>, - <<"http://jabber.org/protocol/pubsub#event">>} -> - true; - {<<"redirect">>, - <<"http://jabber.org/protocol/pubsub">>, _} -> - true; - {<<"redirect">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - true; - {<<"redirect">>, - <<"http://jabber.org/protocol/pubsub#owner">>, _} -> - true; - {<<"redirect">>, <<>>, - <<"http://jabber.org/protocol/pubsub#owner">>} -> - true; - {<<"redirect">>, - <<"http://jabber.org/protocol/pubsub#event">>, _} -> - true; - {<<"redirect">>, <<>>, - <<"http://jabber.org/protocol/pubsub#event">>} -> - true; - {<<"default">>, <<"http://jabber.org/protocol/pubsub">>, - _} -> - true; - {<<"default">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - true; - {<<"default">>, - <<"http://jabber.org/protocol/pubsub#owner">>, _} -> - true; - {<<"default">>, <<>>, - <<"http://jabber.org/protocol/pubsub#owner">>} -> - true; - {<<"publish-options">>, - <<"http://jabber.org/protocol/pubsub">>, _} -> - true; - {<<"publish-options">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - true; - {<<"configure">>, - <<"http://jabber.org/protocol/pubsub">>, _} -> - true; - {<<"configure">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - true; - {<<"configure">>, - <<"http://jabber.org/protocol/pubsub#owner">>, _} -> - true; - {<<"configure">>, <<>>, - <<"http://jabber.org/protocol/pubsub#owner">>} -> - true; - {<<"create">>, <<"http://jabber.org/protocol/pubsub">>, - _} -> - true; - {<<"create">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - true; - {<<"create">>, - <<"http://jabber.org/protocol/pubsub#event">>, _} -> - true; - {<<"create">>, <<>>, - <<"http://jabber.org/protocol/pubsub#event">>} -> - true; - {<<"retract">>, <<"http://jabber.org/protocol/pubsub">>, - _} -> - true; - {<<"retract">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - true; - {<<"options">>, <<"http://jabber.org/protocol/pubsub">>, - _} -> - true; - {<<"options">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - true; - {<<"publish">>, <<"http://jabber.org/protocol/pubsub">>, - _} -> - true; - {<<"publish">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - true; - {<<"unsubscribe">>, - <<"http://jabber.org/protocol/pubsub">>, _} -> - true; - {<<"unsubscribe">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - true; - {<<"subscribe">>, - <<"http://jabber.org/protocol/pubsub">>, _} -> - true; - {<<"subscribe">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - true; - {<<"affiliations">>, - <<"http://jabber.org/protocol/pubsub#owner">>, _} -> - true; - {<<"affiliations">>, <<>>, - <<"http://jabber.org/protocol/pubsub#owner">>} -> - true; - {<<"affiliations">>, - <<"http://jabber.org/protocol/pubsub">>, _} -> - true; - {<<"affiliations">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - true; - {<<"subscriptions">>, - <<"http://jabber.org/protocol/pubsub">>, _} -> - true; - {<<"subscriptions">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - true; - {<<"subscriptions">>, - <<"http://jabber.org/protocol/pubsub#owner">>, _} -> - true; - {<<"subscriptions">>, <<>>, - <<"http://jabber.org/protocol/pubsub#owner">>} -> - true; - {<<"event">>, - <<"http://jabber.org/protocol/pubsub#event">>, _} -> - true; - {<<"event">>, <<>>, - <<"http://jabber.org/protocol/pubsub#event">>} -> - true; - {<<"items">>, <<"http://jabber.org/protocol/pubsub">>, - _} -> - true; - {<<"items">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - true; - {<<"items">>, - <<"http://jabber.org/protocol/pubsub#event">>, _} -> - true; - {<<"items">>, <<>>, - <<"http://jabber.org/protocol/pubsub#event">>} -> - true; - {<<"item">>, <<"http://jabber.org/protocol/pubsub">>, - _} -> - true; - {<<"item">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - true; - {<<"item">>, - <<"http://jabber.org/protocol/pubsub#event">>, _} -> - true; - {<<"item">>, <<>>, - <<"http://jabber.org/protocol/pubsub#event">>} -> - true; - {<<"retract">>, - <<"http://jabber.org/protocol/pubsub#event">>, _} -> - true; - {<<"retract">>, <<>>, - <<"http://jabber.org/protocol/pubsub#event">>} -> - true; - {<<"configuration">>, - <<"http://jabber.org/protocol/pubsub#event">>, _} -> - true; - {<<"configuration">>, <<>>, - <<"http://jabber.org/protocol/pubsub#event">>} -> - true; - {<<"affiliation">>, - <<"http://jabber.org/protocol/pubsub#owner">>, _} -> - true; - {<<"affiliation">>, <<>>, - <<"http://jabber.org/protocol/pubsub#owner">>} -> - true; - {<<"affiliation">>, - <<"http://jabber.org/protocol/pubsub">>, _} -> - true; - {<<"affiliation">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - true; - {<<"subscription">>, - <<"http://jabber.org/protocol/pubsub">>, _} -> - true; - {<<"subscription">>, <<>>, - <<"http://jabber.org/protocol/pubsub">>} -> - true; - {<<"subscription">>, - <<"http://jabber.org/protocol/pubsub#owner">>, _} -> - true; - {<<"subscription">>, <<>>, - <<"http://jabber.org/protocol/pubsub#owner">>} -> - true; - {<<"subscription">>, - <<"http://jabber.org/protocol/pubsub#event">>, _} -> - true; - {<<"subscription">>, <<>>, - <<"http://jabber.org/protocol/pubsub#event">>} -> - true; - {<<"x">>, <<"jabber:x:data">>, _} -> true; - {<<"x">>, <<>>, <<"jabber:x:data">>} -> true; - {<<"item">>, <<"jabber:x:data">>, _} -> true; - {<<"item">>, <<>>, <<"jabber:x:data">>} -> true; - {<<"reported">>, <<"jabber:x:data">>, _} -> true; - {<<"reported">>, <<>>, <<"jabber:x:data">>} -> true; - {<<"title">>, <<"jabber:x:data">>, _} -> true; - {<<"title">>, <<>>, <<"jabber:x:data">>} -> true; - {<<"instructions">>, <<"jabber:x:data">>, _} -> true; - {<<"instructions">>, <<>>, <<"jabber:x:data">>} -> true; - {<<"field">>, <<"jabber:x:data">>, _} -> true; - {<<"field">>, <<>>, <<"jabber:x:data">>} -> true; - {<<"option">>, <<"jabber:x:data">>, _} -> true; - {<<"option">>, <<>>, <<"jabber:x:data">>} -> true; - {<<"value">>, <<"jabber:x:data">>, _} -> true; - {<<"value">>, <<>>, <<"jabber:x:data">>} -> true; - {<<"desc">>, <<"jabber:x:data">>, _} -> true; - {<<"desc">>, <<>>, <<"jabber:x:data">>} -> true; - {<<"required">>, <<"jabber:x:data">>, _} -> true; - {<<"required">>, <<>>, <<"jabber:x:data">>} -> true; - {<<"x">>, <<"vcard-temp:x:update">>, _} -> true; - {<<"x">>, <<>>, <<"vcard-temp:x:update">>} -> true; - {<<"photo">>, <<"vcard-temp:x:update">>, _} -> true; - {<<"photo">>, <<>>, <<"vcard-temp:x:update">>} -> true; - {<<"vCard">>, <<"vcard-temp">>, _} -> true; - {<<"vCard">>, <<>>, <<"vcard-temp">>} -> true; - {<<"CLASS">>, <<"vcard-temp">>, _} -> true; - {<<"CLASS">>, <<>>, <<"vcard-temp">>} -> true; - {<<"CATEGORIES">>, <<"vcard-temp">>, _} -> true; - {<<"CATEGORIES">>, <<>>, <<"vcard-temp">>} -> true; - {<<"KEY">>, <<"vcard-temp">>, _} -> true; - {<<"KEY">>, <<>>, <<"vcard-temp">>} -> true; - {<<"SOUND">>, <<"vcard-temp">>, _} -> true; - {<<"SOUND">>, <<>>, <<"vcard-temp">>} -> true; - {<<"ORG">>, <<"vcard-temp">>, _} -> true; - {<<"ORG">>, <<>>, <<"vcard-temp">>} -> true; - {<<"PHOTO">>, <<"vcard-temp">>, _} -> true; - {<<"PHOTO">>, <<>>, <<"vcard-temp">>} -> true; - {<<"LOGO">>, <<"vcard-temp">>, _} -> true; - {<<"LOGO">>, <<>>, <<"vcard-temp">>} -> true; - {<<"BINVAL">>, <<"vcard-temp">>, _} -> true; - {<<"BINVAL">>, <<>>, <<"vcard-temp">>} -> true; - {<<"GEO">>, <<"vcard-temp">>, _} -> true; - {<<"GEO">>, <<>>, <<"vcard-temp">>} -> true; - {<<"EMAIL">>, <<"vcard-temp">>, _} -> true; - {<<"EMAIL">>, <<>>, <<"vcard-temp">>} -> true; - {<<"TEL">>, <<"vcard-temp">>, _} -> true; - {<<"TEL">>, <<>>, <<"vcard-temp">>} -> true; - {<<"LABEL">>, <<"vcard-temp">>, _} -> true; - {<<"LABEL">>, <<>>, <<"vcard-temp">>} -> true; - {<<"ADR">>, <<"vcard-temp">>, _} -> true; - {<<"ADR">>, <<>>, <<"vcard-temp">>} -> true; - {<<"N">>, <<"vcard-temp">>, _} -> true; - {<<"N">>, <<>>, <<"vcard-temp">>} -> true; - {<<"CONFIDENTIAL">>, <<"vcard-temp">>, _} -> true; - {<<"CONFIDENTIAL">>, <<>>, <<"vcard-temp">>} -> true; - {<<"PRIVATE">>, <<"vcard-temp">>, _} -> true; - {<<"PRIVATE">>, <<>>, <<"vcard-temp">>} -> true; - {<<"PUBLIC">>, <<"vcard-temp">>, _} -> true; - {<<"PUBLIC">>, <<>>, <<"vcard-temp">>} -> true; - {<<"EXTVAL">>, <<"vcard-temp">>, _} -> true; - {<<"EXTVAL">>, <<>>, <<"vcard-temp">>} -> true; - {<<"TYPE">>, <<"vcard-temp">>, _} -> true; - {<<"TYPE">>, <<>>, <<"vcard-temp">>} -> true; - {<<"DESC">>, <<"vcard-temp">>, _} -> true; - {<<"DESC">>, <<>>, <<"vcard-temp">>} -> true; - {<<"URL">>, <<"vcard-temp">>, _} -> true; - {<<"URL">>, <<>>, <<"vcard-temp">>} -> true; - {<<"UID">>, <<"vcard-temp">>, _} -> true; - {<<"UID">>, <<>>, <<"vcard-temp">>} -> true; - {<<"SORT-STRING">>, <<"vcard-temp">>, _} -> true; - {<<"SORT-STRING">>, <<>>, <<"vcard-temp">>} -> true; - {<<"REV">>, <<"vcard-temp">>, _} -> true; - {<<"REV">>, <<>>, <<"vcard-temp">>} -> true; - {<<"PRODID">>, <<"vcard-temp">>, _} -> true; - {<<"PRODID">>, <<>>, <<"vcard-temp">>} -> true; - {<<"NOTE">>, <<"vcard-temp">>, _} -> true; - {<<"NOTE">>, <<>>, <<"vcard-temp">>} -> true; - {<<"KEYWORD">>, <<"vcard-temp">>, _} -> true; - {<<"KEYWORD">>, <<>>, <<"vcard-temp">>} -> true; - {<<"ROLE">>, <<"vcard-temp">>, _} -> true; - {<<"ROLE">>, <<>>, <<"vcard-temp">>} -> true; - {<<"TITLE">>, <<"vcard-temp">>, _} -> true; - {<<"TITLE">>, <<>>, <<"vcard-temp">>} -> true; - {<<"TZ">>, <<"vcard-temp">>, _} -> true; - {<<"TZ">>, <<>>, <<"vcard-temp">>} -> true; - {<<"MAILER">>, <<"vcard-temp">>, _} -> true; - {<<"MAILER">>, <<>>, <<"vcard-temp">>} -> true; - {<<"JABBERID">>, <<"vcard-temp">>, _} -> true; - {<<"JABBERID">>, <<>>, <<"vcard-temp">>} -> true; - {<<"BDAY">>, <<"vcard-temp">>, _} -> true; - {<<"BDAY">>, <<>>, <<"vcard-temp">>} -> true; - {<<"NICKNAME">>, <<"vcard-temp">>, _} -> true; - {<<"NICKNAME">>, <<>>, <<"vcard-temp">>} -> true; - {<<"FN">>, <<"vcard-temp">>, _} -> true; - {<<"FN">>, <<>>, <<"vcard-temp">>} -> true; - {<<"VERSION">>, <<"vcard-temp">>, _} -> true; - {<<"VERSION">>, <<>>, <<"vcard-temp">>} -> true; - {<<"CRED">>, <<"vcard-temp">>, _} -> true; - {<<"CRED">>, <<>>, <<"vcard-temp">>} -> true; - {<<"PHONETIC">>, <<"vcard-temp">>, _} -> true; - {<<"PHONETIC">>, <<>>, <<"vcard-temp">>} -> true; - {<<"ORGUNIT">>, <<"vcard-temp">>, _} -> true; - {<<"ORGUNIT">>, <<>>, <<"vcard-temp">>} -> true; - {<<"ORGNAME">>, <<"vcard-temp">>, _} -> true; - {<<"ORGNAME">>, <<>>, <<"vcard-temp">>} -> true; - {<<"LON">>, <<"vcard-temp">>, _} -> true; - {<<"LON">>, <<>>, <<"vcard-temp">>} -> true; - {<<"LAT">>, <<"vcard-temp">>, _} -> true; - {<<"LAT">>, <<>>, <<"vcard-temp">>} -> true; - {<<"USERID">>, <<"vcard-temp">>, _} -> true; - {<<"USERID">>, <<>>, <<"vcard-temp">>} -> true; - {<<"NUMBER">>, <<"vcard-temp">>, _} -> true; - {<<"NUMBER">>, <<>>, <<"vcard-temp">>} -> true; - {<<"LINE">>, <<"vcard-temp">>, _} -> true; - {<<"LINE">>, <<>>, <<"vcard-temp">>} -> true; - {<<"CTRY">>, <<"vcard-temp">>, _} -> true; - {<<"CTRY">>, <<>>, <<"vcard-temp">>} -> true; - {<<"PCODE">>, <<"vcard-temp">>, _} -> true; - {<<"PCODE">>, <<>>, <<"vcard-temp">>} -> true; - {<<"REGION">>, <<"vcard-temp">>, _} -> true; - {<<"REGION">>, <<>>, <<"vcard-temp">>} -> true; - {<<"LOCALITY">>, <<"vcard-temp">>, _} -> true; - {<<"LOCALITY">>, <<>>, <<"vcard-temp">>} -> true; - {<<"STREET">>, <<"vcard-temp">>, _} -> true; - {<<"STREET">>, <<>>, <<"vcard-temp">>} -> true; - {<<"EXTADD">>, <<"vcard-temp">>, _} -> true; - {<<"EXTADD">>, <<>>, <<"vcard-temp">>} -> true; - {<<"POBOX">>, <<"vcard-temp">>, _} -> true; - {<<"POBOX">>, <<>>, <<"vcard-temp">>} -> true; - {<<"SUFFIX">>, <<"vcard-temp">>, _} -> true; - {<<"SUFFIX">>, <<>>, <<"vcard-temp">>} -> true; - {<<"PREFIX">>, <<"vcard-temp">>, _} -> true; - {<<"PREFIX">>, <<>>, <<"vcard-temp">>} -> true; - {<<"MIDDLE">>, <<"vcard-temp">>, _} -> true; - {<<"MIDDLE">>, <<>>, <<"vcard-temp">>} -> true; - {<<"GIVEN">>, <<"vcard-temp">>, _} -> true; - {<<"GIVEN">>, <<>>, <<"vcard-temp">>} -> true; - {<<"FAMILY">>, <<"vcard-temp">>, _} -> true; - {<<"FAMILY">>, <<>>, <<"vcard-temp">>} -> true; - {<<"X400">>, <<"vcard-temp">>, _} -> true; - {<<"X400">>, <<>>, <<"vcard-temp">>} -> true; - {<<"INTERNET">>, <<"vcard-temp">>, _} -> true; - {<<"INTERNET">>, <<>>, <<"vcard-temp">>} -> true; - {<<"PREF">>, <<"vcard-temp">>, _} -> true; - {<<"PREF">>, <<>>, <<"vcard-temp">>} -> true; - {<<"INTL">>, <<"vcard-temp">>, _} -> true; - {<<"INTL">>, <<>>, <<"vcard-temp">>} -> true; - {<<"DOM">>, <<"vcard-temp">>, _} -> true; - {<<"DOM">>, <<>>, <<"vcard-temp">>} -> true; - {<<"PARCEL">>, <<"vcard-temp">>, _} -> true; - {<<"PARCEL">>, <<>>, <<"vcard-temp">>} -> true; - {<<"POSTAL">>, <<"vcard-temp">>, _} -> true; - {<<"POSTAL">>, <<>>, <<"vcard-temp">>} -> true; - {<<"PCS">>, <<"vcard-temp">>, _} -> true; - {<<"PCS">>, <<>>, <<"vcard-temp">>} -> true; - {<<"ISDN">>, <<"vcard-temp">>, _} -> true; - {<<"ISDN">>, <<>>, <<"vcard-temp">>} -> true; - {<<"MODEM">>, <<"vcard-temp">>, _} -> true; - {<<"MODEM">>, <<>>, <<"vcard-temp">>} -> true; - {<<"BBS">>, <<"vcard-temp">>, _} -> true; - {<<"BBS">>, <<>>, <<"vcard-temp">>} -> true; - {<<"VIDEO">>, <<"vcard-temp">>, _} -> true; - {<<"VIDEO">>, <<>>, <<"vcard-temp">>} -> true; - {<<"CELL">>, <<"vcard-temp">>, _} -> true; - {<<"CELL">>, <<>>, <<"vcard-temp">>} -> true; - {<<"MSG">>, <<"vcard-temp">>, _} -> true; - {<<"MSG">>, <<>>, <<"vcard-temp">>} -> true; - {<<"PAGER">>, <<"vcard-temp">>, _} -> true; - {<<"PAGER">>, <<>>, <<"vcard-temp">>} -> true; - {<<"FAX">>, <<"vcard-temp">>, _} -> true; - {<<"FAX">>, <<>>, <<"vcard-temp">>} -> true; - {<<"VOICE">>, <<"vcard-temp">>, _} -> true; - {<<"VOICE">>, <<>>, <<"vcard-temp">>} -> true; - {<<"WORK">>, <<"vcard-temp">>, _} -> true; - {<<"WORK">>, <<>>, <<"vcard-temp">>} -> true; - {<<"HOME">>, <<"vcard-temp">>, _} -> true; - {<<"HOME">>, <<>>, <<"vcard-temp">>} -> true; - {<<"stream:error">>, <<"jabber:client">>, _} -> true; - {<<"stream:error">>, <<>>, <<"jabber:client">>} -> true; - {<<"stream:error">>, <<"jabber:server">>, _} -> true; - {<<"stream:error">>, <<>>, <<"jabber:server">>} -> true; - {<<"stream:error">>, <<"jabber:component:accept">>, - _} -> - true; - {<<"stream:error">>, <<>>, - <<"jabber:component:accept">>} -> - true; - {<<"unsupported-version">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - true; - {<<"unsupported-version">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"unsupported-stanza-type">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - true; - {<<"unsupported-stanza-type">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"unsupported-encoding">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - true; - {<<"unsupported-encoding">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"undefined-condition">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - true; - {<<"undefined-condition">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"system-shutdown">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - true; - {<<"system-shutdown">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"see-other-host">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - true; - {<<"see-other-host">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"restricted-xml">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - true; - {<<"restricted-xml">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"resource-constraint">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - true; - {<<"resource-constraint">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"reset">>, <<"urn:ietf:params:xml:ns:xmpp-streams">>, - _} -> - true; - {<<"reset">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"remote-connection-failed">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - true; - {<<"remote-connection-failed">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"policy-violation">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - true; - {<<"policy-violation">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"not-well-formed">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - true; - {<<"not-well-formed">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"not-authorized">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - true; - {<<"not-authorized">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"invalid-xml">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - true; - {<<"invalid-xml">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"invalid-namespace">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - true; - {<<"invalid-namespace">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"invalid-id">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - true; - {<<"invalid-id">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"invalid-from">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - true; - {<<"invalid-from">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"internal-server-error">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - true; - {<<"internal-server-error">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"improper-addressing">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - true; - {<<"improper-addressing">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"host-unknown">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - true; - {<<"host-unknown">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"host-gone">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - true; - {<<"host-gone">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"connection-timeout">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - true; - {<<"connection-timeout">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"conflict">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - true; - {<<"conflict">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"bad-namespace-prefix">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - true; - {<<"bad-namespace-prefix">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"bad-format">>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>, _} -> - true; - {<<"bad-format">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"text">>, <<"urn:ietf:params:xml:ns:xmpp-streams">>, - _} -> - true; - {<<"text">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-streams">>} -> - true; - {<<"time">>, <<"urn:xmpp:time">>, _} -> true; - {<<"time">>, <<>>, <<"urn:xmpp:time">>} -> true; - {<<"tzo">>, <<"urn:xmpp:time">>, _} -> true; - {<<"tzo">>, <<>>, <<"urn:xmpp:time">>} -> true; - {<<"utc">>, <<"urn:xmpp:time">>, _} -> true; - {<<"utc">>, <<>>, <<"urn:xmpp:time">>} -> true; - {<<"ping">>, <<"urn:xmpp:ping">>, _} -> true; - {<<"ping">>, <<>>, <<"urn:xmpp:ping">>} -> true; - {<<"session">>, - <<"urn:ietf:params:xml:ns:xmpp-session">>, _} -> - true; - {<<"session">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-session">>} -> - true; - {<<"optional">>, - <<"urn:ietf:params:xml:ns:xmpp-session">>, _} -> - true; - {<<"optional">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-session">>} -> - true; - {<<"query">>, <<"jabber:iq:register">>, _} -> true; - {<<"query">>, <<>>, <<"jabber:iq:register">>} -> true; - {<<"key">>, <<"jabber:iq:register">>, _} -> true; - {<<"key">>, <<>>, <<"jabber:iq:register">>} -> true; - {<<"text">>, <<"jabber:iq:register">>, _} -> true; - {<<"text">>, <<>>, <<"jabber:iq:register">>} -> true; - {<<"misc">>, <<"jabber:iq:register">>, _} -> true; - {<<"misc">>, <<>>, <<"jabber:iq:register">>} -> true; - {<<"date">>, <<"jabber:iq:register">>, _} -> true; - {<<"date">>, <<>>, <<"jabber:iq:register">>} -> true; - {<<"url">>, <<"jabber:iq:register">>, _} -> true; - {<<"url">>, <<>>, <<"jabber:iq:register">>} -> true; - {<<"phone">>, <<"jabber:iq:register">>, _} -> true; - {<<"phone">>, <<>>, <<"jabber:iq:register">>} -> true; - {<<"zip">>, <<"jabber:iq:register">>, _} -> true; - {<<"zip">>, <<>>, <<"jabber:iq:register">>} -> true; - {<<"state">>, <<"jabber:iq:register">>, _} -> true; - {<<"state">>, <<>>, <<"jabber:iq:register">>} -> true; - {<<"city">>, <<"jabber:iq:register">>, _} -> true; - {<<"city">>, <<>>, <<"jabber:iq:register">>} -> true; - {<<"address">>, <<"jabber:iq:register">>, _} -> true; - {<<"address">>, <<>>, <<"jabber:iq:register">>} -> true; - {<<"email">>, <<"jabber:iq:register">>, _} -> true; - {<<"email">>, <<>>, <<"jabber:iq:register">>} -> true; - {<<"last">>, <<"jabber:iq:register">>, _} -> true; - {<<"last">>, <<>>, <<"jabber:iq:register">>} -> true; - {<<"first">>, <<"jabber:iq:register">>, _} -> true; - {<<"first">>, <<>>, <<"jabber:iq:register">>} -> true; - {<<"name">>, <<"jabber:iq:register">>, _} -> true; - {<<"name">>, <<>>, <<"jabber:iq:register">>} -> true; - {<<"password">>, <<"jabber:iq:register">>, _} -> true; - {<<"password">>, <<>>, <<"jabber:iq:register">>} -> - true; - {<<"nick">>, <<"jabber:iq:register">>, _} -> true; - {<<"nick">>, <<>>, <<"jabber:iq:register">>} -> true; - {<<"username">>, <<"jabber:iq:register">>, _} -> true; - {<<"username">>, <<>>, <<"jabber:iq:register">>} -> - true; - {<<"instructions">>, <<"jabber:iq:register">>, _} -> - true; - {<<"instructions">>, <<>>, <<"jabber:iq:register">>} -> - true; - {<<"remove">>, <<"jabber:iq:register">>, _} -> true; - {<<"remove">>, <<>>, <<"jabber:iq:register">>} -> true; - {<<"registered">>, <<"jabber:iq:register">>, _} -> true; - {<<"registered">>, <<>>, <<"jabber:iq:register">>} -> - true; - {<<"register">>, - <<"http://jabber.org/features/iq-register">>, _} -> - true; - {<<"register">>, <<>>, - <<"http://jabber.org/features/iq-register">>} -> - true; - {<<"c">>, <<"http://jabber.org/protocol/caps">>, _} -> - true; - {<<"c">>, <<>>, - <<"http://jabber.org/protocol/caps">>} -> - true; - {<<"ack">>, <<"p1:ack">>, _} -> true; - {<<"ack">>, <<>>, <<"p1:ack">>} -> true; - {<<"rebind">>, <<"p1:rebind">>, _} -> true; - {<<"rebind">>, <<>>, <<"p1:rebind">>} -> true; - {<<"push">>, <<"p1:push">>, _} -> true; - {<<"push">>, <<>>, <<"p1:push">>} -> true; - {<<"stream:features">>, <<"jabber:client">>, _} -> true; - {<<"stream:features">>, <<>>, <<"jabber:client">>} -> - true; - {<<"stream:features">>, <<"jabber:server">>, _} -> true; - {<<"stream:features">>, <<>>, <<"jabber:server">>} -> - true; - {<<"compression">>, - <<"http://jabber.org/features/compress">>, _} -> - true; - {<<"compression">>, <<>>, - <<"http://jabber.org/features/compress">>} -> - true; - {<<"method">>, - <<"http://jabber.org/features/compress">>, _} -> - true; - {<<"method">>, <<>>, - <<"http://jabber.org/features/compress">>} -> - true; - {<<"compressed">>, - <<"http://jabber.org/protocol/compress">>, _} -> - true; - {<<"compressed">>, <<>>, - <<"http://jabber.org/protocol/compress">>} -> - true; - {<<"compress">>, - <<"http://jabber.org/protocol/compress">>, _} -> - true; - {<<"compress">>, <<>>, - <<"http://jabber.org/protocol/compress">>} -> - true; - {<<"method">>, - <<"http://jabber.org/protocol/compress">>, _} -> - true; - {<<"method">>, <<>>, - <<"http://jabber.org/protocol/compress">>} -> - true; - {<<"failure">>, - <<"http://jabber.org/protocol/compress">>, _} -> - true; - {<<"failure">>, <<>>, - <<"http://jabber.org/protocol/compress">>} -> - true; - {<<"unsupported-method">>, - <<"http://jabber.org/protocol/compress">>, _} -> - true; - {<<"unsupported-method">>, <<>>, - <<"http://jabber.org/protocol/compress">>} -> - true; - {<<"processing-failed">>, - <<"http://jabber.org/protocol/compress">>, _} -> - true; - {<<"processing-failed">>, <<>>, - <<"http://jabber.org/protocol/compress">>} -> - true; - {<<"setup-failed">>, - <<"http://jabber.org/protocol/compress">>, _} -> - true; - {<<"setup-failed">>, <<>>, - <<"http://jabber.org/protocol/compress">>} -> - true; - {<<"failure">>, <<"urn:ietf:params:xml:ns:xmpp-tls">>, - _} -> - true; - {<<"failure">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-tls">>} -> - true; - {<<"proceed">>, <<"urn:ietf:params:xml:ns:xmpp-tls">>, - _} -> - true; - {<<"proceed">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-tls">>} -> - true; - {<<"starttls">>, <<"urn:ietf:params:xml:ns:xmpp-tls">>, - _} -> - true; - {<<"starttls">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-tls">>} -> - true; - {<<"required">>, <<"urn:ietf:params:xml:ns:xmpp-tls">>, - _} -> - true; - {<<"required">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-tls">>} -> - true; - {<<"mechanisms">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - true; - {<<"mechanisms">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - true; - {<<"mechanism">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - true; - {<<"mechanism">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - true; - {<<"failure">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, - _} -> - true; - {<<"failure">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - true; - {<<"temporary-auth-failure">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - true; - {<<"temporary-auth-failure">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - true; - {<<"bad-protocol">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - true; - {<<"bad-protocol">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - true; - {<<"not-authorized">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - true; - {<<"not-authorized">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - true; - {<<"mechanism-too-weak">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - true; - {<<"mechanism-too-weak">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - true; - {<<"malformed-request">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - true; - {<<"malformed-request">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - true; - {<<"invalid-mechanism">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - true; - {<<"invalid-mechanism">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - true; - {<<"invalid-authzid">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - true; - {<<"invalid-authzid">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - true; - {<<"incorrect-encoding">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - true; - {<<"incorrect-encoding">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - true; - {<<"encryption-required">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - true; - {<<"encryption-required">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - true; - {<<"credentials-expired">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - true; - {<<"credentials-expired">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - true; - {<<"account-disabled">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - true; - {<<"account-disabled">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - true; - {<<"aborted">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, - _} -> - true; - {<<"aborted">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - true; - {<<"text">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, - _} -> - true; - {<<"text">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - true; - {<<"success">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, - _} -> - true; - {<<"success">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - true; - {<<"response">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, - _} -> - true; - {<<"response">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - true; - {<<"challenge">>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>, _} -> - true; - {<<"challenge">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - true; - {<<"abort">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, - _} -> - true; - {<<"abort">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - true; - {<<"auth">>, <<"urn:ietf:params:xml:ns:xmpp-sasl">>, - _} -> - true; - {<<"auth">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-sasl">>} -> - true; - {<<"query">>, <<"jabber:iq:auth">>, _} -> true; - {<<"query">>, <<>>, <<"jabber:iq:auth">>} -> true; - {<<"resource">>, <<"jabber:iq:auth">>, _} -> true; - {<<"resource">>, <<>>, <<"jabber:iq:auth">>} -> true; - {<<"digest">>, <<"jabber:iq:auth">>, _} -> true; - {<<"digest">>, <<>>, <<"jabber:iq:auth">>} -> true; - {<<"password">>, <<"jabber:iq:auth">>, _} -> true; - {<<"password">>, <<>>, <<"jabber:iq:auth">>} -> true; - {<<"username">>, <<"jabber:iq:auth">>, _} -> true; - {<<"username">>, <<>>, <<"jabber:iq:auth">>} -> true; - {<<"bind">>, <<"urn:ietf:params:xml:ns:xmpp-bind">>, - _} -> - true; - {<<"bind">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-bind">>} -> - true; - {<<"resource">>, <<"urn:ietf:params:xml:ns:xmpp-bind">>, - _} -> - true; - {<<"resource">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-bind">>} -> - true; - {<<"jid">>, <<"urn:ietf:params:xml:ns:xmpp-bind">>, - _} -> - true; - {<<"jid">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-bind">>} -> - true; - {<<"error">>, <<"jabber:client">>, _} -> true; - {<<"error">>, <<>>, <<"jabber:client">>} -> true; - {<<"error">>, <<"jabber:server">>, _} -> true; - {<<"error">>, <<>>, <<"jabber:server">>} -> true; - {<<"error">>, <<"jabber:component:accept">>, _} -> true; - {<<"error">>, <<>>, <<"jabber:component:accept">>} -> - true; - {<<"text">>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - _} -> - true; - {<<"text">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - true; - {<<"unexpected-request">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - true; - {<<"unexpected-request">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - true; - {<<"undefined-condition">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - true; - {<<"undefined-condition">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - true; - {<<"subscription-required">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - true; - {<<"subscription-required">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - true; - {<<"service-unavailable">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - true; - {<<"service-unavailable">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - true; - {<<"resource-constraint">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - true; - {<<"resource-constraint">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - true; - {<<"remote-server-timeout">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - true; - {<<"remote-server-timeout">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - true; - {<<"remote-server-not-found">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - true; - {<<"remote-server-not-found">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - true; - {<<"registration-required">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - true; - {<<"registration-required">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - true; - {<<"redirect">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - true; - {<<"redirect">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - true; - {<<"recipient-unavailable">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - true; - {<<"recipient-unavailable">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - true; - {<<"policy-violation">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - true; - {<<"policy-violation">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - true; - {<<"payment-required">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - true; - {<<"payment-required">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - true; - {<<"not-authorized">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - true; - {<<"not-authorized">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - true; - {<<"not-allowed">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - true; - {<<"not-allowed">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - true; - {<<"not-acceptable">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - true; - {<<"not-acceptable">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - true; - {<<"jid-malformed">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - true; - {<<"jid-malformed">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - true; - {<<"item-not-found">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - true; - {<<"item-not-found">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - true; - {<<"internal-server-error">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - true; - {<<"internal-server-error">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - true; - {<<"gone">>, <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - _} -> - true; - {<<"gone">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - true; - {<<"forbidden">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - true; - {<<"forbidden">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - true; - {<<"feature-not-implemented">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - true; - {<<"feature-not-implemented">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - true; - {<<"conflict">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - true; - {<<"conflict">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - true; - {<<"bad-request">>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>, _} -> - true; - {<<"bad-request">>, <<>>, - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>} -> - true; - {<<"presence">>, <<"jabber:client">>, _} -> true; - {<<"presence">>, <<>>, <<"jabber:client">>} -> true; - {<<"presence">>, <<"jabber:server">>, _} -> true; - {<<"presence">>, <<>>, <<"jabber:server">>} -> true; - {<<"presence">>, <<"jabber:component:accept">>, _} -> - true; - {<<"presence">>, <<>>, <<"jabber:component:accept">>} -> - true; - {<<"priority">>, <<"jabber:client">>, _} -> true; - {<<"priority">>, <<>>, <<"jabber:client">>} -> true; - {<<"priority">>, <<"jabber:server">>, _} -> true; - {<<"priority">>, <<>>, <<"jabber:server">>} -> true; - {<<"priority">>, <<"jabber:component:accept">>, _} -> - true; - {<<"priority">>, <<>>, <<"jabber:component:accept">>} -> - true; - {<<"status">>, <<"jabber:client">>, _} -> true; - {<<"status">>, <<>>, <<"jabber:client">>} -> true; - {<<"status">>, <<"jabber:server">>, _} -> true; - {<<"status">>, <<>>, <<"jabber:server">>} -> true; - {<<"status">>, <<"jabber:component:accept">>, _} -> - true; - {<<"status">>, <<>>, <<"jabber:component:accept">>} -> - true; - {<<"show">>, <<"jabber:client">>, _} -> true; - {<<"show">>, <<>>, <<"jabber:client">>} -> true; - {<<"show">>, <<"jabber:server">>, _} -> true; - {<<"show">>, <<>>, <<"jabber:server">>} -> true; - {<<"show">>, <<"jabber:component:accept">>, _} -> true; - {<<"show">>, <<>>, <<"jabber:component:accept">>} -> - true; - {<<"message">>, <<"jabber:client">>, _} -> true; - {<<"message">>, <<>>, <<"jabber:client">>} -> true; - {<<"message">>, <<"jabber:server">>, _} -> true; - {<<"message">>, <<>>, <<"jabber:server">>} -> true; - {<<"message">>, <<"jabber:component:accept">>, _} -> - true; - {<<"message">>, <<>>, <<"jabber:component:accept">>} -> - true; - {<<"thread">>, <<"jabber:client">>, _} -> true; - {<<"thread">>, <<>>, <<"jabber:client">>} -> true; - {<<"thread">>, <<"jabber:server">>, _} -> true; - {<<"thread">>, <<>>, <<"jabber:server">>} -> true; - {<<"thread">>, <<"jabber:component:accept">>, _} -> - true; - {<<"thread">>, <<>>, <<"jabber:component:accept">>} -> - true; - {<<"body">>, <<"jabber:client">>, _} -> true; - {<<"body">>, <<>>, <<"jabber:client">>} -> true; - {<<"body">>, <<"jabber:server">>, _} -> true; - {<<"body">>, <<>>, <<"jabber:server">>} -> true; - {<<"body">>, <<"jabber:component:accept">>, _} -> true; - {<<"body">>, <<>>, <<"jabber:component:accept">>} -> - true; - {<<"subject">>, <<"jabber:client">>, _} -> true; - {<<"subject">>, <<>>, <<"jabber:client">>} -> true; - {<<"subject">>, <<"jabber:server">>, _} -> true; - {<<"subject">>, <<>>, <<"jabber:server">>} -> true; - {<<"subject">>, <<"jabber:component:accept">>, _} -> - true; - {<<"subject">>, <<>>, <<"jabber:component:accept">>} -> - true; - {<<"iq">>, <<"jabber:client">>, _} -> true; - {<<"iq">>, <<>>, <<"jabber:client">>} -> true; - {<<"iq">>, <<"jabber:server">>, _} -> true; - {<<"iq">>, <<>>, <<"jabber:server">>} -> true; - {<<"iq">>, <<"jabber:component:accept">>, _} -> true; - {<<"iq">>, <<>>, <<"jabber:component:accept">>} -> true; - {<<"query">>, <<"http://jabber.org/protocol/stats">>, - _} -> - true; - {<<"query">>, <<>>, - <<"http://jabber.org/protocol/stats">>} -> - true; - {<<"stat">>, <<"http://jabber.org/protocol/stats">>, - _} -> - true; - {<<"stat">>, <<>>, - <<"http://jabber.org/protocol/stats">>} -> - true; - {<<"error">>, <<"http://jabber.org/protocol/stats">>, - _} -> - true; - {<<"error">>, <<>>, - <<"http://jabber.org/protocol/stats">>} -> - true; - {<<"storage">>, <<"storage:bookmarks">>, _} -> true; - {<<"storage">>, <<>>, <<"storage:bookmarks">>} -> true; - {<<"url">>, <<"storage:bookmarks">>, _} -> true; - {<<"url">>, <<>>, <<"storage:bookmarks">>} -> true; - {<<"conference">>, <<"storage:bookmarks">>, _} -> true; - {<<"conference">>, <<>>, <<"storage:bookmarks">>} -> - true; - {<<"password">>, <<"storage:bookmarks">>, _} -> true; - {<<"password">>, <<>>, <<"storage:bookmarks">>} -> true; - {<<"nick">>, <<"storage:bookmarks">>, _} -> true; - {<<"nick">>, <<>>, <<"storage:bookmarks">>} -> true; - {<<"query">>, <<"jabber:iq:private">>, _} -> true; - {<<"query">>, <<>>, <<"jabber:iq:private">>} -> true; - {<<"query">>, - <<"http://jabber.org/protocol/disco#items">>, _} -> - true; - {<<"query">>, <<>>, - <<"http://jabber.org/protocol/disco#items">>} -> - true; - {<<"item">>, - <<"http://jabber.org/protocol/disco#items">>, _} -> - true; - {<<"item">>, <<>>, - <<"http://jabber.org/protocol/disco#items">>} -> - true; - {<<"query">>, - <<"http://jabber.org/protocol/disco#info">>, _} -> - true; - {<<"query">>, <<>>, - <<"http://jabber.org/protocol/disco#info">>} -> - true; - {<<"feature">>, - <<"http://jabber.org/protocol/disco#info">>, _} -> - true; - {<<"feature">>, <<>>, - <<"http://jabber.org/protocol/disco#info">>} -> - true; - {<<"identity">>, - <<"http://jabber.org/protocol/disco#info">>, _} -> - true; - {<<"identity">>, <<>>, - <<"http://jabber.org/protocol/disco#info">>} -> - true; - {<<"blocklist">>, <<"urn:xmpp:blocking">>, _} -> true; - {<<"blocklist">>, <<>>, <<"urn:xmpp:blocking">>} -> - true; - {<<"unblock">>, <<"urn:xmpp:blocking">>, _} -> true; - {<<"unblock">>, <<>>, <<"urn:xmpp:blocking">>} -> true; - {<<"block">>, <<"urn:xmpp:blocking">>, _} -> true; - {<<"block">>, <<>>, <<"urn:xmpp:blocking">>} -> true; - {<<"item">>, <<"urn:xmpp:blocking">>, _} -> true; - {<<"item">>, <<>>, <<"urn:xmpp:blocking">>} -> true; - {<<"query">>, <<"jabber:iq:privacy">>, _} -> true; - {<<"query">>, <<>>, <<"jabber:iq:privacy">>} -> true; - {<<"active">>, <<"jabber:iq:privacy">>, _} -> true; - {<<"active">>, <<>>, <<"jabber:iq:privacy">>} -> true; - {<<"default">>, <<"jabber:iq:privacy">>, _} -> true; - {<<"default">>, <<>>, <<"jabber:iq:privacy">>} -> true; - {<<"list">>, <<"jabber:iq:privacy">>, _} -> true; - {<<"list">>, <<>>, <<"jabber:iq:privacy">>} -> true; - {<<"item">>, <<"jabber:iq:privacy">>, _} -> true; - {<<"item">>, <<>>, <<"jabber:iq:privacy">>} -> true; - {<<"presence-out">>, <<"jabber:iq:privacy">>, _} -> - true; - {<<"presence-out">>, <<>>, <<"jabber:iq:privacy">>} -> - true; - {<<"presence-in">>, <<"jabber:iq:privacy">>, _} -> true; - {<<"presence-in">>, <<>>, <<"jabber:iq:privacy">>} -> - true; - {<<"iq">>, <<"jabber:iq:privacy">>, _} -> true; - {<<"iq">>, <<>>, <<"jabber:iq:privacy">>} -> true; - {<<"message">>, <<"jabber:iq:privacy">>, _} -> true; - {<<"message">>, <<>>, <<"jabber:iq:privacy">>} -> true; - {<<"ver">>, <<"urn:xmpp:features:rosterver">>, _} -> - true; - {<<"ver">>, <<>>, <<"urn:xmpp:features:rosterver">>} -> - true; - {<<"query">>, <<"jabber:iq:roster">>, _} -> true; - {<<"query">>, <<>>, <<"jabber:iq:roster">>} -> true; - {<<"item">>, <<"jabber:iq:roster">>, _} -> true; - {<<"item">>, <<>>, <<"jabber:iq:roster">>} -> true; - {<<"group">>, <<"jabber:iq:roster">>, _} -> true; - {<<"group">>, <<>>, <<"jabber:iq:roster">>} -> true; - {<<"query">>, <<"jabber:iq:version">>, _} -> true; - {<<"query">>, <<>>, <<"jabber:iq:version">>} -> true; - {<<"os">>, <<"jabber:iq:version">>, _} -> true; - {<<"os">>, <<>>, <<"jabber:iq:version">>} -> true; - {<<"version">>, <<"jabber:iq:version">>, _} -> true; - {<<"version">>, <<>>, <<"jabber:iq:version">>} -> true; - {<<"name">>, <<"jabber:iq:version">>, _} -> true; - {<<"name">>, <<>>, <<"jabber:iq:version">>} -> true; - {<<"query">>, <<"jabber:iq:last">>, _} -> true; - {<<"query">>, <<>>, <<"jabber:iq:last">>} -> true; - _ -> false - end. - -encode(_el) -> encode(_el, <<>>). - -encode({xmlel, _, _, _} = El, _) -> El; -encode({last, _, _} = Query, TopXMLNS) -> - encode_last(Query, TopXMLNS); -encode({version, _, _, _} = Query, TopXMLNS) -> - encode_version(Query, TopXMLNS); -encode({roster_item, _, _, _, _, _} = Item, TopXMLNS) -> - encode_roster_item(Item, TopXMLNS); -encode({roster_query, _, _} = Query, TopXMLNS) -> - encode_roster_query(Query, TopXMLNS); -encode({rosterver_feature} = Ver, TopXMLNS) -> - encode_rosterver_feature(Ver, TopXMLNS); -encode({privacy_item, _, _, _, _, _, _, _, _} = Item, - TopXMLNS) -> - encode_privacy_item(Item, TopXMLNS); -encode({privacy_list, _, _} = List, TopXMLNS) -> - encode_privacy_list(List, TopXMLNS); -encode({privacy_query, _, _, _} = Query, TopXMLNS) -> - encode_privacy(Query, TopXMLNS); -encode({block, _} = Block, TopXMLNS) -> - encode_block(Block, TopXMLNS); -encode({unblock, _} = Unblock, TopXMLNS) -> - encode_unblock(Unblock, TopXMLNS); -encode({block_list, _} = Blocklist, TopXMLNS) -> - encode_block_list(Blocklist, TopXMLNS); -encode({identity, _, _, _, _} = Identity, TopXMLNS) -> - encode_disco_identity(Identity, TopXMLNS); -encode({disco_info, _, _, _, _} = Query, TopXMLNS) -> - encode_disco_info(Query, TopXMLNS); -encode({disco_item, _, _, _} = Item, TopXMLNS) -> - encode_disco_item(Item, TopXMLNS); -encode({disco_items, _, _, _} = Query, TopXMLNS) -> - encode_disco_items(Query, TopXMLNS); -encode({private, _} = Query, TopXMLNS) -> - encode_private(Query, TopXMLNS); -encode({bookmark_conference, _, _, _, _, _} = - Conference, - TopXMLNS) -> - encode_bookmark_conference(Conference, TopXMLNS); -encode({bookmark_url, _, _} = Url, TopXMLNS) -> - encode_bookmark_url(Url, TopXMLNS); -encode({bookmark_storage, _, _} = Storage, TopXMLNS) -> - encode_bookmarks_storage(Storage, TopXMLNS); -encode({stat_error, _, _} = Error, TopXMLNS) -> - encode_stat_error(Error, TopXMLNS); -encode({stat, _, _, _, _} = Stat, TopXMLNS) -> - encode_stat(Stat, TopXMLNS); -encode({stats, _, _} = Query, TopXMLNS) -> - encode_stats(Query, TopXMLNS); -encode({iq, _, _, _, _, _, _} = Iq, TopXMLNS) -> - encode_iq(Iq, TopXMLNS); -encode({message, _, _, _, _, _, _, _, _, _} = Message, - TopXMLNS) -> - encode_message(Message, TopXMLNS); -encode({presence, _, _, _, _, _, _, _, _, _} = Presence, - TopXMLNS) -> - encode_presence(Presence, TopXMLNS); -encode({gone, _} = Gone, TopXMLNS) -> - encode_error_gone(Gone, TopXMLNS); -encode({redirect, _} = Redirect, TopXMLNS) -> - encode_error_redirect(Redirect, TopXMLNS); -encode({stanza_error, _, _, _, _, _, _} = Error, - TopXMLNS) -> - encode_error(Error, TopXMLNS); -encode({bind, _, _} = Bind, TopXMLNS) -> - encode_bind(Bind, TopXMLNS); -encode({legacy_auth, _, _, _, _} = Query, TopXMLNS) -> - encode_legacy_auth(Query, TopXMLNS); -encode({sasl_auth, _, _} = Auth, TopXMLNS) -> - encode_sasl_auth(Auth, TopXMLNS); -encode({sasl_abort} = Abort, TopXMLNS) -> - encode_sasl_abort(Abort, TopXMLNS); -encode({sasl_challenge, _} = Challenge, TopXMLNS) -> - encode_sasl_challenge(Challenge, TopXMLNS); -encode({sasl_response, _} = Response, TopXMLNS) -> - encode_sasl_response(Response, TopXMLNS); -encode({sasl_success, _} = Success, TopXMLNS) -> - encode_sasl_success(Success, TopXMLNS); -encode({sasl_failure, _, _} = Failure, TopXMLNS) -> - encode_sasl_failure(Failure, TopXMLNS); -encode({sasl_mechanisms, _} = Mechanisms, TopXMLNS) -> - encode_sasl_mechanisms(Mechanisms, TopXMLNS); -encode({starttls, _} = Starttls, TopXMLNS) -> - encode_starttls(Starttls, TopXMLNS); -encode({starttls_proceed} = Proceed, TopXMLNS) -> - encode_starttls_proceed(Proceed, TopXMLNS); -encode({starttls_failure} = Failure, TopXMLNS) -> - encode_starttls_failure(Failure, TopXMLNS); -encode({compress_failure, _} = Failure, TopXMLNS) -> - encode_compress_failure(Failure, TopXMLNS); -encode({compress, _} = Compress, TopXMLNS) -> - encode_compress(Compress, TopXMLNS); -encode({compressed} = Compressed, TopXMLNS) -> - encode_compressed(Compressed, TopXMLNS); -encode({compression, _} = Compression, TopXMLNS) -> - encode_compression(Compression, TopXMLNS); -encode({stream_features, _} = Stream_features, - TopXMLNS) -> - encode_stream_features(Stream_features, TopXMLNS); -encode({p1_push} = Push, TopXMLNS) -> - encode_p1_push(Push, TopXMLNS); -encode({p1_rebind} = Rebind, TopXMLNS) -> - encode_p1_rebind(Rebind, TopXMLNS); -encode({p1_ack} = Ack, TopXMLNS) -> - encode_p1_ack(Ack, TopXMLNS); -encode({caps, _, _, _, _} = C, TopXMLNS) -> - encode_caps(C, TopXMLNS); -encode({feature_register} = Register, TopXMLNS) -> - encode_feature_register(Register, TopXMLNS); -encode({register, _, _, _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, _} = - Query, - TopXMLNS) -> - encode_register(Query, TopXMLNS); -encode({xmpp_session, _} = Session, TopXMLNS) -> - encode_session(Session, TopXMLNS); -encode({ping} = Ping, TopXMLNS) -> - encode_ping(Ping, TopXMLNS); -encode({time, _, _} = Time, TopXMLNS) -> - encode_time(Time, TopXMLNS); -encode({text, _, _} = Text, TopXMLNS) -> - encode_stream_error_text(Text, TopXMLNS); -encode({'see-other-host', _} = See_other_host, - TopXMLNS) -> - encode_stream_error_see_other_host(See_other_host, - TopXMLNS); -encode({stream_error, _, _} = Stream_error, TopXMLNS) -> - encode_stream_error(Stream_error, TopXMLNS); -encode({vcard_name, _, _, _, _, _} = N, TopXMLNS) -> - encode_vcard_N(N, TopXMLNS); -encode({vcard_adr, _, _, _, _, _, _, _, _, _, _, _, _, - _, _} = - Adr, - TopXMLNS) -> - encode_vcard_ADR(Adr, TopXMLNS); -encode({vcard_label, _, _, _, _, _, _, _, _} = Label, - TopXMLNS) -> - encode_vcard_LABEL(Label, TopXMLNS); -encode({vcard_tel, _, _, _, _, _, _, _, _, _, _, _, _, - _, _} = - Tel, - TopXMLNS) -> - encode_vcard_TEL(Tel, TopXMLNS); -encode({vcard_email, _, _, _, _, _, _} = Email, - TopXMLNS) -> - encode_vcard_EMAIL(Email, TopXMLNS); -encode({vcard_geo, _, _} = Geo, TopXMLNS) -> - encode_vcard_GEO(Geo, TopXMLNS); -encode({vcard_logo, _, _, _} = Logo, TopXMLNS) -> - encode_vcard_LOGO(Logo, TopXMLNS); -encode({vcard_photo, _, _, _} = Photo, TopXMLNS) -> - encode_vcard_PHOTO(Photo, TopXMLNS); -encode({vcard_org, _, _} = Org, TopXMLNS) -> - encode_vcard_ORG(Org, TopXMLNS); -encode({vcard_sound, _, _, _} = Sound, TopXMLNS) -> - encode_vcard_SOUND(Sound, TopXMLNS); -encode({vcard_key, _, _} = Key, TopXMLNS) -> - encode_vcard_KEY(Key, TopXMLNS); -encode({vcard_temp, _, _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _} = - Vcard, - TopXMLNS) -> - encode_vcard_temp(Vcard, TopXMLNS); -encode({vcard_xupdate, _, _} = X, TopXMLNS) -> - encode_vcard_xupdate(X, TopXMLNS); -encode({xdata_option, _, _} = Option, TopXMLNS) -> - encode_xdata_field_option(Option, TopXMLNS); -encode({xdata_field, _, _, _, _, _, _, _, _} = Field, - TopXMLNS) -> - encode_xdata_field(Field, TopXMLNS); -encode({xdata, _, _, _, _, _, _} = X, TopXMLNS) -> - encode_xdata(X, TopXMLNS); -encode({ps_subscription, _, _, _, _, _, _} = - Subscription, - TopXMLNS) -> - encode_pubsub_subscription(Subscription, TopXMLNS); -encode({ps_affiliation, - <<"http://jabber.org/protocol/pubsub">>, _, _, _} = - Affiliation, - TopXMLNS) -> - encode_pubsub_affiliation(Affiliation, TopXMLNS); -encode({ps_affiliation, <<>>, _, _, _} = Affiliation, - TopXMLNS = <<"http://jabber.org/protocol/pubsub">>) -> - encode_pubsub_affiliation(Affiliation, TopXMLNS); -encode({ps_affiliation, - <<"http://jabber.org/protocol/pubsub#owner">>, _, _, - _} = - Affiliation, - TopXMLNS) -> - encode_pubsub_owner_affiliation(Affiliation, TopXMLNS); -encode({ps_affiliation, <<>>, _, _, _} = Affiliation, - TopXMLNS = - <<"http://jabber.org/protocol/pubsub#owner">>) -> - encode_pubsub_owner_affiliation(Affiliation, TopXMLNS); -encode({ps_item, _, _, _, _, _} = Item, TopXMLNS) -> - encode_pubsub_item(Item, TopXMLNS); -encode({ps_items, _, _, _, _, _, _} = Items, - TopXMLNS) -> - encode_pubsub_items(Items, TopXMLNS); -encode({ps_event, _, _, _, _, _, _} = Event, - TopXMLNS) -> - encode_pubsub_event(Event, TopXMLNS); -encode({ps_subscribe, _, _} = Subscribe, TopXMLNS) -> - encode_pubsub_subscribe(Subscribe, TopXMLNS); -encode({ps_unsubscribe, _, _, _} = Unsubscribe, - TopXMLNS) -> - encode_pubsub_unsubscribe(Unsubscribe, TopXMLNS); -encode({ps_publish, _, _} = Publish, TopXMLNS) -> - encode_pubsub_publish(Publish, TopXMLNS); -encode({ps_options, _, _, _, _} = Options, TopXMLNS) -> - encode_pubsub_options(Options, TopXMLNS); -encode({ps_retract, _, _, _} = Retract, TopXMLNS) -> - encode_pubsub_retract(Retract, TopXMLNS); -encode({pubsub, _, _, _, _, _, _, _, _, _, _, _, _, _, - _, _, _} = - Pubsub, - TopXMLNS) -> - encode_pubsub(Pubsub, TopXMLNS); -encode({pubsub_owner, _, _, _, _, _, _} = Pubsub, - TopXMLNS) -> - encode_pubsub_owner(Pubsub, TopXMLNS); -encode({ps_error, 'closed-node', _} = Closed_node, - TopXMLNS) -> - encode_pubsub_error_closed_node(Closed_node, TopXMLNS); -encode({ps_error, 'configuration-required', _} = - Configuration_required, - TopXMLNS) -> - encode_pubsub_error_configuration_required(Configuration_required, - TopXMLNS); -encode({ps_error, 'invalid-jid', _} = Invalid_jid, - TopXMLNS) -> - encode_pubsub_error_invalid_jid(Invalid_jid, TopXMLNS); -encode({ps_error, 'invalid-options', _} = - Invalid_options, - TopXMLNS) -> - encode_pubsub_error_invalid_options(Invalid_options, - TopXMLNS); -encode({ps_error, 'invalid-payload', _} = - Invalid_payload, - TopXMLNS) -> - encode_pubsub_error_invalid_payload(Invalid_payload, - TopXMLNS); -encode({ps_error, 'invalid-subid', _} = Invalid_subid, - TopXMLNS) -> - encode_pubsub_error_invalid_subid(Invalid_subid, - TopXMLNS); -encode({ps_error, 'item-forbidden', _} = Item_forbidden, - TopXMLNS) -> - encode_pubsub_error_item_forbidden(Item_forbidden, - TopXMLNS); -encode({ps_error, 'item-required', _} = Item_required, - TopXMLNS) -> - encode_pubsub_error_item_required(Item_required, - TopXMLNS); -encode({ps_error, 'jid-required', _} = Jid_required, - TopXMLNS) -> - encode_pubsub_error_jid_required(Jid_required, - TopXMLNS); -encode({ps_error, 'max-items-exceeded', _} = - Max_items_exceeded, - TopXMLNS) -> - encode_pubsub_error_max_items_exceeded(Max_items_exceeded, - TopXMLNS); -encode({ps_error, 'max-nodes-exceeded', _} = - Max_nodes_exceeded, - TopXMLNS) -> - encode_pubsub_error_max_nodes_exceeded(Max_nodes_exceeded, - TopXMLNS); -encode({ps_error, 'nodeid-required', _} = - Nodeid_required, - TopXMLNS) -> - encode_pubsub_error_nodeid_required(Nodeid_required, - TopXMLNS); -encode({ps_error, 'not-in-roster-group', _} = - Not_in_roster_group, - TopXMLNS) -> - encode_pubsub_error_not_in_roster_group(Not_in_roster_group, - TopXMLNS); -encode({ps_error, 'not-subscribed', _} = Not_subscribed, - TopXMLNS) -> - encode_pubsub_error_not_subscribed(Not_subscribed, - TopXMLNS); -encode({ps_error, 'payload-too-big', _} = - Payload_too_big, - TopXMLNS) -> - encode_pubsub_error_payload_too_big(Payload_too_big, - TopXMLNS); -encode({ps_error, 'payload-required', _} = - Payload_required, - TopXMLNS) -> - encode_pubsub_error_payload_required(Payload_required, - TopXMLNS); -encode({ps_error, 'pending-subscription', _} = - Pending_subscription, - TopXMLNS) -> - encode_pubsub_error_pending_subscription(Pending_subscription, - TopXMLNS); -encode({ps_error, 'presence-subscription-required', _} = - Presence_subscription_required, - TopXMLNS) -> - encode_pubsub_error_presence_subscription_required(Presence_subscription_required, - TopXMLNS); -encode({ps_error, 'subid-required', _} = Subid_required, - TopXMLNS) -> - encode_pubsub_error_subid_required(Subid_required, - TopXMLNS); -encode({ps_error, 'too-many-subscriptions', _} = - Too_many_subscriptions, - TopXMLNS) -> - encode_pubsub_error_too_many_subscriptions(Too_many_subscriptions, - TopXMLNS); -encode({ps_error, unsupported, _} = Unsupported, - TopXMLNS) -> - encode_pubsub_error_unsupported(Unsupported, TopXMLNS); -encode({ps_error, 'unsupported-access-model', _} = - Unsupported_access_model, - TopXMLNS) -> - encode_pubsub_error_unsupported_access_model(Unsupported_access_model, - TopXMLNS); -encode({shim, _} = Headers, TopXMLNS) -> - encode_shim_headers(Headers, TopXMLNS); -encode({chatstate, active} = Active, TopXMLNS) -> - encode_chatstate_active(Active, TopXMLNS); -encode({chatstate, composing} = Composing, TopXMLNS) -> - encode_chatstate_composing(Composing, TopXMLNS); -encode({chatstate, gone} = Gone, TopXMLNS) -> - encode_chatstate_gone(Gone, TopXMLNS); -encode({chatstate, inactive} = Inactive, TopXMLNS) -> - encode_chatstate_inactive(Inactive, TopXMLNS); -encode({chatstate, paused} = Paused, TopXMLNS) -> - encode_chatstate_paused(Paused, TopXMLNS); -encode({delay, _, _, _} = Delay, TopXMLNS) -> - encode_delay(Delay, TopXMLNS); -encode({streamhost, _, _, _} = Streamhost, TopXMLNS) -> - encode_bytestreams_streamhost(Streamhost, TopXMLNS); -encode({bytestreams, _, _, _, _, _, _} = Query, - TopXMLNS) -> - encode_bytestreams(Query, TopXMLNS); -encode({muc_history, _, _, _, _} = History, TopXMLNS) -> - encode_muc_history(History, TopXMLNS); -encode({muc_decline, _, _, _} = Decline, TopXMLNS) -> - encode_muc_user_decline(Decline, TopXMLNS); -encode({muc_destroy, _, _, _, _} = Destroy, TopXMLNS) -> - encode_muc_destroy(Destroy, TopXMLNS); -encode({muc_invite, _, _, _, _} = Invite, TopXMLNS) -> - encode_muc_user_invite(Invite, TopXMLNS); -encode({muc_user, _, _, _, _, _, _} = X, TopXMLNS) -> - encode_muc_user(X, TopXMLNS); -encode({muc_owner, _, _, _} = Query, TopXMLNS) -> - encode_muc_owner(Query, TopXMLNS); -encode({muc_item, _, _, _, _, _, _, _} = Item, - TopXMLNS) -> - encode_muc_admin_item(Item, TopXMLNS); -encode({muc_actor, _, _} = Actor, TopXMLNS) -> - encode_muc_admin_actor(Actor, TopXMLNS); -encode({muc_admin, _} = Query, TopXMLNS) -> - encode_muc_admin(Query, TopXMLNS); -encode({muc, _, _} = X, TopXMLNS) -> - encode_muc(X, TopXMLNS); -encode({muc_unique, _} = Unique, TopXMLNS) -> - encode_muc_unique(Unique, TopXMLNS); -encode({x_conference, _, _, _, _, _} = X, TopXMLNS) -> - encode_x_conference(X, TopXMLNS); -encode({muc_subscriptions, _} = Subscriptions, - TopXMLNS) -> - encode_muc_subscriptions(Subscriptions, TopXMLNS); -encode({muc_subscribe, _, _} = Subscribe, TopXMLNS) -> - encode_muc_subscribe(Subscribe, TopXMLNS); -encode({muc_unsubscribe} = Unsubscribe, TopXMLNS) -> - encode_muc_unsubscribe(Unsubscribe, TopXMLNS); -encode({rsm_first, _, _} = First, TopXMLNS) -> - encode_rsm_first(First, TopXMLNS); -encode({rsm_set, _, _, _, _, _, _, _} = Set, - TopXMLNS) -> - encode_rsm_set(Set, TopXMLNS); -encode({mam_query, _, _, _, _, _, _, _, _} = Query, - TopXMLNS) -> - encode_mam_query(Query, TopXMLNS); -encode({mam_archived, _, _} = Archived, TopXMLNS) -> - encode_mam_archived(Archived, TopXMLNS); -encode({mam_result, _, _, _, _} = Result, TopXMLNS) -> - encode_mam_result(Result, TopXMLNS); -encode({mam_prefs, _, _, _, _} = Prefs, TopXMLNS) -> - encode_mam_prefs(Prefs, TopXMLNS); -encode({mam_fin, _, _, _, _, _} = Fin, TopXMLNS) -> - encode_mam_fin(Fin, TopXMLNS); -encode({forwarded, _, _} = Forwarded, TopXMLNS) -> - encode_forwarded(Forwarded, TopXMLNS); -encode({carbons_disable} = Disable, TopXMLNS) -> - encode_carbons_disable(Disable, TopXMLNS); -encode({carbons_enable} = Enable, TopXMLNS) -> - encode_carbons_enable(Enable, TopXMLNS); -encode({carbons_private} = Private, TopXMLNS) -> - encode_carbons_private(Private, TopXMLNS); -encode({carbons_received, _} = Received, TopXMLNS) -> - encode_carbons_received(Received, TopXMLNS); -encode({carbons_sent, _} = Sent, TopXMLNS) -> - encode_carbons_sent(Sent, TopXMLNS); -encode({feature_csi, <<"urn:xmpp:csi:0">>} = Csi, - TopXMLNS) -> - encode_feature_csi(Csi, TopXMLNS); -encode({feature_csi, <<>>} = Csi, - TopXMLNS = <<"urn:xmpp:csi:0">>) -> - encode_feature_csi(Csi, TopXMLNS); -encode({csi, active} = Active, TopXMLNS) -> - encode_csi_active(Active, TopXMLNS); -encode({csi, inactive} = Inactive, TopXMLNS) -> - encode_csi_inactive(Inactive, TopXMLNS); -encode({feature_sm, _} = Sm, TopXMLNS) -> - encode_feature_sm(Sm, TopXMLNS); -encode({sm_enable, _, _, _} = Enable, TopXMLNS) -> - encode_sm_enable(Enable, TopXMLNS); -encode({sm_enabled, _, _, _, _, _} = Enabled, - TopXMLNS) -> - encode_sm_enabled(Enabled, TopXMLNS); -encode({sm_resume, _, _, _} = Resume, TopXMLNS) -> - encode_sm_resume(Resume, TopXMLNS); -encode({sm_resumed, _, _, _} = Resumed, TopXMLNS) -> - encode_sm_resumed(Resumed, TopXMLNS); -encode({sm_r, _} = R, TopXMLNS) -> - encode_sm_r(R, TopXMLNS); -encode({sm_a, _, _} = A, TopXMLNS) -> - encode_sm_a(A, TopXMLNS); -encode({sm_failed, _, _, _} = Failed, TopXMLNS) -> - encode_sm_failed(Failed, TopXMLNS); -encode({offline_item, _, _} = Item, TopXMLNS) -> - encode_offline_item(Item, TopXMLNS); -encode({offline, _, _, _} = Offline, TopXMLNS) -> - encode_offline(Offline, TopXMLNS); -encode({mix_join, _, _} = Join, TopXMLNS) -> - encode_mix_join(Join, TopXMLNS); -encode({mix_leave} = Leave, TopXMLNS) -> - encode_mix_leave(Leave, TopXMLNS); -encode({mix_participant, _, _} = Participant, - TopXMLNS) -> - encode_mix_participant(Participant, TopXMLNS); -encode({hint, 'no-copy'} = No_copy, TopXMLNS) -> - encode_hint_no_copy(No_copy, TopXMLNS); -encode({hint, 'no-store'} = No_store, TopXMLNS) -> - encode_hint_no_store(No_store, TopXMLNS); -encode({hint, 'no-storage'} = No_storage, TopXMLNS) -> - encode_hint_no_storage(No_storage, TopXMLNS); -encode({hint, store} = Store, TopXMLNS) -> - encode_hint_store(Store, TopXMLNS); -encode({hint, 'no-permanent-store'} = - No_permanent_store, - TopXMLNS) -> - encode_hint_no_permanent_store(No_permanent_store, - TopXMLNS); -encode({hint, 'no-permanent-storage'} = - No_permanent_storage, - TopXMLNS) -> - encode_hint_no_permanent_storage(No_permanent_storage, - TopXMLNS); -encode({search_item, _, _, _, _, _} = Item, TopXMLNS) -> - encode_search_item(Item, TopXMLNS); -encode({search, _, _, _, _, _, _, _} = Query, - TopXMLNS) -> - encode_search(Query, TopXMLNS); -encode({xevent, _, _, _, _, _} = X, TopXMLNS) -> - encode_xevent(X, TopXMLNS); -encode({expire, _, _} = X, TopXMLNS) -> - encode_expire(X, TopXMLNS); -encode({nick, _} = Nick, TopXMLNS) -> - encode_nick(Nick, TopXMLNS); -encode({address, _, _, _, _, _} = Address, TopXMLNS) -> - encode_address(Address, TopXMLNS); -encode({addresses, _} = Addresses, TopXMLNS) -> - encode_addresses(Addresses, TopXMLNS); -encode({stanza_id, _, _} = Stanza_id, TopXMLNS) -> - encode_stanza_id(Stanza_id, TopXMLNS); -encode({client_id, _} = Client_id, TopXMLNS) -> - encode_client_id(Client_id, TopXMLNS); -encode({adhoc_actions, _, _, _, _} = Actions, - TopXMLNS) -> - encode_adhoc_command_actions(Actions, TopXMLNS); -encode({adhoc_note, _, _} = Note, TopXMLNS) -> - encode_adhoc_command_notes(Note, TopXMLNS); -encode({adhoc_command, _, _, _, _, _, _, _, _} = - Command, - TopXMLNS) -> - encode_adhoc_command(Command, TopXMLNS); -encode({db_result, _, _, _, _, _} = Db_result, - TopXMLNS) -> - encode_db_result(Db_result, TopXMLNS); -encode({db_verify, _, _, _, _, _, _} = Db_verify, - TopXMLNS) -> - encode_db_verify(Db_verify, TopXMLNS); -encode({handshake, _} = Handshake, TopXMLNS) -> - encode_handshake(Handshake, TopXMLNS); -encode({stream_start, _, _, _, _, _, _, _, _} = - Stream_stream, - TopXMLNS) -> - encode_stream_start(Stream_stream, TopXMLNS); -encode({bob_data, _, _, _, _} = Data, TopXMLNS) -> - encode_bob_data(Data, TopXMLNS); -encode({xcaptcha, _} = Captcha, TopXMLNS) -> - encode_captcha(Captcha, TopXMLNS); -encode({media_uri, _, _} = Uri, TopXMLNS) -> - encode_media_uri(Uri, TopXMLNS); -encode({media, _, _, _} = Media, TopXMLNS) -> - encode_media(Media, TopXMLNS); -encode({oob_x, _, _, _} = X, TopXMLNS) -> - encode_oob_x(X, TopXMLNS); -encode({sic, _, _, _} = Address, TopXMLNS) -> - encode_sic(Address, TopXMLNS); -encode({upload_request, _, _, _, _} = Request, - TopXMLNS) -> - encode_upload_request(Request, TopXMLNS); -encode({upload_slot, _, _, _} = Slot, TopXMLNS) -> - encode_upload_slot(Slot, TopXMLNS); -encode({thumbnail, _, _, _, _} = Thumbnail, TopXMLNS) -> - encode_thumbnail(Thumbnail, TopXMLNS); -encode({privilege_perm, _, _} = Perm, TopXMLNS) -> - encode_privilege_perm(Perm, TopXMLNS); -encode({privilege, _, _} = Privilege, TopXMLNS) -> - encode_privilege(Privilege, TopXMLNS); -encode({delegated, _, _} = Delegated, TopXMLNS) -> - encode_delegated(Delegated, TopXMLNS); -encode({delegation, _, _} = Delegation, TopXMLNS) -> - encode_delegation(Delegation, TopXMLNS); -encode({delegation_query, _, _} = Query, TopXMLNS) -> - encode_delegation_query(Query, TopXMLNS). - -get_name({address, _, _, _, _, _}) -> <<"address">>; -get_name({addresses, _}) -> <<"addresses">>; -get_name({adhoc_actions, _, _, _, _}) -> <<"actions">>; -get_name({adhoc_command, _, _, _, _, _, _, _, _}) -> - <<"command">>; -get_name({adhoc_note, _, _}) -> <<"note">>; -get_name({bind, _, _}) -> <<"bind">>; -get_name({block, _}) -> <<"block">>; -get_name({block_list, _}) -> <<"blocklist">>; -get_name({bob_data, _, _, _, _}) -> <<"data">>; -get_name({bookmark_conference, _, _, _, _, _}) -> - <<"conference">>; -get_name({bookmark_storage, _, _}) -> <<"storage">>; -get_name({bookmark_url, _, _}) -> <<"url">>; -get_name({bytestreams, _, _, _, _, _, _}) -> - <<"query">>; -get_name({caps, _, _, _, _}) -> <<"c">>; -get_name({carbons_disable}) -> <<"disable">>; -get_name({carbons_enable}) -> <<"enable">>; -get_name({carbons_private}) -> <<"private">>; -get_name({carbons_received, _}) -> <<"received">>; -get_name({carbons_sent, _}) -> <<"sent">>; -get_name({chatstate, active}) -> <<"active">>; -get_name({chatstate, composing}) -> <<"composing">>; -get_name({chatstate, gone}) -> <<"gone">>; -get_name({chatstate, inactive}) -> <<"inactive">>; -get_name({chatstate, paused}) -> <<"paused">>; -get_name({client_id, _}) -> <<"client-id">>; -get_name({compress, _}) -> <<"compress">>; -get_name({compress_failure, _}) -> <<"failure">>; -get_name({compressed}) -> <<"compressed">>; -get_name({compression, _}) -> <<"compression">>; -get_name({csi, active}) -> <<"active">>; -get_name({csi, inactive}) -> <<"inactive">>; -get_name({db_result, _, _, _, _, _}) -> <<"db:result">>; -get_name({db_verify, _, _, _, _, _, _}) -> - <<"db:verify">>; -get_name({delay, _, _, _}) -> <<"delay">>; -get_name({delegated, _, _}) -> <<"delegated">>; -get_name({delegation, _, _}) -> <<"delegation">>; -get_name({delegation_query, _, _}) -> <<"query">>; -get_name({disco_info, _, _, _, _}) -> <<"query">>; -get_name({disco_item, _, _, _}) -> <<"item">>; -get_name({disco_items, _, _, _}) -> <<"query">>; -get_name({expire, _, _}) -> <<"x">>; -get_name({feature_csi, _}) -> <<"csi">>; -get_name({feature_register}) -> <<"register">>; -get_name({feature_sm, _}) -> <<"sm">>; -get_name({forwarded, _, _}) -> <<"forwarded">>; -get_name({gone, _}) -> <<"gone">>; -get_name({handshake, _}) -> <<"handshake">>; -get_name({hint, 'no-copy'}) -> <<"no-copy">>; -get_name({hint, 'no-permanent-storage'}) -> - <<"no-permanent-storage">>; -get_name({hint, 'no-permanent-store'}) -> - <<"no-permanent-store">>; -get_name({hint, 'no-storage'}) -> <<"no-storage">>; -get_name({hint, 'no-store'}) -> <<"no-store">>; -get_name({hint, store}) -> <<"store">>; -get_name({identity, _, _, _, _}) -> <<"identity">>; -get_name({iq, _, _, _, _, _, _}) -> <<"iq">>; -get_name({last, _, _}) -> <<"query">>; -get_name({legacy_auth, _, _, _, _}) -> <<"query">>; -get_name({mam_archived, _, _}) -> <<"archived">>; -get_name({mam_fin, _, _, _, _, _}) -> <<"fin">>; -get_name({mam_prefs, _, _, _, _}) -> <<"prefs">>; -get_name({mam_query, _, _, _, _, _, _, _, _}) -> - <<"query">>; -get_name({mam_result, _, _, _, _}) -> <<"result">>; -get_name({media, _, _, _}) -> <<"media">>; -get_name({media_uri, _, _}) -> <<"uri">>; -get_name({message, _, _, _, _, _, _, _, _, _}) -> - <<"message">>; -get_name({mix_join, _, _}) -> <<"join">>; -get_name({mix_leave}) -> <<"leave">>; -get_name({mix_participant, _, _}) -> <<"participant">>; -get_name({muc, _, _}) -> <<"x">>; -get_name({muc_actor, _, _}) -> <<"actor">>; -get_name({muc_admin, _}) -> <<"query">>; -get_name({muc_decline, _, _, _}) -> <<"decline">>; -get_name({muc_destroy, _, _, _, _}) -> <<"destroy">>; -get_name({muc_history, _, _, _, _}) -> <<"history">>; -get_name({muc_invite, _, _, _, _}) -> <<"invite">>; -get_name({muc_item, _, _, _, _, _, _, _}) -> <<"item">>; -get_name({muc_owner, _, _, _}) -> <<"query">>; -get_name({muc_subscribe, _, _}) -> <<"subscribe">>; -get_name({muc_subscriptions, _}) -> <<"subscriptions">>; -get_name({muc_unique, _}) -> <<"unique">>; -get_name({muc_unsubscribe}) -> <<"unsubscribe">>; -get_name({muc_user, _, _, _, _, _, _}) -> <<"x">>; -get_name({nick, _}) -> <<"nick">>; -get_name({offline, _, _, _}) -> <<"offline">>; -get_name({offline_item, _, _}) -> <<"item">>; -get_name({oob_x, _, _, _}) -> <<"x">>; -get_name({p1_ack}) -> <<"ack">>; -get_name({p1_push}) -> <<"push">>; -get_name({p1_rebind}) -> <<"rebind">>; -get_name({ping}) -> <<"ping">>; -get_name({presence, _, _, _, _, _, _, _, _, _}) -> - <<"presence">>; -get_name({privacy_item, _, _, _, _, _, _, _, _}) -> - <<"item">>; -get_name({privacy_list, _, _}) -> <<"list">>; -get_name({privacy_query, _, _, _}) -> <<"query">>; -get_name({private, _}) -> <<"query">>; -get_name({privilege, _, _}) -> <<"privilege">>; -get_name({privilege_perm, _, _}) -> <<"perm">>; -get_name({ps_affiliation, _, _, _, _}) -> - <<"affiliation">>; -get_name({ps_error, 'closed-node', _}) -> - <<"closed-node">>; -get_name({ps_error, 'configuration-required', _}) -> - <<"configuration-required">>; -get_name({ps_error, 'invalid-jid', _}) -> - <<"invalid-jid">>; -get_name({ps_error, 'invalid-options', _}) -> - <<"invalid-options">>; -get_name({ps_error, 'invalid-payload', _}) -> - <<"invalid-payload">>; -get_name({ps_error, 'invalid-subid', _}) -> - <<"invalid-subid">>; -get_name({ps_error, 'item-forbidden', _}) -> - <<"item-forbidden">>; -get_name({ps_error, 'item-required', _}) -> - <<"item-required">>; -get_name({ps_error, 'jid-required', _}) -> - <<"jid-required">>; -get_name({ps_error, 'max-items-exceeded', _}) -> - <<"max-items-exceeded">>; -get_name({ps_error, 'max-nodes-exceeded', _}) -> - <<"max-nodes-exceeded">>; -get_name({ps_error, 'nodeid-required', _}) -> - <<"nodeid-required">>; -get_name({ps_error, 'not-in-roster-group', _}) -> - <<"not-in-roster-group">>; -get_name({ps_error, 'not-subscribed', _}) -> - <<"not-subscribed">>; -get_name({ps_error, 'payload-required', _}) -> - <<"payload-required">>; -get_name({ps_error, 'payload-too-big', _}) -> - <<"payload-too-big">>; -get_name({ps_error, 'pending-subscription', _}) -> - <<"pending-subscription">>; -get_name({ps_error, 'presence-subscription-required', - _}) -> - <<"presence-subscription-required">>; -get_name({ps_error, 'subid-required', _}) -> - <<"subid-required">>; -get_name({ps_error, 'too-many-subscriptions', _}) -> - <<"too-many-subscriptions">>; -get_name({ps_error, unsupported, _}) -> - <<"unsupported">>; -get_name({ps_error, 'unsupported-access-model', _}) -> - <<"unsupported-access-model">>; -get_name({ps_event, _, _, _, _, _, _}) -> <<"event">>; -get_name({ps_item, _, _, _, _, _}) -> <<"item">>; -get_name({ps_items, _, _, _, _, _, _}) -> <<"items">>; -get_name({ps_options, _, _, _, _}) -> <<"options">>; -get_name({ps_publish, _, _}) -> <<"publish">>; -get_name({ps_retract, _, _, _}) -> <<"retract">>; -get_name({ps_subscribe, _, _}) -> <<"subscribe">>; -get_name({ps_subscription, _, _, _, _, _, _}) -> - <<"subscription">>; -get_name({ps_unsubscribe, _, _, _}) -> - <<"unsubscribe">>; -get_name({pubsub, _, _, _, _, _, _, _, _, _, _, _, _, _, - _, _, _}) -> - <<"pubsub">>; -get_name({pubsub_owner, _, _, _, _, _, _}) -> - <<"pubsub">>; -get_name({redirect, _}) -> <<"redirect">>; -get_name({register, _, _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, _, _}) -> - <<"query">>; -get_name({roster_item, _, _, _, _, _}) -> <<"item">>; -get_name({roster_query, _, _}) -> <<"query">>; -get_name({rosterver_feature}) -> <<"ver">>; -get_name({rsm_first, _, _}) -> <<"first">>; -get_name({rsm_set, _, _, _, _, _, _, _}) -> <<"set">>; -get_name({sasl_abort}) -> <<"abort">>; -get_name({sasl_auth, _, _}) -> <<"auth">>; -get_name({sasl_challenge, _}) -> <<"challenge">>; -get_name({sasl_failure, _, _}) -> <<"failure">>; -get_name({sasl_mechanisms, _}) -> <<"mechanisms">>; -get_name({sasl_response, _}) -> <<"response">>; -get_name({sasl_success, _}) -> <<"success">>; -get_name({search, _, _, _, _, _, _, _}) -> <<"query">>; -get_name({search_item, _, _, _, _, _}) -> <<"item">>; -get_name({'see-other-host', _}) -> <<"see-other-host">>; -get_name({shim, _}) -> <<"headers">>; -get_name({sic, _, _, _}) -> <<"address">>; -get_name({sm_a, _, _}) -> <<"a">>; -get_name({sm_enable, _, _, _}) -> <<"enable">>; -get_name({sm_enabled, _, _, _, _, _}) -> <<"enabled">>; -get_name({sm_failed, _, _, _}) -> <<"failed">>; -get_name({sm_r, _}) -> <<"r">>; -get_name({sm_resume, _, _, _}) -> <<"resume">>; -get_name({sm_resumed, _, _, _}) -> <<"resumed">>; -get_name({stanza_error, _, _, _, _, _, _}) -> - <<"error">>; -get_name({stanza_id, _, _}) -> <<"stanza-id">>; -get_name({starttls, _}) -> <<"starttls">>; -get_name({starttls_failure}) -> <<"failure">>; -get_name({starttls_proceed}) -> <<"proceed">>; -get_name({stat, _, _, _, _}) -> <<"stat">>; -get_name({stat_error, _, _}) -> <<"error">>; -get_name({stats, _, _}) -> <<"query">>; -get_name({stream_error, _, _}) -> <<"stream:error">>; -get_name({stream_features, _}) -> <<"stream:features">>; -get_name({stream_start, _, _, _, _, _, _, _, _}) -> - <<"stream:stream">>; -get_name({streamhost, _, _, _}) -> <<"streamhost">>; -get_name({text, _, _}) -> <<"text">>; -get_name({thumbnail, _, _, _, _}) -> <<"thumbnail">>; -get_name({time, _, _}) -> <<"time">>; -get_name({unblock, _}) -> <<"unblock">>; -get_name({upload_request, _, _, _, _}) -> <<"request">>; -get_name({upload_slot, _, _, _}) -> <<"slot">>; -get_name({vcard_adr, _, _, _, _, _, _, _, _, _, _, _, _, - _, _}) -> - <<"ADR">>; -get_name({vcard_email, _, _, _, _, _, _}) -> - <<"EMAIL">>; -get_name({vcard_geo, _, _}) -> <<"GEO">>; -get_name({vcard_key, _, _}) -> <<"KEY">>; -get_name({vcard_label, _, _, _, _, _, _, _, _}) -> - <<"LABEL">>; -get_name({vcard_logo, _, _, _}) -> <<"LOGO">>; -get_name({vcard_name, _, _, _, _, _}) -> <<"N">>; -get_name({vcard_org, _, _}) -> <<"ORG">>; -get_name({vcard_photo, _, _, _}) -> <<"PHOTO">>; -get_name({vcard_sound, _, _, _}) -> <<"SOUND">>; -get_name({vcard_tel, _, _, _, _, _, _, _, _, _, _, _, _, - _, _}) -> - <<"TEL">>; -get_name({vcard_temp, _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, - _}) -> - <<"vCard">>; -get_name({vcard_xupdate, _, _}) -> <<"x">>; -get_name({version, _, _, _}) -> <<"query">>; -get_name({x_conference, _, _, _, _, _}) -> <<"x">>; -get_name({xcaptcha, _}) -> <<"captcha">>; -get_name({xdata, _, _, _, _, _, _}) -> <<"x">>; -get_name({xdata_field, _, _, _, _, _, _, _, _}) -> - <<"field">>; -get_name({xdata_option, _, _}) -> <<"option">>; -get_name({xevent, _, _, _, _, _}) -> <<"x">>; -get_name({xmpp_session, _}) -> <<"session">>. - -get_ns({address, _, _, _, _, _}) -> - <<"http://jabber.org/protocol/address">>; -get_ns({addresses, _}) -> - <<"http://jabber.org/protocol/address">>; -get_ns({adhoc_actions, _, _, _, _}) -> - <<"http://jabber.org/protocol/commands">>; -get_ns({adhoc_command, _, _, _, _, _, _, _, _}) -> - <<"http://jabber.org/protocol/commands">>; -get_ns({adhoc_note, _, _}) -> - <<"http://jabber.org/protocol/commands">>; -get_ns({bind, _, _}) -> - <<"urn:ietf:params:xml:ns:xmpp-bind">>; -get_ns({block, _}) -> <<"urn:xmpp:blocking">>; -get_ns({block_list, _}) -> <<"urn:xmpp:blocking">>; -get_ns({bob_data, _, _, _, _}) -> <<"urn:xmpp:bob">>; -get_ns({bookmark_conference, _, _, _, _, _}) -> - <<"storage:bookmarks">>; -get_ns({bookmark_storage, _, _}) -> - <<"storage:bookmarks">>; -get_ns({bookmark_url, _, _}) -> <<"storage:bookmarks">>; -get_ns({bytestreams, _, _, _, _, _, _}) -> - <<"http://jabber.org/protocol/bytestreams">>; -get_ns({caps, _, _, _, _}) -> - <<"http://jabber.org/protocol/caps">>; -get_ns({carbons_disable}) -> <<"urn:xmpp:carbons:2">>; -get_ns({carbons_enable}) -> <<"urn:xmpp:carbons:2">>; -get_ns({carbons_private}) -> <<"urn:xmpp:carbons:2">>; -get_ns({carbons_received, _}) -> - <<"urn:xmpp:carbons:2">>; -get_ns({carbons_sent, _}) -> <<"urn:xmpp:carbons:2">>; -get_ns({chatstate, active}) -> - <<"http://jabber.org/protocol/chatstates">>; -get_ns({chatstate, composing}) -> - <<"http://jabber.org/protocol/chatstates">>; -get_ns({chatstate, gone}) -> - <<"http://jabber.org/protocol/chatstates">>; -get_ns({chatstate, inactive}) -> - <<"http://jabber.org/protocol/chatstates">>; -get_ns({chatstate, paused}) -> - <<"http://jabber.org/protocol/chatstates">>; -get_ns({client_id, _}) -> <<"urn:xmpp:sid:0">>; -get_ns({compress, _}) -> - <<"http://jabber.org/protocol/compress">>; -get_ns({compress_failure, _}) -> - <<"http://jabber.org/protocol/compress">>; -get_ns({compressed}) -> - <<"http://jabber.org/protocol/compress">>; -get_ns({compression, _}) -> - <<"http://jabber.org/features/compress">>; -get_ns({csi, active}) -> <<"urn:xmpp:csi:0">>; -get_ns({csi, inactive}) -> <<"urn:xmpp:csi:0">>; -get_ns({db_result, _, _, _, _, _}) -> - <<"jabber:server">>; -get_ns({db_verify, _, _, _, _, _, _}) -> - <<"jabber:server">>; -get_ns({delay, _, _, _}) -> <<"urn:xmpp:delay">>; -get_ns({delegated, _, _}) -> - <<"urn:xmpp:delegation:1">>; -get_ns({delegation, _, _}) -> - <<"urn:xmpp:delegation:1">>; -get_ns({delegation_query, _, _}) -> - <<"urn:xmpp:delegation:1">>; -get_ns({disco_info, _, _, _, _}) -> - <<"http://jabber.org/protocol/disco#info">>; -get_ns({disco_item, _, _, _}) -> - <<"http://jabber.org/protocol/disco#items">>; -get_ns({disco_items, _, _, _}) -> - <<"http://jabber.org/protocol/disco#items">>; -get_ns({expire, _, _}) -> <<"jabber:x:expire">>; -get_ns({feature_csi, Xmlns}) -> Xmlns; -get_ns({feature_register}) -> - <<"http://jabber.org/features/iq-register">>; -get_ns({feature_sm, Xmlns}) -> Xmlns; -get_ns({forwarded, _, _}) -> <<"urn:xmpp:forward:0">>; -get_ns({gone, _}) -> - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>; -get_ns({handshake, _}) -> <<"jabber:component:accept">>; -get_ns({hint, 'no-copy'}) -> <<"urn:xmpp:hints">>; -get_ns({hint, 'no-permanent-storage'}) -> - <<"urn:xmpp:hints">>; -get_ns({hint, 'no-permanent-store'}) -> - <<"urn:xmpp:hints">>; -get_ns({hint, 'no-storage'}) -> <<"urn:xmpp:hints">>; -get_ns({hint, 'no-store'}) -> <<"urn:xmpp:hints">>; -get_ns({hint, store}) -> <<"urn:xmpp:hints">>; -get_ns({identity, _, _, _, _}) -> - <<"http://jabber.org/protocol/disco#info">>; -get_ns({iq, _, _, _, _, _, _}) -> <<"jabber:client">>; -get_ns({last, _, _}) -> <<"jabber:iq:last">>; -get_ns({legacy_auth, _, _, _, _}) -> - <<"jabber:iq:auth">>; -get_ns({mam_archived, _, _}) -> <<"urn:xmpp:mam:tmp">>; -get_ns({mam_fin, Xmlns, _, _, _, _}) -> Xmlns; -get_ns({mam_prefs, Xmlns, _, _, _}) -> Xmlns; -get_ns({mam_query, Xmlns, _, _, _, _, _, _, _}) -> - Xmlns; -get_ns({mam_result, Xmlns, _, _, _}) -> Xmlns; -get_ns({media, _, _, _}) -> - <<"urn:xmpp:media-element">>; -get_ns({media_uri, _, _}) -> - <<"urn:xmpp:media-element">>; -get_ns({message, _, _, _, _, _, _, _, _, _}) -> - <<"jabber:client">>; -get_ns({mix_join, _, _}) -> <<"urn:xmpp:mix:0">>; -get_ns({mix_leave}) -> <<"urn:xmpp:mix:0">>; -get_ns({mix_participant, _, _}) -> <<"urn:xmpp:mix:0">>; -get_ns({muc, _, _}) -> - <<"http://jabber.org/protocol/muc">>; -get_ns({muc_admin, _}) -> - <<"http://jabber.org/protocol/muc#admin">>; -get_ns({muc_decline, _, _, _}) -> - <<"http://jabber.org/protocol/muc#user">>; -get_ns({muc_destroy, Xmlns, _, _, _}) -> Xmlns; -get_ns({muc_history, _, _, _, _}) -> - <<"http://jabber.org/protocol/muc">>; -get_ns({muc_invite, _, _, _, _}) -> - <<"http://jabber.org/protocol/muc#user">>; -get_ns({muc_owner, _, _, _}) -> - <<"http://jabber.org/protocol/muc#owner">>; -get_ns({muc_subscribe, _, _}) -> - <<"urn:xmpp:mucsub:0">>; -get_ns({muc_subscriptions, _}) -> - <<"urn:xmpp:mucsub:0">>; -get_ns({muc_unique, _}) -> - <<"http://jabber.org/protocol/muc#unique">>; -get_ns({muc_unsubscribe}) -> <<"urn:xmpp:mucsub:0">>; -get_ns({muc_user, _, _, _, _, _, _}) -> - <<"http://jabber.org/protocol/muc#user">>; -get_ns({nick, _}) -> - <<"http://jabber.org/protocol/nick">>; -get_ns({offline, _, _, _}) -> - <<"http://jabber.org/protocol/offline">>; -get_ns({offline_item, _, _}) -> - <<"http://jabber.org/protocol/offline">>; -get_ns({oob_x, _, _, _}) -> <<"jabber:x:oob">>; -get_ns({p1_ack}) -> <<"p1:ack">>; -get_ns({p1_push}) -> <<"p1:push">>; -get_ns({p1_rebind}) -> <<"p1:rebind">>; -get_ns({ping}) -> <<"urn:xmpp:ping">>; -get_ns({presence, _, _, _, _, _, _, _, _, _}) -> - <<"jabber:client">>; -get_ns({privacy_item, _, _, _, _, _, _, _, _}) -> - <<"jabber:iq:privacy">>; -get_ns({privacy_list, _, _}) -> <<"jabber:iq:privacy">>; -get_ns({privacy_query, _, _, _}) -> - <<"jabber:iq:privacy">>; -get_ns({private, _}) -> <<"jabber:iq:private">>; -get_ns({privilege, _, _}) -> <<"urn:xmpp:privilege:1">>; -get_ns({privilege_perm, _, _}) -> - <<"urn:xmpp:privilege:1">>; -get_ns({ps_affiliation, Xmlns, _, _, _}) -> Xmlns; -get_ns({ps_error, 'closed-node', _}) -> - <<"http://jabber.org/protocol/pubsub#errors">>; -get_ns({ps_error, 'configuration-required', _}) -> - <<"http://jabber.org/protocol/pubsub#errors">>; -get_ns({ps_error, 'invalid-jid', _}) -> - <<"http://jabber.org/protocol/pubsub#errors">>; -get_ns({ps_error, 'invalid-options', _}) -> - <<"http://jabber.org/protocol/pubsub#errors">>; -get_ns({ps_error, 'invalid-payload', _}) -> - <<"http://jabber.org/protocol/pubsub#errors">>; -get_ns({ps_error, 'invalid-subid', _}) -> - <<"http://jabber.org/protocol/pubsub#errors">>; -get_ns({ps_error, 'item-forbidden', _}) -> - <<"http://jabber.org/protocol/pubsub#errors">>; -get_ns({ps_error, 'item-required', _}) -> - <<"http://jabber.org/protocol/pubsub#errors">>; -get_ns({ps_error, 'jid-required', _}) -> - <<"http://jabber.org/protocol/pubsub#errors">>; -get_ns({ps_error, 'max-items-exceeded', _}) -> - <<"http://jabber.org/protocol/pubsub#errors">>; -get_ns({ps_error, 'max-nodes-exceeded', _}) -> - <<"http://jabber.org/protocol/pubsub#errors">>; -get_ns({ps_error, 'nodeid-required', _}) -> - <<"http://jabber.org/protocol/pubsub#errors">>; -get_ns({ps_error, 'not-in-roster-group', _}) -> - <<"http://jabber.org/protocol/pubsub#errors">>; -get_ns({ps_error, 'not-subscribed', _}) -> - <<"http://jabber.org/protocol/pubsub#errors">>; -get_ns({ps_error, 'payload-required', _}) -> - <<"http://jabber.org/protocol/pubsub#errors">>; -get_ns({ps_error, 'payload-too-big', _}) -> - <<"http://jabber.org/protocol/pubsub#errors">>; -get_ns({ps_error, 'pending-subscription', _}) -> - <<"http://jabber.org/protocol/pubsub#errors">>; -get_ns({ps_error, 'presence-subscription-required', - _}) -> - <<"http://jabber.org/protocol/pubsub#errors">>; -get_ns({ps_error, 'subid-required', _}) -> - <<"http://jabber.org/protocol/pubsub#errors">>; -get_ns({ps_error, 'too-many-subscriptions', _}) -> - <<"http://jabber.org/protocol/pubsub#errors">>; -get_ns({ps_error, unsupported, _}) -> - <<"http://jabber.org/protocol/pubsub#errors">>; -get_ns({ps_error, 'unsupported-access-model', _}) -> - <<"http://jabber.org/protocol/pubsub#errors">>; -get_ns({ps_event, _, _, _, _, _, _}) -> - <<"http://jabber.org/protocol/pubsub#event">>; -get_ns({ps_item, Xmlns, _, _, _, _}) -> Xmlns; -get_ns({ps_items, Xmlns, _, _, _, _, _}) -> Xmlns; -get_ns({ps_options, _, _, _, _}) -> - <<"http://jabber.org/protocol/pubsub">>; -get_ns({ps_publish, _, _}) -> - <<"http://jabber.org/protocol/pubsub">>; -get_ns({ps_retract, _, _, _}) -> - <<"http://jabber.org/protocol/pubsub">>; -get_ns({ps_subscribe, _, _}) -> - <<"http://jabber.org/protocol/pubsub">>; -get_ns({ps_subscription, Xmlns, _, _, _, _, _}) -> - Xmlns; -get_ns({ps_unsubscribe, _, _, _}) -> - <<"http://jabber.org/protocol/pubsub">>; -get_ns({pubsub, _, _, _, _, _, _, _, _, _, _, _, _, _, - _, _, _}) -> - <<"http://jabber.org/protocol/pubsub">>; -get_ns({pubsub_owner, _, _, _, _, _, _}) -> - <<"http://jabber.org/protocol/pubsub#owner">>; -get_ns({redirect, _}) -> - <<"urn:ietf:params:xml:ns:xmpp-stanzas">>; -get_ns({register, _, _, _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, _}) -> - <<"jabber:iq:register">>; -get_ns({roster_item, _, _, _, _, _}) -> - <<"jabber:iq:roster">>; -get_ns({roster_query, _, _}) -> <<"jabber:iq:roster">>; -get_ns({rosterver_feature}) -> - <<"urn:xmpp:features:rosterver">>; -get_ns({rsm_first, _, _}) -> - <<"http://jabber.org/protocol/rsm">>; -get_ns({rsm_set, _, _, _, _, _, _, _}) -> - <<"http://jabber.org/protocol/rsm">>; -get_ns({sasl_abort}) -> - <<"urn:ietf:params:xml:ns:xmpp-sasl">>; -get_ns({sasl_auth, _, _}) -> - <<"urn:ietf:params:xml:ns:xmpp-sasl">>; -get_ns({sasl_challenge, _}) -> - <<"urn:ietf:params:xml:ns:xmpp-sasl">>; -get_ns({sasl_failure, _, _}) -> - <<"urn:ietf:params:xml:ns:xmpp-sasl">>; -get_ns({sasl_mechanisms, _}) -> - <<"urn:ietf:params:xml:ns:xmpp-sasl">>; -get_ns({sasl_response, _}) -> - <<"urn:ietf:params:xml:ns:xmpp-sasl">>; -get_ns({sasl_success, _}) -> - <<"urn:ietf:params:xml:ns:xmpp-sasl">>; -get_ns({search, _, _, _, _, _, _, _}) -> - <<"jabber:iq:search">>; -get_ns({search_item, _, _, _, _, _}) -> - <<"jabber:iq:search">>; -get_ns({'see-other-host', _}) -> - <<"urn:ietf:params:xml:ns:xmpp-streams">>; -get_ns({shim, _}) -> - <<"http://jabber.org/protocol/shim">>; -get_ns({sic, _, _, Xmlns}) -> Xmlns; -get_ns({sm_a, _, Xmlns}) -> Xmlns; -get_ns({sm_enable, _, _, Xmlns}) -> Xmlns; -get_ns({sm_enabled, _, _, _, _, Xmlns}) -> Xmlns; -get_ns({sm_failed, _, _, Xmlns}) -> Xmlns; -get_ns({sm_r, Xmlns}) -> Xmlns; -get_ns({sm_resume, _, _, Xmlns}) -> Xmlns; -get_ns({sm_resumed, _, _, Xmlns}) -> Xmlns; -get_ns({stanza_error, _, _, _, _, _, _}) -> - <<"jabber:client">>; -get_ns({stanza_id, _, _}) -> <<"urn:xmpp:sid:0">>; -get_ns({starttls, _}) -> - <<"urn:ietf:params:xml:ns:xmpp-tls">>; -get_ns({starttls_failure}) -> - <<"urn:ietf:params:xml:ns:xmpp-tls">>; -get_ns({starttls_proceed}) -> - <<"urn:ietf:params:xml:ns:xmpp-tls">>; -get_ns({stat, _, _, _, _}) -> - <<"http://jabber.org/protocol/stats">>; -get_ns({stat_error, _, _}) -> - <<"http://jabber.org/protocol/stats">>; -get_ns({stats, _, _}) -> - <<"http://jabber.org/protocol/stats">>; -get_ns({stream_error, _, _}) -> <<"jabber:client">>; -get_ns({stream_features, _}) -> <<"jabber:client">>; -get_ns({stream_start, _, _, _, _, Xmlns, _, _, _}) -> - Xmlns; -get_ns({streamhost, _, _, _}) -> - <<"http://jabber.org/protocol/bytestreams">>; -get_ns({thumbnail, _, _, _, _}) -> - <<"urn:xmpp:thumbs:1">>; -get_ns({time, _, _}) -> <<"urn:xmpp:time">>; -get_ns({unblock, _}) -> <<"urn:xmpp:blocking">>; -get_ns({upload_request, _, _, _, Xmlns}) -> Xmlns; -get_ns({upload_slot, _, _, Xmlns}) -> Xmlns; -get_ns({vcard_adr, _, _, _, _, _, _, _, _, _, _, _, _, - _, _}) -> - <<"vcard-temp">>; -get_ns({vcard_email, _, _, _, _, _, _}) -> - <<"vcard-temp">>; -get_ns({vcard_geo, _, _}) -> <<"vcard-temp">>; -get_ns({vcard_key, _, _}) -> <<"vcard-temp">>; -get_ns({vcard_label, _, _, _, _, _, _, _, _}) -> - <<"vcard-temp">>; -get_ns({vcard_logo, _, _, _}) -> <<"vcard-temp">>; -get_ns({vcard_name, _, _, _, _, _}) -> <<"vcard-temp">>; -get_ns({vcard_org, _, _}) -> <<"vcard-temp">>; -get_ns({vcard_photo, _, _, _}) -> <<"vcard-temp">>; -get_ns({vcard_sound, _, _, _}) -> <<"vcard-temp">>; -get_ns({vcard_tel, _, _, _, _, _, _, _, _, _, _, _, _, - _, _}) -> - <<"vcard-temp">>; -get_ns({vcard_temp, _, _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _}) -> - <<"vcard-temp">>; -get_ns({vcard_xupdate, _, _}) -> - <<"vcard-temp:x:update">>; -get_ns({version, _, _, _}) -> <<"jabber:iq:version">>; -get_ns({x_conference, _, _, _, _, _}) -> - <<"jabber:x:conference">>; -get_ns({xcaptcha, _}) -> <<"urn:xmpp:captcha">>; -get_ns({xdata, _, _, _, _, _, _}) -> - <<"jabber:x:data">>; -get_ns({xdata_field, _, _, _, _, _, _, _, _}) -> - <<"jabber:x:data">>; -get_ns({xdata_option, _, _}) -> <<"jabber:x:data">>; -get_ns({xevent, _, _, _, _, _}) -> <<"jabber:x:event">>; -get_ns({xmpp_session, _}) -> - <<"urn:ietf:params:xml:ns:xmpp-session">>. - -dec_int(Val) -> dec_int(Val, infinity, infinity). - -dec_int(Val, Min, Max) -> - case list_to_integer(binary_to_list(Val)) of - Int when Int =< Max, Min == infinity -> Int; - Int when Int =< Max, Int >= Min -> Int - end. - -enc_int(Int) -> list_to_binary(integer_to_list(Int)). - -dec_enum(Val, Enums) -> - AtomVal = erlang:binary_to_existing_atom(Val, utf8), - case lists:member(AtomVal, Enums) of - true -> AtomVal - end. - -enc_enum(Atom) -> erlang:atom_to_binary(Atom, utf8). - -format_error({bad_attr_value, Attr, Tag, XMLNS}) -> - <<"Bad value of attribute '", Attr/binary, "' in tag <", - Tag/binary, "/> qualified by namespace '", XMLNS/binary, - "'">>; -format_error({bad_cdata_value, <<>>, Tag, XMLNS}) -> - <<"Bad value of cdata in tag <", Tag/binary, - "/> qualified by namespace '", XMLNS/binary, "'">>; -format_error({missing_tag, Tag, XMLNS}) -> - <<"Missing tag <", Tag/binary, - "/> qualified by namespace '", XMLNS/binary, "'">>; -format_error({missing_attr, Attr, Tag, XMLNS}) -> - <<"Missing attribute '", Attr/binary, "' in tag <", - Tag/binary, "/> qualified by namespace '", XMLNS/binary, - "'">>; -format_error({missing_cdata, <<>>, Tag, XMLNS}) -> - <<"Missing cdata in tag <", Tag/binary, - "/> qualified by namespace '", XMLNS/binary, "'">>; -format_error({unknown_tag, Tag, XMLNS}) -> - <<"Unknown tag <", Tag/binary, - "/> qualified by namespace '", XMLNS/binary, "'">>; -format_error({missing_tag_xmlns, Tag}) -> - <<"Missing namespace for tag <", Tag/binary, "/>">>. - -get_attr(Attr, Attrs) -> - case lists:keyfind(Attr, 1, Attrs) of - {_, Val} -> Val; - false -> <<>> - end. - -enc_xmlns_attrs(XMLNS, XMLNS) -> []; -enc_xmlns_attrs(XMLNS, _) -> [{<<"xmlns">>, XMLNS}]. - -choose_top_xmlns(<<>>, NSList, TopXMLNS) -> - case lists:member(TopXMLNS, NSList) of - true -> TopXMLNS; - false -> hd(NSList) - end; -choose_top_xmlns(XMLNS, _, _) -> XMLNS. - -pp(Term) -> io_lib_pretty:print(Term, fun pp/2). - -pp(last, 2) -> [seconds, status]; -pp(version, 3) -> [name, ver, os]; -pp(roster_item, 5) -> - [jid, name, groups, subscription, ask]; -pp(roster_query, 2) -> [items, ver]; -pp(rosterver_feature, 0) -> []; -pp(privacy_item, 8) -> - [order, action, type, value, message, iq, presence_in, - presence_out]; -pp(privacy_list, 2) -> [name, items]; -pp(privacy_query, 3) -> [lists, default, active]; -pp(block, 1) -> [items]; -pp(unblock, 1) -> [items]; -pp(block_list, 1) -> [items]; -pp(identity, 4) -> [category, type, lang, name]; -pp(disco_info, 4) -> - [node, identities, features, xdata]; -pp(disco_item, 3) -> [jid, name, node]; -pp(disco_items, 3) -> [node, items, rsm]; -pp(private, 1) -> [xml_els]; -pp(bookmark_conference, 5) -> - [name, jid, autojoin, nick, password]; -pp(bookmark_url, 2) -> [name, url]; -pp(bookmark_storage, 2) -> [conference, url]; -pp(stat_error, 2) -> [code, reason]; -pp(stat, 4) -> [name, units, value, error]; -pp(stats, 2) -> [list, node]; -pp(iq, 6) -> [id, type, lang, from, to, sub_els]; -pp(message, 9) -> - [id, type, lang, from, to, subject, body, thread, - sub_els]; -pp(presence, 9) -> - [id, type, lang, from, to, show, status, priority, - sub_els]; -pp(gone, 1) -> [uri]; -pp(redirect, 1) -> [uri]; -pp(stanza_error, 6) -> - [type, code, by, reason, text, sub_els]; -pp(bind, 2) -> [jid, resource]; -pp(legacy_auth, 4) -> - [username, password, digest, resource]; -pp(sasl_auth, 2) -> [mechanism, text]; -pp(sasl_abort, 0) -> []; -pp(sasl_challenge, 1) -> [text]; -pp(sasl_response, 1) -> [text]; -pp(sasl_success, 1) -> [text]; -pp(sasl_failure, 2) -> [reason, text]; -pp(sasl_mechanisms, 1) -> [list]; -pp(starttls, 1) -> [required]; -pp(starttls_proceed, 0) -> []; -pp(starttls_failure, 0) -> []; -pp(compress_failure, 1) -> [reason]; -pp(compress, 1) -> [methods]; -pp(compressed, 0) -> []; -pp(compression, 1) -> [methods]; -pp(stream_features, 1) -> [sub_els]; -pp(p1_push, 0) -> []; -pp(p1_rebind, 0) -> []; -pp(p1_ack, 0) -> []; -pp(caps, 4) -> [node, version, hash, exts]; -pp(feature_register, 0) -> []; -pp(register, 22) -> - [registered, remove, instructions, username, nick, - password, name, first, last, email, address, city, - state, zip, phone, url, date, misc, text, key, xdata, - sub_els]; -pp(xmpp_session, 1) -> [optional]; -pp(ping, 0) -> []; -pp(time, 2) -> [tzo, utc]; -pp(text, 2) -> [lang, data]; -pp('see-other-host', 1) -> [host]; -pp(stream_error, 2) -> [reason, text]; -pp(vcard_name, 5) -> - [family, given, middle, prefix, suffix]; -pp(vcard_adr, 14) -> - [home, work, postal, parcel, dom, intl, pref, pobox, - extadd, street, locality, region, pcode, ctry]; -pp(vcard_label, 8) -> - [home, work, postal, parcel, dom, intl, pref, line]; -pp(vcard_tel, 14) -> - [home, work, voice, fax, pager, msg, cell, video, bbs, - modem, isdn, pcs, pref, number]; -pp(vcard_email, 6) -> - [home, work, internet, pref, x400, userid]; -pp(vcard_geo, 2) -> [lat, lon]; -pp(vcard_logo, 3) -> [type, binval, extval]; -pp(vcard_photo, 3) -> [type, binval, extval]; -pp(vcard_org, 2) -> [name, units]; -pp(vcard_sound, 3) -> [phonetic, binval, extval]; -pp(vcard_key, 2) -> [type, cred]; -pp(vcard_temp, 29) -> - [version, fn, n, nickname, photo, bday, adr, label, tel, - email, jabberid, mailer, tz, geo, title, role, logo, - org, categories, note, prodid, rev, sort_string, sound, - uid, url, class, key, desc]; -pp(xdata_option, 2) -> [label, value]; -pp(xdata_field, 8) -> - [label, type, var, required, desc, values, options, - sub_els]; -pp(xdata, 6) -> - [type, instructions, title, reported, items, fields]; -pp(ps_subscription, 6) -> - [xmlns, jid, type, node, subid, expiry]; -pp(ps_item, 5) -> [xmlns, id, xml_els, node, publisher]; -pp(ps_items, 6) -> - [xmlns, node, items, max_items, subid, retract]; -pp(ps_event, 6) -> - [items, purge, subscription, delete, create, - configuration]; -pp(ps_subscribe, 2) -> [node, jid]; -pp(ps_unsubscribe, 3) -> [node, jid, subid]; -pp(ps_publish, 2) -> [node, items]; -pp(ps_options, 4) -> [node, jid, subid, xdata]; -pp(ps_retract, 3) -> [node, notify, items]; -pp(pubsub, 16) -> - [subscriptions, subscription, affiliations, publish, - publish_options, subscribe, unsubscribe, options, items, - retract, create, configure, default, delete, purge, - rsm]; -pp(pubsub_owner, 6) -> - [affiliations, configure, default, delete, purge, - subscriptions]; -pp(shim, 1) -> [headers]; -pp(delay, 3) -> [stamp, from, desc]; -pp(streamhost, 3) -> [jid, host, port]; -pp(bytestreams, 6) -> - [hosts, used, activate, dstaddr, mode, sid]; -pp(muc_history, 4) -> - [maxchars, maxstanzas, seconds, since]; -pp(muc_decline, 3) -> [reason, from, to]; -pp(muc_destroy, 4) -> [xmlns, jid, reason, password]; -pp(muc_invite, 4) -> [reason, from, to, continue]; -pp(muc_user, 6) -> - [decline, destroy, invites, items, status_codes, - password]; -pp(muc_owner, 3) -> [destroy, config, items]; -pp(muc_item, 7) -> - [actor, continue, reason, affiliation, role, jid, nick]; -pp(muc_actor, 2) -> [jid, nick]; -pp(muc_admin, 1) -> [items]; -pp(muc, 2) -> [history, password]; -pp(muc_unique, 1) -> [name]; -pp(x_conference, 5) -> - [jid, password, reason, continue, thread]; -pp(muc_subscriptions, 1) -> [list]; -pp(muc_subscribe, 2) -> [nick, events]; -pp(muc_unsubscribe, 0) -> []; -pp(rsm_first, 2) -> [index, data]; -pp(rsm_set, 7) -> - ['after', before, count, first, index, last, max]; -pp(mam_query, 8) -> - [xmlns, id, start, 'end', with, withtext, rsm, xdata]; -pp(mam_archived, 2) -> [by, id]; -pp(mam_result, 4) -> [xmlns, queryid, id, sub_els]; -pp(mam_prefs, 4) -> [xmlns, default, always, never]; -pp(mam_fin, 5) -> [xmlns, id, rsm, stable, complete]; -pp(forwarded, 2) -> [delay, xml_els]; -pp(carbons_disable, 0) -> []; -pp(carbons_enable, 0) -> []; -pp(carbons_private, 0) -> []; -pp(carbons_received, 1) -> [forwarded]; -pp(carbons_sent, 1) -> [forwarded]; -pp(feature_csi, 1) -> [xmlns]; -pp(feature_sm, 1) -> [xmlns]; -pp(sm_enable, 3) -> [max, resume, xmlns]; -pp(sm_enabled, 5) -> [id, location, max, resume, xmlns]; -pp(sm_resume, 3) -> [h, previd, xmlns]; -pp(sm_resumed, 3) -> [h, previd, xmlns]; -pp(sm_r, 1) -> [xmlns]; -pp(sm_a, 2) -> [h, xmlns]; -pp(sm_failed, 3) -> [reason, h, xmlns]; -pp(offline_item, 2) -> [node, action]; -pp(offline, 3) -> [items, purge, fetch]; -pp(mix_join, 2) -> [jid, subscribe]; -pp(mix_leave, 0) -> []; -pp(mix_participant, 2) -> [jid, nick]; -pp(search_item, 5) -> [jid, first, last, nick, email]; -pp(search, 7) -> - [instructions, first, last, nick, email, items, xdata]; -pp(xevent, 5) -> - [offline, delivered, displayed, composing, id]; -pp(expire, 2) -> [seconds, stored]; -pp(nick, 1) -> [name]; -pp(address, 5) -> [type, jid, desc, node, delivered]; -pp(addresses, 1) -> [list]; -pp(stanza_id, 2) -> [by, id]; -pp(client_id, 1) -> [id]; -pp(adhoc_actions, 4) -> [execute, prev, next, complete]; -pp(adhoc_note, 2) -> [type, data]; -pp(adhoc_command, 8) -> - [node, action, sid, status, lang, actions, notes, - xdata]; -pp(db_result, 5) -> [from, to, type, key, sub_els]; -pp(db_verify, 6) -> [from, to, id, type, key, sub_els]; -pp(handshake, 1) -> [data]; -pp(stream_start, 8) -> - [from, to, id, version, xmlns, stream_xmlns, db_xmlns, - lang]; -pp(bob_data, 4) -> [cid, 'max-age', type, data]; -pp(xcaptcha, 1) -> [xdata]; -pp(media_uri, 2) -> [type, uri]; -pp(media, 3) -> [height, width, uri]; -pp(oob_x, 3) -> [url, desc, sid]; -pp(sic, 3) -> [ip, port, xmlns]; -pp(upload_request, 4) -> - [filename, size, 'content-type', xmlns]; -pp(upload_slot, 3) -> [get, put, xmlns]; -pp(thumbnail, 4) -> [uri, 'media-type', width, height]; -pp(privilege_perm, 2) -> [access, type]; -pp(privilege, 2) -> [perms, forwarded]; -pp(delegated, 2) -> [ns, attrs]; -pp(delegation, 2) -> [delegated, forwarded]; -pp(delegation_query, 2) -> [to, delegate]; -pp(_, _) -> no. - -enc_ps_aff(member) -> <<"member">>; -enc_ps_aff(none) -> <<"none">>; -enc_ps_aff(outcast) -> <<"outcast">>; -enc_ps_aff(owner) -> <<"owner">>; -enc_ps_aff(publisher) -> <<"publisher">>; -enc_ps_aff(publish_only) -> <<"publish-only">>. - -dec_ps_aff(<<"member">>) -> member; -dec_ps_aff(<<"none">>) -> none; -dec_ps_aff(<<"outcast">>) -> outcast; -dec_ps_aff(<<"owner">>) -> owner; -dec_ps_aff(<<"publisher">>) -> publisher; -dec_ps_aff(<<"publish-only">>) -> publish_only. - -enc_version({Maj, Min}) -> - <<(integer_to_binary(Maj))/binary, $., - (integer_to_binary(Min))/binary>>. - -dec_version(S) -> - [Major, Minor] = binary:split(S, <<$.>>), - {binary_to_integer(Major), binary_to_integer(Minor)}. - -enc_host_port(Host) when is_binary(Host) -> Host; -enc_host_port({{_, _, _, _, _, _, _, _} = IPv6, - Port}) -> - enc_host_port({<<$[, (enc_ip(IPv6))/binary, $]>>, - Port}); -enc_host_port({{_, _, _, _} = IPv4, Port}) -> - enc_host_port({enc_ip(IPv4), Port}); -enc_host_port({Host, Port}) -> - <>; -enc_host_port(Addr) -> enc_ip(Addr). - -dec_host_port(<<$[, T/binary>>) -> - [IP, <<$:, Port/binary>>] = binary:split(T, <<$]>>), - {dec_ip(IP), dec_int(Port, 0, 65535)}; -dec_host_port(S) -> - case binary:split(S, <<$:>>) of - [S] -> try dec_ip(S) catch _:_ -> S end; - [S, P] -> - {try dec_ip(S) catch _:_ -> S end, dec_int(P, 0, 65535)} - end. - -enc_ip({0, 0, 0, 0, 0, 65535, A, B}) -> - enc_ip({(A bsr 8) band 255, A band 255, - (B bsr 8) band 255, B band 255}); -enc_ip(Addr) -> list_to_binary(inet_parse:ntoa(Addr)). - -dec_ip(S) -> - {ok, Addr} = inet_parse:address(binary_to_list(S)), - Addr. - -join([], _Sep) -> <<>>; -join([H | T], Sep) -> - <> || X <- T >>/binary>>. - -enc_bool(false) -> <<"false">>; -enc_bool(true) -> <<"true">>. - -dec_bool(<<"false">>) -> false; -dec_bool(<<"0">>) -> false; -dec_bool(<<"true">>) -> true; -dec_bool(<<"1">>) -> true. - -nameprep(S) -> - case jid:nameprep(S) of - error -> erlang:error(badarg); - S1 -> S1 - end. - -resourceprep(R) -> - case jid:resourceprep(R) of - error -> erlang:error(badarg); - R1 -> R1 - end. - -enc_jid(J) -> jid:to_string(J). - -dec_jid(Val) -> - case jid:from_string(Val) of - error -> erlang:error(badarg); - J -> J - end. - -enc_utc(Val) -> xmpp_util:encode_timestamp(Val). - -dec_utc(Val) -> xmpp_util:decode_timestamp(Val). - -enc_tzo({H, M}) -> - Sign = if H >= 0 -> <<>>; - true -> <<"-">> - end, - list_to_binary([Sign, - io_lib:format("~2..0w:~2..0w", [H, M])]). - -dec_tzo(Val) -> - [H1, M1] = str:tokens(Val, <<":">>), - H = binary_to_integer(H1), - M = binary_to_integer(M1), - if H >= -12, H =< 12, M >= 0, M < 60 -> {H, M} end. - -decode_delegation_query(__TopXMLNS, __IgnoreEls, - {xmlel, <<"query">>, _attrs, _els}) -> - Delegate = decode_delegation_query_els(__TopXMLNS, - __IgnoreEls, _els, []), - To = decode_delegation_query_attrs(__TopXMLNS, _attrs, - undefined), - {delegation_query, To, Delegate}. - -decode_delegation_query_els(__TopXMLNS, __IgnoreEls, [], - Delegate) -> - lists:reverse(Delegate); -decode_delegation_query_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"delegate">>, _attrs, _} = _el | _els], - Delegate) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"urn:xmpp:delegation:1">> -> - decode_delegation_query_els(__TopXMLNS, __IgnoreEls, - _els, - [decode_delegate(__TopXMLNS, __IgnoreEls, - _el) - | Delegate]); - <<"urn:xmpp:delegation:1">> -> - decode_delegation_query_els(__TopXMLNS, __IgnoreEls, - _els, - [decode_delegate(<<"urn:xmpp:delegation:1">>, - __IgnoreEls, _el) - | Delegate]); - _ -> - decode_delegation_query_els(__TopXMLNS, __IgnoreEls, - _els, Delegate) - end; -decode_delegation_query_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Delegate) -> - decode_delegation_query_els(__TopXMLNS, __IgnoreEls, - _els, Delegate). - -decode_delegation_query_attrs(__TopXMLNS, - [{<<"to">>, _val} | _attrs], _To) -> - decode_delegation_query_attrs(__TopXMLNS, _attrs, _val); -decode_delegation_query_attrs(__TopXMLNS, [_ | _attrs], - To) -> - decode_delegation_query_attrs(__TopXMLNS, _attrs, To); -decode_delegation_query_attrs(__TopXMLNS, [], To) -> - decode_delegation_query_attr_to(__TopXMLNS, To). - -encode_delegation_query({delegation_query, To, - Delegate}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:delegation:1">>, [], - __TopXMLNS), - _els = - lists:reverse('encode_delegation_query_$delegate'(Delegate, - __NewTopXMLNS, [])), - _attrs = encode_delegation_query_attr_to(To, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"query">>, _attrs, _els}. - -'encode_delegation_query_$delegate'([], __TopXMLNS, - _acc) -> - _acc; -'encode_delegation_query_$delegate'([Delegate | _els], - __TopXMLNS, _acc) -> - 'encode_delegation_query_$delegate'(_els, __TopXMLNS, - [encode_delegate(Delegate, __TopXMLNS) - | _acc]). - -decode_delegation_query_attr_to(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"to">>, <<"query">>, __TopXMLNS}}); -decode_delegation_query_attr_to(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"to">>, <<"query">>, __TopXMLNS}}); - _res -> _res - end. - -encode_delegation_query_attr_to(_val, _acc) -> - [{<<"to">>, enc_jid(_val)} | _acc]. - -decode_delegate(__TopXMLNS, __IgnoreEls, - {xmlel, <<"delegate">>, _attrs, _els}) -> - Namespace = decode_delegate_attrs(__TopXMLNS, _attrs, - undefined), - Namespace. - -decode_delegate_attrs(__TopXMLNS, - [{<<"namespace">>, _val} | _attrs], _Namespace) -> - decode_delegate_attrs(__TopXMLNS, _attrs, _val); -decode_delegate_attrs(__TopXMLNS, [_ | _attrs], - Namespace) -> - decode_delegate_attrs(__TopXMLNS, _attrs, Namespace); -decode_delegate_attrs(__TopXMLNS, [], Namespace) -> - decode_delegate_attr_namespace(__TopXMLNS, Namespace). - -encode_delegate(Namespace, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:delegation:1">>, [], - __TopXMLNS), - _els = [], - _attrs = encode_delegate_attr_namespace(Namespace, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"delegate">>, _attrs, _els}. - -decode_delegate_attr_namespace(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"namespace">>, <<"delegate">>, - __TopXMLNS}}); -decode_delegate_attr_namespace(__TopXMLNS, _val) -> - _val. - -encode_delegate_attr_namespace(_val, _acc) -> - [{<<"namespace">>, _val} | _acc]. - -decode_delegation(__TopXMLNS, __IgnoreEls, - {xmlel, <<"delegation">>, _attrs, _els}) -> - {Forwarded, Delegated} = - decode_delegation_els(__TopXMLNS, __IgnoreEls, _els, - undefined, []), - {delegation, Delegated, Forwarded}. - -decode_delegation_els(__TopXMLNS, __IgnoreEls, [], - Forwarded, Delegated) -> - {Forwarded, lists:reverse(Delegated)}; -decode_delegation_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"delegated">>, _attrs, _} = _el | _els], - Forwarded, Delegated) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"urn:xmpp:delegation:1">> -> - decode_delegation_els(__TopXMLNS, __IgnoreEls, _els, - Forwarded, - [decode_delegated(__TopXMLNS, __IgnoreEls, _el) - | Delegated]); - <<"urn:xmpp:delegation:1">> -> - decode_delegation_els(__TopXMLNS, __IgnoreEls, _els, - Forwarded, - [decode_delegated(<<"urn:xmpp:delegation:1">>, - __IgnoreEls, _el) - | Delegated]); - _ -> - decode_delegation_els(__TopXMLNS, __IgnoreEls, _els, - Forwarded, Delegated) - end; -decode_delegation_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"forwarded">>, _attrs, _} = _el | _els], - Forwarded, Delegated) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:xmpp:forward:0">> -> - decode_delegation_els(__TopXMLNS, __IgnoreEls, _els, - decode_forwarded(<<"urn:xmpp:forward:0">>, - __IgnoreEls, _el), - Delegated); - _ -> - decode_delegation_els(__TopXMLNS, __IgnoreEls, _els, - Forwarded, Delegated) - end; -decode_delegation_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Forwarded, Delegated) -> - decode_delegation_els(__TopXMLNS, __IgnoreEls, _els, - Forwarded, Delegated). - -encode_delegation({delegation, Delegated, Forwarded}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:delegation:1">>, [], - __TopXMLNS), - _els = - lists:reverse('encode_delegation_$forwarded'(Forwarded, - __NewTopXMLNS, - 'encode_delegation_$delegated'(Delegated, - __NewTopXMLNS, - []))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"delegation">>, _attrs, _els}. - -'encode_delegation_$forwarded'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_delegation_$forwarded'(Forwarded, __TopXMLNS, - _acc) -> - [encode_forwarded(Forwarded, __TopXMLNS) | _acc]. - -'encode_delegation_$delegated'([], __TopXMLNS, _acc) -> - _acc; -'encode_delegation_$delegated'([Delegated | _els], - __TopXMLNS, _acc) -> - 'encode_delegation_$delegated'(_els, __TopXMLNS, - [encode_delegated(Delegated, __TopXMLNS) - | _acc]). - -decode_delegated(__TopXMLNS, __IgnoreEls, - {xmlel, <<"delegated">>, _attrs, _els}) -> - Attrs = decode_delegated_els(__TopXMLNS, __IgnoreEls, - _els, []), - Ns = decode_delegated_attrs(__TopXMLNS, _attrs, - undefined), - {delegated, Ns, Attrs}. - -decode_delegated_els(__TopXMLNS, __IgnoreEls, [], - Attrs) -> - lists:reverse(Attrs); -decode_delegated_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"attribute">>, _attrs, _} = _el | _els], - Attrs) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"urn:xmpp:delegation:1">> -> - decode_delegated_els(__TopXMLNS, __IgnoreEls, _els, - [decode_delegated_attribute(__TopXMLNS, - __IgnoreEls, _el) - | Attrs]); - <<"urn:xmpp:delegation:1">> -> - decode_delegated_els(__TopXMLNS, __IgnoreEls, _els, - [decode_delegated_attribute(<<"urn:xmpp:delegation:1">>, - __IgnoreEls, _el) - | Attrs]); - _ -> - decode_delegated_els(__TopXMLNS, __IgnoreEls, _els, - Attrs) - end; -decode_delegated_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Attrs) -> - decode_delegated_els(__TopXMLNS, __IgnoreEls, _els, - Attrs). - -decode_delegated_attrs(__TopXMLNS, - [{<<"namespace">>, _val} | _attrs], _Ns) -> - decode_delegated_attrs(__TopXMLNS, _attrs, _val); -decode_delegated_attrs(__TopXMLNS, [_ | _attrs], Ns) -> - decode_delegated_attrs(__TopXMLNS, _attrs, Ns); -decode_delegated_attrs(__TopXMLNS, [], Ns) -> - decode_delegated_attr_namespace(__TopXMLNS, Ns). - -encode_delegated({delegated, Ns, Attrs}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:delegation:1">>, [], - __TopXMLNS), - _els = lists:reverse('encode_delegated_$attrs'(Attrs, - __NewTopXMLNS, [])), - _attrs = encode_delegated_attr_namespace(Ns, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"delegated">>, _attrs, _els}. - -'encode_delegated_$attrs'([], __TopXMLNS, _acc) -> _acc; -'encode_delegated_$attrs'([Attrs | _els], __TopXMLNS, - _acc) -> - 'encode_delegated_$attrs'(_els, __TopXMLNS, - [encode_delegated_attribute(Attrs, __TopXMLNS) - | _acc]). - -decode_delegated_attr_namespace(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"namespace">>, <<"delegated">>, - __TopXMLNS}}); -decode_delegated_attr_namespace(__TopXMLNS, _val) -> - _val. - -encode_delegated_attr_namespace(_val, _acc) -> - [{<<"namespace">>, _val} | _acc]. - -decode_delegated_attribute(__TopXMLNS, __IgnoreEls, - {xmlel, <<"attribute">>, _attrs, _els}) -> - Name = decode_delegated_attribute_attrs(__TopXMLNS, - _attrs, undefined), - Name. - -decode_delegated_attribute_attrs(__TopXMLNS, - [{<<"name">>, _val} | _attrs], _Name) -> - decode_delegated_attribute_attrs(__TopXMLNS, _attrs, - _val); -decode_delegated_attribute_attrs(__TopXMLNS, - [_ | _attrs], Name) -> - decode_delegated_attribute_attrs(__TopXMLNS, _attrs, - Name); -decode_delegated_attribute_attrs(__TopXMLNS, [], - Name) -> - decode_delegated_attribute_attr_name(__TopXMLNS, Name). - -encode_delegated_attribute(Name, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:delegation:1">>, [], - __TopXMLNS), - _els = [], - _attrs = encode_delegated_attribute_attr_name(Name, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"attribute">>, _attrs, _els}. - -decode_delegated_attribute_attr_name(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"name">>, <<"attribute">>, - __TopXMLNS}}); -decode_delegated_attribute_attr_name(__TopXMLNS, - _val) -> - _val. - -encode_delegated_attribute_attr_name(_val, _acc) -> - [{<<"name">>, _val} | _acc]. - -decode_privilege(__TopXMLNS, __IgnoreEls, - {xmlel, <<"privilege">>, _attrs, _els}) -> - {Perms, Forwarded} = decode_privilege_els(__TopXMLNS, - __IgnoreEls, _els, [], undefined), - {privilege, Perms, Forwarded}. - -decode_privilege_els(__TopXMLNS, __IgnoreEls, [], Perms, - Forwarded) -> - {lists:reverse(Perms), Forwarded}; -decode_privilege_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"perm">>, _attrs, _} = _el | _els], Perms, - Forwarded) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"urn:xmpp:privilege:1">> -> - decode_privilege_els(__TopXMLNS, __IgnoreEls, _els, - [decode_privilege_perm(__TopXMLNS, __IgnoreEls, - _el) - | Perms], - Forwarded); - <<"urn:xmpp:privilege:1">> -> - decode_privilege_els(__TopXMLNS, __IgnoreEls, _els, - [decode_privilege_perm(<<"urn:xmpp:privilege:1">>, - __IgnoreEls, _el) - | Perms], - Forwarded); - _ -> - decode_privilege_els(__TopXMLNS, __IgnoreEls, _els, - Perms, Forwarded) - end; -decode_privilege_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"forwarded">>, _attrs, _} = _el | _els], - Perms, Forwarded) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:xmpp:forward:0">> -> - decode_privilege_els(__TopXMLNS, __IgnoreEls, _els, - Perms, - decode_forwarded(<<"urn:xmpp:forward:0">>, - __IgnoreEls, _el)); - _ -> - decode_privilege_els(__TopXMLNS, __IgnoreEls, _els, - Perms, Forwarded) - end; -decode_privilege_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Perms, Forwarded) -> - decode_privilege_els(__TopXMLNS, __IgnoreEls, _els, - Perms, Forwarded). - -encode_privilege({privilege, Perms, Forwarded}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:privilege:1">>, [], - __TopXMLNS), - _els = lists:reverse('encode_privilege_$perms'(Perms, - __NewTopXMLNS, - 'encode_privilege_$forwarded'(Forwarded, - __NewTopXMLNS, - []))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"privilege">>, _attrs, _els}. - -'encode_privilege_$perms'([], __TopXMLNS, _acc) -> _acc; -'encode_privilege_$perms'([Perms | _els], __TopXMLNS, - _acc) -> - 'encode_privilege_$perms'(_els, __TopXMLNS, - [encode_privilege_perm(Perms, __TopXMLNS) - | _acc]). - -'encode_privilege_$forwarded'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_privilege_$forwarded'(Forwarded, __TopXMLNS, - _acc) -> - [encode_forwarded(Forwarded, __TopXMLNS) | _acc]. - -decode_privilege_perm(__TopXMLNS, __IgnoreEls, - {xmlel, <<"perm">>, _attrs, _els}) -> - {Access, Type} = decode_privilege_perm_attrs(__TopXMLNS, - _attrs, undefined, undefined), - {privilege_perm, Access, Type}. - -decode_privilege_perm_attrs(__TopXMLNS, - [{<<"access">>, _val} | _attrs], _Access, Type) -> - decode_privilege_perm_attrs(__TopXMLNS, _attrs, _val, - Type); -decode_privilege_perm_attrs(__TopXMLNS, - [{<<"type">>, _val} | _attrs], Access, _Type) -> - decode_privilege_perm_attrs(__TopXMLNS, _attrs, Access, - _val); -decode_privilege_perm_attrs(__TopXMLNS, [_ | _attrs], - Access, Type) -> - decode_privilege_perm_attrs(__TopXMLNS, _attrs, Access, - Type); -decode_privilege_perm_attrs(__TopXMLNS, [], Access, - Type) -> - {decode_privilege_perm_attr_access(__TopXMLNS, Access), - decode_privilege_perm_attr_type(__TopXMLNS, Type)}. - -encode_privilege_perm({privilege_perm, Access, Type}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:privilege:1">>, [], - __TopXMLNS), - _els = [], - _attrs = encode_privilege_perm_attr_type(Type, - encode_privilege_perm_attr_access(Access, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))), - {xmlel, <<"perm">>, _attrs, _els}. - -decode_privilege_perm_attr_access(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"access">>, <<"perm">>, __TopXMLNS}}); -decode_privilege_perm_attr_access(__TopXMLNS, _val) -> - case catch dec_enum(_val, [roster, message, presence]) - of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"access">>, <<"perm">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_privilege_perm_attr_access(_val, _acc) -> - [{<<"access">>, enc_enum(_val)} | _acc]. - -decode_privilege_perm_attr_type(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"type">>, <<"perm">>, __TopXMLNS}}); -decode_privilege_perm_attr_type(__TopXMLNS, _val) -> - case catch dec_enum(_val, - [none, get, set, both, outgoing, roster, - managed_entity]) - of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"type">>, <<"perm">>, __TopXMLNS}}); - _res -> _res - end. - -encode_privilege_perm_attr_type(_val, _acc) -> - [{<<"type">>, enc_enum(_val)} | _acc]. - -decode_thumbnail(__TopXMLNS, __IgnoreEls, - {xmlel, <<"thumbnail">>, _attrs, _els}) -> - {Uri, Media_type, Width, Height} = - decode_thumbnail_attrs(__TopXMLNS, _attrs, undefined, - undefined, undefined, undefined), - {thumbnail, Uri, Media_type, Width, Height}. - -decode_thumbnail_attrs(__TopXMLNS, - [{<<"uri">>, _val} | _attrs], _Uri, Media_type, Width, - Height) -> - decode_thumbnail_attrs(__TopXMLNS, _attrs, _val, - Media_type, Width, Height); -decode_thumbnail_attrs(__TopXMLNS, - [{<<"media-type">>, _val} | _attrs], Uri, _Media_type, - Width, Height) -> - decode_thumbnail_attrs(__TopXMLNS, _attrs, Uri, _val, - Width, Height); -decode_thumbnail_attrs(__TopXMLNS, - [{<<"width">>, _val} | _attrs], Uri, Media_type, _Width, - Height) -> - decode_thumbnail_attrs(__TopXMLNS, _attrs, Uri, - Media_type, _val, Height); -decode_thumbnail_attrs(__TopXMLNS, - [{<<"height">>, _val} | _attrs], Uri, Media_type, Width, - _Height) -> - decode_thumbnail_attrs(__TopXMLNS, _attrs, Uri, - Media_type, Width, _val); -decode_thumbnail_attrs(__TopXMLNS, [_ | _attrs], Uri, - Media_type, Width, Height) -> - decode_thumbnail_attrs(__TopXMLNS, _attrs, Uri, - Media_type, Width, Height); -decode_thumbnail_attrs(__TopXMLNS, [], Uri, Media_type, - Width, Height) -> - {decode_thumbnail_attr_uri(__TopXMLNS, Uri), - 'decode_thumbnail_attr_media-type'(__TopXMLNS, - Media_type), - decode_thumbnail_attr_width(__TopXMLNS, Width), - decode_thumbnail_attr_height(__TopXMLNS, Height)}. - -encode_thumbnail({thumbnail, Uri, Media_type, Width, - Height}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:thumbs:1">>, [], - __TopXMLNS), - _els = [], - _attrs = encode_thumbnail_attr_height(Height, - encode_thumbnail_attr_width(Width, - 'encode_thumbnail_attr_media-type'(Media_type, - encode_thumbnail_attr_uri(Uri, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))))), - {xmlel, <<"thumbnail">>, _attrs, _els}. - -decode_thumbnail_attr_uri(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"uri">>, <<"thumbnail">>, - __TopXMLNS}}); -decode_thumbnail_attr_uri(__TopXMLNS, _val) -> _val. - -encode_thumbnail_attr_uri(_val, _acc) -> - [{<<"uri">>, _val} | _acc]. - -'decode_thumbnail_attr_media-type'(__TopXMLNS, - undefined) -> - <<>>; -'decode_thumbnail_attr_media-type'(__TopXMLNS, _val) -> - _val. - -'encode_thumbnail_attr_media-type'(<<>>, _acc) -> _acc; -'encode_thumbnail_attr_media-type'(_val, _acc) -> - [{<<"media-type">>, _val} | _acc]. - -decode_thumbnail_attr_width(__TopXMLNS, undefined) -> - undefined; -decode_thumbnail_attr_width(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, infinity) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"width">>, <<"thumbnail">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_thumbnail_attr_width(undefined, _acc) -> _acc; -encode_thumbnail_attr_width(_val, _acc) -> - [{<<"width">>, enc_int(_val)} | _acc]. - -decode_thumbnail_attr_height(__TopXMLNS, undefined) -> - undefined; -decode_thumbnail_attr_height(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, infinity) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"height">>, <<"thumbnail">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_thumbnail_attr_height(undefined, _acc) -> _acc; -encode_thumbnail_attr_height(_val, _acc) -> - [{<<"height">>, enc_int(_val)} | _acc]. - -decode_upload_slot(__TopXMLNS, __IgnoreEls, - {xmlel, <<"slot">>, _attrs, _els}) -> - {Put, Get} = decode_upload_slot_els(__TopXMLNS, - __IgnoreEls, _els, undefined, - undefined), - Xmlns = decode_upload_slot_attrs(__TopXMLNS, _attrs, - undefined), - {upload_slot, Get, Put, Xmlns}. - -decode_upload_slot_els(__TopXMLNS, __IgnoreEls, [], Put, - Get) -> - {Put, Get}; -decode_upload_slot_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"get">>, _attrs, _} = _el | _els], Put, - Get) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"eu:siacs:conversations:http:upload">>; - __TopXMLNS == <<"urn:xmpp:http:upload">> -> - decode_upload_slot_els(__TopXMLNS, __IgnoreEls, _els, - Put, - decode_upload_get(__TopXMLNS, __IgnoreEls, - _el)); - <<"urn:xmpp:http:upload">> -> - decode_upload_slot_els(__TopXMLNS, __IgnoreEls, _els, - Put, - decode_upload_get(<<"urn:xmpp:http:upload">>, - __IgnoreEls, _el)); - <<"eu:siacs:conversations:http:upload">> -> - decode_upload_slot_els(__TopXMLNS, __IgnoreEls, _els, - Put, - decode_upload_get(<<"eu:siacs:conversations:http:upload">>, - __IgnoreEls, _el)); - _ -> - decode_upload_slot_els(__TopXMLNS, __IgnoreEls, _els, - Put, Get) - end; -decode_upload_slot_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"put">>, _attrs, _} = _el | _els], Put, - Get) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"eu:siacs:conversations:http:upload">>; - __TopXMLNS == <<"urn:xmpp:http:upload">> -> - decode_upload_slot_els(__TopXMLNS, __IgnoreEls, _els, - decode_upload_put(__TopXMLNS, __IgnoreEls, - _el), - Get); - <<"urn:xmpp:http:upload">> -> - decode_upload_slot_els(__TopXMLNS, __IgnoreEls, _els, - decode_upload_put(<<"urn:xmpp:http:upload">>, - __IgnoreEls, _el), - Get); - <<"eu:siacs:conversations:http:upload">> -> - decode_upload_slot_els(__TopXMLNS, __IgnoreEls, _els, - decode_upload_put(<<"eu:siacs:conversations:http:upload">>, - __IgnoreEls, _el), - Get); - _ -> - decode_upload_slot_els(__TopXMLNS, __IgnoreEls, _els, - Put, Get) - end; -decode_upload_slot_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Put, Get) -> - decode_upload_slot_els(__TopXMLNS, __IgnoreEls, _els, - Put, Get). - -decode_upload_slot_attrs(__TopXMLNS, - [{<<"xmlns">>, _val} | _attrs], _Xmlns) -> - decode_upload_slot_attrs(__TopXMLNS, _attrs, _val); -decode_upload_slot_attrs(__TopXMLNS, [_ | _attrs], - Xmlns) -> - decode_upload_slot_attrs(__TopXMLNS, _attrs, Xmlns); -decode_upload_slot_attrs(__TopXMLNS, [], Xmlns) -> - decode_upload_slot_attr_xmlns(__TopXMLNS, Xmlns). - -encode_upload_slot({upload_slot, Get, Put, Xmlns}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(Xmlns, - [<<"urn:xmpp:http:upload">>, - <<"eu:siacs:conversations:http:upload">>], - __TopXMLNS), - _els = lists:reverse('encode_upload_slot_$put'(Put, - __NewTopXMLNS, - 'encode_upload_slot_$get'(Get, - __NewTopXMLNS, - []))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"slot">>, _attrs, _els}. - -'encode_upload_slot_$put'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_upload_slot_$put'(Put, __TopXMLNS, _acc) -> - [encode_upload_put(Put, __TopXMLNS) | _acc]. - -'encode_upload_slot_$get'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_upload_slot_$get'(Get, __TopXMLNS, _acc) -> - [encode_upload_get(Get, __TopXMLNS) | _acc]. - -decode_upload_slot_attr_xmlns(__TopXMLNS, undefined) -> - <<>>; -decode_upload_slot_attr_xmlns(__TopXMLNS, _val) -> _val. - -decode_upload_put(__TopXMLNS, __IgnoreEls, - {xmlel, <<"put">>, _attrs, _els}) -> - Cdata = decode_upload_put_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_upload_put_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_upload_put_cdata(__TopXMLNS, Cdata); -decode_upload_put_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_upload_put_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_upload_put_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_upload_put_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_upload_put(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"urn:xmpp:http:upload">>, - <<"eu:siacs:conversations:http:upload">>], - __TopXMLNS), - _els = encode_upload_put_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"put">>, _attrs, _els}. - -decode_upload_put_cdata(__TopXMLNS, <<>>) -> - erlang:error({xmpp_codec, - {missing_cdata, <<>>, <<"put">>, __TopXMLNS}}); -decode_upload_put_cdata(__TopXMLNS, _val) -> _val. - -encode_upload_put_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_upload_get(__TopXMLNS, __IgnoreEls, - {xmlel, <<"get">>, _attrs, _els}) -> - Cdata = decode_upload_get_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_upload_get_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_upload_get_cdata(__TopXMLNS, Cdata); -decode_upload_get_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_upload_get_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_upload_get_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_upload_get_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_upload_get(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"urn:xmpp:http:upload">>, - <<"eu:siacs:conversations:http:upload">>], - __TopXMLNS), - _els = encode_upload_get_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"get">>, _attrs, _els}. - -decode_upload_get_cdata(__TopXMLNS, <<>>) -> - erlang:error({xmpp_codec, - {missing_cdata, <<>>, <<"get">>, __TopXMLNS}}); -decode_upload_get_cdata(__TopXMLNS, _val) -> _val. - -encode_upload_get_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_upload_request(__TopXMLNS, __IgnoreEls, - {xmlel, <<"request">>, _attrs, _els}) -> - {Content_type, Size, Filename} = - decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, - <<>>, error, error), - Xmlns = decode_upload_request_attrs(__TopXMLNS, _attrs, - undefined), - {upload_request, Filename, Size, Content_type, Xmlns}. - -decode_upload_request_els(__TopXMLNS, __IgnoreEls, [], - Content_type, Size, Filename) -> - {Content_type, - case Size of - error -> - erlang:error({xmpp_codec, - {missing_tag, <<"size">>, __TopXMLNS}}); - {value, Size1} -> Size1 - end, - case Filename of - error -> - erlang:error({xmpp_codec, - {missing_tag, <<"filename">>, __TopXMLNS}}); - {value, Filename1} -> Filename1 - end}; -decode_upload_request_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"filename">>, _attrs, _} = _el | _els], - Content_type, Size, Filename) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"eu:siacs:conversations:http:upload">>; - __TopXMLNS == <<"urn:xmpp:http:upload">> -> - decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, - Content_type, Size, - {value, - decode_upload_filename(__TopXMLNS, - __IgnoreEls, _el)}); - <<"urn:xmpp:http:upload">> -> - decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, - Content_type, Size, - {value, - decode_upload_filename(<<"urn:xmpp:http:upload">>, - __IgnoreEls, _el)}); - <<"eu:siacs:conversations:http:upload">> -> - decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, - Content_type, Size, - {value, - decode_upload_filename(<<"eu:siacs:conversations:http:upload">>, - __IgnoreEls, _el)}); - _ -> - decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, - Content_type, Size, Filename) - end; -decode_upload_request_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"size">>, _attrs, _} = _el | _els], - Content_type, Size, Filename) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"eu:siacs:conversations:http:upload">>; - __TopXMLNS == <<"urn:xmpp:http:upload">> -> - decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, - Content_type, - {value, - decode_upload_size(__TopXMLNS, __IgnoreEls, - _el)}, - Filename); - <<"urn:xmpp:http:upload">> -> - decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, - Content_type, - {value, - decode_upload_size(<<"urn:xmpp:http:upload">>, - __IgnoreEls, _el)}, - Filename); - <<"eu:siacs:conversations:http:upload">> -> - decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, - Content_type, - {value, - decode_upload_size(<<"eu:siacs:conversations:http:upload">>, - __IgnoreEls, _el)}, - Filename); - _ -> - decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, - Content_type, Size, Filename) - end; -decode_upload_request_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"content-type">>, _attrs, _} = _el | _els], - Content_type, Size, Filename) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"eu:siacs:conversations:http:upload">>; - __TopXMLNS == <<"urn:xmpp:http:upload">> -> - decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, - decode_upload_content_type(__TopXMLNS, - __IgnoreEls, - _el), - Size, Filename); - <<"urn:xmpp:http:upload">> -> - decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, - decode_upload_content_type(<<"urn:xmpp:http:upload">>, - __IgnoreEls, - _el), - Size, Filename); - <<"eu:siacs:conversations:http:upload">> -> - decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, - decode_upload_content_type(<<"eu:siacs:conversations:http:upload">>, - __IgnoreEls, - _el), - Size, Filename); - _ -> - decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, - Content_type, Size, Filename) - end; -decode_upload_request_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Content_type, Size, Filename) -> - decode_upload_request_els(__TopXMLNS, __IgnoreEls, _els, - Content_type, Size, Filename). - -decode_upload_request_attrs(__TopXMLNS, - [{<<"xmlns">>, _val} | _attrs], _Xmlns) -> - decode_upload_request_attrs(__TopXMLNS, _attrs, _val); -decode_upload_request_attrs(__TopXMLNS, [_ | _attrs], - Xmlns) -> - decode_upload_request_attrs(__TopXMLNS, _attrs, Xmlns); -decode_upload_request_attrs(__TopXMLNS, [], Xmlns) -> - decode_upload_request_attr_xmlns(__TopXMLNS, Xmlns). - -encode_upload_request({upload_request, Filename, Size, - Content_type, Xmlns}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(Xmlns, - [<<"urn:xmpp:http:upload">>, - <<"eu:siacs:conversations:http:upload">>], - __TopXMLNS), - _els = - lists:reverse('encode_upload_request_$content-type'(Content_type, - __NewTopXMLNS, - 'encode_upload_request_$size'(Size, - __NewTopXMLNS, - 'encode_upload_request_$filename'(Filename, - __NewTopXMLNS, - [])))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"request">>, _attrs, _els}. - -'encode_upload_request_$content-type'(<<>>, __TopXMLNS, - _acc) -> - _acc; -'encode_upload_request_$content-type'(Content_type, - __TopXMLNS, _acc) -> - [encode_upload_content_type(Content_type, __TopXMLNS) - | _acc]. - -'encode_upload_request_$size'(Size, __TopXMLNS, _acc) -> - [encode_upload_size(Size, __TopXMLNS) | _acc]. - -'encode_upload_request_$filename'(Filename, __TopXMLNS, - _acc) -> - [encode_upload_filename(Filename, __TopXMLNS) | _acc]. - -decode_upload_request_attr_xmlns(__TopXMLNS, - undefined) -> - <<>>; -decode_upload_request_attr_xmlns(__TopXMLNS, _val) -> - _val. - -decode_upload_content_type(__TopXMLNS, __IgnoreEls, - {xmlel, <<"content-type">>, _attrs, _els}) -> - Cdata = decode_upload_content_type_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_upload_content_type_els(__TopXMLNS, __IgnoreEls, - [], Cdata) -> - decode_upload_content_type_cdata(__TopXMLNS, Cdata); -decode_upload_content_type_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_upload_content_type_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_upload_content_type_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_upload_content_type_els(__TopXMLNS, __IgnoreEls, - _els, Cdata). - -encode_upload_content_type(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"urn:xmpp:http:upload">>, - <<"eu:siacs:conversations:http:upload">>], - __TopXMLNS), - _els = encode_upload_content_type_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"content-type">>, _attrs, _els}. - -decode_upload_content_type_cdata(__TopXMLNS, <<>>) -> - <<>>; -decode_upload_content_type_cdata(__TopXMLNS, _val) -> - _val. - -encode_upload_content_type_cdata(<<>>, _acc) -> _acc; -encode_upload_content_type_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_upload_size(__TopXMLNS, __IgnoreEls, - {xmlel, <<"size">>, _attrs, _els}) -> - Cdata = decode_upload_size_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_upload_size_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_upload_size_cdata(__TopXMLNS, Cdata); -decode_upload_size_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_upload_size_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_upload_size_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_upload_size_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_upload_size(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"urn:xmpp:http:upload">>, - <<"eu:siacs:conversations:http:upload">>], - __TopXMLNS), - _els = encode_upload_size_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"size">>, _attrs, _els}. - -decode_upload_size_cdata(__TopXMLNS, <<>>) -> - erlang:error({xmpp_codec, - {missing_cdata, <<>>, <<"size">>, __TopXMLNS}}); -decode_upload_size_cdata(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, infinity) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_cdata_value, <<>>, <<"size">>, __TopXMLNS}}); - _res -> _res - end. - -encode_upload_size_cdata(_val, _acc) -> - [{xmlcdata, enc_int(_val)} | _acc]. - -decode_upload_filename(__TopXMLNS, __IgnoreEls, - {xmlel, <<"filename">>, _attrs, _els}) -> - Cdata = decode_upload_filename_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_upload_filename_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_upload_filename_cdata(__TopXMLNS, Cdata); -decode_upload_filename_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_upload_filename_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_upload_filename_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_upload_filename_els(__TopXMLNS, __IgnoreEls, - _els, Cdata). - -encode_upload_filename(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"urn:xmpp:http:upload">>, - <<"eu:siacs:conversations:http:upload">>], - __TopXMLNS), - _els = encode_upload_filename_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"filename">>, _attrs, _els}. - -decode_upload_filename_cdata(__TopXMLNS, <<>>) -> - erlang:error({xmpp_codec, - {missing_cdata, <<>>, <<"filename">>, __TopXMLNS}}); -decode_upload_filename_cdata(__TopXMLNS, _val) -> _val. - -encode_upload_filename_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_sic(__TopXMLNS, __IgnoreEls, - {xmlel, <<"address">>, _attrs, _els}) -> - {Ip, Port} = decode_sic_els(__TopXMLNS, __IgnoreEls, - _els, undefined, undefined), - Xmlns = decode_sic_attrs(__TopXMLNS, _attrs, undefined), - {sic, Ip, Port, Xmlns}. - -decode_sic_els(__TopXMLNS, __IgnoreEls, [], Ip, Port) -> - {Ip, Port}; -decode_sic_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"ip">>, _attrs, _} = _el | _els], Ip, - Port) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == <<"urn:xmpp:sic:1">>; - __TopXMLNS == <<"urn:xmpp:sic:0">> -> - decode_sic_els(__TopXMLNS, __IgnoreEls, _els, - decode_sic_ip(__TopXMLNS, __IgnoreEls, _el), Port); - <<"urn:xmpp:sic:0">> -> - decode_sic_els(__TopXMLNS, __IgnoreEls, _els, - decode_sic_ip(<<"urn:xmpp:sic:0">>, __IgnoreEls, _el), - Port); - <<"urn:xmpp:sic:1">> -> - decode_sic_els(__TopXMLNS, __IgnoreEls, _els, - decode_sic_ip(<<"urn:xmpp:sic:1">>, __IgnoreEls, _el), - Port); - _ -> - decode_sic_els(__TopXMLNS, __IgnoreEls, _els, Ip, Port) - end; -decode_sic_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"port">>, _attrs, _} = _el | _els], Ip, - Port) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"urn:xmpp:sic:1">> -> - decode_sic_els(__TopXMLNS, __IgnoreEls, _els, Ip, - decode_sip_port(__TopXMLNS, __IgnoreEls, _el)); - <<"urn:xmpp:sic:1">> -> - decode_sic_els(__TopXMLNS, __IgnoreEls, _els, Ip, - decode_sip_port(<<"urn:xmpp:sic:1">>, __IgnoreEls, - _el)); - _ -> - decode_sic_els(__TopXMLNS, __IgnoreEls, _els, Ip, Port) - end; -decode_sic_els(__TopXMLNS, __IgnoreEls, [_ | _els], Ip, - Port) -> - decode_sic_els(__TopXMLNS, __IgnoreEls, _els, Ip, Port). - -decode_sic_attrs(__TopXMLNS, - [{<<"xmlns">>, _val} | _attrs], _Xmlns) -> - decode_sic_attrs(__TopXMLNS, _attrs, _val); -decode_sic_attrs(__TopXMLNS, [_ | _attrs], Xmlns) -> - decode_sic_attrs(__TopXMLNS, _attrs, Xmlns); -decode_sic_attrs(__TopXMLNS, [], Xmlns) -> - decode_sic_attr_xmlns(__TopXMLNS, Xmlns). - -encode_sic({sic, Ip, Port, Xmlns}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(Xmlns, - [<<"urn:xmpp:sic:0">>, - <<"urn:xmpp:sic:1">>], - __TopXMLNS), - _els = lists:reverse('encode_sic_$ip'(Ip, __NewTopXMLNS, - 'encode_sic_$port'(Port, - __NewTopXMLNS, - []))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"address">>, _attrs, _els}. - -'encode_sic_$ip'(undefined, __TopXMLNS, _acc) -> _acc; -'encode_sic_$ip'(Ip, __TopXMLNS, _acc) -> - [encode_sic_ip(Ip, __TopXMLNS) | _acc]. - -'encode_sic_$port'(undefined, __TopXMLNS, _acc) -> _acc; -'encode_sic_$port'(Port, __TopXMLNS, _acc) -> - [encode_sip_port(Port, __TopXMLNS) | _acc]. - -decode_sic_attr_xmlns(__TopXMLNS, undefined) -> <<>>; -decode_sic_attr_xmlns(__TopXMLNS, _val) -> _val. - -decode_sip_port(__TopXMLNS, __IgnoreEls, - {xmlel, <<"port">>, _attrs, _els}) -> - Cdata = decode_sip_port_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_sip_port_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_sip_port_cdata(__TopXMLNS, Cdata); -decode_sip_port_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_sip_port_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_sip_port_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Cdata) -> - decode_sip_port_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_sip_port(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:sic:1">>, - [], __TopXMLNS), - _els = encode_sip_port_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"port">>, _attrs, _els}. - -decode_sip_port_cdata(__TopXMLNS, <<>>) -> - erlang:error({xmpp_codec, - {missing_cdata, <<>>, <<"port">>, __TopXMLNS}}); -decode_sip_port_cdata(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, 65535) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_cdata_value, <<>>, <<"port">>, __TopXMLNS}}); - _res -> _res - end. - -encode_sip_port_cdata(_val, _acc) -> - [{xmlcdata, enc_int(_val)} | _acc]. - -decode_sic_ip(__TopXMLNS, __IgnoreEls, - {xmlel, <<"ip">>, _attrs, _els}) -> - Cdata = decode_sic_ip_els(__TopXMLNS, __IgnoreEls, _els, - <<>>), - Cdata. - -decode_sic_ip_els(__TopXMLNS, __IgnoreEls, [], Cdata) -> - decode_sic_ip_cdata(__TopXMLNS, Cdata); -decode_sic_ip_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_sic_ip_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_sic_ip_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Cdata) -> - decode_sic_ip_els(__TopXMLNS, __IgnoreEls, _els, Cdata). - -encode_sic_ip(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"urn:xmpp:sic:0">>, - <<"urn:xmpp:sic:1">>], - __TopXMLNS), - _els = encode_sic_ip_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"ip">>, _attrs, _els}. - -decode_sic_ip_cdata(__TopXMLNS, <<>>) -> - erlang:error({xmpp_codec, - {missing_cdata, <<>>, <<"ip">>, __TopXMLNS}}); -decode_sic_ip_cdata(__TopXMLNS, _val) -> - case catch dec_ip(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_cdata_value, <<>>, <<"ip">>, __TopXMLNS}}); - _res -> _res - end. - -encode_sic_ip_cdata(_val, _acc) -> - [{xmlcdata, enc_ip(_val)} | _acc]. - -decode_oob_x(__TopXMLNS, __IgnoreEls, - {xmlel, <<"x">>, _attrs, _els}) -> - {Desc, Url} = decode_oob_x_els(__TopXMLNS, __IgnoreEls, - _els, <<>>, error), - Sid = decode_oob_x_attrs(__TopXMLNS, _attrs, undefined), - {oob_x, Url, Desc, Sid}. - -decode_oob_x_els(__TopXMLNS, __IgnoreEls, [], Desc, - Url) -> - {Desc, - case Url of - error -> - erlang:error({xmpp_codec, - {missing_tag, <<"url">>, __TopXMLNS}}); - {value, Url1} -> Url1 - end}; -decode_oob_x_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"url">>, _attrs, _} = _el | _els], Desc, - Url) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:x:oob">> -> - decode_oob_x_els(__TopXMLNS, __IgnoreEls, _els, Desc, - {value, - decode_oob_url(__TopXMLNS, __IgnoreEls, _el)}); - <<"jabber:x:oob">> -> - decode_oob_x_els(__TopXMLNS, __IgnoreEls, _els, Desc, - {value, - decode_oob_url(<<"jabber:x:oob">>, __IgnoreEls, - _el)}); - _ -> - decode_oob_x_els(__TopXMLNS, __IgnoreEls, _els, Desc, - Url) - end; -decode_oob_x_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"desc">>, _attrs, _} = _el | _els], Desc, - Url) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:x:oob">> -> - decode_oob_x_els(__TopXMLNS, __IgnoreEls, _els, - decode_oob_desc(__TopXMLNS, __IgnoreEls, _el), Url); - <<"jabber:x:oob">> -> - decode_oob_x_els(__TopXMLNS, __IgnoreEls, _els, - decode_oob_desc(<<"jabber:x:oob">>, __IgnoreEls, - _el), - Url); - _ -> - decode_oob_x_els(__TopXMLNS, __IgnoreEls, _els, Desc, - Url) - end; -decode_oob_x_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Desc, Url) -> - decode_oob_x_els(__TopXMLNS, __IgnoreEls, _els, Desc, - Url). - -decode_oob_x_attrs(__TopXMLNS, - [{<<"sid">>, _val} | _attrs], _Sid) -> - decode_oob_x_attrs(__TopXMLNS, _attrs, _val); -decode_oob_x_attrs(__TopXMLNS, [_ | _attrs], Sid) -> - decode_oob_x_attrs(__TopXMLNS, _attrs, Sid); -decode_oob_x_attrs(__TopXMLNS, [], Sid) -> - decode_oob_x_attr_sid(__TopXMLNS, Sid). - -encode_oob_x({oob_x, Url, Desc, Sid}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:oob">>, [], - __TopXMLNS), - _els = lists:reverse('encode_oob_x_$desc'(Desc, - __NewTopXMLNS, - 'encode_oob_x_$url'(Url, - __NewTopXMLNS, - []))), - _attrs = encode_oob_x_attr_sid(Sid, - enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS)), - {xmlel, <<"x">>, _attrs, _els}. - -'encode_oob_x_$desc'(<<>>, __TopXMLNS, _acc) -> _acc; -'encode_oob_x_$desc'(Desc, __TopXMLNS, _acc) -> - [encode_oob_desc(Desc, __TopXMLNS) | _acc]. - -'encode_oob_x_$url'(Url, __TopXMLNS, _acc) -> - [encode_oob_url(Url, __TopXMLNS) | _acc]. - -decode_oob_x_attr_sid(__TopXMLNS, undefined) -> <<>>; -decode_oob_x_attr_sid(__TopXMLNS, _val) -> _val. - -encode_oob_x_attr_sid(<<>>, _acc) -> _acc; -encode_oob_x_attr_sid(_val, _acc) -> - [{<<"sid">>, _val} | _acc]. - -decode_oob_desc(__TopXMLNS, __IgnoreEls, - {xmlel, <<"desc">>, _attrs, _els}) -> - Cdata = decode_oob_desc_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_oob_desc_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_oob_desc_cdata(__TopXMLNS, Cdata); -decode_oob_desc_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_oob_desc_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_oob_desc_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Cdata) -> - decode_oob_desc_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_oob_desc(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:oob">>, [], - __TopXMLNS), - _els = encode_oob_desc_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"desc">>, _attrs, _els}. - -decode_oob_desc_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_oob_desc_cdata(__TopXMLNS, _val) -> _val. - -encode_oob_desc_cdata(<<>>, _acc) -> _acc; -encode_oob_desc_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_oob_url(__TopXMLNS, __IgnoreEls, - {xmlel, <<"url">>, _attrs, _els}) -> - Cdata = decode_oob_url_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_oob_url_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_oob_url_cdata(__TopXMLNS, Cdata); -decode_oob_url_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_oob_url_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_oob_url_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Cdata) -> - decode_oob_url_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_oob_url(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:oob">>, [], - __TopXMLNS), - _els = encode_oob_url_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"url">>, _attrs, _els}. - -decode_oob_url_cdata(__TopXMLNS, <<>>) -> - erlang:error({xmpp_codec, - {missing_cdata, <<>>, <<"url">>, __TopXMLNS}}); -decode_oob_url_cdata(__TopXMLNS, _val) -> _val. - -encode_oob_url_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_media(__TopXMLNS, __IgnoreEls, - {xmlel, <<"media">>, _attrs, _els}) -> - Uri = decode_media_els(__TopXMLNS, __IgnoreEls, _els, - []), - {Height, Width} = decode_media_attrs(__TopXMLNS, _attrs, - undefined, undefined), - {media, Height, Width, Uri}. - -decode_media_els(__TopXMLNS, __IgnoreEls, [], Uri) -> - lists:reverse(Uri); -decode_media_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"uri">>, _attrs, _} = _el | _els], Uri) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == <<"urn:xmpp:media-element">> -> - decode_media_els(__TopXMLNS, __IgnoreEls, _els, - [decode_media_uri(__TopXMLNS, __IgnoreEls, _el) - | Uri]); - <<"urn:xmpp:media-element">> -> - decode_media_els(__TopXMLNS, __IgnoreEls, _els, - [decode_media_uri(<<"urn:xmpp:media-element">>, - __IgnoreEls, _el) - | Uri]); - _ -> - decode_media_els(__TopXMLNS, __IgnoreEls, _els, Uri) - end; -decode_media_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Uri) -> - decode_media_els(__TopXMLNS, __IgnoreEls, _els, Uri). - -decode_media_attrs(__TopXMLNS, - [{<<"height">>, _val} | _attrs], _Height, Width) -> - decode_media_attrs(__TopXMLNS, _attrs, _val, Width); -decode_media_attrs(__TopXMLNS, - [{<<"width">>, _val} | _attrs], Height, _Width) -> - decode_media_attrs(__TopXMLNS, _attrs, Height, _val); -decode_media_attrs(__TopXMLNS, [_ | _attrs], Height, - Width) -> - decode_media_attrs(__TopXMLNS, _attrs, Height, Width); -decode_media_attrs(__TopXMLNS, [], Height, Width) -> - {decode_media_attr_height(__TopXMLNS, Height), - decode_media_attr_width(__TopXMLNS, Width)}. - -encode_media({media, Height, Width, Uri}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:media-element">>, [], - __TopXMLNS), - _els = lists:reverse('encode_media_$uri'(Uri, - __NewTopXMLNS, [])), - _attrs = encode_media_attr_width(Width, - encode_media_attr_height(Height, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))), - {xmlel, <<"media">>, _attrs, _els}. - -'encode_media_$uri'([], __TopXMLNS, _acc) -> _acc; -'encode_media_$uri'([Uri | _els], __TopXMLNS, _acc) -> - 'encode_media_$uri'(_els, __TopXMLNS, - [encode_media_uri(Uri, __TopXMLNS) | _acc]). - -decode_media_attr_height(__TopXMLNS, undefined) -> - undefined; -decode_media_attr_height(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, infinity) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"height">>, <<"media">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_media_attr_height(undefined, _acc) -> _acc; -encode_media_attr_height(_val, _acc) -> - [{<<"height">>, enc_int(_val)} | _acc]. - -decode_media_attr_width(__TopXMLNS, undefined) -> - undefined; -decode_media_attr_width(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, inifinity) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"width">>, <<"media">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_media_attr_width(undefined, _acc) -> _acc; -encode_media_attr_width(_val, _acc) -> - [{<<"width">>, enc_int(_val)} | _acc]. - -decode_media_uri(__TopXMLNS, __IgnoreEls, - {xmlel, <<"uri">>, _attrs, _els}) -> - Uri = decode_media_uri_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Type = decode_media_uri_attrs(__TopXMLNS, _attrs, - undefined), - {media_uri, Type, Uri}. - -decode_media_uri_els(__TopXMLNS, __IgnoreEls, [], - Uri) -> - decode_media_uri_cdata(__TopXMLNS, Uri); -decode_media_uri_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Uri) -> - decode_media_uri_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_media_uri_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Uri) -> - decode_media_uri_els(__TopXMLNS, __IgnoreEls, _els, - Uri). - -decode_media_uri_attrs(__TopXMLNS, - [{<<"type">>, _val} | _attrs], _Type) -> - decode_media_uri_attrs(__TopXMLNS, _attrs, _val); -decode_media_uri_attrs(__TopXMLNS, [_ | _attrs], - Type) -> - decode_media_uri_attrs(__TopXMLNS, _attrs, Type); -decode_media_uri_attrs(__TopXMLNS, [], Type) -> - decode_media_uri_attr_type(__TopXMLNS, Type). - -encode_media_uri({media_uri, Type, Uri}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:media-element">>, [], - __TopXMLNS), - _els = encode_media_uri_cdata(Uri, []), - _attrs = encode_media_uri_attr_type(Type, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"uri">>, _attrs, _els}. - -decode_media_uri_attr_type(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"type">>, <<"uri">>, __TopXMLNS}}); -decode_media_uri_attr_type(__TopXMLNS, _val) -> _val. - -encode_media_uri_attr_type(_val, _acc) -> - [{<<"type">>, _val} | _acc]. - -decode_media_uri_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_media_uri_cdata(__TopXMLNS, _val) -> _val. - -encode_media_uri_cdata(<<>>, _acc) -> _acc; -encode_media_uri_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_captcha(__TopXMLNS, __IgnoreEls, - {xmlel, <<"captcha">>, _attrs, _els}) -> - Xdata = decode_captcha_els(__TopXMLNS, __IgnoreEls, - _els, error), - {xcaptcha, Xdata}. - -decode_captcha_els(__TopXMLNS, __IgnoreEls, [], - Xdata) -> - case Xdata of - error -> - erlang:error({xmpp_codec, - {missing_tag, <<"x">>, __TopXMLNS}}); - {value, Xdata1} -> Xdata1 - end; -decode_captcha_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"x">>, _attrs, _} = _el | _els], Xdata) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"jabber:x:data">> -> - decode_captcha_els(__TopXMLNS, __IgnoreEls, _els, - {value, - decode_xdata(<<"jabber:x:data">>, __IgnoreEls, - _el)}); - _ -> - decode_captcha_els(__TopXMLNS, __IgnoreEls, _els, Xdata) - end; -decode_captcha_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Xdata) -> - decode_captcha_els(__TopXMLNS, __IgnoreEls, _els, - Xdata). - -encode_captcha({xcaptcha, Xdata}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:captcha">>, - [], __TopXMLNS), - _els = lists:reverse('encode_captcha_$xdata'(Xdata, - __NewTopXMLNS, [])), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"captcha">>, _attrs, _els}. - -'encode_captcha_$xdata'(Xdata, __TopXMLNS, _acc) -> - [encode_xdata(Xdata, __TopXMLNS) | _acc]. - -decode_bob_data(__TopXMLNS, __IgnoreEls, - {xmlel, <<"data">>, _attrs, _els}) -> - Data = decode_bob_data_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - {Cid, Max_age, Type} = decode_bob_data_attrs(__TopXMLNS, - _attrs, undefined, undefined, - undefined), - {bob_data, Cid, Max_age, Type, Data}. - -decode_bob_data_els(__TopXMLNS, __IgnoreEls, [], - Data) -> - decode_bob_data_cdata(__TopXMLNS, Data); -decode_bob_data_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Data) -> - decode_bob_data_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_bob_data_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Data) -> - decode_bob_data_els(__TopXMLNS, __IgnoreEls, _els, - Data). - -decode_bob_data_attrs(__TopXMLNS, - [{<<"cid">>, _val} | _attrs], _Cid, Max_age, Type) -> - decode_bob_data_attrs(__TopXMLNS, _attrs, _val, Max_age, - Type); -decode_bob_data_attrs(__TopXMLNS, - [{<<"max-age">>, _val} | _attrs], Cid, _Max_age, - Type) -> - decode_bob_data_attrs(__TopXMLNS, _attrs, Cid, _val, - Type); -decode_bob_data_attrs(__TopXMLNS, - [{<<"type">>, _val} | _attrs], Cid, Max_age, _Type) -> - decode_bob_data_attrs(__TopXMLNS, _attrs, Cid, Max_age, - _val); -decode_bob_data_attrs(__TopXMLNS, [_ | _attrs], Cid, - Max_age, Type) -> - decode_bob_data_attrs(__TopXMLNS, _attrs, Cid, Max_age, - Type); -decode_bob_data_attrs(__TopXMLNS, [], Cid, Max_age, - Type) -> - {decode_bob_data_attr_cid(__TopXMLNS, Cid), - 'decode_bob_data_attr_max-age'(__TopXMLNS, Max_age), - decode_bob_data_attr_type(__TopXMLNS, Type)}. - -encode_bob_data({bob_data, Cid, Max_age, Type, Data}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:bob">>, [], - __TopXMLNS), - _els = encode_bob_data_cdata(Data, []), - _attrs = encode_bob_data_attr_type(Type, - 'encode_bob_data_attr_max-age'(Max_age, - encode_bob_data_attr_cid(Cid, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)))), - {xmlel, <<"data">>, _attrs, _els}. - -decode_bob_data_attr_cid(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"cid">>, <<"data">>, __TopXMLNS}}); -decode_bob_data_attr_cid(__TopXMLNS, _val) -> _val. - -encode_bob_data_attr_cid(_val, _acc) -> - [{<<"cid">>, _val} | _acc]. - -'decode_bob_data_attr_max-age'(__TopXMLNS, undefined) -> - undefined; -'decode_bob_data_attr_max-age'(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, infinity) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"max-age">>, <<"data">>, - __TopXMLNS}}); - _res -> _res - end. - -'encode_bob_data_attr_max-age'(undefined, _acc) -> _acc; -'encode_bob_data_attr_max-age'(_val, _acc) -> - [{<<"max-age">>, enc_int(_val)} | _acc]. - -decode_bob_data_attr_type(__TopXMLNS, undefined) -> - <<>>; -decode_bob_data_attr_type(__TopXMLNS, _val) -> _val. - -encode_bob_data_attr_type(<<>>, _acc) -> _acc; -encode_bob_data_attr_type(_val, _acc) -> - [{<<"type">>, _val} | _acc]. - -decode_bob_data_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_bob_data_cdata(__TopXMLNS, _val) -> - case catch base64:decode(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_cdata_value, <<>>, <<"data">>, __TopXMLNS}}); - _res -> _res - end. - -encode_bob_data_cdata(<<>>, _acc) -> _acc; -encode_bob_data_cdata(_val, _acc) -> - [{xmlcdata, base64:encode(_val)} | _acc]. - -decode_stream_start(__TopXMLNS, __IgnoreEls, - {xmlel, <<"stream:stream">>, _attrs, _els}) -> - {From, To, Xmlns, Stream_xmlns, Db_xmlns, Lang, Version, - Id} = - decode_stream_start_attrs(__TopXMLNS, _attrs, undefined, - undefined, undefined, undefined, undefined, - undefined, undefined, undefined), - {stream_start, From, To, Id, Version, Xmlns, - Stream_xmlns, Db_xmlns, Lang}. - -decode_stream_start_attrs(__TopXMLNS, - [{<<"from">>, _val} | _attrs], _From, To, Xmlns, - Stream_xmlns, Db_xmlns, Lang, Version, Id) -> - decode_stream_start_attrs(__TopXMLNS, _attrs, _val, To, - Xmlns, Stream_xmlns, Db_xmlns, Lang, Version, Id); -decode_stream_start_attrs(__TopXMLNS, - [{<<"to">>, _val} | _attrs], From, _To, Xmlns, - Stream_xmlns, Db_xmlns, Lang, Version, Id) -> - decode_stream_start_attrs(__TopXMLNS, _attrs, From, - _val, Xmlns, Stream_xmlns, Db_xmlns, Lang, - Version, Id); -decode_stream_start_attrs(__TopXMLNS, - [{<<"xmlns">>, _val} | _attrs], From, To, _Xmlns, - Stream_xmlns, Db_xmlns, Lang, Version, Id) -> - decode_stream_start_attrs(__TopXMLNS, _attrs, From, To, - _val, Stream_xmlns, Db_xmlns, Lang, Version, Id); -decode_stream_start_attrs(__TopXMLNS, - [{<<"xmlns:stream">>, _val} | _attrs], From, To, - Xmlns, _Stream_xmlns, Db_xmlns, Lang, Version, Id) -> - decode_stream_start_attrs(__TopXMLNS, _attrs, From, To, - Xmlns, _val, Db_xmlns, Lang, Version, Id); -decode_stream_start_attrs(__TopXMLNS, - [{<<"xmlns:db">>, _val} | _attrs], From, To, Xmlns, - Stream_xmlns, _Db_xmlns, Lang, Version, Id) -> - decode_stream_start_attrs(__TopXMLNS, _attrs, From, To, - Xmlns, Stream_xmlns, _val, Lang, Version, Id); -decode_stream_start_attrs(__TopXMLNS, - [{<<"xml:lang">>, _val} | _attrs], From, To, Xmlns, - Stream_xmlns, Db_xmlns, _Lang, Version, Id) -> - decode_stream_start_attrs(__TopXMLNS, _attrs, From, To, - Xmlns, Stream_xmlns, Db_xmlns, _val, Version, Id); -decode_stream_start_attrs(__TopXMLNS, - [{<<"version">>, _val} | _attrs], From, To, Xmlns, - Stream_xmlns, Db_xmlns, Lang, _Version, Id) -> - decode_stream_start_attrs(__TopXMLNS, _attrs, From, To, - Xmlns, Stream_xmlns, Db_xmlns, Lang, _val, Id); -decode_stream_start_attrs(__TopXMLNS, - [{<<"id">>, _val} | _attrs], From, To, Xmlns, - Stream_xmlns, Db_xmlns, Lang, Version, _Id) -> - decode_stream_start_attrs(__TopXMLNS, _attrs, From, To, - Xmlns, Stream_xmlns, Db_xmlns, Lang, Version, - _val); -decode_stream_start_attrs(__TopXMLNS, [_ | _attrs], - From, To, Xmlns, Stream_xmlns, Db_xmlns, Lang, - Version, Id) -> - decode_stream_start_attrs(__TopXMLNS, _attrs, From, To, - Xmlns, Stream_xmlns, Db_xmlns, Lang, Version, Id); -decode_stream_start_attrs(__TopXMLNS, [], From, To, - Xmlns, Stream_xmlns, Db_xmlns, Lang, Version, Id) -> - {decode_stream_start_attr_from(__TopXMLNS, From), - decode_stream_start_attr_to(__TopXMLNS, To), - decode_stream_start_attr_xmlns(__TopXMLNS, Xmlns), - 'decode_stream_start_attr_xmlns:stream'(__TopXMLNS, - Stream_xmlns), - 'decode_stream_start_attr_xmlns:db'(__TopXMLNS, - Db_xmlns), - 'decode_stream_start_attr_xml:lang'(__TopXMLNS, Lang), - decode_stream_start_attr_version(__TopXMLNS, Version), - decode_stream_start_attr_id(__TopXMLNS, Id)}. - -encode_stream_start({stream_start, From, To, Id, - Version, Xmlns, Stream_xmlns, Db_xmlns, Lang}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(Xmlns, - [<<"jabber:client">>, <<"jabber:server">>, - <<"jabber:component:accept">>], - __TopXMLNS), - _els = [], - _attrs = encode_stream_start_attr_id(Id, - encode_stream_start_attr_version(Version, - 'encode_stream_start_attr_xml:lang'(Lang, - 'encode_stream_start_attr_xmlns:db'(Db_xmlns, - 'encode_stream_start_attr_xmlns:stream'(Stream_xmlns, - encode_stream_start_attr_to(To, - encode_stream_start_attr_from(From, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)))))))), - {xmlel, <<"stream:stream">>, _attrs, _els}. - -decode_stream_start_attr_from(__TopXMLNS, undefined) -> - undefined; -decode_stream_start_attr_from(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"from">>, <<"stream:stream">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_stream_start_attr_from(undefined, _acc) -> _acc; -encode_stream_start_attr_from(_val, _acc) -> - [{<<"from">>, enc_jid(_val)} | _acc]. - -decode_stream_start_attr_to(__TopXMLNS, undefined) -> - undefined; -decode_stream_start_attr_to(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"to">>, <<"stream:stream">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_stream_start_attr_to(undefined, _acc) -> _acc; -encode_stream_start_attr_to(_val, _acc) -> - [{<<"to">>, enc_jid(_val)} | _acc]. - -decode_stream_start_attr_xmlns(__TopXMLNS, undefined) -> - <<>>; -decode_stream_start_attr_xmlns(__TopXMLNS, _val) -> - _val. - -'decode_stream_start_attr_xmlns:stream'(__TopXMLNS, - undefined) -> - <<>>; -'decode_stream_start_attr_xmlns:stream'(__TopXMLNS, - _val) -> - _val. - -'encode_stream_start_attr_xmlns:stream'(<<>>, _acc) -> - _acc; -'encode_stream_start_attr_xmlns:stream'(_val, _acc) -> - [{<<"xmlns:stream">>, _val} | _acc]. - -'decode_stream_start_attr_xmlns:db'(__TopXMLNS, - undefined) -> - <<>>; -'decode_stream_start_attr_xmlns:db'(__TopXMLNS, _val) -> - _val. - -'encode_stream_start_attr_xmlns:db'(<<>>, _acc) -> _acc; -'encode_stream_start_attr_xmlns:db'(_val, _acc) -> - [{<<"xmlns:db">>, _val} | _acc]. - -'decode_stream_start_attr_xml:lang'(__TopXMLNS, - undefined) -> - <<>>; -'decode_stream_start_attr_xml:lang'(__TopXMLNS, _val) -> - _val. - -'encode_stream_start_attr_xml:lang'(<<>>, _acc) -> _acc; -'encode_stream_start_attr_xml:lang'(_val, _acc) -> - [{<<"xml:lang">>, _val} | _acc]. - -decode_stream_start_attr_version(__TopXMLNS, - undefined) -> - undefined; -decode_stream_start_attr_version(__TopXMLNS, _val) -> - case catch dec_version(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"version">>, <<"stream:stream">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_stream_start_attr_version(undefined, _acc) -> - _acc; -encode_stream_start_attr_version(_val, _acc) -> - [{<<"version">>, enc_version(_val)} | _acc]. - -decode_stream_start_attr_id(__TopXMLNS, undefined) -> - <<>>; -decode_stream_start_attr_id(__TopXMLNS, _val) -> _val. - -encode_stream_start_attr_id(<<>>, _acc) -> _acc; -encode_stream_start_attr_id(_val, _acc) -> - [{<<"id">>, _val} | _acc]. - -decode_handshake(__TopXMLNS, __IgnoreEls, - {xmlel, <<"handshake">>, _attrs, _els}) -> - Data = decode_handshake_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - {handshake, Data}. - -decode_handshake_els(__TopXMLNS, __IgnoreEls, [], - Data) -> - decode_handshake_cdata(__TopXMLNS, Data); -decode_handshake_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Data) -> - decode_handshake_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_handshake_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Data) -> - decode_handshake_els(__TopXMLNS, __IgnoreEls, _els, - Data). - -encode_handshake({handshake, Data}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:component:accept">>, [], - __TopXMLNS), - _els = encode_handshake_cdata(Data, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"handshake">>, _attrs, _els}. - -decode_handshake_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_handshake_cdata(__TopXMLNS, _val) -> _val. - -encode_handshake_cdata(<<>>, _acc) -> _acc; -encode_handshake_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_db_verify(__TopXMLNS, __IgnoreEls, - {xmlel, <<"db:verify">>, _attrs, _els}) -> - {Key, __Els} = decode_db_verify_els(__TopXMLNS, - __IgnoreEls, _els, <<>>, []), - {From, To, Id, Type} = - decode_db_verify_attrs(__TopXMLNS, _attrs, undefined, - undefined, undefined, undefined), - {db_verify, From, To, Id, Type, Key, __Els}. - -decode_db_verify_els(__TopXMLNS, __IgnoreEls, [], Key, - __Els) -> - {decode_db_verify_cdata(__TopXMLNS, Key), - lists:reverse(__Els)}; -decode_db_verify_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Key, __Els) -> - decode_db_verify_els(__TopXMLNS, __IgnoreEls, _els, - <>, __Els); -decode_db_verify_els(__TopXMLNS, __IgnoreEls, - [{xmlel, _, _, _} = _el | _els], Key, __Els) -> - if __IgnoreEls -> - decode_db_verify_els(__TopXMLNS, __IgnoreEls, _els, Key, - [_el | __Els]); - true -> - case is_known_tag(_el, __TopXMLNS) of - true -> - decode_db_verify_els(__TopXMLNS, __IgnoreEls, _els, Key, - [decode(_el, __TopXMLNS, []) | __Els]); - false -> - decode_db_verify_els(__TopXMLNS, __IgnoreEls, _els, Key, - __Els) - end - end. - -decode_db_verify_attrs(__TopXMLNS, - [{<<"from">>, _val} | _attrs], _From, To, Id, Type) -> - decode_db_verify_attrs(__TopXMLNS, _attrs, _val, To, Id, - Type); -decode_db_verify_attrs(__TopXMLNS, - [{<<"to">>, _val} | _attrs], From, _To, Id, Type) -> - decode_db_verify_attrs(__TopXMLNS, _attrs, From, _val, - Id, Type); -decode_db_verify_attrs(__TopXMLNS, - [{<<"id">>, _val} | _attrs], From, To, _Id, Type) -> - decode_db_verify_attrs(__TopXMLNS, _attrs, From, To, - _val, Type); -decode_db_verify_attrs(__TopXMLNS, - [{<<"type">>, _val} | _attrs], From, To, Id, _Type) -> - decode_db_verify_attrs(__TopXMLNS, _attrs, From, To, Id, - _val); -decode_db_verify_attrs(__TopXMLNS, [_ | _attrs], From, - To, Id, Type) -> - decode_db_verify_attrs(__TopXMLNS, _attrs, From, To, Id, - Type); -decode_db_verify_attrs(__TopXMLNS, [], From, To, Id, - Type) -> - {decode_db_verify_attr_from(__TopXMLNS, From), - decode_db_verify_attr_to(__TopXMLNS, To), - decode_db_verify_attr_id(__TopXMLNS, Id), - decode_db_verify_attr_type(__TopXMLNS, Type)}. - -encode_db_verify({db_verify, From, To, Id, Type, Key, - __Els}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:server">>, - [], __TopXMLNS), - _els = [encode(_el, __NewTopXMLNS) || _el <- __Els] ++ - encode_db_verify_cdata(Key, []), - _attrs = encode_db_verify_attr_type(Type, - encode_db_verify_attr_id(Id, - encode_db_verify_attr_to(To, - encode_db_verify_attr_from(From, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))))), - {xmlel, <<"db:verify">>, _attrs, _els}. - -decode_db_verify_attr_from(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"from">>, <<"db:verify">>, - __TopXMLNS}}); -decode_db_verify_attr_from(__TopXMLNS, _val) -> - case catch nameprep(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"from">>, <<"db:verify">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_db_verify_attr_from(_val, _acc) -> - [{<<"from">>, nameprep(_val)} | _acc]. - -decode_db_verify_attr_to(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"to">>, <<"db:verify">>, __TopXMLNS}}); -decode_db_verify_attr_to(__TopXMLNS, _val) -> - case catch nameprep(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"to">>, <<"db:verify">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_db_verify_attr_to(_val, _acc) -> - [{<<"to">>, nameprep(_val)} | _acc]. - -decode_db_verify_attr_id(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"id">>, <<"db:verify">>, __TopXMLNS}}); -decode_db_verify_attr_id(__TopXMLNS, _val) -> _val. - -encode_db_verify_attr_id(_val, _acc) -> - [{<<"id">>, _val} | _acc]. - -decode_db_verify_attr_type(__TopXMLNS, undefined) -> - undefined; -decode_db_verify_attr_type(__TopXMLNS, _val) -> - case catch dec_enum(_val, [valid, invalid, error]) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"type">>, <<"db:verify">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_db_verify_attr_type(undefined, _acc) -> _acc; -encode_db_verify_attr_type(_val, _acc) -> - [{<<"type">>, enc_enum(_val)} | _acc]. - -decode_db_verify_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_db_verify_cdata(__TopXMLNS, _val) -> _val. - -encode_db_verify_cdata(<<>>, _acc) -> _acc; -encode_db_verify_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_db_result(__TopXMLNS, __IgnoreEls, - {xmlel, <<"db:result">>, _attrs, _els}) -> - {Key, __Els} = decode_db_result_els(__TopXMLNS, - __IgnoreEls, _els, <<>>, []), - {From, To, Type} = decode_db_result_attrs(__TopXMLNS, - _attrs, undefined, undefined, - undefined), - {db_result, From, To, Type, Key, __Els}. - -decode_db_result_els(__TopXMLNS, __IgnoreEls, [], Key, - __Els) -> - {decode_db_result_cdata(__TopXMLNS, Key), - lists:reverse(__Els)}; -decode_db_result_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Key, __Els) -> - decode_db_result_els(__TopXMLNS, __IgnoreEls, _els, - <>, __Els); -decode_db_result_els(__TopXMLNS, __IgnoreEls, - [{xmlel, _, _, _} = _el | _els], Key, __Els) -> - if __IgnoreEls -> - decode_db_result_els(__TopXMLNS, __IgnoreEls, _els, Key, - [_el | __Els]); - true -> - case is_known_tag(_el, __TopXMLNS) of - true -> - decode_db_result_els(__TopXMLNS, __IgnoreEls, _els, Key, - [decode(_el, __TopXMLNS, []) | __Els]); - false -> - decode_db_result_els(__TopXMLNS, __IgnoreEls, _els, Key, - __Els) - end - end. - -decode_db_result_attrs(__TopXMLNS, - [{<<"from">>, _val} | _attrs], _From, To, Type) -> - decode_db_result_attrs(__TopXMLNS, _attrs, _val, To, - Type); -decode_db_result_attrs(__TopXMLNS, - [{<<"to">>, _val} | _attrs], From, _To, Type) -> - decode_db_result_attrs(__TopXMLNS, _attrs, From, _val, - Type); -decode_db_result_attrs(__TopXMLNS, - [{<<"type">>, _val} | _attrs], From, To, _Type) -> - decode_db_result_attrs(__TopXMLNS, _attrs, From, To, - _val); -decode_db_result_attrs(__TopXMLNS, [_ | _attrs], From, - To, Type) -> - decode_db_result_attrs(__TopXMLNS, _attrs, From, To, - Type); -decode_db_result_attrs(__TopXMLNS, [], From, To, - Type) -> - {decode_db_result_attr_from(__TopXMLNS, From), - decode_db_result_attr_to(__TopXMLNS, To), - decode_db_result_attr_type(__TopXMLNS, Type)}. - -encode_db_result({db_result, From, To, Type, Key, - __Els}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:server">>, - [], __TopXMLNS), - _els = [encode(_el, __NewTopXMLNS) || _el <- __Els] ++ - encode_db_result_cdata(Key, []), - _attrs = encode_db_result_attr_type(Type, - encode_db_result_attr_to(To, - encode_db_result_attr_from(From, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)))), - {xmlel, <<"db:result">>, _attrs, _els}. - -decode_db_result_attr_from(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"from">>, <<"db:result">>, - __TopXMLNS}}); -decode_db_result_attr_from(__TopXMLNS, _val) -> - case catch nameprep(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"from">>, <<"db:result">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_db_result_attr_from(_val, _acc) -> - [{<<"from">>, nameprep(_val)} | _acc]. - -decode_db_result_attr_to(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"to">>, <<"db:result">>, __TopXMLNS}}); -decode_db_result_attr_to(__TopXMLNS, _val) -> - case catch nameprep(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"to">>, <<"db:result">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_db_result_attr_to(_val, _acc) -> - [{<<"to">>, nameprep(_val)} | _acc]. - -decode_db_result_attr_type(__TopXMLNS, undefined) -> - undefined; -decode_db_result_attr_type(__TopXMLNS, _val) -> - case catch dec_enum(_val, [valid, invalid, error]) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"type">>, <<"db:result">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_db_result_attr_type(undefined, _acc) -> _acc; -encode_db_result_attr_type(_val, _acc) -> - [{<<"type">>, enc_enum(_val)} | _acc]. - -decode_db_result_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_db_result_cdata(__TopXMLNS, _val) -> _val. - -encode_db_result_cdata(<<>>, _acc) -> _acc; -encode_db_result_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_adhoc_command(__TopXMLNS, __IgnoreEls, - {xmlel, <<"command">>, _attrs, _els}) -> - {Xdata, Notes, Actions} = - decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, _els, - undefined, [], undefined), - {Node, Lang, Sid, Status, Action} = - decode_adhoc_command_attrs(__TopXMLNS, _attrs, - undefined, undefined, undefined, undefined, - undefined), - {adhoc_command, Node, Action, Sid, Status, Lang, - Actions, Notes, Xdata}. - -decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, [], - Xdata, Notes, Actions) -> - {Xdata, lists:reverse(Notes), Actions}; -decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"actions">>, _attrs, _} = _el | _els], - Xdata, Notes, Actions) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/commands">> -> - decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Notes, - decode_adhoc_command_actions(__TopXMLNS, - __IgnoreEls, - _el)); - <<"http://jabber.org/protocol/commands">> -> - decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Notes, - decode_adhoc_command_actions(<<"http://jabber.org/protocol/commands">>, - __IgnoreEls, - _el)); - _ -> - decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Notes, Actions) - end; -decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"x">>, _attrs, _} = _el | _els], Xdata, - Notes, Actions) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"jabber:x:data">> -> - decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, _els, - decode_xdata(<<"jabber:x:data">>, - __IgnoreEls, _el), - Notes, Actions); - _ -> - decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Notes, Actions) - end; -decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"note">>, _attrs, _} = _el | _els], Xdata, - Notes, Actions) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/commands">> -> - decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, - [decode_adhoc_command_notes(__TopXMLNS, - __IgnoreEls, _el) - | Notes], - Actions); - <<"http://jabber.org/protocol/commands">> -> - decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, - [decode_adhoc_command_notes(<<"http://jabber.org/protocol/commands">>, - __IgnoreEls, _el) - | Notes], - Actions); - _ -> - decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Notes, Actions) - end; -decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Xdata, Notes, Actions) -> - decode_adhoc_command_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Notes, Actions). - -decode_adhoc_command_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], _Node, Lang, Sid, - Status, Action) -> - decode_adhoc_command_attrs(__TopXMLNS, _attrs, _val, - Lang, Sid, Status, Action); -decode_adhoc_command_attrs(__TopXMLNS, - [{<<"xml:lang">>, _val} | _attrs], Node, _Lang, Sid, - Status, Action) -> - decode_adhoc_command_attrs(__TopXMLNS, _attrs, Node, - _val, Sid, Status, Action); -decode_adhoc_command_attrs(__TopXMLNS, - [{<<"sessionid">>, _val} | _attrs], Node, Lang, _Sid, - Status, Action) -> - decode_adhoc_command_attrs(__TopXMLNS, _attrs, Node, - Lang, _val, Status, Action); -decode_adhoc_command_attrs(__TopXMLNS, - [{<<"status">>, _val} | _attrs], Node, Lang, Sid, - _Status, Action) -> - decode_adhoc_command_attrs(__TopXMLNS, _attrs, Node, - Lang, Sid, _val, Action); -decode_adhoc_command_attrs(__TopXMLNS, - [{<<"action">>, _val} | _attrs], Node, Lang, Sid, - Status, _Action) -> - decode_adhoc_command_attrs(__TopXMLNS, _attrs, Node, - Lang, Sid, Status, _val); -decode_adhoc_command_attrs(__TopXMLNS, [_ | _attrs], - Node, Lang, Sid, Status, Action) -> - decode_adhoc_command_attrs(__TopXMLNS, _attrs, Node, - Lang, Sid, Status, Action); -decode_adhoc_command_attrs(__TopXMLNS, [], Node, Lang, - Sid, Status, Action) -> - {decode_adhoc_command_attr_node(__TopXMLNS, Node), - 'decode_adhoc_command_attr_xml:lang'(__TopXMLNS, Lang), - decode_adhoc_command_attr_sessionid(__TopXMLNS, Sid), - decode_adhoc_command_attr_status(__TopXMLNS, Status), - decode_adhoc_command_attr_action(__TopXMLNS, Action)}. - -encode_adhoc_command({adhoc_command, Node, Action, Sid, - Status, Lang, Actions, Notes, Xdata}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/commands">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_adhoc_command_$xdata'(Xdata, - __NewTopXMLNS, - 'encode_adhoc_command_$notes'(Notes, - __NewTopXMLNS, - 'encode_adhoc_command_$actions'(Actions, - __NewTopXMLNS, - [])))), - _attrs = encode_adhoc_command_attr_action(Action, - encode_adhoc_command_attr_status(Status, - encode_adhoc_command_attr_sessionid(Sid, - 'encode_adhoc_command_attr_xml:lang'(Lang, - encode_adhoc_command_attr_node(Node, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)))))), - {xmlel, <<"command">>, _attrs, _els}. - -'encode_adhoc_command_$xdata'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_adhoc_command_$xdata'(Xdata, __TopXMLNS, - _acc) -> - [encode_xdata(Xdata, __TopXMLNS) | _acc]. - -'encode_adhoc_command_$notes'([], __TopXMLNS, _acc) -> - _acc; -'encode_adhoc_command_$notes'([Notes | _els], - __TopXMLNS, _acc) -> - 'encode_adhoc_command_$notes'(_els, __TopXMLNS, - [encode_adhoc_command_notes(Notes, __TopXMLNS) - | _acc]). - -'encode_adhoc_command_$actions'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_adhoc_command_$actions'(Actions, __TopXMLNS, - _acc) -> - [encode_adhoc_command_actions(Actions, __TopXMLNS) - | _acc]. - -decode_adhoc_command_attr_node(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"node">>, <<"command">>, __TopXMLNS}}); -decode_adhoc_command_attr_node(__TopXMLNS, _val) -> - _val. - -encode_adhoc_command_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -'decode_adhoc_command_attr_xml:lang'(__TopXMLNS, - undefined) -> - <<>>; -'decode_adhoc_command_attr_xml:lang'(__TopXMLNS, - _val) -> - _val. - -'encode_adhoc_command_attr_xml:lang'(<<>>, _acc) -> - _acc; -'encode_adhoc_command_attr_xml:lang'(_val, _acc) -> - [{<<"xml:lang">>, _val} | _acc]. - -decode_adhoc_command_attr_sessionid(__TopXMLNS, - undefined) -> - <<>>; -decode_adhoc_command_attr_sessionid(__TopXMLNS, _val) -> - _val. - -encode_adhoc_command_attr_sessionid(<<>>, _acc) -> _acc; -encode_adhoc_command_attr_sessionid(_val, _acc) -> - [{<<"sessionid">>, _val} | _acc]. - -decode_adhoc_command_attr_status(__TopXMLNS, - undefined) -> - undefined; -decode_adhoc_command_attr_status(__TopXMLNS, _val) -> - case catch dec_enum(_val, - [canceled, completed, executing]) - of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"status">>, <<"command">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_adhoc_command_attr_status(undefined, _acc) -> - _acc; -encode_adhoc_command_attr_status(_val, _acc) -> - [{<<"status">>, enc_enum(_val)} | _acc]. - -decode_adhoc_command_attr_action(__TopXMLNS, - undefined) -> - execute; -decode_adhoc_command_attr_action(__TopXMLNS, _val) -> - case catch dec_enum(_val, - [cancel, complete, execute, next, prev]) - of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"action">>, <<"command">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_adhoc_command_attr_action(execute, _acc) -> _acc; -encode_adhoc_command_attr_action(_val, _acc) -> - [{<<"action">>, enc_enum(_val)} | _acc]. - -decode_adhoc_command_notes(__TopXMLNS, __IgnoreEls, - {xmlel, <<"note">>, _attrs, _els}) -> - Data = decode_adhoc_command_notes_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Type = decode_adhoc_command_notes_attrs(__TopXMLNS, - _attrs, undefined), - {adhoc_note, Type, Data}. - -decode_adhoc_command_notes_els(__TopXMLNS, __IgnoreEls, - [], Data) -> - decode_adhoc_command_notes_cdata(__TopXMLNS, Data); -decode_adhoc_command_notes_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Data) -> - decode_adhoc_command_notes_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_adhoc_command_notes_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Data) -> - decode_adhoc_command_notes_els(__TopXMLNS, __IgnoreEls, - _els, Data). - -decode_adhoc_command_notes_attrs(__TopXMLNS, - [{<<"type">>, _val} | _attrs], _Type) -> - decode_adhoc_command_notes_attrs(__TopXMLNS, _attrs, - _val); -decode_adhoc_command_notes_attrs(__TopXMLNS, - [_ | _attrs], Type) -> - decode_adhoc_command_notes_attrs(__TopXMLNS, _attrs, - Type); -decode_adhoc_command_notes_attrs(__TopXMLNS, [], - Type) -> - decode_adhoc_command_notes_attr_type(__TopXMLNS, Type). - -encode_adhoc_command_notes({adhoc_note, Type, Data}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/commands">>, - [], __TopXMLNS), - _els = encode_adhoc_command_notes_cdata(Data, []), - _attrs = encode_adhoc_command_notes_attr_type(Type, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"note">>, _attrs, _els}. - -decode_adhoc_command_notes_attr_type(__TopXMLNS, - undefined) -> - info; -decode_adhoc_command_notes_attr_type(__TopXMLNS, - _val) -> - case catch dec_enum(_val, [info, warn, error]) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"type">>, <<"note">>, __TopXMLNS}}); - _res -> _res - end. - -encode_adhoc_command_notes_attr_type(info, _acc) -> - _acc; -encode_adhoc_command_notes_attr_type(_val, _acc) -> - [{<<"type">>, enc_enum(_val)} | _acc]. - -decode_adhoc_command_notes_cdata(__TopXMLNS, <<>>) -> - <<>>; -decode_adhoc_command_notes_cdata(__TopXMLNS, _val) -> - _val. - -encode_adhoc_command_notes_cdata(<<>>, _acc) -> _acc; -encode_adhoc_command_notes_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_adhoc_command_actions(__TopXMLNS, __IgnoreEls, - {xmlel, <<"actions">>, _attrs, _els}) -> - {Next, Complete, Prev} = - decode_adhoc_command_actions_els(__TopXMLNS, - __IgnoreEls, _els, false, false, - false), - Execute = decode_adhoc_command_actions_attrs(__TopXMLNS, - _attrs, undefined), - {adhoc_actions, Execute, Prev, Next, Complete}. - -decode_adhoc_command_actions_els(__TopXMLNS, - __IgnoreEls, [], Next, Complete, Prev) -> - {Next, Complete, Prev}; -decode_adhoc_command_actions_els(__TopXMLNS, - __IgnoreEls, - [{xmlel, <<"prev">>, _attrs, _} = _el | _els], - Next, Complete, Prev) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/commands">> -> - decode_adhoc_command_actions_els(__TopXMLNS, - __IgnoreEls, _els, Next, Complete, - decode_adhoc_command_prev(__TopXMLNS, - __IgnoreEls, - _el)); - <<"http://jabber.org/protocol/commands">> -> - decode_adhoc_command_actions_els(__TopXMLNS, - __IgnoreEls, _els, Next, Complete, - decode_adhoc_command_prev(<<"http://jabber.org/protocol/commands">>, - __IgnoreEls, - _el)); - _ -> - decode_adhoc_command_actions_els(__TopXMLNS, - __IgnoreEls, _els, Next, Complete, - Prev) - end; -decode_adhoc_command_actions_els(__TopXMLNS, - __IgnoreEls, - [{xmlel, <<"next">>, _attrs, _} = _el | _els], - Next, Complete, Prev) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/commands">> -> - decode_adhoc_command_actions_els(__TopXMLNS, - __IgnoreEls, _els, - decode_adhoc_command_next(__TopXMLNS, - __IgnoreEls, - _el), - Complete, Prev); - <<"http://jabber.org/protocol/commands">> -> - decode_adhoc_command_actions_els(__TopXMLNS, - __IgnoreEls, _els, - decode_adhoc_command_next(<<"http://jabber.org/protocol/commands">>, - __IgnoreEls, - _el), - Complete, Prev); - _ -> - decode_adhoc_command_actions_els(__TopXMLNS, - __IgnoreEls, _els, Next, Complete, - Prev) - end; -decode_adhoc_command_actions_els(__TopXMLNS, - __IgnoreEls, - [{xmlel, <<"complete">>, _attrs, _} = _el - | _els], - Next, Complete, Prev) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/commands">> -> - decode_adhoc_command_actions_els(__TopXMLNS, - __IgnoreEls, _els, Next, - decode_adhoc_command_complete(__TopXMLNS, - __IgnoreEls, - _el), - Prev); - <<"http://jabber.org/protocol/commands">> -> - decode_adhoc_command_actions_els(__TopXMLNS, - __IgnoreEls, _els, Next, - decode_adhoc_command_complete(<<"http://jabber.org/protocol/commands">>, - __IgnoreEls, - _el), - Prev); - _ -> - decode_adhoc_command_actions_els(__TopXMLNS, - __IgnoreEls, _els, Next, Complete, - Prev) - end; -decode_adhoc_command_actions_els(__TopXMLNS, - __IgnoreEls, [_ | _els], Next, Complete, - Prev) -> - decode_adhoc_command_actions_els(__TopXMLNS, - __IgnoreEls, _els, Next, Complete, Prev). - -decode_adhoc_command_actions_attrs(__TopXMLNS, - [{<<"execute">>, _val} | _attrs], - _Execute) -> - decode_adhoc_command_actions_attrs(__TopXMLNS, _attrs, - _val); -decode_adhoc_command_actions_attrs(__TopXMLNS, - [_ | _attrs], Execute) -> - decode_adhoc_command_actions_attrs(__TopXMLNS, _attrs, - Execute); -decode_adhoc_command_actions_attrs(__TopXMLNS, [], - Execute) -> - decode_adhoc_command_actions_attr_execute(__TopXMLNS, - Execute). - -encode_adhoc_command_actions({adhoc_actions, Execute, - Prev, Next, Complete}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/commands">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_adhoc_command_actions_$next'(Next, - __NewTopXMLNS, - 'encode_adhoc_command_actions_$complete'(Complete, - __NewTopXMLNS, - 'encode_adhoc_command_actions_$prev'(Prev, - __NewTopXMLNS, - [])))), - _attrs = - encode_adhoc_command_actions_attr_execute(Execute, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"actions">>, _attrs, _els}. - -'encode_adhoc_command_actions_$next'(false, __TopXMLNS, - _acc) -> - _acc; -'encode_adhoc_command_actions_$next'(Next, __TopXMLNS, - _acc) -> - [encode_adhoc_command_next(Next, __TopXMLNS) | _acc]. - -'encode_adhoc_command_actions_$complete'(false, - __TopXMLNS, _acc) -> - _acc; -'encode_adhoc_command_actions_$complete'(Complete, - __TopXMLNS, _acc) -> - [encode_adhoc_command_complete(Complete, __TopXMLNS) - | _acc]. - -'encode_adhoc_command_actions_$prev'(false, __TopXMLNS, - _acc) -> - _acc; -'encode_adhoc_command_actions_$prev'(Prev, __TopXMLNS, - _acc) -> - [encode_adhoc_command_prev(Prev, __TopXMLNS) | _acc]. - -decode_adhoc_command_actions_attr_execute(__TopXMLNS, - undefined) -> - undefined; -decode_adhoc_command_actions_attr_execute(__TopXMLNS, - _val) -> - case catch dec_enum(_val, [complete, next, prev]) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"execute">>, <<"actions">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_adhoc_command_actions_attr_execute(undefined, - _acc) -> - _acc; -encode_adhoc_command_actions_attr_execute(_val, _acc) -> - [{<<"execute">>, enc_enum(_val)} | _acc]. - -decode_adhoc_command_complete(__TopXMLNS, __IgnoreEls, - {xmlel, <<"complete">>, _attrs, _els}) -> - true. - -encode_adhoc_command_complete(true, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/commands">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"complete">>, _attrs, _els}. - -decode_adhoc_command_next(__TopXMLNS, __IgnoreEls, - {xmlel, <<"next">>, _attrs, _els}) -> - true. - -encode_adhoc_command_next(true, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/commands">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"next">>, _attrs, _els}. - -decode_adhoc_command_prev(__TopXMLNS, __IgnoreEls, - {xmlel, <<"prev">>, _attrs, _els}) -> - true. - -encode_adhoc_command_prev(true, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/commands">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"prev">>, _attrs, _els}. - -decode_client_id(__TopXMLNS, __IgnoreEls, - {xmlel, <<"client-id">>, _attrs, _els}) -> - Id = decode_client_id_attrs(__TopXMLNS, _attrs, - undefined), - {client_id, Id}. - -decode_client_id_attrs(__TopXMLNS, - [{<<"id">>, _val} | _attrs], _Id) -> - decode_client_id_attrs(__TopXMLNS, _attrs, _val); -decode_client_id_attrs(__TopXMLNS, [_ | _attrs], Id) -> - decode_client_id_attrs(__TopXMLNS, _attrs, Id); -decode_client_id_attrs(__TopXMLNS, [], Id) -> - decode_client_id_attr_id(__TopXMLNS, Id). - -encode_client_id({client_id, Id}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:sid:0">>, - [], __TopXMLNS), - _els = [], - _attrs = encode_client_id_attr_id(Id, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"client-id">>, _attrs, _els}. - -decode_client_id_attr_id(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"id">>, <<"client-id">>, __TopXMLNS}}); -decode_client_id_attr_id(__TopXMLNS, _val) -> _val. - -encode_client_id_attr_id(_val, _acc) -> - [{<<"id">>, _val} | _acc]. - -decode_stanza_id(__TopXMLNS, __IgnoreEls, - {xmlel, <<"stanza-id">>, _attrs, _els}) -> - {Id, By} = decode_stanza_id_attrs(__TopXMLNS, _attrs, - undefined, undefined), - {stanza_id, By, Id}. - -decode_stanza_id_attrs(__TopXMLNS, - [{<<"id">>, _val} | _attrs], _Id, By) -> - decode_stanza_id_attrs(__TopXMLNS, _attrs, _val, By); -decode_stanza_id_attrs(__TopXMLNS, - [{<<"by">>, _val} | _attrs], Id, _By) -> - decode_stanza_id_attrs(__TopXMLNS, _attrs, Id, _val); -decode_stanza_id_attrs(__TopXMLNS, [_ | _attrs], Id, - By) -> - decode_stanza_id_attrs(__TopXMLNS, _attrs, Id, By); -decode_stanza_id_attrs(__TopXMLNS, [], Id, By) -> - {decode_stanza_id_attr_id(__TopXMLNS, Id), - decode_stanza_id_attr_by(__TopXMLNS, By)}. - -encode_stanza_id({stanza_id, By, Id}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:sid:0">>, - [], __TopXMLNS), - _els = [], - _attrs = encode_stanza_id_attr_by(By, - encode_stanza_id_attr_id(Id, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))), - {xmlel, <<"stanza-id">>, _attrs, _els}. - -decode_stanza_id_attr_id(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"id">>, <<"stanza-id">>, __TopXMLNS}}); -decode_stanza_id_attr_id(__TopXMLNS, _val) -> _val. - -encode_stanza_id_attr_id(_val, _acc) -> - [{<<"id">>, _val} | _acc]. - -decode_stanza_id_attr_by(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"by">>, <<"stanza-id">>, __TopXMLNS}}); -decode_stanza_id_attr_by(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"by">>, <<"stanza-id">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_stanza_id_attr_by(_val, _acc) -> - [{<<"by">>, enc_jid(_val)} | _acc]. - -decode_addresses(__TopXMLNS, __IgnoreEls, - {xmlel, <<"addresses">>, _attrs, _els}) -> - List = decode_addresses_els(__TopXMLNS, __IgnoreEls, - _els, []), - {addresses, List}. - -decode_addresses_els(__TopXMLNS, __IgnoreEls, [], - List) -> - lists:reverse(List); -decode_addresses_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"address">>, _attrs, _} = _el | _els], - List) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/address">> -> - decode_addresses_els(__TopXMLNS, __IgnoreEls, _els, - [decode_address(__TopXMLNS, __IgnoreEls, _el) - | List]); - <<"http://jabber.org/protocol/address">> -> - decode_addresses_els(__TopXMLNS, __IgnoreEls, _els, - [decode_address(<<"http://jabber.org/protocol/address">>, - __IgnoreEls, _el) - | List]); - _ -> - decode_addresses_els(__TopXMLNS, __IgnoreEls, _els, - List) - end; -decode_addresses_els(__TopXMLNS, __IgnoreEls, - [_ | _els], List) -> - decode_addresses_els(__TopXMLNS, __IgnoreEls, _els, - List). - -encode_addresses({addresses, List}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/address">>, - [], __TopXMLNS), - _els = lists:reverse('encode_addresses_$list'(List, - __NewTopXMLNS, [])), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"addresses">>, _attrs, _els}. - -'encode_addresses_$list'([], __TopXMLNS, _acc) -> _acc; -'encode_addresses_$list'([List | _els], __TopXMLNS, - _acc) -> - 'encode_addresses_$list'(_els, __TopXMLNS, - [encode_address(List, __TopXMLNS) | _acc]). - -decode_address(__TopXMLNS, __IgnoreEls, - {xmlel, <<"address">>, _attrs, _els}) -> - {Type, Jid, Desc, Node, Delivered} = - decode_address_attrs(__TopXMLNS, _attrs, undefined, - undefined, undefined, undefined, undefined), - {address, Type, Jid, Desc, Node, Delivered}. - -decode_address_attrs(__TopXMLNS, - [{<<"type">>, _val} | _attrs], _Type, Jid, Desc, Node, - Delivered) -> - decode_address_attrs(__TopXMLNS, _attrs, _val, Jid, - Desc, Node, Delivered); -decode_address_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], Type, _Jid, Desc, Node, - Delivered) -> - decode_address_attrs(__TopXMLNS, _attrs, Type, _val, - Desc, Node, Delivered); -decode_address_attrs(__TopXMLNS, - [{<<"desc">>, _val} | _attrs], Type, Jid, _Desc, Node, - Delivered) -> - decode_address_attrs(__TopXMLNS, _attrs, Type, Jid, - _val, Node, Delivered); -decode_address_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], Type, Jid, Desc, _Node, - Delivered) -> - decode_address_attrs(__TopXMLNS, _attrs, Type, Jid, - Desc, _val, Delivered); -decode_address_attrs(__TopXMLNS, - [{<<"delivered">>, _val} | _attrs], Type, Jid, Desc, - Node, _Delivered) -> - decode_address_attrs(__TopXMLNS, _attrs, Type, Jid, - Desc, Node, _val); -decode_address_attrs(__TopXMLNS, [_ | _attrs], Type, - Jid, Desc, Node, Delivered) -> - decode_address_attrs(__TopXMLNS, _attrs, Type, Jid, - Desc, Node, Delivered); -decode_address_attrs(__TopXMLNS, [], Type, Jid, Desc, - Node, Delivered) -> - {decode_address_attr_type(__TopXMLNS, Type), - decode_address_attr_jid(__TopXMLNS, Jid), - decode_address_attr_desc(__TopXMLNS, Desc), - decode_address_attr_node(__TopXMLNS, Node), - decode_address_attr_delivered(__TopXMLNS, Delivered)}. - -encode_address({address, Type, Jid, Desc, Node, - Delivered}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/address">>, - [], __TopXMLNS), - _els = [], - _attrs = encode_address_attr_delivered(Delivered, - encode_address_attr_node(Node, - encode_address_attr_desc(Desc, - encode_address_attr_jid(Jid, - encode_address_attr_type(Type, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)))))), - {xmlel, <<"address">>, _attrs, _els}. - -decode_address_attr_type(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"type">>, <<"address">>, __TopXMLNS}}); -decode_address_attr_type(__TopXMLNS, _val) -> - case catch dec_enum(_val, - [bcc, cc, noreply, ofrom, replyroom, replyto, to]) - of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"type">>, <<"address">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_address_attr_type(_val, _acc) -> - [{<<"type">>, enc_enum(_val)} | _acc]. - -decode_address_attr_jid(__TopXMLNS, undefined) -> - undefined; -decode_address_attr_jid(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"jid">>, <<"address">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_address_attr_jid(undefined, _acc) -> _acc; -encode_address_attr_jid(_val, _acc) -> - [{<<"jid">>, enc_jid(_val)} | _acc]. - -decode_address_attr_desc(__TopXMLNS, undefined) -> <<>>; -decode_address_attr_desc(__TopXMLNS, _val) -> _val. - -encode_address_attr_desc(<<>>, _acc) -> _acc; -encode_address_attr_desc(_val, _acc) -> - [{<<"desc">>, _val} | _acc]. - -decode_address_attr_node(__TopXMLNS, undefined) -> <<>>; -decode_address_attr_node(__TopXMLNS, _val) -> _val. - -encode_address_attr_node(<<>>, _acc) -> _acc; -encode_address_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_address_attr_delivered(__TopXMLNS, undefined) -> - undefined; -decode_address_attr_delivered(__TopXMLNS, _val) -> - case catch dec_bool(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"delivered">>, <<"address">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_address_attr_delivered(undefined, _acc) -> _acc; -encode_address_attr_delivered(_val, _acc) -> - [{<<"delivered">>, enc_bool(_val)} | _acc]. - -decode_nick(__TopXMLNS, __IgnoreEls, - {xmlel, <<"nick">>, _attrs, _els}) -> - Name = decode_nick_els(__TopXMLNS, __IgnoreEls, _els, - <<>>), - {nick, Name}. - -decode_nick_els(__TopXMLNS, __IgnoreEls, [], Name) -> - decode_nick_cdata(__TopXMLNS, Name); -decode_nick_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Name) -> - decode_nick_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_nick_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Name) -> - decode_nick_els(__TopXMLNS, __IgnoreEls, _els, Name). - -encode_nick({nick, Name}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/nick">>, - [], __TopXMLNS), - _els = encode_nick_cdata(Name, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"nick">>, _attrs, _els}. - -decode_nick_cdata(__TopXMLNS, <<>>) -> - erlang:error({xmpp_codec, - {missing_cdata, <<>>, <<"nick">>, __TopXMLNS}}); -decode_nick_cdata(__TopXMLNS, _val) -> _val. - -encode_nick_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_expire(__TopXMLNS, __IgnoreEls, - {xmlel, <<"x">>, _attrs, _els}) -> - {Seconds, Stored} = decode_expire_attrs(__TopXMLNS, - _attrs, undefined, undefined), - {expire, Seconds, Stored}. - -decode_expire_attrs(__TopXMLNS, - [{<<"seconds">>, _val} | _attrs], _Seconds, Stored) -> - decode_expire_attrs(__TopXMLNS, _attrs, _val, Stored); -decode_expire_attrs(__TopXMLNS, - [{<<"stored">>, _val} | _attrs], Seconds, _Stored) -> - decode_expire_attrs(__TopXMLNS, _attrs, Seconds, _val); -decode_expire_attrs(__TopXMLNS, [_ | _attrs], Seconds, - Stored) -> - decode_expire_attrs(__TopXMLNS, _attrs, Seconds, - Stored); -decode_expire_attrs(__TopXMLNS, [], Seconds, Stored) -> - {decode_expire_attr_seconds(__TopXMLNS, Seconds), - decode_expire_attr_stored(__TopXMLNS, Stored)}. - -encode_expire({expire, Seconds, Stored}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:expire">>, - [], __TopXMLNS), - _els = [], - _attrs = encode_expire_attr_stored(Stored, - encode_expire_attr_seconds(Seconds, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))), - {xmlel, <<"x">>, _attrs, _els}. - -decode_expire_attr_seconds(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"seconds">>, <<"x">>, __TopXMLNS}}); -decode_expire_attr_seconds(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, infinity) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"seconds">>, <<"x">>, __TopXMLNS}}); - _res -> _res - end. - -encode_expire_attr_seconds(_val, _acc) -> - [{<<"seconds">>, enc_int(_val)} | _acc]. - -decode_expire_attr_stored(__TopXMLNS, undefined) -> - undefined; -decode_expire_attr_stored(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, infinity) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"stored">>, <<"x">>, __TopXMLNS}}); - _res -> _res - end. - -encode_expire_attr_stored(undefined, _acc) -> _acc; -encode_expire_attr_stored(_val, _acc) -> - [{<<"stored">>, enc_int(_val)} | _acc]. - -decode_xevent(__TopXMLNS, __IgnoreEls, - {xmlel, <<"x">>, _attrs, _els}) -> - {Id, Displayed, Delivered, Offline, Composing} = - decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, - undefined, false, false, false, false), - {xevent, Offline, Delivered, Displayed, Composing, Id}. - -decode_xevent_els(__TopXMLNS, __IgnoreEls, [], Id, - Displayed, Delivered, Offline, Composing) -> - {Id, Displayed, Delivered, Offline, Composing}; -decode_xevent_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"offline">>, _attrs, _} = _el | _els], Id, - Displayed, Delivered, Offline, Composing) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:x:event">> -> - decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, - Displayed, Delivered, - decode_xevent_offline(__TopXMLNS, __IgnoreEls, _el), - Composing); - <<"jabber:x:event">> -> - decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, - Displayed, Delivered, - decode_xevent_offline(<<"jabber:x:event">>, - __IgnoreEls, _el), - Composing); - _ -> - decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, - Displayed, Delivered, Offline, Composing) - end; -decode_xevent_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"delivered">>, _attrs, _} = _el | _els], Id, - Displayed, Delivered, Offline, Composing) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:x:event">> -> - decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, - Displayed, - decode_xevent_delivered(__TopXMLNS, __IgnoreEls, - _el), - Offline, Composing); - <<"jabber:x:event">> -> - decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, - Displayed, - decode_xevent_delivered(<<"jabber:x:event">>, - __IgnoreEls, _el), - Offline, Composing); - _ -> - decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, - Displayed, Delivered, Offline, Composing) - end; -decode_xevent_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"displayed">>, _attrs, _} = _el | _els], Id, - Displayed, Delivered, Offline, Composing) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:x:event">> -> - decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, - decode_xevent_displayed(__TopXMLNS, __IgnoreEls, - _el), - Delivered, Offline, Composing); - <<"jabber:x:event">> -> - decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, - decode_xevent_displayed(<<"jabber:x:event">>, - __IgnoreEls, _el), - Delivered, Offline, Composing); - _ -> - decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, - Displayed, Delivered, Offline, Composing) - end; -decode_xevent_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"composing">>, _attrs, _} = _el | _els], Id, - Displayed, Delivered, Offline, Composing) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:x:event">> -> - decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, - Displayed, Delivered, Offline, - decode_xevent_composing(__TopXMLNS, __IgnoreEls, - _el)); - <<"jabber:x:event">> -> - decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, - Displayed, Delivered, Offline, - decode_xevent_composing(<<"jabber:x:event">>, - __IgnoreEls, _el)); - _ -> - decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, - Displayed, Delivered, Offline, Composing) - end; -decode_xevent_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"id">>, _attrs, _} = _el | _els], Id, - Displayed, Delivered, Offline, Composing) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:x:event">> -> - decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, - decode_xevent_id(__TopXMLNS, __IgnoreEls, _el), - Displayed, Delivered, Offline, Composing); - <<"jabber:x:event">> -> - decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, - decode_xevent_id(<<"jabber:x:event">>, __IgnoreEls, - _el), - Displayed, Delivered, Offline, Composing); - _ -> - decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, - Displayed, Delivered, Offline, Composing) - end; -decode_xevent_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Id, Displayed, Delivered, Offline, Composing) -> - decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id, - Displayed, Delivered, Offline, Composing). - -encode_xevent({xevent, Offline, Delivered, Displayed, - Composing, Id}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:event">>, - [], __TopXMLNS), - _els = lists:reverse('encode_xevent_$id'(Id, - __NewTopXMLNS, - 'encode_xevent_$displayed'(Displayed, - __NewTopXMLNS, - 'encode_xevent_$delivered'(Delivered, - __NewTopXMLNS, - 'encode_xevent_$offline'(Offline, - __NewTopXMLNS, - 'encode_xevent_$composing'(Composing, - __NewTopXMLNS, - [])))))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"x">>, _attrs, _els}. - -'encode_xevent_$id'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_xevent_$id'(Id, __TopXMLNS, _acc) -> - [encode_xevent_id(Id, __TopXMLNS) | _acc]. - -'encode_xevent_$displayed'(false, __TopXMLNS, _acc) -> - _acc; -'encode_xevent_$displayed'(Displayed, __TopXMLNS, - _acc) -> - [encode_xevent_displayed(Displayed, __TopXMLNS) | _acc]. - -'encode_xevent_$delivered'(false, __TopXMLNS, _acc) -> - _acc; -'encode_xevent_$delivered'(Delivered, __TopXMLNS, - _acc) -> - [encode_xevent_delivered(Delivered, __TopXMLNS) | _acc]. - -'encode_xevent_$offline'(false, __TopXMLNS, _acc) -> - _acc; -'encode_xevent_$offline'(Offline, __TopXMLNS, _acc) -> - [encode_xevent_offline(Offline, __TopXMLNS) | _acc]. - -'encode_xevent_$composing'(false, __TopXMLNS, _acc) -> - _acc; -'encode_xevent_$composing'(Composing, __TopXMLNS, - _acc) -> - [encode_xevent_composing(Composing, __TopXMLNS) | _acc]. - -decode_xevent_id(__TopXMLNS, __IgnoreEls, - {xmlel, <<"id">>, _attrs, _els}) -> - Cdata = decode_xevent_id_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_xevent_id_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_xevent_id_cdata(__TopXMLNS, Cdata); -decode_xevent_id_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_xevent_id_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_xevent_id_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_xevent_id_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_xevent_id(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:event">>, - [], __TopXMLNS), - _els = encode_xevent_id_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"id">>, _attrs, _els}. - -decode_xevent_id_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_xevent_id_cdata(__TopXMLNS, _val) -> _val. - -encode_xevent_id_cdata(<<>>, _acc) -> _acc; -encode_xevent_id_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_xevent_composing(__TopXMLNS, __IgnoreEls, - {xmlel, <<"composing">>, _attrs, _els}) -> - true. - -encode_xevent_composing(true, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:event">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"composing">>, _attrs, _els}. - -decode_xevent_displayed(__TopXMLNS, __IgnoreEls, - {xmlel, <<"displayed">>, _attrs, _els}) -> - true. - -encode_xevent_displayed(true, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:event">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"displayed">>, _attrs, _els}. - -decode_xevent_delivered(__TopXMLNS, __IgnoreEls, - {xmlel, <<"delivered">>, _attrs, _els}) -> - true. - -encode_xevent_delivered(true, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:event">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"delivered">>, _attrs, _els}. - -decode_xevent_offline(__TopXMLNS, __IgnoreEls, - {xmlel, <<"offline">>, _attrs, _els}) -> - true. - -encode_xevent_offline(true, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:event">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"offline">>, _attrs, _els}. - -decode_search(__TopXMLNS, __IgnoreEls, - {xmlel, <<"query">>, _attrs, _els}) -> - {Xdata, Items, Instructions, Last, First, Nick, Email} = - decode_search_els(__TopXMLNS, __IgnoreEls, _els, - undefined, [], undefined, undefined, undefined, - undefined, undefined), - {search, Instructions, First, Last, Nick, Email, Items, - Xdata}. - -decode_search_els(__TopXMLNS, __IgnoreEls, [], Xdata, - Items, Instructions, Last, First, Nick, Email) -> - {Xdata, lists:reverse(Items), Instructions, Last, First, - Nick, Email}; -decode_search_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"instructions">>, _attrs, _} = _el | _els], - Xdata, Items, Instructions, Last, First, Nick, Email) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:search">> -> - decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, - Items, - decode_search_instructions(__TopXMLNS, __IgnoreEls, - _el), - Last, First, Nick, Email); - <<"jabber:iq:search">> -> - decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, - Items, - decode_search_instructions(<<"jabber:iq:search">>, - __IgnoreEls, _el), - Last, First, Nick, Email); - _ -> - decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, - Items, Instructions, Last, First, Nick, Email) - end; -decode_search_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"first">>, _attrs, _} = _el | _els], Xdata, - Items, Instructions, Last, First, Nick, Email) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:search">> -> - decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, - Items, Instructions, Last, - decode_search_first(__TopXMLNS, __IgnoreEls, _el), - Nick, Email); - <<"jabber:iq:search">> -> - decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, - Items, Instructions, Last, - decode_search_first(<<"jabber:iq:search">>, - __IgnoreEls, _el), - Nick, Email); - _ -> - decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, - Items, Instructions, Last, First, Nick, Email) - end; -decode_search_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"last">>, _attrs, _} = _el | _els], Xdata, - Items, Instructions, Last, First, Nick, Email) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:search">> -> - decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, - Items, Instructions, - decode_search_last(__TopXMLNS, __IgnoreEls, _el), - First, Nick, Email); - <<"jabber:iq:search">> -> - decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, - Items, Instructions, - decode_search_last(<<"jabber:iq:search">>, - __IgnoreEls, _el), - First, Nick, Email); - _ -> - decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, - Items, Instructions, Last, First, Nick, Email) - end; -decode_search_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"nick">>, _attrs, _} = _el | _els], Xdata, - Items, Instructions, Last, First, Nick, Email) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:search">> -> - decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, - Items, Instructions, Last, First, - decode_search_nick(__TopXMLNS, __IgnoreEls, _el), - Email); - <<"jabber:iq:search">> -> - decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, - Items, Instructions, Last, First, - decode_search_nick(<<"jabber:iq:search">>, - __IgnoreEls, _el), - Email); - _ -> - decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, - Items, Instructions, Last, First, Nick, Email) - end; -decode_search_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"email">>, _attrs, _} = _el | _els], Xdata, - Items, Instructions, Last, First, Nick, Email) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:search">> -> - decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, - Items, Instructions, Last, First, Nick, - decode_search_email(__TopXMLNS, __IgnoreEls, _el)); - <<"jabber:iq:search">> -> - decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, - Items, Instructions, Last, First, Nick, - decode_search_email(<<"jabber:iq:search">>, - __IgnoreEls, _el)); - _ -> - decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, - Items, Instructions, Last, First, Nick, Email) - end; -decode_search_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"item">>, _attrs, _} = _el | _els], Xdata, - Items, Instructions, Last, First, Nick, Email) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:search">> -> - decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, - [decode_search_item(__TopXMLNS, __IgnoreEls, _el) - | Items], - Instructions, Last, First, Nick, Email); - <<"jabber:iq:search">> -> - decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, - [decode_search_item(<<"jabber:iq:search">>, - __IgnoreEls, _el) - | Items], - Instructions, Last, First, Nick, Email); - _ -> - decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, - Items, Instructions, Last, First, Nick, Email) - end; -decode_search_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"x">>, _attrs, _} = _el | _els], Xdata, - Items, Instructions, Last, First, Nick, Email) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"jabber:x:data">> -> - decode_search_els(__TopXMLNS, __IgnoreEls, _els, - decode_xdata(<<"jabber:x:data">>, __IgnoreEls, _el), - Items, Instructions, Last, First, Nick, Email); - _ -> - decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, - Items, Instructions, Last, First, Nick, Email) - end; -decode_search_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Xdata, Items, Instructions, Last, First, Nick, Email) -> - decode_search_els(__TopXMLNS, __IgnoreEls, _els, Xdata, - Items, Instructions, Last, First, Nick, Email). - -encode_search({search, Instructions, First, Last, Nick, - Email, Items, Xdata}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:search">>, - [], __TopXMLNS), - _els = lists:reverse('encode_search_$xdata'(Xdata, - __NewTopXMLNS, - 'encode_search_$items'(Items, - __NewTopXMLNS, - 'encode_search_$instructions'(Instructions, - __NewTopXMLNS, - 'encode_search_$last'(Last, - __NewTopXMLNS, - 'encode_search_$first'(First, - __NewTopXMLNS, - 'encode_search_$nick'(Nick, - __NewTopXMLNS, - 'encode_search_$email'(Email, - __NewTopXMLNS, - [])))))))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"query">>, _attrs, _els}. - -'encode_search_$xdata'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_search_$xdata'(Xdata, __TopXMLNS, _acc) -> - [encode_xdata(Xdata, __TopXMLNS) | _acc]. - -'encode_search_$items'([], __TopXMLNS, _acc) -> _acc; -'encode_search_$items'([Items | _els], __TopXMLNS, - _acc) -> - 'encode_search_$items'(_els, __TopXMLNS, - [encode_search_item(Items, __TopXMLNS) | _acc]). - -'encode_search_$instructions'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_search_$instructions'(Instructions, __TopXMLNS, - _acc) -> - [encode_search_instructions(Instructions, __TopXMLNS) - | _acc]. - -'encode_search_$last'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_search_$last'(Last, __TopXMLNS, _acc) -> - [encode_search_last(Last, __TopXMLNS) | _acc]. - -'encode_search_$first'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_search_$first'(First, __TopXMLNS, _acc) -> - [encode_search_first(First, __TopXMLNS) | _acc]. - -'encode_search_$nick'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_search_$nick'(Nick, __TopXMLNS, _acc) -> - [encode_search_nick(Nick, __TopXMLNS) | _acc]. - -'encode_search_$email'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_search_$email'(Email, __TopXMLNS, _acc) -> - [encode_search_email(Email, __TopXMLNS) | _acc]. - -decode_search_item(__TopXMLNS, __IgnoreEls, - {xmlel, <<"item">>, _attrs, _els}) -> - {Last, First, Nick, Email} = - decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, - undefined, undefined, undefined, undefined), - Jid = decode_search_item_attrs(__TopXMLNS, _attrs, - undefined), - {search_item, Jid, First, Last, Nick, Email}. - -decode_search_item_els(__TopXMLNS, __IgnoreEls, [], - Last, First, Nick, Email) -> - {Last, First, Nick, Email}; -decode_search_item_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"first">>, _attrs, _} = _el | _els], Last, - First, Nick, Email) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:search">> -> - decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, - Last, - decode_search_first(__TopXMLNS, __IgnoreEls, - _el), - Nick, Email); - <<"jabber:iq:search">> -> - decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, - Last, - decode_search_first(<<"jabber:iq:search">>, - __IgnoreEls, _el), - Nick, Email); - _ -> - decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, - Last, First, Nick, Email) - end; -decode_search_item_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"last">>, _attrs, _} = _el | _els], Last, - First, Nick, Email) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:search">> -> - decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, - decode_search_last(__TopXMLNS, __IgnoreEls, - _el), - First, Nick, Email); - <<"jabber:iq:search">> -> - decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, - decode_search_last(<<"jabber:iq:search">>, - __IgnoreEls, _el), - First, Nick, Email); - _ -> - decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, - Last, First, Nick, Email) - end; -decode_search_item_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"nick">>, _attrs, _} = _el | _els], Last, - First, Nick, Email) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:search">> -> - decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, - Last, First, - decode_search_nick(__TopXMLNS, __IgnoreEls, - _el), - Email); - <<"jabber:iq:search">> -> - decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, - Last, First, - decode_search_nick(<<"jabber:iq:search">>, - __IgnoreEls, _el), - Email); - _ -> - decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, - Last, First, Nick, Email) - end; -decode_search_item_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"email">>, _attrs, _} = _el | _els], Last, - First, Nick, Email) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:search">> -> - decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, - Last, First, Nick, - decode_search_email(__TopXMLNS, __IgnoreEls, - _el)); - <<"jabber:iq:search">> -> - decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, - Last, First, Nick, - decode_search_email(<<"jabber:iq:search">>, - __IgnoreEls, _el)); - _ -> - decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, - Last, First, Nick, Email) - end; -decode_search_item_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Last, First, Nick, Email) -> - decode_search_item_els(__TopXMLNS, __IgnoreEls, _els, - Last, First, Nick, Email). - -decode_search_item_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], _Jid) -> - decode_search_item_attrs(__TopXMLNS, _attrs, _val); -decode_search_item_attrs(__TopXMLNS, [_ | _attrs], - Jid) -> - decode_search_item_attrs(__TopXMLNS, _attrs, Jid); -decode_search_item_attrs(__TopXMLNS, [], Jid) -> - decode_search_item_attr_jid(__TopXMLNS, Jid). - -encode_search_item({search_item, Jid, First, Last, Nick, - Email}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:search">>, - [], __TopXMLNS), - _els = lists:reverse('encode_search_item_$last'(Last, - __NewTopXMLNS, - 'encode_search_item_$first'(First, - __NewTopXMLNS, - 'encode_search_item_$nick'(Nick, - __NewTopXMLNS, - 'encode_search_item_$email'(Email, - __NewTopXMLNS, - []))))), - _attrs = encode_search_item_attr_jid(Jid, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"item">>, _attrs, _els}. - -'encode_search_item_$last'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_search_item_$last'(Last, __TopXMLNS, _acc) -> - [encode_search_last(Last, __TopXMLNS) | _acc]. - -'encode_search_item_$first'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_search_item_$first'(First, __TopXMLNS, _acc) -> - [encode_search_first(First, __TopXMLNS) | _acc]. - -'encode_search_item_$nick'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_search_item_$nick'(Nick, __TopXMLNS, _acc) -> - [encode_search_nick(Nick, __TopXMLNS) | _acc]. - -'encode_search_item_$email'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_search_item_$email'(Email, __TopXMLNS, _acc) -> - [encode_search_email(Email, __TopXMLNS) | _acc]. - -decode_search_item_attr_jid(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"jid">>, <<"item">>, __TopXMLNS}}); -decode_search_item_attr_jid(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"jid">>, <<"item">>, __TopXMLNS}}); - _res -> _res - end. - -encode_search_item_attr_jid(_val, _acc) -> - [{<<"jid">>, enc_jid(_val)} | _acc]. - -decode_search_email(__TopXMLNS, __IgnoreEls, - {xmlel, <<"email">>, _attrs, _els}) -> - Cdata = decode_search_email_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_search_email_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_search_email_cdata(__TopXMLNS, Cdata); -decode_search_email_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_search_email_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_search_email_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_search_email_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_search_email(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:search">>, - [], __TopXMLNS), - _els = encode_search_email_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"email">>, _attrs, _els}. - -decode_search_email_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_search_email_cdata(__TopXMLNS, _val) -> _val. - -encode_search_email_cdata(<<>>, _acc) -> _acc; -encode_search_email_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_search_nick(__TopXMLNS, __IgnoreEls, - {xmlel, <<"nick">>, _attrs, _els}) -> - Cdata = decode_search_nick_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_search_nick_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_search_nick_cdata(__TopXMLNS, Cdata); -decode_search_nick_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_search_nick_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_search_nick_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_search_nick_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_search_nick(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:search">>, - [], __TopXMLNS), - _els = encode_search_nick_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"nick">>, _attrs, _els}. - -decode_search_nick_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_search_nick_cdata(__TopXMLNS, _val) -> _val. - -encode_search_nick_cdata(<<>>, _acc) -> _acc; -encode_search_nick_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_search_last(__TopXMLNS, __IgnoreEls, - {xmlel, <<"last">>, _attrs, _els}) -> - Cdata = decode_search_last_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_search_last_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_search_last_cdata(__TopXMLNS, Cdata); -decode_search_last_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_search_last_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_search_last_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_search_last_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_search_last(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:search">>, - [], __TopXMLNS), - _els = encode_search_last_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"last">>, _attrs, _els}. - -decode_search_last_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_search_last_cdata(__TopXMLNS, _val) -> _val. - -encode_search_last_cdata(<<>>, _acc) -> _acc; -encode_search_last_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_search_first(__TopXMLNS, __IgnoreEls, - {xmlel, <<"first">>, _attrs, _els}) -> - Cdata = decode_search_first_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_search_first_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_search_first_cdata(__TopXMLNS, Cdata); -decode_search_first_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_search_first_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_search_first_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_search_first_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_search_first(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:search">>, - [], __TopXMLNS), - _els = encode_search_first_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"first">>, _attrs, _els}. - -decode_search_first_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_search_first_cdata(__TopXMLNS, _val) -> _val. - -encode_search_first_cdata(<<>>, _acc) -> _acc; -encode_search_first_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_search_instructions(__TopXMLNS, __IgnoreEls, - {xmlel, <<"instructions">>, _attrs, _els}) -> - Cdata = decode_search_instructions_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_search_instructions_els(__TopXMLNS, __IgnoreEls, - [], Cdata) -> - decode_search_instructions_cdata(__TopXMLNS, Cdata); -decode_search_instructions_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_search_instructions_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_search_instructions_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_search_instructions_els(__TopXMLNS, __IgnoreEls, - _els, Cdata). - -encode_search_instructions(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:search">>, - [], __TopXMLNS), - _els = encode_search_instructions_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"instructions">>, _attrs, _els}. - -decode_search_instructions_cdata(__TopXMLNS, <<>>) -> - <<>>; -decode_search_instructions_cdata(__TopXMLNS, _val) -> - _val. - -encode_search_instructions_cdata(<<>>, _acc) -> _acc; -encode_search_instructions_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_hint_no_permanent_storage(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"no-permanent-storage">>, _attrs, - _els}) -> - {hint, 'no-permanent-storage'}. - -encode_hint_no_permanent_storage({hint, - 'no-permanent-storage'}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:hints">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"no-permanent-storage">>, _attrs, _els}. - -decode_hint_no_permanent_store(__TopXMLNS, __IgnoreEls, - {xmlel, <<"no-permanent-store">>, _attrs, - _els}) -> - {hint, 'no-permanent-store'}. - -encode_hint_no_permanent_store({hint, - 'no-permanent-store'}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:hints">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"no-permanent-store">>, _attrs, _els}. - -decode_hint_store(__TopXMLNS, __IgnoreEls, - {xmlel, <<"store">>, _attrs, _els}) -> - {hint, store}. - -encode_hint_store({hint, store}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:hints">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"store">>, _attrs, _els}. - -decode_hint_no_storage(__TopXMLNS, __IgnoreEls, - {xmlel, <<"no-storage">>, _attrs, _els}) -> - {hint, 'no-storage'}. - -encode_hint_no_storage({hint, 'no-storage'}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:hints">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"no-storage">>, _attrs, _els}. - -decode_hint_no_store(__TopXMLNS, __IgnoreEls, - {xmlel, <<"no-store">>, _attrs, _els}) -> - {hint, 'no-store'}. - -encode_hint_no_store({hint, 'no-store'}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:hints">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"no-store">>, _attrs, _els}. - -decode_hint_no_copy(__TopXMLNS, __IgnoreEls, - {xmlel, <<"no-copy">>, _attrs, _els}) -> - {hint, 'no-copy'}. - -encode_hint_no_copy({hint, 'no-copy'}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:hints">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"no-copy">>, _attrs, _els}. - -decode_mix_participant(__TopXMLNS, __IgnoreEls, - {xmlel, <<"participant">>, _attrs, _els}) -> - {Jid, Nick} = decode_mix_participant_attrs(__TopXMLNS, - _attrs, undefined, undefined), - {mix_participant, Jid, Nick}. - -decode_mix_participant_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], _Jid, Nick) -> - decode_mix_participant_attrs(__TopXMLNS, _attrs, _val, - Nick); -decode_mix_participant_attrs(__TopXMLNS, - [{<<"nick">>, _val} | _attrs], Jid, _Nick) -> - decode_mix_participant_attrs(__TopXMLNS, _attrs, Jid, - _val); -decode_mix_participant_attrs(__TopXMLNS, [_ | _attrs], - Jid, Nick) -> - decode_mix_participant_attrs(__TopXMLNS, _attrs, Jid, - Nick); -decode_mix_participant_attrs(__TopXMLNS, [], Jid, - Nick) -> - {decode_mix_participant_attr_jid(__TopXMLNS, Jid), - decode_mix_participant_attr_nick(__TopXMLNS, Nick)}. - -encode_mix_participant({mix_participant, Jid, Nick}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:mix:0">>, - [], __TopXMLNS), - _els = [], - _attrs = encode_mix_participant_attr_nick(Nick, - encode_mix_participant_attr_jid(Jid, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))), - {xmlel, <<"participant">>, _attrs, _els}. - -decode_mix_participant_attr_jid(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"jid">>, <<"participant">>, - __TopXMLNS}}); -decode_mix_participant_attr_jid(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"jid">>, <<"participant">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_mix_participant_attr_jid(_val, _acc) -> - [{<<"jid">>, enc_jid(_val)} | _acc]. - -decode_mix_participant_attr_nick(__TopXMLNS, - undefined) -> - <<>>; -decode_mix_participant_attr_nick(__TopXMLNS, _val) -> - _val. - -encode_mix_participant_attr_nick(<<>>, _acc) -> _acc; -encode_mix_participant_attr_nick(_val, _acc) -> - [{<<"nick">>, _val} | _acc]. - -decode_mix_leave(__TopXMLNS, __IgnoreEls, - {xmlel, <<"leave">>, _attrs, _els}) -> - {mix_leave}. - -encode_mix_leave({mix_leave}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:mix:0">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"leave">>, _attrs, _els}. - -decode_mix_join(__TopXMLNS, __IgnoreEls, - {xmlel, <<"join">>, _attrs, _els}) -> - Subscribe = decode_mix_join_els(__TopXMLNS, __IgnoreEls, - _els, []), - Jid = decode_mix_join_attrs(__TopXMLNS, _attrs, - undefined), - {mix_join, Jid, Subscribe}. - -decode_mix_join_els(__TopXMLNS, __IgnoreEls, [], - Subscribe) -> - lists:reverse(Subscribe); -decode_mix_join_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"subscribe">>, _attrs, _} = _el | _els], - Subscribe) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"urn:xmpp:mix:0">> -> - decode_mix_join_els(__TopXMLNS, __IgnoreEls, _els, - [decode_mix_subscribe(__TopXMLNS, __IgnoreEls, - _el) - | Subscribe]); - <<"urn:xmpp:mix:0">> -> - decode_mix_join_els(__TopXMLNS, __IgnoreEls, _els, - [decode_mix_subscribe(<<"urn:xmpp:mix:0">>, - __IgnoreEls, _el) - | Subscribe]); - _ -> - decode_mix_join_els(__TopXMLNS, __IgnoreEls, _els, - Subscribe) - end; -decode_mix_join_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Subscribe) -> - decode_mix_join_els(__TopXMLNS, __IgnoreEls, _els, - Subscribe). - -decode_mix_join_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], _Jid) -> - decode_mix_join_attrs(__TopXMLNS, _attrs, _val); -decode_mix_join_attrs(__TopXMLNS, [_ | _attrs], Jid) -> - decode_mix_join_attrs(__TopXMLNS, _attrs, Jid); -decode_mix_join_attrs(__TopXMLNS, [], Jid) -> - decode_mix_join_attr_jid(__TopXMLNS, Jid). - -encode_mix_join({mix_join, Jid, Subscribe}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:mix:0">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_mix_join_$subscribe'(Subscribe, - __NewTopXMLNS, [])), - _attrs = encode_mix_join_attr_jid(Jid, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"join">>, _attrs, _els}. - -'encode_mix_join_$subscribe'([], __TopXMLNS, _acc) -> - _acc; -'encode_mix_join_$subscribe'([Subscribe | _els], - __TopXMLNS, _acc) -> - 'encode_mix_join_$subscribe'(_els, __TopXMLNS, - [encode_mix_subscribe(Subscribe, __TopXMLNS) - | _acc]). - -decode_mix_join_attr_jid(__TopXMLNS, undefined) -> - undefined; -decode_mix_join_attr_jid(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"jid">>, <<"join">>, __TopXMLNS}}); - _res -> _res - end. - -encode_mix_join_attr_jid(undefined, _acc) -> _acc; -encode_mix_join_attr_jid(_val, _acc) -> - [{<<"jid">>, enc_jid(_val)} | _acc]. - -decode_mix_subscribe(__TopXMLNS, __IgnoreEls, - {xmlel, <<"subscribe">>, _attrs, _els}) -> - Node = decode_mix_subscribe_attrs(__TopXMLNS, _attrs, - undefined), - Node. - -decode_mix_subscribe_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], _Node) -> - decode_mix_subscribe_attrs(__TopXMLNS, _attrs, _val); -decode_mix_subscribe_attrs(__TopXMLNS, [_ | _attrs], - Node) -> - decode_mix_subscribe_attrs(__TopXMLNS, _attrs, Node); -decode_mix_subscribe_attrs(__TopXMLNS, [], Node) -> - decode_mix_subscribe_attr_node(__TopXMLNS, Node). - -encode_mix_subscribe(Node, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:mix:0">>, - [], __TopXMLNS), - _els = [], - _attrs = encode_mix_subscribe_attr_node(Node, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"subscribe">>, _attrs, _els}. - -decode_mix_subscribe_attr_node(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"node">>, <<"subscribe">>, - __TopXMLNS}}); -decode_mix_subscribe_attr_node(__TopXMLNS, _val) -> - _val. - -encode_mix_subscribe_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_offline(__TopXMLNS, __IgnoreEls, - {xmlel, <<"offline">>, _attrs, _els}) -> - {Items, Purge, Fetch} = decode_offline_els(__TopXMLNS, - __IgnoreEls, _els, [], false, - false), - {offline, Items, Purge, Fetch}. - -decode_offline_els(__TopXMLNS, __IgnoreEls, [], Items, - Purge, Fetch) -> - {lists:reverse(Items), Purge, Fetch}; -decode_offline_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"purge">>, _attrs, _} = _el | _els], Items, - Purge, Fetch) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/offline">> -> - decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items, - decode_offline_purge(__TopXMLNS, __IgnoreEls, _el), - Fetch); - <<"http://jabber.org/protocol/offline">> -> - decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items, - decode_offline_purge(<<"http://jabber.org/protocol/offline">>, - __IgnoreEls, _el), - Fetch); - _ -> - decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items, - Purge, Fetch) - end; -decode_offline_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"fetch">>, _attrs, _} = _el | _els], Items, - Purge, Fetch) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/offline">> -> - decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items, - Purge, - decode_offline_fetch(__TopXMLNS, __IgnoreEls, - _el)); - <<"http://jabber.org/protocol/offline">> -> - decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items, - Purge, - decode_offline_fetch(<<"http://jabber.org/protocol/offline">>, - __IgnoreEls, _el)); - _ -> - decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items, - Purge, Fetch) - end; -decode_offline_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items, - Purge, Fetch) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/offline">> -> - decode_offline_els(__TopXMLNS, __IgnoreEls, _els, - [decode_offline_item(__TopXMLNS, __IgnoreEls, _el) - | Items], - Purge, Fetch); - <<"http://jabber.org/protocol/offline">> -> - decode_offline_els(__TopXMLNS, __IgnoreEls, _els, - [decode_offline_item(<<"http://jabber.org/protocol/offline">>, - __IgnoreEls, _el) - | Items], - Purge, Fetch); - _ -> - decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items, - Purge, Fetch) - end; -decode_offline_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Items, Purge, Fetch) -> - decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items, - Purge, Fetch). - -encode_offline({offline, Items, Purge, Fetch}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/offline">>, - [], __TopXMLNS), - _els = lists:reverse('encode_offline_$items'(Items, - __NewTopXMLNS, - 'encode_offline_$purge'(Purge, - __NewTopXMLNS, - 'encode_offline_$fetch'(Fetch, - __NewTopXMLNS, - [])))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"offline">>, _attrs, _els}. - -'encode_offline_$items'([], __TopXMLNS, _acc) -> _acc; -'encode_offline_$items'([Items | _els], __TopXMLNS, - _acc) -> - 'encode_offline_$items'(_els, __TopXMLNS, - [encode_offline_item(Items, __TopXMLNS) | _acc]). - -'encode_offline_$purge'(false, __TopXMLNS, _acc) -> - _acc; -'encode_offline_$purge'(Purge, __TopXMLNS, _acc) -> - [encode_offline_purge(Purge, __TopXMLNS) | _acc]. - -'encode_offline_$fetch'(false, __TopXMLNS, _acc) -> - _acc; -'encode_offline_$fetch'(Fetch, __TopXMLNS, _acc) -> - [encode_offline_fetch(Fetch, __TopXMLNS) | _acc]. - -decode_offline_item(__TopXMLNS, __IgnoreEls, - {xmlel, <<"item">>, _attrs, _els}) -> - {Node, Action} = decode_offline_item_attrs(__TopXMLNS, - _attrs, undefined, undefined), - {offline_item, Node, Action}. - -decode_offline_item_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], _Node, Action) -> - decode_offline_item_attrs(__TopXMLNS, _attrs, _val, - Action); -decode_offline_item_attrs(__TopXMLNS, - [{<<"action">>, _val} | _attrs], Node, _Action) -> - decode_offline_item_attrs(__TopXMLNS, _attrs, Node, - _val); -decode_offline_item_attrs(__TopXMLNS, [_ | _attrs], - Node, Action) -> - decode_offline_item_attrs(__TopXMLNS, _attrs, Node, - Action); -decode_offline_item_attrs(__TopXMLNS, [], Node, - Action) -> - {decode_offline_item_attr_node(__TopXMLNS, Node), - decode_offline_item_attr_action(__TopXMLNS, Action)}. - -encode_offline_item({offline_item, Node, Action}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/offline">>, - [], __TopXMLNS), - _els = [], - _attrs = encode_offline_item_attr_action(Action, - encode_offline_item_attr_node(Node, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))), - {xmlel, <<"item">>, _attrs, _els}. - -decode_offline_item_attr_node(__TopXMLNS, undefined) -> - <<>>; -decode_offline_item_attr_node(__TopXMLNS, _val) -> _val. - -encode_offline_item_attr_node(<<>>, _acc) -> _acc; -encode_offline_item_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_offline_item_attr_action(__TopXMLNS, - undefined) -> - undefined; -decode_offline_item_attr_action(__TopXMLNS, _val) -> - case catch dec_enum(_val, [view, remove]) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"action">>, <<"item">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_offline_item_attr_action(undefined, _acc) -> - _acc; -encode_offline_item_attr_action(_val, _acc) -> - [{<<"action">>, enc_enum(_val)} | _acc]. - -decode_offline_fetch(__TopXMLNS, __IgnoreEls, - {xmlel, <<"fetch">>, _attrs, _els}) -> - true. - -encode_offline_fetch(true, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/offline">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"fetch">>, _attrs, _els}. - -decode_offline_purge(__TopXMLNS, __IgnoreEls, - {xmlel, <<"purge">>, _attrs, _els}) -> - true. - -encode_offline_purge(true, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/offline">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"purge">>, _attrs, _els}. - -decode_sm_failed(__TopXMLNS, __IgnoreEls, - {xmlel, <<"failed">>, _attrs, _els}) -> - Reason = decode_sm_failed_els(__TopXMLNS, __IgnoreEls, - _els, undefined), - {H, Xmlns} = decode_sm_failed_attrs(__TopXMLNS, _attrs, - undefined, undefined), - {sm_failed, Reason, H, Xmlns}. - -decode_sm_failed_els(__TopXMLNS, __IgnoreEls, [], - Reason) -> - Reason; -decode_sm_failed_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"bad-request">>, _attrs, _} = _el | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_bad_request(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el)); - _ -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) - end; -decode_sm_failed_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"conflict">>, _attrs, _} = _el | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_conflict(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el)); - _ -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) - end; -decode_sm_failed_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"feature-not-implemented">>, _attrs, _} = _el - | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_feature_not_implemented(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, - _el)); - _ -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) - end; -decode_sm_failed_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"forbidden">>, _attrs, _} = _el | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_forbidden(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el)); - _ -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) - end; -decode_sm_failed_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"gone">>, _attrs, _} = _el | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_gone(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el)); - _ -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) - end; -decode_sm_failed_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"internal-server-error">>, _attrs, _} = _el - | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_internal_server_error(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, - _el)); - _ -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) - end; -decode_sm_failed_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"item-not-found">>, _attrs, _} = _el | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_item_not_found(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el)); - _ -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) - end; -decode_sm_failed_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"jid-malformed">>, _attrs, _} = _el | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_jid_malformed(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el)); - _ -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) - end; -decode_sm_failed_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"not-acceptable">>, _attrs, _} = _el | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_not_acceptable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el)); - _ -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) - end; -decode_sm_failed_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"not-allowed">>, _attrs, _} = _el | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_not_allowed(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el)); - _ -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) - end; -decode_sm_failed_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"not-authorized">>, _attrs, _} = _el | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_not_authorized(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el)); - _ -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) - end; -decode_sm_failed_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"policy-violation">>, _attrs, _} = _el - | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_policy_violation(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el)); - _ -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) - end; -decode_sm_failed_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"recipient-unavailable">>, _attrs, _} = _el - | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_recipient_unavailable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, - _el)); - _ -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) - end; -decode_sm_failed_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"redirect">>, _attrs, _} = _el | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_redirect(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el)); - _ -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) - end; -decode_sm_failed_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"registration-required">>, _attrs, _} = _el - | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_registration_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, - _el)); - _ -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) - end; -decode_sm_failed_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"remote-server-not-found">>, _attrs, _} = _el - | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_remote_server_not_found(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, - _el)); - _ -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) - end; -decode_sm_failed_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"remote-server-timeout">>, _attrs, _} = _el - | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_remote_server_timeout(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, - _el)); - _ -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) - end; -decode_sm_failed_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"resource-constraint">>, _attrs, _} = _el - | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_resource_constraint(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, - _el)); - _ -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) - end; -decode_sm_failed_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"service-unavailable">>, _attrs, _} = _el - | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_service_unavailable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, - _el)); - _ -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) - end; -decode_sm_failed_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"subscription-required">>, _attrs, _} = _el - | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_subscription_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, - _el)); - _ -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) - end; -decode_sm_failed_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"undefined-condition">>, _attrs, _} = _el - | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_undefined_condition(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, - _el)); - _ -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) - end; -decode_sm_failed_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"unexpected-request">>, _attrs, _} = _el - | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_unexpected_request(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, - _el)); - _ -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason) - end; -decode_sm_failed_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Reason) -> - decode_sm_failed_els(__TopXMLNS, __IgnoreEls, _els, - Reason). - -decode_sm_failed_attrs(__TopXMLNS, - [{<<"h">>, _val} | _attrs], _H, Xmlns) -> - decode_sm_failed_attrs(__TopXMLNS, _attrs, _val, Xmlns); -decode_sm_failed_attrs(__TopXMLNS, - [{<<"xmlns">>, _val} | _attrs], H, _Xmlns) -> - decode_sm_failed_attrs(__TopXMLNS, _attrs, H, _val); -decode_sm_failed_attrs(__TopXMLNS, [_ | _attrs], H, - Xmlns) -> - decode_sm_failed_attrs(__TopXMLNS, _attrs, H, Xmlns); -decode_sm_failed_attrs(__TopXMLNS, [], H, Xmlns) -> - {decode_sm_failed_attr_h(__TopXMLNS, H), - decode_sm_failed_attr_xmlns(__TopXMLNS, Xmlns)}. - -encode_sm_failed({sm_failed, Reason, H, Xmlns}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(Xmlns, - [<<"urn:xmpp:sm:2">>, <<"urn:xmpp:sm:3">>], - __TopXMLNS), - _els = lists:reverse('encode_sm_failed_$reason'(Reason, - __NewTopXMLNS, [])), - _attrs = encode_sm_failed_attr_h(H, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"failed">>, _attrs, _els}. - -'encode_sm_failed_$reason'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_sm_failed_$reason'('bad-request' = Reason, - __TopXMLNS, _acc) -> - [encode_error_bad_request(Reason, __TopXMLNS) | _acc]; -'encode_sm_failed_$reason'(conflict = Reason, - __TopXMLNS, _acc) -> - [encode_error_conflict(Reason, __TopXMLNS) | _acc]; -'encode_sm_failed_$reason'('feature-not-implemented' = - Reason, - __TopXMLNS, _acc) -> - [encode_error_feature_not_implemented(Reason, - __TopXMLNS) - | _acc]; -'encode_sm_failed_$reason'(forbidden = Reason, - __TopXMLNS, _acc) -> - [encode_error_forbidden(Reason, __TopXMLNS) | _acc]; -'encode_sm_failed_$reason'({gone, _} = Reason, - __TopXMLNS, _acc) -> - [encode_error_gone(Reason, __TopXMLNS) | _acc]; -'encode_sm_failed_$reason'('internal-server-error' = - Reason, - __TopXMLNS, _acc) -> - [encode_error_internal_server_error(Reason, __TopXMLNS) - | _acc]; -'encode_sm_failed_$reason'('item-not-found' = Reason, - __TopXMLNS, _acc) -> - [encode_error_item_not_found(Reason, __TopXMLNS) - | _acc]; -'encode_sm_failed_$reason'('jid-malformed' = Reason, - __TopXMLNS, _acc) -> - [encode_error_jid_malformed(Reason, __TopXMLNS) | _acc]; -'encode_sm_failed_$reason'('not-acceptable' = Reason, - __TopXMLNS, _acc) -> - [encode_error_not_acceptable(Reason, __TopXMLNS) - | _acc]; -'encode_sm_failed_$reason'('not-allowed' = Reason, - __TopXMLNS, _acc) -> - [encode_error_not_allowed(Reason, __TopXMLNS) | _acc]; -'encode_sm_failed_$reason'('not-authorized' = Reason, - __TopXMLNS, _acc) -> - [encode_error_not_authorized(Reason, __TopXMLNS) - | _acc]; -'encode_sm_failed_$reason'('policy-violation' = Reason, - __TopXMLNS, _acc) -> - [encode_error_policy_violation(Reason, __TopXMLNS) - | _acc]; -'encode_sm_failed_$reason'('recipient-unavailable' = - Reason, - __TopXMLNS, _acc) -> - [encode_error_recipient_unavailable(Reason, __TopXMLNS) - | _acc]; -'encode_sm_failed_$reason'({redirect, _} = Reason, - __TopXMLNS, _acc) -> - [encode_error_redirect(Reason, __TopXMLNS) | _acc]; -'encode_sm_failed_$reason'('registration-required' = - Reason, - __TopXMLNS, _acc) -> - [encode_error_registration_required(Reason, __TopXMLNS) - | _acc]; -'encode_sm_failed_$reason'('remote-server-not-found' = - Reason, - __TopXMLNS, _acc) -> - [encode_error_remote_server_not_found(Reason, - __TopXMLNS) - | _acc]; -'encode_sm_failed_$reason'('remote-server-timeout' = - Reason, - __TopXMLNS, _acc) -> - [encode_error_remote_server_timeout(Reason, __TopXMLNS) - | _acc]; -'encode_sm_failed_$reason'('resource-constraint' = - Reason, - __TopXMLNS, _acc) -> - [encode_error_resource_constraint(Reason, __TopXMLNS) - | _acc]; -'encode_sm_failed_$reason'('service-unavailable' = - Reason, - __TopXMLNS, _acc) -> - [encode_error_service_unavailable(Reason, __TopXMLNS) - | _acc]; -'encode_sm_failed_$reason'('subscription-required' = - Reason, - __TopXMLNS, _acc) -> - [encode_error_subscription_required(Reason, __TopXMLNS) - | _acc]; -'encode_sm_failed_$reason'('undefined-condition' = - Reason, - __TopXMLNS, _acc) -> - [encode_error_undefined_condition(Reason, __TopXMLNS) - | _acc]; -'encode_sm_failed_$reason'('unexpected-request' = - Reason, - __TopXMLNS, _acc) -> - [encode_error_unexpected_request(Reason, __TopXMLNS) - | _acc]. - -decode_sm_failed_attr_h(__TopXMLNS, undefined) -> - undefined; -decode_sm_failed_attr_h(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, infinity) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"h">>, <<"failed">>, __TopXMLNS}}); - _res -> _res - end. - -encode_sm_failed_attr_h(undefined, _acc) -> _acc; -encode_sm_failed_attr_h(_val, _acc) -> - [{<<"h">>, enc_int(_val)} | _acc]. - -decode_sm_failed_attr_xmlns(__TopXMLNS, undefined) -> - <<>>; -decode_sm_failed_attr_xmlns(__TopXMLNS, _val) -> _val. - -decode_sm_a(__TopXMLNS, __IgnoreEls, - {xmlel, <<"a">>, _attrs, _els}) -> - {H, Xmlns} = decode_sm_a_attrs(__TopXMLNS, _attrs, - undefined, undefined), - {sm_a, H, Xmlns}. - -decode_sm_a_attrs(__TopXMLNS, - [{<<"h">>, _val} | _attrs], _H, Xmlns) -> - decode_sm_a_attrs(__TopXMLNS, _attrs, _val, Xmlns); -decode_sm_a_attrs(__TopXMLNS, - [{<<"xmlns">>, _val} | _attrs], H, _Xmlns) -> - decode_sm_a_attrs(__TopXMLNS, _attrs, H, _val); -decode_sm_a_attrs(__TopXMLNS, [_ | _attrs], H, Xmlns) -> - decode_sm_a_attrs(__TopXMLNS, _attrs, H, Xmlns); -decode_sm_a_attrs(__TopXMLNS, [], H, Xmlns) -> - {decode_sm_a_attr_h(__TopXMLNS, H), - decode_sm_a_attr_xmlns(__TopXMLNS, Xmlns)}. - -encode_sm_a({sm_a, H, Xmlns}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(Xmlns, - [<<"urn:xmpp:sm:2">>, <<"urn:xmpp:sm:3">>], - __TopXMLNS), - _els = [], - _attrs = encode_sm_a_attr_h(H, - enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS)), - {xmlel, <<"a">>, _attrs, _els}. - -decode_sm_a_attr_h(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"h">>, <<"a">>, __TopXMLNS}}); -decode_sm_a_attr_h(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, infinity) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"h">>, <<"a">>, __TopXMLNS}}); - _res -> _res - end. - -encode_sm_a_attr_h(_val, _acc) -> - [{<<"h">>, enc_int(_val)} | _acc]. - -decode_sm_a_attr_xmlns(__TopXMLNS, undefined) -> <<>>; -decode_sm_a_attr_xmlns(__TopXMLNS, _val) -> _val. - -decode_sm_r(__TopXMLNS, __IgnoreEls, - {xmlel, <<"r">>, _attrs, _els}) -> - Xmlns = decode_sm_r_attrs(__TopXMLNS, _attrs, - undefined), - {sm_r, Xmlns}. - -decode_sm_r_attrs(__TopXMLNS, - [{<<"xmlns">>, _val} | _attrs], _Xmlns) -> - decode_sm_r_attrs(__TopXMLNS, _attrs, _val); -decode_sm_r_attrs(__TopXMLNS, [_ | _attrs], Xmlns) -> - decode_sm_r_attrs(__TopXMLNS, _attrs, Xmlns); -decode_sm_r_attrs(__TopXMLNS, [], Xmlns) -> - decode_sm_r_attr_xmlns(__TopXMLNS, Xmlns). - -encode_sm_r({sm_r, Xmlns}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(Xmlns, - [<<"urn:xmpp:sm:2">>, <<"urn:xmpp:sm:3">>], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"r">>, _attrs, _els}. - -decode_sm_r_attr_xmlns(__TopXMLNS, undefined) -> <<>>; -decode_sm_r_attr_xmlns(__TopXMLNS, _val) -> _val. - -decode_sm_resumed(__TopXMLNS, __IgnoreEls, - {xmlel, <<"resumed">>, _attrs, _els}) -> - {H, Xmlns, Previd} = decode_sm_resumed_attrs(__TopXMLNS, - _attrs, undefined, undefined, - undefined), - {sm_resumed, H, Previd, Xmlns}. - -decode_sm_resumed_attrs(__TopXMLNS, - [{<<"h">>, _val} | _attrs], _H, Xmlns, Previd) -> - decode_sm_resumed_attrs(__TopXMLNS, _attrs, _val, Xmlns, - Previd); -decode_sm_resumed_attrs(__TopXMLNS, - [{<<"xmlns">>, _val} | _attrs], H, _Xmlns, Previd) -> - decode_sm_resumed_attrs(__TopXMLNS, _attrs, H, _val, - Previd); -decode_sm_resumed_attrs(__TopXMLNS, - [{<<"previd">>, _val} | _attrs], H, Xmlns, _Previd) -> - decode_sm_resumed_attrs(__TopXMLNS, _attrs, H, Xmlns, - _val); -decode_sm_resumed_attrs(__TopXMLNS, [_ | _attrs], H, - Xmlns, Previd) -> - decode_sm_resumed_attrs(__TopXMLNS, _attrs, H, Xmlns, - Previd); -decode_sm_resumed_attrs(__TopXMLNS, [], H, Xmlns, - Previd) -> - {decode_sm_resumed_attr_h(__TopXMLNS, H), - decode_sm_resumed_attr_xmlns(__TopXMLNS, Xmlns), - decode_sm_resumed_attr_previd(__TopXMLNS, Previd)}. - -encode_sm_resumed({sm_resumed, H, Previd, Xmlns}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(Xmlns, - [<<"urn:xmpp:sm:2">>, <<"urn:xmpp:sm:3">>], - __TopXMLNS), - _els = [], - _attrs = encode_sm_resumed_attr_previd(Previd, - encode_sm_resumed_attr_h(H, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))), - {xmlel, <<"resumed">>, _attrs, _els}. - -decode_sm_resumed_attr_h(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"h">>, <<"resumed">>, __TopXMLNS}}); -decode_sm_resumed_attr_h(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, infinity) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"h">>, <<"resumed">>, __TopXMLNS}}); - _res -> _res - end. - -encode_sm_resumed_attr_h(_val, _acc) -> - [{<<"h">>, enc_int(_val)} | _acc]. - -decode_sm_resumed_attr_xmlns(__TopXMLNS, undefined) -> - <<>>; -decode_sm_resumed_attr_xmlns(__TopXMLNS, _val) -> _val. - -decode_sm_resumed_attr_previd(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"previd">>, <<"resumed">>, - __TopXMLNS}}); -decode_sm_resumed_attr_previd(__TopXMLNS, _val) -> _val. - -encode_sm_resumed_attr_previd(_val, _acc) -> - [{<<"previd">>, _val} | _acc]. - -decode_sm_resume(__TopXMLNS, __IgnoreEls, - {xmlel, <<"resume">>, _attrs, _els}) -> - {H, Xmlns, Previd} = decode_sm_resume_attrs(__TopXMLNS, - _attrs, undefined, undefined, - undefined), - {sm_resume, H, Previd, Xmlns}. - -decode_sm_resume_attrs(__TopXMLNS, - [{<<"h">>, _val} | _attrs], _H, Xmlns, Previd) -> - decode_sm_resume_attrs(__TopXMLNS, _attrs, _val, Xmlns, - Previd); -decode_sm_resume_attrs(__TopXMLNS, - [{<<"xmlns">>, _val} | _attrs], H, _Xmlns, Previd) -> - decode_sm_resume_attrs(__TopXMLNS, _attrs, H, _val, - Previd); -decode_sm_resume_attrs(__TopXMLNS, - [{<<"previd">>, _val} | _attrs], H, Xmlns, _Previd) -> - decode_sm_resume_attrs(__TopXMLNS, _attrs, H, Xmlns, - _val); -decode_sm_resume_attrs(__TopXMLNS, [_ | _attrs], H, - Xmlns, Previd) -> - decode_sm_resume_attrs(__TopXMLNS, _attrs, H, Xmlns, - Previd); -decode_sm_resume_attrs(__TopXMLNS, [], H, Xmlns, - Previd) -> - {decode_sm_resume_attr_h(__TopXMLNS, H), - decode_sm_resume_attr_xmlns(__TopXMLNS, Xmlns), - decode_sm_resume_attr_previd(__TopXMLNS, Previd)}. - -encode_sm_resume({sm_resume, H, Previd, Xmlns}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(Xmlns, - [<<"urn:xmpp:sm:2">>, <<"urn:xmpp:sm:3">>], - __TopXMLNS), - _els = [], - _attrs = encode_sm_resume_attr_previd(Previd, - encode_sm_resume_attr_h(H, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))), - {xmlel, <<"resume">>, _attrs, _els}. - -decode_sm_resume_attr_h(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"h">>, <<"resume">>, __TopXMLNS}}); -decode_sm_resume_attr_h(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, infinity) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"h">>, <<"resume">>, __TopXMLNS}}); - _res -> _res - end. - -encode_sm_resume_attr_h(_val, _acc) -> - [{<<"h">>, enc_int(_val)} | _acc]. - -decode_sm_resume_attr_xmlns(__TopXMLNS, undefined) -> - <<>>; -decode_sm_resume_attr_xmlns(__TopXMLNS, _val) -> _val. - -decode_sm_resume_attr_previd(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"previd">>, <<"resume">>, - __TopXMLNS}}); -decode_sm_resume_attr_previd(__TopXMLNS, _val) -> _val. - -encode_sm_resume_attr_previd(_val, _acc) -> - [{<<"previd">>, _val} | _acc]. - -decode_sm_enabled(__TopXMLNS, __IgnoreEls, - {xmlel, <<"enabled">>, _attrs, _els}) -> - {Id, Location, Xmlns, Max, Resume} = - decode_sm_enabled_attrs(__TopXMLNS, _attrs, undefined, - undefined, undefined, undefined, undefined), - {sm_enabled, Id, Location, Max, Resume, Xmlns}. - -decode_sm_enabled_attrs(__TopXMLNS, - [{<<"id">>, _val} | _attrs], _Id, Location, Xmlns, Max, - Resume) -> - decode_sm_enabled_attrs(__TopXMLNS, _attrs, _val, - Location, Xmlns, Max, Resume); -decode_sm_enabled_attrs(__TopXMLNS, - [{<<"location">>, _val} | _attrs], Id, _Location, Xmlns, - Max, Resume) -> - decode_sm_enabled_attrs(__TopXMLNS, _attrs, Id, _val, - Xmlns, Max, Resume); -decode_sm_enabled_attrs(__TopXMLNS, - [{<<"xmlns">>, _val} | _attrs], Id, Location, _Xmlns, - Max, Resume) -> - decode_sm_enabled_attrs(__TopXMLNS, _attrs, Id, - Location, _val, Max, Resume); -decode_sm_enabled_attrs(__TopXMLNS, - [{<<"max">>, _val} | _attrs], Id, Location, Xmlns, _Max, - Resume) -> - decode_sm_enabled_attrs(__TopXMLNS, _attrs, Id, - Location, Xmlns, _val, Resume); -decode_sm_enabled_attrs(__TopXMLNS, - [{<<"resume">>, _val} | _attrs], Id, Location, Xmlns, - Max, _Resume) -> - decode_sm_enabled_attrs(__TopXMLNS, _attrs, Id, - Location, Xmlns, Max, _val); -decode_sm_enabled_attrs(__TopXMLNS, [_ | _attrs], Id, - Location, Xmlns, Max, Resume) -> - decode_sm_enabled_attrs(__TopXMLNS, _attrs, Id, - Location, Xmlns, Max, Resume); -decode_sm_enabled_attrs(__TopXMLNS, [], Id, Location, - Xmlns, Max, Resume) -> - {decode_sm_enabled_attr_id(__TopXMLNS, Id), - decode_sm_enabled_attr_location(__TopXMLNS, Location), - decode_sm_enabled_attr_xmlns(__TopXMLNS, Xmlns), - decode_sm_enabled_attr_max(__TopXMLNS, Max), - decode_sm_enabled_attr_resume(__TopXMLNS, Resume)}. - -encode_sm_enabled({sm_enabled, Id, Location, Max, - Resume, Xmlns}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(Xmlns, - [<<"urn:xmpp:sm:2">>, <<"urn:xmpp:sm:3">>], - __TopXMLNS), - _els = [], - _attrs = encode_sm_enabled_attr_resume(Resume, - encode_sm_enabled_attr_max(Max, - encode_sm_enabled_attr_location(Location, - encode_sm_enabled_attr_id(Id, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))))), - {xmlel, <<"enabled">>, _attrs, _els}. - -decode_sm_enabled_attr_id(__TopXMLNS, undefined) -> - <<>>; -decode_sm_enabled_attr_id(__TopXMLNS, _val) -> _val. - -encode_sm_enabled_attr_id(<<>>, _acc) -> _acc; -encode_sm_enabled_attr_id(_val, _acc) -> - [{<<"id">>, _val} | _acc]. - -decode_sm_enabled_attr_location(__TopXMLNS, - undefined) -> - <<>>; -decode_sm_enabled_attr_location(__TopXMLNS, _val) -> - _val. - -encode_sm_enabled_attr_location(<<>>, _acc) -> _acc; -encode_sm_enabled_attr_location(_val, _acc) -> - [{<<"location">>, _val} | _acc]. - -decode_sm_enabled_attr_xmlns(__TopXMLNS, undefined) -> - <<>>; -decode_sm_enabled_attr_xmlns(__TopXMLNS, _val) -> _val. - -decode_sm_enabled_attr_max(__TopXMLNS, undefined) -> - undefined; -decode_sm_enabled_attr_max(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, infinity) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"max">>, <<"enabled">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_sm_enabled_attr_max(undefined, _acc) -> _acc; -encode_sm_enabled_attr_max(_val, _acc) -> - [{<<"max">>, enc_int(_val)} | _acc]. - -decode_sm_enabled_attr_resume(__TopXMLNS, undefined) -> - false; -decode_sm_enabled_attr_resume(__TopXMLNS, _val) -> - case catch dec_bool(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"resume">>, <<"enabled">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_sm_enabled_attr_resume(false, _acc) -> _acc; -encode_sm_enabled_attr_resume(_val, _acc) -> - [{<<"resume">>, enc_bool(_val)} | _acc]. - -decode_sm_enable(__TopXMLNS, __IgnoreEls, - {xmlel, <<"enable">>, _attrs, _els}) -> - {Max, Xmlns, Resume} = - decode_sm_enable_attrs(__TopXMLNS, _attrs, undefined, - undefined, undefined), - {sm_enable, Max, Resume, Xmlns}. - -decode_sm_enable_attrs(__TopXMLNS, - [{<<"max">>, _val} | _attrs], _Max, Xmlns, Resume) -> - decode_sm_enable_attrs(__TopXMLNS, _attrs, _val, Xmlns, - Resume); -decode_sm_enable_attrs(__TopXMLNS, - [{<<"xmlns">>, _val} | _attrs], Max, _Xmlns, Resume) -> - decode_sm_enable_attrs(__TopXMLNS, _attrs, Max, _val, - Resume); -decode_sm_enable_attrs(__TopXMLNS, - [{<<"resume">>, _val} | _attrs], Max, Xmlns, _Resume) -> - decode_sm_enable_attrs(__TopXMLNS, _attrs, Max, Xmlns, - _val); -decode_sm_enable_attrs(__TopXMLNS, [_ | _attrs], Max, - Xmlns, Resume) -> - decode_sm_enable_attrs(__TopXMLNS, _attrs, Max, Xmlns, - Resume); -decode_sm_enable_attrs(__TopXMLNS, [], Max, Xmlns, - Resume) -> - {decode_sm_enable_attr_max(__TopXMLNS, Max), - decode_sm_enable_attr_xmlns(__TopXMLNS, Xmlns), - decode_sm_enable_attr_resume(__TopXMLNS, Resume)}. - -encode_sm_enable({sm_enable, Max, Resume, Xmlns}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(Xmlns, - [<<"urn:xmpp:sm:2">>, <<"urn:xmpp:sm:3">>], - __TopXMLNS), - _els = [], - _attrs = encode_sm_enable_attr_resume(Resume, - encode_sm_enable_attr_max(Max, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))), - {xmlel, <<"enable">>, _attrs, _els}. - -decode_sm_enable_attr_max(__TopXMLNS, undefined) -> - undefined; -decode_sm_enable_attr_max(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, infinity) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"max">>, <<"enable">>, __TopXMLNS}}); - _res -> _res - end. - -encode_sm_enable_attr_max(undefined, _acc) -> _acc; -encode_sm_enable_attr_max(_val, _acc) -> - [{<<"max">>, enc_int(_val)} | _acc]. - -decode_sm_enable_attr_xmlns(__TopXMLNS, undefined) -> - <<>>; -decode_sm_enable_attr_xmlns(__TopXMLNS, _val) -> _val. - -decode_sm_enable_attr_resume(__TopXMLNS, undefined) -> - false; -decode_sm_enable_attr_resume(__TopXMLNS, _val) -> - case catch dec_bool(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"resume">>, <<"enable">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_sm_enable_attr_resume(false, _acc) -> _acc; -encode_sm_enable_attr_resume(_val, _acc) -> - [{<<"resume">>, enc_bool(_val)} | _acc]. - -decode_feature_sm(__TopXMLNS, __IgnoreEls, - {xmlel, <<"sm">>, _attrs, _els}) -> - Xmlns = decode_feature_sm_attrs(__TopXMLNS, _attrs, - undefined), - {feature_sm, Xmlns}. - -decode_feature_sm_attrs(__TopXMLNS, - [{<<"xmlns">>, _val} | _attrs], _Xmlns) -> - decode_feature_sm_attrs(__TopXMLNS, _attrs, _val); -decode_feature_sm_attrs(__TopXMLNS, [_ | _attrs], - Xmlns) -> - decode_feature_sm_attrs(__TopXMLNS, _attrs, Xmlns); -decode_feature_sm_attrs(__TopXMLNS, [], Xmlns) -> - decode_feature_sm_attr_xmlns(__TopXMLNS, Xmlns). - -encode_feature_sm({feature_sm, Xmlns}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(Xmlns, - [<<"urn:xmpp:sm:2">>, <<"urn:xmpp:sm:3">>], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"sm">>, _attrs, _els}. - -decode_feature_sm_attr_xmlns(__TopXMLNS, undefined) -> - <<>>; -decode_feature_sm_attr_xmlns(__TopXMLNS, _val) -> _val. - -decode_csi_inactive(__TopXMLNS, __IgnoreEls, - {xmlel, <<"inactive">>, _attrs, _els}) -> - {csi, inactive}. - -encode_csi_inactive({csi, inactive}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:csi:0">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"inactive">>, _attrs, _els}. - -decode_csi_active(__TopXMLNS, __IgnoreEls, - {xmlel, <<"active">>, _attrs, _els}) -> - {csi, active}. - -encode_csi_active({csi, active}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:csi:0">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"active">>, _attrs, _els}. - -decode_feature_csi(__TopXMLNS, __IgnoreEls, - {xmlel, <<"csi">>, _attrs, _els}) -> - Xmlns = decode_feature_csi_attrs(__TopXMLNS, _attrs, - undefined), - {feature_csi, Xmlns}. - -decode_feature_csi_attrs(__TopXMLNS, - [{<<"xmlns">>, _val} | _attrs], _Xmlns) -> - decode_feature_csi_attrs(__TopXMLNS, _attrs, _val); -decode_feature_csi_attrs(__TopXMLNS, [_ | _attrs], - Xmlns) -> - decode_feature_csi_attrs(__TopXMLNS, _attrs, Xmlns); -decode_feature_csi_attrs(__TopXMLNS, [], Xmlns) -> - decode_feature_csi_attr_xmlns(__TopXMLNS, Xmlns). - -encode_feature_csi({feature_csi, Xmlns}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(Xmlns, - [<<"urn:xmpp:csi:0">>], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"csi">>, _attrs, _els}. - -decode_feature_csi_attr_xmlns(__TopXMLNS, undefined) -> - <<>>; -decode_feature_csi_attr_xmlns(__TopXMLNS, _val) -> _val. - -decode_carbons_sent(__TopXMLNS, __IgnoreEls, - {xmlel, <<"sent">>, _attrs, _els}) -> - Forwarded = decode_carbons_sent_els(__TopXMLNS, - __IgnoreEls, _els, error), - {carbons_sent, Forwarded}. - -decode_carbons_sent_els(__TopXMLNS, __IgnoreEls, [], - Forwarded) -> - case Forwarded of - error -> - erlang:error({xmpp_codec, - {missing_tag, <<"forwarded">>, __TopXMLNS}}); - {value, Forwarded1} -> Forwarded1 - end; -decode_carbons_sent_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"forwarded">>, _attrs, _} = _el | _els], - Forwarded) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:xmpp:forward:0">> -> - decode_carbons_sent_els(__TopXMLNS, __IgnoreEls, _els, - {value, - decode_forwarded(<<"urn:xmpp:forward:0">>, - __IgnoreEls, _el)}); - _ -> - decode_carbons_sent_els(__TopXMLNS, __IgnoreEls, _els, - Forwarded) - end; -decode_carbons_sent_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Forwarded) -> - decode_carbons_sent_els(__TopXMLNS, __IgnoreEls, _els, - Forwarded). - -encode_carbons_sent({carbons_sent, Forwarded}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:carbons:2">>, [], - __TopXMLNS), - _els = - lists:reverse('encode_carbons_sent_$forwarded'(Forwarded, - __NewTopXMLNS, [])), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"sent">>, _attrs, _els}. - -'encode_carbons_sent_$forwarded'(Forwarded, __TopXMLNS, - _acc) -> - [encode_forwarded(Forwarded, __TopXMLNS) | _acc]. - -decode_carbons_received(__TopXMLNS, __IgnoreEls, - {xmlel, <<"received">>, _attrs, _els}) -> - Forwarded = decode_carbons_received_els(__TopXMLNS, - __IgnoreEls, _els, error), - {carbons_received, Forwarded}. - -decode_carbons_received_els(__TopXMLNS, __IgnoreEls, [], - Forwarded) -> - case Forwarded of - error -> - erlang:error({xmpp_codec, - {missing_tag, <<"forwarded">>, __TopXMLNS}}); - {value, Forwarded1} -> Forwarded1 - end; -decode_carbons_received_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"forwarded">>, _attrs, _} = _el | _els], - Forwarded) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:xmpp:forward:0">> -> - decode_carbons_received_els(__TopXMLNS, __IgnoreEls, - _els, - {value, - decode_forwarded(<<"urn:xmpp:forward:0">>, - __IgnoreEls, _el)}); - _ -> - decode_carbons_received_els(__TopXMLNS, __IgnoreEls, - _els, Forwarded) - end; -decode_carbons_received_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Forwarded) -> - decode_carbons_received_els(__TopXMLNS, __IgnoreEls, - _els, Forwarded). - -encode_carbons_received({carbons_received, Forwarded}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:carbons:2">>, [], - __TopXMLNS), - _els = - lists:reverse('encode_carbons_received_$forwarded'(Forwarded, - __NewTopXMLNS, [])), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"received">>, _attrs, _els}. - -'encode_carbons_received_$forwarded'(Forwarded, - __TopXMLNS, _acc) -> - [encode_forwarded(Forwarded, __TopXMLNS) | _acc]. - -decode_carbons_private(__TopXMLNS, __IgnoreEls, - {xmlel, <<"private">>, _attrs, _els}) -> - {carbons_private}. - -encode_carbons_private({carbons_private}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:carbons:2">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"private">>, _attrs, _els}. - -decode_carbons_enable(__TopXMLNS, __IgnoreEls, - {xmlel, <<"enable">>, _attrs, _els}) -> - {carbons_enable}. - -encode_carbons_enable({carbons_enable}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:carbons:2">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"enable">>, _attrs, _els}. - -decode_carbons_disable(__TopXMLNS, __IgnoreEls, - {xmlel, <<"disable">>, _attrs, _els}) -> - {carbons_disable}. - -encode_carbons_disable({carbons_disable}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:carbons:2">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"disable">>, _attrs, _els}. - -decode_forwarded(__TopXMLNS, __IgnoreEls, - {xmlel, <<"forwarded">>, _attrs, _els}) -> - {Delay, __Xmls} = decode_forwarded_els(__TopXMLNS, - __IgnoreEls, _els, undefined, []), - {forwarded, Delay, __Xmls}. - -decode_forwarded_els(__TopXMLNS, __IgnoreEls, [], Delay, - __Xmls) -> - {Delay, lists:reverse(__Xmls)}; -decode_forwarded_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"delay">>, _attrs, _} = _el | _els], Delay, - __Xmls) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:xmpp:delay">> -> - decode_forwarded_els(__TopXMLNS, __IgnoreEls, _els, - decode_delay(<<"urn:xmpp:delay">>, __IgnoreEls, - _el), - __Xmls); - _ -> - decode_forwarded_els(__TopXMLNS, __IgnoreEls, _els, - Delay, __Xmls) - end; -decode_forwarded_els(__TopXMLNS, __IgnoreEls, - [{xmlel, _, _, _} = _el | _els], Delay, __Xmls) -> - decode_forwarded_els(__TopXMLNS, __IgnoreEls, _els, - Delay, [_el | __Xmls]); -decode_forwarded_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Delay, __Xmls) -> - decode_forwarded_els(__TopXMLNS, __IgnoreEls, _els, - Delay, __Xmls). - -encode_forwarded({forwarded, Delay, __Xmls}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:forward:0">>, [], - __TopXMLNS), - _els = __Xmls ++ - lists:reverse('encode_forwarded_$delay'(Delay, - __NewTopXMLNS, [])), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"forwarded">>, _attrs, _els}. - -'encode_forwarded_$delay'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_forwarded_$delay'(Delay, __TopXMLNS, _acc) -> - [encode_delay(Delay, __TopXMLNS) | _acc]. - -decode_mam_fin(__TopXMLNS, __IgnoreEls, - {xmlel, <<"fin">>, _attrs, _els}) -> - Rsm = decode_mam_fin_els(__TopXMLNS, __IgnoreEls, _els, - undefined), - {Id, Xmlns, Stable, Complete} = - decode_mam_fin_attrs(__TopXMLNS, _attrs, undefined, - undefined, undefined, undefined), - {mam_fin, Xmlns, Id, Rsm, Stable, Complete}. - -decode_mam_fin_els(__TopXMLNS, __IgnoreEls, [], Rsm) -> - Rsm; -decode_mam_fin_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"set">>, _attrs, _} = _el | _els], Rsm) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"http://jabber.org/protocol/rsm">> -> - decode_mam_fin_els(__TopXMLNS, __IgnoreEls, _els, - decode_rsm_set(<<"http://jabber.org/protocol/rsm">>, - __IgnoreEls, _el)); - _ -> - decode_mam_fin_els(__TopXMLNS, __IgnoreEls, _els, Rsm) - end; -decode_mam_fin_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Rsm) -> - decode_mam_fin_els(__TopXMLNS, __IgnoreEls, _els, Rsm). - -decode_mam_fin_attrs(__TopXMLNS, - [{<<"queryid">>, _val} | _attrs], _Id, Xmlns, Stable, - Complete) -> - decode_mam_fin_attrs(__TopXMLNS, _attrs, _val, Xmlns, - Stable, Complete); -decode_mam_fin_attrs(__TopXMLNS, - [{<<"xmlns">>, _val} | _attrs], Id, _Xmlns, Stable, - Complete) -> - decode_mam_fin_attrs(__TopXMLNS, _attrs, Id, _val, - Stable, Complete); -decode_mam_fin_attrs(__TopXMLNS, - [{<<"stable">>, _val} | _attrs], Id, Xmlns, _Stable, - Complete) -> - decode_mam_fin_attrs(__TopXMLNS, _attrs, Id, Xmlns, - _val, Complete); -decode_mam_fin_attrs(__TopXMLNS, - [{<<"complete">>, _val} | _attrs], Id, Xmlns, Stable, - _Complete) -> - decode_mam_fin_attrs(__TopXMLNS, _attrs, Id, Xmlns, - Stable, _val); -decode_mam_fin_attrs(__TopXMLNS, [_ | _attrs], Id, - Xmlns, Stable, Complete) -> - decode_mam_fin_attrs(__TopXMLNS, _attrs, Id, Xmlns, - Stable, Complete); -decode_mam_fin_attrs(__TopXMLNS, [], Id, Xmlns, Stable, - Complete) -> - {decode_mam_fin_attr_queryid(__TopXMLNS, Id), - decode_mam_fin_attr_xmlns(__TopXMLNS, Xmlns), - decode_mam_fin_attr_stable(__TopXMLNS, Stable), - decode_mam_fin_attr_complete(__TopXMLNS, Complete)}. - -encode_mam_fin({mam_fin, Xmlns, Id, Rsm, Stable, - Complete}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(Xmlns, - [<<"urn:xmpp:mam:0">>, - <<"urn:xmpp:mam:1">>], - __TopXMLNS), - _els = lists:reverse('encode_mam_fin_$rsm'(Rsm, - __NewTopXMLNS, [])), - _attrs = encode_mam_fin_attr_complete(Complete, - encode_mam_fin_attr_stable(Stable, - encode_mam_fin_attr_queryid(Id, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)))), - {xmlel, <<"fin">>, _attrs, _els}. - -'encode_mam_fin_$rsm'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_mam_fin_$rsm'(Rsm, __TopXMLNS, _acc) -> - [encode_rsm_set(Rsm, __TopXMLNS) | _acc]. - -decode_mam_fin_attr_queryid(__TopXMLNS, undefined) -> - <<>>; -decode_mam_fin_attr_queryid(__TopXMLNS, _val) -> _val. - -encode_mam_fin_attr_queryid(<<>>, _acc) -> _acc; -encode_mam_fin_attr_queryid(_val, _acc) -> - [{<<"queryid">>, _val} | _acc]. - -decode_mam_fin_attr_xmlns(__TopXMLNS, undefined) -> - <<>>; -decode_mam_fin_attr_xmlns(__TopXMLNS, _val) -> _val. - -decode_mam_fin_attr_stable(__TopXMLNS, undefined) -> - undefined; -decode_mam_fin_attr_stable(__TopXMLNS, _val) -> - case catch dec_bool(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"stable">>, <<"fin">>, __TopXMLNS}}); - _res -> _res - end. - -encode_mam_fin_attr_stable(undefined, _acc) -> _acc; -encode_mam_fin_attr_stable(_val, _acc) -> - [{<<"stable">>, enc_bool(_val)} | _acc]. - -decode_mam_fin_attr_complete(__TopXMLNS, undefined) -> - undefined; -decode_mam_fin_attr_complete(__TopXMLNS, _val) -> - case catch dec_bool(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"complete">>, <<"fin">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_mam_fin_attr_complete(undefined, _acc) -> _acc; -encode_mam_fin_attr_complete(_val, _acc) -> - [{<<"complete">>, enc_bool(_val)} | _acc]. - -decode_mam_prefs(__TopXMLNS, __IgnoreEls, - {xmlel, <<"prefs">>, _attrs, _els}) -> - {Never, Always} = decode_mam_prefs_els(__TopXMLNS, - __IgnoreEls, _els, undefined, - undefined), - {Default, Xmlns} = decode_mam_prefs_attrs(__TopXMLNS, - _attrs, undefined, undefined), - {mam_prefs, Xmlns, Default, Always, Never}. - -decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, [], Never, - Always) -> - {Never, Always}; -decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"always">>, _attrs, _} = _el | _els], Never, - Always) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == <<"urn:xmpp:mam:1">>; - __TopXMLNS == <<"urn:xmpp:mam:0">>; - __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> - decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, - Never, - decode_mam_always(__TopXMLNS, __IgnoreEls, _el)); - <<"urn:xmpp:mam:0">> -> - decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, - Never, - decode_mam_always(<<"urn:xmpp:mam:0">>, - __IgnoreEls, _el)); - <<"urn:xmpp:mam:1">> -> - decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, - Never, - decode_mam_always(<<"urn:xmpp:mam:1">>, - __IgnoreEls, _el)); - <<"urn:xmpp:mam:tmp">> -> - decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, - Never, - decode_mam_always(<<"urn:xmpp:mam:tmp">>, - __IgnoreEls, _el)); - _ -> - decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, - Never, Always) - end; -decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"never">>, _attrs, _} = _el | _els], Never, - Always) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == <<"urn:xmpp:mam:1">>; - __TopXMLNS == <<"urn:xmpp:mam:0">>; - __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> - decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, - decode_mam_never(__TopXMLNS, __IgnoreEls, _el), - Always); - <<"urn:xmpp:mam:0">> -> - decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, - decode_mam_never(<<"urn:xmpp:mam:0">>, - __IgnoreEls, _el), - Always); - <<"urn:xmpp:mam:1">> -> - decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, - decode_mam_never(<<"urn:xmpp:mam:1">>, - __IgnoreEls, _el), - Always); - <<"urn:xmpp:mam:tmp">> -> - decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, - decode_mam_never(<<"urn:xmpp:mam:tmp">>, - __IgnoreEls, _el), - Always); - _ -> - decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, - Never, Always) - end; -decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Never, Always) -> - decode_mam_prefs_els(__TopXMLNS, __IgnoreEls, _els, - Never, Always). - -decode_mam_prefs_attrs(__TopXMLNS, - [{<<"default">>, _val} | _attrs], _Default, Xmlns) -> - decode_mam_prefs_attrs(__TopXMLNS, _attrs, _val, Xmlns); -decode_mam_prefs_attrs(__TopXMLNS, - [{<<"xmlns">>, _val} | _attrs], Default, _Xmlns) -> - decode_mam_prefs_attrs(__TopXMLNS, _attrs, Default, - _val); -decode_mam_prefs_attrs(__TopXMLNS, [_ | _attrs], - Default, Xmlns) -> - decode_mam_prefs_attrs(__TopXMLNS, _attrs, Default, - Xmlns); -decode_mam_prefs_attrs(__TopXMLNS, [], Default, - Xmlns) -> - {decode_mam_prefs_attr_default(__TopXMLNS, Default), - decode_mam_prefs_attr_xmlns(__TopXMLNS, Xmlns)}. - -encode_mam_prefs({mam_prefs, Xmlns, Default, Always, - Never}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(Xmlns, - [<<"urn:xmpp:mam:0">>, - <<"urn:xmpp:mam:1">>, - <<"urn:xmpp:mam:tmp">>], - __TopXMLNS), - _els = lists:reverse('encode_mam_prefs_$never'(Never, - __NewTopXMLNS, - 'encode_mam_prefs_$always'(Always, - __NewTopXMLNS, - []))), - _attrs = encode_mam_prefs_attr_default(Default, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"prefs">>, _attrs, _els}. - -'encode_mam_prefs_$never'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_mam_prefs_$never'(Never, __TopXMLNS, _acc) -> - [encode_mam_never(Never, __TopXMLNS) | _acc]. - -'encode_mam_prefs_$always'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_mam_prefs_$always'(Always, __TopXMLNS, _acc) -> - [encode_mam_always(Always, __TopXMLNS) | _acc]. - -decode_mam_prefs_attr_default(__TopXMLNS, undefined) -> - undefined; -decode_mam_prefs_attr_default(__TopXMLNS, _val) -> - case catch dec_enum(_val, [always, never, roster]) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"default">>, <<"prefs">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_mam_prefs_attr_default(undefined, _acc) -> _acc; -encode_mam_prefs_attr_default(_val, _acc) -> - [{<<"default">>, enc_enum(_val)} | _acc]. - -decode_mam_prefs_attr_xmlns(__TopXMLNS, undefined) -> - <<>>; -decode_mam_prefs_attr_xmlns(__TopXMLNS, _val) -> _val. - -decode_mam_always(__TopXMLNS, __IgnoreEls, - {xmlel, <<"always">>, _attrs, _els}) -> - Jids = decode_mam_always_els(__TopXMLNS, __IgnoreEls, - _els, []), - Jids. - -decode_mam_always_els(__TopXMLNS, __IgnoreEls, [], - Jids) -> - lists:reverse(Jids); -decode_mam_always_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"jid">>, _attrs, _} = _el | _els], Jids) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == <<"urn:xmpp:mam:1">>; - __TopXMLNS == <<"urn:xmpp:mam:0">>; - __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> - decode_mam_always_els(__TopXMLNS, __IgnoreEls, _els, - [decode_mam_jid(__TopXMLNS, __IgnoreEls, _el) - | Jids]); - <<"urn:xmpp:mam:0">> -> - decode_mam_always_els(__TopXMLNS, __IgnoreEls, _els, - [decode_mam_jid(<<"urn:xmpp:mam:0">>, - __IgnoreEls, _el) - | Jids]); - <<"urn:xmpp:mam:1">> -> - decode_mam_always_els(__TopXMLNS, __IgnoreEls, _els, - [decode_mam_jid(<<"urn:xmpp:mam:1">>, - __IgnoreEls, _el) - | Jids]); - <<"urn:xmpp:mam:tmp">> -> - decode_mam_always_els(__TopXMLNS, __IgnoreEls, _els, - [decode_mam_jid(<<"urn:xmpp:mam:tmp">>, - __IgnoreEls, _el) - | Jids]); - _ -> - decode_mam_always_els(__TopXMLNS, __IgnoreEls, _els, - Jids) - end; -decode_mam_always_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Jids) -> - decode_mam_always_els(__TopXMLNS, __IgnoreEls, _els, - Jids). - -encode_mam_always(Jids, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"urn:xmpp:mam:0">>, - <<"urn:xmpp:mam:1">>, - <<"urn:xmpp:mam:tmp">>], - __TopXMLNS), - _els = lists:reverse('encode_mam_always_$jids'(Jids, - __NewTopXMLNS, [])), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"always">>, _attrs, _els}. - -'encode_mam_always_$jids'([], __TopXMLNS, _acc) -> _acc; -'encode_mam_always_$jids'([Jids | _els], __TopXMLNS, - _acc) -> - 'encode_mam_always_$jids'(_els, __TopXMLNS, - [encode_mam_jid(Jids, __TopXMLNS) | _acc]). - -decode_mam_never(__TopXMLNS, __IgnoreEls, - {xmlel, <<"never">>, _attrs, _els}) -> - Jids = decode_mam_never_els(__TopXMLNS, __IgnoreEls, - _els, []), - Jids. - -decode_mam_never_els(__TopXMLNS, __IgnoreEls, [], - Jids) -> - lists:reverse(Jids); -decode_mam_never_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"jid">>, _attrs, _} = _el | _els], Jids) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == <<"urn:xmpp:mam:1">>; - __TopXMLNS == <<"urn:xmpp:mam:0">>; - __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> - decode_mam_never_els(__TopXMLNS, __IgnoreEls, _els, - [decode_mam_jid(__TopXMLNS, __IgnoreEls, _el) - | Jids]); - <<"urn:xmpp:mam:0">> -> - decode_mam_never_els(__TopXMLNS, __IgnoreEls, _els, - [decode_mam_jid(<<"urn:xmpp:mam:0">>, - __IgnoreEls, _el) - | Jids]); - <<"urn:xmpp:mam:1">> -> - decode_mam_never_els(__TopXMLNS, __IgnoreEls, _els, - [decode_mam_jid(<<"urn:xmpp:mam:1">>, - __IgnoreEls, _el) - | Jids]); - <<"urn:xmpp:mam:tmp">> -> - decode_mam_never_els(__TopXMLNS, __IgnoreEls, _els, - [decode_mam_jid(<<"urn:xmpp:mam:tmp">>, - __IgnoreEls, _el) - | Jids]); - _ -> - decode_mam_never_els(__TopXMLNS, __IgnoreEls, _els, - Jids) - end; -decode_mam_never_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Jids) -> - decode_mam_never_els(__TopXMLNS, __IgnoreEls, _els, - Jids). - -encode_mam_never(Jids, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"urn:xmpp:mam:0">>, - <<"urn:xmpp:mam:1">>, - <<"urn:xmpp:mam:tmp">>], - __TopXMLNS), - _els = lists:reverse('encode_mam_never_$jids'(Jids, - __NewTopXMLNS, [])), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"never">>, _attrs, _els}. - -'encode_mam_never_$jids'([], __TopXMLNS, _acc) -> _acc; -'encode_mam_never_$jids'([Jids | _els], __TopXMLNS, - _acc) -> - 'encode_mam_never_$jids'(_els, __TopXMLNS, - [encode_mam_jid(Jids, __TopXMLNS) | _acc]). - -decode_mam_jid(__TopXMLNS, __IgnoreEls, - {xmlel, <<"jid">>, _attrs, _els}) -> - Cdata = decode_mam_jid_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_mam_jid_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_mam_jid_cdata(__TopXMLNS, Cdata); -decode_mam_jid_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_mam_jid_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_mam_jid_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Cdata) -> - decode_mam_jid_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_mam_jid(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"urn:xmpp:mam:0">>, - <<"urn:xmpp:mam:1">>, - <<"urn:xmpp:mam:tmp">>], - __TopXMLNS), - _els = encode_mam_jid_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"jid">>, _attrs, _els}. - -decode_mam_jid_cdata(__TopXMLNS, <<>>) -> - erlang:error({xmpp_codec, - {missing_cdata, <<>>, <<"jid">>, __TopXMLNS}}); -decode_mam_jid_cdata(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_cdata_value, <<>>, <<"jid">>, __TopXMLNS}}); - _res -> _res - end. - -encode_mam_jid_cdata(_val, _acc) -> - [{xmlcdata, enc_jid(_val)} | _acc]. - -decode_mam_result(__TopXMLNS, __IgnoreEls, - {xmlel, <<"result">>, _attrs, _els}) -> - __Els = decode_mam_result_els(__TopXMLNS, __IgnoreEls, - _els, []), - {Queryid, Xmlns, Id} = - decode_mam_result_attrs(__TopXMLNS, _attrs, undefined, - undefined, undefined), - {mam_result, Xmlns, Queryid, Id, __Els}. - -decode_mam_result_els(__TopXMLNS, __IgnoreEls, [], - __Els) -> - lists:reverse(__Els); -decode_mam_result_els(__TopXMLNS, __IgnoreEls, - [{xmlel, _, _, _} = _el | _els], __Els) -> - if __IgnoreEls -> - decode_mam_result_els(__TopXMLNS, __IgnoreEls, _els, - [_el | __Els]); - true -> - case is_known_tag(_el, __TopXMLNS) of - true -> - decode_mam_result_els(__TopXMLNS, __IgnoreEls, _els, - [decode(_el, __TopXMLNS, []) | __Els]); - false -> - decode_mam_result_els(__TopXMLNS, __IgnoreEls, _els, - __Els) - end - end; -decode_mam_result_els(__TopXMLNS, __IgnoreEls, - [_ | _els], __Els) -> - decode_mam_result_els(__TopXMLNS, __IgnoreEls, _els, - __Els). - -decode_mam_result_attrs(__TopXMLNS, - [{<<"queryid">>, _val} | _attrs], _Queryid, Xmlns, - Id) -> - decode_mam_result_attrs(__TopXMLNS, _attrs, _val, Xmlns, - Id); -decode_mam_result_attrs(__TopXMLNS, - [{<<"xmlns">>, _val} | _attrs], Queryid, _Xmlns, Id) -> - decode_mam_result_attrs(__TopXMLNS, _attrs, Queryid, - _val, Id); -decode_mam_result_attrs(__TopXMLNS, - [{<<"id">>, _val} | _attrs], Queryid, Xmlns, _Id) -> - decode_mam_result_attrs(__TopXMLNS, _attrs, Queryid, - Xmlns, _val); -decode_mam_result_attrs(__TopXMLNS, [_ | _attrs], - Queryid, Xmlns, Id) -> - decode_mam_result_attrs(__TopXMLNS, _attrs, Queryid, - Xmlns, Id); -decode_mam_result_attrs(__TopXMLNS, [], Queryid, Xmlns, - Id) -> - {decode_mam_result_attr_queryid(__TopXMLNS, Queryid), - decode_mam_result_attr_xmlns(__TopXMLNS, Xmlns), - decode_mam_result_attr_id(__TopXMLNS, Id)}. - -encode_mam_result({mam_result, Xmlns, Queryid, Id, - __Els}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(Xmlns, - [<<"urn:xmpp:mam:0">>, - <<"urn:xmpp:mam:1">>, - <<"urn:xmpp:mam:tmp">>], - __TopXMLNS), - _els = [encode(_el, __NewTopXMLNS) || _el <- __Els], - _attrs = encode_mam_result_attr_id(Id, - encode_mam_result_attr_queryid(Queryid, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))), - {xmlel, <<"result">>, _attrs, _els}. - -decode_mam_result_attr_queryid(__TopXMLNS, undefined) -> - <<>>; -decode_mam_result_attr_queryid(__TopXMLNS, _val) -> - _val. - -encode_mam_result_attr_queryid(<<>>, _acc) -> _acc; -encode_mam_result_attr_queryid(_val, _acc) -> - [{<<"queryid">>, _val} | _acc]. - -decode_mam_result_attr_xmlns(__TopXMLNS, undefined) -> - <<>>; -decode_mam_result_attr_xmlns(__TopXMLNS, _val) -> _val. - -decode_mam_result_attr_id(__TopXMLNS, undefined) -> - <<>>; -decode_mam_result_attr_id(__TopXMLNS, _val) -> _val. - -encode_mam_result_attr_id(<<>>, _acc) -> _acc; -encode_mam_result_attr_id(_val, _acc) -> - [{<<"id">>, _val} | _acc]. - -decode_mam_archived(__TopXMLNS, __IgnoreEls, - {xmlel, <<"archived">>, _attrs, _els}) -> - {Id, By} = decode_mam_archived_attrs(__TopXMLNS, _attrs, - undefined, undefined), - {mam_archived, By, Id}. - -decode_mam_archived_attrs(__TopXMLNS, - [{<<"id">>, _val} | _attrs], _Id, By) -> - decode_mam_archived_attrs(__TopXMLNS, _attrs, _val, By); -decode_mam_archived_attrs(__TopXMLNS, - [{<<"by">>, _val} | _attrs], Id, _By) -> - decode_mam_archived_attrs(__TopXMLNS, _attrs, Id, _val); -decode_mam_archived_attrs(__TopXMLNS, [_ | _attrs], Id, - By) -> - decode_mam_archived_attrs(__TopXMLNS, _attrs, Id, By); -decode_mam_archived_attrs(__TopXMLNS, [], Id, By) -> - {decode_mam_archived_attr_id(__TopXMLNS, Id), - decode_mam_archived_attr_by(__TopXMLNS, By)}. - -encode_mam_archived({mam_archived, By, Id}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:mam:tmp">>, - [], __TopXMLNS), - _els = [], - _attrs = encode_mam_archived_attr_by(By, - encode_mam_archived_attr_id(Id, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))), - {xmlel, <<"archived">>, _attrs, _els}. - -decode_mam_archived_attr_id(__TopXMLNS, undefined) -> - <<>>; -decode_mam_archived_attr_id(__TopXMLNS, _val) -> _val. - -encode_mam_archived_attr_id(<<>>, _acc) -> _acc; -encode_mam_archived_attr_id(_val, _acc) -> - [{<<"id">>, _val} | _acc]. - -decode_mam_archived_attr_by(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"by">>, <<"archived">>, __TopXMLNS}}); -decode_mam_archived_attr_by(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"by">>, <<"archived">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_mam_archived_attr_by(_val, _acc) -> - [{<<"by">>, enc_jid(_val)} | _acc]. - -decode_mam_query(__TopXMLNS, __IgnoreEls, - {xmlel, <<"query">>, _attrs, _els}) -> - {Xdata, Withtext, End, Start, With, Rsm} = - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - undefined, undefined, undefined, undefined, - undefined, undefined), - {Id, Xmlns} = decode_mam_query_attrs(__TopXMLNS, _attrs, - undefined, undefined), - {mam_query, Xmlns, Id, Start, End, With, Withtext, Rsm, - Xdata}. - -decode_mam_query_els(__TopXMLNS, __IgnoreEls, [], Xdata, - Withtext, End, Start, With, Rsm) -> - {Xdata, Withtext, End, Start, With, Rsm}; -decode_mam_query_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"start">>, _attrs, _} = _el | _els], Xdata, - Withtext, End, Start, With, Rsm) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Withtext, End, - decode_mam_start(__TopXMLNS, __IgnoreEls, _el), - With, Rsm); - <<"urn:xmpp:mam:tmp">> -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Withtext, End, - decode_mam_start(<<"urn:xmpp:mam:tmp">>, - __IgnoreEls, _el), - With, Rsm); - _ -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Withtext, End, Start, With, Rsm) - end; -decode_mam_query_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"end">>, _attrs, _} = _el | _els], Xdata, - Withtext, End, Start, With, Rsm) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Withtext, - decode_mam_end(__TopXMLNS, __IgnoreEls, _el), - Start, With, Rsm); - <<"urn:xmpp:mam:tmp">> -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Withtext, - decode_mam_end(<<"urn:xmpp:mam:tmp">>, - __IgnoreEls, _el), - Start, With, Rsm); - _ -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Withtext, End, Start, With, Rsm) - end; -decode_mam_query_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"with">>, _attrs, _} = _el | _els], Xdata, - Withtext, End, Start, With, Rsm) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Withtext, End, Start, - decode_mam_with(__TopXMLNS, __IgnoreEls, _el), - Rsm); - <<"urn:xmpp:mam:tmp">> -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Withtext, End, Start, - decode_mam_with(<<"urn:xmpp:mam:tmp">>, - __IgnoreEls, _el), - Rsm); - _ -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Withtext, End, Start, With, Rsm) - end; -decode_mam_query_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"withtext">>, _attrs, _} = _el | _els], - Xdata, Withtext, End, Start, With, Rsm) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"urn:xmpp:mam:tmp">> -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, - decode_mam_withtext(__TopXMLNS, __IgnoreEls, - _el), - End, Start, With, Rsm); - <<"urn:xmpp:mam:tmp">> -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, - decode_mam_withtext(<<"urn:xmpp:mam:tmp">>, - __IgnoreEls, _el), - End, Start, With, Rsm); - _ -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Withtext, End, Start, With, Rsm) - end; -decode_mam_query_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"set">>, _attrs, _} = _el | _els], Xdata, - Withtext, End, Start, With, Rsm) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"http://jabber.org/protocol/rsm">> -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Withtext, End, Start, With, - decode_rsm_set(<<"http://jabber.org/protocol/rsm">>, - __IgnoreEls, _el)); - _ -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Withtext, End, Start, With, Rsm) - end; -decode_mam_query_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"x">>, _attrs, _} = _el | _els], Xdata, - Withtext, End, Start, With, Rsm) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"jabber:x:data">> -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - decode_xdata(<<"jabber:x:data">>, __IgnoreEls, - _el), - Withtext, End, Start, With, Rsm); - _ -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Withtext, End, Start, With, Rsm) - end; -decode_mam_query_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Xdata, Withtext, End, Start, With, Rsm) -> - decode_mam_query_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Withtext, End, Start, With, Rsm). - -decode_mam_query_attrs(__TopXMLNS, - [{<<"queryid">>, _val} | _attrs], _Id, Xmlns) -> - decode_mam_query_attrs(__TopXMLNS, _attrs, _val, Xmlns); -decode_mam_query_attrs(__TopXMLNS, - [{<<"xmlns">>, _val} | _attrs], Id, _Xmlns) -> - decode_mam_query_attrs(__TopXMLNS, _attrs, Id, _val); -decode_mam_query_attrs(__TopXMLNS, [_ | _attrs], Id, - Xmlns) -> - decode_mam_query_attrs(__TopXMLNS, _attrs, Id, Xmlns); -decode_mam_query_attrs(__TopXMLNS, [], Id, Xmlns) -> - {decode_mam_query_attr_queryid(__TopXMLNS, Id), - decode_mam_query_attr_xmlns(__TopXMLNS, Xmlns)}. - -encode_mam_query({mam_query, Xmlns, Id, Start, End, - With, Withtext, Rsm, Xdata}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(Xmlns, - [<<"urn:xmpp:mam:0">>, - <<"urn:xmpp:mam:1">>, - <<"urn:xmpp:mam:tmp">>], - __TopXMLNS), - _els = lists:reverse('encode_mam_query_$xdata'(Xdata, - __NewTopXMLNS, - 'encode_mam_query_$withtext'(Withtext, - __NewTopXMLNS, - 'encode_mam_query_$end'(End, - __NewTopXMLNS, - 'encode_mam_query_$start'(Start, - __NewTopXMLNS, - 'encode_mam_query_$with'(With, - __NewTopXMLNS, - 'encode_mam_query_$rsm'(Rsm, - __NewTopXMLNS, - []))))))), - _attrs = encode_mam_query_attr_queryid(Id, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"query">>, _attrs, _els}. - -'encode_mam_query_$xdata'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_mam_query_$xdata'(Xdata, __TopXMLNS, _acc) -> - [encode_xdata(Xdata, __TopXMLNS) | _acc]. - -'encode_mam_query_$withtext'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_mam_query_$withtext'(Withtext, __TopXMLNS, - _acc) -> - [encode_mam_withtext(Withtext, __TopXMLNS) | _acc]. - -'encode_mam_query_$end'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_mam_query_$end'(End, __TopXMLNS, _acc) -> - [encode_mam_end(End, __TopXMLNS) | _acc]. - -'encode_mam_query_$start'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_mam_query_$start'(Start, __TopXMLNS, _acc) -> - [encode_mam_start(Start, __TopXMLNS) | _acc]. - -'encode_mam_query_$with'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_mam_query_$with'(With, __TopXMLNS, _acc) -> - [encode_mam_with(With, __TopXMLNS) | _acc]. - -'encode_mam_query_$rsm'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_mam_query_$rsm'(Rsm, __TopXMLNS, _acc) -> - [encode_rsm_set(Rsm, __TopXMLNS) | _acc]. - -decode_mam_query_attr_queryid(__TopXMLNS, undefined) -> - <<>>; -decode_mam_query_attr_queryid(__TopXMLNS, _val) -> _val. - -encode_mam_query_attr_queryid(<<>>, _acc) -> _acc; -encode_mam_query_attr_queryid(_val, _acc) -> - [{<<"queryid">>, _val} | _acc]. - -decode_mam_query_attr_xmlns(__TopXMLNS, undefined) -> - <<>>; -decode_mam_query_attr_xmlns(__TopXMLNS, _val) -> _val. - -decode_mam_withtext(__TopXMLNS, __IgnoreEls, - {xmlel, <<"withtext">>, _attrs, _els}) -> - Cdata = decode_mam_withtext_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_mam_withtext_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_mam_withtext_cdata(__TopXMLNS, Cdata); -decode_mam_withtext_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_mam_withtext_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_mam_withtext_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_mam_withtext_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_mam_withtext(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:mam:tmp">>, - [], __TopXMLNS), - _els = encode_mam_withtext_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"withtext">>, _attrs, _els}. - -decode_mam_withtext_cdata(__TopXMLNS, <<>>) -> - erlang:error({xmpp_codec, - {missing_cdata, <<>>, <<"withtext">>, __TopXMLNS}}); -decode_mam_withtext_cdata(__TopXMLNS, _val) -> _val. - -encode_mam_withtext_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_mam_with(__TopXMLNS, __IgnoreEls, - {xmlel, <<"with">>, _attrs, _els}) -> - Cdata = decode_mam_with_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_mam_with_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_mam_with_cdata(__TopXMLNS, Cdata); -decode_mam_with_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_mam_with_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_mam_with_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Cdata) -> - decode_mam_with_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_mam_with(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:mam:tmp">>, - [], __TopXMLNS), - _els = encode_mam_with_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"with">>, _attrs, _els}. - -decode_mam_with_cdata(__TopXMLNS, <<>>) -> - erlang:error({xmpp_codec, - {missing_cdata, <<>>, <<"with">>, __TopXMLNS}}); -decode_mam_with_cdata(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_cdata_value, <<>>, <<"with">>, __TopXMLNS}}); - _res -> _res - end. - -encode_mam_with_cdata(_val, _acc) -> - [{xmlcdata, enc_jid(_val)} | _acc]. - -decode_mam_end(__TopXMLNS, __IgnoreEls, - {xmlel, <<"end">>, _attrs, _els}) -> - Cdata = decode_mam_end_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_mam_end_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_mam_end_cdata(__TopXMLNS, Cdata); -decode_mam_end_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_mam_end_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_mam_end_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Cdata) -> - decode_mam_end_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_mam_end(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:mam:tmp">>, - [], __TopXMLNS), - _els = encode_mam_end_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"end">>, _attrs, _els}. - -decode_mam_end_cdata(__TopXMLNS, <<>>) -> - erlang:error({xmpp_codec, - {missing_cdata, <<>>, <<"end">>, __TopXMLNS}}); -decode_mam_end_cdata(__TopXMLNS, _val) -> - case catch dec_utc(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_cdata_value, <<>>, <<"end">>, __TopXMLNS}}); - _res -> _res - end. - -encode_mam_end_cdata(_val, _acc) -> - [{xmlcdata, enc_utc(_val)} | _acc]. - -decode_mam_start(__TopXMLNS, __IgnoreEls, - {xmlel, <<"start">>, _attrs, _els}) -> - Cdata = decode_mam_start_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_mam_start_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_mam_start_cdata(__TopXMLNS, Cdata); -decode_mam_start_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_mam_start_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_mam_start_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_mam_start_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_mam_start(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:mam:tmp">>, - [], __TopXMLNS), - _els = encode_mam_start_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"start">>, _attrs, _els}. - -decode_mam_start_cdata(__TopXMLNS, <<>>) -> - erlang:error({xmpp_codec, - {missing_cdata, <<>>, <<"start">>, __TopXMLNS}}); -decode_mam_start_cdata(__TopXMLNS, _val) -> - case catch dec_utc(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_cdata_value, <<>>, <<"start">>, __TopXMLNS}}); - _res -> _res - end. - -encode_mam_start_cdata(_val, _acc) -> - [{xmlcdata, enc_utc(_val)} | _acc]. - -decode_rsm_set(__TopXMLNS, __IgnoreEls, - {xmlel, <<"set">>, _attrs, _els}) -> - {After, Last, First, Count, Before, Max, Index} = - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, - undefined, undefined, undefined, undefined, - undefined, undefined, undefined), - {rsm_set, After, Before, Count, First, Index, Last, - Max}. - -decode_rsm_set_els(__TopXMLNS, __IgnoreEls, [], After, - Last, First, Count, Before, Max, Index) -> - {After, Last, First, Count, Before, Max, Index}; -decode_rsm_set_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"after">>, _attrs, _} = _el | _els], After, - Last, First, Count, Before, Max, Index) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/rsm">> -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, - decode_rsm_after(__TopXMLNS, __IgnoreEls, _el), - Last, First, Count, Before, Max, Index); - <<"http://jabber.org/protocol/rsm">> -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, - decode_rsm_after(<<"http://jabber.org/protocol/rsm">>, - __IgnoreEls, _el), - Last, First, Count, Before, Max, Index); - _ -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, Count, Before, Max, Index) - end; -decode_rsm_set_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"before">>, _attrs, _} = _el | _els], After, - Last, First, Count, Before, Max, Index) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/rsm">> -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, Count, - decode_rsm_before(__TopXMLNS, __IgnoreEls, _el), - Max, Index); - <<"http://jabber.org/protocol/rsm">> -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, Count, - decode_rsm_before(<<"http://jabber.org/protocol/rsm">>, - __IgnoreEls, _el), - Max, Index); - _ -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, Count, Before, Max, Index) - end; -decode_rsm_set_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"count">>, _attrs, _} = _el | _els], After, - Last, First, Count, Before, Max, Index) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/rsm">> -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, - decode_rsm_count(__TopXMLNS, __IgnoreEls, _el), - Before, Max, Index); - <<"http://jabber.org/protocol/rsm">> -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, - decode_rsm_count(<<"http://jabber.org/protocol/rsm">>, - __IgnoreEls, _el), - Before, Max, Index); - _ -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, Count, Before, Max, Index) - end; -decode_rsm_set_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"first">>, _attrs, _} = _el | _els], After, - Last, First, Count, Before, Max, Index) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/rsm">> -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, - decode_rsm_first(__TopXMLNS, __IgnoreEls, _el), - Count, Before, Max, Index); - <<"http://jabber.org/protocol/rsm">> -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, - decode_rsm_first(<<"http://jabber.org/protocol/rsm">>, - __IgnoreEls, _el), - Count, Before, Max, Index); - _ -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, Count, Before, Max, Index) - end; -decode_rsm_set_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"index">>, _attrs, _} = _el | _els], After, - Last, First, Count, Before, Max, Index) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/rsm">> -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, Count, Before, Max, - decode_rsm_index(__TopXMLNS, __IgnoreEls, _el)); - <<"http://jabber.org/protocol/rsm">> -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, Count, Before, Max, - decode_rsm_index(<<"http://jabber.org/protocol/rsm">>, - __IgnoreEls, _el)); - _ -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, Count, Before, Max, Index) - end; -decode_rsm_set_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"last">>, _attrs, _} = _el | _els], After, - Last, First, Count, Before, Max, Index) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/rsm">> -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - decode_rsm_last(__TopXMLNS, __IgnoreEls, _el), - First, Count, Before, Max, Index); - <<"http://jabber.org/protocol/rsm">> -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - decode_rsm_last(<<"http://jabber.org/protocol/rsm">>, - __IgnoreEls, _el), - First, Count, Before, Max, Index); - _ -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, Count, Before, Max, Index) - end; -decode_rsm_set_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"max">>, _attrs, _} = _el | _els], After, - Last, First, Count, Before, Max, Index) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/rsm">> -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, Count, Before, - decode_rsm_max(__TopXMLNS, __IgnoreEls, _el), - Index); - <<"http://jabber.org/protocol/rsm">> -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, Count, Before, - decode_rsm_max(<<"http://jabber.org/protocol/rsm">>, - __IgnoreEls, _el), - Index); - _ -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, Count, Before, Max, Index) - end; -decode_rsm_set_els(__TopXMLNS, __IgnoreEls, [_ | _els], - After, Last, First, Count, Before, Max, Index) -> - decode_rsm_set_els(__TopXMLNS, __IgnoreEls, _els, After, - Last, First, Count, Before, Max, Index). - -encode_rsm_set({rsm_set, After, Before, Count, First, - Index, Last, Max}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/rsm">>, - [], __TopXMLNS), - _els = lists:reverse('encode_rsm_set_$after'(After, - __NewTopXMLNS, - 'encode_rsm_set_$last'(Last, - __NewTopXMLNS, - 'encode_rsm_set_$first'(First, - __NewTopXMLNS, - 'encode_rsm_set_$count'(Count, - __NewTopXMLNS, - 'encode_rsm_set_$before'(Before, - __NewTopXMLNS, - 'encode_rsm_set_$max'(Max, - __NewTopXMLNS, - 'encode_rsm_set_$index'(Index, - __NewTopXMLNS, - [])))))))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"set">>, _attrs, _els}. - -'encode_rsm_set_$after'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_rsm_set_$after'(After, __TopXMLNS, _acc) -> - [encode_rsm_after(After, __TopXMLNS) | _acc]. - -'encode_rsm_set_$last'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_rsm_set_$last'(Last, __TopXMLNS, _acc) -> - [encode_rsm_last(Last, __TopXMLNS) | _acc]. - -'encode_rsm_set_$first'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_rsm_set_$first'(First, __TopXMLNS, _acc) -> - [encode_rsm_first(First, __TopXMLNS) | _acc]. - -'encode_rsm_set_$count'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_rsm_set_$count'(Count, __TopXMLNS, _acc) -> - [encode_rsm_count(Count, __TopXMLNS) | _acc]. - -'encode_rsm_set_$before'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_rsm_set_$before'(Before, __TopXMLNS, _acc) -> - [encode_rsm_before(Before, __TopXMLNS) | _acc]. - -'encode_rsm_set_$max'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_rsm_set_$max'(Max, __TopXMLNS, _acc) -> - [encode_rsm_max(Max, __TopXMLNS) | _acc]. - -'encode_rsm_set_$index'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_rsm_set_$index'(Index, __TopXMLNS, _acc) -> - [encode_rsm_index(Index, __TopXMLNS) | _acc]. - -decode_rsm_first(__TopXMLNS, __IgnoreEls, - {xmlel, <<"first">>, _attrs, _els}) -> - Data = decode_rsm_first_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Index = decode_rsm_first_attrs(__TopXMLNS, _attrs, - undefined), - {rsm_first, Index, Data}. - -decode_rsm_first_els(__TopXMLNS, __IgnoreEls, [], - Data) -> - decode_rsm_first_cdata(__TopXMLNS, Data); -decode_rsm_first_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Data) -> - decode_rsm_first_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_rsm_first_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Data) -> - decode_rsm_first_els(__TopXMLNS, __IgnoreEls, _els, - Data). - -decode_rsm_first_attrs(__TopXMLNS, - [{<<"index">>, _val} | _attrs], _Index) -> - decode_rsm_first_attrs(__TopXMLNS, _attrs, _val); -decode_rsm_first_attrs(__TopXMLNS, [_ | _attrs], - Index) -> - decode_rsm_first_attrs(__TopXMLNS, _attrs, Index); -decode_rsm_first_attrs(__TopXMLNS, [], Index) -> - decode_rsm_first_attr_index(__TopXMLNS, Index). - -encode_rsm_first({rsm_first, Index, Data}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/rsm">>, - [], __TopXMLNS), - _els = encode_rsm_first_cdata(Data, []), - _attrs = encode_rsm_first_attr_index(Index, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"first">>, _attrs, _els}. - -decode_rsm_first_attr_index(__TopXMLNS, undefined) -> - undefined; -decode_rsm_first_attr_index(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, infinity) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"index">>, <<"first">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_rsm_first_attr_index(undefined, _acc) -> _acc; -encode_rsm_first_attr_index(_val, _acc) -> - [{<<"index">>, enc_int(_val)} | _acc]. - -decode_rsm_first_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_rsm_first_cdata(__TopXMLNS, _val) -> _val. - -encode_rsm_first_cdata(<<>>, _acc) -> _acc; -encode_rsm_first_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_rsm_max(__TopXMLNS, __IgnoreEls, - {xmlel, <<"max">>, _attrs, _els}) -> - Cdata = decode_rsm_max_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_rsm_max_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_rsm_max_cdata(__TopXMLNS, Cdata); -decode_rsm_max_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_rsm_max_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_rsm_max_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Cdata) -> - decode_rsm_max_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_rsm_max(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/rsm">>, - [], __TopXMLNS), - _els = encode_rsm_max_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"max">>, _attrs, _els}. - -decode_rsm_max_cdata(__TopXMLNS, <<>>) -> undefined; -decode_rsm_max_cdata(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, infinity) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_cdata_value, <<>>, <<"max">>, __TopXMLNS}}); - _res -> _res - end. - -encode_rsm_max_cdata(undefined, _acc) -> _acc; -encode_rsm_max_cdata(_val, _acc) -> - [{xmlcdata, enc_int(_val)} | _acc]. - -decode_rsm_index(__TopXMLNS, __IgnoreEls, - {xmlel, <<"index">>, _attrs, _els}) -> - Cdata = decode_rsm_index_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_rsm_index_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_rsm_index_cdata(__TopXMLNS, Cdata); -decode_rsm_index_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_rsm_index_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_rsm_index_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_rsm_index_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_rsm_index(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/rsm">>, - [], __TopXMLNS), - _els = encode_rsm_index_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"index">>, _attrs, _els}. - -decode_rsm_index_cdata(__TopXMLNS, <<>>) -> undefined; -decode_rsm_index_cdata(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, infinity) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_cdata_value, <<>>, <<"index">>, __TopXMLNS}}); - _res -> _res - end. - -encode_rsm_index_cdata(undefined, _acc) -> _acc; -encode_rsm_index_cdata(_val, _acc) -> - [{xmlcdata, enc_int(_val)} | _acc]. - -decode_rsm_count(__TopXMLNS, __IgnoreEls, - {xmlel, <<"count">>, _attrs, _els}) -> - Cdata = decode_rsm_count_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_rsm_count_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_rsm_count_cdata(__TopXMLNS, Cdata); -decode_rsm_count_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_rsm_count_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_rsm_count_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_rsm_count_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_rsm_count(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/rsm">>, - [], __TopXMLNS), - _els = encode_rsm_count_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"count">>, _attrs, _els}. - -decode_rsm_count_cdata(__TopXMLNS, <<>>) -> undefined; -decode_rsm_count_cdata(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, infinity) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_cdata_value, <<>>, <<"count">>, __TopXMLNS}}); - _res -> _res - end. - -encode_rsm_count_cdata(undefined, _acc) -> _acc; -encode_rsm_count_cdata(_val, _acc) -> - [{xmlcdata, enc_int(_val)} | _acc]. - -decode_rsm_last(__TopXMLNS, __IgnoreEls, - {xmlel, <<"last">>, _attrs, _els}) -> - Cdata = decode_rsm_last_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_rsm_last_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_rsm_last_cdata(__TopXMLNS, Cdata); -decode_rsm_last_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_rsm_last_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_rsm_last_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Cdata) -> - decode_rsm_last_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_rsm_last(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/rsm">>, - [], __TopXMLNS), - _els = encode_rsm_last_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"last">>, _attrs, _els}. - -decode_rsm_last_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_rsm_last_cdata(__TopXMLNS, _val) -> _val. - -encode_rsm_last_cdata(<<>>, _acc) -> _acc; -encode_rsm_last_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_rsm_before(__TopXMLNS, __IgnoreEls, - {xmlel, <<"before">>, _attrs, _els}) -> - Cdata = decode_rsm_before_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_rsm_before_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_rsm_before_cdata(__TopXMLNS, Cdata); -decode_rsm_before_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_rsm_before_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_rsm_before_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_rsm_before_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_rsm_before(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/rsm">>, - [], __TopXMLNS), - _els = encode_rsm_before_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"before">>, _attrs, _els}. - -decode_rsm_before_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_rsm_before_cdata(__TopXMLNS, _val) -> _val. - -encode_rsm_before_cdata(<<>>, _acc) -> _acc; -encode_rsm_before_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_rsm_after(__TopXMLNS, __IgnoreEls, - {xmlel, <<"after">>, _attrs, _els}) -> - Cdata = decode_rsm_after_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_rsm_after_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_rsm_after_cdata(__TopXMLNS, Cdata); -decode_rsm_after_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_rsm_after_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_rsm_after_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_rsm_after_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_rsm_after(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/rsm">>, - [], __TopXMLNS), - _els = encode_rsm_after_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"after">>, _attrs, _els}. - -decode_rsm_after_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_rsm_after_cdata(__TopXMLNS, _val) -> _val. - -encode_rsm_after_cdata(<<>>, _acc) -> _acc; -encode_rsm_after_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_muc_unsubscribe(__TopXMLNS, __IgnoreEls, - {xmlel, <<"unsubscribe">>, _attrs, _els}) -> - {muc_unsubscribe}. - -encode_muc_unsubscribe({muc_unsubscribe}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:mucsub:0">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"unsubscribe">>, _attrs, _els}. - -decode_muc_subscribe(__TopXMLNS, __IgnoreEls, - {xmlel, <<"subscribe">>, _attrs, _els}) -> - Events = decode_muc_subscribe_els(__TopXMLNS, - __IgnoreEls, _els, []), - Nick = decode_muc_subscribe_attrs(__TopXMLNS, _attrs, - undefined), - {muc_subscribe, Nick, Events}. - -decode_muc_subscribe_els(__TopXMLNS, __IgnoreEls, [], - Events) -> - lists:reverse(Events); -decode_muc_subscribe_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"event">>, _attrs, _} = _el | _els], - Events) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"urn:xmpp:mucsub:0">> -> - decode_muc_subscribe_els(__TopXMLNS, __IgnoreEls, _els, - [decode_muc_subscribe_event(__TopXMLNS, - __IgnoreEls, _el) - | Events]); - <<"urn:xmpp:mucsub:0">> -> - decode_muc_subscribe_els(__TopXMLNS, __IgnoreEls, _els, - [decode_muc_subscribe_event(<<"urn:xmpp:mucsub:0">>, - __IgnoreEls, _el) - | Events]); - _ -> - decode_muc_subscribe_els(__TopXMLNS, __IgnoreEls, _els, - Events) - end; -decode_muc_subscribe_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Events) -> - decode_muc_subscribe_els(__TopXMLNS, __IgnoreEls, _els, - Events). - -decode_muc_subscribe_attrs(__TopXMLNS, - [{<<"nick">>, _val} | _attrs], _Nick) -> - decode_muc_subscribe_attrs(__TopXMLNS, _attrs, _val); -decode_muc_subscribe_attrs(__TopXMLNS, [_ | _attrs], - Nick) -> - decode_muc_subscribe_attrs(__TopXMLNS, _attrs, Nick); -decode_muc_subscribe_attrs(__TopXMLNS, [], Nick) -> - decode_muc_subscribe_attr_nick(__TopXMLNS, Nick). - -encode_muc_subscribe({muc_subscribe, Nick, Events}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:mucsub:0">>, [], - __TopXMLNS), - _els = - lists:reverse('encode_muc_subscribe_$events'(Events, - __NewTopXMLNS, [])), - _attrs = encode_muc_subscribe_attr_nick(Nick, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"subscribe">>, _attrs, _els}. - -'encode_muc_subscribe_$events'([], __TopXMLNS, _acc) -> - _acc; -'encode_muc_subscribe_$events'([Events | _els], - __TopXMLNS, _acc) -> - 'encode_muc_subscribe_$events'(_els, __TopXMLNS, - [encode_muc_subscribe_event(Events, - __TopXMLNS) - | _acc]). - -decode_muc_subscribe_attr_nick(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"nick">>, <<"subscribe">>, - __TopXMLNS}}); -decode_muc_subscribe_attr_nick(__TopXMLNS, _val) -> - _val. - -encode_muc_subscribe_attr_nick(_val, _acc) -> - [{<<"nick">>, _val} | _acc]. - -decode_muc_subscribe_event(__TopXMLNS, __IgnoreEls, - {xmlel, <<"event">>, _attrs, _els}) -> - Node = decode_muc_subscribe_event_attrs(__TopXMLNS, - _attrs, undefined), - Node. - -decode_muc_subscribe_event_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], _Node) -> - decode_muc_subscribe_event_attrs(__TopXMLNS, _attrs, - _val); -decode_muc_subscribe_event_attrs(__TopXMLNS, - [_ | _attrs], Node) -> - decode_muc_subscribe_event_attrs(__TopXMLNS, _attrs, - Node); -decode_muc_subscribe_event_attrs(__TopXMLNS, [], - Node) -> - decode_muc_subscribe_event_attr_node(__TopXMLNS, Node). - -encode_muc_subscribe_event(Node, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:mucsub:0">>, [], - __TopXMLNS), - _els = [], - _attrs = encode_muc_subscribe_event_attr_node(Node, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"event">>, _attrs, _els}. - -decode_muc_subscribe_event_attr_node(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"node">>, <<"event">>, __TopXMLNS}}); -decode_muc_subscribe_event_attr_node(__TopXMLNS, - _val) -> - _val. - -encode_muc_subscribe_event_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_muc_subscriptions(__TopXMLNS, __IgnoreEls, - {xmlel, <<"subscriptions">>, _attrs, _els}) -> - List = decode_muc_subscriptions_els(__TopXMLNS, - __IgnoreEls, _els, []), - {muc_subscriptions, List}. - -decode_muc_subscriptions_els(__TopXMLNS, __IgnoreEls, - [], List) -> - lists:reverse(List); -decode_muc_subscriptions_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"subscription">>, _attrs, _} = _el - | _els], - List) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"urn:xmpp:mucsub:0">> -> - decode_muc_subscriptions_els(__TopXMLNS, __IgnoreEls, - _els, - [decode_muc_subscription(__TopXMLNS, - __IgnoreEls, - _el) - | List]); - <<"urn:xmpp:mucsub:0">> -> - decode_muc_subscriptions_els(__TopXMLNS, __IgnoreEls, - _els, - [decode_muc_subscription(<<"urn:xmpp:mucsub:0">>, - __IgnoreEls, - _el) - | List]); - _ -> - decode_muc_subscriptions_els(__TopXMLNS, __IgnoreEls, - _els, List) - end; -decode_muc_subscriptions_els(__TopXMLNS, __IgnoreEls, - [_ | _els], List) -> - decode_muc_subscriptions_els(__TopXMLNS, __IgnoreEls, - _els, List). - -encode_muc_subscriptions({muc_subscriptions, List}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:mucsub:0">>, [], - __TopXMLNS), - _els = - lists:reverse('encode_muc_subscriptions_$list'(List, - __NewTopXMLNS, [])), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"subscriptions">>, _attrs, _els}. - -'encode_muc_subscriptions_$list'([], __TopXMLNS, - _acc) -> - _acc; -'encode_muc_subscriptions_$list'([List | _els], - __TopXMLNS, _acc) -> - 'encode_muc_subscriptions_$list'(_els, __TopXMLNS, - [encode_muc_subscription(List, __TopXMLNS) - | _acc]). - -decode_muc_subscription(__TopXMLNS, __IgnoreEls, - {xmlel, <<"subscription">>, _attrs, _els}) -> - Jid = decode_muc_subscription_attrs(__TopXMLNS, _attrs, - undefined), - Jid. - -decode_muc_subscription_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], _Jid) -> - decode_muc_subscription_attrs(__TopXMLNS, _attrs, _val); -decode_muc_subscription_attrs(__TopXMLNS, [_ | _attrs], - Jid) -> - decode_muc_subscription_attrs(__TopXMLNS, _attrs, Jid); -decode_muc_subscription_attrs(__TopXMLNS, [], Jid) -> - decode_muc_subscription_attr_jid(__TopXMLNS, Jid). - -encode_muc_subscription(Jid, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:mucsub:0">>, [], - __TopXMLNS), - _els = [], - _attrs = encode_muc_subscription_attr_jid(Jid, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"subscription">>, _attrs, _els}. - -decode_muc_subscription_attr_jid(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"jid">>, <<"subscription">>, - __TopXMLNS}}); -decode_muc_subscription_attr_jid(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"jid">>, <<"subscription">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_muc_subscription_attr_jid(_val, _acc) -> - [{<<"jid">>, enc_jid(_val)} | _acc]. - -decode_x_conference(__TopXMLNS, __IgnoreEls, - {xmlel, <<"x">>, _attrs, _els}) -> - {Jid, Password, Reason, Thread, Continue} = - decode_x_conference_attrs(__TopXMLNS, _attrs, undefined, - undefined, undefined, undefined, undefined), - {x_conference, Jid, Password, Reason, Continue, Thread}. - -decode_x_conference_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], _Jid, Password, Reason, - Thread, Continue) -> - decode_x_conference_attrs(__TopXMLNS, _attrs, _val, - Password, Reason, Thread, Continue); -decode_x_conference_attrs(__TopXMLNS, - [{<<"password">>, _val} | _attrs], Jid, _Password, - Reason, Thread, Continue) -> - decode_x_conference_attrs(__TopXMLNS, _attrs, Jid, _val, - Reason, Thread, Continue); -decode_x_conference_attrs(__TopXMLNS, - [{<<"reason">>, _val} | _attrs], Jid, Password, - _Reason, Thread, Continue) -> - decode_x_conference_attrs(__TopXMLNS, _attrs, Jid, - Password, _val, Thread, Continue); -decode_x_conference_attrs(__TopXMLNS, - [{<<"thread">>, _val} | _attrs], Jid, Password, - Reason, _Thread, Continue) -> - decode_x_conference_attrs(__TopXMLNS, _attrs, Jid, - Password, Reason, _val, Continue); -decode_x_conference_attrs(__TopXMLNS, - [{<<"continue">>, _val} | _attrs], Jid, Password, - Reason, Thread, _Continue) -> - decode_x_conference_attrs(__TopXMLNS, _attrs, Jid, - Password, Reason, Thread, _val); -decode_x_conference_attrs(__TopXMLNS, [_ | _attrs], Jid, - Password, Reason, Thread, Continue) -> - decode_x_conference_attrs(__TopXMLNS, _attrs, Jid, - Password, Reason, Thread, Continue); -decode_x_conference_attrs(__TopXMLNS, [], Jid, Password, - Reason, Thread, Continue) -> - {decode_x_conference_attr_jid(__TopXMLNS, Jid), - decode_x_conference_attr_password(__TopXMLNS, Password), - decode_x_conference_attr_reason(__TopXMLNS, Reason), - decode_x_conference_attr_thread(__TopXMLNS, Thread), - decode_x_conference_attr_continue(__TopXMLNS, - Continue)}. - -encode_x_conference({x_conference, Jid, Password, - Reason, Continue, Thread}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:x:conference">>, [], - __TopXMLNS), - _els = [], - _attrs = encode_x_conference_attr_continue(Continue, - encode_x_conference_attr_thread(Thread, - encode_x_conference_attr_reason(Reason, - encode_x_conference_attr_password(Password, - encode_x_conference_attr_jid(Jid, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)))))), - {xmlel, <<"x">>, _attrs, _els}. - -decode_x_conference_attr_jid(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"jid">>, <<"x">>, __TopXMLNS}}); -decode_x_conference_attr_jid(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"jid">>, <<"x">>, __TopXMLNS}}); - _res -> _res - end. - -encode_x_conference_attr_jid(_val, _acc) -> - [{<<"jid">>, enc_jid(_val)} | _acc]. - -decode_x_conference_attr_password(__TopXMLNS, - undefined) -> - <<>>; -decode_x_conference_attr_password(__TopXMLNS, _val) -> - _val. - -encode_x_conference_attr_password(<<>>, _acc) -> _acc; -encode_x_conference_attr_password(_val, _acc) -> - [{<<"password">>, _val} | _acc]. - -decode_x_conference_attr_reason(__TopXMLNS, - undefined) -> - <<>>; -decode_x_conference_attr_reason(__TopXMLNS, _val) -> - _val. - -encode_x_conference_attr_reason(<<>>, _acc) -> _acc; -encode_x_conference_attr_reason(_val, _acc) -> - [{<<"reason">>, _val} | _acc]. - -decode_x_conference_attr_thread(__TopXMLNS, - undefined) -> - <<>>; -decode_x_conference_attr_thread(__TopXMLNS, _val) -> - _val. - -encode_x_conference_attr_thread(<<>>, _acc) -> _acc; -encode_x_conference_attr_thread(_val, _acc) -> - [{<<"thread">>, _val} | _acc]. - -decode_x_conference_attr_continue(__TopXMLNS, - undefined) -> - undefined; -decode_x_conference_attr_continue(__TopXMLNS, _val) -> - case catch dec_bool(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"continue">>, <<"x">>, __TopXMLNS}}); - _res -> _res - end. - -encode_x_conference_attr_continue(undefined, _acc) -> - _acc; -encode_x_conference_attr_continue(_val, _acc) -> - [{<<"continue">>, enc_bool(_val)} | _acc]. - -decode_muc_unique(__TopXMLNS, __IgnoreEls, - {xmlel, <<"unique">>, _attrs, _els}) -> - Name = decode_muc_unique_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - {muc_unique, Name}. - -decode_muc_unique_els(__TopXMLNS, __IgnoreEls, [], - Name) -> - decode_muc_unique_cdata(__TopXMLNS, Name); -decode_muc_unique_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Name) -> - decode_muc_unique_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_muc_unique_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Name) -> - decode_muc_unique_els(__TopXMLNS, __IgnoreEls, _els, - Name). - -encode_muc_unique({muc_unique, Name}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/muc#unique">>, - [], __TopXMLNS), - _els = encode_muc_unique_cdata(Name, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"unique">>, _attrs, _els}. - -decode_muc_unique_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_muc_unique_cdata(__TopXMLNS, _val) -> _val. - -encode_muc_unique_cdata(<<>>, _acc) -> _acc; -encode_muc_unique_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_muc(__TopXMLNS, __IgnoreEls, - {xmlel, <<"x">>, _attrs, _els}) -> - {Password, History} = decode_muc_els(__TopXMLNS, - __IgnoreEls, _els, undefined, - undefined), - {muc, History, Password}. - -decode_muc_els(__TopXMLNS, __IgnoreEls, [], Password, - History) -> - {Password, History}; -decode_muc_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"history">>, _attrs, _} = _el | _els], - Password, History) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/muc">> -> - decode_muc_els(__TopXMLNS, __IgnoreEls, _els, Password, - decode_muc_history(__TopXMLNS, __IgnoreEls, _el)); - <<"http://jabber.org/protocol/muc">> -> - decode_muc_els(__TopXMLNS, __IgnoreEls, _els, Password, - decode_muc_history(<<"http://jabber.org/protocol/muc">>, - __IgnoreEls, _el)); - _ -> - decode_muc_els(__TopXMLNS, __IgnoreEls, _els, Password, - History) - end; -decode_muc_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"password">>, _attrs, _} = _el | _els], - Password, History) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/muc">> -> - decode_muc_els(__TopXMLNS, __IgnoreEls, _els, - decode_muc_password(__TopXMLNS, __IgnoreEls, _el), - History); - <<"http://jabber.org/protocol/muc#owner">> -> - decode_muc_els(__TopXMLNS, __IgnoreEls, _els, - decode_muc_password(<<"http://jabber.org/protocol/muc#owner">>, - __IgnoreEls, _el), - History); - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_els(__TopXMLNS, __IgnoreEls, _els, - decode_muc_password(<<"http://jabber.org/protocol/muc#user">>, - __IgnoreEls, _el), - History); - <<"http://jabber.org/protocol/muc">> -> - decode_muc_els(__TopXMLNS, __IgnoreEls, _els, - decode_muc_password(<<"http://jabber.org/protocol/muc">>, - __IgnoreEls, _el), - History); - _ -> - decode_muc_els(__TopXMLNS, __IgnoreEls, _els, Password, - History) - end; -decode_muc_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Password, History) -> - decode_muc_els(__TopXMLNS, __IgnoreEls, _els, Password, - History). - -encode_muc({muc, History, Password}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/muc">>, - [], __TopXMLNS), - _els = lists:reverse('encode_muc_$password'(Password, - __NewTopXMLNS, - 'encode_muc_$history'(History, - __NewTopXMLNS, - []))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"x">>, _attrs, _els}. - -'encode_muc_$password'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_muc_$password'(Password, __TopXMLNS, _acc) -> - [encode_muc_password(Password, __TopXMLNS) | _acc]. - -'encode_muc_$history'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_muc_$history'(History, __TopXMLNS, _acc) -> - [encode_muc_history(History, __TopXMLNS) | _acc]. - -decode_muc_admin(__TopXMLNS, __IgnoreEls, - {xmlel, <<"query">>, _attrs, _els}) -> - Items = decode_muc_admin_els(__TopXMLNS, __IgnoreEls, - _els, []), - {muc_admin, Items}. - -decode_muc_admin_els(__TopXMLNS, __IgnoreEls, [], - Items) -> - lists:reverse(Items); -decode_muc_admin_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/muc#admin">> -> - decode_muc_admin_els(__TopXMLNS, __IgnoreEls, _els, - [decode_muc_admin_item(__TopXMLNS, __IgnoreEls, - _el) - | Items]); - <<"http://jabber.org/protocol/muc#admin">> -> - decode_muc_admin_els(__TopXMLNS, __IgnoreEls, _els, - [decode_muc_admin_item(<<"http://jabber.org/protocol/muc#admin">>, - __IgnoreEls, _el) - | Items]); - _ -> - decode_muc_admin_els(__TopXMLNS, __IgnoreEls, _els, - Items) - end; -decode_muc_admin_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Items) -> - decode_muc_admin_els(__TopXMLNS, __IgnoreEls, _els, - Items). - -encode_muc_admin({muc_admin, Items}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/muc#admin">>, - [], __TopXMLNS), - _els = lists:reverse('encode_muc_admin_$items'(Items, - __NewTopXMLNS, [])), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"query">>, _attrs, _els}. - -'encode_muc_admin_$items'([], __TopXMLNS, _acc) -> _acc; -'encode_muc_admin_$items'([Items | _els], __TopXMLNS, - _acc) -> - 'encode_muc_admin_$items'(_els, __TopXMLNS, - [encode_muc_admin_item(Items, __TopXMLNS) - | _acc]). - -decode_muc_admin_continue(__TopXMLNS, __IgnoreEls, - {xmlel, <<"continue">>, _attrs, _els}) -> - Thread = decode_muc_admin_continue_attrs(__TopXMLNS, - _attrs, undefined), - Thread. - -decode_muc_admin_continue_attrs(__TopXMLNS, - [{<<"thread">>, _val} | _attrs], _Thread) -> - decode_muc_admin_continue_attrs(__TopXMLNS, _attrs, - _val); -decode_muc_admin_continue_attrs(__TopXMLNS, - [_ | _attrs], Thread) -> - decode_muc_admin_continue_attrs(__TopXMLNS, _attrs, - Thread); -decode_muc_admin_continue_attrs(__TopXMLNS, [], - Thread) -> - decode_muc_admin_continue_attr_thread(__TopXMLNS, - Thread). - -encode_muc_admin_continue(Thread, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/muc#admin">>, - [], __TopXMLNS), - _els = [], - _attrs = encode_muc_admin_continue_attr_thread(Thread, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"continue">>, _attrs, _els}. - -decode_muc_admin_continue_attr_thread(__TopXMLNS, - undefined) -> - <<>>; -decode_muc_admin_continue_attr_thread(__TopXMLNS, - _val) -> - _val. - -encode_muc_admin_continue_attr_thread(<<>>, _acc) -> - _acc; -encode_muc_admin_continue_attr_thread(_val, _acc) -> - [{<<"thread">>, _val} | _acc]. - -decode_muc_admin_actor(__TopXMLNS, __IgnoreEls, - {xmlel, <<"actor">>, _attrs, _els}) -> - {Jid, Nick} = decode_muc_admin_actor_attrs(__TopXMLNS, - _attrs, undefined, undefined), - {muc_actor, Jid, Nick}. - -decode_muc_admin_actor_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], _Jid, Nick) -> - decode_muc_admin_actor_attrs(__TopXMLNS, _attrs, _val, - Nick); -decode_muc_admin_actor_attrs(__TopXMLNS, - [{<<"nick">>, _val} | _attrs], Jid, _Nick) -> - decode_muc_admin_actor_attrs(__TopXMLNS, _attrs, Jid, - _val); -decode_muc_admin_actor_attrs(__TopXMLNS, [_ | _attrs], - Jid, Nick) -> - decode_muc_admin_actor_attrs(__TopXMLNS, _attrs, Jid, - Nick); -decode_muc_admin_actor_attrs(__TopXMLNS, [], Jid, - Nick) -> - {decode_muc_admin_actor_attr_jid(__TopXMLNS, Jid), - decode_muc_admin_actor_attr_nick(__TopXMLNS, Nick)}. - -encode_muc_admin_actor({muc_actor, Jid, Nick}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/muc#admin">>, - [], __TopXMLNS), - _els = [], - _attrs = encode_muc_admin_actor_attr_nick(Nick, - encode_muc_admin_actor_attr_jid(Jid, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))), - {xmlel, <<"actor">>, _attrs, _els}. - -decode_muc_admin_actor_attr_jid(__TopXMLNS, - undefined) -> - undefined; -decode_muc_admin_actor_attr_jid(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"jid">>, <<"actor">>, __TopXMLNS}}); - _res -> _res - end. - -encode_muc_admin_actor_attr_jid(undefined, _acc) -> - _acc; -encode_muc_admin_actor_attr_jid(_val, _acc) -> - [{<<"jid">>, enc_jid(_val)} | _acc]. - -decode_muc_admin_actor_attr_nick(__TopXMLNS, - undefined) -> - <<>>; -decode_muc_admin_actor_attr_nick(__TopXMLNS, _val) -> - _val. - -encode_muc_admin_actor_attr_nick(<<>>, _acc) -> _acc; -encode_muc_admin_actor_attr_nick(_val, _acc) -> - [{<<"nick">>, _val} | _acc]. - -decode_muc_admin_item(__TopXMLNS, __IgnoreEls, - {xmlel, <<"item">>, _attrs, _els}) -> - {Actor, Continue, Reason} = - decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, - undefined, undefined, <<>>), - {Affiliation, Role, Jid, Nick} = - decode_muc_admin_item_attrs(__TopXMLNS, _attrs, - undefined, undefined, undefined, undefined), - {muc_item, Actor, Continue, Reason, Affiliation, Role, - Jid, Nick}. - -decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, [], - Actor, Continue, Reason) -> - {Actor, Continue, Reason}; -decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"actor">>, _attrs, _} = _el | _els], Actor, - Continue, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/muc#admin">> -> - decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, - decode_muc_admin_actor(__TopXMLNS, - __IgnoreEls, _el), - Continue, Reason); - <<"http://jabber.org/protocol/muc#admin">> -> - decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, - decode_muc_admin_actor(<<"http://jabber.org/protocol/muc#admin">>, - __IgnoreEls, _el), - Continue, Reason); - _ -> - decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, Reason) - end; -decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"continue">>, _attrs, _} = _el | _els], - Actor, Continue, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/muc#admin">> -> - decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, - decode_muc_admin_continue(__TopXMLNS, - __IgnoreEls, _el), - Reason); - <<"http://jabber.org/protocol/muc#admin">> -> - decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, - decode_muc_admin_continue(<<"http://jabber.org/protocol/muc#admin">>, - __IgnoreEls, _el), - Reason); - _ -> - decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, Reason) - end; -decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"reason">>, _attrs, _} = _el | _els], - Actor, Continue, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/muc#admin">> -> - decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, - decode_muc_reason(__TopXMLNS, __IgnoreEls, - _el)); - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, - decode_muc_reason(<<"http://jabber.org/protocol/muc#user">>, - __IgnoreEls, _el)); - <<"http://jabber.org/protocol/muc#admin">> -> - decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, - decode_muc_reason(<<"http://jabber.org/protocol/muc#admin">>, - __IgnoreEls, _el)); - <<"http://jabber.org/protocol/muc#owner">> -> - decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, - decode_muc_reason(<<"http://jabber.org/protocol/muc#owner">>, - __IgnoreEls, _el)); - _ -> - decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, Reason) - end; -decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Actor, Continue, Reason) -> - decode_muc_admin_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, Reason). - -decode_muc_admin_item_attrs(__TopXMLNS, - [{<<"affiliation">>, _val} | _attrs], _Affiliation, - Role, Jid, Nick) -> - decode_muc_admin_item_attrs(__TopXMLNS, _attrs, _val, - Role, Jid, Nick); -decode_muc_admin_item_attrs(__TopXMLNS, - [{<<"role">>, _val} | _attrs], Affiliation, _Role, - Jid, Nick) -> - decode_muc_admin_item_attrs(__TopXMLNS, _attrs, - Affiliation, _val, Jid, Nick); -decode_muc_admin_item_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], Affiliation, Role, - _Jid, Nick) -> - decode_muc_admin_item_attrs(__TopXMLNS, _attrs, - Affiliation, Role, _val, Nick); -decode_muc_admin_item_attrs(__TopXMLNS, - [{<<"nick">>, _val} | _attrs], Affiliation, Role, - Jid, _Nick) -> - decode_muc_admin_item_attrs(__TopXMLNS, _attrs, - Affiliation, Role, Jid, _val); -decode_muc_admin_item_attrs(__TopXMLNS, [_ | _attrs], - Affiliation, Role, Jid, Nick) -> - decode_muc_admin_item_attrs(__TopXMLNS, _attrs, - Affiliation, Role, Jid, Nick); -decode_muc_admin_item_attrs(__TopXMLNS, [], Affiliation, - Role, Jid, Nick) -> - {decode_muc_admin_item_attr_affiliation(__TopXMLNS, - Affiliation), - decode_muc_admin_item_attr_role(__TopXMLNS, Role), - decode_muc_admin_item_attr_jid(__TopXMLNS, Jid), - decode_muc_admin_item_attr_nick(__TopXMLNS, Nick)}. - -encode_muc_admin_item({muc_item, Actor, Continue, - Reason, Affiliation, Role, Jid, Nick}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/muc#admin">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_muc_admin_item_$actor'(Actor, - __NewTopXMLNS, - 'encode_muc_admin_item_$continue'(Continue, - __NewTopXMLNS, - 'encode_muc_admin_item_$reason'(Reason, - __NewTopXMLNS, - [])))), - _attrs = encode_muc_admin_item_attr_nick(Nick, - encode_muc_admin_item_attr_jid(Jid, - encode_muc_admin_item_attr_role(Role, - encode_muc_admin_item_attr_affiliation(Affiliation, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))))), - {xmlel, <<"item">>, _attrs, _els}. - -'encode_muc_admin_item_$actor'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_muc_admin_item_$actor'(Actor, __TopXMLNS, - _acc) -> - [encode_muc_admin_actor(Actor, __TopXMLNS) | _acc]. - -'encode_muc_admin_item_$continue'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_muc_admin_item_$continue'(Continue, __TopXMLNS, - _acc) -> - [encode_muc_admin_continue(Continue, __TopXMLNS) - | _acc]. - -'encode_muc_admin_item_$reason'(<<>>, __TopXMLNS, - _acc) -> - _acc; -'encode_muc_admin_item_$reason'(Reason, __TopXMLNS, - _acc) -> - [encode_muc_reason(Reason, __TopXMLNS) | _acc]. - -decode_muc_admin_item_attr_affiliation(__TopXMLNS, - undefined) -> - undefined; -decode_muc_admin_item_attr_affiliation(__TopXMLNS, - _val) -> - case catch dec_enum(_val, - [admin, member, none, outcast, owner]) - of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"affiliation">>, <<"item">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_muc_admin_item_attr_affiliation(undefined, - _acc) -> - _acc; -encode_muc_admin_item_attr_affiliation(_val, _acc) -> - [{<<"affiliation">>, enc_enum(_val)} | _acc]. - -decode_muc_admin_item_attr_role(__TopXMLNS, - undefined) -> - undefined; -decode_muc_admin_item_attr_role(__TopXMLNS, _val) -> - case catch dec_enum(_val, - [moderator, none, participant, visitor]) - of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"role">>, <<"item">>, __TopXMLNS}}); - _res -> _res - end. - -encode_muc_admin_item_attr_role(undefined, _acc) -> - _acc; -encode_muc_admin_item_attr_role(_val, _acc) -> - [{<<"role">>, enc_enum(_val)} | _acc]. - -decode_muc_admin_item_attr_jid(__TopXMLNS, undefined) -> - undefined; -decode_muc_admin_item_attr_jid(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"jid">>, <<"item">>, __TopXMLNS}}); - _res -> _res - end. - -encode_muc_admin_item_attr_jid(undefined, _acc) -> _acc; -encode_muc_admin_item_attr_jid(_val, _acc) -> - [{<<"jid">>, enc_jid(_val)} | _acc]. - -decode_muc_admin_item_attr_nick(__TopXMLNS, - undefined) -> - <<>>; -decode_muc_admin_item_attr_nick(__TopXMLNS, _val) -> - _val. - -encode_muc_admin_item_attr_nick(<<>>, _acc) -> _acc; -encode_muc_admin_item_attr_nick(_val, _acc) -> - [{<<"nick">>, _val} | _acc]. - -decode_muc_owner_item(__TopXMLNS, __IgnoreEls, - {xmlel, <<"item">>, _attrs, _els}) -> - {Actor, Continue, Reason} = - decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, _els, - undefined, undefined, <<>>), - {Affiliation, Role, Jid, Nick} = - decode_muc_owner_item_attrs(__TopXMLNS, _attrs, - undefined, undefined, undefined, undefined), - {muc_item, Actor, Continue, Reason, Affiliation, Role, - Jid, Nick}. - -decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, [], - Actor, Continue, Reason) -> - {Actor, Continue, Reason}; -decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"actor">>, _attrs, _} = _el | _els], Actor, - Continue, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"http://jabber.org/protocol/muc#admin">> -> - decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, _els, - decode_muc_admin_actor(<<"http://jabber.org/protocol/muc#admin">>, - __IgnoreEls, _el), - Continue, Reason); - _ -> - decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, Reason) - end; -decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"continue">>, _attrs, _} = _el | _els], - Actor, Continue, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"http://jabber.org/protocol/muc#admin">> -> - decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, - decode_muc_admin_continue(<<"http://jabber.org/protocol/muc#admin">>, - __IgnoreEls, _el), - Reason); - _ -> - decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, Reason) - end; -decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"reason">>, _attrs, _} = _el | _els], - Actor, Continue, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/muc#owner">> -> - decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, - decode_muc_reason(__TopXMLNS, __IgnoreEls, - _el)); - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, - decode_muc_reason(<<"http://jabber.org/protocol/muc#user">>, - __IgnoreEls, _el)); - <<"http://jabber.org/protocol/muc#admin">> -> - decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, - decode_muc_reason(<<"http://jabber.org/protocol/muc#admin">>, - __IgnoreEls, _el)); - <<"http://jabber.org/protocol/muc#owner">> -> - decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, - decode_muc_reason(<<"http://jabber.org/protocol/muc#owner">>, - __IgnoreEls, _el)); - _ -> - decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, Reason) - end; -decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Actor, Continue, Reason) -> - decode_muc_owner_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, Reason). - -decode_muc_owner_item_attrs(__TopXMLNS, - [{<<"affiliation">>, _val} | _attrs], _Affiliation, - Role, Jid, Nick) -> - decode_muc_owner_item_attrs(__TopXMLNS, _attrs, _val, - Role, Jid, Nick); -decode_muc_owner_item_attrs(__TopXMLNS, - [{<<"role">>, _val} | _attrs], Affiliation, _Role, - Jid, Nick) -> - decode_muc_owner_item_attrs(__TopXMLNS, _attrs, - Affiliation, _val, Jid, Nick); -decode_muc_owner_item_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], Affiliation, Role, - _Jid, Nick) -> - decode_muc_owner_item_attrs(__TopXMLNS, _attrs, - Affiliation, Role, _val, Nick); -decode_muc_owner_item_attrs(__TopXMLNS, - [{<<"nick">>, _val} | _attrs], Affiliation, Role, - Jid, _Nick) -> - decode_muc_owner_item_attrs(__TopXMLNS, _attrs, - Affiliation, Role, Jid, _val); -decode_muc_owner_item_attrs(__TopXMLNS, [_ | _attrs], - Affiliation, Role, Jid, Nick) -> - decode_muc_owner_item_attrs(__TopXMLNS, _attrs, - Affiliation, Role, Jid, Nick); -decode_muc_owner_item_attrs(__TopXMLNS, [], Affiliation, - Role, Jid, Nick) -> - {decode_muc_owner_item_attr_affiliation(__TopXMLNS, - Affiliation), - decode_muc_owner_item_attr_role(__TopXMLNS, Role), - decode_muc_owner_item_attr_jid(__TopXMLNS, Jid), - decode_muc_owner_item_attr_nick(__TopXMLNS, Nick)}. - -encode_muc_owner_item({muc_item, Actor, Continue, - Reason, Affiliation, Role, Jid, Nick}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/muc#owner">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_muc_owner_item_$actor'(Actor, - __NewTopXMLNS, - 'encode_muc_owner_item_$continue'(Continue, - __NewTopXMLNS, - 'encode_muc_owner_item_$reason'(Reason, - __NewTopXMLNS, - [])))), - _attrs = encode_muc_owner_item_attr_nick(Nick, - encode_muc_owner_item_attr_jid(Jid, - encode_muc_owner_item_attr_role(Role, - encode_muc_owner_item_attr_affiliation(Affiliation, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))))), - {xmlel, <<"item">>, _attrs, _els}. - -'encode_muc_owner_item_$actor'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_muc_owner_item_$actor'(Actor, __TopXMLNS, - _acc) -> - [encode_muc_admin_actor(Actor, __TopXMLNS) | _acc]. - -'encode_muc_owner_item_$continue'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_muc_owner_item_$continue'(Continue, __TopXMLNS, - _acc) -> - [encode_muc_admin_continue(Continue, __TopXMLNS) - | _acc]. - -'encode_muc_owner_item_$reason'(<<>>, __TopXMLNS, - _acc) -> - _acc; -'encode_muc_owner_item_$reason'(Reason, __TopXMLNS, - _acc) -> - [encode_muc_reason(Reason, __TopXMLNS) | _acc]. - -decode_muc_owner_item_attr_affiliation(__TopXMLNS, - undefined) -> - undefined; -decode_muc_owner_item_attr_affiliation(__TopXMLNS, - _val) -> - case catch dec_enum(_val, - [admin, member, none, outcast, owner]) - of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"affiliation">>, <<"item">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_muc_owner_item_attr_affiliation(undefined, - _acc) -> - _acc; -encode_muc_owner_item_attr_affiliation(_val, _acc) -> - [{<<"affiliation">>, enc_enum(_val)} | _acc]. - -decode_muc_owner_item_attr_role(__TopXMLNS, - undefined) -> - undefined; -decode_muc_owner_item_attr_role(__TopXMLNS, _val) -> - case catch dec_enum(_val, - [moderator, none, participant, visitor]) - of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"role">>, <<"item">>, __TopXMLNS}}); - _res -> _res - end. - -encode_muc_owner_item_attr_role(undefined, _acc) -> - _acc; -encode_muc_owner_item_attr_role(_val, _acc) -> - [{<<"role">>, enc_enum(_val)} | _acc]. - -decode_muc_owner_item_attr_jid(__TopXMLNS, undefined) -> - undefined; -decode_muc_owner_item_attr_jid(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"jid">>, <<"item">>, __TopXMLNS}}); - _res -> _res - end. - -encode_muc_owner_item_attr_jid(undefined, _acc) -> _acc; -encode_muc_owner_item_attr_jid(_val, _acc) -> - [{<<"jid">>, enc_jid(_val)} | _acc]. - -decode_muc_owner_item_attr_nick(__TopXMLNS, - undefined) -> - <<>>; -decode_muc_owner_item_attr_nick(__TopXMLNS, _val) -> - _val. - -encode_muc_owner_item_attr_nick(<<>>, _acc) -> _acc; -encode_muc_owner_item_attr_nick(_val, _acc) -> - [{<<"nick">>, _val} | _acc]. - -decode_muc_owner(__TopXMLNS, __IgnoreEls, - {xmlel, <<"query">>, _attrs, _els}) -> - {Items, Config, Destroy} = - decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, [], - undefined, undefined), - {muc_owner, Destroy, Config, Items}. - -decode_muc_owner_els(__TopXMLNS, __IgnoreEls, [], Items, - Config, Destroy) -> - {lists:reverse(Items), Config, Destroy}; -decode_muc_owner_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"destroy">>, _attrs, _} = _el | _els], Items, - Config, Destroy) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/muc#owner">> -> - decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, - Items, Config, - decode_muc_destroy(__TopXMLNS, __IgnoreEls, - _el)); - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, - Items, Config, - decode_muc_destroy(<<"http://jabber.org/protocol/muc#user">>, - __IgnoreEls, _el)); - <<"http://jabber.org/protocol/muc#owner">> -> - decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, - Items, Config, - decode_muc_destroy(<<"http://jabber.org/protocol/muc#owner">>, - __IgnoreEls, _el)); - _ -> - decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, - Items, Config, Destroy) - end; -decode_muc_owner_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"x">>, _attrs, _} = _el | _els], Items, - Config, Destroy) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"jabber:x:data">> -> - decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, - Items, - decode_xdata(<<"jabber:x:data">>, __IgnoreEls, - _el), - Destroy); - _ -> - decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, - Items, Config, Destroy) - end; -decode_muc_owner_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items, - Config, Destroy) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/muc#owner">> -> - decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, - [decode_muc_owner_item(__TopXMLNS, __IgnoreEls, - _el) - | Items], - Config, Destroy); - <<"http://jabber.org/protocol/muc#owner">> -> - decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, - [decode_muc_owner_item(<<"http://jabber.org/protocol/muc#owner">>, - __IgnoreEls, _el) - | Items], - Config, Destroy); - _ -> - decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, - Items, Config, Destroy) - end; -decode_muc_owner_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Items, Config, Destroy) -> - decode_muc_owner_els(__TopXMLNS, __IgnoreEls, _els, - Items, Config, Destroy). - -encode_muc_owner({muc_owner, Destroy, Config, Items}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/muc#owner">>, - [], __TopXMLNS), - _els = lists:reverse('encode_muc_owner_$items'(Items, - __NewTopXMLNS, - 'encode_muc_owner_$config'(Config, - __NewTopXMLNS, - 'encode_muc_owner_$destroy'(Destroy, - __NewTopXMLNS, - [])))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"query">>, _attrs, _els}. - -'encode_muc_owner_$items'([], __TopXMLNS, _acc) -> _acc; -'encode_muc_owner_$items'([Items | _els], __TopXMLNS, - _acc) -> - 'encode_muc_owner_$items'(_els, __TopXMLNS, - [encode_muc_owner_item(Items, __TopXMLNS) - | _acc]). - -'encode_muc_owner_$config'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_muc_owner_$config'(Config, __TopXMLNS, _acc) -> - [encode_xdata(Config, __TopXMLNS) | _acc]. - -'encode_muc_owner_$destroy'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_muc_owner_$destroy'(Destroy, __TopXMLNS, - _acc) -> - [encode_muc_destroy(Destroy, __TopXMLNS) | _acc]. - -decode_muc_password(__TopXMLNS, __IgnoreEls, - {xmlel, <<"password">>, _attrs, _els}) -> - Cdata = decode_muc_password_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_muc_password_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_muc_password_cdata(__TopXMLNS, Cdata); -decode_muc_password_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_muc_password_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_muc_password_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_muc_password_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_muc_password(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"http://jabber.org/protocol/muc#owner">>, - <<"http://jabber.org/protocol/muc#user">>, - <<"http://jabber.org/protocol/muc">>], - __TopXMLNS), - _els = encode_muc_password_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"password">>, _attrs, _els}. - -decode_muc_password_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_muc_password_cdata(__TopXMLNS, _val) -> _val. - -encode_muc_password_cdata(<<>>, _acc) -> _acc; -encode_muc_password_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_muc_user(__TopXMLNS, __IgnoreEls, - {xmlel, <<"x">>, _attrs, _els}) -> - {Status_codes, Items, Invites, Password, Decline, - Destroy} = - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, [], - [], [], undefined, undefined, undefined), - {muc_user, Decline, Destroy, Invites, Items, - Status_codes, Password}. - -decode_muc_user_els(__TopXMLNS, __IgnoreEls, [], - Status_codes, Items, Invites, Password, Decline, - Destroy) -> - {lists:reverse(Status_codes), lists:reverse(Items), - lists:reverse(Invites), Password, Decline, Destroy}; -decode_muc_user_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"decline">>, _attrs, _} = _el | _els], - Status_codes, Items, Invites, Password, Decline, - Destroy) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Password, - decode_muc_user_decline(__TopXMLNS, __IgnoreEls, - _el), - Destroy); - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Password, - decode_muc_user_decline(<<"http://jabber.org/protocol/muc#user">>, - __IgnoreEls, _el), - Destroy); - _ -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Password, Decline, - Destroy) - end; -decode_muc_user_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"destroy">>, _attrs, _} = _el | _els], - Status_codes, Items, Invites, Password, Decline, - Destroy) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Password, Decline, - decode_muc_destroy(__TopXMLNS, __IgnoreEls, _el)); - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Password, Decline, - decode_muc_destroy(<<"http://jabber.org/protocol/muc#user">>, - __IgnoreEls, _el)); - <<"http://jabber.org/protocol/muc#owner">> -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Password, Decline, - decode_muc_destroy(<<"http://jabber.org/protocol/muc#owner">>, - __IgnoreEls, _el)); - _ -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Password, Decline, - Destroy) - end; -decode_muc_user_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"password">>, _attrs, _} = _el | _els], - Status_codes, Items, Invites, Password, Decline, - Destroy) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, - decode_muc_password(__TopXMLNS, __IgnoreEls, _el), - Decline, Destroy); - <<"http://jabber.org/protocol/muc#owner">> -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, - decode_muc_password(<<"http://jabber.org/protocol/muc#owner">>, - __IgnoreEls, _el), - Decline, Destroy); - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, - decode_muc_password(<<"http://jabber.org/protocol/muc#user">>, - __IgnoreEls, _el), - Decline, Destroy); - <<"http://jabber.org/protocol/muc">> -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, - decode_muc_password(<<"http://jabber.org/protocol/muc">>, - __IgnoreEls, _el), - Decline, Destroy); - _ -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Password, Decline, - Destroy) - end; -decode_muc_user_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"invite">>, _attrs, _} = _el | _els], - Status_codes, Items, Invites, Password, Decline, - Destroy) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, - [decode_muc_user_invite(__TopXMLNS, __IgnoreEls, - _el) - | Invites], - Password, Decline, Destroy); - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, - [decode_muc_user_invite(<<"http://jabber.org/protocol/muc#user">>, - __IgnoreEls, _el) - | Invites], - Password, Decline, Destroy); - _ -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Password, Decline, - Destroy) - end; -decode_muc_user_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"item">>, _attrs, _} = _el | _els], - Status_codes, Items, Invites, Password, Decline, - Destroy) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, - [decode_muc_user_item(__TopXMLNS, __IgnoreEls, - _el) - | Items], - Invites, Password, Decline, Destroy); - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, - [decode_muc_user_item(<<"http://jabber.org/protocol/muc#user">>, - __IgnoreEls, _el) - | Items], - Invites, Password, Decline, Destroy); - _ -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Password, Decline, - Destroy) - end; -decode_muc_user_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"status">>, _attrs, _} = _el | _els], - Status_codes, Items, Invites, Password, Decline, - Destroy) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - case decode_muc_user_status(__TopXMLNS, - __IgnoreEls, _el) - of - undefined -> Status_codes; - _new_el -> [_new_el | Status_codes] - end, - Items, Invites, Password, Decline, Destroy); - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - case - decode_muc_user_status(<<"http://jabber.org/protocol/muc#user">>, - __IgnoreEls, _el) - of - undefined -> Status_codes; - _new_el -> [_new_el | Status_codes] - end, - Items, Invites, Password, Decline, Destroy); - _ -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Password, Decline, - Destroy) - end; -decode_muc_user_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Status_codes, Items, Invites, Password, Decline, - Destroy) -> - decode_muc_user_els(__TopXMLNS, __IgnoreEls, _els, - Status_codes, Items, Invites, Password, Decline, - Destroy). - -encode_muc_user({muc_user, Decline, Destroy, Invites, - Items, Status_codes, Password}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/muc#user">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_muc_user_$status_codes'(Status_codes, - __NewTopXMLNS, - 'encode_muc_user_$items'(Items, - __NewTopXMLNS, - 'encode_muc_user_$invites'(Invites, - __NewTopXMLNS, - 'encode_muc_user_$password'(Password, - __NewTopXMLNS, - 'encode_muc_user_$decline'(Decline, - __NewTopXMLNS, - 'encode_muc_user_$destroy'(Destroy, - __NewTopXMLNS, - []))))))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"x">>, _attrs, _els}. - -'encode_muc_user_$status_codes'([], __TopXMLNS, _acc) -> - _acc; -'encode_muc_user_$status_codes'([Status_codes | _els], - __TopXMLNS, _acc) -> - 'encode_muc_user_$status_codes'(_els, __TopXMLNS, - [encode_muc_user_status(Status_codes, - __TopXMLNS) - | _acc]). - -'encode_muc_user_$items'([], __TopXMLNS, _acc) -> _acc; -'encode_muc_user_$items'([Items | _els], __TopXMLNS, - _acc) -> - 'encode_muc_user_$items'(_els, __TopXMLNS, - [encode_muc_user_item(Items, __TopXMLNS) | _acc]). - -'encode_muc_user_$invites'([], __TopXMLNS, _acc) -> - _acc; -'encode_muc_user_$invites'([Invites | _els], __TopXMLNS, - _acc) -> - 'encode_muc_user_$invites'(_els, __TopXMLNS, - [encode_muc_user_invite(Invites, __TopXMLNS) - | _acc]). - -'encode_muc_user_$password'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_muc_user_$password'(Password, __TopXMLNS, - _acc) -> - [encode_muc_password(Password, __TopXMLNS) | _acc]. - -'encode_muc_user_$decline'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_muc_user_$decline'(Decline, __TopXMLNS, _acc) -> - [encode_muc_user_decline(Decline, __TopXMLNS) | _acc]. - -'encode_muc_user_$destroy'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_muc_user_$destroy'(Destroy, __TopXMLNS, _acc) -> - [encode_muc_destroy(Destroy, __TopXMLNS) | _acc]. - -decode_muc_user_item(__TopXMLNS, __IgnoreEls, - {xmlel, <<"item">>, _attrs, _els}) -> - {Actor, Continue, Reason} = - decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, - undefined, undefined, <<>>), - {Affiliation, Role, Jid, Nick} = - decode_muc_user_item_attrs(__TopXMLNS, _attrs, - undefined, undefined, undefined, undefined), - {muc_item, Actor, Continue, Reason, Affiliation, Role, - Jid, Nick}. - -decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, [], - Actor, Continue, Reason) -> - {Actor, Continue, Reason}; -decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"actor">>, _attrs, _} = _el | _els], Actor, - Continue, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, - decode_muc_user_actor(__TopXMLNS, - __IgnoreEls, _el), - Continue, Reason); - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, - decode_muc_user_actor(<<"http://jabber.org/protocol/muc#user">>, - __IgnoreEls, _el), - Continue, Reason); - _ -> - decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, Reason) - end; -decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"continue">>, _attrs, _} = _el | _els], - Actor, Continue, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, - decode_muc_user_continue(__TopXMLNS, - __IgnoreEls, _el), - Reason); - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, - decode_muc_user_continue(<<"http://jabber.org/protocol/muc#user">>, - __IgnoreEls, _el), - Reason); - _ -> - decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, Reason) - end; -decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"reason">>, _attrs, _} = _el | _els], Actor, - Continue, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, - decode_muc_reason(__TopXMLNS, __IgnoreEls, - _el)); - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, - decode_muc_reason(<<"http://jabber.org/protocol/muc#user">>, - __IgnoreEls, _el)); - <<"http://jabber.org/protocol/muc#admin">> -> - decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, - decode_muc_reason(<<"http://jabber.org/protocol/muc#admin">>, - __IgnoreEls, _el)); - <<"http://jabber.org/protocol/muc#owner">> -> - decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, - decode_muc_reason(<<"http://jabber.org/protocol/muc#owner">>, - __IgnoreEls, _el)); - _ -> - decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, Reason) - end; -decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Actor, Continue, Reason) -> - decode_muc_user_item_els(__TopXMLNS, __IgnoreEls, _els, - Actor, Continue, Reason). - -decode_muc_user_item_attrs(__TopXMLNS, - [{<<"affiliation">>, _val} | _attrs], _Affiliation, - Role, Jid, Nick) -> - decode_muc_user_item_attrs(__TopXMLNS, _attrs, _val, - Role, Jid, Nick); -decode_muc_user_item_attrs(__TopXMLNS, - [{<<"role">>, _val} | _attrs], Affiliation, _Role, - Jid, Nick) -> - decode_muc_user_item_attrs(__TopXMLNS, _attrs, - Affiliation, _val, Jid, Nick); -decode_muc_user_item_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], Affiliation, Role, - _Jid, Nick) -> - decode_muc_user_item_attrs(__TopXMLNS, _attrs, - Affiliation, Role, _val, Nick); -decode_muc_user_item_attrs(__TopXMLNS, - [{<<"nick">>, _val} | _attrs], Affiliation, Role, - Jid, _Nick) -> - decode_muc_user_item_attrs(__TopXMLNS, _attrs, - Affiliation, Role, Jid, _val); -decode_muc_user_item_attrs(__TopXMLNS, [_ | _attrs], - Affiliation, Role, Jid, Nick) -> - decode_muc_user_item_attrs(__TopXMLNS, _attrs, - Affiliation, Role, Jid, Nick); -decode_muc_user_item_attrs(__TopXMLNS, [], Affiliation, - Role, Jid, Nick) -> - {decode_muc_user_item_attr_affiliation(__TopXMLNS, - Affiliation), - decode_muc_user_item_attr_role(__TopXMLNS, Role), - decode_muc_user_item_attr_jid(__TopXMLNS, Jid), - decode_muc_user_item_attr_nick(__TopXMLNS, Nick)}. - -encode_muc_user_item({muc_item, Actor, Continue, Reason, - Affiliation, Role, Jid, Nick}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/muc#user">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_muc_user_item_$actor'(Actor, - __NewTopXMLNS, - 'encode_muc_user_item_$continue'(Continue, - __NewTopXMLNS, - 'encode_muc_user_item_$reason'(Reason, - __NewTopXMLNS, - [])))), - _attrs = encode_muc_user_item_attr_nick(Nick, - encode_muc_user_item_attr_jid(Jid, - encode_muc_user_item_attr_role(Role, - encode_muc_user_item_attr_affiliation(Affiliation, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))))), - {xmlel, <<"item">>, _attrs, _els}. - -'encode_muc_user_item_$actor'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_muc_user_item_$actor'(Actor, __TopXMLNS, - _acc) -> - [encode_muc_user_actor(Actor, __TopXMLNS) | _acc]. - -'encode_muc_user_item_$continue'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_muc_user_item_$continue'(Continue, __TopXMLNS, - _acc) -> - [encode_muc_user_continue(Continue, __TopXMLNS) | _acc]. - -'encode_muc_user_item_$reason'(<<>>, __TopXMLNS, - _acc) -> - _acc; -'encode_muc_user_item_$reason'(Reason, __TopXMLNS, - _acc) -> - [encode_muc_reason(Reason, __TopXMLNS) | _acc]. - -decode_muc_user_item_attr_affiliation(__TopXMLNS, - undefined) -> - undefined; -decode_muc_user_item_attr_affiliation(__TopXMLNS, - _val) -> - case catch dec_enum(_val, - [admin, member, none, outcast, owner]) - of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"affiliation">>, <<"item">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_muc_user_item_attr_affiliation(undefined, - _acc) -> - _acc; -encode_muc_user_item_attr_affiliation(_val, _acc) -> - [{<<"affiliation">>, enc_enum(_val)} | _acc]. - -decode_muc_user_item_attr_role(__TopXMLNS, undefined) -> - undefined; -decode_muc_user_item_attr_role(__TopXMLNS, _val) -> - case catch dec_enum(_val, - [moderator, none, participant, visitor]) - of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"role">>, <<"item">>, __TopXMLNS}}); - _res -> _res - end. - -encode_muc_user_item_attr_role(undefined, _acc) -> _acc; -encode_muc_user_item_attr_role(_val, _acc) -> - [{<<"role">>, enc_enum(_val)} | _acc]. - -decode_muc_user_item_attr_jid(__TopXMLNS, undefined) -> - undefined; -decode_muc_user_item_attr_jid(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"jid">>, <<"item">>, __TopXMLNS}}); - _res -> _res - end. - -encode_muc_user_item_attr_jid(undefined, _acc) -> _acc; -encode_muc_user_item_attr_jid(_val, _acc) -> - [{<<"jid">>, enc_jid(_val)} | _acc]. - -decode_muc_user_item_attr_nick(__TopXMLNS, undefined) -> - <<>>; -decode_muc_user_item_attr_nick(__TopXMLNS, _val) -> - _val. - -encode_muc_user_item_attr_nick(<<>>, _acc) -> _acc; -encode_muc_user_item_attr_nick(_val, _acc) -> - [{<<"nick">>, _val} | _acc]. - -decode_muc_user_status(__TopXMLNS, __IgnoreEls, - {xmlel, <<"status">>, _attrs, _els}) -> - Code = decode_muc_user_status_attrs(__TopXMLNS, _attrs, - undefined), - Code. - -decode_muc_user_status_attrs(__TopXMLNS, - [{<<"code">>, _val} | _attrs], _Code) -> - decode_muc_user_status_attrs(__TopXMLNS, _attrs, _val); -decode_muc_user_status_attrs(__TopXMLNS, [_ | _attrs], - Code) -> - decode_muc_user_status_attrs(__TopXMLNS, _attrs, Code); -decode_muc_user_status_attrs(__TopXMLNS, [], Code) -> - decode_muc_user_status_attr_code(__TopXMLNS, Code). - -encode_muc_user_status(Code, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/muc#user">>, - [], __TopXMLNS), - _els = [], - _attrs = encode_muc_user_status_attr_code(Code, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"status">>, _attrs, _els}. - -decode_muc_user_status_attr_code(__TopXMLNS, - undefined) -> - undefined; -decode_muc_user_status_attr_code(__TopXMLNS, _val) -> - case catch dec_int(_val, 100, 999) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"code">>, <<"status">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_muc_user_status_attr_code(undefined, _acc) -> - _acc; -encode_muc_user_status_attr_code(_val, _acc) -> - [{<<"code">>, enc_int(_val)} | _acc]. - -decode_muc_user_continue(__TopXMLNS, __IgnoreEls, - {xmlel, <<"continue">>, _attrs, _els}) -> - Thread = decode_muc_user_continue_attrs(__TopXMLNS, - _attrs, undefined), - Thread. - -decode_muc_user_continue_attrs(__TopXMLNS, - [{<<"thread">>, _val} | _attrs], _Thread) -> - decode_muc_user_continue_attrs(__TopXMLNS, _attrs, - _val); -decode_muc_user_continue_attrs(__TopXMLNS, [_ | _attrs], - Thread) -> - decode_muc_user_continue_attrs(__TopXMLNS, _attrs, - Thread); -decode_muc_user_continue_attrs(__TopXMLNS, [], - Thread) -> - decode_muc_user_continue_attr_thread(__TopXMLNS, - Thread). - -encode_muc_user_continue(Thread, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/muc#user">>, - [], __TopXMLNS), - _els = [], - _attrs = encode_muc_user_continue_attr_thread(Thread, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"continue">>, _attrs, _els}. - -decode_muc_user_continue_attr_thread(__TopXMLNS, - undefined) -> - <<>>; -decode_muc_user_continue_attr_thread(__TopXMLNS, - _val) -> - _val. - -encode_muc_user_continue_attr_thread(<<>>, _acc) -> - _acc; -encode_muc_user_continue_attr_thread(_val, _acc) -> - [{<<"thread">>, _val} | _acc]. - -decode_muc_user_actor(__TopXMLNS, __IgnoreEls, - {xmlel, <<"actor">>, _attrs, _els}) -> - {Jid, Nick} = decode_muc_user_actor_attrs(__TopXMLNS, - _attrs, undefined, undefined), - {muc_actor, Jid, Nick}. - -decode_muc_user_actor_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], _Jid, Nick) -> - decode_muc_user_actor_attrs(__TopXMLNS, _attrs, _val, - Nick); -decode_muc_user_actor_attrs(__TopXMLNS, - [{<<"nick">>, _val} | _attrs], Jid, _Nick) -> - decode_muc_user_actor_attrs(__TopXMLNS, _attrs, Jid, - _val); -decode_muc_user_actor_attrs(__TopXMLNS, [_ | _attrs], - Jid, Nick) -> - decode_muc_user_actor_attrs(__TopXMLNS, _attrs, Jid, - Nick); -decode_muc_user_actor_attrs(__TopXMLNS, [], Jid, - Nick) -> - {decode_muc_user_actor_attr_jid(__TopXMLNS, Jid), - decode_muc_user_actor_attr_nick(__TopXMLNS, Nick)}. - -encode_muc_user_actor({muc_actor, Jid, Nick}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/muc#user">>, - [], __TopXMLNS), - _els = [], - _attrs = encode_muc_user_actor_attr_nick(Nick, - encode_muc_user_actor_attr_jid(Jid, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))), - {xmlel, <<"actor">>, _attrs, _els}. - -decode_muc_user_actor_attr_jid(__TopXMLNS, undefined) -> - undefined; -decode_muc_user_actor_attr_jid(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"jid">>, <<"actor">>, __TopXMLNS}}); - _res -> _res - end. - -encode_muc_user_actor_attr_jid(undefined, _acc) -> _acc; -encode_muc_user_actor_attr_jid(_val, _acc) -> - [{<<"jid">>, enc_jid(_val)} | _acc]. - -decode_muc_user_actor_attr_nick(__TopXMLNS, - undefined) -> - <<>>; -decode_muc_user_actor_attr_nick(__TopXMLNS, _val) -> - _val. - -encode_muc_user_actor_attr_nick(<<>>, _acc) -> _acc; -encode_muc_user_actor_attr_nick(_val, _acc) -> - [{<<"nick">>, _val} | _acc]. - -decode_muc_user_invite(__TopXMLNS, __IgnoreEls, - {xmlel, <<"invite">>, _attrs, _els}) -> - {Continue, Reason} = - decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, - _els, undefined, <<>>), - {To, From} = decode_muc_user_invite_attrs(__TopXMLNS, - _attrs, undefined, undefined), - {muc_invite, Reason, From, To, Continue}. - -decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, [], - Continue, Reason) -> - {Continue, Reason}; -decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"reason">>, _attrs, _} = _el | _els], - Continue, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, - _els, Continue, - decode_muc_reason(__TopXMLNS, __IgnoreEls, - _el)); - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, - _els, Continue, - decode_muc_reason(<<"http://jabber.org/protocol/muc#user">>, - __IgnoreEls, _el)); - <<"http://jabber.org/protocol/muc#admin">> -> - decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, - _els, Continue, - decode_muc_reason(<<"http://jabber.org/protocol/muc#admin">>, - __IgnoreEls, _el)); - <<"http://jabber.org/protocol/muc#owner">> -> - decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, - _els, Continue, - decode_muc_reason(<<"http://jabber.org/protocol/muc#owner">>, - __IgnoreEls, _el)); - _ -> - decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, - _els, Continue, Reason) - end; -decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"continue">>, _attrs, _} = _el | _els], - Continue, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, - _els, - decode_muc_user_continue(__TopXMLNS, - __IgnoreEls, _el), - Reason); - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, - _els, - decode_muc_user_continue(<<"http://jabber.org/protocol/muc#user">>, - __IgnoreEls, _el), - Reason); - _ -> - decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, - _els, Continue, Reason) - end; -decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Continue, Reason) -> - decode_muc_user_invite_els(__TopXMLNS, __IgnoreEls, - _els, Continue, Reason). - -decode_muc_user_invite_attrs(__TopXMLNS, - [{<<"to">>, _val} | _attrs], _To, From) -> - decode_muc_user_invite_attrs(__TopXMLNS, _attrs, _val, - From); -decode_muc_user_invite_attrs(__TopXMLNS, - [{<<"from">>, _val} | _attrs], To, _From) -> - decode_muc_user_invite_attrs(__TopXMLNS, _attrs, To, - _val); -decode_muc_user_invite_attrs(__TopXMLNS, [_ | _attrs], - To, From) -> - decode_muc_user_invite_attrs(__TopXMLNS, _attrs, To, - From); -decode_muc_user_invite_attrs(__TopXMLNS, [], To, - From) -> - {decode_muc_user_invite_attr_to(__TopXMLNS, To), - decode_muc_user_invite_attr_from(__TopXMLNS, From)}. - -encode_muc_user_invite({muc_invite, Reason, From, To, - Continue}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/muc#user">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_muc_user_invite_$continue'(Continue, - __NewTopXMLNS, - 'encode_muc_user_invite_$reason'(Reason, - __NewTopXMLNS, - []))), - _attrs = encode_muc_user_invite_attr_from(From, - encode_muc_user_invite_attr_to(To, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))), - {xmlel, <<"invite">>, _attrs, _els}. - -'encode_muc_user_invite_$continue'(undefined, - __TopXMLNS, _acc) -> - _acc; -'encode_muc_user_invite_$continue'(Continue, __TopXMLNS, - _acc) -> - [encode_muc_user_continue(Continue, __TopXMLNS) | _acc]. - -'encode_muc_user_invite_$reason'(<<>>, __TopXMLNS, - _acc) -> - _acc; -'encode_muc_user_invite_$reason'(Reason, __TopXMLNS, - _acc) -> - [encode_muc_reason(Reason, __TopXMLNS) | _acc]. - -decode_muc_user_invite_attr_to(__TopXMLNS, undefined) -> - undefined; -decode_muc_user_invite_attr_to(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"to">>, <<"invite">>, __TopXMLNS}}); - _res -> _res - end. - -encode_muc_user_invite_attr_to(undefined, _acc) -> _acc; -encode_muc_user_invite_attr_to(_val, _acc) -> - [{<<"to">>, enc_jid(_val)} | _acc]. - -decode_muc_user_invite_attr_from(__TopXMLNS, - undefined) -> - undefined; -decode_muc_user_invite_attr_from(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"from">>, <<"invite">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_muc_user_invite_attr_from(undefined, _acc) -> - _acc; -encode_muc_user_invite_attr_from(_val, _acc) -> - [{<<"from">>, enc_jid(_val)} | _acc]. - -decode_muc_destroy(__TopXMLNS, __IgnoreEls, - {xmlel, <<"destroy">>, _attrs, _els}) -> - {Password, Reason} = decode_muc_destroy_els(__TopXMLNS, - __IgnoreEls, _els, undefined, - <<>>), - {Jid, Xmlns} = decode_muc_destroy_attrs(__TopXMLNS, - _attrs, undefined, undefined), - {muc_destroy, Xmlns, Jid, Reason, Password}. - -decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, [], - Password, Reason) -> - {Password, Reason}; -decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"reason">>, _attrs, _} = _el | _els], - Password, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/muc#user">>; - __TopXMLNS == - <<"http://jabber.org/protocol/muc#owner">> -> - decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, _els, - Password, - decode_muc_reason(__TopXMLNS, __IgnoreEls, - _el)); - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, _els, - Password, - decode_muc_reason(<<"http://jabber.org/protocol/muc#user">>, - __IgnoreEls, _el)); - <<"http://jabber.org/protocol/muc#admin">> -> - decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, _els, - Password, - decode_muc_reason(<<"http://jabber.org/protocol/muc#admin">>, - __IgnoreEls, _el)); - <<"http://jabber.org/protocol/muc#owner">> -> - decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, _els, - Password, - decode_muc_reason(<<"http://jabber.org/protocol/muc#owner">>, - __IgnoreEls, _el)); - _ -> - decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, _els, - Password, Reason) - end; -decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"password">>, _attrs, _} = _el | _els], - Password, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/muc#user">>; - __TopXMLNS == - <<"http://jabber.org/protocol/muc#owner">> -> - decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, _els, - decode_muc_password(__TopXMLNS, __IgnoreEls, - _el), - Reason); - <<"http://jabber.org/protocol/muc#owner">> -> - decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, _els, - decode_muc_password(<<"http://jabber.org/protocol/muc#owner">>, - __IgnoreEls, _el), - Reason); - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, _els, - decode_muc_password(<<"http://jabber.org/protocol/muc#user">>, - __IgnoreEls, _el), - Reason); - <<"http://jabber.org/protocol/muc">> -> - decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, _els, - decode_muc_password(<<"http://jabber.org/protocol/muc">>, - __IgnoreEls, _el), - Reason); - _ -> - decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, _els, - Password, Reason) - end; -decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Password, Reason) -> - decode_muc_destroy_els(__TopXMLNS, __IgnoreEls, _els, - Password, Reason). - -decode_muc_destroy_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], _Jid, Xmlns) -> - decode_muc_destroy_attrs(__TopXMLNS, _attrs, _val, - Xmlns); -decode_muc_destroy_attrs(__TopXMLNS, - [{<<"xmlns">>, _val} | _attrs], Jid, _Xmlns) -> - decode_muc_destroy_attrs(__TopXMLNS, _attrs, Jid, _val); -decode_muc_destroy_attrs(__TopXMLNS, [_ | _attrs], Jid, - Xmlns) -> - decode_muc_destroy_attrs(__TopXMLNS, _attrs, Jid, - Xmlns); -decode_muc_destroy_attrs(__TopXMLNS, [], Jid, Xmlns) -> - {decode_muc_destroy_attr_jid(__TopXMLNS, Jid), - decode_muc_destroy_attr_xmlns(__TopXMLNS, Xmlns)}. - -encode_muc_destroy({muc_destroy, Xmlns, Jid, Reason, - Password}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(Xmlns, - [<<"http://jabber.org/protocol/muc#user">>, - <<"http://jabber.org/protocol/muc#owner">>], - __TopXMLNS), - _els = - lists:reverse('encode_muc_destroy_$password'(Password, - __NewTopXMLNS, - 'encode_muc_destroy_$reason'(Reason, - __NewTopXMLNS, - []))), - _attrs = encode_muc_destroy_attr_jid(Jid, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"destroy">>, _attrs, _els}. - -'encode_muc_destroy_$password'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_muc_destroy_$password'(Password, __TopXMLNS, - _acc) -> - [encode_muc_password(Password, __TopXMLNS) | _acc]. - -'encode_muc_destroy_$reason'(<<>>, __TopXMLNS, _acc) -> - _acc; -'encode_muc_destroy_$reason'(Reason, __TopXMLNS, - _acc) -> - [encode_muc_reason(Reason, __TopXMLNS) | _acc]. - -decode_muc_destroy_attr_jid(__TopXMLNS, undefined) -> - undefined; -decode_muc_destroy_attr_jid(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"jid">>, <<"destroy">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_muc_destroy_attr_jid(undefined, _acc) -> _acc; -encode_muc_destroy_attr_jid(_val, _acc) -> - [{<<"jid">>, enc_jid(_val)} | _acc]. - -decode_muc_destroy_attr_xmlns(__TopXMLNS, undefined) -> - <<>>; -decode_muc_destroy_attr_xmlns(__TopXMLNS, _val) -> _val. - -decode_muc_user_decline(__TopXMLNS, __IgnoreEls, - {xmlel, <<"decline">>, _attrs, _els}) -> - Reason = decode_muc_user_decline_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - {To, From} = decode_muc_user_decline_attrs(__TopXMLNS, - _attrs, undefined, undefined), - {muc_decline, Reason, From, To}. - -decode_muc_user_decline_els(__TopXMLNS, __IgnoreEls, [], - Reason) -> - Reason; -decode_muc_user_decline_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"reason">>, _attrs, _} = _el | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_decline_els(__TopXMLNS, __IgnoreEls, - _els, - decode_muc_reason(__TopXMLNS, __IgnoreEls, - _el)); - <<"http://jabber.org/protocol/muc#user">> -> - decode_muc_user_decline_els(__TopXMLNS, __IgnoreEls, - _els, - decode_muc_reason(<<"http://jabber.org/protocol/muc#user">>, - __IgnoreEls, _el)); - <<"http://jabber.org/protocol/muc#admin">> -> - decode_muc_user_decline_els(__TopXMLNS, __IgnoreEls, - _els, - decode_muc_reason(<<"http://jabber.org/protocol/muc#admin">>, - __IgnoreEls, _el)); - <<"http://jabber.org/protocol/muc#owner">> -> - decode_muc_user_decline_els(__TopXMLNS, __IgnoreEls, - _els, - decode_muc_reason(<<"http://jabber.org/protocol/muc#owner">>, - __IgnoreEls, _el)); - _ -> - decode_muc_user_decline_els(__TopXMLNS, __IgnoreEls, - _els, Reason) - end; -decode_muc_user_decline_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Reason) -> - decode_muc_user_decline_els(__TopXMLNS, __IgnoreEls, - _els, Reason). - -decode_muc_user_decline_attrs(__TopXMLNS, - [{<<"to">>, _val} | _attrs], _To, From) -> - decode_muc_user_decline_attrs(__TopXMLNS, _attrs, _val, - From); -decode_muc_user_decline_attrs(__TopXMLNS, - [{<<"from">>, _val} | _attrs], To, _From) -> - decode_muc_user_decline_attrs(__TopXMLNS, _attrs, To, - _val); -decode_muc_user_decline_attrs(__TopXMLNS, [_ | _attrs], - To, From) -> - decode_muc_user_decline_attrs(__TopXMLNS, _attrs, To, - From); -decode_muc_user_decline_attrs(__TopXMLNS, [], To, - From) -> - {decode_muc_user_decline_attr_to(__TopXMLNS, To), - decode_muc_user_decline_attr_from(__TopXMLNS, From)}. - -encode_muc_user_decline({muc_decline, Reason, From, To}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/muc#user">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_muc_user_decline_$reason'(Reason, - __NewTopXMLNS, [])), - _attrs = encode_muc_user_decline_attr_from(From, - encode_muc_user_decline_attr_to(To, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))), - {xmlel, <<"decline">>, _attrs, _els}. - -'encode_muc_user_decline_$reason'(<<>>, __TopXMLNS, - _acc) -> - _acc; -'encode_muc_user_decline_$reason'(Reason, __TopXMLNS, - _acc) -> - [encode_muc_reason(Reason, __TopXMLNS) | _acc]. - -decode_muc_user_decline_attr_to(__TopXMLNS, - undefined) -> - undefined; -decode_muc_user_decline_attr_to(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"to">>, <<"decline">>, __TopXMLNS}}); - _res -> _res - end. - -encode_muc_user_decline_attr_to(undefined, _acc) -> - _acc; -encode_muc_user_decline_attr_to(_val, _acc) -> - [{<<"to">>, enc_jid(_val)} | _acc]. - -decode_muc_user_decline_attr_from(__TopXMLNS, - undefined) -> - undefined; -decode_muc_user_decline_attr_from(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"from">>, <<"decline">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_muc_user_decline_attr_from(undefined, _acc) -> - _acc; -encode_muc_user_decline_attr_from(_val, _acc) -> - [{<<"from">>, enc_jid(_val)} | _acc]. - -decode_muc_reason(__TopXMLNS, __IgnoreEls, - {xmlel, <<"reason">>, _attrs, _els}) -> - Cdata = decode_muc_reason_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_muc_reason_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_muc_reason_cdata(__TopXMLNS, Cdata); -decode_muc_reason_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_muc_reason_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_muc_reason_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_muc_reason_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_muc_reason(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"http://jabber.org/protocol/muc#user">>, - <<"http://jabber.org/protocol/muc#admin">>, - <<"http://jabber.org/protocol/muc#owner">>], - __TopXMLNS), - _els = encode_muc_reason_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"reason">>, _attrs, _els}. - -decode_muc_reason_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_muc_reason_cdata(__TopXMLNS, _val) -> _val. - -encode_muc_reason_cdata(<<>>, _acc) -> _acc; -encode_muc_reason_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_muc_history(__TopXMLNS, __IgnoreEls, - {xmlel, <<"history">>, _attrs, _els}) -> - {Maxchars, Maxstanzas, Seconds, Since} = - decode_muc_history_attrs(__TopXMLNS, _attrs, undefined, - undefined, undefined, undefined), - {muc_history, Maxchars, Maxstanzas, Seconds, Since}. - -decode_muc_history_attrs(__TopXMLNS, - [{<<"maxchars">>, _val} | _attrs], _Maxchars, - Maxstanzas, Seconds, Since) -> - decode_muc_history_attrs(__TopXMLNS, _attrs, _val, - Maxstanzas, Seconds, Since); -decode_muc_history_attrs(__TopXMLNS, - [{<<"maxstanzas">>, _val} | _attrs], Maxchars, - _Maxstanzas, Seconds, Since) -> - decode_muc_history_attrs(__TopXMLNS, _attrs, Maxchars, - _val, Seconds, Since); -decode_muc_history_attrs(__TopXMLNS, - [{<<"seconds">>, _val} | _attrs], Maxchars, Maxstanzas, - _Seconds, Since) -> - decode_muc_history_attrs(__TopXMLNS, _attrs, Maxchars, - Maxstanzas, _val, Since); -decode_muc_history_attrs(__TopXMLNS, - [{<<"since">>, _val} | _attrs], Maxchars, Maxstanzas, - Seconds, _Since) -> - decode_muc_history_attrs(__TopXMLNS, _attrs, Maxchars, - Maxstanzas, Seconds, _val); -decode_muc_history_attrs(__TopXMLNS, [_ | _attrs], - Maxchars, Maxstanzas, Seconds, Since) -> - decode_muc_history_attrs(__TopXMLNS, _attrs, Maxchars, - Maxstanzas, Seconds, Since); -decode_muc_history_attrs(__TopXMLNS, [], Maxchars, - Maxstanzas, Seconds, Since) -> - {decode_muc_history_attr_maxchars(__TopXMLNS, Maxchars), - decode_muc_history_attr_maxstanzas(__TopXMLNS, - Maxstanzas), - decode_muc_history_attr_seconds(__TopXMLNS, Seconds), - decode_muc_history_attr_since(__TopXMLNS, Since)}. - -encode_muc_history({muc_history, Maxchars, Maxstanzas, - Seconds, Since}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/muc">>, - [], __TopXMLNS), - _els = [], - _attrs = encode_muc_history_attr_since(Since, - encode_muc_history_attr_seconds(Seconds, - encode_muc_history_attr_maxstanzas(Maxstanzas, - encode_muc_history_attr_maxchars(Maxchars, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))))), - {xmlel, <<"history">>, _attrs, _els}. - -decode_muc_history_attr_maxchars(__TopXMLNS, - undefined) -> - undefined; -decode_muc_history_attr_maxchars(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, infinity) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"maxchars">>, <<"history">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_muc_history_attr_maxchars(undefined, _acc) -> - _acc; -encode_muc_history_attr_maxchars(_val, _acc) -> - [{<<"maxchars">>, enc_int(_val)} | _acc]. - -decode_muc_history_attr_maxstanzas(__TopXMLNS, - undefined) -> - undefined; -decode_muc_history_attr_maxstanzas(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, infinity) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"maxstanzas">>, <<"history">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_muc_history_attr_maxstanzas(undefined, _acc) -> - _acc; -encode_muc_history_attr_maxstanzas(_val, _acc) -> - [{<<"maxstanzas">>, enc_int(_val)} | _acc]. - -decode_muc_history_attr_seconds(__TopXMLNS, - undefined) -> - undefined; -decode_muc_history_attr_seconds(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, infinity) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"seconds">>, <<"history">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_muc_history_attr_seconds(undefined, _acc) -> - _acc; -encode_muc_history_attr_seconds(_val, _acc) -> - [{<<"seconds">>, enc_int(_val)} | _acc]. - -decode_muc_history_attr_since(__TopXMLNS, undefined) -> - undefined; -decode_muc_history_attr_since(__TopXMLNS, _val) -> - case catch dec_utc(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"since">>, <<"history">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_muc_history_attr_since(undefined, _acc) -> _acc; -encode_muc_history_attr_since(_val, _acc) -> - [{<<"since">>, enc_utc(_val)} | _acc]. - -decode_bytestreams(__TopXMLNS, __IgnoreEls, - {xmlel, <<"query">>, _attrs, _els}) -> - {Hosts, Used, Activate} = - decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, - [], undefined, undefined), - {Dstaddr, Sid, Mode} = - decode_bytestreams_attrs(__TopXMLNS, _attrs, undefined, - undefined, undefined), - {bytestreams, Hosts, Used, Activate, Dstaddr, Mode, - Sid}. - -decode_bytestreams_els(__TopXMLNS, __IgnoreEls, [], - Hosts, Used, Activate) -> - {lists:reverse(Hosts), Used, Activate}; -decode_bytestreams_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"streamhost">>, _attrs, _} = _el | _els], - Hosts, Used, Activate) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/bytestreams">> -> - decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, - [decode_bytestreams_streamhost(__TopXMLNS, - __IgnoreEls, - _el) - | Hosts], - Used, Activate); - <<"http://jabber.org/protocol/bytestreams">> -> - decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, - [decode_bytestreams_streamhost(<<"http://jabber.org/protocol/bytestreams">>, - __IgnoreEls, - _el) - | Hosts], - Used, Activate); - _ -> - decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, - Hosts, Used, Activate) - end; -decode_bytestreams_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"streamhost-used">>, _attrs, _} = _el - | _els], - Hosts, Used, Activate) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/bytestreams">> -> - decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, - Hosts, - decode_bytestreams_streamhost_used(__TopXMLNS, - __IgnoreEls, - _el), - Activate); - <<"http://jabber.org/protocol/bytestreams">> -> - decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, - Hosts, - decode_bytestreams_streamhost_used(<<"http://jabber.org/protocol/bytestreams">>, - __IgnoreEls, - _el), - Activate); - _ -> - decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, - Hosts, Used, Activate) - end; -decode_bytestreams_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"activate">>, _attrs, _} = _el | _els], - Hosts, Used, Activate) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/bytestreams">> -> - decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, - Hosts, Used, - decode_bytestreams_activate(__TopXMLNS, - __IgnoreEls, _el)); - <<"http://jabber.org/protocol/bytestreams">> -> - decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, - Hosts, Used, - decode_bytestreams_activate(<<"http://jabber.org/protocol/bytestreams">>, - __IgnoreEls, _el)); - _ -> - decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, - Hosts, Used, Activate) - end; -decode_bytestreams_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Hosts, Used, Activate) -> - decode_bytestreams_els(__TopXMLNS, __IgnoreEls, _els, - Hosts, Used, Activate). - -decode_bytestreams_attrs(__TopXMLNS, - [{<<"dstaddr">>, _val} | _attrs], _Dstaddr, Sid, - Mode) -> - decode_bytestreams_attrs(__TopXMLNS, _attrs, _val, Sid, - Mode); -decode_bytestreams_attrs(__TopXMLNS, - [{<<"sid">>, _val} | _attrs], Dstaddr, _Sid, Mode) -> - decode_bytestreams_attrs(__TopXMLNS, _attrs, Dstaddr, - _val, Mode); -decode_bytestreams_attrs(__TopXMLNS, - [{<<"mode">>, _val} | _attrs], Dstaddr, Sid, _Mode) -> - decode_bytestreams_attrs(__TopXMLNS, _attrs, Dstaddr, - Sid, _val); -decode_bytestreams_attrs(__TopXMLNS, [_ | _attrs], - Dstaddr, Sid, Mode) -> - decode_bytestreams_attrs(__TopXMLNS, _attrs, Dstaddr, - Sid, Mode); -decode_bytestreams_attrs(__TopXMLNS, [], Dstaddr, Sid, - Mode) -> - {decode_bytestreams_attr_dstaddr(__TopXMLNS, Dstaddr), - decode_bytestreams_attr_sid(__TopXMLNS, Sid), - decode_bytestreams_attr_mode(__TopXMLNS, Mode)}. - -encode_bytestreams({bytestreams, Hosts, Used, Activate, - Dstaddr, Mode, Sid}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/bytestreams">>, - [], __TopXMLNS), - _els = lists:reverse('encode_bytestreams_$hosts'(Hosts, - __NewTopXMLNS, - 'encode_bytestreams_$used'(Used, - __NewTopXMLNS, - 'encode_bytestreams_$activate'(Activate, - __NewTopXMLNS, - [])))), - _attrs = encode_bytestreams_attr_mode(Mode, - encode_bytestreams_attr_sid(Sid, - encode_bytestreams_attr_dstaddr(Dstaddr, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)))), - {xmlel, <<"query">>, _attrs, _els}. - -'encode_bytestreams_$hosts'([], __TopXMLNS, _acc) -> - _acc; -'encode_bytestreams_$hosts'([Hosts | _els], __TopXMLNS, - _acc) -> - 'encode_bytestreams_$hosts'(_els, __TopXMLNS, - [encode_bytestreams_streamhost(Hosts, - __TopXMLNS) - | _acc]). - -'encode_bytestreams_$used'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_bytestreams_$used'(Used, __TopXMLNS, _acc) -> - [encode_bytestreams_streamhost_used(Used, __TopXMLNS) - | _acc]. - -'encode_bytestreams_$activate'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_bytestreams_$activate'(Activate, __TopXMLNS, - _acc) -> - [encode_bytestreams_activate(Activate, __TopXMLNS) - | _acc]. - -decode_bytestreams_attr_dstaddr(__TopXMLNS, - undefined) -> - <<>>; -decode_bytestreams_attr_dstaddr(__TopXMLNS, _val) -> - _val. - -encode_bytestreams_attr_dstaddr(<<>>, _acc) -> _acc; -encode_bytestreams_attr_dstaddr(_val, _acc) -> - [{<<"dstaddr">>, _val} | _acc]. - -decode_bytestreams_attr_sid(__TopXMLNS, undefined) -> - <<>>; -decode_bytestreams_attr_sid(__TopXMLNS, _val) -> _val. - -encode_bytestreams_attr_sid(<<>>, _acc) -> _acc; -encode_bytestreams_attr_sid(_val, _acc) -> - [{<<"sid">>, _val} | _acc]. - -decode_bytestreams_attr_mode(__TopXMLNS, undefined) -> - tcp; -decode_bytestreams_attr_mode(__TopXMLNS, _val) -> - case catch dec_enum(_val, [tcp, udp]) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"mode">>, <<"query">>, __TopXMLNS}}); - _res -> _res - end. - -encode_bytestreams_attr_mode(tcp, _acc) -> _acc; -encode_bytestreams_attr_mode(_val, _acc) -> - [{<<"mode">>, enc_enum(_val)} | _acc]. - -decode_bytestreams_activate(__TopXMLNS, __IgnoreEls, - {xmlel, <<"activate">>, _attrs, _els}) -> - Cdata = decode_bytestreams_activate_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_bytestreams_activate_els(__TopXMLNS, __IgnoreEls, - [], Cdata) -> - decode_bytestreams_activate_cdata(__TopXMLNS, Cdata); -decode_bytestreams_activate_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_bytestreams_activate_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_bytestreams_activate_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_bytestreams_activate_els(__TopXMLNS, __IgnoreEls, - _els, Cdata). - -encode_bytestreams_activate(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/bytestreams">>, - [], __TopXMLNS), - _els = encode_bytestreams_activate_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"activate">>, _attrs, _els}. - -decode_bytestreams_activate_cdata(__TopXMLNS, <<>>) -> - undefined; -decode_bytestreams_activate_cdata(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_cdata_value, <<>>, <<"activate">>, __TopXMLNS}}); - _res -> _res - end. - -encode_bytestreams_activate_cdata(undefined, _acc) -> - _acc; -encode_bytestreams_activate_cdata(_val, _acc) -> - [{xmlcdata, enc_jid(_val)} | _acc]. - -decode_bytestreams_streamhost_used(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"streamhost-used">>, _attrs, - _els}) -> - Jid = - decode_bytestreams_streamhost_used_attrs(__TopXMLNS, - _attrs, undefined), - Jid. - -decode_bytestreams_streamhost_used_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], _Jid) -> - decode_bytestreams_streamhost_used_attrs(__TopXMLNS, - _attrs, _val); -decode_bytestreams_streamhost_used_attrs(__TopXMLNS, - [_ | _attrs], Jid) -> - decode_bytestreams_streamhost_used_attrs(__TopXMLNS, - _attrs, Jid); -decode_bytestreams_streamhost_used_attrs(__TopXMLNS, [], - Jid) -> - decode_bytestreams_streamhost_used_attr_jid(__TopXMLNS, - Jid). - -encode_bytestreams_streamhost_used(Jid, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/bytestreams">>, - [], __TopXMLNS), - _els = [], - _attrs = - encode_bytestreams_streamhost_used_attr_jid(Jid, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"streamhost-used">>, _attrs, _els}. - -decode_bytestreams_streamhost_used_attr_jid(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"jid">>, <<"streamhost-used">>, - __TopXMLNS}}); -decode_bytestreams_streamhost_used_attr_jid(__TopXMLNS, - _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"jid">>, <<"streamhost-used">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_bytestreams_streamhost_used_attr_jid(_val, - _acc) -> - [{<<"jid">>, enc_jid(_val)} | _acc]. - -decode_bytestreams_streamhost(__TopXMLNS, __IgnoreEls, - {xmlel, <<"streamhost">>, _attrs, _els}) -> - {Jid, Host, Port} = - decode_bytestreams_streamhost_attrs(__TopXMLNS, _attrs, - undefined, undefined, undefined), - {streamhost, Jid, Host, Port}. - -decode_bytestreams_streamhost_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], _Jid, Host, - Port) -> - decode_bytestreams_streamhost_attrs(__TopXMLNS, _attrs, - _val, Host, Port); -decode_bytestreams_streamhost_attrs(__TopXMLNS, - [{<<"host">>, _val} | _attrs], Jid, _Host, - Port) -> - decode_bytestreams_streamhost_attrs(__TopXMLNS, _attrs, - Jid, _val, Port); -decode_bytestreams_streamhost_attrs(__TopXMLNS, - [{<<"port">>, _val} | _attrs], Jid, Host, - _Port) -> - decode_bytestreams_streamhost_attrs(__TopXMLNS, _attrs, - Jid, Host, _val); -decode_bytestreams_streamhost_attrs(__TopXMLNS, - [_ | _attrs], Jid, Host, Port) -> - decode_bytestreams_streamhost_attrs(__TopXMLNS, _attrs, - Jid, Host, Port); -decode_bytestreams_streamhost_attrs(__TopXMLNS, [], Jid, - Host, Port) -> - {decode_bytestreams_streamhost_attr_jid(__TopXMLNS, - Jid), - decode_bytestreams_streamhost_attr_host(__TopXMLNS, - Host), - decode_bytestreams_streamhost_attr_port(__TopXMLNS, - Port)}. - -encode_bytestreams_streamhost({streamhost, Jid, Host, - Port}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/bytestreams">>, - [], __TopXMLNS), - _els = [], - _attrs = encode_bytestreams_streamhost_attr_port(Port, - encode_bytestreams_streamhost_attr_host(Host, - encode_bytestreams_streamhost_attr_jid(Jid, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)))), - {xmlel, <<"streamhost">>, _attrs, _els}. - -decode_bytestreams_streamhost_attr_jid(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"jid">>, <<"streamhost">>, - __TopXMLNS}}); -decode_bytestreams_streamhost_attr_jid(__TopXMLNS, - _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"jid">>, <<"streamhost">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_bytestreams_streamhost_attr_jid(_val, _acc) -> - [{<<"jid">>, enc_jid(_val)} | _acc]. - -decode_bytestreams_streamhost_attr_host(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"host">>, <<"streamhost">>, - __TopXMLNS}}); -decode_bytestreams_streamhost_attr_host(__TopXMLNS, - _val) -> - _val. - -encode_bytestreams_streamhost_attr_host(_val, _acc) -> - [{<<"host">>, _val} | _acc]. - -decode_bytestreams_streamhost_attr_port(__TopXMLNS, - undefined) -> - 1080; -decode_bytestreams_streamhost_attr_port(__TopXMLNS, - _val) -> - case catch dec_int(_val, 0, 65535) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"port">>, <<"streamhost">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_bytestreams_streamhost_attr_port(1080, _acc) -> - _acc; -encode_bytestreams_streamhost_attr_port(_val, _acc) -> - [{<<"port">>, enc_int(_val)} | _acc]. - -decode_delay(__TopXMLNS, __IgnoreEls, - {xmlel, <<"delay">>, _attrs, _els}) -> - Desc = decode_delay_els(__TopXMLNS, __IgnoreEls, _els, - <<>>), - {Stamp, From} = decode_delay_attrs(__TopXMLNS, _attrs, - undefined, undefined), - {delay, Stamp, From, Desc}. - -decode_delay_els(__TopXMLNS, __IgnoreEls, [], Desc) -> - decode_delay_cdata(__TopXMLNS, Desc); -decode_delay_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Desc) -> - decode_delay_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_delay_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Desc) -> - decode_delay_els(__TopXMLNS, __IgnoreEls, _els, Desc). - -decode_delay_attrs(__TopXMLNS, - [{<<"stamp">>, _val} | _attrs], _Stamp, From) -> - decode_delay_attrs(__TopXMLNS, _attrs, _val, From); -decode_delay_attrs(__TopXMLNS, - [{<<"from">>, _val} | _attrs], Stamp, _From) -> - decode_delay_attrs(__TopXMLNS, _attrs, Stamp, _val); -decode_delay_attrs(__TopXMLNS, [_ | _attrs], Stamp, - From) -> - decode_delay_attrs(__TopXMLNS, _attrs, Stamp, From); -decode_delay_attrs(__TopXMLNS, [], Stamp, From) -> - {decode_delay_attr_stamp(__TopXMLNS, Stamp), - decode_delay_attr_from(__TopXMLNS, From)}. - -encode_delay({delay, Stamp, From, Desc}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:delay">>, - [], __TopXMLNS), - _els = encode_delay_cdata(Desc, []), - _attrs = encode_delay_attr_from(From, - encode_delay_attr_stamp(Stamp, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))), - {xmlel, <<"delay">>, _attrs, _els}. - -decode_delay_attr_stamp(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"stamp">>, <<"delay">>, __TopXMLNS}}); -decode_delay_attr_stamp(__TopXMLNS, _val) -> - case catch dec_utc(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"stamp">>, <<"delay">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_delay_attr_stamp(_val, _acc) -> - [{<<"stamp">>, enc_utc(_val)} | _acc]. - -decode_delay_attr_from(__TopXMLNS, undefined) -> - undefined; -decode_delay_attr_from(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"from">>, <<"delay">>, __TopXMLNS}}); - _res -> _res - end. - -encode_delay_attr_from(undefined, _acc) -> _acc; -encode_delay_attr_from(_val, _acc) -> - [{<<"from">>, enc_jid(_val)} | _acc]. - -decode_delay_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_delay_cdata(__TopXMLNS, _val) -> _val. - -encode_delay_cdata(<<>>, _acc) -> _acc; -encode_delay_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_chatstate_paused(__TopXMLNS, __IgnoreEls, - {xmlel, <<"paused">>, _attrs, _els}) -> - {chatstate, paused}. - -encode_chatstate_paused({chatstate, paused}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/chatstates">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"paused">>, _attrs, _els}. - -decode_chatstate_inactive(__TopXMLNS, __IgnoreEls, - {xmlel, <<"inactive">>, _attrs, _els}) -> - {chatstate, inactive}. - -encode_chatstate_inactive({chatstate, inactive}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/chatstates">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"inactive">>, _attrs, _els}. - -decode_chatstate_gone(__TopXMLNS, __IgnoreEls, - {xmlel, <<"gone">>, _attrs, _els}) -> - {chatstate, gone}. - -encode_chatstate_gone({chatstate, gone}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/chatstates">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"gone">>, _attrs, _els}. - -decode_chatstate_composing(__TopXMLNS, __IgnoreEls, - {xmlel, <<"composing">>, _attrs, _els}) -> - {chatstate, composing}. - -encode_chatstate_composing({chatstate, composing}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/chatstates">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"composing">>, _attrs, _els}. - -decode_chatstate_active(__TopXMLNS, __IgnoreEls, - {xmlel, <<"active">>, _attrs, _els}) -> - {chatstate, active}. - -encode_chatstate_active({chatstate, active}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/chatstates">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"active">>, _attrs, _els}. - -decode_shim_headers(__TopXMLNS, __IgnoreEls, - {xmlel, <<"headers">>, _attrs, _els}) -> - Headers = decode_shim_headers_els(__TopXMLNS, - __IgnoreEls, _els, []), - {shim, Headers}. - -decode_shim_headers_els(__TopXMLNS, __IgnoreEls, [], - Headers) -> - lists:reverse(Headers); -decode_shim_headers_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"header">>, _attrs, _} = _el | _els], - Headers) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/shim">> -> - decode_shim_headers_els(__TopXMLNS, __IgnoreEls, _els, - [decode_shim_header(__TopXMLNS, __IgnoreEls, - _el) - | Headers]); - <<"http://jabber.org/protocol/shim">> -> - decode_shim_headers_els(__TopXMLNS, __IgnoreEls, _els, - [decode_shim_header(<<"http://jabber.org/protocol/shim">>, - __IgnoreEls, _el) - | Headers]); - _ -> - decode_shim_headers_els(__TopXMLNS, __IgnoreEls, _els, - Headers) - end; -decode_shim_headers_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Headers) -> - decode_shim_headers_els(__TopXMLNS, __IgnoreEls, _els, - Headers). - -encode_shim_headers({shim, Headers}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/shim">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_shim_headers_$headers'(Headers, - __NewTopXMLNS, [])), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"headers">>, _attrs, _els}. - -'encode_shim_headers_$headers'([], __TopXMLNS, _acc) -> - _acc; -'encode_shim_headers_$headers'([Headers | _els], - __TopXMLNS, _acc) -> - 'encode_shim_headers_$headers'(_els, __TopXMLNS, - [encode_shim_header(Headers, __TopXMLNS) - | _acc]). - -decode_shim_header(__TopXMLNS, __IgnoreEls, - {xmlel, <<"header">>, _attrs, _els}) -> - Cdata = decode_shim_header_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Name = decode_shim_header_attrs(__TopXMLNS, _attrs, - undefined), - {Name, Cdata}. - -decode_shim_header_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_shim_header_cdata(__TopXMLNS, Cdata); -decode_shim_header_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_shim_header_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_shim_header_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_shim_header_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -decode_shim_header_attrs(__TopXMLNS, - [{<<"name">>, _val} | _attrs], _Name) -> - decode_shim_header_attrs(__TopXMLNS, _attrs, _val); -decode_shim_header_attrs(__TopXMLNS, [_ | _attrs], - Name) -> - decode_shim_header_attrs(__TopXMLNS, _attrs, Name); -decode_shim_header_attrs(__TopXMLNS, [], Name) -> - decode_shim_header_attr_name(__TopXMLNS, Name). - -encode_shim_header({Name, Cdata}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/shim">>, - [], __TopXMLNS), - _els = encode_shim_header_cdata(Cdata, []), - _attrs = encode_shim_header_attr_name(Name, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"header">>, _attrs, _els}. - -decode_shim_header_attr_name(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"name">>, <<"header">>, __TopXMLNS}}); -decode_shim_header_attr_name(__TopXMLNS, _val) -> _val. - -encode_shim_header_attr_name(_val, _acc) -> - [{<<"name">>, _val} | _acc]. - -decode_shim_header_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_shim_header_cdata(__TopXMLNS, _val) -> _val. - -encode_shim_header_cdata(<<>>, _acc) -> _acc; -encode_shim_header_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_pubsub_error_unsupported_access_model(__TopXMLNS, - __IgnoreEls, - {xmlel, - <<"unsupported-access-model">>, - _attrs, _els}) -> - {ps_error, 'unsupported-access-model', undefined}. - -encode_pubsub_error_unsupported_access_model({ps_error, - 'unsupported-access-model', _}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"unsupported-access-model">>, _attrs, _els}. - -decode_pubsub_error_unsupported(__TopXMLNS, __IgnoreEls, - {xmlel, <<"unsupported">>, _attrs, _els}) -> - Feature = - decode_pubsub_error_unsupported_attrs(__TopXMLNS, - _attrs, undefined), - {ps_error, unsupported, Feature}. - -decode_pubsub_error_unsupported_attrs(__TopXMLNS, - [{<<"feature">>, _val} | _attrs], - _Feature) -> - decode_pubsub_error_unsupported_attrs(__TopXMLNS, - _attrs, _val); -decode_pubsub_error_unsupported_attrs(__TopXMLNS, - [_ | _attrs], Feature) -> - decode_pubsub_error_unsupported_attrs(__TopXMLNS, - _attrs, Feature); -decode_pubsub_error_unsupported_attrs(__TopXMLNS, [], - Feature) -> - decode_pubsub_error_unsupported_attr_feature(__TopXMLNS, - Feature). - -encode_pubsub_error_unsupported({ps_error, unsupported, - Feature}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, - [], __TopXMLNS), - _els = [], - _attrs = - encode_pubsub_error_unsupported_attr_feature(Feature, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"unsupported">>, _attrs, _els}. - -decode_pubsub_error_unsupported_attr_feature(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"feature">>, <<"unsupported">>, - __TopXMLNS}}); -decode_pubsub_error_unsupported_attr_feature(__TopXMLNS, - _val) -> - case catch dec_enum(_val, - ['access-authorize', 'access-open', 'access-presence', - 'access-roster', 'access-whitelist', 'auto-create', - 'auto-subscribe', collections, 'config-node', - 'create-and-configure', 'create-nodes', 'delete-items', - 'delete-nodes', 'filtered-notifications', - 'get-pending', 'instant-nodes', 'item-ids', - 'last-published', 'leased-subscription', - 'manage-subscriptions', 'member-affiliation', - 'meta-data', 'modify-affiliations', 'multi-collection', - 'multi-subscribe', 'outcast-affiliation', - 'persistent-items', 'presence-notifications', - 'presence-subscribe', publish, 'publish-options', - 'publish-only-affiliation', 'publisher-affiliation', - 'purge-nodes', 'retract-items', - 'retrieve-affiliations', 'retrieve-default', - 'retrieve-items', 'retrieve-subscriptions', subscribe, - 'subscription-options', 'subscription-notifications']) - of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"feature">>, <<"unsupported">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_pubsub_error_unsupported_attr_feature(_val, - _acc) -> - [{<<"feature">>, enc_enum(_val)} | _acc]. - -decode_pubsub_error_too_many_subscriptions(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"too-many-subscriptions">>, - _attrs, _els}) -> - {ps_error, 'too-many-subscriptions', undefined}. - -encode_pubsub_error_too_many_subscriptions({ps_error, - 'too-many-subscriptions', _}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"too-many-subscriptions">>, _attrs, _els}. - -decode_pubsub_error_subid_required(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"subid-required">>, _attrs, - _els}) -> - {ps_error, 'subid-required', undefined}. - -encode_pubsub_error_subid_required({ps_error, - 'subid-required', _}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"subid-required">>, _attrs, _els}. - -decode_pubsub_error_presence_subscription_required(__TopXMLNS, - __IgnoreEls, - {xmlel, - <<"presence-subscription-required">>, - _attrs, _els}) -> - {ps_error, 'presence-subscription-required', undefined}. - -encode_pubsub_error_presence_subscription_required({ps_error, - 'presence-subscription-required', - _}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"presence-subscription-required">>, _attrs, - _els}. - -decode_pubsub_error_pending_subscription(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"pending-subscription">>, - _attrs, _els}) -> - {ps_error, 'pending-subscription', undefined}. - -encode_pubsub_error_pending_subscription({ps_error, - 'pending-subscription', _}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"pending-subscription">>, _attrs, _els}. - -decode_pubsub_error_payload_required(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"payload-required">>, _attrs, - _els}) -> - {ps_error, 'payload-required', undefined}. - -encode_pubsub_error_payload_required({ps_error, - 'payload-required', _}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"payload-required">>, _attrs, _els}. - -decode_pubsub_error_payload_too_big(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"payload-too-big">>, _attrs, - _els}) -> - {ps_error, 'payload-too-big', undefined}. - -encode_pubsub_error_payload_too_big({ps_error, - 'payload-too-big', _}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"payload-too-big">>, _attrs, _els}. - -decode_pubsub_error_not_subscribed(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"not-subscribed">>, _attrs, - _els}) -> - {ps_error, 'not-subscribed', undefined}. - -encode_pubsub_error_not_subscribed({ps_error, - 'not-subscribed', _}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"not-subscribed">>, _attrs, _els}. - -decode_pubsub_error_not_in_roster_group(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"not-in-roster-group">>, - _attrs, _els}) -> - {ps_error, 'not-in-roster-group', undefined}. - -encode_pubsub_error_not_in_roster_group({ps_error, - 'not-in-roster-group', _}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"not-in-roster-group">>, _attrs, _els}. - -decode_pubsub_error_nodeid_required(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"nodeid-required">>, _attrs, - _els}) -> - {ps_error, 'nodeid-required', undefined}. - -encode_pubsub_error_nodeid_required({ps_error, - 'nodeid-required', _}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"nodeid-required">>, _attrs, _els}. - -decode_pubsub_error_max_nodes_exceeded(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"max-nodes-exceeded">>, _attrs, - _els}) -> - {ps_error, 'max-nodes-exceeded', undefined}. - -encode_pubsub_error_max_nodes_exceeded({ps_error, - 'max-nodes-exceeded', _}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"max-nodes-exceeded">>, _attrs, _els}. - -decode_pubsub_error_max_items_exceeded(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"max-items-exceeded">>, _attrs, - _els}) -> - {ps_error, 'max-items-exceeded', undefined}. - -encode_pubsub_error_max_items_exceeded({ps_error, - 'max-items-exceeded', _}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"max-items-exceeded">>, _attrs, _els}. - -decode_pubsub_error_jid_required(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"jid-required">>, _attrs, _els}) -> - {ps_error, 'jid-required', undefined}. - -encode_pubsub_error_jid_required({ps_error, - 'jid-required', _}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"jid-required">>, _attrs, _els}. - -decode_pubsub_error_item_required(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"item-required">>, _attrs, _els}) -> - {ps_error, 'item-required', undefined}. - -encode_pubsub_error_item_required({ps_error, - 'item-required', _}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"item-required">>, _attrs, _els}. - -decode_pubsub_error_item_forbidden(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"item-forbidden">>, _attrs, - _els}) -> - {ps_error, 'item-forbidden', undefined}. - -encode_pubsub_error_item_forbidden({ps_error, - 'item-forbidden', _}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"item-forbidden">>, _attrs, _els}. - -decode_pubsub_error_invalid_subid(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"invalid-subid">>, _attrs, _els}) -> - {ps_error, 'invalid-subid', undefined}. - -encode_pubsub_error_invalid_subid({ps_error, - 'invalid-subid', _}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"invalid-subid">>, _attrs, _els}. - -decode_pubsub_error_invalid_payload(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"invalid-payload">>, _attrs, - _els}) -> - {ps_error, 'invalid-payload', undefined}. - -encode_pubsub_error_invalid_payload({ps_error, - 'invalid-payload', _}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"invalid-payload">>, _attrs, _els}. - -decode_pubsub_error_invalid_options(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"invalid-options">>, _attrs, - _els}) -> - {ps_error, 'invalid-options', undefined}. - -encode_pubsub_error_invalid_options({ps_error, - 'invalid-options', _}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"invalid-options">>, _attrs, _els}. - -decode_pubsub_error_invalid_jid(__TopXMLNS, __IgnoreEls, - {xmlel, <<"invalid-jid">>, _attrs, _els}) -> - {ps_error, 'invalid-jid', undefined}. - -encode_pubsub_error_invalid_jid({ps_error, - 'invalid-jid', _}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"invalid-jid">>, _attrs, _els}. - -decode_pubsub_error_configuration_required(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"configuration-required">>, - _attrs, _els}) -> - {ps_error, 'configuration-required', undefined}. - -encode_pubsub_error_configuration_required({ps_error, - 'configuration-required', _}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"configuration-required">>, _attrs, _els}. - -decode_pubsub_error_closed_node(__TopXMLNS, __IgnoreEls, - {xmlel, <<"closed-node">>, _attrs, _els}) -> - {ps_error, 'closed-node', undefined}. - -encode_pubsub_error_closed_node({ps_error, - 'closed-node', _}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#errors">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"closed-node">>, _attrs, _els}. - -decode_pubsub_owner(__TopXMLNS, __IgnoreEls, - {xmlel, <<"pubsub">>, _attrs, _els}) -> - {Subscriptions, Affiliations, Default, Purge, Delete, - Configure} = - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - undefined, undefined, undefined, undefined, - undefined, undefined), - {pubsub_owner, Affiliations, Configure, Default, Delete, - Purge, Subscriptions}. - -decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, [], - Subscriptions, Affiliations, Default, Purge, Delete, - Configure) -> - {Subscriptions, Affiliations, Default, Purge, Delete, - Configure}; -decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"affiliations">>, _attrs, _} = _el | _els], - Subscriptions, Affiliations, Default, Purge, Delete, - Configure) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - Subscriptions, - decode_pubsub_owner_affiliations(__TopXMLNS, - __IgnoreEls, - _el), - Default, Purge, Delete, Configure); - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - Subscriptions, - decode_pubsub_owner_affiliations(<<"http://jabber.org/protocol/pubsub#owner">>, - __IgnoreEls, - _el), - Default, Purge, Delete, Configure); - _ -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - Subscriptions, Affiliations, Default, Purge, - Delete, Configure) - end; -decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"configure">>, _attrs, _} = _el | _els], - Subscriptions, Affiliations, Default, Purge, Delete, - Configure) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - Subscriptions, Affiliations, Default, Purge, - Delete, - decode_pubsub_configure(__TopXMLNS, - __IgnoreEls, _el)); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - Subscriptions, Affiliations, Default, Purge, - Delete, - decode_pubsub_configure(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el)); - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - Subscriptions, Affiliations, Default, Purge, - Delete, - decode_pubsub_configure(<<"http://jabber.org/protocol/pubsub#owner">>, - __IgnoreEls, _el)); - _ -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - Subscriptions, Affiliations, Default, Purge, - Delete, Configure) - end; -decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"default">>, _attrs, _} = _el | _els], - Subscriptions, Affiliations, Default, Purge, Delete, - Configure) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - Subscriptions, Affiliations, - decode_pubsub_default(__TopXMLNS, __IgnoreEls, - _el), - Purge, Delete, Configure); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - Subscriptions, Affiliations, - decode_pubsub_default(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el), - Purge, Delete, Configure); - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - Subscriptions, Affiliations, - decode_pubsub_default(<<"http://jabber.org/protocol/pubsub#owner">>, - __IgnoreEls, _el), - Purge, Delete, Configure); - _ -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - Subscriptions, Affiliations, Default, Purge, - Delete, Configure) - end; -decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"delete">>, _attrs, _} = _el | _els], - Subscriptions, Affiliations, Default, Purge, Delete, - Configure) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - Subscriptions, Affiliations, Default, Purge, - decode_pubsub_delete(__TopXMLNS, __IgnoreEls, - _el), - Configure); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - Subscriptions, Affiliations, Default, Purge, - decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el), - Configure); - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - Subscriptions, Affiliations, Default, Purge, - decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub#owner">>, - __IgnoreEls, _el), - Configure); - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - Subscriptions, Affiliations, Default, Purge, - decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub#event">>, - __IgnoreEls, _el), - Configure); - _ -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - Subscriptions, Affiliations, Default, Purge, - Delete, Configure) - end; -decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"purge">>, _attrs, _} = _el | _els], - Subscriptions, Affiliations, Default, Purge, Delete, - Configure) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - Subscriptions, Affiliations, Default, - decode_pubsub_purge(__TopXMLNS, __IgnoreEls, - _el), - Delete, Configure); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - Subscriptions, Affiliations, Default, - decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el), - Delete, Configure); - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - Subscriptions, Affiliations, Default, - decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub#owner">>, - __IgnoreEls, _el), - Delete, Configure); - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - Subscriptions, Affiliations, Default, - decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub#event">>, - __IgnoreEls, _el), - Delete, Configure); - _ -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - Subscriptions, Affiliations, Default, Purge, - Delete, Configure) - end; -decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"subscriptions">>, _attrs, _} = _el | _els], - Subscriptions, Affiliations, Default, Purge, Delete, - Configure) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - decode_pubsub_subscriptions(__TopXMLNS, - __IgnoreEls, _el), - Affiliations, Default, Purge, Delete, - Configure); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - decode_pubsub_subscriptions(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el), - Affiliations, Default, Purge, Delete, - Configure); - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - decode_pubsub_subscriptions(<<"http://jabber.org/protocol/pubsub#owner">>, - __IgnoreEls, _el), - Affiliations, Default, Purge, Delete, - Configure); - _ -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - Subscriptions, Affiliations, Default, Purge, - Delete, Configure) - end; -decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Subscriptions, Affiliations, Default, Purge, - Delete, Configure) -> - decode_pubsub_owner_els(__TopXMLNS, __IgnoreEls, _els, - Subscriptions, Affiliations, Default, Purge, Delete, - Configure). - -encode_pubsub_owner({pubsub_owner, Affiliations, - Configure, Default, Delete, Purge, Subscriptions}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#owner">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_pubsub_owner_$subscriptions'(Subscriptions, - __NewTopXMLNS, - 'encode_pubsub_owner_$affiliations'(Affiliations, - __NewTopXMLNS, - 'encode_pubsub_owner_$default'(Default, - __NewTopXMLNS, - 'encode_pubsub_owner_$purge'(Purge, - __NewTopXMLNS, - 'encode_pubsub_owner_$delete'(Delete, - __NewTopXMLNS, - 'encode_pubsub_owner_$configure'(Configure, - __NewTopXMLNS, - []))))))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"pubsub">>, _attrs, _els}. - -'encode_pubsub_owner_$subscriptions'(undefined, - __TopXMLNS, _acc) -> - _acc; -'encode_pubsub_owner_$subscriptions'(Subscriptions, - __TopXMLNS, _acc) -> - [encode_pubsub_subscriptions(Subscriptions, __TopXMLNS) - | _acc]. - -'encode_pubsub_owner_$affiliations'(undefined, - __TopXMLNS, _acc) -> - _acc; -'encode_pubsub_owner_$affiliations'(Affiliations, - __TopXMLNS, _acc) -> - [encode_pubsub_owner_affiliations(Affiliations, - __TopXMLNS) - | _acc]. - -'encode_pubsub_owner_$default'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_pubsub_owner_$default'(Default, __TopXMLNS, - _acc) -> - [encode_pubsub_default(Default, __TopXMLNS) | _acc]. - -'encode_pubsub_owner_$purge'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_pubsub_owner_$purge'(Purge, __TopXMLNS, _acc) -> - [encode_pubsub_purge(Purge, __TopXMLNS) | _acc]. - -'encode_pubsub_owner_$delete'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_pubsub_owner_$delete'(Delete, __TopXMLNS, - _acc) -> - [encode_pubsub_delete(Delete, __TopXMLNS) | _acc]. - -'encode_pubsub_owner_$configure'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_pubsub_owner_$configure'(Configure, __TopXMLNS, - _acc) -> - [encode_pubsub_configure(Configure, __TopXMLNS) | _acc]. - -decode_pubsub(__TopXMLNS, __IgnoreEls, - {xmlel, <<"pubsub">>, _attrs, _els}) -> - {Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, - Subscription} = - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - undefined, undefined, undefined, undefined, undefined, - undefined, undefined, undefined, undefined, undefined, - undefined, undefined, undefined, undefined, undefined, - undefined), - {pubsub, Subscriptions, Subscription, Affiliations, - Publish, Publish_options, Subscribe, Unsubscribe, - Options, Items, Retract, Create, Configure, Default, - Delete, Purge, Rsm}. - -decode_pubsub_els(__TopXMLNS, __IgnoreEls, [], - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, - Subscription) -> - {Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, - Subscription}; -decode_pubsub_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"subscriptions">>, _attrs, _} = _el | _els], - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, - Subscription) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - decode_pubsub_subscriptions(__TopXMLNS, __IgnoreEls, - _el), - Default, Retract, Purge, Delete, Configure, Create, - Unsubscribe, Subscribe, Publish, Rsm, Subscription); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - decode_pubsub_subscriptions(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el), - Default, Retract, Purge, Delete, Configure, Create, - Unsubscribe, Subscribe, Publish, Rsm, Subscription); - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - decode_pubsub_subscriptions(<<"http://jabber.org/protocol/pubsub#owner">>, - __IgnoreEls, _el), - Default, Retract, Purge, Delete, Configure, Create, - Unsubscribe, Subscribe, Publish, Rsm, Subscription); - _ -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, Subscription) - end; -decode_pubsub_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"affiliations">>, _attrs, _} = _el | _els], - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, - Subscription) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, - decode_pubsub_affiliations(__TopXMLNS, __IgnoreEls, - _el), - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, Subscription); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, - decode_pubsub_affiliations(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el), - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, Subscription); - _ -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, Subscription) - end; -decode_pubsub_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"subscribe">>, _attrs, _} = _el | _els], - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, - Subscription) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, - decode_pubsub_subscribe(__TopXMLNS, __IgnoreEls, - _el), - Publish, Rsm, Subscription); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, - decode_pubsub_subscribe(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el), - Publish, Rsm, Subscription); - _ -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, Subscription) - end; -decode_pubsub_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"unsubscribe">>, _attrs, _} = _el | _els], - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, - Subscription) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, - decode_pubsub_unsubscribe(__TopXMLNS, __IgnoreEls, - _el), - Subscribe, Publish, Rsm, Subscription); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, - decode_pubsub_unsubscribe(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el), - Subscribe, Publish, Rsm, Subscription); - _ -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, Subscription) - end; -decode_pubsub_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"options">>, _attrs, _} = _el | _els], - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, - Subscription) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, - decode_pubsub_options(__TopXMLNS, __IgnoreEls, _el), - Affiliations, Subscriptions, Default, Retract, - Purge, Delete, Configure, Create, Unsubscribe, - Subscribe, Publish, Rsm, Subscription); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, - decode_pubsub_options(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el), - Affiliations, Subscriptions, Default, Retract, - Purge, Delete, Configure, Create, Unsubscribe, - Subscribe, Publish, Rsm, Subscription); - _ -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, Subscription) - end; -decode_pubsub_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"items">>, _attrs, _} = _el | _els], - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, - Subscription) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, - decode_pubsub_items(__TopXMLNS, __IgnoreEls, _el), - Options, Affiliations, Subscriptions, Default, - Retract, Purge, Delete, Configure, Create, - Unsubscribe, Subscribe, Publish, Rsm, Subscription); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, - decode_pubsub_items(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el), - Options, Affiliations, Subscriptions, Default, - Retract, Purge, Delete, Configure, Create, - Unsubscribe, Subscribe, Publish, Rsm, Subscription); - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, - decode_pubsub_items(<<"http://jabber.org/protocol/pubsub#event">>, - __IgnoreEls, _el), - Options, Affiliations, Subscriptions, Default, - Retract, Purge, Delete, Configure, Create, - Unsubscribe, Subscribe, Publish, Rsm, Subscription); - _ -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, Subscription) - end; -decode_pubsub_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"retract">>, _attrs, _} = _el | _els], - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, - Subscription) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, - decode_pubsub_retract(__TopXMLNS, __IgnoreEls, _el), - Purge, Delete, Configure, Create, Unsubscribe, - Subscribe, Publish, Rsm, Subscription); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, - decode_pubsub_retract(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el), - Purge, Delete, Configure, Create, Unsubscribe, - Subscribe, Publish, Rsm, Subscription); - _ -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, Subscription) - end; -decode_pubsub_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"create">>, _attrs, _} = _el | _els], - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, - Subscription) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, - decode_pubsub_create(__TopXMLNS, __IgnoreEls, _el), - Unsubscribe, Subscribe, Publish, Rsm, Subscription); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, - decode_pubsub_create(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el), - Unsubscribe, Subscribe, Publish, Rsm, Subscription); - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, - decode_pubsub_create(<<"http://jabber.org/protocol/pubsub#event">>, - __IgnoreEls, _el), - Unsubscribe, Subscribe, Publish, Rsm, Subscription); - _ -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, Subscription) - end; -decode_pubsub_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"configure">>, _attrs, _} = _el | _els], - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, - Subscription) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - decode_pubsub_configure(__TopXMLNS, __IgnoreEls, - _el), - Create, Unsubscribe, Subscribe, Publish, Rsm, - Subscription); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - decode_pubsub_configure(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el), - Create, Unsubscribe, Subscribe, Publish, Rsm, - Subscription); - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - decode_pubsub_configure(<<"http://jabber.org/protocol/pubsub#owner">>, - __IgnoreEls, _el), - Create, Unsubscribe, Subscribe, Publish, Rsm, - Subscription); - _ -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, Subscription) - end; -decode_pubsub_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"publish-options">>, _attrs, _} = _el - | _els], - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, - Subscription) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - decode_pubsub_publish_options(__TopXMLNS, - __IgnoreEls, _el), - Items, Options, Affiliations, Subscriptions, - Default, Retract, Purge, Delete, Configure, Create, - Unsubscribe, Subscribe, Publish, Rsm, Subscription); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - decode_pubsub_publish_options(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el), - Items, Options, Affiliations, Subscriptions, - Default, Retract, Purge, Delete, Configure, Create, - Unsubscribe, Subscribe, Publish, Rsm, Subscription); - _ -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, Subscription) - end; -decode_pubsub_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"default">>, _attrs, _} = _el | _els], - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, - Subscription) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, - decode_pubsub_default(__TopXMLNS, __IgnoreEls, _el), - Retract, Purge, Delete, Configure, Create, - Unsubscribe, Subscribe, Publish, Rsm, Subscription); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, - decode_pubsub_default(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el), - Retract, Purge, Delete, Configure, Create, - Unsubscribe, Subscribe, Publish, Rsm, Subscription); - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, - decode_pubsub_default(<<"http://jabber.org/protocol/pubsub#owner">>, - __IgnoreEls, _el), - Retract, Purge, Delete, Configure, Create, - Unsubscribe, Subscribe, Publish, Rsm, Subscription); - _ -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, Subscription) - end; -decode_pubsub_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"delete">>, _attrs, _} = _el | _els], - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, - Subscription) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, - decode_pubsub_delete(__TopXMLNS, __IgnoreEls, _el), - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, Subscription); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, - decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el), - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, Subscription); - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, - decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub#owner">>, - __IgnoreEls, _el), - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, Subscription); - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, - decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub#event">>, - __IgnoreEls, _el), - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, Subscription); - _ -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, Subscription) - end; -decode_pubsub_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"purge">>, _attrs, _} = _el | _els], - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, - Subscription) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, - decode_pubsub_purge(__TopXMLNS, __IgnoreEls, _el), - Delete, Configure, Create, Unsubscribe, Subscribe, - Publish, Rsm, Subscription); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, - decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el), - Delete, Configure, Create, Unsubscribe, Subscribe, - Publish, Rsm, Subscription); - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, - decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub#owner">>, - __IgnoreEls, _el), - Delete, Configure, Create, Unsubscribe, Subscribe, - Publish, Rsm, Subscription); - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, - decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub#event">>, - __IgnoreEls, _el), - Delete, Configure, Create, Unsubscribe, Subscribe, - Publish, Rsm, Subscription); - _ -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, Subscription) - end; -decode_pubsub_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"subscription">>, _attrs, _} = _el | _els], - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, - Subscription) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, - decode_pubsub_subscription(__TopXMLNS, __IgnoreEls, - _el)); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, - decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el)); - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, - decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub#owner">>, - __IgnoreEls, _el)); - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, - decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub#event">>, - __IgnoreEls, _el)); - _ -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, Subscription) - end; -decode_pubsub_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"set">>, _attrs, _} = _el | _els], - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, - Subscription) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"http://jabber.org/protocol/rsm">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, - decode_rsm_set(<<"http://jabber.org/protocol/rsm">>, - __IgnoreEls, _el), - Subscription); - _ -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, Subscription) - end; -decode_pubsub_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"publish">>, _attrs, _} = _el | _els], - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, - Subscription) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, - decode_pubsub_publish(__TopXMLNS, __IgnoreEls, _el), - Rsm, Subscription); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, - decode_pubsub_publish(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el), - Rsm, Subscription); - _ -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, - Rsm, Subscription) - end; -decode_pubsub_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, - Subscription) -> - decode_pubsub_els(__TopXMLNS, __IgnoreEls, _els, - Publish_options, Items, Options, Affiliations, - Subscriptions, Default, Retract, Purge, Delete, - Configure, Create, Unsubscribe, Subscribe, Publish, Rsm, - Subscription). - -encode_pubsub({pubsub, Subscriptions, Subscription, - Affiliations, Publish, Publish_options, Subscribe, - Unsubscribe, Options, Items, Retract, Create, Configure, - Default, Delete, Purge, Rsm}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_pubsub_$publish_options'(Publish_options, - __NewTopXMLNS, - 'encode_pubsub_$items'(Items, - __NewTopXMLNS, - 'encode_pubsub_$options'(Options, - __NewTopXMLNS, - 'encode_pubsub_$affiliations'(Affiliations, - __NewTopXMLNS, - 'encode_pubsub_$subscriptions'(Subscriptions, - __NewTopXMLNS, - 'encode_pubsub_$default'(Default, - __NewTopXMLNS, - 'encode_pubsub_$retract'(Retract, - __NewTopXMLNS, - 'encode_pubsub_$purge'(Purge, - __NewTopXMLNS, - 'encode_pubsub_$delete'(Delete, - __NewTopXMLNS, - 'encode_pubsub_$configure'(Configure, - __NewTopXMLNS, - 'encode_pubsub_$create'(Create, - __NewTopXMLNS, - 'encode_pubsub_$unsubscribe'(Unsubscribe, - __NewTopXMLNS, - 'encode_pubsub_$subscribe'(Subscribe, - __NewTopXMLNS, - 'encode_pubsub_$publish'(Publish, - __NewTopXMLNS, - 'encode_pubsub_$rsm'(Rsm, - __NewTopXMLNS, - 'encode_pubsub_$subscription'(Subscription, - __NewTopXMLNS, - []))))))))))))))))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"pubsub">>, _attrs, _els}. - -'encode_pubsub_$publish_options'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_pubsub_$publish_options'(Publish_options, - __TopXMLNS, _acc) -> - [encode_pubsub_publish_options(Publish_options, - __TopXMLNS) - | _acc]. - -'encode_pubsub_$items'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_pubsub_$items'(Items, __TopXMLNS, _acc) -> - [encode_pubsub_items(Items, __TopXMLNS) | _acc]. - -'encode_pubsub_$options'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_pubsub_$options'(Options, __TopXMLNS, _acc) -> - [encode_pubsub_options(Options, __TopXMLNS) | _acc]. - -'encode_pubsub_$affiliations'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_pubsub_$affiliations'(Affiliations, __TopXMLNS, - _acc) -> - [encode_pubsub_affiliations(Affiliations, __TopXMLNS) - | _acc]. - -'encode_pubsub_$subscriptions'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_pubsub_$subscriptions'(Subscriptions, - __TopXMLNS, _acc) -> - [encode_pubsub_subscriptions(Subscriptions, __TopXMLNS) - | _acc]. - -'encode_pubsub_$default'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_pubsub_$default'(Default, __TopXMLNS, _acc) -> - [encode_pubsub_default(Default, __TopXMLNS) | _acc]. - -'encode_pubsub_$retract'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_pubsub_$retract'(Retract, __TopXMLNS, _acc) -> - [encode_pubsub_retract(Retract, __TopXMLNS) | _acc]. - -'encode_pubsub_$purge'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_pubsub_$purge'(Purge, __TopXMLNS, _acc) -> - [encode_pubsub_purge(Purge, __TopXMLNS) | _acc]. - -'encode_pubsub_$delete'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_pubsub_$delete'(Delete, __TopXMLNS, _acc) -> - [encode_pubsub_delete(Delete, __TopXMLNS) | _acc]. - -'encode_pubsub_$configure'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_pubsub_$configure'(Configure, __TopXMLNS, - _acc) -> - [encode_pubsub_configure(Configure, __TopXMLNS) | _acc]. - -'encode_pubsub_$create'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_pubsub_$create'(Create, __TopXMLNS, _acc) -> - [encode_pubsub_create(Create, __TopXMLNS) | _acc]. - -'encode_pubsub_$unsubscribe'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_pubsub_$unsubscribe'(Unsubscribe, __TopXMLNS, - _acc) -> - [encode_pubsub_unsubscribe(Unsubscribe, __TopXMLNS) - | _acc]. - -'encode_pubsub_$subscribe'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_pubsub_$subscribe'(Subscribe, __TopXMLNS, - _acc) -> - [encode_pubsub_subscribe(Subscribe, __TopXMLNS) | _acc]. - -'encode_pubsub_$publish'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_pubsub_$publish'(Publish, __TopXMLNS, _acc) -> - [encode_pubsub_publish(Publish, __TopXMLNS) | _acc]. - -'encode_pubsub_$rsm'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_pubsub_$rsm'(Rsm, __TopXMLNS, _acc) -> - [encode_rsm_set(Rsm, __TopXMLNS) | _acc]. - -'encode_pubsub_$subscription'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_pubsub_$subscription'(Subscription, __TopXMLNS, - _acc) -> - [encode_pubsub_subscription(Subscription, __TopXMLNS) - | _acc]. - -decode_pubsub_purge(__TopXMLNS, __IgnoreEls, - {xmlel, <<"purge">>, _attrs, _els}) -> - Node = decode_pubsub_purge_attrs(__TopXMLNS, _attrs, - undefined), - Node. - -decode_pubsub_purge_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], _Node) -> - decode_pubsub_purge_attrs(__TopXMLNS, _attrs, _val); -decode_pubsub_purge_attrs(__TopXMLNS, [_ | _attrs], - Node) -> - decode_pubsub_purge_attrs(__TopXMLNS, _attrs, Node); -decode_pubsub_purge_attrs(__TopXMLNS, [], Node) -> - decode_pubsub_purge_attr_node(__TopXMLNS, Node). - -encode_pubsub_purge(Node, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"http://jabber.org/protocol/pubsub">>, - <<"http://jabber.org/protocol/pubsub#owner">>, - <<"http://jabber.org/protocol/pubsub#event">>], - __TopXMLNS), - _els = [], - _attrs = encode_pubsub_purge_attr_node(Node, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"purge">>, _attrs, _els}. - -decode_pubsub_purge_attr_node(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"node">>, <<"purge">>, __TopXMLNS}}); -decode_pubsub_purge_attr_node(__TopXMLNS, _val) -> _val. - -encode_pubsub_purge_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_pubsub_delete(__TopXMLNS, __IgnoreEls, - {xmlel, <<"delete">>, _attrs, _els}) -> - Uri = decode_pubsub_delete_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Node = decode_pubsub_delete_attrs(__TopXMLNS, _attrs, - undefined), - {Node, Uri}. - -decode_pubsub_delete_els(__TopXMLNS, __IgnoreEls, [], - Uri) -> - Uri; -decode_pubsub_delete_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"redirect">>, _attrs, _} = _el | _els], - Uri) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub">>; - __TopXMLNS == - <<"http://jabber.org/protocol/pubsub#owner">>; - __TopXMLNS == - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_delete_els(__TopXMLNS, __IgnoreEls, _els, - decode_pubsub_redirect(__TopXMLNS, - __IgnoreEls, _el)); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_delete_els(__TopXMLNS, __IgnoreEls, _els, - decode_pubsub_redirect(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el)); - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_delete_els(__TopXMLNS, __IgnoreEls, _els, - decode_pubsub_redirect(<<"http://jabber.org/protocol/pubsub#owner">>, - __IgnoreEls, _el)); - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_delete_els(__TopXMLNS, __IgnoreEls, _els, - decode_pubsub_redirect(<<"http://jabber.org/protocol/pubsub#event">>, - __IgnoreEls, _el)); - _ -> - decode_pubsub_delete_els(__TopXMLNS, __IgnoreEls, _els, - Uri) - end; -decode_pubsub_delete_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Uri) -> - decode_pubsub_delete_els(__TopXMLNS, __IgnoreEls, _els, - Uri). - -decode_pubsub_delete_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], _Node) -> - decode_pubsub_delete_attrs(__TopXMLNS, _attrs, _val); -decode_pubsub_delete_attrs(__TopXMLNS, [_ | _attrs], - Node) -> - decode_pubsub_delete_attrs(__TopXMLNS, _attrs, Node); -decode_pubsub_delete_attrs(__TopXMLNS, [], Node) -> - decode_pubsub_delete_attr_node(__TopXMLNS, Node). - -encode_pubsub_delete({Node, Uri}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"http://jabber.org/protocol/pubsub">>, - <<"http://jabber.org/protocol/pubsub#owner">>, - <<"http://jabber.org/protocol/pubsub#event">>], - __TopXMLNS), - _els = lists:reverse('encode_pubsub_delete_$uri'(Uri, - __NewTopXMLNS, [])), - _attrs = encode_pubsub_delete_attr_node(Node, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"delete">>, _attrs, _els}. - -'encode_pubsub_delete_$uri'(<<>>, __TopXMLNS, _acc) -> - _acc; -'encode_pubsub_delete_$uri'(Uri, __TopXMLNS, _acc) -> - [encode_pubsub_redirect(Uri, __TopXMLNS) | _acc]. - -decode_pubsub_delete_attr_node(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"node">>, <<"delete">>, __TopXMLNS}}); -decode_pubsub_delete_attr_node(__TopXMLNS, _val) -> - _val. - -encode_pubsub_delete_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_pubsub_redirect(__TopXMLNS, __IgnoreEls, - {xmlel, <<"redirect">>, _attrs, _els}) -> - Uri = decode_pubsub_redirect_attrs(__TopXMLNS, _attrs, - undefined), - Uri. - -decode_pubsub_redirect_attrs(__TopXMLNS, - [{<<"uri">>, _val} | _attrs], _Uri) -> - decode_pubsub_redirect_attrs(__TopXMLNS, _attrs, _val); -decode_pubsub_redirect_attrs(__TopXMLNS, [_ | _attrs], - Uri) -> - decode_pubsub_redirect_attrs(__TopXMLNS, _attrs, Uri); -decode_pubsub_redirect_attrs(__TopXMLNS, [], Uri) -> - decode_pubsub_redirect_attr_uri(__TopXMLNS, Uri). - -encode_pubsub_redirect(Uri, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"http://jabber.org/protocol/pubsub">>, - <<"http://jabber.org/protocol/pubsub#owner">>, - <<"http://jabber.org/protocol/pubsub#event">>], - __TopXMLNS), - _els = [], - _attrs = encode_pubsub_redirect_attr_uri(Uri, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"redirect">>, _attrs, _els}. - -decode_pubsub_redirect_attr_uri(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"uri">>, <<"redirect">>, __TopXMLNS}}); -decode_pubsub_redirect_attr_uri(__TopXMLNS, _val) -> - _val. - -encode_pubsub_redirect_attr_uri(_val, _acc) -> - [{<<"uri">>, _val} | _acc]. - -decode_pubsub_default(__TopXMLNS, __IgnoreEls, - {xmlel, <<"default">>, _attrs, _els}) -> - Xdata = decode_pubsub_default_els(__TopXMLNS, - __IgnoreEls, _els, undefined), - Node = decode_pubsub_default_attrs(__TopXMLNS, _attrs, - undefined), - {Node, Xdata}. - -decode_pubsub_default_els(__TopXMLNS, __IgnoreEls, [], - Xdata) -> - Xdata; -decode_pubsub_default_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"x">>, _attrs, _} = _el | _els], Xdata) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"jabber:x:data">> -> - decode_pubsub_default_els(__TopXMLNS, __IgnoreEls, _els, - decode_xdata(<<"jabber:x:data">>, - __IgnoreEls, _el)); - _ -> - decode_pubsub_default_els(__TopXMLNS, __IgnoreEls, _els, - Xdata) - end; -decode_pubsub_default_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Xdata) -> - decode_pubsub_default_els(__TopXMLNS, __IgnoreEls, _els, - Xdata). - -decode_pubsub_default_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], _Node) -> - decode_pubsub_default_attrs(__TopXMLNS, _attrs, _val); -decode_pubsub_default_attrs(__TopXMLNS, [_ | _attrs], - Node) -> - decode_pubsub_default_attrs(__TopXMLNS, _attrs, Node); -decode_pubsub_default_attrs(__TopXMLNS, [], Node) -> - decode_pubsub_default_attr_node(__TopXMLNS, Node). - -encode_pubsub_default({Node, Xdata}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"http://jabber.org/protocol/pubsub">>, - <<"http://jabber.org/protocol/pubsub#owner">>], - __TopXMLNS), - _els = - lists:reverse('encode_pubsub_default_$xdata'(Xdata, - __NewTopXMLNS, [])), - _attrs = encode_pubsub_default_attr_node(Node, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"default">>, _attrs, _els}. - -'encode_pubsub_default_$xdata'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_pubsub_default_$xdata'(Xdata, __TopXMLNS, - _acc) -> - [encode_xdata(Xdata, __TopXMLNS) | _acc]. - -decode_pubsub_default_attr_node(__TopXMLNS, - undefined) -> - <<>>; -decode_pubsub_default_attr_node(__TopXMLNS, _val) -> - _val. - -encode_pubsub_default_attr_node(<<>>, _acc) -> _acc; -encode_pubsub_default_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_pubsub_publish_options(__TopXMLNS, __IgnoreEls, - {xmlel, <<"publish-options">>, _attrs, _els}) -> - Xdata = decode_pubsub_publish_options_els(__TopXMLNS, - __IgnoreEls, _els, undefined), - Xdata. - -decode_pubsub_publish_options_els(__TopXMLNS, - __IgnoreEls, [], Xdata) -> - Xdata; -decode_pubsub_publish_options_els(__TopXMLNS, - __IgnoreEls, - [{xmlel, <<"x">>, _attrs, _} = _el | _els], - Xdata) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"jabber:x:data">> -> - decode_pubsub_publish_options_els(__TopXMLNS, - __IgnoreEls, _els, - decode_xdata(<<"jabber:x:data">>, - __IgnoreEls, _el)); - _ -> - decode_pubsub_publish_options_els(__TopXMLNS, - __IgnoreEls, _els, Xdata) - end; -decode_pubsub_publish_options_els(__TopXMLNS, - __IgnoreEls, [_ | _els], Xdata) -> - decode_pubsub_publish_options_els(__TopXMLNS, - __IgnoreEls, _els, Xdata). - -encode_pubsub_publish_options(Xdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_pubsub_publish_options_$xdata'(Xdata, - __NewTopXMLNS, - [])), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"publish-options">>, _attrs, _els}. - -'encode_pubsub_publish_options_$xdata'(undefined, - __TopXMLNS, _acc) -> - _acc; -'encode_pubsub_publish_options_$xdata'(Xdata, - __TopXMLNS, _acc) -> - [encode_xdata(Xdata, __TopXMLNS) | _acc]. - -decode_pubsub_configure(__TopXMLNS, __IgnoreEls, - {xmlel, <<"configure">>, _attrs, _els}) -> - Xdata = decode_pubsub_configure_els(__TopXMLNS, - __IgnoreEls, _els, undefined), - Node = decode_pubsub_configure_attrs(__TopXMLNS, _attrs, - undefined), - {Node, Xdata}. - -decode_pubsub_configure_els(__TopXMLNS, __IgnoreEls, [], - Xdata) -> - Xdata; -decode_pubsub_configure_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"x">>, _attrs, _} = _el | _els], - Xdata) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"jabber:x:data">> -> - decode_pubsub_configure_els(__TopXMLNS, __IgnoreEls, - _els, - decode_xdata(<<"jabber:x:data">>, - __IgnoreEls, _el)); - _ -> - decode_pubsub_configure_els(__TopXMLNS, __IgnoreEls, - _els, Xdata) - end; -decode_pubsub_configure_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Xdata) -> - decode_pubsub_configure_els(__TopXMLNS, __IgnoreEls, - _els, Xdata). - -decode_pubsub_configure_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], _Node) -> - decode_pubsub_configure_attrs(__TopXMLNS, _attrs, _val); -decode_pubsub_configure_attrs(__TopXMLNS, [_ | _attrs], - Node) -> - decode_pubsub_configure_attrs(__TopXMLNS, _attrs, Node); -decode_pubsub_configure_attrs(__TopXMLNS, [], Node) -> - decode_pubsub_configure_attr_node(__TopXMLNS, Node). - -encode_pubsub_configure({Node, Xdata}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"http://jabber.org/protocol/pubsub">>, - <<"http://jabber.org/protocol/pubsub#owner">>], - __TopXMLNS), - _els = - lists:reverse('encode_pubsub_configure_$xdata'(Xdata, - __NewTopXMLNS, [])), - _attrs = encode_pubsub_configure_attr_node(Node, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"configure">>, _attrs, _els}. - -'encode_pubsub_configure_$xdata'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_pubsub_configure_$xdata'(Xdata, __TopXMLNS, - _acc) -> - [encode_xdata(Xdata, __TopXMLNS) | _acc]. - -decode_pubsub_configure_attr_node(__TopXMLNS, - undefined) -> - <<>>; -decode_pubsub_configure_attr_node(__TopXMLNS, _val) -> - _val. - -encode_pubsub_configure_attr_node(<<>>, _acc) -> _acc; -encode_pubsub_configure_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_pubsub_create(__TopXMLNS, __IgnoreEls, - {xmlel, <<"create">>, _attrs, _els}) -> - Node = decode_pubsub_create_attrs(__TopXMLNS, _attrs, - undefined), - Node. - -decode_pubsub_create_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], _Node) -> - decode_pubsub_create_attrs(__TopXMLNS, _attrs, _val); -decode_pubsub_create_attrs(__TopXMLNS, [_ | _attrs], - Node) -> - decode_pubsub_create_attrs(__TopXMLNS, _attrs, Node); -decode_pubsub_create_attrs(__TopXMLNS, [], Node) -> - decode_pubsub_create_attr_node(__TopXMLNS, Node). - -encode_pubsub_create(Node, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"http://jabber.org/protocol/pubsub">>, - <<"http://jabber.org/protocol/pubsub#event">>], - __TopXMLNS), - _els = [], - _attrs = encode_pubsub_create_attr_node(Node, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"create">>, _attrs, _els}. - -decode_pubsub_create_attr_node(__TopXMLNS, undefined) -> - <<>>; -decode_pubsub_create_attr_node(__TopXMLNS, _val) -> - _val. - -encode_pubsub_create_attr_node(<<>>, _acc) -> _acc; -encode_pubsub_create_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_pubsub_retract(__TopXMLNS, __IgnoreEls, - {xmlel, <<"retract">>, _attrs, _els}) -> - Items = decode_pubsub_retract_els(__TopXMLNS, - __IgnoreEls, _els, []), - {Node, Notify} = decode_pubsub_retract_attrs(__TopXMLNS, - _attrs, undefined, undefined), - {ps_retract, Node, Notify, Items}. - -decode_pubsub_retract_els(__TopXMLNS, __IgnoreEls, [], - Items) -> - lists:reverse(Items); -decode_pubsub_retract_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"item">>, _attrs, _} = _el | _els], - Items) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_retract_els(__TopXMLNS, __IgnoreEls, _els, - [decode_pubsub_item(__TopXMLNS, __IgnoreEls, - _el) - | Items]); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_retract_els(__TopXMLNS, __IgnoreEls, _els, - [decode_pubsub_item(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el) - | Items]); - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_retract_els(__TopXMLNS, __IgnoreEls, _els, - [decode_pubsub_item(<<"http://jabber.org/protocol/pubsub#event">>, - __IgnoreEls, _el) - | Items]); - _ -> - decode_pubsub_retract_els(__TopXMLNS, __IgnoreEls, _els, - Items) - end; -decode_pubsub_retract_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Items) -> - decode_pubsub_retract_els(__TopXMLNS, __IgnoreEls, _els, - Items). - -decode_pubsub_retract_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], _Node, Notify) -> - decode_pubsub_retract_attrs(__TopXMLNS, _attrs, _val, - Notify); -decode_pubsub_retract_attrs(__TopXMLNS, - [{<<"notify">>, _val} | _attrs], Node, _Notify) -> - decode_pubsub_retract_attrs(__TopXMLNS, _attrs, Node, - _val); -decode_pubsub_retract_attrs(__TopXMLNS, [_ | _attrs], - Node, Notify) -> - decode_pubsub_retract_attrs(__TopXMLNS, _attrs, Node, - Notify); -decode_pubsub_retract_attrs(__TopXMLNS, [], Node, - Notify) -> - {decode_pubsub_retract_attr_node(__TopXMLNS, Node), - decode_pubsub_retract_attr_notify(__TopXMLNS, Notify)}. - -encode_pubsub_retract({ps_retract, Node, Notify, Items}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_pubsub_retract_$items'(Items, - __NewTopXMLNS, [])), - _attrs = encode_pubsub_retract_attr_notify(Notify, - encode_pubsub_retract_attr_node(Node, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))), - {xmlel, <<"retract">>, _attrs, _els}. - -'encode_pubsub_retract_$items'([], __TopXMLNS, _acc) -> - _acc; -'encode_pubsub_retract_$items'([Items | _els], - __TopXMLNS, _acc) -> - 'encode_pubsub_retract_$items'(_els, __TopXMLNS, - [encode_pubsub_item(Items, __TopXMLNS) - | _acc]). - -decode_pubsub_retract_attr_node(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"node">>, <<"retract">>, __TopXMLNS}}); -decode_pubsub_retract_attr_node(__TopXMLNS, _val) -> - _val. - -encode_pubsub_retract_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_pubsub_retract_attr_notify(__TopXMLNS, - undefined) -> - false; -decode_pubsub_retract_attr_notify(__TopXMLNS, _val) -> - case catch dec_bool(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"notify">>, <<"retract">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_pubsub_retract_attr_notify(false, _acc) -> _acc; -encode_pubsub_retract_attr_notify(_val, _acc) -> - [{<<"notify">>, enc_bool(_val)} | _acc]. - -decode_pubsub_options(__TopXMLNS, __IgnoreEls, - {xmlel, <<"options">>, _attrs, _els}) -> - Xdata = decode_pubsub_options_els(__TopXMLNS, - __IgnoreEls, _els, undefined), - {Node, Subid, Jid} = - decode_pubsub_options_attrs(__TopXMLNS, _attrs, - undefined, undefined, undefined), - {ps_options, Node, Jid, Subid, Xdata}. - -decode_pubsub_options_els(__TopXMLNS, __IgnoreEls, [], - Xdata) -> - Xdata; -decode_pubsub_options_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"x">>, _attrs, _} = _el | _els], Xdata) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"jabber:x:data">> -> - decode_pubsub_options_els(__TopXMLNS, __IgnoreEls, _els, - decode_xdata(<<"jabber:x:data">>, - __IgnoreEls, _el)); - _ -> - decode_pubsub_options_els(__TopXMLNS, __IgnoreEls, _els, - Xdata) - end; -decode_pubsub_options_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Xdata) -> - decode_pubsub_options_els(__TopXMLNS, __IgnoreEls, _els, - Xdata). - -decode_pubsub_options_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], _Node, Subid, Jid) -> - decode_pubsub_options_attrs(__TopXMLNS, _attrs, _val, - Subid, Jid); -decode_pubsub_options_attrs(__TopXMLNS, - [{<<"subid">>, _val} | _attrs], Node, _Subid, - Jid) -> - decode_pubsub_options_attrs(__TopXMLNS, _attrs, Node, - _val, Jid); -decode_pubsub_options_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], Node, Subid, _Jid) -> - decode_pubsub_options_attrs(__TopXMLNS, _attrs, Node, - Subid, _val); -decode_pubsub_options_attrs(__TopXMLNS, [_ | _attrs], - Node, Subid, Jid) -> - decode_pubsub_options_attrs(__TopXMLNS, _attrs, Node, - Subid, Jid); -decode_pubsub_options_attrs(__TopXMLNS, [], Node, Subid, - Jid) -> - {decode_pubsub_options_attr_node(__TopXMLNS, Node), - decode_pubsub_options_attr_subid(__TopXMLNS, Subid), - decode_pubsub_options_attr_jid(__TopXMLNS, Jid)}. - -encode_pubsub_options({ps_options, Node, Jid, Subid, - Xdata}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_pubsub_options_$xdata'(Xdata, - __NewTopXMLNS, [])), - _attrs = encode_pubsub_options_attr_jid(Jid, - encode_pubsub_options_attr_subid(Subid, - encode_pubsub_options_attr_node(Node, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)))), - {xmlel, <<"options">>, _attrs, _els}. - -'encode_pubsub_options_$xdata'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_pubsub_options_$xdata'(Xdata, __TopXMLNS, - _acc) -> - [encode_xdata(Xdata, __TopXMLNS) | _acc]. - -decode_pubsub_options_attr_node(__TopXMLNS, - undefined) -> - <<>>; -decode_pubsub_options_attr_node(__TopXMLNS, _val) -> - _val. - -encode_pubsub_options_attr_node(<<>>, _acc) -> _acc; -encode_pubsub_options_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_pubsub_options_attr_subid(__TopXMLNS, - undefined) -> - <<>>; -decode_pubsub_options_attr_subid(__TopXMLNS, _val) -> - _val. - -encode_pubsub_options_attr_subid(<<>>, _acc) -> _acc; -encode_pubsub_options_attr_subid(_val, _acc) -> - [{<<"subid">>, _val} | _acc]. - -decode_pubsub_options_attr_jid(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"jid">>, <<"options">>, __TopXMLNS}}); -decode_pubsub_options_attr_jid(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"jid">>, <<"options">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_pubsub_options_attr_jid(_val, _acc) -> - [{<<"jid">>, enc_jid(_val)} | _acc]. - -decode_pubsub_publish(__TopXMLNS, __IgnoreEls, - {xmlel, <<"publish">>, _attrs, _els}) -> - Items = decode_pubsub_publish_els(__TopXMLNS, - __IgnoreEls, _els, []), - Node = decode_pubsub_publish_attrs(__TopXMLNS, _attrs, - undefined), - {ps_publish, Node, Items}. - -decode_pubsub_publish_els(__TopXMLNS, __IgnoreEls, [], - Items) -> - lists:reverse(Items); -decode_pubsub_publish_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"item">>, _attrs, _} = _el | _els], - Items) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_publish_els(__TopXMLNS, __IgnoreEls, _els, - [decode_pubsub_item(__TopXMLNS, __IgnoreEls, - _el) - | Items]); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_publish_els(__TopXMLNS, __IgnoreEls, _els, - [decode_pubsub_item(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el) - | Items]); - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_publish_els(__TopXMLNS, __IgnoreEls, _els, - [decode_pubsub_item(<<"http://jabber.org/protocol/pubsub#event">>, - __IgnoreEls, _el) - | Items]); - _ -> - decode_pubsub_publish_els(__TopXMLNS, __IgnoreEls, _els, - Items) - end; -decode_pubsub_publish_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Items) -> - decode_pubsub_publish_els(__TopXMLNS, __IgnoreEls, _els, - Items). - -decode_pubsub_publish_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], _Node) -> - decode_pubsub_publish_attrs(__TopXMLNS, _attrs, _val); -decode_pubsub_publish_attrs(__TopXMLNS, [_ | _attrs], - Node) -> - decode_pubsub_publish_attrs(__TopXMLNS, _attrs, Node); -decode_pubsub_publish_attrs(__TopXMLNS, [], Node) -> - decode_pubsub_publish_attr_node(__TopXMLNS, Node). - -encode_pubsub_publish({ps_publish, Node, Items}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_pubsub_publish_$items'(Items, - __NewTopXMLNS, [])), - _attrs = encode_pubsub_publish_attr_node(Node, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"publish">>, _attrs, _els}. - -'encode_pubsub_publish_$items'([], __TopXMLNS, _acc) -> - _acc; -'encode_pubsub_publish_$items'([Items | _els], - __TopXMLNS, _acc) -> - 'encode_pubsub_publish_$items'(_els, __TopXMLNS, - [encode_pubsub_item(Items, __TopXMLNS) - | _acc]). - -decode_pubsub_publish_attr_node(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"node">>, <<"publish">>, __TopXMLNS}}); -decode_pubsub_publish_attr_node(__TopXMLNS, _val) -> - _val. - -encode_pubsub_publish_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_pubsub_unsubscribe(__TopXMLNS, __IgnoreEls, - {xmlel, <<"unsubscribe">>, _attrs, _els}) -> - {Node, Subid, Jid} = - decode_pubsub_unsubscribe_attrs(__TopXMLNS, _attrs, - undefined, undefined, undefined), - {ps_unsubscribe, Node, Jid, Subid}. - -decode_pubsub_unsubscribe_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], _Node, Subid, - Jid) -> - decode_pubsub_unsubscribe_attrs(__TopXMLNS, _attrs, - _val, Subid, Jid); -decode_pubsub_unsubscribe_attrs(__TopXMLNS, - [{<<"subid">>, _val} | _attrs], Node, _Subid, - Jid) -> - decode_pubsub_unsubscribe_attrs(__TopXMLNS, _attrs, - Node, _val, Jid); -decode_pubsub_unsubscribe_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], Node, Subid, - _Jid) -> - decode_pubsub_unsubscribe_attrs(__TopXMLNS, _attrs, - Node, Subid, _val); -decode_pubsub_unsubscribe_attrs(__TopXMLNS, - [_ | _attrs], Node, Subid, Jid) -> - decode_pubsub_unsubscribe_attrs(__TopXMLNS, _attrs, - Node, Subid, Jid); -decode_pubsub_unsubscribe_attrs(__TopXMLNS, [], Node, - Subid, Jid) -> - {decode_pubsub_unsubscribe_attr_node(__TopXMLNS, Node), - decode_pubsub_unsubscribe_attr_subid(__TopXMLNS, Subid), - decode_pubsub_unsubscribe_attr_jid(__TopXMLNS, Jid)}. - -encode_pubsub_unsubscribe({ps_unsubscribe, Node, Jid, - Subid}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub">>, - [], __TopXMLNS), - _els = [], - _attrs = encode_pubsub_unsubscribe_attr_jid(Jid, - encode_pubsub_unsubscribe_attr_subid(Subid, - encode_pubsub_unsubscribe_attr_node(Node, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)))), - {xmlel, <<"unsubscribe">>, _attrs, _els}. - -decode_pubsub_unsubscribe_attr_node(__TopXMLNS, - undefined) -> - <<>>; -decode_pubsub_unsubscribe_attr_node(__TopXMLNS, _val) -> - _val. - -encode_pubsub_unsubscribe_attr_node(<<>>, _acc) -> _acc; -encode_pubsub_unsubscribe_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_pubsub_unsubscribe_attr_subid(__TopXMLNS, - undefined) -> - <<>>; -decode_pubsub_unsubscribe_attr_subid(__TopXMLNS, - _val) -> - _val. - -encode_pubsub_unsubscribe_attr_subid(<<>>, _acc) -> - _acc; -encode_pubsub_unsubscribe_attr_subid(_val, _acc) -> - [{<<"subid">>, _val} | _acc]. - -decode_pubsub_unsubscribe_attr_jid(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"jid">>, <<"unsubscribe">>, - __TopXMLNS}}); -decode_pubsub_unsubscribe_attr_jid(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"jid">>, <<"unsubscribe">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_pubsub_unsubscribe_attr_jid(_val, _acc) -> - [{<<"jid">>, enc_jid(_val)} | _acc]. - -decode_pubsub_subscribe(__TopXMLNS, __IgnoreEls, - {xmlel, <<"subscribe">>, _attrs, _els}) -> - {Node, Jid} = decode_pubsub_subscribe_attrs(__TopXMLNS, - _attrs, undefined, undefined), - {ps_subscribe, Node, Jid}. - -decode_pubsub_subscribe_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], _Node, Jid) -> - decode_pubsub_subscribe_attrs(__TopXMLNS, _attrs, _val, - Jid); -decode_pubsub_subscribe_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], Node, _Jid) -> - decode_pubsub_subscribe_attrs(__TopXMLNS, _attrs, Node, - _val); -decode_pubsub_subscribe_attrs(__TopXMLNS, [_ | _attrs], - Node, Jid) -> - decode_pubsub_subscribe_attrs(__TopXMLNS, _attrs, Node, - Jid); -decode_pubsub_subscribe_attrs(__TopXMLNS, [], Node, - Jid) -> - {decode_pubsub_subscribe_attr_node(__TopXMLNS, Node), - decode_pubsub_subscribe_attr_jid(__TopXMLNS, Jid)}. - -encode_pubsub_subscribe({ps_subscribe, Node, Jid}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub">>, - [], __TopXMLNS), - _els = [], - _attrs = encode_pubsub_subscribe_attr_jid(Jid, - encode_pubsub_subscribe_attr_node(Node, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))), - {xmlel, <<"subscribe">>, _attrs, _els}. - -decode_pubsub_subscribe_attr_node(__TopXMLNS, - undefined) -> - <<>>; -decode_pubsub_subscribe_attr_node(__TopXMLNS, _val) -> - _val. - -encode_pubsub_subscribe_attr_node(<<>>, _acc) -> _acc; -encode_pubsub_subscribe_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_pubsub_subscribe_attr_jid(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"jid">>, <<"subscribe">>, - __TopXMLNS}}); -decode_pubsub_subscribe_attr_jid(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"jid">>, <<"subscribe">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_pubsub_subscribe_attr_jid(_val, _acc) -> - [{<<"jid">>, enc_jid(_val)} | _acc]. - -decode_pubsub_owner_affiliations(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"affiliations">>, _attrs, _els}) -> - Affiliations = - decode_pubsub_owner_affiliations_els(__TopXMLNS, - __IgnoreEls, _els, []), - Node = - decode_pubsub_owner_affiliations_attrs(__TopXMLNS, - _attrs, undefined), - {Node, Affiliations}. - -decode_pubsub_owner_affiliations_els(__TopXMLNS, - __IgnoreEls, [], Affiliations) -> - lists:reverse(Affiliations); -decode_pubsub_owner_affiliations_els(__TopXMLNS, - __IgnoreEls, - [{xmlel, <<"affiliation">>, _attrs, _} = - _el - | _els], - Affiliations) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_owner_affiliations_els(__TopXMLNS, - __IgnoreEls, _els, - [decode_pubsub_owner_affiliation(__TopXMLNS, - __IgnoreEls, - _el) - | Affiliations]); - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_owner_affiliations_els(__TopXMLNS, - __IgnoreEls, _els, - [decode_pubsub_owner_affiliation(<<"http://jabber.org/protocol/pubsub#owner">>, - __IgnoreEls, - _el) - | Affiliations]); - _ -> - decode_pubsub_owner_affiliations_els(__TopXMLNS, - __IgnoreEls, _els, Affiliations) - end; -decode_pubsub_owner_affiliations_els(__TopXMLNS, - __IgnoreEls, [_ | _els], Affiliations) -> - decode_pubsub_owner_affiliations_els(__TopXMLNS, - __IgnoreEls, _els, Affiliations). - -decode_pubsub_owner_affiliations_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], _Node) -> - decode_pubsub_owner_affiliations_attrs(__TopXMLNS, - _attrs, _val); -decode_pubsub_owner_affiliations_attrs(__TopXMLNS, - [_ | _attrs], Node) -> - decode_pubsub_owner_affiliations_attrs(__TopXMLNS, - _attrs, Node); -decode_pubsub_owner_affiliations_attrs(__TopXMLNS, [], - Node) -> - decode_pubsub_owner_affiliations_attr_node(__TopXMLNS, - Node). - -encode_pubsub_owner_affiliations({Node, Affiliations}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#owner">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_pubsub_owner_affiliations_$affiliations'(Affiliations, - __NewTopXMLNS, - [])), - _attrs = - encode_pubsub_owner_affiliations_attr_node(Node, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"affiliations">>, _attrs, _els}. - -'encode_pubsub_owner_affiliations_$affiliations'([], - __TopXMLNS, _acc) -> - _acc; -'encode_pubsub_owner_affiliations_$affiliations'([Affiliations - | _els], - __TopXMLNS, _acc) -> - 'encode_pubsub_owner_affiliations_$affiliations'(_els, - __TopXMLNS, - [encode_pubsub_owner_affiliation(Affiliations, - __TopXMLNS) - | _acc]). - -decode_pubsub_owner_affiliations_attr_node(__TopXMLNS, - undefined) -> - <<>>; -decode_pubsub_owner_affiliations_attr_node(__TopXMLNS, - _val) -> - _val. - -encode_pubsub_owner_affiliations_attr_node(<<>>, - _acc) -> - _acc; -encode_pubsub_owner_affiliations_attr_node(_val, - _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_pubsub_affiliations(__TopXMLNS, __IgnoreEls, - {xmlel, <<"affiliations">>, _attrs, _els}) -> - Affiliations = - decode_pubsub_affiliations_els(__TopXMLNS, __IgnoreEls, - _els, []), - Node = decode_pubsub_affiliations_attrs(__TopXMLNS, - _attrs, undefined), - {Node, Affiliations}. - -decode_pubsub_affiliations_els(__TopXMLNS, __IgnoreEls, - [], Affiliations) -> - lists:reverse(Affiliations); -decode_pubsub_affiliations_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"affiliation">>, _attrs, _} = _el - | _els], - Affiliations) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_affiliations_els(__TopXMLNS, __IgnoreEls, - _els, - [decode_pubsub_affiliation(__TopXMLNS, - __IgnoreEls, - _el) - | Affiliations]); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_affiliations_els(__TopXMLNS, __IgnoreEls, - _els, - [decode_pubsub_affiliation(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, - _el) - | Affiliations]); - _ -> - decode_pubsub_affiliations_els(__TopXMLNS, __IgnoreEls, - _els, Affiliations) - end; -decode_pubsub_affiliations_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Affiliations) -> - decode_pubsub_affiliations_els(__TopXMLNS, __IgnoreEls, - _els, Affiliations). - -decode_pubsub_affiliations_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], _Node) -> - decode_pubsub_affiliations_attrs(__TopXMLNS, _attrs, - _val); -decode_pubsub_affiliations_attrs(__TopXMLNS, - [_ | _attrs], Node) -> - decode_pubsub_affiliations_attrs(__TopXMLNS, _attrs, - Node); -decode_pubsub_affiliations_attrs(__TopXMLNS, [], - Node) -> - decode_pubsub_affiliations_attr_node(__TopXMLNS, Node). - -encode_pubsub_affiliations({Node, Affiliations}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_pubsub_affiliations_$affiliations'(Affiliations, - __NewTopXMLNS, - [])), - _attrs = encode_pubsub_affiliations_attr_node(Node, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"affiliations">>, _attrs, _els}. - -'encode_pubsub_affiliations_$affiliations'([], - __TopXMLNS, _acc) -> - _acc; -'encode_pubsub_affiliations_$affiliations'([Affiliations - | _els], - __TopXMLNS, _acc) -> - 'encode_pubsub_affiliations_$affiliations'(_els, - __TopXMLNS, - [encode_pubsub_affiliation(Affiliations, - __TopXMLNS) - | _acc]). - -decode_pubsub_affiliations_attr_node(__TopXMLNS, - undefined) -> - <<>>; -decode_pubsub_affiliations_attr_node(__TopXMLNS, - _val) -> - _val. - -encode_pubsub_affiliations_attr_node(<<>>, _acc) -> - _acc; -encode_pubsub_affiliations_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_pubsub_subscriptions(__TopXMLNS, __IgnoreEls, - {xmlel, <<"subscriptions">>, _attrs, _els}) -> - Subscriptions = - decode_pubsub_subscriptions_els(__TopXMLNS, __IgnoreEls, - _els, []), - Node = decode_pubsub_subscriptions_attrs(__TopXMLNS, - _attrs, undefined), - {Node, Subscriptions}. - -decode_pubsub_subscriptions_els(__TopXMLNS, __IgnoreEls, - [], Subscriptions) -> - lists:reverse(Subscriptions); -decode_pubsub_subscriptions_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"subscription">>, _attrs, _} = _el - | _els], - Subscriptions) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub">>; - __TopXMLNS == - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_subscriptions_els(__TopXMLNS, __IgnoreEls, - _els, - [decode_pubsub_subscription(__TopXMLNS, - __IgnoreEls, - _el) - | Subscriptions]); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_subscriptions_els(__TopXMLNS, __IgnoreEls, - _els, - [decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, - _el) - | Subscriptions]); - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_subscriptions_els(__TopXMLNS, __IgnoreEls, - _els, - [decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub#owner">>, - __IgnoreEls, - _el) - | Subscriptions]); - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_subscriptions_els(__TopXMLNS, __IgnoreEls, - _els, - [decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub#event">>, - __IgnoreEls, - _el) - | Subscriptions]); - _ -> - decode_pubsub_subscriptions_els(__TopXMLNS, __IgnoreEls, - _els, Subscriptions) - end; -decode_pubsub_subscriptions_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Subscriptions) -> - decode_pubsub_subscriptions_els(__TopXMLNS, __IgnoreEls, - _els, Subscriptions). - -decode_pubsub_subscriptions_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], _Node) -> - decode_pubsub_subscriptions_attrs(__TopXMLNS, _attrs, - _val); -decode_pubsub_subscriptions_attrs(__TopXMLNS, - [_ | _attrs], Node) -> - decode_pubsub_subscriptions_attrs(__TopXMLNS, _attrs, - Node); -decode_pubsub_subscriptions_attrs(__TopXMLNS, [], - Node) -> - decode_pubsub_subscriptions_attr_node(__TopXMLNS, Node). - -encode_pubsub_subscriptions({Node, Subscriptions}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"http://jabber.org/protocol/pubsub">>, - <<"http://jabber.org/protocol/pubsub#owner">>], - __TopXMLNS), - _els = - lists:reverse('encode_pubsub_subscriptions_$subscriptions'(Subscriptions, - __NewTopXMLNS, - [])), - _attrs = encode_pubsub_subscriptions_attr_node(Node, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"subscriptions">>, _attrs, _els}. - -'encode_pubsub_subscriptions_$subscriptions'([], - __TopXMLNS, _acc) -> - _acc; -'encode_pubsub_subscriptions_$subscriptions'([Subscriptions - | _els], - __TopXMLNS, _acc) -> - 'encode_pubsub_subscriptions_$subscriptions'(_els, - __TopXMLNS, - [encode_pubsub_subscription(Subscriptions, - __TopXMLNS) - | _acc]). - -decode_pubsub_subscriptions_attr_node(__TopXMLNS, - undefined) -> - <<>>; -decode_pubsub_subscriptions_attr_node(__TopXMLNS, - _val) -> - _val. - -encode_pubsub_subscriptions_attr_node(<<>>, _acc) -> - _acc; -encode_pubsub_subscriptions_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_pubsub_event(__TopXMLNS, __IgnoreEls, - {xmlel, <<"event">>, _attrs, _els}) -> - {Items, Create, Delete, Purge, Configuration, - Subscription} = - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - undefined, undefined, undefined, undefined, - undefined, undefined), - {ps_event, Items, Purge, Subscription, Delete, Create, - Configuration}. - -decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, [], - Items, Create, Delete, Purge, Configuration, - Subscription) -> - {Items, Create, Delete, Purge, Configuration, - Subscription}; -decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"items">>, _attrs, _} = _el | _els], Items, - Create, Delete, Purge, Configuration, Subscription) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - decode_pubsub_items(__TopXMLNS, __IgnoreEls, - _el), - Create, Delete, Purge, Configuration, - Subscription); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - decode_pubsub_items(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el), - Create, Delete, Purge, Configuration, - Subscription); - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - decode_pubsub_items(<<"http://jabber.org/protocol/pubsub#event">>, - __IgnoreEls, _el), - Create, Delete, Purge, Configuration, - Subscription); - _ -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items, Create, Delete, Purge, Configuration, - Subscription) - end; -decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"subscription">>, _attrs, _} = _el | _els], - Items, Create, Delete, Purge, Configuration, - Subscription) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items, Create, Delete, Purge, Configuration, - decode_pubsub_subscription(__TopXMLNS, - __IgnoreEls, _el)); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items, Create, Delete, Purge, Configuration, - decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el)); - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items, Create, Delete, Purge, Configuration, - decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub#owner">>, - __IgnoreEls, _el)); - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items, Create, Delete, Purge, Configuration, - decode_pubsub_subscription(<<"http://jabber.org/protocol/pubsub#event">>, - __IgnoreEls, _el)); - _ -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items, Create, Delete, Purge, Configuration, - Subscription) - end; -decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"purge">>, _attrs, _} = _el | _els], Items, - Create, Delete, Purge, Configuration, Subscription) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items, Create, Delete, - decode_pubsub_purge(__TopXMLNS, __IgnoreEls, - _el), - Configuration, Subscription); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items, Create, Delete, - decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el), - Configuration, Subscription); - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items, Create, Delete, - decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub#owner">>, - __IgnoreEls, _el), - Configuration, Subscription); - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items, Create, Delete, - decode_pubsub_purge(<<"http://jabber.org/protocol/pubsub#event">>, - __IgnoreEls, _el), - Configuration, Subscription); - _ -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items, Create, Delete, Purge, Configuration, - Subscription) - end; -decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"delete">>, _attrs, _} = _el | _els], Items, - Create, Delete, Purge, Configuration, Subscription) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items, Create, - decode_pubsub_delete(__TopXMLNS, __IgnoreEls, - _el), - Purge, Configuration, Subscription); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items, Create, - decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el), - Purge, Configuration, Subscription); - <<"http://jabber.org/protocol/pubsub#owner">> -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items, Create, - decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub#owner">>, - __IgnoreEls, _el), - Purge, Configuration, Subscription); - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items, Create, - decode_pubsub_delete(<<"http://jabber.org/protocol/pubsub#event">>, - __IgnoreEls, _el), - Purge, Configuration, Subscription); - _ -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items, Create, Delete, Purge, Configuration, - Subscription) - end; -decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"create">>, _attrs, _} = _el | _els], Items, - Create, Delete, Purge, Configuration, Subscription) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items, - decode_pubsub_create(__TopXMLNS, __IgnoreEls, - _el), - Delete, Purge, Configuration, Subscription); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items, - decode_pubsub_create(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el), - Delete, Purge, Configuration, Subscription); - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items, - decode_pubsub_create(<<"http://jabber.org/protocol/pubsub#event">>, - __IgnoreEls, _el), - Delete, Purge, Configuration, Subscription); - _ -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items, Create, Delete, Purge, Configuration, - Subscription) - end; -decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"configuration">>, _attrs, _} = _el | _els], - Items, Create, Delete, Purge, Configuration, - Subscription) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items, Create, Delete, Purge, - decode_pubsub_event_configuration(__TopXMLNS, - __IgnoreEls, - _el), - Subscription); - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items, Create, Delete, Purge, - decode_pubsub_event_configuration(<<"http://jabber.org/protocol/pubsub#event">>, - __IgnoreEls, - _el), - Subscription); - _ -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items, Create, Delete, Purge, Configuration, - Subscription) - end; -decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Items, Create, Delete, Purge, Configuration, - Subscription) -> - decode_pubsub_event_els(__TopXMLNS, __IgnoreEls, _els, - Items, Create, Delete, Purge, Configuration, - Subscription). - -encode_pubsub_event({ps_event, Items, Purge, - Subscription, Delete, Create, Configuration}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#event">>, - [], __TopXMLNS), - _els = lists:reverse('encode_pubsub_event_$items'(Items, - __NewTopXMLNS, - 'encode_pubsub_event_$create'(Create, - __NewTopXMLNS, - 'encode_pubsub_event_$delete'(Delete, - __NewTopXMLNS, - 'encode_pubsub_event_$purge'(Purge, - __NewTopXMLNS, - 'encode_pubsub_event_$configuration'(Configuration, - __NewTopXMLNS, - 'encode_pubsub_event_$subscription'(Subscription, - __NewTopXMLNS, - []))))))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"event">>, _attrs, _els}. - -'encode_pubsub_event_$items'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_pubsub_event_$items'(Items, __TopXMLNS, _acc) -> - [encode_pubsub_items(Items, __TopXMLNS) | _acc]. - -'encode_pubsub_event_$create'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_pubsub_event_$create'(Create, __TopXMLNS, - _acc) -> - [encode_pubsub_create(Create, __TopXMLNS) | _acc]. - -'encode_pubsub_event_$delete'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_pubsub_event_$delete'(Delete, __TopXMLNS, - _acc) -> - [encode_pubsub_delete(Delete, __TopXMLNS) | _acc]. - -'encode_pubsub_event_$purge'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_pubsub_event_$purge'(Purge, __TopXMLNS, _acc) -> - [encode_pubsub_purge(Purge, __TopXMLNS) | _acc]. - -'encode_pubsub_event_$configuration'(undefined, - __TopXMLNS, _acc) -> - _acc; -'encode_pubsub_event_$configuration'(Configuration, - __TopXMLNS, _acc) -> - [encode_pubsub_event_configuration(Configuration, - __TopXMLNS) - | _acc]. - -'encode_pubsub_event_$subscription'(undefined, - __TopXMLNS, _acc) -> - _acc; -'encode_pubsub_event_$subscription'(Subscription, - __TopXMLNS, _acc) -> - [encode_pubsub_subscription(Subscription, __TopXMLNS) - | _acc]. - -decode_pubsub_items(__TopXMLNS, __IgnoreEls, - {xmlel, <<"items">>, _attrs, _els}) -> - {Items, Retract} = decode_pubsub_items_els(__TopXMLNS, - __IgnoreEls, _els, [], - undefined), - {Xmlns, Max_items, Node, Subid} = - decode_pubsub_items_attrs(__TopXMLNS, _attrs, undefined, - undefined, undefined, undefined), - {ps_items, Xmlns, Node, Items, Max_items, Subid, - Retract}. - -decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, [], - Items, Retract) -> - {lists:reverse(Items), Retract}; -decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"retract">>, _attrs, _} = _el | _els], Items, - Retract) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, _els, - Items, - decode_pubsub_event_retract(__TopXMLNS, - __IgnoreEls, - _el)); - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, _els, - Items, - decode_pubsub_event_retract(<<"http://jabber.org/protocol/pubsub#event">>, - __IgnoreEls, - _el)); - _ -> - decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, _els, - Items, Retract) - end; -decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items, - Retract) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/pubsub">>; - __TopXMLNS == - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, _els, - [decode_pubsub_item(__TopXMLNS, __IgnoreEls, - _el) - | Items], - Retract); - <<"http://jabber.org/protocol/pubsub">> -> - decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, _els, - [decode_pubsub_item(<<"http://jabber.org/protocol/pubsub">>, - __IgnoreEls, _el) - | Items], - Retract); - <<"http://jabber.org/protocol/pubsub#event">> -> - decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, _els, - [decode_pubsub_item(<<"http://jabber.org/protocol/pubsub#event">>, - __IgnoreEls, _el) - | Items], - Retract); - _ -> - decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, _els, - Items, Retract) - end; -decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Items, Retract) -> - decode_pubsub_items_els(__TopXMLNS, __IgnoreEls, _els, - Items, Retract). - -decode_pubsub_items_attrs(__TopXMLNS, - [{<<"xmlns">>, _val} | _attrs], _Xmlns, Max_items, - Node, Subid) -> - decode_pubsub_items_attrs(__TopXMLNS, _attrs, _val, - Max_items, Node, Subid); -decode_pubsub_items_attrs(__TopXMLNS, - [{<<"max_items">>, _val} | _attrs], Xmlns, _Max_items, - Node, Subid) -> - decode_pubsub_items_attrs(__TopXMLNS, _attrs, Xmlns, - _val, Node, Subid); -decode_pubsub_items_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], Xmlns, Max_items, - _Node, Subid) -> - decode_pubsub_items_attrs(__TopXMLNS, _attrs, Xmlns, - Max_items, _val, Subid); -decode_pubsub_items_attrs(__TopXMLNS, - [{<<"subid">>, _val} | _attrs], Xmlns, Max_items, - Node, _Subid) -> - decode_pubsub_items_attrs(__TopXMLNS, _attrs, Xmlns, - Max_items, Node, _val); -decode_pubsub_items_attrs(__TopXMLNS, [_ | _attrs], - Xmlns, Max_items, Node, Subid) -> - decode_pubsub_items_attrs(__TopXMLNS, _attrs, Xmlns, - Max_items, Node, Subid); -decode_pubsub_items_attrs(__TopXMLNS, [], Xmlns, - Max_items, Node, Subid) -> - {decode_pubsub_items_attr_xmlns(__TopXMLNS, Xmlns), - decode_pubsub_items_attr_max_items(__TopXMLNS, - Max_items), - decode_pubsub_items_attr_node(__TopXMLNS, Node), - decode_pubsub_items_attr_subid(__TopXMLNS, Subid)}. - -encode_pubsub_items({ps_items, Xmlns, Node, Items, - Max_items, Subid, Retract}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(Xmlns, - [<<"http://jabber.org/protocol/pubsub">>, - <<"http://jabber.org/protocol/pubsub#event">>], - __TopXMLNS), - _els = lists:reverse('encode_pubsub_items_$items'(Items, - __NewTopXMLNS, - 'encode_pubsub_items_$retract'(Retract, - __NewTopXMLNS, - []))), - _attrs = encode_pubsub_items_attr_subid(Subid, - encode_pubsub_items_attr_node(Node, - encode_pubsub_items_attr_max_items(Max_items, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)))), - {xmlel, <<"items">>, _attrs, _els}. - -'encode_pubsub_items_$items'([], __TopXMLNS, _acc) -> - _acc; -'encode_pubsub_items_$items'([Items | _els], __TopXMLNS, - _acc) -> - 'encode_pubsub_items_$items'(_els, __TopXMLNS, - [encode_pubsub_item(Items, __TopXMLNS) - | _acc]). - -'encode_pubsub_items_$retract'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_pubsub_items_$retract'(Retract, __TopXMLNS, - _acc) -> - [encode_pubsub_event_retract(Retract, __TopXMLNS) - | _acc]. - -decode_pubsub_items_attr_xmlns(__TopXMLNS, undefined) -> - <<>>; -decode_pubsub_items_attr_xmlns(__TopXMLNS, _val) -> - _val. - -decode_pubsub_items_attr_max_items(__TopXMLNS, - undefined) -> - undefined; -decode_pubsub_items_attr_max_items(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, infinity) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"max_items">>, <<"items">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_pubsub_items_attr_max_items(undefined, _acc) -> - _acc; -encode_pubsub_items_attr_max_items(_val, _acc) -> - [{<<"max_items">>, enc_int(_val)} | _acc]. - -decode_pubsub_items_attr_node(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"node">>, <<"items">>, __TopXMLNS}}); -decode_pubsub_items_attr_node(__TopXMLNS, _val) -> _val. - -encode_pubsub_items_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_pubsub_items_attr_subid(__TopXMLNS, undefined) -> - <<>>; -decode_pubsub_items_attr_subid(__TopXMLNS, _val) -> - _val. - -encode_pubsub_items_attr_subid(<<>>, _acc) -> _acc; -encode_pubsub_items_attr_subid(_val, _acc) -> - [{<<"subid">>, _val} | _acc]. - -decode_pubsub_item(__TopXMLNS, __IgnoreEls, - {xmlel, <<"item">>, _attrs, _els}) -> - __Xmls = decode_pubsub_item_els(__TopXMLNS, __IgnoreEls, - _els, []), - {Id, Xmlns, Node, Publisher} = - decode_pubsub_item_attrs(__TopXMLNS, _attrs, undefined, - undefined, undefined, undefined), - {ps_item, Xmlns, Id, __Xmls, Node, Publisher}. - -decode_pubsub_item_els(__TopXMLNS, __IgnoreEls, [], - __Xmls) -> - lists:reverse(__Xmls); -decode_pubsub_item_els(__TopXMLNS, __IgnoreEls, - [{xmlel, _, _, _} = _el | _els], __Xmls) -> - decode_pubsub_item_els(__TopXMLNS, __IgnoreEls, _els, - [_el | __Xmls]); -decode_pubsub_item_els(__TopXMLNS, __IgnoreEls, - [_ | _els], __Xmls) -> - decode_pubsub_item_els(__TopXMLNS, __IgnoreEls, _els, - __Xmls). - -decode_pubsub_item_attrs(__TopXMLNS, - [{<<"id">>, _val} | _attrs], _Id, Xmlns, Node, - Publisher) -> - decode_pubsub_item_attrs(__TopXMLNS, _attrs, _val, - Xmlns, Node, Publisher); -decode_pubsub_item_attrs(__TopXMLNS, - [{<<"xmlns">>, _val} | _attrs], Id, _Xmlns, Node, - Publisher) -> - decode_pubsub_item_attrs(__TopXMLNS, _attrs, Id, _val, - Node, Publisher); -decode_pubsub_item_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], Id, Xmlns, _Node, - Publisher) -> - decode_pubsub_item_attrs(__TopXMLNS, _attrs, Id, Xmlns, - _val, Publisher); -decode_pubsub_item_attrs(__TopXMLNS, - [{<<"publisher">>, _val} | _attrs], Id, Xmlns, Node, - _Publisher) -> - decode_pubsub_item_attrs(__TopXMLNS, _attrs, Id, Xmlns, - Node, _val); -decode_pubsub_item_attrs(__TopXMLNS, [_ | _attrs], Id, - Xmlns, Node, Publisher) -> - decode_pubsub_item_attrs(__TopXMLNS, _attrs, Id, Xmlns, - Node, Publisher); -decode_pubsub_item_attrs(__TopXMLNS, [], Id, Xmlns, - Node, Publisher) -> - {decode_pubsub_item_attr_id(__TopXMLNS, Id), - decode_pubsub_item_attr_xmlns(__TopXMLNS, Xmlns), - decode_pubsub_item_attr_node(__TopXMLNS, Node), - decode_pubsub_item_attr_publisher(__TopXMLNS, - Publisher)}. - -encode_pubsub_item({ps_item, Xmlns, Id, __Xmls, Node, - Publisher}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(Xmlns, - [<<"http://jabber.org/protocol/pubsub">>, - <<"http://jabber.org/protocol/pubsub#event">>], - __TopXMLNS), - _els = __Xmls, - _attrs = encode_pubsub_item_attr_publisher(Publisher, - encode_pubsub_item_attr_node(Node, - encode_pubsub_item_attr_id(Id, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)))), - {xmlel, <<"item">>, _attrs, _els}. - -decode_pubsub_item_attr_id(__TopXMLNS, undefined) -> - <<>>; -decode_pubsub_item_attr_id(__TopXMLNS, _val) -> _val. - -encode_pubsub_item_attr_id(<<>>, _acc) -> _acc; -encode_pubsub_item_attr_id(_val, _acc) -> - [{<<"id">>, _val} | _acc]. - -decode_pubsub_item_attr_xmlns(__TopXMLNS, undefined) -> - <<>>; -decode_pubsub_item_attr_xmlns(__TopXMLNS, _val) -> _val. - -decode_pubsub_item_attr_node(__TopXMLNS, undefined) -> - <<>>; -decode_pubsub_item_attr_node(__TopXMLNS, _val) -> _val. - -encode_pubsub_item_attr_node(<<>>, _acc) -> _acc; -encode_pubsub_item_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_pubsub_item_attr_publisher(__TopXMLNS, - undefined) -> - <<>>; -decode_pubsub_item_attr_publisher(__TopXMLNS, _val) -> - _val. - -encode_pubsub_item_attr_publisher(<<>>, _acc) -> _acc; -encode_pubsub_item_attr_publisher(_val, _acc) -> - [{<<"publisher">>, _val} | _acc]. - -decode_pubsub_event_retract(__TopXMLNS, __IgnoreEls, - {xmlel, <<"retract">>, _attrs, _els}) -> - Id = decode_pubsub_event_retract_attrs(__TopXMLNS, - _attrs, undefined), - Id. - -decode_pubsub_event_retract_attrs(__TopXMLNS, - [{<<"id">>, _val} | _attrs], _Id) -> - decode_pubsub_event_retract_attrs(__TopXMLNS, _attrs, - _val); -decode_pubsub_event_retract_attrs(__TopXMLNS, - [_ | _attrs], Id) -> - decode_pubsub_event_retract_attrs(__TopXMLNS, _attrs, - Id); -decode_pubsub_event_retract_attrs(__TopXMLNS, [], Id) -> - decode_pubsub_event_retract_attr_id(__TopXMLNS, Id). - -encode_pubsub_event_retract(Id, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#event">>, - [], __TopXMLNS), - _els = [], - _attrs = encode_pubsub_event_retract_attr_id(Id, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"retract">>, _attrs, _els}. - -decode_pubsub_event_retract_attr_id(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"id">>, <<"retract">>, __TopXMLNS}}); -decode_pubsub_event_retract_attr_id(__TopXMLNS, _val) -> - _val. - -encode_pubsub_event_retract_attr_id(_val, _acc) -> - [{<<"id">>, _val} | _acc]. - -decode_pubsub_event_configuration(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"configuration">>, _attrs, _els}) -> - Xdata = - decode_pubsub_event_configuration_els(__TopXMLNS, - __IgnoreEls, _els, undefined), - Node = - decode_pubsub_event_configuration_attrs(__TopXMLNS, - _attrs, undefined), - {Node, Xdata}. - -decode_pubsub_event_configuration_els(__TopXMLNS, - __IgnoreEls, [], Xdata) -> - Xdata; -decode_pubsub_event_configuration_els(__TopXMLNS, - __IgnoreEls, - [{xmlel, <<"x">>, _attrs, _} = _el - | _els], - Xdata) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"jabber:x:data">> -> - decode_pubsub_event_configuration_els(__TopXMLNS, - __IgnoreEls, _els, - decode_xdata(<<"jabber:x:data">>, - __IgnoreEls, _el)); - _ -> - decode_pubsub_event_configuration_els(__TopXMLNS, - __IgnoreEls, _els, Xdata) - end; -decode_pubsub_event_configuration_els(__TopXMLNS, - __IgnoreEls, [_ | _els], Xdata) -> - decode_pubsub_event_configuration_els(__TopXMLNS, - __IgnoreEls, _els, Xdata). - -decode_pubsub_event_configuration_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], _Node) -> - decode_pubsub_event_configuration_attrs(__TopXMLNS, - _attrs, _val); -decode_pubsub_event_configuration_attrs(__TopXMLNS, - [_ | _attrs], Node) -> - decode_pubsub_event_configuration_attrs(__TopXMLNS, - _attrs, Node); -decode_pubsub_event_configuration_attrs(__TopXMLNS, [], - Node) -> - decode_pubsub_event_configuration_attr_node(__TopXMLNS, - Node). - -encode_pubsub_event_configuration({Node, Xdata}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/pubsub#event">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_pubsub_event_configuration_$xdata'(Xdata, - __NewTopXMLNS, - [])), - _attrs = - encode_pubsub_event_configuration_attr_node(Node, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"configuration">>, _attrs, _els}. - -'encode_pubsub_event_configuration_$xdata'(undefined, - __TopXMLNS, _acc) -> - _acc; -'encode_pubsub_event_configuration_$xdata'(Xdata, - __TopXMLNS, _acc) -> - [encode_xdata(Xdata, __TopXMLNS) | _acc]. - -decode_pubsub_event_configuration_attr_node(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"node">>, <<"configuration">>, - __TopXMLNS}}); -decode_pubsub_event_configuration_attr_node(__TopXMLNS, - _val) -> - _val. - -encode_pubsub_event_configuration_attr_node(_val, - _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_pubsub_owner_affiliation(__TopXMLNS, __IgnoreEls, - {xmlel, <<"affiliation">>, _attrs, _els}) -> - {Jid, Xmlns, Type} = - decode_pubsub_owner_affiliation_attrs(__TopXMLNS, - _attrs, undefined, undefined, - undefined), - {ps_affiliation, Xmlns, <<>>, Type, Jid}. - -decode_pubsub_owner_affiliation_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], _Jid, Xmlns, - Type) -> - decode_pubsub_owner_affiliation_attrs(__TopXMLNS, - _attrs, _val, Xmlns, Type); -decode_pubsub_owner_affiliation_attrs(__TopXMLNS, - [{<<"xmlns">>, _val} | _attrs], Jid, - _Xmlns, Type) -> - decode_pubsub_owner_affiliation_attrs(__TopXMLNS, - _attrs, Jid, _val, Type); -decode_pubsub_owner_affiliation_attrs(__TopXMLNS, - [{<<"affiliation">>, _val} | _attrs], Jid, - Xmlns, _Type) -> - decode_pubsub_owner_affiliation_attrs(__TopXMLNS, - _attrs, Jid, Xmlns, _val); -decode_pubsub_owner_affiliation_attrs(__TopXMLNS, - [_ | _attrs], Jid, Xmlns, Type) -> - decode_pubsub_owner_affiliation_attrs(__TopXMLNS, - _attrs, Jid, Xmlns, Type); -decode_pubsub_owner_affiliation_attrs(__TopXMLNS, [], - Jid, Xmlns, Type) -> - {decode_pubsub_owner_affiliation_attr_jid(__TopXMLNS, - Jid), - decode_pubsub_owner_affiliation_attr_xmlns(__TopXMLNS, - Xmlns), - decode_pubsub_owner_affiliation_attr_affiliation(__TopXMLNS, - Type)}. - -encode_pubsub_owner_affiliation({ps_affiliation, Xmlns, - _, Type, Jid}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(Xmlns, - [<<"http://jabber.org/protocol/pubsub#owner">>], - __TopXMLNS), - _els = [], - _attrs = - encode_pubsub_owner_affiliation_attr_affiliation(Type, - encode_pubsub_owner_affiliation_attr_jid(Jid, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))), - {xmlel, <<"affiliation">>, _attrs, _els}. - -decode_pubsub_owner_affiliation_attr_jid(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"jid">>, <<"affiliation">>, - __TopXMLNS}}); -decode_pubsub_owner_affiliation_attr_jid(__TopXMLNS, - _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"jid">>, <<"affiliation">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_pubsub_owner_affiliation_attr_jid(_val, _acc) -> - [{<<"jid">>, enc_jid(_val)} | _acc]. - -decode_pubsub_owner_affiliation_attr_xmlns(__TopXMLNS, - undefined) -> - <<>>; -decode_pubsub_owner_affiliation_attr_xmlns(__TopXMLNS, - _val) -> - _val. - -decode_pubsub_owner_affiliation_attr_affiliation(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"affiliation">>, <<"affiliation">>, - __TopXMLNS}}); -decode_pubsub_owner_affiliation_attr_affiliation(__TopXMLNS, - _val) -> - case catch dec_ps_aff(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"affiliation">>, <<"affiliation">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_pubsub_owner_affiliation_attr_affiliation(_val, - _acc) -> - [{<<"affiliation">>, enc_ps_aff(_val)} | _acc]. - -decode_pubsub_affiliation(__TopXMLNS, __IgnoreEls, - {xmlel, <<"affiliation">>, _attrs, _els}) -> - {Node, Xmlns, Type} = - decode_pubsub_affiliation_attrs(__TopXMLNS, _attrs, - undefined, undefined, undefined), - {ps_affiliation, Xmlns, Node, Type, undefined}. - -decode_pubsub_affiliation_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], _Node, Xmlns, - Type) -> - decode_pubsub_affiliation_attrs(__TopXMLNS, _attrs, - _val, Xmlns, Type); -decode_pubsub_affiliation_attrs(__TopXMLNS, - [{<<"xmlns">>, _val} | _attrs], Node, _Xmlns, - Type) -> - decode_pubsub_affiliation_attrs(__TopXMLNS, _attrs, - Node, _val, Type); -decode_pubsub_affiliation_attrs(__TopXMLNS, - [{<<"affiliation">>, _val} | _attrs], Node, - Xmlns, _Type) -> - decode_pubsub_affiliation_attrs(__TopXMLNS, _attrs, - Node, Xmlns, _val); -decode_pubsub_affiliation_attrs(__TopXMLNS, - [_ | _attrs], Node, Xmlns, Type) -> - decode_pubsub_affiliation_attrs(__TopXMLNS, _attrs, - Node, Xmlns, Type); -decode_pubsub_affiliation_attrs(__TopXMLNS, [], Node, - Xmlns, Type) -> - {decode_pubsub_affiliation_attr_node(__TopXMLNS, Node), - decode_pubsub_affiliation_attr_xmlns(__TopXMLNS, Xmlns), - decode_pubsub_affiliation_attr_affiliation(__TopXMLNS, - Type)}. - -encode_pubsub_affiliation({ps_affiliation, Xmlns, Node, - Type, _}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(Xmlns, - [<<"http://jabber.org/protocol/pubsub">>], - __TopXMLNS), - _els = [], - _attrs = - encode_pubsub_affiliation_attr_affiliation(Type, - encode_pubsub_affiliation_attr_node(Node, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))), - {xmlel, <<"affiliation">>, _attrs, _els}. - -decode_pubsub_affiliation_attr_node(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"node">>, <<"affiliation">>, - __TopXMLNS}}); -decode_pubsub_affiliation_attr_node(__TopXMLNS, _val) -> - _val. - -encode_pubsub_affiliation_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_pubsub_affiliation_attr_xmlns(__TopXMLNS, - undefined) -> - <<>>; -decode_pubsub_affiliation_attr_xmlns(__TopXMLNS, - _val) -> - _val. - -decode_pubsub_affiliation_attr_affiliation(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"affiliation">>, <<"affiliation">>, - __TopXMLNS}}); -decode_pubsub_affiliation_attr_affiliation(__TopXMLNS, - _val) -> - case catch dec_ps_aff(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"affiliation">>, <<"affiliation">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_pubsub_affiliation_attr_affiliation(_val, - _acc) -> - [{<<"affiliation">>, enc_ps_aff(_val)} | _acc]. - -decode_pubsub_subscription(__TopXMLNS, __IgnoreEls, - {xmlel, <<"subscription">>, _attrs, _els}) -> - {Xmlns, Jid, Node, Subid, Type, Expiry} = - decode_pubsub_subscription_attrs(__TopXMLNS, _attrs, - undefined, undefined, undefined, - undefined, undefined, undefined), - {ps_subscription, Xmlns, Jid, Type, Node, Subid, - Expiry}. - -decode_pubsub_subscription_attrs(__TopXMLNS, - [{<<"xmlns">>, _val} | _attrs], _Xmlns, Jid, - Node, Subid, Type, Expiry) -> - decode_pubsub_subscription_attrs(__TopXMLNS, _attrs, - _val, Jid, Node, Subid, Type, Expiry); -decode_pubsub_subscription_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], Xmlns, _Jid, - Node, Subid, Type, Expiry) -> - decode_pubsub_subscription_attrs(__TopXMLNS, _attrs, - Xmlns, _val, Node, Subid, Type, Expiry); -decode_pubsub_subscription_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], Xmlns, Jid, - _Node, Subid, Type, Expiry) -> - decode_pubsub_subscription_attrs(__TopXMLNS, _attrs, - Xmlns, Jid, _val, Subid, Type, Expiry); -decode_pubsub_subscription_attrs(__TopXMLNS, - [{<<"subid">>, _val} | _attrs], Xmlns, Jid, - Node, _Subid, Type, Expiry) -> - decode_pubsub_subscription_attrs(__TopXMLNS, _attrs, - Xmlns, Jid, Node, _val, Type, Expiry); -decode_pubsub_subscription_attrs(__TopXMLNS, - [{<<"subscription">>, _val} | _attrs], Xmlns, - Jid, Node, Subid, _Type, Expiry) -> - decode_pubsub_subscription_attrs(__TopXMLNS, _attrs, - Xmlns, Jid, Node, Subid, _val, Expiry); -decode_pubsub_subscription_attrs(__TopXMLNS, - [{<<"expiry">>, _val} | _attrs], Xmlns, Jid, - Node, Subid, Type, _Expiry) -> - decode_pubsub_subscription_attrs(__TopXMLNS, _attrs, - Xmlns, Jid, Node, Subid, Type, _val); -decode_pubsub_subscription_attrs(__TopXMLNS, - [_ | _attrs], Xmlns, Jid, Node, Subid, Type, - Expiry) -> - decode_pubsub_subscription_attrs(__TopXMLNS, _attrs, - Xmlns, Jid, Node, Subid, Type, Expiry); -decode_pubsub_subscription_attrs(__TopXMLNS, [], Xmlns, - Jid, Node, Subid, Type, Expiry) -> - {decode_pubsub_subscription_attr_xmlns(__TopXMLNS, - Xmlns), - decode_pubsub_subscription_attr_jid(__TopXMLNS, Jid), - decode_pubsub_subscription_attr_node(__TopXMLNS, Node), - decode_pubsub_subscription_attr_subid(__TopXMLNS, - Subid), - decode_pubsub_subscription_attr_subscription(__TopXMLNS, - Type), - decode_pubsub_subscription_attr_expiry(__TopXMLNS, - Expiry)}. - -encode_pubsub_subscription({ps_subscription, Xmlns, Jid, - Type, Node, Subid, Expiry}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(Xmlns, - [<<"http://jabber.org/protocol/pubsub">>, - <<"http://jabber.org/protocol/pubsub#owner">>, - <<"http://jabber.org/protocol/pubsub#event">>], - __TopXMLNS), - _els = [], - _attrs = encode_pubsub_subscription_attr_expiry(Expiry, - encode_pubsub_subscription_attr_subscription(Type, - encode_pubsub_subscription_attr_subid(Subid, - encode_pubsub_subscription_attr_node(Node, - encode_pubsub_subscription_attr_jid(Jid, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)))))), - {xmlel, <<"subscription">>, _attrs, _els}. - -decode_pubsub_subscription_attr_xmlns(__TopXMLNS, - undefined) -> - <<>>; -decode_pubsub_subscription_attr_xmlns(__TopXMLNS, - _val) -> - _val. - -decode_pubsub_subscription_attr_jid(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"jid">>, <<"subscription">>, - __TopXMLNS}}); -decode_pubsub_subscription_attr_jid(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"jid">>, <<"subscription">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_pubsub_subscription_attr_jid(_val, _acc) -> - [{<<"jid">>, enc_jid(_val)} | _acc]. - -decode_pubsub_subscription_attr_node(__TopXMLNS, - undefined) -> - <<>>; -decode_pubsub_subscription_attr_node(__TopXMLNS, - _val) -> - _val. - -encode_pubsub_subscription_attr_node(<<>>, _acc) -> - _acc; -encode_pubsub_subscription_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_pubsub_subscription_attr_subid(__TopXMLNS, - undefined) -> - <<>>; -decode_pubsub_subscription_attr_subid(__TopXMLNS, - _val) -> - _val. - -encode_pubsub_subscription_attr_subid(<<>>, _acc) -> - _acc; -encode_pubsub_subscription_attr_subid(_val, _acc) -> - [{<<"subid">>, _val} | _acc]. - -decode_pubsub_subscription_attr_subscription(__TopXMLNS, - undefined) -> - undefined; -decode_pubsub_subscription_attr_subscription(__TopXMLNS, - _val) -> - case catch dec_enum(_val, - [none, pending, subscribed, unconfigured]) - of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"subscription">>, <<"subscription">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_pubsub_subscription_attr_subscription(undefined, - _acc) -> - _acc; -encode_pubsub_subscription_attr_subscription(_val, - _acc) -> - [{<<"subscription">>, enc_enum(_val)} | _acc]. - -decode_pubsub_subscription_attr_expiry(__TopXMLNS, - undefined) -> - undefined; -decode_pubsub_subscription_attr_expiry(__TopXMLNS, - _val) -> - case catch dec_utc(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"expiry">>, <<"subscription">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_pubsub_subscription_attr_expiry(undefined, - _acc) -> - _acc; -encode_pubsub_subscription_attr_expiry(_val, _acc) -> - [{<<"expiry">>, enc_utc(_val)} | _acc]. - -decode_xdata(__TopXMLNS, __IgnoreEls, - {xmlel, <<"x">>, _attrs, _els}) -> - {Fields, Items, Instructions, Reported, Title} = - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, [], [], - [], undefined, undefined), - Type = decode_xdata_attrs(__TopXMLNS, _attrs, - undefined), - {xdata, Type, Instructions, Title, Reported, Items, - Fields}. - -decode_xdata_els(__TopXMLNS, __IgnoreEls, [], Fields, - Items, Instructions, Reported, Title) -> - {lists:reverse(Fields), lists:reverse(Items), - lists:reverse(Instructions), Reported, Title}; -decode_xdata_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"instructions">>, _attrs, _} = _el | _els], - Fields, Items, Instructions, Reported, Title) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:x:data">> -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, - Items, - [decode_xdata_instructions(__TopXMLNS, __IgnoreEls, - _el) - | Instructions], - Reported, Title); - <<"jabber:x:data">> -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, - Items, - [decode_xdata_instructions(<<"jabber:x:data">>, - __IgnoreEls, _el) - | Instructions], - Reported, Title); - _ -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, - Items, Instructions, Reported, Title) - end; -decode_xdata_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"title">>, _attrs, _} = _el | _els], Fields, - Items, Instructions, Reported, Title) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:x:data">> -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, - Items, Instructions, Reported, - decode_xdata_title(__TopXMLNS, __IgnoreEls, _el)); - <<"jabber:x:data">> -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, - Items, Instructions, Reported, - decode_xdata_title(<<"jabber:x:data">>, __IgnoreEls, - _el)); - _ -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, - Items, Instructions, Reported, Title) - end; -decode_xdata_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"reported">>, _attrs, _} = _el | _els], - Fields, Items, Instructions, Reported, Title) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:x:data">> -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, - Items, Instructions, - decode_xdata_reported(__TopXMLNS, __IgnoreEls, _el), - Title); - <<"jabber:x:data">> -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, - Items, Instructions, - decode_xdata_reported(<<"jabber:x:data">>, - __IgnoreEls, _el), - Title); - _ -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, - Items, Instructions, Reported, Title) - end; -decode_xdata_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"item">>, _attrs, _} = _el | _els], Fields, - Items, Instructions, Reported, Title) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:x:data">> -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, - [decode_xdata_item(__TopXMLNS, __IgnoreEls, _el) - | Items], - Instructions, Reported, Title); - <<"jabber:x:data">> -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, - [decode_xdata_item(<<"jabber:x:data">>, __IgnoreEls, - _el) - | Items], - Instructions, Reported, Title); - _ -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, - Items, Instructions, Reported, Title) - end; -decode_xdata_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"field">>, _attrs, _} = _el | _els], Fields, - Items, Instructions, Reported, Title) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:x:data">> -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, - [decode_xdata_field(__TopXMLNS, __IgnoreEls, _el) - | Fields], - Items, Instructions, Reported, Title); - <<"jabber:x:data">> -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, - [decode_xdata_field(<<"jabber:x:data">>, __IgnoreEls, - _el) - | Fields], - Items, Instructions, Reported, Title); - _ -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, - Items, Instructions, Reported, Title) - end; -decode_xdata_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Fields, Items, Instructions, Reported, Title) -> - decode_xdata_els(__TopXMLNS, __IgnoreEls, _els, Fields, - Items, Instructions, Reported, Title). - -decode_xdata_attrs(__TopXMLNS, - [{<<"type">>, _val} | _attrs], _Type) -> - decode_xdata_attrs(__TopXMLNS, _attrs, _val); -decode_xdata_attrs(__TopXMLNS, [_ | _attrs], Type) -> - decode_xdata_attrs(__TopXMLNS, _attrs, Type); -decode_xdata_attrs(__TopXMLNS, [], Type) -> - decode_xdata_attr_type(__TopXMLNS, Type). - -encode_xdata({xdata, Type, Instructions, Title, - Reported, Items, Fields}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:data">>, - [], __TopXMLNS), - _els = lists:reverse('encode_xdata_$fields'(Fields, - __NewTopXMLNS, - 'encode_xdata_$items'(Items, - __NewTopXMLNS, - 'encode_xdata_$instructions'(Instructions, - __NewTopXMLNS, - 'encode_xdata_$reported'(Reported, - __NewTopXMLNS, - 'encode_xdata_$title'(Title, - __NewTopXMLNS, - [])))))), - _attrs = encode_xdata_attr_type(Type, - enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS)), - {xmlel, <<"x">>, _attrs, _els}. - -'encode_xdata_$fields'([], __TopXMLNS, _acc) -> _acc; -'encode_xdata_$fields'([Fields | _els], __TopXMLNS, - _acc) -> - 'encode_xdata_$fields'(_els, __TopXMLNS, - [encode_xdata_field(Fields, __TopXMLNS) | _acc]). - -'encode_xdata_$items'([], __TopXMLNS, _acc) -> _acc; -'encode_xdata_$items'([Items | _els], __TopXMLNS, - _acc) -> - 'encode_xdata_$items'(_els, __TopXMLNS, - [encode_xdata_item(Items, __TopXMLNS) | _acc]). - -'encode_xdata_$instructions'([], __TopXMLNS, _acc) -> - _acc; -'encode_xdata_$instructions'([Instructions | _els], - __TopXMLNS, _acc) -> - 'encode_xdata_$instructions'(_els, __TopXMLNS, - [encode_xdata_instructions(Instructions, - __TopXMLNS) - | _acc]). - -'encode_xdata_$reported'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_xdata_$reported'(Reported, __TopXMLNS, _acc) -> - [encode_xdata_reported(Reported, __TopXMLNS) | _acc]. - -'encode_xdata_$title'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_xdata_$title'(Title, __TopXMLNS, _acc) -> - [encode_xdata_title(Title, __TopXMLNS) | _acc]. - -decode_xdata_attr_type(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"type">>, <<"x">>, __TopXMLNS}}); -decode_xdata_attr_type(__TopXMLNS, _val) -> - case catch dec_enum(_val, - [cancel, form, result, submit]) - of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"type">>, <<"x">>, __TopXMLNS}}); - _res -> _res - end. - -encode_xdata_attr_type(_val, _acc) -> - [{<<"type">>, enc_enum(_val)} | _acc]. - -decode_xdata_item(__TopXMLNS, __IgnoreEls, - {xmlel, <<"item">>, _attrs, _els}) -> - Fields = decode_xdata_item_els(__TopXMLNS, __IgnoreEls, - _els, []), - Fields. - -decode_xdata_item_els(__TopXMLNS, __IgnoreEls, [], - Fields) -> - lists:reverse(Fields); -decode_xdata_item_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"field">>, _attrs, _} = _el | _els], - Fields) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:x:data">> -> - decode_xdata_item_els(__TopXMLNS, __IgnoreEls, _els, - [decode_xdata_field(__TopXMLNS, __IgnoreEls, - _el) - | Fields]); - <<"jabber:x:data">> -> - decode_xdata_item_els(__TopXMLNS, __IgnoreEls, _els, - [decode_xdata_field(<<"jabber:x:data">>, - __IgnoreEls, _el) - | Fields]); - _ -> - decode_xdata_item_els(__TopXMLNS, __IgnoreEls, _els, - Fields) - end; -decode_xdata_item_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Fields) -> - decode_xdata_item_els(__TopXMLNS, __IgnoreEls, _els, - Fields). - -encode_xdata_item(Fields, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:data">>, - [], __TopXMLNS), - _els = lists:reverse('encode_xdata_item_$fields'(Fields, - __NewTopXMLNS, [])), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"item">>, _attrs, _els}. - -'encode_xdata_item_$fields'([], __TopXMLNS, _acc) -> - _acc; -'encode_xdata_item_$fields'([Fields | _els], __TopXMLNS, - _acc) -> - 'encode_xdata_item_$fields'(_els, __TopXMLNS, - [encode_xdata_field(Fields, __TopXMLNS) - | _acc]). - -decode_xdata_reported(__TopXMLNS, __IgnoreEls, - {xmlel, <<"reported">>, _attrs, _els}) -> - Fields = decode_xdata_reported_els(__TopXMLNS, - __IgnoreEls, _els, []), - Fields. - -decode_xdata_reported_els(__TopXMLNS, __IgnoreEls, [], - Fields) -> - lists:reverse(Fields); -decode_xdata_reported_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"field">>, _attrs, _} = _el | _els], - Fields) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:x:data">> -> - decode_xdata_reported_els(__TopXMLNS, __IgnoreEls, _els, - [decode_xdata_field(__TopXMLNS, __IgnoreEls, - _el) - | Fields]); - <<"jabber:x:data">> -> - decode_xdata_reported_els(__TopXMLNS, __IgnoreEls, _els, - [decode_xdata_field(<<"jabber:x:data">>, - __IgnoreEls, _el) - | Fields]); - _ -> - decode_xdata_reported_els(__TopXMLNS, __IgnoreEls, _els, - Fields) - end; -decode_xdata_reported_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Fields) -> - decode_xdata_reported_els(__TopXMLNS, __IgnoreEls, _els, - Fields). - -encode_xdata_reported(Fields, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:data">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_xdata_reported_$fields'(Fields, - __NewTopXMLNS, [])), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"reported">>, _attrs, _els}. - -'encode_xdata_reported_$fields'([], __TopXMLNS, _acc) -> - _acc; -'encode_xdata_reported_$fields'([Fields | _els], - __TopXMLNS, _acc) -> - 'encode_xdata_reported_$fields'(_els, __TopXMLNS, - [encode_xdata_field(Fields, __TopXMLNS) - | _acc]). - -decode_xdata_title(__TopXMLNS, __IgnoreEls, - {xmlel, <<"title">>, _attrs, _els}) -> - Cdata = decode_xdata_title_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_xdata_title_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_xdata_title_cdata(__TopXMLNS, Cdata); -decode_xdata_title_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_xdata_title_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_xdata_title_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_xdata_title_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_xdata_title(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:data">>, - [], __TopXMLNS), - _els = encode_xdata_title_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"title">>, _attrs, _els}. - -decode_xdata_title_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_xdata_title_cdata(__TopXMLNS, _val) -> _val. - -encode_xdata_title_cdata(<<>>, _acc) -> _acc; -encode_xdata_title_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_xdata_instructions(__TopXMLNS, __IgnoreEls, - {xmlel, <<"instructions">>, _attrs, _els}) -> - Cdata = decode_xdata_instructions_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_xdata_instructions_els(__TopXMLNS, __IgnoreEls, - [], Cdata) -> - decode_xdata_instructions_cdata(__TopXMLNS, Cdata); -decode_xdata_instructions_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_xdata_instructions_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_xdata_instructions_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_xdata_instructions_els(__TopXMLNS, __IgnoreEls, - _els, Cdata). - -encode_xdata_instructions(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:data">>, - [], __TopXMLNS), - _els = encode_xdata_instructions_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"instructions">>, _attrs, _els}. - -decode_xdata_instructions_cdata(__TopXMLNS, <<>>) -> - <<>>; -decode_xdata_instructions_cdata(__TopXMLNS, _val) -> - _val. - -encode_xdata_instructions_cdata(<<>>, _acc) -> _acc; -encode_xdata_instructions_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_xdata_field(__TopXMLNS, __IgnoreEls, - {xmlel, <<"field">>, _attrs, _els}) -> - {Options, Values, Desc, Required, __Els} = - decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - [], [], <<>>, false, []), - {Label, Type, Var} = - decode_xdata_field_attrs(__TopXMLNS, _attrs, undefined, - undefined, undefined), - {xdata_field, Label, Type, Var, Required, Desc, Values, - Options, __Els}. - -decode_xdata_field_els(__TopXMLNS, __IgnoreEls, [], - Options, Values, Desc, Required, __Els) -> - {lists:reverse(Options), lists:reverse(Values), Desc, - Required, lists:reverse(__Els)}; -decode_xdata_field_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"required">>, _attrs, _} = _el | _els], - Options, Values, Desc, Required, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:x:data">> -> - decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, Values, Desc, - decode_xdata_field_required(__TopXMLNS, - __IgnoreEls, _el), - __Els); - <<"jabber:x:data">> -> - decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, Values, Desc, - decode_xdata_field_required(<<"jabber:x:data">>, - __IgnoreEls, _el), - __Els); - _ -> - decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, Values, Desc, Required, __Els) - end; -decode_xdata_field_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"desc">>, _attrs, _} = _el | _els], Options, - Values, Desc, Required, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:x:data">> -> - decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, Values, - decode_xdata_field_desc(__TopXMLNS, - __IgnoreEls, _el), - Required, __Els); - <<"jabber:x:data">> -> - decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, Values, - decode_xdata_field_desc(<<"jabber:x:data">>, - __IgnoreEls, _el), - Required, __Els); - _ -> - decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, Values, Desc, Required, __Els) - end; -decode_xdata_field_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"value">>, _attrs, _} = _el | _els], Options, - Values, Desc, Required, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:x:data">> -> - decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, - [decode_xdata_field_value(__TopXMLNS, - __IgnoreEls, _el) - | Values], - Desc, Required, __Els); - <<"jabber:x:data">> -> - decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, - [decode_xdata_field_value(<<"jabber:x:data">>, - __IgnoreEls, _el) - | Values], - Desc, Required, __Els); - _ -> - decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, Values, Desc, Required, __Els) - end; -decode_xdata_field_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"option">>, _attrs, _} = _el | _els], - Options, Values, Desc, Required, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:x:data">> -> - decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - [decode_xdata_field_option(__TopXMLNS, - __IgnoreEls, _el) - | Options], - Values, Desc, Required, __Els); - <<"jabber:x:data">> -> - decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - [decode_xdata_field_option(<<"jabber:x:data">>, - __IgnoreEls, _el) - | Options], - Values, Desc, Required, __Els); - _ -> - decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, Values, Desc, Required, __Els) - end; -decode_xdata_field_els(__TopXMLNS, __IgnoreEls, - [{xmlel, _, _, _} = _el | _els], Options, Values, Desc, - Required, __Els) -> - if __IgnoreEls -> - decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, Values, Desc, Required, - [_el | __Els]); - true -> - case is_known_tag(_el, __TopXMLNS) of - true -> - decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, Values, Desc, Required, - [decode(_el, __TopXMLNS, []) | __Els]); - false -> - decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, Values, Desc, Required, __Els) - end - end; -decode_xdata_field_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Options, Values, Desc, Required, __Els) -> - decode_xdata_field_els(__TopXMLNS, __IgnoreEls, _els, - Options, Values, Desc, Required, __Els). - -decode_xdata_field_attrs(__TopXMLNS, - [{<<"label">>, _val} | _attrs], _Label, Type, Var) -> - decode_xdata_field_attrs(__TopXMLNS, _attrs, _val, Type, - Var); -decode_xdata_field_attrs(__TopXMLNS, - [{<<"type">>, _val} | _attrs], Label, _Type, Var) -> - decode_xdata_field_attrs(__TopXMLNS, _attrs, Label, - _val, Var); -decode_xdata_field_attrs(__TopXMLNS, - [{<<"var">>, _val} | _attrs], Label, Type, _Var) -> - decode_xdata_field_attrs(__TopXMLNS, _attrs, Label, - Type, _val); -decode_xdata_field_attrs(__TopXMLNS, [_ | _attrs], - Label, Type, Var) -> - decode_xdata_field_attrs(__TopXMLNS, _attrs, Label, - Type, Var); -decode_xdata_field_attrs(__TopXMLNS, [], Label, Type, - Var) -> - {decode_xdata_field_attr_label(__TopXMLNS, Label), - decode_xdata_field_attr_type(__TopXMLNS, Type), - decode_xdata_field_attr_var(__TopXMLNS, Var)}. - -encode_xdata_field({xdata_field, Label, Type, Var, - Required, Desc, Values, Options, __Els}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:data">>, - [], __TopXMLNS), - _els = [encode(_el, __NewTopXMLNS) || _el <- __Els] ++ - lists:reverse('encode_xdata_field_$options'(Options, - __NewTopXMLNS, - 'encode_xdata_field_$values'(Values, - __NewTopXMLNS, - 'encode_xdata_field_$desc'(Desc, - __NewTopXMLNS, - 'encode_xdata_field_$required'(Required, - __NewTopXMLNS, - []))))), - _attrs = encode_xdata_field_attr_var(Var, - encode_xdata_field_attr_type(Type, - encode_xdata_field_attr_label(Label, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)))), - {xmlel, <<"field">>, _attrs, _els}. - -'encode_xdata_field_$options'([], __TopXMLNS, _acc) -> - _acc; -'encode_xdata_field_$options'([Options | _els], - __TopXMLNS, _acc) -> - 'encode_xdata_field_$options'(_els, __TopXMLNS, - [encode_xdata_field_option(Options, - __TopXMLNS) - | _acc]). - -'encode_xdata_field_$values'([], __TopXMLNS, _acc) -> - _acc; -'encode_xdata_field_$values'([Values | _els], - __TopXMLNS, _acc) -> - 'encode_xdata_field_$values'(_els, __TopXMLNS, - [encode_xdata_field_value(Values, __TopXMLNS) - | _acc]). - -'encode_xdata_field_$desc'(<<>>, __TopXMLNS, _acc) -> - _acc; -'encode_xdata_field_$desc'(Desc, __TopXMLNS, _acc) -> - [encode_xdata_field_desc(Desc, __TopXMLNS) | _acc]. - -'encode_xdata_field_$required'(false, __TopXMLNS, - _acc) -> - _acc; -'encode_xdata_field_$required'(Required, __TopXMLNS, - _acc) -> - [encode_xdata_field_required(Required, __TopXMLNS) - | _acc]. - -decode_xdata_field_attr_label(__TopXMLNS, undefined) -> - <<>>; -decode_xdata_field_attr_label(__TopXMLNS, _val) -> _val. - -encode_xdata_field_attr_label(<<>>, _acc) -> _acc; -encode_xdata_field_attr_label(_val, _acc) -> - [{<<"label">>, _val} | _acc]. - -decode_xdata_field_attr_type(__TopXMLNS, undefined) -> - undefined; -decode_xdata_field_attr_type(__TopXMLNS, _val) -> - case catch dec_enum(_val, - [boolean, fixed, hidden, 'jid-multi', 'jid-single', - 'list-multi', 'list-single', 'text-multi', - 'text-private', 'text-single']) - of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"type">>, <<"field">>, __TopXMLNS}}); - _res -> _res - end. - -encode_xdata_field_attr_type(undefined, _acc) -> _acc; -encode_xdata_field_attr_type(_val, _acc) -> - [{<<"type">>, enc_enum(_val)} | _acc]. - -decode_xdata_field_attr_var(__TopXMLNS, undefined) -> - <<>>; -decode_xdata_field_attr_var(__TopXMLNS, _val) -> _val. - -encode_xdata_field_attr_var(<<>>, _acc) -> _acc; -encode_xdata_field_attr_var(_val, _acc) -> - [{<<"var">>, _val} | _acc]. - -decode_xdata_field_option(__TopXMLNS, __IgnoreEls, - {xmlel, <<"option">>, _attrs, _els}) -> - Value = decode_xdata_field_option_els(__TopXMLNS, - __IgnoreEls, _els, error), - Label = decode_xdata_field_option_attrs(__TopXMLNS, - _attrs, undefined), - {xdata_option, Label, Value}. - -decode_xdata_field_option_els(__TopXMLNS, __IgnoreEls, - [], Value) -> - case Value of - error -> - erlang:error({xmpp_codec, - {missing_tag, <<"value">>, __TopXMLNS}}); - {value, Value1} -> Value1 - end; -decode_xdata_field_option_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"value">>, _attrs, _} = _el | _els], - Value) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:x:data">> -> - decode_xdata_field_option_els(__TopXMLNS, __IgnoreEls, - _els, - {value, - decode_xdata_field_value(__TopXMLNS, - __IgnoreEls, - _el)}); - <<"jabber:x:data">> -> - decode_xdata_field_option_els(__TopXMLNS, __IgnoreEls, - _els, - {value, - decode_xdata_field_value(<<"jabber:x:data">>, - __IgnoreEls, - _el)}); - _ -> - decode_xdata_field_option_els(__TopXMLNS, __IgnoreEls, - _els, Value) - end; -decode_xdata_field_option_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Value) -> - decode_xdata_field_option_els(__TopXMLNS, __IgnoreEls, - _els, Value). - -decode_xdata_field_option_attrs(__TopXMLNS, - [{<<"label">>, _val} | _attrs], _Label) -> - decode_xdata_field_option_attrs(__TopXMLNS, _attrs, - _val); -decode_xdata_field_option_attrs(__TopXMLNS, - [_ | _attrs], Label) -> - decode_xdata_field_option_attrs(__TopXMLNS, _attrs, - Label); -decode_xdata_field_option_attrs(__TopXMLNS, [], - Label) -> - decode_xdata_field_option_attr_label(__TopXMLNS, Label). - -encode_xdata_field_option({xdata_option, Label, Value}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:data">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_xdata_field_option_$value'(Value, - __NewTopXMLNS, [])), - _attrs = encode_xdata_field_option_attr_label(Label, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"option">>, _attrs, _els}. - -'encode_xdata_field_option_$value'(Value, __TopXMLNS, - _acc) -> - [encode_xdata_field_value(Value, __TopXMLNS) | _acc]. - -decode_xdata_field_option_attr_label(__TopXMLNS, - undefined) -> - <<>>; -decode_xdata_field_option_attr_label(__TopXMLNS, - _val) -> - _val. - -encode_xdata_field_option_attr_label(<<>>, _acc) -> - _acc; -encode_xdata_field_option_attr_label(_val, _acc) -> - [{<<"label">>, _val} | _acc]. - -decode_xdata_field_value(__TopXMLNS, __IgnoreEls, - {xmlel, <<"value">>, _attrs, _els}) -> - Cdata = decode_xdata_field_value_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_xdata_field_value_els(__TopXMLNS, __IgnoreEls, - [], Cdata) -> - decode_xdata_field_value_cdata(__TopXMLNS, Cdata); -decode_xdata_field_value_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_xdata_field_value_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_xdata_field_value_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_xdata_field_value_els(__TopXMLNS, __IgnoreEls, - _els, Cdata). - -encode_xdata_field_value(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:data">>, - [], __TopXMLNS), - _els = encode_xdata_field_value_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"value">>, _attrs, _els}. - -decode_xdata_field_value_cdata(__TopXMLNS, <<>>) -> - <<>>; -decode_xdata_field_value_cdata(__TopXMLNS, _val) -> - _val. - -encode_xdata_field_value_cdata(<<>>, _acc) -> _acc; -encode_xdata_field_value_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_xdata_field_desc(__TopXMLNS, __IgnoreEls, - {xmlel, <<"desc">>, _attrs, _els}) -> - Cdata = decode_xdata_field_desc_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_xdata_field_desc_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_xdata_field_desc_cdata(__TopXMLNS, Cdata); -decode_xdata_field_desc_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_xdata_field_desc_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_xdata_field_desc_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_xdata_field_desc_els(__TopXMLNS, __IgnoreEls, - _els, Cdata). - -encode_xdata_field_desc(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:data">>, - [], __TopXMLNS), - _els = encode_xdata_field_desc_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"desc">>, _attrs, _els}. - -decode_xdata_field_desc_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_xdata_field_desc_cdata(__TopXMLNS, _val) -> _val. - -encode_xdata_field_desc_cdata(<<>>, _acc) -> _acc; -encode_xdata_field_desc_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_xdata_field_required(__TopXMLNS, __IgnoreEls, - {xmlel, <<"required">>, _attrs, _els}) -> - true. - -encode_xdata_field_required(true, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:x:data">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"required">>, _attrs, _els}. - -decode_vcard_xupdate(__TopXMLNS, __IgnoreEls, - {xmlel, <<"x">>, _attrs, _els}) -> - Hash = decode_vcard_xupdate_els(__TopXMLNS, __IgnoreEls, - _els, undefined), - {vcard_xupdate, {<<>>, <<>>}, Hash}. - -decode_vcard_xupdate_els(__TopXMLNS, __IgnoreEls, [], - Hash) -> - Hash; -decode_vcard_xupdate_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"photo">>, _attrs, _} = _el | _els], - Hash) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp:x:update">> -> - decode_vcard_xupdate_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_xupdate_photo(__TopXMLNS, - __IgnoreEls, - _el)); - <<"vcard-temp:x:update">> -> - decode_vcard_xupdate_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_xupdate_photo(<<"vcard-temp:x:update">>, - __IgnoreEls, - _el)); - _ -> - decode_vcard_xupdate_els(__TopXMLNS, __IgnoreEls, _els, - Hash) - end; -decode_vcard_xupdate_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Hash) -> - decode_vcard_xupdate_els(__TopXMLNS, __IgnoreEls, _els, - Hash). - -encode_vcard_xupdate({vcard_xupdate, _, Hash}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"vcard-temp:x:update">>, [], - __TopXMLNS), - _els = lists:reverse('encode_vcard_xupdate_$hash'(Hash, - __NewTopXMLNS, [])), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"x">>, _attrs, _els}. - -'encode_vcard_xupdate_$hash'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_xupdate_$hash'(Hash, __TopXMLNS, _acc) -> - [encode_vcard_xupdate_photo(Hash, __TopXMLNS) | _acc]. - -decode_vcard_xupdate_photo(__TopXMLNS, __IgnoreEls, - {xmlel, <<"photo">>, _attrs, _els}) -> - Cdata = decode_vcard_xupdate_photo_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_vcard_xupdate_photo_els(__TopXMLNS, __IgnoreEls, - [], Cdata) -> - decode_vcard_xupdate_photo_cdata(__TopXMLNS, Cdata); -decode_vcard_xupdate_photo_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_xupdate_photo_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_vcard_xupdate_photo_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_xupdate_photo_els(__TopXMLNS, __IgnoreEls, - _els, Cdata). - -encode_vcard_xupdate_photo(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"vcard-temp:x:update">>, [], - __TopXMLNS), - _els = encode_vcard_xupdate_photo_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"photo">>, _attrs, _els}. - -decode_vcard_xupdate_photo_cdata(__TopXMLNS, <<>>) -> - <<>>; -decode_vcard_xupdate_photo_cdata(__TopXMLNS, _val) -> - _val. - -encode_vcard_xupdate_photo_cdata(<<>>, _acc) -> _acc; -encode_vcard_xupdate_photo_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_temp(__TopXMLNS, __IgnoreEls, - {xmlel, <<"vCard">>, _attrs, _els}) -> - {Mailer, Adr, Class, Categories, Desc, Uid, Prodid, - Jabberid, Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, Label, - Fn, Version, N, Photo, Logo, Geo} = - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - undefined, [], undefined, [], undefined, - undefined, undefined, undefined, undefined, - undefined, undefined, undefined, undefined, - undefined, undefined, undefined, undefined, - undefined, undefined, undefined, [], [], [], - undefined, undefined, undefined, undefined, - undefined, undefined), - {vcard_temp, Version, Fn, N, Nickname, Photo, Bday, Adr, - Label, Tel, Email, Jabberid, Mailer, Tz, Geo, Title, - Role, Logo, Org, Categories, Note, Prodid, Rev, - Sort_string, Sound, Uid, Url, Class, Key, Desc}. - -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, [], - Mailer, Adr, Class, Categories, Desc, Uid, Prodid, - Jabberid, Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, Label, - Fn, Version, N, Photo, Logo, Geo) -> - {Mailer, lists:reverse(Adr), Class, Categories, Desc, - Uid, Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, Url, - lists:reverse(Email), lists:reverse(Tel), - lists:reverse(Label), Fn, Version, N, Photo, Logo, Geo}; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"N">>, _attrs, _} = _el | _els], Mailer, Adr, - Class, Categories, Desc, Uid, Prodid, Jabberid, Sound, - Note, Role, Title, Nickname, Rev, Sort_string, Org, - Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, N, - Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, - decode_vcard_N(__TopXMLNS, __IgnoreEls, _el), - Photo, Logo, Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, - decode_vcard_N(<<"vcard-temp">>, __IgnoreEls, - _el), - Photo, Logo, Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"ADR">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, - [decode_vcard_ADR(__TopXMLNS, __IgnoreEls, _el) - | Adr], - Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, - Tel, Label, Fn, Version, N, Photo, Logo, Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, - [decode_vcard_ADR(<<"vcard-temp">>, __IgnoreEls, - _el) - | Adr], - Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, - Tel, Label, Fn, Version, N, Photo, Logo, Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"LABEL">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, - [decode_vcard_LABEL(__TopXMLNS, __IgnoreEls, - _el) - | Label], - Fn, Version, N, Photo, Logo, Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, - [decode_vcard_LABEL(<<"vcard-temp">>, - __IgnoreEls, _el) - | Label], - Fn, Version, N, Photo, Logo, Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"TEL">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, - [decode_vcard_TEL(__TopXMLNS, __IgnoreEls, _el) - | Tel], - Label, Fn, Version, N, Photo, Logo, Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, - [decode_vcard_TEL(<<"vcard-temp">>, __IgnoreEls, - _el) - | Tel], - Label, Fn, Version, N, Photo, Logo, Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"EMAIL">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, - [decode_vcard_EMAIL(__TopXMLNS, __IgnoreEls, - _el) - | Email], - Tel, Label, Fn, Version, N, Photo, Logo, Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, - [decode_vcard_EMAIL(<<"vcard-temp">>, - __IgnoreEls, _el) - | Email], - Tel, Label, Fn, Version, N, Photo, Logo, Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"GEO">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, - decode_vcard_GEO(__TopXMLNS, __IgnoreEls, _el)); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, - decode_vcard_GEO(<<"vcard-temp">>, __IgnoreEls, - _el)); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"LOGO">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - decode_vcard_LOGO(__TopXMLNS, __IgnoreEls, _el), - Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - decode_vcard_LOGO(<<"vcard-temp">>, __IgnoreEls, - _el), - Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"PHOTO">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, - decode_vcard_PHOTO(__TopXMLNS, __IgnoreEls, - _el), - Logo, Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, - decode_vcard_PHOTO(<<"vcard-temp">>, - __IgnoreEls, _el), - Logo, Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"ORG">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, - decode_vcard_ORG(__TopXMLNS, __IgnoreEls, _el), - Bday, Key, Tz, Url, Email, Tel, Label, Fn, - Version, N, Photo, Logo, Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, - decode_vcard_ORG(<<"vcard-temp">>, __IgnoreEls, - _el), - Bday, Key, Tz, Url, Email, Tel, Label, Fn, - Version, N, Photo, Logo, Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"SOUND">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, - decode_vcard_SOUND(__TopXMLNS, __IgnoreEls, - _el), - Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, - Version, N, Photo, Logo, Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, - decode_vcard_SOUND(<<"vcard-temp">>, - __IgnoreEls, _el), - Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, - Version, N, Photo, Logo, Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"KEY">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, - decode_vcard_KEY(__TopXMLNS, __IgnoreEls, _el), - Tz, Url, Email, Tel, Label, Fn, Version, N, - Photo, Logo, Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, - decode_vcard_KEY(<<"vcard-temp">>, __IgnoreEls, - _el), - Tz, Url, Email, Tel, Label, Fn, Version, N, - Photo, Logo, Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"VERSION">>, _attrs, _} = _el | _els], - Mailer, Adr, Class, Categories, Desc, Uid, Prodid, - Jabberid, Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, Label, - Fn, Version, N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, - decode_vcard_VERSION(__TopXMLNS, __IgnoreEls, - _el), - N, Photo, Logo, Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, - decode_vcard_VERSION(<<"vcard-temp">>, - __IgnoreEls, _el), - N, Photo, Logo, Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"FN">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, - decode_vcard_FN(__TopXMLNS, __IgnoreEls, _el), - Version, N, Photo, Logo, Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, - decode_vcard_FN(<<"vcard-temp">>, __IgnoreEls, - _el), - Version, N, Photo, Logo, Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"NICKNAME">>, _attrs, _} = _el | _els], - Mailer, Adr, Class, Categories, Desc, Uid, Prodid, - Jabberid, Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, Label, - Fn, Version, N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - decode_vcard_NICKNAME(__TopXMLNS, __IgnoreEls, - _el), - Rev, Sort_string, Org, Bday, Key, Tz, Url, - Email, Tel, Label, Fn, Version, N, Photo, Logo, - Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - decode_vcard_NICKNAME(<<"vcard-temp">>, - __IgnoreEls, _el), - Rev, Sort_string, Org, Bday, Key, Tz, Url, - Email, Tel, Label, Fn, Version, N, Photo, Logo, - Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"BDAY">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, - decode_vcard_BDAY(__TopXMLNS, __IgnoreEls, _el), - Key, Tz, Url, Email, Tel, Label, Fn, Version, N, - Photo, Logo, Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, - decode_vcard_BDAY(<<"vcard-temp">>, __IgnoreEls, - _el), - Key, Tz, Url, Email, Tel, Label, Fn, Version, N, - Photo, Logo, Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"JABBERID">>, _attrs, _} = _el | _els], - Mailer, Adr, Class, Categories, Desc, Uid, Prodid, - Jabberid, Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, Label, - Fn, Version, N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, - decode_vcard_JABBERID(__TopXMLNS, __IgnoreEls, - _el), - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, - Tel, Label, Fn, Version, N, Photo, Logo, Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, - decode_vcard_JABBERID(<<"vcard-temp">>, - __IgnoreEls, _el), - Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, - Tel, Label, Fn, Version, N, Photo, Logo, Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"MAILER">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_MAILER(__TopXMLNS, __IgnoreEls, - _el), - Adr, Class, Categories, Desc, Uid, Prodid, - Jabberid, Sound, Note, Role, Title, Nickname, - Rev, Sort_string, Org, Bday, Key, Tz, Url, - Email, Tel, Label, Fn, Version, N, Photo, Logo, - Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_MAILER(<<"vcard-temp">>, - __IgnoreEls, _el), - Adr, Class, Categories, Desc, Uid, Prodid, - Jabberid, Sound, Note, Role, Title, Nickname, - Rev, Sort_string, Org, Bday, Key, Tz, Url, - Email, Tel, Label, Fn, Version, N, Photo, Logo, - Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"TZ">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, - decode_vcard_TZ(__TopXMLNS, __IgnoreEls, _el), - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, - decode_vcard_TZ(<<"vcard-temp">>, __IgnoreEls, - _el), - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"TITLE">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, - decode_vcard_TITLE(__TopXMLNS, __IgnoreEls, - _el), - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, - decode_vcard_TITLE(<<"vcard-temp">>, - __IgnoreEls, _el), - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"ROLE">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, - decode_vcard_ROLE(__TopXMLNS, __IgnoreEls, _el), - Title, Nickname, Rev, Sort_string, Org, Bday, - Key, Tz, Url, Email, Tel, Label, Fn, Version, N, - Photo, Logo, Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, - decode_vcard_ROLE(<<"vcard-temp">>, __IgnoreEls, - _el), - Title, Nickname, Rev, Sort_string, Org, Bday, - Key, Tz, Url, Email, Tel, Label, Fn, Version, N, - Photo, Logo, Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"NOTE">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, - decode_vcard_NOTE(__TopXMLNS, __IgnoreEls, _el), - Role, Title, Nickname, Rev, Sort_string, Org, - Bday, Key, Tz, Url, Email, Tel, Label, Fn, - Version, N, Photo, Logo, Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, - decode_vcard_NOTE(<<"vcard-temp">>, __IgnoreEls, - _el), - Role, Title, Nickname, Rev, Sort_string, Org, - Bday, Key, Tz, Url, Email, Tel, Label, Fn, - Version, N, Photo, Logo, Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"PRODID">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - decode_vcard_PRODID(__TopXMLNS, __IgnoreEls, - _el), - Jabberid, Sound, Note, Role, Title, Nickname, - Rev, Sort_string, Org, Bday, Key, Tz, Url, - Email, Tel, Label, Fn, Version, N, Photo, Logo, - Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - decode_vcard_PRODID(<<"vcard-temp">>, - __IgnoreEls, _el), - Jabberid, Sound, Note, Role, Title, Nickname, - Rev, Sort_string, Org, Bday, Key, Tz, Url, - Email, Tel, Label, Fn, Version, N, Photo, Logo, - Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"REV">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, - decode_vcard_REV(__TopXMLNS, __IgnoreEls, _el), - Sort_string, Org, Bday, Key, Tz, Url, Email, - Tel, Label, Fn, Version, N, Photo, Logo, Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, - decode_vcard_REV(<<"vcard-temp">>, __IgnoreEls, - _el), - Sort_string, Org, Bday, Key, Tz, Url, Email, - Tel, Label, Fn, Version, N, Photo, Logo, Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"SORT-STRING">>, _attrs, _} = _el | _els], - Mailer, Adr, Class, Categories, Desc, Uid, Prodid, - Jabberid, Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, Label, - Fn, Version, N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, - decode_vcard_SORT_STRING(__TopXMLNS, - __IgnoreEls, _el), - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, - Version, N, Photo, Logo, Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, - decode_vcard_SORT_STRING(<<"vcard-temp">>, - __IgnoreEls, _el), - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, - Version, N, Photo, Logo, Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"UID">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, - decode_vcard_UID(__TopXMLNS, __IgnoreEls, _el), - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, - decode_vcard_UID(<<"vcard-temp">>, __IgnoreEls, - _el), - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"URL">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - decode_vcard_URL(__TopXMLNS, __IgnoreEls, _el), - Email, Tel, Label, Fn, Version, N, Photo, Logo, - Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - decode_vcard_URL(<<"vcard-temp">>, __IgnoreEls, - _el), - Email, Tel, Label, Fn, Version, N, Photo, Logo, - Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"DESC">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, - decode_vcard_DESC(__TopXMLNS, __IgnoreEls, _el), - Uid, Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, - decode_vcard_DESC(<<"vcard-temp">>, __IgnoreEls, - _el), - Uid, Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"CATEGORIES">>, _attrs, _} = _el | _els], - Mailer, Adr, Class, Categories, Desc, Uid, Prodid, - Jabberid, Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, Label, - Fn, Version, N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, - decode_vcard_CATEGORIES(__TopXMLNS, __IgnoreEls, - _el), - Desc, Uid, Prodid, Jabberid, Sound, Note, Role, - Title, Nickname, Rev, Sort_string, Org, Bday, - Key, Tz, Url, Email, Tel, Label, Fn, Version, N, - Photo, Logo, Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, - decode_vcard_CATEGORIES(<<"vcard-temp">>, - __IgnoreEls, _el), - Desc, Uid, Prodid, Jabberid, Sound, Note, Role, - Title, Nickname, Rev, Sort_string, Org, Bday, - Key, Tz, Url, Email, Tel, Label, Fn, Version, N, - Photo, Logo, Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"CLASS">>, _attrs, _} = _el | _els], Mailer, - Adr, Class, Categories, Desc, Uid, Prodid, Jabberid, - Sound, Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, Version, - N, Photo, Logo, Geo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, - decode_vcard_CLASS(__TopXMLNS, __IgnoreEls, - _el), - Categories, Desc, Uid, Prodid, Jabberid, Sound, - Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, - Version, N, Photo, Logo, Geo); - <<"vcard-temp">> -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, - decode_vcard_CLASS(<<"vcard-temp">>, - __IgnoreEls, _el), - Categories, Desc, Uid, Prodid, Jabberid, Sound, - Note, Role, Title, Nickname, Rev, Sort_string, - Org, Bday, Key, Tz, Url, Email, Tel, Label, Fn, - Version, N, Photo, Logo, Geo); - _ -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, - Nickname, Rev, Sort_string, Org, Bday, Key, Tz, - Url, Email, Tel, Label, Fn, Version, N, Photo, - Logo, Geo) - end; -decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Mailer, Adr, Class, Categories, Desc, Uid, - Prodid, Jabberid, Sound, Note, Role, Title, Nickname, - Rev, Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo) -> - decode_vcard_temp_els(__TopXMLNS, __IgnoreEls, _els, - Mailer, Adr, Class, Categories, Desc, Uid, Prodid, - Jabberid, Sound, Note, Role, Title, Nickname, Rev, - Sort_string, Org, Bday, Key, Tz, Url, Email, Tel, - Label, Fn, Version, N, Photo, Logo, Geo). - -encode_vcard_temp({vcard_temp, Version, Fn, N, Nickname, - Photo, Bday, Adr, Label, Tel, Email, Jabberid, Mailer, - Tz, Geo, Title, Role, Logo, Org, Categories, Note, - Prodid, Rev, Sort_string, Sound, Uid, Url, Class, Key, - Desc}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = lists:reverse('encode_vcard_temp_$mailer'(Mailer, - __NewTopXMLNS, - 'encode_vcard_temp_$adr'(Adr, - __NewTopXMLNS, - 'encode_vcard_temp_$class'(Class, - __NewTopXMLNS, - 'encode_vcard_temp_$categories'(Categories, - __NewTopXMLNS, - 'encode_vcard_temp_$desc'(Desc, - __NewTopXMLNS, - 'encode_vcard_temp_$uid'(Uid, - __NewTopXMLNS, - 'encode_vcard_temp_$prodid'(Prodid, - __NewTopXMLNS, - 'encode_vcard_temp_$jabberid'(Jabberid, - __NewTopXMLNS, - 'encode_vcard_temp_$sound'(Sound, - __NewTopXMLNS, - 'encode_vcard_temp_$note'(Note, - __NewTopXMLNS, - 'encode_vcard_temp_$role'(Role, - __NewTopXMLNS, - 'encode_vcard_temp_$title'(Title, - __NewTopXMLNS, - 'encode_vcard_temp_$nickname'(Nickname, - __NewTopXMLNS, - 'encode_vcard_temp_$rev'(Rev, - __NewTopXMLNS, - 'encode_vcard_temp_$sort_string'(Sort_string, - __NewTopXMLNS, - 'encode_vcard_temp_$org'(Org, - __NewTopXMLNS, - 'encode_vcard_temp_$bday'(Bday, - __NewTopXMLNS, - 'encode_vcard_temp_$key'(Key, - __NewTopXMLNS, - 'encode_vcard_temp_$tz'(Tz, - __NewTopXMLNS, - 'encode_vcard_temp_$url'(Url, - __NewTopXMLNS, - 'encode_vcard_temp_$email'(Email, - __NewTopXMLNS, - 'encode_vcard_temp_$tel'(Tel, - __NewTopXMLNS, - 'encode_vcard_temp_$label'(Label, - __NewTopXMLNS, - 'encode_vcard_temp_$fn'(Fn, - __NewTopXMLNS, - 'encode_vcard_temp_$version'(Version, - __NewTopXMLNS, - 'encode_vcard_temp_$n'(N, - __NewTopXMLNS, - 'encode_vcard_temp_$photo'(Photo, - __NewTopXMLNS, - 'encode_vcard_temp_$logo'(Logo, - __NewTopXMLNS, - 'encode_vcard_temp_$geo'(Geo, - __NewTopXMLNS, - [])))))))))))))))))))))))))))))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"vCard">>, _attrs, _els}. - -'encode_vcard_temp_$mailer'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_temp_$mailer'(Mailer, __TopXMLNS, _acc) -> - [encode_vcard_MAILER(Mailer, __TopXMLNS) | _acc]. - -'encode_vcard_temp_$adr'([], __TopXMLNS, _acc) -> _acc; -'encode_vcard_temp_$adr'([Adr | _els], __TopXMLNS, - _acc) -> - 'encode_vcard_temp_$adr'(_els, __TopXMLNS, - [encode_vcard_ADR(Adr, __TopXMLNS) | _acc]). - -'encode_vcard_temp_$class'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_temp_$class'(Class, __TopXMLNS, _acc) -> - [encode_vcard_CLASS(Class, __TopXMLNS) | _acc]. - -'encode_vcard_temp_$categories'([], __TopXMLNS, _acc) -> - _acc; -'encode_vcard_temp_$categories'(Categories, __TopXMLNS, - _acc) -> - [encode_vcard_CATEGORIES(Categories, __TopXMLNS) - | _acc]. - -'encode_vcard_temp_$desc'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_temp_$desc'(Desc, __TopXMLNS, _acc) -> - [encode_vcard_DESC(Desc, __TopXMLNS) | _acc]. - -'encode_vcard_temp_$uid'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_temp_$uid'(Uid, __TopXMLNS, _acc) -> - [encode_vcard_UID(Uid, __TopXMLNS) | _acc]. - -'encode_vcard_temp_$prodid'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_temp_$prodid'(Prodid, __TopXMLNS, _acc) -> - [encode_vcard_PRODID(Prodid, __TopXMLNS) | _acc]. - -'encode_vcard_temp_$jabberid'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_temp_$jabberid'(Jabberid, __TopXMLNS, - _acc) -> - [encode_vcard_JABBERID(Jabberid, __TopXMLNS) | _acc]. - -'encode_vcard_temp_$sound'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_temp_$sound'(Sound, __TopXMLNS, _acc) -> - [encode_vcard_SOUND(Sound, __TopXMLNS) | _acc]. - -'encode_vcard_temp_$note'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_temp_$note'(Note, __TopXMLNS, _acc) -> - [encode_vcard_NOTE(Note, __TopXMLNS) | _acc]. - -'encode_vcard_temp_$role'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_temp_$role'(Role, __TopXMLNS, _acc) -> - [encode_vcard_ROLE(Role, __TopXMLNS) | _acc]. - -'encode_vcard_temp_$title'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_temp_$title'(Title, __TopXMLNS, _acc) -> - [encode_vcard_TITLE(Title, __TopXMLNS) | _acc]. - -'encode_vcard_temp_$nickname'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_temp_$nickname'(Nickname, __TopXMLNS, - _acc) -> - [encode_vcard_NICKNAME(Nickname, __TopXMLNS) | _acc]. - -'encode_vcard_temp_$rev'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_temp_$rev'(Rev, __TopXMLNS, _acc) -> - [encode_vcard_REV(Rev, __TopXMLNS) | _acc]. - -'encode_vcard_temp_$sort_string'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_temp_$sort_string'(Sort_string, - __TopXMLNS, _acc) -> - [encode_vcard_SORT_STRING(Sort_string, __TopXMLNS) - | _acc]. - -'encode_vcard_temp_$org'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_temp_$org'(Org, __TopXMLNS, _acc) -> - [encode_vcard_ORG(Org, __TopXMLNS) | _acc]. - -'encode_vcard_temp_$bday'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_temp_$bday'(Bday, __TopXMLNS, _acc) -> - [encode_vcard_BDAY(Bday, __TopXMLNS) | _acc]. - -'encode_vcard_temp_$key'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_temp_$key'(Key, __TopXMLNS, _acc) -> - [encode_vcard_KEY(Key, __TopXMLNS) | _acc]. - -'encode_vcard_temp_$tz'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_temp_$tz'(Tz, __TopXMLNS, _acc) -> - [encode_vcard_TZ(Tz, __TopXMLNS) | _acc]. - -'encode_vcard_temp_$url'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_temp_$url'(Url, __TopXMLNS, _acc) -> - [encode_vcard_URL(Url, __TopXMLNS) | _acc]. - -'encode_vcard_temp_$email'([], __TopXMLNS, _acc) -> - _acc; -'encode_vcard_temp_$email'([Email | _els], __TopXMLNS, - _acc) -> - 'encode_vcard_temp_$email'(_els, __TopXMLNS, - [encode_vcard_EMAIL(Email, __TopXMLNS) | _acc]). - -'encode_vcard_temp_$tel'([], __TopXMLNS, _acc) -> _acc; -'encode_vcard_temp_$tel'([Tel | _els], __TopXMLNS, - _acc) -> - 'encode_vcard_temp_$tel'(_els, __TopXMLNS, - [encode_vcard_TEL(Tel, __TopXMLNS) | _acc]). - -'encode_vcard_temp_$label'([], __TopXMLNS, _acc) -> - _acc; -'encode_vcard_temp_$label'([Label | _els], __TopXMLNS, - _acc) -> - 'encode_vcard_temp_$label'(_els, __TopXMLNS, - [encode_vcard_LABEL(Label, __TopXMLNS) | _acc]). - -'encode_vcard_temp_$fn'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_temp_$fn'(Fn, __TopXMLNS, _acc) -> - [encode_vcard_FN(Fn, __TopXMLNS) | _acc]. - -'encode_vcard_temp_$version'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_temp_$version'(Version, __TopXMLNS, - _acc) -> - [encode_vcard_VERSION(Version, __TopXMLNS) | _acc]. - -'encode_vcard_temp_$n'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_temp_$n'(N, __TopXMLNS, _acc) -> - [encode_vcard_N(N, __TopXMLNS) | _acc]. - -'encode_vcard_temp_$photo'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_temp_$photo'(Photo, __TopXMLNS, _acc) -> - [encode_vcard_PHOTO(Photo, __TopXMLNS) | _acc]. - -'encode_vcard_temp_$logo'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_temp_$logo'(Logo, __TopXMLNS, _acc) -> - [encode_vcard_LOGO(Logo, __TopXMLNS) | _acc]. - -'encode_vcard_temp_$geo'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_temp_$geo'(Geo, __TopXMLNS, _acc) -> - [encode_vcard_GEO(Geo, __TopXMLNS) | _acc]. - -decode_vcard_CLASS(__TopXMLNS, __IgnoreEls, - {xmlel, <<"CLASS">>, _attrs, _els}) -> - Class = decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, - _els, undefined), - Class. - -decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, [], - Class) -> - Class; -decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"PUBLIC">>, _attrs, _} = _el | _els], - Class) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_PUBLIC(__TopXMLNS, __IgnoreEls, - _el)); - <<"vcard-temp">> -> - decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_PUBLIC(<<"vcard-temp">>, - __IgnoreEls, _el)); - _ -> - decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, - Class) - end; -decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"PRIVATE">>, _attrs, _} = _el | _els], - Class) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_PRIVATE(__TopXMLNS, __IgnoreEls, - _el)); - <<"vcard-temp">> -> - decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_PRIVATE(<<"vcard-temp">>, - __IgnoreEls, _el)); - _ -> - decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, - Class) - end; -decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"CONFIDENTIAL">>, _attrs, _} = _el | _els], - Class) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_CONFIDENTIAL(__TopXMLNS, - __IgnoreEls, _el)); - <<"vcard-temp">> -> - decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_CONFIDENTIAL(<<"vcard-temp">>, - __IgnoreEls, _el)); - _ -> - decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, - Class) - end; -decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Class) -> - decode_vcard_CLASS_els(__TopXMLNS, __IgnoreEls, _els, - Class). - -encode_vcard_CLASS(Class, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = lists:reverse('encode_vcard_CLASS_$class'(Class, - __NewTopXMLNS, [])), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"CLASS">>, _attrs, _els}. - -'encode_vcard_CLASS_$class'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_CLASS_$class'(public = Class, __TopXMLNS, - _acc) -> - [encode_vcard_PUBLIC(Class, __TopXMLNS) | _acc]; -'encode_vcard_CLASS_$class'(private = Class, __TopXMLNS, - _acc) -> - [encode_vcard_PRIVATE(Class, __TopXMLNS) | _acc]; -'encode_vcard_CLASS_$class'(confidential = Class, - __TopXMLNS, _acc) -> - [encode_vcard_CONFIDENTIAL(Class, __TopXMLNS) | _acc]. - -decode_vcard_CATEGORIES(__TopXMLNS, __IgnoreEls, - {xmlel, <<"CATEGORIES">>, _attrs, _els}) -> - Keywords = decode_vcard_CATEGORIES_els(__TopXMLNS, - __IgnoreEls, _els, []), - Keywords. - -decode_vcard_CATEGORIES_els(__TopXMLNS, __IgnoreEls, [], - Keywords) -> - lists:reverse(Keywords); -decode_vcard_CATEGORIES_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"KEYWORD">>, _attrs, _} = _el | _els], - Keywords) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_CATEGORIES_els(__TopXMLNS, __IgnoreEls, - _els, - [decode_vcard_KEYWORD(__TopXMLNS, - __IgnoreEls, _el) - | Keywords]); - <<"vcard-temp">> -> - decode_vcard_CATEGORIES_els(__TopXMLNS, __IgnoreEls, - _els, - [decode_vcard_KEYWORD(<<"vcard-temp">>, - __IgnoreEls, _el) - | Keywords]); - _ -> - decode_vcard_CATEGORIES_els(__TopXMLNS, __IgnoreEls, - _els, Keywords) - end; -decode_vcard_CATEGORIES_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Keywords) -> - decode_vcard_CATEGORIES_els(__TopXMLNS, __IgnoreEls, - _els, Keywords). - -encode_vcard_CATEGORIES(Keywords, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = - lists:reverse('encode_vcard_CATEGORIES_$keywords'(Keywords, - __NewTopXMLNS, [])), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"CATEGORIES">>, _attrs, _els}. - -'encode_vcard_CATEGORIES_$keywords'([], __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_CATEGORIES_$keywords'([Keywords | _els], - __TopXMLNS, _acc) -> - 'encode_vcard_CATEGORIES_$keywords'(_els, __TopXMLNS, - [encode_vcard_KEYWORD(Keywords, - __TopXMLNS) - | _acc]). - -decode_vcard_KEY(__TopXMLNS, __IgnoreEls, - {xmlel, <<"KEY">>, _attrs, _els}) -> - {Cred, Type} = decode_vcard_KEY_els(__TopXMLNS, - __IgnoreEls, _els, undefined, - undefined), - {vcard_key, Type, Cred}. - -decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, [], Cred, - Type) -> - {Cred, Type}; -decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"TYPE">>, _attrs, _} = _el | _els], Cred, - Type) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, _els, - Cred, - decode_vcard_TYPE(__TopXMLNS, __IgnoreEls, _el)); - <<"vcard-temp">> -> - decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, _els, - Cred, - decode_vcard_TYPE(<<"vcard-temp">>, __IgnoreEls, - _el)); - _ -> - decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, _els, - Cred, Type) - end; -decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"CRED">>, _attrs, _} = _el | _els], Cred, - Type) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_CRED(__TopXMLNS, __IgnoreEls, _el), - Type); - <<"vcard-temp">> -> - decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_CRED(<<"vcard-temp">>, __IgnoreEls, - _el), - Type); - _ -> - decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, _els, - Cred, Type) - end; -decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cred, Type) -> - decode_vcard_KEY_els(__TopXMLNS, __IgnoreEls, _els, - Cred, Type). - -encode_vcard_KEY({vcard_key, Type, Cred}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = lists:reverse('encode_vcard_KEY_$cred'(Cred, - __NewTopXMLNS, - 'encode_vcard_KEY_$type'(Type, - __NewTopXMLNS, - []))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"KEY">>, _attrs, _els}. - -'encode_vcard_KEY_$cred'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_KEY_$cred'(Cred, __TopXMLNS, _acc) -> - [encode_vcard_CRED(Cred, __TopXMLNS) | _acc]. - -'encode_vcard_KEY_$type'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_KEY_$type'(Type, __TopXMLNS, _acc) -> - [encode_vcard_TYPE(Type, __TopXMLNS) | _acc]. - -decode_vcard_SOUND(__TopXMLNS, __IgnoreEls, - {xmlel, <<"SOUND">>, _attrs, _els}) -> - {Phonetic, Extval, Binval} = - decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, - undefined, undefined, undefined), - {vcard_sound, Phonetic, Binval, Extval}. - -decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, [], - Phonetic, Extval, Binval) -> - {Phonetic, Extval, Binval}; -decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"BINVAL">>, _attrs, _} = _el | _els], - Phonetic, Extval, Binval) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, - Phonetic, Extval, - decode_vcard_BINVAL(__TopXMLNS, __IgnoreEls, - _el)); - <<"vcard-temp">> -> - decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, - Phonetic, Extval, - decode_vcard_BINVAL(<<"vcard-temp">>, - __IgnoreEls, _el)); - _ -> - decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, - Phonetic, Extval, Binval) - end; -decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"EXTVAL">>, _attrs, _} = _el | _els], - Phonetic, Extval, Binval) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, - Phonetic, - decode_vcard_EXTVAL(__TopXMLNS, __IgnoreEls, - _el), - Binval); - <<"vcard-temp">> -> - decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, - Phonetic, - decode_vcard_EXTVAL(<<"vcard-temp">>, - __IgnoreEls, _el), - Binval); - _ -> - decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, - Phonetic, Extval, Binval) - end; -decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"PHONETIC">>, _attrs, _} = _el | _els], - Phonetic, Extval, Binval) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_PHONETIC(__TopXMLNS, __IgnoreEls, - _el), - Extval, Binval); - <<"vcard-temp">> -> - decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_PHONETIC(<<"vcard-temp">>, - __IgnoreEls, _el), - Extval, Binval); - _ -> - decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, - Phonetic, Extval, Binval) - end; -decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Phonetic, Extval, Binval) -> - decode_vcard_SOUND_els(__TopXMLNS, __IgnoreEls, _els, - Phonetic, Extval, Binval). - -encode_vcard_SOUND({vcard_sound, Phonetic, Binval, - Extval}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = - lists:reverse('encode_vcard_SOUND_$phonetic'(Phonetic, - __NewTopXMLNS, - 'encode_vcard_SOUND_$extval'(Extval, - __NewTopXMLNS, - 'encode_vcard_SOUND_$binval'(Binval, - __NewTopXMLNS, - [])))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"SOUND">>, _attrs, _els}. - -'encode_vcard_SOUND_$phonetic'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_SOUND_$phonetic'(Phonetic, __TopXMLNS, - _acc) -> - [encode_vcard_PHONETIC(Phonetic, __TopXMLNS) | _acc]. - -'encode_vcard_SOUND_$extval'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_SOUND_$extval'(Extval, __TopXMLNS, - _acc) -> - [encode_vcard_EXTVAL(Extval, __TopXMLNS) | _acc]. - -'encode_vcard_SOUND_$binval'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_SOUND_$binval'(Binval, __TopXMLNS, - _acc) -> - [encode_vcard_BINVAL(Binval, __TopXMLNS) | _acc]. - -decode_vcard_ORG(__TopXMLNS, __IgnoreEls, - {xmlel, <<"ORG">>, _attrs, _els}) -> - {Units, Name} = decode_vcard_ORG_els(__TopXMLNS, - __IgnoreEls, _els, [], undefined), - {vcard_org, Name, Units}. - -decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, [], Units, - Name) -> - {lists:reverse(Units), Name}; -decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"ORGNAME">>, _attrs, _} = _el | _els], Units, - Name) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, _els, - Units, - decode_vcard_ORGNAME(__TopXMLNS, __IgnoreEls, - _el)); - <<"vcard-temp">> -> - decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, _els, - Units, - decode_vcard_ORGNAME(<<"vcard-temp">>, - __IgnoreEls, _el)); - _ -> - decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, _els, - Units, Name) - end; -decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"ORGUNIT">>, _attrs, _} = _el | _els], Units, - Name) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, _els, - [decode_vcard_ORGUNIT(__TopXMLNS, __IgnoreEls, - _el) - | Units], - Name); - <<"vcard-temp">> -> - decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, _els, - [decode_vcard_ORGUNIT(<<"vcard-temp">>, - __IgnoreEls, _el) - | Units], - Name); - _ -> - decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, _els, - Units, Name) - end; -decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Units, Name) -> - decode_vcard_ORG_els(__TopXMLNS, __IgnoreEls, _els, - Units, Name). - -encode_vcard_ORG({vcard_org, Name, Units}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = lists:reverse('encode_vcard_ORG_$units'(Units, - __NewTopXMLNS, - 'encode_vcard_ORG_$name'(Name, - __NewTopXMLNS, - []))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"ORG">>, _attrs, _els}. - -'encode_vcard_ORG_$units'([], __TopXMLNS, _acc) -> _acc; -'encode_vcard_ORG_$units'([Units | _els], __TopXMLNS, - _acc) -> - 'encode_vcard_ORG_$units'(_els, __TopXMLNS, - [encode_vcard_ORGUNIT(Units, __TopXMLNS) | _acc]). - -'encode_vcard_ORG_$name'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_ORG_$name'(Name, __TopXMLNS, _acc) -> - [encode_vcard_ORGNAME(Name, __TopXMLNS) | _acc]. - -decode_vcard_PHOTO(__TopXMLNS, __IgnoreEls, - {xmlel, <<"PHOTO">>, _attrs, _els}) -> - {Type, Extval, Binval} = - decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, - undefined, undefined, undefined), - {vcard_photo, Type, Binval, Extval}. - -decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, [], - Type, Extval, Binval) -> - {Type, Extval, Binval}; -decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"TYPE">>, _attrs, _} = _el | _els], Type, - Extval, Binval) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_TYPE(__TopXMLNS, __IgnoreEls, - _el), - Extval, Binval); - <<"vcard-temp">> -> - decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_TYPE(<<"vcard-temp">>, - __IgnoreEls, _el), - Extval, Binval); - _ -> - decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, - Type, Extval, Binval) - end; -decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"BINVAL">>, _attrs, _} = _el | _els], Type, - Extval, Binval) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, - Type, Extval, - decode_vcard_BINVAL(__TopXMLNS, __IgnoreEls, - _el)); - <<"vcard-temp">> -> - decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, - Type, Extval, - decode_vcard_BINVAL(<<"vcard-temp">>, - __IgnoreEls, _el)); - _ -> - decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, - Type, Extval, Binval) - end; -decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"EXTVAL">>, _attrs, _} = _el | _els], Type, - Extval, Binval) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, - Type, - decode_vcard_EXTVAL(__TopXMLNS, __IgnoreEls, - _el), - Binval); - <<"vcard-temp">> -> - decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, - Type, - decode_vcard_EXTVAL(<<"vcard-temp">>, - __IgnoreEls, _el), - Binval); - _ -> - decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, - Type, Extval, Binval) - end; -decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Type, Extval, Binval) -> - decode_vcard_PHOTO_els(__TopXMLNS, __IgnoreEls, _els, - Type, Extval, Binval). - -encode_vcard_PHOTO({vcard_photo, Type, Binval, Extval}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = lists:reverse('encode_vcard_PHOTO_$type'(Type, - __NewTopXMLNS, - 'encode_vcard_PHOTO_$extval'(Extval, - __NewTopXMLNS, - 'encode_vcard_PHOTO_$binval'(Binval, - __NewTopXMLNS, - [])))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"PHOTO">>, _attrs, _els}. - -'encode_vcard_PHOTO_$type'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_PHOTO_$type'(Type, __TopXMLNS, _acc) -> - [encode_vcard_TYPE(Type, __TopXMLNS) | _acc]. - -'encode_vcard_PHOTO_$extval'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_PHOTO_$extval'(Extval, __TopXMLNS, - _acc) -> - [encode_vcard_EXTVAL(Extval, __TopXMLNS) | _acc]. - -'encode_vcard_PHOTO_$binval'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_PHOTO_$binval'(Binval, __TopXMLNS, - _acc) -> - [encode_vcard_BINVAL(Binval, __TopXMLNS) | _acc]. - -decode_vcard_LOGO(__TopXMLNS, __IgnoreEls, - {xmlel, <<"LOGO">>, _attrs, _els}) -> - {Type, Extval, Binval} = - decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, - undefined, undefined, undefined), - {vcard_logo, Type, Binval, Extval}. - -decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, [], Type, - Extval, Binval) -> - {Type, Extval, Binval}; -decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"TYPE">>, _attrs, _} = _el | _els], Type, - Extval, Binval) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_TYPE(__TopXMLNS, __IgnoreEls, _el), - Extval, Binval); - <<"vcard-temp">> -> - decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_TYPE(<<"vcard-temp">>, __IgnoreEls, - _el), - Extval, Binval); - _ -> - decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, - Type, Extval, Binval) - end; -decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"BINVAL">>, _attrs, _} = _el | _els], Type, - Extval, Binval) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, - Type, Extval, - decode_vcard_BINVAL(__TopXMLNS, __IgnoreEls, - _el)); - <<"vcard-temp">> -> - decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, - Type, Extval, - decode_vcard_BINVAL(<<"vcard-temp">>, - __IgnoreEls, _el)); - _ -> - decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, - Type, Extval, Binval) - end; -decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"EXTVAL">>, _attrs, _} = _el | _els], Type, - Extval, Binval) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, - Type, - decode_vcard_EXTVAL(__TopXMLNS, __IgnoreEls, - _el), - Binval); - <<"vcard-temp">> -> - decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, - Type, - decode_vcard_EXTVAL(<<"vcard-temp">>, - __IgnoreEls, _el), - Binval); - _ -> - decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, - Type, Extval, Binval) - end; -decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Type, Extval, Binval) -> - decode_vcard_LOGO_els(__TopXMLNS, __IgnoreEls, _els, - Type, Extval, Binval). - -encode_vcard_LOGO({vcard_logo, Type, Binval, Extval}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = lists:reverse('encode_vcard_LOGO_$type'(Type, - __NewTopXMLNS, - 'encode_vcard_LOGO_$extval'(Extval, - __NewTopXMLNS, - 'encode_vcard_LOGO_$binval'(Binval, - __NewTopXMLNS, - [])))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"LOGO">>, _attrs, _els}. - -'encode_vcard_LOGO_$type'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_LOGO_$type'(Type, __TopXMLNS, _acc) -> - [encode_vcard_TYPE(Type, __TopXMLNS) | _acc]. - -'encode_vcard_LOGO_$extval'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_LOGO_$extval'(Extval, __TopXMLNS, _acc) -> - [encode_vcard_EXTVAL(Extval, __TopXMLNS) | _acc]. - -'encode_vcard_LOGO_$binval'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_LOGO_$binval'(Binval, __TopXMLNS, _acc) -> - [encode_vcard_BINVAL(Binval, __TopXMLNS) | _acc]. - -decode_vcard_BINVAL(__TopXMLNS, __IgnoreEls, - {xmlel, <<"BINVAL">>, _attrs, _els}) -> - Cdata = decode_vcard_BINVAL_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_BINVAL_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_BINVAL_cdata(__TopXMLNS, Cdata); -decode_vcard_BINVAL_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_BINVAL_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_BINVAL_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_BINVAL_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_BINVAL(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_BINVAL_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"BINVAL">>, _attrs, _els}. - -decode_vcard_BINVAL_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_BINVAL_cdata(__TopXMLNS, _val) -> - case catch base64:decode(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_cdata_value, <<>>, <<"BINVAL">>, __TopXMLNS}}); - _res -> _res - end. - -encode_vcard_BINVAL_cdata(<<>>, _acc) -> _acc; -encode_vcard_BINVAL_cdata(_val, _acc) -> - [{xmlcdata, base64:encode(_val)} | _acc]. - -decode_vcard_GEO(__TopXMLNS, __IgnoreEls, - {xmlel, <<"GEO">>, _attrs, _els}) -> - {Lat, Lon} = decode_vcard_GEO_els(__TopXMLNS, - __IgnoreEls, _els, undefined, undefined), - {vcard_geo, Lat, Lon}. - -decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, [], Lat, - Lon) -> - {Lat, Lon}; -decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"LAT">>, _attrs, _} = _el | _els], Lat, - Lon) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_LAT(__TopXMLNS, __IgnoreEls, _el), - Lon); - <<"vcard-temp">> -> - decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_LAT(<<"vcard-temp">>, __IgnoreEls, - _el), - Lon); - _ -> - decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, _els, Lat, - Lon) - end; -decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"LON">>, _attrs, _} = _el | _els], Lat, - Lon) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, _els, Lat, - decode_vcard_LON(__TopXMLNS, __IgnoreEls, _el)); - <<"vcard-temp">> -> - decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, _els, Lat, - decode_vcard_LON(<<"vcard-temp">>, __IgnoreEls, - _el)); - _ -> - decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, _els, Lat, - Lon) - end; -decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Lat, Lon) -> - decode_vcard_GEO_els(__TopXMLNS, __IgnoreEls, _els, Lat, - Lon). - -encode_vcard_GEO({vcard_geo, Lat, Lon}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = lists:reverse('encode_vcard_GEO_$lat'(Lat, - __NewTopXMLNS, - 'encode_vcard_GEO_$lon'(Lon, - __NewTopXMLNS, - []))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"GEO">>, _attrs, _els}. - -'encode_vcard_GEO_$lat'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_GEO_$lat'(Lat, __TopXMLNS, _acc) -> - [encode_vcard_LAT(Lat, __TopXMLNS) | _acc]. - -'encode_vcard_GEO_$lon'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_GEO_$lon'(Lon, __TopXMLNS, _acc) -> - [encode_vcard_LON(Lon, __TopXMLNS) | _acc]. - -decode_vcard_EMAIL(__TopXMLNS, __IgnoreEls, - {xmlel, <<"EMAIL">>, _attrs, _els}) -> - {X400, Userid, Internet, Home, Pref, Work} = - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - false, undefined, false, false, false, false), - {vcard_email, Home, Work, Internet, Pref, X400, Userid}. - -decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, [], - X400, Userid, Internet, Home, Pref, Work) -> - {X400, Userid, Internet, Home, Pref, Work}; -decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"HOME">>, _attrs, _} = _el | _els], X400, - Userid, Internet, Home, Pref, Work) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, Userid, Internet, - decode_vcard_HOME(__TopXMLNS, __IgnoreEls, - _el), - Pref, Work); - <<"vcard-temp">> -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, Userid, Internet, - decode_vcard_HOME(<<"vcard-temp">>, - __IgnoreEls, _el), - Pref, Work); - _ -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, Userid, Internet, Home, Pref, Work) - end; -decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"WORK">>, _attrs, _} = _el | _els], X400, - Userid, Internet, Home, Pref, Work) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, Userid, Internet, Home, Pref, - decode_vcard_WORK(__TopXMLNS, __IgnoreEls, - _el)); - <<"vcard-temp">> -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, Userid, Internet, Home, Pref, - decode_vcard_WORK(<<"vcard-temp">>, - __IgnoreEls, _el)); - _ -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, Userid, Internet, Home, Pref, Work) - end; -decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"INTERNET">>, _attrs, _} = _el | _els], X400, - Userid, Internet, Home, Pref, Work) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, Userid, - decode_vcard_INTERNET(__TopXMLNS, __IgnoreEls, - _el), - Home, Pref, Work); - <<"vcard-temp">> -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, Userid, - decode_vcard_INTERNET(<<"vcard-temp">>, - __IgnoreEls, _el), - Home, Pref, Work); - _ -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, Userid, Internet, Home, Pref, Work) - end; -decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"PREF">>, _attrs, _} = _el | _els], X400, - Userid, Internet, Home, Pref, Work) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, Userid, Internet, Home, - decode_vcard_PREF(__TopXMLNS, __IgnoreEls, - _el), - Work); - <<"vcard-temp">> -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, Userid, Internet, Home, - decode_vcard_PREF(<<"vcard-temp">>, - __IgnoreEls, _el), - Work); - _ -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, Userid, Internet, Home, Pref, Work) - end; -decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"X400">>, _attrs, _} = _el | _els], X400, - Userid, Internet, Home, Pref, Work) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_X400(__TopXMLNS, __IgnoreEls, - _el), - Userid, Internet, Home, Pref, Work); - <<"vcard-temp">> -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_X400(<<"vcard-temp">>, - __IgnoreEls, _el), - Userid, Internet, Home, Pref, Work); - _ -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, Userid, Internet, Home, Pref, Work) - end; -decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"USERID">>, _attrs, _} = _el | _els], X400, - Userid, Internet, Home, Pref, Work) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, - decode_vcard_USERID(__TopXMLNS, __IgnoreEls, - _el), - Internet, Home, Pref, Work); - <<"vcard-temp">> -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, - decode_vcard_USERID(<<"vcard-temp">>, - __IgnoreEls, _el), - Internet, Home, Pref, Work); - _ -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, Userid, Internet, Home, Pref, Work) - end; -decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, - [_ | _els], X400, Userid, Internet, Home, Pref, Work) -> - decode_vcard_EMAIL_els(__TopXMLNS, __IgnoreEls, _els, - X400, Userid, Internet, Home, Pref, Work). - -encode_vcard_EMAIL({vcard_email, Home, Work, Internet, - Pref, X400, Userid}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = lists:reverse('encode_vcard_EMAIL_$x400'(X400, - __NewTopXMLNS, - 'encode_vcard_EMAIL_$userid'(Userid, - __NewTopXMLNS, - 'encode_vcard_EMAIL_$internet'(Internet, - __NewTopXMLNS, - 'encode_vcard_EMAIL_$home'(Home, - __NewTopXMLNS, - 'encode_vcard_EMAIL_$pref'(Pref, - __NewTopXMLNS, - 'encode_vcard_EMAIL_$work'(Work, - __NewTopXMLNS, - []))))))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"EMAIL">>, _attrs, _els}. - -'encode_vcard_EMAIL_$x400'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_EMAIL_$x400'(X400, __TopXMLNS, _acc) -> - [encode_vcard_X400(X400, __TopXMLNS) | _acc]. - -'encode_vcard_EMAIL_$userid'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_EMAIL_$userid'(Userid, __TopXMLNS, - _acc) -> - [encode_vcard_USERID(Userid, __TopXMLNS) | _acc]. - -'encode_vcard_EMAIL_$internet'(false, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_EMAIL_$internet'(Internet, __TopXMLNS, - _acc) -> - [encode_vcard_INTERNET(Internet, __TopXMLNS) | _acc]. - -'encode_vcard_EMAIL_$home'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_EMAIL_$home'(Home, __TopXMLNS, _acc) -> - [encode_vcard_HOME(Home, __TopXMLNS) | _acc]. - -'encode_vcard_EMAIL_$pref'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_EMAIL_$pref'(Pref, __TopXMLNS, _acc) -> - [encode_vcard_PREF(Pref, __TopXMLNS) | _acc]. - -'encode_vcard_EMAIL_$work'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_EMAIL_$work'(Work, __TopXMLNS, _acc) -> - [encode_vcard_WORK(Work, __TopXMLNS) | _acc]. - -decode_vcard_TEL(__TopXMLNS, __IgnoreEls, - {xmlel, <<"TEL">>, _attrs, _els}) -> - {Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, - Work, Cell, Modem, Isdn, Video} = - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - undefined, false, false, false, false, false, - false, false, false, false, false, false, false, - false), - {vcard_tel, Home, Work, Voice, Fax, Pager, Msg, Cell, - Video, Bbs, Modem, Isdn, Pcs, Pref, Number}. - -decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, [], - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, - Work, Cell, Modem, Isdn, Video) -> - {Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, - Work, Cell, Modem, Isdn, Video}; -decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"HOME">>, _attrs, _} = _el | _els], Number, - Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, - Cell, Modem, Isdn, Video) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, - decode_vcard_HOME(__TopXMLNS, __IgnoreEls, _el), - Pref, Msg, Fax, Work, Cell, Modem, Isdn, Video); - <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, - decode_vcard_HOME(<<"vcard-temp">>, __IgnoreEls, - _el), - Pref, Msg, Fax, Work, Cell, Modem, Isdn, Video); - _ -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) - end; -decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"WORK">>, _attrs, _} = _el | _els], Number, - Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, - Cell, Modem, Isdn, Video) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, - decode_vcard_WORK(__TopXMLNS, __IgnoreEls, _el), - Cell, Modem, Isdn, Video); - <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, - decode_vcard_WORK(<<"vcard-temp">>, __IgnoreEls, - _el), - Cell, Modem, Isdn, Video); - _ -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) - end; -decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"VOICE">>, _attrs, _} = _el | _els], Number, - Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, - Cell, Modem, Isdn, Video) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, - decode_vcard_VOICE(__TopXMLNS, __IgnoreEls, _el), - Home, Pref, Msg, Fax, Work, Cell, Modem, Isdn, - Video); - <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, - decode_vcard_VOICE(<<"vcard-temp">>, __IgnoreEls, - _el), - Home, Pref, Msg, Fax, Work, Cell, Modem, Isdn, - Video); - _ -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) - end; -decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"FAX">>, _attrs, _} = _el | _els], Number, - Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, - Cell, Modem, Isdn, Video) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - decode_vcard_FAX(__TopXMLNS, __IgnoreEls, _el), - Work, Cell, Modem, Isdn, Video); - <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - decode_vcard_FAX(<<"vcard-temp">>, __IgnoreEls, - _el), - Work, Cell, Modem, Isdn, Video); - _ -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) - end; -decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"PAGER">>, _attrs, _} = _el | _els], Number, - Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, - Cell, Modem, Isdn, Video) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, - decode_vcard_PAGER(__TopXMLNS, __IgnoreEls, _el), - Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, - Cell, Modem, Isdn, Video); - <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, - decode_vcard_PAGER(<<"vcard-temp">>, __IgnoreEls, - _el), - Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, - Cell, Modem, Isdn, Video); - _ -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) - end; -decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"MSG">>, _attrs, _} = _el | _els], Number, - Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, - Cell, Modem, Isdn, Video) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, - decode_vcard_MSG(__TopXMLNS, __IgnoreEls, _el), - Fax, Work, Cell, Modem, Isdn, Video); - <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, - decode_vcard_MSG(<<"vcard-temp">>, __IgnoreEls, - _el), - Fax, Work, Cell, Modem, Isdn, Video); - _ -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) - end; -decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"CELL">>, _attrs, _} = _el | _els], Number, - Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, - Cell, Modem, Isdn, Video) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, - decode_vcard_CELL(__TopXMLNS, __IgnoreEls, _el), - Modem, Isdn, Video); - <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, - decode_vcard_CELL(<<"vcard-temp">>, __IgnoreEls, - _el), - Modem, Isdn, Video); - _ -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) - end; -decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"VIDEO">>, _attrs, _} = _el | _els], Number, - Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, - Cell, Modem, Isdn, Video) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, - decode_vcard_VIDEO(__TopXMLNS, __IgnoreEls, - _el)); - <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, - decode_vcard_VIDEO(<<"vcard-temp">>, __IgnoreEls, - _el)); - _ -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) - end; -decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"BBS">>, _attrs, _} = _el | _els], Number, - Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, - Cell, Modem, Isdn, Video) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, - decode_vcard_BBS(__TopXMLNS, __IgnoreEls, _el), - Voice, Home, Pref, Msg, Fax, Work, Cell, Modem, - Isdn, Video); - <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, - decode_vcard_BBS(<<"vcard-temp">>, __IgnoreEls, - _el), - Voice, Home, Pref, Msg, Fax, Work, Cell, Modem, - Isdn, Video); - _ -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) - end; -decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"MODEM">>, _attrs, _} = _el | _els], Number, - Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, - Cell, Modem, Isdn, Video) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, - decode_vcard_MODEM(__TopXMLNS, __IgnoreEls, _el), - Isdn, Video); - <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, - decode_vcard_MODEM(<<"vcard-temp">>, __IgnoreEls, - _el), - Isdn, Video); - _ -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) - end; -decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"ISDN">>, _attrs, _} = _el | _els], Number, - Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, - Cell, Modem, Isdn, Video) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, - decode_vcard_ISDN(__TopXMLNS, __IgnoreEls, _el), - Video); - <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, - decode_vcard_ISDN(<<"vcard-temp">>, __IgnoreEls, - _el), - Video); - _ -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) - end; -decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"PCS">>, _attrs, _} = _el | _els], Number, - Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, - Cell, Modem, Isdn, Video) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, - decode_vcard_PCS(__TopXMLNS, __IgnoreEls, _el), - Bbs, Voice, Home, Pref, Msg, Fax, Work, Cell, - Modem, Isdn, Video); - <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, - decode_vcard_PCS(<<"vcard-temp">>, __IgnoreEls, - _el), - Bbs, Voice, Home, Pref, Msg, Fax, Work, Cell, - Modem, Isdn, Video); - _ -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) - end; -decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"PREF">>, _attrs, _} = _el | _els], Number, - Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, - Cell, Modem, Isdn, Video) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, - decode_vcard_PREF(__TopXMLNS, __IgnoreEls, _el), - Msg, Fax, Work, Cell, Modem, Isdn, Video); - <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, - decode_vcard_PREF(<<"vcard-temp">>, __IgnoreEls, - _el), - Msg, Fax, Work, Cell, Modem, Isdn, Video); - _ -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) - end; -decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"NUMBER">>, _attrs, _} = _el | _els], Number, - Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, Work, - Cell, Modem, Isdn, Video) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_NUMBER(__TopXMLNS, __IgnoreEls, - _el), - Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, - Work, Cell, Modem, Isdn, Video); - <<"vcard-temp">> -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_NUMBER(<<"vcard-temp">>, - __IgnoreEls, _el), - Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, - Work, Cell, Modem, Isdn, Video); - _ -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, - Fax, Work, Cell, Modem, Isdn, Video) - end; -decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Number, Pager, Pcs, Bbs, Voice, Home, Pref, - Msg, Fax, Work, Cell, Modem, Isdn, Video) -> - decode_vcard_TEL_els(__TopXMLNS, __IgnoreEls, _els, - Number, Pager, Pcs, Bbs, Voice, Home, Pref, Msg, Fax, - Work, Cell, Modem, Isdn, Video). - -encode_vcard_TEL({vcard_tel, Home, Work, Voice, Fax, - Pager, Msg, Cell, Video, Bbs, Modem, Isdn, Pcs, Pref, - Number}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = lists:reverse('encode_vcard_TEL_$number'(Number, - __NewTopXMLNS, - 'encode_vcard_TEL_$pager'(Pager, - __NewTopXMLNS, - 'encode_vcard_TEL_$pcs'(Pcs, - __NewTopXMLNS, - 'encode_vcard_TEL_$bbs'(Bbs, - __NewTopXMLNS, - 'encode_vcard_TEL_$voice'(Voice, - __NewTopXMLNS, - 'encode_vcard_TEL_$home'(Home, - __NewTopXMLNS, - 'encode_vcard_TEL_$pref'(Pref, - __NewTopXMLNS, - 'encode_vcard_TEL_$msg'(Msg, - __NewTopXMLNS, - 'encode_vcard_TEL_$fax'(Fax, - __NewTopXMLNS, - 'encode_vcard_TEL_$work'(Work, - __NewTopXMLNS, - 'encode_vcard_TEL_$cell'(Cell, - __NewTopXMLNS, - 'encode_vcard_TEL_$modem'(Modem, - __NewTopXMLNS, - 'encode_vcard_TEL_$isdn'(Isdn, - __NewTopXMLNS, - 'encode_vcard_TEL_$video'(Video, - __NewTopXMLNS, - []))))))))))))))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"TEL">>, _attrs, _els}. - -'encode_vcard_TEL_$number'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_TEL_$number'(Number, __TopXMLNS, _acc) -> - [encode_vcard_NUMBER(Number, __TopXMLNS) | _acc]. - -'encode_vcard_TEL_$pager'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_TEL_$pager'(Pager, __TopXMLNS, _acc) -> - [encode_vcard_PAGER(Pager, __TopXMLNS) | _acc]. - -'encode_vcard_TEL_$pcs'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_TEL_$pcs'(Pcs, __TopXMLNS, _acc) -> - [encode_vcard_PCS(Pcs, __TopXMLNS) | _acc]. - -'encode_vcard_TEL_$bbs'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_TEL_$bbs'(Bbs, __TopXMLNS, _acc) -> - [encode_vcard_BBS(Bbs, __TopXMLNS) | _acc]. - -'encode_vcard_TEL_$voice'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_TEL_$voice'(Voice, __TopXMLNS, _acc) -> - [encode_vcard_VOICE(Voice, __TopXMLNS) | _acc]. - -'encode_vcard_TEL_$home'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_TEL_$home'(Home, __TopXMLNS, _acc) -> - [encode_vcard_HOME(Home, __TopXMLNS) | _acc]. - -'encode_vcard_TEL_$pref'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_TEL_$pref'(Pref, __TopXMLNS, _acc) -> - [encode_vcard_PREF(Pref, __TopXMLNS) | _acc]. - -'encode_vcard_TEL_$msg'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_TEL_$msg'(Msg, __TopXMLNS, _acc) -> - [encode_vcard_MSG(Msg, __TopXMLNS) | _acc]. - -'encode_vcard_TEL_$fax'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_TEL_$fax'(Fax, __TopXMLNS, _acc) -> - [encode_vcard_FAX(Fax, __TopXMLNS) | _acc]. - -'encode_vcard_TEL_$work'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_TEL_$work'(Work, __TopXMLNS, _acc) -> - [encode_vcard_WORK(Work, __TopXMLNS) | _acc]. - -'encode_vcard_TEL_$cell'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_TEL_$cell'(Cell, __TopXMLNS, _acc) -> - [encode_vcard_CELL(Cell, __TopXMLNS) | _acc]. - -'encode_vcard_TEL_$modem'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_TEL_$modem'(Modem, __TopXMLNS, _acc) -> - [encode_vcard_MODEM(Modem, __TopXMLNS) | _acc]. - -'encode_vcard_TEL_$isdn'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_TEL_$isdn'(Isdn, __TopXMLNS, _acc) -> - [encode_vcard_ISDN(Isdn, __TopXMLNS) | _acc]. - -'encode_vcard_TEL_$video'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_TEL_$video'(Video, __TopXMLNS, _acc) -> - [encode_vcard_VIDEO(Video, __TopXMLNS) | _acc]. - -decode_vcard_LABEL(__TopXMLNS, __IgnoreEls, - {xmlel, <<"LABEL">>, _attrs, _els}) -> - {Line, Home, Pref, Work, Intl, Parcel, Postal, Dom} = - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - [], false, false, false, false, false, false, - false), - {vcard_label, Home, Work, Postal, Parcel, Dom, Intl, - Pref, Line}. - -decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, [], - Line, Home, Pref, Work, Intl, Parcel, Postal, Dom) -> - {lists:reverse(Line), Home, Pref, Work, Intl, Parcel, - Postal, Dom}; -decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"HOME">>, _attrs, _} = _el | _els], Line, - Home, Pref, Work, Intl, Parcel, Postal, Dom) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, - decode_vcard_HOME(__TopXMLNS, __IgnoreEls, - _el), - Pref, Work, Intl, Parcel, Postal, Dom); - <<"vcard-temp">> -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, - decode_vcard_HOME(<<"vcard-temp">>, - __IgnoreEls, _el), - Pref, Work, Intl, Parcel, Postal, Dom); - _ -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, Parcel, Postal, - Dom) - end; -decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"WORK">>, _attrs, _} = _el | _els], Line, - Home, Pref, Work, Intl, Parcel, Postal, Dom) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, - decode_vcard_WORK(__TopXMLNS, __IgnoreEls, - _el), - Intl, Parcel, Postal, Dom); - <<"vcard-temp">> -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, - decode_vcard_WORK(<<"vcard-temp">>, - __IgnoreEls, _el), - Intl, Parcel, Postal, Dom); - _ -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, Parcel, Postal, - Dom) - end; -decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"POSTAL">>, _attrs, _} = _el | _els], Line, - Home, Pref, Work, Intl, Parcel, Postal, Dom) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, Parcel, - decode_vcard_POSTAL(__TopXMLNS, __IgnoreEls, - _el), - Dom); - <<"vcard-temp">> -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, Parcel, - decode_vcard_POSTAL(<<"vcard-temp">>, - __IgnoreEls, _el), - Dom); - _ -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, Parcel, Postal, - Dom) - end; -decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"PARCEL">>, _attrs, _} = _el | _els], Line, - Home, Pref, Work, Intl, Parcel, Postal, Dom) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, - decode_vcard_PARCEL(__TopXMLNS, __IgnoreEls, - _el), - Postal, Dom); - <<"vcard-temp">> -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, - decode_vcard_PARCEL(<<"vcard-temp">>, - __IgnoreEls, _el), - Postal, Dom); - _ -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, Parcel, Postal, - Dom) - end; -decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"DOM">>, _attrs, _} = _el | _els], Line, - Home, Pref, Work, Intl, Parcel, Postal, Dom) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, Parcel, Postal, - decode_vcard_DOM(__TopXMLNS, __IgnoreEls, - _el)); - <<"vcard-temp">> -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, Parcel, Postal, - decode_vcard_DOM(<<"vcard-temp">>, __IgnoreEls, - _el)); - _ -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, Parcel, Postal, - Dom) - end; -decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"INTL">>, _attrs, _} = _el | _els], Line, - Home, Pref, Work, Intl, Parcel, Postal, Dom) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, - decode_vcard_INTL(__TopXMLNS, __IgnoreEls, - _el), - Parcel, Postal, Dom); - <<"vcard-temp">> -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, - decode_vcard_INTL(<<"vcard-temp">>, - __IgnoreEls, _el), - Parcel, Postal, Dom); - _ -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, Parcel, Postal, - Dom) - end; -decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"PREF">>, _attrs, _} = _el | _els], Line, - Home, Pref, Work, Intl, Parcel, Postal, Dom) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, - decode_vcard_PREF(__TopXMLNS, __IgnoreEls, - _el), - Work, Intl, Parcel, Postal, Dom); - <<"vcard-temp">> -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, - decode_vcard_PREF(<<"vcard-temp">>, - __IgnoreEls, _el), - Work, Intl, Parcel, Postal, Dom); - _ -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, Parcel, Postal, - Dom) - end; -decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"LINE">>, _attrs, _} = _el | _els], Line, - Home, Pref, Work, Intl, Parcel, Postal, Dom) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - [decode_vcard_LINE(__TopXMLNS, __IgnoreEls, - _el) - | Line], - Home, Pref, Work, Intl, Parcel, Postal, Dom); - <<"vcard-temp">> -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - [decode_vcard_LINE(<<"vcard-temp">>, - __IgnoreEls, _el) - | Line], - Home, Pref, Work, Intl, Parcel, Postal, Dom); - _ -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, Parcel, Postal, - Dom) - end; -decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Line, Home, Pref, Work, Intl, Parcel, - Postal, Dom) -> - decode_vcard_LABEL_els(__TopXMLNS, __IgnoreEls, _els, - Line, Home, Pref, Work, Intl, Parcel, Postal, Dom). - -encode_vcard_LABEL({vcard_label, Home, Work, Postal, - Parcel, Dom, Intl, Pref, Line}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = lists:reverse('encode_vcard_LABEL_$line'(Line, - __NewTopXMLNS, - 'encode_vcard_LABEL_$home'(Home, - __NewTopXMLNS, - 'encode_vcard_LABEL_$pref'(Pref, - __NewTopXMLNS, - 'encode_vcard_LABEL_$work'(Work, - __NewTopXMLNS, - 'encode_vcard_LABEL_$intl'(Intl, - __NewTopXMLNS, - 'encode_vcard_LABEL_$parcel'(Parcel, - __NewTopXMLNS, - 'encode_vcard_LABEL_$postal'(Postal, - __NewTopXMLNS, - 'encode_vcard_LABEL_$dom'(Dom, - __NewTopXMLNS, - []))))))))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"LABEL">>, _attrs, _els}. - -'encode_vcard_LABEL_$line'([], __TopXMLNS, _acc) -> - _acc; -'encode_vcard_LABEL_$line'([Line | _els], __TopXMLNS, - _acc) -> - 'encode_vcard_LABEL_$line'(_els, __TopXMLNS, - [encode_vcard_LINE(Line, __TopXMLNS) | _acc]). - -'encode_vcard_LABEL_$home'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_LABEL_$home'(Home, __TopXMLNS, _acc) -> - [encode_vcard_HOME(Home, __TopXMLNS) | _acc]. - -'encode_vcard_LABEL_$pref'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_LABEL_$pref'(Pref, __TopXMLNS, _acc) -> - [encode_vcard_PREF(Pref, __TopXMLNS) | _acc]. - -'encode_vcard_LABEL_$work'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_LABEL_$work'(Work, __TopXMLNS, _acc) -> - [encode_vcard_WORK(Work, __TopXMLNS) | _acc]. - -'encode_vcard_LABEL_$intl'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_LABEL_$intl'(Intl, __TopXMLNS, _acc) -> - [encode_vcard_INTL(Intl, __TopXMLNS) | _acc]. - -'encode_vcard_LABEL_$parcel'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_LABEL_$parcel'(Parcel, __TopXMLNS, - _acc) -> - [encode_vcard_PARCEL(Parcel, __TopXMLNS) | _acc]. - -'encode_vcard_LABEL_$postal'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_LABEL_$postal'(Postal, __TopXMLNS, - _acc) -> - [encode_vcard_POSTAL(Postal, __TopXMLNS) | _acc]. - -'encode_vcard_LABEL_$dom'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_LABEL_$dom'(Dom, __TopXMLNS, _acc) -> - [encode_vcard_DOM(Dom, __TopXMLNS) | _acc]. - -decode_vcard_ADR(__TopXMLNS, __IgnoreEls, - {xmlel, <<"ADR">>, _attrs, _els}) -> - {Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, Region} = - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - undefined, undefined, undefined, false, false, - undefined, undefined, undefined, false, false, - false, false, false, undefined), - {vcard_adr, Home, Work, Postal, Parcel, Dom, Intl, Pref, - Pobox, Extadd, Street, Locality, Region, Pcode, Ctry}. - -decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, [], - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, Region) -> - {Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, Region}; -decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"HOME">>, _attrs, _} = _el | _els], Street, - Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, - Intl, Parcel, Postal, Dom, Region) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, - decode_vcard_HOME(__TopXMLNS, __IgnoreEls, _el), - Pref, Pobox, Ctry, Locality, Work, Intl, Parcel, - Postal, Dom, Region); - <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, - decode_vcard_HOME(<<"vcard-temp">>, __IgnoreEls, - _el), - Pref, Pobox, Ctry, Locality, Work, Intl, Parcel, - Postal, Dom, Region); - _ -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) - end; -decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"WORK">>, _attrs, _} = _el | _els], Street, - Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, - Intl, Parcel, Postal, Dom, Region) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, - decode_vcard_WORK(__TopXMLNS, __IgnoreEls, _el), - Intl, Parcel, Postal, Dom, Region); - <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, - decode_vcard_WORK(<<"vcard-temp">>, __IgnoreEls, - _el), - Intl, Parcel, Postal, Dom, Region); - _ -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) - end; -decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"POSTAL">>, _attrs, _} = _el | _els], Street, - Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, - Intl, Parcel, Postal, Dom, Region) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, - decode_vcard_POSTAL(__TopXMLNS, __IgnoreEls, - _el), - Dom, Region); - <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, - decode_vcard_POSTAL(<<"vcard-temp">>, - __IgnoreEls, _el), - Dom, Region); - _ -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) - end; -decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"PARCEL">>, _attrs, _} = _el | _els], Street, - Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, - Intl, Parcel, Postal, Dom, Region) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, - decode_vcard_PARCEL(__TopXMLNS, __IgnoreEls, - _el), - Postal, Dom, Region); - <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, - decode_vcard_PARCEL(<<"vcard-temp">>, - __IgnoreEls, _el), - Postal, Dom, Region); - _ -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) - end; -decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"DOM">>, _attrs, _} = _el | _els], Street, - Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, - Intl, Parcel, Postal, Dom, Region) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, - decode_vcard_DOM(__TopXMLNS, __IgnoreEls, _el), - Region); - <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, - decode_vcard_DOM(<<"vcard-temp">>, __IgnoreEls, - _el), - Region); - _ -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) - end; -decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"INTL">>, _attrs, _} = _el | _els], Street, - Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, - Intl, Parcel, Postal, Dom, Region) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, - decode_vcard_INTL(__TopXMLNS, __IgnoreEls, _el), - Parcel, Postal, Dom, Region); - <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, - decode_vcard_INTL(<<"vcard-temp">>, __IgnoreEls, - _el), - Parcel, Postal, Dom, Region); - _ -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) - end; -decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"PREF">>, _attrs, _} = _el | _els], Street, - Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, - Intl, Parcel, Postal, Dom, Region) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, - decode_vcard_PREF(__TopXMLNS, __IgnoreEls, _el), - Pobox, Ctry, Locality, Work, Intl, Parcel, - Postal, Dom, Region); - <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, - decode_vcard_PREF(<<"vcard-temp">>, __IgnoreEls, - _el), - Pobox, Ctry, Locality, Work, Intl, Parcel, - Postal, Dom, Region); - _ -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) - end; -decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"POBOX">>, _attrs, _} = _el | _els], Street, - Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, - Intl, Parcel, Postal, Dom, Region) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, - decode_vcard_POBOX(__TopXMLNS, __IgnoreEls, _el), - Ctry, Locality, Work, Intl, Parcel, Postal, Dom, - Region); - <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, - decode_vcard_POBOX(<<"vcard-temp">>, __IgnoreEls, - _el), - Ctry, Locality, Work, Intl, Parcel, Postal, Dom, - Region); - _ -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) - end; -decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"EXTADD">>, _attrs, _} = _el | _els], Street, - Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, - Intl, Parcel, Postal, Dom, Region) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, - decode_vcard_EXTADD(__TopXMLNS, __IgnoreEls, - _el), - Pcode, Home, Pref, Pobox, Ctry, Locality, Work, - Intl, Parcel, Postal, Dom, Region); - <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, - decode_vcard_EXTADD(<<"vcard-temp">>, - __IgnoreEls, _el), - Pcode, Home, Pref, Pobox, Ctry, Locality, Work, - Intl, Parcel, Postal, Dom, Region); - _ -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) - end; -decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"STREET">>, _attrs, _} = _el | _els], Street, - Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, - Intl, Parcel, Postal, Dom, Region) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_STREET(__TopXMLNS, __IgnoreEls, - _el), - Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, - Work, Intl, Parcel, Postal, Dom, Region); - <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_STREET(<<"vcard-temp">>, - __IgnoreEls, _el), - Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, - Work, Intl, Parcel, Postal, Dom, Region); - _ -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) - end; -decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"LOCALITY">>, _attrs, _} = _el | _els], - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, Region) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - decode_vcard_LOCALITY(__TopXMLNS, __IgnoreEls, - _el), - Work, Intl, Parcel, Postal, Dom, Region); - <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - decode_vcard_LOCALITY(<<"vcard-temp">>, - __IgnoreEls, _el), - Work, Intl, Parcel, Postal, Dom, Region); - _ -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) - end; -decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"REGION">>, _attrs, _} = _el | _els], Street, - Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, - Intl, Parcel, Postal, Dom, Region) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - decode_vcard_REGION(__TopXMLNS, __IgnoreEls, - _el)); - <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - decode_vcard_REGION(<<"vcard-temp">>, - __IgnoreEls, _el)); - _ -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) - end; -decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"PCODE">>, _attrs, _} = _el | _els], Street, - Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, - Intl, Parcel, Postal, Dom, Region) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, - decode_vcard_PCODE(__TopXMLNS, __IgnoreEls, _el), - Home, Pref, Pobox, Ctry, Locality, Work, Intl, - Parcel, Postal, Dom, Region); - <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, - decode_vcard_PCODE(<<"vcard-temp">>, __IgnoreEls, - _el), - Home, Pref, Pobox, Ctry, Locality, Work, Intl, - Parcel, Postal, Dom, Region); - _ -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) - end; -decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"CTRY">>, _attrs, _} = _el | _els], Street, - Extadd, Pcode, Home, Pref, Pobox, Ctry, Locality, Work, - Intl, Parcel, Postal, Dom, Region) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, - decode_vcard_CTRY(__TopXMLNS, __IgnoreEls, _el), - Locality, Work, Intl, Parcel, Postal, Dom, - Region); - <<"vcard-temp">> -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, - decode_vcard_CTRY(<<"vcard-temp">>, __IgnoreEls, - _el), - Locality, Work, Intl, Parcel, Postal, Dom, - Region); - _ -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, - Region) - end; -decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Street, Extadd, Pcode, Home, Pref, Pobox, - Ctry, Locality, Work, Intl, Parcel, Postal, Dom, - Region) -> - decode_vcard_ADR_els(__TopXMLNS, __IgnoreEls, _els, - Street, Extadd, Pcode, Home, Pref, Pobox, Ctry, - Locality, Work, Intl, Parcel, Postal, Dom, Region). - -encode_vcard_ADR({vcard_adr, Home, Work, Postal, Parcel, - Dom, Intl, Pref, Pobox, Extadd, Street, Locality, - Region, Pcode, Ctry}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = lists:reverse('encode_vcard_ADR_$street'(Street, - __NewTopXMLNS, - 'encode_vcard_ADR_$extadd'(Extadd, - __NewTopXMLNS, - 'encode_vcard_ADR_$pcode'(Pcode, - __NewTopXMLNS, - 'encode_vcard_ADR_$home'(Home, - __NewTopXMLNS, - 'encode_vcard_ADR_$pref'(Pref, - __NewTopXMLNS, - 'encode_vcard_ADR_$pobox'(Pobox, - __NewTopXMLNS, - 'encode_vcard_ADR_$ctry'(Ctry, - __NewTopXMLNS, - 'encode_vcard_ADR_$locality'(Locality, - __NewTopXMLNS, - 'encode_vcard_ADR_$work'(Work, - __NewTopXMLNS, - 'encode_vcard_ADR_$intl'(Intl, - __NewTopXMLNS, - 'encode_vcard_ADR_$parcel'(Parcel, - __NewTopXMLNS, - 'encode_vcard_ADR_$postal'(Postal, - __NewTopXMLNS, - 'encode_vcard_ADR_$dom'(Dom, - __NewTopXMLNS, - 'encode_vcard_ADR_$region'(Region, - __NewTopXMLNS, - []))))))))))))))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"ADR">>, _attrs, _els}. - -'encode_vcard_ADR_$street'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_ADR_$street'(Street, __TopXMLNS, _acc) -> - [encode_vcard_STREET(Street, __TopXMLNS) | _acc]. - -'encode_vcard_ADR_$extadd'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_ADR_$extadd'(Extadd, __TopXMLNS, _acc) -> - [encode_vcard_EXTADD(Extadd, __TopXMLNS) | _acc]. - -'encode_vcard_ADR_$pcode'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_ADR_$pcode'(Pcode, __TopXMLNS, _acc) -> - [encode_vcard_PCODE(Pcode, __TopXMLNS) | _acc]. - -'encode_vcard_ADR_$home'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_ADR_$home'(Home, __TopXMLNS, _acc) -> - [encode_vcard_HOME(Home, __TopXMLNS) | _acc]. - -'encode_vcard_ADR_$pref'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_ADR_$pref'(Pref, __TopXMLNS, _acc) -> - [encode_vcard_PREF(Pref, __TopXMLNS) | _acc]. - -'encode_vcard_ADR_$pobox'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_ADR_$pobox'(Pobox, __TopXMLNS, _acc) -> - [encode_vcard_POBOX(Pobox, __TopXMLNS) | _acc]. - -'encode_vcard_ADR_$ctry'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_ADR_$ctry'(Ctry, __TopXMLNS, _acc) -> - [encode_vcard_CTRY(Ctry, __TopXMLNS) | _acc]. - -'encode_vcard_ADR_$locality'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_ADR_$locality'(Locality, __TopXMLNS, - _acc) -> - [encode_vcard_LOCALITY(Locality, __TopXMLNS) | _acc]. - -'encode_vcard_ADR_$work'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_ADR_$work'(Work, __TopXMLNS, _acc) -> - [encode_vcard_WORK(Work, __TopXMLNS) | _acc]. - -'encode_vcard_ADR_$intl'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_ADR_$intl'(Intl, __TopXMLNS, _acc) -> - [encode_vcard_INTL(Intl, __TopXMLNS) | _acc]. - -'encode_vcard_ADR_$parcel'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_ADR_$parcel'(Parcel, __TopXMLNS, _acc) -> - [encode_vcard_PARCEL(Parcel, __TopXMLNS) | _acc]. - -'encode_vcard_ADR_$postal'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_ADR_$postal'(Postal, __TopXMLNS, _acc) -> - [encode_vcard_POSTAL(Postal, __TopXMLNS) | _acc]. - -'encode_vcard_ADR_$dom'(false, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_ADR_$dom'(Dom, __TopXMLNS, _acc) -> - [encode_vcard_DOM(Dom, __TopXMLNS) | _acc]. - -'encode_vcard_ADR_$region'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_vcard_ADR_$region'(Region, __TopXMLNS, _acc) -> - [encode_vcard_REGION(Region, __TopXMLNS) | _acc]. - -decode_vcard_N(__TopXMLNS, __IgnoreEls, - {xmlel, <<"N">>, _attrs, _els}) -> - {Middle, Suffix, Prefix, Family, Given} = - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - undefined, undefined, undefined, undefined, - undefined), - {vcard_name, Family, Given, Middle, Prefix, Suffix}. - -decode_vcard_N_els(__TopXMLNS, __IgnoreEls, [], Middle, - Suffix, Prefix, Family, Given) -> - {Middle, Suffix, Prefix, Family, Given}; -decode_vcard_N_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"FAMILY">>, _attrs, _} = _el | _els], Middle, - Suffix, Prefix, Family, Given) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - Middle, Suffix, Prefix, - decode_vcard_FAMILY(__TopXMLNS, __IgnoreEls, _el), - Given); - <<"vcard-temp">> -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - Middle, Suffix, Prefix, - decode_vcard_FAMILY(<<"vcard-temp">>, __IgnoreEls, - _el), - Given); - _ -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - Middle, Suffix, Prefix, Family, Given) - end; -decode_vcard_N_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"GIVEN">>, _attrs, _} = _el | _els], Middle, - Suffix, Prefix, Family, Given) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - Middle, Suffix, Prefix, Family, - decode_vcard_GIVEN(__TopXMLNS, __IgnoreEls, _el)); - <<"vcard-temp">> -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - Middle, Suffix, Prefix, Family, - decode_vcard_GIVEN(<<"vcard-temp">>, __IgnoreEls, - _el)); - _ -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - Middle, Suffix, Prefix, Family, Given) - end; -decode_vcard_N_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"MIDDLE">>, _attrs, _} = _el | _els], Middle, - Suffix, Prefix, Family, Given) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_MIDDLE(__TopXMLNS, __IgnoreEls, _el), - Suffix, Prefix, Family, Given); - <<"vcard-temp">> -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - decode_vcard_MIDDLE(<<"vcard-temp">>, __IgnoreEls, - _el), - Suffix, Prefix, Family, Given); - _ -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - Middle, Suffix, Prefix, Family, Given) - end; -decode_vcard_N_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"PREFIX">>, _attrs, _} = _el | _els], Middle, - Suffix, Prefix, Family, Given) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - Middle, Suffix, - decode_vcard_PREFIX(__TopXMLNS, __IgnoreEls, _el), - Family, Given); - <<"vcard-temp">> -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - Middle, Suffix, - decode_vcard_PREFIX(<<"vcard-temp">>, __IgnoreEls, - _el), - Family, Given); - _ -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - Middle, Suffix, Prefix, Family, Given) - end; -decode_vcard_N_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"SUFFIX">>, _attrs, _} = _el | _els], Middle, - Suffix, Prefix, Family, Given) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"vcard-temp">> -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - Middle, - decode_vcard_SUFFIX(__TopXMLNS, __IgnoreEls, _el), - Prefix, Family, Given); - <<"vcard-temp">> -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - Middle, - decode_vcard_SUFFIX(<<"vcard-temp">>, __IgnoreEls, - _el), - Prefix, Family, Given); - _ -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - Middle, Suffix, Prefix, Family, Given) - end; -decode_vcard_N_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Middle, Suffix, Prefix, Family, Given) -> - decode_vcard_N_els(__TopXMLNS, __IgnoreEls, _els, - Middle, Suffix, Prefix, Family, Given). - -encode_vcard_N({vcard_name, Family, Given, Middle, - Prefix, Suffix}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = lists:reverse('encode_vcard_N_$middle'(Middle, - __NewTopXMLNS, - 'encode_vcard_N_$suffix'(Suffix, - __NewTopXMLNS, - 'encode_vcard_N_$prefix'(Prefix, - __NewTopXMLNS, - 'encode_vcard_N_$family'(Family, - __NewTopXMLNS, - 'encode_vcard_N_$given'(Given, - __NewTopXMLNS, - [])))))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"N">>, _attrs, _els}. - -'encode_vcard_N_$middle'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_N_$middle'(Middle, __TopXMLNS, _acc) -> - [encode_vcard_MIDDLE(Middle, __TopXMLNS) | _acc]. - -'encode_vcard_N_$suffix'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_N_$suffix'(Suffix, __TopXMLNS, _acc) -> - [encode_vcard_SUFFIX(Suffix, __TopXMLNS) | _acc]. - -'encode_vcard_N_$prefix'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_N_$prefix'(Prefix, __TopXMLNS, _acc) -> - [encode_vcard_PREFIX(Prefix, __TopXMLNS) | _acc]. - -'encode_vcard_N_$family'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_N_$family'(Family, __TopXMLNS, _acc) -> - [encode_vcard_FAMILY(Family, __TopXMLNS) | _acc]. - -'encode_vcard_N_$given'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_vcard_N_$given'(Given, __TopXMLNS, _acc) -> - [encode_vcard_GIVEN(Given, __TopXMLNS) | _acc]. - -decode_vcard_CONFIDENTIAL(__TopXMLNS, __IgnoreEls, - {xmlel, <<"CONFIDENTIAL">>, _attrs, _els}) -> - confidential. - -encode_vcard_CONFIDENTIAL(confidential, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"CONFIDENTIAL">>, _attrs, _els}. - -decode_vcard_PRIVATE(__TopXMLNS, __IgnoreEls, - {xmlel, <<"PRIVATE">>, _attrs, _els}) -> - private. - -encode_vcard_PRIVATE(private, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"PRIVATE">>, _attrs, _els}. - -decode_vcard_PUBLIC(__TopXMLNS, __IgnoreEls, - {xmlel, <<"PUBLIC">>, _attrs, _els}) -> - public. - -encode_vcard_PUBLIC(public, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"PUBLIC">>, _attrs, _els}. - -decode_vcard_EXTVAL(__TopXMLNS, __IgnoreEls, - {xmlel, <<"EXTVAL">>, _attrs, _els}) -> - Cdata = decode_vcard_EXTVAL_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_EXTVAL_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_EXTVAL_cdata(__TopXMLNS, Cdata); -decode_vcard_EXTVAL_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_EXTVAL_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_EXTVAL_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_EXTVAL_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_EXTVAL(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_EXTVAL_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"EXTVAL">>, _attrs, _els}. - -decode_vcard_EXTVAL_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_EXTVAL_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_EXTVAL_cdata(<<>>, _acc) -> _acc; -encode_vcard_EXTVAL_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_TYPE(__TopXMLNS, __IgnoreEls, - {xmlel, <<"TYPE">>, _attrs, _els}) -> - Cdata = decode_vcard_TYPE_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_TYPE_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_TYPE_cdata(__TopXMLNS, Cdata); -decode_vcard_TYPE_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_TYPE_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_TYPE_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_TYPE_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_TYPE(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_TYPE_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"TYPE">>, _attrs, _els}. - -decode_vcard_TYPE_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_TYPE_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_TYPE_cdata(<<>>, _acc) -> _acc; -encode_vcard_TYPE_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_DESC(__TopXMLNS, __IgnoreEls, - {xmlel, <<"DESC">>, _attrs, _els}) -> - Cdata = decode_vcard_DESC_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_DESC_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_DESC_cdata(__TopXMLNS, Cdata); -decode_vcard_DESC_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_DESC_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_DESC_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_DESC_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_DESC(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_DESC_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"DESC">>, _attrs, _els}. - -decode_vcard_DESC_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_DESC_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_DESC_cdata(<<>>, _acc) -> _acc; -encode_vcard_DESC_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_URL(__TopXMLNS, __IgnoreEls, - {xmlel, <<"URL">>, _attrs, _els}) -> - Cdata = decode_vcard_URL_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_URL_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_URL_cdata(__TopXMLNS, Cdata); -decode_vcard_URL_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_URL_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_URL_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_URL_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_URL(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_URL_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"URL">>, _attrs, _els}. - -decode_vcard_URL_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_URL_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_URL_cdata(<<>>, _acc) -> _acc; -encode_vcard_URL_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_UID(__TopXMLNS, __IgnoreEls, - {xmlel, <<"UID">>, _attrs, _els}) -> - Cdata = decode_vcard_UID_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_UID_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_UID_cdata(__TopXMLNS, Cdata); -decode_vcard_UID_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_UID_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_UID_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_UID_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_UID(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_UID_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"UID">>, _attrs, _els}. - -decode_vcard_UID_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_UID_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_UID_cdata(<<>>, _acc) -> _acc; -encode_vcard_UID_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_SORT_STRING(__TopXMLNS, __IgnoreEls, - {xmlel, <<"SORT-STRING">>, _attrs, _els}) -> - Cdata = decode_vcard_SORT_STRING_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_vcard_SORT_STRING_els(__TopXMLNS, __IgnoreEls, - [], Cdata) -> - decode_vcard_SORT_STRING_cdata(__TopXMLNS, Cdata); -decode_vcard_SORT_STRING_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_SORT_STRING_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_vcard_SORT_STRING_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_SORT_STRING_els(__TopXMLNS, __IgnoreEls, - _els, Cdata). - -encode_vcard_SORT_STRING(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_SORT_STRING_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"SORT-STRING">>, _attrs, _els}. - -decode_vcard_SORT_STRING_cdata(__TopXMLNS, <<>>) -> - <<>>; -decode_vcard_SORT_STRING_cdata(__TopXMLNS, _val) -> - _val. - -encode_vcard_SORT_STRING_cdata(<<>>, _acc) -> _acc; -encode_vcard_SORT_STRING_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_REV(__TopXMLNS, __IgnoreEls, - {xmlel, <<"REV">>, _attrs, _els}) -> - Cdata = decode_vcard_REV_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_REV_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_REV_cdata(__TopXMLNS, Cdata); -decode_vcard_REV_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_REV_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_REV_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_REV_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_REV(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_REV_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"REV">>, _attrs, _els}. - -decode_vcard_REV_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_REV_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_REV_cdata(<<>>, _acc) -> _acc; -encode_vcard_REV_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_PRODID(__TopXMLNS, __IgnoreEls, - {xmlel, <<"PRODID">>, _attrs, _els}) -> - Cdata = decode_vcard_PRODID_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_PRODID_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_PRODID_cdata(__TopXMLNS, Cdata); -decode_vcard_PRODID_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_PRODID_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_PRODID_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_PRODID_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_PRODID(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_PRODID_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"PRODID">>, _attrs, _els}. - -decode_vcard_PRODID_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_PRODID_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_PRODID_cdata(<<>>, _acc) -> _acc; -encode_vcard_PRODID_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_NOTE(__TopXMLNS, __IgnoreEls, - {xmlel, <<"NOTE">>, _attrs, _els}) -> - Cdata = decode_vcard_NOTE_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_NOTE_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_NOTE_cdata(__TopXMLNS, Cdata); -decode_vcard_NOTE_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_NOTE_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_NOTE_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_NOTE_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_NOTE(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_NOTE_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"NOTE">>, _attrs, _els}. - -decode_vcard_NOTE_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_NOTE_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_NOTE_cdata(<<>>, _acc) -> _acc; -encode_vcard_NOTE_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_KEYWORD(__TopXMLNS, __IgnoreEls, - {xmlel, <<"KEYWORD">>, _attrs, _els}) -> - Cdata = decode_vcard_KEYWORD_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_vcard_KEYWORD_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_KEYWORD_cdata(__TopXMLNS, Cdata); -decode_vcard_KEYWORD_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_KEYWORD_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_KEYWORD_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_KEYWORD_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_KEYWORD(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_KEYWORD_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"KEYWORD">>, _attrs, _els}. - -decode_vcard_KEYWORD_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_KEYWORD_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_KEYWORD_cdata(<<>>, _acc) -> _acc; -encode_vcard_KEYWORD_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_ROLE(__TopXMLNS, __IgnoreEls, - {xmlel, <<"ROLE">>, _attrs, _els}) -> - Cdata = decode_vcard_ROLE_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_ROLE_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_ROLE_cdata(__TopXMLNS, Cdata); -decode_vcard_ROLE_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_ROLE_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_ROLE_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_ROLE_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_ROLE(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_ROLE_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"ROLE">>, _attrs, _els}. - -decode_vcard_ROLE_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_ROLE_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_ROLE_cdata(<<>>, _acc) -> _acc; -encode_vcard_ROLE_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_TITLE(__TopXMLNS, __IgnoreEls, - {xmlel, <<"TITLE">>, _attrs, _els}) -> - Cdata = decode_vcard_TITLE_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_TITLE_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_TITLE_cdata(__TopXMLNS, Cdata); -decode_vcard_TITLE_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_TITLE_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_TITLE_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_TITLE_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_TITLE(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_TITLE_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"TITLE">>, _attrs, _els}. - -decode_vcard_TITLE_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_TITLE_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_TITLE_cdata(<<>>, _acc) -> _acc; -encode_vcard_TITLE_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_TZ(__TopXMLNS, __IgnoreEls, - {xmlel, <<"TZ">>, _attrs, _els}) -> - Cdata = decode_vcard_TZ_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_TZ_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_TZ_cdata(__TopXMLNS, Cdata); -decode_vcard_TZ_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_TZ_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_TZ_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Cdata) -> - decode_vcard_TZ_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_TZ(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_TZ_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"TZ">>, _attrs, _els}. - -decode_vcard_TZ_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_TZ_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_TZ_cdata(<<>>, _acc) -> _acc; -encode_vcard_TZ_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_MAILER(__TopXMLNS, __IgnoreEls, - {xmlel, <<"MAILER">>, _attrs, _els}) -> - Cdata = decode_vcard_MAILER_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_MAILER_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_MAILER_cdata(__TopXMLNS, Cdata); -decode_vcard_MAILER_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_MAILER_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_MAILER_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_MAILER_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_MAILER(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_MAILER_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"MAILER">>, _attrs, _els}. - -decode_vcard_MAILER_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_MAILER_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_MAILER_cdata(<<>>, _acc) -> _acc; -encode_vcard_MAILER_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_JABBERID(__TopXMLNS, __IgnoreEls, - {xmlel, <<"JABBERID">>, _attrs, _els}) -> - Cdata = decode_vcard_JABBERID_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_vcard_JABBERID_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_JABBERID_cdata(__TopXMLNS, Cdata); -decode_vcard_JABBERID_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_JABBERID_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_JABBERID_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_JABBERID_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_JABBERID(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_JABBERID_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"JABBERID">>, _attrs, _els}. - -decode_vcard_JABBERID_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_JABBERID_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_JABBERID_cdata(<<>>, _acc) -> _acc; -encode_vcard_JABBERID_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_BDAY(__TopXMLNS, __IgnoreEls, - {xmlel, <<"BDAY">>, _attrs, _els}) -> - Cdata = decode_vcard_BDAY_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_BDAY_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_BDAY_cdata(__TopXMLNS, Cdata); -decode_vcard_BDAY_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_BDAY_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_BDAY_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_BDAY_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_BDAY(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_BDAY_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"BDAY">>, _attrs, _els}. - -decode_vcard_BDAY_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_BDAY_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_BDAY_cdata(<<>>, _acc) -> _acc; -encode_vcard_BDAY_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_NICKNAME(__TopXMLNS, __IgnoreEls, - {xmlel, <<"NICKNAME">>, _attrs, _els}) -> - Cdata = decode_vcard_NICKNAME_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_vcard_NICKNAME_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_NICKNAME_cdata(__TopXMLNS, Cdata); -decode_vcard_NICKNAME_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_NICKNAME_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_NICKNAME_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_NICKNAME_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_NICKNAME(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_NICKNAME_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"NICKNAME">>, _attrs, _els}. - -decode_vcard_NICKNAME_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_NICKNAME_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_NICKNAME_cdata(<<>>, _acc) -> _acc; -encode_vcard_NICKNAME_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_FN(__TopXMLNS, __IgnoreEls, - {xmlel, <<"FN">>, _attrs, _els}) -> - Cdata = decode_vcard_FN_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_FN_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_FN_cdata(__TopXMLNS, Cdata); -decode_vcard_FN_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_FN_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_FN_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Cdata) -> - decode_vcard_FN_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_FN(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_FN_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"FN">>, _attrs, _els}. - -decode_vcard_FN_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_FN_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_FN_cdata(<<>>, _acc) -> _acc; -encode_vcard_FN_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_VERSION(__TopXMLNS, __IgnoreEls, - {xmlel, <<"VERSION">>, _attrs, _els}) -> - Cdata = decode_vcard_VERSION_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_vcard_VERSION_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_VERSION_cdata(__TopXMLNS, Cdata); -decode_vcard_VERSION_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_VERSION_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_VERSION_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_VERSION_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_VERSION(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_VERSION_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"VERSION">>, _attrs, _els}. - -decode_vcard_VERSION_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_VERSION_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_VERSION_cdata(<<>>, _acc) -> _acc; -encode_vcard_VERSION_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_CRED(__TopXMLNS, __IgnoreEls, - {xmlel, <<"CRED">>, _attrs, _els}) -> - Cdata = decode_vcard_CRED_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_CRED_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_CRED_cdata(__TopXMLNS, Cdata); -decode_vcard_CRED_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_CRED_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_CRED_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_CRED_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_CRED(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_CRED_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"CRED">>, _attrs, _els}. - -decode_vcard_CRED_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_CRED_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_CRED_cdata(<<>>, _acc) -> _acc; -encode_vcard_CRED_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_PHONETIC(__TopXMLNS, __IgnoreEls, - {xmlel, <<"PHONETIC">>, _attrs, _els}) -> - Cdata = decode_vcard_PHONETIC_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_vcard_PHONETIC_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_PHONETIC_cdata(__TopXMLNS, Cdata); -decode_vcard_PHONETIC_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_PHONETIC_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_PHONETIC_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_PHONETIC_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_PHONETIC(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_PHONETIC_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"PHONETIC">>, _attrs, _els}. - -decode_vcard_PHONETIC_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_PHONETIC_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_PHONETIC_cdata(<<>>, _acc) -> _acc; -encode_vcard_PHONETIC_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_ORGUNIT(__TopXMLNS, __IgnoreEls, - {xmlel, <<"ORGUNIT">>, _attrs, _els}) -> - Cdata = decode_vcard_ORGUNIT_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_vcard_ORGUNIT_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_ORGUNIT_cdata(__TopXMLNS, Cdata); -decode_vcard_ORGUNIT_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_ORGUNIT_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_ORGUNIT_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_ORGUNIT_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_ORGUNIT(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_ORGUNIT_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"ORGUNIT">>, _attrs, _els}. - -decode_vcard_ORGUNIT_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_ORGUNIT_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_ORGUNIT_cdata(<<>>, _acc) -> _acc; -encode_vcard_ORGUNIT_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_ORGNAME(__TopXMLNS, __IgnoreEls, - {xmlel, <<"ORGNAME">>, _attrs, _els}) -> - Cdata = decode_vcard_ORGNAME_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_vcard_ORGNAME_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_ORGNAME_cdata(__TopXMLNS, Cdata); -decode_vcard_ORGNAME_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_ORGNAME_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_ORGNAME_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_ORGNAME_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_ORGNAME(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_ORGNAME_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"ORGNAME">>, _attrs, _els}. - -decode_vcard_ORGNAME_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_ORGNAME_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_ORGNAME_cdata(<<>>, _acc) -> _acc; -encode_vcard_ORGNAME_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_LON(__TopXMLNS, __IgnoreEls, - {xmlel, <<"LON">>, _attrs, _els}) -> - Cdata = decode_vcard_LON_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_LON_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_LON_cdata(__TopXMLNS, Cdata); -decode_vcard_LON_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_LON_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_LON_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_LON_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_LON(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_LON_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"LON">>, _attrs, _els}. - -decode_vcard_LON_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_LON_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_LON_cdata(<<>>, _acc) -> _acc; -encode_vcard_LON_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_LAT(__TopXMLNS, __IgnoreEls, - {xmlel, <<"LAT">>, _attrs, _els}) -> - Cdata = decode_vcard_LAT_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_LAT_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_LAT_cdata(__TopXMLNS, Cdata); -decode_vcard_LAT_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_LAT_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_LAT_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_LAT_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_LAT(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_LAT_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"LAT">>, _attrs, _els}. - -decode_vcard_LAT_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_LAT_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_LAT_cdata(<<>>, _acc) -> _acc; -encode_vcard_LAT_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_USERID(__TopXMLNS, __IgnoreEls, - {xmlel, <<"USERID">>, _attrs, _els}) -> - Cdata = decode_vcard_USERID_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_USERID_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_USERID_cdata(__TopXMLNS, Cdata); -decode_vcard_USERID_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_USERID_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_USERID_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_USERID_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_USERID(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_USERID_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"USERID">>, _attrs, _els}. - -decode_vcard_USERID_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_USERID_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_USERID_cdata(<<>>, _acc) -> _acc; -encode_vcard_USERID_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_NUMBER(__TopXMLNS, __IgnoreEls, - {xmlel, <<"NUMBER">>, _attrs, _els}) -> - Cdata = decode_vcard_NUMBER_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_NUMBER_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_NUMBER_cdata(__TopXMLNS, Cdata); -decode_vcard_NUMBER_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_NUMBER_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_NUMBER_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_NUMBER_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_NUMBER(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_NUMBER_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"NUMBER">>, _attrs, _els}. - -decode_vcard_NUMBER_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_NUMBER_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_NUMBER_cdata(<<>>, _acc) -> _acc; -encode_vcard_NUMBER_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_LINE(__TopXMLNS, __IgnoreEls, - {xmlel, <<"LINE">>, _attrs, _els}) -> - Cdata = decode_vcard_LINE_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_LINE_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_LINE_cdata(__TopXMLNS, Cdata); -decode_vcard_LINE_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_LINE_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_LINE_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_LINE_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_LINE(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_LINE_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"LINE">>, _attrs, _els}. - -decode_vcard_LINE_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_LINE_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_LINE_cdata(<<>>, _acc) -> _acc; -encode_vcard_LINE_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_CTRY(__TopXMLNS, __IgnoreEls, - {xmlel, <<"CTRY">>, _attrs, _els}) -> - Cdata = decode_vcard_CTRY_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_CTRY_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_CTRY_cdata(__TopXMLNS, Cdata); -decode_vcard_CTRY_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_CTRY_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_CTRY_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_CTRY_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_CTRY(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_CTRY_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"CTRY">>, _attrs, _els}. - -decode_vcard_CTRY_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_CTRY_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_CTRY_cdata(<<>>, _acc) -> _acc; -encode_vcard_CTRY_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_PCODE(__TopXMLNS, __IgnoreEls, - {xmlel, <<"PCODE">>, _attrs, _els}) -> - Cdata = decode_vcard_PCODE_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_PCODE_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_PCODE_cdata(__TopXMLNS, Cdata); -decode_vcard_PCODE_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_PCODE_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_PCODE_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_PCODE_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_PCODE(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_PCODE_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"PCODE">>, _attrs, _els}. - -decode_vcard_PCODE_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_PCODE_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_PCODE_cdata(<<>>, _acc) -> _acc; -encode_vcard_PCODE_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_REGION(__TopXMLNS, __IgnoreEls, - {xmlel, <<"REGION">>, _attrs, _els}) -> - Cdata = decode_vcard_REGION_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_REGION_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_REGION_cdata(__TopXMLNS, Cdata); -decode_vcard_REGION_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_REGION_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_REGION_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_REGION_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_REGION(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_REGION_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"REGION">>, _attrs, _els}. - -decode_vcard_REGION_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_REGION_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_REGION_cdata(<<>>, _acc) -> _acc; -encode_vcard_REGION_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_LOCALITY(__TopXMLNS, __IgnoreEls, - {xmlel, <<"LOCALITY">>, _attrs, _els}) -> - Cdata = decode_vcard_LOCALITY_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_vcard_LOCALITY_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_LOCALITY_cdata(__TopXMLNS, Cdata); -decode_vcard_LOCALITY_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_LOCALITY_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_LOCALITY_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_LOCALITY_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_LOCALITY(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_LOCALITY_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"LOCALITY">>, _attrs, _els}. - -decode_vcard_LOCALITY_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_LOCALITY_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_LOCALITY_cdata(<<>>, _acc) -> _acc; -encode_vcard_LOCALITY_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_STREET(__TopXMLNS, __IgnoreEls, - {xmlel, <<"STREET">>, _attrs, _els}) -> - Cdata = decode_vcard_STREET_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_STREET_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_STREET_cdata(__TopXMLNS, Cdata); -decode_vcard_STREET_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_STREET_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_STREET_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_STREET_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_STREET(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_STREET_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"STREET">>, _attrs, _els}. - -decode_vcard_STREET_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_STREET_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_STREET_cdata(<<>>, _acc) -> _acc; -encode_vcard_STREET_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_EXTADD(__TopXMLNS, __IgnoreEls, - {xmlel, <<"EXTADD">>, _attrs, _els}) -> - Cdata = decode_vcard_EXTADD_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_EXTADD_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_EXTADD_cdata(__TopXMLNS, Cdata); -decode_vcard_EXTADD_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_EXTADD_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_EXTADD_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_EXTADD_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_EXTADD(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_EXTADD_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"EXTADD">>, _attrs, _els}. - -decode_vcard_EXTADD_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_EXTADD_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_EXTADD_cdata(<<>>, _acc) -> _acc; -encode_vcard_EXTADD_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_POBOX(__TopXMLNS, __IgnoreEls, - {xmlel, <<"POBOX">>, _attrs, _els}) -> - Cdata = decode_vcard_POBOX_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_POBOX_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_POBOX_cdata(__TopXMLNS, Cdata); -decode_vcard_POBOX_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_POBOX_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_POBOX_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_POBOX_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_POBOX(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_POBOX_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"POBOX">>, _attrs, _els}. - -decode_vcard_POBOX_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_POBOX_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_POBOX_cdata(<<>>, _acc) -> _acc; -encode_vcard_POBOX_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_SUFFIX(__TopXMLNS, __IgnoreEls, - {xmlel, <<"SUFFIX">>, _attrs, _els}) -> - Cdata = decode_vcard_SUFFIX_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_SUFFIX_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_SUFFIX_cdata(__TopXMLNS, Cdata); -decode_vcard_SUFFIX_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_SUFFIX_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_SUFFIX_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_SUFFIX_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_SUFFIX(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_SUFFIX_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"SUFFIX">>, _attrs, _els}. - -decode_vcard_SUFFIX_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_SUFFIX_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_SUFFIX_cdata(<<>>, _acc) -> _acc; -encode_vcard_SUFFIX_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_PREFIX(__TopXMLNS, __IgnoreEls, - {xmlel, <<"PREFIX">>, _attrs, _els}) -> - Cdata = decode_vcard_PREFIX_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_PREFIX_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_PREFIX_cdata(__TopXMLNS, Cdata); -decode_vcard_PREFIX_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_PREFIX_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_PREFIX_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_PREFIX_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_PREFIX(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_PREFIX_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"PREFIX">>, _attrs, _els}. - -decode_vcard_PREFIX_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_PREFIX_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_PREFIX_cdata(<<>>, _acc) -> _acc; -encode_vcard_PREFIX_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_MIDDLE(__TopXMLNS, __IgnoreEls, - {xmlel, <<"MIDDLE">>, _attrs, _els}) -> - Cdata = decode_vcard_MIDDLE_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_MIDDLE_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_MIDDLE_cdata(__TopXMLNS, Cdata); -decode_vcard_MIDDLE_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_MIDDLE_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_MIDDLE_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_MIDDLE_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_MIDDLE(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_MIDDLE_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"MIDDLE">>, _attrs, _els}. - -decode_vcard_MIDDLE_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_MIDDLE_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_MIDDLE_cdata(<<>>, _acc) -> _acc; -encode_vcard_MIDDLE_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_GIVEN(__TopXMLNS, __IgnoreEls, - {xmlel, <<"GIVEN">>, _attrs, _els}) -> - Cdata = decode_vcard_GIVEN_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_GIVEN_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_GIVEN_cdata(__TopXMLNS, Cdata); -decode_vcard_GIVEN_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_GIVEN_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_GIVEN_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_GIVEN_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_GIVEN(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_GIVEN_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"GIVEN">>, _attrs, _els}. - -decode_vcard_GIVEN_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_GIVEN_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_GIVEN_cdata(<<>>, _acc) -> _acc; -encode_vcard_GIVEN_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_FAMILY(__TopXMLNS, __IgnoreEls, - {xmlel, <<"FAMILY">>, _attrs, _els}) -> - Cdata = decode_vcard_FAMILY_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_vcard_FAMILY_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_vcard_FAMILY_cdata(__TopXMLNS, Cdata); -decode_vcard_FAMILY_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_vcard_FAMILY_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_vcard_FAMILY_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_vcard_FAMILY_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_vcard_FAMILY(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = encode_vcard_FAMILY_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"FAMILY">>, _attrs, _els}. - -decode_vcard_FAMILY_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_vcard_FAMILY_cdata(__TopXMLNS, _val) -> _val. - -encode_vcard_FAMILY_cdata(<<>>, _acc) -> _acc; -encode_vcard_FAMILY_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_vcard_X400(__TopXMLNS, __IgnoreEls, - {xmlel, <<"X400">>, _attrs, _els}) -> - true. - -encode_vcard_X400(true, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"X400">>, _attrs, _els}. - -decode_vcard_INTERNET(__TopXMLNS, __IgnoreEls, - {xmlel, <<"INTERNET">>, _attrs, _els}) -> - true. - -encode_vcard_INTERNET(true, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"INTERNET">>, _attrs, _els}. - -decode_vcard_PREF(__TopXMLNS, __IgnoreEls, - {xmlel, <<"PREF">>, _attrs, _els}) -> - true. - -encode_vcard_PREF(true, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"PREF">>, _attrs, _els}. - -decode_vcard_INTL(__TopXMLNS, __IgnoreEls, - {xmlel, <<"INTL">>, _attrs, _els}) -> - true. - -encode_vcard_INTL(true, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"INTL">>, _attrs, _els}. - -decode_vcard_DOM(__TopXMLNS, __IgnoreEls, - {xmlel, <<"DOM">>, _attrs, _els}) -> - true. - -encode_vcard_DOM(true, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"DOM">>, _attrs, _els}. - -decode_vcard_PARCEL(__TopXMLNS, __IgnoreEls, - {xmlel, <<"PARCEL">>, _attrs, _els}) -> - true. - -encode_vcard_PARCEL(true, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"PARCEL">>, _attrs, _els}. - -decode_vcard_POSTAL(__TopXMLNS, __IgnoreEls, - {xmlel, <<"POSTAL">>, _attrs, _els}) -> - true. - -encode_vcard_POSTAL(true, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"POSTAL">>, _attrs, _els}. - -decode_vcard_PCS(__TopXMLNS, __IgnoreEls, - {xmlel, <<"PCS">>, _attrs, _els}) -> - true. - -encode_vcard_PCS(true, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"PCS">>, _attrs, _els}. - -decode_vcard_ISDN(__TopXMLNS, __IgnoreEls, - {xmlel, <<"ISDN">>, _attrs, _els}) -> - true. - -encode_vcard_ISDN(true, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"ISDN">>, _attrs, _els}. - -decode_vcard_MODEM(__TopXMLNS, __IgnoreEls, - {xmlel, <<"MODEM">>, _attrs, _els}) -> - true. - -encode_vcard_MODEM(true, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"MODEM">>, _attrs, _els}. - -decode_vcard_BBS(__TopXMLNS, __IgnoreEls, - {xmlel, <<"BBS">>, _attrs, _els}) -> - true. - -encode_vcard_BBS(true, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"BBS">>, _attrs, _els}. - -decode_vcard_VIDEO(__TopXMLNS, __IgnoreEls, - {xmlel, <<"VIDEO">>, _attrs, _els}) -> - true. - -encode_vcard_VIDEO(true, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"VIDEO">>, _attrs, _els}. - -decode_vcard_CELL(__TopXMLNS, __IgnoreEls, - {xmlel, <<"CELL">>, _attrs, _els}) -> - true. - -encode_vcard_CELL(true, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"CELL">>, _attrs, _els}. - -decode_vcard_MSG(__TopXMLNS, __IgnoreEls, - {xmlel, <<"MSG">>, _attrs, _els}) -> - true. - -encode_vcard_MSG(true, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"MSG">>, _attrs, _els}. - -decode_vcard_PAGER(__TopXMLNS, __IgnoreEls, - {xmlel, <<"PAGER">>, _attrs, _els}) -> - true. - -encode_vcard_PAGER(true, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"PAGER">>, _attrs, _els}. - -decode_vcard_FAX(__TopXMLNS, __IgnoreEls, - {xmlel, <<"FAX">>, _attrs, _els}) -> - true. - -encode_vcard_FAX(true, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"FAX">>, _attrs, _els}. - -decode_vcard_VOICE(__TopXMLNS, __IgnoreEls, - {xmlel, <<"VOICE">>, _attrs, _els}) -> - true. - -encode_vcard_VOICE(true, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"VOICE">>, _attrs, _els}. - -decode_vcard_WORK(__TopXMLNS, __IgnoreEls, - {xmlel, <<"WORK">>, _attrs, _els}) -> - true. - -encode_vcard_WORK(true, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"WORK">>, _attrs, _els}. - -decode_vcard_HOME(__TopXMLNS, __IgnoreEls, - {xmlel, <<"HOME">>, _attrs, _els}) -> - true. - -encode_vcard_HOME(true, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"vcard-temp">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"HOME">>, _attrs, _els}. - -decode_stream_error(__TopXMLNS, __IgnoreEls, - {xmlel, <<"stream:error">>, _attrs, _els}) -> - {Text, Reason} = decode_stream_error_els(__TopXMLNS, - __IgnoreEls, _els, undefined, - undefined), - {stream_error, Reason, Text}. - -decode_stream_error_els(__TopXMLNS, __IgnoreEls, [], - Text, Reason) -> - {Text, Reason}; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"text">>, _attrs, _} = _el | _els], Text, - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - decode_stream_error_text(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, _el), - Reason); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"bad-format">>, _attrs, _} = _el | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_bad_format(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, - _el)); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"bad-namespace-prefix">>, _attrs, _} = _el - | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_bad_namespace_prefix(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, - _el)); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"conflict">>, _attrs, _} = _el | _els], Text, - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_conflict(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, - _el)); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"connection-timeout">>, _attrs, _} = _el - | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_connection_timeout(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, - _el)); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"host-gone">>, _attrs, _} = _el | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_host_gone(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, - _el)); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"host-unknown">>, _attrs, _} = _el | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_host_unknown(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, - _el)); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"improper-addressing">>, _attrs, _} = _el - | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_improper_addressing(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, - _el)); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"internal-server-error">>, _attrs, _} = _el - | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_internal_server_error(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, - _el)); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"invalid-from">>, _attrs, _} = _el | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_invalid_from(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, - _el)); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"invalid-id">>, _attrs, _} = _el | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_invalid_id(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, - _el)); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"invalid-namespace">>, _attrs, _} = _el - | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_invalid_namespace(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, - _el)); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"invalid-xml">>, _attrs, _} = _el | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_invalid_xml(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, - _el)); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"not-authorized">>, _attrs, _} = _el | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_not_authorized(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, - _el)); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"not-well-formed">>, _attrs, _} = _el - | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_not_well_formed(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, - _el)); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"policy-violation">>, _attrs, _} = _el - | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_policy_violation(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, - _el)); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"remote-connection-failed">>, _attrs, _} = - _el - | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_remote_connection_failed(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, - _el)); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"reset">>, _attrs, _} = _el | _els], Text, - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_reset(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, _el)); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"resource-constraint">>, _attrs, _} = _el - | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_resource_constraint(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, - _el)); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"restricted-xml">>, _attrs, _} = _el | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_restricted_xml(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, - _el)); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"see-other-host">>, _attrs, _} = _el | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_see_other_host(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, - _el)); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"system-shutdown">>, _attrs, _} = _el - | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_system_shutdown(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, - _el)); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"undefined-condition">>, _attrs, _} = _el - | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_undefined_condition(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, - _el)); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"unsupported-encoding">>, _attrs, _} = _el - | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_unsupported_encoding(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, - _el)); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"unsupported-stanza-type">>, _attrs, _} = _el - | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_unsupported_stanza_type(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, - _el)); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"unsupported-version">>, _attrs, _} = _el - | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-streams">> -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_stream_error_unsupported_version(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - __IgnoreEls, - _el)); - _ -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_stream_error_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Text, Reason) -> - decode_stream_error_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason). - -encode_stream_error({stream_error, Reason, Text}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"jabber:client">>, <<"jabber:server">>, - <<"jabber:component:accept">>], - __TopXMLNS), - _els = lists:reverse('encode_stream_error_$text'(Text, - __NewTopXMLNS, - 'encode_stream_error_$reason'(Reason, - __NewTopXMLNS, - []))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"stream:error">>, _attrs, _els}. - -'encode_stream_error_$text'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_stream_error_$text'(Text, __TopXMLNS, _acc) -> - [encode_stream_error_text(Text, __TopXMLNS) | _acc]. - -'encode_stream_error_$reason'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_stream_error_$reason'('bad-format' = Reason, - __TopXMLNS, _acc) -> - [encode_stream_error_bad_format(Reason, __TopXMLNS) - | _acc]; -'encode_stream_error_$reason'('bad-namespace-prefix' = - Reason, - __TopXMLNS, _acc) -> - [encode_stream_error_bad_namespace_prefix(Reason, - __TopXMLNS) - | _acc]; -'encode_stream_error_$reason'(conflict = Reason, - __TopXMLNS, _acc) -> - [encode_stream_error_conflict(Reason, __TopXMLNS) - | _acc]; -'encode_stream_error_$reason'('connection-timeout' = - Reason, - __TopXMLNS, _acc) -> - [encode_stream_error_connection_timeout(Reason, - __TopXMLNS) - | _acc]; -'encode_stream_error_$reason'('host-gone' = Reason, - __TopXMLNS, _acc) -> - [encode_stream_error_host_gone(Reason, __TopXMLNS) - | _acc]; -'encode_stream_error_$reason'('host-unknown' = Reason, - __TopXMLNS, _acc) -> - [encode_stream_error_host_unknown(Reason, __TopXMLNS) - | _acc]; -'encode_stream_error_$reason'('improper-addressing' = - Reason, - __TopXMLNS, _acc) -> - [encode_stream_error_improper_addressing(Reason, - __TopXMLNS) - | _acc]; -'encode_stream_error_$reason'('internal-server-error' = - Reason, - __TopXMLNS, _acc) -> - [encode_stream_error_internal_server_error(Reason, - __TopXMLNS) - | _acc]; -'encode_stream_error_$reason'('invalid-from' = Reason, - __TopXMLNS, _acc) -> - [encode_stream_error_invalid_from(Reason, __TopXMLNS) - | _acc]; -'encode_stream_error_$reason'('invalid-id' = Reason, - __TopXMLNS, _acc) -> - [encode_stream_error_invalid_id(Reason, __TopXMLNS) - | _acc]; -'encode_stream_error_$reason'('invalid-namespace' = - Reason, - __TopXMLNS, _acc) -> - [encode_stream_error_invalid_namespace(Reason, - __TopXMLNS) - | _acc]; -'encode_stream_error_$reason'('invalid-xml' = Reason, - __TopXMLNS, _acc) -> - [encode_stream_error_invalid_xml(Reason, __TopXMLNS) - | _acc]; -'encode_stream_error_$reason'('not-authorized' = Reason, - __TopXMLNS, _acc) -> - [encode_stream_error_not_authorized(Reason, __TopXMLNS) - | _acc]; -'encode_stream_error_$reason'('not-well-formed' = - Reason, - __TopXMLNS, _acc) -> - [encode_stream_error_not_well_formed(Reason, __TopXMLNS) - | _acc]; -'encode_stream_error_$reason'('policy-violation' = - Reason, - __TopXMLNS, _acc) -> - [encode_stream_error_policy_violation(Reason, - __TopXMLNS) - | _acc]; -'encode_stream_error_$reason'('remote-connection-failed' = - Reason, - __TopXMLNS, _acc) -> - [encode_stream_error_remote_connection_failed(Reason, - __TopXMLNS) - | _acc]; -'encode_stream_error_$reason'(reset = Reason, - __TopXMLNS, _acc) -> - [encode_stream_error_reset(Reason, __TopXMLNS) | _acc]; -'encode_stream_error_$reason'('resource-constraint' = - Reason, - __TopXMLNS, _acc) -> - [encode_stream_error_resource_constraint(Reason, - __TopXMLNS) - | _acc]; -'encode_stream_error_$reason'('restricted-xml' = Reason, - __TopXMLNS, _acc) -> - [encode_stream_error_restricted_xml(Reason, __TopXMLNS) - | _acc]; -'encode_stream_error_$reason'({'see-other-host', _} = - Reason, - __TopXMLNS, _acc) -> - [encode_stream_error_see_other_host(Reason, __TopXMLNS) - | _acc]; -'encode_stream_error_$reason'('system-shutdown' = - Reason, - __TopXMLNS, _acc) -> - [encode_stream_error_system_shutdown(Reason, __TopXMLNS) - | _acc]; -'encode_stream_error_$reason'('undefined-condition' = - Reason, - __TopXMLNS, _acc) -> - [encode_stream_error_undefined_condition(Reason, - __TopXMLNS) - | _acc]; -'encode_stream_error_$reason'('unsupported-encoding' = - Reason, - __TopXMLNS, _acc) -> - [encode_stream_error_unsupported_encoding(Reason, - __TopXMLNS) - | _acc]; -'encode_stream_error_$reason'('unsupported-stanza-type' = - Reason, - __TopXMLNS, _acc) -> - [encode_stream_error_unsupported_stanza_type(Reason, - __TopXMLNS) - | _acc]; -'encode_stream_error_$reason'('unsupported-version' = - Reason, - __TopXMLNS, _acc) -> - [encode_stream_error_unsupported_version(Reason, - __TopXMLNS) - | _acc]. - -decode_stream_error_unsupported_version(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"unsupported-version">>, - _attrs, _els}) -> - 'unsupported-version'. - -encode_stream_error_unsupported_version('unsupported-version', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"unsupported-version">>, _attrs, _els}. - -decode_stream_error_unsupported_stanza_type(__TopXMLNS, - __IgnoreEls, - {xmlel, - <<"unsupported-stanza-type">>, - _attrs, _els}) -> - 'unsupported-stanza-type'. - -encode_stream_error_unsupported_stanza_type('unsupported-stanza-type', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"unsupported-stanza-type">>, _attrs, _els}. - -decode_stream_error_unsupported_encoding(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"unsupported-encoding">>, - _attrs, _els}) -> - 'unsupported-encoding'. - -encode_stream_error_unsupported_encoding('unsupported-encoding', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"unsupported-encoding">>, _attrs, _els}. - -decode_stream_error_undefined_condition(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"undefined-condition">>, - _attrs, _els}) -> - 'undefined-condition'. - -encode_stream_error_undefined_condition('undefined-condition', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"undefined-condition">>, _attrs, _els}. - -decode_stream_error_system_shutdown(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"system-shutdown">>, _attrs, - _els}) -> - 'system-shutdown'. - -encode_stream_error_system_shutdown('system-shutdown', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"system-shutdown">>, _attrs, _els}. - -decode_stream_error_see_other_host(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"see-other-host">>, _attrs, - _els}) -> - Host = - decode_stream_error_see_other_host_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - {'see-other-host', Host}. - -decode_stream_error_see_other_host_els(__TopXMLNS, - __IgnoreEls, [], Host) -> - decode_stream_error_see_other_host_cdata(__TopXMLNS, - Host); -decode_stream_error_see_other_host_els(__TopXMLNS, - __IgnoreEls, [{xmlcdata, _data} | _els], - Host) -> - decode_stream_error_see_other_host_els(__TopXMLNS, - __IgnoreEls, _els, - <>); -decode_stream_error_see_other_host_els(__TopXMLNS, - __IgnoreEls, [_ | _els], Host) -> - decode_stream_error_see_other_host_els(__TopXMLNS, - __IgnoreEls, _els, Host). - -encode_stream_error_see_other_host({'see-other-host', - Host}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = encode_stream_error_see_other_host_cdata(Host, - []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"see-other-host">>, _attrs, _els}. - -decode_stream_error_see_other_host_cdata(__TopXMLNS, - <<>>) -> - erlang:error({xmpp_codec, - {missing_cdata, <<>>, <<"see-other-host">>, - __TopXMLNS}}); -decode_stream_error_see_other_host_cdata(__TopXMLNS, - _val) -> - case catch dec_host_port(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_cdata_value, <<>>, <<"see-other-host">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_stream_error_see_other_host_cdata(_val, _acc) -> - [{xmlcdata, enc_host_port(_val)} | _acc]. - -decode_stream_error_restricted_xml(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"restricted-xml">>, _attrs, - _els}) -> - 'restricted-xml'. - -encode_stream_error_restricted_xml('restricted-xml', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"restricted-xml">>, _attrs, _els}. - -decode_stream_error_resource_constraint(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"resource-constraint">>, - _attrs, _els}) -> - 'resource-constraint'. - -encode_stream_error_resource_constraint('resource-constraint', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"resource-constraint">>, _attrs, _els}. - -decode_stream_error_reset(__TopXMLNS, __IgnoreEls, - {xmlel, <<"reset">>, _attrs, _els}) -> - reset. - -encode_stream_error_reset(reset, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"reset">>, _attrs, _els}. - -decode_stream_error_remote_connection_failed(__TopXMLNS, - __IgnoreEls, - {xmlel, - <<"remote-connection-failed">>, - _attrs, _els}) -> - 'remote-connection-failed'. - -encode_stream_error_remote_connection_failed('remote-connection-failed', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"remote-connection-failed">>, _attrs, _els}. - -decode_stream_error_policy_violation(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"policy-violation">>, _attrs, - _els}) -> - 'policy-violation'. - -encode_stream_error_policy_violation('policy-violation', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"policy-violation">>, _attrs, _els}. - -decode_stream_error_not_well_formed(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"not-well-formed">>, _attrs, - _els}) -> - 'not-well-formed'. - -encode_stream_error_not_well_formed('not-well-formed', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"not-well-formed">>, _attrs, _els}. - -decode_stream_error_not_authorized(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"not-authorized">>, _attrs, - _els}) -> - 'not-authorized'. - -encode_stream_error_not_authorized('not-authorized', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"not-authorized">>, _attrs, _els}. - -decode_stream_error_invalid_xml(__TopXMLNS, __IgnoreEls, - {xmlel, <<"invalid-xml">>, _attrs, _els}) -> - 'invalid-xml'. - -encode_stream_error_invalid_xml('invalid-xml', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"invalid-xml">>, _attrs, _els}. - -decode_stream_error_invalid_namespace(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"invalid-namespace">>, _attrs, - _els}) -> - 'invalid-namespace'. - -encode_stream_error_invalid_namespace('invalid-namespace', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"invalid-namespace">>, _attrs, _els}. - -decode_stream_error_invalid_id(__TopXMLNS, __IgnoreEls, - {xmlel, <<"invalid-id">>, _attrs, _els}) -> - 'invalid-id'. - -encode_stream_error_invalid_id('invalid-id', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"invalid-id">>, _attrs, _els}. - -decode_stream_error_invalid_from(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"invalid-from">>, _attrs, _els}) -> - 'invalid-from'. - -encode_stream_error_invalid_from('invalid-from', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"invalid-from">>, _attrs, _els}. - -decode_stream_error_internal_server_error(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"internal-server-error">>, - _attrs, _els}) -> - 'internal-server-error'. - -encode_stream_error_internal_server_error('internal-server-error', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"internal-server-error">>, _attrs, _els}. - -decode_stream_error_improper_addressing(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"improper-addressing">>, - _attrs, _els}) -> - 'improper-addressing'. - -encode_stream_error_improper_addressing('improper-addressing', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"improper-addressing">>, _attrs, _els}. - -decode_stream_error_host_unknown(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"host-unknown">>, _attrs, _els}) -> - 'host-unknown'. - -encode_stream_error_host_unknown('host-unknown', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"host-unknown">>, _attrs, _els}. - -decode_stream_error_host_gone(__TopXMLNS, __IgnoreEls, - {xmlel, <<"host-gone">>, _attrs, _els}) -> - 'host-gone'. - -encode_stream_error_host_gone('host-gone', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"host-gone">>, _attrs, _els}. - -decode_stream_error_connection_timeout(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"connection-timeout">>, _attrs, - _els}) -> - 'connection-timeout'. - -encode_stream_error_connection_timeout('connection-timeout', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"connection-timeout">>, _attrs, _els}. - -decode_stream_error_conflict(__TopXMLNS, __IgnoreEls, - {xmlel, <<"conflict">>, _attrs, _els}) -> - conflict. - -encode_stream_error_conflict(conflict, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"conflict">>, _attrs, _els}. - -decode_stream_error_bad_namespace_prefix(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"bad-namespace-prefix">>, - _attrs, _els}) -> - 'bad-namespace-prefix'. - -encode_stream_error_bad_namespace_prefix('bad-namespace-prefix', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"bad-namespace-prefix">>, _attrs, _els}. - -decode_stream_error_bad_format(__TopXMLNS, __IgnoreEls, - {xmlel, <<"bad-format">>, _attrs, _els}) -> - 'bad-format'. - -encode_stream_error_bad_format('bad-format', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"bad-format">>, _attrs, _els}. - -decode_stream_error_text(__TopXMLNS, __IgnoreEls, - {xmlel, <<"text">>, _attrs, _els}) -> - Data = decode_stream_error_text_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Lang = decode_stream_error_text_attrs(__TopXMLNS, - _attrs, undefined), - {text, Lang, Data}. - -decode_stream_error_text_els(__TopXMLNS, __IgnoreEls, - [], Data) -> - decode_stream_error_text_cdata(__TopXMLNS, Data); -decode_stream_error_text_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Data) -> - decode_stream_error_text_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_stream_error_text_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Data) -> - decode_stream_error_text_els(__TopXMLNS, __IgnoreEls, - _els, Data). - -decode_stream_error_text_attrs(__TopXMLNS, - [{<<"xml:lang">>, _val} | _attrs], _Lang) -> - decode_stream_error_text_attrs(__TopXMLNS, _attrs, - _val); -decode_stream_error_text_attrs(__TopXMLNS, [_ | _attrs], - Lang) -> - decode_stream_error_text_attrs(__TopXMLNS, _attrs, - Lang); -decode_stream_error_text_attrs(__TopXMLNS, [], Lang) -> - 'decode_stream_error_text_attr_xml:lang'(__TopXMLNS, - Lang). - -encode_stream_error_text({text, Lang, Data}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-streams">>, - [], __TopXMLNS), - _els = encode_stream_error_text_cdata(Data, []), - _attrs = 'encode_stream_error_text_attr_xml:lang'(Lang, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"text">>, _attrs, _els}. - -'decode_stream_error_text_attr_xml:lang'(__TopXMLNS, - undefined) -> - <<>>; -'decode_stream_error_text_attr_xml:lang'(__TopXMLNS, - _val) -> - _val. - -'encode_stream_error_text_attr_xml:lang'(<<>>, _acc) -> - _acc; -'encode_stream_error_text_attr_xml:lang'(_val, _acc) -> - [{<<"xml:lang">>, _val} | _acc]. - -decode_stream_error_text_cdata(__TopXMLNS, <<>>) -> - <<>>; -decode_stream_error_text_cdata(__TopXMLNS, _val) -> - _val. - -encode_stream_error_text_cdata(<<>>, _acc) -> _acc; -encode_stream_error_text_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_time(__TopXMLNS, __IgnoreEls, - {xmlel, <<"time">>, _attrs, _els}) -> - {Utc, Tzo} = decode_time_els(__TopXMLNS, __IgnoreEls, - _els, undefined, undefined), - {time, Tzo, Utc}. - -decode_time_els(__TopXMLNS, __IgnoreEls, [], Utc, - Tzo) -> - {Utc, Tzo}; -decode_time_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"tzo">>, _attrs, _} = _el | _els], Utc, - Tzo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"urn:xmpp:time">> -> - decode_time_els(__TopXMLNS, __IgnoreEls, _els, Utc, - decode_time_tzo(__TopXMLNS, __IgnoreEls, _el)); - <<"urn:xmpp:time">> -> - decode_time_els(__TopXMLNS, __IgnoreEls, _els, Utc, - decode_time_tzo(<<"urn:xmpp:time">>, __IgnoreEls, - _el)); - _ -> - decode_time_els(__TopXMLNS, __IgnoreEls, _els, Utc, Tzo) - end; -decode_time_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"utc">>, _attrs, _} = _el | _els], Utc, - Tzo) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"urn:xmpp:time">> -> - decode_time_els(__TopXMLNS, __IgnoreEls, _els, - decode_time_utc(__TopXMLNS, __IgnoreEls, _el), Tzo); - <<"urn:xmpp:time">> -> - decode_time_els(__TopXMLNS, __IgnoreEls, _els, - decode_time_utc(<<"urn:xmpp:time">>, __IgnoreEls, - _el), - Tzo); - _ -> - decode_time_els(__TopXMLNS, __IgnoreEls, _els, Utc, Tzo) - end; -decode_time_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Utc, Tzo) -> - decode_time_els(__TopXMLNS, __IgnoreEls, _els, Utc, - Tzo). - -encode_time({time, Tzo, Utc}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:time">>, - [], __TopXMLNS), - _els = lists:reverse('encode_time_$utc'(Utc, - __NewTopXMLNS, - 'encode_time_$tzo'(Tzo, - __NewTopXMLNS, - []))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"time">>, _attrs, _els}. - -'encode_time_$utc'(undefined, __TopXMLNS, _acc) -> _acc; -'encode_time_$utc'(Utc, __TopXMLNS, _acc) -> - [encode_time_utc(Utc, __TopXMLNS) | _acc]. - -'encode_time_$tzo'(undefined, __TopXMLNS, _acc) -> _acc; -'encode_time_$tzo'(Tzo, __TopXMLNS, _acc) -> - [encode_time_tzo(Tzo, __TopXMLNS) | _acc]. - -decode_time_tzo(__TopXMLNS, __IgnoreEls, - {xmlel, <<"tzo">>, _attrs, _els}) -> - Cdata = decode_time_tzo_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_time_tzo_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_time_tzo_cdata(__TopXMLNS, Cdata); -decode_time_tzo_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_time_tzo_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_time_tzo_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Cdata) -> - decode_time_tzo_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_time_tzo(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:time">>, - [], __TopXMLNS), - _els = encode_time_tzo_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"tzo">>, _attrs, _els}. - -decode_time_tzo_cdata(__TopXMLNS, <<>>) -> undefined; -decode_time_tzo_cdata(__TopXMLNS, _val) -> - case catch dec_tzo(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_cdata_value, <<>>, <<"tzo">>, __TopXMLNS}}); - _res -> _res - end. - -encode_time_tzo_cdata(undefined, _acc) -> _acc; -encode_time_tzo_cdata(_val, _acc) -> - [{xmlcdata, enc_tzo(_val)} | _acc]. - -decode_time_utc(__TopXMLNS, __IgnoreEls, - {xmlel, <<"utc">>, _attrs, _els}) -> - Cdata = decode_time_utc_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_time_utc_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_time_utc_cdata(__TopXMLNS, Cdata); -decode_time_utc_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_time_utc_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_time_utc_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Cdata) -> - decode_time_utc_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_time_utc(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:time">>, - [], __TopXMLNS), - _els = encode_time_utc_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"utc">>, _attrs, _els}. - -decode_time_utc_cdata(__TopXMLNS, <<>>) -> undefined; -decode_time_utc_cdata(__TopXMLNS, _val) -> - case catch dec_utc(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_cdata_value, <<>>, <<"utc">>, __TopXMLNS}}); - _res -> _res - end. - -encode_time_utc_cdata(undefined, _acc) -> _acc; -encode_time_utc_cdata(_val, _acc) -> - [{xmlcdata, enc_utc(_val)} | _acc]. - -decode_ping(__TopXMLNS, __IgnoreEls, - {xmlel, <<"ping">>, _attrs, _els}) -> - {ping}. - -encode_ping({ping}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"urn:xmpp:ping">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"ping">>, _attrs, _els}. - -decode_session(__TopXMLNS, __IgnoreEls, - {xmlel, <<"session">>, _attrs, _els}) -> - Optional = decode_session_els(__TopXMLNS, __IgnoreEls, - _els, false), - {xmpp_session, Optional}. - -decode_session_els(__TopXMLNS, __IgnoreEls, [], - Optional) -> - Optional; -decode_session_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"optional">>, _attrs, _} = _el | _els], - Optional) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"urn:ietf:params:xml:ns:xmpp-session">> -> - decode_session_els(__TopXMLNS, __IgnoreEls, _els, - decode_session_optional(__TopXMLNS, __IgnoreEls, - _el)); - <<"urn:ietf:params:xml:ns:xmpp-session">> -> - decode_session_els(__TopXMLNS, __IgnoreEls, _els, - decode_session_optional(<<"urn:ietf:params:xml:ns:xmpp-session">>, - __IgnoreEls, _el)); - _ -> - decode_session_els(__TopXMLNS, __IgnoreEls, _els, - Optional) - end; -decode_session_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Optional) -> - decode_session_els(__TopXMLNS, __IgnoreEls, _els, - Optional). - -encode_session({xmpp_session, Optional}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-session">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_session_$optional'(Optional, - __NewTopXMLNS, [])), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"session">>, _attrs, _els}. - -'encode_session_$optional'(false, __TopXMLNS, _acc) -> - _acc; -'encode_session_$optional'(Optional, __TopXMLNS, - _acc) -> - [encode_session_optional(Optional, __TopXMLNS) | _acc]. - -decode_session_optional(__TopXMLNS, __IgnoreEls, - {xmlel, <<"optional">>, _attrs, _els}) -> - true. - -encode_session_optional(true, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-session">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"optional">>, _attrs, _els}. - -decode_register(__TopXMLNS, __IgnoreEls, - {xmlel, <<"query">>, _attrs, _els}) -> - {Zip, Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, __Els} = - decode_register_els(__TopXMLNS, __IgnoreEls, _els, - undefined, undefined, undefined, undefined, - undefined, undefined, undefined, undefined, - undefined, false, undefined, undefined, undefined, - undefined, undefined, false, undefined, undefined, - undefined, undefined, undefined, []), - {register, Registered, Remove, Instructions, Username, - Nick, Password, Name, First, Last, Email, Address, City, - State, Zip, Phone, Url, Date, Misc, Text, Key, Xdata, - __Els}. - -decode_register_els(__TopXMLNS, __IgnoreEls, [], Zip, - Xdata, Misc, Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, __Els) -> - {Zip, Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, - lists:reverse(__Els)}; -decode_register_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"x">>, _attrs, _} = _el | _els], Zip, Xdata, - Misc, Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"jabber:x:data">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - decode_xdata(<<"jabber:x:data">>, __IgnoreEls, - _el), - Misc, Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, - __Els); - _ -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els) - end; -decode_register_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"registered">>, _attrs, _} = _el | _els], - Zip, Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, - decode_register_registered(__TopXMLNS, - __IgnoreEls, _el), - Date, Phone, State, Name, Username, Remove, Key, - City, Nick, Url, Email, __Els); - <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, - decode_register_registered(<<"jabber:iq:register">>, - __IgnoreEls, _el), - Date, Phone, State, Name, Username, Remove, Key, - City, Nick, Url, Email, __Els); - _ -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els) - end; -decode_register_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"remove">>, _attrs, _} = _el | _els], Zip, - Xdata, Misc, Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, - decode_register_remove(__TopXMLNS, __IgnoreEls, - _el), - Key, City, Nick, Url, Email, __Els); - <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, - decode_register_remove(<<"jabber:iq:register">>, - __IgnoreEls, _el), - Key, City, Nick, Url, Email, __Els); - _ -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els) - end; -decode_register_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"instructions">>, _attrs, _} = _el | _els], - Zip, Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, - decode_register_instructions(__TopXMLNS, - __IgnoreEls, _el), - Text, Last, First, Password, Registered, Date, - Phone, State, Name, Username, Remove, Key, City, - Nick, Url, Email, __Els); - <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, - decode_register_instructions(<<"jabber:iq:register">>, - __IgnoreEls, _el), - Text, Last, First, Password, Registered, Date, - Phone, State, Name, Username, Remove, Key, City, - Nick, Url, Email, __Els); - _ -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els) - end; -decode_register_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"username">>, _attrs, _} = _el | _els], Zip, - Xdata, Misc, Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, - decode_register_username(__TopXMLNS, __IgnoreEls, - _el), - Remove, Key, City, Nick, Url, Email, __Els); - <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, - decode_register_username(<<"jabber:iq:register">>, - __IgnoreEls, _el), - Remove, Key, City, Nick, Url, Email, __Els); - _ -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els) - end; -decode_register_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"nick">>, _attrs, _} = _el | _els], Zip, - Xdata, Misc, Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, - decode_register_nick(__TopXMLNS, __IgnoreEls, - _el), - Url, Email, __Els); - <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, - decode_register_nick(<<"jabber:iq:register">>, - __IgnoreEls, _el), - Url, Email, __Els); - _ -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els) - end; -decode_register_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"password">>, _attrs, _} = _el | _els], Zip, - Xdata, Misc, Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, - decode_register_password(__TopXMLNS, __IgnoreEls, - _el), - Registered, Date, Phone, State, Name, Username, - Remove, Key, City, Nick, Url, Email, __Els); - <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, - decode_register_password(<<"jabber:iq:register">>, - __IgnoreEls, _el), - Registered, Date, Phone, State, Name, Username, - Remove, Key, City, Nick, Url, Email, __Els); - _ -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els) - end; -decode_register_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"name">>, _attrs, _} = _el | _els], Zip, - Xdata, Misc, Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - decode_register_name(__TopXMLNS, __IgnoreEls, - _el), - Username, Remove, Key, City, Nick, Url, Email, - __Els); - <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - decode_register_name(<<"jabber:iq:register">>, - __IgnoreEls, _el), - Username, Remove, Key, City, Nick, Url, Email, - __Els); - _ -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els) - end; -decode_register_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"first">>, _attrs, _} = _el | _els], Zip, - Xdata, Misc, Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - decode_register_first(__TopXMLNS, __IgnoreEls, - _el), - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, - __Els); - <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - decode_register_first(<<"jabber:iq:register">>, - __IgnoreEls, _el), - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, - __Els); - _ -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els) - end; -decode_register_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"last">>, _attrs, _} = _el | _els], Zip, - Xdata, Misc, Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, - decode_register_last(__TopXMLNS, __IgnoreEls, - _el), - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els); - <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, - decode_register_last(<<"jabber:iq:register">>, - __IgnoreEls, _el), - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els); - _ -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els) - end; -decode_register_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"email">>, _attrs, _} = _el | _els], Zip, - Xdata, Misc, Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - decode_register_email(__TopXMLNS, __IgnoreEls, - _el), - __Els); - <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - decode_register_email(<<"jabber:iq:register">>, - __IgnoreEls, _el), - __Els); - _ -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els) - end; -decode_register_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"address">>, _attrs, _} = _el | _els], Zip, - Xdata, Misc, Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, - decode_register_address(__TopXMLNS, __IgnoreEls, - _el), - Instructions, Text, Last, First, Password, - Registered, Date, Phone, State, Name, Username, - Remove, Key, City, Nick, Url, Email, __Els); - <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, - decode_register_address(<<"jabber:iq:register">>, - __IgnoreEls, _el), - Instructions, Text, Last, First, Password, - Registered, Date, Phone, State, Name, Username, - Remove, Key, City, Nick, Url, Email, __Els); - _ -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els) - end; -decode_register_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"city">>, _attrs, _} = _el | _els], Zip, - Xdata, Misc, Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, - decode_register_city(__TopXMLNS, __IgnoreEls, - _el), - Nick, Url, Email, __Els); - <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, - decode_register_city(<<"jabber:iq:register">>, - __IgnoreEls, _el), - Nick, Url, Email, __Els); - _ -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els) - end; -decode_register_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"state">>, _attrs, _} = _el | _els], Zip, - Xdata, Misc, Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, - decode_register_state(__TopXMLNS, __IgnoreEls, - _el), - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els); - <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, - decode_register_state(<<"jabber:iq:register">>, - __IgnoreEls, _el), - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els); - _ -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els) - end; -decode_register_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"zip">>, _attrs, _} = _el | _els], Zip, - Xdata, Misc, Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, - decode_register_zip(__TopXMLNS, __IgnoreEls, _el), - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els); - <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, - decode_register_zip(<<"jabber:iq:register">>, - __IgnoreEls, _el), - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els); - _ -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els) - end; -decode_register_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"phone">>, _attrs, _} = _el | _els], Zip, - Xdata, Misc, Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, - decode_register_phone(__TopXMLNS, __IgnoreEls, - _el), - State, Name, Username, Remove, Key, City, Nick, - Url, Email, __Els); - <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, - decode_register_phone(<<"jabber:iq:register">>, - __IgnoreEls, _el), - State, Name, Username, Remove, Key, City, Nick, - Url, Email, __Els); - _ -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els) - end; -decode_register_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"url">>, _attrs, _} = _el | _els], Zip, - Xdata, Misc, Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, - decode_register_url(__TopXMLNS, __IgnoreEls, _el), - Email, __Els); - <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, - decode_register_url(<<"jabber:iq:register">>, - __IgnoreEls, _el), - Email, __Els); - _ -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els) - end; -decode_register_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"date">>, _attrs, _} = _el | _els], Zip, - Xdata, Misc, Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, - decode_register_date(__TopXMLNS, __IgnoreEls, - _el), - Phone, State, Name, Username, Remove, Key, City, - Nick, Url, Email, __Els); - <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, - decode_register_date(<<"jabber:iq:register">>, - __IgnoreEls, _el), - Phone, State, Name, Username, Remove, Key, City, - Nick, Url, Email, __Els); - _ -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els) - end; -decode_register_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"misc">>, _attrs, _} = _el | _els], Zip, - Xdata, Misc, Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, - decode_register_misc(__TopXMLNS, __IgnoreEls, - _el), - Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, - __Els); - <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, - decode_register_misc(<<"jabber:iq:register">>, - __IgnoreEls, _el), - Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, - __Els); - _ -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els) - end; -decode_register_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"text">>, _attrs, _} = _el | _els], Zip, - Xdata, Misc, Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, - decode_register_text(__TopXMLNS, __IgnoreEls, - _el), - Last, First, Password, Registered, Date, Phone, - State, Name, Username, Remove, Key, City, Nick, - Url, Email, __Els); - <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, - decode_register_text(<<"jabber:iq:register">>, - __IgnoreEls, _el), - Last, First, Password, Registered, Date, Phone, - State, Name, Username, Remove, Key, City, Nick, - Url, Email, __Els); - _ -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els) - end; -decode_register_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"key">>, _attrs, _} = _el | _els], Zip, - Xdata, Misc, Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, - decode_register_key(__TopXMLNS, __IgnoreEls, _el), - City, Nick, Url, Email, __Els); - <<"jabber:iq:register">> -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, - decode_register_key(<<"jabber:iq:register">>, - __IgnoreEls, _el), - City, Nick, Url, Email, __Els); - _ -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, __Els) - end; -decode_register_els(__TopXMLNS, __IgnoreEls, - [{xmlel, _, _, _} = _el | _els], Zip, Xdata, Misc, - Address, Instructions, Text, Last, First, Password, - Registered, Date, Phone, State, Name, Username, Remove, - Key, City, Nick, Url, Email, __Els) -> - if __IgnoreEls -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, - Name, Username, Remove, Key, City, Nick, Url, - Email, [_el | __Els]); - true -> - case is_known_tag(_el, __TopXMLNS) of - true -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, - Last, First, Password, Registered, Date, - Phone, State, Name, Username, Remove, Key, - City, Nick, Url, Email, - [decode(_el, __TopXMLNS, []) | __Els]); - false -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, - Last, First, Password, Registered, Date, - Phone, State, Name, Username, Remove, Key, - City, Nick, Url, Email, __Els) - end - end; -decode_register_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Zip, Xdata, Misc, Address, Instructions, Text, Last, - First, Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, __Els) -> - decode_register_els(__TopXMLNS, __IgnoreEls, _els, Zip, - Xdata, Misc, Address, Instructions, Text, Last, First, - Password, Registered, Date, Phone, State, Name, - Username, Remove, Key, City, Nick, Url, Email, __Els). - -encode_register({register, Registered, Remove, - Instructions, Username, Nick, Password, Name, First, - Last, Email, Address, City, State, Zip, Phone, Url, - Date, Misc, Text, Key, Xdata, __Els}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:register">>, [], - __TopXMLNS), - _els = [encode(_el, __NewTopXMLNS) || _el <- __Els] ++ - lists:reverse('encode_register_$zip'(Zip, __NewTopXMLNS, - 'encode_register_$xdata'(Xdata, - __NewTopXMLNS, - 'encode_register_$misc'(Misc, - __NewTopXMLNS, - 'encode_register_$address'(Address, - __NewTopXMLNS, - 'encode_register_$instructions'(Instructions, - __NewTopXMLNS, - 'encode_register_$text'(Text, - __NewTopXMLNS, - 'encode_register_$last'(Last, - __NewTopXMLNS, - 'encode_register_$first'(First, - __NewTopXMLNS, - 'encode_register_$password'(Password, - __NewTopXMLNS, - 'encode_register_$registered'(Registered, - __NewTopXMLNS, - 'encode_register_$date'(Date, - __NewTopXMLNS, - 'encode_register_$phone'(Phone, - __NewTopXMLNS, - 'encode_register_$state'(State, - __NewTopXMLNS, - 'encode_register_$name'(Name, - __NewTopXMLNS, - 'encode_register_$username'(Username, - __NewTopXMLNS, - 'encode_register_$remove'(Remove, - __NewTopXMLNS, - 'encode_register_$key'(Key, - __NewTopXMLNS, - 'encode_register_$city'(City, - __NewTopXMLNS, - 'encode_register_$nick'(Nick, - __NewTopXMLNS, - 'encode_register_$url'(Url, - __NewTopXMLNS, - 'encode_register_$email'(Email, - __NewTopXMLNS, - [])))))))))))))))))))))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"query">>, _attrs, _els}. - -'encode_register_$zip'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_register_$zip'(Zip, __TopXMLNS, _acc) -> - [encode_register_zip(Zip, __TopXMLNS) | _acc]. - -'encode_register_$xdata'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_register_$xdata'(Xdata, __TopXMLNS, _acc) -> - [encode_xdata(Xdata, __TopXMLNS) | _acc]. - -'encode_register_$misc'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_register_$misc'(Misc, __TopXMLNS, _acc) -> - [encode_register_misc(Misc, __TopXMLNS) | _acc]. - -'encode_register_$address'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_register_$address'(Address, __TopXMLNS, _acc) -> - [encode_register_address(Address, __TopXMLNS) | _acc]. - -'encode_register_$instructions'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_register_$instructions'(Instructions, - __TopXMLNS, _acc) -> - [encode_register_instructions(Instructions, __TopXMLNS) - | _acc]. - -'encode_register_$text'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_register_$text'(Text, __TopXMLNS, _acc) -> - [encode_register_text(Text, __TopXMLNS) | _acc]. - -'encode_register_$last'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_register_$last'(Last, __TopXMLNS, _acc) -> - [encode_register_last(Last, __TopXMLNS) | _acc]. - -'encode_register_$first'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_register_$first'(First, __TopXMLNS, _acc) -> - [encode_register_first(First, __TopXMLNS) | _acc]. - -'encode_register_$password'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_register_$password'(Password, __TopXMLNS, - _acc) -> - [encode_register_password(Password, __TopXMLNS) | _acc]. - -'encode_register_$registered'(false, __TopXMLNS, - _acc) -> - _acc; -'encode_register_$registered'(Registered, __TopXMLNS, - _acc) -> - [encode_register_registered(Registered, __TopXMLNS) - | _acc]. - -'encode_register_$date'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_register_$date'(Date, __TopXMLNS, _acc) -> - [encode_register_date(Date, __TopXMLNS) | _acc]. - -'encode_register_$phone'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_register_$phone'(Phone, __TopXMLNS, _acc) -> - [encode_register_phone(Phone, __TopXMLNS) | _acc]. - -'encode_register_$state'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_register_$state'(State, __TopXMLNS, _acc) -> - [encode_register_state(State, __TopXMLNS) | _acc]. - -'encode_register_$name'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_register_$name'(Name, __TopXMLNS, _acc) -> - [encode_register_name(Name, __TopXMLNS) | _acc]. - -'encode_register_$username'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_register_$username'(Username, __TopXMLNS, - _acc) -> - [encode_register_username(Username, __TopXMLNS) | _acc]. - -'encode_register_$remove'(false, __TopXMLNS, _acc) -> - _acc; -'encode_register_$remove'(Remove, __TopXMLNS, _acc) -> - [encode_register_remove(Remove, __TopXMLNS) | _acc]. - -'encode_register_$key'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_register_$key'(Key, __TopXMLNS, _acc) -> - [encode_register_key(Key, __TopXMLNS) | _acc]. - -'encode_register_$city'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_register_$city'(City, __TopXMLNS, _acc) -> - [encode_register_city(City, __TopXMLNS) | _acc]. - -'encode_register_$nick'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_register_$nick'(Nick, __TopXMLNS, _acc) -> - [encode_register_nick(Nick, __TopXMLNS) | _acc]. - -'encode_register_$url'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_register_$url'(Url, __TopXMLNS, _acc) -> - [encode_register_url(Url, __TopXMLNS) | _acc]. - -'encode_register_$email'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_register_$email'(Email, __TopXMLNS, _acc) -> - [encode_register_email(Email, __TopXMLNS) | _acc]. - -decode_register_key(__TopXMLNS, __IgnoreEls, - {xmlel, <<"key">>, _attrs, _els}) -> - Cdata = decode_register_key_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_register_key_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_register_key_cdata(__TopXMLNS, Cdata); -decode_register_key_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_register_key_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_register_key_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_register_key_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_register_key(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:register">>, [], - __TopXMLNS), - _els = encode_register_key_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"key">>, _attrs, _els}. - -decode_register_key_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_register_key_cdata(__TopXMLNS, _val) -> _val. - -encode_register_key_cdata(<<>>, _acc) -> _acc; -encode_register_key_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_register_text(__TopXMLNS, __IgnoreEls, - {xmlel, <<"text">>, _attrs, _els}) -> - Cdata = decode_register_text_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_register_text_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_register_text_cdata(__TopXMLNS, Cdata); -decode_register_text_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_register_text_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_register_text_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_register_text_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_register_text(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:register">>, [], - __TopXMLNS), - _els = encode_register_text_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"text">>, _attrs, _els}. - -decode_register_text_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_register_text_cdata(__TopXMLNS, _val) -> _val. - -encode_register_text_cdata(<<>>, _acc) -> _acc; -encode_register_text_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_register_misc(__TopXMLNS, __IgnoreEls, - {xmlel, <<"misc">>, _attrs, _els}) -> - Cdata = decode_register_misc_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_register_misc_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_register_misc_cdata(__TopXMLNS, Cdata); -decode_register_misc_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_register_misc_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_register_misc_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_register_misc_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_register_misc(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:register">>, [], - __TopXMLNS), - _els = encode_register_misc_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"misc">>, _attrs, _els}. - -decode_register_misc_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_register_misc_cdata(__TopXMLNS, _val) -> _val. - -encode_register_misc_cdata(<<>>, _acc) -> _acc; -encode_register_misc_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_register_date(__TopXMLNS, __IgnoreEls, - {xmlel, <<"date">>, _attrs, _els}) -> - Cdata = decode_register_date_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_register_date_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_register_date_cdata(__TopXMLNS, Cdata); -decode_register_date_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_register_date_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_register_date_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_register_date_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_register_date(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:register">>, [], - __TopXMLNS), - _els = encode_register_date_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"date">>, _attrs, _els}. - -decode_register_date_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_register_date_cdata(__TopXMLNS, _val) -> _val. - -encode_register_date_cdata(<<>>, _acc) -> _acc; -encode_register_date_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_register_url(__TopXMLNS, __IgnoreEls, - {xmlel, <<"url">>, _attrs, _els}) -> - Cdata = decode_register_url_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_register_url_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_register_url_cdata(__TopXMLNS, Cdata); -decode_register_url_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_register_url_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_register_url_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_register_url_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_register_url(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:register">>, [], - __TopXMLNS), - _els = encode_register_url_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"url">>, _attrs, _els}. - -decode_register_url_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_register_url_cdata(__TopXMLNS, _val) -> _val. - -encode_register_url_cdata(<<>>, _acc) -> _acc; -encode_register_url_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_register_phone(__TopXMLNS, __IgnoreEls, - {xmlel, <<"phone">>, _attrs, _els}) -> - Cdata = decode_register_phone_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_register_phone_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_register_phone_cdata(__TopXMLNS, Cdata); -decode_register_phone_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_register_phone_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_register_phone_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_register_phone_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_register_phone(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:register">>, [], - __TopXMLNS), - _els = encode_register_phone_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"phone">>, _attrs, _els}. - -decode_register_phone_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_register_phone_cdata(__TopXMLNS, _val) -> _val. - -encode_register_phone_cdata(<<>>, _acc) -> _acc; -encode_register_phone_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_register_zip(__TopXMLNS, __IgnoreEls, - {xmlel, <<"zip">>, _attrs, _els}) -> - Cdata = decode_register_zip_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_register_zip_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_register_zip_cdata(__TopXMLNS, Cdata); -decode_register_zip_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_register_zip_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_register_zip_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_register_zip_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_register_zip(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:register">>, [], - __TopXMLNS), - _els = encode_register_zip_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"zip">>, _attrs, _els}. - -decode_register_zip_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_register_zip_cdata(__TopXMLNS, _val) -> _val. - -encode_register_zip_cdata(<<>>, _acc) -> _acc; -encode_register_zip_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_register_state(__TopXMLNS, __IgnoreEls, - {xmlel, <<"state">>, _attrs, _els}) -> - Cdata = decode_register_state_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_register_state_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_register_state_cdata(__TopXMLNS, Cdata); -decode_register_state_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_register_state_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_register_state_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_register_state_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_register_state(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:register">>, [], - __TopXMLNS), - _els = encode_register_state_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"state">>, _attrs, _els}. - -decode_register_state_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_register_state_cdata(__TopXMLNS, _val) -> _val. - -encode_register_state_cdata(<<>>, _acc) -> _acc; -encode_register_state_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_register_city(__TopXMLNS, __IgnoreEls, - {xmlel, <<"city">>, _attrs, _els}) -> - Cdata = decode_register_city_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_register_city_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_register_city_cdata(__TopXMLNS, Cdata); -decode_register_city_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_register_city_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_register_city_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_register_city_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_register_city(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:register">>, [], - __TopXMLNS), - _els = encode_register_city_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"city">>, _attrs, _els}. - -decode_register_city_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_register_city_cdata(__TopXMLNS, _val) -> _val. - -encode_register_city_cdata(<<>>, _acc) -> _acc; -encode_register_city_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_register_address(__TopXMLNS, __IgnoreEls, - {xmlel, <<"address">>, _attrs, _els}) -> - Cdata = decode_register_address_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_register_address_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_register_address_cdata(__TopXMLNS, Cdata); -decode_register_address_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_register_address_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_register_address_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_register_address_els(__TopXMLNS, __IgnoreEls, - _els, Cdata). - -encode_register_address(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:register">>, [], - __TopXMLNS), - _els = encode_register_address_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"address">>, _attrs, _els}. - -decode_register_address_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_register_address_cdata(__TopXMLNS, _val) -> _val. - -encode_register_address_cdata(<<>>, _acc) -> _acc; -encode_register_address_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_register_email(__TopXMLNS, __IgnoreEls, - {xmlel, <<"email">>, _attrs, _els}) -> - Cdata = decode_register_email_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_register_email_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_register_email_cdata(__TopXMLNS, Cdata); -decode_register_email_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_register_email_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_register_email_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_register_email_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_register_email(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:register">>, [], - __TopXMLNS), - _els = encode_register_email_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"email">>, _attrs, _els}. - -decode_register_email_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_register_email_cdata(__TopXMLNS, _val) -> _val. - -encode_register_email_cdata(<<>>, _acc) -> _acc; -encode_register_email_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_register_last(__TopXMLNS, __IgnoreEls, - {xmlel, <<"last">>, _attrs, _els}) -> - Cdata = decode_register_last_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_register_last_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_register_last_cdata(__TopXMLNS, Cdata); -decode_register_last_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_register_last_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_register_last_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_register_last_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_register_last(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:register">>, [], - __TopXMLNS), - _els = encode_register_last_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"last">>, _attrs, _els}. - -decode_register_last_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_register_last_cdata(__TopXMLNS, _val) -> _val. - -encode_register_last_cdata(<<>>, _acc) -> _acc; -encode_register_last_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_register_first(__TopXMLNS, __IgnoreEls, - {xmlel, <<"first">>, _attrs, _els}) -> - Cdata = decode_register_first_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_register_first_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_register_first_cdata(__TopXMLNS, Cdata); -decode_register_first_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_register_first_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_register_first_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_register_first_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_register_first(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:register">>, [], - __TopXMLNS), - _els = encode_register_first_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"first">>, _attrs, _els}. - -decode_register_first_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_register_first_cdata(__TopXMLNS, _val) -> _val. - -encode_register_first_cdata(<<>>, _acc) -> _acc; -encode_register_first_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_register_name(__TopXMLNS, __IgnoreEls, - {xmlel, <<"name">>, _attrs, _els}) -> - Cdata = decode_register_name_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_register_name_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_register_name_cdata(__TopXMLNS, Cdata); -decode_register_name_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_register_name_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_register_name_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_register_name_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_register_name(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:register">>, [], - __TopXMLNS), - _els = encode_register_name_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"name">>, _attrs, _els}. - -decode_register_name_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_register_name_cdata(__TopXMLNS, _val) -> _val. - -encode_register_name_cdata(<<>>, _acc) -> _acc; -encode_register_name_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_register_password(__TopXMLNS, __IgnoreEls, - {xmlel, <<"password">>, _attrs, _els}) -> - Cdata = decode_register_password_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_register_password_els(__TopXMLNS, __IgnoreEls, - [], Cdata) -> - decode_register_password_cdata(__TopXMLNS, Cdata); -decode_register_password_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_register_password_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_register_password_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_register_password_els(__TopXMLNS, __IgnoreEls, - _els, Cdata). - -encode_register_password(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:register">>, [], - __TopXMLNS), - _els = encode_register_password_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"password">>, _attrs, _els}. - -decode_register_password_cdata(__TopXMLNS, <<>>) -> - <<>>; -decode_register_password_cdata(__TopXMLNS, _val) -> - _val. - -encode_register_password_cdata(<<>>, _acc) -> _acc; -encode_register_password_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_register_nick(__TopXMLNS, __IgnoreEls, - {xmlel, <<"nick">>, _attrs, _els}) -> - Cdata = decode_register_nick_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_register_nick_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_register_nick_cdata(__TopXMLNS, Cdata); -decode_register_nick_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_register_nick_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_register_nick_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_register_nick_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_register_nick(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:register">>, [], - __TopXMLNS), - _els = encode_register_nick_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"nick">>, _attrs, _els}. - -decode_register_nick_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_register_nick_cdata(__TopXMLNS, _val) -> _val. - -encode_register_nick_cdata(<<>>, _acc) -> _acc; -encode_register_nick_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_register_username(__TopXMLNS, __IgnoreEls, - {xmlel, <<"username">>, _attrs, _els}) -> - Cdata = decode_register_username_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_register_username_els(__TopXMLNS, __IgnoreEls, - [], Cdata) -> - decode_register_username_cdata(__TopXMLNS, Cdata); -decode_register_username_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_register_username_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_register_username_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_register_username_els(__TopXMLNS, __IgnoreEls, - _els, Cdata). - -encode_register_username(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:register">>, [], - __TopXMLNS), - _els = encode_register_username_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"username">>, _attrs, _els}. - -decode_register_username_cdata(__TopXMLNS, <<>>) -> - <<>>; -decode_register_username_cdata(__TopXMLNS, _val) -> - _val. - -encode_register_username_cdata(<<>>, _acc) -> _acc; -encode_register_username_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_register_instructions(__TopXMLNS, __IgnoreEls, - {xmlel, <<"instructions">>, _attrs, _els}) -> - Cdata = decode_register_instructions_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_register_instructions_els(__TopXMLNS, - __IgnoreEls, [], Cdata) -> - decode_register_instructions_cdata(__TopXMLNS, Cdata); -decode_register_instructions_els(__TopXMLNS, - __IgnoreEls, [{xmlcdata, _data} | _els], - Cdata) -> - decode_register_instructions_els(__TopXMLNS, - __IgnoreEls, _els, - <>); -decode_register_instructions_els(__TopXMLNS, - __IgnoreEls, [_ | _els], Cdata) -> - decode_register_instructions_els(__TopXMLNS, - __IgnoreEls, _els, Cdata). - -encode_register_instructions(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:register">>, [], - __TopXMLNS), - _els = encode_register_instructions_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"instructions">>, _attrs, _els}. - -decode_register_instructions_cdata(__TopXMLNS, <<>>) -> - <<>>; -decode_register_instructions_cdata(__TopXMLNS, _val) -> - _val. - -encode_register_instructions_cdata(<<>>, _acc) -> _acc; -encode_register_instructions_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_register_remove(__TopXMLNS, __IgnoreEls, - {xmlel, <<"remove">>, _attrs, _els}) -> - true. - -encode_register_remove(true, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:register">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"remove">>, _attrs, _els}. - -decode_register_registered(__TopXMLNS, __IgnoreEls, - {xmlel, <<"registered">>, _attrs, _els}) -> - true. - -encode_register_registered(true, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:register">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"registered">>, _attrs, _els}. - -decode_feature_register(__TopXMLNS, __IgnoreEls, - {xmlel, <<"register">>, _attrs, _els}) -> - {feature_register}. - -encode_feature_register({feature_register}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/features/iq-register">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"register">>, _attrs, _els}. - -decode_caps(__TopXMLNS, __IgnoreEls, - {xmlel, <<"c">>, _attrs, _els}) -> - {Hash, Node, Exts, Version} = - decode_caps_attrs(__TopXMLNS, _attrs, undefined, - undefined, undefined, undefined), - {caps, Node, Version, Hash, Exts}. - -decode_caps_attrs(__TopXMLNS, - [{<<"hash">>, _val} | _attrs], _Hash, Node, Exts, - Version) -> - decode_caps_attrs(__TopXMLNS, _attrs, _val, Node, Exts, - Version); -decode_caps_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], Hash, _Node, Exts, - Version) -> - decode_caps_attrs(__TopXMLNS, _attrs, Hash, _val, Exts, - Version); -decode_caps_attrs(__TopXMLNS, - [{<<"ext">>, _val} | _attrs], Hash, Node, _Exts, - Version) -> - decode_caps_attrs(__TopXMLNS, _attrs, Hash, Node, _val, - Version); -decode_caps_attrs(__TopXMLNS, - [{<<"ver">>, _val} | _attrs], Hash, Node, Exts, - _Version) -> - decode_caps_attrs(__TopXMLNS, _attrs, Hash, Node, Exts, - _val); -decode_caps_attrs(__TopXMLNS, [_ | _attrs], Hash, Node, - Exts, Version) -> - decode_caps_attrs(__TopXMLNS, _attrs, Hash, Node, Exts, - Version); -decode_caps_attrs(__TopXMLNS, [], Hash, Node, Exts, - Version) -> - {decode_caps_attr_hash(__TopXMLNS, Hash), - decode_caps_attr_node(__TopXMLNS, Node), - decode_caps_attr_ext(__TopXMLNS, Exts), - decode_caps_attr_ver(__TopXMLNS, Version)}. - -encode_caps({caps, Node, Version, Hash, Exts}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/caps">>, - [], __TopXMLNS), - _els = [], - _attrs = encode_caps_attr_ver(Version, - encode_caps_attr_ext(Exts, - encode_caps_attr_node(Node, - encode_caps_attr_hash(Hash, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))))), - {xmlel, <<"c">>, _attrs, _els}. - -decode_caps_attr_hash(__TopXMLNS, undefined) -> <<>>; -decode_caps_attr_hash(__TopXMLNS, _val) -> _val. - -encode_caps_attr_hash(<<>>, _acc) -> _acc; -encode_caps_attr_hash(_val, _acc) -> - [{<<"hash">>, _val} | _acc]. - -decode_caps_attr_node(__TopXMLNS, undefined) -> <<>>; -decode_caps_attr_node(__TopXMLNS, _val) -> _val. - -encode_caps_attr_node(<<>>, _acc) -> _acc; -encode_caps_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_caps_attr_ext(__TopXMLNS, undefined) -> []; -decode_caps_attr_ext(__TopXMLNS, _val) -> - case catch re:split(_val, "\\h+") of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"ext">>, <<"c">>, __TopXMLNS}}); - _res -> _res - end. - -encode_caps_attr_ext([], _acc) -> _acc; -encode_caps_attr_ext(_val, _acc) -> - [{<<"ext">>, join(_val, 32)} | _acc]. - -decode_caps_attr_ver(__TopXMLNS, undefined) -> <<>>; -decode_caps_attr_ver(__TopXMLNS, _val) -> _val. - -encode_caps_attr_ver(<<>>, _acc) -> _acc; -encode_caps_attr_ver(_val, _acc) -> - [{<<"ver">>, _val} | _acc]. - -decode_p1_ack(__TopXMLNS, __IgnoreEls, - {xmlel, <<"ack">>, _attrs, _els}) -> - {p1_ack}. - -encode_p1_ack({p1_ack}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"p1:ack">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"ack">>, _attrs, _els}. - -decode_p1_rebind(__TopXMLNS, __IgnoreEls, - {xmlel, <<"rebind">>, _attrs, _els}) -> - {p1_rebind}. - -encode_p1_rebind({p1_rebind}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"p1:rebind">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"rebind">>, _attrs, _els}. - -decode_p1_push(__TopXMLNS, __IgnoreEls, - {xmlel, <<"push">>, _attrs, _els}) -> - {p1_push}. - -encode_p1_push({p1_push}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"p1:push">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"push">>, _attrs, _els}. - -decode_stream_features(__TopXMLNS, __IgnoreEls, - {xmlel, <<"stream:features">>, _attrs, _els}) -> - __Els = decode_stream_features_els(__TopXMLNS, - __IgnoreEls, _els, []), - {stream_features, __Els}. - -decode_stream_features_els(__TopXMLNS, __IgnoreEls, [], - __Els) -> - lists:reverse(__Els); -decode_stream_features_els(__TopXMLNS, __IgnoreEls, - [{xmlel, _, _, _} = _el | _els], __Els) -> - if __IgnoreEls -> - decode_stream_features_els(__TopXMLNS, __IgnoreEls, - _els, [_el | __Els]); - true -> - case is_known_tag(_el, __TopXMLNS) of - true -> - decode_stream_features_els(__TopXMLNS, __IgnoreEls, - _els, - [decode(_el, __TopXMLNS, []) - | __Els]); - false -> - decode_stream_features_els(__TopXMLNS, __IgnoreEls, - _els, __Els) - end - end; -decode_stream_features_els(__TopXMLNS, __IgnoreEls, - [_ | _els], __Els) -> - decode_stream_features_els(__TopXMLNS, __IgnoreEls, - _els, __Els). - -encode_stream_features({stream_features, __Els}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"jabber:client">>, <<"jabber:server">>], - __TopXMLNS), - _els = [encode(_el, __NewTopXMLNS) || _el <- __Els], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"stream:features">>, _attrs, _els}. - -decode_compression(__TopXMLNS, __IgnoreEls, - {xmlel, <<"compression">>, _attrs, _els}) -> - Methods = decode_compression_els(__TopXMLNS, - __IgnoreEls, _els, []), - {compression, Methods}. - -decode_compression_els(__TopXMLNS, __IgnoreEls, [], - Methods) -> - lists:reverse(Methods); -decode_compression_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"method">>, _attrs, _} = _el | _els], - Methods) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/features/compress">> -> - decode_compression_els(__TopXMLNS, __IgnoreEls, _els, - [decode_compression_method(__TopXMLNS, - __IgnoreEls, _el) - | Methods]); - <<"http://jabber.org/features/compress">> -> - decode_compression_els(__TopXMLNS, __IgnoreEls, _els, - [decode_compression_method(<<"http://jabber.org/features/compress">>, - __IgnoreEls, _el) - | Methods]); - _ -> - decode_compression_els(__TopXMLNS, __IgnoreEls, _els, - Methods) - end; -decode_compression_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Methods) -> - decode_compression_els(__TopXMLNS, __IgnoreEls, _els, - Methods). - -encode_compression({compression, Methods}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/features/compress">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_compression_$methods'(Methods, - __NewTopXMLNS, [])), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"compression">>, _attrs, _els}. - -'encode_compression_$methods'([], __TopXMLNS, _acc) -> - _acc; -'encode_compression_$methods'([Methods | _els], - __TopXMLNS, _acc) -> - 'encode_compression_$methods'(_els, __TopXMLNS, - [encode_compression_method(Methods, - __TopXMLNS) - | _acc]). - -decode_compression_method(__TopXMLNS, __IgnoreEls, - {xmlel, <<"method">>, _attrs, _els}) -> - Cdata = decode_compression_method_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_compression_method_els(__TopXMLNS, __IgnoreEls, - [], Cdata) -> - decode_compression_method_cdata(__TopXMLNS, Cdata); -decode_compression_method_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_compression_method_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_compression_method_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_compression_method_els(__TopXMLNS, __IgnoreEls, - _els, Cdata). - -encode_compression_method(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/features/compress">>, - [], __TopXMLNS), - _els = encode_compression_method_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"method">>, _attrs, _els}. - -decode_compression_method_cdata(__TopXMLNS, <<>>) -> - <<>>; -decode_compression_method_cdata(__TopXMLNS, _val) -> - _val. - -encode_compression_method_cdata(<<>>, _acc) -> _acc; -encode_compression_method_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_compressed(__TopXMLNS, __IgnoreEls, - {xmlel, <<"compressed">>, _attrs, _els}) -> - {compressed}. - -encode_compressed({compressed}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/compress">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"compressed">>, _attrs, _els}. - -decode_compress(__TopXMLNS, __IgnoreEls, - {xmlel, <<"compress">>, _attrs, _els}) -> - Methods = decode_compress_els(__TopXMLNS, __IgnoreEls, - _els, []), - {compress, Methods}. - -decode_compress_els(__TopXMLNS, __IgnoreEls, [], - Methods) -> - lists:reverse(Methods); -decode_compress_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"method">>, _attrs, _} = _el | _els], - Methods) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/compress">> -> - decode_compress_els(__TopXMLNS, __IgnoreEls, _els, - [decode_compress_method(__TopXMLNS, __IgnoreEls, - _el) - | Methods]); - <<"http://jabber.org/protocol/compress">> -> - decode_compress_els(__TopXMLNS, __IgnoreEls, _els, - [decode_compress_method(<<"http://jabber.org/protocol/compress">>, - __IgnoreEls, _el) - | Methods]); - _ -> - decode_compress_els(__TopXMLNS, __IgnoreEls, _els, - Methods) - end; -decode_compress_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Methods) -> - decode_compress_els(__TopXMLNS, __IgnoreEls, _els, - Methods). - -encode_compress({compress, Methods}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/compress">>, - [], __TopXMLNS), - _els = lists:reverse('encode_compress_$methods'(Methods, - __NewTopXMLNS, [])), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"compress">>, _attrs, _els}. - -'encode_compress_$methods'([], __TopXMLNS, _acc) -> - _acc; -'encode_compress_$methods'([Methods | _els], __TopXMLNS, - _acc) -> - 'encode_compress_$methods'(_els, __TopXMLNS, - [encode_compress_method(Methods, __TopXMLNS) - | _acc]). - -decode_compress_method(__TopXMLNS, __IgnoreEls, - {xmlel, <<"method">>, _attrs, _els}) -> - Cdata = decode_compress_method_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_compress_method_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_compress_method_cdata(__TopXMLNS, Cdata); -decode_compress_method_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_compress_method_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_compress_method_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_compress_method_els(__TopXMLNS, __IgnoreEls, - _els, Cdata). - -encode_compress_method(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/compress">>, - [], __TopXMLNS), - _els = encode_compress_method_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"method">>, _attrs, _els}. - -decode_compress_method_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_compress_method_cdata(__TopXMLNS, _val) -> _val. - -encode_compress_method_cdata(<<>>, _acc) -> _acc; -encode_compress_method_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_compress_failure(__TopXMLNS, __IgnoreEls, - {xmlel, <<"failure">>, _attrs, _els}) -> - Reason = decode_compress_failure_els(__TopXMLNS, - __IgnoreEls, _els, undefined), - {compress_failure, Reason}. - -decode_compress_failure_els(__TopXMLNS, __IgnoreEls, [], - Reason) -> - Reason; -decode_compress_failure_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"setup-failed">>, _attrs, _} = _el - | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/compress">> -> - decode_compress_failure_els(__TopXMLNS, __IgnoreEls, - _els, - decode_compress_failure_setup_failed(__TopXMLNS, - __IgnoreEls, - _el)); - <<"http://jabber.org/protocol/compress">> -> - decode_compress_failure_els(__TopXMLNS, __IgnoreEls, - _els, - decode_compress_failure_setup_failed(<<"http://jabber.org/protocol/compress">>, - __IgnoreEls, - _el)); - _ -> - decode_compress_failure_els(__TopXMLNS, __IgnoreEls, - _els, Reason) - end; -decode_compress_failure_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"processing-failed">>, _attrs, _} = _el - | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/compress">> -> - decode_compress_failure_els(__TopXMLNS, __IgnoreEls, - _els, - decode_compress_failure_processing_failed(__TopXMLNS, - __IgnoreEls, - _el)); - <<"http://jabber.org/protocol/compress">> -> - decode_compress_failure_els(__TopXMLNS, __IgnoreEls, - _els, - decode_compress_failure_processing_failed(<<"http://jabber.org/protocol/compress">>, - __IgnoreEls, - _el)); - _ -> - decode_compress_failure_els(__TopXMLNS, __IgnoreEls, - _els, Reason) - end; -decode_compress_failure_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"unsupported-method">>, _attrs, _} = _el - | _els], - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/compress">> -> - decode_compress_failure_els(__TopXMLNS, __IgnoreEls, - _els, - decode_compress_failure_unsupported_method(__TopXMLNS, - __IgnoreEls, - _el)); - <<"http://jabber.org/protocol/compress">> -> - decode_compress_failure_els(__TopXMLNS, __IgnoreEls, - _els, - decode_compress_failure_unsupported_method(<<"http://jabber.org/protocol/compress">>, - __IgnoreEls, - _el)); - _ -> - decode_compress_failure_els(__TopXMLNS, __IgnoreEls, - _els, Reason) - end; -decode_compress_failure_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Reason) -> - decode_compress_failure_els(__TopXMLNS, __IgnoreEls, - _els, Reason). - -encode_compress_failure({compress_failure, Reason}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/compress">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_compress_failure_$reason'(Reason, - __NewTopXMLNS, [])), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"failure">>, _attrs, _els}. - -'encode_compress_failure_$reason'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_compress_failure_$reason'('setup-failed' = - Reason, - __TopXMLNS, _acc) -> - [encode_compress_failure_setup_failed(Reason, - __TopXMLNS) - | _acc]; -'encode_compress_failure_$reason'('processing-failed' = - Reason, - __TopXMLNS, _acc) -> - [encode_compress_failure_processing_failed(Reason, - __TopXMLNS) - | _acc]; -'encode_compress_failure_$reason'('unsupported-method' = - Reason, - __TopXMLNS, _acc) -> - [encode_compress_failure_unsupported_method(Reason, - __TopXMLNS) - | _acc]. - -decode_compress_failure_unsupported_method(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"unsupported-method">>, - _attrs, _els}) -> - 'unsupported-method'. - -encode_compress_failure_unsupported_method('unsupported-method', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/compress">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"unsupported-method">>, _attrs, _els}. - -decode_compress_failure_processing_failed(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"processing-failed">>, - _attrs, _els}) -> - 'processing-failed'. - -encode_compress_failure_processing_failed('processing-failed', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/compress">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"processing-failed">>, _attrs, _els}. - -decode_compress_failure_setup_failed(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"setup-failed">>, _attrs, - _els}) -> - 'setup-failed'. - -encode_compress_failure_setup_failed('setup-failed', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/compress">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"setup-failed">>, _attrs, _els}. - -decode_starttls_failure(__TopXMLNS, __IgnoreEls, - {xmlel, <<"failure">>, _attrs, _els}) -> - {starttls_failure}. - -encode_starttls_failure({starttls_failure}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-tls">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"failure">>, _attrs, _els}. - -decode_starttls_proceed(__TopXMLNS, __IgnoreEls, - {xmlel, <<"proceed">>, _attrs, _els}) -> - {starttls_proceed}. - -encode_starttls_proceed({starttls_proceed}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-tls">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"proceed">>, _attrs, _els}. - -decode_starttls(__TopXMLNS, __IgnoreEls, - {xmlel, <<"starttls">>, _attrs, _els}) -> - Required = decode_starttls_els(__TopXMLNS, __IgnoreEls, - _els, false), - {starttls, Required}. - -decode_starttls_els(__TopXMLNS, __IgnoreEls, [], - Required) -> - Required; -decode_starttls_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"required">>, _attrs, _} = _el | _els], - Required) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"urn:ietf:params:xml:ns:xmpp-tls">> -> - decode_starttls_els(__TopXMLNS, __IgnoreEls, _els, - decode_starttls_required(__TopXMLNS, __IgnoreEls, - _el)); - <<"urn:ietf:params:xml:ns:xmpp-tls">> -> - decode_starttls_els(__TopXMLNS, __IgnoreEls, _els, - decode_starttls_required(<<"urn:ietf:params:xml:ns:xmpp-tls">>, - __IgnoreEls, _el)); - _ -> - decode_starttls_els(__TopXMLNS, __IgnoreEls, _els, - Required) - end; -decode_starttls_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Required) -> - decode_starttls_els(__TopXMLNS, __IgnoreEls, _els, - Required). - -encode_starttls({starttls, Required}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-tls">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_starttls_$required'(Required, - __NewTopXMLNS, [])), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"starttls">>, _attrs, _els}. - -'encode_starttls_$required'(false, __TopXMLNS, _acc) -> - _acc; -'encode_starttls_$required'(Required, __TopXMLNS, - _acc) -> - [encode_starttls_required(Required, __TopXMLNS) | _acc]. - -decode_starttls_required(__TopXMLNS, __IgnoreEls, - {xmlel, <<"required">>, _attrs, _els}) -> - true. - -encode_starttls_required(true, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-tls">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"required">>, _attrs, _els}. - -decode_sasl_mechanisms(__TopXMLNS, __IgnoreEls, - {xmlel, <<"mechanisms">>, _attrs, _els}) -> - List = decode_sasl_mechanisms_els(__TopXMLNS, - __IgnoreEls, _els, []), - {sasl_mechanisms, List}. - -decode_sasl_mechanisms_els(__TopXMLNS, __IgnoreEls, [], - List) -> - lists:reverse(List); -decode_sasl_mechanisms_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"mechanism">>, _attrs, _} = _el | _els], - List) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_mechanisms_els(__TopXMLNS, __IgnoreEls, - _els, - [decode_sasl_mechanism(__TopXMLNS, - __IgnoreEls, _el) - | List]); - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_mechanisms_els(__TopXMLNS, __IgnoreEls, - _els, - [decode_sasl_mechanism(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - __IgnoreEls, _el) - | List]); - _ -> - decode_sasl_mechanisms_els(__TopXMLNS, __IgnoreEls, - _els, List) - end; -decode_sasl_mechanisms_els(__TopXMLNS, __IgnoreEls, - [_ | _els], List) -> - decode_sasl_mechanisms_els(__TopXMLNS, __IgnoreEls, - _els, List). - -encode_sasl_mechanisms({sasl_mechanisms, List}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_sasl_mechanisms_$list'(List, - __NewTopXMLNS, [])), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"mechanisms">>, _attrs, _els}. - -'encode_sasl_mechanisms_$list'([], __TopXMLNS, _acc) -> - _acc; -'encode_sasl_mechanisms_$list'([List | _els], - __TopXMLNS, _acc) -> - 'encode_sasl_mechanisms_$list'(_els, __TopXMLNS, - [encode_sasl_mechanism(List, __TopXMLNS) - | _acc]). - -decode_sasl_mechanism(__TopXMLNS, __IgnoreEls, - {xmlel, <<"mechanism">>, _attrs, _els}) -> - Cdata = decode_sasl_mechanism_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_sasl_mechanism_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_sasl_mechanism_cdata(__TopXMLNS, Cdata); -decode_sasl_mechanism_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_sasl_mechanism_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_sasl_mechanism_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_sasl_mechanism_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_sasl_mechanism(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - [], __TopXMLNS), - _els = encode_sasl_mechanism_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"mechanism">>, _attrs, _els}. - -decode_sasl_mechanism_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_sasl_mechanism_cdata(__TopXMLNS, _val) -> _val. - -encode_sasl_mechanism_cdata(<<>>, _acc) -> _acc; -encode_sasl_mechanism_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_sasl_failure(__TopXMLNS, __IgnoreEls, - {xmlel, <<"failure">>, _attrs, _els}) -> - {Text, Reason} = decode_sasl_failure_els(__TopXMLNS, - __IgnoreEls, _els, [], undefined), - {sasl_failure, Reason, Text}. - -decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, [], - Text, Reason) -> - {lists:reverse(Text), Reason}; -decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"text">>, _attrs, _} = _el | _els], Text, - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - [decode_sasl_failure_text(__TopXMLNS, - __IgnoreEls, _el) - | Text], - Reason); - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - [decode_sasl_failure_text(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - __IgnoreEls, _el) - | Text], - Reason); - _ -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"aborted">>, _attrs, _} = _el | _els], Text, - Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_aborted(__TopXMLNS, - __IgnoreEls, - _el)); - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_aborted(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - __IgnoreEls, - _el)); - _ -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"account-disabled">>, _attrs, _} = _el - | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_account_disabled(__TopXMLNS, - __IgnoreEls, - _el)); - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_account_disabled(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - __IgnoreEls, - _el)); - _ -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"credentials-expired">>, _attrs, _} = _el - | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_credentials_expired(__TopXMLNS, - __IgnoreEls, - _el)); - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_credentials_expired(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - __IgnoreEls, - _el)); - _ -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"encryption-required">>, _attrs, _} = _el - | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_encryption_required(__TopXMLNS, - __IgnoreEls, - _el)); - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_encryption_required(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - __IgnoreEls, - _el)); - _ -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"incorrect-encoding">>, _attrs, _} = _el - | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_incorrect_encoding(__TopXMLNS, - __IgnoreEls, - _el)); - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_incorrect_encoding(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - __IgnoreEls, - _el)); - _ -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"invalid-authzid">>, _attrs, _} = _el - | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_invalid_authzid(__TopXMLNS, - __IgnoreEls, - _el)); - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_invalid_authzid(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - __IgnoreEls, - _el)); - _ -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"invalid-mechanism">>, _attrs, _} = _el - | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_invalid_mechanism(__TopXMLNS, - __IgnoreEls, - _el)); - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_invalid_mechanism(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - __IgnoreEls, - _el)); - _ -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"malformed-request">>, _attrs, _} = _el - | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_malformed_request(__TopXMLNS, - __IgnoreEls, - _el)); - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_malformed_request(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - __IgnoreEls, - _el)); - _ -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"mechanism-too-weak">>, _attrs, _} = _el - | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_mechanism_too_weak(__TopXMLNS, - __IgnoreEls, - _el)); - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_mechanism_too_weak(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - __IgnoreEls, - _el)); - _ -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"not-authorized">>, _attrs, _} = _el | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_not_authorized(__TopXMLNS, - __IgnoreEls, - _el)); - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_not_authorized(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - __IgnoreEls, - _el)); - _ -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"bad-protocol">>, _attrs, _} = _el | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_bad_protocol(__TopXMLNS, - __IgnoreEls, - _el)); - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_bad_protocol(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - __IgnoreEls, - _el)); - _ -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"temporary-auth-failure">>, _attrs, _} = _el - | _els], - Text, Reason) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_temporary_auth_failure(__TopXMLNS, - __IgnoreEls, - _el)); - <<"urn:ietf:params:xml:ns:xmpp-sasl">> -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, - decode_sasl_failure_temporary_auth_failure(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - __IgnoreEls, - _el)); - _ -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason) - end; -decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Text, Reason) -> - decode_sasl_failure_els(__TopXMLNS, __IgnoreEls, _els, - Text, Reason). - -encode_sasl_failure({sasl_failure, Reason, Text}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - [], __TopXMLNS), - _els = lists:reverse('encode_sasl_failure_$text'(Text, - __NewTopXMLNS, - 'encode_sasl_failure_$reason'(Reason, - __NewTopXMLNS, - []))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"failure">>, _attrs, _els}. - -'encode_sasl_failure_$text'([], __TopXMLNS, _acc) -> - _acc; -'encode_sasl_failure_$text'([Text | _els], __TopXMLNS, - _acc) -> - 'encode_sasl_failure_$text'(_els, __TopXMLNS, - [encode_sasl_failure_text(Text, __TopXMLNS) - | _acc]). - -'encode_sasl_failure_$reason'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_sasl_failure_$reason'(aborted = Reason, - __TopXMLNS, _acc) -> - [encode_sasl_failure_aborted(Reason, __TopXMLNS) - | _acc]; -'encode_sasl_failure_$reason'('account-disabled' = - Reason, - __TopXMLNS, _acc) -> - [encode_sasl_failure_account_disabled(Reason, - __TopXMLNS) - | _acc]; -'encode_sasl_failure_$reason'('credentials-expired' = - Reason, - __TopXMLNS, _acc) -> - [encode_sasl_failure_credentials_expired(Reason, - __TopXMLNS) - | _acc]; -'encode_sasl_failure_$reason'('encryption-required' = - Reason, - __TopXMLNS, _acc) -> - [encode_sasl_failure_encryption_required(Reason, - __TopXMLNS) - | _acc]; -'encode_sasl_failure_$reason'('incorrect-encoding' = - Reason, - __TopXMLNS, _acc) -> - [encode_sasl_failure_incorrect_encoding(Reason, - __TopXMLNS) - | _acc]; -'encode_sasl_failure_$reason'('invalid-authzid' = - Reason, - __TopXMLNS, _acc) -> - [encode_sasl_failure_invalid_authzid(Reason, __TopXMLNS) - | _acc]; -'encode_sasl_failure_$reason'('invalid-mechanism' = - Reason, - __TopXMLNS, _acc) -> - [encode_sasl_failure_invalid_mechanism(Reason, - __TopXMLNS) - | _acc]; -'encode_sasl_failure_$reason'('malformed-request' = - Reason, - __TopXMLNS, _acc) -> - [encode_sasl_failure_malformed_request(Reason, - __TopXMLNS) - | _acc]; -'encode_sasl_failure_$reason'('mechanism-too-weak' = - Reason, - __TopXMLNS, _acc) -> - [encode_sasl_failure_mechanism_too_weak(Reason, - __TopXMLNS) - | _acc]; -'encode_sasl_failure_$reason'('not-authorized' = Reason, - __TopXMLNS, _acc) -> - [encode_sasl_failure_not_authorized(Reason, __TopXMLNS) - | _acc]; -'encode_sasl_failure_$reason'('bad-protocol' = Reason, - __TopXMLNS, _acc) -> - [encode_sasl_failure_bad_protocol(Reason, __TopXMLNS) - | _acc]; -'encode_sasl_failure_$reason'('temporary-auth-failure' = - Reason, - __TopXMLNS, _acc) -> - [encode_sasl_failure_temporary_auth_failure(Reason, - __TopXMLNS) - | _acc]. - -decode_sasl_failure_temporary_auth_failure(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"temporary-auth-failure">>, - _attrs, _els}) -> - 'temporary-auth-failure'. - -encode_sasl_failure_temporary_auth_failure('temporary-auth-failure', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"temporary-auth-failure">>, _attrs, _els}. - -decode_sasl_failure_bad_protocol(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"bad-protocol">>, _attrs, _els}) -> - 'bad-protocol'. - -encode_sasl_failure_bad_protocol('bad-protocol', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"bad-protocol">>, _attrs, _els}. - -decode_sasl_failure_not_authorized(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"not-authorized">>, _attrs, - _els}) -> - 'not-authorized'. - -encode_sasl_failure_not_authorized('not-authorized', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"not-authorized">>, _attrs, _els}. - -decode_sasl_failure_mechanism_too_weak(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"mechanism-too-weak">>, _attrs, - _els}) -> - 'mechanism-too-weak'. - -encode_sasl_failure_mechanism_too_weak('mechanism-too-weak', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"mechanism-too-weak">>, _attrs, _els}. - -decode_sasl_failure_malformed_request(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"malformed-request">>, _attrs, - _els}) -> - 'malformed-request'. - -encode_sasl_failure_malformed_request('malformed-request', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"malformed-request">>, _attrs, _els}. - -decode_sasl_failure_invalid_mechanism(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"invalid-mechanism">>, _attrs, - _els}) -> - 'invalid-mechanism'. - -encode_sasl_failure_invalid_mechanism('invalid-mechanism', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"invalid-mechanism">>, _attrs, _els}. - -decode_sasl_failure_invalid_authzid(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"invalid-authzid">>, _attrs, - _els}) -> - 'invalid-authzid'. - -encode_sasl_failure_invalid_authzid('invalid-authzid', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"invalid-authzid">>, _attrs, _els}. - -decode_sasl_failure_incorrect_encoding(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"incorrect-encoding">>, _attrs, - _els}) -> - 'incorrect-encoding'. - -encode_sasl_failure_incorrect_encoding('incorrect-encoding', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"incorrect-encoding">>, _attrs, _els}. - -decode_sasl_failure_encryption_required(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"encryption-required">>, - _attrs, _els}) -> - 'encryption-required'. - -encode_sasl_failure_encryption_required('encryption-required', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"encryption-required">>, _attrs, _els}. - -decode_sasl_failure_credentials_expired(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"credentials-expired">>, - _attrs, _els}) -> - 'credentials-expired'. - -encode_sasl_failure_credentials_expired('credentials-expired', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"credentials-expired">>, _attrs, _els}. - -decode_sasl_failure_account_disabled(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"account-disabled">>, _attrs, - _els}) -> - 'account-disabled'. - -encode_sasl_failure_account_disabled('account-disabled', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"account-disabled">>, _attrs, _els}. - -decode_sasl_failure_aborted(__TopXMLNS, __IgnoreEls, - {xmlel, <<"aborted">>, _attrs, _els}) -> - aborted. - -encode_sasl_failure_aborted(aborted, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"aborted">>, _attrs, _els}. - -decode_sasl_failure_text(__TopXMLNS, __IgnoreEls, - {xmlel, <<"text">>, _attrs, _els}) -> - Data = decode_sasl_failure_text_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Lang = decode_sasl_failure_text_attrs(__TopXMLNS, - _attrs, undefined), - {text, Lang, Data}. - -decode_sasl_failure_text_els(__TopXMLNS, __IgnoreEls, - [], Data) -> - decode_sasl_failure_text_cdata(__TopXMLNS, Data); -decode_sasl_failure_text_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Data) -> - decode_sasl_failure_text_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_sasl_failure_text_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Data) -> - decode_sasl_failure_text_els(__TopXMLNS, __IgnoreEls, - _els, Data). - -decode_sasl_failure_text_attrs(__TopXMLNS, - [{<<"xml:lang">>, _val} | _attrs], _Lang) -> - decode_sasl_failure_text_attrs(__TopXMLNS, _attrs, - _val); -decode_sasl_failure_text_attrs(__TopXMLNS, [_ | _attrs], - Lang) -> - decode_sasl_failure_text_attrs(__TopXMLNS, _attrs, - Lang); -decode_sasl_failure_text_attrs(__TopXMLNS, [], Lang) -> - 'decode_sasl_failure_text_attr_xml:lang'(__TopXMLNS, - Lang). - -encode_sasl_failure_text({text, Lang, Data}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - [], __TopXMLNS), - _els = encode_sasl_failure_text_cdata(Data, []), - _attrs = 'encode_sasl_failure_text_attr_xml:lang'(Lang, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"text">>, _attrs, _els}. - -'decode_sasl_failure_text_attr_xml:lang'(__TopXMLNS, - undefined) -> - <<>>; -'decode_sasl_failure_text_attr_xml:lang'(__TopXMLNS, - _val) -> - _val. - -'encode_sasl_failure_text_attr_xml:lang'(<<>>, _acc) -> - _acc; -'encode_sasl_failure_text_attr_xml:lang'(_val, _acc) -> - [{<<"xml:lang">>, _val} | _acc]. - -decode_sasl_failure_text_cdata(__TopXMLNS, <<>>) -> - <<>>; -decode_sasl_failure_text_cdata(__TopXMLNS, _val) -> - _val. - -encode_sasl_failure_text_cdata(<<>>, _acc) -> _acc; -encode_sasl_failure_text_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_sasl_success(__TopXMLNS, __IgnoreEls, - {xmlel, <<"success">>, _attrs, _els}) -> - Text = decode_sasl_success_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - {sasl_success, Text}. - -decode_sasl_success_els(__TopXMLNS, __IgnoreEls, [], - Text) -> - decode_sasl_success_cdata(__TopXMLNS, Text); -decode_sasl_success_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Text) -> - decode_sasl_success_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_sasl_success_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Text) -> - decode_sasl_success_els(__TopXMLNS, __IgnoreEls, _els, - Text). - -encode_sasl_success({sasl_success, Text}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - [], __TopXMLNS), - _els = encode_sasl_success_cdata(Text, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"success">>, _attrs, _els}. - -decode_sasl_success_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_sasl_success_cdata(__TopXMLNS, _val) -> - case catch base64:mime_decode(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_cdata_value, <<>>, <<"success">>, __TopXMLNS}}); - _res -> _res - end. - -encode_sasl_success_cdata(<<>>, _acc) -> _acc; -encode_sasl_success_cdata(_val, _acc) -> - [{xmlcdata, base64:encode(_val)} | _acc]. - -decode_sasl_response(__TopXMLNS, __IgnoreEls, - {xmlel, <<"response">>, _attrs, _els}) -> - Text = decode_sasl_response_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - {sasl_response, Text}. - -decode_sasl_response_els(__TopXMLNS, __IgnoreEls, [], - Text) -> - decode_sasl_response_cdata(__TopXMLNS, Text); -decode_sasl_response_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Text) -> - decode_sasl_response_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_sasl_response_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Text) -> - decode_sasl_response_els(__TopXMLNS, __IgnoreEls, _els, - Text). - -encode_sasl_response({sasl_response, Text}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - [], __TopXMLNS), - _els = encode_sasl_response_cdata(Text, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"response">>, _attrs, _els}. - -decode_sasl_response_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_sasl_response_cdata(__TopXMLNS, _val) -> - case catch base64:mime_decode(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_cdata_value, <<>>, <<"response">>, __TopXMLNS}}); - _res -> _res - end. - -encode_sasl_response_cdata(<<>>, _acc) -> _acc; -encode_sasl_response_cdata(_val, _acc) -> - [{xmlcdata, base64:encode(_val)} | _acc]. - -decode_sasl_challenge(__TopXMLNS, __IgnoreEls, - {xmlel, <<"challenge">>, _attrs, _els}) -> - Text = decode_sasl_challenge_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - {sasl_challenge, Text}. - -decode_sasl_challenge_els(__TopXMLNS, __IgnoreEls, [], - Text) -> - decode_sasl_challenge_cdata(__TopXMLNS, Text); -decode_sasl_challenge_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Text) -> - decode_sasl_challenge_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_sasl_challenge_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Text) -> - decode_sasl_challenge_els(__TopXMLNS, __IgnoreEls, _els, - Text). - -encode_sasl_challenge({sasl_challenge, Text}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - [], __TopXMLNS), - _els = encode_sasl_challenge_cdata(Text, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"challenge">>, _attrs, _els}. - -decode_sasl_challenge_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_sasl_challenge_cdata(__TopXMLNS, _val) -> - case catch base64:mime_decode(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_cdata_value, <<>>, <<"challenge">>, __TopXMLNS}}); - _res -> _res - end. - -encode_sasl_challenge_cdata(<<>>, _acc) -> _acc; -encode_sasl_challenge_cdata(_val, _acc) -> - [{xmlcdata, base64:encode(_val)} | _acc]. - -decode_sasl_abort(__TopXMLNS, __IgnoreEls, - {xmlel, <<"abort">>, _attrs, _els}) -> - {sasl_abort}. - -encode_sasl_abort({sasl_abort}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"abort">>, _attrs, _els}. - -decode_sasl_auth(__TopXMLNS, __IgnoreEls, - {xmlel, <<"auth">>, _attrs, _els}) -> - Text = decode_sasl_auth_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Mechanism = decode_sasl_auth_attrs(__TopXMLNS, _attrs, - undefined), - {sasl_auth, Mechanism, Text}. - -decode_sasl_auth_els(__TopXMLNS, __IgnoreEls, [], - Text) -> - decode_sasl_auth_cdata(__TopXMLNS, Text); -decode_sasl_auth_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Text) -> - decode_sasl_auth_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_sasl_auth_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Text) -> - decode_sasl_auth_els(__TopXMLNS, __IgnoreEls, _els, - Text). - -decode_sasl_auth_attrs(__TopXMLNS, - [{<<"mechanism">>, _val} | _attrs], _Mechanism) -> - decode_sasl_auth_attrs(__TopXMLNS, _attrs, _val); -decode_sasl_auth_attrs(__TopXMLNS, [_ | _attrs], - Mechanism) -> - decode_sasl_auth_attrs(__TopXMLNS, _attrs, Mechanism); -decode_sasl_auth_attrs(__TopXMLNS, [], Mechanism) -> - decode_sasl_auth_attr_mechanism(__TopXMLNS, Mechanism). - -encode_sasl_auth({sasl_auth, Mechanism, Text}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-sasl">>, - [], __TopXMLNS), - _els = encode_sasl_auth_cdata(Text, []), - _attrs = encode_sasl_auth_attr_mechanism(Mechanism, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"auth">>, _attrs, _els}. - -decode_sasl_auth_attr_mechanism(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"mechanism">>, <<"auth">>, - __TopXMLNS}}); -decode_sasl_auth_attr_mechanism(__TopXMLNS, _val) -> - _val. - -encode_sasl_auth_attr_mechanism(_val, _acc) -> - [{<<"mechanism">>, _val} | _acc]. - -decode_sasl_auth_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_sasl_auth_cdata(__TopXMLNS, _val) -> - case catch base64:mime_decode(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_cdata_value, <<>>, <<"auth">>, __TopXMLNS}}); - _res -> _res - end. - -encode_sasl_auth_cdata(<<>>, _acc) -> _acc; -encode_sasl_auth_cdata(_val, _acc) -> - [{xmlcdata, base64:encode(_val)} | _acc]. - -decode_legacy_auth(__TopXMLNS, __IgnoreEls, - {xmlel, <<"query">>, _attrs, _els}) -> - {Digest, Password, Resource, Username} = - decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, - undefined, undefined, undefined, undefined), - {legacy_auth, Username, Password, Digest, Resource}. - -decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, [], - Digest, Password, Resource, Username) -> - {Digest, Password, Resource, Username}; -decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"username">>, _attrs, _} = _el | _els], - Digest, Password, Resource, Username) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:auth">> -> - decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, - Digest, Password, Resource, - decode_legacy_auth_username(__TopXMLNS, - __IgnoreEls, _el)); - <<"jabber:iq:auth">> -> - decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, - Digest, Password, Resource, - decode_legacy_auth_username(<<"jabber:iq:auth">>, - __IgnoreEls, _el)); - _ -> - decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, - Digest, Password, Resource, Username) - end; -decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"password">>, _attrs, _} = _el | _els], - Digest, Password, Resource, Username) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:auth">> -> - decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, - Digest, - decode_legacy_auth_password(__TopXMLNS, - __IgnoreEls, _el), - Resource, Username); - <<"jabber:iq:auth">> -> - decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, - Digest, - decode_legacy_auth_password(<<"jabber:iq:auth">>, - __IgnoreEls, _el), - Resource, Username); - _ -> - decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, - Digest, Password, Resource, Username) - end; -decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"digest">>, _attrs, _} = _el | _els], Digest, - Password, Resource, Username) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:auth">> -> - decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, - decode_legacy_auth_digest(__TopXMLNS, - __IgnoreEls, _el), - Password, Resource, Username); - <<"jabber:iq:auth">> -> - decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, - decode_legacy_auth_digest(<<"jabber:iq:auth">>, - __IgnoreEls, _el), - Password, Resource, Username); - _ -> - decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, - Digest, Password, Resource, Username) - end; -decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"resource">>, _attrs, _} = _el | _els], - Digest, Password, Resource, Username) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:auth">> -> - decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, - Digest, Password, - decode_legacy_auth_resource(__TopXMLNS, - __IgnoreEls, _el), - Username); - <<"jabber:iq:auth">> -> - decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, - Digest, Password, - decode_legacy_auth_resource(<<"jabber:iq:auth">>, - __IgnoreEls, _el), - Username); - _ -> - decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, - Digest, Password, Resource, Username) - end; -decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Digest, Password, Resource, Username) -> - decode_legacy_auth_els(__TopXMLNS, __IgnoreEls, _els, - Digest, Password, Resource, Username). - -encode_legacy_auth({legacy_auth, Username, Password, - Digest, Resource}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:auth">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_legacy_auth_$digest'(Digest, - __NewTopXMLNS, - 'encode_legacy_auth_$password'(Password, - __NewTopXMLNS, - 'encode_legacy_auth_$resource'(Resource, - __NewTopXMLNS, - 'encode_legacy_auth_$username'(Username, - __NewTopXMLNS, - []))))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"query">>, _attrs, _els}. - -'encode_legacy_auth_$digest'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_legacy_auth_$digest'(Digest, __TopXMLNS, - _acc) -> - [encode_legacy_auth_digest(Digest, __TopXMLNS) | _acc]. - -'encode_legacy_auth_$password'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_legacy_auth_$password'(Password, __TopXMLNS, - _acc) -> - [encode_legacy_auth_password(Password, __TopXMLNS) - | _acc]. - -'encode_legacy_auth_$resource'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_legacy_auth_$resource'(Resource, __TopXMLNS, - _acc) -> - [encode_legacy_auth_resource(Resource, __TopXMLNS) - | _acc]. - -'encode_legacy_auth_$username'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_legacy_auth_$username'(Username, __TopXMLNS, - _acc) -> - [encode_legacy_auth_username(Username, __TopXMLNS) - | _acc]. - -decode_legacy_auth_resource(__TopXMLNS, __IgnoreEls, - {xmlel, <<"resource">>, _attrs, _els}) -> - Cdata = decode_legacy_auth_resource_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_legacy_auth_resource_els(__TopXMLNS, __IgnoreEls, - [], Cdata) -> - decode_legacy_auth_resource_cdata(__TopXMLNS, Cdata); -decode_legacy_auth_resource_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_legacy_auth_resource_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_legacy_auth_resource_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_legacy_auth_resource_els(__TopXMLNS, __IgnoreEls, - _els, Cdata). - -encode_legacy_auth_resource(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:auth">>, - [], __TopXMLNS), - _els = encode_legacy_auth_resource_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"resource">>, _attrs, _els}. - -decode_legacy_auth_resource_cdata(__TopXMLNS, <<>>) -> - <<>>; -decode_legacy_auth_resource_cdata(__TopXMLNS, _val) -> - _val. - -encode_legacy_auth_resource_cdata(<<>>, _acc) -> _acc; -encode_legacy_auth_resource_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_legacy_auth_digest(__TopXMLNS, __IgnoreEls, - {xmlel, <<"digest">>, _attrs, _els}) -> - Cdata = decode_legacy_auth_digest_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_legacy_auth_digest_els(__TopXMLNS, __IgnoreEls, - [], Cdata) -> - decode_legacy_auth_digest_cdata(__TopXMLNS, Cdata); -decode_legacy_auth_digest_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_legacy_auth_digest_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_legacy_auth_digest_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_legacy_auth_digest_els(__TopXMLNS, __IgnoreEls, - _els, Cdata). - -encode_legacy_auth_digest(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:auth">>, - [], __TopXMLNS), - _els = encode_legacy_auth_digest_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"digest">>, _attrs, _els}. - -decode_legacy_auth_digest_cdata(__TopXMLNS, <<>>) -> - <<>>; -decode_legacy_auth_digest_cdata(__TopXMLNS, _val) -> - _val. - -encode_legacy_auth_digest_cdata(<<>>, _acc) -> _acc; -encode_legacy_auth_digest_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_legacy_auth_password(__TopXMLNS, __IgnoreEls, - {xmlel, <<"password">>, _attrs, _els}) -> - Cdata = decode_legacy_auth_password_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_legacy_auth_password_els(__TopXMLNS, __IgnoreEls, - [], Cdata) -> - decode_legacy_auth_password_cdata(__TopXMLNS, Cdata); -decode_legacy_auth_password_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_legacy_auth_password_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_legacy_auth_password_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_legacy_auth_password_els(__TopXMLNS, __IgnoreEls, - _els, Cdata). - -encode_legacy_auth_password(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:auth">>, - [], __TopXMLNS), - _els = encode_legacy_auth_password_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"password">>, _attrs, _els}. - -decode_legacy_auth_password_cdata(__TopXMLNS, <<>>) -> - <<>>; -decode_legacy_auth_password_cdata(__TopXMLNS, _val) -> - _val. - -encode_legacy_auth_password_cdata(<<>>, _acc) -> _acc; -encode_legacy_auth_password_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_legacy_auth_username(__TopXMLNS, __IgnoreEls, - {xmlel, <<"username">>, _attrs, _els}) -> - Cdata = decode_legacy_auth_username_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_legacy_auth_username_els(__TopXMLNS, __IgnoreEls, - [], Cdata) -> - decode_legacy_auth_username_cdata(__TopXMLNS, Cdata); -decode_legacy_auth_username_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_legacy_auth_username_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_legacy_auth_username_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_legacy_auth_username_els(__TopXMLNS, __IgnoreEls, - _els, Cdata). - -encode_legacy_auth_username(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:auth">>, - [], __TopXMLNS), - _els = encode_legacy_auth_username_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"username">>, _attrs, _els}. - -decode_legacy_auth_username_cdata(__TopXMLNS, <<>>) -> - <<>>; -decode_legacy_auth_username_cdata(__TopXMLNS, _val) -> - _val. - -encode_legacy_auth_username_cdata(<<>>, _acc) -> _acc; -encode_legacy_auth_username_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_bind(__TopXMLNS, __IgnoreEls, - {xmlel, <<"bind">>, _attrs, _els}) -> - {Jid, Resource} = decode_bind_els(__TopXMLNS, - __IgnoreEls, _els, undefined, <<>>), - {bind, Jid, Resource}. - -decode_bind_els(__TopXMLNS, __IgnoreEls, [], Jid, - Resource) -> - {Jid, Resource}; -decode_bind_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"jid">>, _attrs, _} = _el | _els], Jid, - Resource) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"urn:ietf:params:xml:ns:xmpp-bind">> -> - decode_bind_els(__TopXMLNS, __IgnoreEls, _els, - decode_bind_jid(__TopXMLNS, __IgnoreEls, _el), - Resource); - <<"urn:ietf:params:xml:ns:xmpp-bind">> -> - decode_bind_els(__TopXMLNS, __IgnoreEls, _els, - decode_bind_jid(<<"urn:ietf:params:xml:ns:xmpp-bind">>, - __IgnoreEls, _el), - Resource); - _ -> - decode_bind_els(__TopXMLNS, __IgnoreEls, _els, Jid, - Resource) - end; -decode_bind_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"resource">>, _attrs, _} = _el | _els], Jid, - Resource) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"urn:ietf:params:xml:ns:xmpp-bind">> -> - decode_bind_els(__TopXMLNS, __IgnoreEls, _els, Jid, - decode_bind_resource(__TopXMLNS, __IgnoreEls, _el)); - <<"urn:ietf:params:xml:ns:xmpp-bind">> -> - decode_bind_els(__TopXMLNS, __IgnoreEls, _els, Jid, - decode_bind_resource(<<"urn:ietf:params:xml:ns:xmpp-bind">>, - __IgnoreEls, _el)); - _ -> - decode_bind_els(__TopXMLNS, __IgnoreEls, _els, Jid, - Resource) - end; -decode_bind_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Jid, Resource) -> - decode_bind_els(__TopXMLNS, __IgnoreEls, _els, Jid, - Resource). - -encode_bind({bind, Jid, Resource}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-bind">>, - [], __TopXMLNS), - _els = lists:reverse('encode_bind_$jid'(Jid, - __NewTopXMLNS, - 'encode_bind_$resource'(Resource, - __NewTopXMLNS, - []))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"bind">>, _attrs, _els}. - -'encode_bind_$jid'(undefined, __TopXMLNS, _acc) -> _acc; -'encode_bind_$jid'(Jid, __TopXMLNS, _acc) -> - [encode_bind_jid(Jid, __TopXMLNS) | _acc]. - -'encode_bind_$resource'(<<>>, __TopXMLNS, _acc) -> _acc; -'encode_bind_$resource'(Resource, __TopXMLNS, _acc) -> - [encode_bind_resource(Resource, __TopXMLNS) | _acc]. - -decode_bind_resource(__TopXMLNS, __IgnoreEls, - {xmlel, <<"resource">>, _attrs, _els}) -> - Cdata = decode_bind_resource_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_bind_resource_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_bind_resource_cdata(__TopXMLNS, Cdata); -decode_bind_resource_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_bind_resource_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_bind_resource_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_bind_resource_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_bind_resource(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-bind">>, - [], __TopXMLNS), - _els = encode_bind_resource_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"resource">>, _attrs, _els}. - -decode_bind_resource_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_bind_resource_cdata(__TopXMLNS, _val) -> - case catch resourceprep(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_cdata_value, <<>>, <<"resource">>, __TopXMLNS}}); - _res -> _res - end. - -encode_bind_resource_cdata(<<>>, _acc) -> _acc; -encode_bind_resource_cdata(_val, _acc) -> - [{xmlcdata, resourceprep(_val)} | _acc]. - -decode_bind_jid(__TopXMLNS, __IgnoreEls, - {xmlel, <<"jid">>, _attrs, _els}) -> - Cdata = decode_bind_jid_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_bind_jid_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_bind_jid_cdata(__TopXMLNS, Cdata); -decode_bind_jid_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_bind_jid_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_bind_jid_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Cdata) -> - decode_bind_jid_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_bind_jid(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-bind">>, - [], __TopXMLNS), - _els = encode_bind_jid_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"jid">>, _attrs, _els}. - -decode_bind_jid_cdata(__TopXMLNS, <<>>) -> undefined; -decode_bind_jid_cdata(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_cdata_value, <<>>, <<"jid">>, __TopXMLNS}}); - _res -> _res - end. - -encode_bind_jid_cdata(undefined, _acc) -> _acc; -encode_bind_jid_cdata(_val, _acc) -> - [{xmlcdata, enc_jid(_val)} | _acc]. - -decode_error(__TopXMLNS, __IgnoreEls, - {xmlel, <<"error">>, _attrs, _els}) -> - {Text, Reason, __Els} = decode_error_els(__TopXMLNS, - __IgnoreEls, _els, undefined, - undefined, []), - {Type, Code, By} = decode_error_attrs(__TopXMLNS, - _attrs, undefined, undefined, - undefined), - {stanza_error, Type, Code, By, Reason, Text, __Els}. - -decode_error_els(__TopXMLNS, __IgnoreEls, [], Text, - Reason, __Els) -> - {Text, Reason, lists:reverse(__Els)}; -decode_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"text">>, _attrs, _} = _el | _els], Text, - Reason, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, - decode_error_text(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el), - Reason, __Els); - _ -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els) - end; -decode_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"bad-request">>, _attrs, _} = _el | _els], - Text, Reason, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_bad_request(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el), - __Els); - _ -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els) - end; -decode_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"conflict">>, _attrs, _} = _el | _els], Text, - Reason, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_conflict(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el), - __Els); - _ -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els) - end; -decode_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"feature-not-implemented">>, _attrs, _} = _el - | _els], - Text, Reason, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_feature_not_implemented(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, - _el), - __Els); - _ -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els) - end; -decode_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"forbidden">>, _attrs, _} = _el | _els], - Text, Reason, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_forbidden(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el), - __Els); - _ -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els) - end; -decode_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"gone">>, _attrs, _} = _el | _els], Text, - Reason, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_gone(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el), - __Els); - _ -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els) - end; -decode_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"internal-server-error">>, _attrs, _} = _el - | _els], - Text, Reason, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_internal_server_error(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el), - __Els); - _ -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els) - end; -decode_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"item-not-found">>, _attrs, _} = _el | _els], - Text, Reason, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_item_not_found(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el), - __Els); - _ -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els) - end; -decode_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"jid-malformed">>, _attrs, _} = _el | _els], - Text, Reason, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_jid_malformed(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el), - __Els); - _ -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els) - end; -decode_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"not-acceptable">>, _attrs, _} = _el | _els], - Text, Reason, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_not_acceptable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el), - __Els); - _ -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els) - end; -decode_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"not-allowed">>, _attrs, _} = _el | _els], - Text, Reason, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_not_allowed(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el), - __Els); - _ -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els) - end; -decode_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"not-authorized">>, _attrs, _} = _el | _els], - Text, Reason, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_not_authorized(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el), - __Els); - _ -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els) - end; -decode_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"payment-required">>, _attrs, _} = _el - | _els], - Text, Reason, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_payment_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el), - __Els); - _ -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els) - end; -decode_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"policy-violation">>, _attrs, _} = _el - | _els], - Text, Reason, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_policy_violation(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el), - __Els); - _ -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els) - end; -decode_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"recipient-unavailable">>, _attrs, _} = _el - | _els], - Text, Reason, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_recipient_unavailable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el), - __Els); - _ -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els) - end; -decode_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"redirect">>, _attrs, _} = _el | _els], Text, - Reason, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_redirect(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el), - __Els); - _ -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els) - end; -decode_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"registration-required">>, _attrs, _} = _el - | _els], - Text, Reason, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_registration_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el), - __Els); - _ -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els) - end; -decode_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"remote-server-not-found">>, _attrs, _} = _el - | _els], - Text, Reason, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_remote_server_not_found(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, - _el), - __Els); - _ -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els) - end; -decode_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"remote-server-timeout">>, _attrs, _} = _el - | _els], - Text, Reason, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_remote_server_timeout(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el), - __Els); - _ -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els) - end; -decode_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"resource-constraint">>, _attrs, _} = _el - | _els], - Text, Reason, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_resource_constraint(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el), - __Els); - _ -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els) - end; -decode_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"service-unavailable">>, _attrs, _} = _el - | _els], - Text, Reason, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_service_unavailable(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el), - __Els); - _ -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els) - end; -decode_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"subscription-required">>, _attrs, _} = _el - | _els], - Text, Reason, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_subscription_required(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el), - __Els); - _ -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els) - end; -decode_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"undefined-condition">>, _attrs, _} = _el - | _els], - Text, Reason, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_undefined_condition(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el), - __Els); - _ -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els) - end; -decode_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"unexpected-request">>, _attrs, _} = _el - | _els], - Text, Reason, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"urn:ietf:params:xml:ns:xmpp-stanzas">> -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - decode_error_unexpected_request(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - __IgnoreEls, _el), - __Els); - _ -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els) - end; -decode_error_els(__TopXMLNS, __IgnoreEls, - [{xmlel, _, _, _} = _el | _els], Text, Reason, __Els) -> - if __IgnoreEls -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, [_el | __Els]); - true -> - case is_known_tag(_el, __TopXMLNS) of - true -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, - [decode(_el, __TopXMLNS, []) | __Els]); - false -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els) - end - end; -decode_error_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Text, Reason, __Els) -> - decode_error_els(__TopXMLNS, __IgnoreEls, _els, Text, - Reason, __Els). - -decode_error_attrs(__TopXMLNS, - [{<<"type">>, _val} | _attrs], _Type, Code, By) -> - decode_error_attrs(__TopXMLNS, _attrs, _val, Code, By); -decode_error_attrs(__TopXMLNS, - [{<<"code">>, _val} | _attrs], Type, _Code, By) -> - decode_error_attrs(__TopXMLNS, _attrs, Type, _val, By); -decode_error_attrs(__TopXMLNS, - [{<<"by">>, _val} | _attrs], Type, Code, _By) -> - decode_error_attrs(__TopXMLNS, _attrs, Type, Code, - _val); -decode_error_attrs(__TopXMLNS, [_ | _attrs], Type, Code, - By) -> - decode_error_attrs(__TopXMLNS, _attrs, Type, Code, By); -decode_error_attrs(__TopXMLNS, [], Type, Code, By) -> - {decode_error_attr_type(__TopXMLNS, Type), - decode_error_attr_code(__TopXMLNS, Code), - decode_error_attr_by(__TopXMLNS, By)}. - -encode_error({stanza_error, Type, Code, By, Reason, - Text, __Els}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"jabber:client">>, <<"jabber:server">>, - <<"jabber:component:accept">>], - __TopXMLNS), - _els = [encode(_el, __NewTopXMLNS) || _el <- __Els] ++ - lists:reverse('encode_error_$text'(Text, __NewTopXMLNS, - 'encode_error_$reason'(Reason, - __NewTopXMLNS, - []))), - _attrs = encode_error_attr_by(By, - encode_error_attr_code(Code, - encode_error_attr_type(Type, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)))), - {xmlel, <<"error">>, _attrs, _els}. - -'encode_error_$text'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_error_$text'(Text, __TopXMLNS, _acc) -> - [encode_error_text(Text, __TopXMLNS) | _acc]. - -'encode_error_$reason'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_error_$reason'('bad-request' = Reason, - __TopXMLNS, _acc) -> - [encode_error_bad_request(Reason, __TopXMLNS) | _acc]; -'encode_error_$reason'(conflict = Reason, __TopXMLNS, - _acc) -> - [encode_error_conflict(Reason, __TopXMLNS) | _acc]; -'encode_error_$reason'('feature-not-implemented' = - Reason, - __TopXMLNS, _acc) -> - [encode_error_feature_not_implemented(Reason, - __TopXMLNS) - | _acc]; -'encode_error_$reason'(forbidden = Reason, __TopXMLNS, - _acc) -> - [encode_error_forbidden(Reason, __TopXMLNS) | _acc]; -'encode_error_$reason'({gone, _} = Reason, __TopXMLNS, - _acc) -> - [encode_error_gone(Reason, __TopXMLNS) | _acc]; -'encode_error_$reason'('internal-server-error' = Reason, - __TopXMLNS, _acc) -> - [encode_error_internal_server_error(Reason, __TopXMLNS) - | _acc]; -'encode_error_$reason'('item-not-found' = Reason, - __TopXMLNS, _acc) -> - [encode_error_item_not_found(Reason, __TopXMLNS) - | _acc]; -'encode_error_$reason'('jid-malformed' = Reason, - __TopXMLNS, _acc) -> - [encode_error_jid_malformed(Reason, __TopXMLNS) | _acc]; -'encode_error_$reason'('not-acceptable' = Reason, - __TopXMLNS, _acc) -> - [encode_error_not_acceptable(Reason, __TopXMLNS) - | _acc]; -'encode_error_$reason'('not-allowed' = Reason, - __TopXMLNS, _acc) -> - [encode_error_not_allowed(Reason, __TopXMLNS) | _acc]; -'encode_error_$reason'('not-authorized' = Reason, - __TopXMLNS, _acc) -> - [encode_error_not_authorized(Reason, __TopXMLNS) - | _acc]; -'encode_error_$reason'('payment-required' = Reason, - __TopXMLNS, _acc) -> - [encode_error_payment_required(Reason, __TopXMLNS) - | _acc]; -'encode_error_$reason'('policy-violation' = Reason, - __TopXMLNS, _acc) -> - [encode_error_policy_violation(Reason, __TopXMLNS) - | _acc]; -'encode_error_$reason'('recipient-unavailable' = Reason, - __TopXMLNS, _acc) -> - [encode_error_recipient_unavailable(Reason, __TopXMLNS) - | _acc]; -'encode_error_$reason'({redirect, _} = Reason, - __TopXMLNS, _acc) -> - [encode_error_redirect(Reason, __TopXMLNS) | _acc]; -'encode_error_$reason'('registration-required' = Reason, - __TopXMLNS, _acc) -> - [encode_error_registration_required(Reason, __TopXMLNS) - | _acc]; -'encode_error_$reason'('remote-server-not-found' = - Reason, - __TopXMLNS, _acc) -> - [encode_error_remote_server_not_found(Reason, - __TopXMLNS) - | _acc]; -'encode_error_$reason'('remote-server-timeout' = Reason, - __TopXMLNS, _acc) -> - [encode_error_remote_server_timeout(Reason, __TopXMLNS) - | _acc]; -'encode_error_$reason'('resource-constraint' = Reason, - __TopXMLNS, _acc) -> - [encode_error_resource_constraint(Reason, __TopXMLNS) - | _acc]; -'encode_error_$reason'('service-unavailable' = Reason, - __TopXMLNS, _acc) -> - [encode_error_service_unavailable(Reason, __TopXMLNS) - | _acc]; -'encode_error_$reason'('subscription-required' = Reason, - __TopXMLNS, _acc) -> - [encode_error_subscription_required(Reason, __TopXMLNS) - | _acc]; -'encode_error_$reason'('undefined-condition' = Reason, - __TopXMLNS, _acc) -> - [encode_error_undefined_condition(Reason, __TopXMLNS) - | _acc]; -'encode_error_$reason'('unexpected-request' = Reason, - __TopXMLNS, _acc) -> - [encode_error_unexpected_request(Reason, __TopXMLNS) - | _acc]. - -decode_error_attr_type(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"type">>, <<"error">>, __TopXMLNS}}); -decode_error_attr_type(__TopXMLNS, _val) -> - case catch dec_enum(_val, - [auth, cancel, continue, modify, wait]) - of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"type">>, <<"error">>, __TopXMLNS}}); - _res -> _res - end. - -encode_error_attr_type(_val, _acc) -> - [{<<"type">>, enc_enum(_val)} | _acc]. - -decode_error_attr_code(__TopXMLNS, undefined) -> - undefined; -decode_error_attr_code(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, infinity) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"code">>, <<"error">>, __TopXMLNS}}); - _res -> _res - end. - -encode_error_attr_code(undefined, _acc) -> _acc; -encode_error_attr_code(_val, _acc) -> - [{<<"code">>, enc_int(_val)} | _acc]. - -decode_error_attr_by(__TopXMLNS, undefined) -> <<>>; -decode_error_attr_by(__TopXMLNS, _val) -> _val. - -encode_error_attr_by(<<>>, _acc) -> _acc; -encode_error_attr_by(_val, _acc) -> - [{<<"by">>, _val} | _acc]. - -decode_error_text(__TopXMLNS, __IgnoreEls, - {xmlel, <<"text">>, _attrs, _els}) -> - Data = decode_error_text_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Lang = decode_error_text_attrs(__TopXMLNS, _attrs, - undefined), - {text, Lang, Data}. - -decode_error_text_els(__TopXMLNS, __IgnoreEls, [], - Data) -> - decode_error_text_cdata(__TopXMLNS, Data); -decode_error_text_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Data) -> - decode_error_text_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_error_text_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Data) -> - decode_error_text_els(__TopXMLNS, __IgnoreEls, _els, - Data). - -decode_error_text_attrs(__TopXMLNS, - [{<<"xml:lang">>, _val} | _attrs], _Lang) -> - decode_error_text_attrs(__TopXMLNS, _attrs, _val); -decode_error_text_attrs(__TopXMLNS, [_ | _attrs], - Lang) -> - decode_error_text_attrs(__TopXMLNS, _attrs, Lang); -decode_error_text_attrs(__TopXMLNS, [], Lang) -> - 'decode_error_text_attr_xml:lang'(__TopXMLNS, Lang). - -encode_error_text({text, Lang, Data}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - [], __TopXMLNS), - _els = encode_error_text_cdata(Data, []), - _attrs = 'encode_error_text_attr_xml:lang'(Lang, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"text">>, _attrs, _els}. - -'decode_error_text_attr_xml:lang'(__TopXMLNS, - undefined) -> - <<>>; -'decode_error_text_attr_xml:lang'(__TopXMLNS, _val) -> - _val. - -'encode_error_text_attr_xml:lang'(<<>>, _acc) -> _acc; -'encode_error_text_attr_xml:lang'(_val, _acc) -> - [{<<"xml:lang">>, _val} | _acc]. - -decode_error_text_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_error_text_cdata(__TopXMLNS, _val) -> _val. - -encode_error_text_cdata(<<>>, _acc) -> _acc; -encode_error_text_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_error_unexpected_request(__TopXMLNS, __IgnoreEls, - {xmlel, <<"unexpected-request">>, _attrs, - _els}) -> - 'unexpected-request'. - -encode_error_unexpected_request('unexpected-request', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"unexpected-request">>, _attrs, _els}. - -decode_error_undefined_condition(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"undefined-condition">>, _attrs, - _els}) -> - 'undefined-condition'. - -encode_error_undefined_condition('undefined-condition', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"undefined-condition">>, _attrs, _els}. - -decode_error_subscription_required(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"subscription-required">>, _attrs, - _els}) -> - 'subscription-required'. - -encode_error_subscription_required('subscription-required', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"subscription-required">>, _attrs, _els}. - -decode_error_service_unavailable(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"service-unavailable">>, _attrs, - _els}) -> - 'service-unavailable'. - -encode_error_service_unavailable('service-unavailable', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"service-unavailable">>, _attrs, _els}. - -decode_error_resource_constraint(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"resource-constraint">>, _attrs, - _els}) -> - 'resource-constraint'. - -encode_error_resource_constraint('resource-constraint', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"resource-constraint">>, _attrs, _els}. - -decode_error_remote_server_timeout(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"remote-server-timeout">>, _attrs, - _els}) -> - 'remote-server-timeout'. - -encode_error_remote_server_timeout('remote-server-timeout', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"remote-server-timeout">>, _attrs, _els}. - -decode_error_remote_server_not_found(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"remote-server-not-found">>, - _attrs, _els}) -> - 'remote-server-not-found'. - -encode_error_remote_server_not_found('remote-server-not-found', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"remote-server-not-found">>, _attrs, _els}. - -decode_error_registration_required(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"registration-required">>, _attrs, - _els}) -> - 'registration-required'. - -encode_error_registration_required('registration-required', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"registration-required">>, _attrs, _els}. - -decode_error_redirect(__TopXMLNS, __IgnoreEls, - {xmlel, <<"redirect">>, _attrs, _els}) -> - Uri = decode_error_redirect_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - {redirect, Uri}. - -decode_error_redirect_els(__TopXMLNS, __IgnoreEls, [], - Uri) -> - decode_error_redirect_cdata(__TopXMLNS, Uri); -decode_error_redirect_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Uri) -> - decode_error_redirect_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_error_redirect_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Uri) -> - decode_error_redirect_els(__TopXMLNS, __IgnoreEls, _els, - Uri). - -encode_error_redirect({redirect, Uri}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - [], __TopXMLNS), - _els = encode_error_redirect_cdata(Uri, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"redirect">>, _attrs, _els}. - -decode_error_redirect_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_error_redirect_cdata(__TopXMLNS, _val) -> _val. - -encode_error_redirect_cdata(<<>>, _acc) -> _acc; -encode_error_redirect_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_error_recipient_unavailable(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"recipient-unavailable">>, _attrs, - _els}) -> - 'recipient-unavailable'. - -encode_error_recipient_unavailable('recipient-unavailable', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"recipient-unavailable">>, _attrs, _els}. - -decode_error_policy_violation(__TopXMLNS, __IgnoreEls, - {xmlel, <<"policy-violation">>, _attrs, _els}) -> - 'policy-violation'. - -encode_error_policy_violation('policy-violation', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"policy-violation">>, _attrs, _els}. - -decode_error_payment_required(__TopXMLNS, __IgnoreEls, - {xmlel, <<"payment-required">>, _attrs, _els}) -> - 'payment-required'. - -encode_error_payment_required('payment-required', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"payment-required">>, _attrs, _els}. - -decode_error_not_authorized(__TopXMLNS, __IgnoreEls, - {xmlel, <<"not-authorized">>, _attrs, _els}) -> - 'not-authorized'. - -encode_error_not_authorized('not-authorized', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"not-authorized">>, _attrs, _els}. - -decode_error_not_allowed(__TopXMLNS, __IgnoreEls, - {xmlel, <<"not-allowed">>, _attrs, _els}) -> - 'not-allowed'. - -encode_error_not_allowed('not-allowed', __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"not-allowed">>, _attrs, _els}. - -decode_error_not_acceptable(__TopXMLNS, __IgnoreEls, - {xmlel, <<"not-acceptable">>, _attrs, _els}) -> - 'not-acceptable'. - -encode_error_not_acceptable('not-acceptable', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"not-acceptable">>, _attrs, _els}. - -decode_error_jid_malformed(__TopXMLNS, __IgnoreEls, - {xmlel, <<"jid-malformed">>, _attrs, _els}) -> - 'jid-malformed'. - -encode_error_jid_malformed('jid-malformed', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"jid-malformed">>, _attrs, _els}. - -decode_error_item_not_found(__TopXMLNS, __IgnoreEls, - {xmlel, <<"item-not-found">>, _attrs, _els}) -> - 'item-not-found'. - -encode_error_item_not_found('item-not-found', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"item-not-found">>, _attrs, _els}. - -decode_error_internal_server_error(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"internal-server-error">>, _attrs, - _els}) -> - 'internal-server-error'. - -encode_error_internal_server_error('internal-server-error', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"internal-server-error">>, _attrs, _els}. - -decode_error_gone(__TopXMLNS, __IgnoreEls, - {xmlel, <<"gone">>, _attrs, _els}) -> - Uri = decode_error_gone_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - {gone, Uri}. - -decode_error_gone_els(__TopXMLNS, __IgnoreEls, [], - Uri) -> - decode_error_gone_cdata(__TopXMLNS, Uri); -decode_error_gone_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Uri) -> - decode_error_gone_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_error_gone_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Uri) -> - decode_error_gone_els(__TopXMLNS, __IgnoreEls, _els, - Uri). - -encode_error_gone({gone, Uri}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - [], __TopXMLNS), - _els = encode_error_gone_cdata(Uri, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"gone">>, _attrs, _els}. - -decode_error_gone_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_error_gone_cdata(__TopXMLNS, _val) -> _val. - -encode_error_gone_cdata(<<>>, _acc) -> _acc; -encode_error_gone_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_error_forbidden(__TopXMLNS, __IgnoreEls, - {xmlel, <<"forbidden">>, _attrs, _els}) -> - forbidden. - -encode_error_forbidden(forbidden, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"forbidden">>, _attrs, _els}. - -decode_error_feature_not_implemented(__TopXMLNS, - __IgnoreEls, - {xmlel, <<"feature-not-implemented">>, - _attrs, _els}) -> - 'feature-not-implemented'. - -encode_error_feature_not_implemented('feature-not-implemented', - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"feature-not-implemented">>, _attrs, _els}. - -decode_error_conflict(__TopXMLNS, __IgnoreEls, - {xmlel, <<"conflict">>, _attrs, _els}) -> - conflict. - -encode_error_conflict(conflict, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"conflict">>, _attrs, _els}. - -decode_error_bad_request(__TopXMLNS, __IgnoreEls, - {xmlel, <<"bad-request">>, _attrs, _els}) -> - 'bad-request'. - -encode_error_bad_request('bad-request', __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:ietf:params:xml:ns:xmpp-stanzas">>, - [], __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"bad-request">>, _attrs, _els}. - -decode_presence(__TopXMLNS, __IgnoreEls, - {xmlel, <<"presence">>, _attrs, _els}) -> - {Status, Show, Priority, __Els} = - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, [], - undefined, undefined, []), - {Id, Type, From, To, Lang} = - decode_presence_attrs(__TopXMLNS, _attrs, undefined, - undefined, undefined, undefined, undefined), - {presence, Id, Type, Lang, From, To, Show, Status, - Priority, __Els}. - -decode_presence_els(__TopXMLNS, __IgnoreEls, [], Status, - Show, Priority, __Els) -> - {lists:reverse(Status), Show, Priority, - lists:reverse(__Els)}; -decode_presence_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"show">>, _attrs, _} = _el | _els], Status, - Show, Priority, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == <<"jabber:server">>; - __TopXMLNS == <<"jabber:component:accept">>; - __TopXMLNS == <<"jabber:client">> -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - Status, - decode_presence_show(__TopXMLNS, __IgnoreEls, - _el), - Priority, __Els); - <<"jabber:client">> -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - Status, - decode_presence_show(<<"jabber:client">>, - __IgnoreEls, _el), - Priority, __Els); - <<"jabber:server">> -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - Status, - decode_presence_show(<<"jabber:server">>, - __IgnoreEls, _el), - Priority, __Els); - <<"jabber:component:accept">> -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - Status, - decode_presence_show(<<"jabber:component:accept">>, - __IgnoreEls, _el), - Priority, __Els); - _ -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - Status, Show, Priority, __Els) - end; -decode_presence_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"status">>, _attrs, _} = _el | _els], Status, - Show, Priority, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == <<"jabber:server">>; - __TopXMLNS == <<"jabber:component:accept">>; - __TopXMLNS == <<"jabber:client">> -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - [decode_presence_status(__TopXMLNS, __IgnoreEls, - _el) - | Status], - Show, Priority, __Els); - <<"jabber:client">> -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - [decode_presence_status(<<"jabber:client">>, - __IgnoreEls, _el) - | Status], - Show, Priority, __Els); - <<"jabber:server">> -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - [decode_presence_status(<<"jabber:server">>, - __IgnoreEls, _el) - | Status], - Show, Priority, __Els); - <<"jabber:component:accept">> -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - [decode_presence_status(<<"jabber:component:accept">>, - __IgnoreEls, _el) - | Status], - Show, Priority, __Els); - _ -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - Status, Show, Priority, __Els) - end; -decode_presence_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"priority">>, _attrs, _} = _el | _els], - Status, Show, Priority, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == <<"jabber:server">>; - __TopXMLNS == <<"jabber:component:accept">>; - __TopXMLNS == <<"jabber:client">> -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - Status, Show, - decode_presence_priority(__TopXMLNS, __IgnoreEls, - _el), - __Els); - <<"jabber:client">> -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - Status, Show, - decode_presence_priority(<<"jabber:client">>, - __IgnoreEls, _el), - __Els); - <<"jabber:server">> -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - Status, Show, - decode_presence_priority(<<"jabber:server">>, - __IgnoreEls, _el), - __Els); - <<"jabber:component:accept">> -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - Status, Show, - decode_presence_priority(<<"jabber:component:accept">>, - __IgnoreEls, _el), - __Els); - _ -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - Status, Show, Priority, __Els) - end; -decode_presence_els(__TopXMLNS, __IgnoreEls, - [{xmlel, _, _, _} = _el | _els], Status, Show, Priority, - __Els) -> - if __IgnoreEls -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - Status, Show, Priority, [_el | __Els]); - true -> - case is_known_tag(_el, __TopXMLNS) of - true -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - Status, Show, Priority, - [decode(_el, __TopXMLNS, []) | __Els]); - false -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - Status, Show, Priority, __Els) - end - end; -decode_presence_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Status, Show, Priority, __Els) -> - decode_presence_els(__TopXMLNS, __IgnoreEls, _els, - Status, Show, Priority, __Els). - -decode_presence_attrs(__TopXMLNS, - [{<<"id">>, _val} | _attrs], _Id, Type, From, To, - Lang) -> - decode_presence_attrs(__TopXMLNS, _attrs, _val, Type, - From, To, Lang); -decode_presence_attrs(__TopXMLNS, - [{<<"type">>, _val} | _attrs], Id, _Type, From, To, - Lang) -> - decode_presence_attrs(__TopXMLNS, _attrs, Id, _val, - From, To, Lang); -decode_presence_attrs(__TopXMLNS, - [{<<"from">>, _val} | _attrs], Id, Type, _From, To, - Lang) -> - decode_presence_attrs(__TopXMLNS, _attrs, Id, Type, - _val, To, Lang); -decode_presence_attrs(__TopXMLNS, - [{<<"to">>, _val} | _attrs], Id, Type, From, _To, - Lang) -> - decode_presence_attrs(__TopXMLNS, _attrs, Id, Type, - From, _val, Lang); -decode_presence_attrs(__TopXMLNS, - [{<<"xml:lang">>, _val} | _attrs], Id, Type, From, To, - _Lang) -> - decode_presence_attrs(__TopXMLNS, _attrs, Id, Type, - From, To, _val); -decode_presence_attrs(__TopXMLNS, [_ | _attrs], Id, - Type, From, To, Lang) -> - decode_presence_attrs(__TopXMLNS, _attrs, Id, Type, - From, To, Lang); -decode_presence_attrs(__TopXMLNS, [], Id, Type, From, - To, Lang) -> - {decode_presence_attr_id(__TopXMLNS, Id), - decode_presence_attr_type(__TopXMLNS, Type), - decode_presence_attr_from(__TopXMLNS, From), - decode_presence_attr_to(__TopXMLNS, To), - 'decode_presence_attr_xml:lang'(__TopXMLNS, Lang)}. - -encode_presence({presence, Id, Type, Lang, From, To, - Show, Status, Priority, __Els}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"jabber:client">>, <<"jabber:server">>, - <<"jabber:component:accept">>], - __TopXMLNS), - _els = [encode(_el, __NewTopXMLNS) || _el <- __Els] ++ - lists:reverse('encode_presence_$status'(Status, - __NewTopXMLNS, - 'encode_presence_$show'(Show, - __NewTopXMLNS, - 'encode_presence_$priority'(Priority, - __NewTopXMLNS, - [])))), - _attrs = 'encode_presence_attr_xml:lang'(Lang, - encode_presence_attr_to(To, - encode_presence_attr_from(From, - encode_presence_attr_type(Type, - encode_presence_attr_id(Id, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)))))), - {xmlel, <<"presence">>, _attrs, _els}. - -'encode_presence_$status'([], __TopXMLNS, _acc) -> _acc; -'encode_presence_$status'([Status | _els], __TopXMLNS, - _acc) -> - 'encode_presence_$status'(_els, __TopXMLNS, - [encode_presence_status(Status, __TopXMLNS) - | _acc]). - -'encode_presence_$show'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_presence_$show'(Show, __TopXMLNS, _acc) -> - [encode_presence_show(Show, __TopXMLNS) | _acc]. - -'encode_presence_$priority'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_presence_$priority'(Priority, __TopXMLNS, - _acc) -> - [encode_presence_priority(Priority, __TopXMLNS) | _acc]. - -decode_presence_attr_id(__TopXMLNS, undefined) -> <<>>; -decode_presence_attr_id(__TopXMLNS, _val) -> _val. - -encode_presence_attr_id(<<>>, _acc) -> _acc; -encode_presence_attr_id(_val, _acc) -> - [{<<"id">>, _val} | _acc]. - -decode_presence_attr_type(__TopXMLNS, undefined) -> - available; -decode_presence_attr_type(__TopXMLNS, _val) -> - case catch dec_enum(_val, - [unavailable, subscribe, subscribed, unsubscribe, - unsubscribed, available, probe, error]) - of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"type">>, <<"presence">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_presence_attr_type(available, _acc) -> _acc; -encode_presence_attr_type(_val, _acc) -> - [{<<"type">>, enc_enum(_val)} | _acc]. - -decode_presence_attr_from(__TopXMLNS, undefined) -> - undefined; -decode_presence_attr_from(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"from">>, <<"presence">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_presence_attr_from(undefined, _acc) -> _acc; -encode_presence_attr_from(_val, _acc) -> - [{<<"from">>, enc_jid(_val)} | _acc]. - -decode_presence_attr_to(__TopXMLNS, undefined) -> - undefined; -decode_presence_attr_to(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"to">>, <<"presence">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_presence_attr_to(undefined, _acc) -> _acc; -encode_presence_attr_to(_val, _acc) -> - [{<<"to">>, enc_jid(_val)} | _acc]. - -'decode_presence_attr_xml:lang'(__TopXMLNS, - undefined) -> - <<>>; -'decode_presence_attr_xml:lang'(__TopXMLNS, _val) -> - _val. - -'encode_presence_attr_xml:lang'(<<>>, _acc) -> _acc; -'encode_presence_attr_xml:lang'(_val, _acc) -> - [{<<"xml:lang">>, _val} | _acc]. - -decode_presence_priority(__TopXMLNS, __IgnoreEls, - {xmlel, <<"priority">>, _attrs, _els}) -> - Cdata = decode_presence_priority_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_presence_priority_els(__TopXMLNS, __IgnoreEls, - [], Cdata) -> - decode_presence_priority_cdata(__TopXMLNS, Cdata); -decode_presence_priority_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_presence_priority_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_presence_priority_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_presence_priority_els(__TopXMLNS, __IgnoreEls, - _els, Cdata). - -encode_presence_priority(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"jabber:client">>, <<"jabber:server">>, - <<"jabber:component:accept">>], - __TopXMLNS), - _els = encode_presence_priority_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"priority">>, _attrs, _els}. - -decode_presence_priority_cdata(__TopXMLNS, <<>>) -> - undefined; -decode_presence_priority_cdata(__TopXMLNS, _val) -> - case catch dec_int(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_cdata_value, <<>>, <<"priority">>, __TopXMLNS}}); - _res -> _res - end. - -encode_presence_priority_cdata(undefined, _acc) -> _acc; -encode_presence_priority_cdata(_val, _acc) -> - [{xmlcdata, enc_int(_val)} | _acc]. - -decode_presence_status(__TopXMLNS, __IgnoreEls, - {xmlel, <<"status">>, _attrs, _els}) -> - Data = decode_presence_status_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Lang = decode_presence_status_attrs(__TopXMLNS, _attrs, - undefined), - {text, Lang, Data}. - -decode_presence_status_els(__TopXMLNS, __IgnoreEls, [], - Data) -> - decode_presence_status_cdata(__TopXMLNS, Data); -decode_presence_status_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Data) -> - decode_presence_status_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_presence_status_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Data) -> - decode_presence_status_els(__TopXMLNS, __IgnoreEls, - _els, Data). - -decode_presence_status_attrs(__TopXMLNS, - [{<<"xml:lang">>, _val} | _attrs], _Lang) -> - decode_presence_status_attrs(__TopXMLNS, _attrs, _val); -decode_presence_status_attrs(__TopXMLNS, [_ | _attrs], - Lang) -> - decode_presence_status_attrs(__TopXMLNS, _attrs, Lang); -decode_presence_status_attrs(__TopXMLNS, [], Lang) -> - 'decode_presence_status_attr_xml:lang'(__TopXMLNS, - Lang). - -encode_presence_status({text, Lang, Data}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"jabber:client">>, <<"jabber:server">>, - <<"jabber:component:accept">>], - __TopXMLNS), - _els = encode_presence_status_cdata(Data, []), - _attrs = 'encode_presence_status_attr_xml:lang'(Lang, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"status">>, _attrs, _els}. - -'decode_presence_status_attr_xml:lang'(__TopXMLNS, - undefined) -> - <<>>; -'decode_presence_status_attr_xml:lang'(__TopXMLNS, - _val) -> - _val. - -'encode_presence_status_attr_xml:lang'(<<>>, _acc) -> - _acc; -'encode_presence_status_attr_xml:lang'(_val, _acc) -> - [{<<"xml:lang">>, _val} | _acc]. - -decode_presence_status_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_presence_status_cdata(__TopXMLNS, _val) -> _val. - -encode_presence_status_cdata(<<>>, _acc) -> _acc; -encode_presence_status_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_presence_show(__TopXMLNS, __IgnoreEls, - {xmlel, <<"show">>, _attrs, _els}) -> - Cdata = decode_presence_show_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_presence_show_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_presence_show_cdata(__TopXMLNS, Cdata); -decode_presence_show_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_presence_show_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_presence_show_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_presence_show_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_presence_show(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"jabber:client">>, <<"jabber:server">>, - <<"jabber:component:accept">>], - __TopXMLNS), - _els = encode_presence_show_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"show">>, _attrs, _els}. - -decode_presence_show_cdata(__TopXMLNS, <<>>) -> - undefined; -decode_presence_show_cdata(__TopXMLNS, _val) -> - case catch dec_enum(_val, [away, chat, dnd, xa]) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_cdata_value, <<>>, <<"show">>, __TopXMLNS}}); - _res -> _res - end. - -encode_presence_show_cdata(undefined, _acc) -> _acc; -encode_presence_show_cdata(_val, _acc) -> - [{xmlcdata, enc_enum(_val)} | _acc]. - -decode_message(__TopXMLNS, __IgnoreEls, - {xmlel, <<"message">>, _attrs, _els}) -> - {Thread, Subject, Body, __Els} = - decode_message_els(__TopXMLNS, __IgnoreEls, _els, - undefined, [], [], []), - {Id, Type, From, To, Lang} = - decode_message_attrs(__TopXMLNS, _attrs, undefined, - undefined, undefined, undefined, undefined), - {message, Id, Type, Lang, From, To, Subject, Body, - Thread, __Els}. - -decode_message_els(__TopXMLNS, __IgnoreEls, [], Thread, - Subject, Body, __Els) -> - {Thread, lists:reverse(Subject), lists:reverse(Body), - lists:reverse(__Els)}; -decode_message_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"subject">>, _attrs, _} = _el | _els], - Thread, Subject, Body, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == <<"jabber:server">>; - __TopXMLNS == <<"jabber:component:accept">>; - __TopXMLNS == <<"jabber:client">> -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, - Thread, - [decode_message_subject(__TopXMLNS, __IgnoreEls, - _el) - | Subject], - Body, __Els); - <<"jabber:client">> -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, - Thread, - [decode_message_subject(<<"jabber:client">>, - __IgnoreEls, _el) - | Subject], - Body, __Els); - <<"jabber:server">> -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, - Thread, - [decode_message_subject(<<"jabber:server">>, - __IgnoreEls, _el) - | Subject], - Body, __Els); - <<"jabber:component:accept">> -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, - Thread, - [decode_message_subject(<<"jabber:component:accept">>, - __IgnoreEls, _el) - | Subject], - Body, __Els); - _ -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, - Thread, Subject, Body, __Els) - end; -decode_message_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"thread">>, _attrs, _} = _el | _els], Thread, - Subject, Body, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == <<"jabber:server">>; - __TopXMLNS == <<"jabber:component:accept">>; - __TopXMLNS == <<"jabber:client">> -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, - decode_message_thread(__TopXMLNS, __IgnoreEls, - _el), - Subject, Body, __Els); - <<"jabber:client">> -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, - decode_message_thread(<<"jabber:client">>, - __IgnoreEls, _el), - Subject, Body, __Els); - <<"jabber:server">> -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, - decode_message_thread(<<"jabber:server">>, - __IgnoreEls, _el), - Subject, Body, __Els); - <<"jabber:component:accept">> -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, - decode_message_thread(<<"jabber:component:accept">>, - __IgnoreEls, _el), - Subject, Body, __Els); - _ -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, - Thread, Subject, Body, __Els) - end; -decode_message_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"body">>, _attrs, _} = _el | _els], Thread, - Subject, Body, __Els) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == <<"jabber:server">>; - __TopXMLNS == <<"jabber:component:accept">>; - __TopXMLNS == <<"jabber:client">> -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, - Thread, Subject, - [decode_message_body(__TopXMLNS, __IgnoreEls, _el) - | Body], - __Els); - <<"jabber:client">> -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, - Thread, Subject, - [decode_message_body(<<"jabber:client">>, - __IgnoreEls, _el) - | Body], - __Els); - <<"jabber:server">> -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, - Thread, Subject, - [decode_message_body(<<"jabber:server">>, - __IgnoreEls, _el) - | Body], - __Els); - <<"jabber:component:accept">> -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, - Thread, Subject, - [decode_message_body(<<"jabber:component:accept">>, - __IgnoreEls, _el) - | Body], - __Els); - _ -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, - Thread, Subject, Body, __Els) - end; -decode_message_els(__TopXMLNS, __IgnoreEls, - [{xmlel, _, _, _} = _el | _els], Thread, Subject, Body, - __Els) -> - if __IgnoreEls -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, - Thread, Subject, Body, [_el | __Els]); - true -> - case is_known_tag(_el, __TopXMLNS) of - true -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, - Thread, Subject, Body, - [decode(_el, __TopXMLNS, []) | __Els]); - false -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, - Thread, Subject, Body, __Els) - end - end; -decode_message_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Thread, Subject, Body, __Els) -> - decode_message_els(__TopXMLNS, __IgnoreEls, _els, - Thread, Subject, Body, __Els). - -decode_message_attrs(__TopXMLNS, - [{<<"id">>, _val} | _attrs], _Id, Type, From, To, - Lang) -> - decode_message_attrs(__TopXMLNS, _attrs, _val, Type, - From, To, Lang); -decode_message_attrs(__TopXMLNS, - [{<<"type">>, _val} | _attrs], Id, _Type, From, To, - Lang) -> - decode_message_attrs(__TopXMLNS, _attrs, Id, _val, From, - To, Lang); -decode_message_attrs(__TopXMLNS, - [{<<"from">>, _val} | _attrs], Id, Type, _From, To, - Lang) -> - decode_message_attrs(__TopXMLNS, _attrs, Id, Type, _val, - To, Lang); -decode_message_attrs(__TopXMLNS, - [{<<"to">>, _val} | _attrs], Id, Type, From, _To, - Lang) -> - decode_message_attrs(__TopXMLNS, _attrs, Id, Type, From, - _val, Lang); -decode_message_attrs(__TopXMLNS, - [{<<"xml:lang">>, _val} | _attrs], Id, Type, From, To, - _Lang) -> - decode_message_attrs(__TopXMLNS, _attrs, Id, Type, From, - To, _val); -decode_message_attrs(__TopXMLNS, [_ | _attrs], Id, Type, - From, To, Lang) -> - decode_message_attrs(__TopXMLNS, _attrs, Id, Type, From, - To, Lang); -decode_message_attrs(__TopXMLNS, [], Id, Type, From, To, - Lang) -> - {decode_message_attr_id(__TopXMLNS, Id), - decode_message_attr_type(__TopXMLNS, Type), - decode_message_attr_from(__TopXMLNS, From), - decode_message_attr_to(__TopXMLNS, To), - 'decode_message_attr_xml:lang'(__TopXMLNS, Lang)}. - -encode_message({message, Id, Type, Lang, From, To, - Subject, Body, Thread, __Els}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"jabber:client">>, <<"jabber:server">>, - <<"jabber:component:accept">>], - __TopXMLNS), - _els = [encode(_el, __NewTopXMLNS) || _el <- __Els] ++ - lists:reverse('encode_message_$thread'(Thread, - __NewTopXMLNS, - 'encode_message_$subject'(Subject, - __NewTopXMLNS, - 'encode_message_$body'(Body, - __NewTopXMLNS, - [])))), - _attrs = 'encode_message_attr_xml:lang'(Lang, - encode_message_attr_to(To, - encode_message_attr_from(From, - encode_message_attr_type(Type, - encode_message_attr_id(Id, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)))))), - {xmlel, <<"message">>, _attrs, _els}. - -'encode_message_$thread'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_message_$thread'(Thread, __TopXMLNS, _acc) -> - [encode_message_thread(Thread, __TopXMLNS) | _acc]. - -'encode_message_$subject'([], __TopXMLNS, _acc) -> _acc; -'encode_message_$subject'([Subject | _els], __TopXMLNS, - _acc) -> - 'encode_message_$subject'(_els, __TopXMLNS, - [encode_message_subject(Subject, __TopXMLNS) - | _acc]). - -'encode_message_$body'([], __TopXMLNS, _acc) -> _acc; -'encode_message_$body'([Body | _els], __TopXMLNS, - _acc) -> - 'encode_message_$body'(_els, __TopXMLNS, - [encode_message_body(Body, __TopXMLNS) | _acc]). - -decode_message_attr_id(__TopXMLNS, undefined) -> <<>>; -decode_message_attr_id(__TopXMLNS, _val) -> _val. - -encode_message_attr_id(<<>>, _acc) -> _acc; -encode_message_attr_id(_val, _acc) -> - [{<<"id">>, _val} | _acc]. - -decode_message_attr_type(__TopXMLNS, undefined) -> - normal; -decode_message_attr_type(__TopXMLNS, _val) -> - case catch dec_enum(_val, - [chat, normal, groupchat, headline, error]) - of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"type">>, <<"message">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_message_attr_type(normal, _acc) -> _acc; -encode_message_attr_type(_val, _acc) -> - [{<<"type">>, enc_enum(_val)} | _acc]. - -decode_message_attr_from(__TopXMLNS, undefined) -> - undefined; -decode_message_attr_from(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"from">>, <<"message">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_message_attr_from(undefined, _acc) -> _acc; -encode_message_attr_from(_val, _acc) -> - [{<<"from">>, enc_jid(_val)} | _acc]. - -decode_message_attr_to(__TopXMLNS, undefined) -> - undefined; -decode_message_attr_to(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"to">>, <<"message">>, __TopXMLNS}}); - _res -> _res - end. - -encode_message_attr_to(undefined, _acc) -> _acc; -encode_message_attr_to(_val, _acc) -> - [{<<"to">>, enc_jid(_val)} | _acc]. - -'decode_message_attr_xml:lang'(__TopXMLNS, undefined) -> - <<>>; -'decode_message_attr_xml:lang'(__TopXMLNS, _val) -> - _val. - -'encode_message_attr_xml:lang'(<<>>, _acc) -> _acc; -'encode_message_attr_xml:lang'(_val, _acc) -> - [{<<"xml:lang">>, _val} | _acc]. - -decode_message_thread(__TopXMLNS, __IgnoreEls, - {xmlel, <<"thread">>, _attrs, _els}) -> - Cdata = decode_message_thread_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_message_thread_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_message_thread_cdata(__TopXMLNS, Cdata); -decode_message_thread_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_message_thread_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_message_thread_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_message_thread_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_message_thread(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"jabber:client">>, <<"jabber:server">>, - <<"jabber:component:accept">>], - __TopXMLNS), - _els = encode_message_thread_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"thread">>, _attrs, _els}. - -decode_message_thread_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_message_thread_cdata(__TopXMLNS, _val) -> _val. - -encode_message_thread_cdata(<<>>, _acc) -> _acc; -encode_message_thread_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_message_body(__TopXMLNS, __IgnoreEls, - {xmlel, <<"body">>, _attrs, _els}) -> - Data = decode_message_body_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Lang = decode_message_body_attrs(__TopXMLNS, _attrs, - undefined), - {text, Lang, Data}. - -decode_message_body_els(__TopXMLNS, __IgnoreEls, [], - Data) -> - decode_message_body_cdata(__TopXMLNS, Data); -decode_message_body_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Data) -> - decode_message_body_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_message_body_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Data) -> - decode_message_body_els(__TopXMLNS, __IgnoreEls, _els, - Data). - -decode_message_body_attrs(__TopXMLNS, - [{<<"xml:lang">>, _val} | _attrs], _Lang) -> - decode_message_body_attrs(__TopXMLNS, _attrs, _val); -decode_message_body_attrs(__TopXMLNS, [_ | _attrs], - Lang) -> - decode_message_body_attrs(__TopXMLNS, _attrs, Lang); -decode_message_body_attrs(__TopXMLNS, [], Lang) -> - 'decode_message_body_attr_xml:lang'(__TopXMLNS, Lang). - -encode_message_body({text, Lang, Data}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"jabber:client">>, <<"jabber:server">>, - <<"jabber:component:accept">>], - __TopXMLNS), - _els = encode_message_body_cdata(Data, []), - _attrs = 'encode_message_body_attr_xml:lang'(Lang, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"body">>, _attrs, _els}. - -'decode_message_body_attr_xml:lang'(__TopXMLNS, - undefined) -> - <<>>; -'decode_message_body_attr_xml:lang'(__TopXMLNS, _val) -> - _val. - -'encode_message_body_attr_xml:lang'(<<>>, _acc) -> _acc; -'encode_message_body_attr_xml:lang'(_val, _acc) -> - [{<<"xml:lang">>, _val} | _acc]. - -decode_message_body_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_message_body_cdata(__TopXMLNS, _val) -> _val. - -encode_message_body_cdata(<<>>, _acc) -> _acc; -encode_message_body_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_message_subject(__TopXMLNS, __IgnoreEls, - {xmlel, <<"subject">>, _attrs, _els}) -> - Data = decode_message_subject_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Lang = decode_message_subject_attrs(__TopXMLNS, _attrs, - undefined), - {text, Lang, Data}. - -decode_message_subject_els(__TopXMLNS, __IgnoreEls, [], - Data) -> - decode_message_subject_cdata(__TopXMLNS, Data); -decode_message_subject_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Data) -> - decode_message_subject_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_message_subject_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Data) -> - decode_message_subject_els(__TopXMLNS, __IgnoreEls, - _els, Data). - -decode_message_subject_attrs(__TopXMLNS, - [{<<"xml:lang">>, _val} | _attrs], _Lang) -> - decode_message_subject_attrs(__TopXMLNS, _attrs, _val); -decode_message_subject_attrs(__TopXMLNS, [_ | _attrs], - Lang) -> - decode_message_subject_attrs(__TopXMLNS, _attrs, Lang); -decode_message_subject_attrs(__TopXMLNS, [], Lang) -> - 'decode_message_subject_attr_xml:lang'(__TopXMLNS, - Lang). - -encode_message_subject({text, Lang, Data}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"jabber:client">>, <<"jabber:server">>, - <<"jabber:component:accept">>], - __TopXMLNS), - _els = encode_message_subject_cdata(Data, []), - _attrs = 'encode_message_subject_attr_xml:lang'(Lang, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"subject">>, _attrs, _els}. - -'decode_message_subject_attr_xml:lang'(__TopXMLNS, - undefined) -> - <<>>; -'decode_message_subject_attr_xml:lang'(__TopXMLNS, - _val) -> - _val. - -'encode_message_subject_attr_xml:lang'(<<>>, _acc) -> - _acc; -'encode_message_subject_attr_xml:lang'(_val, _acc) -> - [{<<"xml:lang">>, _val} | _acc]. - -decode_message_subject_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_message_subject_cdata(__TopXMLNS, _val) -> _val. - -encode_message_subject_cdata(<<>>, _acc) -> _acc; -encode_message_subject_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_iq(__TopXMLNS, __IgnoreEls, - {xmlel, <<"iq">>, _attrs, _els}) -> - __Els = decode_iq_els(__TopXMLNS, __IgnoreEls, _els, - []), - {Id, Type, From, To, Lang} = decode_iq_attrs(__TopXMLNS, - _attrs, undefined, undefined, - undefined, undefined, - undefined), - {iq, Id, Type, Lang, From, To, __Els}. - -decode_iq_els(__TopXMLNS, __IgnoreEls, [], __Els) -> - lists:reverse(__Els); -decode_iq_els(__TopXMLNS, __IgnoreEls, - [{xmlel, _, _, _} = _el | _els], __Els) -> - if __IgnoreEls -> - decode_iq_els(__TopXMLNS, __IgnoreEls, _els, - [_el | __Els]); - true -> - case is_known_tag(_el, __TopXMLNS) of - true -> - decode_iq_els(__TopXMLNS, __IgnoreEls, _els, - [decode(_el, __TopXMLNS, []) | __Els]); - false -> - decode_iq_els(__TopXMLNS, __IgnoreEls, _els, __Els) - end - end; -decode_iq_els(__TopXMLNS, __IgnoreEls, [_ | _els], - __Els) -> - decode_iq_els(__TopXMLNS, __IgnoreEls, _els, __Els). - -decode_iq_attrs(__TopXMLNS, [{<<"id">>, _val} | _attrs], - _Id, Type, From, To, Lang) -> - decode_iq_attrs(__TopXMLNS, _attrs, _val, Type, From, - To, Lang); -decode_iq_attrs(__TopXMLNS, - [{<<"type">>, _val} | _attrs], Id, _Type, From, To, - Lang) -> - decode_iq_attrs(__TopXMLNS, _attrs, Id, _val, From, To, - Lang); -decode_iq_attrs(__TopXMLNS, - [{<<"from">>, _val} | _attrs], Id, Type, _From, To, - Lang) -> - decode_iq_attrs(__TopXMLNS, _attrs, Id, Type, _val, To, - Lang); -decode_iq_attrs(__TopXMLNS, [{<<"to">>, _val} | _attrs], - Id, Type, From, _To, Lang) -> - decode_iq_attrs(__TopXMLNS, _attrs, Id, Type, From, - _val, Lang); -decode_iq_attrs(__TopXMLNS, - [{<<"xml:lang">>, _val} | _attrs], Id, Type, From, To, - _Lang) -> - decode_iq_attrs(__TopXMLNS, _attrs, Id, Type, From, To, - _val); -decode_iq_attrs(__TopXMLNS, [_ | _attrs], Id, Type, - From, To, Lang) -> - decode_iq_attrs(__TopXMLNS, _attrs, Id, Type, From, To, - Lang); -decode_iq_attrs(__TopXMLNS, [], Id, Type, From, To, - Lang) -> - {decode_iq_attr_id(__TopXMLNS, Id), - decode_iq_attr_type(__TopXMLNS, Type), - decode_iq_attr_from(__TopXMLNS, From), - decode_iq_attr_to(__TopXMLNS, To), - 'decode_iq_attr_xml:lang'(__TopXMLNS, Lang)}. - -encode_iq({iq, Id, Type, Lang, From, To, __Els}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<>>, - [<<"jabber:client">>, <<"jabber:server">>, - <<"jabber:component:accept">>], - __TopXMLNS), - _els = [encode(_el, __NewTopXMLNS) || _el <- __Els], - _attrs = 'encode_iq_attr_xml:lang'(Lang, - encode_iq_attr_to(To, - encode_iq_attr_from(From, - encode_iq_attr_type(Type, - encode_iq_attr_id(Id, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)))))), - {xmlel, <<"iq">>, _attrs, _els}. - -decode_iq_attr_id(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"id">>, <<"iq">>, __TopXMLNS}}); -decode_iq_attr_id(__TopXMLNS, _val) -> _val. - -encode_iq_attr_id(_val, _acc) -> - [{<<"id">>, _val} | _acc]. - -decode_iq_attr_type(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"type">>, <<"iq">>, __TopXMLNS}}); -decode_iq_attr_type(__TopXMLNS, _val) -> - case catch dec_enum(_val, [get, set, result, error]) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"type">>, <<"iq">>, __TopXMLNS}}); - _res -> _res - end. - -encode_iq_attr_type(_val, _acc) -> - [{<<"type">>, enc_enum(_val)} | _acc]. - -decode_iq_attr_from(__TopXMLNS, undefined) -> undefined; -decode_iq_attr_from(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"from">>, <<"iq">>, __TopXMLNS}}); - _res -> _res - end. - -encode_iq_attr_from(undefined, _acc) -> _acc; -encode_iq_attr_from(_val, _acc) -> - [{<<"from">>, enc_jid(_val)} | _acc]. - -decode_iq_attr_to(__TopXMLNS, undefined) -> undefined; -decode_iq_attr_to(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"to">>, <<"iq">>, __TopXMLNS}}); - _res -> _res - end. - -encode_iq_attr_to(undefined, _acc) -> _acc; -encode_iq_attr_to(_val, _acc) -> - [{<<"to">>, enc_jid(_val)} | _acc]. - -'decode_iq_attr_xml:lang'(__TopXMLNS, undefined) -> - <<>>; -'decode_iq_attr_xml:lang'(__TopXMLNS, _val) -> _val. - -'encode_iq_attr_xml:lang'(<<>>, _acc) -> _acc; -'encode_iq_attr_xml:lang'(_val, _acc) -> - [{<<"xml:lang">>, _val} | _acc]. - -decode_stats(__TopXMLNS, __IgnoreEls, - {xmlel, <<"query">>, _attrs, _els}) -> - List = decode_stats_els(__TopXMLNS, __IgnoreEls, _els, - []), - Node = decode_stats_attrs(__TopXMLNS, _attrs, - undefined), - {stats, List, Node}. - -decode_stats_els(__TopXMLNS, __IgnoreEls, [], List) -> - lists:reverse(List); -decode_stats_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"stat">>, _attrs, _} = _el | _els], List) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/stats">> -> - decode_stats_els(__TopXMLNS, __IgnoreEls, _els, - [decode_stat(__TopXMLNS, __IgnoreEls, _el) | List]); - <<"http://jabber.org/protocol/stats">> -> - decode_stats_els(__TopXMLNS, __IgnoreEls, _els, - [decode_stat(<<"http://jabber.org/protocol/stats">>, - __IgnoreEls, _el) - | List]); - _ -> - decode_stats_els(__TopXMLNS, __IgnoreEls, _els, List) - end; -decode_stats_els(__TopXMLNS, __IgnoreEls, [_ | _els], - List) -> - decode_stats_els(__TopXMLNS, __IgnoreEls, _els, List). - -decode_stats_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], _Node) -> - decode_stats_attrs(__TopXMLNS, _attrs, _val); -decode_stats_attrs(__TopXMLNS, [_ | _attrs], Node) -> - decode_stats_attrs(__TopXMLNS, _attrs, Node); -decode_stats_attrs(__TopXMLNS, [], Node) -> - decode_stats_attr_node(__TopXMLNS, Node). - -encode_stats({stats, List, Node}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/stats">>, - [], __TopXMLNS), - _els = lists:reverse('encode_stats_$list'(List, - __NewTopXMLNS, [])), - _attrs = encode_stats_attr_node(Node, - enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS)), - {xmlel, <<"query">>, _attrs, _els}. - -'encode_stats_$list'([], __TopXMLNS, _acc) -> _acc; -'encode_stats_$list'([List | _els], __TopXMLNS, _acc) -> - 'encode_stats_$list'(_els, __TopXMLNS, - [encode_stat(List, __TopXMLNS) | _acc]). - -decode_stats_attr_node(__TopXMLNS, undefined) -> <<>>; -decode_stats_attr_node(__TopXMLNS, _val) -> _val. - -encode_stats_attr_node(<<>>, _acc) -> _acc; -encode_stats_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_stat(__TopXMLNS, __IgnoreEls, - {xmlel, <<"stat">>, _attrs, _els}) -> - Error = decode_stat_els(__TopXMLNS, __IgnoreEls, _els, - undefined), - {Name, Units, Value} = decode_stat_attrs(__TopXMLNS, - _attrs, undefined, undefined, - undefined), - {stat, Name, Units, Value, Error}. - -decode_stat_els(__TopXMLNS, __IgnoreEls, [], Error) -> - Error; -decode_stat_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"error">>, _attrs, _} = _el | _els], - Error) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/stats">> -> - decode_stat_els(__TopXMLNS, __IgnoreEls, _els, - decode_stat_error(__TopXMLNS, __IgnoreEls, _el)); - <<"http://jabber.org/protocol/stats">> -> - decode_stat_els(__TopXMLNS, __IgnoreEls, _els, - decode_stat_error(<<"http://jabber.org/protocol/stats">>, - __IgnoreEls, _el)); - _ -> - decode_stat_els(__TopXMLNS, __IgnoreEls, _els, Error) - end; -decode_stat_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Error) -> - decode_stat_els(__TopXMLNS, __IgnoreEls, _els, Error). - -decode_stat_attrs(__TopXMLNS, - [{<<"name">>, _val} | _attrs], _Name, Units, Value) -> - decode_stat_attrs(__TopXMLNS, _attrs, _val, Units, - Value); -decode_stat_attrs(__TopXMLNS, - [{<<"units">>, _val} | _attrs], Name, _Units, Value) -> - decode_stat_attrs(__TopXMLNS, _attrs, Name, _val, - Value); -decode_stat_attrs(__TopXMLNS, - [{<<"value">>, _val} | _attrs], Name, Units, _Value) -> - decode_stat_attrs(__TopXMLNS, _attrs, Name, Units, - _val); -decode_stat_attrs(__TopXMLNS, [_ | _attrs], Name, Units, - Value) -> - decode_stat_attrs(__TopXMLNS, _attrs, Name, Units, - Value); -decode_stat_attrs(__TopXMLNS, [], Name, Units, Value) -> - {decode_stat_attr_name(__TopXMLNS, Name), - decode_stat_attr_units(__TopXMLNS, Units), - decode_stat_attr_value(__TopXMLNS, Value)}. - -encode_stat({stat, Name, Units, Value, Error}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/stats">>, - [], __TopXMLNS), - _els = lists:reverse('encode_stat_$error'(Error, - __NewTopXMLNS, [])), - _attrs = encode_stat_attr_value(Value, - encode_stat_attr_units(Units, - encode_stat_attr_name(Name, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)))), - {xmlel, <<"stat">>, _attrs, _els}. - -'encode_stat_$error'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_stat_$error'(Error, __TopXMLNS, _acc) -> - [encode_stat_error(Error, __TopXMLNS) | _acc]. - -decode_stat_attr_name(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"name">>, <<"stat">>, __TopXMLNS}}); -decode_stat_attr_name(__TopXMLNS, _val) -> _val. - -encode_stat_attr_name(_val, _acc) -> - [{<<"name">>, _val} | _acc]. - -decode_stat_attr_units(__TopXMLNS, undefined) -> <<>>; -decode_stat_attr_units(__TopXMLNS, _val) -> _val. - -encode_stat_attr_units(<<>>, _acc) -> _acc; -encode_stat_attr_units(_val, _acc) -> - [{<<"units">>, _val} | _acc]. - -decode_stat_attr_value(__TopXMLNS, undefined) -> <<>>; -decode_stat_attr_value(__TopXMLNS, _val) -> _val. - -encode_stat_attr_value(<<>>, _acc) -> _acc; -encode_stat_attr_value(_val, _acc) -> - [{<<"value">>, _val} | _acc]. - -decode_stat_error(__TopXMLNS, __IgnoreEls, - {xmlel, <<"error">>, _attrs, _els}) -> - Reason = decode_stat_error_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Code = decode_stat_error_attrs(__TopXMLNS, _attrs, - undefined), - {stat_error, Code, Reason}. - -decode_stat_error_els(__TopXMLNS, __IgnoreEls, [], - Reason) -> - decode_stat_error_cdata(__TopXMLNS, Reason); -decode_stat_error_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Reason) -> - decode_stat_error_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_stat_error_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Reason) -> - decode_stat_error_els(__TopXMLNS, __IgnoreEls, _els, - Reason). - -decode_stat_error_attrs(__TopXMLNS, - [{<<"code">>, _val} | _attrs], _Code) -> - decode_stat_error_attrs(__TopXMLNS, _attrs, _val); -decode_stat_error_attrs(__TopXMLNS, [_ | _attrs], - Code) -> - decode_stat_error_attrs(__TopXMLNS, _attrs, Code); -decode_stat_error_attrs(__TopXMLNS, [], Code) -> - decode_stat_error_attr_code(__TopXMLNS, Code). - -encode_stat_error({stat_error, Code, Reason}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/stats">>, - [], __TopXMLNS), - _els = encode_stat_error_cdata(Reason, []), - _attrs = encode_stat_error_attr_code(Code, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"error">>, _attrs, _els}. - -decode_stat_error_attr_code(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"code">>, <<"error">>, __TopXMLNS}}); -decode_stat_error_attr_code(__TopXMLNS, _val) -> - case catch dec_int(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"code">>, <<"error">>, __TopXMLNS}}); - _res -> _res - end. - -encode_stat_error_attr_code(_val, _acc) -> - [{<<"code">>, enc_int(_val)} | _acc]. - -decode_stat_error_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_stat_error_cdata(__TopXMLNS, _val) -> _val. - -encode_stat_error_cdata(<<>>, _acc) -> _acc; -encode_stat_error_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_bookmarks_storage(__TopXMLNS, __IgnoreEls, - {xmlel, <<"storage">>, _attrs, _els}) -> - {Conference, Url} = - decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, - _els, [], []), - {bookmark_storage, Conference, Url}. - -decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, - [], Conference, Url) -> - {lists:reverse(Conference), lists:reverse(Url)}; -decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"conference">>, _attrs, _} = _el - | _els], - Conference, Url) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"storage:bookmarks">> -> - decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, - _els, - [decode_bookmark_conference(__TopXMLNS, - __IgnoreEls, - _el) - | Conference], - Url); - <<"storage:bookmarks">> -> - decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, - _els, - [decode_bookmark_conference(<<"storage:bookmarks">>, - __IgnoreEls, - _el) - | Conference], - Url); - _ -> - decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, - _els, Conference, Url) - end; -decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"url">>, _attrs, _} = _el | _els], - Conference, Url) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"storage:bookmarks">> -> - decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, - _els, Conference, - [decode_bookmark_url(__TopXMLNS, - __IgnoreEls, _el) - | Url]); - <<"storage:bookmarks">> -> - decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, - _els, Conference, - [decode_bookmark_url(<<"storage:bookmarks">>, - __IgnoreEls, _el) - | Url]); - _ -> - decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, - _els, Conference, Url) - end; -decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Conference, Url) -> - decode_bookmarks_storage_els(__TopXMLNS, __IgnoreEls, - _els, Conference, Url). - -encode_bookmarks_storage({bookmark_storage, Conference, - Url}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"storage:bookmarks">>, [], - __TopXMLNS), - _els = - lists:reverse('encode_bookmarks_storage_$conference'(Conference, - __NewTopXMLNS, - 'encode_bookmarks_storage_$url'(Url, - __NewTopXMLNS, - []))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"storage">>, _attrs, _els}. - -'encode_bookmarks_storage_$conference'([], __TopXMLNS, - _acc) -> - _acc; -'encode_bookmarks_storage_$conference'([Conference - | _els], - __TopXMLNS, _acc) -> - 'encode_bookmarks_storage_$conference'(_els, __TopXMLNS, - [encode_bookmark_conference(Conference, - __TopXMLNS) - | _acc]). - -'encode_bookmarks_storage_$url'([], __TopXMLNS, _acc) -> - _acc; -'encode_bookmarks_storage_$url'([Url | _els], - __TopXMLNS, _acc) -> - 'encode_bookmarks_storage_$url'(_els, __TopXMLNS, - [encode_bookmark_url(Url, __TopXMLNS) - | _acc]). - -decode_bookmark_url(__TopXMLNS, __IgnoreEls, - {xmlel, <<"url">>, _attrs, _els}) -> - {Name, Url} = decode_bookmark_url_attrs(__TopXMLNS, - _attrs, undefined, undefined), - {bookmark_url, Name, Url}. - -decode_bookmark_url_attrs(__TopXMLNS, - [{<<"name">>, _val} | _attrs], _Name, Url) -> - decode_bookmark_url_attrs(__TopXMLNS, _attrs, _val, - Url); -decode_bookmark_url_attrs(__TopXMLNS, - [{<<"url">>, _val} | _attrs], Name, _Url) -> - decode_bookmark_url_attrs(__TopXMLNS, _attrs, Name, - _val); -decode_bookmark_url_attrs(__TopXMLNS, [_ | _attrs], - Name, Url) -> - decode_bookmark_url_attrs(__TopXMLNS, _attrs, Name, - Url); -decode_bookmark_url_attrs(__TopXMLNS, [], Name, Url) -> - {decode_bookmark_url_attr_name(__TopXMLNS, Name), - decode_bookmark_url_attr_url(__TopXMLNS, Url)}. - -encode_bookmark_url({bookmark_url, Name, Url}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"storage:bookmarks">>, [], - __TopXMLNS), - _els = [], - _attrs = encode_bookmark_url_attr_url(Url, - encode_bookmark_url_attr_name(Name, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))), - {xmlel, <<"url">>, _attrs, _els}. - -decode_bookmark_url_attr_name(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"name">>, <<"url">>, __TopXMLNS}}); -decode_bookmark_url_attr_name(__TopXMLNS, _val) -> _val. - -encode_bookmark_url_attr_name(_val, _acc) -> - [{<<"name">>, _val} | _acc]. - -decode_bookmark_url_attr_url(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"url">>, <<"url">>, __TopXMLNS}}); -decode_bookmark_url_attr_url(__TopXMLNS, _val) -> _val. - -encode_bookmark_url_attr_url(_val, _acc) -> - [{<<"url">>, _val} | _acc]. - -decode_bookmark_conference(__TopXMLNS, __IgnoreEls, - {xmlel, <<"conference">>, _attrs, _els}) -> - {Password, Nick} = - decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, - _els, undefined, undefined), - {Name, Jid, Autojoin} = - decode_bookmark_conference_attrs(__TopXMLNS, _attrs, - undefined, undefined, undefined), - {bookmark_conference, Name, Jid, Autojoin, Nick, - Password}. - -decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, - [], Password, Nick) -> - {Password, Nick}; -decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"nick">>, _attrs, _} = _el | _els], - Password, Nick) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"storage:bookmarks">> -> - decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, - _els, Password, - decode_conference_nick(__TopXMLNS, - __IgnoreEls, - _el)); - <<"storage:bookmarks">> -> - decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, - _els, Password, - decode_conference_nick(<<"storage:bookmarks">>, - __IgnoreEls, - _el)); - _ -> - decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, - _els, Password, Nick) - end; -decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"password">>, _attrs, _} = _el - | _els], - Password, Nick) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"storage:bookmarks">> -> - decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, - _els, - decode_conference_password(__TopXMLNS, - __IgnoreEls, - _el), - Nick); - <<"storage:bookmarks">> -> - decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, - _els, - decode_conference_password(<<"storage:bookmarks">>, - __IgnoreEls, - _el), - Nick); - _ -> - decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, - _els, Password, Nick) - end; -decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Password, Nick) -> - decode_bookmark_conference_els(__TopXMLNS, __IgnoreEls, - _els, Password, Nick). - -decode_bookmark_conference_attrs(__TopXMLNS, - [{<<"name">>, _val} | _attrs], _Name, Jid, - Autojoin) -> - decode_bookmark_conference_attrs(__TopXMLNS, _attrs, - _val, Jid, Autojoin); -decode_bookmark_conference_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], Name, _Jid, - Autojoin) -> - decode_bookmark_conference_attrs(__TopXMLNS, _attrs, - Name, _val, Autojoin); -decode_bookmark_conference_attrs(__TopXMLNS, - [{<<"autojoin">>, _val} | _attrs], Name, Jid, - _Autojoin) -> - decode_bookmark_conference_attrs(__TopXMLNS, _attrs, - Name, Jid, _val); -decode_bookmark_conference_attrs(__TopXMLNS, - [_ | _attrs], Name, Jid, Autojoin) -> - decode_bookmark_conference_attrs(__TopXMLNS, _attrs, - Name, Jid, Autojoin); -decode_bookmark_conference_attrs(__TopXMLNS, [], Name, - Jid, Autojoin) -> - {decode_bookmark_conference_attr_name(__TopXMLNS, Name), - decode_bookmark_conference_attr_jid(__TopXMLNS, Jid), - decode_bookmark_conference_attr_autojoin(__TopXMLNS, - Autojoin)}. - -encode_bookmark_conference({bookmark_conference, Name, - Jid, Autojoin, Nick, Password}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"storage:bookmarks">>, [], - __TopXMLNS), - _els = - lists:reverse('encode_bookmark_conference_$password'(Password, - __NewTopXMLNS, - 'encode_bookmark_conference_$nick'(Nick, - __NewTopXMLNS, - []))), - _attrs = - encode_bookmark_conference_attr_autojoin(Autojoin, - encode_bookmark_conference_attr_jid(Jid, - encode_bookmark_conference_attr_name(Name, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)))), - {xmlel, <<"conference">>, _attrs, _els}. - -'encode_bookmark_conference_$password'(undefined, - __TopXMLNS, _acc) -> - _acc; -'encode_bookmark_conference_$password'(Password, - __TopXMLNS, _acc) -> - [encode_conference_password(Password, __TopXMLNS) - | _acc]. - -'encode_bookmark_conference_$nick'(undefined, - __TopXMLNS, _acc) -> - _acc; -'encode_bookmark_conference_$nick'(Nick, __TopXMLNS, - _acc) -> - [encode_conference_nick(Nick, __TopXMLNS) | _acc]. - -decode_bookmark_conference_attr_name(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"name">>, <<"conference">>, - __TopXMLNS}}); -decode_bookmark_conference_attr_name(__TopXMLNS, - _val) -> - _val. - -encode_bookmark_conference_attr_name(_val, _acc) -> - [{<<"name">>, _val} | _acc]. - -decode_bookmark_conference_attr_jid(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"jid">>, <<"conference">>, - __TopXMLNS}}); -decode_bookmark_conference_attr_jid(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"jid">>, <<"conference">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_bookmark_conference_attr_jid(_val, _acc) -> - [{<<"jid">>, enc_jid(_val)} | _acc]. - -decode_bookmark_conference_attr_autojoin(__TopXMLNS, - undefined) -> - false; -decode_bookmark_conference_attr_autojoin(__TopXMLNS, - _val) -> - case catch dec_bool(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"autojoin">>, <<"conference">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_bookmark_conference_attr_autojoin(false, _acc) -> - _acc; -encode_bookmark_conference_attr_autojoin(_val, _acc) -> - [{<<"autojoin">>, enc_bool(_val)} | _acc]. - -decode_conference_password(__TopXMLNS, __IgnoreEls, - {xmlel, <<"password">>, _attrs, _els}) -> - Cdata = decode_conference_password_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_conference_password_els(__TopXMLNS, __IgnoreEls, - [], Cdata) -> - decode_conference_password_cdata(__TopXMLNS, Cdata); -decode_conference_password_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_conference_password_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_conference_password_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_conference_password_els(__TopXMLNS, __IgnoreEls, - _els, Cdata). - -encode_conference_password(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"storage:bookmarks">>, [], - __TopXMLNS), - _els = encode_conference_password_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"password">>, _attrs, _els}. - -decode_conference_password_cdata(__TopXMLNS, <<>>) -> - <<>>; -decode_conference_password_cdata(__TopXMLNS, _val) -> - _val. - -encode_conference_password_cdata(<<>>, _acc) -> _acc; -encode_conference_password_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_conference_nick(__TopXMLNS, __IgnoreEls, - {xmlel, <<"nick">>, _attrs, _els}) -> - Cdata = decode_conference_nick_els(__TopXMLNS, - __IgnoreEls, _els, <<>>), - Cdata. - -decode_conference_nick_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_conference_nick_cdata(__TopXMLNS, Cdata); -decode_conference_nick_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_conference_nick_els(__TopXMLNS, __IgnoreEls, - _els, <>); -decode_conference_nick_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_conference_nick_els(__TopXMLNS, __IgnoreEls, - _els, Cdata). - -encode_conference_nick(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"storage:bookmarks">>, [], - __TopXMLNS), - _els = encode_conference_nick_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"nick">>, _attrs, _els}. - -decode_conference_nick_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_conference_nick_cdata(__TopXMLNS, _val) -> _val. - -encode_conference_nick_cdata(<<>>, _acc) -> _acc; -encode_conference_nick_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_private(__TopXMLNS, __IgnoreEls, - {xmlel, <<"query">>, _attrs, _els}) -> - __Xmls = decode_private_els(__TopXMLNS, __IgnoreEls, - _els, []), - {private, __Xmls}. - -decode_private_els(__TopXMLNS, __IgnoreEls, [], - __Xmls) -> - lists:reverse(__Xmls); -decode_private_els(__TopXMLNS, __IgnoreEls, - [{xmlel, _, _, _} = _el | _els], __Xmls) -> - decode_private_els(__TopXMLNS, __IgnoreEls, _els, - [_el | __Xmls]); -decode_private_els(__TopXMLNS, __IgnoreEls, [_ | _els], - __Xmls) -> - decode_private_els(__TopXMLNS, __IgnoreEls, _els, - __Xmls). - -encode_private({private, __Xmls}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:private">>, [], - __TopXMLNS), - _els = __Xmls, - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"query">>, _attrs, _els}. - -decode_disco_items(__TopXMLNS, __IgnoreEls, - {xmlel, <<"query">>, _attrs, _els}) -> - {Items, Rsm} = decode_disco_items_els(__TopXMLNS, - __IgnoreEls, _els, [], undefined), - Node = decode_disco_items_attrs(__TopXMLNS, _attrs, - undefined), - {disco_items, Node, Items, Rsm}. - -decode_disco_items_els(__TopXMLNS, __IgnoreEls, [], - Items, Rsm) -> - {lists:reverse(Items), Rsm}; -decode_disco_items_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items, - Rsm) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/disco#items">> -> - decode_disco_items_els(__TopXMLNS, __IgnoreEls, _els, - [decode_disco_item(__TopXMLNS, __IgnoreEls, - _el) - | Items], - Rsm); - <<"http://jabber.org/protocol/disco#items">> -> - decode_disco_items_els(__TopXMLNS, __IgnoreEls, _els, - [decode_disco_item(<<"http://jabber.org/protocol/disco#items">>, - __IgnoreEls, _el) - | Items], - Rsm); - _ -> - decode_disco_items_els(__TopXMLNS, __IgnoreEls, _els, - Items, Rsm) - end; -decode_disco_items_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"set">>, _attrs, _} = _el | _els], Items, - Rsm) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"http://jabber.org/protocol/rsm">> -> - decode_disco_items_els(__TopXMLNS, __IgnoreEls, _els, - Items, - decode_rsm_set(<<"http://jabber.org/protocol/rsm">>, - __IgnoreEls, _el)); - _ -> - decode_disco_items_els(__TopXMLNS, __IgnoreEls, _els, - Items, Rsm) - end; -decode_disco_items_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Items, Rsm) -> - decode_disco_items_els(__TopXMLNS, __IgnoreEls, _els, - Items, Rsm). - -decode_disco_items_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], _Node) -> - decode_disco_items_attrs(__TopXMLNS, _attrs, _val); -decode_disco_items_attrs(__TopXMLNS, [_ | _attrs], - Node) -> - decode_disco_items_attrs(__TopXMLNS, _attrs, Node); -decode_disco_items_attrs(__TopXMLNS, [], Node) -> - decode_disco_items_attr_node(__TopXMLNS, Node). - -encode_disco_items({disco_items, Node, Items, Rsm}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/disco#items">>, - [], __TopXMLNS), - _els = lists:reverse('encode_disco_items_$items'(Items, - __NewTopXMLNS, - 'encode_disco_items_$rsm'(Rsm, - __NewTopXMLNS, - []))), - _attrs = encode_disco_items_attr_node(Node, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"query">>, _attrs, _els}. - -'encode_disco_items_$items'([], __TopXMLNS, _acc) -> - _acc; -'encode_disco_items_$items'([Items | _els], __TopXMLNS, - _acc) -> - 'encode_disco_items_$items'(_els, __TopXMLNS, - [encode_disco_item(Items, __TopXMLNS) | _acc]). - -'encode_disco_items_$rsm'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_disco_items_$rsm'(Rsm, __TopXMLNS, _acc) -> - [encode_rsm_set(Rsm, __TopXMLNS) | _acc]. - -decode_disco_items_attr_node(__TopXMLNS, undefined) -> - <<>>; -decode_disco_items_attr_node(__TopXMLNS, _val) -> _val. - -encode_disco_items_attr_node(<<>>, _acc) -> _acc; -encode_disco_items_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_disco_item(__TopXMLNS, __IgnoreEls, - {xmlel, <<"item">>, _attrs, _els}) -> - {Jid, Name, Node} = decode_disco_item_attrs(__TopXMLNS, - _attrs, undefined, undefined, - undefined), - {disco_item, Jid, Name, Node}. - -decode_disco_item_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], _Jid, Name, Node) -> - decode_disco_item_attrs(__TopXMLNS, _attrs, _val, Name, - Node); -decode_disco_item_attrs(__TopXMLNS, - [{<<"name">>, _val} | _attrs], Jid, _Name, Node) -> - decode_disco_item_attrs(__TopXMLNS, _attrs, Jid, _val, - Node); -decode_disco_item_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], Jid, Name, _Node) -> - decode_disco_item_attrs(__TopXMLNS, _attrs, Jid, Name, - _val); -decode_disco_item_attrs(__TopXMLNS, [_ | _attrs], Jid, - Name, Node) -> - decode_disco_item_attrs(__TopXMLNS, _attrs, Jid, Name, - Node); -decode_disco_item_attrs(__TopXMLNS, [], Jid, Name, - Node) -> - {decode_disco_item_attr_jid(__TopXMLNS, Jid), - decode_disco_item_attr_name(__TopXMLNS, Name), - decode_disco_item_attr_node(__TopXMLNS, Node)}. - -encode_disco_item({disco_item, Jid, Name, Node}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/disco#items">>, - [], __TopXMLNS), - _els = [], - _attrs = encode_disco_item_attr_node(Node, - encode_disco_item_attr_name(Name, - encode_disco_item_attr_jid(Jid, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)))), - {xmlel, <<"item">>, _attrs, _els}. - -decode_disco_item_attr_jid(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"jid">>, <<"item">>, __TopXMLNS}}); -decode_disco_item_attr_jid(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"jid">>, <<"item">>, __TopXMLNS}}); - _res -> _res - end. - -encode_disco_item_attr_jid(_val, _acc) -> - [{<<"jid">>, enc_jid(_val)} | _acc]. - -decode_disco_item_attr_name(__TopXMLNS, undefined) -> - <<>>; -decode_disco_item_attr_name(__TopXMLNS, _val) -> _val. - -encode_disco_item_attr_name(<<>>, _acc) -> _acc; -encode_disco_item_attr_name(_val, _acc) -> - [{<<"name">>, _val} | _acc]. - -decode_disco_item_attr_node(__TopXMLNS, undefined) -> - <<>>; -decode_disco_item_attr_node(__TopXMLNS, _val) -> _val. - -encode_disco_item_attr_node(<<>>, _acc) -> _acc; -encode_disco_item_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_disco_info(__TopXMLNS, __IgnoreEls, - {xmlel, <<"query">>, _attrs, _els}) -> - {Xdata, Features, Identities} = - decode_disco_info_els(__TopXMLNS, __IgnoreEls, _els, [], - [], []), - Node = decode_disco_info_attrs(__TopXMLNS, _attrs, - undefined), - {disco_info, Node, Identities, Features, Xdata}. - -decode_disco_info_els(__TopXMLNS, __IgnoreEls, [], - Xdata, Features, Identities) -> - {lists:reverse(Xdata), lists:reverse(Features), - lists:reverse(Identities)}; -decode_disco_info_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"identity">>, _attrs, _} = _el | _els], - Xdata, Features, Identities) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/disco#info">> -> - decode_disco_info_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Features, - [decode_disco_identity(__TopXMLNS, __IgnoreEls, - _el) - | Identities]); - <<"http://jabber.org/protocol/disco#info">> -> - decode_disco_info_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Features, - [decode_disco_identity(<<"http://jabber.org/protocol/disco#info">>, - __IgnoreEls, _el) - | Identities]); - _ -> - decode_disco_info_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Features, Identities) - end; -decode_disco_info_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"feature">>, _attrs, _} = _el | _els], Xdata, - Features, Identities) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> - when __TopXMLNS == - <<"http://jabber.org/protocol/disco#info">> -> - decode_disco_info_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, - [decode_disco_feature(__TopXMLNS, __IgnoreEls, - _el) - | Features], - Identities); - <<"http://jabber.org/protocol/disco#info">> -> - decode_disco_info_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, - [decode_disco_feature(<<"http://jabber.org/protocol/disco#info">>, - __IgnoreEls, _el) - | Features], - Identities); - _ -> - decode_disco_info_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Features, Identities) - end; -decode_disco_info_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"x">>, _attrs, _} = _el | _els], Xdata, - Features, Identities) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"jabber:x:data">> -> - decode_disco_info_els(__TopXMLNS, __IgnoreEls, _els, - [decode_xdata(<<"jabber:x:data">>, __IgnoreEls, - _el) - | Xdata], - Features, Identities); - _ -> - decode_disco_info_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Features, Identities) - end; -decode_disco_info_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Xdata, Features, Identities) -> - decode_disco_info_els(__TopXMLNS, __IgnoreEls, _els, - Xdata, Features, Identities). - -decode_disco_info_attrs(__TopXMLNS, - [{<<"node">>, _val} | _attrs], _Node) -> - decode_disco_info_attrs(__TopXMLNS, _attrs, _val); -decode_disco_info_attrs(__TopXMLNS, [_ | _attrs], - Node) -> - decode_disco_info_attrs(__TopXMLNS, _attrs, Node); -decode_disco_info_attrs(__TopXMLNS, [], Node) -> - decode_disco_info_attr_node(__TopXMLNS, Node). - -encode_disco_info({disco_info, Node, Identities, - Features, Xdata}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/disco#info">>, - [], __TopXMLNS), - _els = lists:reverse('encode_disco_info_$xdata'(Xdata, - __NewTopXMLNS, - 'encode_disco_info_$features'(Features, - __NewTopXMLNS, - 'encode_disco_info_$identities'(Identities, - __NewTopXMLNS, - [])))), - _attrs = encode_disco_info_attr_node(Node, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"query">>, _attrs, _els}. - -'encode_disco_info_$xdata'([], __TopXMLNS, _acc) -> - _acc; -'encode_disco_info_$xdata'([Xdata | _els], __TopXMLNS, - _acc) -> - 'encode_disco_info_$xdata'(_els, __TopXMLNS, - [encode_xdata(Xdata, __TopXMLNS) | _acc]). - -'encode_disco_info_$features'([], __TopXMLNS, _acc) -> - _acc; -'encode_disco_info_$features'([Features | _els], - __TopXMLNS, _acc) -> - 'encode_disco_info_$features'(_els, __TopXMLNS, - [encode_disco_feature(Features, __TopXMLNS) - | _acc]). - -'encode_disco_info_$identities'([], __TopXMLNS, _acc) -> - _acc; -'encode_disco_info_$identities'([Identities | _els], - __TopXMLNS, _acc) -> - 'encode_disco_info_$identities'(_els, __TopXMLNS, - [encode_disco_identity(Identities, - __TopXMLNS) - | _acc]). - -decode_disco_info_attr_node(__TopXMLNS, undefined) -> - <<>>; -decode_disco_info_attr_node(__TopXMLNS, _val) -> _val. - -encode_disco_info_attr_node(<<>>, _acc) -> _acc; -encode_disco_info_attr_node(_val, _acc) -> - [{<<"node">>, _val} | _acc]. - -decode_disco_feature(__TopXMLNS, __IgnoreEls, - {xmlel, <<"feature">>, _attrs, _els}) -> - Var = decode_disco_feature_attrs(__TopXMLNS, _attrs, - undefined), - Var. - -decode_disco_feature_attrs(__TopXMLNS, - [{<<"var">>, _val} | _attrs], _Var) -> - decode_disco_feature_attrs(__TopXMLNS, _attrs, _val); -decode_disco_feature_attrs(__TopXMLNS, [_ | _attrs], - Var) -> - decode_disco_feature_attrs(__TopXMLNS, _attrs, Var); -decode_disco_feature_attrs(__TopXMLNS, [], Var) -> - decode_disco_feature_attr_var(__TopXMLNS, Var). - -encode_disco_feature(Var, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/disco#info">>, - [], __TopXMLNS), - _els = [], - _attrs = encode_disco_feature_attr_var(Var, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"feature">>, _attrs, _els}. - -decode_disco_feature_attr_var(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"var">>, <<"feature">>, __TopXMLNS}}); -decode_disco_feature_attr_var(__TopXMLNS, _val) -> _val. - -encode_disco_feature_attr_var(_val, _acc) -> - [{<<"var">>, _val} | _acc]. - -decode_disco_identity(__TopXMLNS, __IgnoreEls, - {xmlel, <<"identity">>, _attrs, _els}) -> - {Category, Type, Lang, Name} = - decode_disco_identity_attrs(__TopXMLNS, _attrs, - undefined, undefined, undefined, undefined), - {identity, Category, Type, Lang, Name}. - -decode_disco_identity_attrs(__TopXMLNS, - [{<<"category">>, _val} | _attrs], _Category, Type, - Lang, Name) -> - decode_disco_identity_attrs(__TopXMLNS, _attrs, _val, - Type, Lang, Name); -decode_disco_identity_attrs(__TopXMLNS, - [{<<"type">>, _val} | _attrs], Category, _Type, - Lang, Name) -> - decode_disco_identity_attrs(__TopXMLNS, _attrs, - Category, _val, Lang, Name); -decode_disco_identity_attrs(__TopXMLNS, - [{<<"xml:lang">>, _val} | _attrs], Category, Type, - _Lang, Name) -> - decode_disco_identity_attrs(__TopXMLNS, _attrs, - Category, Type, _val, Name); -decode_disco_identity_attrs(__TopXMLNS, - [{<<"name">>, _val} | _attrs], Category, Type, Lang, - _Name) -> - decode_disco_identity_attrs(__TopXMLNS, _attrs, - Category, Type, Lang, _val); -decode_disco_identity_attrs(__TopXMLNS, [_ | _attrs], - Category, Type, Lang, Name) -> - decode_disco_identity_attrs(__TopXMLNS, _attrs, - Category, Type, Lang, Name); -decode_disco_identity_attrs(__TopXMLNS, [], Category, - Type, Lang, Name) -> - {decode_disco_identity_attr_category(__TopXMLNS, - Category), - decode_disco_identity_attr_type(__TopXMLNS, Type), - 'decode_disco_identity_attr_xml:lang'(__TopXMLNS, Lang), - decode_disco_identity_attr_name(__TopXMLNS, Name)}. - -encode_disco_identity({identity, Category, Type, Lang, - Name}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"http://jabber.org/protocol/disco#info">>, - [], __TopXMLNS), - _els = [], - _attrs = encode_disco_identity_attr_name(Name, - 'encode_disco_identity_attr_xml:lang'(Lang, - encode_disco_identity_attr_type(Type, - encode_disco_identity_attr_category(Category, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))))), - {xmlel, <<"identity">>, _attrs, _els}. - -decode_disco_identity_attr_category(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"category">>, <<"identity">>, - __TopXMLNS}}); -decode_disco_identity_attr_category(__TopXMLNS, _val) -> - _val. - -encode_disco_identity_attr_category(_val, _acc) -> - [{<<"category">>, _val} | _acc]. - -decode_disco_identity_attr_type(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"type">>, <<"identity">>, - __TopXMLNS}}); -decode_disco_identity_attr_type(__TopXMLNS, _val) -> - _val. - -encode_disco_identity_attr_type(_val, _acc) -> - [{<<"type">>, _val} | _acc]. - -'decode_disco_identity_attr_xml:lang'(__TopXMLNS, - undefined) -> - <<>>; -'decode_disco_identity_attr_xml:lang'(__TopXMLNS, - _val) -> - _val. - -'encode_disco_identity_attr_xml:lang'(<<>>, _acc) -> - _acc; -'encode_disco_identity_attr_xml:lang'(_val, _acc) -> - [{<<"xml:lang">>, _val} | _acc]. - -decode_disco_identity_attr_name(__TopXMLNS, - undefined) -> - <<>>; -decode_disco_identity_attr_name(__TopXMLNS, _val) -> - _val. - -encode_disco_identity_attr_name(<<>>, _acc) -> _acc; -encode_disco_identity_attr_name(_val, _acc) -> - [{<<"name">>, _val} | _acc]. - -decode_block_list(__TopXMLNS, __IgnoreEls, - {xmlel, <<"blocklist">>, _attrs, _els}) -> - Items = decode_block_list_els(__TopXMLNS, __IgnoreEls, - _els, []), - {block_list, Items}. - -decode_block_list_els(__TopXMLNS, __IgnoreEls, [], - Items) -> - lists:reverse(Items); -decode_block_list_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"urn:xmpp:blocking">> -> - decode_block_list_els(__TopXMLNS, __IgnoreEls, _els, - [decode_block_item(__TopXMLNS, __IgnoreEls, _el) - | Items]); - <<"urn:xmpp:blocking">> -> - decode_block_list_els(__TopXMLNS, __IgnoreEls, _els, - [decode_block_item(<<"urn:xmpp:blocking">>, - __IgnoreEls, _el) - | Items]); - _ -> - decode_block_list_els(__TopXMLNS, __IgnoreEls, _els, - Items) - end; -decode_block_list_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Items) -> - decode_block_list_els(__TopXMLNS, __IgnoreEls, _els, - Items). - -encode_block_list({block_list, Items}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:blocking">>, [], - __TopXMLNS), - _els = lists:reverse('encode_block_list_$items'(Items, - __NewTopXMLNS, [])), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"blocklist">>, _attrs, _els}. - -'encode_block_list_$items'([], __TopXMLNS, _acc) -> - _acc; -'encode_block_list_$items'([Items | _els], __TopXMLNS, - _acc) -> - 'encode_block_list_$items'(_els, __TopXMLNS, - [encode_block_item(Items, __TopXMLNS) | _acc]). - -decode_unblock(__TopXMLNS, __IgnoreEls, - {xmlel, <<"unblock">>, _attrs, _els}) -> - Items = decode_unblock_els(__TopXMLNS, __IgnoreEls, - _els, []), - {unblock, Items}. - -decode_unblock_els(__TopXMLNS, __IgnoreEls, [], - Items) -> - lists:reverse(Items); -decode_unblock_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"urn:xmpp:blocking">> -> - decode_unblock_els(__TopXMLNS, __IgnoreEls, _els, - [decode_block_item(__TopXMLNS, __IgnoreEls, _el) - | Items]); - <<"urn:xmpp:blocking">> -> - decode_unblock_els(__TopXMLNS, __IgnoreEls, _els, - [decode_block_item(<<"urn:xmpp:blocking">>, - __IgnoreEls, _el) - | Items]); - _ -> - decode_unblock_els(__TopXMLNS, __IgnoreEls, _els, Items) - end; -decode_unblock_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Items) -> - decode_unblock_els(__TopXMLNS, __IgnoreEls, _els, - Items). - -encode_unblock({unblock, Items}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:blocking">>, [], - __TopXMLNS), - _els = lists:reverse('encode_unblock_$items'(Items, - __NewTopXMLNS, [])), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"unblock">>, _attrs, _els}. - -'encode_unblock_$items'([], __TopXMLNS, _acc) -> _acc; -'encode_unblock_$items'([Items | _els], __TopXMLNS, - _acc) -> - 'encode_unblock_$items'(_els, __TopXMLNS, - [encode_block_item(Items, __TopXMLNS) | _acc]). - -decode_block(__TopXMLNS, __IgnoreEls, - {xmlel, <<"block">>, _attrs, _els}) -> - Items = decode_block_els(__TopXMLNS, __IgnoreEls, _els, - []), - {block, Items}. - -decode_block_els(__TopXMLNS, __IgnoreEls, [], Items) -> - lists:reverse(Items); -decode_block_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"urn:xmpp:blocking">> -> - decode_block_els(__TopXMLNS, __IgnoreEls, _els, - [decode_block_item(__TopXMLNS, __IgnoreEls, _el) - | Items]); - <<"urn:xmpp:blocking">> -> - decode_block_els(__TopXMLNS, __IgnoreEls, _els, - [decode_block_item(<<"urn:xmpp:blocking">>, - __IgnoreEls, _el) - | Items]); - _ -> - decode_block_els(__TopXMLNS, __IgnoreEls, _els, Items) - end; -decode_block_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Items) -> - decode_block_els(__TopXMLNS, __IgnoreEls, _els, Items). - -encode_block({block, Items}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:blocking">>, [], - __TopXMLNS), - _els = lists:reverse('encode_block_$items'(Items, - __NewTopXMLNS, [])), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"block">>, _attrs, _els}. - -'encode_block_$items'([], __TopXMLNS, _acc) -> _acc; -'encode_block_$items'([Items | _els], __TopXMLNS, - _acc) -> - 'encode_block_$items'(_els, __TopXMLNS, - [encode_block_item(Items, __TopXMLNS) | _acc]). - -decode_block_item(__TopXMLNS, __IgnoreEls, - {xmlel, <<"item">>, _attrs, _els}) -> - Jid = decode_block_item_attrs(__TopXMLNS, _attrs, - undefined), - Jid. - -decode_block_item_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], _Jid) -> - decode_block_item_attrs(__TopXMLNS, _attrs, _val); -decode_block_item_attrs(__TopXMLNS, [_ | _attrs], - Jid) -> - decode_block_item_attrs(__TopXMLNS, _attrs, Jid); -decode_block_item_attrs(__TopXMLNS, [], Jid) -> - decode_block_item_attr_jid(__TopXMLNS, Jid). - -encode_block_item(Jid, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:blocking">>, [], - __TopXMLNS), - _els = [], - _attrs = encode_block_item_attr_jid(Jid, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"item">>, _attrs, _els}. - -decode_block_item_attr_jid(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"jid">>, <<"item">>, __TopXMLNS}}); -decode_block_item_attr_jid(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"jid">>, <<"item">>, __TopXMLNS}}); - _res -> _res - end. - -encode_block_item_attr_jid(_val, _acc) -> - [{<<"jid">>, enc_jid(_val)} | _acc]. - -decode_privacy(__TopXMLNS, __IgnoreEls, - {xmlel, <<"query">>, _attrs, _els}) -> - {Lists, Default, Active} = - decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, [], - undefined, undefined), - {privacy_query, Lists, Default, Active}. - -decode_privacy_els(__TopXMLNS, __IgnoreEls, [], Lists, - Default, Active) -> - {lists:reverse(Lists), Default, Active}; -decode_privacy_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"list">>, _attrs, _} = _el | _els], Lists, - Default, Active) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:privacy">> -> - decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, - [decode_privacy_list(__TopXMLNS, __IgnoreEls, _el) - | Lists], - Default, Active); - <<"jabber:iq:privacy">> -> - decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, - [decode_privacy_list(<<"jabber:iq:privacy">>, - __IgnoreEls, _el) - | Lists], - Default, Active); - _ -> - decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, Lists, - Default, Active) - end; -decode_privacy_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"default">>, _attrs, _} = _el | _els], Lists, - Default, Active) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:privacy">> -> - decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, Lists, - decode_privacy_default_list(__TopXMLNS, - __IgnoreEls, _el), - Active); - <<"jabber:iq:privacy">> -> - decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, Lists, - decode_privacy_default_list(<<"jabber:iq:privacy">>, - __IgnoreEls, _el), - Active); - _ -> - decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, Lists, - Default, Active) - end; -decode_privacy_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"active">>, _attrs, _} = _el | _els], Lists, - Default, Active) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:privacy">> -> - decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, Lists, - Default, - decode_privacy_active_list(__TopXMLNS, __IgnoreEls, - _el)); - <<"jabber:iq:privacy">> -> - decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, Lists, - Default, - decode_privacy_active_list(<<"jabber:iq:privacy">>, - __IgnoreEls, _el)); - _ -> - decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, Lists, - Default, Active) - end; -decode_privacy_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Lists, Default, Active) -> - decode_privacy_els(__TopXMLNS, __IgnoreEls, _els, Lists, - Default, Active). - -encode_privacy({privacy_query, Lists, Default, Active}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:privacy">>, [], - __TopXMLNS), - _els = lists:reverse('encode_privacy_$lists'(Lists, - __NewTopXMLNS, - 'encode_privacy_$default'(Default, - __NewTopXMLNS, - 'encode_privacy_$active'(Active, - __NewTopXMLNS, - [])))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"query">>, _attrs, _els}. - -'encode_privacy_$lists'([], __TopXMLNS, _acc) -> _acc; -'encode_privacy_$lists'([Lists | _els], __TopXMLNS, - _acc) -> - 'encode_privacy_$lists'(_els, __TopXMLNS, - [encode_privacy_list(Lists, __TopXMLNS) | _acc]). - -'encode_privacy_$default'(undefined, __TopXMLNS, - _acc) -> - _acc; -'encode_privacy_$default'(Default, __TopXMLNS, _acc) -> - [encode_privacy_default_list(Default, __TopXMLNS) - | _acc]. - -'encode_privacy_$active'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_privacy_$active'(Active, __TopXMLNS, _acc) -> - [encode_privacy_active_list(Active, __TopXMLNS) | _acc]. - -decode_privacy_active_list(__TopXMLNS, __IgnoreEls, - {xmlel, <<"active">>, _attrs, _els}) -> - Name = decode_privacy_active_list_attrs(__TopXMLNS, - _attrs, undefined), - Name. - -decode_privacy_active_list_attrs(__TopXMLNS, - [{<<"name">>, _val} | _attrs], _Name) -> - decode_privacy_active_list_attrs(__TopXMLNS, _attrs, - _val); -decode_privacy_active_list_attrs(__TopXMLNS, - [_ | _attrs], Name) -> - decode_privacy_active_list_attrs(__TopXMLNS, _attrs, - Name); -decode_privacy_active_list_attrs(__TopXMLNS, [], - Name) -> - decode_privacy_active_list_attr_name(__TopXMLNS, Name). - -encode_privacy_active_list(Name, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:privacy">>, [], - __TopXMLNS), - _els = [], - _attrs = encode_privacy_active_list_attr_name(Name, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"active">>, _attrs, _els}. - -decode_privacy_active_list_attr_name(__TopXMLNS, - undefined) -> - none; -decode_privacy_active_list_attr_name(__TopXMLNS, - _val) -> - _val. - -encode_privacy_active_list_attr_name(none, _acc) -> - _acc; -encode_privacy_active_list_attr_name(_val, _acc) -> - [{<<"name">>, _val} | _acc]. - -decode_privacy_default_list(__TopXMLNS, __IgnoreEls, - {xmlel, <<"default">>, _attrs, _els}) -> - Name = decode_privacy_default_list_attrs(__TopXMLNS, - _attrs, undefined), - Name. - -decode_privacy_default_list_attrs(__TopXMLNS, - [{<<"name">>, _val} | _attrs], _Name) -> - decode_privacy_default_list_attrs(__TopXMLNS, _attrs, - _val); -decode_privacy_default_list_attrs(__TopXMLNS, - [_ | _attrs], Name) -> - decode_privacy_default_list_attrs(__TopXMLNS, _attrs, - Name); -decode_privacy_default_list_attrs(__TopXMLNS, [], - Name) -> - decode_privacy_default_list_attr_name(__TopXMLNS, Name). - -encode_privacy_default_list(Name, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:privacy">>, [], - __TopXMLNS), - _els = [], - _attrs = encode_privacy_default_list_attr_name(Name, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"default">>, _attrs, _els}. - -decode_privacy_default_list_attr_name(__TopXMLNS, - undefined) -> - none; -decode_privacy_default_list_attr_name(__TopXMLNS, - _val) -> - _val. - -encode_privacy_default_list_attr_name(none, _acc) -> - _acc; -encode_privacy_default_list_attr_name(_val, _acc) -> - [{<<"name">>, _val} | _acc]. - -decode_privacy_list(__TopXMLNS, __IgnoreEls, - {xmlel, <<"list">>, _attrs, _els}) -> - Items = decode_privacy_list_els(__TopXMLNS, __IgnoreEls, - _els, []), - Name = decode_privacy_list_attrs(__TopXMLNS, _attrs, - undefined), - {privacy_list, Name, Items}. - -decode_privacy_list_els(__TopXMLNS, __IgnoreEls, [], - Items) -> - lists:reverse(Items); -decode_privacy_list_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:privacy">> -> - decode_privacy_list_els(__TopXMLNS, __IgnoreEls, _els, - [decode_privacy_item(__TopXMLNS, __IgnoreEls, - _el) - | Items]); - <<"jabber:iq:privacy">> -> - decode_privacy_list_els(__TopXMLNS, __IgnoreEls, _els, - [decode_privacy_item(<<"jabber:iq:privacy">>, - __IgnoreEls, _el) - | Items]); - _ -> - decode_privacy_list_els(__TopXMLNS, __IgnoreEls, _els, - Items) - end; -decode_privacy_list_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Items) -> - decode_privacy_list_els(__TopXMLNS, __IgnoreEls, _els, - Items). - -decode_privacy_list_attrs(__TopXMLNS, - [{<<"name">>, _val} | _attrs], _Name) -> - decode_privacy_list_attrs(__TopXMLNS, _attrs, _val); -decode_privacy_list_attrs(__TopXMLNS, [_ | _attrs], - Name) -> - decode_privacy_list_attrs(__TopXMLNS, _attrs, Name); -decode_privacy_list_attrs(__TopXMLNS, [], Name) -> - decode_privacy_list_attr_name(__TopXMLNS, Name). - -encode_privacy_list({privacy_list, Name, Items}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:privacy">>, [], - __TopXMLNS), - _els = lists:reverse('encode_privacy_list_$items'(Items, - __NewTopXMLNS, [])), - _attrs = encode_privacy_list_attr_name(Name, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"list">>, _attrs, _els}. - -'encode_privacy_list_$items'([], __TopXMLNS, _acc) -> - _acc; -'encode_privacy_list_$items'([Items | _els], __TopXMLNS, - _acc) -> - 'encode_privacy_list_$items'(_els, __TopXMLNS, - [encode_privacy_item(Items, __TopXMLNS) - | _acc]). - -decode_privacy_list_attr_name(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"name">>, <<"list">>, __TopXMLNS}}); -decode_privacy_list_attr_name(__TopXMLNS, _val) -> _val. - -encode_privacy_list_attr_name(_val, _acc) -> - [{<<"name">>, _val} | _acc]. - -decode_privacy_item(__TopXMLNS, __IgnoreEls, - {xmlel, <<"item">>, _attrs, _els}) -> - {Iq, Presence_out, Message, Presence_in} = - decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, - false, false, false, false), - {Action, Order, Type, Value} = - decode_privacy_item_attrs(__TopXMLNS, _attrs, undefined, - undefined, undefined, undefined), - {privacy_item, Order, Action, Type, Value, Message, Iq, - Presence_in, Presence_out}. - -decode_privacy_item_els(__TopXMLNS, __IgnoreEls, [], Iq, - Presence_out, Message, Presence_in) -> - {Iq, Presence_out, Message, Presence_in}; -decode_privacy_item_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"message">>, _attrs, _} = _el | _els], Iq, - Presence_out, Message, Presence_in) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:privacy">> -> - decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, - Iq, Presence_out, - decode_privacy_message(__TopXMLNS, - __IgnoreEls, _el), - Presence_in); - <<"jabber:iq:privacy">> -> - decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, - Iq, Presence_out, - decode_privacy_message(<<"jabber:iq:privacy">>, - __IgnoreEls, _el), - Presence_in); - _ -> - decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, - Iq, Presence_out, Message, Presence_in) - end; -decode_privacy_item_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"iq">>, _attrs, _} = _el | _els], Iq, - Presence_out, Message, Presence_in) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:privacy">> -> - decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, - decode_privacy_iq(__TopXMLNS, __IgnoreEls, - _el), - Presence_out, Message, Presence_in); - <<"jabber:iq:privacy">> -> - decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, - decode_privacy_iq(<<"jabber:iq:privacy">>, - __IgnoreEls, _el), - Presence_out, Message, Presence_in); - _ -> - decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, - Iq, Presence_out, Message, Presence_in) - end; -decode_privacy_item_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"presence-in">>, _attrs, _} = _el | _els], - Iq, Presence_out, Message, Presence_in) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:privacy">> -> - decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, - Iq, Presence_out, Message, - decode_privacy_presence_in(__TopXMLNS, - __IgnoreEls, _el)); - <<"jabber:iq:privacy">> -> - decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, - Iq, Presence_out, Message, - decode_privacy_presence_in(<<"jabber:iq:privacy">>, - __IgnoreEls, _el)); - _ -> - decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, - Iq, Presence_out, Message, Presence_in) - end; -decode_privacy_item_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"presence-out">>, _attrs, _} = _el | _els], - Iq, Presence_out, Message, Presence_in) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:privacy">> -> - decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, - Iq, - decode_privacy_presence_out(__TopXMLNS, - __IgnoreEls, _el), - Message, Presence_in); - <<"jabber:iq:privacy">> -> - decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, - Iq, - decode_privacy_presence_out(<<"jabber:iq:privacy">>, - __IgnoreEls, _el), - Message, Presence_in); - _ -> - decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, - Iq, Presence_out, Message, Presence_in) - end; -decode_privacy_item_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Iq, Presence_out, Message, Presence_in) -> - decode_privacy_item_els(__TopXMLNS, __IgnoreEls, _els, - Iq, Presence_out, Message, Presence_in). - -decode_privacy_item_attrs(__TopXMLNS, - [{<<"action">>, _val} | _attrs], _Action, Order, Type, - Value) -> - decode_privacy_item_attrs(__TopXMLNS, _attrs, _val, - Order, Type, Value); -decode_privacy_item_attrs(__TopXMLNS, - [{<<"order">>, _val} | _attrs], Action, _Order, Type, - Value) -> - decode_privacy_item_attrs(__TopXMLNS, _attrs, Action, - _val, Type, Value); -decode_privacy_item_attrs(__TopXMLNS, - [{<<"type">>, _val} | _attrs], Action, Order, _Type, - Value) -> - decode_privacy_item_attrs(__TopXMLNS, _attrs, Action, - Order, _val, Value); -decode_privacy_item_attrs(__TopXMLNS, - [{<<"value">>, _val} | _attrs], Action, Order, Type, - _Value) -> - decode_privacy_item_attrs(__TopXMLNS, _attrs, Action, - Order, Type, _val); -decode_privacy_item_attrs(__TopXMLNS, [_ | _attrs], - Action, Order, Type, Value) -> - decode_privacy_item_attrs(__TopXMLNS, _attrs, Action, - Order, Type, Value); -decode_privacy_item_attrs(__TopXMLNS, [], Action, Order, - Type, Value) -> - {decode_privacy_item_attr_action(__TopXMLNS, Action), - decode_privacy_item_attr_order(__TopXMLNS, Order), - decode_privacy_item_attr_type(__TopXMLNS, Type), - decode_privacy_item_attr_value(__TopXMLNS, Value)}. - -encode_privacy_item({privacy_item, Order, Action, Type, - Value, Message, Iq, Presence_in, Presence_out}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:privacy">>, [], - __TopXMLNS), - _els = lists:reverse('encode_privacy_item_$iq'(Iq, - __NewTopXMLNS, - 'encode_privacy_item_$presence_out'(Presence_out, - __NewTopXMLNS, - 'encode_privacy_item_$message'(Message, - __NewTopXMLNS, - 'encode_privacy_item_$presence_in'(Presence_in, - __NewTopXMLNS, - []))))), - _attrs = encode_privacy_item_attr_value(Value, - encode_privacy_item_attr_type(Type, - encode_privacy_item_attr_order(Order, - encode_privacy_item_attr_action(Action, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))))), - {xmlel, <<"item">>, _attrs, _els}. - -'encode_privacy_item_$iq'(false, __TopXMLNS, _acc) -> - _acc; -'encode_privacy_item_$iq'(Iq, __TopXMLNS, _acc) -> - [encode_privacy_iq(Iq, __TopXMLNS) | _acc]. - -'encode_privacy_item_$presence_out'(false, __TopXMLNS, - _acc) -> - _acc; -'encode_privacy_item_$presence_out'(Presence_out, - __TopXMLNS, _acc) -> - [encode_privacy_presence_out(Presence_out, __TopXMLNS) - | _acc]. - -'encode_privacy_item_$message'(false, __TopXMLNS, - _acc) -> - _acc; -'encode_privacy_item_$message'(Message, __TopXMLNS, - _acc) -> - [encode_privacy_message(Message, __TopXMLNS) | _acc]. - -'encode_privacy_item_$presence_in'(false, __TopXMLNS, - _acc) -> - _acc; -'encode_privacy_item_$presence_in'(Presence_in, - __TopXMLNS, _acc) -> - [encode_privacy_presence_in(Presence_in, __TopXMLNS) - | _acc]. - -decode_privacy_item_attr_action(__TopXMLNS, - undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"action">>, <<"item">>, __TopXMLNS}}); -decode_privacy_item_attr_action(__TopXMLNS, _val) -> - case catch dec_enum(_val, [allow, deny]) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"action">>, <<"item">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_privacy_item_attr_action(_val, _acc) -> - [{<<"action">>, enc_enum(_val)} | _acc]. - -decode_privacy_item_attr_order(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"order">>, <<"item">>, __TopXMLNS}}); -decode_privacy_item_attr_order(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, infinity) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"order">>, <<"item">>, __TopXMLNS}}); - _res -> _res - end. - -encode_privacy_item_attr_order(_val, _acc) -> - [{<<"order">>, enc_int(_val)} | _acc]. - -decode_privacy_item_attr_type(__TopXMLNS, undefined) -> - undefined; -decode_privacy_item_attr_type(__TopXMLNS, _val) -> - case catch dec_enum(_val, [group, jid, subscription]) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"type">>, <<"item">>, __TopXMLNS}}); - _res -> _res - end. - -encode_privacy_item_attr_type(undefined, _acc) -> _acc; -encode_privacy_item_attr_type(_val, _acc) -> - [{<<"type">>, enc_enum(_val)} | _acc]. - -decode_privacy_item_attr_value(__TopXMLNS, undefined) -> - <<>>; -decode_privacy_item_attr_value(__TopXMLNS, _val) -> - _val. - -encode_privacy_item_attr_value(<<>>, _acc) -> _acc; -encode_privacy_item_attr_value(_val, _acc) -> - [{<<"value">>, _val} | _acc]. - -decode_privacy_presence_out(__TopXMLNS, __IgnoreEls, - {xmlel, <<"presence-out">>, _attrs, _els}) -> - true. - -encode_privacy_presence_out(true, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:privacy">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"presence-out">>, _attrs, _els}. - -decode_privacy_presence_in(__TopXMLNS, __IgnoreEls, - {xmlel, <<"presence-in">>, _attrs, _els}) -> - true. - -encode_privacy_presence_in(true, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:privacy">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"presence-in">>, _attrs, _els}. - -decode_privacy_iq(__TopXMLNS, __IgnoreEls, - {xmlel, <<"iq">>, _attrs, _els}) -> - true. - -encode_privacy_iq(true, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:privacy">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"iq">>, _attrs, _els}. - -decode_privacy_message(__TopXMLNS, __IgnoreEls, - {xmlel, <<"message">>, _attrs, _els}) -> - true. - -encode_privacy_message(true, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:privacy">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"message">>, _attrs, _els}. - -decode_rosterver_feature(__TopXMLNS, __IgnoreEls, - {xmlel, <<"ver">>, _attrs, _els}) -> - {rosterver_feature}. - -encode_rosterver_feature({rosterver_feature}, - __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"urn:xmpp:features:rosterver">>, [], - __TopXMLNS), - _els = [], - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"ver">>, _attrs, _els}. - -decode_roster_query(__TopXMLNS, __IgnoreEls, - {xmlel, <<"query">>, _attrs, _els}) -> - Items = decode_roster_query_els(__TopXMLNS, __IgnoreEls, - _els, []), - Ver = decode_roster_query_attrs(__TopXMLNS, _attrs, - undefined), - {roster_query, Items, Ver}. - -decode_roster_query_els(__TopXMLNS, __IgnoreEls, [], - Items) -> - lists:reverse(Items); -decode_roster_query_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"item">>, _attrs, _} = _el | _els], Items) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:roster">> -> - decode_roster_query_els(__TopXMLNS, __IgnoreEls, _els, - [decode_roster_item(__TopXMLNS, __IgnoreEls, - _el) - | Items]); - <<"jabber:iq:roster">> -> - decode_roster_query_els(__TopXMLNS, __IgnoreEls, _els, - [decode_roster_item(<<"jabber:iq:roster">>, - __IgnoreEls, _el) - | Items]); - _ -> - decode_roster_query_els(__TopXMLNS, __IgnoreEls, _els, - Items) - end; -decode_roster_query_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Items) -> - decode_roster_query_els(__TopXMLNS, __IgnoreEls, _els, - Items). - -decode_roster_query_attrs(__TopXMLNS, - [{<<"ver">>, _val} | _attrs], _Ver) -> - decode_roster_query_attrs(__TopXMLNS, _attrs, _val); -decode_roster_query_attrs(__TopXMLNS, [_ | _attrs], - Ver) -> - decode_roster_query_attrs(__TopXMLNS, _attrs, Ver); -decode_roster_query_attrs(__TopXMLNS, [], Ver) -> - decode_roster_query_attr_ver(__TopXMLNS, Ver). - -encode_roster_query({roster_query, Items, Ver}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:roster">>, - [], __TopXMLNS), - _els = lists:reverse('encode_roster_query_$items'(Items, - __NewTopXMLNS, [])), - _attrs = encode_roster_query_attr_ver(Ver, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"query">>, _attrs, _els}. - -'encode_roster_query_$items'([], __TopXMLNS, _acc) -> - _acc; -'encode_roster_query_$items'([Items | _els], __TopXMLNS, - _acc) -> - 'encode_roster_query_$items'(_els, __TopXMLNS, - [encode_roster_item(Items, __TopXMLNS) - | _acc]). - -decode_roster_query_attr_ver(__TopXMLNS, undefined) -> - undefined; -decode_roster_query_attr_ver(__TopXMLNS, _val) -> _val. - -encode_roster_query_attr_ver(undefined, _acc) -> _acc; -encode_roster_query_attr_ver(_val, _acc) -> - [{<<"ver">>, _val} | _acc]. - -decode_roster_item(__TopXMLNS, __IgnoreEls, - {xmlel, <<"item">>, _attrs, _els}) -> - Groups = decode_roster_item_els(__TopXMLNS, __IgnoreEls, - _els, []), - {Jid, Name, Subscription, Ask} = - decode_roster_item_attrs(__TopXMLNS, _attrs, undefined, - undefined, undefined, undefined), - {roster_item, Jid, Name, Groups, Subscription, Ask}. - -decode_roster_item_els(__TopXMLNS, __IgnoreEls, [], - Groups) -> - lists:reverse(Groups); -decode_roster_item_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"group">>, _attrs, _} = _el | _els], - Groups) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:roster">> -> - decode_roster_item_els(__TopXMLNS, __IgnoreEls, _els, - [decode_roster_group(__TopXMLNS, __IgnoreEls, - _el) - | Groups]); - <<"jabber:iq:roster">> -> - decode_roster_item_els(__TopXMLNS, __IgnoreEls, _els, - [decode_roster_group(<<"jabber:iq:roster">>, - __IgnoreEls, _el) - | Groups]); - _ -> - decode_roster_item_els(__TopXMLNS, __IgnoreEls, _els, - Groups) - end; -decode_roster_item_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Groups) -> - decode_roster_item_els(__TopXMLNS, __IgnoreEls, _els, - Groups). - -decode_roster_item_attrs(__TopXMLNS, - [{<<"jid">>, _val} | _attrs], _Jid, Name, Subscription, - Ask) -> - decode_roster_item_attrs(__TopXMLNS, _attrs, _val, Name, - Subscription, Ask); -decode_roster_item_attrs(__TopXMLNS, - [{<<"name">>, _val} | _attrs], Jid, _Name, - Subscription, Ask) -> - decode_roster_item_attrs(__TopXMLNS, _attrs, Jid, _val, - Subscription, Ask); -decode_roster_item_attrs(__TopXMLNS, - [{<<"subscription">>, _val} | _attrs], Jid, Name, - _Subscription, Ask) -> - decode_roster_item_attrs(__TopXMLNS, _attrs, Jid, Name, - _val, Ask); -decode_roster_item_attrs(__TopXMLNS, - [{<<"ask">>, _val} | _attrs], Jid, Name, Subscription, - _Ask) -> - decode_roster_item_attrs(__TopXMLNS, _attrs, Jid, Name, - Subscription, _val); -decode_roster_item_attrs(__TopXMLNS, [_ | _attrs], Jid, - Name, Subscription, Ask) -> - decode_roster_item_attrs(__TopXMLNS, _attrs, Jid, Name, - Subscription, Ask); -decode_roster_item_attrs(__TopXMLNS, [], Jid, Name, - Subscription, Ask) -> - {decode_roster_item_attr_jid(__TopXMLNS, Jid), - decode_roster_item_attr_name(__TopXMLNS, Name), - decode_roster_item_attr_subscription(__TopXMLNS, - Subscription), - decode_roster_item_attr_ask(__TopXMLNS, Ask)}. - -encode_roster_item({roster_item, Jid, Name, Groups, - Subscription, Ask}, - __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:roster">>, - [], __TopXMLNS), - _els = - lists:reverse('encode_roster_item_$groups'(Groups, - __NewTopXMLNS, [])), - _attrs = encode_roster_item_attr_ask(Ask, - encode_roster_item_attr_subscription(Subscription, - encode_roster_item_attr_name(Name, - encode_roster_item_attr_jid(Jid, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS))))), - {xmlel, <<"item">>, _attrs, _els}. - -'encode_roster_item_$groups'([], __TopXMLNS, _acc) -> - _acc; -'encode_roster_item_$groups'([Groups | _els], - __TopXMLNS, _acc) -> - 'encode_roster_item_$groups'(_els, __TopXMLNS, - [encode_roster_group(Groups, __TopXMLNS) - | _acc]). - -decode_roster_item_attr_jid(__TopXMLNS, undefined) -> - erlang:error({xmpp_codec, - {missing_attr, <<"jid">>, <<"item">>, __TopXMLNS}}); -decode_roster_item_attr_jid(__TopXMLNS, _val) -> - case catch dec_jid(_val) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"jid">>, <<"item">>, __TopXMLNS}}); - _res -> _res - end. - -encode_roster_item_attr_jid(_val, _acc) -> - [{<<"jid">>, enc_jid(_val)} | _acc]. - -decode_roster_item_attr_name(__TopXMLNS, undefined) -> - <<>>; -decode_roster_item_attr_name(__TopXMLNS, _val) -> _val. - -encode_roster_item_attr_name(<<>>, _acc) -> _acc; -encode_roster_item_attr_name(_val, _acc) -> - [{<<"name">>, _val} | _acc]. - -decode_roster_item_attr_subscription(__TopXMLNS, - undefined) -> - none; -decode_roster_item_attr_subscription(__TopXMLNS, - _val) -> - case catch dec_enum(_val, - [none, to, from, both, remove]) - of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"subscription">>, <<"item">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_roster_item_attr_subscription(none, _acc) -> - _acc; -encode_roster_item_attr_subscription(_val, _acc) -> - [{<<"subscription">>, enc_enum(_val)} | _acc]. - -decode_roster_item_attr_ask(__TopXMLNS, undefined) -> - undefined; -decode_roster_item_attr_ask(__TopXMLNS, _val) -> - case catch dec_enum(_val, [subscribe]) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"ask">>, <<"item">>, __TopXMLNS}}); - _res -> _res - end. - -encode_roster_item_attr_ask(undefined, _acc) -> _acc; -encode_roster_item_attr_ask(_val, _acc) -> - [{<<"ask">>, enc_enum(_val)} | _acc]. - -decode_roster_group(__TopXMLNS, __IgnoreEls, - {xmlel, <<"group">>, _attrs, _els}) -> - Cdata = decode_roster_group_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_roster_group_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_roster_group_cdata(__TopXMLNS, Cdata); -decode_roster_group_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_roster_group_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_roster_group_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_roster_group_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_roster_group(Cdata, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:roster">>, - [], __TopXMLNS), - _els = encode_roster_group_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"group">>, _attrs, _els}. - -decode_roster_group_cdata(__TopXMLNS, <<>>) -> - erlang:error({xmpp_codec, - {missing_cdata, <<>>, <<"group">>, __TopXMLNS}}); -decode_roster_group_cdata(__TopXMLNS, _val) -> _val. - -encode_roster_group_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_version(__TopXMLNS, __IgnoreEls, - {xmlel, <<"query">>, _attrs, _els}) -> - {Ver, Os, Name} = decode_version_els(__TopXMLNS, - __IgnoreEls, _els, undefined, - undefined, undefined), - {version, Name, Ver, Os}. - -decode_version_els(__TopXMLNS, __IgnoreEls, [], Ver, Os, - Name) -> - {Ver, Os, Name}; -decode_version_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"name">>, _attrs, _} = _el | _els], Ver, Os, - Name) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:version">> -> - decode_version_els(__TopXMLNS, __IgnoreEls, _els, Ver, - Os, - decode_version_name(__TopXMLNS, __IgnoreEls, _el)); - <<"jabber:iq:version">> -> - decode_version_els(__TopXMLNS, __IgnoreEls, _els, Ver, - Os, - decode_version_name(<<"jabber:iq:version">>, - __IgnoreEls, _el)); - _ -> - decode_version_els(__TopXMLNS, __IgnoreEls, _els, Ver, - Os, Name) - end; -decode_version_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"version">>, _attrs, _} = _el | _els], Ver, - Os, Name) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:version">> -> - decode_version_els(__TopXMLNS, __IgnoreEls, _els, - decode_version_ver(__TopXMLNS, __IgnoreEls, _el), - Os, Name); - <<"jabber:iq:version">> -> - decode_version_els(__TopXMLNS, __IgnoreEls, _els, - decode_version_ver(<<"jabber:iq:version">>, - __IgnoreEls, _el), - Os, Name); - _ -> - decode_version_els(__TopXMLNS, __IgnoreEls, _els, Ver, - Os, Name) - end; -decode_version_els(__TopXMLNS, __IgnoreEls, - [{xmlel, <<"os">>, _attrs, _} = _el | _els], Ver, Os, - Name) -> - case get_attr(<<"xmlns">>, _attrs) of - <<"">> when __TopXMLNS == <<"jabber:iq:version">> -> - decode_version_els(__TopXMLNS, __IgnoreEls, _els, Ver, - decode_version_os(__TopXMLNS, __IgnoreEls, _el), - Name); - <<"jabber:iq:version">> -> - decode_version_els(__TopXMLNS, __IgnoreEls, _els, Ver, - decode_version_os(<<"jabber:iq:version">>, - __IgnoreEls, _el), - Name); - _ -> - decode_version_els(__TopXMLNS, __IgnoreEls, _els, Ver, - Os, Name) - end; -decode_version_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Ver, Os, Name) -> - decode_version_els(__TopXMLNS, __IgnoreEls, _els, Ver, - Os, Name). - -encode_version({version, Name, Ver, Os}, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:version">>, [], - __TopXMLNS), - _els = lists:reverse('encode_version_$ver'(Ver, - __NewTopXMLNS, - 'encode_version_$os'(Os, - __NewTopXMLNS, - 'encode_version_$name'(Name, - __NewTopXMLNS, - [])))), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"query">>, _attrs, _els}. - -'encode_version_$ver'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_version_$ver'(Ver, __TopXMLNS, _acc) -> - [encode_version_ver(Ver, __TopXMLNS) | _acc]. - -'encode_version_$os'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_version_$os'(Os, __TopXMLNS, _acc) -> - [encode_version_os(Os, __TopXMLNS) | _acc]. - -'encode_version_$name'(undefined, __TopXMLNS, _acc) -> - _acc; -'encode_version_$name'(Name, __TopXMLNS, _acc) -> - [encode_version_name(Name, __TopXMLNS) | _acc]. - -decode_version_os(__TopXMLNS, __IgnoreEls, - {xmlel, <<"os">>, _attrs, _els}) -> - Cdata = decode_version_os_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_version_os_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_version_os_cdata(__TopXMLNS, Cdata); -decode_version_os_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_version_os_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_version_os_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_version_os_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_version_os(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:version">>, [], - __TopXMLNS), - _els = encode_version_os_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"os">>, _attrs, _els}. - -decode_version_os_cdata(__TopXMLNS, <<>>) -> - erlang:error({xmpp_codec, - {missing_cdata, <<>>, <<"os">>, __TopXMLNS}}); -decode_version_os_cdata(__TopXMLNS, _val) -> _val. - -encode_version_os_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_version_ver(__TopXMLNS, __IgnoreEls, - {xmlel, <<"version">>, _attrs, _els}) -> - Cdata = decode_version_ver_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_version_ver_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_version_ver_cdata(__TopXMLNS, Cdata); -decode_version_ver_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_version_ver_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_version_ver_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_version_ver_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_version_ver(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:version">>, [], - __TopXMLNS), - _els = encode_version_ver_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"version">>, _attrs, _els}. - -decode_version_ver_cdata(__TopXMLNS, <<>>) -> - erlang:error({xmpp_codec, - {missing_cdata, <<>>, <<"version">>, __TopXMLNS}}); -decode_version_ver_cdata(__TopXMLNS, _val) -> _val. - -encode_version_ver_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_version_name(__TopXMLNS, __IgnoreEls, - {xmlel, <<"name">>, _attrs, _els}) -> - Cdata = decode_version_name_els(__TopXMLNS, __IgnoreEls, - _els, <<>>), - Cdata. - -decode_version_name_els(__TopXMLNS, __IgnoreEls, [], - Cdata) -> - decode_version_name_cdata(__TopXMLNS, Cdata); -decode_version_name_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Cdata) -> - decode_version_name_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_version_name_els(__TopXMLNS, __IgnoreEls, - [_ | _els], Cdata) -> - decode_version_name_els(__TopXMLNS, __IgnoreEls, _els, - Cdata). - -encode_version_name(Cdata, __TopXMLNS) -> - __NewTopXMLNS = - choose_top_xmlns(<<"jabber:iq:version">>, [], - __TopXMLNS), - _els = encode_version_name_cdata(Cdata, []), - _attrs = enc_xmlns_attrs(__NewTopXMLNS, __TopXMLNS), - {xmlel, <<"name">>, _attrs, _els}. - -decode_version_name_cdata(__TopXMLNS, <<>>) -> - erlang:error({xmpp_codec, - {missing_cdata, <<>>, <<"name">>, __TopXMLNS}}); -decode_version_name_cdata(__TopXMLNS, _val) -> _val. - -encode_version_name_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. - -decode_last(__TopXMLNS, __IgnoreEls, - {xmlel, <<"query">>, _attrs, _els}) -> - Status = decode_last_els(__TopXMLNS, __IgnoreEls, _els, - <<>>), - Seconds = decode_last_attrs(__TopXMLNS, _attrs, - undefined), - {last, Seconds, Status}. - -decode_last_els(__TopXMLNS, __IgnoreEls, [], Status) -> - decode_last_cdata(__TopXMLNS, Status); -decode_last_els(__TopXMLNS, __IgnoreEls, - [{xmlcdata, _data} | _els], Status) -> - decode_last_els(__TopXMLNS, __IgnoreEls, _els, - <>); -decode_last_els(__TopXMLNS, __IgnoreEls, [_ | _els], - Status) -> - decode_last_els(__TopXMLNS, __IgnoreEls, _els, Status). - -decode_last_attrs(__TopXMLNS, - [{<<"seconds">>, _val} | _attrs], _Seconds) -> - decode_last_attrs(__TopXMLNS, _attrs, _val); -decode_last_attrs(__TopXMLNS, [_ | _attrs], Seconds) -> - decode_last_attrs(__TopXMLNS, _attrs, Seconds); -decode_last_attrs(__TopXMLNS, [], Seconds) -> - decode_last_attr_seconds(__TopXMLNS, Seconds). - -encode_last({last, Seconds, Status}, __TopXMLNS) -> - __NewTopXMLNS = choose_top_xmlns(<<"jabber:iq:last">>, - [], __TopXMLNS), - _els = encode_last_cdata(Status, []), - _attrs = encode_last_attr_seconds(Seconds, - enc_xmlns_attrs(__NewTopXMLNS, - __TopXMLNS)), - {xmlel, <<"query">>, _attrs, _els}. - -decode_last_attr_seconds(__TopXMLNS, undefined) -> - undefined; -decode_last_attr_seconds(__TopXMLNS, _val) -> - case catch dec_int(_val, 0, infinity) of - {'EXIT', _} -> - erlang:error({xmpp_codec, - {bad_attr_value, <<"seconds">>, <<"query">>, - __TopXMLNS}}); - _res -> _res - end. - -encode_last_attr_seconds(undefined, _acc) -> _acc; -encode_last_attr_seconds(_val, _acc) -> - [{<<"seconds">>, enc_int(_val)} | _acc]. - -decode_last_cdata(__TopXMLNS, <<>>) -> <<>>; -decode_last_cdata(__TopXMLNS, _val) -> _val. - -encode_last_cdata(<<>>, _acc) -> _acc; -encode_last_cdata(_val, _acc) -> - [{xmlcdata, _val} | _acc]. From de7a143a2c2d9e6b74e4270afda26458e72684ee Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sat, 19 Nov 2016 13:05:13 +0300 Subject: [PATCH 102/151] Transform ejabberd_commands on the start --- src/ejabberd_commands.erl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ejabberd_commands.erl b/src/ejabberd_commands.erl index 8d74ad5a2..6172b18ed 100644 --- a/src/ejabberd_commands.erl +++ b/src/ejabberd_commands.erl @@ -277,6 +277,10 @@ get_commands_spec() -> args_example = ["/home/me/docs/api.html", "mod_admin", "java,json"], result_example = ok}]. init() -> + try mnesia:transform_table(ejabberd_commands, ignore, + record_info(fields, ejabberd_commands)) + catch exit:{aborted, {no_exists, _}} -> ok + end, mnesia:create_table(ejabberd_commands, [{ram_copies, [node()]}, {local_content, true}, From 13c603970043c556e6e5f1a598c967c5db14f5f9 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sat, 19 Nov 2016 13:57:25 +0300 Subject: [PATCH 103/151] Use xmpp_util.erl from XMPP library --- rebar.config | 2 +- src/xmpp_util.erl | 169 ---------------------------------------------- 2 files changed, 1 insertion(+), 170 deletions(-) delete mode 100644 src/xmpp_util.erl diff --git a/rebar.config b/rebar.config index 0fa157e7a..6db14c87b 100644 --- a/rebar.config +++ b/rebar.config @@ -13,7 +13,7 @@ {fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.7"}}}, {stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.6"}}}, {fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.16"}}}, - {xmpp, ".*", {git, "https://github.com/processone/xmpp", {tag, "1.0.2"}}}, + {xmpp, ".*", {git, "https://github.com/processone/xmpp", {tag, "1.0.3"}}}, {stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.7"}}}, {esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.8"}}}, {fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.6"}}}, diff --git a/src/xmpp_util.erl b/src/xmpp_util.erl deleted file mode 100644 index 22b8ea597..000000000 --- a/src/xmpp_util.erl +++ /dev/null @@ -1,169 +0,0 @@ -%%%------------------------------------------------------------------- -%%% @author Evgeny Khramtsov -%%% @copyright (C) 2016, Evgeny Khramtsov -%%% @doc -%%% -%%% @end -%%% Created : 12 Jul 2016 by Evgeny Khramtsov -%%%------------------------------------------------------------------- --module(xmpp_util). - -%% API --export([add_delay_info/3, add_delay_info/4, unwrap_carbon/1, - is_standalone_chat_state/1, get_xdata_values/2, - set_xdata_field/2, has_xdata_var/2, - make_adhoc_response/1, make_adhoc_response/2, - decode_timestamp/1, encode_timestamp/1]). - --include("xmpp.hrl"). - -%%%=================================================================== -%%% API -%%%=================================================================== --spec add_delay_info(stanza(), jid(), erlang:timestamp()) -> stanza(). -add_delay_info(Stz, From, Time) -> - add_delay_info(Stz, From, Time, <<"">>). - --spec add_delay_info(stanza(), jid(), - erlang:timestamp(), binary()) -> stanza(). - -add_delay_info(Stz, From, Time, Desc) -> - NewDelay = #delay{stamp = Time, from = From, desc = Desc}, - case xmpp:get_subtag(Stz, #delay{}) of - #delay{from = OldFrom} -> - case jid:tolower(From) == jid:tolower(OldFrom) of - false -> - xmpp:set_subtag(Stz, NewDelay); - true -> - xmpp:append_subtags(Stz, [NewDelay]) - end; - false -> - xmpp:append_subtags(Stz, [NewDelay]) - end. - --spec unwrap_carbon(stanza()) -> xmpp_element(). -unwrap_carbon(#message{} = Msg) -> - try - case xmpp:get_subtag(Msg, #carbons_sent{}) of - #carbons_sent{forwarded = #forwarded{xml_els = [El]}} -> - xmpp:decode(El, ?NS_CLIENT, [ignore_els]); - _ -> - case xmpp:get_subtag(Msg, #carbons_received{}) of - #carbons_received{forwarded = #forwarded{xml_els = [El]}} -> - xmpp:decode(El, ?NS_CLIENT, [ignore_els]); - _ -> - Msg - end - end - catch _:{xmpp_codec, _} -> - Msg - end; -unwrap_carbon(Stanza) -> Stanza. - --spec is_standalone_chat_state(stanza()) -> boolean(). -is_standalone_chat_state(Stanza) -> - case unwrap_carbon(Stanza) of - #message{body = [], subject = [], sub_els = Els} -> - IgnoreNS = [?NS_CHATSTATES, ?NS_DELAY, ?NS_EVENT], - Stripped = [El || El <- Els, - not lists:member(xmpp:get_ns(El), IgnoreNS)], - Stripped == []; - _ -> - false - end. - --spec get_xdata_values(binary(), xdata()) -> [binary()]. -get_xdata_values(Var, #xdata{fields = Fields}) -> - case lists:keyfind(Var, #xdata_field.var, Fields) of - #xdata_field{values = Vals} -> Vals; - false -> [] - end. - --spec set_xdata_field(xdata_field(), xdata()) -> xdata(). -set_xdata_field(Field, #xdata{fields = Fields} = X) -> - NewFields = lists:keystore(Field#xdata_field.var, #xdata_field.var, - Fields, Field), - X#xdata{fields = NewFields}. - --spec has_xdata_var(binary(), xdata()) -> boolean(). -has_xdata_var(Var, #xdata{fields = Fields}) -> - lists:keymember(Var, #xdata_field.var, Fields). - --spec make_adhoc_response(adhoc_command(), adhoc_command()) -> adhoc_command(). -make_adhoc_response(#adhoc_command{lang = Lang, node = Node, sid = SID}, - Command) -> - make_adhoc_response( - Command#adhoc_command{lang = Lang, node = Node, sid = SID}). - --spec make_adhoc_response(adhoc_command()) -> adhoc_command(). -make_adhoc_response(#adhoc_command{sid = <<"">>, - status = Status, - actions = Actions} = Command) -> - SID = encode_timestamp(p1_time_compat:timestamp()), - NewActions = if Actions == undefined, Status /= completed -> - #adhoc_actions{execute = complete, complete = true}; - true -> - undefined - end, - Command#adhoc_command{sid = SID, actions = NewActions}; -make_adhoc_response(Command) -> - Command. - --spec decode_timestamp(binary()) -> erlang:timestamp(). -decode_timestamp(S) -> - try try_decode_timestamp(S) - catch _:_ -> erlang:error({bad_timestamp, S}) - end. - --spec encode_timestamp(erlang:timestamp()) -> binary(). -encode_timestamp({MegaSecs, Secs, MicroSecs}) -> - {{Year, Month, Day}, {Hour, Minute, Second}} = - calendar:now_to_universal_time({MegaSecs, Secs, MicroSecs}), - Fraction = if MicroSecs > 0 -> - io_lib:format(".~6..0B", [MicroSecs]); - true -> - "" - end, - list_to_binary(io_lib:format("~4..0B-~2..0B-~2..0BT" - "~2..0B:~2..0B:~2..0B~sZ", - [Year, Month, Day, Hour, Minute, Second, - Fraction])). - -%%%=================================================================== -%%% Internal functions -%%%=================================================================== -try_decode_timestamp(<>) -> - Date = {to_integer(Y, 1970, 9999), to_integer(Mo, 1, 12), to_integer(D, 1, 31)}, - Time = {to_integer(H, 0, 23), to_integer(Mi, 0, 59), to_integer(S, 0, 59)}, - {MS, {TZH, TZM}} = try_decode_fraction(T), - Seconds = calendar:datetime_to_gregorian_seconds({Date, Time}) - - calendar:datetime_to_gregorian_seconds({{1970,1,1}, {0,0,0}}) - - TZH * 60 * 60 - TZM * 60, - {Seconds div 1000000, Seconds rem 1000000, MS}; -try_decode_timestamp(<>) -> - try_decode_timestamp(<>). - -try_decode_fraction(<<$., T/binary>>) -> - {match, [V]} = re:run(T, <<"^[0-9]+">>, [{capture, [0], list}]), - Size = length(V), - <<_:Size/binary, TZD/binary>> = T, - {list_to_integer(string:left(V, 6, $0)), - try_decode_tzd(TZD)}; -try_decode_fraction(TZD) -> - {0, try_decode_tzd(TZD)}. - -try_decode_tzd(<<$Z>>) -> - {0, 0}; -try_decode_tzd(<<$-, H:2/binary, $:, M:2/binary>>) -> - {-1 * to_integer(H, 0, 12), to_integer(M, 0, 59)}; -try_decode_tzd(<<$+, H:2/binary, $:, M:2/binary>>) -> - {to_integer(H, 0, 12), to_integer(M, 0, 59)}. - -to_integer(S, Min, Max) -> - case binary_to_integer(S) of - I when I >= Min, I =< Max -> - I - end. From 049a6d97f1216b831e7cc3b1ebaf85564082a4d3 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sun, 20 Nov 2016 18:08:49 +0300 Subject: [PATCH 104/151] Fix RSM for conference disco#items --- src/mod_muc.erl | 223 ++++++++++++++++++++++++++----------------- src/mod_muc_room.erl | 3 +- 2 files changed, 138 insertions(+), 88 deletions(-) diff --git a/src/mod_muc.erl b/src/mod_muc.erl index ea8bff5e3..9b475f69d 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -62,7 +62,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). - +-include_lib("stdlib/include/ms_transform.hrl"). -include("xmpp.hrl"). -include("mod_muc.hrl"). @@ -175,8 +175,10 @@ init([Host, Opts]) -> <<"conference.@HOST@">>), Mod = gen_mod:db_mod(Host, Opts, ?MODULE), Mod:init(Host, [{host, MyHost}|Opts]), + update_tables(), mnesia:create_table(muc_online_room, [{ram_copies, [node()]}, + {type, ordered_set}, {attributes, record_info(fields, muc_online_room)}]), mnesia:add_table_copy(muc_online_room, node(), ram_copies), catch ets:new(muc_online_users, [bag, named_table, public, {keypos, 2}]), @@ -497,8 +499,12 @@ process_disco_items(#iq{type = get, from = From, to = To, lang = Lang, ServerHost, ?MODULE, max_rooms_discoitems, fun(I) when is_integer(I), I>=0 -> I end, 100), - Items = iq_disco_items(Host, From, Lang, MaxRoomsDiscoItems, Node, RSM), - xmpp:make_iq_result(IQ, #disco_items{node = Node, items = Items}); + case iq_disco_items(Host, From, Lang, MaxRoomsDiscoItems, Node, RSM) of + {error, Err} -> + xmpp:make_error(IQ, Err); + {result, Result} -> + xmpp:make_iq_result(IQ, Result) + end; process_disco_items(#iq{lang = Lang} = IQ) -> Txt = <<"No module is handling this query">>, xmpp:make_error(IQ, xmpp:err_service_unavailable(Txt, Lang)). @@ -597,76 +603,112 @@ register_room(Host, Room, Pid) -> end, mnesia:transaction(F). -iq_disco_items(Host, From, Lang, MaxRoomsDiscoItems, <<"">>, undefined) -> - Rooms = get_vh_rooms(Host), - case erlang:length(Rooms) < MaxRoomsDiscoItems of - true -> - iq_disco_items_list(Host, Rooms, {get_disco_item, all, From, Lang}); - false -> - iq_disco_items(Host, From, Lang, MaxRoomsDiscoItems, <<"nonemptyrooms">>, undefined) - end; -iq_disco_items(Host, From, Lang, _MaxRoomsDiscoItems, <<"nonemptyrooms">>, undefined) -> - Empty = #disco_item{jid = jid:make(<<"conference.localhost">>), - node = <<"emptyrooms">>, - name = translate:translate(Lang, <<"Empty Rooms">>)}, - Query = {get_disco_item, only_non_empty, From, Lang}, - [Empty | iq_disco_items_list(Host, get_vh_rooms(Host), Query)]; -iq_disco_items(Host, From, Lang, _MaxRoomsDiscoItems, <<"emptyrooms">>, undefined) -> - iq_disco_items_list(Host, get_vh_rooms(Host), {get_disco_item, 0, From, Lang}); -iq_disco_items(Host, From, Lang, _MaxRoomsDiscoItems, _DiscoNode, Rsm) -> - {Rooms, RsmO} = get_vh_rooms(Host, Rsm), - RsmOut = jlib:rsm_encode(RsmO), - iq_disco_items_list(Host, Rooms, {get_disco_item, all, From, Lang}) ++ RsmOut. +-spec iq_disco_items(binary(), jid(), binary(), integer(), binary(), + rsm_set() | undefined) -> + {result, disco_items()} | {error, stanza_error()}. +iq_disco_items(Host, From, Lang, MaxRoomsDiscoItems, Node, RSM) + when Node == <<"">>; Node == <<"nonemptyrooms">>; Node == <<"emptyrooms">> -> + Count = get_vh_rooms_count(Host), + Query = if Node == <<"">>, RSM == undefined, Count > MaxRoomsDiscoItems -> + {get_disco_item, only_non_empty, From, Lang}; + Node == <<"nonemptyrooms">> -> + {get_disco_item, only_non_empty, From, Lang}; + Node == <<"emptyrooms">> -> + {get_disco_item, 0, From, Lang}; + true -> + {get_disco_item, all, From, Lang} + end, + Items = get_vh_rooms(Host, Query, RSM), + ResRSM = case Items of + [_|_] when RSM /= undefined -> + #disco_item{jid = #jid{luser = First}} = hd(Items), + #disco_item{jid = #jid{luser = Last}} = lists:last(Items), + #rsm_set{first = #rsm_first{data = First}, + last = Last, + count = Count}; + [] when RSM /= undefined -> + #rsm_set{count = Count}; + _ -> + undefined + end, + {result, #disco_items{node = Node, items = Items, rsm = ResRSM}}; +iq_disco_items(_Host, _From, Lang, _MaxRoomsDiscoItems, _Node, _RSM) -> + {error, xmpp:err_item_not_found(<<"Node not found">>, Lang)}. -iq_disco_items_list(Host, Rooms, Query) -> - lists:zf( - fun(#muc_online_room{name_host = {Name, _Host}, pid = Pid}) -> - case catch gen_fsm:sync_send_all_state_event(Pid, Query, 100) of - {item, Desc} -> - flush(), - {true, #disco_item{jid = jid:make(Name, Host), - name = Desc}}; - _ -> - false - end - end, Rooms). +-spec get_vh_rooms(binary, term(), rsm_set() | undefined) -> [disco_item()]. +get_vh_rooms(Host, Query, + #rsm_set{max = Max, 'after' = After, before = undefined}) + when is_binary(After), After /= <<"">> -> + lists:reverse(get_vh_rooms(next, {After, Host}, Query, 0, Max, [])); +get_vh_rooms(Host, Query, + #rsm_set{max = Max, 'after' = undefined, before = Before}) + when is_binary(Before), Before /= <<"">> -> + get_vh_rooms(prev, {Before, Host}, Query, 0, Max, []); +get_vh_rooms(Host, Query, + #rsm_set{max = Max, 'after' = undefined, before = <<"">>}) -> + get_vh_rooms(last, {<<"">>, Host}, Query, 0, Max, []); +get_vh_rooms(Host, Query, #rsm_set{max = Max}) -> + lists:reverse(get_vh_rooms(first, {<<"">>, Host}, Query, 0, Max, [])); +get_vh_rooms(Host, Query, undefined) -> + lists:reverse(get_vh_rooms(first, {<<"">>, Host}, Query, 0, undefined, [])). -get_vh_rooms(_, _) -> - todo. - %% AllRooms = lists:sort(get_vh_rooms(Host)), - %% Count = erlang:length(AllRooms), - %% Guard = case Direction of - %% _ when Index =/= undefined -> [{'==', {element, 2, '$1'}, Host}]; - %% aft -> [{'==', {element, 2, '$1'}, Host}, {'>=',{element, 1, '$1'} ,I}]; - %% before when I =/= []-> [{'==', {element, 2, '$1'}, Host}, {'=<',{element, 1, '$1'} ,I}]; - %% _ -> [{'==', {element, 2, '$1'}, Host}] - %% end, - %% L = lists:sort( - %% mnesia:dirty_select(muc_online_room, - %% [{#muc_online_room{name_host = '$1', _ = '_'}, - %% Guard, - %% ['$_']}])), - %% L2 = if - %% Index == undefined andalso Direction == before -> - %% lists:reverse(lists:sublist(lists:reverse(L), 1, M)); - %% Index == undefined -> - %% lists:sublist(L, 1, M); - %% Index > Count orelse Index < 0 -> - %% []; - %% true -> - %% lists:sublist(L, Index+1, M) - %% end, - %% if L2 == [] -> {L2, #rsm_out{count = Count}}; - %% true -> - %% H = hd(L2), - %% NewIndex = get_room_pos(H, AllRooms), - %% T = lists:last(L2), - %% {F, _} = H#muc_online_room.name_host, - %% {Last, _} = T#muc_online_room.name_host, - %% {L2, - %% #rsm_out{first = F, last = Last, count = Count, - %% index = NewIndex}} - %% end. +-spec get_vh_rooms(prev | next | last | first, + {binary(), binary()}, term(), + non_neg_integer(), non_neg_integer() | undefined, + [disco_item()]) -> [disco_item()]. +get_vh_rooms(_Action, _Key, _Query, Count, Max, Items) when Count >= Max -> + Items; +get_vh_rooms(Action, {_, Host} = Key, Query, Count, Max, Items) -> + Call = fun() -> + case Action of + prev -> mnesia:dirty_prev(muc_online_room, Key); + next -> mnesia:dirty_next(muc_online_room, Key); + last -> mnesia:dirty_last(muc_online_room); + first -> mnesia:dirty_first(muc_online_room) + end + end, + NewAction = case Action of + last -> prev; + first -> next; + _ -> Action + end, + try Call() of + '$end_of_table' -> + Items; + {_, Host} = NewKey -> + case get_room_disco_item(NewKey, Query) of + {ok, Item} -> + get_vh_rooms(NewAction, NewKey, Query, + Count + 1, Max, [Item|Items]); + {error, _} -> + get_vh_rooms(NewAction, NewKey, Query, + Count, Max, Items) + end; + NewKey -> + get_vh_rooms(NewAction, NewKey, Query, Count, Max, Items) + catch _:{aborted, {badarg, _}} -> + Items + end. + +-spec get_room_disco_item({binary(), binary()}, term()) -> {ok, disco_item()} | + {error, timeout | notfound}. +get_room_disco_item({Name, Host}, Query) -> + case mnesia:dirty_read(muc_online_room, {Name, Host}) of + [#muc_online_room{pid = Pid}|_] -> + RoomJID = jid:make(Name, Host), + try gen_fsm:sync_send_all_state_event(Pid, Query, 100) of + {item, Desc} -> + {ok, #disco_item{jid = RoomJID, name = Desc}}; + false -> + {error, notfound} + catch _:{timeout, _} -> + {error, timeout}; + _:{noproc, _} -> + {error, notfound} + end; + _ -> + {error, notfound} + end. get_subscribed_rooms(_ServerHost, Host, From) -> Rooms = get_vh_rooms(Host), @@ -681,21 +723,6 @@ get_subscribed_rooms(_ServerHost, Host, From) -> [] end, Rooms). -%% @doc Return the position of desired room in the list of rooms. -%% The room must exist in the list. The count starts in 0. -%% @spec (Desired::muc_online_room(), Rooms::[muc_online_room()]) -> integer() -get_room_pos(Desired, Rooms) -> - get_room_pos(Desired, Rooms, 0). - -get_room_pos(Desired, [HeadRoom | _], HeadPosition) - when Desired#muc_online_room.name_host == - HeadRoom#muc_online_room.name_host -> - HeadPosition; -get_room_pos(Desired, [_ | Rooms], HeadPosition) -> - get_room_pos(Desired, Rooms, HeadPosition + 1). - -flush() -> receive _ -> flush() after 0 -> ok end. - get_nick(ServerHost, Host, From) -> LServer = jid:nameprep(ServerHost), Mod = gen_mod:db_mod(LServer, ?MODULE), @@ -782,6 +809,13 @@ get_vh_rooms(Host) -> [{'==', {element, 2, '$1'}, Host}], ['$_']}]). +-spec get_vh_rooms_count(binary()) -> non_neg_integer(). +get_vh_rooms_count(Host) -> + ets:select_count(muc_online_room, + ets:fun2ms( + fun(#muc_online_room{name_host = {_, H}}) -> + H == Host + end)). clean_table_from_bad_node(Node) -> F = fun() -> @@ -811,6 +845,23 @@ clean_table_from_bad_node(Node, Host) -> end, mnesia:async_dirty(F). +update_tables() -> + try + case mnesia:table_info(muc_online_room, type) of + ordered_set -> ok; + _ -> + case mnesia:delete_table(muc_online_room) of + {atomic, ok} -> ok; + Err -> erlang:error(Err) + end + end + catch _:{aborted, {no_exists, muc_online_room}} -> ok; + _:{aborted, {no_exists, muc_online_room, type}} -> ok; + E:R -> + ?ERROR_MSG("failed to update mnesia table '~s': ~p", + [muc_online_room, {E, R}]) + end. + opts_to_binary(Opts) -> lists:map( fun({title, Title}) -> diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl index 060ac2bcd..5b000548a 100644 --- a/src/mod_muc_room.erl +++ b/src/mod_muc_room.erl @@ -504,8 +504,7 @@ handle_event(_Event, StateName, StateData) -> {next_state, StateName, StateData}. handle_sync_event({get_disco_item, Filter, JID, Lang}, _From, StateName, StateData) -> - Len = ?DICT:fold(fun(_, _, Acc) -> Acc + 1 end, 0, - StateData#state.users), + Len = ?DICT:size(StateData#state.users), Reply = case (Filter == all) or (Filter == Len) or ((Filter /= 0) and (Len /= 0)) of true -> get_roomdesc_reply(JID, StateData, From c7ae916afc048e75f836344177f5411fccb5a00e Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Mon, 21 Nov 2016 10:23:09 +0300 Subject: [PATCH 105/151] Don't forget to start XMPP application --- src/ejabberd_app.erl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl index 1791aa790..e4333c816 100644 --- a/src/ejabberd_app.erl +++ b/src/ejabberd_app.erl @@ -43,7 +43,6 @@ start(normal, _Args) -> ejabberd_logger:start(), write_pid_file(), - jid:start(), start_apps(), start_elixir_application(), ejabberd:check_app(ejabberd), @@ -223,8 +222,7 @@ start_apps() -> ejabberd:start_app(ssl), ejabberd:start_app(fast_yaml), ejabberd:start_app(fast_tls), - ejabberd:start_app(fast_xml), - ejabberd:start_app(stringprep), + ejabberd:start_app(xmpp), ejabberd:start_app(cache_tab). opt_type(net_ticktime) -> From 3f91668c46c0eca28333fd2a749c67b75dc105a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Mon, 21 Nov 2016 09:52:29 +0100 Subject: [PATCH 106/151] Log more data for failed s2s connection --- src/ejabberd_s2s_out.erl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index 076ba2d3b..b9ce47830 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -231,10 +231,10 @@ open_socket(init, StateData) -> send_header(NewStateData, Version), {next_state, wait_for_stream, NewStateData, ?FSMTIMEOUT}; - {error, _Reason} -> + {error, Reason} -> ?INFO_MSG("s2s connection: ~s -> ~s (remote server " - "not found)", - [StateData#state.myname, StateData#state.server]), + "not found: ~p)", + [StateData#state.myname, StateData#state.server, Reason]), case ejabberd_hooks:run_fold(find_s2s_bridge, undefined, [StateData#state.myname, StateData#state.server]) From 507e756b69190ec1676a677b6a4a07b129f77cba Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Mon, 21 Nov 2016 12:13:34 +0300 Subject: [PATCH 107/151] Do not send empty tag --- test/mam_tests.erl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/mam_tests.erl b/test/mam_tests.erl index 9154ea240..d628ddd2a 100644 --- a/test/mam_tests.erl +++ b/test/mam_tests.erl @@ -513,7 +513,8 @@ query_rsm_after(Config, From, To, NS) -> #rsm_set{count = 5, first = First} = recv_fin(Config, ID, QID, NS, true), First - end, #rsm_first{}, [lists:seq(N, 5) || N <- lists:seq(1, 6)]). + end, #rsm_first{data = undefined}, + [lists:seq(N, 5) || N <- lists:seq(1, 6)]). query_rsm_before(Config, From, To) -> lists:foreach( From 274303f24829c347d91fa3f9e464b38cfa5b18c2 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Mon, 21 Nov 2016 12:14:24 +0300 Subject: [PATCH 108/151] Fix conference disco#items when running multiple virtual hosts --- src/mod_muc.erl | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/mod_muc.erl b/src/mod_muc.erl index 9b475f69d..1f8b2479c 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -639,26 +639,26 @@ iq_disco_items(_Host, _From, Lang, _MaxRoomsDiscoItems, _Node, _RSM) -> get_vh_rooms(Host, Query, #rsm_set{max = Max, 'after' = After, before = undefined}) when is_binary(After), After /= <<"">> -> - lists:reverse(get_vh_rooms(next, {After, Host}, Query, 0, Max, [])); + lists:reverse(get_vh_rooms(next, {After, Host}, Host, Query, 0, Max, [])); get_vh_rooms(Host, Query, #rsm_set{max = Max, 'after' = undefined, before = Before}) when is_binary(Before), Before /= <<"">> -> - get_vh_rooms(prev, {Before, Host}, Query, 0, Max, []); + get_vh_rooms(prev, {Before, Host}, Host, Query, 0, Max, []); get_vh_rooms(Host, Query, #rsm_set{max = Max, 'after' = undefined, before = <<"">>}) -> - get_vh_rooms(last, {<<"">>, Host}, Query, 0, Max, []); + get_vh_rooms(last, {<<"">>, Host}, Host, Query, 0, Max, []); get_vh_rooms(Host, Query, #rsm_set{max = Max}) -> - lists:reverse(get_vh_rooms(first, {<<"">>, Host}, Query, 0, Max, [])); + lists:reverse(get_vh_rooms(first, {<<"">>, Host}, Host, Query, 0, Max, [])); get_vh_rooms(Host, Query, undefined) -> - lists:reverse(get_vh_rooms(first, {<<"">>, Host}, Query, 0, undefined, [])). + lists:reverse(get_vh_rooms(first, {<<"">>, Host}, Host, Query, 0, undefined, [])). -spec get_vh_rooms(prev | next | last | first, - {binary(), binary()}, term(), + {binary(), binary()}, binary(), term(), non_neg_integer(), non_neg_integer() | undefined, [disco_item()]) -> [disco_item()]. -get_vh_rooms(_Action, _Key, _Query, Count, Max, Items) when Count >= Max -> +get_vh_rooms(_Action, _Key, _Host, _Query, Count, Max, Items) when Count >= Max -> Items; -get_vh_rooms(Action, {_, Host} = Key, Query, Count, Max, Items) -> +get_vh_rooms(Action, Key, Host, Query, Count, Max, Items) -> Call = fun() -> case Action of prev -> mnesia:dirty_prev(muc_online_room, Key); @@ -678,14 +678,14 @@ get_vh_rooms(Action, {_, Host} = Key, Query, Count, Max, Items) -> {_, Host} = NewKey -> case get_room_disco_item(NewKey, Query) of {ok, Item} -> - get_vh_rooms(NewAction, NewKey, Query, + get_vh_rooms(NewAction, NewKey, Host, Query, Count + 1, Max, [Item|Items]); {error, _} -> - get_vh_rooms(NewAction, NewKey, Query, + get_vh_rooms(NewAction, NewKey, Host, Query, Count, Max, Items) end; NewKey -> - get_vh_rooms(NewAction, NewKey, Query, Count, Max, Items) + get_vh_rooms(NewAction, NewKey, Host, Query, Count, Max, Items) catch _:{aborted, {badarg, _}} -> Items end. From c5e7b4738f6e2f2bf21da8530ebc4c9887cf1e44 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 21 Nov 2016 12:06:11 +0100 Subject: [PATCH 109/151] Fix handling mod_http_upload disco#info queries: need decoded elements As reported in https://www.ejabberd.im/forum/28605/ejabberd-modhttpupload-error-405-not-allowed --- src/mod_http_upload.erl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mod_http_upload.erl b/src/mod_http_upload.erl index 6ad18531c..1abde4f5b 100644 --- a/src/mod_http_upload.erl +++ b/src/mod_http_upload.erl @@ -360,7 +360,8 @@ handle_cast(Request, State) -> -spec handle_info(timeout | _, state()) -> {noreply, state()}. -handle_info({route, From, To, #iq{} = IQ}, State) -> +handle_info({route, From, To, #iq{} = Packet}, State) -> + IQ = xmpp:decode_els(Packet), {Reply, NewState} = case process_iq(From, IQ, State) of R when is_record(R, iq) -> {R, State}; From e57de02e0f30bf017c4c313049ddcb2f73909611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Mon, 21 Nov 2016 12:06:45 +0100 Subject: [PATCH 110/151] Fix s2s test --- test/ejabberd_SUITE_data/ejabberd.yml | 1 + test/suite.erl | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/test/ejabberd_SUITE_data/ejabberd.yml b/test/ejabberd_SUITE_data/ejabberd.yml index 29243d683..9d663a116 100644 --- a/test/ejabberd_SUITE_data/ejabberd.yml +++ b/test/ejabberd_SUITE_data/ejabberd.yml @@ -456,6 +456,7 @@ route_subdomains: s2s domain_certfile: CERTFILE s2s_use_starttls: false s2s_cafile: CAFILE +outgoing_s2s_port: @@s2s_port@@ shaper: fast: 50000 normal: 10000 diff --git a/test/suite.erl b/test/suite.erl index a288a5f66..e2390c599 100644 --- a/test/suite.erl +++ b/test/suite.erl @@ -142,7 +142,9 @@ process_config_tpl(Content, [{Name, DefaultValue} | Rest]) -> V3 -> V3 end, - NewContent = binary:replace(Content, <<"@@",(atom_to_binary(Name, latin1))/binary, "@@">>, Val), + NewContent = binary:replace(Content, + <<"@@",(atom_to_binary(Name,latin1))/binary, "@@">>, + Val, [global]), process_config_tpl(NewContent, Rest). stream_header(Config) -> From 04fdf69737c8219f052a5a538c94b8e955058b2c Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Mon, 21 Nov 2016 14:21:34 +0300 Subject: [PATCH 111/151] Fix non-empty disco-nodes processing --- src/mod_delegation.erl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mod_delegation.erl b/src/mod_delegation.erl index 571817963..2cf9525fc 100644 --- a/src/mod_delegation.erl +++ b/src/mod_delegation.erl @@ -344,7 +344,9 @@ disco_identity(Acc, _From, To, <<"">>, _Lang, Type) -> empty when Identities /= [] -> {result, Identities}; {result, Ids} -> {result, Ids ++ Identities}; Acc -> Acc - end. + end; +disco_identity(Acc, _From, _To, _Node, _Lang, _Type) -> + Acc. my_features(ejabberd_local) -> [?NS_DELEGATION]; my_features(ejabberd_sm) -> []. From b8e8e4b9712b411774edb40eb5e76a28020955cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Mon, 21 Nov 2016 12:25:50 +0100 Subject: [PATCH 112/151] Fix elixir tests --- test/acl_test.exs | 2 +- test/ejabberd_commands_mock_test.exs | 2 +- test/ejabberd_cyrsasl_test.exs | 2 +- test/jid_test.exs | 1 + test/mod_admin_extra_test.exs | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/test/acl_test.exs b/test/acl_test.exs index 4bd8e6989..0ab92ade8 100644 --- a/test/acl_test.exs +++ b/test/acl_test.exs @@ -25,7 +25,7 @@ defmodule ACLTest do setup_all do :ok = :mnesia.start - :ok = :jid.start + {:ok, _} = :jid.start :stringprep.start :ok = :ejabberd_config.start(["domain1", "domain2"], []) :ok = :acl.start diff --git a/test/ejabberd_commands_mock_test.exs b/test/ejabberd_commands_mock_test.exs index 419a989d6..12444f79a 100644 --- a/test/ejabberd_commands_mock_test.exs +++ b/test/ejabberd_commands_mock_test.exs @@ -48,7 +48,7 @@ defmodule EjabberdCommandsMockTest do _ -> :ok end :mnesia.start - :ok = :jid.start + {:ok, _} = :jid.start :ok = :ejabberd_config.start(["domain1", "domain2"], []) {:ok, _} = :ejabberd_access_permissions.start_link() :ok = :acl.start diff --git a/test/ejabberd_cyrsasl_test.exs b/test/ejabberd_cyrsasl_test.exs index b85be0f8e..1b98048c7 100644 --- a/test/ejabberd_cyrsasl_test.exs +++ b/test/ejabberd_cyrsasl_test.exs @@ -27,7 +27,7 @@ defmodule EjabberdCyrsaslTest do :p1_sha.load_nif() :mnesia.start :ok = start_module(:stringprep) - :ok = start_module(:jid) + {:ok, _} = start_module(:jid) :ok = :ejabberd_config.start(["domain1"], []) :ok = :cyrsasl.start cyrstate = :cyrsasl.server_new("domain1", "domain1", "domain1", :ok, &get_password/1, diff --git a/test/jid_test.exs b/test/jid_test.exs index b75a3603a..7d063b707 100644 --- a/test/jid_test.exs +++ b/test/jid_test.exs @@ -29,6 +29,7 @@ defmodule JidTest do setup_all do :stringprep.start :jid.start + :ok end test "create a jid from a binary" do diff --git a/test/mod_admin_extra_test.exs b/test/mod_admin_extra_test.exs index fde66f03f..3baf4922f 100644 --- a/test/mod_admin_extra_test.exs +++ b/test/mod_admin_extra_test.exs @@ -38,7 +38,7 @@ defmodule EjabberdModAdminExtraTest do setup_all do try do - :jid.start + :jid.start :stringprep.start :mnesia.start :p1_sha.load_nif From 1a02a2a51d17b24af28e7c46bca8232a526bf25c Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Mon, 21 Nov 2016 16:55:18 +0300 Subject: [PATCH 113/151] Set 'sql_pool_size' to 1 for sqlite tests --- test/ejabberd_SUITE_data/ejabberd.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/test/ejabberd_SUITE_data/ejabberd.yml b/test/ejabberd_SUITE_data/ejabberd.yml index 9d663a116..9448df080 100644 --- a/test/ejabberd_SUITE_data/ejabberd.yml +++ b/test/ejabberd_SUITE_data/ejabberd.yml @@ -61,6 +61,7 @@ Welcome to this XMPP server." mod_version: [] "sqlite.localhost": sql_type: sqlite + sql_pool_size: 1 auth_method: sql sm_db_type: sql modules: From 3189bb3bb907335ac9288b1ef0e9738c6cfd56ea Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Mon, 21 Nov 2016 21:34:56 +0300 Subject: [PATCH 114/151] Set 'sql_pool_size' to 1 by default for sqlite --- src/ejabberd_sql_sup.erl | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/ejabberd_sql_sup.erl b/src/ejabberd_sql_sup.erl index 682414557..29099fce3 100644 --- a/src/ejabberd_sql_sup.erl +++ b/src/ejabberd_sql_sup.erl @@ -61,10 +61,6 @@ start_link(Host) -> ?MODULE, [Host]). init([Host]) -> - PoolSize = ejabberd_config:get_option( - {sql_pool_size, Host}, - fun(I) when is_integer(I), I>0 -> I end, - ?DEFAULT_POOL_SIZE), StartInterval = ejabberd_config:get_option( {sql_start_interval, Host}, fun(I) when is_integer(I), I>0 -> I end, @@ -76,6 +72,7 @@ init([Host]) -> (mssql) -> mssql; (odbc) -> odbc end, odbc), + PoolSize = get_pool_size(Type, Host), case Type of sqlite -> check_sqlite_db(Host); @@ -117,6 +114,23 @@ remove_pid(Host, Pid) -> end, mnesia:ets(F). +-spec get_pool_size(atom(), binary()) -> pos_integer(). +get_pool_size(SQLType, Host) -> + PoolSize = ejabberd_config:get_option( + {sql_pool_size, Host}, + fun(I) when is_integer(I), I>0 -> I end, + case SQLType of + sqlite -> 1; + _ -> ?DEFAULT_POOL_SIZE + end), + if PoolSize > 1 andalso SQLType == sqlite -> + ?WARNING_MSG("it's not recommended to set sql_pool_size > 1 for " + "sqlite, because it may cause race conditions", []); + true -> + ok + end, + PoolSize. + transform_options(Opts) -> lists:foldl(fun transform_options/2, [], Opts). From c0b5c6e9d4166eab221d881974ce912abfcb6bc3 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Mon, 21 Nov 2016 22:04:25 +0300 Subject: [PATCH 115/151] Fix logging in tests on R17 --- test/suite.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/suite.erl b/test/suite.erl index e2390c599..3d832dd59 100644 --- a/test/suite.erl +++ b/test/suite.erl @@ -480,7 +480,7 @@ decode_stream_element(NS, El) -> format_element(El) -> case erlang:function_exported(ct, log, 5) of true -> ejabberd_web_admin:pretty_print_xml(El); - false -> io_lib:format(" ~s~n", El) + false -> io_lib:format("~p~n", [El]) end. decode(El, NS, Opts) -> From 2786df651aa0d0fbc8aee4a326b55a139f139e84 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Tue, 22 Nov 2016 09:52:26 +0300 Subject: [PATCH 116/151] Add OTP 19.1 to Travis' testing platforms --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index d30afbb18..aa9acef82 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ language: erlang otp_release: - 17.5 - 18.3 + - 19.1 services: - riak From 7ffab38b44212688a7269ab0876f29d75f462fce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Tue, 22 Nov 2016 13:15:16 +0100 Subject: [PATCH 117/151] Remove now() from mod_offline.hrl --- include/mod_offline.hrl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mod_offline.hrl b/include/mod_offline.hrl index c4c70604a..cc644c4c2 100644 --- a/include/mod_offline.hrl +++ b/include/mod_offline.hrl @@ -1,7 +1,7 @@ -record(offline_msg, {us = {<<"">>, <<"">>} :: {binary(), binary()}, - timestamp = now() :: erlang:timestamp() | '_', - expire = now() :: erlang:timestamp() | never | '_', + timestamp = p1_time_compat:timestamp() :: erlang:timestamp() | '_', + expire = p1_time_compat:timestamp() :: erlang:timestamp() | never | '_', from = #jid{} :: jid() | '_', to = #jid{} :: jid() | '_', packet = #xmlel{} :: xmlel() | '_'}). From 577eeb642f2280f030303a06094947d3e6be85d0 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 22 Nov 2016 14:43:10 +0100 Subject: [PATCH 118/151] Add new xmpp repo as dependency in mix.exs --- mix.exs | 9 +++++---- mix.lock | 7 ++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/mix.exs b/mix.exs index c77f2abb4..5e1676043 100644 --- a/mix.exs +++ b/mix.exs @@ -27,14 +27,14 @@ defmodule Ejabberd.Mixfile do [mod: {:ejabberd_app, []}, applications: [:ssl], included_applications: [:lager, :mnesia, :p1_utils, :cache_tab, - :fast_tls, :stringprep, :fast_xml, + :fast_tls, :stringprep, :fast_xml, :xmpp, :stun, :fast_yaml, :esip, :jiffy, :p1_oauth2] ++ cond_apps] end defp erlc_options do # Use our own includes + includes from all dependencies - includes = ["include"] ++ Path.wildcard(Path.join("..", "/*/include")) + includes = ["include"] ++ Path.wildcard("deps/*/include") [:debug_info] ++ Enum.map(includes, fn(path) -> {:i, path} end) end @@ -42,10 +42,11 @@ defmodule Ejabberd.Mixfile do [{:lager, "~> 3.2"}, {:p1_utils, "~> 1.0"}, {:cache_tab, "~> 1.0"}, - {:stringprep, "~> 1.0"}, + {:stringprep, "~> 1.0", override: true}, # override cause of :xmpp {:fast_yaml, "~> 1.0"}, {:fast_tls, "~> 1.0"}, - {:fast_xml, "~> 1.1"}, + {:fast_xml, "~> 1.1", override: true}, # override cause of :xmpp + {:xmpp, github: "processone/xmpp", tag: "1.0.3"}, {:stun, "~> 1.0"}, {:esip, "~> 1.0"}, {:jiffy, "~> 0.14.7"}, diff --git a/mix.lock b/mix.lock index e515fd346..47a335975 100644 --- a/mix.lock +++ b/mix.lock @@ -1,7 +1,7 @@ %{"bbmustache": {:hex, :bbmustache, "1.0.4", "7ba94f971c5afd7b6617918a4bb74705e36cab36eb84b19b6a1b7ee06427aa38", [:rebar], []}, "cache_tab": {:hex, :cache_tab, "1.0.4", "3fd2b1ab40c36e7830a4e09e836c6b0fa89191cd4e5fd471873e4eb42f5cd37c", [:rebar3], [{:p1_utils, "1.0.5", [hex: :p1_utils, optional: false]}]}, "cf": {:hex, :cf, "0.2.1", "69d0b1349fd4d7d4dc55b7f407d29d7a840bf9a1ef5af529f1ebe0ce153fc2ab", [:rebar3], []}, - "earmark": {:hex, :earmark, "1.0.2", "a0b0904d74ecc14da8bd2e6e0248e1a409a2bc91aade75fcf428125603de3853", [:mix], []}, + "earmark": {:hex, :earmark, "1.0.3", "89bdbaf2aca8bbb5c97d8b3b55c5dd0cff517ecc78d417e87f1d0982e514557b", [:mix], []}, "erlware_commons": {:hex, :erlware_commons, "0.21.0", "a04433071ad7d112edefc75ac77719dd3e6753e697ac09428fc83d7564b80b15", [:rebar3], [{:cf, "0.2.1", [hex: :cf, optional: false]}]}, "esip": {:hex, :esip, "1.0.8", "69885a6c07964aabc6c077fe1372aa810a848bd3d9a415b160dabdce9c7a79b5", [:rebar3], [{:fast_tls, "1.0.7", [hex: :fast_tls, optional: false]}, {:p1_utils, "1.0.5", [hex: :p1_utils, optional: false]}, {:stun, "1.0.7", [hex: :stun, optional: false]}]}, "ex_doc": {:hex, :ex_doc, "0.14.3", "e61cec6cf9731d7d23d254266ab06ac1decbb7651c3d1568402ec535d387b6f7", [:mix], [{:earmark, "~> 1.0", [hex: :earmark, optional: false]}]}, @@ -13,11 +13,12 @@ "getopt": {:hex, :getopt, "0.8.2", "b17556db683000ba50370b16c0619df1337e7af7ecbf7d64fbf8d1d6bce3109b", [:rebar], []}, "goldrush": {:hex, :goldrush, "0.1.8", "2024ba375ceea47e27ea70e14d2c483b2d8610101b4e852ef7f89163cdb6e649", [:rebar3], []}, "iconv": {:hex, :iconv, "1.0.2", "a0792f06ab4b5ea1b5bb49789405739f1281a91c44cf3879cb70e4d777666217", [:rebar3], [{:p1_utils, "1.0.5", [hex: :p1_utils, optional: false]}]}, - "jiffy": {:hex, :jiffy, "0.14.7", "9f33b893edd6041ceae03bc1e50b412e858cc80b46f3d7535a7a9940a79a1c37", [:rebar, :make], []}, + "jiffy": {:hex, :jiffy, "0.14.7", "9f33b893edd6041ceae03bc1e50b412e858cc80b46f3d7535a7a9940a79a1c37", [:make, :rebar], []}, "lager": {:hex, :lager, "3.2.1", "eef4e18b39e4195d37606d9088ea05bf1b745986cf8ec84f01d332456fe88d17", [:rebar3], [{:goldrush, "0.1.8", [hex: :goldrush, optional: false]}]}, "p1_oauth2": {:hex, :p1_oauth2, "0.6.1", "4e021250cc198c538b097393671a41e7cebf463c248980320e038fe0316eb56b", [:rebar3], []}, "p1_utils": {:hex, :p1_utils, "1.0.5", "3e698354fdc1fea5491d991457b0cb986c0a00a47d224feb841dc3ec82b9f721", [:rebar3], []}, "providers": {:hex, :providers, "1.6.0", "db0e2f9043ae60c0155205fcd238d68516331d0e5146155e33d1e79dc452964a", [:rebar3], [{:getopt, "0.8.2", [hex: :getopt, optional: false]}]}, "relx": {:hex, :relx, "3.21.1", "f989dc520730efd9075e9f4debcb8ba1d7d1e86b018b0bcf45a2eb80270b4ad6", [:rebar3], [{:bbmustache, "1.0.4", [hex: :bbmustache, optional: false]}, {:cf, "0.2.1", [hex: :cf, optional: false]}, {:erlware_commons, "0.21.0", [hex: :erlware_commons, optional: false]}, {:getopt, "0.8.2", [hex: :getopt, optional: false]}, {:providers, "1.6.0", [hex: :providers, optional: false]}]}, "stringprep": {:hex, :stringprep, "1.0.6", "1cf1c439eb038aa590da5456e019f86afbfbfeb5a2d37b6e5f873041624c6701", [:rebar3], [{:p1_utils, "1.0.5", [hex: :p1_utils, optional: false]}]}, - "stun": {:hex, :stun, "1.0.7", "904dc6f26a3c30c54881c4c3003699f2a4968067ee6b3aecdf9895aad02df75e", [:rebar3], [{:fast_tls, "1.0.7", [hex: :fast_tls, optional: false]}, {:p1_utils, "1.0.5", [hex: :p1_utils, optional: false]}]}} + "stun": {:hex, :stun, "1.0.7", "904dc6f26a3c30c54881c4c3003699f2a4968067ee6b3aecdf9895aad02df75e", [:rebar3], [{:fast_tls, "1.0.7", [hex: :fast_tls, optional: false]}, {:p1_utils, "1.0.5", [hex: :p1_utils, optional: false]}]}, + "xmpp": {:git, "https://github.com/processone/xmpp.git", "e4630667bc63de7ad2d236387f4631a0656a9355", [tag: "1.0.3"]}} From fbfbb968727617ae9bbeedc9b3d4adb7636ad5da Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 22 Nov 2016 14:48:01 +0100 Subject: [PATCH 119/151] Improve ODBC import --- src/ejabberd_auth.erl | 25 +-- src/ejabberd_auth_mnesia.erl | 17 +- src/ejabberd_auth_riak.erl | 16 +- src/ejd2sql.erl | 294 +++++++++++++++++-------------- src/mod_announce.erl | 22 +-- src/mod_announce_mnesia.erl | 11 +- src/mod_announce_riak.erl | 12 +- src/mod_announce_sql.erl | 19 +- src/mod_caps.erl | 31 +--- src/mod_caps_mnesia.erl | 9 +- src/mod_caps_riak.erl | 11 +- src/mod_caps_sql.erl | 5 +- src/mod_last.erl | 30 ++-- src/mod_last_sql.erl | 19 +- src/mod_muc.erl | 20 ++- src/mod_muc_mnesia.erl | 37 +++- src/mod_muc_riak.erl | 36 +++- src/mod_muc_sql.erl | 37 ++-- src/mod_offline.erl | 39 +++- src/mod_offline_mnesia.erl | 4 +- src/mod_offline_sql.erl | 28 +-- src/mod_privacy.erl | 112 ++++++++++-- src/mod_privacy_sql.erl | 35 +--- src/mod_private.erl | 23 +-- src/mod_private_mnesia.erl | 7 +- src/mod_private_riak.erl | 7 +- src/mod_private_sql.erl | 14 +- src/mod_roster.erl | 38 +++- src/mod_roster_mnesia.erl | 12 +- src/mod_roster_riak.erl | 21 ++- src/mod_roster_sql.erl | 25 +-- src/mod_shared_roster.erl | 19 +- src/mod_shared_roster_mnesia.erl | 13 +- src/mod_shared_roster_riak.erl | 19 +- src/mod_shared_roster_sql.erl | 20 +-- src/mod_vcard.erl | 35 ++-- src/mod_vcard_mnesia.erl | 31 +++- src/mod_vcard_riak.erl | 12 +- src/mod_vcard_sql.erl | 39 +--- src/mod_vcard_xupdate.erl | 24 +-- src/mod_vcard_xupdate_mnesia.erl | 7 +- src/mod_vcard_xupdate_riak.erl | 8 +- src/mod_vcard_xupdate_sql.erl | 14 +- 43 files changed, 718 insertions(+), 539 deletions(-) diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index 6b7f537c0..74c8009c2 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -36,8 +36,8 @@ check_password/6, check_password_with_authmodule/4, check_password_with_authmodule/6, try_register/3, dirty_get_registered_users/0, get_vh_registered_users/1, - get_vh_registered_users/2, export/1, import/1, - get_vh_registered_users_number/1, import/3, + get_vh_registered_users/2, export/1, import_info/0, + get_vh_registered_users_number/1, import/5, import_start/2, get_vh_registered_users_number/2, get_password/2, get_password_s/2, get_password_with_authmodule/2, is_user_exists/2, is_user_exists_in_other_modules/3, @@ -438,15 +438,20 @@ auth_modules(Server) -> export(Server) -> ejabberd_auth_mnesia:export(Server). -import(Server) -> - ejabberd_auth_mnesia:import(Server). +import_info() -> + [{<<"users">>, 3}]. -import(Server, mnesia, Passwd) -> - ejabberd_auth_mnesia:import(Server, mnesia, Passwd); -import(Server, riak, Passwd) -> - ejabberd_auth_riak:import(Server, riak, Passwd); -import(_, _, _) -> - pass. +import_start(_LServer, mnesia) -> + ejabberd_auth_mnesia:init_db(); +import_start(_LServer, _) -> + ok. + +import(Server, {sql, _}, mnesia, <<"users">>, Fields) -> + ejabberd_auth_mnesia:import(Server, Fields); +import(Server, {sql, _}, riak, <<"users">>, Fields) -> + ejabberd_auth_riak:import(Server, Fields); +import(_LServer, {sql, _}, sql, <<"users">>, _) -> + ok. opt_type(auth_method) -> fun (V) when is_list(V) -> diff --git a/src/ejabberd_auth_mnesia.erl b/src/ejabberd_auth_mnesia.erl index f36c9fbc7..2e9ef5c94 100644 --- a/src/ejabberd_auth_mnesia.erl +++ b/src/ejabberd_auth_mnesia.erl @@ -40,8 +40,8 @@ get_vh_registered_users_number/1, get_vh_registered_users_number/2, get_password/2, get_password_s/2, is_user_exists/2, remove_user/2, - remove_user/3, store_type/0, export/1, import/1, - import/3, plain_password_required/0, opt_type/1]). + remove_user/3, store_type/0, export/1, import/2, + plain_password_required/0, opt_type/1]). -include("ejabberd.hrl"). -include("logger.hrl"). @@ -493,16 +493,9 @@ export(_Server) -> [] end}]. -import(LServer) -> - [{<<"select username, password from users;">>, - fun([LUser, Password]) -> - #passwd{us = {LUser, LServer}, password = Password} - end}]. - -import(_LServer, mnesia, #passwd{} = P) -> - mnesia:dirty_write(P); -import(_, _, _) -> - pass. +import(LServer, [LUser, Password, _TimeStamp]) -> + mnesia:dirty_write( + #passwd{us = {LUser, LServer}, password = Password}). opt_type(auth_password_format) -> fun (V) -> V end; opt_type(_) -> [auth_password_format]. diff --git a/src/ejabberd_auth_riak.erl b/src/ejabberd_auth_riak.erl index 05add262e..51571c4e2 100644 --- a/src/ejabberd_auth_riak.erl +++ b/src/ejabberd_auth_riak.erl @@ -27,6 +27,8 @@ -compile([{parse_transform, ejabberd_sql_pt}]). +-behaviour(ejabberd_config). + -author('alexey@process-one.net'). -behaviour(ejabberd_auth). @@ -39,8 +41,8 @@ get_vh_registered_users_number/1, get_vh_registered_users_number/2, get_password/2, get_password_s/2, is_user_exists/2, remove_user/2, - remove_user/3, store_type/0, export/1, import/3, - plain_password_required/0]). + remove_user/3, store_type/0, export/1, import/2, + plain_password_required/0, opt_type/1]). -export([passwd_schema/0]). -include("ejabberd.hrl"). @@ -301,7 +303,9 @@ export(_Server) -> [] end}]. -import(LServer, riak, #passwd{} = Passwd) -> - ejabberd_riak:put(Passwd, passwd_schema(), [{'2i', [{<<"host">>, LServer}]}]); -import(_, _, _) -> - pass. +import(LServer, [LUser, Password, _TimeStamp]) -> + Passwd = #passwd{us = {LUser, LServer}, password = Password}, + ejabberd_riak:put(Passwd, passwd_schema(), [{'2i', [{<<"host">>, LServer}]}]). + +opt_type(auth_password_format) -> fun (V) -> V end; +opt_type(_) -> [auth_password_format]. diff --git a/src/ejd2sql.erl b/src/ejd2sql.erl index 7bace05dd..9b7fdbbef 100644 --- a/src/ejd2sql.erl +++ b/src/ejd2sql.erl @@ -30,12 +30,12 @@ -include("logger.hrl"). -include("ejabberd_sql_pt.hrl"). --export([export/2, export/3, import_file/2, import/2, - import/3, delete/1]). +-export([export/2, export/3, import/3, import/4, delete/1, import_info/1]). + -define(MAX_RECORDS_PER_TRANSACTION, 100). --record(dump, {fd, cont = start}). +-record(sql_dump, {fd, type}). %%%---------------------------------------------------------------------- %%% API @@ -50,13 +50,14 @@ modules() -> [ejabberd_auth, mod_announce, + mod_caps, mod_irc, mod_last, mod_muc, mod_offline, mod_privacy, mod_private, - %% mod_pubsub, + mod_pubsub, mod_roster, mod_shared_roster, mod_vcard, @@ -100,49 +101,44 @@ delete(Server, Module) -> delete(LServer, Table, ConvertFun) end, Module:export(Server)). -import_file(Server, FileName) when is_binary(FileName) -> - import(Server, binary_to_list(FileName)); -import_file(Server, FileName) -> - case disk_log:open([{name, make_ref()}, - {file, FileName}, - {mode, read_only}]) of - {ok, Fd} -> - LServer = jid:nameprep(Server), - Mods = [{Mod, gen_mod:db_type(LServer, Mod)} - || Mod <- modules(), gen_mod:is_loaded(LServer, Mod)], - AuthMods = case lists:member(ejabberd_auth_mnesia, - ejabberd_auth:auth_modules(LServer)) of - true -> - [{ejabberd_auth, mnesia}]; - false -> - [] - end, - import_dump(LServer, AuthMods ++ Mods, #dump{fd = Fd}); - Err -> - exit(Err) - end. - -import(Server, Output) -> - import(Server, Output, [{fast, true}]). - -import(Server, Output, Opts) -> - LServer = jid:nameprep(iolist_to_binary(Server)), - Modules = modules(), - IO = prepare_output(Output, disk_log), +import(Server, Dir, ToType) -> lists:foreach( - fun(Module) -> - import(LServer, IO, Opts, Module) - end, Modules), - close_output(Output, IO). + fun(Mod) -> + ?INFO_MSG("importing ~p...", [Mod]), + import(Mod, Server, Dir, ToType) + end, modules()). -import(Server, Output, Opts, Module) -> +import(Mod, Server, Dir, ToType) -> LServer = jid:nameprep(iolist_to_binary(Server)), - IO = prepare_output(Output, disk_log), + try Mod:import_start(LServer, ToType) + catch error:undef -> ok end, lists:foreach( - fun({SelectQuery, ConvertFun}) -> - import(LServer, SelectQuery, IO, ConvertFun, Opts) - end, Module:import(Server)), - close_output(Output, IO). + fun({File, Tab, _Mod, FieldsNumber}) -> + FileName = filename:join([Dir, File]), + case open_sql_dump(FileName) of + {ok, #sql_dump{type = FromType} = Dump} -> + import_rows(LServer, {sql, FromType}, ToType, + Tab, Mod, Dump, FieldsNumber), + close_sql_dump(Dump); + {error, enoent} -> + ok; + eof -> + ?INFO_MSG("It seems like SQL dump ~s is empty", [FileName]); + Err -> + ?ERROR_MSG("Failed to open SQL dump ~s: ~s", + [FileName, format_error(Err)]) + end + end, import_info(Mod)), + try Mod:import_stop(LServer, ToType) + catch error:undef -> ok end. + +import_info(Mod) -> + Info = Mod:import_info(), + lists:map( + fun({Tab, FieldsNum}) -> + FileName = <>, + {FileName, Tab, Mod, FieldsNum} + end, Info). %%%---------------------------------------------------------------------- %%% Internal functions @@ -200,79 +196,6 @@ delete(LServer, Table, ConvertFun) -> end, mnesia:transaction(F). -import(LServer, SelectQuery, IO, ConvertFun, Opts) -> - F = case proplists:get_bool(fast, Opts) of - true -> - fun() -> - case ejabberd_sql:sql_query_t(SelectQuery) of - {selected, _, Rows} -> - lists:foldl(fun process_sql_row/2, - {IO, ConvertFun, undefined}, Rows); - Err -> - erlang:error(Err) - end - end; - false -> - fun() -> - ejabberd_sql:sql_query_t( - [iolist_to_binary( - [<<"declare c cursor for ">>, SelectQuery])]), - fetch(IO, ConvertFun, undefined) - end - end, - ejabberd_sql:sql_transaction(LServer, F). - -fetch(IO, ConvertFun, PrevRow) -> - case ejabberd_sql:sql_query_t([<<"fetch c;">>]) of - {selected, _, [Row]} -> - process_sql_row(Row, {IO, ConvertFun, PrevRow}), - fetch(IO, ConvertFun, Row); - {selected, _, []} -> - ok; - Err -> - erlang:error(Err) - end. - -process_sql_row(Row, {IO, ConvertFun, PrevRow}) when Row == PrevRow -> - %% Avoid calling ConvertFun with the same input - {IO, ConvertFun, Row}; -process_sql_row(Row, {IO, ConvertFun, _PrevRow}) -> - case catch ConvertFun(Row) of - {'EXIT', _} = Err -> - ?ERROR_MSG("failed to convert ~p: ~p", [Row, Err]); - Term -> - ok = disk_log:log(IO#dump.fd, Term) - end, - {IO, ConvertFun, Row}. - -import_dump(LServer, Mods, #dump{fd = Fd, cont = Cont}) -> - case disk_log:chunk(Fd, Cont) of - {NewCont, Terms} -> - import_terms(LServer, Mods, Terms), - import_dump(LServer, Mods, #dump{fd = Fd, cont = NewCont}); - eof -> - ok; - Err -> - exit(Err) - end. - -import_terms(LServer, Mods, [Term|Terms]) -> - import_term(LServer, Mods, Term), - import_terms(LServer, Mods, Terms); -import_terms(_LServer, _Mods, []) -> - ok. - -import_term(LServer, [{Mod, DBType}|Mods], Term) -> - case catch Mod:import(LServer, DBType, Term) of - pass -> import_term(LServer, Mods, Term); - ok -> ok; - Err -> - ?ERROR_MSG("failed to import ~p for module ~p: ~p", - [Term, Mod, Err]) - end; -import_term(_LServer, [], _Term) -> - ok. - prepare_output(FileName) -> prepare_output(FileName, normal). @@ -285,25 +208,11 @@ prepare_output(FileName, normal) when is_list(FileName) -> Err -> exit(Err) end; -prepare_output(FileName, disk_log) when is_list(FileName) -> - case disk_log:open([{name, make_ref()}, - {repair, truncate}, - {file, FileName}]) of - {ok, Fd} -> - #dump{fd = Fd}; - Err -> - exit(Err) - end; prepare_output(Output, _Type) -> Output. close_output(FileName, Fd) when FileName /= Fd -> - case Fd of - #dump{} -> - disk_log:close(Fd#dump.fd); - _ -> - file:close(Fd) - end, + file:close(Fd), ok; close_output(_, _) -> ok. @@ -321,6 +230,129 @@ flatten1([H|T], Acc) -> flatten1([], Acc) -> Acc. +import_rows(LServer, FromType, ToType, Tab, Mod, Dump, FieldsNumber) -> + case read_row_from_sql_dump(Dump, FieldsNumber) of + {ok, Fields} -> + case catch Mod:import(LServer, FromType, ToType, Tab, Fields) of + ok -> + ok; + Err -> + ?ERROR_MSG("Failed to import fields ~p for tab ~p: ~p", + [Fields, Tab, Err]) + end, + import_rows(LServer, FromType, ToType, + Tab, Mod, Dump, FieldsNumber); + eof -> + ok; + Err -> + ?ERROR_MSG("Failed to read row from SQL dump: ~s", + [format_error(Err)]) + end. + +open_sql_dump(FileName) -> + case file:open(FileName, [raw, read, binary, read_ahead]) of + {ok, Fd} -> + case file:read(Fd, 11) of + {ok, <<"PGCOPY\n", 16#ff, "\r\n", 0>>} -> + case skip_pgcopy_header(Fd) of + ok -> + {ok, #sql_dump{fd = Fd, type = pgsql}}; + Err -> + Err + end; + {ok, _} -> + file:position(Fd, 0), + {ok, #sql_dump{fd = Fd, type = mysql}}; + Err -> + Err + end; + Err -> + Err + end. + +close_sql_dump(#sql_dump{fd = Fd}) -> + file:close(Fd). + +read_row_from_sql_dump(#sql_dump{fd = Fd, type = pgsql}, _) -> + case file:read(Fd, 2) of + {ok, <<(-1):16/signed>>} -> + eof; + {ok, <>} -> + read_fields(Fd, FieldsNum, []); + {ok, _} -> + {error, eof}; + eof -> + {error, eof}; + {error, _} = Err -> + Err + end; +read_row_from_sql_dump(#sql_dump{fd = Fd, type = mysql}, FieldsNum) -> + read_lines(Fd, FieldsNum, <<"">>, []). + +skip_pgcopy_header(Fd) -> + try + {ok, <<_:4/binary, ExtSize:32>>} = file:read(Fd, 8), + {ok, <<_:ExtSize/binary>>} = file:read(Fd, ExtSize), + ok + catch error:{badmatch, {error, _} = Err} -> + Err; + error:{badmatch, _} -> + {error, eof} + end. + +read_fields(_Fd, 0, Acc) -> + {ok, lists:reverse(Acc)}; +read_fields(Fd, N, Acc) -> + case file:read(Fd, 4) of + {ok, <<(-1):32/signed>>} -> + read_fields(Fd, N-1, [null|Acc]); + {ok, <>} -> + case file:read(Fd, ValSize) of + {ok, <>} -> + read_fields(Fd, N-1, [Val|Acc]); + {ok, _} -> + {error, eof}; + Err -> + Err + end; + {ok, _} -> + {error, eof}; + eof -> + {error, eof}; + {error, _} = Err -> + Err + end. + +read_lines(_Fd, 0, <<"">>, Acc) -> + {ok, lists:reverse(Acc)}; +read_lines(Fd, N, Buf, Acc) -> + case file:read_line(Fd) of + {ok, Data} when size(Data) >= 2 -> + Size = size(Data) - 2, + case Data of + <> -> + NewBuf = <>, + read_lines(Fd, N-1, <<"">>, [NewBuf|Acc]); + _ -> + NewBuf = <>, + read_lines(Fd, N, NewBuf, Acc) + end; + {ok, Data} -> + NewBuf = <>, + read_lines(Fd, N, NewBuf, Acc); + eof when Buf == <<"">>, Acc == [] -> + eof; + eof -> + {error, eof}; + {error, _} = Err -> + Err + end. + +format_error({error, eof}) -> + "unexpected end of file"; +format_error({error, Posix}) -> + file:format_error(Posix). + format_queries(SQLs) -> lists:map( fun(#sql_query{} = SQL) -> diff --git a/src/mod_announce.erl b/src/mod_announce.erl index 1d93cbe65..a1c60f3c9 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -31,8 +31,8 @@ -behaviour(gen_mod). --export([start/2, init/0, stop/1, export/1, import/1, - import/3, announce/3, send_motd/1, disco_identity/5, +-export([start/2, init/0, stop/1, export/1, import_info/0, + import_start/2, import/5, announce/3, send_motd/1, disco_identity/5, disco_features/5, disco_items/5, depends/2, send_announcement_to_all/3, announce_commands/4, announce_items/4, mod_opt_type/1]). @@ -43,7 +43,7 @@ -include("mod_announce.hrl"). -callback init(binary(), gen_mod:opts()) -> any(). --callback import(binary(), #motd{} | #motd_users{}) -> ok | pass. +-callback import(binary(), binary(), [binary()]) -> ok. -callback set_motd_users(binary(), [{binary(), binary(), binary()}]) -> {atomic, any()}. -callback set_motd(binary(), xmlel()) -> {atomic, any()}. -callback delete_motd(binary()) -> {atomic, any()}. @@ -832,15 +832,17 @@ export(LServer) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:export(LServer). -import(LServer) -> - Mod = gen_mod:db_mod(LServer, ?MODULE), - Mod:import(LServer). +import_info() -> + [{<<"motd">>, 3}]. -import(LServer, DBType, LA) -> +import_start(LServer, DBType) -> Mod = gen_mod:db_mod(DBType, ?MODULE), - Mod:import(LServer, LA). + Mod:init(LServer, []). -mod_opt_type(access) -> - fun acl:access_rules_validator/1; +import(LServer, {sql, _}, DBType, Tab, List) -> + Mod = gen_mod:db_mod(DBType, ?MODULE), + Mod:import(LServer, Tab, List). + +mod_opt_type(access) -> fun acl:access_rules_validator/1; mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; mod_opt_type(_) -> [access, db_type]. diff --git a/src/mod_announce_mnesia.erl b/src/mod_announce_mnesia.erl index b5a1f590e..23b2a5ba3 100644 --- a/src/mod_announce_mnesia.erl +++ b/src/mod_announce_mnesia.erl @@ -11,7 +11,7 @@ %% API -export([init/2, set_motd_users/2, set_motd/2, delete_motd/1, - get_motd/1, is_motd_user/2, set_motd_user/2, import/2]). + get_motd/1, is_motd_user/2, set_motd_user/2, import/3]). -include("xmpp.hrl"). -include("mod_announce.hrl"). @@ -81,10 +81,11 @@ set_motd_user(LUser, LServer) -> end, mnesia:transaction(F). -import(_LServer, #motd{} = Motd) -> - mnesia:dirty_write(Motd); -import(_LServer, #motd_users{} = Users) -> - mnesia:dirty_write(Users). +import(LServer, <<"motd">>, [<<>>, XML, _TimeStamp]) -> + El = fxml_stream:parse_element(XML), + mnesia:dirty_write(#motd{server = LServer, packet = El}); +import(LServer, <<"motd">>, [LUser, <<>>, _TimeStamp]) -> + mnesia:dirty_write(#motd_users{us = {LUser, LServer}}). %%%=================================================================== %%% Internal functions diff --git a/src/mod_announce_riak.erl b/src/mod_announce_riak.erl index 879eb196d..242adee0c 100644 --- a/src/mod_announce_riak.erl +++ b/src/mod_announce_riak.erl @@ -11,7 +11,7 @@ %% API -export([init/2, set_motd_users/2, set_motd/2, delete_motd/1, - get_motd/1, is_motd_user/2, set_motd_user/2, import/2]). + get_motd/1, is_motd_user/2, set_motd_user/2, import/3]). -include("xmpp.hrl"). -include("mod_announce.hrl"). @@ -71,11 +71,13 @@ set_motd_user(LUser, LServer) -> #motd_users{us = {LUser, LServer}}, motd_users_schema(), [{'2i', [{<<"server">>, LServer}]}])}. -import(_LServer, #motd{} = Motd) -> - ejabberd_riak:put(Motd, motd_schema()); -import(_LServer, #motd_users{us = {_, S}} = Users) -> +import(LServer, <<"motd">>, [<<>>, XML, _TimeStamp]) -> + El = fxml_stream:parse_element(XML), + ejabberd_riak:put(#motd{server = LServer, packet = El}, motd_schema()); +import(LServer, <<"motd">>, [LUser, <<>>, _TimeStamp]) -> + Users = #motd_users{us = {LUser, LServer}}, ejabberd_riak:put(Users, motd_users_schema(), - [{'2i', [{<<"server">>, S}]}]). + [{'2i', [{<<"server">>, LServer}]}]). %%%=================================================================== %%% Internal functions diff --git a/src/mod_announce_sql.erl b/src/mod_announce_sql.erl index 37b4412d3..90e3f9d75 100644 --- a/src/mod_announce_sql.erl +++ b/src/mod_announce_sql.erl @@ -13,8 +13,8 @@ %% API -export([init/2, set_motd_users/2, set_motd/2, delete_motd/1, - get_motd/1, is_motd_user/2, set_motd_user/2, import/1, - import/2, export/1]). + get_motd/1, is_motd_user/2, set_motd_user/2, import/3, + export/1]). -include("xmpp.hrl"). -include("mod_announce.hrl"). @@ -108,19 +108,8 @@ export(_Server) -> [] end}]. -import(LServer) -> - [{<<"select xml from motd where username='';">>, - fun([XML]) -> - El = fxml_stream:parse_element(XML), - #motd{server = LServer, packet = El} - end}, - {<<"select username from motd where xml='';">>, - fun([LUser]) -> - #motd_users{us = {LUser, LServer}} - end}]. - -import(_, _) -> - pass. +import(_, _, _) -> + ok. %%%=================================================================== %%% Internal functions diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 65a745d2d..3a4492f5c 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -55,20 +55,16 @@ -include("logger.hrl"). -include("xmpp.hrl"). +-include("mod_caps.hrl"). -define(PROCNAME, ejabberd_mod_caps). -define(BAD_HASH_LIFETIME, 600). --record(caps_features, -{ - node_pair = {<<"">>, <<"">>} :: {binary(), binary()}, - features = [] :: [binary()] | pos_integer() -}). - -record(state, {host = <<"">> :: binary()}). -callback init(binary(), gen_mod:opts()) -> any(). +-callback import(binary(), {binary(), binary()}, [binary() | pos_integer()]) -> ok. -callback caps_read(binary(), {binary(), binary()}) -> {ok, non_neg_integer() | [binary()]} | error. -callback caps_write(binary(), {binary(), binary()}, @@ -525,9 +521,6 @@ is_valid_node(Node) -> false end. -caps_features_schema() -> - {record_info(fields, caps_features), #caps_features{}}. - export(LServer) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:export(LServer). @@ -559,24 +552,8 @@ import_next(_LServer, _DBType, '$end_of_table') -> ok; import_next(LServer, DBType, NodePair) -> Features = [F || {_, F} <- ets:lookup(caps_features_tmp, NodePair)], - case Features of - [I] when is_integer(I), DBType == mnesia -> - mnesia:dirty_write( - #caps_features{node_pair = NodePair, features = I}); - [I] when is_integer(I), DBType == riak -> - ejabberd_riak:put( - #caps_features{node_pair = NodePair, features = I}, - caps_features_schema()); - _ when DBType == mnesia -> - mnesia:dirty_write( - #caps_features{node_pair = NodePair, features = Features}); - _ when DBType == riak -> - ejabberd_riak:put( - #caps_features{node_pair = NodePair, features = Features}, - caps_features_schema()); - _ when DBType == sql -> - ok - end, + Mod = gen_mod:db_mod(DBType, ?MODULE), + Mod:import(LServer, NodePair, Features), import_next(LServer, DBType, ets:next(caps_features_tmp, NodePair)). mod_opt_type(cache_life_time) -> diff --git a/src/mod_caps_mnesia.erl b/src/mod_caps_mnesia.erl index 0bf04b2c3..660fcb4ef 100644 --- a/src/mod_caps_mnesia.erl +++ b/src/mod_caps_mnesia.erl @@ -10,7 +10,7 @@ -behaviour(mod_caps). %% API --export([init/2, caps_read/2, caps_write/3]). +-export([init/2, caps_read/2, caps_write/3, import/3]). -include("mod_caps.hrl"). -include("logger.hrl"). @@ -46,6 +46,13 @@ caps_write(_LServer, Node, Features) -> mnesia:dirty_write(#caps_features{node_pair = Node, features = Features}). +import(_LServer, NodePair, [I]) when is_integer(I) -> + mnesia:dirty_write( + #caps_features{node_pair = NodePair, features = I}); +import(_LServer, NodePair, Features) -> + mnesia:dirty_write( + #caps_features{node_pair = NodePair, features = Features}). + %%%=================================================================== %%% Internal functions %%%=================================================================== diff --git a/src/mod_caps_riak.erl b/src/mod_caps_riak.erl index 6e59ba867..a504bb6ce 100644 --- a/src/mod_caps_riak.erl +++ b/src/mod_caps_riak.erl @@ -10,7 +10,7 @@ -behaviour(mod_caps). %% API --export([init/2, caps_read/2, caps_write/3]). +-export([init/2, caps_read/2, caps_write/3, import/3]). -include("mod_caps.hrl"). @@ -31,6 +31,15 @@ caps_write(_LServer, Node, Features) -> features = Features}, caps_features_schema()). +import(_LServer, NodePair, [I]) when is_integer(I) -> + ejabberd_riak:put( + #caps_features{node_pair = NodePair, features = I}, + caps_features_schema()); +import(_LServer, NodePair, Features) -> + ejabberd_riak:put( + #caps_features{node_pair = NodePair, features = Features}, + caps_features_schema()). + %%%=================================================================== %%% Internal functions %%%=================================================================== diff --git a/src/mod_caps_sql.erl b/src/mod_caps_sql.erl index dde301575..fee0f0960 100644 --- a/src/mod_caps_sql.erl +++ b/src/mod_caps_sql.erl @@ -12,7 +12,7 @@ -compile([{parse_transform, ejabberd_sql_pt}]). %% API --export([init/2, caps_read/2, caps_write/3, export/1]). +-export([init/2, caps_read/2, caps_write/3, export/1, import/3]). -include("mod_caps.hrl"). -include("ejabberd_sql_pt.hrl"). @@ -53,6 +53,9 @@ export(_Server) -> [] end}]. +import(_, _, _) -> + ok. + %%%=================================================================== %%% Internal functions %%%=================================================================== diff --git a/src/mod_last.erl b/src/mod_last.erl index 56e3b1c5e..47db0b6c6 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -34,8 +34,8 @@ -behaviour(gen_mod). -export([start/2, stop/1, process_local_iq/1, export/1, - process_sm_iq/1, on_presence_update/4, import/1, - import/3, store_last_info/4, get_last_info/2, + process_sm_iq/1, on_presence_update/4, import_info/0, + import/5, store_last_info/4, get_last_info/2, remove_user/2, transform_options/1, mod_opt_type/1, opt_type/1, register_user/2, depends/2]). @@ -207,18 +207,28 @@ remove_user(User, Server) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:remove_user(LUser, LServer). +import_info() -> + [{<<"last">>, 3}]. + +import_start(LServer, DBType) -> + Mod = gen_mod:db_mod(DBType, ?MODULE), + Mod:init(LServer, []). + +import(LServer, {sql, _}, DBType, <<"last">>, [LUser, TimeStamp, State]) -> + TS = case TimeStamp of + <<"">> -> 0; + _ -> jlib:binary_to_integer(TimeStamp) + end, + LA = #last_activity{us = {LUser, LServer}, + timestamp = TS, + status = State}, + Mod = gen_mod:db_mod(DBType, ?MODULE), + Mod:import(LServer, LA). + export(LServer) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:export(LServer). -import(LServer) -> - Mod = gen_mod:db_mod(LServer, ?MODULE), - Mod:import(LServer). - -import(LServer, DBType, LA) -> - Mod = gen_mod:db_mod(DBType, ?MODULE), - Mod:import(LServer, LA). - transform_options(Opts) -> lists:foldl(fun transform_options/2, [], Opts). diff --git a/src/mod_last_sql.erl b/src/mod_last_sql.erl index 718f01dff..0351e668c 100644 --- a/src/mod_last_sql.erl +++ b/src/mod_last_sql.erl @@ -13,7 +13,7 @@ %% API -export([init/2, get_last/2, store_last_info/4, remove_user/2, - import/1, import/2, export/1]). + import/2, export/1]). -include("mod_last.hrl"). -include("logger.hrl"). @@ -43,9 +43,6 @@ store_last_info(LUser, LServer, TimeStamp, Status) -> remove_user(LUser, LServer) -> sql_queries:del_last(LServer, LUser). -import(_LServer, _LA) -> - pass. - export(_Server) -> [{last_activity, fun(Host, #last_activity{us = {LUser, LServer}, @@ -58,15 +55,5 @@ export(_Server) -> [] end}]. -import(LServer) -> - [{<<"select username, seconds, state from last">>, - fun([LUser, TimeStamp, State]) -> - #last_activity{us = {LUser, LServer}, - timestamp = binary_to_integer( - TimeStamp), - status = State} - end}]. - -%%%=================================================================== -%%% Internal functions -%%%=================================================================== +import(_LServer, _LA) -> + pass. diff --git a/src/mod_muc.erl b/src/mod_muc.erl index 1f8b2479c..28008aaae 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -51,8 +51,9 @@ process_mucsub/1, broadcast_service_message/2, export/1, - import/1, - import/3, + import_info/0, + import/5, + import_start/2, opts_to_binary/1, can_use_nick/4]). @@ -79,7 +80,7 @@ -type muc_room_opts() :: [{atom(), any()}]. -callback init(binary(), gen_mod:opts()) -> any(). --callback import(binary(), #muc_room{} | #muc_registered{}) -> ok | pass. +-callback import(binary(), binary(), [binary()]) -> ok. -callback store_room(binary(), binary(), binary(), list()) -> {atomic, any()}. -callback restore_room(binary(), binary(), binary()) -> muc_room_opts() | error. -callback forget_room(binary(), binary(), binary()) -> {atomic, any()}. @@ -904,13 +905,16 @@ export(LServer) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:export(LServer). -import(LServer) -> - Mod = gen_mod:db_mod(LServer, ?MODULE), - Mod:import(LServer). +import_info() -> + [{<<"muc_room">>, 4}, {<<"muc_registered">>, 4}]. -import(LServer, DBType, Data) -> +import_start(LServer, DBType) -> Mod = gen_mod:db_mod(DBType, ?MODULE), - Mod:import(LServer, Data). + Mod:init(LServer, []). + +import(LServer, {sql, _}, DBType, Tab, L) -> + Mod = gen_mod:db_mod(DBType, ?MODULE), + Mod:import(LServer, Tab, L). mod_opt_type(access) -> fun acl:access_rules_validator/1; diff --git a/src/mod_muc_mnesia.erl b/src/mod_muc_mnesia.erl index e3ae36978..072dddaae 100644 --- a/src/mod_muc_mnesia.erl +++ b/src/mod_muc_mnesia.erl @@ -9,11 +9,15 @@ -module(mod_muc_mnesia). -behaviour(mod_muc). +-behaviour(mod_muc_room). %% API --export([init/2, import/2, store_room/4, restore_room/3, forget_room/3, +-export([init/2, import/3, store_room/4, restore_room/3, forget_room/3, can_use_nick/4, get_rooms/2, get_nick/3, set_nick/4]). +-export([set_affiliation/6, set_affiliations/4, get_affiliation/5, + get_affiliations/3, search_affiliation/4]). +-include("jlib.hrl"). -include("mod_muc.hrl"). -include("logger.hrl"). @@ -113,10 +117,33 @@ set_nick(_LServer, Host, From, Nick) -> end, mnesia:transaction(F). -import(_LServer, #muc_room{} = R) -> - mnesia:dirty_write(R); -import(_LServer, #muc_registered{} = R) -> - mnesia:dirty_write(R). +set_affiliation(_ServerHost, _Room, _Host, _JID, _Affiliation, _Reason) -> + {error, not_implemented}. + +set_affiliations(_ServerHost, _Room, _Host, _Affiliations) -> + {error, not_implemented}. + +get_affiliation(_ServerHost, _Room, _Host, _LUser, _LServer) -> + {error, not_implemented}. + +get_affiliations(_ServerHost, _Room, _Host) -> + {error, not_implemented}. + +search_affiliation(_ServerHost, _Room, _Host, _Affiliation) -> + {error, not_implemented}. + +import(_LServer, <<"muc_room">>, + [Name, RoomHost, SOpts, _TimeStamp]) -> + Opts = mod_muc:opts_to_binary(ejabberd_sql:decode_term(SOpts)), + mnesia:dirty_write( + #muc_room{name_host = {Name, RoomHost}, + opts = Opts}); +import(_LServer, <<"muc_registered">>, + [J, RoomHost, Nick, _TimeStamp]) -> + #jid{user = U, server = S} = jid:from_string(J), + mnesia:dirty_write( + #muc_registered{us_host = {{U, S}, RoomHost}, + nick = Nick}). %%%=================================================================== %%% Internal functions diff --git a/src/mod_muc_riak.erl b/src/mod_muc_riak.erl index bc6e5959a..ada08ace6 100644 --- a/src/mod_muc_riak.erl +++ b/src/mod_muc_riak.erl @@ -9,11 +9,15 @@ -module(mod_muc_riak). -behaviour(mod_muc). +-behaviour(mod_muc_room). %% API --export([init/2, import/2, store_room/4, restore_room/3, forget_room/3, +-export([init/2, import/3, store_room/4, restore_room/3, forget_room/3, can_use_nick/4, get_rooms/2, get_nick/3, set_nick/4]). +-export([set_affiliation/6, set_affiliations/4, get_affiliation/5, + get_affiliations/3, search_affiliation/4]). +-include("jlib.hrl"). -include("mod_muc.hrl"). %%%=================================================================== @@ -101,11 +105,33 @@ set_nick(LServer, Host, From, Nick) -> end end}. -import(_LServer, #muc_room{} = R) -> - ejabberd_riak:put(R, muc_room_schema()); -import(_LServer, #muc_registered{us_host = {_, Host}, nick = Nick} = R) -> +set_affiliation(_ServerHost, _Room, _Host, _JID, _Affiliation, _Reason) -> + {error, not_implemented}. + +set_affiliations(_ServerHost, _Room, _Host, _Affiliations) -> + {error, not_implemented}. + +get_affiliation(_ServerHost, _Room, _Host, _LUser, _LServer) -> + {error, not_implemented}. + +get_affiliations(_ServerHost, _Room, _Host) -> + {error, not_implemented}. + +search_affiliation(_ServerHost, _Room, _Host, _Affiliation) -> + {error, not_implemented}. + +import(_LServer, <<"muc_room">>, + [Name, RoomHost, SOpts, _TimeStamp]) -> + Opts = mod_muc:opts_to_binary(ejabberd_sql:decode_term(SOpts)), + ejabberd_riak:put( + #muc_room{name_host = {Name, RoomHost}, opts = Opts}, + muc_room_schema()); +import(_LServer, <<"muc_registered">>, + [J, RoomHost, Nick, _TimeStamp]) -> + #jid{user = U, server = S} = jid:from_string(J), + R = #muc_registered{us_host = {{U, S}, RoomHost}, nick = Nick}, ejabberd_riak:put(R, muc_registered_schema(), - [{'2i', [{<<"nick_host">>, {Nick, Host}}]}]). + [{'2i', [{<<"nick_host">>, {Nick, RoomHost}}]}]). %%%=================================================================== %%% Internal functions diff --git a/src/mod_muc_sql.erl b/src/mod_muc_sql.erl index 3139b5316..4b6be7d06 100644 --- a/src/mod_muc_sql.erl +++ b/src/mod_muc_sql.erl @@ -11,11 +11,14 @@ -compile([{parse_transform, ejabberd_sql_pt}]). -behaviour(mod_muc). +-behaviour(mod_muc_room). %% API -export([init/2, store_room/4, restore_room/3, forget_room/3, can_use_nick/4, get_rooms/2, get_nick/3, set_nick/4, - import/1, import/2, export/1]). + import/3, export/1]). +-export([set_affiliation/6, set_affiliations/4, get_affiliation/5, + get_affiliations/3, search_affiliation/4]). -include("jid.hrl"). -include("mod_muc.hrl"). @@ -127,6 +130,21 @@ set_nick(LServer, Host, From, Nick) -> end, ejabberd_sql:sql_transaction(LServer, F). +set_affiliation(_ServerHost, _Room, _Host, _JID, _Affiliation, _Reason) -> + {error, not_implemented}. + +set_affiliations(_ServerHost, _Room, _Host, _Affiliations) -> + {error, not_implemented}. + +get_affiliation(_ServerHost, _Room, _Host, _LUser, _LServer) -> + {error, not_implemented}. + +get_affiliations(_ServerHost, _Room, _Host) -> + {error, not_implemented}. + +search_affiliation(_ServerHost, _Room, _Host, _Affiliation) -> + {error, not_implemented}. + export(_Server) -> [{muc_room, fun(Host, #muc_room{name_host = {Name, RoomHost}, opts = Opts}) -> @@ -158,21 +176,8 @@ export(_Server) -> end end}]. -import(_LServer) -> - [{<<"select name, host, opts from muc_room;">>, - fun([Name, RoomHost, SOpts]) -> - Opts = mod_muc:opts_to_binary(ejabberd_sql:decode_term(SOpts)), - #muc_room{name_host = {Name, RoomHost}, opts = Opts} - end}, - {<<"select jid, host, nick from muc_registered;">>, - fun([J, RoomHost, Nick]) -> - #jid{user = U, server = S} = jid:from_string(J), - #muc_registered{us_host = {{U, S}, RoomHost}, - nick = Nick} - end}]. - -import(_, _) -> - pass. +import(_, _, _) -> + ok. %%%=================================================================== %%% Internal functions diff --git a/src/mod_offline.erl b/src/mod_offline.erl index d007bf3c6..241677b2a 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -53,8 +53,9 @@ remove_expired_messages/1, remove_old_messages/2, remove_user/2, - import/1, - import/3, + import_info/0, + import_start/2, + import/5, export/1, get_queue_length/2, count_offline_messages/2, @@ -90,7 +91,7 @@ -type us() :: {binary(), binary()}. -callback init(binary(), gen_mod:opts()) -> any(). --callback import(binary(), #offline_msg{}) -> ok | pass. +-callback import(#offline_msg{}) -> ok. -callback store_messages(binary(), us(), [#offline_msg{}], non_neg_integer(), non_neg_integer()) -> {atomic, any()}. @@ -851,13 +852,35 @@ export(LServer) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:export(LServer). -import(LServer) -> - Mod = gen_mod:db_mod(LServer, ?MODULE), - Mod:import(LServer). +import_info() -> + [{<<"spool">>, 4}]. -import(LServer, DBType, Data) -> +import_start(LServer, DBType) -> Mod = gen_mod:db_mod(DBType, ?MODULE), - Mod:import(LServer, Data). + Mod:import(LServer, []). + +import(LServer, {sql, _}, DBType, <<"spool">>, + [LUser, XML, _Seq, _TimeStamp]) -> + El = fxml_stream:parse_element(XML), + From = #jid{} = jid:from_string( + fxml:get_attr_s(<<"from">>, El#xmlel.attrs)), + To = #jid{} = jid:from_string( + fxml:get_attr_s(<<"to">>, El#xmlel.attrs)), + Stamp = fxml:get_path_s(El, [{elem, <<"delay">>}, + {attr, <<"stamp">>}]), + TS = case jlib:datetime_string_to_timestamp(Stamp) of + {MegaSecs, Secs, _} -> + {MegaSecs, Secs, 0}; + undefined -> + p1_time_compat:timestamp() + end, + US = {LUser, LServer}, + Expire = find_x_expire(TS, El#xmlel.children), + Msg = #offline_msg{us = US, packet = El, + from = From, to = To, + timestamp = TS, expire = Expire}, + Mod = gen_mod:db_mod(DBType, ?MODULE), + Mod:import(Msg). mod_opt_type(access_max_user_messages) -> fun acl:shaper_rules_validator/1; diff --git a/src/mod_offline_mnesia.erl b/src/mod_offline_mnesia.erl index 9fec9c4d5..e84f7078a 100644 --- a/src/mod_offline_mnesia.erl +++ b/src/mod_offline_mnesia.erl @@ -13,7 +13,7 @@ -export([init/2, store_messages/5, pop_messages/2, remove_expired_messages/1, remove_old_messages/2, remove_user/2, read_message_headers/2, read_message/3, remove_message/3, read_all_messages/2, - remove_all_messages/2, count_messages/2, import/2]). + remove_all_messages/2, count_messages/2, import/1]). -include("xmpp.hrl"). -include("mod_offline.hrl"). @@ -164,7 +164,7 @@ count_messages(LUser, LServer) -> _ -> 0 end. -import(_LServer, #offline_msg{} = Msg) -> +import(#offline_msg{} = Msg) -> mnesia:dirty_write(Msg). %%%=================================================================== diff --git a/src/mod_offline_sql.erl b/src/mod_offline_sql.erl index 025aa56f5..e626df425 100644 --- a/src/mod_offline_sql.erl +++ b/src/mod_offline_sql.erl @@ -15,8 +15,7 @@ -export([init/2, store_messages/5, pop_messages/2, remove_expired_messages/1, remove_old_messages/2, remove_user/2, read_message_headers/2, read_message/3, remove_message/3, read_all_messages/2, - remove_all_messages/2, count_messages/2, import/1, import/2, - export/1]). + remove_all_messages/2, count_messages/2, import/1, export/1]). -include("xmpp.hrl"). -include("mod_offline.hrl"). @@ -193,29 +192,8 @@ export(_Server) -> [] end}]. -import(LServer) -> - [{<<"select username, xml from spool;">>, - fun([LUser, XML]) -> - El = #xmlel{} = fxml_stream:parse_element(XML), - #message{} = Pkt = xmpp:decode(El, ?NS_CLIENT, [ignore_els]), - From = Pkt#message.from, - To = case Pkt#message.to of - undefined -> jid:make(LUser, LServer); - JID -> JID - end, - TS = case xmpp:get_subtag(Pkt, #delay{}) of - #delay{stamp = Stamp} -> Stamp; - false -> p1_time_compat:timestamp() - end, - Expire = mod_offline:find_x_expire(TS, Pkt), - #offline_msg{us = {LUser, LServer}, - from = From, to = To, - packet = El, - timestamp = TS, expire = Expire} - end}]. - -import(_, _) -> - pass. +import(_) -> + ok. %%%=================================================================== %%% Internal functions diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index d4c8464f1..97a8f1804 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -31,11 +31,11 @@ -behaviour(gen_mod). --export([start/2, stop/1, process_iq/1, export/1, import/1, +-export([start/2, stop/1, process_iq/1, export/1, import_info/0, process_iq_set/3, process_iq_get/3, get_user_list/3, check_packet/6, remove_user/2, encode_list_item/1, is_list_needdb/1, updated_list/3, - item_to_xml/1, get_user_lists/2, import/3, + item_to_xml/1, get_user_lists/2, import/5, set_privacy_list/1, mod_opt_type/1, depends/2]). -include("ejabberd.hrl"). @@ -46,7 +46,7 @@ -include("mod_privacy.hrl"). -callback init(binary(), gen_mod:opts()) -> any(). --callback import(binary(), #privacy{}) -> ok | pass. +-callback import(#privacy{}) -> ok. -callback process_lists_get(binary(), binary()) -> {none | binary(), [binary()]} | error. -callback process_list_get(binary(), binary(), binary()) -> [listitem()] | error | not_found. -callback process_default_set(binary(), binary(), binary() | none) -> {atomic, any()}. @@ -544,18 +544,108 @@ updated_list(_, #userlist{name = OldName} = Old, true -> Old end. +numeric_to_binary(<<0, 0, _/binary>>) -> + <<"0">>; +numeric_to_binary(<<0, _, _:6/binary, T/binary>>) -> + Res = lists:foldl( + fun(X, Sum) -> + Sum*10000 + X + end, 0, [X || <> <= T]), + jlib:integer_to_binary(Res). + +bool_to_binary(<<0>>) -> <<"0">>; +bool_to_binary(<<1>>) -> <<"1">>. + +prepare_list_data(mysql, [ID|Row]) -> + [jlib:binary_to_integer(ID)|Row]; +prepare_list_data(pgsql, [<>, + SType, SValue, SAction, SOrder, SMatchAll, + SMatchIQ, SMatchMessage, SMatchPresenceIn, + SMatchPresenceOut]) -> + [ID, SType, SValue, SAction, + numeric_to_binary(SOrder), + bool_to_binary(SMatchAll), + bool_to_binary(SMatchIQ), + bool_to_binary(SMatchMessage), + bool_to_binary(SMatchPresenceIn), + bool_to_binary(SMatchPresenceOut)]. + +prepare_id(mysql, ID) -> + jlib:binary_to_integer(ID); +prepare_id(pgsql, <>) -> + ID. + +import_info() -> + [{<<"privacy_default_list">>, 2}, + {<<"privacy_list_data">>, 10}, + {<<"privacy_list">>, 4}]. + +import_start(LServer, DBType) -> + ets:new(privacy_default_list_tmp, [private, named_table]), + ets:new(privacy_list_data_tmp, [private, named_table, bag]), + ets:new(privacy_list_tmp, [private, named_table, bag, + {keypos, #privacy.us}]), + Mod = gen_mod:db_mod(DBType, ?MODULE), + Mod:init(LServer, []). + +import(LServer, {sql, _}, _DBType, <<"privacy_default_list">>, [LUser, Name]) -> + US = {LUser, LServer}, + ets:insert(privacy_default_list_tmp, {US, Name}), + ok; +import(LServer, {sql, SQLType}, _DBType, <<"privacy_list_data">>, Row1) -> + [ID|Row] = prepare_list_data(SQLType, Row1), + case mod_privacy_sql:raw_to_item(Row) of + [Item] -> + IS = {ID, LServer}, + ets:insert(privacy_list_data_tmp, {IS, Item}), + ok; + [] -> + ok + end; +import(LServer, {sql, SQLType}, _DBType, <<"privacy_list">>, + [LUser, Name, ID, _TimeStamp]) -> + US = {LUser, LServer}, + IS = {prepare_id(SQLType, ID), LServer}, + Default = case ets:lookup(privacy_default_list_tmp, US) of + [{_, Name}] -> Name; + _ -> none + end, + case [Item || {_, Item} <- ets:lookup(privacy_list_data_tmp, IS)] of + [_|_] = Items -> + Privacy = #privacy{us = {LUser, LServer}, + default = Default, + lists = [{Name, Items}]}, + ets:insert(privacy_list_tmp, Privacy), + ets:delete(privacy_list_data_tmp, IS), + ok; + _ -> + ok + end. + +import_stop(_LServer, DBType) -> + import_next(DBType, ets:first(privacy_list_tmp)), + ets:delete(privacy_default_list_tmp), + ets:delete(privacy_list_data_tmp), + ets:delete(privacy_list_tmp), + ok. + +import_next(_DBType, '$end_of_table') -> + ok; +import_next(DBType, US) -> + [P|_] = Ps = ets:lookup(privacy_list_tmp, US), + Lists = lists:flatmap( + fun(#privacy{lists = Lists}) -> + Lists + end, Ps), + Privacy = P#privacy{lists = Lists}, + Mod = gen_mod:db_mod(DBType, ?MODULE), + Mod:import(Privacy), + import_next(DBType, ets:next(privacy_list_tmp, US)). + export(LServer) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:export(LServer). -import(LServer) -> - Mod = gen_mod:db_mod(LServer, ?MODULE), - Mod:import(LServer). - -import(LServer, DBType, Data) -> - Mod = gen_mod:db_mod(DBType, ?MODULE), - Mod:import(LServer, Data). - depends(_Host, _Opts) -> []. diff --git a/src/mod_privacy_sql.erl b/src/mod_privacy_sql.erl index 10f3cddc8..a39e36766 100644 --- a/src/mod_privacy_sql.erl +++ b/src/mod_privacy_sql.erl @@ -17,7 +17,7 @@ process_default_set/3, process_active_set/3, remove_privacy_list/3, set_privacy_list/1, set_privacy_list/4, get_user_list/2, get_user_lists/2, - remove_user/2, import/1, import/2, export/1]). + remove_user/2, import/1, export/1]). -export([item_to_raw/1, raw_to_item/1, sql_add_privacy_list/2, @@ -249,37 +249,8 @@ get_id() -> put(id, ID + 1), ID + 1. -import(LServer) -> - [{<<"select username from privacy_list;">>, - fun([LUser]) -> - Default = case sql_get_default_privacy_list_t(LUser) of - {selected, [<<"name">>], []} -> - none; - {selected, [<<"name">>], [[DefName]]} -> - DefName; - _ -> - none - end, - {selected, [<<"name">>], Names} = - sql_get_privacy_list_names_t(LUser), - Lists = lists:flatmap( - fun([Name]) -> - case sql_get_privacy_list_data_t(LUser, Name) of - {selected, _, RItems} -> - [{Name, - lists:map(fun raw_to_item/1, - RItems)}]; - _ -> - [] - end - end, Names), - #privacy{default = Default, - us = {LUser, LServer}, - lists = Lists} - end}]. - -import(_, _) -> - pass. +import(_) -> + ok. %%%=================================================================== %%% Internal functions diff --git a/src/mod_private.erl b/src/mod_private.erl index 565500d4a..d11cad36f 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -31,9 +31,9 @@ -behaviour(gen_mod). --export([start/2, stop/1, process_sm_iq/1, import/3, - remove_user/2, get_data/2, get_data/3, export/1, import/1, - mod_opt_type/1, set_data/3, depends/2]). +-export([start/2, stop/1, process_sm_iq/1, import_info/0, + remove_user/2, get_data/2, get_data/3, export/1, + import/5, import_start/2, mod_opt_type/1, set_data/3, depends/2]). -include("ejabberd.hrl"). -include("logger.hrl"). @@ -42,7 +42,7 @@ -include("mod_private.hrl"). -callback init(binary(), gen_mod:opts()) -> any(). --callback import(binary(), #private_storage{}) -> ok | pass. +-callback import(binary(), binary(), [binary()]) -> ok. -callback set_data(binary(), binary(), [{binary(), xmlel()}]) -> {atomic, any()}. -callback get_data(binary(), binary(), binary()) -> {ok, xmlel()} | error. -callback get_all_data(binary(), binary()) -> [xmlel()]. @@ -124,17 +124,20 @@ remove_user(User, Server) -> Mod = gen_mod:db_mod(Server, ?MODULE), Mod:remove_user(LUser, LServer). +import_info() -> + [{<<"private_storage">>, 4}]. + +import_start(LServer, DBType) -> + Mod = gen_mod:db_mod(DBType, ?MODULE), + Mod:init(LServer, []). + export(LServer) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:export(LServer). -import(LServer) -> - Mod = gen_mod:db_mod(LServer, ?MODULE), - Mod:import(LServer). - -import(LServer, DBType, PD) -> +import(LServer, {sql, _}, DBType, Tab, L) -> Mod = gen_mod:db_mod(DBType, ?MODULE), - Mod:import(LServer, PD). + Mod:import(LServer, Tab, L). depends(_Host, _Opts) -> []. diff --git a/src/mod_private_mnesia.erl b/src/mod_private_mnesia.erl index d1bf20c85..84871c1e7 100644 --- a/src/mod_private_mnesia.erl +++ b/src/mod_private_mnesia.erl @@ -11,7 +11,7 @@ %% API -export([init/2, set_data/3, get_data/3, get_all_data/2, remove_user/2, - import/2]). + import/3]). -include("xmpp.hrl"). -include("mod_private.hrl"). @@ -72,7 +72,10 @@ remove_user(LUser, LServer) -> end, mnesia:transaction(F). -import(_LServer, #private_storage{} = PS) -> +import(LServer, <<"private_storage">>, + [LUser, XMLNS, XML, _TimeStamp]) -> + El = #xmlel{} = fxml_stream:parse_element(XML), + PS = #private_storage{usns = {LUser, LServer, XMLNS}, xml = El}, mnesia:dirty_write(PS). %%%=================================================================== diff --git a/src/mod_private_riak.erl b/src/mod_private_riak.erl index b05e7d725..7b091c4a6 100644 --- a/src/mod_private_riak.erl +++ b/src/mod_private_riak.erl @@ -12,7 +12,7 @@ %% API -export([init/2, set_data/3, get_data/3, get_all_data/2, remove_user/2, - import/2]). + import/3]). -include("xmpp.hrl"). -include("mod_private.hrl"). @@ -56,7 +56,10 @@ remove_user(LUser, LServer) -> {atomic, ejabberd_riak:delete_by_index(private_storage, <<"us">>, {LUser, LServer})}. -import(_LServer, #private_storage{usns = {LUser, LServer, _}} = PS) -> +import(LServer, <<"private_storage">>, + [LUser, XMLNS, XML, _TimeStamp]) -> + El = #xmlel{} = fxml_stream:parse_element(XML), + PS = #private_storage{usns = {LUser, LServer, XMLNS}, xml = El}, ejabberd_riak:put(PS, private_storage_schema(), [{'2i', [{<<"us">>, {LUser, LServer}}]}]). diff --git a/src/mod_private_sql.erl b/src/mod_private_sql.erl index eb113d923..b459916e4 100644 --- a/src/mod_private_sql.erl +++ b/src/mod_private_sql.erl @@ -12,7 +12,7 @@ %% API -export([init/2, set_data/3, get_data/3, get_all_data/2, remove_user/2, - import/1, import/2, export/1]). + import/3, export/1]). -include("xmpp.hrl"). -include("mod_private.hrl"). @@ -77,16 +77,8 @@ export(_Server) -> [] end}]. -import(LServer) -> - [{<<"select username, namespace, data from private_storage;">>, - fun([LUser, XMLNS, XML]) -> - El = #xmlel{} = fxml_stream:parse_element(XML), - #private_storage{usns = {LUser, LServer, XMLNS}, - xml = El} - end}]. - -import(_, _) -> - pass. +import(_, _, _) -> + ok. %%%=================================================================== %%% Internal functions diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 2da09d317..89578571c 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -42,8 +42,9 @@ -behaviour(gen_mod). -export([start/2, stop/1, process_iq/1, export/1, - import/1, process_local_iq/1, get_user_roster/2, - import/3, get_subscription_lists/3, get_roster/2, + import_info/0, process_local_iq/1, get_user_roster/2, + import/5, get_subscription_lists/3, get_roster/2, + import_start/2, import_stop/2, get_in_pending_subscriptions/3, in_subscription/6, out_subscription/4, set_items/3, remove_user/2, get_jid_info/4, encode_item/1, webadmin_page/3, @@ -65,7 +66,7 @@ -export_type([subscription/0]). -callback init(binary(), gen_mod:opts()) -> any(). --callback import(binary(), #roster{} | #roster_version{}) -> ok | pass. +-callback import(binary(), binary(), #roster{} | [binary()]) -> ok. -callback read_roster_version(binary(), binary()) -> binary() | error. -callback write_roster_version(binary(), binary(), boolean(), binary()) -> any(). -callback get_roster(binary(), binary()) -> [#roster{}]. @@ -1022,13 +1023,34 @@ export(LServer) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:export(LServer). -import(LServer) -> - Mod = gen_mod:db_mod(LServer, ?MODULE), - Mod:import(LServer). +import_info() -> + [{<<"roster_version">>, 2}, + {<<"rostergroups">>, 3}, + {<<"rosterusers">>, 10}]. -import(LServer, DBType, R) -> +import_start(LServer, DBType) -> Mod = gen_mod:db_mod(DBType, ?MODULE), - Mod:import(LServer, R). + ets:new(rostergroups_tmp, [private, named_table, bag]), + Mod:init(LServer, []), + ok. + +import_stop(_LServer, _DBType) -> + ets:delete(rostergroups_tmp), + ok. + +import(LServer, {sql, _}, _DBType, <<"rostergroups">>, [LUser, SJID, Group]) -> + LJID = jid:tolower(jid:from_string(SJID)), + ets:insert(rostergroups_tmp, {{LUser, LServer, LJID}, Group}), + ok; +import(LServer, {sql, _}, DBType, <<"rosterusers">>, Row) -> + I = mod_roster_sql:raw_to_record(LServer, lists:sublist(Row, 9)), + Groups = [G || {_, G} <- ets:lookup(rostergroups_tmp, I#roster.usj)], + RosterItem = I#roster{groups = Groups}, + Mod = gen_mod:db_mod(DBType, ?MODULE), + Mod:import(LServer, <<"rosterusers">>, RosterItem); +import(LServer, {sql, _}, DBType, <<"roster_version">>, [LUser, Ver]) -> + Mod = gen_mod:db_mod(DBType, ?MODULE), + Mod:import(LServer, <<"roster_version">>, [LUser, Ver]). mod_opt_type(access) -> fun acl:access_rules_validator/1; diff --git a/src/mod_roster_mnesia.erl b/src/mod_roster_mnesia.erl index 398f105d5..1a33407e1 100644 --- a/src/mod_roster_mnesia.erl +++ b/src/mod_roster_mnesia.erl @@ -15,7 +15,7 @@ get_roster/2, get_roster_by_jid/3, get_only_items/2, roster_subscribe/4, get_roster_by_jid_with_groups/3, remove_user/2, update_roster/4, del_roster/3, transaction/2, - read_subscription_and_groups/3, import/2]). + read_subscription_and_groups/3, import/3, create_roster/1]). -include("mod_roster.hrl"). -include("logger.hrl"). @@ -51,7 +51,7 @@ write_roster_version(LUser, LServer, InTransaction, Ver) -> end. get_roster(LUser, LServer) -> - mnesia:dirty_index_read(roster, {LUser, LServer}, #roster.us). + {ok, mnesia:dirty_index_read(roster, {LUser, LServer}, #roster.us)}. get_roster_by_jid(LUser, LServer, LJID) -> case mnesia:read({roster, {LUser, LServer, LJID}}) of @@ -103,9 +103,13 @@ read_subscription_and_groups(LUser, LServer, LJID) -> transaction(_LServer, F) -> mnesia:transaction(F). -import(_LServer, #roster{} = R) -> +create_roster(RItem) -> + mnesia:dirty_write(RItem). + +import(_LServer, <<"rosterusers">>, #roster{} = R) -> mnesia:dirty_write(R); -import(_LServer, #roster_version{} = RV) -> +import(LServer, <<"roster_version">>, [LUser, Ver]) -> + RV = #roster_version{us = {LUser, LServer}, version = Ver}, mnesia:dirty_write(RV). %%%=================================================================== diff --git a/src/mod_roster_riak.erl b/src/mod_roster_riak.erl index 9ed5e7927..53f0e7fb4 100644 --- a/src/mod_roster_riak.erl +++ b/src/mod_roster_riak.erl @@ -13,10 +13,10 @@ %% API -export([init/2, read_roster_version/2, write_roster_version/4, - get_roster/2, get_roster_by_jid/3, + get_roster/2, get_roster_by_jid/3, create_roster/1, roster_subscribe/4, get_roster_by_jid_with_groups/3, remove_user/2, update_roster/4, del_roster/3, transaction/2, - read_subscription_and_groups/3, get_only_items/2, import/2]). + read_subscription_and_groups/3, get_only_items/2, import/3]). -include("mod_roster.hrl"). @@ -41,8 +41,8 @@ write_roster_version(LUser, LServer, _InTransaction, Ver) -> get_roster(LUser, LServer) -> case ejabberd_riak:get_by_index(roster, roster_schema(), <<"us">>, {LUser, LServer}) of - {ok, Items} -> Items; - _Err -> [] + {ok, Items} -> {ok, Items}; + _Err -> error end. get_roster_by_jid(LUser, LServer, LJID) -> @@ -96,10 +96,17 @@ read_subscription_and_groups(LUser, LServer, LJID) -> error end. -import(_LServer, #roster{us = {LUser, LServer}} = R) -> - ejabberd_riak:put(R, roster_schema(), +create_roster(#roster{us = {LUser, LServer}} = RItem) -> + ejabberd_riak:put( + RItem, roster_schema(), + [{'2i', [{<<"us">>, {LUser, LServer}}]}]). + +import(_LServer, <<"rosterusers">>, RosterItem) -> + {LUser, LServer} = RosterItem#roster.us, + ejabberd_riak:put(RosterItem, roster_schema(), [{'2i', [{<<"us">>, {LUser, LServer}}]}]); -import(_LServer, #roster_version{} = RV) -> +import(LServer, <<"roster_version">>, [LUser, Ver]) -> + RV = #roster_version{us = {LUser, LServer}, version = Ver}, ejabberd_riak:put(RV, roster_version_schema()). %%%=================================================================== diff --git a/src/mod_roster_sql.erl b/src/mod_roster_sql.erl index 4d97aead0..708a20295 100644 --- a/src/mod_roster_sql.erl +++ b/src/mod_roster_sql.erl @@ -18,7 +18,7 @@ roster_subscribe/4, get_roster_by_jid_with_groups/3, remove_user/2, update_roster/4, del_roster/3, transaction/2, read_subscription_and_groups/3, get_only_items/2, - import/1, import/2, export/1]). + import/3, export/1]). -include("mod_roster.hrl"). -include("ejabberd_sql_pt.hrl"). @@ -185,27 +185,8 @@ export(_Server) -> [] end}]. -import(LServer) -> - [{<<"select username, jid, nick, subscription, " - "ask, askmessage, server, subscribe, type from rosterusers;">>, - fun([LUser, JID|_] = Row) -> - Item = raw_to_record(LServer, Row), - Username = ejabberd_sql:escape(LUser), - SJID = ejabberd_sql:escape(JID), - {selected, _, Rows} = - ejabberd_sql:sql_query_t( - [<<"select grp from rostergroups where username='">>, - Username, <<"' and jid='">>, SJID, <<"'">>]), - Groups = [Grp || [Grp] <- Rows], - Item#roster{groups = Groups} - end}, - {<<"select username, version from roster_version;">>, - fun([LUser, Ver]) -> - #roster_version{us = {LUser, LServer}, version = Ver} - end}]. - -import(_, _) -> - pass. +import(_, _, _) -> + ok. %%%=================================================================== %%% Internal functions diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index 45d91bccd..8ef0f41b5 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -30,9 +30,9 @@ -behaviour(gen_mod). -export([start/2, stop/1, export/1, - import/1, webadmin_menu/3, webadmin_page/3, + import_info/0, webadmin_menu/3, webadmin_page/3, get_user_roster/2, get_subscription_lists/3, - get_jid_info/4, import/3, process_item/2, + get_jid_info/4, import/5, process_item/2, import_start/2, in_subscription/6, out_subscription/4, user_available/1, unset_presence/4, register_user/2, remove_user/2, list_groups/1, create_group/2, create_group/3, @@ -56,7 +56,7 @@ -type group_options() :: [{atom(), any()}]. -callback init(binary(), gen_mod:opts()) -> any(). --callback import(binary(), #sr_user{} | #sr_group{}) -> ok | pass. +-callback import(binary(), binary(), [binary()]) -> ok. -callback list_groups(binary()) -> [binary()]. -callback groups_with_opts(binary()) -> [{binary(), group_options()}]. -callback create_group(binary(), binary(), group_options()) -> {atomic, any()}. @@ -1072,13 +1072,16 @@ export(LServer) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:export(LServer). -import(LServer) -> - Mod = gen_mod:db_mod(LServer, ?MODULE), - Mod:import(LServer). +import_info() -> + [{<<"sr_group">>, 3}, {<<"sr_user">>, 3}]. -import(LServer, DBType, Data) -> +import_start(LServer, DBType) -> Mod = gen_mod:db_mod(DBType, ?MODULE), - Mod:import(LServer, Data). + Mod:init(LServer, []). + +import(LServer, {sql, _}, DBType, Tab, L) -> + Mod = gen_mod:db_mod(DBType, ?MODULE), + Mod:import(LServer, Tab, L). mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; mod_opt_type(_) -> [db_type]. diff --git a/src/mod_shared_roster_mnesia.erl b/src/mod_shared_roster_mnesia.erl index eb7c3c37d..0f9e93bf6 100644 --- a/src/mod_shared_roster_mnesia.erl +++ b/src/mod_shared_roster_mnesia.erl @@ -15,11 +15,12 @@ delete_group/2, get_group_opts/2, set_group_opts/3, get_user_groups/2, get_group_explicit_users/2, get_user_displayed_groups/3, is_user_in_group/3, - add_user_to_group/3, remove_user_from_group/3, import/2]). + add_user_to_group/3, remove_user_from_group/3, import/3]). -include("mod_roster.hrl"). -include("mod_shared_roster.hrl"). -include("logger.hrl"). +-include("xmpp.hrl"). %%%=================================================================== %%% API @@ -118,10 +119,14 @@ remove_user_from_group(Host, US, Group) -> F = fun () -> mnesia:delete_object(R) end, mnesia:transaction(F). -import(_LServer, #sr_group{} = G) -> +import(LServer, <<"sr_group">>, [Group, SOpts, _TimeStamp]) -> + G = #sr_group{group_host = {Group, LServer}, + opts = ejabberd_sql:decode_term(SOpts)}, mnesia:dirty_write(G); -import(_LServer, #sr_user{} = U) -> - mnesia:dirty_write(U). +import(LServer, <<"sr_user">>, [SJID, Group, _TimeStamp]) -> + #jid{luser = U, lserver = S} = jid:from_string(SJID), + User = #sr_user{us = {U, S}, group_host = {Group, LServer}}, + mnesia:dirty_write(User). %%%=================================================================== %%% Internal functions diff --git a/src/mod_shared_roster_riak.erl b/src/mod_shared_roster_riak.erl index 49d6edfcd..bdb750981 100644 --- a/src/mod_shared_roster_riak.erl +++ b/src/mod_shared_roster_riak.erl @@ -15,10 +15,11 @@ delete_group/2, get_group_opts/2, set_group_opts/3, get_user_groups/2, get_group_explicit_users/2, get_user_displayed_groups/3, is_user_in_group/3, - add_user_to_group/3, remove_user_from_group/3, import/2]). + add_user_to_group/3, remove_user_from_group/3, import/3]). -include("mod_roster.hrl"). -include("mod_shared_roster.hrl"). +-include("xmpp.hrl"). %%%=================================================================== %%% API @@ -120,13 +121,17 @@ add_user_to_group(Host, US, Group) -> remove_user_from_group(Host, US, Group) -> {atomic, ejabberd_riak:delete(sr_group, {US, {Group, Host}})}. -import(_LServer, #sr_group{group_host = {_, Host}} = G) -> - ejabberd_riak:put(G, sr_group_schema(), [{'2i', [{<<"host">>, Host}]}]); -import(_LServer, #sr_user{us = US, group_host = {Group, Host}} = User) -> +import(LServer, <<"sr_group">>, [Group, SOpts, _TimeStamp]) -> + G = #sr_group{group_host = {Group, LServer}, + opts = ejabberd_sql:decode_term(SOpts)}, + ejabberd_riak:put(G, sr_group_schema(), [{'2i', [{<<"host">>, LServer}]}]); +import(LServer, <<"sr_user">>, [SJID, Group|_]) -> + #jid{luser = U, lserver = S} = jid:from_string(SJID), + User = #sr_user{us = {U, S}, group_host = {Group, LServer}}, ejabberd_riak:put(User, sr_user_schema(), - [{i, {US, {Group, Host}}}, - {'2i', [{<<"us">>, US}, - {<<"group_host">>, {Group, Host}}]}]). + [{i, {{U, S}, {Group, LServer}}}, + {'2i', [{<<"us">>, {U, S}}, + {<<"group_host">>, {Group, LServer}}]}]). %%%=================================================================== %%% Internal functions diff --git a/src/mod_shared_roster_sql.erl b/src/mod_shared_roster_sql.erl index 5cffffeb3..9f723f839 100644 --- a/src/mod_shared_roster_sql.erl +++ b/src/mod_shared_roster_sql.erl @@ -17,8 +17,8 @@ delete_group/2, get_group_opts/2, set_group_opts/3, get_user_groups/2, get_group_explicit_users/2, get_user_displayed_groups/3, is_user_in_group/3, - add_user_to_group/3, remove_user_from_group/3, import/1, - import/2, export/1]). + add_user_to_group/3, remove_user_from_group/3, import/3, + export/1]). -include("jid.hrl"). -include("mod_roster.hrl"). @@ -177,20 +177,8 @@ export(_Server) -> [] end}]. -import(LServer) -> - [{<<"select name, opts from sr_group;">>, - fun([Group, SOpts]) -> - #sr_group{group_host = {Group, LServer}, - opts = ejabberd_sql:decode_term(SOpts)} - end}, - {<<"select jid, grp from sr_user;">>, - fun([SJID, Group]) -> - #jid{luser = U, lserver = S} = jid:from_string(SJID), - #sr_user{us = {U, S}, group_host = {Group, LServer}} - end}]. - -import(_, _) -> - pass. +import(_, _, _) -> + ok. %%%=================================================================== %%% Internal functions diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index 35b907f95..dc9476206 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -34,8 +34,8 @@ -export([start/2, init/3, stop/1, get_sm_features/5, process_local_iq/1, process_sm_iq/1, string2lower/1, - remove_user/2, export/1, import/1, import/3, depends/2, - process_search/1, process_vcard/1, get_vcard/2, + remove_user/2, export/1, import_info/0, import/5, import_start/2, + depends/2, process_search/1, process_vcard/1, get_vcard/2, disco_items/5, disco_features/5, disco_identity/5, decode_iq_subel/1, mod_opt_type/1, set_vcard/3, make_vcard_search/4]). @@ -50,7 +50,7 @@ -callback init(binary(), gen_mod:opts()) -> any(). -callback stop(binary()) -> any(). --callback import(binary(), #vcard{} | #vcard_search{}) -> ok | pass. +-callback import(binary(), binary(), [binary()]) -> ok. -callback get_vcard(binary(), binary()) -> [xmlel()] | error. -callback set_vcard(binary(), binary(), xmlel(), #vcard_search{}) -> {atomic, any()}. @@ -59,6 +59,7 @@ -callback search(binary(), [{binary(), [binary()]}], boolean(), infinity | pos_integer()) -> [{binary(), binary()}]. -callback remove_user(binary(), binary()) -> {atomic, any()}. +-callback is_search_supported(binary()) -> boolean(). start(Host, Opts) -> Mod = gen_mod:db_mod(Host, Opts, ?MODULE), @@ -105,6 +106,15 @@ init(Host, ServerHost, Search) -> false -> loop(Host, ServerHost); _ -> ejabberd_router:register_route(Host, ServerHost), + Mod = gen_mod:db_mod(ServerHost, ?MODULE), + case Mod:is_search_supported(ServerHost) of + false -> + ?WARNING_MSG("vcard search functionality is " + "not implemented for ~s backend", + [gen_mod:db_type(ServerHost, ?MODULE)]); + true -> + ejabberd_router:register_route(Host, ServerHost) + end, loop(Host, ServerHost) end. @@ -438,18 +448,21 @@ remove_user(User, Server) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:remove_user(LUser, LServer). +import_info() -> + [{<<"vcard">>, 3}, {<<"vcard_search">>, 24}]. + +import_start(LServer, DBType) -> + Mod = gen_mod:db_mod(DBType, ?MODULE), + Mod:init(LServer, []). + +import(LServer, {sql, _}, DBType, Tab, L) -> + Mod = gen_mod:db_mod(DBType, ?MODULE), + Mod:import(LServer, Tab, L). + export(LServer) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:export(LServer). -import(LServer) -> - Mod = gen_mod:db_mod(LServer, ?MODULE), - Mod:import(LServer). - -import(LServer, DBType, VCard) -> - Mod = gen_mod:db_mod(DBType, ?MODULE), - Mod:import(LServer, VCard). - depends(_Host, _Opts) -> []. diff --git a/src/mod_vcard_mnesia.erl b/src/mod_vcard_mnesia.erl index 3b64c29ef..a4a5f2562 100644 --- a/src/mod_vcard_mnesia.erl +++ b/src/mod_vcard_mnesia.erl @@ -11,8 +11,9 @@ -behaviour(mod_vcard). %% API --export([init/2, stop/1, import/2, get_vcard/2, set_vcard/4, search/4, +-export([init/2, stop/1, import/3, get_vcard/2, set_vcard/4, search/4, search_fields/1, search_reported/1, remove_user/2]). +-export([is_search_supported/1]). -include("ejabberd.hrl"). -include("xmpp.hrl"). @@ -47,6 +48,9 @@ init(_Host, _Opts) -> stop(_Host) -> ok. +is_search_supported(_ServerHost) -> + true. + get_vcard(LUser, LServer) -> US = {LUser, LServer}, F = fun () -> mnesia:read({vcard, US}) end, @@ -121,10 +125,29 @@ remove_user(LUser, LServer) -> end, mnesia:transaction(F). -import(_LServer, #vcard{} = VCard) -> +import(LServer, <<"vcard">>, [LUser, XML, _TimeStamp]) -> + #xmlel{} = El = fxml_stream:parse_element(XML), + VCard = #vcard{us = {LUser, LServer}, vcard = El}, mnesia:dirty_write(VCard); -import(_LServer, #vcard_search{} = S) -> - mnesia:dirty_write(S). +import(LServer, <<"vcard_search">>, + [User, LUser, FN, LFN, + Family, LFamily, Given, LGiven, + Middle, LMiddle, Nickname, LNickname, + BDay, LBDay, CTRY, LCTRY, Locality, LLocality, + EMail, LEMail, OrgName, LOrgName, OrgUnit, LOrgUnit]) -> + mnesia:dirty_write( + #vcard_search{us = {LUser, LServer}, + user = {User, LServer}, luser = LUser, + fn = FN, lfn = LFN, family = Family, + lfamily = LFamily, given = Given, + lgiven = LGiven, middle = Middle, + lmiddle = LMiddle, nickname = Nickname, + lnickname = LNickname, bday = BDay, + lbday = LBDay, ctry = CTRY, lctry = LCTRY, + locality = Locality, llocality = LLocality, + email = EMail, lemail = LEMail, + orgname = OrgName, lorgname = LOrgName, + orgunit = OrgUnit, lorgunit = LOrgUnit}). %%%=================================================================== %%% Internal functions diff --git a/src/mod_vcard_riak.erl b/src/mod_vcard_riak.erl index 23f05f17d..411ec45fa 100644 --- a/src/mod_vcard_riak.erl +++ b/src/mod_vcard_riak.erl @@ -12,7 +12,8 @@ %% API -export([init/2, get_vcard/2, set_vcard/4, search/4, remove_user/2, - search_fields/1, search_reported/1, import/2, stop/1]). + search_fields/1, search_reported/1, import/3, stop/1]). +-export([is_search_supported/1]). -include("xmpp.hrl"). -include("mod_vcard.hrl"). @@ -26,6 +27,9 @@ init(_Host, _Opts) -> stop(_Host) -> ok. +is_search_supported(_LServer) -> + false. + get_vcard(LUser, LServer) -> case ejabberd_riak:get(vcard, vcard_schema(), {LUser, LServer}) of {ok, R} -> @@ -101,7 +105,9 @@ search_reported(_LServer) -> remove_user(LUser, LServer) -> {atomic, ejabberd_riak:delete(vcard, {LUser, LServer})}. -import(_LServer, #vcard{us = {LUser, LServer}, vcard = El} = VCard) -> +import(LServer, <<"vcard">>, [LUser, XML, _TimeStamp]) -> + El = fxml_stream:parse_element(XML), + VCard = #vcard{us = {LUser, LServer}, vcard = El}, #vcard_search{fn = FN, lfn = LFN, family = Family, @@ -150,7 +156,7 @@ import(_LServer, #vcard{us = {LUser, LServer}, vcard = El} = VCard) -> {<<"lorgname">>, LOrgName}, {<<"orgunit">>, OrgUnit}, {<<"lorgunit">>, LOrgUnit}]}]); -import(_LServer, #vcard_search{}) -> +import(_LServer, <<"vcard_search">>, _) -> ok. %%%=================================================================== diff --git a/src/mod_vcard_sql.erl b/src/mod_vcard_sql.erl index 129f76b5a..7fd64c44e 100644 --- a/src/mod_vcard_sql.erl +++ b/src/mod_vcard_sql.erl @@ -14,7 +14,8 @@ %% API -export([init/2, stop/1, get_vcard/2, set_vcard/4, search/4, remove_user/2, - search_fields/1, search_reported/1, import/1, import/2, export/1]). + search_fields/1, search_reported/1, import/3, export/1]). +-export([is_search_supported/1]). -include("xmpp.hrl"). -include("mod_vcard.hrl"). @@ -30,6 +31,9 @@ init(_Host, _Opts) -> stop(_Host) -> ok. +is_search_supported(_LServer) -> + true. + get_vcard(LUser, LServer) -> case catch sql_queries:get_vcard(LServer, LUser) of {selected, [{SVCARD}]} -> @@ -188,37 +192,8 @@ export(_Server) -> [] end}]. -import(LServer) -> - [{<<"select username, vcard from vcard;">>, - fun([LUser, SVCard]) -> - #xmlel{} = VCARD = fxml_stream:parse_element(SVCard), - #vcard{us = {LUser, LServer}, vcard = VCARD} - end}, - {<<"select username, lusername, fn, lfn, family, lfamily, " - "given, lgiven, middle, lmiddle, nickname, lnickname, " - "bday, lbday, ctry, lctry, locality, llocality, email, " - "lemail, orgname, lorgname, orgunit, lorgunit from vcard_search;">>, - fun([User, LUser, FN, LFN, - Family, LFamily, Given, LGiven, - Middle, LMiddle, Nickname, LNickname, - BDay, LBDay, CTRY, LCTRY, Locality, LLocality, - EMail, LEMail, OrgName, LOrgName, OrgUnit, LOrgUnit]) -> - #vcard_search{us = {LUser, LServer}, - user = {User, LServer}, luser = LUser, - fn = FN, lfn = LFN, family = Family, - lfamily = LFamily, given = Given, - lgiven = LGiven, middle = Middle, - lmiddle = LMiddle, nickname = Nickname, - lnickname = LNickname, bday = BDay, - lbday = LBDay, ctry = CTRY, lctry = LCTRY, - locality = Locality, llocality = LLocality, - email = EMail, lemail = LEMail, - orgname = OrgName, lorgname = LOrgName, - orgunit = OrgUnit, lorgunit = LOrgUnit} - end}]. - -import(_, _) -> - pass. +import(_, _, _) -> + ok. %%%=================================================================== %%% Internal functions diff --git a/src/mod_vcard_xupdate.erl b/src/mod_vcard_xupdate.erl index 27688e8fb..4d1dfa2fc 100644 --- a/src/mod_vcard_xupdate.erl +++ b/src/mod_vcard_xupdate.erl @@ -13,14 +13,15 @@ -export([start/2, stop/1]). -export([update_presence/3, vcard_set/3, export/1, - import/1, import/3, mod_opt_type/1, depends/2]). + import_info/0, import/5, import_start/2, + mod_opt_type/1, depends/2]). -include("ejabberd.hrl"). -include("logger.hrl"). -include("xmpp.hrl"). -callback init(binary(), gen_mod:opts()) -> any(). --callback import(binary(), #vcard_xupdate{}) -> ok | pass. +-callback import(binary(), binary(), [binary()]) -> ok. -callback add_xupdate(binary(), binary(), binary()) -> {atomic, any()}. -callback get_xupdate(binary(), binary()) -> binary() | undefined. -callback remove_xupdate(binary(), binary()) -> {atomic, any()}. @@ -94,17 +95,20 @@ presence_with_xupdate(Presence, User, Host) -> Presence1 = xmpp:remove_subtag(Presence, #vcard_xupdate{}), xmpp:set_subtag(Presence1, #vcard_xupdate{hash = Hash}). +import_info() -> + [{<<"vcard_xupdate">>, 3}]. + +import_start(LServer, DBType) -> + Mod = gen_mod:db_mod(DBType, ?MODULE), + Mod:init(LServer, []). + +import(LServer, {sql, _}, DBType, Tab, [LUser, Hash, TimeStamp]) -> + Mod = gen_mod:db_mod(DBType, ?MODULE), + Mod:import(LServer, Tab, [LUser, Hash, TimeStamp]). + export(LServer) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:export(LServer). -import(LServer) -> - Mod = gen_mod:db_mod(LServer, ?MODULE), - Mod:import(LServer). - -import(LServer, DBType, LA) -> - Mod = gen_mod:db_mod(DBType, ?MODULE), - Mod:import(LServer, LA). - mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; mod_opt_type(_) -> [db_type]. diff --git a/src/mod_vcard_xupdate_mnesia.erl b/src/mod_vcard_xupdate_mnesia.erl index f1b1693e4..3f8d6fcab 100644 --- a/src/mod_vcard_xupdate_mnesia.erl +++ b/src/mod_vcard_xupdate_mnesia.erl @@ -10,7 +10,7 @@ -behaviour(mod_vcard_xupdate). %% API --export([init/2, import/2, add_xupdate/3, get_xupdate/2, remove_xupdate/2]). +-export([init/2, import/3, add_xupdate/3, get_xupdate/2, remove_xupdate/2]). -include("mod_vcard_xupdate.hrl"). -include("logger.hrl"). @@ -45,8 +45,9 @@ remove_xupdate(LUser, LServer) -> end, mnesia:transaction(F). -import(_LServer, #vcard_xupdate{} = R) -> - mnesia:dirty_write(R). +import(LServer, <<"vcard_xupdate">>, [LUser, Hash, _TimeStamp]) -> + mnesia:dirty_write( + #vcard_xupdate{us = {LUser, LServer}, hash = Hash}). %%%=================================================================== %%% Internal functions diff --git a/src/mod_vcard_xupdate_riak.erl b/src/mod_vcard_xupdate_riak.erl index 242485bf2..cff77f887 100644 --- a/src/mod_vcard_xupdate_riak.erl +++ b/src/mod_vcard_xupdate_riak.erl @@ -11,7 +11,7 @@ -behaviour(mod_vcard_xupdate). %% API --export([init/2, import/2, add_xupdate/3, get_xupdate/2, remove_xupdate/2]). +-export([init/2, import/3, add_xupdate/3, get_xupdate/2, remove_xupdate/2]). -include("mod_vcard_xupdate.hrl"). @@ -36,8 +36,10 @@ get_xupdate(LUser, LServer) -> remove_xupdate(LUser, LServer) -> {atomic, ejabberd_riak:delete(vcard_xupdate, {LUser, LServer})}. -import(_LServer, #vcard_xupdate{} = R) -> - ejabberd_riak:put(R, vcard_xupdate_schema()). +import(LServer, <<"vcard_xupdate">>, [LUser, Hash, _TimeStamp]) -> + ejabberd_riak:put( + #vcard_xupdate{us = {LUser, LServer}, hash = Hash}, + vcard_xupdate_schema()). %%%=================================================================== %%% Internal functions diff --git a/src/mod_vcard_xupdate_sql.erl b/src/mod_vcard_xupdate_sql.erl index 938114b8f..fd2716c33 100644 --- a/src/mod_vcard_xupdate_sql.erl +++ b/src/mod_vcard_xupdate_sql.erl @@ -13,8 +13,8 @@ -behaviour(mod_vcard_xupdate). %% API --export([init/2, import/2, add_xupdate/3, get_xupdate/2, remove_xupdate/2, - import/1, export/1]). +-export([init/2, import/3, add_xupdate/3, get_xupdate/2, remove_xupdate/2, + export/1]). -include("mod_vcard_xupdate.hrl"). -include("ejabberd_sql_pt.hrl"). @@ -62,14 +62,8 @@ export(_Server) -> [] end}]. -import(LServer) -> - [{<<"select username, hash from vcard_xupdate;">>, - fun([LUser, Hash]) -> - #vcard_xupdate{us = {LUser, LServer}, hash = Hash} - end}]. - -import(_LServer, _) -> - pass. +import(_, _, _) -> + ok. %%%=================================================================== %%% Internal functions From ebadcf71c2e12e379afd31829c58717565d541c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Tue, 22 Nov 2016 13:17:05 +0100 Subject: [PATCH 120/151] New bosh module --- src/ejabberd_bosh.erl | 1095 +++++++++++++++++++++++++++++++++++++++ src/ejabberd_socket.erl | 6 +- src/mod_bosh.erl | 296 +++++++++++ 3 files changed, 1395 insertions(+), 2 deletions(-) create mode 100644 src/ejabberd_bosh.erl create mode 100644 src/mod_bosh.erl diff --git a/src/ejabberd_bosh.erl b/src/ejabberd_bosh.erl new file mode 100644 index 000000000..d4fc6809d --- /dev/null +++ b/src/ejabberd_bosh.erl @@ -0,0 +1,1095 @@ +%%%------------------------------------------------------------------- +%%% File : ejabberd_bosh.erl +%%% Author : Evgeniy Khramtsov +%%% Purpose : Manage BOSH sockets +%%% Created : 20 Jul 2011 by Evgeniy Khramtsov +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2016 ProcessOne +%%% +%%% This program is free software; you can redistribute it and/or +%%% modify it under the terms of the GNU General Public License as +%%% published by the Free Software Foundation; either version 2 of the +%%% License, or (at your option) any later version. +%%% +%%% This program is distributed in the hope that it will be useful, +%%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%%% General Public License for more details. +%%% +%%% You should have received a copy of the GNU General Public License along +%%% with this program; if not, write to the Free Software Foundation, Inc., +%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +%%% +%%%------------------------------------------------------------------- +-module(ejabberd_bosh). + +-protocol({xep, 124, '1.11'}). +-protocol({xep, 206, '1.4'}). + +-define(GEN_FSM, p1_fsm). + +-behaviour(?GEN_FSM). + +%% API +-export([start/2, start/3, start_link/3]). + +-export([send_xml/2, setopts/2, controlling_process/2, + migrate/3, custom_receiver/1, become_controller/2, + reset_stream/1, change_shaper/2, monitor/1, close/1, + sockname/1, peername/1, process_request/3, send/2, + change_controller/2]). + +%% gen_fsm callbacks +-export([init/1, wait_for_session/2, wait_for_session/3, + active/2, active/3, handle_event/3, print_state/1, + handle_sync_event/4, handle_info/3, terminate/3, + code_change/4]). + +-include("ejabberd.hrl"). +-include("logger.hrl"). + +-include("jlib.hrl"). + +-include("ejabberd_http.hrl"). + +-include("bosh.hrl"). + +%%-define(DBGFSM, true). +-ifdef(DBGFSM). + +-define(FSMOPTS, [{debug, [trace]}]). + +-else. + +-define(FSMOPTS, []). + +-endif. + +-define(BOSH_VERSION, <<"1.11">>). + +-define(NS_BOSH, <<"urn:xmpp:xbosh">>). + +-define(NS_HTTP_BIND, + <<"http://jabber.org/protocol/httpbind">>). + +-define(DEFAULT_MAXPAUSE, 120). + +-define(DEFAULT_WAIT, 300). + +-define(DEFAULT_HOLD, 1). + +-define(DEFAULT_POLLING, 2). + +-define(DEFAULT_INACTIVITY, 30). + +-define(MAX_SHAPED_REQUESTS_QUEUE_LEN, 1000). + +-define(SEND_TIMEOUT, 15000). + +-type bosh_socket() :: {http_bind, pid(), + {inet:ip_address(), + inet:port_number()}}. + +-export_type([bosh_socket/0]). + +-record(state, + {host = <<"">> :: binary(), + sid = <<"">> :: binary(), + el_ibuf = buf_new() :: ?TQUEUE, + el_obuf = buf_new() :: ?TQUEUE, + shaper_state = none :: shaper:shaper(), + c2s_pid :: pid(), + xmpp_ver = <<"">> :: binary(), + inactivity_timer :: reference(), + wait_timer :: reference(), + wait_timeout = ?DEFAULT_WAIT :: timeout(), + inactivity_timeout = ?DEFAULT_INACTIVITY :: timeout(), + prev_rid = 0 :: non_neg_integer(), + prev_key = <<"">> :: binary(), + prev_poll :: erlang:timestamp(), + max_concat = unlimited :: unlimited | non_neg_integer(), + responses = gb_trees:empty() :: ?TGB_TREE, + receivers = gb_trees:empty() :: ?TGB_TREE, + shaped_receivers = queue:new() :: ?TQUEUE, + ip :: inet:ip_address(), + max_requests = 1 :: non_neg_integer()}). + +-record(body, + {http_reason = <<"">> :: binary(), + attrs = [] :: [{any(), any()}], + els = [] :: [fxml_stream:xml_stream_el()], + size = 0 :: non_neg_integer()}). + +start(#body{attrs = Attrs} = Body, IP, SID) -> + XMPPDomain = get_attr(to, Attrs), + SupervisorProc = gen_mod:get_module_proc(XMPPDomain, ?PROCNAME), + case catch supervisor:start_child(SupervisorProc, + [Body, IP, SID]) + of + {ok, Pid} -> {ok, Pid}; + {'EXIT', {noproc, _}} -> + check_bosh_module(XMPPDomain), + {error, module_not_loaded}; + Err -> + ?ERROR_MSG("Failed to start BOSH session: ~p", [Err]), + {error, Err} + end. + +start(StateName, State) -> + (?GEN_FSM):start_link(?MODULE, [StateName, State], + ?FSMOPTS). + +start_link(Body, IP, SID) -> + (?GEN_FSM):start_link(?MODULE, [Body, IP, SID], + ?FSMOPTS). + +send({http_bind, FsmRef, IP}, Packet) -> + send_xml({http_bind, FsmRef, IP}, Packet). + +send_xml({http_bind, FsmRef, _IP}, Packet) -> + case catch (?GEN_FSM):sync_send_all_state_event(FsmRef, + {send_xml, Packet}, + ?SEND_TIMEOUT) + of + {'EXIT', {timeout, _}} -> {error, timeout}; + {'EXIT', _} -> {error, einval}; + Res -> Res + end. + +setopts({http_bind, FsmRef, _IP}, Opts) -> + case lists:member({active, once}, Opts) of + true -> + (?GEN_FSM):send_all_state_event(FsmRef, + {activate, self()}); + _ -> + case lists:member({active, false}, Opts) of + true -> + case catch (?GEN_FSM):sync_send_all_state_event(FsmRef, + deactivate_socket) + of + {'EXIT', _} -> {error, einval}; + Res -> Res + end; + _ -> ok + end + end. + +controlling_process(_Socket, _Pid) -> ok. + +custom_receiver({http_bind, FsmRef, _IP}) -> + {receiver, ?MODULE, FsmRef}. + +become_controller(FsmRef, C2SPid) -> + (?GEN_FSM):send_all_state_event(FsmRef, + {become_controller, C2SPid}). + +change_controller({http_bind, FsmRef, _IP}, C2SPid) -> + become_controller(FsmRef, C2SPid). + +reset_stream({http_bind, _FsmRef, _IP}) -> ok. + +change_shaper({http_bind, FsmRef, _IP}, Shaper) -> + (?GEN_FSM):send_all_state_event(FsmRef, + {change_shaper, Shaper}). + +monitor({http_bind, FsmRef, _IP}) -> + erlang:monitor(process, FsmRef). + +close({http_bind, FsmRef, _IP}) -> + catch (?GEN_FSM):sync_send_all_state_event(FsmRef, + close). + +sockname(_Socket) -> {ok, {{0, 0, 0, 0}, 0}}. + +peername({http_bind, _FsmRef, IP}) -> {ok, IP}. + +migrate(FsmRef, Node, After) when node(FsmRef) == node() -> + catch erlang:send_after(After, FsmRef, {migrate, Node}); +migrate(_FsmRef, _Node, _After) -> + ok. + +process_request(Data, IP, Type) -> + Opts1 = ejabberd_c2s_config:get_c2s_limits(), + Opts = case Type of + xml -> + [{xml_socket, true} | Opts1]; + json -> + Opts1 + end, + MaxStanzaSize = case lists:keysearch(max_stanza_size, 1, + Opts) + of + {value, {_, Size}} -> Size; + _ -> infinity + end, + PayloadSize = iolist_size(Data), + if PayloadSize > MaxStanzaSize -> + http_error(403, <<"Request Too Large">>, Type); + true -> + case decode_body(Data, PayloadSize, Type) of + {ok, #body{attrs = Attrs} = Body} -> + SID = get_attr(sid, Attrs), + To = get_attr(to, Attrs), + if SID == <<"">>, To == <<"">> -> + bosh_response_with_msg(#body{http_reason = + <<"Missing 'to' attribute">>, + attrs = + [{type, <<"terminate">>}, + {condition, + <<"improper-addressing">>}]}, + Type, Body); + SID == <<"">> -> + case start(Body, IP, make_sid()) of + {ok, Pid} -> process_request(Pid, Body, IP, Type); + _Err -> + bosh_response_with_msg(#body{http_reason = + <<"Failed to start BOSH session">>, + attrs = + [{type, <<"terminate">>}, + {condition, + <<"internal-server-error">>}]}, + Type, Body) + end; + true -> + case mod_bosh:find_session(SID) of + {ok, Pid} -> process_request(Pid, Body, IP, Type); + error -> + bosh_response_with_msg(#body{http_reason = + <<"Session ID mismatch">>, + attrs = + [{type, <<"terminate">>}, + {condition, + <<"item-not-found">>}]}, + Type, Body) + end + end; + {error, Reason} -> http_error(400, Reason, Type) + end + end. + +process_request(Pid, Req, _IP, Type) -> + case catch (?GEN_FSM):sync_send_event(Pid, Req, + infinity) + of + #body{} = Resp -> bosh_response(Resp, Type); + {'EXIT', {Reason, _}} + when Reason == noproc; Reason == normal -> + bosh_response(#body{http_reason = + <<"BOSH session not found">>, + attrs = + [{type, <<"terminate">>}, + {condition, <<"item-not-found">>}]}, + Type); + {'EXIT', _} -> + bosh_response(#body{http_reason = + <<"Unexpected error">>, + attrs = + [{type, <<"terminate">>}, + {condition, <<"internal-server-error">>}]}, + Type) + end. + +init([#body{attrs = Attrs}, IP, SID]) -> + Opts1 = ejabberd_c2s_config:get_c2s_limits(), + Opts2 = [{xml_socket, true} | Opts1], + Shaper = none, + ShaperState = shaper:new(Shaper), + Socket = make_socket(self(), IP), + XMPPVer = get_attr('xmpp:version', Attrs), + XMPPDomain = get_attr(to, Attrs), + {InBuf, Opts} = case gen_mod:get_module_opt( + XMPPDomain, + mod_bosh, prebind, + fun(B) when is_boolean(B) -> B end, + false) of + true -> + JID = make_random_jid(XMPPDomain), + {buf_new(), [{jid, JID} | Opts2]}; + false -> + {buf_in([make_xmlstreamstart(XMPPDomain, XMPPVer)], + buf_new()), + Opts2} + end, + ejabberd_socket:start(ejabberd_c2s, ?MODULE, Socket, + Opts), + Inactivity = gen_mod:get_module_opt(XMPPDomain, + mod_bosh, max_inactivity, + fun(I) when is_integer(I), I>0 -> I end, + ?DEFAULT_INACTIVITY), + MaxConcat = gen_mod:get_module_opt(XMPPDomain, mod_bosh, max_concat, + fun(unlimited) -> unlimited; + (N) when is_integer(N), N>0 -> N + end, unlimited), + State = #state{host = XMPPDomain, sid = SID, ip = IP, + xmpp_ver = XMPPVer, el_ibuf = InBuf, + max_concat = MaxConcat, el_obuf = buf_new(), + inactivity_timeout = Inactivity, + shaper_state = ShaperState}, + NewState = restart_inactivity_timer(State), + mod_bosh:open_session(SID, self()), + {ok, wait_for_session, NewState}; +init([StateName, State]) -> + mod_bosh:open_session(State#state.sid, self()), + case State#state.c2s_pid of + C2SPid when is_pid(C2SPid) -> + NewSocket = make_socket(self(), State#state.ip), + C2SPid ! {change_socket, NewSocket}, + NewState = restart_inactivity_timer(State), + {ok, StateName, NewState}; + _ -> {stop, normal} + end. + +wait_for_session(_Event, State) -> + ?ERROR_MSG("unexpected event in 'wait_for_session': ~p", + [_Event]), + {next_state, wait_for_session, State}. + +wait_for_session(#body{attrs = Attrs} = Req, From, + State) -> + RID = get_attr(rid, Attrs), + ?DEBUG("got request:~n** RequestID: ~p~n** Request: " + "~p~n** From: ~p~n** State: ~p", + [RID, Req, From, State]), + Wait = min(get_attr(wait, Attrs, undefined), + ?DEFAULT_WAIT), + Hold = min(get_attr(hold, Attrs, undefined), + ?DEFAULT_HOLD), + NewKey = get_attr(newkey, Attrs), + Type = get_attr(type, Attrs), + Requests = Hold + 1, + {PollTime, Polling} = if Wait == 0, Hold == 0 -> + {p1_time_compat:timestamp(), [{polling, ?DEFAULT_POLLING}]}; + true -> {undefined, []} + end, + MaxPause = gen_mod:get_module_opt(State#state.host, + mod_bosh, max_pause, + fun(I) when is_integer(I), I>0 -> I end, + ?DEFAULT_MAXPAUSE), + Resp = #body{attrs = + [{sid, State#state.sid}, {wait, Wait}, + {ver, ?BOSH_VERSION}, {polling, ?DEFAULT_POLLING}, + {inactivity, State#state.inactivity_timeout}, + {hold, Hold}, {'xmpp:restartlogic', true}, + {requests, Requests}, {secure, true}, + {maxpause, MaxPause}, {'xmlns:xmpp', ?NS_BOSH}, + {'xmlns:stream', ?NS_STREAM}, {from, State#state.host} + | Polling]}, + {ShaperState, _} = + shaper:update(State#state.shaper_state, Req#body.size), + State1 = State#state{wait_timeout = Wait, + prev_rid = RID, prev_key = NewKey, + prev_poll = PollTime, shaper_state = ShaperState, + max_requests = Requests}, + Els = maybe_add_xmlstreamend(Req#body.els, Type), + State2 = route_els(State1, Els), + {State3, RespEls} = get_response_els(State2), + State4 = stop_inactivity_timer(State3), + case RespEls of + [] -> + State5 = restart_wait_timer(State4), + Receivers = gb_trees:insert(RID, {From, Resp}, + State5#state.receivers), + {next_state, active, + State5#state{receivers = Receivers}}; + _ -> + reply_next_state(State4, Resp#body{els = RespEls}, RID, + From) + end; +wait_for_session(_Event, _From, State) -> + ?ERROR_MSG("unexpected sync event in 'wait_for_session': ~p", + [_Event]), + {reply, {error, badarg}, wait_for_session, State}. + +active({#body{} = Body, From}, State) -> + active1(Body, From, State); +active(_Event, State) -> + ?ERROR_MSG("unexpected event in 'active': ~p", + [_Event]), + {next_state, active, State}. + +active(#body{attrs = Attrs, size = Size} = Req, From, + State) -> + ?DEBUG("got request:~n** Request: ~p~n** From: " + "~p~n** State: ~p", + [Req, From, State]), + {ShaperState, Pause} = + shaper:update(State#state.shaper_state, Size), + State1 = State#state{shaper_state = ShaperState}, + if Pause > 0 -> + QLen = queue:len(State1#state.shaped_receivers), + if QLen < (?MAX_SHAPED_REQUESTS_QUEUE_LEN) -> + TRef = start_shaper_timer(Pause), + Q = queue:in({TRef, From, Req}, + State1#state.shaped_receivers), + State2 = stop_inactivity_timer(State1), + {next_state, active, + State2#state{shaped_receivers = Q}}; + true -> + RID = get_attr(rid, Attrs), + reply_stop(State1, + #body{http_reason = <<"Too many requests">>, + attrs = + [{<<"type">>, <<"terminate">>}, + {<<"condition">>, + <<"policy-violation">>}]}, + From, RID) + end; + true -> active1(Req, From, State1) + end; +active(_Event, _From, State) -> + ?ERROR_MSG("unexpected sync event in 'active': ~p", + [_Event]), + {reply, {error, badarg}, active, State}. + +active1(#body{attrs = Attrs} = Req, From, State) -> + RID = get_attr(rid, Attrs), + Key = get_attr(key, Attrs), + IsValidKey = is_valid_key(State#state.prev_key, Key), + IsOveractivity = is_overactivity(State#state.prev_poll), + Type = get_attr(type, Attrs), + if RID > + State#state.prev_rid + State#state.max_requests -> + reply_stop(State, + #body{http_reason = <<"Request ID is out of range">>, + attrs = + [{<<"type">>, <<"terminate">>}, + {<<"condition">>, <<"item-not-found">>}]}, + From, RID); + RID > State#state.prev_rid + 1 -> + State1 = restart_inactivity_timer(State), + Receivers = gb_trees:insert(RID, {From, Req}, + State1#state.receivers), + {next_state, active, + State1#state{receivers = Receivers}}; + RID =< State#state.prev_rid -> + %% TODO: do we need to check 'key' here? It seems so... + case gb_trees:lookup(RID, State#state.responses) of + {value, PrevBody} -> + {next_state, active, + do_reply(State, From, PrevBody, RID)}; + none -> + State1 = drop_holding_receiver(State), + State2 = stop_inactivity_timer(State1), + State3 = restart_wait_timer(State2), + Receivers = gb_trees:insert(RID, {From, Req}, + State3#state.receivers), + {next_state, active, State3#state{receivers = Receivers}} + end; + not IsValidKey -> + reply_stop(State, + #body{http_reason = <<"Session key mismatch">>, + attrs = + [{<<"type">>, <<"terminate">>}, + {<<"condition">>, <<"item-not-found">>}]}, + From, RID); + IsOveractivity -> + reply_stop(State, + #body{http_reason = <<"Too many requests">>, + attrs = + [{<<"type">>, <<"terminate">>}, + {<<"condition">>, <<"policy-violation">>}]}, + From, RID); + true -> + State1 = stop_inactivity_timer(State), + State2 = stop_wait_timer(State1), + Els = case get_attr('xmpp:restart', Attrs, false) of + true -> + XMPPDomain = get_attr(to, Attrs, State#state.host), + XMPPVer = get_attr('xmpp:version', Attrs, + State#state.xmpp_ver), + [make_xmlstreamstart(XMPPDomain, XMPPVer)]; + false -> Req#body.els + end, + State3 = route_els(State2, + maybe_add_xmlstreamend(Els, Type)), + {State4, RespEls} = get_response_els(State3), + NewKey = get_attr(newkey, Attrs, Key), + Pause = get_attr(pause, Attrs, undefined), + NewPoll = case State#state.prev_poll of + undefined -> undefined; + _ -> p1_time_compat:timestamp() + end, + State5 = State4#state{prev_poll = NewPoll, + prev_key = NewKey}, + if Type == <<"terminate">> -> + reply_stop(State5, + #body{http_reason = <<"Session close">>, + attrs = [{<<"type">>, <<"terminate">>}], + els = RespEls}, + From, RID); + Pause /= undefined -> + State6 = drop_holding_receiver(State5), + State7 = restart_inactivity_timer(State6, Pause), + InBuf = buf_in(RespEls, State7#state.el_ibuf), + {next_state, active, + State7#state{prev_rid = RID, el_ibuf = InBuf}}; + RespEls == [] -> + State6 = drop_holding_receiver(State5), + State7 = stop_inactivity_timer(State6), + State8 = restart_wait_timer(State7), + Receivers = gb_trees:insert(RID, {From, #body{}}, + State8#state.receivers), + {next_state, active, + State8#state{prev_rid = RID, receivers = Receivers}}; + true -> + State6 = drop_holding_receiver(State5), + reply_next_state(State6#state{prev_rid = RID}, + #body{els = RespEls}, RID, From) + end + end. + +handle_event({become_controller, C2SPid}, StateName, + State) -> + State1 = route_els(State#state{c2s_pid = C2SPid}), + {next_state, StateName, State1}; +handle_event({change_shaper, Shaper}, StateName, + State) -> + NewShaperState = shaper:new(Shaper), + {next_state, StateName, + State#state{shaper_state = NewShaperState}}; +handle_event(_Event, StateName, State) -> + ?ERROR_MSG("unexpected event in '~s': ~p", + [StateName, _Event]), + {next_state, StateName, State}. + +handle_sync_event({send_xml, + {xmlstreamstart, _, _} = El}, + _From, StateName, State) + when State#state.xmpp_ver >= <<"1.0">> -> + OutBuf = buf_in([El], State#state.el_obuf), + {reply, ok, StateName, State#state{el_obuf = OutBuf}}; +handle_sync_event({send_xml, El}, _From, StateName, + State) -> + OutBuf = buf_in([El], State#state.el_obuf), + State1 = State#state{el_obuf = OutBuf}, + case gb_trees:lookup(State1#state.prev_rid, + State1#state.receivers) + of + {value, {From, Body}} -> + {State2, Els} = get_response_els(State1), + {reply, ok, StateName, + reply(State2, Body#body{els = Els}, + State2#state.prev_rid, From)}; + none -> + State2 = case queue:out(State1#state.shaped_receivers) + of + {{value, {TRef, From, Body}}, Q} -> + cancel_timer(TRef), + (?GEN_FSM):send_event(self(), {Body, From}), + State1#state{shaped_receivers = Q}; + _ -> State1 + end, + {reply, ok, StateName, State2} + end; +handle_sync_event(close, _From, _StateName, State) -> + {stop, normal, State}; +handle_sync_event(deactivate_socket, _From, StateName, + StateData) -> + {reply, ok, StateName, + StateData#state{c2s_pid = undefined}}; +handle_sync_event(_Event, _From, StateName, State) -> + ?ERROR_MSG("unexpected sync event in '~s': ~p", + [StateName, _Event]), + {reply, {error, badarg}, StateName, State}. + +handle_info({timeout, TRef, wait_timeout}, StateName, + #state{wait_timer = TRef} = State) -> + {next_state, StateName, drop_holding_receiver(State)}; +handle_info({timeout, TRef, inactive}, _StateName, + #state{inactivity_timer = TRef} = State) -> + {stop, normal, State}; +handle_info({timeout, TRef, shaper_timeout}, StateName, + State) -> + case queue:out(State#state.shaped_receivers) of + {{value, {TRef, From, Req}}, Q} -> + (?GEN_FSM):send_event(self(), {Req, From}), + {next_state, StateName, + State#state{shaped_receivers = Q}}; + {{value, _}, _} -> + ?ERROR_MSG("shaper_timeout mismatch:~n** TRef: ~p~n** " + "State: ~p", + [TRef, State]), + {stop, normal, State}; + _ -> {next_state, StateName, State} + end; +handle_info({migrate, Node}, StateName, State) -> + if Node /= node() -> + NewState = bounce_receivers(State, migrated), + {migrate, NewState, + {Node, ?MODULE, start, [StateName, NewState]}, 0}; + true -> {next_state, StateName, State} + end; +handle_info(_Info, StateName, State) -> + ?ERROR_MSG("unexpected info:~n** Msg: ~p~n** StateName: ~p", + [_Info, StateName]), + {next_state, StateName, State}. + +terminate({migrated, ClonePid}, _StateName, State) -> + ?INFO_MSG("Migrating session \"~s\" (c2s_pid = " + "~p) to ~p on node ~p", + [State#state.sid, State#state.c2s_pid, ClonePid, + node(ClonePid)]), + mod_bosh:close_session(State#state.sid); +terminate(_Reason, _StateName, State) -> + mod_bosh:close_session(State#state.sid), + case State#state.c2s_pid of + C2SPid when is_pid(C2SPid) -> + (?GEN_FSM):send_event(C2SPid, closed); + _ -> ok + end, + bounce_receivers(State, closed), + bounce_els_from_obuf(State). + +code_change(_OldVsn, StateName, State, _Extra) -> + {ok, StateName, State}. + +print_state(State) -> State. + +route_els(#state{el_ibuf = Buf} = State) -> + route_els(State#state{el_ibuf = buf_new()}, + buf_to_list(Buf)). + +route_els(State, Els) -> + case State#state.c2s_pid of + C2SPid when is_pid(C2SPid) -> + lists:foreach(fun (El) -> + (?GEN_FSM):send_event(C2SPid, El) + end, + Els), + State; + _ -> + InBuf = buf_in(Els, State#state.el_ibuf), + State#state{el_ibuf = InBuf} + end. + +get_response_els(#state{el_obuf = OutBuf, + max_concat = MaxConcat} = + State) -> + {Els, NewOutBuf} = buf_out(OutBuf, MaxConcat), + {State#state{el_obuf = NewOutBuf}, Els}. + +reply(State, Body, RID, From) -> + State1 = restart_inactivity_timer(State), + Receivers = gb_trees:delete_any(RID, + State1#state.receivers), + State2 = do_reply(State1, From, Body, RID), + case catch gb_trees:take_smallest(Receivers) of + {NextRID, {From1, Req}, Receivers1} + when NextRID == RID + 1 -> + (?GEN_FSM):send_event(self(), {Req, From1}), + State2#state{receivers = Receivers1}; + _ -> State2#state{receivers = Receivers} + end. + +reply_next_state(State, Body, RID, From) -> + State1 = restart_inactivity_timer(State), + Receivers = gb_trees:delete_any(RID, + State1#state.receivers), + State2 = do_reply(State1, From, Body, RID), + case catch gb_trees:take_smallest(Receivers) of + {NextRID, {From1, Req}, Receivers1} + when NextRID == RID + 1 -> + active(Req, From1, + State2#state{receivers = Receivers1}); + _ -> + {next_state, active, + State2#state{receivers = Receivers}} + end. + +reply_stop(State, Body, From, RID) -> + {stop, normal, do_reply(State, From, Body, RID)}. + +drop_holding_receiver(State) -> + RID = State#state.prev_rid, + case gb_trees:lookup(RID, State#state.receivers) of + {value, {From, Body}} -> + State1 = restart_inactivity_timer(State), + Receivers = gb_trees:delete_any(RID, + State1#state.receivers), + State2 = State1#state{receivers = Receivers}, + do_reply(State2, From, Body, RID); + none -> State + end. + +do_reply(State, From, Body, RID) -> + ?DEBUG("send reply:~n** RequestID: ~p~n** Reply: " + "~p~n** To: ~p~n** State: ~p", + [RID, Body, From, State]), + (?GEN_FSM):reply(From, Body), + Responses = gb_trees:delete_any(RID, + State#state.responses), + Responses1 = case gb_trees:size(Responses) of + N when N < State#state.max_requests; N == 0 -> + Responses; + _ -> element(3, gb_trees:take_smallest(Responses)) + end, + Responses2 = gb_trees:insert(RID, Body, Responses1), + State#state{responses = Responses2}. + +bounce_receivers(State, Reason) -> + Receivers = gb_trees:to_list(State#state.receivers), + ShapedReceivers = lists:map(fun ({_, From, + #body{attrs = Attrs} = Body}) -> + RID = get_attr(rid, Attrs), + {RID, {From, Body}} + end, + queue:to_list(State#state.shaped_receivers)), + lists:foldl(fun ({RID, {From, Body}}, AccState) -> + NewBody = if Reason == closed -> + #body{http_reason = + <<"Session closed">>, + attrs = + [{type, <<"terminate">>}, + {condition, + <<"other-request">>}]}; + Reason == migrated -> + Body#body{http_reason = + <<"Session migrated">>} + end, + do_reply(AccState, From, NewBody, RID) + end, + State, Receivers ++ ShapedReceivers). + +bounce_els_from_obuf(State) -> + lists:foreach(fun ({xmlstreamelement, El}) -> + case El of + #xmlel{name = Name, attrs = Attrs} + when Name == <<"presence">>; + Name == <<"message">>; + Name == <<"iq">> -> + FromS = fxml:get_attr_s(<<"from">>, Attrs), + ToS = fxml:get_attr_s(<<"to">>, Attrs), + case {jid:from_string(FromS), + jid:from_string(ToS)} + of + {#jid{} = From, #jid{} = To} -> + ejabberd_router:route(From, To, El); + _ -> ok + end; + _ -> ok + end; + (_) -> ok + end, + buf_to_list(State#state.el_obuf)). + +is_valid_key(<<"">>, <<"">>) -> true; +is_valid_key(PrevKey, Key) -> + p1_sha:sha(Key) == PrevKey. + +is_overactivity(undefined) -> false; +is_overactivity(PrevPoll) -> + PollPeriod = timer:now_diff(p1_time_compat:timestamp(), PrevPoll) div + 1000000, + if PollPeriod < (?DEFAULT_POLLING) -> true; + true -> false + end. + +make_xmlstreamstart(XMPPDomain, Version) -> + VersionEl = case Version of + <<"">> -> []; + _ -> [{<<"version">>, Version}] + end, + {xmlstreamstart, <<"stream:stream">>, + [{<<"to">>, XMPPDomain}, {<<"xmlns">>, ?NS_CLIENT}, + {<<"xmlns:xmpp">>, ?NS_BOSH}, + {<<"xmlns:stream">>, ?NS_STREAM} + | VersionEl]}. + +maybe_add_xmlstreamend(Els, <<"terminate">>) -> + Els ++ [{xmlstreamend, <<"stream:stream">>}]; +maybe_add_xmlstreamend(Els, _) -> Els. + +encode_body(#body{attrs = Attrs, els = Els}, Type) -> + Attrs1 = lists:map(fun ({K, V}) when is_atom(K) -> + AmK = iolist_to_binary(atom_to_list(K)), + case V of + true -> {AmK, <<"true">>}; + false -> {AmK, <<"false">>}; + I when is_integer(I), I >= 0 -> + {AmK, iolist_to_binary(integer_to_list(I))}; + _ -> {AmK, V} + end; + ({K, V}) -> {K, V} + end, + Attrs), + Attrs2 = [{<<"xmlns">>, ?NS_HTTP_BIND} | Attrs1], + {Attrs3, XMLs} = lists:foldr(fun ({xmlstreamraw, XML}, + {AttrsAcc, XMLBuf}) -> + {AttrsAcc, [XML | XMLBuf]}; + ({xmlstreamelement, + #xmlel{name = <<"stream:error">>} = El}, + {AttrsAcc, XMLBuf}) -> + {[{<<"type">>, <<"terminate">>}, + {<<"condition">>, + <<"remote-stream-error">>}, + {<<"xmlns:stream">>, ?NS_STREAM} + | AttrsAcc], + [encode_element(El, Type) | XMLBuf]}; + ({xmlstreamelement, + #xmlel{name = <<"stream:features">>} = + El}, + {AttrsAcc, XMLBuf}) -> + {lists:keystore(<<"xmlns:stream">>, 1, + AttrsAcc, + {<<"xmlns:stream">>, + ?NS_STREAM}), + [encode_element(El, Type) | XMLBuf]}; + ({xmlstreamelement, + #xmlel{name = Name, attrs = EAttrs} = El}, + {AttrsAcc, XMLBuf}) + when Name == <<"message">>; + Name == <<"presence">>; + Name == <<"iq">> -> + NewAttrs = lists:keystore( + <<"xmlns">>, 1, EAttrs, + {<<"xmlns">>, ?NS_CLIENT}), + NewEl = El#xmlel{attrs = NewAttrs}, + {AttrsAcc, + [encode_element(NewEl, Type) | XMLBuf]}; + ({xmlstreamelement, El}, + {AttrsAcc, XMLBuf}) -> + {AttrsAcc, + [encode_element(El, Type) | XMLBuf]}; + ({xmlstreamend, _}, {AttrsAcc, XMLBuf}) -> + {[{<<"type">>, <<"terminate">>}, + {<<"condition">>, + <<"remote-stream-error">>} + | AttrsAcc], + XMLBuf}; + ({xmlstreamstart, <<"stream:stream">>, + SAttrs}, + {AttrsAcc, XMLBuf}) -> + StreamID = fxml:get_attr_s(<<"id">>, + SAttrs), + NewAttrs = case + fxml:get_attr_s(<<"version">>, + SAttrs) + of + <<"">> -> + [{<<"authid">>, + StreamID} + | AttrsAcc]; + V -> + lists:keystore(<<"xmlns:xmpp">>, + 1, + [{<<"xmpp:version">>, + V}, + {<<"authid">>, + StreamID} + | AttrsAcc], + {<<"xmlns:xmpp">>, + ?NS_BOSH}) + end, + {NewAttrs, XMLBuf}; + ({xmlstreamerror, _}, + {AttrsAcc, XMLBuf}) -> + {[{<<"type">>, <<"terminate">>}, + {<<"condition">>, + <<"remote-stream-error">>} + | AttrsAcc], + XMLBuf}; + (_, Acc) -> Acc + end, + {Attrs2, []}, Els), + case XMLs of + [] when Type == xml -> + [<<">, attrs_to_list(Attrs3), <<"/>">>]; + _ when Type == xml -> + [<<">, attrs_to_list(Attrs3), $>, XMLs, + <<"">>] + end. + +encode_element(El, xml) -> + fxml:element_to_binary(El); +encode_element(El, json) -> + El. + +decode_body(Data, Size, Type) -> + case decode(Data, Type) of + #xmlel{name = <<"body">>, attrs = Attrs, + children = Els} -> + case attrs_to_body_attrs(Attrs) of + {error, _} = Err -> Err; + BodyAttrs -> + case get_attr(rid, BodyAttrs) of + <<"">> -> {error, <<"Missing \"rid\" attribute">>}; + _ -> + Els1 = lists:flatmap(fun (#xmlel{} = El) -> + [{xmlstreamelement, El}]; + (_) -> [] + end, + Els), + {ok, #body{attrs = BodyAttrs, size = Size, els = Els1}} + end + end; + #xmlel{} -> {error, <<"Unexpected payload">>}; + _ when Type == xml -> + {error, <<"XML is not well-formed">>}; + _ when Type == json -> + {error, <<"JSON is not well-formed">>} + end. + +decode(Data, xml) -> + fxml_stream:parse_element(Data). + +attrs_to_body_attrs(Attrs) -> + lists:foldl(fun (_, {error, Reason}) -> {error, Reason}; + ({Attr, Val}, Acc) -> + try case Attr of + <<"ver">> -> [{ver, Val} | Acc]; + <<"xmpp:version">> -> + [{'xmpp:version', Val} | Acc]; + <<"type">> -> [{type, Val} | Acc]; + <<"key">> -> [{key, Val} | Acc]; + <<"newkey">> -> [{newkey, Val} | Acc]; + <<"xmlns">> -> Val = (?NS_HTTP_BIND), Acc; + <<"secure">> -> [{secure, to_bool(Val)} | Acc]; + <<"xmpp:restart">> -> + [{'xmpp:restart', to_bool(Val)} | Acc]; + <<"to">> -> + [{to, jid:nameprep(Val)} | Acc]; + <<"wait">> -> [{wait, to_int(Val, 0)} | Acc]; + <<"ack">> -> [{ack, to_int(Val, 0)} | Acc]; + <<"sid">> -> [{sid, Val} | Acc]; + <<"hold">> -> [{hold, to_int(Val, 0)} | Acc]; + <<"rid">> -> [{rid, to_int(Val, 0)} | Acc]; + <<"pause">> -> [{pause, to_int(Val, 0)} | Acc]; + _ -> [{Attr, Val} | Acc] + end + catch + _:_ -> + {error, + <<"Invalid \"", Attr/binary, "\" attribute">>} + end + end, + [], Attrs). + +to_int(S, Min) -> + case jlib:binary_to_integer(S) of + I when I >= Min -> I; + _ -> erlang:error(badarg) + end. + +to_bool(<<"true">>) -> true; +to_bool(<<"1">>) -> true; +to_bool(<<"false">>) -> false; +to_bool(<<"0">>) -> false. + +attrs_to_list(Attrs) -> [attr_to_list(A) || A <- Attrs]. + +attr_to_list({Name, Value}) -> + [$\s, Name, $=, $', fxml:crypt(Value), $']. + +bosh_response(Body, Type) -> + CType = case Type of + xml -> ?CT_XML; + json -> ?CT_JSON + end, + {200, Body#body.http_reason, ?HEADER(CType), + encode_body(Body, Type)}. + +bosh_response_with_msg(Body, Type, RcvBody) -> + ?DEBUG("send error reply:~p~n** Receiced body: ~p", + [Body, RcvBody]), + bosh_response(Body, Type). + +http_error(Status, Reason, Type) -> + CType = case Type of + xml -> ?CT_XML; + json -> ?CT_JSON + end, + {Status, Reason, ?HEADER(CType), <<"">>}. + +make_sid() -> p1_sha:sha(randoms:get_string()). + +-compile({no_auto_import, [{min, 2}]}). + +min(undefined, B) -> B; +min(A, B) -> erlang:min(A, B). + +check_bosh_module(XmppDomain) -> + case gen_mod:is_loaded(XmppDomain, mod_bosh) of + true -> ok; + false -> + ?ERROR_MSG("You are trying to use BOSH (HTTP Bind) " + "in host ~p, but the module mod_bosh " + "is not started in that host. Configure " + "your BOSH client to connect to the correct " + "host, or add your desired host to the " + "configuration, or check your 'modules' " + "section in your ejabberd configuration " + "file.", + [XmppDomain]) + end. + +get_attr(Attr, Attrs) -> get_attr(Attr, Attrs, <<"">>). + +get_attr(Attr, Attrs, Default) -> + case lists:keysearch(Attr, 1, Attrs) of + {value, {_, Val}} -> Val; + _ -> Default + end. + +buf_new() -> queue:new(). + +buf_in(Xs, Buf) -> + lists:foldl(fun (X, Acc) -> queue:in(X, Acc) end, Buf, + Xs). + +buf_out(Buf, Num) when is_integer(Num), Num > 0 -> + buf_out(Buf, Num, []); +buf_out(Buf, _) -> {queue:to_list(Buf), buf_new()}. + +buf_out(Buf, 0, Els) -> {lists:reverse(Els), Buf}; +buf_out(Buf, I, Els) -> + case queue:out(Buf) of + {{value, El}, NewBuf} -> + buf_out(NewBuf, I - 1, [El | Els]); + {empty, _} -> buf_out(Buf, 0, Els) + end. + +buf_to_list(Buf) -> queue:to_list(Buf). + +cancel_timer(TRef) when is_reference(TRef) -> + (?GEN_FSM):cancel_timer(TRef); +cancel_timer(_) -> false. + +restart_timer(TRef, Timeout, Msg) -> + cancel_timer(TRef), + erlang:start_timer(timer:seconds(Timeout), self(), Msg). + +restart_inactivity_timer(#state{inactivity_timeout = + Timeout} = + State) -> + restart_inactivity_timer(State, Timeout). + +restart_inactivity_timer(#state{inactivity_timer = + TRef} = + State, + Timeout) -> + NewTRef = restart_timer(TRef, Timeout, inactive), + State#state{inactivity_timer = NewTRef}. + +stop_inactivity_timer(#state{inactivity_timer = TRef} = + State) -> + cancel_timer(TRef), + State#state{inactivity_timer = undefined}. + +restart_wait_timer(#state{wait_timer = TRef, + wait_timeout = Timeout} = + State) -> + NewTRef = restart_timer(TRef, Timeout, wait_timeout), + State#state{wait_timer = NewTRef}. + +stop_wait_timer(#state{wait_timer = TRef} = State) -> + cancel_timer(TRef), State#state{wait_timer = undefined}. + +start_shaper_timer(Timeout) -> + erlang:start_timer(Timeout, self(), shaper_timeout). + +make_random_jid(Host) -> + User = randoms:get_string(), + jid:make(User, Host, randoms:get_string()). + +make_socket(Pid, IP) -> {http_bind, Pid, IP}. diff --git a/src/ejabberd_socket.erl b/src/ejabberd_socket.erl index b5fa52ded..e26fc8652 100644 --- a/src/ejabberd_socket.erl +++ b/src/ejabberd_socket.erl @@ -52,12 +52,14 @@ -include("logger.hrl"). -type sockmod() :: ejabberd_http_bind | + ejabberd_bosh | ejabberd_http_ws | gen_tcp | fast_tls | ezlib. -type receiver() :: pid () | atom(). -type socket() :: pid() | inet:socket() | fast_tls:tls_socket() | - ezlib:zlib_socket() | + ezlib:zlib_socket() | + ejabberd_bosh:bind_socket() | ejabberd_http_bind:bind_socket(). -record(socket_state, {sockmod = gen_tcp :: sockmod(), @@ -228,6 +230,7 @@ get_transport(#socket_state{sockmod = SockMod, tcp -> tcp_zlib; tls -> tls_zlib end; + ejabberd_bosh -> http_bind; ejabberd_http_bind -> http_bind; ejabberd_http_ws -> websocket end. @@ -254,4 +257,3 @@ peername(#socket_state{sockmod = SockMod, gen_tcp -> inet:peername(Socket); _ -> SockMod:peername(Socket) end. - diff --git a/src/mod_bosh.erl b/src/mod_bosh.erl new file mode 100644 index 000000000..13d85b3cb --- /dev/null +++ b/src/mod_bosh.erl @@ -0,0 +1,296 @@ +%%%------------------------------------------------------------------- +%%% File : mod_bosh.erl +%%% Author : Evgeniy Khramtsov +%%% Purpose : This module acts as a bridge to ejabberd_bosh which implements +%%% the real stuff, this is to handle the new pluggable architecture +%%% for extending ejabberd's http service. +%%% Created : 20 Jul 2011 by Evgeniy Khramtsov +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2016 ProcessOne +%%% +%%% This program is free software; you can redistribute it and/or +%%% modify it under the terms of the GNU General Public License as +%%% published by the Free Software Foundation; either version 2 of the +%%% License, or (at your option) any later version. +%%% +%%% This program is distributed in the hope that it will be useful, +%%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%%% General Public License for more details. +%%% +%%% You should have received a copy of the GNU General Public License along +%%% with this program; if not, write to the Free Software Foundation, Inc., +%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +%%% +%%%------------------------------------------------------------------- +-module(mod_bosh). + +-author('steve@zeank.in-berlin.de'). + +%%-define(ejabberd_debug, true). + +-behaviour(gen_server). +-behaviour(gen_mod). + +-export([start_link/0]). +-export([start/2, stop/1, process/2, open_session/2, + close_session/1, find_session/1]). + +-export([init/1, handle_call/3, handle_cast/2, + handle_info/2, terminate/2, code_change/3, + depends/2, mod_opt_type/1]). + +-include("ejabberd.hrl"). +-include("logger.hrl"). +-include_lib("stdlib/include/ms_transform.hrl"). +-include("jlib.hrl"). + +-include("ejabberd_http.hrl"). + +-include("bosh.hrl"). + +-record(bosh, {sid = <<"">> :: binary() | '_', + timestamp = p1_time_compat:timestamp() :: erlang:timestamp() | '_', + pid = self() :: pid() | '$1'}). + +-record(state, {}). + +%%%---------------------------------------------------------------------- +%%% API +%%%---------------------------------------------------------------------- +start_link() -> + gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). + +process([], #request{method = 'POST', data = <<>>}) -> + ?DEBUG("Bad Request: no data", []), + {400, ?HEADER(?CT_XML), + #xmlel{name = <<"h1">>, attrs = [], + children = [{xmlcdata, <<"400 Bad Request">>}]}}; +process([], + #request{method = 'POST', data = Data, ip = IP, headers = Hdrs}) -> + ?DEBUG("Incoming data: ~p", [Data]), + Type = get_type(Hdrs), + ejabberd_bosh:process_request(Data, IP, Type); +process([], #request{method = 'GET', data = <<>>}) -> + {200, ?HEADER(?CT_XML), get_human_html_xmlel()}; +process([], #request{method = 'OPTIONS', data = <<>>}) -> + {200, ?OPTIONS_HEADER, []}; +process(_Path, _Request) -> + ?DEBUG("Bad Request: ~p", [_Request]), + {400, ?HEADER(?CT_XML), + #xmlel{name = <<"h1">>, attrs = [], + children = [{xmlcdata, <<"400 Bad Request">>}]}}. + +get_human_html_xmlel() -> + Heading = <<"ejabberd ", (jlib:atom_to_binary(?MODULE))/binary>>, + #xmlel{name = <<"html">>, + attrs = + [{<<"xmlns">>, <<"http://www.w3.org/1999/xhtml">>}], + children = + [#xmlel{name = <<"head">>, attrs = [], + children = + [#xmlel{name = <<"title">>, attrs = [], + children = [{xmlcdata, Heading}]}]}, + #xmlel{name = <<"body">>, attrs = [], + children = + [#xmlel{name = <<"h1">>, attrs = [], + children = [{xmlcdata, Heading}]}, + #xmlel{name = <<"p">>, attrs = [], + children = + [{xmlcdata, <<"An implementation of ">>}, + #xmlel{name = <<"a">>, + attrs = + [{<<"href">>, + <<"http://xmpp.org/extensions/xep-0206.html">>}], + children = + [{xmlcdata, + <<"XMPP over BOSH (XEP-0206)">>}]}]}, + #xmlel{name = <<"p">>, attrs = [], + children = + [{xmlcdata, + <<"This web page is only informative. To " + "use HTTP-Bind you need a Jabber/XMPP " + "client that supports it.">>}]}]}]}. + +open_session(SID, Pid) -> + Session = #bosh{sid = SID, timestamp = p1_time_compat:timestamp(), pid = Pid}, + lists:foreach( + fun(Node) when Node == node() -> + gen_server:call(?MODULE, {write, Session}); + (Node) -> + cluster_send({?MODULE, Node}, {write, Session}) + end, ejabberd_cluster:get_nodes()). + +close_session(SID) -> + case mnesia:dirty_read(bosh, SID) of + [Session] -> + lists:foreach( + fun(Node) when Node == node() -> + gen_server:call(?MODULE, {delete, Session}); + (Node) -> + cluster_send({?MODULE, Node}, {delete, Session}) + end, ejabberd_cluster:get_nodes()); + [] -> + ok + end. + +write_session(#bosh{pid = Pid1, sid = SID, timestamp = T1} = S1) -> + case mnesia:dirty_read(bosh, SID) of + [#bosh{pid = Pid2, timestamp = T2} = S2] -> + if Pid1 == Pid2 -> + mnesia:dirty_write(S1); + T1 < T2 -> + cluster_send(Pid2, replaced), + mnesia:dirty_write(S1); + true -> + cluster_send(Pid1, replaced), + mnesia:dirty_write(S2) + end; + [] -> + mnesia:dirty_write(S1) + end. + +delete_session(#bosh{sid = SID, pid = Pid1}) -> + case mnesia:dirty_read(bosh, SID) of + [#bosh{pid = Pid2}] -> + if Pid1 == Pid2 -> + mnesia:dirty_delete(bosh, SID); + true -> + ok + end; + [] -> + ok + end. + +find_session(SID) -> + case mnesia:dirty_read(bosh, SID) of + [#bosh{pid = Pid}] -> + {ok, Pid}; + [] -> + error + end. + +start(Host, Opts) -> + setup_database(), + start_jiffy(Opts), + TmpSup = gen_mod:get_module_proc(Host, ?PROCNAME), + TmpSupSpec = {TmpSup, + {ejabberd_tmp_sup, start_link, [TmpSup, ejabberd_bosh]}, + permanent, infinity, supervisor, [ejabberd_tmp_sup]}, + ProcSpec = {?MODULE, + {?MODULE, start_link, []}, + transient, 2000, worker, [?MODULE]}, + case supervisor:start_child(ejabberd_sup, ProcSpec) of + {ok, _} -> + supervisor:start_child(ejabberd_sup, TmpSupSpec); + {error, {already_started, _}} -> + supervisor:start_child(ejabberd_sup, TmpSupSpec); + Err -> + Err + end. + +stop(Host) -> + TmpSup = gen_mod:get_module_proc(Host, ?PROCNAME), + supervisor:terminate_child(ejabberd_sup, TmpSup), + supervisor:delete_child(ejabberd_sup, TmpSup). + +%%%=================================================================== +%%% gen_server callbacks +%%%=================================================================== +init([]) -> + {ok, #state{}}. + +handle_call({write, Session}, _From, State) -> + Res = write_session(Session), + {reply, Res, State}; +handle_call({delete, Session}, _From, State) -> + Res = delete_session(Session), + {reply, Res, State}; +handle_call(_Request, _From, State) -> + Reply = ok, + {reply, Reply, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info({write, Session}, State) -> + write_session(Session), + {noreply, State}; +handle_info({delete, Session}, State) -> + delete_session(Session), + {noreply, State}; +handle_info(_Info, State) -> + ?ERROR_MSG("got unexpected info: ~p", [_Info]), + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +setup_database() -> + case catch mnesia:table_info(bosh, attributes) of + [sid, pid] -> + mnesia:delete_table(bosh); + _ -> + ok + end, + mnesia:create_table(bosh, + [{ram_copies, [node()]}, {local_content, true}, + {attributes, record_info(fields, bosh)}]), + mnesia:add_table_copy(bosh, node(), ram_copies). + +start_jiffy(Opts) -> + case gen_mod:get_opt(json, Opts, + fun(false) -> false; + (true) -> true + end, false) of + false -> + ok; + true -> + case catch ejabberd:start_app(jiffy) of + ok -> + ok; + Err -> + ?WARNING_MSG("Failed to start JSON codec (jiffy): ~p. " + "JSON support will be disabled", [Err]) + end + end. + +get_type(Hdrs) -> + try + {_, S} = lists:keyfind('Content-Type', 1, Hdrs), + [T|_] = str:tokens(S, <<";">>), + [_, <<"json">>] = str:tokens(T, <<"/">>), + json + catch _:_ -> + xml + end. + +cluster_send(NodePid, Msg) -> + erlang:send(NodePid, Msg, [noconnect, nosuspend]). + +depends(_Host, _Opts) -> + []. + +mod_opt_type(json) -> + fun (false) -> false; + (true) -> true + end; +mod_opt_type(max_concat) -> + fun (unlimited) -> unlimited; + (N) when is_integer(N), N > 0 -> N + end; +mod_opt_type(max_inactivity) -> + fun (I) when is_integer(I), I > 0 -> I end; +mod_opt_type(max_pause) -> + fun (I) when is_integer(I), I > 0 -> I end; +mod_opt_type(prebind) -> + fun (B) when is_boolean(B) -> B end; +mod_opt_type(_) -> + [json, max_concat, max_inactivity, max_pause, prebind]. From a2fb493f91fee325db2d87cce3aa06d67701f359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Tue, 22 Nov 2016 15:35:47 +0100 Subject: [PATCH 121/151] Add missing include file --- include/bosh.hrl | 51 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 include/bosh.hrl diff --git a/include/bosh.hrl b/include/bosh.hrl new file mode 100644 index 000000000..9cdfd98d8 --- /dev/null +++ b/include/bosh.hrl @@ -0,0 +1,51 @@ +%%%---------------------------------------------------------------------- +%%% +%%% ejabberd, Copyright (C) 2002-2016 ProcessOne +%%% +%%% This program is free software; you can redistribute it and/or +%%% modify it under the terms of the GNU General Public License as +%%% published by the Free Software Foundation; either version 2 of the +%%% License, or (at your option) any later version. +%%% +%%% This program is distributed in the hope that it will be useful, +%%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%%% General Public License for more details. +%%% +%%% You should have received a copy of the GNU General Public License along +%%% with this program; if not, write to the Free Software Foundation, Inc., +%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +%%% +%%%---------------------------------------------------------------------- + +-define(CT_XML, + {<<"Content-Type">>, <<"text/xml; charset=utf-8">>}). + +-define(CT_PLAIN, + {<<"Content-Type">>, <<"text/plain">>}). + +-define(CT_JSON, + {<<"Content-Type">>, <<"application/json">>}). + +-define(AC_ALLOW_ORIGIN, + {<<"Access-Control-Allow-Origin">>, <<"*">>}). + +-define(AC_ALLOW_METHODS, + {<<"Access-Control-Allow-Methods">>, + <<"GET, POST, OPTIONS">>}). + +-define(AC_ALLOW_HEADERS, + {<<"Access-Control-Allow-Headers">>, + <<"Content-Type">>}). + +-define(AC_MAX_AGE, + {<<"Access-Control-Max-Age">>, <<"86400">>}). + +-define(OPTIONS_HEADER, + [?CT_PLAIN, ?AC_ALLOW_ORIGIN, ?AC_ALLOW_METHODS, + ?AC_ALLOW_HEADERS, ?AC_MAX_AGE]). + +-define(HEADER(CType), + [CType, ?AC_ALLOW_ORIGIN, ?AC_ALLOW_HEADERS]). + +-define(PROCNAME, ejabberd_mod_bosh). From cc63bcc997282da99e250dfc0d5dcd46ba2469c7 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 22 Nov 2016 16:01:08 +0100 Subject: [PATCH 122/151] Fix issues on import improvements --- src/mod_offline_riak.erl | 4 ++-- src/mod_privacy.erl | 1 + src/mod_privacy_mnesia.erl | 4 ++-- src/mod_privacy_riak.erl | 4 ++-- src/mod_vcard_ldap.erl | 4 ++-- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/mod_offline_riak.erl b/src/mod_offline_riak.erl index 24d565383..824abc89c 100644 --- a/src/mod_offline_riak.erl +++ b/src/mod_offline_riak.erl @@ -13,7 +13,7 @@ -export([init/2, store_messages/5, pop_messages/2, remove_expired_messages/1, remove_old_messages/2, remove_user/2, read_message_headers/2, read_message/3, remove_message/3, read_all_messages/2, - remove_all_messages/2, count_messages/2, import/2]). + remove_all_messages/2, count_messages/2, import/1]). -include("xmpp.hrl"). -include("mod_offline.hrl"). @@ -133,7 +133,7 @@ count_messages(LUser, LServer) -> 0 end. -import(_LServer, #offline_msg{us = US, timestamp = TS} = M) -> +import(#offline_msg{us = US, timestamp = TS} = M) -> ejabberd_riak:put(M, offline_msg_schema(), [{i, TS}, {'2i', [{<<"us">>, US}]}]). diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index 97a8f1804..f1b8411d2 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -35,6 +35,7 @@ process_iq_set/3, process_iq_get/3, get_user_list/3, check_packet/6, remove_user/2, encode_list_item/1, is_list_needdb/1, updated_list/3, + import_start/2, import_stop/2, item_to_xml/1, get_user_lists/2, import/5, set_privacy_list/1, mod_opt_type/1, depends/2]). diff --git a/src/mod_privacy_mnesia.erl b/src/mod_privacy_mnesia.erl index 4642ba58e..a93e92139 100644 --- a/src/mod_privacy_mnesia.erl +++ b/src/mod_privacy_mnesia.erl @@ -15,7 +15,7 @@ process_default_set/3, process_active_set/3, remove_privacy_list/3, set_privacy_list/1, set_privacy_list/4, get_user_list/2, get_user_lists/2, - remove_user/2, import/2]). + remove_user/2, import/1]). -include("xmpp.hrl"). -include("mod_privacy.hrl"). @@ -144,7 +144,7 @@ remove_user(LUser, LServer) -> F = fun () -> mnesia:delete({privacy, {LUser, LServer}}) end, mnesia:transaction(F). -import(_LServer, #privacy{} = P) -> +import(#privacy{} = P) -> mnesia:dirty_write(P). %%%=================================================================== diff --git a/src/mod_privacy_riak.erl b/src/mod_privacy_riak.erl index 509ff5ebb..b96a08cbc 100644 --- a/src/mod_privacy_riak.erl +++ b/src/mod_privacy_riak.erl @@ -15,7 +15,7 @@ process_default_set/3, process_active_set/3, remove_privacy_list/3, set_privacy_list/1, set_privacy_list/4, get_user_list/2, get_user_lists/2, - remove_user/2, import/2]). + remove_user/2, import/1]). -export([privacy_schema/0]). @@ -145,7 +145,7 @@ get_user_lists(LUser, LServer) -> remove_user(LUser, LServer) -> {atomic, ejabberd_riak:delete(privacy, {LUser, LServer})}. -import(_LServer, #privacy{} = P) -> +import(#privacy{} = P) -> ejabberd_riak:put(P, privacy_schema()). %%%=================================================================== diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl index d8efe30f5..c9e19690f 100644 --- a/src/mod_vcard_ldap.erl +++ b/src/mod_vcard_ldap.erl @@ -14,7 +14,7 @@ %% API -export([start_link/2]). -export([init/2, stop/1, get_vcard/2, set_vcard/4, search/4, - remove_user/2, import/2, search_fields/1, search_reported/1, + remove_user/2, import/3, search_fields/1, search_reported/1, mod_opt_type/1, opt_type/1]). %% gen_server callbacks @@ -157,7 +157,7 @@ search_items(Entries, State) -> remove_user(_User, _Server) -> {atomic, not_implemented}. -import(_, _) -> +import(_, _, _) -> pass. %%%=================================================================== From c0e7b298db4bf045bfda196b029708cef3b9acc3 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 22 Nov 2016 16:12:19 +0100 Subject: [PATCH 123/151] Add missing export --- src/mod_last.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod_last.erl b/src/mod_last.erl index 47db0b6c6..895a8e215 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -35,7 +35,7 @@ -export([start/2, stop/1, process_local_iq/1, export/1, process_sm_iq/1, on_presence_update/4, import_info/0, - import/5, store_last_info/4, get_last_info/2, + import/5, import_start/2, store_last_info/4, get_last_info/2, remove_user/2, transform_options/1, mod_opt_type/1, opt_type/1, register_user/2, depends/2]). From 24ef90c5567c4bf6c60e2963dcdd59ab91a9570f Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 22 Nov 2016 16:23:02 +0100 Subject: [PATCH 124/151] Fix vcard_ldap exports --- src/mod_vcard_ldap.erl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl index c9e19690f..47504c39d 100644 --- a/src/mod_vcard_ldap.erl +++ b/src/mod_vcard_ldap.erl @@ -8,6 +8,8 @@ %%%------------------------------------------------------------------- -module(mod_vcard_ldap). +-behaviour(ejabberd_config). + -behaviour(gen_server). -behaviour(mod_vcard). @@ -16,6 +18,7 @@ -export([init/2, stop/1, get_vcard/2, set_vcard/4, search/4, remove_user/2, import/3, search_fields/1, search_reported/1, mod_opt_type/1, opt_type/1]). +-export([is_search_supported/1]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, @@ -70,6 +73,9 @@ stop(Host) -> supervisor:terminate_child(ejabberd_sup, Proc), supervisor:delete_child(ejabberd_sup, Proc). +is_search_supported(_LServer) -> + true. + get_vcard(LUser, LServer) -> {ok, State} = eldap_utils:get_state(LServer, ?PROCNAME), VCardMap = State#state.vcard_map, From 9ab169bc6366187d17e1137d0c26a67849ff4451 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 22 Nov 2016 16:59:02 +0100 Subject: [PATCH 125/151] Fix get_roster issue injected by fbfbb96 --- src/mod_roster_mnesia.erl | 2 +- src/mod_roster_riak.erl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mod_roster_mnesia.erl b/src/mod_roster_mnesia.erl index 1a33407e1..e274ac5eb 100644 --- a/src/mod_roster_mnesia.erl +++ b/src/mod_roster_mnesia.erl @@ -51,7 +51,7 @@ write_roster_version(LUser, LServer, InTransaction, Ver) -> end. get_roster(LUser, LServer) -> - {ok, mnesia:dirty_index_read(roster, {LUser, LServer}, #roster.us)}. + mnesia:dirty_index_read(roster, {LUser, LServer}, #roster.us). get_roster_by_jid(LUser, LServer, LJID) -> case mnesia:read({roster, {LUser, LServer, LJID}}) of diff --git a/src/mod_roster_riak.erl b/src/mod_roster_riak.erl index 53f0e7fb4..40992d77d 100644 --- a/src/mod_roster_riak.erl +++ b/src/mod_roster_riak.erl @@ -41,8 +41,8 @@ write_roster_version(LUser, LServer, _InTransaction, Ver) -> get_roster(LUser, LServer) -> case ejabberd_riak:get_by_index(roster, roster_schema(), <<"us">>, {LUser, LServer}) of - {ok, Items} -> {ok, Items}; - _Err -> error + {ok, Items} -> Items; + _Err -> [] end. get_roster_by_jid(LUser, LServer, LJID) -> From ee8cc1dac2a9cfcb3e845108c42d414764c0eb64 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 22 Nov 2016 17:51:21 +0100 Subject: [PATCH 126/151] Fix xref issue injected by fbfbb96 --- src/ejabberd_auth_mnesia.erl | 15 +++++++++------ src/mod_roster_sql.erl | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/ejabberd_auth_mnesia.erl b/src/ejabberd_auth_mnesia.erl index 2e9ef5c94..dee3774db 100644 --- a/src/ejabberd_auth_mnesia.erl +++ b/src/ejabberd_auth_mnesia.erl @@ -36,7 +36,7 @@ -export([start/1, set_password/3, check_password/4, check_password/6, try_register/3, dirty_get_registered_users/0, get_vh_registered_users/1, - get_vh_registered_users/2, + get_vh_registered_users/2, init_db/0, get_vh_registered_users_number/1, get_vh_registered_users_number/2, get_password/2, get_password_s/2, is_user_exists/2, remove_user/2, @@ -59,16 +59,19 @@ %%% API %%%---------------------------------------------------------------------- start(Host) -> + init_db(), + update_table(), + update_reg_users_counter_table(Host), + maybe_alert_password_scrammed_without_option(), + ok. + +init_db() -> mnesia:create_table(passwd, [{disc_copies, [node()]}, {attributes, record_info(fields, passwd)}]), mnesia:create_table(reg_users_counter, [{ram_copies, [node()]}, - {attributes, record_info(fields, reg_users_counter)}]), - update_table(), - update_reg_users_counter_table(Host), - maybe_alert_password_scrammed_without_option(), - ok. + {attributes, record_info(fields, reg_users_counter)}]). update_reg_users_counter_table(Server) -> Set = get_vh_registered_users(Server), diff --git a/src/mod_roster_sql.erl b/src/mod_roster_sql.erl index 708a20295..2fc6b112e 100644 --- a/src/mod_roster_sql.erl +++ b/src/mod_roster_sql.erl @@ -18,7 +18,7 @@ roster_subscribe/4, get_roster_by_jid_with_groups/3, remove_user/2, update_roster/4, del_roster/3, transaction/2, read_subscription_and_groups/3, get_only_items/2, - import/3, export/1]). + import/3, export/1, raw_to_record/2]). -include("mod_roster.hrl"). -include("ejabberd_sql_pt.hrl"). From 114ca786ee051b68c6ddc88b012af2226b07601e Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Tue, 22 Nov 2016 19:25:20 +0100 Subject: [PATCH 127/151] Let ejabberd_sm mark copied messages When multiple resources have the same (highest) priority, ejabberd_sm dispatches messages addressed to the bare JID (or to an unavailable resource) to each of these resources. Such messages are now marked with an 'sm_copy' flag for all but one of the resources. This makes it easier for other modules to identify those duplicates. Resolves #1356. --- src/ejabberd_sm.erl | 23 +++++++++++++++++++---- src/mod_carboncopy.erl | 20 ++++++++++---------- src/mod_mam.erl | 39 ++++----------------------------------- 3 files changed, 33 insertions(+), 49 deletions(-) diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 18703dc9c..b3953ec49 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -570,9 +570,9 @@ route_message(From, To, Packet, Type) -> LServer = To#jid.lserver, PrioRes = get_user_present_resources(LUser, LServer), case catch lists:max(PrioRes) of - {Priority, _R} - when is_integer(Priority), Priority >= 0 -> - lists:foreach(fun ({P, R}) when P == Priority; + {MaxPrio, MaxRes} + when is_integer(MaxPrio), MaxPrio >= 0 -> + lists:foreach(fun ({P, R}) when P == MaxPrio; (P >= 0) and (Type == headline) -> LResource = jid:resourceprep(R), Mod = get_sm_backend(LServer), @@ -584,7 +584,12 @@ route_message(From, To, Packet, Type) -> Session = lists:max(Ss), Pid = element(2, Session#session.sid), ?DEBUG("sending to process ~p~n", [Pid]), - Pid ! {route, From, To, Packet} + LMaxRes = jid:resourceprep(MaxRes), + Packet1 = maybe_mark_as_copy(Packet, + LResource, + LMaxRes, + P, MaxPrio), + Pid ! {route, From, To, Packet1} end; %% Ignore other priority: ({_Prio, _Res}) -> ok @@ -603,6 +608,16 @@ route_message(From, To, Packet, Type) -> end end. +-spec maybe_mark_as_copy(message(), binary(), binary(), integer(), integer()) + -> message(). +maybe_mark_as_copy(Packet, R, R, P, P) -> + Packet; +maybe_mark_as_copy(Packet, _, _, P, P) -> + Meta = Packet#message.meta, + Packet#message{meta = Meta#{sm_copy => true}}; +maybe_mark_as_copy(Packet, _, _, _, _) -> + Packet. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -spec clean_session_list([#session{}]) -> [#session{}]. clean_session_list(Ss) -> diff --git a/src/mod_carboncopy.erl b/src/mod_carboncopy.erl index 1c8ca1fdc..f1eb3e790 100644 --- a/src/mod_carboncopy.erl +++ b/src/mod_carboncopy.erl @@ -153,7 +153,7 @@ send_copies(JID, To, Packet, Direction)-> {U, S, R} = jid:tolower(JID), PrioRes = ejabberd_sm:get_user_present_resources(U, S), {_, AvailRs} = lists:unzip(PrioRes), - {MaxPrio, MaxRes} = case catch lists:max(PrioRes) of + {MaxPrio, _MaxRes} = case catch lists:max(PrioRes) of {Prio, Res} -> {Prio, Res}; _ -> {0, undefined} end, @@ -166,19 +166,19 @@ send_copies(JID, To, Packet, Direction)-> end, %% list of JIDs that should receive a carbon copy of this message (excluding the %% receiver(s) of the original message - TargetJIDs = case {IsBareTo, R} of - {true, MaxRes} -> + TargetJIDs = case {IsBareTo, Packet} of + {true, #message{meta = #{sm_copy := true}}} -> + %% The message was sent to our bare JID, and we currently have + %% multiple resources with the same highest priority, so the session + %% manager routes the message to each of them. We create carbon + %% copies only from one of those resources in order to avoid + %% duplicates. + []; + {true, _} -> OrigTo = fun(Res) -> lists:member({MaxPrio, Res}, PrioRes) end, [ {jid:make({U, S, CCRes}), CC_Version} || {CCRes, CC_Version} <- list(U, S), lists:member(CCRes, AvailRs), not OrigTo(CCRes) ]; - {true, _} -> - %% The message was sent to our bare JID, and we currently have - %% multiple resources with the same highest priority, so the session - %% manager routes the message to each of them. We create carbon - %% copies only from one of those resources (the one where R equals - %% MaxRes) in order to avoid duplicates. - []; {false, _} -> [ {jid:make({U, S, CCRes}), CC_Version} || {CCRes, CC_Version} <- list(U, S), diff --git a/src/mod_mam.erl b/src/mod_mam.erl index 61754ae59..0433dee79 100644 --- a/src/mod_mam.erl +++ b/src/mod_mam.erl @@ -200,12 +200,11 @@ set_room_option(Acc, _Property, _Lang) -> Acc. -spec user_receive_packet(stanza(), ejabberd_c2s:state(), jid(), jid(), jid()) -> stanza(). -user_receive_packet(Pkt, C2SState, JID, Peer, To) -> +user_receive_packet(Pkt, C2SState, JID, Peer, _To) -> LUser = JID#jid.luser, LServer = JID#jid.lserver, - IsBareCopy = is_bare_copy(JID, To), case should_archive(Pkt, LServer) of - true when not IsBareCopy -> + true -> NewPkt = strip_my_archived_tag(Pkt, LServer), case store_msg(C2SState, NewPkt, LUser, LServer, Peer, recv) of {ok, ID} -> @@ -454,6 +453,8 @@ process_iq(LServer, #iq{from = #jid{luser = LUser}, lang = Lang, should_archive(#message{type = error}, _LServer) -> false; +should_archive(#message{meta = #{sm_copy := true}}, _LServer) -> + false; should_archive(#message{body = Body, subject = Subject, type = Type} = Pkt, LServer) -> case is_resent(Pkt, LServer) of @@ -812,38 +813,6 @@ maybe_update_from_to(#message{sub_els = Els} = Pkt, JidRequestor, JidArchive, maybe_update_from_to(Pkt, _JidRequestor, _JidArchive, _Peer, chat, _Nick) -> Pkt. -is_bare_copy(#jid{luser = U, lserver = S, lresource = R}, To) -> - PrioRes = ejabberd_sm:get_user_present_resources(U, S), - MaxRes = case catch lists:max(PrioRes) of - {_Prio, Res} when is_binary(Res) -> - Res; - _ -> - undefined - end, - IsBareTo = case To of - #jid{lresource = <<"">>} -> - true; - #jid{lresource = LRes} -> - %% Unavailable resources are handled like bare JIDs. - lists:keyfind(LRes, 2, PrioRes) =:= false - end, - case {IsBareTo, R} of - {true, MaxRes} -> - ?DEBUG("Recipient of message to bare JID has top priority: ~s@~s/~s", - [U, S, R]), - false; - {true, _R} -> - %% The message was sent to our bare JID, and we currently have - %% multiple resources with the same highest priority, so the session - %% manager routes the message to each of them. We store the message - %% only from the resource where R equals MaxRes. - ?DEBUG("Additional recipient of message to bare JID: ~s@~s/~s", - [U, S, R]), - true; - {false, _R} -> - false - end. - -spec send([{binary(), integer(), xmlel()}], non_neg_integer(), boolean(), iq()) -> iq() | ignore. send(Msgs, Count, IsComplete, From 3325e69ae6d625968ce8ec09d9100b5eeca9fb28 Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Tue, 22 Nov 2016 22:21:34 +0100 Subject: [PATCH 128/151] Let mod_carboncopy mark copied messages Carbon copies are now marked with a 'carbon_copy' flag. This makes it easier to identify them. --- src/ejabberd_c2s.erl | 44 ++++++++++++++---------------------------- src/mod_carboncopy.erl | 10 ++++++---- 2 files changed, 21 insertions(+), 33 deletions(-) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 7ef708d31..6d84d8d93 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -2645,44 +2645,30 @@ handle_unacked_stanzas(#state{mgmt_state = MgmtState} = StateData) Txt = <<"User session terminated">>, ejabberd_router:route_error( To, From, El, xmpp:err_service_unavailable(Txt, Lang)); + (From, _To, #message{meta = #{carbon_copy := true}}, _Time) -> + %% XEP-0280 says: "When a receiving server attempts to deliver a + %% forked message, and that message bounces with an error for + %% any reason, the receiving server MUST NOT forward that error + %% back to the original sender." Resending such a stanza could + %% easily lead to unexpected results as well. + ?DEBUG("Dropping forwarded message stanza from ~s", + [jid:to_string(From)]); (From, To, El, Time) -> - %% We'll drop the stanza if it was by some - %% encapsulating protocol as per XEP-0297. One such protocol is - %% XEP-0280, which says: "When a receiving server attempts to - %% deliver a forked message, and that message bounces with an - %% error for any reason, the receiving server MUST NOT forward - %% that error back to the original sender." Resending such a - %% stanza could easily lead to unexpected results as well. - case is_encapsulated_forward(El) of + case ejabberd_hooks:run_fold(message_is_archived, + StateData#state.server, false, + [StateData, From, + StateData#state.jid, El]) of true -> - ?DEBUG("Dropping forwarded message stanza from ~s", - [jid:to_string(From)]); + ?DEBUG("Dropping archived message stanza from ~p", + [jid:to_string(xmpp:get_from(El))]); false -> - case ejabberd_hooks:run_fold(message_is_archived, - StateData#state.server, - false, - [StateData, From, - StateData#state.jid, El]) of - true -> - ?DEBUG("Dropping archived message stanza from ~p", - [jid:to_string(xmpp:get_from(El))]); - false -> - ReRoute(From, To, El, Time) - end + ReRoute(From, To, El, Time) end end, handle_unacked_stanzas(StateData, F); handle_unacked_stanzas(_StateData) -> ok. --spec is_encapsulated_forward(stanza()) -> boolean(). -is_encapsulated_forward(#message{} = Msg) -> - xmpp:has_subtag(Msg, #forwarded{}) orelse - xmpp:has_subtag(Msg, #carbons_sent{}) orelse - xmpp:has_subtag(Msg, #carbons_received{}); -is_encapsulated_forward(_El) -> - false. - -spec inherit_session_state(state(), binary()) -> {ok, state()} | {error, binary()} | {error, binary(), non_neg_integer()}. diff --git a/src/mod_carboncopy.erl b/src/mod_carboncopy.erl index f1eb3e790..5839a65b2 100644 --- a/src/mod_carboncopy.erl +++ b/src/mod_carboncopy.erl @@ -52,9 +52,10 @@ -callback list(binary(), binary()) -> [{binary(), binary()}]. -spec is_carbon_copy(stanza()) -> boolean(). -is_carbon_copy(Packet) -> - xmpp:has_subtag(Packet, #carbons_sent{}) orelse - xmpp:has_subtag(Packet, #carbons_received{}). +is_carbon_copy(#message{meta = #{carbon_copy := true}}) -> + true; +is_carbon_copy(_) -> + false. start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts,fun gen_iq_handler:check_type/1, one_queue), @@ -203,7 +204,8 @@ build_forward_packet(JID, #message{type = T} = Msg, Sender, Dest, Direction) -> sent -> #carbons_sent{forwarded = Forwarded}; received -> #carbons_received{forwarded = Forwarded} end, - #message{from = Sender, to = Dest, type = T, sub_els = [Carbon]}. + #message{from = Sender, to = Dest, type = T, sub_els = [Carbon], + meta = #{carbon_copy => true}}. -spec enable(binary(), binary(), binary(), binary()) -> ok | {error, any()}. enable(Host, U, R, CC)-> From 6f2f1e87c950b7bc7396ae7f556f85b38c1e5fd4 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Wed, 23 Nov 2016 10:41:26 +0300 Subject: [PATCH 129/151] Don't use deprecated functions from jlib.erl --- src/ejabberd_bosh.erl | 2 +- src/mod_last.erl | 2 +- src/mod_offline.erl | 8 ++++---- src/mod_privacy.erl | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ejabberd_bosh.erl b/src/ejabberd_bosh.erl index d4fc6809d..1dc103aee 100644 --- a/src/ejabberd_bosh.erl +++ b/src/ejabberd_bosh.erl @@ -966,7 +966,7 @@ attrs_to_body_attrs(Attrs) -> [], Attrs). to_int(S, Min) -> - case jlib:binary_to_integer(S) of + case binary_to_integer(S) of I when I >= Min -> I; _ -> erlang:error(badarg) end. diff --git a/src/mod_last.erl b/src/mod_last.erl index 895a8e215..463eac051 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -217,7 +217,7 @@ import_start(LServer, DBType) -> import(LServer, {sql, _}, DBType, <<"last">>, [LUser, TimeStamp, State]) -> TS = case TimeStamp of <<"">> -> 0; - _ -> jlib:binary_to_integer(TimeStamp) + _ -> binary_to_integer(TimeStamp) end, LA = #last_activity{us = {LUser, LServer}, timestamp = TS, diff --git a/src/mod_offline.erl b/src/mod_offline.erl index 241677b2a..f620e73c5 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -868,10 +868,10 @@ import(LServer, {sql, _}, DBType, <<"spool">>, fxml:get_attr_s(<<"to">>, El#xmlel.attrs)), Stamp = fxml:get_path_s(El, [{elem, <<"delay">>}, {attr, <<"stamp">>}]), - TS = case jlib:datetime_string_to_timestamp(Stamp) of - {MegaSecs, Secs, _} -> - {MegaSecs, Secs, 0}; - undefined -> + TS = try xmpp_util:decode_timestamp(Stamp) of + {MegaSecs, Secs, _} -> + {MegaSecs, Secs, 0} + catch _:_ -> p1_time_compat:timestamp() end, US = {LUser, LServer}, diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index f1b8411d2..d6936e1b7 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -552,13 +552,13 @@ numeric_to_binary(<<0, _, _:6/binary, T/binary>>) -> fun(X, Sum) -> Sum*10000 + X end, 0, [X || <> <= T]), - jlib:integer_to_binary(Res). + integer_to_binary(Res). bool_to_binary(<<0>>) -> <<"0">>; bool_to_binary(<<1>>) -> <<"1">>. prepare_list_data(mysql, [ID|Row]) -> - [jlib:binary_to_integer(ID)|Row]; + [binary_to_integer(ID)|Row]; prepare_list_data(pgsql, [<>, SType, SValue, SAction, SOrder, SMatchAll, SMatchIQ, SMatchMessage, SMatchPresenceIn, @@ -572,7 +572,7 @@ prepare_list_data(pgsql, [<>, bool_to_binary(SMatchPresenceOut)]. prepare_id(mysql, ID) -> - jlib:binary_to_integer(ID); + binary_to_integer(ID); prepare_id(pgsql, <>) -> ID. From 5d434c1aeac42323a9913c7261bf3f7ac6b6b1a8 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Wed, 23 Nov 2016 15:51:48 +0300 Subject: [PATCH 130/151] Move copyright definition to ejabberd.hrl --- include/ejabberd.hrl | 2 ++ src/mod_irc.erl | 3 +-- src/mod_muc.erl | 3 +-- src/mod_multicast.erl | 3 +-- src/mod_proxy65_service.erl | 3 +-- src/mod_pubsub.erl | 3 +-- src/mod_vcard.erl | 6 ++---- test/proxy65_tests.erl | 10 +++++++++- test/pubsub_tests.erl | 8 ++++++++ test/vcard_tests.erl | 12 ++++++++++-- 10 files changed, 36 insertions(+), 17 deletions(-) diff --git a/include/ejabberd.hrl b/include/ejabberd.hrl index 7a6df5644..391089a0e 100644 --- a/include/ejabberd.hrl +++ b/include/ejabberd.hrl @@ -39,6 +39,8 @@ -define(EJABBERD_URI, <<"http://www.process-one.net/en/ejabberd/">>). +-define(COPYRIGHT, "Copyright (c) 2002-2016 ProcessOne"). + -define(S2STIMEOUT, timer:minutes(10)). %%-define(DBGFSM, true). diff --git a/src/mod_irc.erl b/src/mod_irc.erl index 2fb35414d..3dd0e492d 100644 --- a/src/mod_irc.erl +++ b/src/mod_irc.erl @@ -420,10 +420,9 @@ iq_disco(ServerHost, Node, Lang) -> iq_get_vcard(Lang) -> Desc = translate:translate(Lang, <<"ejabberd IRC module">>), - Copyright = <<"Copyright (c) 2003-2016 ProcessOne">>, #vcard_temp{fn = <<"ejabberd/mod_irc">>, url = ?EJABBERD_URI, - desc = <>}. + desc = <>}. command_items(ServerHost, Host, Lang) -> lists:map(fun({Node, Name, _Function}) -> diff --git a/src/mod_muc.erl b/src/mod_muc.erl index 28008aaae..554a21704 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -429,11 +429,10 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper, -spec process_vcard(iq()) -> iq(). process_vcard(#iq{type = get, lang = Lang, sub_els = [#vcard_temp{}]} = IQ) -> Desc = translate:translate(Lang, <<"ejabberd MUC module">>), - Copyright = <<"Copyright (c) 2003-2016 ProcessOne">>, xmpp:make_iq_result( IQ, #vcard_temp{fn = <<"ejabberd/mod_muc">>, url = ?EJABBERD_URI, - desc = <>}); + desc = <>}); process_vcard(#iq{type = set, lang = Lang} = IQ) -> Txt = <<"Value 'set' of 'type' attribute is not allowed">>, xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); diff --git a/src/mod_multicast.erl b/src/mod_multicast.erl index 72046491f..0aa2270ae 100644 --- a/src/mod_multicast.erl +++ b/src/mod_multicast.erl @@ -268,10 +268,9 @@ iq_disco_info(From, Lang, State) -> iq_vcard(Lang) -> Desc = translate:translate(Lang, <<"ejabberd Multicast service">>), - Copyright = <<"Copyright (c) 2002-2016 ProcessOne">>, #vcard_temp{fn = <<"ejabberd/mod_multicast">>, url = ?EJABBERD_URI, - desc = <>}. + desc = <>}. %%%------------------------- %%% Route diff --git a/src/mod_proxy65_service.erl b/src/mod_proxy65_service.erl index 789771d7d..0f69086e0 100644 --- a/src/mod_proxy65_service.erl +++ b/src/mod_proxy65_service.erl @@ -136,11 +136,10 @@ process_vcard(#iq{type = set, lang = Lang} = IQ) -> xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); process_vcard(#iq{type = get, lang = Lang} = IQ) -> Desc = translate:translate(Lang, <<"ejabberd SOCKS5 Bytestreams module">>), - Copyright = <<"Copyright (c) 2003-2016 ProcessOne">>, xmpp:make_iq_result( IQ, #vcard_temp{fn = <<"ejabberd/mod_proxy65">>, url = ?EJABBERD_URI, - desc = <>}). + desc = <>}). -spec process_bytestreams(iq()) -> iq(). process_bytestreams(#iq{type = get, from = JID, to = To, lang = Lang} = IQ) -> diff --git a/src/mod_pubsub.erl b/src/mod_pubsub.erl index a138b1896..c379760ed 100644 --- a/src/mod_pubsub.erl +++ b/src/mod_pubsub.erl @@ -1186,10 +1186,9 @@ iq_sm(#iq{to = To, sub_els = [SubEl]} = IQ) -> -spec iq_get_vcard(binary()) -> vcard_temp(). iq_get_vcard(Lang) -> Desc = translate:translate(Lang, <<"ejabberd Publish-Subscribe module">>), - Copyright = <<"Copyright (c) 2004-2016 ProcessOne">>, #vcard_temp{fn = <<"ejabberd/mod_pubsub">>, url = ?EJABBERD_URI, - desc = <>}. + desc = <>}. -spec iq_pubsub(binary() | ljid(), atom(), iq()) -> {result, pubsub()} | {error, stanza_error()}. diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index dc9476206..843281ef8 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -191,11 +191,10 @@ process_local_iq(#iq{type = set, lang = Lang} = IQ) -> xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); process_local_iq(#iq{type = get, lang = Lang} = IQ) -> Desc = translate:translate(Lang, <<"Erlang Jabber Server">>), - Copyright = <<"Copyright (c) 2002-2016 ProcessOne">>, xmpp:make_iq_result( IQ, #vcard_temp{fn = <<"ejabberd">>, url = ?EJABBERD_URI, - desc = <>, + desc = <>, bday = <<"2002-11-16">>}). -spec process_sm_iq(iq()) -> iq(). @@ -228,11 +227,10 @@ process_vcard(#iq{type = set, lang = Lang} = IQ) -> xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); process_vcard(#iq{type = get, lang = Lang} = IQ) -> Desc = translate:translate(Lang, <<"ejabberd vCard module">>), - Copyright = <<"Copyright (c) 2003-2016 ProcessOne">>, xmpp:make_iq_result( IQ, #vcard_temp{fn = <<"ejabberd/mod_vcard">>, url = ?EJABBERD_URI, - desc = <>}). + desc = <>}). -spec process_search(iq()) -> iq(). process_search(#iq{type = get, to = To, lang = Lang} = IQ) -> diff --git a/test/proxy65_tests.erl b/test/proxy65_tests.erl index 01292f508..49e195d38 100644 --- a/test/proxy65_tests.erl +++ b/test/proxy65_tests.erl @@ -24,12 +24,20 @@ %%%=================================================================== single_cases() -> {proxy65_single, [sequence], - [single_test(feature_enabled)]}. + [single_test(feature_enabled), + single_test(service_vcard)]}. feature_enabled(Config) -> true = is_feature_advertised(Config, ?NS_BYTESTREAMS, proxy_jid(Config)), disconnect(Config). +service_vcard(Config) -> + JID = proxy_jid(Config), + ct:comment("Retreiving vCard from ~s", [jid:to_string(JID)]), + #iq{type = result, sub_els = [#vcard_temp{}]} = + send_recv(Config, #iq{type = get, to = JID, sub_els = [#vcard_temp{}]}), + disconnect(Config). + %%%=================================================================== %%% Master-slave tests %%%=================================================================== diff --git a/test/pubsub_tests.erl b/test/pubsub_tests.erl index fae7234e4..daffc29ec 100644 --- a/test/pubsub_tests.erl +++ b/test/pubsub_tests.erl @@ -25,6 +25,7 @@ single_cases() -> {pubsub_single, [sequence], [single_test(test_features), + single_test(test_vcard), single_test(test_create), single_test(test_configure), single_test(test_delete), @@ -67,6 +68,13 @@ test_features(Config) -> true = sets:is_subset(NeededFeatures, AllFeatures), disconnect(Config). +test_vcard(Config) -> + JID = pubsub_jid(Config), + ct:comment("Retreiving vCard from ~s", [jid:to_string(JID)]), + #iq{type = result, sub_els = [#vcard_temp{}]} = + send_recv(Config, #iq{type = get, to = JID, sub_els = [#vcard_temp{}]}), + disconnect(Config). + test_create(Config) -> Node = ?config(pubsub_node, Config), Node = create_node(Config, Node), diff --git a/test/vcard_tests.erl b/test/vcard_tests.erl index bb3efb475..26cfdc92b 100644 --- a/test/vcard_tests.erl +++ b/test/vcard_tests.erl @@ -11,7 +11,7 @@ %% API -compile(export_all). -import(suite, [send_recv/2, disconnect/1, is_feature_advertised/2, - is_feature_advertised/3, + is_feature_advertised/3, server_jid/1, my_jid/1, wait_for_slave/1, wait_for_master/1, recv_presence/1, recv/1]). @@ -26,7 +26,8 @@ single_cases() -> {vcard_single, [sequence], [single_test(feature_enabled), - single_test(get_set)]}. + single_test(get_set), + single_test(service_vcard)]}. feature_enabled(Config) -> BareMyJID = jid:remove_resource(my_jid(Config)), @@ -72,6 +73,13 @@ get_set(Config) -> send_recv(Config, #iq{type = get, sub_els = [#vcard_temp{}]}), disconnect(Config). +service_vcard(Config) -> + JID = server_jid(Config), + ct:comment("Retreiving vCard from ~s", [jid:to_string(JID)]), + #iq{type = result, sub_els = [#vcard_temp{}]} = + send_recv(Config, #iq{type = get, to = JID, sub_els = [#vcard_temp{}]}), + disconnect(Config). + %%%=================================================================== %%% Master-slave tests %%%=================================================================== From 12683b4aaff813b3fbc0e34029f412afdd19699f Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Wed, 23 Nov 2016 14:35:13 +0100 Subject: [PATCH 131/151] Fix typo in copyright date --- src/ejabberd_commands_doc.erl | 2 +- src/mod_admin_extra.erl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ejabberd_commands_doc.erl b/src/ejabberd_commands_doc.erl index 477e4f5d5..bb519a600 100644 --- a/src/ejabberd_commands_doc.erl +++ b/src/ejabberd_commands_doc.erl @@ -5,7 +5,7 @@ %%% Created : 20 May 2008 by Badlop %%% %%% -%%% ejabberd, Copyright (C) 2002-2015 ProcessOne +%%% ejabberd, Copyright (C) 2002-2016 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_admin_extra.erl b/src/mod_admin_extra.erl index 053ce8092..3c51e8c69 100644 --- a/src/mod_admin_extra.erl +++ b/src/mod_admin_extra.erl @@ -5,7 +5,7 @@ %%% Created : 10 Aug 2008 by Badlop %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2016 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as From b6ddcf3e5815451047b3e505ae07f2fc69cb1e31 Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Thu, 24 Nov 2016 07:55:06 +0100 Subject: [PATCH 132/151] Makefile.in: Substitute all @variables@ in a line There are now lines with multiple occurrences of the @ctlscriptpath@ variable in the ejabberd.service template. --- Makefile.in | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Makefile.in b/Makefile.in index 00fd4f62c..1cb1074a6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -173,15 +173,15 @@ install: all copy-files [ -f $(ETCDIR)/ejabberd.yml ] \ && $(INSTALL) -b -m 640 $(G_USER) ejabberd.yml.example $(ETCDIR)/ejabberd.yml-new \ || $(INSTALL) -b -m 640 $(G_USER) ejabberd.yml.example $(ETCDIR)/ejabberd.yml - $(SED) -e "s*{{rootdir}}*@prefix@*" \ - -e "s*{{installuser}}*@INSTALLUSER@*" \ - -e "s*{{bindir}}*@bindir@*" \ - -e "s*{{libdir}}*@libdir@*" \ - -e "s*{{sysconfdir}}*@sysconfdir@*" \ - -e "s*{{localstatedir}}*@localstatedir@*" \ - -e "s*{{docdir}}*@docdir@*" \ - -e "s*{{erl}}*@ERL@*" \ - -e "s*{{epmd}}*@EPMD@*" ejabberdctl.template \ + $(SED) -e "s*{{rootdir}}*@prefix@*g" \ + -e "s*{{installuser}}*@INSTALLUSER@*g" \ + -e "s*{{bindir}}*@bindir@*g" \ + -e "s*{{libdir}}*@libdir@*g" \ + -e "s*{{sysconfdir}}*@sysconfdir@*g" \ + -e "s*{{localstatedir}}*@localstatedir@*g" \ + -e "s*{{docdir}}*@docdir@*g" \ + -e "s*{{erl}}*@ERL@*g" \ + -e "s*{{epmd}}*@EPMD@*g" ejabberdctl.template \ > ejabberdctl.example [ -f $(ETCDIR)/ejabberdctl.cfg ] \ && $(INSTALL) -b -m 640 $(G_USER) ejabberdctl.cfg.example $(ETCDIR)/ejabberdctl.cfg-new \ @@ -198,13 +198,13 @@ install: all copy-files [ -f deps/elixir/bin/mix ] && $(INSTALL) -m 550 $(G_USER) deps/elixir/bin/mix $(BINDIR)/mix || true # # Init script - $(SED) -e "s*@ctlscriptpath@*$(SBINDIR)*" \ - -e "s*@installuser@*$(INIT_USER)*" ejabberd.init.template \ + $(SED) -e "s*@ctlscriptpath@*$(SBINDIR)*g" \ + -e "s*@installuser@*$(INIT_USER)*g" ejabberd.init.template \ > ejabberd.init chmod 755 ejabberd.init # # Service script - $(SED) -e "s*@ctlscriptpath@*$(SBINDIR)*" ejabberd.service.template \ + $(SED) -e "s*@ctlscriptpath@*$(SBINDIR)*g" ejabberd.service.template \ > ejabberd.service chmod 755 ejabberd.service # From 9c3ebb7d22b980985f0c7853485c78ca6ebc831b Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Thu, 24 Nov 2016 07:59:27 +0100 Subject: [PATCH 133/151] Don't make ejabberd.service file executable --- Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index 1cb1074a6..5ff3efe0b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -206,7 +206,7 @@ install: all copy-files # Service script $(SED) -e "s*@ctlscriptpath@*$(SBINDIR)*g" ejabberd.service.template \ > ejabberd.service - chmod 755 ejabberd.service + chmod 644 ejabberd.service # # Spool directory $(INSTALL) -d -m 750 $(O_USER) $(SPOOLDIR) From d12210f4e158bdb261e76e75956ec3b38b7aac48 Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Thu, 24 Nov 2016 10:45:57 +0100 Subject: [PATCH 134/151] Use new versions of fast_xml and xmpp --- rebar.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rebar.config b/rebar.config index 6db14c87b..929c15304 100644 --- a/rebar.config +++ b/rebar.config @@ -12,8 +12,8 @@ {cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.4"}}}, {fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.7"}}}, {stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.6"}}}, - {fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.16"}}}, - {xmpp, ".*", {git, "https://github.com/processone/xmpp", {tag, "1.0.3"}}}, + {fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.17"}}}, + {xmpp, ".*", {git, "https://github.com/processone/xmpp", {tag, "1.0.4"}}}, {stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.7"}}}, {esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.8"}}}, {fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.6"}}}, From 560038c808cafe08e0cc5c6abb431e1e82f02f88 Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Thu, 24 Nov 2016 10:47:26 +0100 Subject: [PATCH 135/151] Use xmpp:put_meta/3 to update metadata --- src/ejabberd_sm.erl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index b3953ec49..d40db28cc 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -613,8 +613,7 @@ route_message(From, To, Packet, Type) -> maybe_mark_as_copy(Packet, R, R, P, P) -> Packet; maybe_mark_as_copy(Packet, _, _, P, P) -> - Meta = Packet#message.meta, - Packet#message{meta = Meta#{sm_copy => true}}; + xmpp:put_meta(Packet, sm_copy, true); maybe_mark_as_copy(Packet, _, _, _, _) -> Packet. From b14843d098dcfd8f9a7859132356caa396fd907c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Thu, 24 Nov 2016 12:44:09 +0100 Subject: [PATCH 136/151] Add missing -callbacks --- rebar.config | 2 +- src/mod_muc_room.erl | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/rebar.config b/rebar.config index 929c15304..11249e822 100644 --- a/rebar.config +++ b/rebar.config @@ -64,7 +64,7 @@ ezlib, iconv]}}. -{erl_first_files, ["src/ejabberd_config.erl", "src/gen_mod.erl"]}. +{erl_first_files, ["src/ejabberd_config.erl", "src/gen_mod.erl", "src/mod_muc_room.erl"]}. {erl_opts, [nowarn_deprecated_function, {i, "include"}, diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl index 5b000548a..aa1c77aad 100644 --- a/src/mod_muc_room.erl +++ b/src/mod_muc_room.erl @@ -79,6 +79,16 @@ -export_type([state/0]). +-callback set_affiliation(binary(), binary(), binary(), jid(), affiliation(), + binary()) -> ok | {error, any()}. +-callback set_affiliations(binary(), binary(), binary(), + ?TDICT) -> ok | {error, any()}. +-callback get_affiliation(binary(), binary(), binary(), + binary(), binary()) -> {ok, affiliation()} | {error, any()}. +-callback get_affiliations(binary(), binary(), binary()) -> {ok, ?TDICT} | {error, any()}. +-callback search_affiliation(binary(), binary(), binary(), affiliation()) -> + {ok, [{ljid(), {affiliation(), binary()}}]} | {error, any()}. + %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- From 49f1275e2005c8bce2fdcad8499f4fad94a9d768 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Thu, 24 Nov 2016 15:06:06 +0300 Subject: [PATCH 137/151] Get rid of excessive (io)list_to_binary/1 calls --- src/acl.erl | 2 +- src/ejabberd_access_permissions.erl | 4 +- src/ejabberd_admin.erl | 7 +-- src/ejabberd_bosh.erl | 2 +- src/ejabberd_captcha.erl | 2 +- src/ejabberd_http.erl | 6 +- src/ejabberd_http_bind.erl | 18 +++--- src/ejabberd_piefxis.erl | 9 ++- src/ejabberd_riak.erl | 6 +- src/ejabberd_system_monitor.erl | 7 +-- src/ejabberd_web_admin.erl | 64 ++++++++++----------- src/jlib.erl | 8 +-- src/mod_configure.erl | 50 +++++++---------- src/mod_irc.erl | 87 +++++++++++++---------------- src/mod_irc_connection.erl | 2 +- src/mod_muc_log.erl | 10 ++-- src/mod_offline.erl | 4 +- src/mod_pubsub.erl | 2 +- src/mod_register.erl | 2 +- src/mod_sip_proxy.erl | 4 +- src/mod_sip_registrar.erl | 2 +- src/mod_stats.erl | 26 ++++----- src/mod_version.erl | 2 +- src/pubsub_db_sql.erl | 2 +- src/pubsub_subscription.erl | 14 ++--- src/pubsub_subscription_sql.erl | 14 ++--- 26 files changed, 163 insertions(+), 193 deletions(-) diff --git a/src/acl.erl b/src/acl.erl index e3fdfcae1..595228ee9 100644 --- a/src/acl.erl +++ b/src/acl.erl @@ -342,7 +342,7 @@ acl_rule_verify({node_glob, {UR, SR}}) when is_binary(UR), is_binary(SR) -> acl_rule_verify(_Spec) -> false. invalid_syntax(Msg, Data) -> - throw({invalid_syntax, iolist_to_binary(io_lib:format(Msg, Data))}). + throw({invalid_syntax, (str:format(Msg, Data))}). acl_rules_verify([{acl, Name} | Rest], true) when is_atom(Name) -> acl_rules_verify(Rest, true); diff --git a/src/ejabberd_access_permissions.erl b/src/ejabberd_access_permissions.erl index 7ce75aa9c..60ad68a29 100644 --- a/src/ejabberd_access_permissions.erl +++ b/src/ejabberd_access_permissions.erl @@ -532,10 +532,10 @@ key_split([{Arg, Value} | Rest], Results, Order, Required, Duplicates) -> end. report_error(Format, Args) -> - throw({invalid_syntax, iolist_to_binary(io_lib:format(Format, Args))}). + throw({invalid_syntax, (str:format(Format, Args))}). parse_error(Format, Args) -> - {error, iolist_to_binary(io_lib:format(Format, Args))}. + {error, (str:format(Format, Args))}. opt_type(api_permissions) -> fun parse_api_permissions/1; diff --git a/src/ejabberd_admin.erl b/src/ejabberd_admin.erl index 8622ea8d0..99aa51794 100644 --- a/src/ejabberd_admin.erl +++ b/src/ejabberd_admin.erl @@ -302,8 +302,8 @@ set_loglevel(LogLevel) -> %%% stop_kindly(DelaySeconds, AnnouncementTextString) -> - Subject = list_to_binary(io_lib:format("Server stop in ~p seconds!", [DelaySeconds])), - WaitingDesc = list_to_binary(io_lib:format("Waiting ~p seconds", [DelaySeconds])), + Subject = (str:format("Server stop in ~p seconds!", [DelaySeconds])), + WaitingDesc = (str:format("Waiting ~p seconds", [DelaySeconds])), AnnouncementText = list_to_binary(AnnouncementTextString), Steps = [ {"Stopping ejabberd port listeners", @@ -337,8 +337,7 @@ stop_kindly(DelaySeconds, AnnouncementTextString) -> ok. send_service_message_all_mucs(Subject, AnnouncementText) -> - Message = list_to_binary( - io_lib:format("~s~n~s", [Subject, AnnouncementText])), + Message = str:format("~s~n~s", [Subject, AnnouncementText]), lists:foreach( fun(ServerHost) -> MUCHost = gen_mod:get_module_opt_host( diff --git a/src/ejabberd_bosh.erl b/src/ejabberd_bosh.erl index 1dc103aee..b94184167 100644 --- a/src/ejabberd_bosh.erl +++ b/src/ejabberd_bosh.erl @@ -807,7 +807,7 @@ encode_body(#body{attrs = Attrs, els = Els}, Type) -> true -> {AmK, <<"true">>}; false -> {AmK, <<"false">>}; I when is_integer(I), I >= 0 -> - {AmK, iolist_to_binary(integer_to_list(I))}; + {AmK, integer_to_binary(I)}; _ -> {AmK, V} end; ({K, V}) -> {K, V} diff --git a/src/ejabberd_captcha.erl b/src/ejabberd_captcha.erl index a122eda8e..f959d7f30 100644 --- a/src/ejabberd_captcha.erl +++ b/src/ejabberd_captcha.erl @@ -103,7 +103,7 @@ create_captcha(SID, From, To, Lang, Limiter, Args) -> BodyString1 = translate:translate(Lang, <<"Your messages to ~s are being blocked. " "To unblock them, visit ~s">>), - BodyString = iolist_to_binary(io_lib:format(BodyString1, + BodyString = (str:format(BodyString1, [JID, get_url(Id)])), Body = xmpp:mk_text(BodyString, Lang), OOB = #oob_x{url = get_url(Id)}, diff --git a/src/ejabberd_http.erl b/src/ejabberd_http.erl index c6c31a971..c0c7bbbd6 100644 --- a/src/ejabberd_http.erl +++ b/src/ejabberd_http.erl @@ -550,12 +550,12 @@ make_xhtml_output(State, Status, Headers, XHTML) -> of {value, _} -> [{<<"Content-Length">>, - iolist_to_binary(integer_to_list(byte_size(Data)))} + integer_to_binary(byte_size(Data))} | Headers]; _ -> [{<<"Content-Type">>, <<"text/html; charset=utf-8">>}, {<<"Content-Length">>, - iolist_to_binary(integer_to_list(byte_size(Data)))} + integer_to_binary(byte_size(Data))} | Headers] end, HeadersOut = case {State#state.request_version, @@ -577,7 +577,7 @@ make_xhtml_output(State, Status, Headers, XHTML) -> end, HeadersOut), SL = [Version, - iolist_to_binary(integer_to_list(Status)), <<" ">>, + integer_to_binary(Status), <<" ">>, code_to_phrase(Status), <<"\r\n">>], Data2 = case State#state.request_method of 'HEAD' -> <<"">>; diff --git a/src/ejabberd_http_bind.erl b/src/ejabberd_http_bind.erl index db529e69e..ea64b3cdf 100644 --- a/src/ejabberd_http_bind.erl +++ b/src/ejabberd_http_bind.erl @@ -972,21 +972,17 @@ prepare_outpacket_response(#http_bind{id = Sid, [{<<"xmlns">>, ?NS_HTTP_BIND}, {<<"sid">>, Sid}, {<<"wait">>, - iolist_to_binary(integer_to_list(Wait))}, + integer_to_binary(Wait)}, {<<"requests">>, - iolist_to_binary(integer_to_list(Hold - + - 1))}, + integer_to_binary(Hold + 1)}, {<<"inactivity">>, - iolist_to_binary(integer_to_list(trunc(MaxInactivity - / - 1000)))}, + integer_to_binary( + trunc(MaxInactivity / 1000))}, {<<"maxpause">>, - iolist_to_binary(integer_to_list(MaxPause))}, + integer_to_binary(MaxPause)}, {<<"polling">>, - iolist_to_binary(integer_to_list(trunc((?MIN_POLLING) - / - 1000000)))}, + integer_to_binary( + trunc((?MIN_POLLING) / 1000000))}, {<<"ver">>, ?BOSH_VERSION}, {<<"from">>, From}, {<<"secure">>, <<"true">>}] diff --git a/src/ejabberd_piefxis.erl b/src/ejabberd_piefxis.erl index 0e79c9913..b6f90ccf8 100644 --- a/src/ejabberd_piefxis.erl +++ b/src/ejabberd_piefxis.erl @@ -196,7 +196,7 @@ format_scram_password({StoredKey, ServerKey, Salt, IterationCount}) -> StoredKeyB64 = base64:encode(StoredKey), ServerKeyB64 = base64:encode(ServerKey), SaltB64 = base64:encode(Salt), - IterationCountBin = list_to_binary(integer_to_list(IterationCount)), + IterationCountBin = (integer_to_binary(IterationCount)), <<"scram:", StoredKeyB64/binary, ",", ServerKeyB64/binary, ",", SaltB64/binary, ",", IterationCountBin/binary>>. parse_scram_password(PassData) -> @@ -206,7 +206,7 @@ parse_scram_password(PassData) -> storedkey = StoredKeyB64, serverkey = ServerKeyB64, salt = SaltB64, - iterationcount = list_to_integer(binary_to_list(IterationCountBin)) + iterationcount = (binary_to_integer(IterationCountBin)) }. -spec get_vcard(binary(), binary()) -> [xmlel()]. @@ -554,9 +554,8 @@ stop(Fmt, Args) -> make_filename_template() -> {{Year, Month, Day}, {Hour, Minute, Second}} = calendar:local_time(), - list_to_binary( - io_lib:format("~4..0w~2..0w~2..0w-~2..0w~2..0w~2..0w", - [Year, Month, Day, Hour, Minute, Second])). + str:format("~4..0w~2..0w~2..0w-~2..0w~2..0w~2..0w", + [Year, Month, Day, Hour, Minute, Second]). make_main_basefilename(Dir, FnT) -> Filename2 = <>, diff --git a/src/ejabberd_riak.erl b/src/ejabberd_riak.erl index 575810acc..44628d1c2 100644 --- a/src/ejabberd_riak.erl +++ b/src/ejabberd_riak.erl @@ -428,7 +428,7 @@ map_key(Obj, _, _) -> <<"b_", B/binary>> -> B; <<"i_", B/binary>> -> - list_to_integer(binary_to_list(B)); + (binary_to_integer(B)); B -> erlang:binary_to_term(B) end]. @@ -483,7 +483,7 @@ encode_index_key(Idx, Key) -> encode_key(Bin) when is_binary(Bin) -> <<"b_", Bin/binary>>; encode_key(Int) when is_integer(Int) -> - <<"i_", (list_to_binary(integer_to_list(Int)))/binary>>; + <<"i_", ((integer_to_binary(Int)))/binary>>; encode_key(Term) -> erlang:term_to_binary(Term). @@ -519,7 +519,7 @@ log_error(_, _, _) -> ok. make_invalid_object(Val) -> - list_to_binary(io_lib:fwrite("Invalid object: ~p", [Val])). + (str:format("Invalid object: ~p", [Val])). get_random_pid() -> PoolPid = ejabberd_riak_sup:get_random_pid(), diff --git a/src/ejabberd_system_monitor.erl b/src/ejabberd_system_monitor.erl index df6af1c95..5d52a041d 100644 --- a/src/ejabberd_system_monitor.erl +++ b/src/ejabberd_system_monitor.erl @@ -180,10 +180,9 @@ process_large_heap(Pid, Info) -> Host = (?MYNAME), JIDs = get_admin_jids(), DetailedInfo = detailed_info(Pid), - Body = iolist_to_binary( - io_lib:format("(~w) The process ~w is consuming too " - "much memory:~n~p~n~s", - [node(), Pid, Info, DetailedInfo])), + Body = str:format("(~w) The process ~w is consuming too " + "much memory:~n~p~n~s", + [node(), Pid, Info, DetailedInfo]), From = jid:make(<<"">>, Host, <<"watchdog">>), Hint = [#hint{type = 'no-permanent-store'}], lists:foreach( diff --git a/src/ejabberd_web_admin.erl b/src/ejabberd_web_admin.erl index bf17c8ab1..3836beda7 100644 --- a/src/ejabberd_web_admin.erl +++ b/src/ejabberd_web_admin.erl @@ -763,8 +763,8 @@ process_admin(Host, [?XAE(<<"form">>, [{<<"action">>, <<"">>}, {<<"method">>, <<"post">>}]++direction(ltr), [?TEXTAREA(<<"acls">>, - (iolist_to_binary(integer_to_list(lists:max([16, - NumLines])))), + (integer_to_binary(lists:max([16, + NumLines]))), <<"80">>, <<(iolist_to_binary(ACLsP))/binary, ".">>), ?BR, ?INPUTT(<<"submit">>, <<"submit">>, <<"Submit">>)])], @@ -865,8 +865,8 @@ process_admin(Host, [?XAE(<<"form">>, [{<<"action">>, <<"">>}, {<<"method">>, <<"post">>}]++direction(ltr), [?TEXTAREA(<<"access">>, - (iolist_to_binary(integer_to_list(lists:max([16, - NumLines])))), + (integer_to_binary(lists:max([16, + NumLines]))), <<"80">>, <<(iolist_to_binary(AccessP))/binary, ".">>), ?BR, ?INPUTT(<<"submit">>, <<"submit">>, <<"Submit">>)])], @@ -926,7 +926,7 @@ process_admin(Host, Rs1 -> Rs1 end, make_xhtml([?XC(<<"h1">>, - list_to_binary(io_lib:format( + (str:format( ?T(<<"~s access rule configuration">>), [SName])))] ++ @@ -1141,7 +1141,7 @@ acl_spec_select(ID, Opt) -> %% @spec (T::any()) -> StringLine::string() term_to_string(T) -> StringParagraph = - iolist_to_binary(io_lib:format("~1000000p", [T])), + (str:format("~1000000p", [T])), ejabberd_regexp:greplace(StringParagraph, <<"\\n ">>, <<"">>). @@ -1506,7 +1506,7 @@ list_given_users(Host, Users, Prefix, Lang, URLFunc) -> {{Year, Month, Day}, {Hour, Minute, Second}} = calendar:now_to_local_time(TimeStamp), - iolist_to_binary(io_lib:format("~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w", + (str:format("~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w", [Year, Month, Day, @@ -1683,14 +1683,14 @@ user_info(User, Server, Query, Lang) -> Shift rem 1000000, 0}, {{Year, Month, Day}, {Hour, Minute, Second}} = calendar:now_to_local_time(TimeStamp), - iolist_to_binary(io_lib:format("~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w", + (str:format("~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w", [Year, Month, Day, Hour, Minute, Second])) end; _ -> ?T(<<"Online">>) end, - [?XC(<<"h1">>, list_to_binary(io_lib:format(?T(<<"User ~s">>), + [?XC(<<"h1">>, (str:format(?T(<<"User ~s">>), [us_to_list(US)])))] ++ case Res of @@ -1773,9 +1773,7 @@ list_last_activity(Host, Lang, Integral, Period) -> [?XAE(<<"li">>, [{<<"style">>, <<"width:", - (iolist_to_binary(integer_to_list(trunc(90 * V - / - Max))))/binary, + (integer_to_binary(trunc(90 * V / Max)))/binary, "%;">>}], [{xmlcdata, pretty_string_int(V)}]) || V <- Hist ++ Tail])] @@ -1850,7 +1848,7 @@ get_node(global, Node, [], Query, Lang) -> Base = get_base_path(global, Node), MenuItems2 = make_menu_items(global, Node, Base, Lang), [?XC(<<"h1">>, - list_to_binary(io_lib:format(?T(<<"Node ~p">>), [Node])))] + (str:format(?T(<<"Node ~p">>), [Node])))] ++ case Res of ok -> [?XREST(<<"Submitted">>)]; @@ -1875,7 +1873,7 @@ get_node(global, Node, [], Query, Lang) -> get_node(Host, Node, [], _Query, Lang) -> Base = get_base_path(Host, Node), MenuItems2 = make_menu_items(Host, Node, Base, Lang), - [?XC(<<"h1">>, list_to_binary(io_lib:format(?T(<<"Node ~p">>), [Node]))), + [?XC(<<"h1">>, (str:format(?T(<<"Node ~p">>), [Node]))), ?XE(<<"ul">>, ([?LI([?ACT(<>, <<"Modules">>)])] @@ -1934,7 +1932,7 @@ get_node(global, Node, [<<"db">>], Query, Lang) -> end, STables), [?XC(<<"h1">>, - list_to_binary(io_lib:format(?T(<<"Database Tables at ~p">>), + (str:format(?T(<<"Database Tables at ~p">>), [Node])) )] ++ @@ -1970,9 +1968,9 @@ get_node(global, Node, [<<"backup">>], Query, Lang) -> ok -> [?XREST(<<"Submitted">>)]; {error, Error} -> [?XRES(<<(?T(<<"Error">>))/binary, ": ", - (list_to_binary(io_lib:format("~p", [Error])))/binary>>)] + ((str:format("~p", [Error])))/binary>>)] end, - [?XC(<<"h1">>, list_to_binary(io_lib:format(?T(<<"Backup of ~p">>), [Node])))] + [?XC(<<"h1">>, (str:format(?T(<<"Backup of ~p">>), [Node])))] ++ ResS ++ [?XCT(<<"p">>, @@ -2124,7 +2122,7 @@ get_node(global, Node, [<<"ports">>], Query, Lang) -> {'EXIT', _Reason} -> error; {is_added, ok} -> ok; {is_added, {error, Reason}} -> - {error, iolist_to_binary(io_lib:format("~p", [Reason]))}; + {error, (str:format("~p", [Reason]))}; _ -> nothing end, NewPorts = lists:sort(ejabberd_cluster:call(Node, ejabberd_config, @@ -2161,7 +2159,7 @@ get_node(Host, Node, [<<"modules">>], Query, Lang) end, NewModules = lists:sort(ejabberd_cluster:call(Node, gen_mod, loaded_modules_with_opts, [Host])), - H1String = list_to_binary(io_lib:format(?T(<<"Modules at ~p">>), [Node])), + H1String = (str:format(?T(<<"Modules at ~p">>), [Node])), (?H1GL(H1String, <<"modulesoverview">>, <<"Modules Overview">>)) ++ @@ -2177,10 +2175,10 @@ get_node(Host, Node, [<<"modules">>], Query, Lang) get_node(global, Node, [<<"stats">>], _Query, Lang) -> UpTime = ejabberd_cluster:call(Node, erlang, statistics, [wall_clock]), - UpTimeS = list_to_binary(io_lib:format("~.3f", + UpTimeS = (str:format("~.3f", [element(1, UpTime) / 1000])), CPUTime = ejabberd_cluster:call(Node, erlang, statistics, [runtime]), - CPUTimeS = list_to_binary(io_lib:format("~.3f", + CPUTimeS = (str:format("~.3f", [element(1, CPUTime) / 1000])), OnlineUsers = ejabberd_sm:connected_users_number(), TransactionsCommitted = ejabberd_cluster:call(Node, mnesia, @@ -2192,7 +2190,7 @@ get_node(global, Node, [<<"stats">>], _Query, Lang) -> TransactionsLogged = ejabberd_cluster:call(Node, mnesia, system_info, [transaction_log_writes]), [?XC(<<"h1">>, - list_to_binary(io_lib:format(?T(<<"Statistics of ~p">>), [Node]))), + (str:format(?T(<<"Statistics of ~p">>), [Node]))), ?XAE(<<"table">>, [], [?XE(<<"tbody">>, [?XE(<<"tr">>, @@ -2256,11 +2254,11 @@ get_node(global, Node, [<<"update">>], Query, Lang) -> (BeamsLis ++ SelectButtons)) end, FmtScript = (?XC(<<"pre">>, - list_to_binary(io_lib:format("~p", [Script])))), + (str:format("~p", [Script])))), FmtLowLevelScript = (?XC(<<"pre">>, - list_to_binary(io_lib:format("~p", [LowLevelScript])))), + (str:format("~p", [LowLevelScript])))), [?XC(<<"h1">>, - list_to_binary(io_lib:format(?T(<<"Update ~p">>), [Node])))] + (str:format(?T(<<"Update ~p">>), [Node])))] ++ case Res of ok -> [?XREST(<<"Submitted">>)]; @@ -2482,7 +2480,7 @@ node_ports_to_xhtml(Ports, Lang) -> SModule, <<"15">>)]), ?XAE(<<"td">>, direction(ltr), [?TEXTAREA(<<"opts", SSPort/binary>>, - (iolist_to_binary(integer_to_list(NumLines))), + (integer_to_binary(NumLines)), <<"35">>, SOptsClean)]), ?XE(<<"td">>, [?INPUTT(<<"submit">>, @@ -2625,7 +2623,7 @@ node_modules_to_xhtml(Modules, Lang) -> [?XC(<<"td">>, SModule), ?XAE(<<"td">>, direction(ltr), [?TEXTAREA(<<"opts", SModule/binary>>, - (iolist_to_binary(integer_to_list(NumLines))), + (integer_to_binary(NumLines)), <<"40">>, SOpts)]), ?XE(<<"td">>, [?INPUTT(<<"submit">>, @@ -2707,11 +2705,11 @@ node_update_parse_query(Node, Query) -> {ok, _} -> ok; {error, Error} -> ?ERROR_MSG("~p~n", [Error]), - {error, iolist_to_binary(io_lib:format("~p", [Error]))}; + {error, (str:format("~p", [Error]))}; {badrpc, Error} -> ?ERROR_MSG("Bad RPC: ~p~n", [Error]), {error, - <<"Bad RPC: ", (iolist_to_binary(io_lib:format("~p", [Error])))/binary>>} + <<"Bad RPC: ", ((str:format("~p", [Error])))/binary>>} end; _ -> nothing end. @@ -2776,7 +2774,7 @@ pretty_print_xml(#xmlel{name = Name, attrs = Attrs, element_to_list(X) when is_atom(X) -> iolist_to_binary(atom_to_list(X)); element_to_list(X) when is_integer(X) -> - iolist_to_binary(integer_to_list(X)). + integer_to_binary(X). list_to_element(Bin) -> {ok, Tokens, _} = erl_scan:string(binary_to_list(Bin)), @@ -2784,8 +2782,8 @@ list_to_element(Bin) -> Element. url_func({user_diapason, From, To}) -> - <<(iolist_to_binary(integer_to_list(From)))/binary, "-", - (iolist_to_binary(integer_to_list(To)))/binary, "/">>; + <<(integer_to_binary(From))/binary, "-", + (integer_to_binary(To))/binary, "/">>; url_func({users_queue, Prefix, User, _Server}) -> <>; url_func({user, Prefix, User, _Server}) -> @@ -2800,7 +2798,7 @@ cache_control_public() -> %% Transform 1234567890 into "1,234,567,890" pretty_string_int(Integer) when is_integer(Integer) -> - pretty_string_int(iolist_to_binary(integer_to_list(Integer))); + pretty_string_int(integer_to_binary(Integer)); pretty_string_int(String) when is_binary(String) -> {_, Result} = lists:foldl(fun (NewNumber, {3, Result}) -> {1, <>}; diff --git a/src/jlib.erl b/src/jlib.erl index f7dbebd86..096ef4012 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -677,14 +677,14 @@ timestamp_to_iso({{Year, Month, Day}, %% http://xmpp.org/extensions/xep-0091.html#time timestamp_to_legacy({{Year, Month, Day}, {Hour, Minute, Second}}) -> - iolist_to_binary(io_lib:format("~4..0B~2..0B~2..0BT~2..0B:~2..0B:~2..0B", + (str:format("~4..0B~2..0B~2..0BT~2..0B:~2..0B:~2..0B", [Year, Month, Day, Hour, Minute, Second])). -spec timestamp_to_iso_basic(calendar:datetime()) -> binary(). %% This is the ISO 8601 basic bormat timestamp_to_iso_basic({{Year, Month, Day}, {Hour, Minute, Second}}) -> - iolist_to_binary(io_lib:format("~4..0B~2..0B~2..0BT~2..0B~2..0B~2..0B", + (str:format("~4..0B~2..0B~2..0BT~2..0B~2..0B~2..0B", [Year, Month, Day, Hour, Minute, Second])). -spec now_to_utc_string(erlang:timestamp()) -> binary(). @@ -703,7 +703,7 @@ now_to_utc_string({MegaSecs, Secs, MicroSecs}, Precision) -> Max -> now_to_utc_string({MegaSecs, Secs + 1, 0}, Precision); FracOfSec -> - list_to_binary(io_lib:format("~4..0B-~2..0B-~2..0BT" + (str:format("~4..0B-~2..0B-~2..0BT" "~2..0B:~2..0B:~2..0B.~*..0BZ", [Year, Month, Day, Hour, Minute, Second, Precision, FracOfSec])) @@ -725,7 +725,7 @@ now_to_local_string({MegaSecs, Secs, MicroSecs}) -> end, {{Year, Month, Day}, {Hour, Minute, Second}} = LocalTime, - list_to_binary(io_lib:format("~4..0B-~2..0B-~2..0BT~2..0B:~2..0B:~2..0B.~6." + (str:format("~4..0B-~2..0B-~2..0BT~2..0B:~2..0B:~2..0B.~6." ".0B~s~2..0B:~2..0B", [Year, Month, Day, Hour, Minute, Second, MicroSecs, Sign, H, M])). diff --git a/src/mod_configure.erl b/src/mod_configure.erl index fc274dc03..436d736e6 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -680,9 +680,9 @@ get_all_vh_users(Host) -> lists:map(fun (K) -> L = K + M - 1, Node = <<"@", - (iolist_to_binary(integer_to_list(K)))/binary, + (integer_to_binary(K))/binary, "-", - (iolist_to_binary(integer_to_list(L)))/binary>>, + (integer_to_binary(L))/binary>>, {FS, FU} = lists:nth(K, SUsers), {LS, LU} = if L < N -> lists:nth(L, SUsers); true -> lists:last(SUsers) @@ -707,8 +707,7 @@ get_outgoing_s2s(Host, Lang) -> Host == FH orelse str:suffix(DotHost, FH)], lists:map( fun (T) -> - Name = iolist_to_binary( - io_lib:format(?T(Lang, <<"To ~s">>),[T])), + Name = str:format(?T(Lang, <<"To ~s">>),[T]), #disco_item{jid = jid:make(Host), node = <<"outgoing s2s/", T/binary>>, name = Name} @@ -722,8 +721,7 @@ get_outgoing_s2s(Host, Lang, To) -> lists:map( fun ({F, _T}) -> Node = <<"outgoing s2s/", To/binary, "/", F/binary>>, - Name = iolist_to_binary( - io_lib:format(?T(Lang, <<"From ~s">>), [F])), + Name = str:format(?T(Lang, <<"From ~s">>), [F]), #disco_item{jid = jid:make(Host), node = Node, name = Name} end, lists:keysort(1, @@ -1082,14 +1080,13 @@ get_form(_Host, label = ?T(Lang, <<"Message body">>)}]}}; get_form(Host, [<<"config">>, <<"acls">>], Lang) -> ACLs = str:tokens( - iolist_to_binary( - io_lib:format("~p.", - [mnesia:dirty_select( - acl, - ets:fun2ms( - fun({acl, {Name, H}, Spec}) when H == Host -> - {acl, Name, Spec} - end))])), + str:format("~p.", + [mnesia:dirty_select( + acl, + ets:fun2ms( + fun({acl, {Name, H}, Spec}) when H == Host -> + {acl, Name, Spec} + end))]), <<"\n">>), {result, #xdata{title = ?T(Lang, <<"Access Control List Configuration">>), @@ -1101,14 +1098,13 @@ get_form(Host, [<<"config">>, <<"acls">>], Lang) -> values = ACLs}]}}; get_form(Host, [<<"config">>, <<"access">>], Lang) -> Accs = str:tokens( - iolist_to_binary( - io_lib:format("~p.", - [mnesia:dirty_select( - access, - ets:fun2ms( - fun({access, {Name, H}, Acc}) when H == Host -> - {access, Name, Acc} - end))])), + str:format("~p.", + [mnesia:dirty_select( + access, + ets:fun2ms( + fun({access, {Name, H}, Acc}) when H == Host -> + {access, Name, Acc} + end))]), <<"\n">>), {result, #xdata{title = ?T(Lang, <<"Access Configuration">>), @@ -1199,9 +1195,7 @@ get_form(_Host, ?NS_ADMINL(<<"user-stats">>), Lang) -> required = true}]}}; get_form(Host, ?NS_ADMINL(<<"get-registered-users-num">>), Lang) -> - Num = list_to_binary( - io_lib:format("~p", - [ejabberd_auth:get_vh_registered_users_number(Host)])), + Num = integer_to_binary(ejabberd_auth:get_vh_registered_users_number(Host)), {result, completed, #xdata{type = form, fields = [?HFIELD(), @@ -1211,9 +1205,7 @@ get_form(Host, values = [Num]}]}}; get_form(Host, ?NS_ADMINL(<<"get-online-users-num">>), Lang) -> - Num = list_to_binary( - io_lib:format("~p", - [length(ejabberd_sm:get_vh_session_list(Host))])), + Num = integer_to_binary(ejabberd_sm:get_vh_session_number(Host)), {result, completed, #xdata{type = form, fields = [?HFIELD(), @@ -1641,7 +1633,7 @@ set_form(From, Host, TimeStamp = {Shift div 1000000, Shift rem 1000000, 0}, {{Year, Month, Day}, {Hour, Minute, Second}} = calendar:now_to_local_time(TimeStamp), - iolist_to_binary(io_lib:format("~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w", + (str:format("~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w", [Year, Month, Day, Hour, Minute, Second])) end; diff --git a/src/mod_irc.erl b/src/mod_irc.erl index 3dd0e492d..77bf34801 100644 --- a/src/mod_irc.erl +++ b/src/mod_irc.erl @@ -464,24 +464,23 @@ get_form(ServerHost, Host, From, Lang) -> var = <<"username">>, values = [Username]}, #xdata_field{type = fixed, - values = [iolist_to_binary( - io_lib:format( - translate:translate( - Lang, - <<"If you want to specify" - " different ports, " - "passwords, encodings " - "for IRC servers, " - "fill this list with " - "values in format " - "'{\"irc server\", " - "\"encoding\", port, " - "\"password\"}'. " - "By default this " - "service use \"~s\" " - "encoding, port ~p, " - "empty password.">>), - [DefaultEncoding, ?DEFAULT_IRC_PORT]))]}, + values = [str:format( + translate:translate( + Lang, + <<"If you want to specify" + " different ports, " + "passwords, encodings " + "for IRC servers, " + "fill this list with " + "values in format " + "'{\"irc server\", " + "\"encoding\", port, " + "\"password\"}'. " + "By default this " + "service use \"~s\" " + "encoding, port ~p, " + "empty password.">>), + [DefaultEncoding, ?DEFAULT_IRC_PORT])]}, #xdata_field{type = fixed, values = [translate:translate( Lang, @@ -493,11 +492,10 @@ get_form(ServerHost, Host, From, Lang) -> label = translate:translate( Lang, <<"Connections parameters">>), var = <<"connections_params">>, - values = str:tokens(list_to_binary( - io_lib:format( - "~p.", - [conn_params_to_list( - ConnectionsParams)])), + values = str:tokens(str:format( + "~p.", + [conn_params_to_list( + ConnectionsParams)]), <<"\n">>)}], X = #xdata{type = form, title = <<(translate:translate( @@ -657,11 +655,10 @@ adhoc_join(From, To, #adhoc_command{lang = Lang, xdata = X} = Request) -> RoomJID = jid:make(<>, To#jid.server), Reason = translate:translate(Lang, <<"Join the IRC channel here.">>), - Body = iolist_to_binary( - io_lib:format( - translate:translate( - Lang, <<"Join the IRC channel in this Jabber ID: ~s">>), - [jid:to_string(RoomJID)])), + Body = str:format( + translate:translate( + Lang, <<"Join the IRC channel in this Jabber ID: ~s">>), + [jid:to_string(RoomJID)]), Invite = #message{ body = xmpp:mk_text(Body, Lang), sub_els = [#muc_user{ @@ -782,43 +779,37 @@ generate_connection_params_field(Lang, Server, Encoding, Port; true -> ?DEFAULT_IRC_PORT end, - PortUsed = - iolist_to_binary(integer_to_list(PortUsedInt)), + PortUsed = integer_to_binary(PortUsedInt), PasswordUsed = case Password of <<>> -> <<>>; _ -> Password end, - NumberString = - iolist_to_binary(integer_to_list(Number)), + NumberString = integer_to_binary(Number), [#xdata_field{var = <<"password", NumberString/binary>>, type = 'text-single', - label = iolist_to_binary( - io_lib:format( - translate:translate(Lang, <<"Password ~b">>), - [Number])), + label = str:format( + translate:translate(Lang, <<"Password ~b">>), + [Number]), values = [PasswordUsed]}, #xdata_field{var = <<"port", NumberString/binary>>, type = 'text-single', - label = iolist_to_binary( - io_lib:format( - translate:translate(Lang, <<"Port ~b">>), - [Number])), + label = str:format( + translate:translate(Lang, <<"Port ~b">>), + [Number]), values = [PortUsed]}, #xdata_field{var = <<"encoding", NumberString/binary>>, type = 'list-single', - label = list_to_binary( - io_lib:format( - translate:translate(Lang, <<"Encoding for server ~b">>), - [Number])), + label = str:format( + translate:translate(Lang, <<"Encoding for server ~b">>), + [Number]), values = [EncodingUsed], options = [#xdata_option{label = E, value = E} || E <- ?POSSIBLE_ENCODINGS]}, #xdata_field{var = <<"server", NumberString/binary>>, type = 'text-single', - label = list_to_binary( - io_lib:format( - translate:translate(Lang, <<"Server ~b">>), - [Number])), + label = str:format( + translate:translate(Lang, <<"Server ~b">>), + [Number]), values = [Server]}]. parse_connections_params(#xdata{fields = Fields}) -> diff --git a/src/mod_irc_connection.erl b/src/mod_irc_connection.erl index c9b460ad0..2e604203c 100644 --- a/src/mod_irc_connection.erl +++ b/src/mod_irc_connection.erl @@ -1213,5 +1213,5 @@ unixtime2string(Unixtime) -> {0, 0, 0}}), {{Year, Month, Day}, {Hour, Minute, Second}} = calendar:universal_time_to_local_time(calendar:gregorian_seconds_to_datetime(Secs)), - iolist_to_binary(io_lib:format("~4..0w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w", + (str:format("~4..0w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w", [Year, Month, Day, Hour, Minute, Second])). diff --git a/src/mod_muc_log.erl b/src/mod_muc_log.erl index 5cf52e60f..2675db9b5 100644 --- a/src/mod_muc_log.erl +++ b/src/mod_muc_log.erl @@ -247,18 +247,18 @@ build_filename_string(TimeStamp, OutDir, RoomJID, {Dir, Filename, Rel} = case DirType of subdirs -> SYear = - iolist_to_binary(io_lib:format("~4..0w", + (str:format("~4..0w", [Year])), SMonth = - iolist_to_binary(io_lib:format("~2..0w", + (str:format("~2..0w", [Month])), - SDay = iolist_to_binary(io_lib:format("~2..0w", + SDay = (str:format("~2..0w", [Day])), {fjoin([SYear, SMonth]), SDay, <<"../..">>}; plain -> Date = - iolist_to_binary(io_lib:format("~4..0w-~2..0w-~2..0w", + (str:format("~4..0w-~2..0w-~2..0w", [Year, Month, Day])), @@ -727,7 +727,7 @@ fw(F, S, FileFormat) when is_atom(FileFormat) -> fw(F, S, [], FileFormat). fw(F, S, O, FileFormat) -> - S1 = list_to_binary(io_lib:format(binary_to_list(S) ++ "~n", O)), + S1 = (str:format(binary_to_list(S) ++ "~n", O)), S2 = case FileFormat of html -> S1; diff --git a/src/mod_offline.erl b/src/mod_offline.erl index f620e73c5..eedbcaeb1 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -717,7 +717,7 @@ user_queue(User, Server, Query, Lang) -> Hdrs = get_messages_subset(US, Server, HdrsAll), FMsgs = format_user_queue(Hdrs), [?XC(<<"h1">>, - list_to_binary(io_lib:format(?T(<<"~s's Offline Messages Queue">>), + (str:format(?T(<<"~s's Offline Messages Queue">>), [us_to_list(US)])))] ++ case Res of @@ -801,7 +801,7 @@ webadmin_user(Acc, User, Server, Lang) -> QueueLen = count_offline_messages(jid:nodeprep(User), jid:nameprep(Server)), FQueueLen = [?AC(<<"queue/">>, - (iolist_to_binary(integer_to_list(QueueLen))))], + (integer_to_binary(QueueLen)))], Acc ++ [?XCT(<<"h3">>, <<"Offline Messages:">>)] ++ FQueueLen ++ diff --git a/src/mod_pubsub.erl b/src/mod_pubsub.erl index c379760ed..ba79cf7bc 100644 --- a/src/mod_pubsub.erl +++ b/src/mod_pubsub.erl @@ -3776,7 +3776,7 @@ err_unsupported_access_model() -> -spec uniqid() -> mod_pubsub:itemId(). uniqid() -> {T1, T2, T3} = p1_time_compat:timestamp(), - iolist_to_binary(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3])). + (str:format("~.16B~.16B~.16B", [T1, T2, T3])). -spec itemsEls([#pubsub_item{}]) -> [ps_item()]. itemsEls(Items) -> diff --git a/src/mod_register.erl b/src/mod_register.erl index dc8ca995c..3cec0660b 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -392,7 +392,7 @@ send_registration_notifications(Mod, UJID, Source) -> [] -> ok; JIDs when is_list(JIDs) -> Body = - iolist_to_binary(io_lib:format("[~s] The account ~s was registered from " + (str:format("[~s] The account ~s was registered from " "IP address ~s on node ~w using ~p.", [get_time_string(), jid:to_string(UJID), diff --git a/src/mod_sip_proxy.erl b/src/mod_sip_proxy.erl index 04ae55ae7..06daf0810 100644 --- a/src/mod_sip_proxy.erl +++ b/src/mod_sip_proxy.erl @@ -299,7 +299,7 @@ add_record_route_and_set_uri(URI, LServer, #sip{hdrs = Hdrs} = Req) -> case need_record_route(LServer) of true -> RR_URI = get_configured_record_route(LServer), - TS = list_to_binary(integer_to_list(p1_time_compat:system_time(seconds))), + TS = (integer_to_binary(p1_time_compat:system_time(seconds))), Sign = make_sign(TS, Hdrs), User = <>, NewRR_URI = RR_URI#uri{user = User}, @@ -339,7 +339,7 @@ make_sign(TS, Hdrs) -> is_signed_by_me(TS_Sign, Hdrs) -> try [TSBin, Sign] = str:tokens(TS_Sign, <<"-">>), - TS = list_to_integer(binary_to_list(TSBin)), + TS = (binary_to_integer(TSBin)), NowTS = p1_time_compat:system_time(seconds), true = (NowTS - TS) =< ?SIGN_LIFETIME, Sign == make_sign(TSBin, Hdrs) diff --git a/src/mod_sip_registrar.erl b/src/mod_sip_registrar.erl index fcaa42365..e6532c934 100644 --- a/src/mod_sip_registrar.erl +++ b/src/mod_sip_registrar.erl @@ -355,7 +355,7 @@ min_expires() -> 60. to_integer(Bin, Min, Max) -> - case catch list_to_integer(binary_to_list(Bin)) of + case catch (binary_to_integer(Bin)) of N when N >= Min, N =< Max -> {ok, N}; _ -> diff --git a/src/mod_stats.erl b/src/mod_stats.erl index f146498c6..e43409e06 100644 --- a/src/mod_stats.erl +++ b/src/mod_stats.erl @@ -111,7 +111,7 @@ get_local_stat(Server, [], Name) {'EXIT', _Reason} -> ?STATERR(500, <<"Internal Server Error">>); Users -> - ?STATVAL((iolist_to_binary(integer_to_list(length(Users)))), + ?STATVAL((integer_to_binary(length(Users))), <<"users">>) end; get_local_stat(Server, [], Name) @@ -122,13 +122,13 @@ get_local_stat(Server, [], Name) {'EXIT', _Reason} -> ?STATERR(500, <<"Internal Server Error">>); NUsers -> - ?STATVAL((iolist_to_binary(integer_to_list(NUsers))), + ?STATVAL((integer_to_binary(NUsers)), <<"users">>) end; get_local_stat(_Server, [], Name) when Name == <<"users/all-hosts/online">> -> Users = ejabberd_sm:connected_users_number(), - ?STATVAL((iolist_to_binary(integer_to_list(Users))), <<"users">>); + ?STATVAL((integer_to_binary(Users)), <<"users">>); get_local_stat(_Server, [], Name) when Name == <<"users/all-hosts/total">> -> NumUsers = lists:foldl(fun (Host, Total) -> @@ -136,7 +136,7 @@ get_local_stat(_Server, [], Name) + Total end, 0, ?MYHOSTS), - ?STATVAL((iolist_to_binary(integer_to_list(NumUsers))), + ?STATVAL((integer_to_binary(NumUsers)), <<"users">>); get_local_stat(_Server, _, Name) -> ?STATERR(404, <<"Not Found">>). @@ -149,9 +149,7 @@ get_node_stat(Node, Name) {badrpc, _Reason} -> ?STATERR(500, <<"Internal Server Error">>); CPUTime -> - ?STATVAL(list_to_binary( - io_lib:format("~.3f", - [element(1, CPUTime) / 1000])), + ?STATVAL(str:format("~.3f", [element(1, CPUTime) / 1000]), <<"seconds">>) end; get_node_stat(Node, Name) @@ -161,9 +159,7 @@ get_node_stat(Node, Name) {badrpc, _Reason} -> ?STATERR(500, <<"Internal Server Error">>); RunTime -> - ?STATVAL(list_to_binary( - io_lib:format("~.3f", - [element(1, RunTime) / 1000])), + ?STATVAL(str:format("~.3f", [element(1, RunTime) / 1000]), <<"seconds">>) end; get_node_stat(Node, Name) @@ -174,7 +170,7 @@ get_node_stat(Node, Name) {badrpc, _Reason} -> ?STATERR(500, <<"Internal Server Error">>); Users -> - ?STATVAL((iolist_to_binary(integer_to_list(length(Users)))), + ?STATVAL((integer_to_binary(length(Users))), <<"users">>) end; get_node_stat(Node, Name) @@ -185,7 +181,7 @@ get_node_stat(Node, Name) {badrpc, _Reason} -> ?STATERR(500, <<"Internal Server Error">>); Transactions -> - ?STATVAL((iolist_to_binary(integer_to_list(Transactions))), + ?STATVAL((integer_to_binary(Transactions)), <<"transactions">>) end; get_node_stat(Node, Name) @@ -196,7 +192,7 @@ get_node_stat(Node, Name) {badrpc, _Reason} -> ?STATERR(500, <<"Internal Server Error">>); Transactions -> - ?STATVAL((iolist_to_binary(integer_to_list(Transactions))), + ?STATVAL((integer_to_binary(Transactions)), <<"transactions">>) end; get_node_stat(Node, Name) @@ -207,7 +203,7 @@ get_node_stat(Node, Name) {badrpc, _Reason} -> ?STATERR(500, <<"Internal Server Error">>); Transactions -> - ?STATVAL((iolist_to_binary(integer_to_list(Transactions))), + ?STATVAL((integer_to_binary(Transactions)), <<"transactions">>) end; get_node_stat(Node, Name) @@ -218,7 +214,7 @@ get_node_stat(Node, Name) {badrpc, _Reason} -> ?STATERR(500, <<"Internal Server Error">>); Transactions -> - ?STATVAL((iolist_to_binary(integer_to_list(Transactions))), + ?STATVAL((integer_to_binary(Transactions)), <<"transactions">>) end; get_node_stat(_, Name) -> diff --git a/src/mod_version.erl b/src/mod_version.erl index 80b22554d..36bf796ee 100644 --- a/src/mod_version.erl +++ b/src/mod_version.erl @@ -70,7 +70,7 @@ get_os() -> OSType = list_to_binary([atom_to_list(Osfamily), $/, atom_to_list(Osname)]), OSVersion = case os:version() of {Major, Minor, Release} -> - iolist_to_binary(io_lib:format("~w.~w.~w", + (str:format("~w.~w.~w", [Major, Minor, Release])); VersionString -> VersionString end, diff --git a/src/pubsub_db_sql.erl b/src/pubsub_db_sql.erl index 713d33970..986a0b9b2 100644 --- a/src/pubsub_db_sql.erl +++ b/src/pubsub_db_sql.erl @@ -127,7 +127,7 @@ subscription_opt_to_sql({subscription_depth, Depth}) -> N -> integer_to_sql(N) end}. -integer_to_sql(N) -> iolist_to_binary(integer_to_list(N)). +integer_to_sql(N) -> integer_to_binary(N). boolean_to_sql(true) -> <<"1">>; boolean_to_sql(false) -> <<"0">>. diff --git a/src/pubsub_subscription.erl b/src/pubsub_subscription.erl index 297c6627c..b6986b69d 100644 --- a/src/pubsub_subscription.erl +++ b/src/pubsub_subscription.erl @@ -170,7 +170,7 @@ write_subscription(_JID, _NodeId, SubID, Options) -> -spec make_subid() -> SubId::mod_pubsub:subId(). make_subid() -> {T1, T2, T3} = p1_time_compat:timestamp(), - iolist_to_binary(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3])). + (str:format("~.16B~.16B~.16B", [T1, T2, T3])). %% %% Subscription XForm processing. @@ -207,14 +207,14 @@ val_xfield(digest_frequency = Opt, [Val]) -> N when is_integer(N) -> N; _ -> Txt = <<"Value of '~s' should be integer">>, - ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), + ErrTxt = (str:format(Txt, [Opt])), {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} end; val_xfield(expire = Opt, [Val]) -> try xmpp_util:decode_timestamp(Val) catch _:{bad_timestamp, _} -> Txt = <<"Value of '~s' should be datetime string">>, - ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), + ErrTxt = (str:format(Txt, [Opt])), {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} end; val_xfield(include_body = Opt, [Val]) -> xopt_to_bool(Opt, Val); @@ -227,7 +227,7 @@ val_xfield(subscription_depth = Opt, [Depth]) -> N when is_integer(N) -> N; _ -> Txt = <<"Value of '~s' should be integer">>, - ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), + ErrTxt = (str:format(Txt, [Opt])), {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} end. @@ -238,7 +238,7 @@ xopt_to_bool(_, <<"false">>) -> false; xopt_to_bool(_, <<"true">>) -> true; xopt_to_bool(Option, _) -> Txt = <<"Value of '~s' should be boolean">>, - ErrTxt = iolist_to_binary(io_lib:format(Txt, [Option])), + ErrTxt = (str:format(Txt, [Option])), {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)}. %% Return a field for an XForm for Key, with data filled in, if @@ -311,7 +311,7 @@ xfield_label(subscription_depth) -> ?SUBSCRIPTION_DEPTH_LABEL. xfield_val(deliver, Val) -> [bool_to_xopt(Val)]; %xfield_val(digest, Val) -> [bool_to_xopt(Val)]; %xfield_val(digest_frequency, Val) -> -% [iolist_to_binary(integer_to_list(Val))]; +% [integer_to_binary(Val))]; %xfield_val(expire, Val) -> % [jlib:now_to_utc_string(Val)]; %xfield_val(include_body, Val) -> [bool_to_xopt(Val)]; @@ -320,7 +320,7 @@ xfield_val(subscription_type, items) -> [<<"items">>]; xfield_val(subscription_type, nodes) -> [<<"nodes">>]; xfield_val(subscription_depth, all) -> [<<"all">>]; xfield_val(subscription_depth, N) -> - [iolist_to_binary(integer_to_list(N))]. + [integer_to_binary(N)]. bool_to_xopt(true) -> <<"true">>; diff --git a/src/pubsub_subscription_sql.erl b/src/pubsub_subscription_sql.erl index bb7b64112..da72cc96e 100644 --- a/src/pubsub_subscription_sql.erl +++ b/src/pubsub_subscription_sql.erl @@ -135,7 +135,7 @@ create_table() -> ok. -spec make_subid() -> mod_pubsub:subId(). make_subid() -> {T1, T2, T3} = p1_time_compat:timestamp(), - iolist_to_binary(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3])). + (str:format("~.16B~.16B~.16B", [T1, T2, T3])). %% %% Subscription XForm processing. @@ -172,14 +172,14 @@ val_xfield(digest_frequency = Opt, [Val]) -> N when is_integer(N) -> N; _ -> Txt = <<"Value of '~s' should be integer">>, - ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), + ErrTxt = (str:format(Txt, [Opt])), {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} end; val_xfield(expire = Opt, [Val]) -> try xmpp_util:decode_timestamp(Val) catch _:{bad_timestamp, _} -> Txt = <<"Value of '~s' should be datetime string">>, - ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), + ErrTxt = (str:format(Txt, [Opt])), {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} end; val_xfield(include_body = Opt, [Val]) -> xopt_to_bool(Opt, Val); @@ -192,7 +192,7 @@ val_xfield(subscription_depth = Opt, [Depth]) -> N when is_integer(N) -> N; _ -> Txt = <<"Value of '~s' should be integer">>, - ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), + ErrTxt = (str:format(Txt, [Opt])), {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} end. @@ -203,7 +203,7 @@ xopt_to_bool(_, <<"false">>) -> false; xopt_to_bool(_, <<"true">>) -> true; xopt_to_bool(Option, _) -> Txt = <<"Value of '~s' should be boolean">>, - ErrTxt = iolist_to_binary(io_lib:format(Txt, [Option])), + ErrTxt = (str:format(Txt, [Option])), {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)}. %% Return a field for an XForm for Key, with data filled in, if @@ -276,7 +276,7 @@ xfield_label(subscription_depth) -> ?SUBSCRIPTION_DEPTH_LABEL. xfield_val(deliver, Val) -> [bool_to_xopt(Val)]; %xfield_val(digest, Val) -> [bool_to_xopt(Val)]; %xfield_val(digest_frequency, Val) -> -% [iolist_to_binary(integer_to_list(Val))]; +% [integer_to_binary(Val))]; %xfield_val(expire, Val) -> % [jlib:now_to_utc_string(Val)]; %xfield_val(include_body, Val) -> [bool_to_xopt(Val)]; @@ -285,7 +285,7 @@ xfield_val(subscription_type, items) -> [<<"items">>]; xfield_val(subscription_type, nodes) -> [<<"nodes">>]; xfield_val(subscription_depth, all) -> [<<"all">>]; xfield_val(subscription_depth, N) -> - [iolist_to_binary(integer_to_list(N))]. + [integer_to_binary(N)]. bool_to_xopt(false) -> <<"false">>; bool_to_xopt(true) -> <<"true">>. From 28d0a1b9d22266df228ed96b84128c663777c982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Thu, 24 Nov 2016 14:07:08 +0100 Subject: [PATCH 138/151] Make compatible with rebar3 --- rebar.config.script | 60 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/rebar.config.script b/rebar.config.script index 2a924d26c..34e0c328e 100644 --- a/rebar.config.script +++ b/rebar.config.script @@ -21,6 +21,14 @@ ModCfg0 = fun(F, Cfg, [Key|Tail], Op, Default) -> end, ModCfg = fun(Cfg, Keys, Op, Default) -> ModCfg0(ModCfg0, Cfg, Keys, Op, Default) end, +IsRebar3 = case application:get_key(rebar, vsn) of + {ok, VSN} -> + [VSN1 | _] = string:tokens(VSN, "-"), + [Maj, Min, Patch] = string:tokens(VSN1, "."), + (list_to_integer(Maj) >= 3); + undefined -> + lists:keymember(mix, 1, application:loaded_applications()) + end, Cfg = case file:consult(filename:join(filename:dirname(SCRIPT), "vars.config")) of {ok, Terms} -> Terms; @@ -121,16 +129,62 @@ TestConfig = case file:read_file_info(TestConfigFile) of "" end, +ResolveDepPath = case IsRebar3 of + true -> + fun("deps/" ++ Rest) -> + Slash = string:str(Rest, "/"), + Dir = "_build/default/lib/" ++ + string:sub_string(Rest, 1, Slash-1), + Dir ++ string:sub_string(Rest, Slash); + (Path) -> + Path + end; + _ -> + fun(P) -> + P + end + end, + CtIncludes = case lists:keyfind(eunit_compile_opts, 1, Conf1) of false -> []; {_, EunitCompOpts} -> - [[" -include ", filename:join([Cwd, IncPath])] + [[" -include ", filename:join([Cwd, ResolveDepPath(IncPath)])] || {i, IncPath} <- EunitCompOpts] end, -Conf2 = [{ct_extra_params, lists:flatten(["-ct_hooks cth_surefire ", TestConfig, - CtIncludes])} | Conf1], +ProcessErlOpt = fun({i, Path}) -> + {i, ResolveDepPath(Path)}; + (ErlOpt) -> + ErlOpt + end, + +Conf1a = ModCfg(Conf1, [erl_opts], + fun(ErlOpts) -> lists:map(ProcessErlOpt, ErlOpts) end, []), + +Conf2a = [{ct_extra_params, lists:flatten(["-ct_hooks cth_surefire ", TestConfig, + CtIncludes])} | Conf1a], + +Conf2 = case IsRebar3 of + true -> + DepsFun = fun(DepsList) -> + lists:filtermap(fun({rebar_elixir_plugin, _, _}) -> + false; + ({DepName,_, {git,_, _} = Git}) -> + {true, {DepName, Git}}; + (Dep) -> + true + end, DepsList) + end, + RB1 = ModCfg(Conf2a, [deps], DepsFun, []), + ModCfg(RB1, [plugins], fun(V) -> V -- [deps_erl_opts, + rebar_elixir_compiler, + rebar_exunit] ++ + [rebar3_hex] end, []); + false -> + Conf2a + end, + Conf3 = case lists:keytake(xref_exclusions, 1, Conf2) of {value, {_, Items2}, Rest2} -> From 0f11b1be364e43189e06eeb577750e7d1b0e9fef Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Thu, 24 Nov 2016 18:40:20 +0300 Subject: [PATCH 139/151] Don't forget to erase cache on user removal --- src/mod_mam.erl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mod_mam.erl b/src/mod_mam.erl index 0433dee79..edb0d1485 100644 --- a/src/mod_mam.erl +++ b/src/mod_mam.erl @@ -176,6 +176,7 @@ remove_user(User, Server) -> LServer = jid:nameprep(Server), Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:remove_user(LUser, LServer), + cache_tab:dirty_delete(archive_prefs, {LUser, LServer}, fun() -> ok end), ok. -spec remove_room(binary(), binary(), binary()) -> ok. From d554827ebc6ae5a81f9f24e5e446606f3e0e916a Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Thu, 24 Nov 2016 20:16:07 +0300 Subject: [PATCH 140/151] Don't check for faked carbons --- test/carbons_tests.erl | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/test/carbons_tests.erl b/test/carbons_tests.erl index 2780dab66..00dd57e3c 100644 --- a/test/carbons_tests.erl +++ b/test/carbons_tests.erl @@ -145,10 +145,6 @@ recv_carbons(Config) -> ok; ({_, #message{sub_els = [#carbons_private{}]}}) -> ok; - ({_, #message{sub_els = [#carbons_sent{}]}}) -> - ok; - ({_, #message{sub_els = [#carbons_received{}]}}) -> - ok; ({_, #message{type = T}}) when T /= normal, T /= chat -> ok; ({Dir, #message{type = T, body = Body} = M}) @@ -197,6 +193,4 @@ message_iterator(_Config) -> Body <- [[], xmpp:mk_text(<<"body">>)], Els <- [[], [#hint{type = 'no-copy'}], - [#carbons_private{}], - [#carbons_sent{forwarded = #forwarded{}}], - [#carbons_received{forwarded = #forwarded{}}]]]. + [#carbons_private{}]]]. From 993cbcb13389940cca481fe334030d9eb3452961 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Fri, 25 Nov 2016 09:39:09 +0300 Subject: [PATCH 141/151] Use new version of xmpp --- rebar.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rebar.config b/rebar.config index 11249e822..95ddbc96b 100644 --- a/rebar.config +++ b/rebar.config @@ -13,7 +13,7 @@ {fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.7"}}}, {stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.6"}}}, {fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.17"}}}, - {xmpp, ".*", {git, "https://github.com/processone/xmpp", {tag, "1.0.4"}}}, + {xmpp, ".*", {git, "https://github.com/processone/xmpp", {tag, "1.1.1"}}}, {stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.7"}}}, {esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.8"}}}, {fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.6"}}}, From e1539e57690b2ecb2203b1010e7ac5b042e955d2 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Fri, 25 Nov 2016 09:48:26 +0300 Subject: [PATCH 142/151] Get rid of compile warnings --- src/ejabberd_ctl.erl | 2 +- src/ejabberd_xmlrpc.erl | 8 ++++---- src/mod_http_api.erl | 4 ++-- src/mod_privacy_sql.erl | 3 --- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/ejabberd_ctl.erl b/src/ejabberd_ctl.erl index a96a28016..63adcdf69 100644 --- a/src/ejabberd_ctl.erl +++ b/src/ejabberd_ctl.erl @@ -311,7 +311,7 @@ try_call_command(Args, Auth, AccessCommands, Version) -> end. %% @spec (Args::[string()], Auth, AccessCommands) -> string() | integer() | {string(), integer()} | {error, ErrorType} -call_command([CmdString | Args], Auth, AccessCommands, Version) -> +call_command([CmdString | Args], Auth, _AccessCommands, Version) -> CmdStringU = ejabberd_regexp:greplace( list_to_binary(CmdString), <<"-">>, <<"_">>), Command = list_to_atom(binary_to_list(CmdStringU)), diff --git a/src/ejabberd_xmlrpc.erl b/src/ejabberd_xmlrpc.erl index 1b795d3fd..2792d08c1 100644 --- a/src/ejabberd_xmlrpc.erl +++ b/src/ejabberd_xmlrpc.erl @@ -216,10 +216,10 @@ process(_, #request{method = 'POST', data = Data, opts = Opts, ip = {IP, _}}) -> L), L end, all), - CommOpts = gen_mod:get_opt( - options, AcOpts, - fun(L) when is_list(L) -> L end, - []), + %% CommOpts = gen_mod:get_opt( + %% options, AcOpts, + %% fun(L) when is_list(L) -> L end, + %% []), [{<<"ejabberd_xmlrpc compatibility shim">>, {[?MODULE], [{access, Ac}], Commands}}]; (Wrong) -> ?WARNING_MSG("wrong options format for ~p: ~p", diff --git a/src/mod_http_api.erl b/src/mod_http_api.erl index a189777b1..3700060cb 100644 --- a/src/mod_http_api.erl +++ b/src/mod_http_api.erl @@ -503,8 +503,8 @@ unauthorized_response() -> invalid_token_response() -> json_error(401, 10, <<"Oauth Token is invalid or expired.">>). -outofscope_response() -> - json_error(401, 11, <<"Token does not grant usage to command required scope.">>). +%% outofscope_response() -> +%% json_error(401, 11, <<"Token does not grant usage to command required scope.">>). badrequest_response() -> badrequest_response(<<"400 Bad Request">>). diff --git a/src/mod_privacy_sql.erl b/src/mod_privacy_sql.erl index a39e36766..1984237c6 100644 --- a/src/mod_privacy_sql.erl +++ b/src/mod_privacy_sql.erl @@ -334,9 +334,6 @@ sql_get_privacy_list_id_t(LUser, Name) -> sql_get_privacy_list_data(LUser, LServer, Name) -> sql_queries:get_privacy_list_data(LServer, LUser, Name). -sql_get_privacy_list_data_t(LUser, Name) -> - sql_queries:get_privacy_list_data_t(LUser, Name). - sql_get_privacy_list_data_by_id(ID, LServer) -> sql_queries:get_privacy_list_data_by_id(LServer, ID). From 4d6eb312642fe018cff007efc6639873a67d72a4 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Fri, 25 Nov 2016 09:31:49 +0100 Subject: [PATCH 143/151] Use new version of xmpp in mix --- mix.exs | 2 +- mix.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.exs b/mix.exs index 5e1676043..d1ef0fbbb 100644 --- a/mix.exs +++ b/mix.exs @@ -46,7 +46,7 @@ defmodule Ejabberd.Mixfile do {:fast_yaml, "~> 1.0"}, {:fast_tls, "~> 1.0"}, {:fast_xml, "~> 1.1", override: true}, # override cause of :xmpp - {:xmpp, github: "processone/xmpp", tag: "1.0.3"}, + {:xmpp, github: "processone/xmpp", tag: "1.1.1"}, {:stun, "~> 1.0"}, {:esip, "~> 1.0"}, {:jiffy, "~> 0.14.7"}, diff --git a/mix.lock b/mix.lock index 47a335975..695a514de 100644 --- a/mix.lock +++ b/mix.lock @@ -21,4 +21,4 @@ "relx": {:hex, :relx, "3.21.1", "f989dc520730efd9075e9f4debcb8ba1d7d1e86b018b0bcf45a2eb80270b4ad6", [:rebar3], [{:bbmustache, "1.0.4", [hex: :bbmustache, optional: false]}, {:cf, "0.2.1", [hex: :cf, optional: false]}, {:erlware_commons, "0.21.0", [hex: :erlware_commons, optional: false]}, {:getopt, "0.8.2", [hex: :getopt, optional: false]}, {:providers, "1.6.0", [hex: :providers, optional: false]}]}, "stringprep": {:hex, :stringprep, "1.0.6", "1cf1c439eb038aa590da5456e019f86afbfbfeb5a2d37b6e5f873041624c6701", [:rebar3], [{:p1_utils, "1.0.5", [hex: :p1_utils, optional: false]}]}, "stun": {:hex, :stun, "1.0.7", "904dc6f26a3c30c54881c4c3003699f2a4968067ee6b3aecdf9895aad02df75e", [:rebar3], [{:fast_tls, "1.0.7", [hex: :fast_tls, optional: false]}, {:p1_utils, "1.0.5", [hex: :p1_utils, optional: false]}]}, - "xmpp": {:git, "https://github.com/processone/xmpp.git", "e4630667bc63de7ad2d236387f4631a0656a9355", [tag: "1.0.3"]}} + "xmpp": {:git, "https://github.com/processone/xmpp.git", "758c3a865563e019e46f8f6e96857a4161a833dd", [tag: "1.1.1"]}} From ca1b22bdd4fbff9ee517d09b9d9c348189b073cf Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Fri, 25 Nov 2016 11:41:24 +0300 Subject: [PATCH 144/151] Use ejabberd_router:route_error/4 wherever possible --- src/ejabberd_local.erl | 15 +++++------ src/ejabberd_sm.erl | 20 ++++++--------- src/gen_iq_handler.erl | 2 +- src/mod_announce.erl | 56 ++++++++++++------------------------------ src/mod_muc.erl | 10 +++----- src/mod_muc_room.erl | 43 +++++++++++++------------------- src/mod_offline.erl | 5 ++-- 7 files changed, 54 insertions(+), 97 deletions(-) diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index 74d86945d..3406192f7 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -87,14 +87,12 @@ process_iq(From, To, #iq{type = T, lang = Lang, sub_els = [El]} = Packet) From, To, Packet); [] -> Txt = <<"No module is handling this query">>, - Err = xmpp:make_error( - Packet, - xmpp:err_service_unavailable(Txt, Lang)), - ejabberd_router:route(To, From, Err) + Err = xmpp:err_service_unavailable(Txt, Lang), + ejabberd_router:route_error(To, From, Packet, Err) end; process_iq(From, To, #iq{type = T} = Packet) when T == get; T == set -> - Err = xmpp:make_error(Packet, xmpp:err_bad_request()), - ejabberd_router:route(To, From, Err); + Err = xmpp:err_bad_request(), + ejabberd_router:route_error(To, From, Packet, Err); process_iq(From, To, #iq{type = T} = Packet) when T == result; T == error -> process_iq_reply(From, To, Packet). @@ -186,9 +184,8 @@ bounce_resource_packet(_From, #jid{lresource = <<"">>}, bounce_resource_packet(From, To, Packet) -> Lang = xmpp:get_lang(Packet), Txt = <<"No available resource found">>, - Err = xmpp:make_error(Packet, - xmpp:err_item_not_found(Txt, Lang)), - ejabberd_router:route(To, From, Err), + Err = xmpp:err_item_not_found(Txt, Lang), + ejabberd_router:route_error(To, From, Packet, Err), stop. %%==================================================================== diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index d40db28cc..56dc3092e 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -173,9 +173,8 @@ check_in_subscription(Acc, User, Server, _JID, _Type, _Reason) -> bounce_offline_message(From, To, Packet) -> Lang = xmpp:get_lang(Packet), Txt = <<"User session not found">>, - Err = xmpp:make_error( - Packet, xmpp:err_service_unavailable(Txt, Lang)), - ejabberd_router:route(To, From, Err), + Err = xmpp:err_service_unavailable(Txt, Lang), + ejabberd_router:route_error(To, From, Packet, Err), stop. -spec disconnect_removed_user(binary(), binary()) -> ok. @@ -602,9 +601,8 @@ route_message(From, To, Packet, Type) -> ejabberd_hooks:run(offline_message_hook, LServer, [From, To, Packet]); false -> - Err = xmpp:make_error(Packet, - xmpp:err_service_unavailable()), - ejabberd_router:route(To, From, Err) + Err = xmpp:err_service_unavailable(), + ejabberd_router:route_error(To, From, Packet, Err) end end. @@ -724,14 +722,12 @@ process_iq(From, To, #iq{type = T, lang = Lang, sub_els = [El]} = Packet) From, To, Packet); [] -> Txt = <<"No module is handling this query">>, - Err = xmpp:make_error( - Packet, - xmpp:err_service_unavailable(Txt, Lang)), - ejabberd_router:route(To, From, Err) + Err = xmpp:err_service_unavailable(Txt, Lang), + ejabberd_router:route_error(To, From, Packet, Err) end; process_iq(From, To, #iq{type = T} = Packet) when T == get; T == set -> - Err = xmpp:make_error(Packet, xmpp:err_bad_request()), - ejabberd_router:route(To, From, Err), + Err = xmpp:err_bad_request(), + ejabberd_router:route_error(To, From, Packet, Err), ok; process_iq(_From, _To, #iq{}) -> ok. diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl index bcbda1d1e..4a7a03c27 100644 --- a/src/gen_iq_handler.erl +++ b/src/gen_iq_handler.erl @@ -147,7 +147,7 @@ process_iq(_Host, Module, Function, From, To, IQ0) -> [xmpp:pp(IQ), {E, {R, erlang:get_stacktrace()}}]), Txt = <<"Module failed to handle the query">>, Err = xmpp:err_internal_server_error(Txt, IQ#iq.lang), - ejabberd_router:route(To, From, xmpp:make_error(IQ, Err)) + ejabberd_router:route_error(To, From, IQ, Err) end. -spec process_iq(module(), atom(), iq()) -> ignore | iq(). diff --git a/src/mod_announce.erl b/src/mod_announce.erl index a1c60f3c9..2e182ed1e 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -601,10 +601,7 @@ announce_all(From, To, Packet) -> Access = get_access(Host), case acl:match_rule(Host, Access, From) of deny -> - Lang = xmpp:get_lang(Packet), - Txt = <<"Denied by ACL">>, - Err = xmpp:make_error(Packet, xmpp:err_forbidden(Txt, Lang)), - ejabberd_router:route(To, From, Err); + route_forbidden_error(From, To, Packet); allow -> Local = jid:make(To#jid.server), lists:foreach( @@ -618,10 +615,7 @@ announce_all_hosts_all(From, To, Packet) -> Access = get_access(global), case acl:match_rule(global, Access, From) of deny -> - Lang = xmpp:get_lang(Packet), - Txt = <<"Denied by ACL">>, - Err = xmpp:make_error(Packet, xmpp:err_forbidden(Txt, Lang)), - ejabberd_router:route(To, From, Err); + route_forbidden_error(From, To, Packet); allow -> Local = jid:make(To#jid.server), lists:foreach( @@ -636,10 +630,7 @@ announce_online(From, To, Packet) -> Access = get_access(Host), case acl:match_rule(Host, Access, From) of deny -> - Lang = xmpp:get_lang(Packet), - Txt = <<"Denied by ACL">>, - Err = xmpp:make_error(Packet, xmpp:err_forbidden(Txt, Lang)), - ejabberd_router:route(To, From, Err); + route_forbidden_error(From, To, Packet); allow -> announce_online1(ejabberd_sm:get_vh_session_list(Host), To#jid.server, @@ -650,10 +641,7 @@ announce_all_hosts_online(From, To, Packet) -> Access = get_access(global), case acl:match_rule(global, Access, From) of deny -> - Lang = xmpp:get_lang(Packet), - Txt = <<"Denied by ACL">>, - Err = xmpp:make_error(Packet, xmpp:err_forbidden(Txt, Lang)), - ejabberd_router:route(To, From, Err); + route_forbidden_error(From, To, Packet); allow -> announce_online1(ejabberd_sm:dirty_get_sessions_list(), To#jid.server, @@ -673,10 +661,7 @@ announce_motd(From, To, Packet) -> Access = get_access(Host), case acl:match_rule(Host, Access, From) of deny -> - Lang = xmpp:get_lang(Packet), - Txt = <<"Denied by ACL">>, - Err = xmpp:make_error(Packet, xmpp:err_forbidden(Txt, Lang)), - ejabberd_router:route(To, From, Err); + route_forbidden_error(From, To, Packet); allow -> announce_motd(Host, Packet) end. @@ -685,10 +670,7 @@ announce_all_hosts_motd(From, To, Packet) -> Access = get_access(global), case acl:match_rule(global, Access, From) of deny -> - Lang = xmpp:get_lang(Packet), - Txt = <<"Denied by ACL">>, - Err = xmpp:make_error(Packet, xmpp:err_forbidden(Txt, Lang)), - ejabberd_router:route(To, From, Err); + route_forbidden_error(From, To, Packet); allow -> Hosts = ?MYHOSTS, [announce_motd(Host, Packet) || Host <- Hosts] @@ -707,10 +689,7 @@ announce_motd_update(From, To, Packet) -> Access = get_access(Host), case acl:match_rule(Host, Access, From) of deny -> - Lang = xmpp:get_lang(Packet), - Txt = <<"Denied by ACL">>, - Err = xmpp:make_error(Packet, xmpp:err_forbidden(Txt, Lang)), - ejabberd_router:route(To, From, Err); + route_forbidden_error(From, To, Packet); allow -> announce_motd_update(Host, Packet) end. @@ -719,10 +698,7 @@ announce_all_hosts_motd_update(From, To, Packet) -> Access = get_access(global), case acl:match_rule(global, Access, From) of deny -> - Lang = xmpp:get_lang(Packet), - Txt = <<"Denied by ACL">>, - Err = xmpp:make_error(Packet, xmpp:err_forbidden(Txt, Lang)), - ejabberd_router:route(To, From, Err); + route_forbidden_error(From, To, Packet); allow -> Hosts = ?MYHOSTS, [announce_motd_update(Host, Packet) || Host <- Hosts] @@ -738,10 +714,7 @@ announce_motd_delete(From, To, Packet) -> Access = get_access(Host), case acl:match_rule(Host, Access, From) of deny -> - Lang = xmpp:get_lang(Packet), - Txt = <<"Denied by ACL">>, - Err = xmpp:make_error(Packet, xmpp:err_forbidden(Txt, Lang)), - ejabberd_router:route(To, From, Err); + route_forbidden_error(From, To, Packet); allow -> announce_motd_delete(Host) end. @@ -750,10 +723,7 @@ announce_all_hosts_motd_delete(From, To, Packet) -> Access = get_access(global), case acl:match_rule(global, Access, From) of deny -> - Lang = xmpp:get_lang(Packet), - Txt = <<"Denied by ACL">>, - Err = xmpp:make_error(Packet, xmpp:err_forbidden(Txt, Lang)), - ejabberd_router:route(To, From, Err); + route_forbidden_error(From, To, Packet); allow -> Hosts = ?MYHOSTS, [announce_motd_delete(Host) || Host <- Hosts] @@ -827,6 +797,12 @@ get_access(Host) -> add_store_hint(El) -> xmpp:set_subtag(El, #hint{type = store}). +-spec route_forbidden_error(jid(), jid(), stanza()) -> ok. +route_forbidden_error(From, To, Packet) -> + Lang = xmpp:get_lang(Packet), + Err = xmpp:err_forbidden(<<"Denied by ACL">>, Lang), + ejabberd_router:route_error(To, From, Packet, Err). + %%------------------------------------------------------------------------- export(LServer) -> Mod = gen_mod:db_mod(LServer, ?MODULE), diff --git a/src/mod_muc.erl b/src/mod_muc.erl index 554a21704..ab358b957 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -378,9 +378,8 @@ do_route1(Host, ServerHost, Access, _HistorySize, _RoomShaper, deny -> ErrText = <<"Only service administrators are allowed " "to send service messages">>, - Err = xmpp:make_error( - Packet, xmpp:err_forbidden(ErrText, Lang)), - ejabberd_router:route(To, From, Err) + Err = xmpp:err_forbidden(ErrText, Lang), + ejabberd_router:route_error(To, From, Packet, Err) end end; do_route1(_Host, _ServerHost, _Access, _HistorySize, _RoomShaper, @@ -409,9 +408,8 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper, false -> Lang = xmpp:get_lang(Packet), ErrText = <<"Room creation is denied by service policy">>, - Err = xmpp:make_error( - Packet, xmpp:err_forbidden(ErrText, Lang)), - ejabberd_router:route(To, From, Err) + Err = xmpp:err_forbidden(ErrText, Lang), + ejabberd_router:route_error(To, From, Packet, Err) end; false -> Lang = xmpp:get_lang(Packet), diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl index aa1c77aad..2d21365d5 100644 --- a/src/mod_muc_room.erl +++ b/src/mod_muc_room.erl @@ -167,10 +167,8 @@ normal_state({route, From, <<"">>, shaper:update(Activity#activity.message_shaper, Size), if Activity#activity.message /= undefined -> ErrText = <<"Traffic rate limit is exceeded">>, - Err = xmpp:make_error( - Packet, - xmpp:err_resource_constraint(ErrText, Lang)), - ejabberd_router:route(StateData#state.jid, From, Err), + Err = xmpp:err_resource_constraint(ErrText, Lang), + ejabberd_router:route_error(StateData#state.jid, From, Packet, Err), {next_state, normal_state, StateData}; Now >= Activity#activity.message_time + MinMessageInterval, MessageShaperInterval == 0 -> @@ -328,8 +326,8 @@ normal_state({route, From, <<"">>, end catch _:{xmpp_codec, Why} -> ErrTxt = xmpp:format_error(Why), - Err = xmpp:make_error(IQ0, xmpp:err_bad_request(ErrTxt, Lang)), - ejabberd_router:route(StateData#state.jid, From, Err) + Err = xmpp:err_bad_request(ErrTxt, Lang), + ejabberd_router:route_error(StateData#state.jid, From, IQ0, Err) end; normal_state({route, From, <<"">>, #iq{} = IQ}, StateData) -> Err = xmpp:err_bad_request(), @@ -1821,9 +1819,8 @@ add_new_user(From, Nick, Packet, StateData) -> {false, _, _, _} when NUsers >= MaxUsers orelse NUsers >= MaxAdminUsers -> Txt = <<"Too many users in this conference">>, Err = xmpp:err_resource_constraint(Txt, Lang), - ErrPacket = xmpp:make_error(Packet, Err), if not IsSubscribeRequest -> - ejabberd_router:route(UserRoomJID, From, ErrPacket), + ejabberd_router:route_error(UserRoomJID, From, Packet, Err), StateData; true -> {error, Err} @@ -1831,18 +1828,16 @@ add_new_user(From, Nick, Packet, StateData) -> {false, _, _, _} when NConferences >= MaxConferences -> Txt = <<"You have joined too many conferences">>, Err = xmpp:err_resource_constraint(Txt, Lang), - ErrPacket = xmpp:make_error(Packet, Err), if not IsSubscribeRequest -> - ejabberd_router:route(UserRoomJID, From, ErrPacket), + ejabberd_router:route_error(UserRoomJID, From, Packet, Err), StateData; true -> {error, Err} end; {false, _, _, _} -> Err = xmpp:err_service_unavailable(), - ErrPacket = xmpp:make_error(Packet, Err), if not IsSubscribeRequest -> - ejabberd_router:route(UserRoomJID, From, ErrPacket), + ejabberd_router:route_error(UserRoomJID, From, Packet, Err), StateData; true -> {error, Err} @@ -1856,9 +1851,8 @@ add_new_user(From, Nick, Packet, StateData) -> ErrText = <<"Membership is required to enter this room">>, xmpp:err_registration_required(ErrText, Lang) end, - ErrPacket = xmpp:make_error(Packet, Err), if not IsSubscribeRequest -> - ejabberd_router:route(UserRoomJID, From, ErrPacket), + ejabberd_router:route_error(UserRoomJID, From, Packet, Err), StateData; true -> {error, Err} @@ -1866,9 +1860,8 @@ add_new_user(From, Nick, Packet, StateData) -> {_, true, _, _} -> ErrText = <<"That nickname is already in use by another occupant">>, Err = xmpp:err_conflict(ErrText, Lang), - ErrPacket = xmpp:make_error(Packet, Err), if not IsSubscribeRequest -> - ejabberd_router:route(UserRoomJID, From, ErrPacket), + ejabberd_router:route_error(UserRoomJID, From, Packet, Err), StateData; true -> {error, Err} @@ -1876,9 +1869,8 @@ add_new_user(From, Nick, Packet, StateData) -> {_, _, false, _} -> ErrText = <<"That nickname is registered by another person">>, Err = xmpp:err_conflict(ErrText, Lang), - ErrPacket = xmpp:make_error(Packet, Err), if not IsSubscribeRequest -> - ejabberd_router:route(UserRoomJID, From, ErrPacket), + ejabberd_router:route_error(UserRoomJID, From, Packet, Err), StateData; true -> {error, Err} @@ -1918,9 +1910,8 @@ add_new_user(From, Nick, Packet, StateData) -> nopass -> ErrText = <<"A password is required to enter this room">>, Err = xmpp:err_not_authorized(ErrText, Lang), - ErrPacket = xmpp:make_error(Packet, Err), if not IsSubscribeRequest -> - ejabberd_router:route(UserRoomJID, From, ErrPacket), + ejabberd_router:route_error(UserRoomJID, From, Packet, Err), StateData; true -> {error, Err} @@ -1948,9 +1939,9 @@ add_new_user(From, Nick, Packet, StateData) -> {error, limit} -> ErrText = <<"Too many CAPTCHA requests">>, Err = xmpp:err_resource_constraint(ErrText, Lang), - ErrPacket = xmpp:make_error(Packet, Err), if not IsSubscribeRequest -> - ejabberd_router:route(UserRoomJID, From, ErrPacket), + ejabberd_router:route_error( + UserRoomJID, From, Packet, Err), StateData; true -> {error, Err} @@ -1958,9 +1949,9 @@ add_new_user(From, Nick, Packet, StateData) -> _ -> ErrText = <<"Unable to generate a CAPTCHA">>, Err = xmpp:err_internal_server_error(ErrText, Lang), - ErrPacket = xmpp:make_error(Packet, Err), if not IsSubscribeRequest -> - ejabberd_router:route(UserRoomJID, From, ErrPacket), + ejabberd_router:route_error( + UserRoomJID, From, Packet, Err), StateData; true -> {error, Err} @@ -1969,9 +1960,9 @@ add_new_user(From, Nick, Packet, StateData) -> _ -> ErrText = <<"Incorrect password">>, Err = xmpp:err_not_authorized(ErrText, Lang), - ErrPacket = xmpp:make_error(Packet, Err), if not IsSubscribeRequest -> - ejabberd_router:route(UserRoomJID, From, ErrPacket), + ejabberd_router:route_error( + UserRoomJID, From, Packet, Err), StateData; true -> {error, Err} diff --git a/src/mod_offline.erl b/src/mod_offline.erl index eedbcaeb1..42bc46631 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -623,9 +623,8 @@ discard_warn_sender(Msgs) -> ErrText = <<"Your contact offline message queue is " "full. The message has been discarded.">>, Lang = xmpp:get_lang(Packet), - Err = xmpp:make_error( - Packet, xmpp:err_resource_constraint(ErrText, Lang)), - ejabberd_router:route(To, From, Err) + Err = xmpp:err_resource_constraint(ErrText, Lang), + ejabberd_router:route_error(To, From, Packet, Err) end, Msgs). webadmin_page(_, Host, From 3ac73f9607034693f07a4a6ce50344d54c41629c Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Fri, 25 Nov 2016 13:02:31 +0100 Subject: [PATCH 145/151] Update dependencies --- rebar.config | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/rebar.config b/rebar.config index 95ddbc96b..80eb25a93 100644 --- a/rebar.config +++ b/rebar.config @@ -9,21 +9,21 @@ {deps, [{lager, ".*", {git, "https://github.com/basho/lager", {tag, "3.2.1"}}}, {p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.6"}}}, - {cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.4"}}}, - {fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.7"}}}, - {stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.6"}}}, - {fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.17"}}}, - {xmpp, ".*", {git, "https://github.com/processone/xmpp", {tag, "1.1.1"}}}, - {stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.7"}}}, - {esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.8"}}}, - {fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.6"}}}, - {jiffy, ".*", {git, "https://github.com/davisp/jiffy", {tag, "0.14.7"}}}, + {cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.5"}}}, + {fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.8"}}}, + {stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.7"}}}, + {fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.18"}}}, + {xmpp, ".*", {git, "https://github.com/processone/xmpp", {tag, "1.1.2"}}}, + {stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.8"}}}, + {esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.9"}}}, + {fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.7"}}}, + {jiffy, ".*", {git, "https://github.com/davisp/jiffy", {tag, "0.14.8"}}}, {p1_oauth2, ".*", {git, "https://github.com/processone/p1_oauth2", {tag, "0.6.1"}}}, {luerl, ".*", {git, "https://github.com/rvirding/luerl", {tag, "v0.2"}}}, {if_var_true, mysql, {p1_mysql, ".*", {git, "https://github.com/processone/p1_mysql", - {tag, "1.0.1"}}}}, + {tag, "1.0.2"}}}}, {if_var_true, pgsql, {p1_pgsql, ".*", {git, "https://github.com/processone/p1_pgsql", - {tag, "1.1.0"}}}}, + {tag, "1.1.1"}}}}, {if_var_true, sqlite, {sqlite3, ".*", {git, "https://github.com/processone/erlang-sqlite3", {tag, "1.1.5"}}}}, {if_var_true, pam, {p1_pam, ".*", {git, "https://github.com/processone/epam", @@ -39,7 +39,7 @@ {if_var_true, elixir, {rebar_elixir_plugin, ".*", {git, "https://github.com/processone/rebar_elixir_plugin", "0.1.0"}}}, {if_var_true, iconv, {iconv, ".*", {git, "https://github.com/processone/iconv", - {tag, "1.0.2"}}}}, + {tag, "1.0.3"}}}}, {if_var_true, tools, {meck, "0.8.*", {git, "https://github.com/eproxus/meck", {tag, "0.8.4"}}}}, {if_var_true, tools, {moka, ".*", {git, "https://github.com/processone/moka.git", From 56b30ab598ba76aa1a59041d67f743793ef877bb Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Sat, 26 Nov 2016 10:05:22 +0300 Subject: [PATCH 146/151] Improve translation of some messages --- src/ejabberd_captcha.erl | 7 ++----- src/mod_http_upload.erl | 3 +-- src/mod_irc.erl | 8 +++----- src/mod_muc_room.erl | 9 +++------ src/mod_register.erl | 9 ++++----- src/pubsub_subscription.erl | 20 ++++++++------------ src/pubsub_subscription_sql.erl | 20 ++++++++------------ 7 files changed, 29 insertions(+), 47 deletions(-) diff --git a/src/ejabberd_captcha.erl b/src/ejabberd_captcha.erl index f959d7f30..85d7595a2 100644 --- a/src/ejabberd_captcha.erl +++ b/src/ejabberd_captcha.erl @@ -100,11 +100,8 @@ create_captcha(SID, From, To, Lang, Limiter, Args) -> mk_ocr_field(Lang, CID, Type)], X = #xdata{type = form, fields = Fs}, Captcha = #xcaptcha{xdata = X}, - BodyString1 = translate:translate(Lang, - <<"Your messages to ~s are being blocked. " - "To unblock them, visit ~s">>), - BodyString = (str:format(BodyString1, - [JID, get_url(Id)])), + BodyString = {<<"Your messages to ~s are being blocked. " + "To unblock them, visit ~s">>, [JID, get_url(Id)]}, Body = xmpp:mk_text(BodyString, Lang), OOB = #oob_x{url = get_url(Id)}, Tref = erlang:send_after(?CAPTCHA_LIFETIME, ?MODULE, diff --git a/src/mod_http_upload.erl b/src/mod_http_upload.erl index 1abde4f5b..37eaad27a 100644 --- a/src/mod_http_upload.erl +++ b/src/mod_http_upload.erl @@ -579,8 +579,7 @@ process_iq(_From, #iq{}, _State) -> create_slot(#state{service_url = undefined, max_size = MaxSize}, JID, File, Size, _ContentType, Lang) when MaxSize /= infinity, Size > MaxSize -> - Text = <<"File larger than ", (integer_to_binary(MaxSize))/binary, - " Bytes.">>, + Text = {<<"File larger than ~w bytes">>, [MaxSize]}, ?INFO_MSG("Rejecting file ~s from ~s (too large: ~B bytes)", [File, jid:to_string(JID), Size]), {error, xmpp:err_not_acceptable(Text, Lang)}; diff --git a/src/mod_irc.erl b/src/mod_irc.erl index 77bf34801..f43a6653d 100644 --- a/src/mod_irc.erl +++ b/src/mod_irc.erl @@ -655,12 +655,10 @@ adhoc_join(From, To, #adhoc_command{lang = Lang, xdata = X} = Request) -> RoomJID = jid:make(<>, To#jid.server), Reason = translate:translate(Lang, <<"Join the IRC channel here.">>), - Body = str:format( - translate:translate( - Lang, <<"Join the IRC channel in this Jabber ID: ~s">>), - [jid:to_string(RoomJID)]), + BodyTxt = {<<"Join the IRC channel in this Jabber ID: ~s">>, + [jid:to_string(RoomJID)]}, Invite = #message{ - body = xmpp:mk_text(Body, Lang), + body = xmpp:mk_text(BodyTxt, Lang), sub_els = [#muc_user{ invites = [#muc_invite{from = From, reason = Reason}]}, diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl index 2d21365d5..957220540 100644 --- a/src/mod_muc_room.erl +++ b/src/mod_muc_room.erl @@ -2723,11 +2723,8 @@ find_changed_items(UJID, UAffiliation, URole, Nick /= <<"">> -> case find_jids_by_nick(Nick, StateData) of [] -> - ErrText = str:format( - translate:translate( - Lang, - <<"Nickname ~s does not exist in the room">>), - [Nick]), + ErrText = {<<"Nickname ~s does not exist in the room">>, + [Nick]}, throw({error, xmpp:err_not_acceptable(ErrText, Lang)}); JIDList -> JIDList @@ -3299,7 +3296,7 @@ set_config(Opts, Config, ServerHost, Lang) -> {0, undefined} -> ?ERROR_MSG("set_room_option hook failed for " "option '~s' with value ~p", [O, V]), - Txt = <<"Failed to process option '", O/binary, "'">>, + Txt = {<<"Failed to process option '~s'">>, [O]}, {error, xmpp:err_internal_server_error(Txt, Lang)}; {Pos, Val} -> setelement(Pos, C, Val) diff --git a/src/mod_register.erl b/src/mod_register.erl index 3cec0660b..ba261e0f3 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -202,13 +202,13 @@ process_iq(#iq{type = get, from = From, to = To, id = ID, lang = Lang} = IQ, _ -> {false, <<"">>} end, + Instr = translate:translate( + Lang, <<"Choose a username and password to register " + "with this server">>), if IsCaptchaEnabled and not IsRegistered -> TopInstr = translate:translate( Lang, <<"You need a client that supports x:data " "and CAPTCHA to register">>), - Instr = translate:translate( - Lang, <<"Choose a username and password to register " - "with this server">>), UField = #xdata_field{type = 'text-single', label = translate:translate(Lang, <<"User">>), var = <<"username">>, @@ -234,10 +234,9 @@ process_iq(#iq{type = get, from = From, to = To, id = ID, lang = Lang} = IQ, IQ, xmpp:err_internal_server_error(ErrText, Lang)) end; true -> - Instr = <<"Choose a username and password to register with this server">>, xmpp:make_iq_result( IQ, - #register{instructions = translate:translate(Lang, Instr), + #register{instructions = Instr, username = Username, password = <<"">>, registered = IsRegistered}) diff --git a/src/pubsub_subscription.erl b/src/pubsub_subscription.erl index b6986b69d..077ac5ba9 100644 --- a/src/pubsub_subscription.erl +++ b/src/pubsub_subscription.erl @@ -206,16 +206,14 @@ val_xfield(digest_frequency = Opt, [Val]) -> case catch binary_to_integer(Val) of N when is_integer(N) -> N; _ -> - Txt = <<"Value of '~s' should be integer">>, - ErrTxt = (str:format(Txt, [Opt])), - {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} + Txt = {<<"Value of '~s' should be integer">>, [Opt]}, + {error, xmpp:err_not_acceptable(Txt, ?MYLANG)} end; val_xfield(expire = Opt, [Val]) -> try xmpp_util:decode_timestamp(Val) catch _:{bad_timestamp, _} -> - Txt = <<"Value of '~s' should be datetime string">>, - ErrTxt = (str:format(Txt, [Opt])), - {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} + Txt = {<<"Value of '~s' should be datetime string">>, [Opt]}, + {error, xmpp:err_not_acceptable(Txt, ?MYLANG)} end; val_xfield(include_body = Opt, [Val]) -> xopt_to_bool(Opt, Val); val_xfield(show_values, Vals) -> Vals; @@ -226,9 +224,8 @@ val_xfield(subscription_depth = Opt, [Depth]) -> case catch binary_to_integer(Depth) of N when is_integer(N) -> N; _ -> - Txt = <<"Value of '~s' should be integer">>, - ErrTxt = (str:format(Txt, [Opt])), - {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} + Txt = {<<"Value of '~s' should be integer">>, [Opt]}, + {error, xmpp:err_not_acceptable(Txt, ?MYLANG)} end. %% Convert XForm booleans to Erlang booleans. @@ -237,9 +234,8 @@ xopt_to_bool(_, <<"1">>) -> true; xopt_to_bool(_, <<"false">>) -> false; xopt_to_bool(_, <<"true">>) -> true; xopt_to_bool(Option, _) -> - Txt = <<"Value of '~s' should be boolean">>, - ErrTxt = (str:format(Txt, [Option])), - {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)}. + Txt = {<<"Value of '~s' should be boolean">>, [Option]}, + {error, xmpp:err_not_acceptable(Txt, ?MYLANG)}. %% Return a field for an XForm for Key, with data filled in, if %% applicable, from Options. diff --git a/src/pubsub_subscription_sql.erl b/src/pubsub_subscription_sql.erl index da72cc96e..fddfe881e 100644 --- a/src/pubsub_subscription_sql.erl +++ b/src/pubsub_subscription_sql.erl @@ -171,16 +171,14 @@ val_xfield(digest_frequency = Opt, [Val]) -> case catch binary_to_integer(Val) of N when is_integer(N) -> N; _ -> - Txt = <<"Value of '~s' should be integer">>, - ErrTxt = (str:format(Txt, [Opt])), - {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} + Txt = {<<"Value of '~s' should be integer">>, [Opt]}, + {error, xmpp:err_not_acceptable(Txt, ?MYLANG)} end; val_xfield(expire = Opt, [Val]) -> try xmpp_util:decode_timestamp(Val) catch _:{bad_timestamp, _} -> - Txt = <<"Value of '~s' should be datetime string">>, - ErrTxt = (str:format(Txt, [Opt])), - {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} + Txt = {<<"Value of '~s' should be datetime string">>, [Opt]}, + {error, xmpp:err_not_acceptable(Txt, ?MYLANG)} end; val_xfield(include_body = Opt, [Val]) -> xopt_to_bool(Opt, Val); val_xfield(show_values, Vals) -> Vals; @@ -191,9 +189,8 @@ val_xfield(subscription_depth = Opt, [Depth]) -> case catch binary_to_integer(Depth) of N when is_integer(N) -> N; _ -> - Txt = <<"Value of '~s' should be integer">>, - ErrTxt = (str:format(Txt, [Opt])), - {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)} + Txt = {<<"Value of '~s' should be integer">>, [Opt]}, + {error, xmpp:err_not_acceptable(Txt, ?MYLANG)} end. %% Convert XForm booleans to Erlang booleans. @@ -202,9 +199,8 @@ xopt_to_bool(_, <<"1">>) -> true; xopt_to_bool(_, <<"false">>) -> false; xopt_to_bool(_, <<"true">>) -> true; xopt_to_bool(Option, _) -> - Txt = <<"Value of '~s' should be boolean">>, - ErrTxt = (str:format(Txt, [Option])), - {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)}. + Txt = {<<"Value of '~s' should be boolean">>, [Option]}, + {error, xmpp:err_not_acceptable(Txt, ?MYLANG)}. %% Return a field for an XForm for Key, with data filled in, if %% applicable, from Options. From fc7e52df71b0b02fb2a0f34fcb5db03e04cfac22 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Mon, 28 Nov 2016 17:15:57 +0100 Subject: [PATCH 147/151] Adds optional post_install and pre_uninstall hooks (thanks Igor Manturov Jr.)(#1300) --- src/ext_mod.erl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ext_mod.erl b/src/ext_mod.erl index 071fb827c..5b970623b 100644 --- a/src/ext_mod.erl +++ b/src/ext_mod.erl @@ -170,7 +170,10 @@ install(Package) when is_binary(Package) -> ok -> code:add_patha(module_ebin_dir(Module)), ejabberd_config:reload_file(), - ok; + case erlang:function_exported(Module, post_install, 0) of + true -> Module:post_install(); + _ -> ok + end; Error -> delete_path(module_lib_dir(Module)), Error @@ -183,6 +186,10 @@ uninstall(Package) when is_binary(Package) -> case installed(Package) of true -> Module = jlib:binary_to_atom(Package), + case erlang:function_exported(Module, pre_uninstall, 0) of + true -> Module:pre_uninstall(); + _ -> ok + end, [catch gen_mod:stop_module(Host, Module) || Host <- ejabberd_config:get_myhosts()], code:purge(Module), From 95a4b1b266355c19de0be4574803f486c0c94c05 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Wed, 30 Nov 2016 10:31:36 +0100 Subject: [PATCH 148/151] Cleanup admin_extra, add few functions --- src/mod_admin_extra.erl | 187 ++++++++++++++++++++++++++++++++++------ 1 file changed, 160 insertions(+), 27 deletions(-) diff --git a/src/mod_admin_extra.erl b/src/mod_admin_extra.erl index 3c51e8c69..4b117d50a 100644 --- a/src/mod_admin_extra.erl +++ b/src/mod_admin_extra.erl @@ -30,24 +30,53 @@ -include("logger.hrl"). --export([start/2, stop/1, compile/1, get_cookie/0, - remove_node/1, set_password/3, check_password/3, - check_password_hash/4, delete_old_users/1, - delete_old_users_vhost/2, ban_account/3, +-export([start/2, stop/1, mod_opt_type/1, + get_commands_spec/0, depends/2]). + +% Commands API +-export([ + % Adminsys + compile/1, get_cookie/0, remove_node/1, export2sql/2, + restart_module/2, + + % Sessions num_active_users/2, num_resources/2, resource_num/3, kick_session/4, status_num/2, status_num/1, status_list/2, status_list/1, connected_users_info/0, connected_users_vhost/1, set_presence/7, - user_sessions_info/2, set_nickname/3, get_vcard/3, + get_presence/2, user_sessions_info/2, get_last/2, + + % Accounts + set_password/3, check_password_hash/4, delete_old_users/1, + delete_old_users_vhost/2, ban_account/3, check_password/3, + + % vCard + set_nickname/3, get_vcard/3, get_vcard/4, get_vcard_multi/4, set_vcard/4, - set_vcard/5, add_rosteritem/7, delete_rosteritem/4, + set_vcard/5, + + % Roster + add_rosteritem/7, delete_rosteritem/4, process_rosteritems/5, get_roster/2, push_roster/3, - push_roster_all/1, push_alltoall/2, get_last/2, - private_get/4, private_set/3, srg_create/5, + push_roster_all/1, push_alltoall/2, + + % Private storage + private_get/4, private_set/3, + + % Shared roster + srg_create/5, srg_delete/2, srg_list/1, srg_get_info/2, srg_get_members/2, srg_user_add/4, srg_user_del/4, - send_message/5, send_stanza/3, send_stanza_c2s/4, privacy_set/3, - stats/1, stats/2, mod_opt_type/1, get_commands_spec/0, depends/2]). + + % Send message + send_message/5, send_stanza/3, send_stanza_c2s/4, + + % Privacy list + privacy_set/3, + + % Stats + stats/1, stats/2 + ]). -include("ejabberd.hrl"). @@ -125,9 +154,30 @@ get_commands_spec() -> result = {res, rescode}, result_example = ok, result_desc = "Status code: 0 on success, 1 otherwise"}, + #ejabberd_commands{name = export2sql, tags = [mnesia], + desc = "Export Mnesia tables to files in directory", + module = ?MODULE, function = export2sql, + args = [{host, string}, {path, string}], + args_example = ["myserver.com","/tmp/export/sql"], + args_desc = ["Server name", "File to write sql export"], + result = {res, rescode}, + result_example = ok, + result_desc = "Status code: 0 on success, 1 otherwise"}, + #ejabberd_commands{name = restart_module, tags = [erlang], + desc = "Stop an ejabberd module, reload code and start", + module = ?MODULE, function = restart_module, + args = [{host, binary}, {module, binary}], + args_example = ["myserver.com","mod_admin_extra"], + args_desc = ["Server name", "Module to restart"], + result = {res, integer}, + result_example = 0, + result_desc = "Returns integer code:\n" + " - 0: code reloaded, module restarted\n" + " - 1: error: module not loaded\n" + " - 2: code not reloaded, but module restarted"}, #ejabberd_commands{name = num_active_users, tags = [accounts, stats], desc = "Get number of users active in the last days", - policy = admin, + policy = admin, module = ?MODULE, function = num_active_users, args = [{host, binary}, {days, integer}], args_example = [<<"myserver.com">>, 3], @@ -236,7 +286,7 @@ get_commands_spec() -> result_desc = "Status code: 0 on success, 1 otherwise"}, #ejabberd_commands{name = status_num_host, tags = [session, stats], desc = "Number of logged users with this status in host", - policy = admin, + policy = admin, module = ?MODULE, function = status_num, args = [{host, binary}, {status, binary}], args_example = [<<"myserver.com">>, <<"dnd">>], @@ -246,7 +296,7 @@ get_commands_spec() -> result_desc = "Number of connected sessions with given status type"}, #ejabberd_commands{name = status_num, tags = [session, stats], desc = "Number of logged users with this status", - policy = admin, + policy = admin, module = ?MODULE, function = status_num, args = [{status, binary}], args_example = [<<"dnd">>], @@ -298,11 +348,11 @@ get_commands_spec() -> ]}} }}}, #ejabberd_commands{name = connected_users_vhost, - tags = [session], - desc = "Get the list of established sessions in a vhost", - module = ?MODULE, function = connected_users_vhost, - args = [{host, binary}], - result = {connected_users_vhost, {list, {sessions, string}}}}, + tags = [session], + desc = "Get the list of established sessions in a vhost", + module = ?MODULE, function = connected_users_vhost, + args = [{host, binary}], + result = {connected_users_vhost, {list, {sessions, string}}}}, #ejabberd_commands{name = user_sessions_info, tags = [session], desc = "Get information about all sessions of a user", @@ -323,6 +373,28 @@ get_commands_spec() -> ]}} }}}, + #ejabberd_commands{name = get_presence, tags = [session], + desc = + "Retrieve the resource with highest priority, " + "and its presence (show and status message) " + "for a given user.", + longdesc = + "The 'jid' value contains the user jid " + "with resource.\nThe 'show' value contains " + "the user presence flag. It can take " + "limited values:\n - available\n - chat " + "(Free for chat)\n - away\n - dnd (Do " + "not disturb)\n - xa (Not available, " + "extended away)\n - unavailable (Not " + "connected)\n\n'status' is a free text " + "defined by the user client.", + module = ?MODULE, function = get_presence, + args = [{user, binary}, {server, binary}], + result = + {presence, + {tuple, + [{jid, string}, {show, string}, + {status, string}]}}}, #ejabberd_commands{name = set_presence, tags = [session], desc = "Set presence of a session", @@ -534,7 +606,7 @@ get_commands_spec() -> #ejabberd_commands{name = get_offline_count, tags = [offline], desc = "Get the number of unread offline messages", - policy = user, + policy = user, module = mod_offline, function = count_offline_messages, args = [], result = {value, integer}}, @@ -562,13 +634,13 @@ get_commands_spec() -> #ejabberd_commands{name = stats, tags = [stats], desc = "Get statistical value: registeredusers onlineusers onlineusersnode uptimeseconds processes", - policy = admin, + policy = admin, module = ?MODULE, function = stats, args = [{name, binary}], result = {stat, integer}}, #ejabberd_commands{name = stats_host, tags = [stats], desc = "Get statistical value for this host: registeredusers onlineusers", - policy = admin, + policy = admin, module = ?MODULE, function = stats, args = [{name, binary}, {host, binary}], result = {stat, integer}} @@ -589,6 +661,48 @@ remove_node(Node) -> mnesia:del_table_copy(schema, list_to_atom(Node)), ok. +restart_module(Host, Module) when is_binary(Module) -> + restart_module(Host, jlib:binary_to_atom(Module)); +restart_module(Host, Module) when is_atom(Module) -> + List = gen_mod:loaded_modules_with_opts(Host), + case proplists:get_value(Module, List) of + undefined -> + % not a running module, force code reload anyway + code:purge(Module), + code:delete(Module), + code:load_file(Module), + 1; + Opts -> + gen_mod:stop_module(Host, Module), + case code:soft_purge(Module) of + true -> + code:delete(Module), + code:load_file(Module), + gen_mod:start_module(Host, Module, Opts), + 0; + false -> + gen_mod:start_module(Host, Module, Opts), + 2 + end + end. + +export2sql(Host, Directory) -> + Tables = [{export_last, last}, + {export_offline, offline}, + {export_passwd, passwd}, + {export_private_storage, private_storage}, + {export_roster, roster}, + {export_vcard, vcard}, + {export_vcard_search, vcard_search}], + Export = fun({TableFun, Table}) -> + Filename = filename:join([Directory, atom_to_list(Table)++".txt"]), + io:format("Trying to export Mnesia table '~p' on Host '~s' to file '~s'~n", [Table, Host, Filename]), + Res = (catch ejd2sql:TableFun(Host, Filename)), + io:format(" Result: ~p~n", [Res]) + end, + lists:foreach(Export, Tables), + ok. + %%% %%% Accounts %%% @@ -607,10 +721,10 @@ check_password_hash(User, Host, PasswordHash, HashMethod) -> {A, _} when is_tuple(A) -> scrammed; {_, <<"md5">>} -> get_md5(AccountPass); {_, <<"sha">>} -> get_sha(AccountPass); - {_, Method} -> + {_, Method} -> ?ERROR_MSG("check_password_hash called " - "with hash method: ~p", [Method]), - undefined + "with hash method: ~p", [Method]), + undefined end, case AccountPassHash of scrammed -> @@ -628,10 +742,11 @@ get_sha(AccountPass) -> || X <- binary_to_list(p1_sha:sha1(AccountPass))]). num_active_users(Host, Days) -> - list_last_activity(Host, true, Days). + DB_Type = gen_mod:db_type(Host, mod_last), + list_last_activity(Host, true, Days, DB_Type). %% Code based on ejabberd/src/web/ejabberd_web_admin.erl -list_last_activity(Host, Integral, Days) -> +list_last_activity(Host, Integral, Days, mnesia) -> TimeStamp = p1_time_compat:system_time(seconds), TS = TimeStamp - Days * 86400, case catch mnesia:dirty_select( @@ -657,7 +772,11 @@ list_last_activity(Host, Integral, Days) -> end, lists:nth(Days, Hist ++ Tail) end - end. + end; +list_last_activity(_Host, _Integral, _Days, DB_Type) -> + throw({error, iolist_to_binary(io_lib:format("Unsupported backend: ~p", + [DB_Type]))}). + histogram(Values, Integral) -> histogram(lists:sort(Values), Integral, 0, 0, []). histogram([H | T], Integral, Current, Count, Hist) when Current == H -> @@ -882,6 +1001,20 @@ stringize(String) -> %% Replace newline characters with other code ejabberd_regexp:greplace(String, <<"\n">>, <<"\\n">>). +get_presence(U, S) -> + Pids = [ejabberd_sm:get_session_pid(U, S, R) + || R <- ejabberd_sm:get_user_resources(U, S)], + OnlinePids = [Pid || Pid <- Pids, Pid=/=none], + case OnlinePids of + [] -> + {jid:to_string({U, S, <<>>}), <<"unavailable">>, <<"">>}; + [SessionPid|_] -> + {_User, Resource, Show, Status} = + ejabberd_c2s:get_presence(SessionPid), + FullJID = jid:to_string({U, S, Resource}), + {FullJID, Show, Status} + end. + set_presence(User, Host, Resource, Type, Show, Status, Priority) when is_integer(Priority) -> BPriority = integer_to_binary(Priority), From 92db9ff10546e4a033621fbfd7d66d2aa3bf55e8 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Wed, 30 Nov 2016 11:09:17 +0100 Subject: [PATCH 149/151] Improve handling of mnesia schema --- src/acl.erl | 4 +- src/ejabberd_auth_anonymous.erl | 2 +- src/ejabberd_auth_mnesia.erl | 4 +- src/ejabberd_commands.erl | 2 +- src/ejabberd_config.erl | 4 +- src/ejabberd_local.erl | 2 +- src/ejabberd_mnesia.erl | 169 ++++++++++++++++++++++++++++++ src/ejabberd_oauth_mnesia.erl | 2 +- src/ejabberd_router.erl | 2 +- src/ejabberd_router_multicast.erl | 2 +- src/ejabberd_s2s.erl | 4 +- src/ejabberd_sm_mnesia.erl | 4 +- src/ejabberd_sql_sup.erl | 2 +- src/mod_announce_mnesia.erl | 4 +- src/mod_bosh.erl | 2 +- src/mod_caps_mnesia.erl | 2 +- src/mod_carboncopy_mnesia.erl | 2 +- src/mod_http_bind.erl | 2 +- src/mod_irc_mnesia.erl | 2 +- src/mod_last_mnesia.erl | 2 +- src/mod_mam_mnesia.erl | 4 +- src/mod_muc.erl | 2 +- src/mod_muc_mnesia.erl | 4 +- src/mod_multicast.erl | 2 +- src/mod_offline_mnesia.erl | 2 +- src/mod_privacy_mnesia.erl | 2 +- src/mod_private_mnesia.erl | 2 +- src/mod_proxy65_sm.erl | 2 +- src/mod_pubsub.erl | 2 +- src/mod_register.erl | 2 +- src/mod_roster_mnesia.erl | 4 +- src/mod_shared_roster_mnesia.erl | 4 +- src/mod_sip_registrar.erl | 2 +- src/mod_vcard_mnesia.erl | 4 +- src/mod_vcard_xupdate_mnesia.erl | 2 +- src/node_flat.erl | 4 +- src/nodetree_tree.erl | 2 +- src/pubsub_index.erl | 2 +- src/pubsub_migrate.erl | 4 +- src/pubsub_subscription.erl | 2 +- src/shaper.erl | 2 +- 41 files changed, 222 insertions(+), 53 deletions(-) create mode 100644 src/ejabberd_mnesia.erl diff --git a/src/acl.erl b/src/acl.erl index 595228ee9..e00aaa5d3 100644 --- a/src/acl.erl +++ b/src/acl.erl @@ -76,11 +76,11 @@ -export_type([acl/0]). start() -> - mnesia:create_table(acl, + ejabberd_mnesia:create(?MODULE, acl, [{ram_copies, [node()]}, {type, bag}, {local_content, true}, {attributes, record_info(fields, acl)}]), - mnesia:create_table(access, + ejabberd_mnesia:create(?MODULE, access, [{ram_copies, [node()]}, {local_content, true}, {attributes, record_info(fields, access)}]), diff --git a/src/ejabberd_auth_anonymous.erl b/src/ejabberd_auth_anonymous.erl index c84321ad9..e0c4d471f 100644 --- a/src/ejabberd_auth_anonymous.erl +++ b/src/ejabberd_auth_anonymous.erl @@ -59,7 +59,7 @@ start(Host) -> %% TODO: Check cluster mode - mnesia:create_table(anonymous, [{ram_copies, [node()]}, + ejabberd_mnesia:create(?MODULE, anonymous, [{ram_copies, [node()]}, {type, bag}, {attributes, record_info(fields, anonymous)}]), %% The hooks are needed to add / remove users from the anonymous tables diff --git a/src/ejabberd_auth_mnesia.erl b/src/ejabberd_auth_mnesia.erl index dee3774db..eac19f024 100644 --- a/src/ejabberd_auth_mnesia.erl +++ b/src/ejabberd_auth_mnesia.erl @@ -66,10 +66,10 @@ start(Host) -> ok. init_db() -> - mnesia:create_table(passwd, + ejabberd_mnesia:create(?MODULE, passwd, [{disc_copies, [node()]}, {attributes, record_info(fields, passwd)}]), - mnesia:create_table(reg_users_counter, + ejabberd_mnesia:create(?MODULE, reg_users_counter, [{ram_copies, [node()]}, {attributes, record_info(fields, reg_users_counter)}]). diff --git a/src/ejabberd_commands.erl b/src/ejabberd_commands.erl index 6172b18ed..223163a2b 100644 --- a/src/ejabberd_commands.erl +++ b/src/ejabberd_commands.erl @@ -281,7 +281,7 @@ init() -> record_info(fields, ejabberd_commands)) catch exit:{aborted, {no_exists, _}} -> ok end, - mnesia:create_table(ejabberd_commands, + ejabberd_mnesia:create(?MODULE, ejabberd_commands, [{ram_copies, [node()]}, {local_content, true}, {attributes, record_info(fields, ejabberd_commands)}, diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index af26767f8..e930e36b1 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -104,7 +104,7 @@ mnesia_init() -> _ -> ok end, - mnesia:create_table(local_config, + ejabberd_mnesia:create(?MODULE, local_config, [{ram_copies, [node()]}, {local_content, true}, {attributes, record_info(fields, local_config)}]), @@ -1300,7 +1300,7 @@ convert_table_to_binary(Tab, Fields, Type, DetectFun, ConvertFun) -> ?INFO_MSG("Converting '~s' table from strings to binaries.", [Tab]), TmpTab = list_to_atom(atom_to_list(Tab) ++ "_tmp_table"), catch mnesia:delete_table(TmpTab), - case mnesia:create_table(TmpTab, + case ejabberd_mnesia:create(?MODULE, TmpTab, [{disc_only_copies, [node()]}, {type, Type}, {local_content, true}, diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index 3406192f7..a5ee6a242 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -205,7 +205,7 @@ init([]) -> ?MYHOSTS), catch ets:new(?IQTABLE, [named_table, public]), update_table(), - mnesia:create_table(iq_response, + ejabberd_mnesia:create(?MODULE, iq_response, [{ram_copies, [node()]}, {attributes, record_info(fields, iq_response)}]), mnesia:add_table_copy(iq_response, node(), ram_copies), diff --git a/src/ejabberd_mnesia.erl b/src/ejabberd_mnesia.erl new file mode 100644 index 000000000..f244d518f --- /dev/null +++ b/src/ejabberd_mnesia.erl @@ -0,0 +1,169 @@ +%%%---------------------------------------------------------------------- +%%% File : mnesia_mnesia.erl +%%% Author : Christophe Romain +%%% Purpose : Handle configurable mnesia schema +%%% Created : 17 Nov 2016 by Christophe Romain +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2016 ProcessOne +%%% +%%% This program is free software; you can redistribute it and/or +%%% modify it under the terms of the GNU General Public License as +%%% published by the Free Software Foundation; either version 2 of the +%%% License, or (at your option) any later version. +%%% +%%% This program is distributed in the hope that it will be useful, +%%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%%% General Public License for more details. +%%% +%%% You should have received a copy of the GNU General Public License along +%%% with this program; if not, write to the Free Software Foundation, Inc., +%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +%%% +%%%---------------------------------------------------------------------- + +%%% This module should be used everywhere ejabberd creates a mnesia table +%%% to make the schema customizable without code change +%%% Just apply this change in ejabberd modules +%%% s/ejabberd_mnesia:create(?MODULE, /ejabberd_mnesia:create(?MODULE, / + +-module(ejabberd_mnesia). +-author('christophe.romain@process-one.net'). +-export([create/3, reset/2, update/2]). + +-define(STORAGE_TYPES, [disc_copies, disc_only_copies, ram_copies]). +-define(NEED_RESET, [local_content, type]). + +create(Module, Name, TabDef) -> + Schema = schema(Module, Name, TabDef), + {attributes, Attrs} = lists:keyfind(attributes, 1, Schema), + case catch mnesia:table_info(Name, attributes) of + {'EXIT', _} -> + ejabberd_mnesia:create(?MODULE, Name, Schema); + Attrs -> + case need_reset(TabDef, Schema) of + true -> reset(Name, Schema); + false -> update(Name, Schema) + end; + OldAttrs -> + Fun = case lists:member({transform,1}, Module:module_info(exports)) of + true -> fun(Old) -> Module:transform(Old) end; + false -> fun(Old) -> transform(OldAttrs, Attrs, Old) end + end, + mnesia:transform_table(Name, Fun, Attrs) + end. + +reset(Name, TabDef) -> + mnesia:delete_table(Name), + ejabberd_mnesia:create(?MODULE, Name, TabDef). + +update(Name, TabDef) -> + Storage = mnesia:table_info(Name, storage_type), + NewStorage = lists:foldl( + fun({Key, _}, Acc) -> + case lists:member(Key, ?STORAGE_TYPES) of + true -> Key; + false -> Acc + end + end, Storage, TabDef), + R1 = if Storage=/=NewStorage -> + mnesia:change_table_copy_type(Name, node(), NewStorage); + true -> + {atomic, ok} + end, + Indexes = mnesia:table_info(Name, index), + NewIndexes = proplists:get_value(index, TabDef, []), + [mnesia:del_table_index(Name, Attr) + || Attr <- Indexes--NewIndexes], + R2 = [mnesia:add_table_index(Name, Attr) + || Attr <- NewIndexes--Indexes], + lists:foldl( + fun({atomic, ok}, Acc) -> Acc; + (Error, _Acc) -> Error + end, {atomic, ok}, [R1|R2]). + +% +% utilities +% + +schema(Module, Name, TabDef) -> + case parse(Module) of + {ok, CustomDefs} -> + case lists:keyfind(Name, 1, CustomDefs) of + {Name, CustomDef} -> merge(TabDef, CustomDef); + _ -> TabDef + end; + _ -> + TabDef + end. + +merge(TabDef, CustomDef) -> + {CustomKeys, _} = lists:unzip(CustomDef), + CleanDef = lists:foldl( + fun(Elem, Acc) -> + case lists:member(Elem, ?STORAGE_TYPES) of + true -> + lists:foldl( + fun(Key, CleanAcc) -> + lists:keydelete(Key, 1, CleanAcc) + end, Acc, ?STORAGE_TYPES); + false -> + Acc + end + end, TabDef, CustomKeys), + lists:ukeymerge(1, + lists:ukeysort(1, CustomDef), + lists:ukeysort(1, CleanDef)). + +parse(Module) -> + Path = case os:getenv("EJABBERD_SCHEMA_PATH") of + false -> + case code:priv_dir(ejabberd) of + {error, _} -> "schema"; % $SPOOL_DIR/schema + Priv -> filename:join(Priv, "schema") + end; + CustomDir -> + CustomDir + end, + File = filename:join(Path, atom_to_list(Module)++".mnesia"), + case file:consult(File) of + {ok, Terms} -> parse(Terms, []); + Error -> Error + end. + +parse([], Acc) -> + {ok, lists:reverse(Acc)}; +parse([{Name, Storage, TabDef}|Tail], Acc) + when is_atom(Name), + is_atom(Storage), + is_list(TabDef) -> + NewDef = case lists:member(Storage, ?STORAGE_TYPES) of + true -> [{Storage, [node()]} | TabDef]; + false -> TabDef + end, + parse(Tail, [{Name, NewDef} | Acc]); +parse([Other|_], _) -> + {error, {invalid, Other}}. + +need_reset(FromDef, ToDef) -> + ValuesF = [lists:keyfind(Key, 1, FromDef) || Key <- ?NEED_RESET], + ValuesT = [lists:keyfind(Key, 1, ToDef) || Key <- ?NEED_RESET], + lists:foldl( + fun({Val, Val}, Acc) -> Acc; + ({_, false}, Acc) -> Acc; + ({_, _}, _) -> true + end, false, lists:zip(ValuesF, ValuesT)). + +transform(OldAttrs, Attrs, Old) -> + [Name|OldValues] = tuple_to_list(Old), + Before = lists:zip(OldAttrs, OldValues), + After = lists:foldl( + fun(Attr, Acc) -> + case lists:keyfind(Attr, 1, Before) of + false -> [{Attr, undefined}|Acc]; + Value -> [Value|Acc] + end + end, [], lists:reverse(Attrs)), + {Attrs, NewRecord} = lists:unzip(After), + list_to_tuple([Name|NewRecord]). diff --git a/src/ejabberd_oauth_mnesia.erl b/src/ejabberd_oauth_mnesia.erl index a23f443ed..bdd2d0edd 100644 --- a/src/ejabberd_oauth_mnesia.erl +++ b/src/ejabberd_oauth_mnesia.erl @@ -34,7 +34,7 @@ -include("ejabberd_oauth.hrl"). init() -> - mnesia:create_table(oauth_token, + ejabberd_mnesia:create(?MODULE, oauth_token, [{disc_copies, [node()]}, {attributes, record_info(fields, oauth_token)}]), diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl index c6d919097..33093abb0 100644 --- a/src/ejabberd_router.erl +++ b/src/ejabberd_router.erl @@ -280,7 +280,7 @@ process_iq(From, To, El) -> %%-------------------------------------------------------------------- init([]) -> update_tables(), - mnesia:create_table(route, + ejabberd_mnesia:create(?MODULE, route, [{ram_copies, [node()]}, {type, bag}, {attributes, record_info(fields, route)}]), diff --git a/src/ejabberd_router_multicast.erl b/src/ejabberd_router_multicast.erl index 283bcac25..c7a190670 100644 --- a/src/ejabberd_router_multicast.erl +++ b/src/ejabberd_router_multicast.erl @@ -115,7 +115,7 @@ unregister_route(Domain) -> %% Description: Initiates the server %%-------------------------------------------------------------------- init([]) -> - mnesia:create_table(route_multicast, + ejabberd_mnesia:create(?MODULE, route_multicast, [{ram_copies, [node()]}, {type, bag}, {attributes, diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl index 97aef3cab..4df1761cb 100644 --- a/src/ejabberd_s2s.erl +++ b/src/ejabberd_s2s.erl @@ -236,14 +236,14 @@ make_key({From, To}, StreamID) -> init([]) -> update_tables(), - mnesia:create_table(s2s, + ejabberd_mnesia:create(?MODULE, s2s, [{ram_copies, [node()]}, {type, bag}, {attributes, record_info(fields, s2s)}]), mnesia:add_table_copy(s2s, node(), ram_copies), mnesia:subscribe(system), ejabberd_commands:register_commands(get_commands_spec()), - mnesia:create_table(temporarily_blocked, + ejabberd_mnesia:create(?MODULE, temporarily_blocked, [{ram_copies, [node()]}, {attributes, record_info(fields, temporarily_blocked)}]), {ok, #state{}}. diff --git a/src/ejabberd_sm_mnesia.erl b/src/ejabberd_sm_mnesia.erl index 491872aee..ed38ceee9 100644 --- a/src/ejabberd_sm_mnesia.erl +++ b/src/ejabberd_sm_mnesia.erl @@ -80,10 +80,10 @@ get_sessions(LUser, LServer, LResource) -> %%%=================================================================== init([]) -> update_tables(), - mnesia:create_table(session, + ejabberd_mnesia:create(?MODULE, session, [{ram_copies, [node()]}, {attributes, record_info(fields, session)}]), - mnesia:create_table(session_counter, + ejabberd_mnesia:create(?MODULE, session_counter, [{ram_copies, [node()]}, {attributes, record_info(fields, session_counter)}]), mnesia:add_table_index(session, usr), diff --git a/src/ejabberd_sql_sup.erl b/src/ejabberd_sql_sup.erl index 29099fce3..93bc10ac5 100644 --- a/src/ejabberd_sql_sup.erl +++ b/src/ejabberd_sql_sup.erl @@ -49,7 +49,7 @@ -record(sql_pool, {host, pid}). start_link(Host) -> - mnesia:create_table(sql_pool, + ejabberd_mnesia:create(?MODULE, sql_pool, [{ram_copies, [node()]}, {type, bag}, {local_content, true}, {attributes, record_info(fields, sql_pool)}]), diff --git a/src/mod_announce_mnesia.erl b/src/mod_announce_mnesia.erl index 23b2a5ba3..47753965d 100644 --- a/src/mod_announce_mnesia.erl +++ b/src/mod_announce_mnesia.erl @@ -21,11 +21,11 @@ %%% API %%%=================================================================== init(_Host, _Opts) -> - mnesia:create_table(motd, + ejabberd_mnesia:create(?MODULE, motd, [{disc_copies, [node()]}, {attributes, record_info(fields, motd)}]), - mnesia:create_table(motd_users, + ejabberd_mnesia:create(?MODULE, motd_users, [{disc_copies, [node()]}, {attributes, record_info(fields, motd_users)}]), diff --git a/src/mod_bosh.erl b/src/mod_bosh.erl index 13d85b3cb..038218739 100644 --- a/src/mod_bosh.erl +++ b/src/mod_bosh.erl @@ -240,7 +240,7 @@ setup_database() -> _ -> ok end, - mnesia:create_table(bosh, + ejabberd_mnesia:create(?MODULE, bosh, [{ram_copies, [node()]}, {local_content, true}, {attributes, record_info(fields, bosh)}]), mnesia:add_table_copy(bosh, node(), ram_copies). diff --git a/src/mod_caps_mnesia.erl b/src/mod_caps_mnesia.erl index 660fcb4ef..ed22841e8 100644 --- a/src/mod_caps_mnesia.erl +++ b/src/mod_caps_mnesia.erl @@ -27,7 +27,7 @@ init(_Host, _Opts) -> _ -> mnesia:delete_table(caps_features) end, - mnesia:create_table(caps_features, + ejabberd_mnesia:create(?MODULE, caps_features, [{disc_only_copies, [node()]}, {local_content, true}, {attributes, diff --git a/src/mod_carboncopy_mnesia.erl b/src/mod_carboncopy_mnesia.erl index bf69bd21c..4cc7e6049 100644 --- a/src/mod_carboncopy_mnesia.erl +++ b/src/mod_carboncopy_mnesia.erl @@ -30,7 +30,7 @@ init(_Host, _Opts) -> %% probably table don't exist ok end, - mnesia:create_table(carboncopy, + ejabberd_mnesia:create(?MODULE, carboncopy, [{ram_copies, [node()]}, {attributes, record_info(fields, carboncopy)}, {type, bag}]), diff --git a/src/mod_http_bind.erl b/src/mod_http_bind.erl index 471b38c00..68500f2c4 100644 --- a/src/mod_http_bind.erl +++ b/src/mod_http_bind.erl @@ -89,7 +89,7 @@ stop(_Host) -> setup_database() -> migrate_database(), - mnesia:create_table(http_bind, + ejabberd_mnesia:create(?MODULE, http_bind, [{ram_copies, [node()]}, {attributes, record_info(fields, http_bind)}]). diff --git a/src/mod_irc_mnesia.erl b/src/mod_irc_mnesia.erl index 95cceb54c..e23f5a268 100644 --- a/src/mod_irc_mnesia.erl +++ b/src/mod_irc_mnesia.erl @@ -21,7 +21,7 @@ %%% API %%%=================================================================== init(_Host, _Opts) -> - mnesia:create_table(irc_custom, + ejabberd_mnesia:create(?MODULE, irc_custom, [{disc_copies, [node()]}, {attributes, record_info(fields, irc_custom)}]), update_table(). diff --git a/src/mod_last_mnesia.erl b/src/mod_last_mnesia.erl index 7a1610abb..269ed4ba0 100644 --- a/src/mod_last_mnesia.erl +++ b/src/mod_last_mnesia.erl @@ -19,7 +19,7 @@ %%% API %%%=================================================================== init(_Host, _Opts) -> - mnesia:create_table(last_activity, + ejabberd_mnesia:create(?MODULE, last_activity, [{disc_copies, [node()]}, {attributes, record_info(fields, last_activity)}]), diff --git a/src/mod_mam_mnesia.erl b/src/mod_mam_mnesia.erl index 8b9c6676c..89ab92ff1 100644 --- a/src/mod_mam_mnesia.erl +++ b/src/mod_mam_mnesia.erl @@ -32,11 +32,11 @@ %%% API %%%=================================================================== init(_Host, _Opts) -> - mnesia:create_table(archive_msg, + ejabberd_mnesia:create(?MODULE, archive_msg, [{disc_only_copies, [node()]}, {type, bag}, {attributes, record_info(fields, archive_msg)}]), - mnesia:create_table(archive_prefs, + ejabberd_mnesia:create(?MODULE, archive_prefs, [{disc_only_copies, [node()]}, {attributes, record_info(fields, archive_prefs)}]). diff --git a/src/mod_muc.erl b/src/mod_muc.erl index ab358b957..298749329 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -177,7 +177,7 @@ init([Host, Opts]) -> Mod = gen_mod:db_mod(Host, Opts, ?MODULE), Mod:init(Host, [{host, MyHost}|Opts]), update_tables(), - mnesia:create_table(muc_online_room, + ejabberd_mnesia:create(?MODULE, muc_online_room, [{ram_copies, [node()]}, {type, ordered_set}, {attributes, record_info(fields, muc_online_room)}]), diff --git a/src/mod_muc_mnesia.erl b/src/mod_muc_mnesia.erl index 072dddaae..8f570746c 100644 --- a/src/mod_muc_mnesia.erl +++ b/src/mod_muc_mnesia.erl @@ -26,11 +26,11 @@ %%%=================================================================== init(_Host, Opts) -> MyHost = proplists:get_value(host, Opts), - mnesia:create_table(muc_room, + ejabberd_mnesia:create(?MODULE, muc_room, [{disc_copies, [node()]}, {attributes, record_info(fields, muc_room)}]), - mnesia:create_table(muc_registered, + ejabberd_mnesia:create(?MODULE, muc_registered, [{disc_copies, [node()]}, {attributes, record_info(fields, muc_registered)}]), diff --git a/src/mod_multicast.erl b/src/mod_multicast.erl index 0aa2270ae..fbd2402ee 100644 --- a/src/mod_multicast.erl +++ b/src/mod_multicast.erl @@ -840,7 +840,7 @@ received_awaiter(JID, Waiter, LServiceS) -> %%%------------------------- create_cache() -> - mnesia:create_table(multicastc, + ejabberd_mnesia:create(?MODULE, multicastc, [{ram_copies, [node()]}, {attributes, record_info(fields, multicastc)}]). diff --git a/src/mod_offline_mnesia.erl b/src/mod_offline_mnesia.erl index e84f7078a..fb75f618e 100644 --- a/src/mod_offline_mnesia.erl +++ b/src/mod_offline_mnesia.erl @@ -25,7 +25,7 @@ %%% API %%%=================================================================== init(_Host, _Opts) -> - mnesia:create_table(offline_msg, + ejabberd_mnesia:create(?MODULE, offline_msg, [{disc_only_copies, [node()]}, {type, bag}, {attributes, record_info(fields, offline_msg)}]), update_table(). diff --git a/src/mod_privacy_mnesia.erl b/src/mod_privacy_mnesia.erl index a93e92139..eca6f8ecd 100644 --- a/src/mod_privacy_mnesia.erl +++ b/src/mod_privacy_mnesia.erl @@ -25,7 +25,7 @@ %%% API %%%=================================================================== init(_Host, _Opts) -> - mnesia:create_table(privacy, + ejabberd_mnesia:create(?MODULE, privacy, [{disc_copies, [node()]}, {attributes, record_info(fields, privacy)}]), update_table(). diff --git a/src/mod_private_mnesia.erl b/src/mod_private_mnesia.erl index 84871c1e7..42e5ddfd8 100644 --- a/src/mod_private_mnesia.erl +++ b/src/mod_private_mnesia.erl @@ -21,7 +21,7 @@ %%% API %%%=================================================================== init(_Host, _Opts) -> - mnesia:create_table(private_storage, + ejabberd_mnesia:create(?MODULE, private_storage, [{disc_only_copies, [node()]}, {attributes, record_info(fields, private_storage)}]), diff --git a/src/mod_proxy65_sm.erl b/src/mod_proxy65_sm.erl index 7ef4d390e..b1d33b5d9 100644 --- a/src/mod_proxy65_sm.erl +++ b/src/mod_proxy65_sm.erl @@ -62,7 +62,7 @@ start_link(Host, Opts) -> []). init([Opts]) -> - mnesia:create_table(bytestream, + ejabberd_mnesia:create(?MODULE, bytestream, [{ram_copies, [node()]}, {attributes, record_info(fields, bytestream)}]), mnesia:add_table_copy(bytestream, node(), ram_copies), diff --git a/src/mod_pubsub.erl b/src/mod_pubsub.erl index ba79cf7bc..717796fec 100644 --- a/src/mod_pubsub.erl +++ b/src/mod_pubsub.erl @@ -268,7 +268,7 @@ init([ServerHost, Opts]) -> BaseOptions = DefaultModule:options(), DefaultNodeCfg = gen_mod:get_opt(default_node_config, Opts, fun(A) when is_list(A) -> filter_node_options(A, BaseOptions) end, []), - mnesia:create_table(pubsub_last_item, + ejabberd_mnesia:create(?MODULE, pubsub_last_item, [{ram_copies, [node()]}, {attributes, record_info(fields, pubsub_last_item)}]), mod_disco:register_feature(ServerHost, ?NS_PUBSUB), diff --git a/src/mod_register.erl b/src/mod_register.erl index ba261e0f3..b96ebecbd 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -54,7 +54,7 @@ start(Host, Opts) -> stream_feature_register, 50), ejabberd_hooks:add(c2s_unauthenticated_iq, Host, ?MODULE, unauthenticated_iq_register, 50), - mnesia:create_table(mod_register_ip, + ejabberd_mnesia:create(?MODULE, mod_register_ip, [{ram_copies, [node()]}, {local_content, true}, {attributes, [key, value]}]), mnesia:add_table_copy(mod_register_ip, node(), diff --git a/src/mod_roster_mnesia.erl b/src/mod_roster_mnesia.erl index e274ac5eb..04bdf72e7 100644 --- a/src/mod_roster_mnesia.erl +++ b/src/mod_roster_mnesia.erl @@ -24,10 +24,10 @@ %%% API %%%=================================================================== init(_Host, _Opts) -> - mnesia:create_table(roster, + ejabberd_mnesia:create(?MODULE, roster, [{disc_copies, [node()]}, {attributes, record_info(fields, roster)}]), - mnesia:create_table(roster_version, + ejabberd_mnesia:create(?MODULE, roster_version, [{disc_copies, [node()]}, {attributes, record_info(fields, roster_version)}]), diff --git a/src/mod_shared_roster_mnesia.erl b/src/mod_shared_roster_mnesia.erl index 0f9e93bf6..ed4525041 100644 --- a/src/mod_shared_roster_mnesia.erl +++ b/src/mod_shared_roster_mnesia.erl @@ -26,10 +26,10 @@ %%% API %%%=================================================================== init(_Host, _Opts) -> - mnesia:create_table(sr_group, + ejabberd_mnesia:create(?MODULE, sr_group, [{disc_copies, [node()]}, {attributes, record_info(fields, sr_group)}]), - mnesia:create_table(sr_user, + ejabberd_mnesia:create(?MODULE, sr_user, [{disc_copies, [node()]}, {type, bag}, {attributes, record_info(fields, sr_user)}]), update_tables(), diff --git a/src/mod_sip_registrar.erl b/src/mod_sip_registrar.erl index e6532c934..4ae8e077b 100644 --- a/src/mod_sip_registrar.erl +++ b/src/mod_sip_registrar.erl @@ -179,7 +179,7 @@ ping(SIPSocket) -> %%%=================================================================== init([]) -> update_table(), - mnesia:create_table(sip_session, + ejabberd_mnesia:create(?MODULE, sip_session, [{ram_copies, [node()]}, {type, bag}, {attributes, record_info(fields, sip_session)}]), diff --git a/src/mod_vcard_mnesia.erl b/src/mod_vcard_mnesia.erl index a4a5f2562..40ea36381 100644 --- a/src/mod_vcard_mnesia.erl +++ b/src/mod_vcard_mnesia.erl @@ -24,10 +24,10 @@ %%% API %%%=================================================================== init(_Host, _Opts) -> - mnesia:create_table(vcard, + ejabberd_mnesia:create(?MODULE, vcard, [{disc_only_copies, [node()]}, {attributes, record_info(fields, vcard)}]), - mnesia:create_table(vcard_search, + ejabberd_mnesia:create(?MODULE, vcard_search, [{disc_copies, [node()]}, {attributes, record_info(fields, vcard_search)}]), diff --git a/src/mod_vcard_xupdate_mnesia.erl b/src/mod_vcard_xupdate_mnesia.erl index 3f8d6fcab..454d97e25 100644 --- a/src/mod_vcard_xupdate_mnesia.erl +++ b/src/mod_vcard_xupdate_mnesia.erl @@ -19,7 +19,7 @@ %%% API %%%=================================================================== init(_Host, _Opts) -> - mnesia:create_table(vcard_xupdate, + ejabberd_mnesia:create(?MODULE, vcard_xupdate, [{disc_copies, [node()]}, {attributes, record_info(fields, vcard_xupdate)}]), diff --git a/src/node_flat.erl b/src/node_flat.erl index 9c1bc9b98..55093b0e7 100644 --- a/src/node_flat.erl +++ b/src/node_flat.erl @@ -51,11 +51,11 @@ init(_Host, _ServerHost, _Opts) -> %pubsub_subscription:init(Host, ServerHost, Opts), - mnesia:create_table(pubsub_state, + ejabberd_mnesia:create(?MODULE, pubsub_state, [{disc_copies, [node()]}, {type, ordered_set}, {attributes, record_info(fields, pubsub_state)}]), - mnesia:create_table(pubsub_item, + ejabberd_mnesia:create(?MODULE, pubsub_item, [{disc_only_copies, [node()]}, {attributes, record_info(fields, pubsub_item)}]), ItemsFields = record_info(fields, pubsub_item), diff --git a/src/nodetree_tree.erl b/src/nodetree_tree.erl index 81972ca3c..eb28e3408 100644 --- a/src/nodetree_tree.erl +++ b/src/nodetree_tree.erl @@ -49,7 +49,7 @@ delete_node/2]). init(_Host, _ServerHost, _Options) -> - mnesia:create_table(pubsub_node, + ejabberd_mnesia:create(?MODULE, pubsub_node, [{disc_copies, [node()]}, {attributes, record_info(fields, pubsub_node)}]), mnesia:add_table_index(pubsub_node, id), diff --git a/src/pubsub_index.erl b/src/pubsub_index.erl index 983356a18..45361e141 100644 --- a/src/pubsub_index.erl +++ b/src/pubsub_index.erl @@ -34,7 +34,7 @@ -export([init/3, new/1, free/2]). init(_Host, _ServerHost, _Opts) -> - mnesia:create_table(pubsub_index, + ejabberd_mnesia:create(?MODULE, pubsub_index, [{disc_copies, [node()]}, {attributes, record_info(fields, pubsub_index)}]). diff --git a/src/pubsub_migrate.erl b/src/pubsub_migrate.erl index c493b58f9..a329f3c39 100644 --- a/src/pubsub_migrate.erl +++ b/src/pubsub_migrate.erl @@ -253,7 +253,7 @@ update_node_database(Host, ServerHost) -> end, {atomic, NewRecords} = mnesia:transaction(F), {atomic, ok} = mnesia:delete_table(pubsub_node), - {atomic, ok} = mnesia:create_table(pubsub_node, + {atomic, ok} = ejabberd_mnesia:create(?MODULE, pubsub_node, [{disc_copies, [node()]}, {attributes, record_info(fields, @@ -421,7 +421,7 @@ update_state_database(_Host, _ServerHost) -> {atomic, NewRecs} = mnesia:transaction(fun mnesia:foldl/3, [F, [], pubsub_state]), {atomic, ok} = mnesia:delete_table(pubsub_state), - {atomic, ok} = mnesia:create_table(pubsub_state, + {atomic, ok} = ejabberd_mnesia:create(?MODULE, pubsub_state, [{disc_copies, [node()]}, {attributes, record_info(fields, pubsub_state)}]), FNew = fun () -> diff --git a/src/pubsub_subscription.erl b/src/pubsub_subscription.erl index 077ac5ba9..0ca066dae 100644 --- a/src/pubsub_subscription.erl +++ b/src/pubsub_subscription.erl @@ -126,7 +126,7 @@ parse_options_xform(XFields) -> %% Internal functions %%==================================================================== create_table() -> - case mnesia:create_table(pubsub_subscription, + case ejabberd_mnesia:create(?MODULE, pubsub_subscription, [{disc_copies, [node()]}, {attributes, record_info(fields, pubsub_subscription)}, diff --git a/src/shaper.erl b/src/shaper.erl index eb82b8faa..19c9a049d 100644 --- a/src/shaper.erl +++ b/src/shaper.erl @@ -50,7 +50,7 @@ -spec start() -> ok. start() -> - mnesia:create_table(shaper, + ejabberd_mnesia:create(?MODULE, shaper, [{ram_copies, [node()]}, {local_content, true}, {attributes, record_info(fields, shaper)}]), From 32f484a3497d9920a5d1e4ac5ad9a7d487e0dee2 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Wed, 30 Nov 2016 13:50:46 +0100 Subject: [PATCH 150/151] Fix typo introduced by 92db9ff changes --- src/ejabberd_mnesia.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ejabberd_mnesia.erl b/src/ejabberd_mnesia.erl index f244d518f..0e067ad65 100644 --- a/src/ejabberd_mnesia.erl +++ b/src/ejabberd_mnesia.erl @@ -40,7 +40,7 @@ create(Module, Name, TabDef) -> {attributes, Attrs} = lists:keyfind(attributes, 1, Schema), case catch mnesia:table_info(Name, attributes) of {'EXIT', _} -> - ejabberd_mnesia:create(?MODULE, Name, Schema); + mnesia:create_table(Name, Schema); Attrs -> case need_reset(TabDef, Schema) of true -> reset(Name, Schema); From 8618af4e34a3f40f98b9a7fed7e847f478b4f27e Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 30 Nov 2016 16:51:42 +0100 Subject: [PATCH 151/151] Fixes pt-br translation (thanks to Rodrigues)(#1393) --- priv/msgs/pt-br.po | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/priv/msgs/pt-br.po b/priv/msgs/pt-br.po index 6d2ae1c57..e211315f3 100644 --- a/priv/msgs/pt-br.po +++ b/priv/msgs/pt-br.po @@ -31,7 +31,7 @@ msgstr "foi removido" #: ejabberd_c2s.erl:2105 msgid "Your active privacy list has denied the routing of this stanza." -msgstr "Sua lista de privacidade ativa negou o roteamento deste." +msgstr "Sua lista de privacidade ativa negou o roteamento desta instância." #: ejabberd_c2s.erl:2420 msgid "Too many unacked stanzas" @@ -286,7 +286,7 @@ msgstr "Nós em execução" #: ejabberd_web_admin.erl:1815 mod_configure.erl:526 msgid "Stopped Nodes" -msgstr "Nos parados" +msgstr "Nós parados" #: ejabberd_web_admin.erl:1833 ejabberd_web_admin.erl:1858 msgid "Node ~p" @@ -302,7 +302,7 @@ msgstr "Salvar cópia de segurança" #: ejabberd_web_admin.erl:1845 msgid "Listened Ports" -msgstr "Portas escutadas" +msgstr "Portas abertas" #: ejabberd_web_admin.erl:1848 ejabberd_web_admin.erl:2261 msgid "Update" @@ -1013,7 +1013,7 @@ msgstr "Apelido" #: mod_muc.erl:1050 mod_muc_room.erl:1104 mod_muc_room.erl:1843 msgid "That nickname is registered by another person" -msgstr "O nick já está registrado por outra pessoa" +msgstr "O apelido já está registrado por outra pessoa" #: mod_muc.erl:1078 msgid "You must fill in field \"Nickname\" in the form" @@ -1303,7 +1303,7 @@ msgstr "O Jabber ID ~s não es válido" #: mod_muc_room.erl:2772 msgid "Nickname ~s does not exist in the room" -msgstr "O nick ~s não existe na sala" +msgstr "O apelido ~s não existe na sala" #: mod_muc_room.erl:2795 mod_muc_room.erl:3175 msgid "Invalid affiliation: ~s" @@ -1568,15 +1568,15 @@ msgstr "Entregar as notificações de evento" #: mod_pubsub.erl:3749 msgid "Notify subscribers when the node configuration changes" -msgstr "Notificar subscritores quando cambia la configuração do nodo" +msgstr "Notificar assinantes a configuração do nó mudar" #: mod_pubsub.erl:3751 msgid "Notify subscribers when the node is deleted" -msgstr "Notificar subscritores quando o nodo se elimine" +msgstr "Notificar assinantes quando o nó for eliminado se elimine" #: mod_pubsub.erl:3753 msgid "Notify subscribers when items are removed from the node" -msgstr "Notificar subscritores quando os elementos se eliminem do nodo" +msgstr "Notificar assinantes quando itens forem eliminados do nó" #: mod_pubsub.erl:3755 msgid "Persist items to storage" @@ -1637,7 +1637,7 @@ msgstr "A verificação do CAPTCHA falhou" #: mod_register.erl:253 msgid "You need a client that supports x:data and CAPTCHA to register" msgstr "" -"Você precisa de um cliente com suporte de x:data para poder registrar o nick" +"Você precisa de um cliente com suporte de x:data para poder registrar o apelido" #: mod_register.erl:259 mod_register.erl:320 msgid "Choose a username and password to register with this server" @@ -1693,7 +1693,7 @@ msgid "" "(Jabber IDentifier) will be of the form: username@server. Please read " "carefully the instructions to fill correctly the fields." msgstr "" -"Esta pagina aceita criações de novas contas Jabber neste servidor. A sua JID " +"Esta pagina aceita criações de novas contas Jabber neste servidor. O seu JID " "(Identificador Jabber) será da seguinte forma: 'usuário@servidor'. Por " "favor, leia cuidadosamente as instruções para preencher corretamente os " "campos." @@ -1732,7 +1732,7 @@ msgid "" "Some Jabber clients can store your password in the computer, but you should " "do this only in your personal computer for safety reasons." msgstr "" -"Alguns clientes jabber podem salvar a sua senha no seu computador. Use " +"Alguns clientes jabber podem salvar a sua senha no seu computador. Use o " "recurso somente se você considera este computador seguro o suficiente." #: mod_register_web.erl:256