.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.43) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "AnyEvent::XMPP::Writer 3pm" .TH AnyEvent::XMPP::Writer 3pm "2022-12-06" "perl v5.36.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" AnyEvent::XMPP::Writer \- "XML" writer for XMPP .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 2 \& use AnyEvent::XMPP::Writer; \& ... .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" This module contains some helper functions for writing \s-1XMPP \*(L"XML\*(R",\s0 which is not real \s-1XML\s0 at all ;\-( I use XML::Writer and tune it until it creates \*(L"\s-1XML\*(R"\s0 that is accepted by most servers propably (all of the \s-1XMPP\s0 servers I tested should work (jabberd14, jabberd2, ejabberd, googletalk). .PP I hope the semantics of XML::Writer don't change much in the future, but if they do and you run into problems, please report them! .PP The whole \*(L"\s-1XML\*(R"\s0 concept of \s-1XMPP\s0 is fundamentally broken anyway. It's supposed to be an subset of \s-1XML.\s0 But a subset of \s-1XML\s0 productions is not \s-1XML.\s0 Strictly speaking you need a special \s-1XMPP \*(L"XML\*(R"\s0 parser and writer to be 100% conformant. .PP On top of that \s-1XMPP\s0 \fBrequires\fR you to parse these partial \*(L"\s-1XML\*(R"\s0 documents. But a partial \s-1XML\s0 document is not well-formed, heck, it's not even a \s-1XML\s0 document! And a parser should bail out with an error. But \s-1XMPP\s0 doesn't care, it just relies on implementation dependend behaviour of chunked parsing modes for \s-1SAX\s0 parsing. This functionality isn't even specified by the \s-1XML\s0 recommendation in any way. The recommendation even says that it's undefined what happens if you process not-well-formed \s-1XML\s0 documents. .PP But I try to be as \s-1XMPP \*(L"XML\*(R"\s0 conformant as possible (it should be around 99\-100%). But it's hard to say what \s-1XML\s0 is conformant, as the specifications of \s-1XMPP \*(L"XML\*(R"\s0 and \s-1XML\s0 are contradicting. For example \s-1XMPP\s0 also says you only have to generated and accept \s-1UTF\-8\s0 encodings of \s-1XML,\s0 but the \s-1XML\s0 recommendation says that each parser has to accept \s-1UTF\-8\s0 \fBand\fR \s-1UTF\-16.\s0 So, what do you do? Do you use a \s-1XML\s0 conformant parser or do you write your own? .PP I'm using XML::Parser::Expat because expat knows how to parse broken (aka \&'partial') \*(L"\s-1XML\*(R"\s0 documents, as \s-1XMPP\s0 requires. Another argument is that if you capture a \s-1XMPP\s0 conversation to the end, and even if a '' tag was captured, you wont have a valid \s-1XML\s0 document. The problem is that you have to resent a tag after \s-1TLS\s0 and \s-1SASL\s0 authentication each! Awww... I'm repeating myself. .PP But well... AnyEvent::XMPP does it's best with expat to cope with the fundamental brokeness of \*(L"\s-1XML\*(R"\s0 in \s-1XMPP.\s0 .PP Back to the issue with \*(L"\s-1XML\*(R"\s0 generation: I've discoverd that many \s-1XMPP\s0 servers (eg. jabberd14 and ejabberd) have problems with \s-1XML\s0 namespaces. Thats the reason why I'm assigning the namespace prefixes manually: The servers just don't accept validly namespaced \s-1XML.\s0 The draft 3921bis does even state that a client \s-1SHOULD\s0 generate a 'stream' prefix for the tag. .PP I advice you to explicitly set the namespaces too if you generate \*(L"\s-1XML\*(R"\s0 for \&\s-1XMPP\s0 yourself, at least until all or most of the \s-1XMPP\s0 servers have been fixed. Which might take some years :\-) And maybe will happen never. .PP And another note: As \s-1XMPP\s0 requires all predefined entity characters to be escaped in character data you need a \*(L"\s-1XML\*(R"\s0 writer that will escape everything: .PP .Vb 1 \& RFC 3920 \- 11.1. Restrictions: \& \& character data or attribute values containing unescaped characters \& that map to the predefined entities (Section 4.6 therein); \& such characters MUST be escaped .Ve .PP This means: You have to escape '>' in the character data. I don't know whether XML::Writer does that. And I honestly don't care much about this. \s-1XMPP\s0 is broken by design and I have barely time to writer my own \s-1XML\s0 parsers and writers to suit their sick taste of \*(L"\s-1XML\*(R".\s0 (Do I repeat myself?) .PP I would be happy if they finally say (in \s-1RFC3920\s0): \*(L"\s-1XMPP\s0 is \s-1NOT XML.\s0 It's just XML-like, and some \s-1XML\s0 utilities allow you to process this kind of \s-1XML.\*(R".\s0 .SH "METHODS" .IX Header "METHODS" .IP "\fBnew (%args)\fR" 4 .IX Item "new (%args)" This methods takes following arguments: .RS 4 .IP "write_cb" 4 .IX Item "write_cb" The callback that is called when a \s-1XML\s0 stanza was completely written and is ready for transfer. The first argument of the callback will be the character data to send to the socket. .RE .RS 4 .Sp And calls \f(CW\*(C`init\*(C'\fR. .RE .IP "\fBinit\fR" 4 .IX Item "init" (Re)initializes the writer. .IP "\fBflush ()\fR" 4 .IX Item "flush ()" This method flushes the internal write buffer and will invoke the \f(CW\*(C`write_cb\*(C'\fR callback. (see also \f(CW\*(C`new ()\*(C'\fR above) .IP "\fBsend_init_stream ($language, \f(CB$domain\fB, \f(CB$namespace\fB)\fR" 4 .IX Item "send_init_stream ($language, $domain, $namespace)" This method will generate a \s-1XMPP\s0 stream header. \f(CW$domain\fR has to be the domain of the server (or endpoint) we want to connect to. .Sp \&\f(CW$namespace\fR is the namespace \s-1URI\s0 or the tag (from AnyEvent::XMPP::Namespaces) for the stream namespace. (This is used by AnyEvent::XMPP::Component to connect as component to a server). \f(CW$namespace\fR can also be undefined, in this case the \f(CW\*(C`client\*(C'\fR namespace will be used. .IP "\fBsend_whitespace_ping\fR" 4 .IX Item "send_whitespace_ping" This method sends a single space to the server. .IP "\fBsend_handshake ($streamid, \f(CB$secret\fB)\fR" 4 .IX Item "send_handshake ($streamid, $secret)" This method sends a component handshake. Please note that \f(CW$secret\fR must be \s-1XML\s0 escaped! .IP "\fBsend_end_of_stream\fR" 4 .IX Item "send_end_of_stream" Sends end of the stream. .IP "\fBsend_sasl_auth ($mechanisms, \f(CB$user\fB, \f(CB$hostname\fB, \f(CB$pass\fB)\fR" 4 .IX Item "send_sasl_auth ($mechanisms, $user, $hostname, $pass)" This methods sends the start of a \s-1SASL\s0 authentication. \f(CW$mechanisms\fR is an array reference, containing the mechanism names that are to be tried. .IP "\fBsend_sasl_response ($challenge)\fR" 4 .IX Item "send_sasl_response ($challenge)" This method generated the \s-1SASL\s0 authentication response to a \f(CW$challenge\fR. You must not call this method without calling \f(CW\*(C`send_sasl_auth ()\*(C'\fR before. .IP "\fBsend_starttls\fR" 4 .IX Item "send_starttls" Sends the starttls command to the server. .IP "\fBsend_iq ($id, \f(CB$type\fB, \f(CB$create_cb\fB, \f(CB%attrs\fB)\fR" 4 .IX Item "send_iq ($id, $type, $create_cb, %attrs)" This method sends an \s-1IQ\s0 stanza of type \f(CW$type\fR (to be compliant only use: 'get', 'set', 'result' and 'error'). .Sp If \f(CW$create_cb\fR is a code reference it will be called with an XML::Writer instance as first argument, which must be used to fill the \s-1IQ\s0 stanza. The XML::Writer is in \s-1UNSAFE\s0 mode, so you can safely use \f(CW\*(C`raw()\*(C'\fR to write out \s-1XML.\s0 .Sp \&\f(CW$create_cb\fR is a hash reference the hash will be used as key=>value arguments for the \f(CW\*(C`simxml\*(C'\fR function defined in AnyEvent::XMPP::Util. \f(CW\*(C`simxml\*(C'\fR will then be used to generate the contents of the \s-1IQ\s0 stanza. (This is very convenient when you want to write the contents of stanzas in the code and don't want to build a \s-1DOM\s0 tree yourself...). .Sp If \f(CW$create_cb\fR is an array reference it's elements will be interpreted as single \f(CW$create_cb\fR argument (which can either be a hash reference or code reference themself) and executed sequentially. .Sp If \f(CW$create_cb\fR is undefined an empty tag will be generated. .Sp Example: .Sp .Vb 4 \& $writer\->send_iq (\*(Aqnewid\*(Aq, \*(Aqget\*(Aq, { \& defns => \*(Aqversion\*(Aq, \& node => { name => \*(Aqquery\*(Aq, ns => \*(Aqversion\*(Aq } \& }, to => \*(Aqjabber.org\*(Aq) .Ve .Sp \&\f(CW%attrs\fR should have further attributes for the \s-1IQ\s0 stanza tag. For example 'to' or 'from'. If the \f(CW%attrs\fR contain a 'lang' attribute it will be put into the 'xml' namespace. If the 'to' attribute contains an undef it will be omitted. .Sp \&\f(CW$id\fR is the id to give this \s-1IQ\s0 stanza and is mandatory in this \s-1API.\s0 .Sp Please note that all attribute values and character data will be filtered by \f(CW\*(C`filter_xml_chars\*(C'\fR (see also AnyEvent::XMPP::Util). .IP "\fBsend_presence ($id, \f(CB$type\fB, \f(CB$create_cb\fB, \f(CB%attrs\fB)\fR" 4 .IX Item "send_presence ($id, $type, $create_cb, %attrs)" Sends a presence stanza. .Sp \&\f(CW$create_cb\fR has the same meaning as for \f(CW\*(C`send_iq\*(C'\fR. \&\f(CW%attrs\fR will let you pass further optional arguments like 'to'. .Sp \&\f(CW$type\fR is the type of the presence, which may be one of: .Sp .Vb 1 \& unavailable, subscribe, subscribed, unsubscribe, unsubscribed, probe, error .Ve .Sp Or undef, in case you want to send a 'normal' presence. Or something completely different if you don't like the \s-1RFC 3921 :\-\s0) .Sp \&\f(CW%attrs\fR contains further attributes for the presence tag or may contain one of the following exceptional keys: .Sp If \f(CW%attrs\fR contains a 'show' key: a child xml tag with that name will be generated with the value as the content, which should be one of 'away', 'chat', 'dnd' and 'xa'. If it contains an undefined value no such tag will be generated, which usually means that the 'available' presence is meant. .Sp If \f(CW%attrs\fR contains a 'status' key: a child xml tag with that name will be generated with the value as content. If the value of the 'status' key is an hash reference the keys will be interpreted as language identifiers for the xml:lang attribute of each status element. If one of these keys is the empty string '' no xml:lang attribute will be generated for it. The values will be the character content of the status tags. .Sp If \f(CW%attrs\fR contains a 'priority' key: a child xml tag with that name will be generated with the value as content, which must be a number between \-128 and +127. .Sp Note: If \f(CW$create_cb\fR is undefined and one of the above attributes (show, status or priority) were given, the generates presence tag won't be empty. .Sp Please note that all attribute values and character data will be filtered by \f(CW\*(C`filter_xml_chars\*(C'\fR (see also AnyEvent::XMPP::Util). .IP "\fBsend_message ($id, \f(CB$to\fB, \f(CB$type\fB, \f(CB$create_cb\fB, \f(CB%attrs\fB)\fR" 4 .IX Item "send_message ($id, $to, $type, $create_cb, %attrs)" Sends a message stanza. .Sp \&\f(CW$to\fR is the destination \s-1JID\s0 of the message. \f(CW$type\fR is the type of the message, and if \f(CW$type\fR is undefined it will default to 'chat'. \&\f(CW$type\fR must be one of the following: 'chat', 'error', 'groupchat', 'headline' or 'normal'. .Sp \&\f(CW$create_cb\fR has the same meaning as in \f(CW\*(C`send_iq\*(C'\fR. .Sp \&\f(CW%attrs\fR contains further attributes for the message tag or may contain one of the following exceptional keys: .Sp If \f(CW%attrs\fR contains a 'body' key: a child xml tag with that name will be generated with the value as content. If the value of the 'body' key is an hash reference the keys will be interpreted as language identifiers for the xml:lang attribute of each body element. If one of these keys is the empty string '' no xml:lang attribute will be generated for it. The values will be the character content of the body tags. .Sp If \f(CW%attrs\fR contains a 'subject' key: a child xml tag with that name will be generated with the value as content. If the value of the 'subject' key is an hash reference the keys will be interpreted as language identifiers for the xml:lang attribute of each subject element. If one of these keys is the empty string '' no xml:lang attribute will be generated for it. The values will be the character content of the subject tags. .Sp If \f(CW%attrs\fR contains a 'thread' key: a child xml tag with that name will be generated and the value will be the character content. .Sp Please note that all attribute values and character data will be filtered by \f(CW\*(C`filter_xml_chars\*(C'\fR (see also AnyEvent::XMPP::Util). .IP "\fBwrite_error_tag ($error_stanza_node, \f(CB$error_type\fB, \f(CB$error\fB)\fR" 4 .IX Item "write_error_tag ($error_stanza_node, $error_type, $error)" \&\f(CW$error_type\fR is one of 'cancel', 'continue', 'modify', 'auth' and 'wait'. \&\f(CW$error\fR is the name of the error tag child element. If \f(CW$error\fR is one of the following: .Sp .Vb 6 \& \*(Aqbad\-request\*(Aq, \*(Aqconflict\*(Aq, \*(Aqfeature\-not\-implemented\*(Aq, \*(Aqforbidden\*(Aq, \*(Aqgone\*(Aq, \& \*(Aqinternal\-server\-error\*(Aq, \*(Aqitem\-not\-found\*(Aq, \*(Aqjid\-malformed\*(Aq, \*(Aqnot\-acceptable\*(Aq, \& \*(Aqnot\-allowed\*(Aq, \*(Aqnot\-authorized\*(Aq, \*(Aqpayment\-required\*(Aq, \*(Aqrecipient\-unavailable\*(Aq, \& \*(Aqredirect\*(Aq, \*(Aqregistration\-required\*(Aq, \*(Aqremote\-server\-not\-found\*(Aq, \& \*(Aqremote\-server\-timeout\*(Aq, \*(Aqresource\-constraint\*(Aq, \*(Aqservice\-unavailable\*(Aq, \& \*(Aqsubscription\-required\*(Aq, \*(Aqundefined\-condition\*(Aq, \*(Aqunexpected\-request\*(Aq .Ve .Sp then a default can be select for \f(CW$error_type\fR, and the argument can be undefined. .Sp Note: This method is currently a bit limited in the generation of the xml for the errors, if you need more please contact me. .SH "AUTHOR" .IX Header "AUTHOR" Robin Redeker, \f(CW\*(C`\*(C'\fR, \s-1JID:\s0 \f(CW\*(C`\*(C'\fR .SH "COPYRIGHT & LICENSE" .IX Header "COPYRIGHT & LICENSE" Copyright 2007, 2008 Robin Redeker, all rights reserved. .PP This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.