forked from Mirrors/freeswitch
1535 lines
50 KiB
Plaintext
1535 lines
50 KiB
Plaintext
\input texinfo @c -*-texinfo-*-
|
|
@c %**start of header
|
|
@setfilename iksemel
|
|
@setcontentsaftertitlepage
|
|
@settitle Iksemel Programmers Manual
|
|
@set VERSION 1.2
|
|
@c %**end of header
|
|
|
|
@titlepage
|
|
@title iksemel programmers manual
|
|
@subtitle A tutorial and API reference for the iksemel library @value{VERSION}
|
|
@page
|
|
@vskip 0pt plus 1filll
|
|
Copyright @copyright{} 2001-2003 G@"urer @"Ozen
|
|
|
|
This is a free document; 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, or
|
|
(at your option) any later version.You may obtain a copy of the
|
|
GNU General Public License from the Free Software Foundation
|
|
by visiting their Web site or by writing to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
|
MA 02111-1307, USA.
|
|
|
|
@end titlepage
|
|
|
|
@ifinfo
|
|
@node Top, , , (dir)
|
|
@top iksemel Programmers Manual
|
|
|
|
Copyright @copyright{} 2001-2003 G@"urer @"Ozen
|
|
|
|
This is a free document; 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, or
|
|
(at your option) any later version.You may obtain a copy of the
|
|
GNU General Public License from the Free Software Foundation
|
|
by visiting their Web site or by writing to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
|
MA 02111-1307, USA.
|
|
|
|
@menu
|
|
* Introduction::
|
|
|
|
* Tutorials::
|
|
|
|
* Development::
|
|
|
|
* Datatype Index::
|
|
|
|
* Function Index::
|
|
@end menu
|
|
@end ifinfo
|
|
|
|
@node Introduction, Tutorials, ,Top
|
|
@chapter Introduction
|
|
|
|
iksemel is an XML (eXtensible Markup Language) parser library
|
|
designed for Jabber applications. It is coded in ANSI C for POSIX
|
|
compatible environments, thus highly portable. It is free software
|
|
released under the GNU Lesser General Public License.
|
|
|
|
The purprose of this manual is to tell you how to use the facilities
|
|
of the iksemel library. Manual is written with the assumption that you
|
|
are familiar with the C programming language, basic programming
|
|
concepts, XML and Jabber protocol.
|
|
|
|
@section Compiling the Library
|
|
|
|
You need to install MinGW (@url{http://mingw.org}) under Windows to be able
|
|
to compile iksemel. Although not tested by the author, Cygwin should
|
|
work equally well.
|
|
|
|
Library can be built with:
|
|
|
|
@example
|
|
./configure
|
|
make
|
|
@end example
|
|
|
|
If you want to make a self test:
|
|
|
|
@example
|
|
make test
|
|
@end example
|
|
|
|
Now you can install it with:
|
|
|
|
@example
|
|
make install
|
|
@end example
|
|
|
|
|
|
@section Using iksemel in Applications
|
|
|
|
You need to include @file{iksemel.h} file in your source to access library API.
|
|
You can do this with:
|
|
|
|
@code{#include "iksemel.h"}
|
|
|
|
Now you can use iksemel functions and compile your source. In able to link
|
|
your compiled object files and generate your executable program, you have to
|
|
link with iksemel library. This can be done with:
|
|
|
|
@example
|
|
gcc -o myprg src1.o src2.o src3.o -liksemel
|
|
@end example
|
|
|
|
iksemel registers itself with pkg-config while installing, so if you are using
|
|
autotools in your program, you can simply check the availability of iksemel
|
|
and configure your build process accordingly with:
|
|
|
|
@example
|
|
PKG_CHECK_MODULES(IKSEMEL,iksemel,,exit)
|
|
@end example
|
|
|
|
This would result in IKSEMEL_LIBS and IKSEMEL_CFLAGS substitution variables
|
|
set to correct values.
|
|
|
|
@node Tutorials,Development,Introduction,Top
|
|
@chapter Tutorials
|
|
|
|
@ifinfo
|
|
@menu
|
|
* Parsing an XML Document::
|
|
|
|
* Working with XML Trees::
|
|
|
|
* XML Streams::
|
|
|
|
* Writing a Jabber Client::
|
|
|
|
* Utility Functions::
|
|
@end menu
|
|
@end ifinfo
|
|
|
|
|
|
@comment ============================================================
|
|
@node Parsing an XML Document,Working with XML Trees,,Tutorials
|
|
@section Parsing an XML Document
|
|
|
|
iksemel parser sequentally processes the XML document. Each encountered XML
|
|
element (i.e. tags, character data, comments, processing instructions, etc.)
|
|
is reported to your application by calling the hook functions you have provided.
|
|
This type of interface is called SAX (serial access) interface.
|
|
|
|
@tindex iksparser
|
|
Parser stores its state in a small structure. This structure is referenced by
|
|
@code{iksparser} type, and managed with following functions:
|
|
|
|
@deftypefun iksparser* iks_sax_new (void* @var{user_data}, iksTagHook* @var{tagHook}, iksCDataHook* @var{cdataHook});
|
|
This function allocates and initializes a parser structure. If allocation fails,
|
|
NULL value is returned. @var{user_data} is passed directly to hook functions.
|
|
@end deftypefun
|
|
|
|
@deftp Typedef iksTagHook
|
|
int iksTagHook (void* @var{user_data}, char* @var{name}, char** @var{atts}, int @var{type});
|
|
|
|
This function is called when a tag parsed. @var{name} is the name of the tag. If tag has
|
|
no attributes @var{atts} is NULL, otherwise it contains a null terminated list of
|
|
pointers to tag's attributes and their values. If return value isn't @code{IKS_OK},
|
|
it is passed immediately to the caller of the @code{iks_parse}.
|
|
|
|
@var{type} is one of the following:
|
|
@table @code
|
|
@item IKS_OPEN
|
|
Opening tag, i.e. <tag attr='value'>
|
|
@item IKS_CLOSE
|
|
Closing tag, i.e. </tag>
|
|
@item IKS_SINGLE
|
|
Standalone tag, i.e. <tag attr='value'/>
|
|
@end table
|
|
@end deftp
|
|
|
|
@deftp Typedef iksCDataHook
|
|
int iksCDataHook (void* @var{user_data}, char* @var{data}, size_t @var{len});
|
|
|
|
@var{data} is a pointer to the character data. Encoding is UTF-8 and it isn't terminated
|
|
with a null character. Size of the data is given with @var{len} in bytes. This function
|
|
can be called several times with smaller sized data for a single string. If
|
|
return value isn't @code{IKS_OK}, it is passed immediately to the caller of the
|
|
@code{iks_parse}.
|
|
@end deftp
|
|
|
|
@deftypefun int iks_parse (iksparser* @var{prs}, char *@var{data}, size_t @var{len}, int @var{finish});
|
|
You give XML document to the parser with this function. @var{data}
|
|
is a @var{len} bytes string. If @var{len} is zero, data must be a null
|
|
terminated string.
|
|
|
|
If @var{finish} value is zero, parser waits for more data later. If you
|
|
want to finish parsing without giving data, call it like:
|
|
@example
|
|
iks_parse (my_parser, NULL, 0, 1);
|
|
@end example
|
|
|
|
You should check the return value for following conditions:
|
|
@table @code
|
|
@item IKS_OK
|
|
There isn't any problem.
|
|
@item IKS_NOMEM
|
|
Not enough memory.
|
|
@item IKS_BADXML
|
|
Document is not well-formed.
|
|
@item IKS_HOOK
|
|
Your hook decided that there is an error.
|
|
@end table
|
|
@end deftypefun
|
|
|
|
@deftypefun void iks_parser_delete (iksparser* @var{prs});
|
|
This function frees parser structure and associated data.
|
|
@end deftypefun
|
|
|
|
Now we have learned how to create and use a sax parser. Lets parse a simple
|
|
XML document. Write following code into a @file{test.c} file.
|
|
|
|
@smallexample
|
|
#include <stdio.h>
|
|
#include <iksemel.h>
|
|
|
|
int pr_tag (void *udata, char *name, char **atts, int type)
|
|
@{
|
|
switch (type) @{
|
|
case IKS_OPEN:
|
|
printf ("TAG <%s>\n", name);
|
|
break;
|
|
case IKS_CLOSE:
|
|
printf ("TAG </%s>\n", name);
|
|
break;
|
|
case IKS_SINGLE:
|
|
printf ("TAG <%s/>\n", name);
|
|
break;
|
|
@}
|
|
if (atts) @{
|
|
int i = 0;
|
|
while (atts[i]) @{
|
|
printf (" ATTRIB %s='%s'\n", atts[i], atts[i+1]);
|
|
i += 2;
|
|
@}
|
|
@}
|
|
return IKS_OK;
|
|
@}
|
|
|
|
enum ikserror pr_cdata (void *udata, char *data, size_t len)
|
|
@{
|
|
int i;
|
|
printf ("CDATA [");
|
|
for (i = 0; i < len; i++)
|
|
putchar (data[i]);
|
|
printf ("]\n");
|
|
return IKS_OK;
|
|
@}
|
|
|
|
int main (int argc, char *argv[])
|
|
@{
|
|
iksparser *p;
|
|
p = iks_sax_new (NULL, pr_tag, pr_cdata);
|
|
switch (iks_parse (p, argv[1], 0, 1)) @{
|
|
case IKS_OK:
|
|
puts ("OK");
|
|
break;
|
|
case IKS_NOMEM:
|
|
puts ("Not enough memory");
|
|
exit (1);
|
|
case IKS_BADXML:
|
|
puts ("XML document is not well-formed");
|
|
exit (2);
|
|
case IKS_HOOK:
|
|
puts ("Our hooks didn't like something");
|
|
exit (2);
|
|
@}
|
|
iks_parser_delete (p);
|
|
return 0;
|
|
@}
|
|
@end smallexample
|
|
|
|
Now compile and test it with:
|
|
|
|
@example
|
|
gcc -o test test.c -liksemel
|
|
./test "<test>Hello<br/>World!</test>"
|
|
./test "<lala a='12' b='42'/>"
|
|
@end example
|
|
|
|
@heading Error Handling
|
|
|
|
XML standart states that once an error is detected, the processor must not continue
|
|
normal processing (i.e. it must not pass character data or markup information to
|
|
the application). So iksemel stops processing immediately when it encounters a
|
|
syntax error, or one of your hook functions return any one value than @code{IKS_OK},
|
|
and @code{iks_parse} function returns with the error code.
|
|
|
|
Since it is useful for debugging, iksemel provides functions to get position of
|
|
the error. Position is usually at the starting character for syntax errors. Since
|
|
your hooks are called after whole element (i.e. markup or character data) is
|
|
passed, position is at the end of the erroneous element for @code{IKS_HOOK} errors.
|
|
|
|
@deftypefun {unsigned long} iks_nr_bytes (iksparser* @var{prs});
|
|
Returns how many number of bytes parsed.
|
|
@end deftypefun
|
|
|
|
@deftypefun {unsigned long} iks_nr_lines (iksparser* @var{prs});
|
|
Returns how many number of lines parsed.
|
|
@end deftypefun
|
|
|
|
If you want to parse another document with your parser again, you should use
|
|
the following function to reset your parser.
|
|
|
|
@deftypefun void iks_parser_reset (iksparser* @var{prs});
|
|
Resets the parser's internal state.
|
|
@end deftypefun
|
|
|
|
|
|
@comment ============================================================
|
|
@node Working with XML Trees,XML Streams,Parsing an XML Document,Tutorials
|
|
@section Working with XML Trees
|
|
|
|
SAX interface uses very little memory, but it forces you to access XML
|
|
documents sequentally. In many cases you want to keep a tree like
|
|
representation of XML document in memory and want to access and
|
|
modify its content randomly.
|
|
|
|
iksemel provides functions for efficiently creating such trees either
|
|
from documents or programmaticaly. You can access and modify this
|
|
tree and can easily generate a new XML document from the tree.
|
|
|
|
This is called DOM (Document Object Model) interface.
|
|
|
|
@ifinfo
|
|
@menu
|
|
* Memory Management::
|
|
|
|
* Creating a Tree::
|
|
|
|
* Accessing the Tree::
|
|
|
|
* Converting a Tree into an XML Document::
|
|
|
|
* Parsing an XML Document into a Tree::
|
|
@end menu
|
|
@end ifinfo
|
|
|
|
|
|
@comment ============================================================
|
|
@node Memory Management,Creating a Tree,,Working with XML Trees
|
|
@subsection Memory Management
|
|
|
|
Since keeping whole document content uses a lot of memory and requires
|
|
many calls to OS's memory allocation layer, iksemel uses a simple object
|
|
stack system for minimizing calls to the @code{malloc} function and releasing
|
|
all the memory associated with a tree in a single step.
|
|
|
|
A parsed XML tree contains following objects:
|
|
@table @samp
|
|
@item Nodes
|
|
These are basic blocks of document. They can contain a tag, attribute pair
|
|
of a tag, or character data. Tag nodes can also contain other nodes as
|
|
children. Node structure has a small fixed size depending on the node type.
|
|
@item Names
|
|
Names of tags and attributes. They are utf-8 encoded small strings.
|
|
@item Character Data
|
|
They are similar to names but usually much bigger.
|
|
@end table
|
|
|
|
iksemel's object stack has two separate areas for keeping these data objects.
|
|
Meta chunk contains all the structures and aligned data, while the data chunk
|
|
contains strings. Each chunk starts with a choosen size memory block, then
|
|
when necessary more blocks allocated for providing space. Unless there is a big
|
|
request, each block is double the size of the previous block, thus real memory
|
|
needs are quickly reached without allocating too many blocks, or wasting
|
|
memory with too big blocks.
|
|
|
|
@deftp Typedef ikstack
|
|
This is a structure defining the object stack. Its fields are private
|
|
and subject to change with new iksemel releases.
|
|
@end deftp
|
|
|
|
@deftypefun {ikstack *} iks_stack_new (size_t @var{meta_chunk}, size_t @var{data_chunk});
|
|
Creates an object stack. @var{meta_chunk} is the initial size of the
|
|
data block used for structures and aligned data. @var{data_chunk} is
|
|
the initial size of the data block used for strings. They are both in byte units.
|
|
|
|
These two initial chunks and a small object stack structure is allocated in
|
|
one @code{malloc} call for optimization purproses.
|
|
@end deftypefun
|
|
|
|
@deftypefun {void *} iks_stack_alloc (ikstack * @var{stack}, size_t @var{size});
|
|
Allocates @var{size} bytes of space from the object stack's meta chunk.
|
|
Allocated space is aligned on platform's default alignment boundary and
|
|
isn't initialized. Returns a pointer to the space, or NULL if there isn't enough
|
|
space available and allocating a new block fails.
|
|
@end deftypefun
|
|
|
|
@deftypefun {void *} iks_stack_strdup (ikstack * @var{stack}, const char * @var{src}, size_t @var{len});
|
|
Copies given string @var{src} into the object stack's data chunk. Returns a
|
|
pointer to the new string, or NULL if there isn't enough space in the stack.
|
|
If @var{len} is zero string must be null terminated.
|
|
@end deftypefun
|
|
|
|
@deftypefun void iks_stack_delete (ikstack * @var{stack});
|
|
Gives all memory associated with object stack to the system.
|
|
@end deftypefun
|
|
|
|
Since character data sections are usually parsed in separate blocks,
|
|
a growable string implementation is necessary for saving memory.
|
|
|
|
@deftypefun {char *} iks_stack_strcat (ikstack *@var{stack}, char *@var{old}, size_t @var{old_len}, const char *@var{src}, size_t @var{src_len});
|
|
This function appends the string @var{src} to the string @var{old} in the
|
|
stack's data chunk. If @var{old} is NULL it behaves like @code{iks_stack_strdup}.
|
|
Otherwise @var{old} has to be a string created with @code{iks_stack_strdup}
|
|
or @code{iks_stack_strcat} functions.
|
|
|
|
If @var{old_len} or @var{src_len} is zero, corresponding string must be null
|
|
terminated.
|
|
|
|
Since string can be moved into another block of the data chunk, you must use the
|
|
returned value for new string, and must not reference to @var{old} anymore.
|
|
Return value can be NULL if there isn't enough space in stack, and allocating a
|
|
new block fails.
|
|
@end deftypefun
|
|
|
|
|
|
@comment ============================================================
|
|
@node Creating a Tree,Accessing the Tree,Memory Management,Working with XML Trees
|
|
@subsection Creating a Tree
|
|
|
|
@deftp Typedef iks
|
|
This is a structure defining a XML node. Its fields are private and only
|
|
accessed by following functions.
|
|
@end deftp
|
|
|
|
@deftypefun iks* iks_new (const char *@var{name});
|
|
Creates an object stack and creates a IKS_TAG type of node with given
|
|
tag name inside the stack. Tag name is also copied into the stack.
|
|
Returns the node pointer, or NULL if there isn't enough memory.
|
|
@end deftypefun
|
|
|
|
@deftypefun iks* iks_new_within (const char *@var{name}, ikstack* @var{stack});
|
|
Creates a IKS_TAG type of node with the given tag name. Node and tag
|
|
name is allocated inside the given object stack. Returns the node
|
|
pointer, or NULL if there isn't enough memory.
|
|
@end deftypefun
|
|
|
|
@deftypefun iks* iks_insert (iks *@var{x}, const char *@var{name});
|
|
Creates a IKS_TAG type of node with the given tag name. Node and tag
|
|
name is allocated inside the @var{x} node's object stack and linked
|
|
to @var{x} as a child node. Returns the node pointer, or NULL if there
|
|
isn't enough memory.
|
|
@end deftypefun
|
|
|
|
@deftypefun iks* iks_insert_cdata (iks* @var{x}, const char* @var{data}, size_t @var{len});
|
|
Creates a IKS_CDATA type of node with given character data. Node is
|
|
allocated inside the @var{x} node's object stack and linked to @var{x}
|
|
as a child node. Data is copied as well. If @var{len} is zero data must
|
|
be a null terminated string. Returns the node pointer, or NULL if
|
|
there isn't enough memory.
|
|
@end deftypefun
|
|
|
|
@deftypefun iks* iks_insert_attrib (iks* @var{x}, const char* @var{name}, const char* @var{value});
|
|
Creates a IKS_ATTRIBUTE type of node with given attribute name and the
|
|
value. Node is allocated inside the @var{x} node's object stack and
|
|
linked to @var{x} as an attribute node. Attribute name and value is
|
|
copied as well. Returns the node pointer, or NULL if there isn't
|
|
enough memory.
|
|
|
|
Reinserting another value with same attribute name changes an attribute's
|
|
value. If @var{value} is NULL, attribute is removed from the tag.
|
|
@end deftypefun
|
|
|
|
@deftypefun iks* iks_insert_node (iks* @var{x}, iks* @var{y});
|
|
Links node @var{y} to node @var{x} as a child node. Nodes are not copied
|
|
between object stacks, be careful.
|
|
@end deftypefun
|
|
|
|
@deftypefun void iks_hide (iks *@var{x});
|
|
Changes the links of the other nodes so that @var{x} becomes invisible.
|
|
It stays in the same object stack with neighbour nodes, be careful.
|
|
@end deftypefun
|
|
|
|
@deftypefun void iks_delete (iks *@var{x});
|
|
Frees the object stack of the node @var{x}.
|
|
@end deftypefun
|
|
|
|
Now lets create a tree representation of following XML document:
|
|
|
|
@example
|
|
<message type='chat' from='bob@@bd.com'>
|
|
<subject>song lyric</subject><priority>high</priority>
|
|
<body>
|
|
<em style='underline'>here is the correct version:</em>
|
|
i just don't see why i should even care
|
|
it's not dark yet, but it's getting there
|
|
</body>
|
|
</message>
|
|
@end example
|
|
|
|
here is the code:
|
|
|
|
@example
|
|
iks *x, *y, *z;
|
|
|
|
x = iks_new ("message");
|
|
iks_insert_attrib (x, "type", "chat");
|
|
iks_insert_attrib (x, "from", "bob@@bd.com");
|
|
iks_insert_cdata (x, "\n", 1);
|
|
iks_insert_cdata (iks_insert (x, "subject"), "song lyric", 10);
|
|
iks_insert_cdata (iks_insert (x, "priority"), "high", 4);
|
|
iks_insert_cdata (x, "\n", 1);
|
|
y = iks_insert (x, "body");
|
|
iks_insert_cdata (y, "\n", 1);
|
|
z = iks_insert (y, "em");
|
|
iks_insert_attrib (z, "style", "underline");
|
|
iks_insert_cdata (z, "here is the correct version", 0);
|
|
iks_insert_cdata (y, "\n", 1);
|
|
iks_insert_cdata (y, "i just don't see why", 0);
|
|
iks_insert_cdata (y, "i should even care\n", 0);
|
|
iks_insert_cdata (y, "it's not dark yet,", 0);
|
|
iks_insert_cdata (y, "but it's getting there\n", 0);
|
|
iks_insert_cdata (x, "\n", 1);
|
|
@end example
|
|
|
|
Notice how newlines are inserted for proper formatting of document. They aren't
|
|
necessary for representing data, but they make it easier to read document for
|
|
humans.
|
|
|
|
Also notice how @code{iks_insert} and @code{iks_insert_cdata} chained.
|
|
|
|
There are also functions for duplicating xml trees. They are:
|
|
|
|
@deftypefun {iks *} iks_copy (iks* @var{x});
|
|
Creates a full copy of the tree in a newly created object stack.
|
|
@end deftypefun
|
|
|
|
@deftypefun {iks *} iks_copy_within (iks* @var{x}, ikstack *@var{s});
|
|
Creates a full copy of the tree in given object stack.
|
|
@end deftypefun
|
|
|
|
@comment ============================================================
|
|
@node Accessing the Tree,Converting a Tree into an XML Document,Creating a Tree,Working with XML Trees
|
|
@subsection Accessing a Tree
|
|
|
|
Basic access functions allow you to move on the tree:
|
|
|
|
@deftypefun iks* iks_next (iks* @var{x});
|
|
@end deftypefun
|
|
@deftypefun iks* iks_prev (iks* @var{x});
|
|
@end deftypefun
|
|
@deftypefun iks* iks_parent (iks* @var{x});
|
|
@end deftypefun
|
|
@deftypefun iks* iks_child (iks* @var{x});
|
|
@end deftypefun
|
|
@deftypefun iks* iks_attrib (iks* @var{x});
|
|
@end deftypefun
|
|
|
|
These functions return a pointer to the next, previous, parent, first child,
|
|
and first attribute node of the given node @var{x}. If that node doesn't
|
|
exist or @var{x} is NULL, a NULL value is returned.
|
|
|
|
@deftypefun {iks *} iks_root (iks *@var{x});
|
|
Returns the topmost parent node of the @var{x}.
|
|
@end deftypefun
|
|
|
|
@deftypefun iks* iks_next_tag (iks* @var{x});
|
|
@end deftypefun
|
|
@deftypefun iks* iks_prev_tag (iks* @var{x});
|
|
@end deftypefun
|
|
@deftypefun iks* iks_first_tag (iks* @var{x});
|
|
@end deftypefun
|
|
|
|
These functions return a pointer to the next, previous, first child node
|
|
of the given node @var{x}. Only tag nodes are considered, other type
|
|
of the nodes are skipped. If such a node doesn't exist or @var{x} is NULL,
|
|
a NULL value is returned.
|
|
|
|
Another group of functions allow you to access specific information and
|
|
content of the nodes:
|
|
|
|
@deftypefun ikstack* iks_stack (iks* @var{x});
|
|
Returns the object stack which node @var{x} stays.
|
|
@end deftypefun
|
|
|
|
@deftypefun {enum ikstype} iks_type (iks* @var{x});
|
|
Returns the type of the node.
|
|
|
|
@tindex ikstype
|
|
@table @code
|
|
@item IKS_TAG
|
|
Node is a tag and can contain child nodes and attributes.
|
|
@item IKS_CDATA
|
|
Node contains character data.
|
|
@item IKS_ATTRIBUTE
|
|
Node contains an attribute and its value.
|
|
@end table
|
|
@end deftypefun
|
|
|
|
@deftypefun char* iks_name (iks* @var{x});
|
|
Returns the name of the tag for nodes with the type @var{IKS_TAG}.
|
|
Returns an attribute's name for nodes of type IKS_ATTRIBUTE.
|
|
@end deftypefun
|
|
|
|
@deftypefun char* iks_cdata (iks* @var{x});
|
|
Returns a pointer to node's character data if available, NULL otherwise.
|
|
Returns an attribute's value for nodes of type IKS_ATTRIBUTE.
|
|
@end deftypefun
|
|
|
|
@deftypefun size_t iks_cdata_size (iks *@var{x});
|
|
Returns the size of the node's character data in bytes.
|
|
@end deftypefun
|
|
|
|
@deftypefun int iks_has_children (iks *@var{x});
|
|
Returns a non-zero value if node @var{x} has a child node.
|
|
@end deftypefun
|
|
|
|
@deftypefun int iks_has_attribs (iks *@var{x});
|
|
Returns a non-zero value if node @var{x} has attributes.
|
|
@end deftypefun
|
|
|
|
Last group of the functions simplifies finding and accessing the content
|
|
of a specific node:
|
|
|
|
@deftypefun iks* iks_find (iks *@var{x}, const char *@var{name});
|
|
Searches a IKS_TAG type of node with @var{name} as tag name in child
|
|
nodes of @var{x}. Returns a pointer to the node if found, NULL otherwise.
|
|
@end deftypefun
|
|
|
|
@deftypefun char* iks_find_cdata (iks* @var{x}, const char* @var{name});
|
|
Searches a IKS_TAG type of node with @var{name} as tag name in child
|
|
nodes of @var{x}. Returns a pointer to the character data of the node's
|
|
first child node if found, NULL otherwise.
|
|
@end deftypefun
|
|
|
|
@deftypefun char* iks_find_attrib (iks* @var{x}, const char* @var{name});
|
|
Searches an attribute with given name in attributes of the @var{x}.
|
|
Returns a pointer to attribute value if found, NULL otherwise.
|
|
@end deftypefun
|
|
|
|
@deftypefun {iks *} iks_find_with_attrib (iks *@var{x}, const char *@var{tagname}, const char *@var{attrname}, const char *@var{value});
|
|
Searches for a child tag of @var{x} which has an attribute with name
|
|
@var{attrname} and value @var{value}. If @var{tagname} isn't NULL,
|
|
name of the tag must also match. Returns a pointer to the node if found,
|
|
NULL otherwise.
|
|
@end deftypefun
|
|
|
|
Here is an example which demonstrates accessing file names in a fictitious
|
|
XML playlist file:
|
|
|
|
@example
|
|
<playlist>
|
|
<item type='mpg'>
|
|
<name>/home/madcat/download/matrix_rev_trailer.mpg</name>
|
|
<duration>1:17</duration>
|
|
</item>
|
|
<item type='rm'>
|
|
<name>/home/madcat/anim/clementine_ep1.rm</name>
|
|
<duration>22:00</duration>
|
|
</item>
|
|
<item type='avi'>
|
|
<name>/home/madcat/anim/futurama/ep101.avi</name>
|
|
<subtitle>/home/madcat/subs/futurama/ep101.txt</subtitle>
|
|
<duration>30:00</duration>
|
|
</item>
|
|
<repeat/>
|
|
<fullscreen/>
|
|
<noui/>
|
|
</playlist>
|
|
@end example
|
|
|
|
and here is the code:
|
|
|
|
@example
|
|
#include <stdio.h>
|
|
#include <iksemel.h>
|
|
|
|
int main (int argc, char *argv[])
|
|
@{
|
|
iks *x, *y;
|
|
int e;
|
|
|
|
if (argc < 2) @{
|
|
printf ("usage: %s <playlistfile>", argv[0]);
|
|
return 0;
|
|
@}
|
|
e = iks_load (argv[1], &x);
|
|
if (e != IKS_OK) @{
|
|
printf ("parse error %d\n", e);
|
|
return 1;
|
|
@}
|
|
if (iks_find (x, "repeat")) puts ("repeat mode enabled");
|
|
y = iks_child (x);
|
|
while (y) @{
|
|
if (iks_type (y) == IKS_TAG
|
|
&& strcmp (iks_name (y), "item") == 0) @{
|
|
printf ("Filename: [%s]\n", iks_find_cdata (y, "name"));
|
|
@}
|
|
y = iks_next (y);
|
|
@}
|
|
iks_delete (x);
|
|
return 0;
|
|
@}
|
|
@end example
|
|
|
|
|
|
@comment ============================================================
|
|
@node Converting a Tree into an XML Document,Parsing an XML Document into a Tree,Accessing the Tree,Working with XML Trees
|
|
@subsection Converting a Tree to an XML Document
|
|
|
|
There is a function for converting given XML tree into a null terminated string.
|
|
|
|
@deftypefun {char *} iks_string (ikstack* @var{stack}, iks* @var{x});
|
|
Converts given tree into a string. String is created inside the given object
|
|
stack. Returns a pointer to the string, or NULL if there isn't enough memory
|
|
available.
|
|
|
|
If @var{stack} is NULL, string is created inside an @code{iks_malloc}ed buffer.
|
|
You can free it later with @code{iks_free} function.
|
|
@end deftypefun
|
|
|
|
Here is an example which builds a tree and print it.
|
|
|
|
@example
|
|
iks *x;
|
|
char *t;
|
|
|
|
x = iks_new ("test");
|
|
iks_insert_cdata (iks_insert (x, "a"), "1234", 4);
|
|
iks_insert (x, "br");
|
|
iks_insert_cdata (x, "1234", 4);
|
|
t = iks_string (iks_stack (x), x);
|
|
puts (t);
|
|
iks_delete (x);
|
|
@end example
|
|
|
|
|
|
@comment ============================================================
|
|
@node Parsing an XML Document into a Tree,,Converting a Tree into an XML Document,Working with XML Trees
|
|
@subsection Parsing a Document into a Tree
|
|
|
|
If you want to automatically convert an XML document into a tree, you can use
|
|
iksemel's DOM parser. It is created with following function:
|
|
|
|
@deftypefun iksparser* iks_dom_new (iks **@var{iksptr});
|
|
Creates a DOM parser. A pointer to the created XML tree is put into the
|
|
variable pointed by @var{iksptr}. Returns a pointer to the parser, or NULL
|
|
is there isn't enough memory.
|
|
@end deftypefun
|
|
|
|
Usage is same as SAX parser. You feed the data with @code{iks_parse}, and if
|
|
there isn't an error, you can access to your tree from variable @code{*iksptr}.
|
|
|
|
Here is a simple example:
|
|
|
|
@example
|
|
iks *x;
|
|
iksparser *p;
|
|
|
|
p = iks_dom_new (&x);
|
|
if (IKS_OK != iks_parse (p, "<a>bcd</a>", 9, 1)) @{
|
|
puts ("parse error");
|
|
@}
|
|
/* x is useable after that point */
|
|
|
|
/* this will print 'bcd' */
|
|
printf ("%s\n", iks_cdata (iks_child (x)));
|
|
@end example
|
|
|
|
If you know the size of the file ahead, or you have an approximate idea,
|
|
you can tell this to the dom parser for choosing a better memory allocation
|
|
strategy. Here is the function for this.
|
|
|
|
@deftypefun void iks_set_size_hint (iksparser *@var{prs}, size_t @var{approx_size});
|
|
Parser @var{prs} must be a dom type parser. @var{approx_size} is the
|
|
expected size of the xml document. Parser chooses its chunk size
|
|
based on this information. Helps performance while processing big files.
|
|
@end deftypefun
|
|
|
|
If you already have your XML document in memory, you can simply parse
|
|
it with:
|
|
|
|
@deftypefun {iks *} iks_tree (const char *@var{xml_str}, size_t @var{len}, int *@var{err});
|
|
This function parses the buffer pointed by @var{xml_str}. If @var{len} is zero
|
|
buffer is considered as a null terminated utf8 string. Returns the parsed tree,
|
|
or NULL if there is an error. If @var{err} is not NULL, actual error code (returned
|
|
by iks_parse) is put there.
|
|
@end deftypefun
|
|
|
|
Most of the times you want to load your configuration (or similar) files directly
|
|
into trees. iksemel provides two functions to greatly simplify this:
|
|
|
|
@deftypefun int iks_load (const char *@var{fname}, iks **@var{xptr});
|
|
Loads the XML file. Tree is placed into the variable pointed by @var{xptr}.
|
|
@end deftypefun
|
|
|
|
@deftypefun int iks_save (const char *@var{fname}, iks *@var{x});
|
|
Converts tree @var{x} into a string and saves to the file.
|
|
@end deftypefun
|
|
|
|
Both functions return same error codes as @code{iks_parse}. Some additional
|
|
error codes are defined for indicating file problems. They are:
|
|
|
|
@table @code
|
|
@item IKS_FILE_NOFILE
|
|
A file with the given name doesn't exist.
|
|
@item IKS_FILE_NOACCESS
|
|
Cannot open file. Possibly a permission problem.
|
|
@item IKS_FILE_RWERR
|
|
Read or write operation failed.
|
|
@end table
|
|
|
|
Here is a simple example which parses a file and saves it into another:
|
|
|
|
@example
|
|
iks *x;
|
|
|
|
if (IKS_OK != iks_load ("file1.xml", &x)) @{
|
|
puts ("loading error");
|
|
@}
|
|
if (IKS_OK != iks_save ("file2.xml", x)) @{
|
|
puts ("saving error");
|
|
@}
|
|
@end example
|
|
|
|
|
|
@comment ============================================================
|
|
@node XML Streams,Writing a Jabber Client,Working with XML Trees,Tutorials
|
|
@section XML Streams
|
|
|
|
XML streams function as containers for any XML chunks sent asynchronously
|
|
between network endpoints. They are used for asyncronously exchanging
|
|
relatively small payload of structured information between entities.
|
|
|
|
A stream is initiated by one of hosts connecting to the other, and sending a
|
|
<stream:stream> tag. Receiving entity replies with a second XML stream
|
|
back to the initiating entity within the same connection. Each unit of
|
|
information is send as a direct child tag of the <stream:stream> tag.
|
|
Stream is closed with </stream:stream>.
|
|
|
|
XML streams use a subset of XML. Specifically they should not contain
|
|
processing instructions, non-predefined entities, comments, or DTDs.
|
|
|
|
Jabber protocol uses XML streams for exchanging messages, presence
|
|
information, and other information like authorization, search, time and
|
|
version queries, protocol extensions.
|
|
|
|
iksemel provides you a stream parser, which automatically handles connection
|
|
to the server, and calls your hook function with incoming information
|
|
parsed and converted to an XML tree.
|
|
|
|
You can create such a parser with:
|
|
|
|
@deftypefun iksparser* iks_stream_new (char* @var{name_space}, void* @var{user_data}, iksStreamHook* @var{streamHook});
|
|
Allocates and initalizes a stream parser. @var{name_space} indicates the
|
|
stream type, jabber clients use "jabber:client" namespace. @var{user_data}
|
|
is passed directly to your hook function.
|
|
@end deftypefun
|
|
|
|
@deftp Typedef iksStreamHook
|
|
int iksStreamHook (void* @var{user_data}, int @var{type}, iks* @var{node});
|
|
|
|
Depending on the value of the @var{type}, @var{node} contains:
|
|
@table @code
|
|
@item IKS_NODE_START
|
|
Got the <stream:stream> tag, namespace, stream id and other information
|
|
is contained in the @var{node}.
|
|
@item IKS_NODE_NORMAL
|
|
A first level child of the <stream:stream> tag is received. @var{node} contains
|
|
the parsed tag. If you are connected to a jabber server, you can get <message>,
|
|
<presence>, or <iq> tags.
|
|
@item IKS_NODE_ERROR
|
|
Got a <stream:error> tag, details can be accessed from @var{node}.
|
|
@item IKS_NODE_STOP
|
|
</stream:stream> tag is received or connection is closed, @var{node} is @code{NULL}.
|
|
@end table
|
|
|
|
Freeing the node with @code{iks_delete} is up to you.
|
|
@end deftp
|
|
|
|
You can manually feed this parser with @code{iks_parse} function, but using
|
|
iksemel's connection facilities is easier for most of the cases.
|
|
|
|
This functions return @code{IKS_OK} for success. Error codes of @code{iks_parse}
|
|
are used in same manner. Following additional codes are defined for
|
|
network related problems:
|
|
|
|
@table @code
|
|
@item IKS_NET_NODNS
|
|
Hostname lookup failed. Possible reasons: hostname is incorrect,
|
|
you are not online, your dns server isn't accessible.
|
|
@item IKS_NET_NOSOCK
|
|
Socket cannot created.
|
|
@item IKS_NET_NOCONN
|
|
Connection attemp failed. Possible reasons: host is not an XML stream
|
|
server, port number is wrong, server is busy or closed for the moment.
|
|
@item IKS_NET_RWERR
|
|
@code{send} or @code{recv} call is failed when attempting to exchange
|
|
the data with the server. You should close the connection with @code{iks_disconnect}
|
|
after getting this error from data transfer functions.
|
|
@end table
|
|
|
|
@deftypefun int iks_connect_tcp (iksparser *@var{prs}, const char *@var{server}, int @var{port});
|
|
This function connects the parser to a server and sends stream header for you.
|
|
@var{server} is the host name of the server and @var{port} is the tcp port
|
|
number which server is listening to. You can use @code{IKS_JABBER_PORT}
|
|
macro for the default jabber client port (5222).
|
|
@end deftypefun
|
|
|
|
@deftypefun int iks_connect_fd (iksparser *@var{prs}, int @var{fd});
|
|
Attaches parser to an already opened connection. @var{fd} is the socket
|
|
descriptor. Note that @code{iks_disconnect} doesn't close the socket
|
|
for this kind of connection, opening and closing of the socket is up to your
|
|
application. Stream header is not sent automatically. You can use
|
|
@code{iks_send_header} function for sending it.
|
|
@end deftypefun
|
|
|
|
@deftypefun void iks_disconnect (iksparser *@var{prs});
|
|
Closes connection to the server, and frees connection resources.
|
|
@end deftypefun
|
|
|
|
After successfully connecting to a server, you can use following functions
|
|
for exchanging information with server.
|
|
|
|
@deftypefun int iks_recv (iksparser* @var{prs}, int @var{timeout});
|
|
If @var{timeout} is @code{-1}, waits until some data arrives from server,
|
|
and process the data. Your stream hook can be called if a complete
|
|
chunk is arrived.
|
|
|
|
If @var{timeout} is a positive integer, @code{iks_recv} returns if no data
|
|
arrives for @var{timeout} seconds.
|
|
|
|
If @var{timeout} is zero, @code{iks_recv} checks if there is any data
|
|
waiting at the network buffer, and returns without waiting for data.
|
|
@end deftypefun
|
|
|
|
@deftypefun int iks_fd (iksparser* @var{prs});
|
|
Returns the file descriptor of the connected socket. You can use this in
|
|
your @code{select} function or some other input loop to act whenever
|
|
some data from the server arrives. This value of only valid between
|
|
a successful @code{iks_connect_tcp} and @code{iks_disconnect}.
|
|
@end deftypefun
|
|
|
|
@deftypefun int iks_send (iksparser* @var{prs}, iks* @var{x});
|
|
Converts the tree given in @var{x} to a string, and sends to the server.
|
|
String is created inside the object stack of @var{x}.
|
|
@end deftypefun
|
|
|
|
@deftypefun int iks_send_raw (iksparser* @var{prs}, char* @var{xmlstr});
|
|
Sends the string given in @var{xmlstr} to the server.
|
|
@end deftypefun
|
|
|
|
@deftypefun int iks_send_header (iksparser *@var{prs}, char *@var{to});
|
|
Sends the stream header. @var{to} is the name of the server.
|
|
Normally @code{iks_connect_tcp} function calls this for you. This
|
|
is only useful if you are using @code{iks_connect_fd}.
|
|
@end deftypefun
|
|
|
|
Sometimes it is useful to log incoming and outgoing data to your parser
|
|
for debugging your applications. iksemel provides a logging facility for you.
|
|
|
|
@deftypefun void iks_set_log_hook (iksparser* @var{prs}, iksLogHook* @var{logHook});
|
|
Sets the log function for your stream parser. You can't use this function
|
|
on any other type of parser.
|
|
@end deftypefun
|
|
|
|
@deftp Typedef iksLogHook
|
|
void iksLogHook (void* @var{user_data}, const char* @var{data}, size_t @var{size}, int @var{is_incoming});
|
|
|
|
@var{user_data} is same value which you give with @code{iks_stream_new}.
|
|
@var{data} is @var{size} bytes of data. Be very careful that this data may be
|
|
coming from other side of the connection and can contain malicius bytes. It isn't
|
|
checked by iksemel yet, so you should check it yourself before displaying or
|
|
passing to other systems in your application or computer. If @var{is_incoming}
|
|
is a non-zero value, data is incoming from server, otherwise it is outgoing to the
|
|
server.
|
|
@end deftp
|
|
|
|
|
|
@comment ============================================================
|
|
@node Writing a Jabber Client,Utility Functions,XML Streams,Tutorials
|
|
@section Writing a Jabber Client
|
|
|
|
@ifinfo
|
|
@menu
|
|
* Security::
|
|
|
|
* Packets::
|
|
|
|
* Packet Filter::
|
|
|
|
* Creating Common Packets::
|
|
|
|
@end menu
|
|
@end ifinfo
|
|
|
|
@comment ============================================================
|
|
@node Security,Packets,,Writing a Jabber Client
|
|
@subsection Security
|
|
|
|
iksemel supports TLS protocol for encrypted communication and SASL
|
|
protocol for authentication. TLS is handled by gnutls library.
|
|
|
|
@deftypefun int iks_has_tls (void);
|
|
If iksemel is compiled with gnutls library, this function returns a non-zero
|
|
value indicating you can try encrypted connection with the server.
|
|
@end deftypefun
|
|
|
|
@deftypefun int iks_start_tls (iksparser* @var{prs});
|
|
Starts a TLS handshake over already connected parser. Returns IKS_OK or
|
|
one of the IKS_NET_ errors. If handshake succeeds you'll get another
|
|
stream header from server.
|
|
@end deftypefun
|
|
|
|
@deftypefun int iks_is_secure (iksparser* @var{prs});
|
|
Returns a non-zero value if a secure connection is fully established
|
|
between server.
|
|
@end deftypefun
|
|
|
|
@deftypefun int iks_start_sasl (iksparser* @var{prs}, enum ikssasltype @var{type}, char* @var{username}, char* @var{pass});
|
|
Starts SASL operation.
|
|
@end deftypefun
|
|
|
|
See tools/iksroster.c for a good example.
|
|
|
|
@comment ============================================================
|
|
@node Packets,Packet Filter,Security,Writing a Jabber Client
|
|
@subsection Packets
|
|
|
|
iksemel can parse a jabber XML node and provide you a public packet
|
|
structure which contains information like node type and subtype, id,
|
|
namespace, sender's jabber id, etc.
|
|
|
|
This handles a lot of node parsing for you. Packets are also used in
|
|
the packet filter subsystem.
|
|
|
|
@deftypefun {ikspak *} iks_packet (iks *@var{x});
|
|
Takes a node from stream and extracts information from it to a packet structure.
|
|
Structure is allocated inside the node's object stack.
|
|
@end deftypefun
|
|
|
|
@tindex ikspak
|
|
@code{ikspak} structure has following fields:
|
|
|
|
@table @code
|
|
@item iks *x;
|
|
This is a pointer to the node.
|
|
@item iksid *from;
|
|
Sender's jabber id in parsed form. See below for @code{iksid} structure.
|
|
@item iks *query;
|
|
A pointer to the <query> tag for IQ nodes.
|
|
@item char *ns;
|
|
Namespace of the content for IQ nodes.
|
|
@item char *id;
|
|
ID of the node.
|
|
@item enum ikspaktype type;
|
|
Type of the node. Possible types are:
|
|
|
|
@table @code
|
|
@item IKS_PAK_NONE
|
|
Unknown node.
|
|
@item IKS_PAK_MESSAGE
|
|
Message node.
|
|
@item IKS_PAK_PRESENCE
|
|
Presence node with presence publishing operation.
|
|
@item IKS_PAK_S10N
|
|
Presence node with subscription operation.
|
|
@item IKS_PAK_IQ
|
|
IQ node.
|
|
@end table
|
|
@item enum iksubtype subtype;
|
|
Sub type of the node. Sub types for message nodes:
|
|
|
|
@table @code
|
|
@item IKS_TYPE_NONE
|
|
A normal message.
|
|
@item IKS_TYPE_CHAT
|
|
Private chat message.
|
|
@item IKS_TYPE_GROUPCHAT
|
|
Multi user chat message.
|
|
@item IKS_TYPE_HEADLINE
|
|
Message from a news source.
|
|
@item IKS_TYPE_ERROR
|
|
Message error.
|
|
@end table
|
|
|
|
Sub types for IQ nodes:
|
|
|
|
@table @code
|
|
@item IKS_TYPE_GET
|
|
Asks for some information.
|
|
@item IKS_TYPE_SET
|
|
Request for changing information.
|
|
@item IKS_TYPE_RESULT
|
|
Reply to get and set requests.
|
|
@item IKS_TYPE_ERROR
|
|
IQ error.
|
|
@end table
|
|
|
|
Sub types for subscription nodes:
|
|
|
|
@table @code
|
|
@item IKS_TYPE_SUBSCRIBE,
|
|
Asks for subscribing to the presence.
|
|
@item IKS_TYPE_SUBSCRIBED,
|
|
Grants subscription.
|
|
@item IKS_TYPE_UNSUBSCRIBE,
|
|
Asks for unsubscribing to the presence.
|
|
@item IKS_TYPE_UNSUBSCRIBED,
|
|
Cancels subscription.
|
|
@item IKS_TYPE_ERROR
|
|
Presence error.
|
|
@end table
|
|
|
|
Sub types for presence nodes:
|
|
|
|
@table @code
|
|
@item IKS_TYPE_PROBE,
|
|
Asks presence status.
|
|
@item IKS_TYPE_AVAILABLE,
|
|
Publishes entity as available. More information can be found in @code{show} field.
|
|
@item IKS_TYPE_UNAVAILABLE
|
|
Publishes entity as unavailable. More information can be found in @code{show} field.
|
|
@end table
|
|
@item enum ikshowtype show;
|
|
Presence state for the presence nodes.
|
|
|
|
@table @code
|
|
@item IKS_SHOW_UNAVAILABLE
|
|
Entity is unavailable.
|
|
@item IKS_SHOW_AVAILABLE
|
|
Entity is available.
|
|
@item IKS_SHOW_CHAT
|
|
Entity is free for chat.
|
|
@item IKS_SHOW_AWAY
|
|
Entity is away for a short time.
|
|
@item IKS_SHOW_XA
|
|
Entity is away for a long time.
|
|
@item IKS_SHOW_DND
|
|
Entity doesn't want to be disturbed.
|
|
@end table
|
|
@end table
|
|
|
|
iksemel has two functions to parse and compare jabber IDs.
|
|
|
|
@deftypefun {iksid *} iks_id_new (ikstack *@var{s}, const char *@var{jid});
|
|
Parses a jabber id into its parts. @code{iksid} structure is created inside
|
|
the @var{s} object stack.
|
|
@end deftypefun
|
|
|
|
@tindex iksid
|
|
@code{iksid} structure has following fields:
|
|
|
|
@table @code
|
|
@item char *user;
|
|
User name.
|
|
@item char *server;
|
|
Server name.
|
|
@item char *resource;
|
|
Resource.
|
|
@item char *partial;
|
|
User name and server name.
|
|
@item char *full;
|
|
User name, server name and resource.
|
|
@end table
|
|
|
|
You can access this fields and read their values. Comparing two parsed jabber
|
|
ids can be done with:
|
|
|
|
@deftypefun int iks_id_cmp (iksid *@var{a}, iksid *@var{b}, int @var{parts});
|
|
Compares @var{parts} of @var{a} and @var{b}. Part values are:
|
|
|
|
@table @code
|
|
@item IKS_ID_USER
|
|
@item IKS_ID_SERVER
|
|
@item IKS_ID_RESOURCE
|
|
@end table
|
|
|
|
@sp 1
|
|
You can combine this values with @code{or} operator. Some common combinations
|
|
are predefined for you:
|
|
|
|
@table @code
|
|
@item IKS_ID_PARTIAL
|
|
@code{IKS_ID_USER | IKS_ID_SERVER}
|
|
@item IKS_ID_FULL
|
|
@code{IKS_ID_USER | IKS_ID_SERVER | IKS_ID_RESOURCE}
|
|
@end table
|
|
|
|
Return value is @code{0} for equality. If entities are not equal a combination of
|
|
part values showing different parts is returned.
|
|
@end deftypefun
|
|
|
|
|
|
@comment ============================================================
|
|
@node Packet Filter,Creating Common Packets,Packets,Writing a Jabber Client
|
|
@subsection Packet Filter
|
|
|
|
Packet filter handles routing incoming packets to related functions.
|
|
|
|
@tindex iksfilter
|
|
@deftypefun {iksfilter *} iks_filter_new (void);
|
|
Creates a new packet filter.
|
|
@end deftypefun
|
|
|
|
@deftypefun void iks_filter_packet (iksfilter *@var{f}, ikspak *@var{pak});
|
|
Feeds the filter with given packet. Packet is compared to registered rules and
|
|
hook functions of the matching rules are called in most matched to least
|
|
matched order.
|
|
@end deftypefun
|
|
|
|
@deftypefun void iks_filter_delete (iksfilter *@var{f});
|
|
Frees filter and rules.
|
|
@end deftypefun
|
|
|
|
Rules are created with following function:
|
|
|
|
@tindex iksrule
|
|
@deftypefun {iksrule *} iks_filter_add_rule (iksfilter *@var{f}, iksFilterHook *@var{filterHook}, void *@var{user_data}, @dots{});
|
|
Adds a rule to the filter @var{f}. @var{user_data} is passed directly to your
|
|
hook function @var{filterHook}.
|
|
|
|
A rule consist of one or more type and value pairs. Possible types:
|
|
@table @code
|
|
@item IKS_RULE_ID
|
|
Compares @code{char *} value to packet ids.
|
|
@item IKS_RULE_FROM
|
|
Compares @code{char *} value to packet senders.
|
|
@item IKS_RULE_FROM_PARTIAL
|
|
Compares @code{char *} value to packet sender. Ignores resource part of jabber id.
|
|
@item IKS_RULE_NS
|
|
Compares @code{char *} value to namespace of iq packets.
|
|
@item IKS_RULE_TYPE
|
|
Compares @code{int} value to packet types.
|
|
@item IKS_RULE_SUBTYPE
|
|
Compares @code{int} value to packet sub types.
|
|
@item IKS_RULE_DONE
|
|
Terminates the rule pairs.
|
|
@end table
|
|
@end deftypefun
|
|
|
|
Here is an example which creates a filter and adds three rules:
|
|
@example
|
|
iksfilter *f;
|
|
|
|
f = iks_filter_new ();
|
|
iks_filter_add_rule (f, on_msg, NULL,
|
|
IKS_RULE_TYPE, IKS_PAK_MESSAGE,
|
|
IKS_RULE_DONE);
|
|
iks_filter_add_rule (f, on_auth_result, NULL,
|
|
IKS_RULE_TYPE, IKS_PAK_IQ,
|
|
IKS_RULE_SUBTYPE, IKS_TYPE_RESULT,
|
|
IKS_RULE_ID, "auth",
|
|
IKS_RULE_DONE);
|
|
iks_filter_add_rule (f, on_roster_push, NULL,
|
|
IKS_RULE_TYPE, IKS_PAK_IQ,
|
|
IKS_RULE_SUBTYPE, IKS_TYPE_SET,
|
|
IKS_RULE_NS, "jabber:iq:roster",
|
|
IKS_RULE_DONE);
|
|
@end example
|
|
|
|
@deftp Typedef iksFilterHook
|
|
int iksFilterHook (void *user_data, ikspak *pak);
|
|
|
|
Your hook is called with your @var{user_data} and matching packet @var{pak}.
|
|
You can return two different values from your hook:
|
|
@table @code
|
|
@item IKS_FILTER_PASS
|
|
Packet is forwarded to least matching rules.
|
|
@item IKS_FILTER_EAT
|
|
Filtering process for the packet ends.
|
|
@end table
|
|
@end deftp
|
|
|
|
You can remove the rules with following functions:
|
|
|
|
@deftypefun void iks_filter_remove_rule (iksfilter *@var{f}, iksrule *@var{rule});
|
|
Removes the rule from filter.
|
|
@end deftypefun
|
|
|
|
@deftypefun void iks_filter_remove_hook (iksfilter *@var{f}, iksFilterHook *@var{filterHook});
|
|
Remove the rules using @var{filterHook} function from filter.
|
|
@end deftypefun
|
|
|
|
|
|
@comment ============================================================
|
|
@node Creating Common Packets,,Packet Filter,Writing a Jabber Client
|
|
@subsection Creating Common Packets
|
|
|
|
A usual jabber network traffic contains many similar XML constructs. iksemel
|
|
provides several utility functions for creating them. They all generate an XML
|
|
tree, so you can add or modify some parts of the tree, and send to server then.
|
|
|
|
@deftypefun {iks *} iks_make_auth (iksid *@var{id}, const char *@var{pass}, const char *@var{sid});
|
|
Creates an authorization packet. @var{id} is your parsed jabber id, and @var{pass}
|
|
is your password.
|
|
|
|
If stream id @var{sid} isn't NULL, SHA1 authentication is used, otherwise password
|
|
is attached in plain text. You can learn stream id from @code{IKS_STREAM_START}
|
|
packet in your stream hook like this:
|
|
|
|
@example
|
|
char *sid;
|
|
|
|
if (type == IKS_STREAM_START) @{
|
|
sid = iks_find_attrib (node, "id");
|
|
@}
|
|
@end example
|
|
@end deftypefun
|
|
|
|
@deftypefun {iks *} iks_make_msg (enum iksubtype @var{type}, const char *@var{to}, const char *@var{body});
|
|
Creates a message packet. @var{type} is the message type, @var{to} is jabber id
|
|
of the recipient, @var{body} is the message.
|
|
@end deftypefun
|
|
|
|
@deftypefun {iks *} iks_make_s10n (enum iksubtype @var{type}, const char *@var{to}, const char *@var{msg});
|
|
Creates a presence packet for subscription operations. @var{type} is operation,
|
|
@var{to} is jabber id of the recipient, @var{msg} is a small message for
|
|
introducing yourself, or explaning the reason of why you are subscribing or
|
|
unsubscribing.
|
|
@end deftypefun
|
|
|
|
@deftypefun {iks *} iks_make_pres (enum ikshowtype @var{show}, const char *@var{status});
|
|
Creates a presence packet for publishing your presence. @var{show} is your
|
|
presence state and @var{status} is a message explaining why you are not
|
|
available at the moment, or what you are doing now.
|
|
@end deftypefun
|
|
|
|
@deftypefun {iks *} iks_make_iq (enum iksubtype @var{type}, const char *@var{xmlns});
|
|
Creates an IQ packet. @var{type} is operation type and @var{xmlns} is the
|
|
namespace of the content. You usually have to add real content to the <query>
|
|
tag before sending this packet.
|
|
@end deftypefun
|
|
|
|
|
|
@comment ============================================================
|
|
@node Utility Functions,,Writing a Jabber Client,Tutorials
|
|
@section Utility Functions
|
|
|
|
@subsection Memory Utilities
|
|
|
|
@deftypefun {void *} iks_malloc (size_t @var{size});
|
|
@end deftypefun
|
|
@deftypefun void iks_free (void *@var{ptr});
|
|
@end deftypefun
|
|
|
|
These are wrappers around ANSI malloc and free functions used by the
|
|
iksemel library itself. You can free the output of iks_string (only if you
|
|
passed it a NULL stack) with iks_free for example. That is important
|
|
if you are using a malloc debugger in your application but not in iksemel
|
|
or vice versa.
|
|
|
|
@comment ============================================================
|
|
@subsection String Utilities
|
|
|
|
@deftypefun {char *} iks_strdup (const char *@var{src});
|
|
@end deftypefun
|
|
@deftypefun int iks_strcmp (const char *@var{a}, const char *@var{b});
|
|
@end deftypefun
|
|
@deftypefun int iks_strcasecmp (const char *@var{a}, const char *@var{b});
|
|
@end deftypefun
|
|
@deftypefun int iks_strncmp (const char *@var{a}, const char *@var{b}, size_t @var{n});
|
|
@end deftypefun
|
|
@deftypefun int iks_strncasecmp (const char *@var{a}, const char *@var{b}, size_t @var{n});
|
|
@end deftypefun
|
|
@deftypefun size_t iks_strlen (const char *@var{src});
|
|
@end deftypefun
|
|
|
|
These functions work exactly like their ANSI equivalents except that they allow
|
|
NULL values for string pointers. If @var{src} is NULL, iks_strdup and iks_strlen
|
|
returns zero. If @var{a} or @var{b} is NULL in string comparisation functions
|
|
they return -1.
|
|
|
|
Their usefulness comes from the fact that they can chained with DOM traversing
|
|
functions like this:
|
|
|
|
@smallexample
|
|
if (iks_strcmp (iks_find_attrib (x, "id"), "x1") == 0) count++;
|
|
@end smallexample
|
|
|
|
That example works even x doesn't have an 'id' attribute and iks_find_attrib
|
|
returns NULL. So you don't need to use temporary variables in such
|
|
situations.
|
|
|
|
@comment ============================================================
|
|
@subsection SHA1 Hash
|
|
|
|
Secure Hash Algorithm (SHA1) is used in the Jabber authentication
|
|
protocol for encoding your password when sending to the server.
|
|
This is normally handled by iks_make_auth() function, but if you
|
|
want to handle it manually, or if you need a good hash function
|
|
for other purproses you can use these functions.
|
|
|
|
@deftypefun iksha* iks_sha_new (void);
|
|
Allocates a structure for keeping calculation values and the state.
|
|
@end deftypefun
|
|
|
|
@deftypefun void iks_sha_reset (iksha *@var{sha});
|
|
Resets the state of the calculation.
|
|
@end deftypefun
|
|
|
|
@deftypefun void iks_sha_hash (iksha *@var{sha}, const unsigned char *@var{data}, int @var{len}, int @var{finish});
|
|
Calculates the hash value of the given data. If @var{finish} is non
|
|
zero, applies the last step of the calculation.
|
|
@end deftypefun
|
|
|
|
@deftypefun void iks_sha_print (iksha *@var{sha}, char *@var{hash});
|
|
Prints the result of a finished calculation into the buffer pointed by @var{hash}
|
|
in hexadecimal string form. Buffer must be at least 40 bytes long. String
|
|
is not null terminated.
|
|
@end deftypefun
|
|
|
|
@deftypefun void iks_sha (const char *@var{data}, char *@var{hash});
|
|
Calculates the hash value of @var{data} and prints into @var{hash}.
|
|
This is a helper function for simple hash calculations. It calls
|
|
other functions for the actual work.
|
|
@end deftypefun
|
|
|
|
|
|
@comment ============================================================
|
|
|
|
|
|
@node Development,Datatype Index,Tutorials,Top
|
|
@chapter Development
|
|
|
|
This chapter contains information on plan, procedure and standarts of
|
|
iksemel development.
|
|
|
|
@section Roadmap
|
|
|
|
There are three main functions iksemel tries to provide to applications:
|
|
@itemize @bullet
|
|
@item
|
|
A generic XML parser with SAX and DOM interfaces.
|
|
@item
|
|
XML stream client and server functionality.
|
|
@item
|
|
Utilities for Jabber clients.
|
|
@end itemize
|
|
|
|
Goal of the iksemel is providing these functions while supporting embedded
|
|
environments, keeping usage simple, and having a robust implementation.
|
|
|
|
Some decisions are made to reach this goal:
|
|
|
|
Code is written in ANSI C with a single dependency on C library. Instead of
|
|
using expat or libxml, a simple built-in parser is used. Similarly glib and
|
|
gnu only features of glibc (like object stacks) are avoided and built-in
|
|
memory and string utilities are used. This may seem like code duplication
|
|
but since they are optimized for iksemel and only a few kb in size,
|
|
it isn't a big disadvantage.
|
|
|
|
Code is placed files in a modular fashion, and different modules don't depend
|
|
on others' internal details. This allows taking unneeded functionality out when
|
|
building for low resource situations.
|
|
|
|
It is tried to give functions names which are consistent, clear and short.
|
|
|
|
API is documented with texinfo for high quality printed output and info file
|
|
output for fast and simple access during application development. Instead
|
|
of using an autogenerated system or simply listing function descriptions,
|
|
a task oriented tutorial approach is used.
|
|
|
|
@section Coding Style
|
|
|
|
Here is a short list describing preferred coding style for iksemel.
|
|
Please keep in mind when sending patches.
|
|
|
|
@itemize @bullet
|
|
@item
|
|
Indentation is done with tabs. Aligning is done with spaces.
|
|
@item
|
|
Placement of braces is K&R style.
|
|
@item
|
|
Function names are put at the start of line.
|
|
@item
|
|
Function names are lowercase.
|
|
@item
|
|
Words of the function names are separated with underscore character.
|
|
@item
|
|
Structure and variable names are lowercase.
|
|
@item
|
|
Macro and enumarations names are uppercase.
|
|
@item
|
|
Exported library API is contained in the single iksemel.h file.
|
|
@item
|
|
Exported function names start with iks_
|
|
@item
|
|
Exported structure and type names start with iks
|
|
@item
|
|
Exported macro and enumaration names start with IKS_
|
|
@end itemize
|
|
|
|
Here is an example:
|
|
|
|
@smallexample
|
|
int
|
|
iks_new_func (char *text)
|
|
@{
|
|
int i;
|
|
|
|
i = an_internal_func (text);
|
|
if (IKS_SOME_VALUE == i) @{
|
|
iks_some_func (text);
|
|
i++;
|
|
@}
|
|
return i;
|
|
@}
|
|
@end smallexample
|
|
|
|
@section Resources
|
|
|
|
@itemize @bullet
|
|
@item
|
|
RFC 2279, UTF-8 format @url{http://www.ietf.org/rfc/rfc2279.txt}
|
|
@item
|
|
W3C Recommendation, Extensible Markup Language 1.0 @url{http://www.w3.org/TR/REC-xml}
|
|
@item
|
|
Annotated XML Specification @url{http://www.xml.com/axml/testaxml.htm}
|
|
@item
|
|
Jabber Protocol Documents @url{http://www.jabber.org/protocol/}
|
|
@end itemize
|
|
|
|
|
|
@comment ============================================================
|
|
|
|
|
|
@node Datatype Index,Function Index,Development,Top
|
|
@unnumbered Datatype Index
|
|
@printindex tp
|
|
|
|
|
|
@node Function Index,,Datatype Index,Top
|
|
@unnumbered Function Index
|
|
@printindex fn
|
|
|
|
|
|
@contents
|
|
@bye
|