/********************************************************************\
* BitlBee -- An IRC to other IM-networks gateway *
* *
* Copyright 2002-2004 Wilmer van der Gaast and others *
\********************************************************************/
/* Account management functions */
/*
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 with
the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
if not, write to the Free Software Foundation, Inc., 59 Temple Place,
Suite 330, Boston, MA 02111-1307 USA
*/
#define BITLBEE_CORE
#include "bitlbee.h"
#include "account.h"
account_t *account_add( irc_t *irc, int protocol, char *user, char *pass )
{
account_t *a;
if( irc->accounts )
{
for( a = irc->accounts; a->next; a = a->next );
a = a->next = g_new0 ( account_t, 1 );
}
else
{
irc->accounts = a = g_new0 ( account_t, 1 );
}
a->protocol = protocol;
a->user = g_strdup( user );
a->pass = g_strdup( pass );
a->irc = irc;
return( a );
}
account_t *account_get( irc_t *irc, char *id )
{
account_t *a, *ret = NULL;
int nr;
if( sscanf( id, "%d", &nr ) == 1 && nr < 1000 )
{
for( a = irc->accounts; a; a = a->next )
if( ( nr-- ) == 0 )
return( a );
return( NULL );
}
for( a = irc->accounts; a; a = a->next )
{
if( g_strcasecmp( id, proto_name[a->protocol] ) == 0 )
{
if( !ret )
ret = a;
else
return( NULL ); /* We don't want to match more than one... */
}
else if( strstr( a->user, id ) )
{
if( !ret )
ret = a;
else
return( NULL );
}
}
return( ret );
}
void account_del( irc_t *irc, account_t *acc )
{
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long *//* --------------------------------------------------------------------------
*
* License
*
* The contents of this file are subject to the Jabber Open Source License
* Version 1.0 (the "JOSL"). You may not copy or use this file, in either
* source code or executable form, except in compliance with the JOSL. You
* may obtain a copy of the JOSL at http://www.jabber.org/ or at
* http://www.opensource.org/.
*
* Software distributed under the JOSL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the JOSL
* for the specific language governing rights and limitations under the
* JOSL.
*
* Copyrights
*
* Portions created by or assigned to Jabber.com, Inc. are
* Copyright (c) 1999-2002 Jabber.com, Inc. All Rights Reserved. Contact
* information for Jabber.com, Inc. is available at http://www.jabber.com/.
*
* Portions Copyright (c) 1998-1999 Jeremie Miller.
*
* Acknowledgements
*
* Special thanks to the Jabber Open Source Contributors for their
* suggestions and support of Jabber.
*
* Alternatively, the contents of this file may be used under the terms of the
* GNU General Public License Version 2 or later (the "GPL"), in which case
* the provisions of the GPL are applicable instead of those above. If you
* wish to allow use of your version of this file only under the terms of the
* GPL and not to allow others to use your version of this file under the JOSL,
* indicate your decision by deleting the provisions above and replace them
* with the notice and other provisions required by the GPL. If you do not
* delete the provisions above, a recipient may use your version of this file
* under either the JOSL or the GPL.
*
*
* --------------------------------------------------------------------------*/
#include "jabber.h"
#include <glib.h>
static xmlnode xmlnode_get_firstattrib(xmlnode parent);
static int xmlnode_get_type(xmlnode node);
static void xmlnode_insert_node(xmlnode parent, xmlnode node);
/* Internal routines */
static xmlnode _xmlnode_new(pool p, const char* name, unsigned int type)
{
xmlnode result = NULL;
if (type > NTYPE_LAST)
return NULL;
if (type != NTYPE_CDATA && name == NULL)
return NULL;
if (p == NULL)
{
p = pool_heap(1*1024);
}
/* Allocate & zero memory */
result = (xmlnode)pmalloco(p, sizeof(_xmlnode));
/* Initialize fields */
if (type != NTYPE_CDATA)
result->name = pstrdup(p,name);
result->type = type;
result->p = p;
return result;
}
static xmlnode _xmlnode_append_sibling(xmlnode lastsibling, const char* name, unsigned int type)
{
xmlnode result;
result = _xmlnode_new(xmlnode_pool(lastsibling), name, type);
if (result != NULL)
{
/* Setup sibling pointers */
result->prev = lastsibling;
lastsibling->next = result;
}
return result;
}
static xmlnode _xmlnode_insert(xmlnode parent, const char* name, unsigned int type)
{
xmlnode result;
if(parent == NULL || (type != NTYPE_CDATA && name == NULL)) return NULL;
/* If parent->firstchild is NULL, simply create a new node for the first child */
if (parent->firstchild == NULL)
{
result = _xmlnode_new(parent->p, name, type);
parent->firstchild = result;
}
/* Otherwise, append this to the lastchild */
else
{
result= _xmlnode_append_sibling(parent->lastchild, name, type);
}
result->parent = parent;
parent->lastchild = result;
return result;
}
static xmlnode _xmlnode_search(xmlnode firstsibling, const char* name, unsigned int type)
{
xmlnode current;
/* Walk the sibling list, looking for a NTYPE_TAG xmlnode with
the specified name */
current = firstsibling;
while (current != NULL)
{
if ((current->type == type) && (j_strcmp(current->name, name) == 0))
return current;
else
current = current->next;
}
return NULL;
}
static void _xmlnode_merge(xmlnode data)
{
xmlnode cur;
char *merge, *scur;
int imerge;
/* get total size of all merged cdata */
imerge = 0;
for(cur = data; cur != NULL && cur->type == NTYPE_CDATA; cur = cur->next)
imerge += cur->data_sz;
/* copy in current data and then spin through all of them and merge */
scur = merge = pmalloc(data->p,imerge + 1);
for(cur = data; cur != NULL && cur->type == NTYPE_CDATA; cur = cur->next)
{
memcpy(scur,cur->data,cur->data_sz);
scur += cur->data_sz;
}
*scur = '\0';
/* this effectively hides all of the merged-in chunks */
data->next = cur;
if(cur == NULL)
data->parent->lastchild = data;
else
cur->prev = data;
/* reset data */
data->data = merge;
data->data_sz = imerge;
}
static void _xmlnode_hide_sibling(xmlnode child)
{
if(child == NULL)
return;
if(child->prev != NULL)
child->prev->next = child->next;
if(child->next != NULL)
child->next->prev = child->prev;
}
static void _xmlnode_tag2str(spool s, xmlnode node, int flag)
{
xmlnode tmp;
if(flag==0 || flag==1)
{
spooler(s,"<",xmlnode_get_name(node),s);
tmp = xmlnode_get_firstattrib(node);
while(tmp) {
spooler(s," ",xmlnode_get_name(tmp),"='",strescape(xmlnode_pool(node),xmlnode_get_data(tmp)),"'",s);
tmp = xmlnode_get_nextsibling(tmp);
}
if(flag==0)
spool_add(s,"/>");
else
spool_add(s,">");
}
else
{
spooler(s,"</",xmlnode_get_name(node),">",s);
}
}
static spool _xmlnode2spool(xmlnode node)
{
spool s;
int level=0,dir=0;
xmlnode tmp;
if(!node || xmlnode_get_type(node)!=NTYPE_TAG)
return NULL;
s = spool_new(xmlnode_pool(node));
if(!s) return(NULL);
while(1)
{
if(dir==0)
{
if(xmlnode_get_type(node) == NTYPE_TAG)
{
if(xmlnode_has_children(node))
{
_xmlnode_tag2str(s,node,1);
node = xmlnode_get_firstchild(node);
level++;
continue;
}else{
_xmlnode_tag2str(s,node,0);
}
}else{
spool_add(s,strescape(xmlnode_pool(node),xmlnode_get_data(node)));
}
}
tmp = xmlnode_get_nextsibling(node);
if(!tmp)
{
node = xmlnode_get_parent(node);
level--;
if(level>=0) _xmlnode_tag2str(s,node,2);
if(level<1) break;
dir = 1;
}else{
node = tmp;
dir = 0;
}
}
return s;
}
/* External routines */
/*
* xmlnode_new_tag -- create a tag node
* Automatically creates a memory pool for the node.
*
* parameters
* name -- name of the tag
*
* returns
* a pointer to the tag node
* or NULL if it was unsuccessfull
*/
xmlnode xmlnode_new_tag(const char* name)
{
return _xmlnode_new(NULL, name, NTYPE_TAG);
}
/*
* xmlnode_insert_tag -- append a child tag to a tag
*
* parameters
* parent -- pointer to the parent tag
* name -- name of the child tag
*
* returns
* a pointer to the child tag node
* or NULL if it was unsuccessfull
*/
xmlnode xmlnode_insert_tag(xmlnode parent, const char* name)
{
return _xmlnode_insert(parent, name, NTYPE_TAG);
}
/*
* xmlnode_insert_cdata -- append character data to a tag
*
* parameters
* parent -- parent tag
* CDATA -- character data
* size -- size of CDATA
* or -1 for null-terminated CDATA strings
*
* returns
* a pointer to the child CDATA node
* or NULL if it was unsuccessfull
*/
xmlnode xmlnode_insert_cdata(xmlnode parent, const char* CDATA, unsigned int size)
{
xmlnode result;
if(CDATA == NULL || parent == NULL)
return NULL;
if(size == -1)
size = strlen(CDATA);
result = _xmlnode_insert(parent, NULL, NTYPE_CDATA);
if (result != NULL)
{
result->data = (char*)pmalloc(result->p, size + 1);
memcpy(result->data, CDATA, size);
result->data[size] = '\0';
result->data_sz = size;
}
return result;
}
/*
* xmlnode_get_tag -- find given tag in an xmlnode tree
*
* parameters
* parent -- pointer to the parent tag
* name -- "name" for the child tag of that name
* "name/name" for a sub child (recurses)
* "?attrib" to match the first tag with that attrib defined
* "?attrib=value" to match the first tag with that attrib and value
* "=cdata" to match the cdata contents of the child
* or any combination: "name/name/?attrib", "name=cdata", etc
*
* results
* a pointer to the tag matching search criteria
* or NULL if search was unsuccessfull
*/
xmlnode xmlnode_get_tag(xmlnode parent, const char* name)
{
char *str, *slash, *qmark, *equals;
xmlnode step, ret;
if(parent == NULL || parent->firstchild == NULL || name == NULL || name == '\0') return NULL;
if(strstr(name, "/") == NULL && strstr(name,"?") == NULL && strstr(name, "=") == NULL)
return _xmlnode_search(parent->firstchild, name, NTYPE_TAG);
str = g_strdup(name);
slash = strstr(str, "/");
qmark = strstr(str, "?");
equals = strstr(str, "=");
if(equals != NULL && (slash == NULL || equals < slash) && (qmark == NULL || equals < qmark))
{ /* of type =cdata */
*equals = '\0';
equals++;
for(step = parent->firstchild; step != NULL; step = xmlnode_get_nextsibling(step))
{
if(xmlnode_get_type(step) != NTYPE_TAG)
continue;
if(*str != '\0')
if(j_strcmp(xmlnode_get_name(step),str) != 0)
continue;
if(j_strcmp(xmlnode_get_data(step),equals) != 0)
continue;
break;
}
g_free(str);
return step;
}
if(qmark != NULL && (slash == NULL || qmark < slash))
{ /* of type ?attrib */
*qmark = '\0';
qmark++;
if(equals != NULL)
{
*equals = '\0';
equals++;
}
for(step = parent->firstchild; step != NULL; step = xmlnode_get_nextsibling(step))
{
if(xmlnode_get_type(step) != NTYPE_TAG)
continue;
if(*str != '\0')
if(j_strcmp(xmlnode_get_name(step),str) != 0)
continue;
if(xmlnode_get_attrib(step,qmark) == NULL)
continue;
if(equals != NULL && j_strcmp(xmlnode_get_attrib(step,qmark),equals) != 0)
continue;
break;
}
g_free(str);
return step;
}
*slash = '\0';
++slash;
for(step = parent->firstchild; step != NULL; step = xmlnode_get_nextsibling(step))
{
if(xmlnode_get_type(step) != NTYPE_TAG) continue;
if(j_strcmp(xmlnode_get_name(step),str) != 0)
continue;
ret = xmlnode_get_tag(step, slash);
if(ret != NULL)
{
g_free(str);
return ret;
}
}
g_free(str);
return NULL;
}
/* return the cdata from any tag */
char *xmlnode_get_tag_data(xmlnode parent, const char *name)
{
xmlnode tag;
tag = xmlnode_get_tag(parent, name);
if(tag == NULL) return NULL;
return xmlnode_get_data(tag);
}
void xmlnode_put_attrib(xmlnode owner, const char* name, const char* value)
{
xmlnode attrib;
if(owner == NULL || name == NULL || value == NULL) return;
/* If there are no existing attributs, allocate a new one to start
the list */
if (owner->firstattrib == NULL)
{
attrib = _xmlnode_new(owner->p, name, NTYPE_ATTRIB);
owner->firstattrib = attrib;
owner->lastattrib = attrib;
}
else
{
attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB);
if(attrib == NULL)
{
attrib = _xmlnode_append_sibling(owner->lastattrib, name, NTYPE_ATTRIB);
owner->lastattrib = attrib;
}
}
/* Update the value of the attribute */
attrib->data_sz = strlen(value);
attrib->data = pstrdup(owner->p, value);
}
char* xmlnode_get_attrib(xmlnode owner, const char* name)
{
xmlnode attrib;
if (owner != NULL && owner->firstattrib != NULL)
{
attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB);
if (attrib != NULL)
return (char*)attrib->data;
}
return NULL;
}
static xmlnode xmlnode_get_firstattrib(xmlnode parent)
{
if (parent != NULL)
return parent->firstattrib;
return NULL;
}
xmlnode xmlnode_get_firstchild(xmlnode parent)
{
if (parent != NULL)
return parent->firstchild;
return NULL;
}
xmlnode xmlnode_get_nextsibling(xmlnode sibling)
{
if (sibling != NULL)
return sibling->next;
return NULL;
}
xmlnode xmlnode_get_parent(xmlnode node)
{
if (node != NULL)
return node->parent;
return NULL;
}
char* xmlnode_get_name(xmlnode node)
{
if (node != NULL)
return node->name;
return NULL;
}
char* xmlnode_get_data(xmlnode node)
{
if(xmlnode_get_type(node) == NTYPE_TAG) /* loop till we find a CDATA in the children */
for(node = xmlnode_get_firstchild(node); node != NULL; node = xmlnode_get_nextsibling(node))
if(xmlnode_get_type(node) == NTYPE_CDATA) break;
if(node == NULL) return NULL;
/* check for a dirty node w/ unassembled cdata chunks */
if(xmlnode_get_type(node->next) == NTYPE_CDATA)
_xmlnode_merge(node);
return node->data;
}
static int xmlnode_get_datasz(xmlnode node)
{
if(xmlnode_get_type(node) != NTYPE_CDATA) return 0;
/* check for a dirty node w/ unassembled cdata chunks */
if(xmlnode_get_type(node->next) == NTYPE_CDATA)
_xmlnode_merge(node);
return node->data_sz;
}
static int xmlnode_get_type(xmlnode node)
{
if (node != NULL)
return node->type;
return NTYPE_UNDEF;
}
int xmlnode_has_children(xmlnode node)
{
if ((node != NULL) && (node->firstchild != NULL))
return 1;
return 0;
}
static int xmlnode_has_attribs(xmlnode node)
{
if ((node != NULL) && (node->firstattrib != NULL))
return 1;
return 0;
}
pool xmlnode_pool(xmlnode node)
{
if (node != NULL)
return node->p;
return (pool)NULL;
}
void xmlnode_hide_attrib(xmlnode parent, const char *name)
{
xmlnode attrib;
if(parent == NULL || parent->firstattrib == NULL || name == NULL)
return;
attrib = _xmlnode_search(parent->firstattrib, name, NTYPE_ATTRIB);
if(attrib == NULL)
return;
/* first fix up at the child level */
_xmlnode_hide_sibling(attrib);
/* next fix up at the parent level */
if(parent->firstattrib == attrib)
parent->firstattrib = attrib->next;
if(parent->lastattrib == attrib)
parent->lastattrib = attrib->prev;
}
/*
* xmlnode2str -- convert given xmlnode tree into a string
*
* parameters
* node -- pointer to the xmlnode structure
*
* results
* a pointer to the created string
* or NULL if it was unsuccessfull
*/
char *xmlnode2str(xmlnode node)
{
return spool_print(_xmlnode2spool(node));
}
/* loop through both a and b comparing everything, attribs, cdata, children, etc */
static int xmlnode_cmp(xmlnode a, xmlnode b)
{
int ret = 0;
while(1)
{
if(a == NULL && b == NULL)
return 0;
if(a == NULL || b == NULL)
return -1;
if(xmlnode_get_type(a) != xmlnode_get_type(b))
return -1;
switch(xmlnode_get_type(a))
{
case NTYPE_ATTRIB:
ret = j_strcmp(xmlnode_get_name(a), xmlnode_get_name(b));
if(ret != 0)
return -1;
ret = j_strcmp(xmlnode_get_data(a), xmlnode_get_data(b));
if(ret != 0)
return -1;
break;
case NTYPE_TAG:
ret = j_strcmp(xmlnode_get_name(a), xmlnode_get_name(b));
if(ret != 0)
return -1;
ret = xmlnode_cmp(xmlnode_get_firstattrib(a), xmlnode_get_firstattrib(b));
if(ret != 0)
return -1;
ret = xmlnode_cmp(xmlnode_get_firstchild(a), xmlnode_get_firstchild(b));
if(ret != 0)
return -1;
break;
case NTYPE_CDATA:
ret = j_strcmp(xmlnode_get_data(a), xmlnode_get_data(b));
if(ret != 0)
return -1;
}
a = xmlnode_get_nextsibling(a);
b = xmlnode_get_nextsibling(b);
}
}
xmlnode xmlnode_insert_tag_node(xmlnode parent, xmlnode node)
{
xmlnode child;
child = xmlnode_insert_tag(parent, xmlnode_get_name(node));
if (xmlnode_has_attribs(node))
xmlnode_insert_node(child, xmlnode_get_firstattrib(node));
if (xmlnode_has_children(node))
xmlnode_insert_node(child, xmlnode_get_firstchild(node));
return child;
}
/* places copy of node and node's siblings in parent */
static void xmlnode_insert_node(xmlnode parent, xmlnode node)
{
if(node == NULL || parent == NULL)
return;
while(node != NULL)
{
switch(xmlnode_get_type(node))
{
case NTYPE_ATTRIB:
xmlnode_put_attrib(parent, xmlnode_get_name(node), xmlnode_get_data(node));
break;
case NTYPE_TAG:
xmlnode_insert_tag_node(parent, node);
break;
case NTYPE_CDATA:
xmlnode_insert_cdata(parent, xmlnode_get_data(node), xmlnode_get_datasz(node));
}
node = xmlnode_get_nextsibling(node);
}
}
void xmlnode_free(xmlnode node)
{
if(node == NULL)
return;
pool_free(node->p);
}