<file_sep>#include "xep_vcard_data.h"
#include "helpers.h"
#include "errors.h"

const char *ns_vcard = "vcard-temp";

struct vcard_vcard_t *
vcard_vcard_decode (xmlreader_t * reader)
{
  struct vcard_vcard_t *elm = NULL;
  elm = malloc (sizeof (struct vcard_vcard_t));
  if (elm == NULL)
    fatal ("vcard_vcard_t: malloc failed");
  memset (elm, 0, sizeof (struct vcard_vcard_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "VERSION") == 0)
	      && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fVERSION = (char *) value;
	    }
	  else if ((strcmp (name, "FN") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fFN = (char *) value;
	    }
	}
    }
  return elm;
}

int
vcard_vcard_encode (xmlwriter_t * writer, struct vcard_vcard_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_vcard, "vCard");
  if (err != 0)
    return err;
  if (elm->fVERSION != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_vcard, "VERSION", elm->fVERSION);
      if (err != 0)
	return err;
    }
  if (elm->fFN != NULL)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "FN", elm->fFN);
      if (err != 0)
	return err;
    }
  if (elm->fN != NULL)
    {
      err = vcard_N_encode (writer, elm->fN);
      if (err != 0)
	return err;
    }
  {
    int len = array_length (elm->fFields);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	extension_t *ext = array_get (elm->fFields, i);
	err = xstream_extension_encode (writer, ext->data, ext->type);
	if (err != 0)
	  return -1;
      }
  }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_vcard_free (struct vcard_vcard_t *data)
{
  if (data == NULL)
    return;
  if (data->fVERSION != NULL)
    {
      free (data->fVERSION);
    }
  if (data->fFN != NULL)
    {
      free (data->fFN);
    }
  if (data->fN != NULL)
    {
    }
  {
    int len = array_length (data->fFields);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	extension_t *ext = array_get (data->fFields, i);
	xstream_extension_free (ext);
      }
    array_free (data->fFields);
  }
  free (data);
}

struct vcard_N_t *
vcard_N_decode (xmlreader_t * reader)
{
  struct vcard_N_t *elm = NULL;
  elm = malloc (sizeof (struct vcard_N_t));
  if (elm == NULL)
    fatal ("vcard_N_t: malloc failed");
  memset (elm, 0, sizeof (struct vcard_N_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "FAMILY") == 0)
	      && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fFAMILY = (char *) value;
	    }
	  else if ((strcmp (name, "GIVEN") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fGIVEN = (char *) value;
	    }
	  else if ((strcmp (name, "NIDDLE") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fNIDDLE = (char *) value;
	    }
	  else if ((strcmp (name, "PREFIX") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fPREFIX = (char *) value;
	    }
	  else if ((strcmp (name, "SUFFIX") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fSUFFIX = (char *) value;
	    }
	}
    }
  return elm;
}

int
vcard_N_encode (xmlwriter_t * writer, struct vcard_N_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_vcard, "N");
  if (err != 0)
    return err;
  if (elm->fFAMILY != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_vcard, "FAMILY", elm->fFAMILY);
      if (err != 0)
	return err;
    }
  if (elm->fGIVEN != NULL)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "GIVEN", elm->fGIVEN);
      if (err != 0)
	return err;
    }
  if (elm->fNIDDLE != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_vcard, "NIDDLE", elm->fNIDDLE);
      if (err != 0)
	return err;
    }
  if (elm->fPREFIX != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_vcard, "PREFIX", elm->fPREFIX);
      if (err != 0)
	return err;
    }
  if (elm->fSUFFIX != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_vcard, "SUFFIX", elm->fSUFFIX);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_N_free (struct vcard_N_t *data)
{
  if (data == NULL)
    return;
  if (data->fFAMILY != NULL)
    {
      free (data->fFAMILY);
    }
  if (data->fGIVEN != NULL)
    {
      free (data->fGIVEN);
    }
  if (data->fNIDDLE != NULL)
    {
      free (data->fNIDDLE);
    }
  if (data->fPREFIX != NULL)
    {
      free (data->fPREFIX);
    }
  if (data->fSUFFIX != NULL)
    {
      free (data->fSUFFIX);
    }
  free (data);
}

vcard_NICKNAME_t *
vcard_NICKNAME_decode (xmlreader_t * reader)
{
  vcard_NICKNAME_t *elm = NULL;
  const char *value = xmlreader_text (reader);
  if (reader->err != 0)
    return NULL;
  elm = (vcard_NICKNAME_t *) value;
  return elm;
}

int
vcard_NICKNAME_encode (xmlwriter_t * writer, vcard_NICKNAME_t * elm)
{
  int err = 0;
  err =
    xmlwriter_simple_element (writer, ns_vcard, "NICKNAME",
			      (vcard_NICKNAME_t *) elm);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_NICKNAME_free (vcard_NICKNAME_t * data)
{
  if (data == NULL)
    return;
  free (data);
  free (data);
}

struct vcard_PHOTO_t *
vcard_PHOTO_decode (xmlreader_t * reader)
{
  struct vcard_PHOTO_t *elm = NULL;
  elm = malloc (sizeof (struct vcard_PHOTO_t));
  if (elm == NULL)
    fatal ("vcard_PHOTO_t: malloc failed");
  memset (elm, 0, sizeof (struct vcard_PHOTO_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "TYPE") == 0)
	      && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fTYPE = (char *) value;
	    }
	  else if ((strcmp (name, "BINVAL") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fBINVAL = (char *) value;
	    }
	  else if ((strcmp (name, "EXTVAL") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fEXTVAL = (char *) value;
	    }
	}
    }
  return elm;
}

int
vcard_PHOTO_encode (xmlwriter_t * writer, struct vcard_PHOTO_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_vcard, "PHOTO");
  if (err != 0)
    return err;
  if (elm->fTYPE != NULL)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "TYPE", elm->fTYPE);
      if (err != 0)
	return err;
    }
  if (elm->fBINVAL != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_vcard, "BINVAL", elm->fBINVAL);
      if (err != 0)
	return err;
    }
  if (elm->fEXTVAL != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_vcard, "EXTVAL", elm->fEXTVAL);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_PHOTO_free (struct vcard_PHOTO_t *data)
{
  if (data == NULL)
    return;
  if (data->fTYPE != NULL)
    {
      free (data->fTYPE);
    }
  if (data->fBINVAL != NULL)
    {
      free (data->fBINVAL);
    }
  if (data->fEXTVAL != NULL)
    {
      free (data->fEXTVAL);
    }
  free (data);
}

vcard_BDAY_t *
vcard_BDAY_decode (xmlreader_t * reader)
{
  vcard_BDAY_t *elm = NULL;
  const char *value = xmlreader_text (reader);
  if (reader->err != 0)
    return NULL;
  elm = (vcard_BDAY_t *) value;
  return elm;
}

int
vcard_BDAY_encode (xmlwriter_t * writer, vcard_BDAY_t * elm)
{
  int err = 0;
  err =
    xmlwriter_simple_element (writer, ns_vcard, "BDAY", (vcard_BDAY_t *) elm);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_BDAY_free (vcard_BDAY_t * data)
{
  if (data == NULL)
    return;
  free (data);
  free (data);
}

enum vcard_DOMINTL_t
enum_vcard_DOMINTL_from_string (const char *value)
{
  if (strcmp (value, "DOM") == 0)
    return VCARD_DOMINTL_DOM;
  else if (strcmp (value, "INTL") == 0)
    return VCARD_DOMINTL_INTL;
  return 0;
}

const char *
enum_vcard_DOMINTL_to_string (enum vcard_DOMINTL_t value)
{
  switch (value)
    {
    case VCARD_DOMINTL_DOM:
      return "DOM";
    case VCARD_DOMINTL_INTL:
      return "INTL";
    }
  return NULL;
}

struct vcard_ADR_t *
vcard_ADR_decode (xmlreader_t * reader)
{
  struct vcard_ADR_t *elm = NULL;
  elm = malloc (sizeof (struct vcard_ADR_t));
  if (elm == NULL)
    fatal ("vcard_ADR_t: malloc failed");
  memset (elm, 0, sizeof (struct vcard_ADR_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "HOME") == 0)
	      && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fHOME = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "WORK") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fWORK = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "POSTAL") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fPOSTAL = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "PARCEL") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fPARCEL = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "PREF") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fPREF = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "POBOX") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fPOBOX = (char *) value;
	    }
	  else if ((strcmp (name, "EXTADD") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fEXTADD = (char *) value;
	    }
	  else if ((strcmp (name, "STREET") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fSTREET = (char *) value;
	    }
	  else if ((strcmp (name, "LOCALITY") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fLOCALITY = (char *) value;
	    }
	  else if ((strcmp (name, "REGION") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fREGION = (char *) value;
	    }
	  else if ((strcmp (name, "PCODE") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fPCODE = (char *) value;
	    }
	  else if ((strcmp (name, "CTRY") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fCTRY = (char *) value;
	    }
	  else if (strcmp (namespace, ns_vcard) != 0)
	    {
	      elm->fDOMINTL = enum_vcard_DOMINTL_from_string (name);
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	    }
	}
    }
  return elm;
}

int
vcard_ADR_encode (xmlwriter_t * writer, struct vcard_ADR_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_vcard, "ADR");
  if (err != 0)
    return err;
  if (elm->fHOME)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "HOME", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fWORK)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "WORK", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fPOSTAL)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "POSTAL", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fPARCEL)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "PARCEL", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fDOMINTL != 0)
    {
      const char *name = enum_vcard_DOMINTL_to_string (elm->fDOMINTL);
      err = xmlwriter_simple_element (writer, ns_vcard, name, NULL);
      if (err != 0)
	return err;
    }
  if (elm->fPREF)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "PREF", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fPOBOX != NULL)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "POBOX", elm->fPOBOX);
      if (err != 0)
	return err;
    }
  if (elm->fEXTADD != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_vcard, "EXTADD", elm->fEXTADD);
      if (err != 0)
	return err;
    }
  if (elm->fSTREET != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_vcard, "STREET", elm->fSTREET);
      if (err != 0)
	return err;
    }
  if (elm->fLOCALITY != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_vcard, "LOCALITY",
				  elm->fLOCALITY);
      if (err != 0)
	return err;
    }
  if (elm->fREGION != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_vcard, "REGION", elm->fREGION);
      if (err != 0)
	return err;
    }
  if (elm->fPCODE != NULL)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "PCODE", elm->fPCODE);
      if (err != 0)
	return err;
    }
  if (elm->fCTRY != NULL)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "CTRY", elm->fCTRY);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_ADR_free (struct vcard_ADR_t *data)
{
  if (data == NULL)
    return;
  if (data->fHOME)
    {
    }
  if (data->fWORK)
    {
    }
  if (data->fPOSTAL)
    {
    }
  if (data->fPARCEL)
    {
    }
  if (data->fDOMINTL != 0)
    {
    }
  if (data->fPREF)
    {
    }
  if (data->fPOBOX != NULL)
    {
      free (data->fPOBOX);
    }
  if (data->fEXTADD != NULL)
    {
      free (data->fEXTADD);
    }
  if (data->fSTREET != NULL)
    {
      free (data->fSTREET);
    }
  if (data->fLOCALITY != NULL)
    {
      free (data->fLOCALITY);
    }
  if (data->fREGION != NULL)
    {
      free (data->fREGION);
    }
  if (data->fPCODE != NULL)
    {
      free (data->fPCODE);
    }
  if (data->fCTRY != NULL)
    {
      free (data->fCTRY);
    }
  free (data);
}

struct vcard_LABEL_t *
vcard_LABEL_decode (xmlreader_t * reader)
{
  struct vcard_LABEL_t *elm = NULL;
  elm = malloc (sizeof (struct vcard_LABEL_t));
  if (elm == NULL)
    fatal ("vcard_LABEL_t: malloc failed");
  memset (elm, 0, sizeof (struct vcard_LABEL_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "HOME") == 0)
	      && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fHOME = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "WORK") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fWORK = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "POSTAL") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fPOSTAL = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "PARCEL") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fPARCEL = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "PREF") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fPREF = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "LINE") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      if (elm->fLINE == NULL)
		elm->fLINE = array_new (sizeof (char *), 0);
	      array_append (elm->fLINE, (void *) &value);
	    }
	  else if (strcmp (namespace, ns_vcard) != 0)
	    {
	      elm->fDOMINTL = enum_vcard_DOMINTL_from_string (name);
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	    }
	}
    }
  return elm;
}

int
vcard_LABEL_encode (xmlwriter_t * writer, struct vcard_LABEL_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_vcard, "LABEL");
  if (err != 0)
    return err;
  if (elm->fHOME)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "HOME", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fWORK)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "WORK", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fPOSTAL)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "POSTAL", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fPARCEL)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "PARCEL", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fDOMINTL != 0)
    {
      const char *name = enum_vcard_DOMINTL_to_string (elm->fDOMINTL);
      err = xmlwriter_simple_element (writer, ns_vcard, name, NULL);
      if (err != 0)
	return err;
    }
  if (elm->fPREF)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "PREF", NULL);
      if (err != 0)
	return err;
    }
  int len = array_length (elm->fLINE);
  int i = 0;
  for (i = 0; i < len; i++)
    {
      char **value = array_get (elm->fLINE, i);
      err =
	xmlwriter_simple_element (writer, ns_vcard, "LINE", (char *) value);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_LABEL_free (struct vcard_LABEL_t *data)
{
  if (data == NULL)
    return;
  if (data->fHOME)
    {
    }
  if (data->fWORK)
    {
    }
  if (data->fPOSTAL)
    {
    }
  if (data->fPARCEL)
    {
    }
  if (data->fDOMINTL != 0)
    {
    }
  if (data->fPREF)
    {
    }
  int len = array_length (data->fLINE);
  int i = 0;
  for (i = 0; i < len; i++)
    {
      char **value = array_get (data->fLINE, i);
      free (*value);
    }
  array_free (data->fLINE);
  free (data);
}

struct vcard_TEL_t *
vcard_TEL_decode (xmlreader_t * reader)
{
  struct vcard_TEL_t *elm = NULL;
  elm = malloc (sizeof (struct vcard_TEL_t));
  if (elm == NULL)
    fatal ("vcard_TEL_t: malloc failed");
  memset (elm, 0, sizeof (struct vcard_TEL_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "HOME") == 0)
	      && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fHOME = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "WORK") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fWORK = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "VOICE") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fVOICE = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "FAX") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fFAX = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "PAGER") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fPAGER = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "MSG") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fMSG = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "CELL") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fCELL = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "VIDEO") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fVIDEO = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "BBS") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fBBS = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "MODEM") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fMODEM = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "ISDN") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fISDN = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "PCS") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fPCS = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "PREF") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fPREF = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "NUMBER") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fNUMBER = (char *) value;
	    }
	}
    }
  return elm;
}

int
vcard_TEL_encode (xmlwriter_t * writer, struct vcard_TEL_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_vcard, "TEL");
  if (err != 0)
    return err;
  if (elm->fHOME)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "HOME", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fWORK)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "WORK", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fVOICE)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "VOICE", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fFAX)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "FAX", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fPAGER)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "PAGER", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fMSG)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "MSG", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fCELL)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "CELL", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fVIDEO)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "VIDEO", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fBBS)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "BBS", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fMODEM)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "MODEM", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fISDN)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "ISDN", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fPCS)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "PCS", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fPREF)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "PREF", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fNUMBER != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_vcard, "NUMBER", elm->fNUMBER);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_TEL_free (struct vcard_TEL_t *data)
{
  if (data == NULL)
    return;
  if (data->fHOME)
    {
    }
  if (data->fWORK)
    {
    }
  if (data->fVOICE)
    {
    }
  if (data->fFAX)
    {
    }
  if (data->fPAGER)
    {
    }
  if (data->fMSG)
    {
    }
  if (data->fCELL)
    {
    }
  if (data->fVIDEO)
    {
    }
  if (data->fBBS)
    {
    }
  if (data->fMODEM)
    {
    }
  if (data->fISDN)
    {
    }
  if (data->fPCS)
    {
    }
  if (data->fPREF)
    {
    }
  if (data->fNUMBER != NULL)
    {
      free (data->fNUMBER);
    }
  free (data);
}

struct vcard_EMAIL_t *
vcard_EMAIL_decode (xmlreader_t * reader)
{
  struct vcard_EMAIL_t *elm = NULL;
  elm = malloc (sizeof (struct vcard_EMAIL_t));
  if (elm == NULL)
    fatal ("vcard_EMAIL_t: malloc failed");
  memset (elm, 0, sizeof (struct vcard_EMAIL_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "HOME") == 0)
	      && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fHOME = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "WORK") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fWORK = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "INTERNET") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fINTERNET = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "PREF") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fPREF = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "X400") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      elm->fX400 = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "USERID") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fUSERID = (char *) value;
	    }
	}
    }
  return elm;
}

int
vcard_EMAIL_encode (xmlwriter_t * writer, struct vcard_EMAIL_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_vcard, "EMAIL");
  if (err != 0)
    return err;
  if (elm->fHOME)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "HOME", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fWORK)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "WORK", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fINTERNET)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "INTERNET", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fPREF)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "PREF", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fX400)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "X400", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fUSERID != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_vcard, "USERID", elm->fUSERID);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_EMAIL_free (struct vcard_EMAIL_t *data)
{
  if (data == NULL)
    return;
  if (data->fHOME)
    {
    }
  if (data->fWORK)
    {
    }
  if (data->fINTERNET)
    {
    }
  if (data->fPREF)
    {
    }
  if (data->fX400)
    {
    }
  if (data->fUSERID != NULL)
    {
      free (data->fUSERID);
    }
  free (data);
}

vcard_JABBERID_t *
vcard_JABBERID_decode (xmlreader_t * reader)
{
  vcard_JABBERID_t *elm = NULL;
  const char *value = xmlreader_text (reader);
  if (reader->err != 0)
    return NULL;
  elm = (vcard_JABBERID_t *) value;
  return elm;
}

int
vcard_JABBERID_encode (xmlwriter_t * writer, vcard_JABBERID_t * elm)
{
  int err = 0;
  err =
    xmlwriter_simple_element (writer, ns_vcard, "JABBERID",
			      (vcard_JABBERID_t *) elm);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_JABBERID_free (vcard_JABBERID_t * data)
{
  if (data == NULL)
    return;
  free (data);
  free (data);
}

vcard_MAILER_t *
vcard_MAILER_decode (xmlreader_t * reader)
{
  vcard_MAILER_t *elm = NULL;
  const char *value = xmlreader_text (reader);
  if (reader->err != 0)
    return NULL;
  elm = (vcard_MAILER_t *) value;
  return elm;
}

int
vcard_MAILER_encode (xmlwriter_t * writer, vcard_MAILER_t * elm)
{
  int err = 0;
  err =
    xmlwriter_simple_element (writer, ns_vcard, "MAILER",
			      (vcard_MAILER_t *) elm);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_MAILER_free (vcard_MAILER_t * data)
{
  if (data == NULL)
    return;
  free (data);
  free (data);
}

vcard_TZ_t *
vcard_TZ_decode (xmlreader_t * reader)
{
  vcard_TZ_t *elm = NULL;
  const char *value = xmlreader_text (reader);
  if (reader->err != 0)
    return NULL;
  elm = (vcard_TZ_t *) value;
  return elm;
}

int
vcard_TZ_encode (xmlwriter_t * writer, vcard_TZ_t * elm)
{
  int err = 0;
  err = xmlwriter_simple_element (writer, ns_vcard, "TZ", (vcard_TZ_t *) elm);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_TZ_free (vcard_TZ_t * data)
{
  if (data == NULL)
    return;
  free (data);
  free (data);
}

struct vcard_GEO_t *
vcard_GEO_decode (xmlreader_t * reader)
{
  struct vcard_GEO_t *elm = NULL;
  elm = malloc (sizeof (struct vcard_GEO_t));
  if (elm == NULL)
    fatal ("vcard_GEO_t: malloc failed");
  memset (elm, 0, sizeof (struct vcard_GEO_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "LAT") == 0)
	      && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fLAT = (char *) value;
	    }
	  else if ((strcmp (name, "LON") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fLON = (char *) value;
	    }
	}
    }
  return elm;
}

int
vcard_GEO_encode (xmlwriter_t * writer, struct vcard_GEO_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_vcard, "GEO");
  if (err != 0)
    return err;
  if (elm->fLAT != NULL)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "LAT", elm->fLAT);
      if (err != 0)
	return err;
    }
  if (elm->fLON != NULL)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "LON", elm->fLON);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_GEO_free (struct vcard_GEO_t *data)
{
  if (data == NULL)
    return;
  if (data->fLAT != NULL)
    {
      free (data->fLAT);
    }
  if (data->fLON != NULL)
    {
      free (data->fLON);
    }
  free (data);
}

vcard_TITLE_t *
vcard_TITLE_decode (xmlreader_t * reader)
{
  vcard_TITLE_t *elm = NULL;
  const char *value = xmlreader_text (reader);
  if (reader->err != 0)
    return NULL;
  elm = (vcard_TITLE_t *) value;
  return elm;
}

int
vcard_TITLE_encode (xmlwriter_t * writer, vcard_TITLE_t * elm)
{
  int err = 0;
  err =
    xmlwriter_simple_element (writer, ns_vcard, "TITLE",
			      (vcard_TITLE_t *) elm);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_TITLE_free (vcard_TITLE_t * data)
{
  if (data == NULL)
    return;
  free (data);
  free (data);
}

vcard_ROLE_t *
vcard_ROLE_decode (xmlreader_t * reader)
{
  vcard_ROLE_t *elm = NULL;
  const char *value = xmlreader_text (reader);
  if (reader->err != 0)
    return NULL;
  elm = (vcard_ROLE_t *) value;
  return elm;
}

int
vcard_ROLE_encode (xmlwriter_t * writer, vcard_ROLE_t * elm)
{
  int err = 0;
  err =
    xmlwriter_simple_element (writer, ns_vcard, "ROLE", (vcard_ROLE_t *) elm);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_ROLE_free (vcard_ROLE_t * data)
{
  if (data == NULL)
    return;
  free (data);
  free (data);
}

struct vcard_LOGO_t *
vcard_LOGO_decode (xmlreader_t * reader)
{
  struct vcard_LOGO_t *elm = NULL;
  elm = malloc (sizeof (struct vcard_LOGO_t));
  if (elm == NULL)
    fatal ("vcard_LOGO_t: malloc failed");
  memset (elm, 0, sizeof (struct vcard_LOGO_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "TYPE") == 0)
	      && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fTYPE = (char *) value;
	    }
	  else if ((strcmp (name, "BINVAL") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fBINVAL = (char *) value;
	    }
	  else if ((strcmp (name, "EXTVAL") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fEXTVAL = (char *) value;
	    }
	}
    }
  return elm;
}

int
vcard_LOGO_encode (xmlwriter_t * writer, struct vcard_LOGO_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_vcard, "LOGO");
  if (err != 0)
    return err;
  if (elm->fTYPE != NULL)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "TYPE", elm->fTYPE);
      if (err != 0)
	return err;
    }
  if (elm->fBINVAL != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_vcard, "BINVAL", elm->fBINVAL);
      if (err != 0)
	return err;
    }
  if (elm->fEXTVAL != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_vcard, "EXTVAL", elm->fEXTVAL);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_LOGO_free (struct vcard_LOGO_t *data)
{
  if (data == NULL)
    return;
  if (data->fTYPE != NULL)
    {
      free (data->fTYPE);
    }
  if (data->fBINVAL != NULL)
    {
      free (data->fBINVAL);
    }
  if (data->fEXTVAL != NULL)
    {
      free (data->fEXTVAL);
    }
  free (data);
}

vcard_EXTVAL_t *
vcard_EXTVAL_decode (xmlreader_t * reader)
{
  vcard_EXTVAL_t *elm = NULL;
  const char *value = xmlreader_text (reader);
  if (reader->err != 0)
    return NULL;
  elm = (vcard_EXTVAL_t *) value;
  return elm;
}

int
vcard_EXTVAL_encode (xmlwriter_t * writer, vcard_EXTVAL_t * elm)
{
  int err = 0;
  err =
    xmlwriter_simple_element (writer, ns_vcard, "EXTVAL",
			      (vcard_EXTVAL_t *) elm);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_EXTVAL_free (vcard_EXTVAL_t * data)
{
  if (data == NULL)
    return;
  free (data);
  free (data);
}

struct vcard_AGENT_t *
vcard_AGENT_decode (xmlreader_t * reader)
{
  struct vcard_AGENT_t *elm = NULL;
  elm = malloc (sizeof (struct vcard_AGENT_t));
  if (elm == NULL)
    fatal ("vcard_AGENT_t: malloc failed");
  memset (elm, 0, sizeof (struct vcard_AGENT_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (namespace, ns_vcard) == 0)
	      && (strcmp (name, "vCard") == 0))
	    {
	      struct vcard_vcard_t *newel = vcard_vcard_decode (reader);
	      if (newel == NULL)
		{
		  return NULL;
		}
	      elm->type = EXTENSION_TYPE_VCARD_VCARD;
	      elm->u->fVcard = newel;
	    }
	  else if ((strcmp (namespace, ns_vcard) == 0)
		   && (strcmp (name, "EXTVAL") == 0))
	    {
	      vcard_EXTVAL_t *newel = vcard_EXTVAL_decode (reader);
	      if (newel == NULL)
		{
		  return NULL;
		}
	      elm->type = EXTENSION_TYPE_VCARD_EXTVAL;
	      elm->u->fEXTVAL = newel;
	    }
	}
    }
  return elm;
}

int
vcard_AGENT_encode (xmlwriter_t * writer, struct vcard_AGENT_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_vcard, "AGENT");
  if (err != 0)
    return err;
  if (elm->u != NULL)
    {
      err = xstream_extension_encode (writer, (void *) elm->u, elm->type);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_AGENT_free (struct vcard_AGENT_t *data)
{
  if (data == NULL)
    return;
  if (data->u != NULL)
    {
      extension_t ext = { data->type, data->u };
      xstream_extension_free (&ext);
    }
  free (data);
}

struct vcard_ORG_t *
vcard_ORG_decode (xmlreader_t * reader)
{
  struct vcard_ORG_t *elm = NULL;
  elm = malloc (sizeof (struct vcard_ORG_t));
  if (elm == NULL)
    fatal ("vcard_ORG_t: malloc failed");
  memset (elm, 0, sizeof (struct vcard_ORG_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "ORGNAME") == 0)
	      && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fORGNAME = (char *) value;
	    }
	  else if ((strcmp (name, "ORGUNIT") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      if (elm->fORGUNIT == NULL)
		elm->fORGUNIT = array_new (sizeof (char *), 0);
	      array_append (elm->fORGUNIT, (void *) &value);
	    }
	}
    }
  return elm;
}

int
vcard_ORG_encode (xmlwriter_t * writer, struct vcard_ORG_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_vcard, "ORG");
  if (err != 0)
    return err;
  if (elm->fORGNAME != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_vcard, "ORGNAME", elm->fORGNAME);
      if (err != 0)
	return err;
    }
  int len = array_length (elm->fORGUNIT);
  int i = 0;
  for (i = 0; i < len; i++)
    {
      char **value = array_get (elm->fORGUNIT, i);
      err =
	xmlwriter_simple_element (writer, ns_vcard, "ORGUNIT",
				  (char *) value);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_ORG_free (struct vcard_ORG_t *data)
{
  if (data == NULL)
    return;
  if (data->fORGNAME != NULL)
    {
      free (data->fORGNAME);
    }
  int len = array_length (data->fORGUNIT);
  int i = 0;
  for (i = 0; i < len; i++)
    {
      char **value = array_get (data->fORGUNIT, i);
      free (*value);
    }
  array_free (data->fORGUNIT);
  free (data);
}

struct vcard_CATEGORIES_t *
vcard_CATEGORIES_decode (xmlreader_t * reader)
{
  struct vcard_CATEGORIES_t *elm = NULL;
  elm = malloc (sizeof (struct vcard_CATEGORIES_t));
  if (elm == NULL)
    fatal ("vcard_CATEGORIES_t: malloc failed");
  memset (elm, 0, sizeof (struct vcard_CATEGORIES_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "KEYWORD") == 0)
	      && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      if (elm->fKEYWORD == NULL)
		elm->fKEYWORD = array_new (sizeof (char *), 0);
	      array_append (elm->fKEYWORD, (void *) &value);
	    }
	}
    }
  return elm;
}

int
vcard_CATEGORIES_encode (xmlwriter_t * writer, struct vcard_CATEGORIES_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_vcard, "CATEGORIES");
  if (err != 0)
    return err;
  int len = array_length (elm->fKEYWORD);
  int i = 0;
  for (i = 0; i < len; i++)
    {
      char **value = array_get (elm->fKEYWORD, i);
      err =
	xmlwriter_simple_element (writer, ns_vcard, "KEYWORD",
				  (char *) value);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_CATEGORIES_free (struct vcard_CATEGORIES_t *data)
{
  if (data == NULL)
    return;
  int len = array_length (data->fKEYWORD);
  int i = 0;
  for (i = 0; i < len; i++)
    {
      char **value = array_get (data->fKEYWORD, i);
      free (*value);
    }
  array_free (data->fKEYWORD);
  free (data);
}

vcard_NOTE_t *
vcard_NOTE_decode (xmlreader_t * reader)
{
  vcard_NOTE_t *elm = NULL;
  const char *value = xmlreader_text (reader);
  if (reader->err != 0)
    return NULL;
  elm = (vcard_NOTE_t *) value;
  return elm;
}

int
vcard_NOTE_encode (xmlwriter_t * writer, vcard_NOTE_t * elm)
{
  int err = 0;
  err =
    xmlwriter_simple_element (writer, ns_vcard, "NOTE", (vcard_NOTE_t *) elm);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_NOTE_free (vcard_NOTE_t * data)
{
  if (data == NULL)
    return;
  free (data);
  free (data);
}

vcard_PRODID_t *
vcard_PRODID_decode (xmlreader_t * reader)
{
  vcard_PRODID_t *elm = NULL;
  const char *value = xmlreader_text (reader);
  if (reader->err != 0)
    return NULL;
  elm = (vcard_PRODID_t *) value;
  return elm;
}

int
vcard_PRODID_encode (xmlwriter_t * writer, vcard_PRODID_t * elm)
{
  int err = 0;
  err =
    xmlwriter_simple_element (writer, ns_vcard, "PRODID",
			      (vcard_PRODID_t *) elm);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_PRODID_free (vcard_PRODID_t * data)
{
  if (data == NULL)
    return;
  free (data);
  free (data);
}

vcard_REV_t *
vcard_REV_decode (xmlreader_t * reader)
{
  vcard_REV_t *elm = NULL;
  const char *value = xmlreader_text (reader);
  if (reader->err != 0)
    return NULL;
  elm = (vcard_REV_t *) value;
  return elm;
}

int
vcard_REV_encode (xmlwriter_t * writer, vcard_REV_t * elm)
{
  int err = 0;
  err =
    xmlwriter_simple_element (writer, ns_vcard, "REV", (vcard_REV_t *) elm);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_REV_free (vcard_REV_t * data)
{
  if (data == NULL)
    return;
  free (data);
  free (data);
}

vcard_SORT_STRING_t *
vcard_SORT_STRING_decode (xmlreader_t * reader)
{
  vcard_SORT_STRING_t *elm = NULL;
  const char *value = xmlreader_text (reader);
  if (reader->err != 0)
    return NULL;
  elm = (vcard_SORT_STRING_t *) value;
  return elm;
}

int
vcard_SORT_STRING_encode (xmlwriter_t * writer, vcard_SORT_STRING_t * elm)
{
  int err = 0;
  err =
    xmlwriter_simple_element (writer, ns_vcard, "SORT-STRING",
			      (vcard_SORT_STRING_t *) elm);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_SORT_STRING_free (vcard_SORT_STRING_t * data)
{
  if (data == NULL)
    return;
  free (data);
  free (data);
}

struct vcard_SOUND_t *
vcard_SOUND_decode (xmlreader_t * reader)
{
  struct vcard_SOUND_t *elm = NULL;
  elm = malloc (sizeof (struct vcard_SOUND_t));
  if (elm == NULL)
    fatal ("vcard_SOUND_t: malloc failed");
  memset (elm, 0, sizeof (struct vcard_SOUND_t));
  const char *value = xmlreader_text (reader);
  if (reader->err != 0)
    return NULL;
  elm->fValue = (char *) value;
  return elm;
}

int
vcard_SOUND_encode (xmlwriter_t * writer, struct vcard_SOUND_t *elm)
{
  int err = 0;
  const char *name = enum_vcard_SOUND_type_to_string (elm->fType);
  err = xmlwriter_start_element (writer, ns_vcard, name);
  if (err != 0)
    return err;
  if (elm->fValue != NULL)
    {
      err = xmlwriter_text (writer, elm->fValue);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_SOUND_free (struct vcard_SOUND_t *data)
{
  if (data == NULL)
    return;
  if (data->fValue != NULL)
    {
      free (data->fValue);
    }
  free (data);
}

vcard_PHONETIC_t *
vcard_PHONETIC_decode (xmlreader_t * reader)
{
  vcard_PHONETIC_t *elm = NULL;
  const char *value = xmlreader_text (reader);
  if (reader->err != 0)
    return NULL;
  elm = (vcard_PHONETIC_t *) value;
  return elm;
}

int
vcard_PHONETIC_encode (xmlwriter_t * writer, vcard_PHONETIC_t * elm)
{
  int err = 0;
  err =
    xmlwriter_simple_element (writer, ns_vcard, "PHONETIC",
			      (vcard_PHONETIC_t *) elm);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_PHONETIC_free (vcard_PHONETIC_t * data)
{
  if (data == NULL)
    return;
  free (data);
  free (data);
}

vcard_UID_t *
vcard_UID_decode (xmlreader_t * reader)
{
  vcard_UID_t *elm = NULL;
  const char *value = xmlreader_text (reader);
  if (reader->err != 0)
    return NULL;
  elm = (vcard_UID_t *) value;
  return elm;
}

int
vcard_UID_encode (xmlwriter_t * writer, vcard_UID_t * elm)
{
  int err = 0;
  err =
    xmlwriter_simple_element (writer, ns_vcard, "UID", (vcard_UID_t *) elm);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_UID_free (vcard_UID_t * data)
{
  if (data == NULL)
    return;
  free (data);
  free (data);
}

vcard_URL_t *
vcard_URL_decode (xmlreader_t * reader)
{
  vcard_URL_t *elm = NULL;
  const char *value = xmlreader_text (reader);
  if (reader->err != 0)
    return NULL;
  elm = (vcard_URL_t *) value;
  return elm;
}

int
vcard_URL_encode (xmlwriter_t * writer, vcard_URL_t * elm)
{
  int err = 0;
  err =
    xmlwriter_simple_element (writer, ns_vcard, "URL", (vcard_URL_t *) elm);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_URL_free (vcard_URL_t * data)
{
  if (data == NULL)
    return;
  free (data);
  free (data);
}

vcard_DESC_t *
vcard_DESC_decode (xmlreader_t * reader)
{
  vcard_DESC_t *elm = NULL;
  const char *value = xmlreader_text (reader);
  if (reader->err != 0)
    return NULL;
  elm = (vcard_DESC_t *) value;
  return elm;
}

int
vcard_DESC_encode (xmlwriter_t * writer, vcard_DESC_t * elm)
{
  int err = 0;
  err =
    xmlwriter_simple_element (writer, ns_vcard, "DESC", (vcard_DESC_t *) elm);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_DESC_free (vcard_DESC_t * data)
{
  if (data == NULL)
    return;
  free (data);
  free (data);
}

struct vcard_CLASS_t *
vcard_CLASS_decode (xmlreader_t * reader)
{
  struct vcard_CLASS_t *elm = NULL;
  elm = malloc (sizeof (struct vcard_CLASS_t));
  if (elm == NULL)
    fatal ("vcard_CLASS_t: malloc failed");
  memset (elm, 0, sizeof (struct vcard_CLASS_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if (strcmp (namespace, ns_vcard) != 0)
	    {
	      elm->fType = enum_vcard_CLASS_type_from_string (name);
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	    }
	}
    }
  return elm;
}

int
vcard_CLASS_encode (xmlwriter_t * writer, struct vcard_CLASS_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_vcard, "CLASS");
  if (err != 0)
    return err;
  if (elm->fType != 0)
    {
      const char *name = enum_vcard_CLASS_type_to_string (elm->fType);
      err = xmlwriter_simple_element (writer, ns_vcard, name, NULL);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_CLASS_free (struct vcard_CLASS_t *data)
{
  if (data == NULL)
    return;
  if (data->fType != 0)
    {
    }
  free (data);
}

struct vcard_KEY_t *
vcard_KEY_decode (xmlreader_t * reader)
{
  struct vcard_KEY_t *elm = NULL;
  elm = malloc (sizeof (struct vcard_KEY_t));
  if (elm == NULL)
    fatal ("vcard_KEY_t: malloc failed");
  memset (elm, 0, sizeof (struct vcard_KEY_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "TYPE") == 0)
	      && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fTYPE = (char *) value;
	    }
	  else if ((strcmp (name, "CRED") == 0)
		   && (strcmp (namespace, ns_vcard) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fCRED = (char *) value;
	    }
	}
    }
  return elm;
}

int
vcard_KEY_encode (xmlwriter_t * writer, struct vcard_KEY_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_vcard, "KEY");
  if (err != 0)
    return err;
  if (elm->fTYPE != NULL)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "TYPE", elm->fTYPE);
      if (err != 0)
	return err;
    }
  if (elm->fCRED != NULL)
    {
      err = xmlwriter_simple_element (writer, ns_vcard, "CRED", elm->fCRED);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
vcard_KEY_free (struct vcard_KEY_t *data)
{
  if (data == NULL)
    return;
  if (data->fTYPE != NULL)
    {
      free (data->fTYPE);
    }
  if (data->fCRED != NULL)
    {
      free (data->fCRED);
    }
  free (data);
}

enum vcard_SOUND_type_t
enum_vcard_SOUND_type_from_string (const char *value)
{
  if (strcmp (value, "PHONETIC") == 0)
    return VCARD_SOUND_TYPE_PHONETIC;
  else if (strcmp (value, "BINVAL") == 0)
    return VCARD_SOUND_TYPE_BINVAL;
  else if (strcmp (value, "EXTVAL") == 0)
    return VCARD_SOUND_TYPE_EXTVAL;
  return 0;
}

const char *
enum_vcard_SOUND_type_to_string (enum vcard_SOUND_type_t value)
{
  switch (value)
    {
    case VCARD_SOUND_TYPE_PHONETIC:
      return "PHONETIC";
    case VCARD_SOUND_TYPE_BINVAL:
      return "BINVAL";
    case VCARD_SOUND_TYPE_EXTVAL:
      return "EXTVAL";
    }
  return NULL;
}

enum vcard_CLASS_type_t
enum_vcard_CLASS_type_from_string (const char *value)
{
  if (strcmp (value, "PUBLIC") == 0)
    return VCARD_CLASS_TYPE_PUBLIC;
  else if (strcmp (value, "PRIVATE") == 0)
    return VCARD_CLASS_TYPE_PRIVATE;
  else if (strcmp (value, "CONFIDENTIAL") == 0)
    return VCARD_CLASS_TYPE_CONFIDENTIAL;
  return 0;
}

const char *
enum_vcard_CLASS_type_to_string (enum vcard_CLASS_type_t value)
{
  switch (value)
    {
    case VCARD_CLASS_TYPE_PUBLIC:
      return "PUBLIC";
    case VCARD_CLASS_TYPE_PRIVATE:
      return "PRIVATE";
    case VCARD_CLASS_TYPE_CONFIDENTIAL:
      return "CONFIDENTIAL";
    }
  return NULL;
}
<file_sep>#ifndef _SESSION_DATA_H_
#define  _SESSION_DATA_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <string.h>
#include "xstream.h"
#include "types.h"


extern const char *ns_session;


struct session_session_t
{
};


struct session_session_t *session_session_decode (xmlreader_t * reader);
int session_session_encode (xmlwriter_t * writer,
			    struct session_session_t *data);
void session_session_free (struct session_session_t *data);
#endif
<file_sep>#ifndef _IQ_H_
#define _IQ_H_

#include "xmppdata/client_data.h"
#include "stream.h"
#include "jid/jid.h"

typedef struct client_iq_t iq_t;

iq_t* iq_new (stream_t* strm, jid_t* from, jid_t* to, int type, void* payload,
              int extension_type);
void iq_free (iq_t* iq);

#endif
<file_sep>#ifndef _XEP_XOOB_DATA_H_
#define  _XEP_XOOB_DATA_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <string.h>
#include "xstream.h"
#include "types.h"


extern const char *ns_xoob;


struct xoob_x_t
{
  char *fUrl;
  char *fDesc;
};


struct xoob_x_t *xoob_x_decode (xmlreader_t * reader);
int xoob_x_encode (xmlwriter_t * writer, struct xoob_x_t *data);
void xoob_x_free (struct xoob_x_t *data);
#endif
<file_sep>#ifndef _BIND_DATA_H_
#define  _BIND_DATA_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <string.h>
#include "xstream.h"
#include "types.h"
#include "jid/jid.h"


extern const char *ns_bind;


struct bind_bind_t
{
  char *fResource;
  jid_t *fJid;
};


struct bind_bind_t *bind_bind_decode (xmlreader_t * reader);
int bind_bind_encode (xmlwriter_t * writer, struct bind_bind_t *data);
void bind_bind_free (struct bind_bind_t *data);
#endif
<file_sep>#ifndef _SASL_DATA_H_
#define  _SASL_DATA_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <string.h>
#include "xstream.h"
#include "types.h"


extern const char *ns_sasl;

enum sasl_failure_condition_t
{
  SASL_FAILURE_CONDITION_ABORTED,
  SASL_FAILURE_CONDITION_ACCOUNT_DISABLED,
  SASL_FAILURE_CONDITION_CREDENTIALS_EXPIRED,
  SASL_FAILURE_CONDITION_ENCRYPTION_REQUIRED,
  SASL_FAILURE_CONDITION_INCORRECT_ENCODING,
  SASL_FAILURE_CONDITION_INVALID_AUTHZID,
  SASL_FAILURE_CONDITION_INVALID_MECHANISM,
  SASL_FAILURE_CONDITION_MALFORMED_REQUEST,
  SASL_FAILURE_CONDITION_MECHANISM_TOO_WEAK,
  SASL_FAILURE_CONDITION_NOT_AUTHORIZED,
  SASL_FAILURE_CONDITION_TEMPORARY_AUTH_FAILURE,
  SASL_FAILURE_CONDITION_TRANSITION_NEEDED,
};

enum sasl_failure_condition_t enum_sasl_failure_condition_from_string (const
								       char
								       *value);
const char *enum_sasl_failure_condition_to_string (enum
						   sasl_failure_condition_t);

struct sasl_mechanisms_t
{
  array_t *fMechanism;
};


struct sasl_auth_t
{
  char *fMechanism;
  unsigned char *fData;
  int fData_len;
};


struct sasl_success_t
{
  unsigned char *fData;
  int fData_len;
};


struct sasl_challenge_t
{
  unsigned char *fData;
  int fData_len;
};


struct sasl_response_t
{
  unsigned char *fData;
  int fData_len;
};


struct sasl_failure_t
{
  langstring_t *fText;
  enum sasl_failure_condition_t fCondition;
};


struct sasl_mechanisms_t *sasl_mechanisms_decode (xmlreader_t * reader);
int sasl_mechanisms_encode (xmlwriter_t * writer,
			    struct sasl_mechanisms_t *data);
void sasl_mechanisms_free (struct sasl_mechanisms_t *data);
struct sasl_auth_t *sasl_auth_decode (xmlreader_t * reader);
int sasl_auth_encode (xmlwriter_t * writer, struct sasl_auth_t *data);
void sasl_auth_free (struct sasl_auth_t *data);
struct sasl_success_t *sasl_success_decode (xmlreader_t * reader);
int sasl_success_encode (xmlwriter_t * writer, struct sasl_success_t *data);
void sasl_success_free (struct sasl_success_t *data);
struct sasl_challenge_t *sasl_challenge_decode (xmlreader_t * reader);
int sasl_challenge_encode (xmlwriter_t * writer,
			   struct sasl_challenge_t *data);
void sasl_challenge_free (struct sasl_challenge_t *data);
struct sasl_response_t *sasl_response_decode (xmlreader_t * reader);
int sasl_response_encode (xmlwriter_t * writer, struct sasl_response_t *data);
void sasl_response_free (struct sasl_response_t *data);
struct sasl_failure_t *sasl_failure_decode (xmlreader_t * reader);
int sasl_failure_encode (xmlwriter_t * writer, struct sasl_failure_t *data);
void sasl_failure_free (struct sasl_failure_t *data);
#endif
<file_sep>#ifndef _JID_H_
#define _JID_H_

typedef struct {
  char *node;
  char *domain;
  char *resource;
  char *full;
} jid_t;

jid_t *jid_of_string (const char* str);
char* jid_to_string (jid_t *jid);
void jid_free (jid_t *jid);

int jid_resourceprep (const char* str, char** result);

#endif
<file_sep>#include "xep_xoob_data.h"
#include "helpers.h"
#include "errors.h"

const char *ns_xoob = "jabber:x:oob";

struct xoob_x_t *
xoob_x_decode (xmlreader_t * reader)
{
  struct xoob_x_t *elm = NULL;
  elm = malloc (sizeof (struct xoob_x_t));
  if (elm == NULL)
    fatal ("xoob_x_t: malloc failed");
  memset (elm, 0, sizeof (struct xoob_x_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "url") == 0)
	      && (strcmp (namespace, ns_xoob) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fUrl = (char *) value;
	    }
	  else if ((strcmp (name, "desc") == 0)
		   && (strcmp (namespace, ns_xoob) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fDesc = (char *) value;
	    }
	}
    }
  return elm;
}

int
xoob_x_encode (xmlwriter_t * writer, struct xoob_x_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_xoob, "x");
  if (err != 0)
    return err;
  if (elm->fUrl != NULL)
    {
      err = xmlwriter_simple_element (writer, ns_xoob, "url", elm->fUrl);
      if (err != 0)
	return err;
    }
  if (elm->fDesc != NULL)
    {
      err = xmlwriter_simple_element (writer, ns_xoob, "desc", elm->fDesc);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
xoob_x_free (struct xoob_x_t *data)
{
  if (data == NULL)
    return;
  if (data->fUrl != NULL)
    {
      free (data->fUrl);
    }
  if (data->fDesc != NULL)
    {
      free (data->fDesc);
    }
  free (data);
}
<file_sep>#include <stdio.h>
#include <unistd.h>

#include "xmlreader.h"
#include <string.h>

#include <xstream.h>
#include "types.h"
#include "account.h"
#include "stream.h"
#include "errors.h"
#include "helpers.h"
#include "xmppdata/client_data.h"

int xstream_extension_decode (xmlreader_t* reader, extension_t* ext) {
  int i = 0;

  const char* name = xmlreader_get_name (reader);
  const char* namespace = xmlreader_get_namespace (reader);

  void *(*decode) (xmlreader_t* reader);

  for (i = 0; i < extensions_len; i++) {
    if (strcmp ((char*) name, extensions[i].name) == 0 &&
        strcmp ((char*) namespace, extensions[i].namespace) == 0) {
      decode = extensions[i].decode;
      ext->type = extensions[i].type;
      ext->data = decode(reader);
      return reader->err;
    }
  }
  
  return ERR_EXTENSION_NOT_FOUND;
}

int xstream_extension_encode (xmlwriter_t* writer, void* data, int type) {
  int i;
  int (*encoder)(xmlwriter_t* writer, void* data);

  for (i = 0; i < extensions_len; i++) {
    if (extensions[i].type == type) {
      encoder = extensions[i].encode;
      return encoder(writer, data);
    }
  }
  return ERR_EXTENSION_NOT_FOUND;
}

void xstream_extension_free (extension_t* ext) {
  if (ext == NULL)
    return;
  int i = 0;
  for (i = 0; i < extensions_len; i++) {
    if (extensions[i].type == ext->type) {
      extensions[i].free (ext->data);
    }
  }
}

int xstream_read (stream_t* strm, extension_t* ext) {
 again:
  xmlreader_stack_clean (&strm->reader, 1);
  xmlreader_read (&strm->reader);
  if (strm->reader.err == 0) {
    xmlreader_next (&strm->reader);
    int ret = xstream_extension_decode (&strm->reader, ext);
    strm->reader.iterator = 0;
    return ret;
  } else if (strm->reader.err == ERR_BUFIO_READER_END_OF_INPUT) {
    strm->reader.err = 0;
      char buf[4096];
      int ret = read (strm->fd, buf, bufio_reader_available (&strm->reader.bufio));
      if (ret > 0) {
        bufio_reader_fill (&strm->reader.bufio, buf, ret);
        goto again;
      } else if (ret == 0)
        return ERR_READ_CLOSE;
      else
        return ERR_READ_ERROR;
  } else
    return strm->reader.err;
}

int xstream_start (int fd, account_t* account) {
  int err = 0;
  stream_t* strm = stream_new (fd, ns_client, "ru", true, NULL);

  err = stream_start (strm, account);
  if (err != 0) return err;

  while (1) {
    extension_t ext;
    err = xstream_read (strm, &ext);
    if (err != 0) return err;
    err = stream_process (strm, account, &ext);
    if (err != 0) return err;
  }

}
<file_sep>#include <stdio.h>
#include <openssl/md5.h>
#include <openssl/hmac.h>
#include <openssl/sha.h>
#include <stdarg.h>
#include <stdio.h>
#include <malloc.h>
#include <string.h>

#include "helpers.h"
#include "base64.h"
#include "bufio.h"
#include "account.h"
#include "stream.h"
#include "xmppdata/sasl_data.h"
#include "errors.h"
#include "jid/jid.h"
#include "hex.h"

struct sasl_state_t {
  int type;
  int stage;
  char clientFirstMessageBare[1054];
  char cnonce[0];
  unsigned char serverSignature[20];
};

struct string_t {
  unsigned char* str;
  int len;
};

static int mystrlen (const char* str, int len) {
  int i = 0;
  for (i = 0; i < len && *str != '\0' && *str != ','; i++) str++;
  return i;
}

static int sasl_PLAIN (stream_t* strm, account_t* account, void** data, extension_t* ext) {
  if (data == NULL || *data == NULL)
    fatal ("sasl_DIGEST_MD5: state data is null");

  switch (ext->type) {
  case EXTENSION_TYPE_SASL_MECHANISMS: {
    int err = 0;

    char data[2024];
    int len1 = strlen (account->jid->node);
    int len2 = strlen (account->password);
  
    data[0] = '\0';
    memcpy (data+1, account->jid->node, len1);
    data[len1+1] = '\0';
    memcpy (data+2+len1, account->password, len2);
    data[len1+len2+2] = '\0';
          
    struct sasl_auth_t sasl_auth = {"PLAIN", (unsigned char*) data, len1+len2+2};
    err = sasl_auth_encode (&strm->writer, &sasl_auth);
    if (err != 0) return err;
    err = xmlwriter_flush (&strm->writer);
    if (err != 0) return err;
    return 1;
  }
  case EXTENSION_TYPE_SASL_SUCCESS:
    free (*data);
    return 0;

  case EXTENSION_TYPE_SASL_FAILURE:
  case EXTENSION_TYPE_STREAM_ERROR: {
    extension_t* error = malloc (sizeof (extension_t));
    memcpy (error, &ext, sizeof (extension_t));
    strm->xmpp_error = error;
    return ERR_XMPP_ERROR;
  }
  }
  return ERR_BAD_PROTOCOL;
}

static void make_cnonce (char *s, const int len) {
  static const char alphanum[] = "0123456789ABCDEF";

  int i = 0;
  for (i = 0; i < len; i++) {
    *s++ = alphanum[rand() % (sizeof(alphanum) - 1)];
  }
  *s = 0;
}

static void md5_sum (unsigned char* out, int nparams, ...) {
  va_list arg;
  va_start (arg, nparams);
  int i = 0;

  MD5_CTX c;

  MD5_Init (&c);
  for (i = 0; i < nparams; i++) {
    unsigned char* data = va_arg (arg, unsigned char*);
    int len = va_arg (arg, int);
    MD5_Update (&c, data, len);
  }
  va_end (arg);
  MD5_Final (out, &c);
}

static int sasl_DIGEST_MD5(stream_t* strm, account_t* account, void** data, extension_t* ext) {
  int err = 0;
  
  if (data == NULL || *data == NULL)
    fatal ("sasl_DIGEST_MD5: state data is null");
  struct sasl_state_t* sasl_state = *data;
  
  switch (ext->type) {
  case EXTENSION_TYPE_SASL_MECHANISMS: {
    struct sasl_auth_t sasl_auth = {"<PASSWORD>", NULL, 0};
    err = sasl_auth_encode (&strm->writer, &sasl_auth);
    if (err != 0) return err;
    err = xmlwriter_flush (&strm->writer);
    if (err != 0) return err;
    return 1;
  }
    
  case EXTENSION_TYPE_SASL_CHALLENGE: {
    if (sasl_state->stage == 0) {
      struct sasl_challenge_t* sasl_challenge = ext->data;
      char* nonce = NULL;
      char* qop = NULL;
    
      char* ptr, *key, *value, *sep;

      ptr =  (char*) sasl_challenge->fData;
      while (ptr != NULL) {
        sep = strchr (ptr, '=');
        if (sep == NULL) {
          key = ptr;
          value = NULL;
          ptr = NULL;
        } else {
          key = ptr;
          ptr = sep+1;
          value = ptr;
          *sep = '\0';
          if (value[0] == '"') {
            ++value;
            sep = strchr (value, '"');
            if (sep == NULL)
              return ERR_SASL;
            *sep++ = '\0';
            ptr = sep;
          }
          sep = strchr (ptr, ',');
          if (sep == NULL)
            ptr = NULL;
          else {
          *sep = '\0';
          ptr = sep+1;
          }
        }

      if (strcmp ("nonce", key) == 0)
        nonce = value;
      else if (strcmp ("qop", key) == 0)
        qop = value;
      }

      if (nonce == NULL || qop == NULL)
        return ERR_SASL;

      char cnonce[9];
      make_cnonce (cnonce, 8);
      char* nc = "00000001";
      
      bool exists = false;
      ptr = qop;
      while (ptr != NULL) {
        if (strncmp (ptr, "auth", 4) == 0 && (ptr[4] == '\0' || ptr[4] == ',')) {
          exists = true;
          break;
        }
        sep = strchr (ptr, ',');
        if (sep == NULL)
          break;
        else
          ptr = sep+1;
      }
      if (!exists) { return ERR_SASL_NO_KNOWN_QOP_METHOD; }

      unsigned char a0[MD5_DIGEST_LENGTH];
      md5_sum (a0, 5, account->jid->node, strlen (account->jid->node), ":", 1,
               account->jid->domain, strlen (account->jid->domain), ":", 1,
               account->password, strlen (account->password));
      
      unsigned char a1[MD5_DIGEST_LENGTH];
      md5_sum (a1, 5, a0, MD5_DIGEST_LENGTH, ":", 1, nonce, strlen (nonce),
               ":", 1, cnonce, strlen (cnonce));
      
      unsigned char a2[MD5_DIGEST_LENGTH];
      md5_sum (a2, 2, "AUTHENTICATE:xmpp/", 18,
               account->jid->domain, strlen (account->jid->domain));
      
      char hex1 [MD5_DIGEST_LENGTH * 2 + 1];
      hex_of_binary (hex1, a1, MD5_DIGEST_LENGTH);
      
      char hex2 [MD5_DIGEST_LENGTH * 2 + 1];
      hex_of_binary (hex2, a2, MD5_DIGEST_LENGTH);
      
      unsigned char t[MD5_DIGEST_LENGTH];
      md5_sum (t, 9, hex1, 32, ":", 1, nonce, strlen (nonce), ":", 1, nc, strlen (nc), 
               ":", 1, cnonce, strlen (cnonce), ":auth:", 6, hex2, 32);
      
      char hext[MD5_DIGEST_LENGTH * 2 + 1];
      hex_of_binary (hext, t, MD5_DIGEST_LENGTH);
      
      char response[4096];
      int len = sprintf (response, 
                         "charset=\"utf-8\",username=\"%s\",realm=\"%s\",nonce=\"%s\",cnonce=\"%s\",nc=\"%s\",qop=\"auth\",digest-uri=\"xmpp/%s\",response=\"%s\"",
                         account->jid->node, account->jid->domain,
                       nonce, cnonce, nc, account->jid->domain, hext);

      sasl_state->stage = 1;
      struct sasl_response_t sasl_response = { (unsigned char*) response, len};
      err = sasl_response_encode (&strm->writer, &sasl_response);
      if (err != 0) return err;
    
      err = xmlwriter_flush (&strm->writer);
      if (err != 0) return err;
      return 1;
    } else {
      struct sasl_response_t sasl_response = { NULL, 0};
      err = sasl_response_encode (&strm->writer, &sasl_response);
      if (err != 0) return err;
      err = xmlwriter_flush (&strm->writer);
      if (err != 0) return err;
      return 1;
    }
  }

  case EXTENSION_TYPE_SASL_SUCCESS:
    free (sasl_state);
    return 0;

  case EXTENSION_TYPE_SASL_FAILURE:
  case EXTENSION_TYPE_STREAM_ERROR: {
    extension_t* error = malloc (sizeof (extension_t));
    memcpy (error, &ext, sizeof (extension_t));
    strm->xmpp_error = error;
    return ERR_XMPP_ERROR;
  }
  }
	return ERR_BAD_PROTOCOL;
}

static void scram_H (unsigned char* data, int data_len, unsigned char* mdkey) {
  SHA_CTX c;
  SHA1_Init (&c);
  SHA1_Update(&c, data, data_len);
  SHA1_Final (mdkey, &c);
}

static void scram_HMAC (const unsigned char* key, const unsigned int key_len,
                        const unsigned char* data, const unsigned int data_len,
                        unsigned char* result) {

  /*
  HMAC (EVP_sha1(), key, key_len, data, data_len, result, 20);
  */
  unsigned int result_len = 20;
  HMAC_CTX hmac;
  HMAC_Init (&hmac, key, key_len, EVP_sha1());
  HMAC_Update (&hmac, data, data_len);
  HMAC_Final (&hmac, result, &result_len);
  HMAC_CTX_cleanup (&hmac);
}

static inline void scram_XOR(unsigned char* x1, const unsigned int x1_len,
                             const unsigned char* x2) {
  int i = 0;
  
  for (i = 0; i < x1_len; i++) {
    x1[i] ^= x2[i];
  }
}

static void scram_Hi (const unsigned char* key, const unsigned int key_len,
                      const unsigned char* salt, const unsigned int salt_len, unsigned int i,
                      unsigned char* result) {

  unsigned char u1[20];
  unsigned int u1_len = 20;

  HMAC_CTX hmac;
  // HMAC_CTX_init (&hmac);
  
  HMAC_Init (&hmac, key, key_len, EVP_sha1());
  HMAC_Update (&hmac, salt, salt_len);
  HMAC_Update (&hmac, (unsigned char*) "\0\0\0\1", 4);
  HMAC_Final (&hmac, u1, &u1_len);
  HMAC_CTX_cleanup (&hmac);

  unsigned char u2[20];
  
  unsigned char x[20];
  memcpy(x, u1, u1_len);
  
  unsigned char uprev[20];
  memcpy (uprev, u1, u1_len);
  
  for (; i > 1; i--) {
    scram_HMAC (key, key_len, uprev, u1_len, u2);
    memcpy (uprev, u2, u1_len);
    scram_XOR(x, u1_len, u2);
  }
  memcpy (result, x, 20);
}

static int sasl_SCRAM_SHA_1 (stream_t* strm, account_t* account, void** data, extension_t* ext) {
  int err = 0;
  
  if (data == NULL || *data == NULL)
    fatal ("sasl_DIGEST_MD5: state data is null");
  struct sasl_state_t* sasl_state = *data;

  switch (ext->type) {
  case EXTENSION_TYPE_SASL_MECHANISMS: {
    make_cnonce(sasl_state->cnonce, 8);

    sprintf (sasl_state->clientFirstMessageBare, "n=%s,r=%s", account->jid->node,
             sasl_state->cnonce);

    char data[1040];
    int len = sprintf (data, "n,,%s", sasl_state->clientFirstMessageBare);

    struct sasl_auth_t sasl_auth = {"SCRAM-SHA-1", (unsigned char*) data, len};
    err = sasl_auth_encode (&strm->writer, &sasl_auth);
    if (err != 0) return err;
    
    err = xmlwriter_flush (&strm->writer);
    if (err != 0) return err;

    return 1;
  }
    
  case EXTENSION_TYPE_SASL_CHALLENGE: {
    struct sasl_challenge_t* sasl_challenge = ext->data;
    if (sasl_challenge->fData == NULL)
      return ERR_BAD_PROTOCOL;

    const char* serverFirstMessage = (const char*) sasl_challenge->fData;
    int serverFirstMessage_len = sasl_challenge->fData_len;

    char key;
    char* value;
    char* ptr = (char*) sasl_challenge->fData;
    int len = 0, l = 0;
    
    struct string_t salt, r;
    unsigned int iteration = 0;
    
    while (len < sasl_challenge->fData_len) {
      key = ptr[0];
      ptr++; len++;
      value = NULL;
      l = 0;
      if (len < sasl_challenge->fData_len) {
        if (*ptr == '=') {
          ptr++; len++;
        }
        l = mystrlen (ptr, sasl_challenge->fData_len - len);
      }
      if (l > 0) {
        value = ptr;
      }
      ptr += l;
      len += l;
      switch (key) {
      case 's': {
        err = base64_decode (value, l, &salt.str, &salt.len);
        if (err != 0) return err;
        break;
      }
      case 'i': {
        char tmp[10];
        memcpy (tmp, value, l);
        tmp[l] = 0;
        iteration = atoi (tmp);
        break;
      }
      case 'r':
        r.str = (unsigned char*) value; r.len = l;
        break;
      }
      if (len + 1 < sasl_challenge->fData_len) {
        if (*ptr == ',') {
          ptr++; len++;
        } else
          return ERR_SASL;
      }
    }
      
    char* str = NULL;
    err = jid_resourceprep (account->password, &str);
    if (err != 0) return err;
    
    unsigned char saltedpassword[20];
    scram_Hi ((unsigned char*) str, strlen (str), salt.str, salt.len, iteration, saltedpassword);
    free (salt.str);
    
    unsigned char clientKey[20];
    scram_HMAC (saltedpassword, 20, (unsigned char*) "Client Key",10, clientKey);
    
    unsigned char storedKey[20];
    scram_H (clientKey, 20, storedKey);
    
    int clientFinalMessageWithoutProof_len = 9 + r.len;
    
    char* clientFinalMessageWithoutProof = malloc (clientFinalMessageWithoutProof_len);
    if (clientFinalMessageWithoutProof == NULL)
      fatal ("sasl_SCRAM_SHA_1: malloc failed");
    memcpy (clientFinalMessageWithoutProof, "c=biws,r=", 9);
    memcpy (clientFinalMessageWithoutProof + 9, r.str, r.len);
      
    int clientFirstMessageBare_len = strlen (sasl_state->clientFirstMessageBare);

    char authMessage[4096];
    memcpy (authMessage, sasl_state->clientFirstMessageBare, clientFirstMessageBare_len);
    authMessage[clientFirstMessageBare_len] = ',';
    memcpy (authMessage + clientFirstMessageBare_len + 1,
            serverFirstMessage, serverFirstMessage_len);
    authMessage[clientFirstMessageBare_len + 1 + serverFirstMessage_len] = ',';
    memcpy (authMessage + clientFirstMessageBare_len + serverFirstMessage_len + 2,
            clientFinalMessageWithoutProof, clientFinalMessageWithoutProof_len);
    int authMessage_len = clientFirstMessageBare_len + serverFirstMessage_len +
      clientFinalMessageWithoutProof_len + 2;
    
    unsigned char clientSignature[20];
    scram_HMAC (storedKey, 20, (unsigned char*) authMessage, authMessage_len, clientSignature);
    
    unsigned char clientProof[20];
    memcpy (clientProof, clientKey, 20);
    scram_XOR (clientProof, 20, clientSignature);
    
    unsigned char serverKey[20];
    scram_HMAC (saltedpassword, 20, (unsigned char*) "Server Key", 10, serverKey);
    
    scram_HMAC (serverKey, 20, (unsigned char*) authMessage,authMessage_len,
                sasl_state->serverSignature);
    
    char* encoded_prof = base64_encode(clientProof, 20);
    int encoded_prof_len = strlen (encoded_prof);
    
    char response[4096];
    memcpy (response, clientFinalMessageWithoutProof, clientFinalMessageWithoutProof_len);
    memcpy (response + clientFinalMessageWithoutProof_len, ",p=", 3);
    memcpy (response + clientFinalMessageWithoutProof_len + 3, encoded_prof, encoded_prof_len);
    len = clientFinalMessageWithoutProof_len + 3 + encoded_prof_len;
    
    free (str);
    free (encoded_prof);
    free (clientFinalMessageWithoutProof);
    
    struct sasl_response_t sasl_response = { (unsigned char*) response , len};
    err = sasl_response_encode (&strm->writer, &sasl_response);
    if (err != 0) return err;
    err = xmlwriter_flush (&strm->writer);
    if (err != 0) return err;
    return 1;
  }

  case EXTENSION_TYPE_SASL_SUCCESS: {
    struct sasl_success_t* sasl_success = ext->data;

    char key;
    char* value;
    char* ptr = (char*) sasl_success->fData;
    int len = 0, l = 0;
    
    while (len < sasl_success->fData_len) {
      key = ptr[0];
      ptr++; len++;
      value = NULL;
      l = 0;
      if (len < sasl_success->fData_len) {
        if (ptr[0] == '=') {
          ptr++; len++;
        } else
          return ERR_SASL;
        l = mystrlen (ptr, sasl_success->fData_len - len);
        if (l > 0) {
          value = ptr;
          ptr += l;
          len += l;
        }
      }
      
      switch (key) {
      case 'v': {
        if (value == NULL) return ERR_SASL;
        struct string_t v;
        err = base64_decode (value, l, &v.str, &v.len);
        if (err != 0) return err;
        
        if (strncmp ((char*) v.str, (char*) sasl_state->serverSignature, v.len) != 0) {
          free (v.str);
          return ERR_SASL_SERVER_SIGNATURE_MISMATCH;
        }
        free (v.str);
      }
      }
      if (len + 1 < sasl_success->fData_len) {
        if (*ptr == ',') {
          ptr++; len++;
        } else
          return ERR_SASL;
      }
    }
    free (sasl_state);
    return 0;
  }
    
  case EXTENSION_TYPE_SASL_FAILURE:
  case EXTENSION_TYPE_STREAM_ERROR: {
    free (sasl_state);
    extension_t* error = malloc (sizeof (extension_t));
    memcpy (error, &ext, sizeof (extension_t));
    strm->xmpp_error = error;
    return ERR_XMPP_ERROR;
  }
  }
  return ERR_BAD_PROTOCOL;
}

struct mechanisms_t {
  char* name;
  int (*callback) (stream_t* strm, account_t* account, void** data, extension_t* ext);
};

static struct mechanisms_t known_mechanismss[] = {
  {"SCRAM-SHA-1", sasl_SCRAM_SHA_1},
  {"DIGEST-MD5", sasl_DIGEST_MD5},
  {"PLAIN", sasl_PLAIN},
};
static int known_mechanismss_len = 3;

bool sasl_is_mandatory (stream_t* strm) {
  return true;
}

bool sasl_need_restart () {
  return true;
}

int sasl_negotate (stream_t* strm, account_t* account, void** data, extension_t* ext) {
  if (ext->type == EXTENSION_TYPE_SASL_MECHANISMS && data != NULL && *data == NULL) {
    struct sasl_mechanisms_t* sasl_mechanisms = ext->data;
    int len = array_length (sasl_mechanisms->fMechanism);
    int i = 0, j = 0;
  
    for (j = 0; j < known_mechanismss_len; j++) {
      for (i = 0; i < len; i++) {
        const char** value = array_get (sasl_mechanisms->fMechanism, i);
        if (value != NULL && strcmp (known_mechanismss[j].name, *value) == 0) {
          struct sasl_state_t* sasl_state = malloc (sizeof (struct sasl_state_t));
          if (sasl_state == NULL)
            fatal ("sasl_negotate: malloc failed");
          memset (sasl_state, 0, sizeof (struct sasl_state_t));
          
          sasl_state->type = j;
          *data = sasl_state;
          return known_mechanismss[j].callback (strm, account, data, ext);
        }
      }
    }
    return ERR_SASL_NO_KNOWN_METHOD;
  }
  if (data == NULL || *data == NULL)
    fatal ("sasl_negotate: sasl_state is null");
    
  struct sasl_state_t* sasl_state = *data;
  if (sasl_state->type < known_mechanismss_len)
    return known_mechanismss[sasl_state->type].callback (strm, account, data, ext);
  
  return ERR_BAD_PROTOCOL;
}

struct stream_feature_t sasl_feature = {
  EXTENSION_TYPE_SASL_MECHANISMS,
  sasl_is_mandatory,
  sasl_need_restart,
  sasl_negotate
};
<file_sep>#include "iq.h"
#include "helpers.h"

iq_t* iq_new (stream_t* strm, jid_t* from, jid_t* to, int type, void* payload,
              int extension_type) {
  iq_t* iq = malloc (sizeof (iq_t));
  if (iq == NULL)
    fatal ("iq_new: malloc failed");
  memset (iq, 0, sizeof (iq_t));

  iq->fId = stream_get_id (strm);

  iq->fFrom = from;
  iq->fTo = to;
  iq->fType = type;

  if (payload != NULL) {
    if (type == CLIENT_IQ_TYPE_ERROR)
      iq->fError = payload;
    else {
      extension_t * ext = malloc (sizeof (extension_t));
      if (ext == NULL)
        fatal ("iq_new: malloc failed");
      ext ->type = extension_type;
      ext->data = payload;
      iq->fPayload = ext;
    }
  }
  return iq;
}
  
void iq_free (iq_t* iq) {
  if (iq == NULL)
    return;
  
  if (iq->fPayload != NULL)
    free (iq->fPayload);

  free (iq);
}
<file_sep>#ifndef _SRV_H_
#define _SRV_H_

typedef struct {
  char *name;
  int prio;
  int weight;
  int port;
} srv_record;

struct _srv_list;

struct _srv_list {
  srv_record *data;
  struct _srv_list *next;
};

typedef struct _srv_list srv_list;

srv_list *srv_lookup(const char* service);

srv_record *srv_record_get(srv_list **srvs);

void srv_list_destroy (srv_list *srvlist);

#endif
<file_sep>#ifndef _LLIST_H_
#define _LLIST_H_

struct _llist_t;
struct _llist_t {
  void* data;
  struct _llist_t* next;
};
typedef struct _llist_t llist_t;

void llist_append (llist_t** root, void* data);
void llist_free (llist_t* root);

struct _vlist_t;
struct _vlist_t {
  int type;
  void *data;
  struct _vlist_t *next;
};
typedef struct _vlist_t vlist_t;

void vlist_append (vlist_t** root, void* data, int type);
void vlist_free (vlist_t* root);
void* vlist_get (vlist_t* root, int type);

#endif
<file_sep>#ifndef _BUFIO_H_
#define _BUFIO_H_

#include <stdint.h>

typedef struct {
  int fd;
  char* buf;
  int length;
  int pos;
} bufio_writer_t;

bufio_writer_t* bufio_writer_new (int fd);
void bufio_writer_free (bufio_writer_t* writer);
void bufio_writer_reset (bufio_writer_t* writer);
int bufio_writer_flush (bufio_writer_t* writer);
int bufio_writer_write (bufio_writer_t* writer, int ncount, ...);
int bufio_writer_write_len (bufio_writer_t* writer, const char* str, int len);

typedef struct {
  int err;
  char* buf;
  int length;
  int read_pos;
  int write_pos;
} bufio_reader_t;

void bufio_reader_init (bufio_reader_t* reader);
int bufio_reader_available (bufio_reader_t* reader);
int bufio_reader_fill (bufio_reader_t* reader, char* buf, int len);
void bufio_reader_free (bufio_reader_t* reader);
void bufio_reader_reset (bufio_reader_t* reader);
uint8_t bufio_reader_get_byte (bufio_reader_t* reader);
void bufio_reader_unget_byte (bufio_reader_t* reader);
uint32_t bufio_reader_get_rune (bufio_reader_t* reader);

#endif
<file_sep>#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

#include "config.h"
#include "connect.h"
#include "xstream.h"

int main(int argc, char* argv[]) {
  config_t *config = config_load ("config.yaml");

  if (config != NULL && config->accounts != NULL) {
    account_t first_account = config->accounts[0];
  
    int sock;

    sock = tcp6_connect (&first_account);
    if (sock < 0) {
      perror ("Unable to use ipv6");
      sock = tcp4_connect(&first_account);
      if (sock < 0) {
        perror ("Unable to use ipv4");
        goto failure;
      }
    }

    int err = xstream_start (sock,  &first_account);
    if (err != 0)
      printf ("err = %d\n", err);
      
    config_destroy (config);
    return 0;
  }
  
 failure:
  printf ("failure\n");
  config_destroy (config);
  exit (EXIT_FAILURE);
}
  
<file_sep>#ifndef _XEP_VCARD_DATA_H_
#define  _XEP_VCARD_DATA_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <string.h>
#include "xstream.h"
#include "types.h"

struct vcard_N_t;
struct vcard_PHOTO_t;
struct vcard_ADR_t;
struct vcard_LABEL_t;
struct vcard_TEL_t;
struct vcard_EMAIL_t;
struct vcard_GEO_t;
struct vcard_LOGO_t;
struct vcard_AGENT_t;
struct vcard_ORG_t;
struct vcard_CATEGORIES_t;
struct vcard_SOUND_t;
struct vcard_CLASS_t;
struct vcard_KEY_t;
struct vcard_vcard_t;

extern const char *ns_vcard;

enum vcard_DOMINTL_t
{
  VCARD_DOMINTL_DOM,
  VCARD_DOMINTL_INTL,
};

enum vcard_DOMINTL_t enum_vcard_DOMINTL_from_string (const char *value);
const char *enum_vcard_DOMINTL_to_string (enum vcard_DOMINTL_t);
enum vcard_SOUND_type_t
{
  VCARD_SOUND_TYPE_PHONETIC,
  VCARD_SOUND_TYPE_BINVAL,
  VCARD_SOUND_TYPE_EXTVAL,
};

enum vcard_SOUND_type_t enum_vcard_SOUND_type_from_string (const char *value);
const char *enum_vcard_SOUND_type_to_string (enum vcard_SOUND_type_t);
enum vcard_CLASS_type_t
{
  VCARD_CLASS_TYPE_PUBLIC,
  VCARD_CLASS_TYPE_PRIVATE,
  VCARD_CLASS_TYPE_CONFIDENTIAL,
};

enum vcard_CLASS_type_t enum_vcard_CLASS_type_from_string (const char *value);
const char *enum_vcard_CLASS_type_to_string (enum vcard_CLASS_type_t);

struct vcard_vcard_t
{
  char *fVERSION;
  char *fFN;
  struct vcard_N_t *fN;
  array_t *fFields;
};


struct vcard_N_t
{
  char *fFAMILY;
  char *fGIVEN;
  char *fNIDDLE;
  char *fPREFIX;
  char *fSUFFIX;
};


typedef char vcard_NICKNAME_t;


struct vcard_PHOTO_t
{
  char *fTYPE;
  char *fBINVAL;
  char *fEXTVAL;
};


typedef char vcard_BDAY_t;


struct vcard_ADR_t
{
  bool fHOME;
  bool fWORK;
  bool fPOSTAL;
  bool fPARCEL;
  enum vcard_DOMINTL_t fDOMINTL;
  bool fPREF;
  char *fPOBOX;
  char *fEXTADD;
  char *fSTREET;
  char *fLOCALITY;
  char *fREGION;
  char *fPCODE;
  char *fCTRY;
};


struct vcard_LABEL_t
{
  bool fHOME;
  bool fWORK;
  bool fPOSTAL;
  bool fPARCEL;
  enum vcard_DOMINTL_t fDOMINTL;
  bool fPREF;
  array_t *fLINE;
};


struct vcard_TEL_t
{
  bool fHOME;
  bool fWORK;
  bool fVOICE;
  bool fFAX;
  bool fPAGER;
  bool fMSG;
  bool fCELL;
  bool fVIDEO;
  bool fBBS;
  bool fMODEM;
  bool fISDN;
  bool fPCS;
  bool fPREF;
  char *fNUMBER;
};


struct vcard_EMAIL_t
{
  bool fHOME;
  bool fWORK;
  bool fINTERNET;
  bool fPREF;
  bool fX400;
  char *fUSERID;
};


typedef char vcard_JABBERID_t;


typedef char vcard_MAILER_t;


typedef char vcard_TZ_t;


struct vcard_GEO_t
{
  char *fLAT;
  char *fLON;
};


typedef char vcard_TITLE_t;


typedef char vcard_ROLE_t;


struct vcard_LOGO_t
{
  char *fTYPE;
  char *fBINVAL;
  char *fEXTVAL;
};


typedef char vcard_EXTVAL_t;


struct vcard_AGENT_t
{
  int type;
  union
  {
    struct vcard_vcard_t *fVcard;
    vcard_EXTVAL_t *fEXTVAL;
  } *u;
};

struct vcard_ORG_t
{
  char *fORGNAME;
  array_t *fORGUNIT;
};


struct vcard_CATEGORIES_t
{
  array_t *fKEYWORD;
};


typedef char vcard_NOTE_t;


typedef char vcard_PRODID_t;


typedef char vcard_REV_t;


typedef char vcard_SORT_STRING_t;


struct vcard_SOUND_t
{
  enum vcard_SOUND_type_t fType;
  char *fValue;
};


typedef char vcard_PHONETIC_t;


typedef char vcard_UID_t;


typedef char vcard_URL_t;


typedef char vcard_DESC_t;


struct vcard_CLASS_t
{
  enum vcard_CLASS_type_t fType;
};


struct vcard_KEY_t
{
  char *fTYPE;
  char *fCRED;
};


struct vcard_vcard_t *vcard_vcard_decode (xmlreader_t * reader);
int vcard_vcard_encode (xmlwriter_t * writer, struct vcard_vcard_t *data);
void vcard_vcard_free (struct vcard_vcard_t *data);
struct vcard_N_t *vcard_N_decode (xmlreader_t * reader);
int vcard_N_encode (xmlwriter_t * writer, struct vcard_N_t *data);
void vcard_N_free (struct vcard_N_t *data);
vcard_NICKNAME_t *vcard_NICKNAME_decode (xmlreader_t * reader);
int vcard_NICKNAME_encode (xmlwriter_t * writer, vcard_NICKNAME_t * data);
void vcard_NICKNAME_free (vcard_NICKNAME_t * data);
struct vcard_PHOTO_t *vcard_PHOTO_decode (xmlreader_t * reader);
int vcard_PHOTO_encode (xmlwriter_t * writer, struct vcard_PHOTO_t *data);
void vcard_PHOTO_free (struct vcard_PHOTO_t *data);
vcard_BDAY_t *vcard_BDAY_decode (xmlreader_t * reader);
int vcard_BDAY_encode (xmlwriter_t * writer, vcard_BDAY_t * data);
void vcard_BDAY_free (vcard_BDAY_t * data);
struct vcard_ADR_t *vcard_ADR_decode (xmlreader_t * reader);
int vcard_ADR_encode (xmlwriter_t * writer, struct vcard_ADR_t *data);
void vcard_ADR_free (struct vcard_ADR_t *data);
struct vcard_LABEL_t *vcard_LABEL_decode (xmlreader_t * reader);
int vcard_LABEL_encode (xmlwriter_t * writer, struct vcard_LABEL_t *data);
void vcard_LABEL_free (struct vcard_LABEL_t *data);
struct vcard_TEL_t *vcard_TEL_decode (xmlreader_t * reader);
int vcard_TEL_encode (xmlwriter_t * writer, struct vcard_TEL_t *data);
void vcard_TEL_free (struct vcard_TEL_t *data);
struct vcard_EMAIL_t *vcard_EMAIL_decode (xmlreader_t * reader);
int vcard_EMAIL_encode (xmlwriter_t * writer, struct vcard_EMAIL_t *data);
void vcard_EMAIL_free (struct vcard_EMAIL_t *data);
vcard_JABBERID_t *vcard_JABBERID_decode (xmlreader_t * reader);
int vcard_JABBERID_encode (xmlwriter_t * writer, vcard_JABBERID_t * data);
void vcard_JABBERID_free (vcard_JABBERID_t * data);
vcard_MAILER_t *vcard_MAILER_decode (xmlreader_t * reader);
int vcard_MAILER_encode (xmlwriter_t * writer, vcard_MAILER_t * data);
void vcard_MAILER_free (vcard_MAILER_t * data);
vcard_TZ_t *vcard_TZ_decode (xmlreader_t * reader);
int vcard_TZ_encode (xmlwriter_t * writer, vcard_TZ_t * data);
void vcard_TZ_free (vcard_TZ_t * data);
struct vcard_GEO_t *vcard_GEO_decode (xmlreader_t * reader);
int vcard_GEO_encode (xmlwriter_t * writer, struct vcard_GEO_t *data);
void vcard_GEO_free (struct vcard_GEO_t *data);
vcard_TITLE_t *vcard_TITLE_decode (xmlreader_t * reader);
int vcard_TITLE_encode (xmlwriter_t * writer, vcard_TITLE_t * data);
void vcard_TITLE_free (vcard_TITLE_t * data);
vcard_ROLE_t *vcard_ROLE_decode (xmlreader_t * reader);
int vcard_ROLE_encode (xmlwriter_t * writer, vcard_ROLE_t * data);
void vcard_ROLE_free (vcard_ROLE_t * data);
struct vcard_LOGO_t *vcard_LOGO_decode (xmlreader_t * reader);
int vcard_LOGO_encode (xmlwriter_t * writer, struct vcard_LOGO_t *data);
void vcard_LOGO_free (struct vcard_LOGO_t *data);
vcard_EXTVAL_t *vcard_EXTVAL_decode (xmlreader_t * reader);
int vcard_EXTVAL_encode (xmlwriter_t * writer, vcard_EXTVAL_t * data);
void vcard_EXTVAL_free (vcard_EXTVAL_t * data);
struct vcard_AGENT_t *vcard_AGENT_decode (xmlreader_t * reader);
int vcard_AGENT_encode (xmlwriter_t * writer, struct vcard_AGENT_t *data);
void vcard_AGENT_free (struct vcard_AGENT_t *data);
struct vcard_ORG_t *vcard_ORG_decode (xmlreader_t * reader);
int vcard_ORG_encode (xmlwriter_t * writer, struct vcard_ORG_t *data);
void vcard_ORG_free (struct vcard_ORG_t *data);
struct vcard_CATEGORIES_t *vcard_CATEGORIES_decode (xmlreader_t * reader);
int vcard_CATEGORIES_encode (xmlwriter_t * writer,
			     struct vcard_CATEGORIES_t *data);
void vcard_CATEGORIES_free (struct vcard_CATEGORIES_t *data);
vcard_NOTE_t *vcard_NOTE_decode (xmlreader_t * reader);
int vcard_NOTE_encode (xmlwriter_t * writer, vcard_NOTE_t * data);
void vcard_NOTE_free (vcard_NOTE_t * data);
vcard_PRODID_t *vcard_PRODID_decode (xmlreader_t * reader);
int vcard_PRODID_encode (xmlwriter_t * writer, vcard_PRODID_t * data);
void vcard_PRODID_free (vcard_PRODID_t * data);
vcard_REV_t *vcard_REV_decode (xmlreader_t * reader);
int vcard_REV_encode (xmlwriter_t * writer, vcard_REV_t * data);
void vcard_REV_free (vcard_REV_t * data);
vcard_SORT_STRING_t *vcard_SORT_STRING_decode (xmlreader_t * reader);
int vcard_SORT_STRING_encode (xmlwriter_t * writer,
			      vcard_SORT_STRING_t * data);
void vcard_SORT_STRING_free (vcard_SORT_STRING_t * data);
struct vcard_SOUND_t *vcard_SOUND_decode (xmlreader_t * reader);
int vcard_SOUND_encode (xmlwriter_t * writer, struct vcard_SOUND_t *data);
void vcard_SOUND_free (struct vcard_SOUND_t *data);
vcard_PHONETIC_t *vcard_PHONETIC_decode (xmlreader_t * reader);
int vcard_PHONETIC_encode (xmlwriter_t * writer, vcard_PHONETIC_t * data);
void vcard_PHONETIC_free (vcard_PHONETIC_t * data);
vcard_UID_t *vcard_UID_decode (xmlreader_t * reader);
int vcard_UID_encode (xmlwriter_t * writer, vcard_UID_t * data);
void vcard_UID_free (vcard_UID_t * data);
vcard_URL_t *vcard_URL_decode (xmlreader_t * reader);
int vcard_URL_encode (xmlwriter_t * writer, vcard_URL_t * data);
void vcard_URL_free (vcard_URL_t * data);
vcard_DESC_t *vcard_DESC_decode (xmlreader_t * reader);
int vcard_DESC_encode (xmlwriter_t * writer, vcard_DESC_t * data);
void vcard_DESC_free (vcard_DESC_t * data);
struct vcard_CLASS_t *vcard_CLASS_decode (xmlreader_t * reader);
int vcard_CLASS_encode (xmlwriter_t * writer, struct vcard_CLASS_t *data);
void vcard_CLASS_free (struct vcard_CLASS_t *data);
struct vcard_KEY_t *vcard_KEY_decode (xmlreader_t * reader);
int vcard_KEY_encode (xmlwriter_t * writer, struct vcard_KEY_t *data);
void vcard_KEY_free (struct vcard_KEY_t *data);
#endif
<file_sep>#include <stdlib.h>

#include <malloc.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include "bufio.h"
#include "helpers.h"
#include "utf8.h"
#include "errors.h"

bufio_writer_t* bufio_writer_new (int fd) {
  bufio_writer_t* writer = malloc (sizeof (bufio_writer_t));
  if (writer == NULL)
    fatal ("bufio_writer_new: malloc failed");
  
  writer->fd = fd;
  writer->buf = malloc (sizeof (unsigned char) * 1024);
  if (writer->buf == NULL)
    fatal ("bufio_writer_new: malloc failed");
  
  writer->length = 1024;
  writer->pos = 0;
  return writer;
}

void bufio_writer_free (bufio_writer_t* writer) {
  if (writer == NULL)
    return;

  free (writer->buf);
  free (writer);
}

void bufio_writer_reset (bufio_writer_t* writer) {
  writer->pos = 0;
}

int bufio_writer_flush (bufio_writer_t* writer) {
  if (writer == NULL)
    fatal ("bufio_writer_flush: writer is null");

  if (writer->pos == 0)
    return 0;
  
  size_t sent = write (writer->fd, writer->buf, writer->pos);
  if (sent < 0)
    return sent;
  if (sent == 0)
    return ERR_IO_CLOSE;

  fwrite ("OUT: ", 1, 5, stdout);
  fwrite (writer->buf, 1, sent, stdout);
  fwrite ("\n", 1, 1, stdout);
  fflush (stdout);
  
  if (sent < writer->pos) {
    memmove (writer->buf, writer->buf + sent, writer->pos - sent);
    writer->pos -= sent;
  } else {
    writer->pos = 0;
  }
      
  return 0;
}

static inline int bufio_writer_available (bufio_writer_t* writer) {
  return writer->length - writer->pos;
}

int bufio_writer_write (bufio_writer_t* writer, int ncount, ...) {
  if (writer == NULL)
    fatal ("bufio_writer_write: writer is null");

  va_list arg;
  va_start (arg, ncount);

  int i, err;
  
  for (i = 0; i < ncount; i++) {
    char* str = va_arg (arg, char*);
    if (str == NULL)
      continue;
    int len = strlen (str);
    int start = 0;

    while (len - start > bufio_writer_available (writer)) {
      int avl = bufio_writer_available (writer);
      memmove (writer->buf + writer->pos, str + start, avl);
      writer->pos += avl;
      start += avl;
      err = bufio_writer_flush (writer);
      if (err != 0) {
        va_end (arg);
        return err;
      }
    }

    if (len - start > 0) {
      memmove (writer->buf + writer->pos, str + start, len - start);
      writer->pos += len - start;
    }
  }
  va_end (arg);
  return 0;
}

int bufio_writer_write_len (bufio_writer_t* writer, const char* str, int len) {
  if (writer == NULL)
    fatal ("bufio_writer_write_len: writer is null");
  
  memmove (writer->buf + writer->pos, str, len);
  writer->pos += len;

  return 0;
}

void bufio_reader_init (bufio_reader_t* reader) {
  memset (reader, 0, sizeof (bufio_reader_t));
  reader->buf = malloc (sizeof (unsigned char) * 4096);
  if (reader->buf == NULL)
    fatal ("bufio_reader_new: malloc failed");
  
  reader->length = 4096;
  reader->read_pos = reader->write_pos = 0;
  
}

void bufio_reader_free (bufio_reader_t* reader) {
  if (reader == NULL)
    return;

  free (reader->buf);
}

void bufio_reader_reset (bufio_reader_t* reader) {
  reader->err = 0;
  reader->read_pos = reader->write_pos = 0;
}  

inline int bufio_reader_available (bufio_reader_t* reader) {
  return reader->length - reader->write_pos;
}

 int bufio_reader_fill (bufio_reader_t* reader, char* buf, int len) {
  if (reader->read_pos > 0) {
    memmove (reader->buf, reader->buf + reader->read_pos, reader->write_pos - reader->read_pos);
      reader->write_pos -= reader->read_pos;
      reader->read_pos = 0;
    }

  if (reader->write_pos == reader->length)
    fatal ("bufio_reader_fill: buffer is full");

  len = (reader->length - reader->write_pos < len) ? reader->length - reader->write_pos : len;
  memmove (reader->buf + reader->write_pos, buf, len);
  
  fwrite ("IN: ", 1, 4, stdout);
  fwrite (reader->buf + reader->write_pos, 1, len, stdout);
  fwrite ("\n", 1, 1, stdout);
  fflush (stdout);
  
  reader->err = 0;
  reader->write_pos += len;
  return len;
}

uint8_t bufio_reader_get_byte (bufio_reader_t* reader) {
  if (reader == NULL)
    fatal ("bufio_reader_get_byte: reader is null");

  if (reader->read_pos == reader->write_pos) {
    reader->err = ERR_BUFIO_READER_END_OF_INPUT;
    return 0;
  }
    
  uint8_t c = (uint8_t) reader->buf[reader->read_pos];
  reader->read_pos++;
  return c;
}

void bufio_reader_unget_byte (bufio_reader_t* reader) {
  reader->read_pos--;
}

uint32_t bufio_reader_get_rune (bufio_reader_t* reader) {
  uint8_t c1 = bufio_reader_get_byte (reader);
  if (reader->err != 0) return 0;

  int width = utf8_width (c1);
  if (width > 0 && width - 1 + reader->read_pos > reader->write_pos) {
    reader->read_pos--;
    reader->err = ERR_BUFIO_READER_END_OF_INPUT;
    return 0;
  }
  
  switch (width) {
  case 1:
    return (uint32_t) c1;
  case 2: {
    uint8_t c2 = bufio_reader_get_byte (reader);
    if (reader->err != 0) return 0;
    if (c2 >> 6 != 0b10) {
      reader->err = ERR_MALFORMED_UTF8;
      return 0;
    } else
      return ((c1 & 0x1f)  << 6) | (c2 & 0x3f);
  }
  case 3: {
    uint8_t c2 = bufio_reader_get_byte (reader);
    if (reader->err != 0) return 0;
    uint8_t c3 = bufio_reader_get_byte (reader);
    if (reader->err != 0) return 0;
    if ((c2 >> 6 != 0b10) || (c3 >> 6 != 0b10)) {
      reader->err = ERR_MALFORMED_UTF8;
      return 0;
    } else {
      uint32_t code = 
        ((c1 & 0x0f) << 12) | ((c2 & 0x3f) < 6) | (c3 & 0x3f);
      if (code >= 0xd800 && code <= 0xdf00) {
        reader->err = ERR_MALFORMED_UTF8;
        return 0;
      } else
        return code;
    }
  }
  case 4: {
    uint8_t c2 = bufio_reader_get_byte (reader);
    if (reader->err != 0) return 0;
    uint8_t c3 = bufio_reader_get_byte (reader);
    if (reader->err != 0) return 0;
    uint8_t c4 = bufio_reader_get_byte (reader);
    if (reader->err != 0) return 0;

    if ((c2 >> 6 != 0b10) || (c3 >> 6 != 0b10) || (c4 >> 6 != 0b10)) {
      reader->err = ERR_MALFORMED_UTF8;
      return 0;
    } else
      return ((c1 & 0x07) << 18) | ((c2 & 0x3f) << 12) | ((c3 & 0x3f) << 6) | (c4 & 0x3f);
    break;
  }
  default:
    reader->err = width;
    return 0;
  }
}
<file_sep>#ifndef _XEP_PING_DATA_H_
#define  _XEP_PING_DATA_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <string.h>
#include "xstream.h"
#include "types.h"


extern const char *ns_ping;


struct ping_ping_t
{
};


struct ping_ping_t *ping_ping_decode (xmlreader_t * reader);
int ping_ping_encode (xmlwriter_t * writer, struct ping_ping_t *data);
void ping_ping_free (struct ping_ping_t *data);
#endif
<file_sep>#ifndef _XEP_STATS_DATA_H_
#define  _XEP_STATS_DATA_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <string.h>
#include "xstream.h"
#include "types.h"

struct stats_stat_t;

extern const char *ns_stats;




struct stats_stat_t
{
  char *fName;
  char *fUnits;
  char *fValue;
};


array_t *stats_stats_decode (xmlreader_t * reader);
int stats_stats_encode (xmlwriter_t * writer, array_t * data);
void stats_stats_free (array_t * data);
struct stats_stat_t *stats_stat_decode (xmlreader_t * reader);
int stats_stat_encode (xmlwriter_t * writer, struct stats_stat_t *data);
void stats_stat_free (struct stats_stat_t *data);
#endif
<file_sep>#include <malloc.h>
#include "llist.h"
#include "helpers.h"

void llist_append(llist_t** root, void* data) {
  llist_t* item = malloc (sizeof (llist_t));
  if (item == NULL)
    fatal ("llist_append: malloc failed");
      
  item->data = data;
  item->next = NULL;

  if (*root == NULL)
    *root = item;
  else {
    llist_t* curr = *root;

    while (curr->next != NULL)
      curr = curr->next;
    curr->next = item;
  }
}

void vlist_append(vlist_t** root, void* data, int type) {
  vlist_t* item = malloc (sizeof (vlist_t));
  if (item == NULL)
    fatal ("vlist_append: malloc failed");
  
  item->type = type;
  item->data = data;
  item->next = NULL;

  if (*root == NULL)
    *root = item;
  else {
    vlist_t* curr = *root;

    while (curr->next != NULL)
      curr = curr->next;
    curr->next = item;
  }
}

void* vlist_get (vlist_t* root, int type) {
  vlist_t* curr = root;
  while (curr != NULL) {
    if (curr->type == type)
      return curr->data;
    curr = curr->next;
  }
  return NULL;
}
<file_sep>#include "xep_caps_data.h"
#include "helpers.h"
#include "errors.h"

const char *ns_caps = "http://jabber.org/protocol/caps";

struct caps_caps_t *
caps_caps_decode (xmlreader_t * reader)
{
  struct caps_caps_t *elm = NULL;
  elm = malloc (sizeof (struct caps_caps_t));
  if (elm == NULL)
    fatal ("caps_caps_t: malloc failed");
  memset (elm, 0, sizeof (struct caps_caps_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "ext");
  if (avalue != NULL)
    {
      elm->fExt = (char *) avalue;
    }
  avalue = xmlreader_attribute (reader, NULL, "hash");
  if (avalue != NULL)
    {
      elm->fHash = (char *) avalue;
    }
  avalue = xmlreader_attribute (reader, NULL, "node");
  if (avalue != NULL)
    {
      elm->fNode = (char *) avalue;
    }
  avalue = xmlreader_attribute (reader, NULL, "ver");
  if (avalue != NULL)
    {
      elm->fVer = (char *) avalue;
    }
  if (xmlreader_skip_element (reader) == -1)
    return NULL;
  return elm;
}

int
caps_caps_encode (xmlwriter_t * writer, struct caps_caps_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_caps, "c");
  if (err != 0)
    return err;
  if (elm->fExt != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "ext", elm->fExt);
      if (err != 0)
	return err;
    }
  if (elm->fHash != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "hash", elm->fHash);
      if (err != 0)
	return err;
    }
  if (elm->fNode != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "node", elm->fNode);
      if (err != 0)
	return err;
    }
  if (elm->fVer != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "ver", elm->fVer);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
caps_caps_free (struct caps_caps_t *data)
{
  if (data == NULL)
    return;
  if (data->fExt != NULL)
    {
      free (data->fExt);
    }
  if (data->fHash != NULL)
    {
      free (data->fHash);
    }
  if (data->fNode != NULL)
    {
      free (data->fNode);
    }
  if (data->fVer != NULL)
    {
      free (data->fVer);
    }
  free (data);
}
<file_sep>#include "xep_iqtime_data.h"
#include "helpers.h"
#include "errors.h"

const char *ns_iqtime = "jabber:iq:time";

struct iqtime_time_t *
iqtime_time_decode (xmlreader_t * reader)
{
  struct iqtime_time_t *elm = NULL;
  elm = malloc (sizeof (struct iqtime_time_t));
  if (elm == NULL)
    fatal ("iqtime_time_t: malloc failed");
  memset (elm, 0, sizeof (struct iqtime_time_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "utc") == 0)
	      && (strcmp (namespace, ns_iqtime) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fUtc = (char *) value;
	    }
	  else if ((strcmp (name, "tz") == 0)
		   && (strcmp (namespace, ns_iqtime) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fTz = (char *) value;
	    }
	  else if ((strcmp (name, "display") == 0)
		   && (strcmp (namespace, ns_iqtime) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fDisplay = (char *) value;
	    }
	}
    }
  return elm;
}

int
iqtime_time_encode (xmlwriter_t * writer, struct iqtime_time_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_iqtime, "query");
  if (err != 0)
    return err;
  if (elm->fUtc != NULL)
    {
      err = xmlwriter_simple_element (writer, ns_iqtime, "utc", elm->fUtc);
      if (err != 0)
	return err;
    }
  if (elm->fTz != NULL)
    {
      err = xmlwriter_simple_element (writer, ns_iqtime, "tz", elm->fTz);
      if (err != 0)
	return err;
    }
  if (elm->fDisplay != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_iqtime, "display",
				  elm->fDisplay);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
iqtime_time_free (struct iqtime_time_t *data)
{
  if (data == NULL)
    return;
  if (data->fUtc != NULL)
    {
      free (data->fUtc);
    }
  if (data->fTz != NULL)
    {
      free (data->fTz);
    }
  if (data->fDisplay != NULL)
    {
      free (data->fDisplay);
    }
  free (data);
}
<file_sep>#include <malloc.h>
#include <string.h>
#include <stdint.h>
#include "array.h"
#include "helpers.h"

const uint32_t DEFAULT_CAPACITY = 16;

array_t* array_new(uint32_t size, uint32_t capacity) {
  array_t* array = malloc (sizeof (array_t));
  if (array == NULL)
    fatal("arraynew: malloc failed");
  array->length = 0;
  array->size = size;
  array->capacity = (capacity == 0) ? DEFAULT_CAPACITY : capacity;
  array->data = malloc (array->size * array->capacity);
  if (array->data == NULL)
    fatal("array_new: malloc failed");
  return array;
}

void array_free (array_t* array) {
  if (array == NULL) return;
  free (array->data);
  free (array);
}

uint32_t array_length (array_t* array) {
  if (array == NULL)
    fatal ("array_length: array is null");
  return array->length;
}

void* array_get (array_t* array, uint32_t idx) {
  if (array == NULL)
    fatal ("array_get: array is null");
  if (idx > array->length)
    fatal ("array_get: idx %d is larger then array length %d", idx, array->length);
  return array->data + idx * array->size;
}

inline void* array_get_last (array_t* array) {
  return array_get (array, array->length - 1);
}

inline void array_delete_last (array_t* array) {
  if (array->length > 0)
    array->length--;
}

void array_set (array_t* array, uint32_t idx, void* element) {
  if (array == NULL)
    fatal ("aggay_get: array is null");
  if (idx > array->length)
    fatal ("array_set: idx %d is larger than array length %d", idx, array->length);
  if (element == NULL)
    fatal ("array_set: element is null");
  memmove (array->data + idx * array->size, element, array->size);
}

void array_append (array_t* array, void* element) {
  if (array == NULL)
    fatal ("array_append: array is null");
  if (element == NULL)
    fatal ("array_append: element is null");
  if (array->length >= array->capacity) {
    int newcapacity = array->length << 1;
    printf ("array_append: reallocated %d %d\n", array->length, newcapacity);
    char* newdata = realloc (array->data, newcapacity * array->size);
    if (newdata == NULL)
      fatal ("array_append: realloc failed");
    array->capacity = newcapacity;
    array->data = newdata;
  }
  array->length += 1;
  array_set (array, array->length - 1, element);
}
  
void array_slice (array_t* array, int start, int length) {
  if (array == NULL)
    fatal ("array_slice: array is null");

  if (start < 0 || start > array->length)
    fatal ("array_slice: start %d is out of bounds", start);

  if (length < 0 || start + length > array->length)
    fatal ("array_slice: end %d is out of bounds", length);
  
  if (start > 0)
    memmove (array->data, array->data + start * array->size, length * array->size);
  array->length = length;
}
<file_sep>#ifndef _XEP_IQREGISTER_DATA_H_
#define  _XEP_IQREGISTER_DATA_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <string.h>
#include "xstream.h"
#include "types.h"
#include "xep_xdata_data.h"
#include "xep_xoob_data.h"


extern const char *ns_iqregister;


struct iqregister_query_t
{
  struct iqregister_fields_set_t
  {
    bool fRegistered;
    char *fInstructions;
    char *fUsername;
    char *fNick;
    char *fPassword;
    char *fName;
    char *fFirst;
    char *fLast;
    char *fEmail;
    char *fAddress;
    char *fCity;
    char *fState;
    char *fZip;
    char *fPhone;
    char *fUrl;
    char *fDate;
    char *fMisc;
    char *fText;
    char *fKey;
  } fFields;
  bool fRemove;
  struct xdata_x_t *fXdata;
  struct xoob_x_t *fXoob;
};


struct iqregister_query_t *iqregister_query_decode (xmlreader_t * reader);
int iqregister_query_encode (xmlwriter_t * writer,
			     struct iqregister_query_t *data);
void iqregister_query_free (struct iqregister_query_t *data);
#endif
<file_sep>#ifndef _STRINGMAP_H_
#define _STRINGMAP_H_

struct _stringpair_t;

struct _stringpair_t {
  const char* key;
  const char* value;
  struct _stringpair_t* next;
};

typedef struct _stringpair_t stringpair_t;

void stringpair_free (stringpair_t* stringpairs);

const char* stringpair_get (stringpair_t* stringpairs, const char* key);
void stringpair_set (stringpair_t** stringpairs, const char* key, const char* value);
void stringpair_delete (stringpair_t** stringpairs, const char* key);
void stringpair_delete_by_value (stringpair_t** root, const char* value);

#endif
<file_sep>#include "types.h"

int langstring_decode (xmlreader_t* reader, langstring_t *map) {
  const char* lang = xmlreader_attribute (reader, ns_xml, "lang");
  const char* value = xmlreader_text (reader);
  langstring_add (map, lang, value);
  return 1;
}

int langstring_encode (xmlwriter_t* writer, const char* space, const char* local, langstring_t *map) {
  return 1;
}

void langstring_free (langstring_t* map) {
}
<file_sep>#include "xep_iqversion_data.h"
#include "helpers.h"
#include "errors.h"

const char *ns_iqversion = "jabber:iq:version";

struct iqversion_version_t *
iqversion_version_decode (xmlreader_t * reader)
{
  struct iqversion_version_t *elm = NULL;
  elm = malloc (sizeof (struct iqversion_version_t));
  if (elm == NULL)
    fatal ("iqversion_version_t: malloc failed");
  memset (elm, 0, sizeof (struct iqversion_version_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "name") == 0)
	      && (strcmp (namespace, ns_iqversion) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fName = (char *) value;
	    }
	  else if ((strcmp (name, "version") == 0)
		   && (strcmp (namespace, ns_iqversion) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fVersion = (char *) value;
	    }
	  else if ((strcmp (name, "os") == 0)
		   && (strcmp (namespace, ns_iqversion) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fOs = (char *) value;
	    }
	}
    }
  return elm;
}

int
iqversion_version_encode (xmlwriter_t * writer,
			  struct iqversion_version_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_iqversion, "query");
  if (err != 0)
    return err;
  if (elm->fName != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_iqversion, "name", elm->fName);
      if (err != 0)
	return err;
    }
  if (elm->fVersion != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_iqversion, "version",
				  elm->fVersion);
      if (err != 0)
	return err;
    }
  if (elm->fOs != NULL)
    {
      err = xmlwriter_simple_element (writer, ns_iqversion, "os", elm->fOs);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
iqversion_version_free (struct iqversion_version_t *data)
{
  if (data == NULL)
    return;
  if (data->fName != NULL)
    {
      free (data->fName);
    }
  if (data->fVersion != NULL)
    {
      free (data->fVersion);
    }
  if (data->fOs != NULL)
    {
      free (data->fOs);
    }
  free (data);
}
<file_sep>#include <malloc.h>
#include "stringpair.h"
#include "helpers.h"

void stringpair_free (stringpair_t* stringpairs) {
  if (stringpairs == NULL)
    return;

  stringpair_t* curr = stringpairs;
  while (curr != NULL) {
    stringpair_t* next = curr->next;
    free (curr);
    curr = next;
  }
}

const char* stringpair_get (stringpair_t* root, const char* key) {
  if (root == NULL)
    return NULL;

  stringpair_t* curr = root;
  while (curr != NULL) {
    if (curr->key == key)
      return curr->value;
    curr = curr->next;
  }
  return NULL;
}

void stringpair_set (stringpair_t** root, const char* key, const char* value) {
  stringpair_t* pair = malloc (sizeof (stringpair_t));
  pair->key = key;
  pair->value = value;
  pair->next = NULL;

  if (*root == NULL)
    *root = pair;
  else {
    stringpair_t* curr = *root;
    while (curr->next != NULL)
      curr = curr->next;
    curr->next = pair;
  }
}

void stringpair_delete (stringpair_t** root, const char* key) {
  if (*root == NULL)
    return;

  stringpair_t* curr = *root;
  stringpair_t* prev = NULL;
  
  while (curr != NULL) {
    if (curr->key == key) {
      if (prev == NULL)
        *root = curr->next;
      else
        prev->next = curr->next;
      break;
    }
    prev = curr;
    curr = curr->next;
  }
}
  

void stringpair_delete_by_value (stringpair_t** root, const char* value) {
  if (*root == NULL)
    return;

  stringpair_t* curr = *root;
  stringpair_t* prev = NULL;
  
  while (curr != NULL) {
    if (curr->value == value) {
      if (prev == NULL)
        *root = curr->next;
      else
        prev->next = curr->next;
      break;
    }
    prev = curr;
    curr = curr->next;
  }
}
<file_sep>#include "xep_privacy_data.h"
#include "helpers.h"
#include "errors.h"

const char *ns_privacy = "jabber:iq:privacy";

struct privacy_privacy_t *
privacy_privacy_decode (xmlreader_t * reader)
{
  struct privacy_privacy_t *elm = NULL;
  elm = malloc (sizeof (struct privacy_privacy_t));
  if (elm == NULL)
    fatal ("privacy_privacy_t: malloc failed");
  memset (elm, 0, sizeof (struct privacy_privacy_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (namespace, ns_privacy) == 0)
	      && (strcmp (name, "list") == 0))
	    {
	      struct privacy_list_t *newel = privacy_list_decode (reader);
	      if (newel == NULL)
		{
		  return NULL;
		}
	      if (elm->fList == NULL)
		elm->fList = array_new (sizeof (extension_t), 0);
	      array_append (elm->fList, newel);
	    }
	}
    }
  return elm;
}

int
privacy_privacy_encode (xmlwriter_t * writer, struct privacy_privacy_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_privacy, "query");
  if (err != 0)
    return err;
  if (elm->fActive != NULL)
    {
      err = privacy_active_encode (writer, elm->fActive);
      if (err != 0)
	return err;
    }
  if (elm->fDefault != NULL)
    {
      err = privacy_default_encode (writer, elm->fDefault);
      if (err != 0)
	return err;
    }
  {
    int len = array_length (elm->fList);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	extension_t *ext = array_get (elm->fList, i);
	err = privacy_list_encode (writer, ext->data);
	if (err != 0)
	  return err;
      }
  }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
privacy_privacy_free (struct privacy_privacy_t *data)
{
  if (data == NULL)
    return;
  if (data->fActive != NULL)
    {
    }
  if (data->fDefault != NULL)
    {
    }
  {
    int len = array_length (data->fList);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	privacy_list_free (array_get (data->fList, i));
      }
    array_free (data->fList);
  }
  free (data);
}

struct privacy_active_t *
privacy_active_decode (xmlreader_t * reader)
{
  struct privacy_active_t *elm = NULL;
  elm = malloc (sizeof (struct privacy_active_t));
  if (elm == NULL)
    fatal ("privacy_active_t: malloc failed");
  memset (elm, 0, sizeof (struct privacy_active_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "name");
  if (avalue != NULL)
    {
      elm->fName = (char *) avalue;
    }
  const char *value = xmlreader_text (reader);
  if (reader->err != 0)
    return NULL;
  elm->fExtra = (char *) value;
  return elm;
}

int
privacy_active_encode (xmlwriter_t * writer, struct privacy_active_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_privacy, "active");
  if (err != 0)
    return err;
  if (elm->fName != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "name", elm->fName);
      if (err != 0)
	return err;
    }
  if (elm->fExtra != NULL)
    {
      err = xmlwriter_text (writer, elm->fExtra);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
privacy_active_free (struct privacy_active_t *data)
{
  if (data == NULL)
    return;
  if (data->fName != NULL)
    {
      free (data->fName);
    }
  if (data->fExtra != NULL)
    {
      free (data->fExtra);
    }
  free (data);
}

struct privacy_default_t *
privacy_default_decode (xmlreader_t * reader)
{
  struct privacy_default_t *elm = NULL;
  elm = malloc (sizeof (struct privacy_default_t));
  if (elm == NULL)
    fatal ("privacy_default_t: malloc failed");
  memset (elm, 0, sizeof (struct privacy_default_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "name");
  if (avalue != NULL)
    {
      elm->fName = (char *) avalue;
    }
  const char *value = xmlreader_text (reader);
  if (reader->err != 0)
    return NULL;
  elm->fExtra = (char *) value;
  return elm;
}

int
privacy_default_encode (xmlwriter_t * writer, struct privacy_default_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_privacy, "default");
  if (err != 0)
    return err;
  if (elm->fName != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "name", elm->fName);
      if (err != 0)
	return err;
    }
  if (elm->fExtra != NULL)
    {
      err = xmlwriter_text (writer, elm->fExtra);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
privacy_default_free (struct privacy_default_t *data)
{
  if (data == NULL)
    return;
  if (data->fName != NULL)
    {
      free (data->fName);
    }
  if (data->fExtra != NULL)
    {
      free (data->fExtra);
    }
  free (data);
}

struct privacy_list_t *
privacy_list_decode (xmlreader_t * reader)
{
  struct privacy_list_t *elm = NULL;
  elm = malloc (sizeof (struct privacy_list_t));
  if (elm == NULL)
    fatal ("privacy_list_t: malloc failed");
  memset (elm, 0, sizeof (struct privacy_list_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "name");
  if (avalue != NULL)
    {
      elm->fName = (char *) avalue;
    }
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (namespace, ns_privacy) == 0)
	      && (strcmp (name, "item") == 0))
	    {
	      struct privacy_item_t *newel = privacy_item_decode (reader);
	      if (newel == NULL)
		{
		  return NULL;
		}
	      if (elm->fItems == NULL)
		elm->fItems = array_new (sizeof (extension_t), 0);
	      array_append (elm->fItems, newel);
	    }
	}
    }
  return elm;
}

int
privacy_list_encode (xmlwriter_t * writer, struct privacy_list_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_privacy, "list");
  if (err != 0)
    return err;
  if (elm->fName != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "name", elm->fName);
      if (err != 0)
	return err;
    }
  {
    int len = array_length (elm->fItems);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	extension_t *ext = array_get (elm->fItems, i);
	err = privacy_item_encode (writer, ext->data);
	if (err != 0)
	  return err;
      }
  }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
privacy_list_free (struct privacy_list_t *data)
{
  if (data == NULL)
    return;
  if (data->fName != NULL)
    {
      free (data->fName);
    }
  {
    int len = array_length (data->fItems);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	privacy_item_free (array_get (data->fItems, i));
      }
    array_free (data->fItems);
  }
  free (data);
}

struct privacy_item_t *
privacy_item_decode (xmlreader_t * reader)
{
  struct privacy_item_t *elm = NULL;
  elm = malloc (sizeof (struct privacy_item_t));
  if (elm == NULL)
    fatal ("privacy_item_t: malloc failed");
  memset (elm, 0, sizeof (struct privacy_item_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "action");
  if (avalue != NULL)
    {
      elm->fAction = enum_privacy_item_action_from_string (avalue);
    }
  avalue = xmlreader_attribute (reader, NULL, "order");
  if (avalue != NULL)
    {
      elm->fOrder = strconv_parse_uint (avalue);
    }
  avalue = xmlreader_attribute (reader, NULL, "type");
  if (avalue != NULL)
    {
      elm->fType = enum_privacy_item_type_from_string (avalue);
    }
  avalue = xmlreader_attribute (reader, NULL, "value");
  if (avalue != NULL)
    {
      elm->fValue = (char *) avalue;
    }
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "iq") == 0)
	      && (strcmp (namespace, ns_privacy) == 0))
	    {
	      elm->fIq = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "message") == 0)
		   && (strcmp (namespace, ns_privacy) == 0))
	    {
	      elm->fMessage = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "presence-in") == 0)
		   && (strcmp (namespace, ns_privacy) == 0))
	    {
	      elm->fPresence_in = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "presence-out") == 0)
		   && (strcmp (namespace, ns_privacy) == 0))
	    {
	      elm->fPresence_out = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	}
    }
  return elm;
}

int
privacy_item_encode (xmlwriter_t * writer, struct privacy_item_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_privacy, "item");
  if (err != 0)
    return err;
  if (elm->fAction != 0)
    {
      err =
	xmlwriter_attribute (writer, NULL, "action",
			     enum_privacy_item_action_to_string (elm->
								 fAction));
      if (err != 0)
	return err;
    }
  if (elm->fOrder != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "order",
			     strconv_format_uint (elm->fOrder));
      if (err != 0)
	return err;
    }
  if (elm->fType != 0)
    {
      err =
	xmlwriter_attribute (writer, NULL, "type",
			     enum_privacy_item_type_to_string (elm->fType));
      if (err != 0)
	return err;
    }
  if (elm->fValue != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "value", elm->fValue);
      if (err != 0)
	return err;
    }
  if (elm->fIq)
    {
      err = xmlwriter_simple_element (writer, ns_privacy, "iq", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fMessage)
    {
      err = xmlwriter_simple_element (writer, ns_privacy, "message", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fPresence_in)
    {
      err =
	xmlwriter_simple_element (writer, ns_privacy, "presence-in", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fPresence_out)
    {
      err =
	xmlwriter_simple_element (writer, ns_privacy, "presence-out", NULL);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
privacy_item_free (struct privacy_item_t *data)
{
  if (data == NULL)
    return;
  if (data->fOrder != NULL)
    {
      free (data->fOrder);
    }
  if (data->fValue != NULL)
    {
      free (data->fValue);
    }
  if (data->fIq)
    {
    }
  if (data->fMessage)
    {
    }
  if (data->fPresence_in)
    {
    }
  if (data->fPresence_out)
    {
    }
  free (data);
}

enum privacy_item_action_t
enum_privacy_item_action_from_string (const char *value)
{
  if (strcmp (value, "allow") == 0)
    return PRIVACY_ITEM_ACTION_ALLOW;
  else if (strcmp (value, "deny") == 0)
    return PRIVACY_ITEM_ACTION_DENY;
  return 0;
}

const char *
enum_privacy_item_action_to_string (enum privacy_item_action_t value)
{
  switch (value)
    {
    case PRIVACY_ITEM_ACTION_ALLOW:
      return "allow";
    case PRIVACY_ITEM_ACTION_DENY:
      return "deny";
    }
  return NULL;
}

enum privacy_item_type_t
enum_privacy_item_type_from_string (const char *value)
{
  if (strcmp (value, "group") == 0)
    return PRIVACY_ITEM_TYPE_GROUP;
  else if (strcmp (value, "jid") == 0)
    return PRIVACY_ITEM_TYPE_JID;
  else if (strcmp (value, "subscription") == 0)
    return PRIVACY_ITEM_TYPE_SUBSCRIPTION;
  return 0;
}

const char *
enum_privacy_item_type_to_string (enum privacy_item_type_t value)
{
  switch (value)
    {
    case PRIVACY_ITEM_TYPE_GROUP:
      return "group";
    case PRIVACY_ITEM_TYPE_JID:
      return "jid";
    case PRIVACY_ITEM_TYPE_SUBSCRIPTION:
      return "subscription";
    }
  return NULL;
}
<file_sep>#include "roster_data.h"
#include "helpers.h"
#include "errors.h"

const char *ns_roster = "jabber:iq:roster";

struct roster_roster_t *
roster_roster_decode (xmlreader_t * reader)
{
  struct roster_roster_t *elm = NULL;
  elm = malloc (sizeof (struct roster_roster_t));
  if (elm == NULL)
    fatal ("roster_roster_t: malloc failed");
  memset (elm, 0, sizeof (struct roster_roster_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "ver");
  if (avalue != NULL)
    {
      elm->fVer = (char *) avalue;
    }
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (namespace, ns_roster) == 0)
	      && (strcmp (name, "item") == 0))
	    {
	      struct roster_item_t *newel = roster_item_decode (reader);
	      if (newel == NULL)
		{
		  return NULL;
		}
	      if (elm->fItems == NULL)
		elm->fItems = array_new (sizeof (extension_t), 0);
	      array_append (elm->fItems, newel);
	    }
	}
    }
  return elm;
}

int
roster_roster_encode (xmlwriter_t * writer, struct roster_roster_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_roster, "query");
  if (err != 0)
    return err;
  if (elm->fVer != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "ver", elm->fVer);
      if (err != 0)
	return err;
    }
  {
    int len = array_length (elm->fItems);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	extension_t *ext = array_get (elm->fItems, i);
	err = roster_item_encode (writer, ext->data);
	if (err != 0)
	  return err;
      }
  }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
roster_roster_free (struct roster_roster_t *data)
{
  if (data == NULL)
    return;
  if (data->fVer != NULL)
    {
      free (data->fVer);
    }
  {
    int len = array_length (data->fItems);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	roster_item_free (array_get (data->fItems, i));
      }
    array_free (data->fItems);
  }
  free (data);
}

struct roster_item_t *
roster_item_decode (xmlreader_t * reader)
{
  struct roster_item_t *elm = NULL;
  elm = malloc (sizeof (struct roster_item_t));
  if (elm == NULL)
    fatal ("roster_item_t: malloc failed");
  memset (elm, 0, sizeof (struct roster_item_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "approved");
  if (avalue != NULL)
    {
      elm->fApproved = strconv_parse_boolean (avalue);
    }
  avalue = xmlreader_attribute (reader, NULL, "ask");
  if (avalue != NULL)
    {
      elm->fAsk = enum_roster_item_ask_from_string (avalue);
    }
  avalue = xmlreader_attribute (reader, NULL, "jid");
  if (avalue != NULL)
    {
      jid_t *jid = jid_of_string (avalue);
      elm->fJid = jid;
    }
  avalue = xmlreader_attribute (reader, NULL, "name");
  if (avalue != NULL)
    {
      elm->fName = (char *) avalue;
    }
  avalue = xmlreader_attribute (reader, NULL, "subscription");
  if (avalue != NULL)
    {
      elm->fSubscription = enum_roster_item_subscription_from_string (avalue);
    }
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "group") == 0)
	      && (strcmp (namespace, ns_roster) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      if (elm->fGroup == NULL)
		elm->fGroup = array_new (sizeof (char *), 0);
	      array_append (elm->fGroup, (void *) &value);
	    }
	}
    }
  return elm;
}

int
roster_item_encode (xmlwriter_t * writer, struct roster_item_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_roster, "item");
  if (err != 0)
    return err;
  if (elm->fApproved)
    {
      err =
	xmlwriter_attribute (writer, NULL, "approved",
			     strconv_format_boolean (elm->fApproved));
      if (err != 0)
	return err;
    }
  if (elm->fAsk != 0)
    {
      err =
	xmlwriter_attribute (writer, NULL, "ask",
			     enum_roster_item_ask_to_string (elm->fAsk));
      if (err != 0)
	return err;
    }
  if (elm->fJid != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "jid", jid_to_string (elm->fJid));
      if (err != 0)
	return err;
    }
  if (elm->fName != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "name", elm->fName);
      if (err != 0)
	return err;
    }
  if (elm->fSubscription != 0)
    {
      err =
	xmlwriter_attribute (writer, NULL, "subscription",
			     enum_roster_item_subscription_to_string (elm->
								      fSubscription));
      if (err != 0)
	return err;
    }
  int len = array_length (elm->fGroup);
  int i = 0;
  for (i = 0; i < len; i++)
    {
      char **value = array_get (elm->fGroup, i);
      err =
	xmlwriter_simple_element (writer, ns_roster, "group", (char *) value);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
roster_item_free (struct roster_item_t *data)
{
  if (data == NULL)
    return;
  if (data->fApproved)
    {
      free (data->fApproved);
    }
  if (data->fJid != NULL)
    {
      jid_free (data->fJid);
    }
  if (data->fName != NULL)
    {
      free (data->fName);
    }
  int len = array_length (data->fGroup);
  int i = 0;
  for (i = 0; i < len; i++)
    {
      char **value = array_get (data->fGroup, i);
      free (*value);
    }
  array_free (data->fGroup);
  free (data);
}

enum roster_item_ask_t
enum_roster_item_ask_from_string (const char *value)
{
  if (strcmp (value, "subscribe") == 0)
    return ROSTER_ITEM_ASK_SUBSCRIBE;
  return 0;
}

const char *
enum_roster_item_ask_to_string (enum roster_item_ask_t value)
{
  switch (value)
    {
    case ROSTER_ITEM_ASK_SUBSCRIBE:
      return "subscribe";
    }
  return NULL;
}

enum roster_item_subscription_t
enum_roster_item_subscription_from_string (const char *value)
{
  if (strcmp (value, "both") == 0)
    return ROSTER_ITEM_SUBSCRIPTION_BOTH;
  else if (strcmp (value, "from") == 0)
    return ROSTER_ITEM_SUBSCRIPTION_FROM;
  else if (strcmp (value, "none") == 0)
    return ROSTER_ITEM_SUBSCRIPTION_NONE;
  else if (strcmp (value, "remove") == 0)
    return ROSTER_ITEM_SUBSCRIPTION_REMOVE;
  else if (strcmp (value, "to") == 0)
    return ROSTER_ITEM_SUBSCRIPTION_TO;
  return 0;
}

const char *
enum_roster_item_subscription_to_string (enum roster_item_subscription_t
					 value)
{
  switch (value)
    {
    case ROSTER_ITEM_SUBSCRIPTION_BOTH:
      return "both";
    case ROSTER_ITEM_SUBSCRIPTION_FROM:
      return "from";
    case ROSTER_ITEM_SUBSCRIPTION_NONE:
      return "none";
    case ROSTER_ITEM_SUBSCRIPTION_REMOVE:
      return "remove";
    case ROSTER_ITEM_SUBSCRIPTION_TO:
      return "to";
    }
  return NULL;
}
<file_sep>#include "xep_pubsub_data.h"
#include "helpers.h"
#include "errors.h"

const char *ns_pubsub_event = "http://jabber.org/protocol/pubsub#event";

struct pubsub_event_event_t *
pubsub_event_event_decode (xmlreader_t * reader)
{
  struct pubsub_event_event_t *elm = NULL;
  elm = malloc (sizeof (struct pubsub_event_event_t));
  if (elm == NULL)
    fatal ("pubsub_event_event_t: malloc failed");
  memset (elm, 0, sizeof (struct pubsub_event_event_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (namespace, ns_pubsub_event) == 0)
	      && (strcmp (name, "collection") == 0))
	    {
	      struct pubsub_event_collection_t *newel =
		pubsub_event_collection_decode (reader);
	      if (newel == NULL)
		{
		  return NULL;
		}
	      elm->type = EXTENSION_TYPE_PUBSUB_EVENT_COLLECTION;
	      elm->u->fCollection = newel;
	    }
	  else if ((strcmp (namespace, ns_pubsub_event) == 0)
		   && (strcmp (name, "configuration") == 0))
	    {
	      struct pubsub_event_configuration_t *newel =
		pubsub_event_configuration_decode (reader);
	      if (newel == NULL)
		{
		  return NULL;
		}
	      elm->type = EXTENSION_TYPE_PUBSUB_EVENT_CONFIGURATION;
	      elm->u->fConfiguration = newel;
	    }
	  else if ((strcmp (namespace, ns_pubsub_event) == 0)
		   && (strcmp (name, "delete") == 0))
	    {
	      struct pubsub_event_delete_t *newel =
		pubsub_event_delete_decode (reader);
	      if (newel == NULL)
		{
		  return NULL;
		}
	      elm->type = EXTENSION_TYPE_PUBSUB_EVENT_DELETE;
	      elm->u->fDelete = newel;
	    }
	  else if ((strcmp (namespace, ns_pubsub_event) == 0)
		   && (strcmp (name, "items") == 0))
	    {
	      struct pubsub_event_items_t *newel =
		pubsub_event_items_decode (reader);
	      if (newel == NULL)
		{
		  return NULL;
		}
	      elm->type = EXTENSION_TYPE_PUBSUB_EVENT_ITEMS;
	      elm->u->fItems = newel;
	    }
	  else if ((strcmp (namespace, ns_pubsub_event) == 0)
		   && (strcmp (name, "purge") == 0))
	    {
	      struct pubsub_event_purge_t *newel =
		pubsub_event_purge_decode (reader);
	      if (newel == NULL)
		{
		  return NULL;
		}
	      elm->type = EXTENSION_TYPE_PUBSUB_EVENT_PURGE;
	      elm->u->fPurge = newel;
	    }
	  else if ((strcmp (namespace, ns_pubsub_event) == 0)
		   && (strcmp (name, "subscription") == 0))
	    {
	      struct pubsub_event_subscription_t *newel =
		pubsub_event_subscription_decode (reader);
	      if (newel == NULL)
		{
		  return NULL;
		}
	      elm->type = EXTENSION_TYPE_PUBSUB_EVENT_SUBSCRIPTION;
	      elm->u->fSubscription = newel;
	    }
	}
    }
  return elm;
}

int
pubsub_event_event_encode (xmlwriter_t * writer,
			   struct pubsub_event_event_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_pubsub_event, "event");
  if (err != 0)
    return err;
  if (elm->u != NULL)
    {
      err = xstream_extension_encode (writer, (void *) elm->u, elm->type);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
pubsub_event_event_free (struct pubsub_event_event_t *data)
{
  if (data == NULL)
    return;
  if (data->u != NULL)
    {
      extension_t ext = { data->type, data->u };
      xstream_extension_free (&ext);
    }
  free (data);
}

struct pubsub_event_collection_t *
pubsub_event_collection_decode (xmlreader_t * reader)
{
  struct pubsub_event_collection_t *elm = NULL;
  elm = malloc (sizeof (struct pubsub_event_collection_t));
  if (elm == NULL)
    fatal ("pubsub_event_collection_t: malloc failed");
  memset (elm, 0, sizeof (struct pubsub_event_collection_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "node");
  if (avalue != NULL)
    {
      elm->fNode = (char *) avalue;
    }
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if (strcmp (namespace, ns_pubsub_event) != 0)
	    {
	      const char *avalue;
	      avalue = xmlreader_attribute (reader, NULL, "node");
	      if (avalue != NULL)
		{
		  elm->fType.fNode = (char *) avalue;
		}
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	    }
	}
    }
  return elm;
}

int
pubsub_event_collection_encode (xmlwriter_t * writer,
				struct pubsub_event_collection_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_pubsub_event, "collection");
  if (err != 0)
    return err;
  if (elm->fNode != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "node", elm->fNode);
      if (err != 0)
	return err;
    }
  const char *name =
    enum_pubsub_event_collection_type_type_to_string (elm->fType.fType);
  err = xmlwriter_start_element (writer, ns_pubsub_event, name);
  if (err != 0)
    return err;
  if (elm->fType.fNode != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "node", elm->fType.fNode);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
pubsub_event_collection_free (struct pubsub_event_collection_t *data)
{
  if (data == NULL)
    return;
  if (data->fNode != NULL)
    {
      free (data->fNode);
    }
  if (data->fType.fNode != NULL)
    {
      free (data->fType.fNode);
    }
  free (data);
}

struct pubsub_event_configuration_t *
pubsub_event_configuration_decode (xmlreader_t * reader)
{
  struct pubsub_event_configuration_t *elm = NULL;
  elm = malloc (sizeof (struct pubsub_event_configuration_t));
  if (elm == NULL)
    fatal ("pubsub_event_configuration_t: malloc failed");
  memset (elm, 0, sizeof (struct pubsub_event_configuration_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "node");
  if (avalue != NULL)
    {
      elm->fNode = (char *) avalue;
    }
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  {
	    if ((strcmp (namespace, "jabber:x:data") == 0)
		&& (strcmp (name, "x") == 0))
	      {
		struct xdata_x_t *newel = xdata_x_decode (reader);
		if (newel == NULL)
		  {
		    return NULL;
		  }
		elm->fXdata = newel;
	      }
	  }
	}
    }
  return elm;
}

int
pubsub_event_configuration_encode (xmlwriter_t * writer,
				   struct pubsub_event_configuration_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_pubsub_event, "configuration");
  if (err != 0)
    return err;
  if (elm->fNode != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "node", elm->fNode);
      if (err != 0)
	return err;
    }
  if (elm->fXdata != NULL)
    {
      err = xdata_x_encode (writer, elm->fXdata);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
pubsub_event_configuration_free (struct pubsub_event_configuration_t *data)
{
  if (data == NULL)
    return;
  if (data->fNode != NULL)
    {
      free (data->fNode);
    }
  if (data->fXdata != NULL)
    {
      xdata_x_free (data->fXdata);
    }
  free (data);
}

struct pubsub_event_delete_t *
pubsub_event_delete_decode (xmlreader_t * reader)
{
  struct pubsub_event_delete_t *elm = NULL;
  elm = malloc (sizeof (struct pubsub_event_delete_t));
  if (elm == NULL)
    fatal ("pubsub_event_delete_t: malloc failed");
  memset (elm, 0, sizeof (struct pubsub_event_delete_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "node");
  if (avalue != NULL)
    {
      elm->fNode = (char *) avalue;
    }
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "redirect") == 0)
	      && (strcmp (namespace, ns_pubsub_event) == 0))
	    {
	      const char *avalue;
	      avalue = xmlreader_attribute (reader, NULL, "url");
	      if (avalue != NULL)
		{
		  elm->fRedirect.fUrl = (char *) avalue;
		}
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	    }
	}
    }
  return elm;
}

int
pubsub_event_delete_encode (xmlwriter_t * writer,
			    struct pubsub_event_delete_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_pubsub_event, "delete");
  if (err != 0)
    return err;
  if (elm->fNode != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "node", elm->fNode);
      if (err != 0)
	return err;
    }
  err = xmlwriter_start_element (writer, ns_pubsub_event, "redirect");
  if (err != 0)
    return err;
  if (elm->fRedirect.fUrl != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "url", elm->fRedirect.fUrl);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
pubsub_event_delete_free (struct pubsub_event_delete_t *data)
{
  if (data == NULL)
    return;
  if (data->fNode != NULL)
    {
      free (data->fNode);
    }
  if (data->fRedirect.fUrl != NULL)
    {
      free (data->fRedirect.fUrl);
    }
  free (data);
}

struct pubsub_event_items_t *
pubsub_event_items_decode (xmlreader_t * reader)
{
  struct pubsub_event_items_t *elm = NULL;
  elm = malloc (sizeof (struct pubsub_event_items_t));
  if (elm == NULL)
    fatal ("pubsub_event_items_t: malloc failed");
  memset (elm, 0, sizeof (struct pubsub_event_items_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "node");
  if (avalue != NULL)
    {
      elm->fNode = (char *) avalue;
    }
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (namespace, ns_pubsub_event) == 0)
	      && (strcmp (name, "item") == 0))
	    {
	      struct pubsub_event_item_t *newel =
		pubsub_event_item_decode (reader);
	      if (newel == NULL)
		{
		  return NULL;
		}
	      if (elm->fItems == NULL)
		elm->fItems = array_new (sizeof (extension_t), 0);
	      array_append (elm->fItems, newel);
	    }
	  else if ((strcmp (namespace, ns_pubsub_event) == 0)
		   && (strcmp (name, "retract") == 0))
	    {
	      struct pubsub_event_retract_t *newel =
		pubsub_event_retract_decode (reader);
	      if (newel == NULL)
		{
		  return NULL;
		}
	      if (elm->fRetracts == NULL)
		elm->fRetracts = array_new (sizeof (extension_t), 0);
	      array_append (elm->fRetracts, newel);
	    }
	}
    }
  return elm;
}

int
pubsub_event_items_encode (xmlwriter_t * writer,
			   struct pubsub_event_items_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_pubsub_event, "items");
  if (err != 0)
    return err;
  if (elm->fNode != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "node", elm->fNode);
      if (err != 0)
	return err;
    }
  {
    int len = array_length (elm->fItems);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	extension_t *ext = array_get (elm->fItems, i);
	err = pubsub_event_item_encode (writer, ext->data);
	if (err != 0)
	  return err;
      }
  }
  {
    int len = array_length (elm->fRetracts);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	extension_t *ext = array_get (elm->fRetracts, i);
	err = pubsub_event_retract_encode (writer, ext->data);
	if (err != 0)
	  return err;
      }
  }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
pubsub_event_items_free (struct pubsub_event_items_t *data)
{
  if (data == NULL)
    return;
  if (data->fNode != NULL)
    {
      free (data->fNode);
    }
  {
    int len = array_length (data->fItems);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	pubsub_event_item_free (array_get (data->fItems, i));
      }
    array_free (data->fItems);
  }
  {
    int len = array_length (data->fRetracts);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	pubsub_event_retract_free (array_get (data->fRetracts, i));
      }
    array_free (data->fRetracts);
  }
  free (data);
}

struct pubsub_event_item_t *
pubsub_event_item_decode (xmlreader_t * reader)
{
  struct pubsub_event_item_t *elm = NULL;
  elm = malloc (sizeof (struct pubsub_event_item_t));
  if (elm == NULL)
    fatal ("pubsub_event_item_t: malloc failed");
  memset (elm, 0, sizeof (struct pubsub_event_item_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "id");
  if (avalue != NULL)
    {
      elm->fId = (char *) avalue;
    }
  avalue = xmlreader_attribute (reader, NULL, "node");
  if (avalue != NULL)
    {
      elm->fNode = (char *) avalue;
    }
  avalue = xmlreader_attribute (reader, NULL, "publisher");
  if (avalue != NULL)
    {
      elm->fPublisher = (char *) avalue;
    }
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if (strcmp (namespace, ns_pubsub_event) != 0)
	    {
	      extension_t *newel = malloc (sizeof (extension_t));
	      int err = xstream_extension_decode (reader, newel);
	      if (reader->err != 0)
		return NULL;
	      if (err == ERR_EXTENSION_NOT_FOUND)
		{
		  if (xmlreader_skip_element (reader) == -1)
		    return NULL;
		}
	      else
		{
		  elm->fEvent = newel;
		}
	    }
	}
    }
  return elm;
}

int
pubsub_event_item_encode (xmlwriter_t * writer,
			  struct pubsub_event_item_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_pubsub_event, "item");
  if (err != 0)
    return err;
  if (elm->fId != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "id", elm->fId);
      if (err != 0)
	return err;
    }
  if (elm->fNode != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "node", elm->fNode);
      if (err != 0)
	return err;
    }
  if (elm->fPublisher != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "publisher", elm->fPublisher);
      if (err != 0)
	return err;
    }
  if (elm->fEvent != NULL)
    {
      err =
	xstream_extension_encode (writer, elm->fEvent->data,
				  elm->fEvent->type);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
pubsub_event_item_free (struct pubsub_event_item_t *data)
{
  if (data == NULL)
    return;
  if (data->fId != NULL)
    {
      free (data->fId);
    }
  if (data->fNode != NULL)
    {
      free (data->fNode);
    }
  if (data->fPublisher != NULL)
    {
      free (data->fPublisher);
    }
  if (data->fEvent != NULL)
    {
      xstream_extension_free (data->fEvent);
      free (data->fEvent);
    }
  free (data);
}

struct pubsub_event_purge_t *
pubsub_event_purge_decode (xmlreader_t * reader)
{
  struct pubsub_event_purge_t *elm = NULL;
  elm = malloc (sizeof (struct pubsub_event_purge_t));
  if (elm == NULL)
    fatal ("pubsub_event_purge_t: malloc failed");
  memset (elm, 0, sizeof (struct pubsub_event_purge_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "node");
  if (avalue != NULL)
    {
      elm->fNode = (char *) avalue;
    }
  if (xmlreader_skip_element (reader) == -1)
    return NULL;
  return elm;
}

int
pubsub_event_purge_encode (xmlwriter_t * writer,
			   struct pubsub_event_purge_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_pubsub_event, "purge");
  if (err != 0)
    return err;
  if (elm->fNode != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "node", elm->fNode);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
pubsub_event_purge_free (struct pubsub_event_purge_t *data)
{
  if (data == NULL)
    return;
  if (data->fNode != NULL)
    {
      free (data->fNode);
    }
  free (data);
}

struct pubsub_event_retract_t *
pubsub_event_retract_decode (xmlreader_t * reader)
{
  struct pubsub_event_retract_t *elm = NULL;
  elm = malloc (sizeof (struct pubsub_event_retract_t));
  if (elm == NULL)
    fatal ("pubsub_event_retract_t: malloc failed");
  memset (elm, 0, sizeof (struct pubsub_event_retract_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "id");
  if (avalue != NULL)
    {
      elm->fId = (char *) avalue;
    }
  if (xmlreader_skip_element (reader) == -1)
    return NULL;
  return elm;
}

int
pubsub_event_retract_encode (xmlwriter_t * writer,
			     struct pubsub_event_retract_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_pubsub_event, "retract");
  if (err != 0)
    return err;
  if (elm->fId != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "id", elm->fId);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
pubsub_event_retract_free (struct pubsub_event_retract_t *data)
{
  if (data == NULL)
    return;
  if (data->fId != NULL)
    {
      free (data->fId);
    }
  free (data);
}

struct pubsub_event_subscription_t *
pubsub_event_subscription_decode (xmlreader_t * reader)
{
  struct pubsub_event_subscription_t *elm = NULL;
  elm = malloc (sizeof (struct pubsub_event_subscription_t));
  if (elm == NULL)
    fatal ("pubsub_event_subscription_t: malloc failed");
  memset (elm, 0, sizeof (struct pubsub_event_subscription_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "expiry");
  if (avalue != NULL)
    {
      elm->fExpiry = datetime_parse (avalue);
    }
  avalue = xmlreader_attribute (reader, NULL, "jid");
  if (avalue != NULL)
    {
      jid_t *jid = jid_of_string (avalue);
      elm->fJid = jid;
    }
  avalue = xmlreader_attribute (reader, NULL, "node");
  if (avalue != NULL)
    {
      elm->fNode = (char *) avalue;
    }
  avalue = xmlreader_attribute (reader, NULL, "subid");
  if (avalue != NULL)
    {
      elm->fSubid = (char *) avalue;
    }
  avalue = xmlreader_attribute (reader, NULL, "subscription");
  if (avalue != NULL)
    {
      elm->fSubscription =
	enum_pubsub_event_subscription_subscription_from_string (avalue);
    }
  if (xmlreader_skip_element (reader) == -1)
    return NULL;
  return elm;
}

int
pubsub_event_subscription_encode (xmlwriter_t * writer,
				  struct pubsub_event_subscription_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_pubsub_event, "subscription");
  if (err != 0)
    return err;
  if (elm->fExpiry != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "expiry",
			     datetime_to_string (elm->fExpiry));
      if (err != 0)
	return err;
    }
  if (elm->fJid != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "jid", jid_to_string (elm->fJid));
      if (err != 0)
	return err;
    }
  if (elm->fNode != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "node", elm->fNode);
      if (err != 0)
	return err;
    }
  if (elm->fSubid != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "subid", elm->fSubid);
      if (err != 0)
	return err;
    }
  if (elm->fSubscription != 0)
    {
      err =
	xmlwriter_attribute (writer, NULL, "subscription",
			     enum_pubsub_event_subscription_subscription_to_string
			     (elm->fSubscription));
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
pubsub_event_subscription_free (struct pubsub_event_subscription_t *data)
{
  if (data == NULL)
    return;
  if (data->fExpiry != NULL)
    {
      free (data->fExpiry);
    }
  if (data->fJid != NULL)
    {
      jid_free (data->fJid);
    }
  if (data->fNode != NULL)
    {
      free (data->fNode);
    }
  if (data->fSubid != NULL)
    {
      free (data->fSubid);
    }
  free (data);
}

enum pubsub_event_collection_type_type_t
enum_pubsub_event_collection_type_type_from_string (const char *value)
{
  if (strcmp (value, "associate") == 0)
    return PUBSUB_EVENT_COLLECTION_TYPE_TYPE_ASSOCIATE;
  else if (strcmp (value, "disassociate") == 0)
    return PUBSUB_EVENT_COLLECTION_TYPE_TYPE_DISASSOCIATE;
  return 0;
}

const char *
enum_pubsub_event_collection_type_type_to_string (enum
						  pubsub_event_collection_type_type_t
						  value)
{
  switch (value)
    {
    case PUBSUB_EVENT_COLLECTION_TYPE_TYPE_ASSOCIATE:
      return "associate";
    case PUBSUB_EVENT_COLLECTION_TYPE_TYPE_DISASSOCIATE:
      return "disassociate";
    }
  return NULL;
}

enum pubsub_event_subscription_subscription_t
enum_pubsub_event_subscription_subscription_from_string (const char *value)
{
  if (strcmp (value, "none") == 0)
    return PUBSUB_EVENT_SUBSCRIPTION_SUBSCRIPTION_NONE;
  else if (strcmp (value, "pending") == 0)
    return PUBSUB_EVENT_SUBSCRIPTION_SUBSCRIPTION_PENDING;
  else if (strcmp (value, "subscribed") == 0)
    return PUBSUB_EVENT_SUBSCRIPTION_SUBSCRIPTION_SUBSCRIBED;
  else if (strcmp (value, "unconfigured") == 0)
    return PUBSUB_EVENT_SUBSCRIPTION_SUBSCRIPTION_UNCONFIGURED;
  return 0;
}

const char *
enum_pubsub_event_subscription_subscription_to_string (enum
						       pubsub_event_subscription_subscription_t
						       value)
{
  switch (value)
    {
    case PUBSUB_EVENT_SUBSCRIPTION_SUBSCRIPTION_NONE:
      return "none";
    case PUBSUB_EVENT_SUBSCRIPTION_SUBSCRIPTION_PENDING:
      return "pending";
    case PUBSUB_EVENT_SUBSCRIPTION_SUBSCRIPTION_SUBSCRIBED:
      return "subscribed";
    case PUBSUB_EVENT_SUBSCRIPTION_SUBSCRIPTION_UNCONFIGURED:
      return "unconfigured";
    }
  return NULL;
}
<file_sep>#ifndef _XEP_DISCO_DATA_H_
#define  _XEP_DISCO_DATA_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <string.h>
#include "xstream.h"
#include "types.h"

struct disco_info_identity_t;
struct disco_info_feature_t;

extern const char *ns_disco_info;
extern const char *ns_disco_items;


struct disco_info_info_t
{
  char *fNode;
  array_t *fIdentities;
  array_t *fFeatures;
};


struct disco_info_identity_t
{
  char *fCategory;
  char *fType;
};


struct disco_info_feature_t
{
  char *fVar;
};


struct disco_info_info_t *disco_info_info_decode (xmlreader_t * reader);
int disco_info_info_encode (xmlwriter_t * writer,
			    struct disco_info_info_t *data);
void disco_info_info_free (struct disco_info_info_t *data);
struct disco_info_identity_t *disco_info_identity_decode (xmlreader_t *
							  reader);
int disco_info_identity_encode (xmlwriter_t * writer,
				struct disco_info_identity_t *data);
void disco_info_identity_free (struct disco_info_identity_t *data);
struct disco_info_feature_t *disco_info_feature_decode (xmlreader_t * reader);
int disco_info_feature_encode (xmlwriter_t * writer,
			       struct disco_info_feature_t *data);
void disco_info_feature_free (struct disco_info_feature_t *data);

#endif
<file_sep>/*
   RFC3339
   date-fullyear   = 4DIGIT
   date-month      = 2DIGIT  ; 01-12
   date-mday       = 2DIGIT  ; 01-28, 01-29, 01-30, 01-31 based on
                             ; month/year
   time-hour       = 2DIGIT  ; 00-23
   time-minute     = 2DIGIT  ; 00-59
   time-second     = 2DIGIT  ; 00-58, 00-59, 00-60 based on leap second
                             ; rules
   time-secfrac    = "." 1*DIGIT
   time-numoffset  = ("+" / "-") time-hour ":" time-minute
   time-offset     = "Z" / time-numoffset

   partial-time    = time-hour ":" time-minute ":" time-second
                     [time-secfrac]
   full-date       = date-fullyear "-" date-month "-" date-mday
   full-time       = partial-time time-offset

   date-time       = full-date "T" full-time
*/
/*
  Format
  %Y-%m-%dT%TZ
  %Y-%m-%dT%T+%H:%M
  %Y-%m-%dT%T-%H:%M
*/

#include <stdio.h>
#define _XOPEN_SOURCE
#define __USE_XOPEN
#include <time.h>
#include <string.h>
#include "types.h"

struct tm* datetime_parse(const char* value) {
  struct tm *result = NULL;
  char **f;
  char *ret;
  char *formats[] = {
    "%Y-%m-%dT%TZ",
    "%Y-%m-%dT%T+%H:%M",
    "%Y-%m-%dT%T-%H:%M",
    NULL
  };
  
  result = malloc (sizeof (struct tm));
  memset (&result, 0, sizeof(result));
  
  for (f = formats; f && *f; f++) {
    ret = strptime ((char*) value, *f, result);
    if (ret && *ret == '\0')
      return result;
  }
  free (result);
  
  return NULL;
}

const char* datetime_to_string(struct tm* data) {
  return NULL;
}
<file_sep>#include "bind_data.h"
#include "helpers.h"
#include "errors.h"

const char *ns_bind = "urn:ietf:params:xml:ns:xmpp-bind";

struct bind_bind_t *
bind_bind_decode (xmlreader_t * reader)
{
  struct bind_bind_t *elm = NULL;
  elm = malloc (sizeof (struct bind_bind_t));
  if (elm == NULL)
    fatal ("bind_bind_t: malloc failed");
  memset (elm, 0, sizeof (struct bind_bind_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "resource") == 0)
	      && (strcmp (namespace, ns_bind) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fResource = (char *) value;
	    }
	  else if ((strcmp (name, "jid") == 0)
		   && (strcmp (namespace, ns_bind) == 0))
	    {
	      const char *s = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      jid_t *jid = jid_of_string ((const char *) s);
	      elm->fJid = jid;
	    }
	}
    }
  return elm;
}

int
bind_bind_encode (xmlwriter_t * writer, struct bind_bind_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_bind, "bind");
  if (err != 0)
    return err;
  if (elm->fResource != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_bind, "resource",
				  elm->fResource);
      if (err != 0)
	return err;
    }
  if (elm->fJid != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_bind, "jid",
				  jid_to_string (elm->fJid));
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
bind_bind_free (struct bind_bind_t *data)
{
  if (data == NULL)
    return;
  if (data->fResource != NULL)
    {
      free (data->fResource);
    }
  if (data->fJid != NULL)
    {
      jid_free (data->fJid);
    }
  free (data);
}
<file_sep>#ifndef _HELPERS_H_
#define _HELPERS_H_

void fatal (char* msg, ...);

#endif
<file_sep>#ifndef _XEP_PUBSUB_DATA_H_
#define  _XEP_PUBSUB_DATA_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <string.h>
#include "xstream.h"
#include "types.h"
#include "xep_xdata_data.h"
#include "jid/jid.h"

struct pubsub_event_collection_t;
struct pubsub_event_configuration_t;
struct pubsub_event_delete_t;
struct pubsub_event_items_t;
struct pubsub_event_purge_t;
struct pubsub_event_subscription_t;
struct pubsub_event_item_t;
struct pubsub_event_retract_t;

extern const char *ns_pubsub_event;

enum pubsub_event_collection_type_type_t
{
  PUBSUB_EVENT_COLLECTION_TYPE_TYPE_ASSOCIATE,
  PUBSUB_EVENT_COLLECTION_TYPE_TYPE_DISASSOCIATE,
};

enum pubsub_event_collection_type_type_t
enum_pubsub_event_collection_type_type_from_string (const char *value);
const char *enum_pubsub_event_collection_type_type_to_string (enum
							      pubsub_event_collection_type_type_t);
enum pubsub_event_subscription_subscription_t
{
  PUBSUB_EVENT_SUBSCRIPTION_SUBSCRIPTION_NONE,
  PUBSUB_EVENT_SUBSCRIPTION_SUBSCRIPTION_PENDING,
  PUBSUB_EVENT_SUBSCRIPTION_SUBSCRIPTION_SUBSCRIBED,
  PUBSUB_EVENT_SUBSCRIPTION_SUBSCRIPTION_UNCONFIGURED,
};

enum pubsub_event_subscription_subscription_t
enum_pubsub_event_subscription_subscription_from_string (const char *value);
const char *enum_pubsub_event_subscription_subscription_to_string (enum
								   pubsub_event_subscription_subscription_t);

struct pubsub_event_event_t
{
  int type;
  union
  {
    struct pubsub_event_collection_t *fCollection;
    struct pubsub_event_configuration_t *fConfiguration;
    struct pubsub_event_delete_t *fDelete;
    struct pubsub_event_items_t *fItems;
    struct pubsub_event_purge_t *fPurge;
    struct pubsub_event_subscription_t *fSubscription;
  } *u;
};

struct pubsub_event_collection_t
{
  char *fNode;
  struct pubsub_event_type_set_t
  {
    char *fNode;
    enum pubsub_event_collection_type_type_t fType;
  } fType;
};


struct pubsub_event_configuration_t
{
  char *fNode;
  struct xdata_x_t *fXdata;
};


struct pubsub_event_delete_t
{
  char *fNode;
  struct pubsub_event_redirect_set_t
  {
    char *fUrl;
  } fRedirect;
};


struct pubsub_event_items_t
{
  char *fNode;
  array_t *fItems;
  array_t *fRetracts;
};


struct pubsub_event_item_t
{
  char *fId;
  char *fNode;
  char *fPublisher;
  extension_t *fEvent;
};


struct pubsub_event_purge_t
{
  char *fNode;
};


struct pubsub_event_retract_t
{
  char *fId;
};


struct pubsub_event_subscription_t
{
  struct tm *fExpiry;
  jid_t *fJid;
  char *fNode;
  char *fSubid;
  enum pubsub_event_subscription_subscription_t fSubscription;
};


struct pubsub_event_event_t *pubsub_event_event_decode (xmlreader_t * reader);
int pubsub_event_event_encode (xmlwriter_t * writer,
			       struct pubsub_event_event_t *data);
void pubsub_event_event_free (struct pubsub_event_event_t *data);
struct pubsub_event_collection_t *pubsub_event_collection_decode (xmlreader_t
								  * reader);
int pubsub_event_collection_encode (xmlwriter_t * writer,
				    struct pubsub_event_collection_t *data);
void pubsub_event_collection_free (struct pubsub_event_collection_t *data);
struct pubsub_event_configuration_t
  *pubsub_event_configuration_decode (xmlreader_t * reader);
int pubsub_event_configuration_encode (xmlwriter_t * writer,
				       struct pubsub_event_configuration_t
				       *data);
void pubsub_event_configuration_free (struct pubsub_event_configuration_t
				      *data);
struct pubsub_event_delete_t *pubsub_event_delete_decode (xmlreader_t *
							  reader);
int pubsub_event_delete_encode (xmlwriter_t * writer,
				struct pubsub_event_delete_t *data);
void pubsub_event_delete_free (struct pubsub_event_delete_t *data);
struct pubsub_event_items_t *pubsub_event_items_decode (xmlreader_t * reader);
int pubsub_event_items_encode (xmlwriter_t * writer,
			       struct pubsub_event_items_t *data);
void pubsub_event_items_free (struct pubsub_event_items_t *data);
struct pubsub_event_item_t *pubsub_event_item_decode (xmlreader_t * reader);
int pubsub_event_item_encode (xmlwriter_t * writer,
			      struct pubsub_event_item_t *data);
void pubsub_event_item_free (struct pubsub_event_item_t *data);
struct pubsub_event_purge_t *pubsub_event_purge_decode (xmlreader_t * reader);
int pubsub_event_purge_encode (xmlwriter_t * writer,
			       struct pubsub_event_purge_t *data);
void pubsub_event_purge_free (struct pubsub_event_purge_t *data);
struct pubsub_event_retract_t *pubsub_event_retract_decode (xmlreader_t *
							    reader);
int pubsub_event_retract_encode (xmlwriter_t * writer,
				 struct pubsub_event_retract_t *data);
void pubsub_event_retract_free (struct pubsub_event_retract_t *data);
struct pubsub_event_subscription_t
  *pubsub_event_subscription_decode (xmlreader_t * reader);
int pubsub_event_subscription_encode (xmlwriter_t * writer,
				      struct pubsub_event_subscription_t
				      *data);
void pubsub_event_subscription_free (struct pubsub_event_subscription_t
				     *data);
#endif
<file_sep>#include "xep_stats_data.h"
#include "helpers.h"
#include "errors.h"

const char *ns_stats = "http://jabber.org/protocol/stats";

array_t *
stats_stats_decode (xmlreader_t * reader)
{
  array_t *elm = array_new (sizeof (extension_t), 0);
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *name = xmlreader_get_name (reader);
	  const char *namespace = xmlreader_get_namespace (reader);
	  if ((strcmp (namespace, ns_stats) == 0)
	      && (strcmp (name, "stat") == 0))
	    {
	      struct stats_stat_t *newel = stats_stat_decode (reader);
	      if (newel == NULL)
		{
		  return NULL;
		}
	      array_append (elm, newel);
	    }
	}
    }
  return elm;
}

int
stats_stats_encode (xmlwriter_t * writer, array_t * elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_stats, "query");
  if (err != 0)
    return err;
  int len = array_length (elm);
  int i = 0;
  for (i = 0; i < len; i++)
    {
      struct stats_stat_t *data = array_get (elm, i);
      err = stats_stat_encode (writer, data);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
stats_stats_free (array_t * data)
{
  if (data == NULL)
    return;
  int len = array_length (data);
  int i = 0;
  for (i = 0; i < len; i++)
    {
      struct stats_stat_t **item = array_get (data, i);
      stats_stat_free (item);
    }
  array_free (data);
}

struct stats_stat_t *
stats_stat_decode (xmlreader_t * reader)
{
  struct stats_stat_t *elm = NULL;
  elm = malloc (sizeof (struct stats_stat_t));
  if (elm == NULL)
    fatal ("stats_stat_t: malloc failed");
  memset (elm, 0, sizeof (struct stats_stat_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "name");
  if (avalue != NULL)
    {
      elm->fName = (char *) avalue;
    }
  avalue = xmlreader_attribute (reader, NULL, "units");
  if (avalue != NULL)
    {
      elm->fUnits = (char *) avalue;
    }
  avalue = xmlreader_attribute (reader, NULL, "value");
  if (avalue != NULL)
    {
      elm->fValue = (char *) avalue;
    }
  if (xmlreader_skip_element (reader) == -1)
    return NULL;
  return elm;
}

int
stats_stat_encode (xmlwriter_t * writer, struct stats_stat_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_stats, "stat");
  if (err != 0)
    return err;
  if (elm->fName != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "name", elm->fName);
      if (err != 0)
	return err;
    }
  if (elm->fUnits != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "units", elm->fUnits);
      if (err != 0)
	return err;
    }
  if (elm->fValue != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "value", elm->fValue);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
stats_stat_free (struct stats_stat_t *data)
{
  if (data == NULL)
    return;
  if (data->fName != NULL)
    {
      free (data->fName);
    }
  if (data->fUnits != NULL)
    {
      free (data->fUnits);
    }
  if (data->fValue != NULL)
    {
      free (data->fValue);
    }
  free (data);
}
<file_sep>#ifndef _HEX_H_
#define _HEX_H_

#include <stdint.h>

void hex_of_binary (char* out, unsigned char* in, int in_len);

void hex_of_int (char* out, uint64_t in);
uint64_t hex_to_int (const char* str);

#endif
<file_sep>#ifndef _XEP_MUC_DATA_H_
#define  _XEP_MUC_DATA_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <string.h>
#include "xstream.h"
#include "types.h"
#include "jid/jid.h"
#include "xep_xdata_data.h"

struct muc_user_decline_t;
struct muc_user_destroy_t;
struct muc_user_invite_t;
struct muc_user_item_t;
struct muc_admin_item_t;
struct muc_user_status_t;

extern const char *ns_muc;
extern const char *ns_muc_user;
extern const char *ns_muc_owner;
extern const char *ns_muc_admin;


struct muc_enter_t
{
  struct muc_history_set_t
  {
    int *fMaxchars;
    int *fMaxstanzas;
    int *fSeconds;
    struct tm *fSince;
  } fHistory;
  char *fPassword;
};


struct muc_enter_t *muc_enter_decode (xmlreader_t * reader);
int muc_enter_encode (xmlwriter_t * writer, struct muc_enter_t *data);
void muc_enter_free (struct muc_enter_t *data);
enum muc_user_item_affiliation_t
{
  MUC_USER_ITEM_AFFILIATION_ADMIN,
  MUC_USER_ITEM_AFFILIATION_MEMBER,
  MUC_USER_ITEM_AFFILIATION_NONE,
  MUC_USER_ITEM_AFFILIATION_OUTCAST,
  MUC_USER_ITEM_AFFILIATION_OWNER,
};

enum muc_user_item_affiliation_t
enum_muc_user_item_affiliation_from_string (const char *value);
const char *enum_muc_user_item_affiliation_to_string (enum
						      muc_user_item_affiliation_t);
enum muc_user_item_role_t
{
  MUC_USER_ITEM_ROLE_MODERATOR,
  MUC_USER_ITEM_ROLE_NONE,
  MUC_USER_ITEM_ROLE_PARTICIPANT,
  MUC_USER_ITEM_ROLE_VISITOR,
};

enum muc_user_item_role_t enum_muc_user_item_role_from_string (const char
							       *value);
const char *enum_muc_user_item_role_to_string (enum muc_user_item_role_t);

struct muc_user_action_t
{
  struct muc_user_decline_t *fDecline;
  struct muc_user_destroy_t *fDestroy;
  array_t *fInvite;
  struct muc_user_item_t *fItem;
  char *fPassword;
  array_t *fStatus;
};


struct muc_user_status_t
{
  int *fCode;
};


struct muc_user_decline_t
{
  jid_t *fFrom;
  jid_t *fTo;
  char *fReason;
};


struct muc_user_destroy_t
{
  jid_t *fJid;
  char *fReason;
};


struct muc_user_invite_t
{
  jid_t *fFrom;
  jid_t *fTo;
  char *fReason;
};


struct muc_user_item_t
{
  enum muc_user_item_affiliation_t fAffiliation;
  jid_t *fJid;
  char *fNick;
  enum muc_user_item_role_t fRole;
  struct muc_user_actor_set_t
  {
    jid_t *fJid;
  } fActor;
  char *fReason;
  bool fContinue;
};


struct muc_user_action_t *muc_user_action_decode (xmlreader_t * reader);
int muc_user_action_encode (xmlwriter_t * writer,
			    struct muc_user_action_t *data);
void muc_user_action_free (struct muc_user_action_t *data);
struct muc_user_status_t *muc_user_status_decode (xmlreader_t * reader);
int muc_user_status_encode (xmlwriter_t * writer,
			    struct muc_user_status_t *data);
void muc_user_status_free (struct muc_user_status_t *data);
struct muc_user_decline_t *muc_user_decline_decode (xmlreader_t * reader);
int muc_user_decline_encode (xmlwriter_t * writer,
			     struct muc_user_decline_t *data);
void muc_user_decline_free (struct muc_user_decline_t *data);
struct muc_user_destroy_t *muc_user_destroy_decode (xmlreader_t * reader);
int muc_user_destroy_encode (xmlwriter_t * writer,
			     struct muc_user_destroy_t *data);
void muc_user_destroy_free (struct muc_user_destroy_t *data);
struct muc_user_invite_t *muc_user_invite_decode (xmlreader_t * reader);
int muc_user_invite_encode (xmlwriter_t * writer,
			    struct muc_user_invite_t *data);
void muc_user_invite_free (struct muc_user_invite_t *data);
struct muc_user_item_t *muc_user_item_decode (xmlreader_t * reader);
int muc_user_item_encode (xmlwriter_t * writer, struct muc_user_item_t *data);
void muc_user_item_free (struct muc_user_item_t *data);

typedef struct xdata_x_t *muc_owner_configure_t;


muc_owner_configure_t *muc_owner_configure_decode (xmlreader_t * reader);
int muc_owner_configure_encode (xmlwriter_t * writer,
				muc_owner_configure_t * data);
void muc_owner_configure_free (muc_owner_configure_t * data);
enum muc_admin_item_affiliation_t
{
  MUC_ADMIN_ITEM_AFFILIATION_ADMIN,
  MUC_ADMIN_ITEM_AFFILIATION_MEMBER,
  MUC_ADMIN_ITEM_AFFILIATION_NONE,
  MUC_ADMIN_ITEM_AFFILIATION_OUTCAST,
  MUC_ADMIN_ITEM_AFFILIATION_OWNER,
};

enum muc_admin_item_affiliation_t
enum_muc_admin_item_affiliation_from_string (const char *value);
const char *enum_muc_admin_item_affiliation_to_string (enum
						       muc_admin_item_affiliation_t);
enum muc_admin_item_role_t
{
  MUC_ADMIN_ITEM_ROLE_MODERATOR,
  MUC_ADMIN_ITEM_ROLE_NONE,
  MUC_ADMIN_ITEM_ROLE_PARTICIPANT,
  MUC_ADMIN_ITEM_ROLE_VISITOR,
};

enum muc_admin_item_role_t enum_muc_admin_item_role_from_string (const char
								 *value);
const char *enum_muc_admin_item_role_to_string (enum muc_admin_item_role_t);

struct muc_admin_query_t
{
  array_t *fItems;
};


struct muc_admin_item_t
{
  enum muc_admin_item_affiliation_t fAffiliation;
  jid_t *fJid;
  char *fNick;
  enum muc_admin_item_role_t fRole;
  struct muc_admin_actor_set_t
  {
    jid_t *fJid;
  } fActor;
  char *fReason;
};


struct muc_admin_query_t *muc_admin_query_decode (xmlreader_t * reader);
int muc_admin_query_encode (xmlwriter_t * writer,
			    struct muc_admin_query_t *data);
void muc_admin_query_free (struct muc_admin_query_t *data);
struct muc_admin_item_t *muc_admin_item_decode (xmlreader_t * reader);
int muc_admin_item_encode (xmlwriter_t * writer,
			   struct muc_admin_item_t *data);
void muc_admin_item_free (struct muc_admin_item_t *data);
#endif
<file_sep>#ifndef _ARRAY_H_
#define _ARRAY_H_

#include <stdlib.h>
#include <stdint.h>

typedef struct {
  uint32_t length;
  size_t size;
  uint32_t capacity;
  char* data;
} array_t;

array_t* array_new (uint32_t size, uint32_t capacity);
void array_free (array_t* array);
uint32_t array_length (array_t* array);
void* array_get (array_t* array, uint32_t idx);
void* array_get_last (array_t* array);
void array_delete_last (array_t* array);
void array_set (array_t* array, uint32_t idx, void* element);
void array_append (array_t* array, void* element);
void array_slice (array_t* array, int start, int length);

#endif
<file_sep>#include "extensions.h"
#include "xstream.h"

#include "xep_iqlast_data.h"
#include "xep_mood_data.h"
#include "xep_vcard_data.h"
#include "xep_privacy_data.h"
#include "stream_data.h"
#include "xep_xoob_data.h"
#include "xep_xdata_data.h"
#include "starttls_data.h"
#include "xep_ping_data.h"
#include "bind_data.h"
#include "sasl_data.h"
#include "xep_caps_data.h"
#include "xep_iqversion_data.h"
#include "roster_data.h"
#include "xep_captcha_data.h"
#include "xep_disco_data.h"
#include "xep_iqtime_data.h"
#include "xep_iqregister_data.h"
#include "xep_pubsub_data.h"
#include "client_data.h"
#include "stanza_data.h"
#include "xep_muc_data.h"
#include "xep_stats_data.h"
#include "xep_time_data.h"
#include "session_data.h"

struct xstream_extension_t extensions[] = {
  {"jabber:iq:last", "query", EXTENSION_TYPE_IQLAST_LAST,
   (void *(*)(xmlreader_t *)) iqlast_last_decode,
   (int (*)(xmlwriter_t *, void *)) iqlast_last_encode,
   (void (*)(void *)) iqlast_last_free},
  {"http://jabber.org/protocol/mood", "mood", EXTENSION_TYPE_MOOD_MOOD,
   (void *(*)(xmlreader_t *)) mood_mood_decode,
   (int (*)(xmlwriter_t *, void *)) mood_mood_encode,
   (void (*)(void *)) mood_mood_free},
  {"vcard-temp", "vCard", EXTENSION_TYPE_VCARD_VCARD,
   (void *(*)(xmlreader_t *)) vcard_vcard_decode,
   (int (*)(xmlwriter_t *, void *)) vcard_vcard_encode,
   (void (*)(void *)) vcard_vcard_free},
  {"vcard-temp", "N", EXTENSION_TYPE_VCARD_N,
   (void *(*)(xmlreader_t *)) vcard_N_decode,
   (int (*)(xmlwriter_t *, void *)) vcard_N_encode,
   (void (*)(void *)) vcard_N_free},
  {"vcard-temp", "PHOTO", EXTENSION_TYPE_VCARD_PHOTO,
   (void *(*)(xmlreader_t *)) vcard_PHOTO_decode,
   (int (*)(xmlwriter_t *, void *)) vcard_PHOTO_encode,
   (void (*)(void *)) vcard_PHOTO_free},
  {"vcard-temp", "ADR", EXTENSION_TYPE_VCARD_ADR,
   (void *(*)(xmlreader_t *)) vcard_ADR_decode,
   (int (*)(xmlwriter_t *, void *)) vcard_ADR_encode,
   (void (*)(void *)) vcard_ADR_free},
  {"vcard-temp", "LABEL", EXTENSION_TYPE_VCARD_LABEL,
   (void *(*)(xmlreader_t *)) vcard_LABEL_decode,
   (int (*)(xmlwriter_t *, void *)) vcard_LABEL_encode,
   (void (*)(void *)) vcard_LABEL_free},
  {"vcard-temp", "TEL", EXTENSION_TYPE_VCARD_TEL,
   (void *(*)(xmlreader_t *)) vcard_TEL_decode,
   (int (*)(xmlwriter_t *, void *)) vcard_TEL_encode,
   (void (*)(void *)) vcard_TEL_free},
  {"vcard-temp", "EMAIL", EXTENSION_TYPE_VCARD_EMAIL,
   (void *(*)(xmlreader_t *)) vcard_EMAIL_decode,
   (int (*)(xmlwriter_t *, void *)) vcard_EMAIL_encode,
   (void (*)(void *)) vcard_EMAIL_free},
  {"vcard-temp", "GEO", EXTENSION_TYPE_VCARD_GEO,
   (void *(*)(xmlreader_t *)) vcard_GEO_decode,
   (int (*)(xmlwriter_t *, void *)) vcard_GEO_encode,
   (void (*)(void *)) vcard_GEO_free},
  {"vcard-temp", "LOGO", EXTENSION_TYPE_VCARD_LOGO,
   (void *(*)(xmlreader_t *)) vcard_LOGO_decode,
   (int (*)(xmlwriter_t *, void *)) vcard_LOGO_encode,
   (void (*)(void *)) vcard_LOGO_free},
  {"vcard-temp", "AGENT", EXTENSION_TYPE_VCARD_AGENT,
   (void *(*)(xmlreader_t *)) vcard_AGENT_decode,
   (int (*)(xmlwriter_t *, void *)) vcard_AGENT_encode,
   (void (*)(void *)) vcard_AGENT_free},
  {"vcard-temp", "ORG", EXTENSION_TYPE_VCARD_ORG,
   (void *(*)(xmlreader_t *)) vcard_ORG_decode,
   (int (*)(xmlwriter_t *, void *)) vcard_ORG_encode,
   (void (*)(void *)) vcard_ORG_free},
  {"vcard-temp", "CATEGORIES", EXTENSION_TYPE_VCARD_CATEGORIES,
   (void *(*)(xmlreader_t *)) vcard_CATEGORIES_decode,
   (int (*)(xmlwriter_t *, void *)) vcard_CATEGORIES_encode,
   (void (*)(void *)) vcard_CATEGORIES_free},
  {"vcard-temp", "SOUND", EXTENSION_TYPE_VCARD_SOUND,
   (void *(*)(xmlreader_t *)) vcard_SOUND_decode,
   (int (*)(xmlwriter_t *, void *)) vcard_SOUND_encode,
   (void (*)(void *)) vcard_SOUND_free},
  {"vcard-temp", "CLASS", EXTENSION_TYPE_VCARD_CLASS,
   (void *(*)(xmlreader_t *)) vcard_CLASS_decode,
   (int (*)(xmlwriter_t *, void *)) vcard_CLASS_encode,
   (void (*)(void *)) vcard_CLASS_free},
  {"vcard-temp", "KEY", EXTENSION_TYPE_VCARD_KEY,
   (void *(*)(xmlreader_t *)) vcard_KEY_decode,
   (int (*)(xmlwriter_t *, void *)) vcard_KEY_encode,
   (void (*)(void *)) vcard_KEY_free},
  {"jabber:iq:privacy", "query", EXTENSION_TYPE_PRIVACY_PRIVACY,
   (void *(*)(xmlreader_t *)) privacy_privacy_decode,
   (int (*)(xmlwriter_t *, void *)) privacy_privacy_encode,
   (void (*)(void *)) privacy_privacy_free},
  {"jabber:iq:privacy", "active", EXTENSION_TYPE_PRIVACY_ACTIVE,
   (void *(*)(xmlreader_t *)) privacy_active_decode,
   (int (*)(xmlwriter_t *, void *)) privacy_active_encode,
   (void (*)(void *)) privacy_active_free},
  {"jabber:iq:privacy", "default", EXTENSION_TYPE_PRIVACY_DEFAULT,
   (void *(*)(xmlreader_t *)) privacy_default_decode,
   (int (*)(xmlwriter_t *, void *)) privacy_default_encode,
   (void (*)(void *)) privacy_default_free},
  {"jabber:iq:privacy", "list", EXTENSION_TYPE_PRIVACY_LIST,
   (void *(*)(xmlreader_t *)) privacy_list_decode,
   (int (*)(xmlwriter_t *, void *)) privacy_list_encode,
   (void (*)(void *)) privacy_list_free},
  {"jabber:iq:privacy", "item", EXTENSION_TYPE_PRIVACY_ITEM,
   (void *(*)(xmlreader_t *)) privacy_item_decode,
   (int (*)(xmlwriter_t *, void *)) privacy_item_encode,
   (void (*)(void *)) privacy_item_free},
  {"http://etherx.jabber.org/streams", "stream", EXTENSION_TYPE_STREAM_START,
   (void *(*)(xmlreader_t *)) stream_start_decode,
   (int (*)(xmlwriter_t *, void *)) stream_start_encode,
   (void (*)(void *)) stream_start_free},
  {"http://etherx.jabber.org/streams", "features",
   EXTENSION_TYPE_STREAM_FEATURES,
   (void *(*)(xmlreader_t *)) stream_features_decode,
   (int (*)(xmlwriter_t *, void *)) stream_features_encode,
   (void (*)(void *)) stream_features_free},
  {"http://etherx.jabber.org/streams", "error", EXTENSION_TYPE_STREAM_ERROR,
   (void *(*)(xmlreader_t *)) stream_error_decode,
   (int (*)(xmlwriter_t *, void *)) stream_error_encode,
   (void (*)(void *)) stream_error_free},
  {"jabber:x:oob", "x", EXTENSION_TYPE_XOOB_X,
   (void *(*)(xmlreader_t *)) xoob_x_decode,
   (int (*)(xmlwriter_t *, void *)) xoob_x_encode,
   (void (*)(void *)) xoob_x_free},
  {"jabber:x:data", "x", EXTENSION_TYPE_XDATA_X,
   (void *(*)(xmlreader_t *)) xdata_x_decode,
   (int (*)(xmlwriter_t *, void *)) xdata_x_encode,
   (void (*)(void *)) xdata_x_free},
  {"jabber:x:data", "field", EXTENSION_TYPE_XDATA_FIELD,
   (void *(*)(xmlreader_t *)) xdata_field_decode,
   (int (*)(xmlwriter_t *, void *)) xdata_field_encode,
   (void (*)(void *)) xdata_field_free},
  {"jabber:x:data", "option", EXTENSION_TYPE_XDATA_OPTION,
   (void *(*)(xmlreader_t *)) xdata_option_decode,
   (int (*)(xmlwriter_t *, void *)) xdata_option_encode,
   (void (*)(void *)) xdata_option_free},
  {"urn:ietf:params:xml:ns:xmpp-tls", "starttls",
   EXTENSION_TYPE_STARTTLS_STARTTLS,
   (void *(*)(xmlreader_t *)) starttls_starttls_decode,
   (int (*)(xmlwriter_t *, void *)) starttls_starttls_encode,
   (void (*)(void *)) starttls_starttls_free},
  {"urn:ietf:params:xml:ns:xmpp-tls", "proceed",
   EXTENSION_TYPE_STARTTLS_PROCEED,
   (void *(*)(xmlreader_t *)) starttls_proceed_decode,
   (int (*)(xmlwriter_t *, void *)) starttls_proceed_encode,
   (void (*)(void *)) starttls_proceed_free},
  {"urn:ietf:params:xml:ns:xmpp-tls", "failure",
   EXTENSION_TYPE_STARTTLS_FAILURE,
   (void *(*)(xmlreader_t *)) starttls_failure_decode,
   (int (*)(xmlwriter_t *, void *)) starttls_failure_encode,
   (void (*)(void *)) starttls_failure_free},
  {"urn:xmpp:ping", "ping", EXTENSION_TYPE_PING_PING,
   (void *(*)(xmlreader_t *)) ping_ping_decode,
   (int (*)(xmlwriter_t *, void *)) ping_ping_encode,
   (void (*)(void *)) ping_ping_free},
  {"urn:ietf:params:xml:ns:xmpp-bind", "bind", EXTENSION_TYPE_BIND_BIND,
   (void *(*)(xmlreader_t *)) bind_bind_decode,
   (int (*)(xmlwriter_t *, void *)) bind_bind_encode,
   (void (*)(void *)) bind_bind_free},
  {"urn:ietf:params:xml:ns:xmpp-sasl", "mechanisms",
   EXTENSION_TYPE_SASL_MECHANISMS,
   (void *(*)(xmlreader_t *)) sasl_mechanisms_decode,
   (int (*)(xmlwriter_t *, void *)) sasl_mechanisms_encode,
   (void (*)(void *)) sasl_mechanisms_free},
  {"urn:ietf:params:xml:ns:xmpp-sasl", "auth", EXTENSION_TYPE_SASL_AUTH,
   (void *(*)(xmlreader_t *)) sasl_auth_decode,
   (int (*)(xmlwriter_t *, void *)) sasl_auth_encode,
   (void (*)(void *)) sasl_auth_free},
  {"urn:ietf:params:xml:ns:xmpp-sasl", "success", EXTENSION_TYPE_SASL_SUCCESS,
   (void *(*)(xmlreader_t *)) sasl_success_decode,
   (int (*)(xmlwriter_t *, void *)) sasl_success_encode,
   (void (*)(void *)) sasl_success_free},
  {"urn:ietf:params:xml:ns:xmpp-sasl", "challenge",
   EXTENSION_TYPE_SASL_CHALLENGE,
   (void *(*)(xmlreader_t *)) sasl_challenge_decode,
   (int (*)(xmlwriter_t *, void *)) sasl_challenge_encode,
   (void (*)(void *)) sasl_challenge_free},
  {"urn:ietf:params:xml:ns:xmpp-sasl", "response",
   EXTENSION_TYPE_SASL_RESPONSE,
   (void *(*)(xmlreader_t *)) sasl_response_decode,
   (int (*)(xmlwriter_t *, void *)) sasl_response_encode,
   (void (*)(void *)) sasl_response_free},
  {"urn:ietf:params:xml:ns:xmpp-sasl", "failure", EXTENSION_TYPE_SASL_FAILURE,
   (void *(*)(xmlreader_t *)) sasl_failure_decode,
   (int (*)(xmlwriter_t *, void *)) sasl_failure_encode,
   (void (*)(void *)) sasl_failure_free},
  {"http://jabber.org/protocol/caps", "c", EXTENSION_TYPE_CAPS_CAPS,
   (void *(*)(xmlreader_t *)) caps_caps_decode,
   (int (*)(xmlwriter_t *, void *)) caps_caps_encode,
   (void (*)(void *)) caps_caps_free},
  {"jabber:iq:version", "query", EXTENSION_TYPE_IQVERSION_VERSION,
   (void *(*)(xmlreader_t *)) iqversion_version_decode,
   (int (*)(xmlwriter_t *, void *)) iqversion_version_encode,
   (void (*)(void *)) iqversion_version_free},
  {"jabber:iq:roster", "query", EXTENSION_TYPE_ROSTER_ROSTER,
   (void *(*)(xmlreader_t *)) roster_roster_decode,
   (int (*)(xmlwriter_t *, void *)) roster_roster_encode,
   (void (*)(void *)) roster_roster_free},
  {"jabber:iq:roster", "item", EXTENSION_TYPE_ROSTER_ITEM,
   (void *(*)(xmlreader_t *)) roster_item_decode,
   (int (*)(xmlwriter_t *, void *)) roster_item_encode,
   (void (*)(void *)) roster_item_free},
  {"urn:xmpp:captcha", "captcha", EXTENSION_TYPE_CAPTCHA_CAPTCHA,
   (void *(*)(xmlreader_t *)) captcha_captcha_decode,
   (int (*)(xmlwriter_t *, void *)) captcha_captcha_encode,
   (void (*)(void *)) captcha_captcha_free},
  {"http://jabber.org/protocol/disco#info", "query",
   EXTENSION_TYPE_DISCO_INFO_INFO,
   (void *(*)(xmlreader_t *)) disco_info_info_decode,
   (int (*)(xmlwriter_t *, void *)) disco_info_info_encode,
   (void (*)(void *)) disco_info_info_free},
  {"http://jabber.org/protocol/disco#info", "identity",
   EXTENSION_TYPE_DISCO_INFO_IDENTITY,
   (void *(*)(xmlreader_t *)) disco_info_identity_decode,
   (int (*)(xmlwriter_t *, void *)) disco_info_identity_encode,
   (void (*)(void *)) disco_info_identity_free},
  {"http://jabber.org/protocol/disco#info", "feature",
   EXTENSION_TYPE_DISCO_INFO_FEATURE,
   (void *(*)(xmlreader_t *)) disco_info_feature_decode,
   (int (*)(xmlwriter_t *, void *)) disco_info_feature_encode,
   (void (*)(void *)) disco_info_feature_free},
  {"jabber:iq:time", "query", EXTENSION_TYPE_IQTIME_TIME,
   (void *(*)(xmlreader_t *)) iqtime_time_decode,
   (int (*)(xmlwriter_t *, void *)) iqtime_time_encode,
   (void (*)(void *)) iqtime_time_free},
  {"jabber:iq:register", "query", EXTENSION_TYPE_IQREGISTER_QUERY,
   (void *(*)(xmlreader_t *)) iqregister_query_decode,
   (int (*)(xmlwriter_t *, void *)) iqregister_query_encode,
   (void (*)(void *)) iqregister_query_free},
  {"http://jabber.org/protocol/pubsub#event", "event",
   EXTENSION_TYPE_PUBSUB_EVENT_EVENT,
   (void *(*)(xmlreader_t *)) pubsub_event_event_decode,
   (int (*)(xmlwriter_t *, void *)) pubsub_event_event_encode,
   (void (*)(void *)) pubsub_event_event_free},
  {"http://jabber.org/protocol/pubsub#event", "collection",
   EXTENSION_TYPE_PUBSUB_EVENT_COLLECTION,
   (void *(*)(xmlreader_t *)) pubsub_event_collection_decode,
   (int (*)(xmlwriter_t *, void *)) pubsub_event_collection_encode,
   (void (*)(void *)) pubsub_event_collection_free},
  {"http://jabber.org/protocol/pubsub#event", "configuration",
   EXTENSION_TYPE_PUBSUB_EVENT_CONFIGURATION,
   (void *(*)(xmlreader_t *)) pubsub_event_configuration_decode,
   (int (*)(xmlwriter_t *, void *)) pubsub_event_configuration_encode,
   (void (*)(void *)) pubsub_event_configuration_free},
  {"http://jabber.org/protocol/pubsub#event", "delete",
   EXTENSION_TYPE_PUBSUB_EVENT_DELETE,
   (void *(*)(xmlreader_t *)) pubsub_event_delete_decode,
   (int (*)(xmlwriter_t *, void *)) pubsub_event_delete_encode,
   (void (*)(void *)) pubsub_event_delete_free},
  {"http://jabber.org/protocol/pubsub#event", "items",
   EXTENSION_TYPE_PUBSUB_EVENT_ITEMS,
   (void *(*)(xmlreader_t *)) pubsub_event_items_decode,
   (int (*)(xmlwriter_t *, void *)) pubsub_event_items_encode,
   (void (*)(void *)) pubsub_event_items_free},
  {"http://jabber.org/protocol/pubsub#event", "item",
   EXTENSION_TYPE_PUBSUB_EVENT_ITEM,
   (void *(*)(xmlreader_t *)) pubsub_event_item_decode,
   (int (*)(xmlwriter_t *, void *)) pubsub_event_item_encode,
   (void (*)(void *)) pubsub_event_item_free},
  {"http://jabber.org/protocol/pubsub#event", "purge",
   EXTENSION_TYPE_PUBSUB_EVENT_PURGE,
   (void *(*)(xmlreader_t *)) pubsub_event_purge_decode,
   (int (*)(xmlwriter_t *, void *)) pubsub_event_purge_encode,
   (void (*)(void *)) pubsub_event_purge_free},
  {"http://jabber.org/protocol/pubsub#event", "retract",
   EXTENSION_TYPE_PUBSUB_EVENT_RETRACT,
   (void *(*)(xmlreader_t *)) pubsub_event_retract_decode,
   (int (*)(xmlwriter_t *, void *)) pubsub_event_retract_encode,
   (void (*)(void *)) pubsub_event_retract_free},
  {"http://jabber.org/protocol/pubsub#event", "subscription",
   EXTENSION_TYPE_PUBSUB_EVENT_SUBSCRIPTION,
   (void *(*)(xmlreader_t *)) pubsub_event_subscription_decode,
   (int (*)(xmlwriter_t *, void *)) pubsub_event_subscription_encode,
   (void (*)(void *)) pubsub_event_subscription_free},
  {"jabber:client", "iq", EXTENSION_TYPE_CLIENT_IQ,
   (void *(*)(xmlreader_t *)) client_iq_decode,
   (int (*)(xmlwriter_t *, void *)) client_iq_encode,
   (void (*)(void *)) client_iq_free},
  {"jabber:client", "presence", EXTENSION_TYPE_CLIENT_PRESENCE,
   (void *(*)(xmlreader_t *)) client_presence_decode,
   (int (*)(xmlwriter_t *, void *)) client_presence_encode,
   (void (*)(void *)) client_presence_free},
  {"jabber:client", "message", EXTENSION_TYPE_CLIENT_MESSAGE,
   (void *(*)(xmlreader_t *)) client_message_decode,
   (int (*)(xmlwriter_t *, void *)) client_message_encode,
   (void (*)(void *)) client_message_free},
  {"urn:ietf:params:xml:ns:xmpp-stanzas", "error",
   EXTENSION_TYPE_STANZA_ERROR,
   (void *(*)(xmlreader_t *)) stanza_error_decode,
   (int (*)(xmlwriter_t *, void *)) stanza_error_encode,
   (void (*)(void *)) stanza_error_free},
  {"http://jabber.org/protocol/muc", "x", EXTENSION_TYPE_MUC_ENTER,
   (void *(*)(xmlreader_t *)) muc_enter_decode,
   (int (*)(xmlwriter_t *, void *)) muc_enter_encode,
   (void (*)(void *)) muc_enter_free},
  {"http://jabber.org/protocol/muc#user", "x", EXTENSION_TYPE_MUC_USER_ACTION,
   (void *(*)(xmlreader_t *)) muc_user_action_decode,
   (int (*)(xmlwriter_t *, void *)) muc_user_action_encode,
   (void (*)(void *)) muc_user_action_free},
  {"http://jabber.org/protocol/muc#user", "status",
   EXTENSION_TYPE_MUC_USER_STATUS,
   (void *(*)(xmlreader_t *)) muc_user_status_decode,
   (int (*)(xmlwriter_t *, void *)) muc_user_status_encode,
   (void (*)(void *)) muc_user_status_free},
  {"http://jabber.org/protocol/muc#user", "decline",
   EXTENSION_TYPE_MUC_USER_DECLINE,
   (void *(*)(xmlreader_t *)) muc_user_decline_decode,
   (int (*)(xmlwriter_t *, void *)) muc_user_decline_encode,
   (void (*)(void *)) muc_user_decline_free},
  {"http://jabber.org/protocol/muc#user", "destroy",
   EXTENSION_TYPE_MUC_USER_DESTROY,
   (void *(*)(xmlreader_t *)) muc_user_destroy_decode,
   (int (*)(xmlwriter_t *, void *)) muc_user_destroy_encode,
   (void (*)(void *)) muc_user_destroy_free},
  {"http://jabber.org/protocol/muc#user", "invite",
   EXTENSION_TYPE_MUC_USER_INVITE,
   (void *(*)(xmlreader_t *)) muc_user_invite_decode,
   (int (*)(xmlwriter_t *, void *)) muc_user_invite_encode,
   (void (*)(void *)) muc_user_invite_free},
  {"http://jabber.org/protocol/muc#user", "item",
   EXTENSION_TYPE_MUC_USER_ITEM,
   (void *(*)(xmlreader_t *)) muc_user_item_decode,
   (int (*)(xmlwriter_t *, void *)) muc_user_item_encode,
   (void (*)(void *)) muc_user_item_free},
  {"http://jabber.org/protocol/muc#owner", "query",
   EXTENSION_TYPE_MUC_OWNER_CONFIGURE,
   (void *(*)(xmlreader_t *)) muc_owner_configure_decode,
   (int (*)(xmlwriter_t *, void *)) muc_owner_configure_encode,
   (void (*)(void *)) muc_owner_configure_free},
  {"http://jabber.org/protocol/muc#admin", "query",
   EXTENSION_TYPE_MUC_ADMIN_QUERY,
   (void *(*)(xmlreader_t *)) muc_admin_query_decode,
   (int (*)(xmlwriter_t *, void *)) muc_admin_query_encode,
   (void (*)(void *)) muc_admin_query_free},
  {"http://jabber.org/protocol/muc#admin", "item",
   EXTENSION_TYPE_MUC_ADMIN_ITEM,
   (void *(*)(xmlreader_t *)) muc_admin_item_decode,
   (int (*)(xmlwriter_t *, void *)) muc_admin_item_encode,
   (void (*)(void *)) muc_admin_item_free},
  {"http://jabber.org/protocol/stats", "query", EXTENSION_TYPE_STATS_STATS,
   (void *(*)(xmlreader_t *)) stats_stats_decode,
   (int (*)(xmlwriter_t *, void *)) stats_stats_encode,
   (void (*)(void *)) stats_stats_free},
  {"http://jabber.org/protocol/stats", "stat", EXTENSION_TYPE_STATS_STAT,
   (void *(*)(xmlreader_t *)) stats_stat_decode,
   (int (*)(xmlwriter_t *, void *)) stats_stat_encode,
   (void (*)(void *)) stats_stat_free},
  {"urn:xmpp:time", "time", EXTENSION_TYPE_TIME_TIME,
   (void *(*)(xmlreader_t *)) time_time_decode,
   (int (*)(xmlwriter_t *, void *)) time_time_encode,
   (void (*)(void *)) time_time_free},
  {"urn:ietf:params:xml:ns:xmpp-session", "session",
   EXTENSION_TYPE_SESSION_SESSION,
   (void *(*)(xmlreader_t *)) session_session_decode,
   (int (*)(xmlwriter_t *, void *)) session_session_encode,
   (void (*)(void *)) session_session_free},
};

int extensions_len = 77;
<file_sep>/*
 * FC 2052 A DNS RR for specifying the location of services (DNS SRV)
 */

#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <arpa/nameser.h>
#include <string.h>
#include <strings.h>
#include <arpa/inet.h>

#include "srv.h"

static void srv_list_sort(srv_list** list) {
  srv_list *head = *list;
  srv_list *t, *t1, *t2, *tt;

  if (head == NULL)
    return;
  
  t1 = head->next;
  while (t1 != NULL) {
    t2 = t1->next;
    for (t = head; t != t1; t = t->next) {
      int reorder =
        (t1->data->prio < t->data->prio) ? 1 :
        (t1->data->weight == 0) ? 0 :
        (t->data->weight == 0) ? 1 : 0;
      if (reorder) {
        t1->next = t;
        for (tt=head; tt->next != t1; tt=tt->next);
        tt->next = t2;
        if (t == head)
          head = t1;
        else {
          for (tt=head; tt->next != t; tt=tt->next);
          tt->next = t1;
        }
        break;
      }
    }
    t1 = t2;
  }
  *list = head;
}

srv_list *srv_lookup (const char* service) {
  int rc;
  unsigned char answer[NS_PACKETSZ];
  HEADER *header;

  if (!(_res.options & RES_INIT)) {
    rc = res_init ();
    if (rc != 0) {
      perror ("res_init");
      return NULL;
    }
  }
  
  rc = res_query(service, C_IN, T_SRV, answer, NS_PACKETSZ);
  if (rc == -1) {
    perror ("res_query");
    return NULL;
  }

  unsigned char *cp, *tcp, *eom;
  
  header = (HEADER *) answer;
  cp = answer + HFIXEDSZ;
  eom = answer + rc;

  uint32_t ancount = ntohs (header->ancount) + ntohs (header->nscount);
  uint32_t qdcount = ntohs (header->qdcount);

  for (; qdcount > 0 && cp < eom; qdcount--) {
    rc = dn_skipname (cp, eom);
    rc += QFIXEDSZ;
    if (rc < 0) {
      perror("dn_skipname");
      return NULL;
    }
    cp += rc;
  }

  char r_name[MAXDNAME+1];
  uint16_t r_class __attribute__ ((unused));
  uint16_t r_type, r_len;
  uint16_t r_ttl __attribute__ ((unused));
  srv_list *srvlist = NULL;
  srv_list *curr = NULL;

  for (; ancount > 0 && cp < eom; ancount--) {
    rc = dn_expand (answer, eom, cp, (void *) r_name, MAXDNAME);
    if (rc < 0) {
      perror("dn_expand");
      return NULL;
    }
    
    cp += rc;

    NS_GET16(r_type, cp);
    NS_GET16(r_class, cp);
    NS_GET32(r_ttl, cp);
    NS_GET16(r_len, cp);

    if(cp + r_len > eom) /* is this check necessary? */
      r_len = eom - cp;
    
    tcp = cp;

    if (r_type == T_SRV) {
      if (INT16SZ * 3 <= r_len) {
        srv_record *srr;
        uint16_t prio, weight, port;
        
        NS_GET16(prio, tcp);
        NS_GET16(weight, tcp);
        NS_GET16(port, tcp);
        
        rc = dn_expand(answer, eom, tcp, (void *) r_name, MAXDNAME);
        if (rc > 0) {
          srr = malloc (sizeof (srv_record));
          srr->prio = prio;
          srr->weight = weight;
          srr->port = port;
          srr->name = strndup(r_name, rc);
          if (srvlist == NULL) {
            srvlist = malloc (sizeof (srv_list));
            srvlist->data = srr;
            srvlist->next = NULL;
            curr = srvlist;
          } else {
            curr->next = malloc (sizeof (srv_list));
            curr = curr->next;
            curr->data = srr;
            curr->next = NULL;
          }
        }
      }
    }
    
    cp += r_len;
  }

  if (srvlist != NULL)
    srv_list_sort (&srvlist);
  return srvlist;
}

void srv_list_destroy (srv_list *list) {
  srv_list *curr = list;
  while (curr != NULL) {
    free (curr->data->name);
    free (curr->data);
    curr = curr->next;
  }
}

srv_record *srv_record_get(srv_list **srvs) {
  if (*srvs == NULL)
    return NULL;

  uint32_t total = 0;
  srv_list *curr = *srvs;
  uint32_t priority = curr->data->prio;
  while (curr != NULL) {
    if (curr->data->prio != priority)
      break;
    total += curr->data->weight;
    curr = curr->next;
  }

  // TODO: init seed()
  int selection = rand() / (RAND_MAX / (total + 1) + 1);
  curr = *srvs;

  srv_list *prev = NULL;
  srv_record *srv = NULL;
  
  while (curr != NULL) {
    if (curr->data->prio != priority) {
      if (prev != NULL)
        prev->next = curr->next;
      else
        *srvs = curr->next;
      srv = curr->data;
      free (curr);
      break;
    }
    selection -= curr->data->weight;
    if (selection <= 0) {
      if (prev != NULL)
        prev->next = curr->next;
      else
        *srvs = curr->next;
      srv = curr->data;
      free (curr);
      break;
    }
    prev = curr;
    curr = curr->next;
  }
  return srv;
}



static void srv_list_display(srv_list *srvs) __attribute__ ((unused));

static void srv_list_display(srv_list *srvs) {
  srv_list *curr = srvs;
  while (curr != NULL) {
    srv_record *srv = curr->data;
    printf("%s %d %d %d\n", srv->name, srv->prio, srv->weight, srv->port);
    curr = curr->next;
  }
  printf("\n");
}
<file_sep>#ifndef _BASE64_H_
#define _BASE64_H_

#include <stdint.h>
extern uint8_t decoding_table[256];

int base64_decode(const char* value, int value_len, unsigned char** result, int* result_len);
char* base64_encode (const unsigned char* data, size_t len);

#endif
<file_sep>#ifndef _ACCOUNT_H_
#define _ACCOUNT_H_

#include "jid/jid.h"

typedef struct {
  jid_t *jid;
  char *password;
  int port;
  char *ip;
} account_t;

#endif
<file_sep>#ifndef _EXTENSIONS_H_
#define _EXTENSIONS_H_

enum extension_type
{
  EXTENSION_TYPE_IQLAST_LAST,
  EXTENSION_TYPE_MOOD_MOOD,
  EXTENSION_TYPE_VCARD_VCARD,
  EXTENSION_TYPE_VCARD_N,
  EXTENSION_TYPE_VCARD_NICKNAME,
  EXTENSION_TYPE_VCARD_PHOTO,
  EXTENSION_TYPE_VCARD_BDAY,
  EXTENSION_TYPE_VCARD_ADR,
  EXTENSION_TYPE_VCARD_LABEL,
  EXTENSION_TYPE_VCARD_TEL,
  EXTENSION_TYPE_VCARD_EMAIL,
  EXTENSION_TYPE_VCARD_JABBERID,
  EXTENSION_TYPE_VCARD_MAILER,
  EXTENSION_TYPE_VCARD_TZ,
  EXTENSION_TYPE_VCARD_GEO,
  EXTENSION_TYPE_VCARD_TITLE,
  EXTENSION_TYPE_VCARD_ROLE,
  EXTENSION_TYPE_VCARD_LOGO,
  EXTENSION_TYPE_VCARD_EXTVAL,
  EXTENSION_TYPE_VCARD_AGENT,
  EXTENSION_TYPE_VCARD_ORG,
  EXTENSION_TYPE_VCARD_CATEGORIES,
  EXTENSION_TYPE_VCARD_NOTE,
  EXTENSION_TYPE_VCARD_PRODID,
  EXTENSION_TYPE_VCARD_REV,
  EXTENSION_TYPE_VCARD_SORT_STRING,
  EXTENSION_TYPE_VCARD_SOUND,
  EXTENSION_TYPE_VCARD_PHONETIC,
  EXTENSION_TYPE_VCARD_UID,
  EXTENSION_TYPE_VCARD_URL,
  EXTENSION_TYPE_VCARD_DESC,
  EXTENSION_TYPE_VCARD_CLASS,
  EXTENSION_TYPE_VCARD_KEY,
  EXTENSION_TYPE_PRIVACY_PRIVACY,
  EXTENSION_TYPE_PRIVACY_ACTIVE,
  EXTENSION_TYPE_PRIVACY_DEFAULT,
  EXTENSION_TYPE_PRIVACY_LIST,
  EXTENSION_TYPE_PRIVACY_ITEM,
  EXTENSION_TYPE_STREAM_START,
  EXTENSION_TYPE_STREAM_FEATURES,
  EXTENSION_TYPE_STREAM_ERROR,
  EXTENSION_TYPE_XOOB_X,
  EXTENSION_TYPE_XDATA_X,
  EXTENSION_TYPE_XDATA_FIELD,
  EXTENSION_TYPE_XDATA_OPTION,
  EXTENSION_TYPE_STARTTLS_STARTTLS,
  EXTENSION_TYPE_STARTTLS_PROCEED,
  EXTENSION_TYPE_STARTTLS_FAILURE,
  EXTENSION_TYPE_PING_PING,
  EXTENSION_TYPE_BIND_BIND,
  EXTENSION_TYPE_SASL_MECHANISMS,
  EXTENSION_TYPE_SASL_AUTH,
  EXTENSION_TYPE_SASL_SUCCESS,
  EXTENSION_TYPE_SASL_CHALLENGE,
  EXTENSION_TYPE_SASL_RESPONSE,
  EXTENSION_TYPE_SASL_FAILURE,
  EXTENSION_TYPE_CAPS_CAPS,
  EXTENSION_TYPE_IQVERSION_VERSION,
  EXTENSION_TYPE_ROSTER_ROSTER,
  EXTENSION_TYPE_ROSTER_ITEM,
  EXTENSION_TYPE_CAPTCHA_CAPTCHA,
  EXTENSION_TYPE_DISCO_INFO_INFO,
  EXTENSION_TYPE_DISCO_INFO_IDENTITY,
  EXTENSION_TYPE_DISCO_INFO_FEATURE,
  EXTENSION_TYPE_IQTIME_TIME,
  EXTENSION_TYPE_IQREGISTER_QUERY,
  EXTENSION_TYPE_PUBSUB_EVENT_EVENT,
  EXTENSION_TYPE_PUBSUB_EVENT_COLLECTION,
  EXTENSION_TYPE_PUBSUB_EVENT_CONFIGURATION,
  EXTENSION_TYPE_PUBSUB_EVENT_DELETE,
  EXTENSION_TYPE_PUBSUB_EVENT_ITEMS,
  EXTENSION_TYPE_PUBSUB_EVENT_ITEM,
  EXTENSION_TYPE_PUBSUB_EVENT_PURGE,
  EXTENSION_TYPE_PUBSUB_EVENT_RETRACT,
  EXTENSION_TYPE_PUBSUB_EVENT_SUBSCRIPTION,
  EXTENSION_TYPE_CLIENT_IQ,
  EXTENSION_TYPE_CLIENT_PRESENCE,
  EXTENSION_TYPE_CLIENT_MESSAGE,
  EXTENSION_TYPE_CLIENT_PRESENCE_SHOW,
  EXTENSION_TYPE_STANZA_ERROR,
  EXTENSION_TYPE_MUC_ENTER,
  EXTENSION_TYPE_MUC_USER_ACTION,
  EXTENSION_TYPE_MUC_USER_STATUS,
  EXTENSION_TYPE_MUC_USER_DECLINE,
  EXTENSION_TYPE_MUC_USER_DESTROY,
  EXTENSION_TYPE_MUC_USER_INVITE,
  EXTENSION_TYPE_MUC_USER_ITEM,
  EXTENSION_TYPE_MUC_OWNER_CONFIGURE,
  EXTENSION_TYPE_MUC_ADMIN_QUERY,
  EXTENSION_TYPE_MUC_ADMIN_ITEM,
  EXTENSION_TYPE_STATS_STATS,
  EXTENSION_TYPE_STATS_STAT,
  EXTENSION_TYPE_TIME_TIME,
  EXTENSION_TYPE_SESSION_SESSION,
};

#endif
<file_sep>#ifndef _USTRING_H_
#define _USTRING_H_

#include <stdlib.h>
#include <stdint.h>

typedef struct {
  uint32_t *ucs4;
  size_t len;
} ustring_t;

int ustring_decode_utf8 (ustring_t *ustring, const char *str, size_t len);
int ustring_encode_utf8 (ustring_t *ustring, char** str);
void ustring_free (ustring_t *ustring);
void ustring_print (ustring_t *usring);
void ustring_print_hex (ustring_t *usring);
int ustring_compare (ustring_t *ustring1, ustring_t *ustring2);

#endif
<file_sep>#ifndef _XEP_MOOD_DATA_H_
#define  _XEP_MOOD_DATA_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <string.h>
#include "xstream.h"
#include "types.h"


extern const char *ns_mood;

enum mood_mood_mood_t
{
  MOOD_MOOD_MOOD_AFRAID,
  MOOD_MOOD_MOOD_AMAZED,
  MOOD_MOOD_MOOD_ANGRY,
  MOOD_MOOD_MOOD_ANNOYED,
  MOOD_MOOD_MOOD_ANXIOUS,
  MOOD_MOOD_MOOD_AROUSED,
  MOOD_MOOD_MOOD_ASHAMED,
  MOOD_MOOD_MOOD_BORED,
  MOOD_MOOD_MOOD_BRAVE,
  MOOD_MOOD_MOOD_CALM,
  MOOD_MOOD_MOOD_COLD,
  MOOD_MOOD_MOOD_CONFUSED,
  MOOD_MOOD_MOOD_CONTENTED,
  MOOD_MOOD_MOOD_CRANKY,
  MOOD_MOOD_MOOD_CURIOUS,
  MOOD_MOOD_MOOD_DEPRESSED,
  MOOD_MOOD_MOOD_DISAPPOINTED,
  MOOD_MOOD_MOOD_DISGUSTED,
  MOOD_MOOD_MOOD_DISTRACTED,
  MOOD_MOOD_MOOD_EMBARRASSED,
  MOOD_MOOD_MOOD_EXCITED,
  MOOD_MOOD_MOOD_FLIRTATIOUS,
  MOOD_MOOD_MOOD_FRUSTRATED,
  MOOD_MOOD_MOOD_GRUMPY,
  MOOD_MOOD_MOOD_GUILTY,
  MOOD_MOOD_MOOD_HAPPY,
  MOOD_MOOD_MOOD_HOT,
  MOOD_MOOD_MOOD_HUMBLED,
  MOOD_MOOD_MOOD_HUMILIATED,
  MOOD_MOOD_MOOD_HUNGRY,
  MOOD_MOOD_MOOD_HURT,
  MOOD_MOOD_MOOD_IMPRESSED,
  MOOD_MOOD_MOOD_IN_AWE,
  MOOD_MOOD_MOOD_IN_LOVE,
  MOOD_MOOD_MOOD_INDIGNANT,
  MOOD_MOOD_MOOD_INTERESTED,
  MOOD_MOOD_MOOD_INTOXICATED,
  MOOD_MOOD_MOOD_INVINCIBLE,
  MOOD_MOOD_MOOD_JEALOUS,
  MOOD_MOOD_MOOD_LONELY,
  MOOD_MOOD_MOOD_MEAN,
  MOOD_MOOD_MOOD_MOODY,
  MOOD_MOOD_MOOD_NERVOUS,
  MOOD_MOOD_MOOD_NEUTRAL,
  MOOD_MOOD_MOOD_OFFENDED,
  MOOD_MOOD_MOOD_PLAYFUL,
  MOOD_MOOD_MOOD_PROUD,
  MOOD_MOOD_MOOD_RELIEVED,
  MOOD_MOOD_MOOD_REMORSEFUL,
  MOOD_MOOD_MOOD_RESTLESS,
  MOOD_MOOD_MOOD_SAD,
  MOOD_MOOD_MOOD_SARCASTIC,
  MOOD_MOOD_MOOD_SERIOUS,
  MOOD_MOOD_MOOD_SHOCKED,
  MOOD_MOOD_MOOD_SHY,
  MOOD_MOOD_MOOD_SICK,
  MOOD_MOOD_MOOD_SLEEPY,
  MOOD_MOOD_MOOD_STRESSED,
  MOOD_MOOD_MOOD_SURPRISED,
  MOOD_MOOD_MOOD_THIRSTY,
  MOOD_MOOD_MOOD_WORRIED,
};

enum mood_mood_mood_t enum_mood_mood_mood_from_string (const char *value);
const char *enum_mood_mood_mood_to_string (enum mood_mood_mood_t);

struct mood_mood_t
{
  enum mood_mood_mood_t fMood;
  char *fText;
};


struct mood_mood_t *mood_mood_decode (xmlreader_t * reader);
int mood_mood_encode (xmlwriter_t * writer, struct mood_mood_t *data);
void mood_mood_free (struct mood_mood_t *data);
#endif
<file_sep>#ifndef _CLIENT_DATA_H_
#define  _CLIENT_DATA_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <string.h>
#include "xstream.h"
#include "types.h"
#include "jid/jid.h"
#include "stanza_data.h"


extern const char *ns_client;

enum client_iq_type_t
{
  CLIENT_IQ_TYPE_GET,
  CLIENT_IQ_TYPE_SET,
  CLIENT_IQ_TYPE_RESULT,
  CLIENT_IQ_TYPE_ERROR,
};

enum client_iq_type_t enum_client_iq_type_from_string (const char *value);
const char *enum_client_iq_type_to_string (enum client_iq_type_t);
enum client_presence_type_t
{
  CLIENT_PRESENCE_TYPE_SUBSCRIBE,
  CLIENT_PRESENCE_TYPE_SUBSCRIBED,
  CLIENT_PRESENCE_TYPE_UNSUBSCRIBE,
  CLIENT_PRESENCE_TYPE_UNSUBSCRIBED,
  CLIENT_PRESENCE_TYPE_UNAVAILABLE,
};

enum client_presence_type_t enum_client_presence_type_from_string (const char
								   *value);
const char *enum_client_presence_type_to_string (enum client_presence_type_t);
enum client_presence_show_t
{
  CLIENT_PRESENCE_SHOW_CHAT,
  CLIENT_PRESENCE_SHOW_AWAY,
  CLIENT_PRESENCE_SHOW_XA,
  CLIENT_PRESENCE_SHOW_DND,
};

enum client_presence_show_t enum_client_presence_show_from_string (const char
								   *value);
const char *enum_client_presence_show_to_string (enum client_presence_show_t);
enum client_message_type_t
{
  CLIENT_MESSAGE_TYPE_NORMAL,
  CLIENT_MESSAGE_TYPE_CHAT,
  CLIENT_MESSAGE_TYPE_GROUPCHAT,
  CLIENT_MESSAGE_TYPE_HEADLINE,
};

enum client_message_type_t enum_client_message_type_from_string (const char
								 *value);
const char *enum_client_message_type_to_string (enum client_message_type_t);

struct client_iq_t
{
  jid_t *fFrom;
  jid_t *fTo;
  char *fId;
  enum client_iq_type_t fType;
  char *fLang;
  extension_t *fPayload;
  struct stanza_error_t *fError;
};


struct client_presence_t
{
  jid_t *fFrom;
  jid_t *fTo;
  char *fId;
  enum client_presence_type_t fType;
  char *fLang;
  enum client_presence_show_t fShow;
  char *fStatus;
  int *fPriority;
  array_t *fX;
  struct stanza_error_t *fError;
};


struct client_message_t
{
  jid_t *fFrom;
  jid_t *fTo;
  char *fId;
  enum client_message_type_t fType;
  char *fLang;
  char *fThread;
  langstring_t *fSubject;
  langstring_t *fBody;
  array_t *fX;
  struct stanza_error_t *fError;
};


struct client_iq_t *client_iq_decode (xmlreader_t * reader);
int client_iq_encode (xmlwriter_t * writer, struct client_iq_t *data);
void client_iq_free (struct client_iq_t *data);
struct client_presence_t *client_presence_decode (xmlreader_t * reader);
int client_presence_encode (xmlwriter_t * writer,
			    struct client_presence_t *data);
void client_presence_free (struct client_presence_t *data);
struct client_message_t *client_message_decode (xmlreader_t * reader);
int client_message_encode (xmlwriter_t * writer,
			   struct client_message_t *data);
void client_message_free (struct client_message_t *data);
#endif
<file_sep>#include <stdio.h>
#include <stdlib.h>
#include "xmpp_prep_tables.h"
#include "xmpp_prep_tables2.h"
#include <string.h>

#include "ustring.h"

/* http://unicode.org/reports/tr15/ */

#define hangulSBase 0xAC00
#define hangulLBase 0x1100
#define hangulVBase 0x1161
#define hangulTBase 0x11A7
#define hangulLCount 19
#define hangulVCount 21
#define hangulTCount 28
#define hangulNCount (hangulVCount * hangulTCount) /* 588 */
#define hangulSCount (hangulLCount * hangulNCount) /* 11172 */

static uint32_t get_bst (uint32_t arr[][3], uint32_t x, uint16_t s, uint16_t e) {
  if (s > e || x < arr[s][0] || x >  arr[e][1])
    return -1;
  else {
    uint16_t mid = s + (e-s)/2;
    uint32_t *amid = arr[mid];
    if (x < amid[0])
      return get_bst (arr, x, s, (mid-1));
    else if (x > amid[1])
      return get_bst (arr, x, (mid+1), e);
    else
      return amid[2];
  }
}

static uint32_t get_casemap (uint32_t x) {
  if (x > 0x40 && x < 0x5b)
    return  casemap[0][2];
  else
    return get_bst (casemap, x, 1, casemap_max_idx);
}

static int16_t get_dmap_idx (uint32_t x, int s, int e) {
  if (s > e)
    return -1;
  else {
    int mid = s + (e - s) / 2;
    dmap_t row = dmap[mid];
    if (x < row.code)
      return get_dmap_idx (x, s, (mid-1));
    else if (x > row.code + row.rows)
      return get_dmap_idx (x, mid+1, e);
    else
      return row.idx + x - row.code;
  }
}

static uint32_t get_composite (uint32_t ch1, int s, int e) {
  if (s > e)
    return -1;
  else {
    int mid = s + (e - s) / 2;
    if (ch1 < cmap_data[mid][0])
      return get_composite (ch1, s, (mid-1));
    else if (ch1 > cmap_data[mid][0])
      return get_composite (ch1, (mid+1), e);
    else
      return cmap_data[mid][1];
  }
}

static uint32_t get_comp (uint32_t ch1, uint32_t ch2, int s, int e) {
  if (s > e)
    return -1;
  else {
    int mid = s + (e - s) / 2;
    dmap_t row = cmap[mid];
    if (ch2 < row.code)
      return get_comp (ch1, ch2, s, (mid-1));
    else if (ch2 > row.code)
      return get_comp (ch1, ch2, mid+1, e);
    else
      return get_composite (ch1, row.idx, row.idx + row.rows);
  }
}

static uint32_t *get_decomp (uint32_t x) {
  if (x > 0x009F && x < 0x2FA1E) {
    int idx = get_dmap_idx (x, 0, dmap_max_idx);
    if (idx != -1) 
      return (uint32_t *) &dmap_data[idx];
  }
  return NULL;
}
  
static uint32_t compose_hangul (uint32_t ch1, uint32_t ch2) {
  /* check if two current characters are L and V */
  int32_t lindex = ch1 - hangulLBase;
  if (lindex >= 0 && lindex < hangulLCount) {
    uint32_t vindex = ch2 - hangulVBase;
    if (vindex >= 0 && vindex < hangulVBase) {
      /* make syllable of form LV */
      return hangulSBase + (lindex * hangulVCount + vindex) * hangulTCount;
    }
  }

  /* 2. check to see if two current characters are LV and T */
  int32_t sindex = ch1 - hangulSBase;
  if ((sindex >= 0 && sindex < hangulSCount) && ((sindex % hangulTCount) == 0)) {
    int32_t tindex = ch2 - hangulTBase;
    if (tindex > 0 && tindex < hangulTCount) {
      /* make syllable of form LVT */
      return ch1 + tindex;
    }
  }
  /* if neither case was true */
  return -1;
}

static uint32_t composeTwo (uint32_t ch1, uint32_t ch2) {
  uint32_t newch = compose_hangul (ch1, ch2);
  if (newch != -1)
    return newch;
  if (ch2 > 767 && ch2 < 12443)
    return get_comp (ch1, ch2, 0, comps_max_idx);
  else
    return -1;
}  

static ustring_t *compose (uint32_t *result, uint8_t *res_class, size_t r_len) {
  int i = 0;
  uint8_t prevcc = 0;
  uint32_t ch1 = result[0];
  uint32_t *acc, *accp;
  acc = malloc (sizeof (uint32_t) * r_len);
  accp = acc;
  uint32_t *comps = malloc (sizeof (uint32_t) * r_len);
  uint32_t *compsp = comps;
  
  for (i = 1; i < r_len; i++) {
    uint32_t ch2 = result[i];
    uint8_t cc = res_class[i];
    uint32_t newch1;
    if (prevcc == 0 || cc > prevcc)
      newch1 = composeTwo (ch1, ch2);
    else
      newch1 = -1;
    if (newch1 != -1) {
      ch1 = newch1;
    } else if (cc == 0) {
      *accp++ = ch1;
      uint32_t *p;
      for (p = comps; p < compsp; p++) *accp++ = *p;
      compsp = comps;
      ch1 = ch2;
      prevcc = 0;
    } else {
      prevcc = cc;
      *compsp++ = ch2;
    }
  }
  *accp++ = ch1;
  if (compsp > comps) {
    uint32_t *p = NULL;
    for (p = comps; p < compsp; p++) *accp++ = *p;
  }
  free (comps);
  ustring_t *ustring = malloc (sizeof (ustring_t));
  ustring->ucs4 = acc;
  ustring->len = accp - acc;
  return ustring;
}

void nfkc (ustring_t *ustring) {
  if (ustring == NULL || ustring->ucs4 == NULL)
    return;

  uint32_t *result = malloc (sizeof (uint32_t) * ustring->len);
  uint8_t *res_class = malloc (sizeof (uint8_t) * ustring->len);
  
  uint32_t *resultp = result;
  uint8_t *res_classp = res_class;
  
  int i = 0, j = 0;

  size_t size = ustring->len;
  
  for (i = 0; i < ustring->len; i++) {
    uint32_t x = ustring->ucs4[i];
    if (x < 0xAC00 || x > 0xD7AF) {
      uint32_t *data = get_decomp (x);
      if (data == NULL) {
        *resultp++ = x;
        *res_classp++ = 0;
      } else {
        for (j = 0; j < 18 && data[j] != 0; j++) {
          if (i + j >= size - 1) {
            int offset = resultp - result;
            result = realloc (result, sizeof (uint32_t) * (size + 6));
            res_class = realloc (res_class, sizeof (uint8_t) * (size + 6));
            resultp = result + offset;
            res_classp = res_class + offset;
            size += 6;
          }
          *resultp++ = data[j] >> 8;
          *res_classp++ = data[j] & 0xFF;
        }
        if (ustring->len - i > size - (result - resultp)) {
          printf ("realloc2\n");
          int offset = resultp - result;
          result = realloc (result, sizeof (uint32_t) * (size + 6));
          res_class = realloc (res_class, sizeof (uint8_t) * (size + 6));
          resultp = result + offset;
          res_classp = res_class + offset;
          size += 6;
        }
      }
    } else {
      int32_t sindex = x - hangulSBase;
      if (sindex < 0 || sindex >= hangulSCount) {
        *resultp++ = x;
        *res_class = 0;
      } else {
        uint32_t l = hangulLBase + sindex / hangulNCount;
        uint32_t v = hangulVBase + (sindex % hangulNCount) / hangulTCount;
        uint32_t t = hangulTBase + sindex % hangulTCount;
        *resultp++ = l;
        *res_classp++ = 0;
        *resultp++ = v;
        *res_classp++ = 0;
        if (t != hangulTBase) {
          *resultp++ = t;
          *res_classp++ = 0;
        }
      }
    }
  }
            
  // canonical order
  size_t r_len = resultp - result;
  int prev = 0;

  for (i = 1; i < r_len; i++) {
    if (res_class[i] == 0 || res_class[prev] <= res_class[i]) {
      prev++;
      continue;
    } else {
      uint32_t tmp = result[prev];
      uint8_t tmp_cc = res_class[prev];
      result[prev] = result[i];
      res_class[prev] = res_class[i];
      result[i] = tmp;
      res_class[i] = tmp_cc;
      if (prev > 0)
        prev--;
      i = prev;
    }
  }

  ustring_t *ret = compose (result, res_class, r_len);

  free (result);
  free (res_class);
  free (ustring->ucs4);
  ustring->ucs4 = ret->ucs4;
  ustring->len = ret->len;
  free (ret);
}

void nodeprep (ustring_t *ustring) {
  if (ustring == NULL || ustring->ucs4 == NULL)
    return;

  int i = 0, j = 0;
  uint32_t *result = malloc (sizeof (uint32_t) * ustring->len);
  if (result == NULL)
    return;
  uint32_t *p = result;
  
  for (i = 0; i < ustring->len; i++) {
    uint32_t x = ustring->ucs4[i];
    uint32_t v = get_casemap (x);
    if (v == -1)
      *p++ = x;
    else if (v == 0)
      ;
    else if (v & b_mc) {
      uint16_t *z = fmap[v >> b_shift];
      for (j = 0; j < 4 && z[j] != 0; j++) {
        *p++ = z[j];
      }
    }
    else
      *p++ = x + (v >> b_shift);
  }
  ustring->len = p - result;
  free (ustring->ucs4);
  ustring->ucs4 = result;

  nfkc (ustring);
}

void resourceprep (ustring_t *ustring) {
  int i = 0, j = 0;

  for (i = 0; i < ustring->len; i++) {
    if (get_casemap (ustring->ucs4[i]) == 0) {
      for (j = i+1; j < ustring->len; j++)
        ustring->ucs4[j-1] = ustring->ucs4[j];
      ustring->len--;
    }
  }
  nfkc (ustring);
}
  
/* Check prohibited symbols and bidi */
static int check_prohibits (int p, ustring_t *ustring) {
  int i = 0;
  int dir;

  if (ustring->len == 0)
    return 0;
  
  uint32_t x = ustring->ucs4[i];
  uint8_t v = get_bst (prohibits, x, 0, prohibits_max_idx);
  if (v == -1)
    dir = b_l;
  else if (v & p)
    return -1;
  else if (v & b_randal)
    dir = b_randal;
  else
    dir = b_l;
  
  for (i = 1; i < ustring->len; i++) {
    uint32_t x = ustring->ucs4[i];
    uint8_t v = get_bst (prohibits, x, 0, prohibits_max_idx);
    if (v == -1)
      if (i + 1 == ustring->len && dir == b_randal)
        return -1;
      else
        ;
    else if (v & p)
      return -1;
    else if (!(v & dir) && (v & b_randal || v & b_l))
      return -1;
  }
  return 0;
}

int strong_nodeprep (ustring_t *ustring) {
  nodeprep (ustring);
  return check_prohibits (b_nodeprep_prohibit, ustring);
}

int strong_resourceprep (ustring_t *ustring) {
  resourceprep (ustring);
  return check_prohibits (b_resourceprep_prohibit, ustring);
}

/* for domains */
void nameprep (ustring_t *ustring) {
  int i = 0, j = 0;
  uint32_t *result = malloc (sizeof (uint32_t) * ustring->len);
  uint32_t *p = result;
  for (i = 0; i < ustring->len; i++) {
    uint32_t v = get_casemap (ustring->ucs4[i]);
    if (v == -1)
      *p++ = ustring->ucs4[i];
    else if (v == 0)
      ;
    else if (v & b_mc) {
      uint16_t *z = fmap[v >> b_shift];
      for (j = 0; j < 4 && z[j] != 0; j++) {
        *p++ = z[j];
      }
    }
    else
      *p++ = ustring->ucs4[i] + (v >> b_shift);
  }
  free (ustring->ucs4);
  ustring->ucs4 = result;
  ustring->len = p - result;
  nfkc (ustring);
}

int strong_nameprep (ustring_t *ustring) {
  nameprep (ustring);
  return check_prohibits (b_nameprep_prohibit, ustring);
}

<file_sep>#ifndef _STREAM_DATA_H_
#define  _STREAM_DATA_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <string.h>
#include "xstream.h"
#include "types.h"
#include "jid/jid.h"


extern const char *ns_stream;

enum stream_error_condition_name_t
{
  STREAM_ERROR_CONDITION_NAME_BAD_FORMAT,
  STREAM_ERROR_CONDITION_NAME_BAD_NAMESPACE_PREFIX,
  STREAM_ERROR_CONDITION_NAME_CONFLICT,
  STREAM_ERROR_CONDITION_NAME_CONNECTION_TIMEOUT,
  STREAM_ERROR_CONDITION_NAME_HOST_GONE,
  STREAM_ERROR_CONDITION_NAME_HOST_UNKNOWN,
  STREAM_ERROR_CONDITION_NAME_IMPROPER_ADDRESSING,
  STREAM_ERROR_CONDITION_NAME_INTERNAL_SERVER_ERROR,
  STREAM_ERROR_CONDITION_NAME_INVALID_FROM,
  STREAM_ERROR_CONDITION_NAME_INVALID_NAMESPACE,
  STREAM_ERROR_CONDITION_NAME_INVALID_XML,
  STREAM_ERROR_CONDITION_NAME_NOT_AUTHORIZED,
  STREAM_ERROR_CONDITION_NAME_NOT_WELL_FORMED,
  STREAM_ERROR_CONDITION_NAME_POLICY_VIOLATION,
  STREAM_ERROR_CONDITION_NAME_REMOTE_CONNECTION_FAILED,
  STREAM_ERROR_CONDITION_NAME_RESET,
  STREAM_ERROR_CONDITION_NAME_RESOURCE_CONSTRAINT,
  STREAM_ERROR_CONDITION_NAME_RESTRICTED_XML,
  STREAM_ERROR_CONDITION_NAME_SEE_OTHER_HOST,
  STREAM_ERROR_CONDITION_NAME_SYSTEM_SHUTDOWN,
  STREAM_ERROR_CONDITION_NAME_UNDEFINED_CONDITION,
  STREAM_ERROR_CONDITION_NAME_UNSUPPORTED_ENCODING,
  STREAM_ERROR_CONDITION_NAME_UNSUPPORTED_FEATURE,
  STREAM_ERROR_CONDITION_NAME_UNSUPPORTED_STANZA_TYPE,
  STREAM_ERROR_CONDITION_NAME_UNSUPPORTED_VERSION,
};

enum stream_error_condition_name_t
enum_stream_error_condition_name_from_string (const char *value);
const char *enum_stream_error_condition_name_to_string (enum
							stream_error_condition_name_t);

struct stream_start_t
{
  jid_t *fTo;
  jid_t *fFrom;
  char *fId;
  char *fVersion;
  char *fLang;
};




struct stream_error_t
{
  langstring_t *fText;
  struct stream_condition_set_t
  {
    enum stream_error_condition_name_t fName;
    char *fExtra;
  } fCondition;
};


struct stream_start_t *stream_start_decode (xmlreader_t * reader);
int stream_start_encode (xmlwriter_t * writer, struct stream_start_t *data);
void stream_start_free (struct stream_start_t *data);
array_t *stream_features_decode (xmlreader_t * reader);
int stream_features_encode (xmlwriter_t * writer, array_t * data);
void stream_features_free (array_t * data);
struct stream_error_t *stream_error_decode (xmlreader_t * reader);
int stream_error_encode (xmlwriter_t * writer, struct stream_error_t *data);
void stream_error_free (struct stream_error_t *data);
#endif
<file_sep>#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>

void fatal(char* msg, ...) {
  va_list arg;
        
  va_start(arg, msg);
  fprintf(stderr, "fatal: ");
  vfprintf(stderr, msg, arg);
  fprintf(stderr, "\n");
  exit(2);
}
<file_sep>#include "xep_mood_data.h"
#include "helpers.h"
#include "errors.h"

const char *ns_mood = "http://jabber.org/protocol/mood";

struct mood_mood_t *
mood_mood_decode (xmlreader_t * reader)
{
  struct mood_mood_t *elm = NULL;
  elm = malloc (sizeof (struct mood_mood_t));
  if (elm == NULL)
    fatal ("mood_mood_t: malloc failed");
  memset (elm, 0, sizeof (struct mood_mood_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "text") == 0)
	      && (strcmp (namespace, ns_mood) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fText = (char *) value;
	    }
	  else if (strcmp (namespace, ns_mood) != 0)
	    {
	      elm->fMood = enum_mood_mood_mood_from_string (name);
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	    }
	}
    }
  return elm;
}

int
mood_mood_encode (xmlwriter_t * writer, struct mood_mood_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_mood, "mood");
  if (err != 0)
    return err;
  if (elm->fMood != 0)
    {
      const char *name = enum_mood_mood_mood_to_string (elm->fMood);
      err = xmlwriter_simple_element (writer, ns_mood, name, NULL);
      if (err != 0)
	return err;
    }
  if (elm->fText != NULL)
    {
      err = xmlwriter_simple_element (writer, ns_mood, "text", elm->fText);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
mood_mood_free (struct mood_mood_t *data)
{
  if (data == NULL)
    return;
  if (data->fMood != 0)
    {
    }
  if (data->fText != NULL)
    {
      free (data->fText);
    }
  free (data);
}

enum mood_mood_mood_t
enum_mood_mood_mood_from_string (const char *value)
{
  if (strcmp (value, "afraid") == 0)
    return MOOD_MOOD_MOOD_AFRAID;
  else if (strcmp (value, "amazed") == 0)
    return MOOD_MOOD_MOOD_AMAZED;
  else if (strcmp (value, "angry") == 0)
    return MOOD_MOOD_MOOD_ANGRY;
  else if (strcmp (value, "annoyed") == 0)
    return MOOD_MOOD_MOOD_ANNOYED;
  else if (strcmp (value, "anxious") == 0)
    return MOOD_MOOD_MOOD_ANXIOUS;
  else if (strcmp (value, "aroused") == 0)
    return MOOD_MOOD_MOOD_AROUSED;
  else if (strcmp (value, "ashamed") == 0)
    return MOOD_MOOD_MOOD_ASHAMED;
  else if (strcmp (value, "bored") == 0)
    return MOOD_MOOD_MOOD_BORED;
  else if (strcmp (value, "brave") == 0)
    return MOOD_MOOD_MOOD_BRAVE;
  else if (strcmp (value, "calm") == 0)
    return MOOD_MOOD_MOOD_CALM;
  else if (strcmp (value, "cold") == 0)
    return MOOD_MOOD_MOOD_COLD;
  else if (strcmp (value, "confused") == 0)
    return MOOD_MOOD_MOOD_CONFUSED;
  else if (strcmp (value, "contented") == 0)
    return MOOD_MOOD_MOOD_CONTENTED;
  else if (strcmp (value, "cranky") == 0)
    return MOOD_MOOD_MOOD_CRANKY;
  else if (strcmp (value, "curious") == 0)
    return MOOD_MOOD_MOOD_CURIOUS;
  else if (strcmp (value, "depressed") == 0)
    return MOOD_MOOD_MOOD_DEPRESSED;
  else if (strcmp (value, "disappointed") == 0)
    return MOOD_MOOD_MOOD_DISAPPOINTED;
  else if (strcmp (value, "disgusted") == 0)
    return MOOD_MOOD_MOOD_DISGUSTED;
  else if (strcmp (value, "distracted") == 0)
    return MOOD_MOOD_MOOD_DISTRACTED;
  else if (strcmp (value, "embarrassed") == 0)
    return MOOD_MOOD_MOOD_EMBARRASSED;
  else if (strcmp (value, "excited") == 0)
    return MOOD_MOOD_MOOD_EXCITED;
  else if (strcmp (value, "flirtatious") == 0)
    return MOOD_MOOD_MOOD_FLIRTATIOUS;
  else if (strcmp (value, "frustrated") == 0)
    return MOOD_MOOD_MOOD_FRUSTRATED;
  else if (strcmp (value, "grumpy") == 0)
    return MOOD_MOOD_MOOD_GRUMPY;
  else if (strcmp (value, "guilty") == 0)
    return MOOD_MOOD_MOOD_GUILTY;
  else if (strcmp (value, "happy") == 0)
    return MOOD_MOOD_MOOD_HAPPY;
  else if (strcmp (value, "hot") == 0)
    return MOOD_MOOD_MOOD_HOT;
  else if (strcmp (value, "humbled") == 0)
    return MOOD_MOOD_MOOD_HUMBLED;
  else if (strcmp (value, "humiliated") == 0)
    return MOOD_MOOD_MOOD_HUMILIATED;
  else if (strcmp (value, "hungry") == 0)
    return MOOD_MOOD_MOOD_HUNGRY;
  else if (strcmp (value, "hurt") == 0)
    return MOOD_MOOD_MOOD_HURT;
  else if (strcmp (value, "impressed") == 0)
    return MOOD_MOOD_MOOD_IMPRESSED;
  else if (strcmp (value, "in_awe") == 0)
    return MOOD_MOOD_MOOD_IN_AWE;
  else if (strcmp (value, "in_love") == 0)
    return MOOD_MOOD_MOOD_IN_LOVE;
  else if (strcmp (value, "indignant") == 0)
    return MOOD_MOOD_MOOD_INDIGNANT;
  else if (strcmp (value, "interested") == 0)
    return MOOD_MOOD_MOOD_INTERESTED;
  else if (strcmp (value, "intoxicated") == 0)
    return MOOD_MOOD_MOOD_INTOXICATED;
  else if (strcmp (value, "invincible") == 0)
    return MOOD_MOOD_MOOD_INVINCIBLE;
  else if (strcmp (value, "jealous") == 0)
    return MOOD_MOOD_MOOD_JEALOUS;
  else if (strcmp (value, "lonely") == 0)
    return MOOD_MOOD_MOOD_LONELY;
  else if (strcmp (value, "mean") == 0)
    return MOOD_MOOD_MOOD_MEAN;
  else if (strcmp (value, "moody") == 0)
    return MOOD_MOOD_MOOD_MOODY;
  else if (strcmp (value, "nervous") == 0)
    return MOOD_MOOD_MOOD_NERVOUS;
  else if (strcmp (value, "neutral") == 0)
    return MOOD_MOOD_MOOD_NEUTRAL;
  else if (strcmp (value, "offended") == 0)
    return MOOD_MOOD_MOOD_OFFENDED;
  else if (strcmp (value, "playful") == 0)
    return MOOD_MOOD_MOOD_PLAYFUL;
  else if (strcmp (value, "proud") == 0)
    return MOOD_MOOD_MOOD_PROUD;
  else if (strcmp (value, "relieved") == 0)
    return MOOD_MOOD_MOOD_RELIEVED;
  else if (strcmp (value, "remorseful") == 0)
    return MOOD_MOOD_MOOD_REMORSEFUL;
  else if (strcmp (value, "restless") == 0)
    return MOOD_MOOD_MOOD_RESTLESS;
  else if (strcmp (value, "sad") == 0)
    return MOOD_MOOD_MOOD_SAD;
  else if (strcmp (value, "sarcastic") == 0)
    return MOOD_MOOD_MOOD_SARCASTIC;
  else if (strcmp (value, "serious") == 0)
    return MOOD_MOOD_MOOD_SERIOUS;
  else if (strcmp (value, "shocked") == 0)
    return MOOD_MOOD_MOOD_SHOCKED;
  else if (strcmp (value, "shy") == 0)
    return MOOD_MOOD_MOOD_SHY;
  else if (strcmp (value, "sick") == 0)
    return MOOD_MOOD_MOOD_SICK;
  else if (strcmp (value, "sleepy") == 0)
    return MOOD_MOOD_MOOD_SLEEPY;
  else if (strcmp (value, "stressed") == 0)
    return MOOD_MOOD_MOOD_STRESSED;
  else if (strcmp (value, "surprised") == 0)
    return MOOD_MOOD_MOOD_SURPRISED;
  else if (strcmp (value, "thirsty") == 0)
    return MOOD_MOOD_MOOD_THIRSTY;
  else if (strcmp (value, "worried") == 0)
    return MOOD_MOOD_MOOD_WORRIED;
  return 0;
}

const char *
enum_mood_mood_mood_to_string (enum mood_mood_mood_t value)
{
  switch (value)
    {
    case MOOD_MOOD_MOOD_AFRAID:
      return "afraid";
    case MOOD_MOOD_MOOD_AMAZED:
      return "amazed";
    case MOOD_MOOD_MOOD_ANGRY:
      return "angry";
    case MOOD_MOOD_MOOD_ANNOYED:
      return "annoyed";
    case MOOD_MOOD_MOOD_ANXIOUS:
      return "anxious";
    case MOOD_MOOD_MOOD_AROUSED:
      return "aroused";
    case MOOD_MOOD_MOOD_ASHAMED:
      return "ashamed";
    case MOOD_MOOD_MOOD_BORED:
      return "bored";
    case MOOD_MOOD_MOOD_BRAVE:
      return "brave";
    case MOOD_MOOD_MOOD_CALM:
      return "calm";
    case MOOD_MOOD_MOOD_COLD:
      return "cold";
    case MOOD_MOOD_MOOD_CONFUSED:
      return "confused";
    case MOOD_MOOD_MOOD_CONTENTED:
      return "contented";
    case MOOD_MOOD_MOOD_CRANKY:
      return "cranky";
    case MOOD_MOOD_MOOD_CURIOUS:
      return "curious";
    case MOOD_MOOD_MOOD_DEPRESSED:
      return "depressed";
    case MOOD_MOOD_MOOD_DISAPPOINTED:
      return "disappointed";
    case MOOD_MOOD_MOOD_DISGUSTED:
      return "disgusted";
    case MOOD_MOOD_MOOD_DISTRACTED:
      return "distracted";
    case MOOD_MOOD_MOOD_EMBARRASSED:
      return "embarrassed";
    case MOOD_MOOD_MOOD_EXCITED:
      return "excited";
    case MOOD_MOOD_MOOD_FLIRTATIOUS:
      return "flirtatious";
    case MOOD_MOOD_MOOD_FRUSTRATED:
      return "frustrated";
    case MOOD_MOOD_MOOD_GRUMPY:
      return "grumpy";
    case MOOD_MOOD_MOOD_GUILTY:
      return "guilty";
    case MOOD_MOOD_MOOD_HAPPY:
      return "happy";
    case MOOD_MOOD_MOOD_HOT:
      return "hot";
    case MOOD_MOOD_MOOD_HUMBLED:
      return "humbled";
    case MOOD_MOOD_MOOD_HUMILIATED:
      return "humiliated";
    case MOOD_MOOD_MOOD_HUNGRY:
      return "hungry";
    case MOOD_MOOD_MOOD_HURT:
      return "hurt";
    case MOOD_MOOD_MOOD_IMPRESSED:
      return "impressed";
    case MOOD_MOOD_MOOD_IN_AWE:
      return "in_awe";
    case MOOD_MOOD_MOOD_IN_LOVE:
      return "in_love";
    case MOOD_MOOD_MOOD_INDIGNANT:
      return "indignant";
    case MOOD_MOOD_MOOD_INTERESTED:
      return "interested";
    case MOOD_MOOD_MOOD_INTOXICATED:
      return "intoxicated";
    case MOOD_MOOD_MOOD_INVINCIBLE:
      return "invincible";
    case MOOD_MOOD_MOOD_JEALOUS:
      return "jealous";
    case MOOD_MOOD_MOOD_LONELY:
      return "lonely";
    case MOOD_MOOD_MOOD_MEAN:
      return "mean";
    case MOOD_MOOD_MOOD_MOODY:
      return "moody";
    case MOOD_MOOD_MOOD_NERVOUS:
      return "nervous";
    case MOOD_MOOD_MOOD_NEUTRAL:
      return "neutral";
    case MOOD_MOOD_MOOD_OFFENDED:
      return "offended";
    case MOOD_MOOD_MOOD_PLAYFUL:
      return "playful";
    case MOOD_MOOD_MOOD_PROUD:
      return "proud";
    case MOOD_MOOD_MOOD_RELIEVED:
      return "relieved";
    case MOOD_MOOD_MOOD_REMORSEFUL:
      return "remorseful";
    case MOOD_MOOD_MOOD_RESTLESS:
      return "restless";
    case MOOD_MOOD_MOOD_SAD:
      return "sad";
    case MOOD_MOOD_MOOD_SARCASTIC:
      return "sarcastic";
    case MOOD_MOOD_MOOD_SERIOUS:
      return "serious";
    case MOOD_MOOD_MOOD_SHOCKED:
      return "shocked";
    case MOOD_MOOD_MOOD_SHY:
      return "shy";
    case MOOD_MOOD_MOOD_SICK:
      return "sick";
    case MOOD_MOOD_MOOD_SLEEPY:
      return "sleepy";
    case MOOD_MOOD_MOOD_STRESSED:
      return "stressed";
    case MOOD_MOOD_MOOD_SURPRISED:
      return "surprised";
    case MOOD_MOOD_MOOD_THIRSTY:
      return "thirsty";
    case MOOD_MOOD_MOOD_WORRIED:
      return "worried";
    }
  return NULL;
}
<file_sep>#ifndef _XEP_IQVERSION_DATA_H_
#define  _XEP_IQVERSION_DATA_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <string.h>
#include "xstream.h"
#include "types.h"


extern const char *ns_iqversion;


struct iqversion_version_t
{
  char *fName;
  char *fVersion;
  char *fOs;
};


struct iqversion_version_t *iqversion_version_decode (xmlreader_t * reader);
int iqversion_version_encode (xmlwriter_t * writer,
			      struct iqversion_version_t *data);
void iqversion_version_free (struct iqversion_version_t *data);
#endif
<file_sep>#include <malloc.h>
#include <string.h>
#include "xmlwriter.h"
#include "helpers.h"
#include "bufio.h"
#include "array.h"
#include "utf8.h"

const char* ns_xml = "http://www.w3.org/XML/1998/namespace";

static const char* empty_string = "";

struct pair_t {
  const char* p1;
  const char* p2;
};

void xmlwriter_init (xmlwriter_t* writer, int fd) {
  memset (writer, 0, sizeof (xmlwriter_t));
  writer->buf = bufio_writer_new (fd);
  stringpair_set (&writer->namespaces, ns_xml, "xml");
  writer->local_namespaces = array_new (sizeof (array_t*), 0);
  writer->tags = array_new (sizeof (struct pair_t), 5);
}

void xmlwriter_free (xmlwriter_t* writer) {
  if (writer == NULL)
    return;

  stringpair_free (writer->namespaces);
  array_free (writer->local_namespaces);
  array_free (writer->tags);
  free (writer);
}

void xmlwriter_reset (xmlwriter_t* writer) {
  bufio_writer_reset (writer->buf);
  stringpair_free (writer->namespaces);
  writer->namespaces = NULL;
  writer->openStartTag = false;
  int len = array_length (writer->local_namespaces);
  int i = 0;
  for (i = 0; i < len; i++) {
    array_t** l = array_get (writer->local_namespaces, i);
    array_free (*l);
  }
  array_slice (writer->local_namespaces, 0, 0);
  writer->depth = 0;
  array_slice (writer->tags, 0, 0);
  stringpair_set (&writer->namespaces, ns_xml, "xml");
}

int xmlwriter_set_prefix (xmlwriter_t* writer, const char* prefix, const char* uri) {
  if (writer == NULL)
    fatal ("xmlwriter_set_prefix: writer is null");

  if (prefix == NULL)
    prefix = empty_string;
  
	if (writer->openStartTag) {
		if (prefix == NULL)
      fatal ("xmlwriter_set_prefix: prefix is null inside opened start tag");

    int err = bufio_writer_write (writer->buf, 5, " xmlns:", prefix,  "=\"", uri,  "\"");
    if (err != 0) return err;
	}
	stringpair_set (&writer->namespaces, uri, prefix);

  if (array_length (writer->local_namespaces) <= writer->depth) {
    array_t* a = array_new (sizeof (array_t*), 5);
    array_append (writer->local_namespaces, &a);
  }
  array_t** lns = array_get_last (writer->local_namespaces);

  array_append (*lns, &uri);
  return 0;
}

void xmlwriter_unset_prefix (xmlwriter_t* writer, const char* prefix) {
  if (writer == NULL)
    fatal ("xmlwriter_unset_prefix: writer is null");

  stringpair_delete_by_value (&writer->namespaces, prefix);
  
}

int xmlwriter_start_stream (xmlwriter_t* writer) {
  if (writer == NULL)
    fatal ("xmlwriter_start_stream: writer is null");

  return bufio_writer_write (writer->buf, 1, "<?xml version=\"1.0\" encoding=\"utf-8\"?>");
}

int xmlwriter_end_stream(xmlwriter_t* writer) {
  if (writer == NULL)
    fatal ("xmlwriter_end_stream: writer is null");

  int i, err = 0;
  for (i = writer->depth-1; i > 0; i--) {
    err = xmlwriter_end_element (writer);
    if (err != 0) return err;
  }
  return xmlwriter_flush (writer);
}

static int xmlwriter_close_start_element(xmlwriter_t* writer) {
  if (writer == NULL)
    fatal ("xmlwriter_close_start_element: writer is null");

	if (writer->openStartTag) {
    int err = bufio_writer_write (writer->buf, 1, ">");
    if (err != 0) return err;
		writer->openStartTag = false;
	}
	return 0;
}

int xmlwriter_flush (xmlwriter_t* writer) {
  if (writer == NULL)
    fatal ("xmlwriter_flush: writer is null");

  int err = xmlwriter_close_start_element (writer);
  if (err != 0) return err;

  return bufio_writer_flush (writer->buf);
}

int xmlwriter_end_element (xmlwriter_t* writer) {
  if (writer == NULL)
    fatal ("xmlwriter_end_element: writer is null");

  writer->depth--;
  struct pair_t* tag = array_get_last (writer->tags);
  array_delete_last (writer->tags);

  array_t** lns = array_get_last (writer->local_namespaces);
  int i, len = array_length (*lns);
  for (i = 0; i < len; i++) {
    char* ns = array_get (*lns, i);
    stringpair_delete (&writer->namespaces, ns);
  }
  array_free (*lns);

  array_delete_last (writer->local_namespaces);
  
  int err = 0;
  if (writer->openStartTag) {
		writer->openStartTag = false;
    return bufio_writer_write (writer->buf, 1, "/>");
	}

  err = bufio_writer_write (writer->buf, 1, "</");
  if (err != 0) return err;
  if (tag->p1 != NULL && tag->p1 != empty_string) {
    err = bufio_writer_write (writer->buf, 2, tag->p1, ":");
    if (err != 0) return err;
  }
  err = bufio_writer_write (writer->buf, 2, tag->p2, ">");
  if (err != 0) return err;

  return 0;
}

int xmlwriter_start_element (xmlwriter_t* writer, const char* space, const char* local) {
  if (writer == NULL)
    fatal ("xmlwriter_start_element: writer is null");

  int err = 0;
  writer->depth++;

  err = xmlwriter_close_start_element (writer);
  if (err != 0) return err;

  const char* prefix = NULL;
  
  array_t* lns = NULL;
	if (array_length (writer->local_namespaces) < writer->depth) {
    lns = array_new (sizeof (array_t*), 5);
    array_append (writer->local_namespaces, &lns);
  } else {
    lns = *(array_t**) array_get (writer->local_namespaces, writer->depth-1);
  }
  if (space != NULL) {
		prefix = stringpair_get (writer->namespaces, space);
    if (prefix == NULL) {
      prefix = empty_string;
      stringpair_set (&writer->namespaces, space, NULL);
      array_append (lns, &space);
		}
	}

  struct pair_t tag = { prefix, local};
  array_append (writer->tags, &tag);

  err = bufio_writer_write (writer->buf, 1, "<");
  if (err != 0) return err;
  
  if (prefix != NULL && prefix != empty_string) {
    err = bufio_writer_write (writer->buf, 2, prefix, ":");
    if (err != 0) return err;
  }
  err = bufio_writer_write (writer->buf, 1, local);
  if (err != 0) return err;
  
	writer->openStartTag = true;

  int i, len = array_length (lns);
  for (i = 0; i < len; i++) {
    const char** aspace = array_get (lns, i);
    const char* aprefix = stringpair_get (writer->namespaces, *aspace);
    err = bufio_writer_write (writer->buf, 1, " xmlns");
    if (err != 0) return err;

    if (aprefix != NULL && aprefix != empty_string) {
      err = bufio_writer_write (writer->buf, 2, ":", prefix);
      if (err != 0) return err;
    }

    err = bufio_writer_write (writer->buf, 3, "=\"", *aspace, "\"");
    if (err != 0) return err;
  }
  return 0;
}

int xmlwriter_simple_element (xmlwriter_t* writer, const char* space, const char* local,
                              const char* value) {
  if (writer == NULL)
    fatal ("xmlwriter_simple_element: writer is null");

  int err = 0;

  err = xmlwriter_start_element (writer, space, local);
  if (err != 0) return err;
  
  err = xmlwriter_text (writer, value);
  if (err != 0) return err;
  
  err = xmlwriter_end_element (writer);
	return err;
}

static int xmlwriter_escapetext (xmlwriter_t* writer, const char* text) {
  if (writer == NULL)
    fatal ("xmlwriter_escapetext: writer is null");

  char* esc;
  int last = 0;
  int i;

  int len = strlen (text);
  int err = 0;
  
  for (i = 0; i < len; ) {
    uint8_t ch = (uint8_t) text[i];
    int width = utf8_width (ch);
    if (width < 1)
      fatal ("xmlwriter_escapetext: width is less than 1");
        
    i += width;
    if (width == 1) {
      switch (ch) {
        case '"':
          esc = "&quot;"; break;
        case '\'':
          esc = "&apos;"; break;
        case '&':
          esc = "&amp;"; break;
        case '<':
          esc = "&lt;"; break;
        case '>':
          esc = "&gt;"; break;
        case '\t':
          esc = "#x9;"; break;
      case '\n':
        esc = "#xA;"; break;
        case '\r':
          esc = "#xD;"; break;
        default:
          // if !isInCharacterRange(r) || (r == 0xFFFD && width == 1) {
          // esc = esc_fffd;
          // break;
          // }
          continue;
        }
    } else {
        continue;
    }
    if (last < i - width) {
      err = bufio_writer_write_len (writer->buf, text + last, i - width - last);
      if (err != 0) return err;
    }
    err = bufio_writer_write (writer->buf, 1, esc);
    if (err != 0) return err;
    last = i;
  }
  if (last < len) {
    err = bufio_writer_write (writer->buf, 1, text + last);
    if (err != 0) return err;
  }
  return 0;
}

int xmlwriter_text (xmlwriter_t* writer, const char* text) {
  if (writer == NULL)
    fatal ("xmlwriter_text: writer is null");

  int err = 0;
  err = xmlwriter_close_start_element (writer);
  if (err != 0) return err;

  err = xmlwriter_escapetext (writer, text);
  
	return err;
}

int xmlwriter_base64 (xmlwriter_t* writer, const unsigned char* data, const int data_len) {
  if (writer == NULL)
    fatal ("xmlwriter_base64: writer is null");

	int err = xmlwriter_close_start_element (writer);
  if (err != 0) return err;

  static const char* encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  
  int len = data_len;
  unsigned char* ptr = (unsigned char*) data;

  while (len > 0) {
    uint8_t b0 = 0, b1 = 0, b2 = 0, b3 = 0;
    char dst[5] = {0,0,0,0,0};
    
    if (len > 2) {
      b3 = ptr[2] & 0x3F;
      b2 = ptr[2] >> 6;
    }
    if (len >= 2) {
      b2 |= (ptr[1] << 2) & 0x3F;
      b1 = ptr[1] >> 4;
    }
    if (len >= 1) {
      b1 |= (ptr[0] << 4) & 0x3F;
      b0 = ptr[0] >> 2;
    }

    dst[0] = encodeStd[b0];
    dst[1] = encodeStd[b1];
    dst[2] = encodeStd[b2];
    dst[3] = encodeStd[b3];

    if (len < 3) {
      dst[3] = '=';
      if (len < 2) {
        dst[2] = '=';
      }
    }

    err = bufio_writer_write (writer->buf, 1, dst);
    if (err != 0) return err;

    if (len < 3)
      break;

    ptr += 3;
    len -= 3;
  }
  return 0;
}

int xmlwriter_attribute (xmlwriter_t* writer, const char* space, const char* local,
                          const char* value) {
  if (writer == NULL)
    fatal ("xmlwriter_attribute: writer is null");
  
	if (!writer->openStartTag) {
    // error `attribute after ">"`
    return -1;
  }

  const char* prefix = NULL;
  if (space != NULL) {
    prefix = stringpair_get (writer->namespaces, space);
    if (prefix == NULL) {
      // error ("no prefix for namespace " + space)
      return -1;
    }
  }
  int err = 0;
  if (prefix != NULL && prefix != empty_string)
    err = bufio_writer_write (writer->buf, 5, " ", prefix, ":", local, "=\"");
  else
    err = bufio_writer_write(writer->buf, 3, " ", local, "=\"");
  if (err != 0) return err;
  
  err = xmlwriter_escapetext (writer, value);
  if (err != 0) return err;
  
  err = bufio_writer_write (writer->buf, 1, "\"");

	return err;
}

<file_sep>#ifndef _XMLWRITER_H_
#define _XMLWRITER_H_

#include <stdbool.h>
#include "stringpair.h"
#include "bufio.h"
#include "array.h"

extern const char* ns_xml;

typedef struct {
  bufio_writer_t* buf;
  stringpair_t* namespaces;
  bool openStartTag;
  array_t* local_namespaces;
  int depth;
  array_t* tags;
} xmlwriter_t;

void xmlwriter_init (xmlwriter_t* writer, int fd);
void xmlwriter_free (xmlwriter_t* writer);
void xmlwriter_reset (xmlwriter_t* writer);
int xmlwriter_set_prefix (xmlwriter_t* writer, const char* prefix, const char* uri);
void xmlwriter_unset_prefix (xmlwriter_t* writer, const char* prefix);
int xmlwriter_start_stream (xmlwriter_t* writer);
int xmlwriter_end_stream (xmlwriter_t* writer);
int xmlwriter_start_element (xmlwriter_t* writer, const char* stace, const char* local);
int xmlwriter_end_element (xmlwriter_t* writer);
int xmlwriter_flush (xmlwriter_t* writer);
int xmlwriter_simple_element (xmlwriter_t* writer, const char* space, const char* local, const char* value);
int xmlwriter_text (xmlwriter_t* writer, const char* text);
int xmlwriter_base64 (xmlwriter_t* writer, const unsigned char* data, const int data_len);
int xmlwriter_attribute (xmlwriter_t* writer, const char* space, const char* local, const char* value);


#endif
<file_sep>#ifndef _ERRORS_H_
#define _ERRORS_H_

#define ERR_IO_CLOSE -9
#define ERR_MALFORMED_UTF8 -10
#define ERR_MALFORMED_UNICODE -11
#define ERR_XML_SYNTAX -12
#define ERR_XML_UNKNOWN_VERSION -13
#define ERR_XML_UNKNOWN_ENCODING -14
#define ERR_EXTENSION_NOT_FOUND -15
#define ERR_BAD_PROTOCOL -16
#define ERR_XMPP_VERSION -17
#define ERR_SASL_NO_KNOWN_METHOD -18
#define ERR_XMPP_ERROR -19
#define ERR_SASL_NO_KNOWN_QOP_METHOD -20
#define ERR_SASL_SERVER_SIGNATURE_MISMATCH -21
#define ERR_BASE64_DECODE -22
#define ERR_SASL -23
#define ERR_XML_NAME_LENGTH_EXCEEDED -24
#define ERR_BUFIO_READER_END_OF_INPUT -25
#define ERR_STREAM_END -26
#define ERR_READ_CLOSE -27
#define ERR_READ_ERROR -28
#define ERR_FEATURE_IS_REQUIRED -29

#endif
<file_sep>#include "xep_iqlast_data.h"
#include "helpers.h"
#include "errors.h"

const char *ns_iqlast = "jabber:iq:last";

struct iqlast_last_t *
iqlast_last_decode (xmlreader_t * reader)
{
  struct iqlast_last_t *elm = NULL;
  elm = malloc (sizeof (struct iqlast_last_t));
  if (elm == NULL)
    fatal ("iqlast_last_t: malloc failed");
  memset (elm, 0, sizeof (struct iqlast_last_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "seconds");
  if (avalue != NULL)
    {
      elm->fSeconds = strconv_parse_uint (avalue);
    }
  const char *value = xmlreader_text (reader);
  if (reader->err != 0)
    return NULL;
  elm->fExtra = (char *) value;
  return elm;
}

int
iqlast_last_encode (xmlwriter_t * writer, struct iqlast_last_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_iqlast, "query");
  if (err != 0)
    return err;
  if (elm->fSeconds != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "seconds",
			     strconv_format_uint (elm->fSeconds));
      if (err != 0)
	return err;
    }
  if (elm->fExtra != NULL)
    {
      err = xmlwriter_text (writer, elm->fExtra);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
iqlast_last_free (struct iqlast_last_t *data)
{
  if (data == NULL)
    return;
  if (data->fSeconds != NULL)
    {
      free (data->fSeconds);
    }
  if (data->fExtra != NULL)
    {
      free (data->fExtra);
    }
  free (data);
}
<file_sep>#include "sasl_data.h"
#include "helpers.h"
#include "errors.h"

const char *ns_sasl = "urn:ietf:params:xml:ns:xmpp-sasl";

struct sasl_mechanisms_t *
sasl_mechanisms_decode (xmlreader_t * reader)
{
  struct sasl_mechanisms_t *elm = NULL;
  elm = malloc (sizeof (struct sasl_mechanisms_t));
  if (elm == NULL)
    fatal ("sasl_mechanisms_t: malloc failed");
  memset (elm, 0, sizeof (struct sasl_mechanisms_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "mechanism") == 0)
	      && (strcmp (namespace, ns_sasl) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      if (elm->fMechanism == NULL)
		elm->fMechanism = array_new (sizeof (char *), 0);
	      array_append (elm->fMechanism, (void *) &value);
	    }
	}
    }
  return elm;
}

int
sasl_mechanisms_encode (xmlwriter_t * writer, struct sasl_mechanisms_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_sasl, "mechanisms");
  if (err != 0)
    return err;
  int len = array_length (elm->fMechanism);
  int i = 0;
  for (i = 0; i < len; i++)
    {
      char **value = array_get (elm->fMechanism, i);
      err =
	xmlwriter_simple_element (writer, ns_sasl, "mechanism",
				  (char *) value);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
sasl_mechanisms_free (struct sasl_mechanisms_t *data)
{
  if (data == NULL)
    return;
  int len = array_length (data->fMechanism);
  int i = 0;
  for (i = 0; i < len; i++)
    {
      char **value = array_get (data->fMechanism, i);
      free (*value);
    }
  array_free (data->fMechanism);
  free (data);
}

struct sasl_auth_t *
sasl_auth_decode (xmlreader_t * reader)
{
  struct sasl_auth_t *elm = NULL;
  elm = malloc (sizeof (struct sasl_auth_t));
  if (elm == NULL)
    fatal ("sasl_auth_t: malloc failed");
  memset (elm, 0, sizeof (struct sasl_auth_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "mechanism");
  if (avalue != NULL)
    {
      elm->fMechanism = (char *) avalue;
    }
  if (xmlreader_base64 (reader, &elm->fData, &elm->fData_len) != 0)
    return NULL;
  return elm;
}

int
sasl_auth_encode (xmlwriter_t * writer, struct sasl_auth_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_sasl, "auth");
  if (err != 0)
    return err;
  if (elm->fMechanism != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "mechanism", elm->fMechanism);
      if (err != 0)
	return err;
    }
  if (elm->fData != NULL)
    {
      err = xmlwriter_base64 (writer, elm->fData, elm->fData_len);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
sasl_auth_free (struct sasl_auth_t *data)
{
  if (data == NULL)
    return;
  if (data->fMechanism != NULL)
    {
      free (data->fMechanism);
    }
  if (data->fData != NULL)
    {
      free (data->fData);
    }
  free (data);
}

struct sasl_success_t *
sasl_success_decode (xmlreader_t * reader)
{
  struct sasl_success_t *elm = NULL;
  elm = malloc (sizeof (struct sasl_success_t));
  if (elm == NULL)
    fatal ("sasl_success_t: malloc failed");
  memset (elm, 0, sizeof (struct sasl_success_t));
  if (xmlreader_base64 (reader, &elm->fData, &elm->fData_len) != 0)
    return NULL;
  return elm;
}

int
sasl_success_encode (xmlwriter_t * writer, struct sasl_success_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_sasl, "success");
  if (err != 0)
    return err;
  if (elm->fData != NULL)
    {
      err = xmlwriter_base64 (writer, elm->fData, elm->fData_len);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
sasl_success_free (struct sasl_success_t *data)
{
  if (data == NULL)
    return;
  if (data->fData != NULL)
    {
      free (data->fData);
    }
  free (data);
}

struct sasl_challenge_t *
sasl_challenge_decode (xmlreader_t * reader)
{
  struct sasl_challenge_t *elm = NULL;
  elm = malloc (sizeof (struct sasl_challenge_t));
  if (elm == NULL)
    fatal ("sasl_challenge_t: malloc failed");
  memset (elm, 0, sizeof (struct sasl_challenge_t));
  if (xmlreader_base64 (reader, &elm->fData, &elm->fData_len) != 0)
    return NULL;
  return elm;
}

int
sasl_challenge_encode (xmlwriter_t * writer, struct sasl_challenge_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_sasl, "challenge");
  if (err != 0)
    return err;
  if (elm->fData != NULL)
    {
      err = xmlwriter_base64 (writer, elm->fData, elm->fData_len);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
sasl_challenge_free (struct sasl_challenge_t *data)
{
  if (data == NULL)
    return;
  if (data->fData != NULL)
    {
      free (data->fData);
    }
  free (data);
}

struct sasl_response_t *
sasl_response_decode (xmlreader_t * reader)
{
  struct sasl_response_t *elm = NULL;
  elm = malloc (sizeof (struct sasl_response_t));
  if (elm == NULL)
    fatal ("sasl_response_t: malloc failed");
  memset (elm, 0, sizeof (struct sasl_response_t));
  if (xmlreader_base64 (reader, &elm->fData, &elm->fData_len) != 0)
    return NULL;
  return elm;
}

int
sasl_response_encode (xmlwriter_t * writer, struct sasl_response_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_sasl, "response");
  if (err != 0)
    return err;
  if (elm->fData != NULL)
    {
      err = xmlwriter_base64 (writer, elm->fData, elm->fData_len);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
sasl_response_free (struct sasl_response_t *data)
{
  if (data == NULL)
    return;
  if (data->fData != NULL)
    {
      free (data->fData);
    }
  free (data);
}

struct sasl_failure_t *
sasl_failure_decode (xmlreader_t * reader)
{
  struct sasl_failure_t *elm = NULL;
  elm = malloc (sizeof (struct sasl_failure_t));
  if (elm == NULL)
    fatal ("sasl_failure_t: malloc failed");
  memset (elm, 0, sizeof (struct sasl_failure_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "text") == 0)
	      && (strcmp (namespace, ns_sasl) == 0))
	    {
	      langstring_decode (reader, elm->fText);
	    }
	  else if (strcmp (namespace, ns_sasl) != 0)
	    {
	      elm->fCondition =
		enum_sasl_failure_condition_from_string (name);
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	    }
	}
    }
  return elm;
}

int
sasl_failure_encode (xmlwriter_t * writer, struct sasl_failure_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_sasl, "failure");
  if (err != 0)
    return err;
  if (elm->fText != NULL)
    {
      err = langstring_encode (writer, ns_sasl, "text", elm->fText);
      if (err != 0)
	return err;
    }
  if (elm->fCondition != 0)
    {
      const char *name =
	enum_sasl_failure_condition_to_string (elm->fCondition);
      err = xmlwriter_simple_element (writer, ns_sasl, name, NULL);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
sasl_failure_free (struct sasl_failure_t *data)
{
  if (data == NULL)
    return;
  if (data->fText != NULL)
    {
      langstring_free (data->fText);
    }
  if (data->fCondition != 0)
    {
    }
  free (data);
}

enum sasl_failure_condition_t
enum_sasl_failure_condition_from_string (const char *value)
{
  if (strcmp (value, "aborted") == 0)
    return SASL_FAILURE_CONDITION_ABORTED;
  else if (strcmp (value, "account-disabled") == 0)
    return SASL_FAILURE_CONDITION_ACCOUNT_DISABLED;
  else if (strcmp (value, "credentials-expired") == 0)
    return SASL_FAILURE_CONDITION_CREDENTIALS_EXPIRED;
  else if (strcmp (value, "encryption-required") == 0)
    return SASL_FAILURE_CONDITION_ENCRYPTION_REQUIRED;
  else if (strcmp (value, "incorrect-encoding") == 0)
    return SASL_FAILURE_CONDITION_INCORRECT_ENCODING;
  else if (strcmp (value, "invalid-authzid") == 0)
    return SASL_FAILURE_CONDITION_INVALID_AUTHZID;
  else if (strcmp (value, "invalid-mechanism") == 0)
    return SASL_FAILURE_CONDITION_INVALID_MECHANISM;
  else if (strcmp (value, "malformed-request") == 0)
    return SASL_FAILURE_CONDITION_MALFORMED_REQUEST;
  else if (strcmp (value, "mechanism-too-weak") == 0)
    return SASL_FAILURE_CONDITION_MECHANISM_TOO_WEAK;
  else if (strcmp (value, "not-authorized") == 0)
    return SASL_FAILURE_CONDITION_NOT_AUTHORIZED;
  else if (strcmp (value, "temporary-auth-failure") == 0)
    return SASL_FAILURE_CONDITION_TEMPORARY_AUTH_FAILURE;
  else if (strcmp (value, "transition-needed") == 0)
    return SASL_FAILURE_CONDITION_TRANSITION_NEEDED;
  return 0;
}

const char *
enum_sasl_failure_condition_to_string (enum sasl_failure_condition_t value)
{
  switch (value)
    {
    case SASL_FAILURE_CONDITION_ABORTED:
      return "aborted";
    case SASL_FAILURE_CONDITION_ACCOUNT_DISABLED:
      return "account-disabled";
    case SASL_FAILURE_CONDITION_CREDENTIALS_EXPIRED:
      return "credentials-expired";
    case SASL_FAILURE_CONDITION_ENCRYPTION_REQUIRED:
      return "encryption-required";
    case SASL_FAILURE_CONDITION_INCORRECT_ENCODING:
      return "incorrect-encoding";
    case SASL_FAILURE_CONDITION_INVALID_AUTHZID:
      return "invalid-authzid";
    case SASL_FAILURE_CONDITION_INVALID_MECHANISM:
      return "invalid-mechanism";
    case SASL_FAILURE_CONDITION_MALFORMED_REQUEST:
      return "malformed-request";
    case SASL_FAILURE_CONDITION_MECHANISM_TOO_WEAK:
      return "mechanism-too-weak";
    case SASL_FAILURE_CONDITION_NOT_AUTHORIZED:
      return "not-authorized";
    case SASL_FAILURE_CONDITION_TEMPORARY_AUTH_FAILURE:
      return "temporary-auth-failure";
    case SASL_FAILURE_CONDITION_TRANSITION_NEEDED:
      return "transition-needed";
    }
  return NULL;
}
<file_sep>#ifndef _XEP_IQTIME_DATA_H_
#define  _XEP_IQTIME_DATA_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <string.h>
#include "xstream.h"
#include "types.h"


extern const char *ns_iqtime;


struct iqtime_time_t
{
  char *fUtc;
  char *fTz;
  char *fDisplay;
};


struct iqtime_time_t *iqtime_time_decode (xmlreader_t * reader);
int iqtime_time_encode (xmlwriter_t * writer, struct iqtime_time_t *data);
void iqtime_time_free (struct iqtime_time_t *data);
#endif
<file_sep>#include "xep_iqregister_data.h"
#include "helpers.h"
#include "errors.h"

const char *ns_iqregister = "jabber:iq:register";

struct iqregister_query_t *
iqregister_query_decode (xmlreader_t * reader)
{
  struct iqregister_query_t *elm = NULL;
  elm = malloc (sizeof (struct iqregister_query_t));
  if (elm == NULL)
    fatal ("iqregister_query_t: malloc failed");
  memset (elm, 0, sizeof (struct iqregister_query_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (namespace, ns_iqregister) == 0)
	      && (strcmp (name, "registered") == 0))
	    {
	      if (xmlreader_skip_element (reader) == 1)
		return NULL;
	    }
	  else if ((strcmp (namespace, ns_iqregister) == 0)
		   && (strcmp (name, "instructions") == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fFields.fInstructions = (char *) value;
	    }
	  else if ((strcmp (namespace, ns_iqregister) == 0)
		   && (strcmp (name, "username") == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fFields.fUsername = (char *) value;
	    }
	  else if ((strcmp (namespace, ns_iqregister) == 0)
		   && (strcmp (name, "nick") == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fFields.fNick = (char *) value;
	    }
	  else if ((strcmp (namespace, ns_iqregister) == 0)
		   && (strcmp (name, "password") == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fFields.fPassword = (char *) value;
	    }
	  else if ((strcmp (namespace, ns_iqregister) == 0)
		   && (strcmp (name, "name") == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fFields.fName = (char *) value;
	    }
	  else if ((strcmp (namespace, ns_iqregister) == 0)
		   && (strcmp (name, "first") == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fFields.fFirst = (char *) value;
	    }
	  else if ((strcmp (namespace, ns_iqregister) == 0)
		   && (strcmp (name, "last") == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fFields.fLast = (char *) value;
	    }
	  else if ((strcmp (namespace, ns_iqregister) == 0)
		   && (strcmp (name, "email") == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fFields.fEmail = (char *) value;
	    }
	  else if ((strcmp (namespace, ns_iqregister) == 0)
		   && (strcmp (name, "address") == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fFields.fAddress = (char *) value;
	    }
	  else if ((strcmp (namespace, ns_iqregister) == 0)
		   && (strcmp (name, "city") == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fFields.fCity = (char *) value;
	    }
	  else if ((strcmp (namespace, ns_iqregister) == 0)
		   && (strcmp (name, "state") == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fFields.fState = (char *) value;
	    }
	  else if ((strcmp (namespace, ns_iqregister) == 0)
		   && (strcmp (name, "zip") == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fFields.fZip = (char *) value;
	    }
	  else if ((strcmp (namespace, ns_iqregister) == 0)
		   && (strcmp (name, "phone") == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fFields.fPhone = (char *) value;
	    }
	  else if ((strcmp (namespace, ns_iqregister) == 0)
		   && (strcmp (name, "url") == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fFields.fUrl = (char *) value;
	    }
	  else if ((strcmp (namespace, ns_iqregister) == 0)
		   && (strcmp (name, "date") == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fFields.fDate = (char *) value;
	    }
	  else if ((strcmp (namespace, ns_iqregister) == 0)
		   && (strcmp (name, "misc") == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fFields.fMisc = (char *) value;
	    }
	  else if ((strcmp (namespace, ns_iqregister) == 0)
		   && (strcmp (name, "text") == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fFields.fText = (char *) value;
	    }
	  else if ((strcmp (namespace, ns_iqregister) == 0)
		   && (strcmp (name, "key") == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fFields.fKey = (char *) value;
	    }
	  else if ((strcmp (name, "remove") == 0)
		   && (strcmp (namespace, ns_iqregister) == 0))
	    {
	      elm->fRemove = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (namespace, "jabber:x:data") == 0)
		   && (strcmp (name, "x") == 0))
	    {
	      struct xdata_x_t *newel = xdata_x_decode (reader);
	      if (newel == NULL)
		{
		  return NULL;
		}
	      elm->fXdata = newel;
	    }
	  else if ((strcmp (namespace, "jabber:x:oob") == 0)
		   && (strcmp (name, "x") == 0))
	    {
	      struct xoob_x_t *newel = xoob_x_decode (reader);
	      if (newel == NULL)
		{
		  return NULL;
		}
	      elm->fXoob = newel;
	    }
	}
    }
  return elm;
}

int
iqregister_query_encode (xmlwriter_t * writer, struct iqregister_query_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_iqregister, "query");
  if (err != 0)
    return err;
  if (elm->fFields.fRegistered)
    {
      err =
	xmlwriter_simple_element (writer, ns_iqregister, "registered", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fFields.fInstructions != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_iqregister, "instructions",
				  elm->fFields.fInstructions);
      if (err != 0)
	return err;
    }
  if (elm->fFields.fUsername != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_iqregister, "username",
				  elm->fFields.fUsername);
      if (err != 0)
	return err;
    }
  if (elm->fFields.fNick != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_iqregister, "nick",
				  elm->fFields.fNick);
      if (err != 0)
	return err;
    }
  if (elm->fFields.fPassword != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_iqregister, "password",
				  elm->fFields.fPassword);
      if (err != 0)
	return err;
    }
  if (elm->fFields.fName != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_iqregister, "name",
				  elm->fFields.fName);
      if (err != 0)
	return err;
    }
  if (elm->fFields.fFirst != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_iqregister, "first",
				  elm->fFields.fFirst);
      if (err != 0)
	return err;
    }
  if (elm->fFields.fLast != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_iqregister, "last",
				  elm->fFields.fLast);
      if (err != 0)
	return err;
    }
  if (elm->fFields.fEmail != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_iqregister, "email",
				  elm->fFields.fEmail);
      if (err != 0)
	return err;
    }
  if (elm->fFields.fAddress != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_iqregister, "address",
				  elm->fFields.fAddress);
      if (err != 0)
	return err;
    }
  if (elm->fFields.fCity != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_iqregister, "city",
				  elm->fFields.fCity);
      if (err != 0)
	return err;
    }
  if (elm->fFields.fState != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_iqregister, "state",
				  elm->fFields.fState);
      if (err != 0)
	return err;
    }
  if (elm->fFields.fZip != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_iqregister, "zip",
				  elm->fFields.fZip);
      if (err != 0)
	return err;
    }
  if (elm->fFields.fPhone != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_iqregister, "phone",
				  elm->fFields.fPhone);
      if (err != 0)
	return err;
    }
  if (elm->fFields.fUrl != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_iqregister, "url",
				  elm->fFields.fUrl);
      if (err != 0)
	return err;
    }
  if (elm->fFields.fDate != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_iqregister, "date",
				  elm->fFields.fDate);
      if (err != 0)
	return err;
    }
  if (elm->fFields.fMisc != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_iqregister, "misc",
				  elm->fFields.fMisc);
      if (err != 0)
	return err;
    }
  if (elm->fFields.fText != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_iqregister, "text",
				  elm->fFields.fText);
      if (err != 0)
	return err;
    }
  if (elm->fFields.fKey != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_iqregister, "key",
				  elm->fFields.fKey);
      if (err != 0)
	return err;
    }
  if (elm->fRemove)
    {
      err = xmlwriter_simple_element (writer, ns_iqregister, "remove", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fXdata != NULL)
    {
      err = xdata_x_encode (writer, elm->fXdata);
      if (err != 0)
	return err;
    }
  if (elm->fXoob != NULL)
    {
      err = xoob_x_encode (writer, elm->fXoob);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
iqregister_query_free (struct iqregister_query_t *data)
{
  if (data == NULL)
    return;
  if (data->fFields.fRegistered)
    {
    }
  if (data->fFields.fInstructions != NULL)
    {
      free (data->fFields.fInstructions);
    }
  if (data->fFields.fUsername != NULL)
    {
      free (data->fFields.fUsername);
    }
  if (data->fFields.fNick != NULL)
    {
      free (data->fFields.fNick);
    }
  if (data->fFields.fPassword != NULL)
    {
      free (data->fFields.fPassword);
    }
  if (data->fFields.fName != NULL)
    {
      free (data->fFields.fName);
    }
  if (data->fFields.fFirst != NULL)
    {
      free (data->fFields.fFirst);
    }
  if (data->fFields.fLast != NULL)
    {
      free (data->fFields.fLast);
    }
  if (data->fFields.fEmail != NULL)
    {
      free (data->fFields.fEmail);
    }
  if (data->fFields.fAddress != NULL)
    {
      free (data->fFields.fAddress);
    }
  if (data->fFields.fCity != NULL)
    {
      free (data->fFields.fCity);
    }
  if (data->fFields.fState != NULL)
    {
      free (data->fFields.fState);
    }
  if (data->fFields.fZip != NULL)
    {
      free (data->fFields.fZip);
    }
  if (data->fFields.fPhone != NULL)
    {
      free (data->fFields.fPhone);
    }
  if (data->fFields.fUrl != NULL)
    {
      free (data->fFields.fUrl);
    }
  if (data->fFields.fDate != NULL)
    {
      free (data->fFields.fDate);
    }
  if (data->fFields.fMisc != NULL)
    {
      free (data->fFields.fMisc);
    }
  if (data->fFields.fText != NULL)
    {
      free (data->fFields.fText);
    }
  if (data->fFields.fKey != NULL)
    {
      free (data->fFields.fKey);
    }
  if (data->fRemove)
    {
    }
  if (data->fXdata != NULL)
    {
      xdata_x_free (data->fXdata);
    }
  if (data->fXoob != NULL)
    {
      xoob_x_free (data->fXoob);
    }
  free (data);
}
<file_sep>#ifndef _XEP_TIME_DATA_H_
#define  _XEP_TIME_DATA_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <string.h>
#include "xstream.h"
#include "types.h"


extern const char *ns_time;


struct time_time_t
{
  char *fTz;
  char *fUtc;
};


struct time_time_t *time_time_decode (xmlreader_t * reader);
int time_time_encode (xmlwriter_t * writer, struct time_time_t *data);
void time_time_free (struct time_time_t *data);
#endif
<file_sep>#include "xmppdata/bind_data.h"
#include "iq.h"
#include "errors.h"
#include "xmppdata/extensions.h"

bool bind_is_mandatory (stream_t* strm) {
  return true;
}

bool bind_need_restart (void) {
  return false;
}

int bind_negotate (stream_t* strm, account_t* account, void** data, extension_t* ext) {
  switch (ext->type) {
  case EXTENSION_TYPE_BIND_BIND: {
    struct bind_bind_t bind = {NULL, NULL};
    if (account->jid->resource != NULL)
      bind.fResource = account->jid->resource;

    jid_t* to = jid_of_string (account->jid->domain);
    iq_t* iq = iq_new (strm, NULL, to, CLIENT_IQ_TYPE_SET, &bind,
                     EXTENSION_TYPE_BIND_BIND);
    int err = client_iq_encode (&strm->writer, iq);
    if (err != 0) return err;
    jid_free (iq->fTo);
    iq_free (iq);
    
    err = xmlwriter_flush (&strm->writer);
    if (err != 0) return err;
    return 1;
  }
    
  case EXTENSION_TYPE_CLIENT_IQ: {
    iq_t* iq = ext->data;
    if (iq->fType == CLIENT_IQ_TYPE_RESULT) {
      if (iq->fPayload != NULL && iq->fPayload->type == EXTENSION_TYPE_BIND_BIND) {
        struct bind_bind_t* bind = iq->fPayload->data;
        if (bind->fJid != NULL) {
          strm->jid = bind->fJid;
          bind->fJid = NULL;
          return 0;
        } else
          return ERR_BAD_PROTOCOL;
      }
    }
    return ERR_BAD_PROTOCOL;
  }

  case EXTENSION_TYPE_STREAM_ERROR: {
    extension_t* error = malloc (sizeof (extension_t));
    memcpy (error, &ext, sizeof (extension_t));
    strm->xmpp_error = error;
    return ERR_XMPP_ERROR;
  }
  }
  return ERR_BAD_PROTOCOL;
}

struct stream_feature_t bind_feature = {
  EXTENSION_TYPE_BIND_BIND,
  bind_is_mandatory,
  bind_need_restart,
  bind_negotate
};
<file_sep>#include <malloc.h>
#include <string.h>
#include <string.h>
#include "jid.h"
#include "helpers.h"
#include "xmpp_prep.h"

jid_t *jid_of_string (const char *str) {
  char* node = NULL;
  char* domain = NULL;
  char* resource = NULL;
  
  int len = strlen (str);
  char* end = NULL;
  
  end = strchr (str, '/');
  if (end != NULL) {
    if (*(end+1) != '\0')
      resource = strdup (end+1);
  } else
    end = str+len;

  char* at = memchr (str, '@', end - str);
  if (at != NULL) {
    node = strndup (str, at - str);
    domain = strndup (at+1, end - at - 1);
  } else
    domain = strndup (str, end - str);

  jid_t *jid = malloc (sizeof (jid_t));
  if (jid == NULL)
    fatal ("jid_of_string: malloc failed");
  
  jid->node = node;
  jid->domain = domain;
  jid->resource = resource;
  jid->full = NULL;;

  return jid;
}


void jid_free (jid_t *jid) {
  if (jid == NULL)
    return;

  if (jid->node != NULL)
    free (jid->node);

  if (jid->domain != NULL)
    free (jid->domain);

  if (jid->resource != NULL)
    free (jid->resource);

  if (jid->full != NULL)
    free (jid->full);

  free (jid);
}

char* jid_to_string (jid_t *jid) {
  if (jid == NULL)
    fatal ("jid_to_string is null");
  
  if (jid->full != NULL)
    return jid->full;
  int len_domain = strlen (jid->domain);
  int len_node = 0, len_resource = 0;

  if (jid->node != NULL)
    len_node = strlen (jid->node) + 1;
  if (jid->resource != NULL)
    len_resource = strlen (jid->resource) + 1;
      
  jid->full = malloc (sizeof (char) * (len_domain + len_node + len_resource + 1));
  if (jid->full == NULL)
    fatal ("jid_to_string: malloc failed");

  if (jid->node != NULL) {
    strcpy (jid->full, jid->node);
    jid->full[len_node - 1] = '@';
  }

  strcpy (jid->full + len_node, jid->domain);

  if (jid->resource != NULL) {
    jid->full [len_node + len_domain] = '/';
    strcpy (jid->full + len_node + len_domain + 1, jid->resource);
  }
  jid->full[len_node + len_domain + len_resource] = '\0';

  return jid->full;
}

int jid_resourceprep (const char* str, char** result) {
  ustring_t ustring = { NULL, 0};
  int err = ustring_decode_utf8 (&ustring, str, strlen (str));
  if (err != 0) return err;
  resourceprep (&ustring);

  err = ustring_encode_utf8 (&ustring, result);
  if (err < 0) return err;

  return 0;
}
<file_sep>#ifndef _XEP_CAPS_DATA_H_
#define  _XEP_CAPS_DATA_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <string.h>
#include "xstream.h"
#include "types.h"


extern const char *ns_caps;


struct caps_caps_t
{
  char *fExt;
  char *fHash;
  char *fNode;
  char *fVer;
};


struct caps_caps_t *caps_caps_decode (xmlreader_t * reader);
int caps_caps_encode (xmlwriter_t * writer, struct caps_caps_t *data);
void caps_caps_free (struct caps_caps_t *data);
#endif
<file_sep>#include "stanza_data.h"
#include "helpers.h"
#include "errors.h"

const char *ns_stanza = "urn:ietf:params:xml:ns:xmpp-stanzas";

struct stanza_error_t *
stanza_error_decode (xmlreader_t * reader)
{
  struct stanza_error_t *elm = NULL;
  elm = malloc (sizeof (struct stanza_error_t));
  if (elm == NULL)
    fatal ("stanza_error_t: malloc failed");
  memset (elm, 0, sizeof (struct stanza_error_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "text") == 0)
	      && (strcmp (namespace, ns_stanza) == 0))
	    {
	      langstring_decode (reader, elm->fText);
	    }
	  else if (strcmp (namespace, ns_stanza) != 0)
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fCondition.fExtra = (char *) value;
	    }
	}
    }
  return elm;
}

int
stanza_error_encode (xmlwriter_t * writer, struct stanza_error_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_stanza, "error");
  if (err != 0)
    return err;
  if (elm->fText != NULL)
    {
      err = langstring_encode (writer, ns_stanza, "text", elm->fText);
      if (err != 0)
	return err;
    }
  const char *name =
    enum_stanza_error_condition_name_to_string (elm->fCondition.fName);
  err = xmlwriter_start_element (writer, ns_stanza, name);
  if (err != 0)
    return err;
  if (elm->fCondition.fExtra != NULL)
    {
      err = xmlwriter_text (writer, elm->fCondition.fExtra);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
stanza_error_free (struct stanza_error_t *data)
{
  if (data == NULL)
    return;
  if (data->fText != NULL)
    {
      langstring_free (data->fText);
    }
  if (data->fCondition.fExtra != NULL)
    {
      free (data->fCondition.fExtra);
    }
  free (data);
}

enum stanza_error_condition_name_t
enum_stanza_error_condition_name_from_string (const char *value)
{
  if (strcmp (value, "bad-request") == 0)
    return STANZA_ERROR_CONDITION_NAME_BAD_REQUEST;
  else if (strcmp (value, "conflict") == 0)
    return STANZA_ERROR_CONDITION_NAME_CONFLICT;
  else if (strcmp (value, "feature-not-implemented") == 0)
    return STANZA_ERROR_CONDITION_NAME_FEATURE_NOT_IMPLEMENTED;
  else if (strcmp (value, "forbidden") == 0)
    return STANZA_ERROR_CONDITION_NAME_FORBIDDEN;
  else if (strcmp (value, "gone") == 0)
    return STANZA_ERROR_CONDITION_NAME_GONE;
  else if (strcmp (value, "internal-server-error") == 0)
    return STANZA_ERROR_CONDITION_NAME_INTERNAL_SERVER_ERROR;
  else if (strcmp (value, "item-not-found") == 0)
    return STANZA_ERROR_CONDITION_NAME_ITEM_NOT_FOUND;
  else if (strcmp (value, "jid-malformed") == 0)
    return STANZA_ERROR_CONDITION_NAME_JID_MALFORMED;
  else if (strcmp (value, "not-acceptable") == 0)
    return STANZA_ERROR_CONDITION_NAME_NOT_ACCEPTABLE;
  else if (strcmp (value, "not-allowed") == 0)
    return STANZA_ERROR_CONDITION_NAME_NOT_ALLOWED;
  else if (strcmp (value, "not-authorized") == 0)
    return STANZA_ERROR_CONDITION_NAME_NOT_AUTHORIZED;
  else if (strcmp (value, "payment-required") == 0)
    return STANZA_ERROR_CONDITION_NAME_PAYMENT_REQUIRED;
  else if (strcmp (value, "policy-violation") == 0)
    return STANZA_ERROR_CONDITION_NAME_POLICY_VIOLATION;
  else if (strcmp (value, "recipient-unavailable") == 0)
    return STANZA_ERROR_CONDITION_NAME_RECIPIENT_UNAVAILABLE;
  else if (strcmp (value, "redirect") == 0)
    return STANZA_ERROR_CONDITION_NAME_REDIRECT;
  else if (strcmp (value, "registration-required") == 0)
    return STANZA_ERROR_CONDITION_NAME_REGISTRATION_REQUIRED;
  else if (strcmp (value, "remote-server-not-found") == 0)
    return STANZA_ERROR_CONDITION_NAME_REMOTE_SERVER_NOT_FOUND;
  else if (strcmp (value, "remote-server-timeout") == 0)
    return STANZA_ERROR_CONDITION_NAME_REMOTE_SERVER_TIMEOUT;
  else if (strcmp (value, "resource-constraint") == 0)
    return STANZA_ERROR_CONDITION_NAME_RESOURCE_CONSTRAINT;
  else if (strcmp (value, "service-unavailable") == 0)
    return STANZA_ERROR_CONDITION_NAME_SERVICE_UNAVAILABLE;
  else if (strcmp (value, "subscription-required") == 0)
    return STANZA_ERROR_CONDITION_NAME_SUBSCRIPTION_REQUIRED;
  else if (strcmp (value, "undefined-condition") == 0)
    return STANZA_ERROR_CONDITION_NAME_UNDEFINED_CONDITION;
  else if (strcmp (value, "unexpected-request") == 0)
    return STANZA_ERROR_CONDITION_NAME_UNEXPECTED_REQUEST;
  return 0;
}

const char *
enum_stanza_error_condition_name_to_string (enum stanza_error_condition_name_t
					    value)
{
  switch (value)
    {
    case STANZA_ERROR_CONDITION_NAME_BAD_REQUEST:
      return "bad-request";
    case STANZA_ERROR_CONDITION_NAME_CONFLICT:
      return "conflict";
    case STANZA_ERROR_CONDITION_NAME_FEATURE_NOT_IMPLEMENTED:
      return "feature-not-implemented";
    case STANZA_ERROR_CONDITION_NAME_FORBIDDEN:
      return "forbidden";
    case STANZA_ERROR_CONDITION_NAME_GONE:
      return "gone";
    case STANZA_ERROR_CONDITION_NAME_INTERNAL_SERVER_ERROR:
      return "internal-server-error";
    case STANZA_ERROR_CONDITION_NAME_ITEM_NOT_FOUND:
      return "item-not-found";
    case STANZA_ERROR_CONDITION_NAME_JID_MALFORMED:
      return "jid-malformed";
    case STANZA_ERROR_CONDITION_NAME_NOT_ACCEPTABLE:
      return "not-acceptable";
    case STANZA_ERROR_CONDITION_NAME_NOT_ALLOWED:
      return "not-allowed";
    case STANZA_ERROR_CONDITION_NAME_NOT_AUTHORIZED:
      return "not-authorized";
    case STANZA_ERROR_CONDITION_NAME_PAYMENT_REQUIRED:
      return "payment-required";
    case STANZA_ERROR_CONDITION_NAME_POLICY_VIOLATION:
      return "policy-violation";
    case STANZA_ERROR_CONDITION_NAME_RECIPIENT_UNAVAILABLE:
      return "recipient-unavailable";
    case STANZA_ERROR_CONDITION_NAME_REDIRECT:
      return "redirect";
    case STANZA_ERROR_CONDITION_NAME_REGISTRATION_REQUIRED:
      return "registration-required";
    case STANZA_ERROR_CONDITION_NAME_REMOTE_SERVER_NOT_FOUND:
      return "remote-server-not-found";
    case STANZA_ERROR_CONDITION_NAME_REMOTE_SERVER_TIMEOUT:
      return "remote-server-timeout";
    case STANZA_ERROR_CONDITION_NAME_RESOURCE_CONSTRAINT:
      return "resource-constraint";
    case STANZA_ERROR_CONDITION_NAME_SERVICE_UNAVAILABLE:
      return "service-unavailable";
    case STANZA_ERROR_CONDITION_NAME_SUBSCRIPTION_REQUIRED:
      return "subscription-required";
    case STANZA_ERROR_CONDITION_NAME_UNDEFINED_CONDITION:
      return "undefined-condition";
    case STANZA_ERROR_CONDITION_NAME_UNEXPECTED_REQUEST:
      return "unexpected-request";
    }
  return NULL;
}
<file_sep>CFLAGS=-Wall -ggdb `pkg-config --cflags yaml-0.1 openssl` -I src
LDFLAGS=-lresolv `pkg-config --libs yaml-0.1 openssl`

SOURCES=$(wildcard src/**/*.c src/*.c) 
OBJECTS=$(patsubst %.c,%.o,$(SOURCES))

TARGET=jru

all: $(TARGET)

$(TARGET): $(OBJECTS)
	$(CC) $(LDFLAGS) $(OBJECTS) -o $@

.c.0:
	$(CC) $(CFLAGS) $< -o $@

clean:
	rm -f $(OBJECTS) $(TARGET)

<file_sep>#ifndef _STANZA_DATA_H_
#define  _STANZA_DATA_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <string.h>
#include "xstream.h"
#include "types.h"


extern const char *ns_stanza;

enum stanza_error_condition_name_t
{
  STANZA_ERROR_CONDITION_NAME_BAD_REQUEST,
  STANZA_ERROR_CONDITION_NAME_CONFLICT,
  STANZA_ERROR_CONDITION_NAME_FEATURE_NOT_IMPLEMENTED,
  STANZA_ERROR_CONDITION_NAME_FORBIDDEN,
  STANZA_ERROR_CONDITION_NAME_GONE,
  STANZA_ERROR_CONDITION_NAME_INTERNAL_SERVER_ERROR,
  STANZA_ERROR_CONDITION_NAME_ITEM_NOT_FOUND,
  STANZA_ERROR_CONDITION_NAME_JID_MALFORMED,
  STANZA_ERROR_CONDITION_NAME_NOT_ACCEPTABLE,
  STANZA_ERROR_CONDITION_NAME_NOT_ALLOWED,
  STANZA_ERROR_CONDITION_NAME_NOT_AUTHORIZED,
  STANZA_ERROR_CONDITION_NAME_PAYMENT_REQUIRED,
  STANZA_ERROR_CONDITION_NAME_POLICY_VIOLATION,
  STANZA_ERROR_CONDITION_NAME_RECIPIENT_UNAVAILABLE,
  STANZA_ERROR_CONDITION_NAME_REDIRECT,
  STANZA_ERROR_CONDITION_NAME_REGISTRATION_REQUIRED,
  STANZA_ERROR_CONDITION_NAME_REMOTE_SERVER_NOT_FOUND,
  STANZA_ERROR_CONDITION_NAME_REMOTE_SERVER_TIMEOUT,
  STANZA_ERROR_CONDITION_NAME_RESOURCE_CONSTRAINT,
  STANZA_ERROR_CONDITION_NAME_SERVICE_UNAVAILABLE,
  STANZA_ERROR_CONDITION_NAME_SUBSCRIPTION_REQUIRED,
  STANZA_ERROR_CONDITION_NAME_UNDEFINED_CONDITION,
  STANZA_ERROR_CONDITION_NAME_UNEXPECTED_REQUEST,
};

enum stanza_error_condition_name_t
enum_stanza_error_condition_name_from_string (const char *value);
const char *enum_stanza_error_condition_name_to_string (enum
							stanza_error_condition_name_t);

struct stanza_error_t
{
  langstring_t *fText;
  struct stanza_condition_set_t
  {
    enum stanza_error_condition_name_t fName;
    char *fExtra;
  } fCondition;
};


struct stanza_error_t *stanza_error_decode (xmlreader_t * reader);
int stanza_error_encode (xmlwriter_t * writer, struct stanza_error_t *data);
void stanza_error_free (struct stanza_error_t *data);
#endif
<file_sep>#ifndef _UTF8_H_
#define _UTF8_H_

#include <stdint.h>

int utf8_width (uint8_t b);
int utf8_append (char* array, uint32_t u);
int utf8_width_of_uint32 (uint32_t u);

#endif
<file_sep>#include "xep_xdata_data.h"
#include "helpers.h"
#include "errors.h"

const char *ns_xdata = "jabber:x:data";

struct xdata_x_t *
xdata_x_decode (xmlreader_t * reader)
{
  struct xdata_x_t *elm = NULL;
  elm = malloc (sizeof (struct xdata_x_t));
  if (elm == NULL)
    fatal ("xdata_x_t: malloc failed");
  memset (elm, 0, sizeof (struct xdata_x_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "type");
  if (avalue != NULL)
    {
      elm->fType = enum_xdata_x_type_from_string (avalue);
    }
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "title") == 0)
	      && (strcmp (namespace, ns_xdata) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fTitle = (char *) value;
	    }
	  else if ((strcmp (name, "reported") == 0)
		   && (strcmp (namespace, ns_xdata) == 0))
	    {
	      int type = 0;
	      while (1)
		{
		  type = xmlreader_next (reader);
		  if (type == XML_END_ELEMENT)
		    break;
		  if (type == XML_ERROR)
		    return NULL;
		  if (type == XML_START_ELEMENT)
		    {
		      if ((strcmp (namespace, ns_xdata) == 0)
			  && (strcmp (name, "field") == 0))
			{
			  struct xdata_field_t *newel =
			    xdata_field_decode (reader);
			  if (newel != NULL)
			    {
			      return NULL;
			    }
			  if (elm->fReported == NULL)
			    elm->fReported =
			      array_new (sizeof (extension_t), 0);
			  array_append (elm->fReported, newel);
			}
		    }
		}
	    }
	}
    }
  return elm;
}

int
xdata_x_encode (xmlwriter_t * writer, struct xdata_x_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_xdata, "x");
  if (err != 0)
    return err;
  if (elm->fType != 0)
    {
      err =
	xmlwriter_attribute (writer, NULL, "type",
			     enum_xdata_x_type_to_string (elm->fType));
      if (err != 0)
	return err;
    }
  if (elm->fTitle != NULL)
    {
      err = xmlwriter_simple_element (writer, ns_xdata, "title", elm->fTitle);
      if (err != 0)
	return err;
    }
  err = xmlwriter_start_element (writer, ns_xdata, "reported");
  if (err != 0)
    return err;
  int len = array_length (elm->fReported);
  int i = 0;
  for (i = 0; i < len; i++)
    {
      struct xdata_field_t *data = array_get (elm->fReported, i);
      err = xdata_field_encode (writer, data);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  {
    int len = array_length (elm->fFields);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	extension_t *ext = array_get (elm->fFields, i);
	err = xstream_extension_encode (writer, ext->data, ext->type);
	if (err != 0)
	  return -1;
      }
  }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
xdata_x_free (struct xdata_x_t *data)
{
  if (data == NULL)
    return;
  if (data->fTitle != NULL)
    {
      free (data->fTitle);
    }
  int len = array_length (data->fReported);
  int i = 0;
  for (i = 0; i < len; i++)
    {
      struct xdata_field_t *item = array_get (data->fReported, i);
      xdata_field_free (item);
    }
  array_free (data->fReported);
  {
    int len = array_length (data->fFields);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	extension_t *ext = array_get (data->fFields, i);
	xstream_extension_free (ext);
      }
    array_free (data->fFields);
  }
  free (data);
}

struct xdata_field_t *
xdata_field_decode (xmlreader_t * reader)
{
  struct xdata_field_t *elm = NULL;
  elm = malloc (sizeof (struct xdata_field_t));
  if (elm == NULL)
    fatal ("xdata_field_t: malloc failed");
  memset (elm, 0, sizeof (struct xdata_field_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "label");
  if (avalue != NULL)
    {
      elm->fLabel = (char *) avalue;
    }
  avalue = xmlreader_attribute (reader, NULL, "type");
  if (avalue != NULL)
    {
      elm->fType = enum_xdata_field_type_from_string (avalue);
    }
  avalue = xmlreader_attribute (reader, NULL, "var");
  if (avalue != NULL)
    {
      elm->fVar = (char *) avalue;
    }
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "desc") == 0)
	      && (strcmp (namespace, ns_xdata) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fDesc = (char *) value;
	    }
	  else if ((strcmp (name, "required") == 0)
		   && (strcmp (namespace, ns_xdata) == 0))
	    {
	      elm->fRequired = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	  else if ((strcmp (name, "value") == 0)
		   && (strcmp (namespace, ns_xdata) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fValue = (char *) value;
	    }
	  else if ((strcmp (namespace, ns_xdata) == 0)
		   && (strcmp (name, "option") == 0))
	    {
	      struct xdata_option_t *newel = xdata_option_decode (reader);
	      if (newel == NULL)
		{
		  return NULL;
		}
	      if (elm->fOption == NULL)
		elm->fOption = array_new (sizeof (extension_t), 0);
	      array_append (elm->fOption, newel);
	    }
	}
    }
  return elm;
}

int
xdata_field_encode (xmlwriter_t * writer, struct xdata_field_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_xdata, "field");
  if (err != 0)
    return err;
  if (elm->fLabel != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "label", elm->fLabel);
      if (err != 0)
	return err;
    }
  if (elm->fType != 0)
    {
      err =
	xmlwriter_attribute (writer, NULL, "type",
			     enum_xdata_field_type_to_string (elm->fType));
      if (err != 0)
	return err;
    }
  if (elm->fVar != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "var", elm->fVar);
      if (err != 0)
	return err;
    }
  if (elm->fDesc != NULL)
    {
      err = xmlwriter_simple_element (writer, ns_xdata, "desc", elm->fDesc);
      if (err != 0)
	return err;
    }
  if (elm->fRequired)
    {
      err = xmlwriter_simple_element (writer, ns_xdata, "required", NULL);
      if (err != 0)
	return err;
    }
  if (elm->fValue != NULL)
    {
      err = xmlwriter_simple_element (writer, ns_xdata, "value", elm->fValue);
      if (err != 0)
	return err;
    }
  {
    int len = array_length (elm->fOption);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	extension_t *ext = array_get (elm->fOption, i);
	err = xdata_option_encode (writer, ext->data);
	if (err != 0)
	  return err;
      }
  }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
xdata_field_free (struct xdata_field_t *data)
{
  if (data == NULL)
    return;
  if (data->fLabel != NULL)
    {
      free (data->fLabel);
    }
  if (data->fVar != NULL)
    {
      free (data->fVar);
    }
  if (data->fDesc != NULL)
    {
      free (data->fDesc);
    }
  if (data->fRequired)
    {
    }
  if (data->fValue != NULL)
    {
      free (data->fValue);
    }
  {
    int len = array_length (data->fOption);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	xdata_option_free (array_get (data->fOption, i));
      }
    array_free (data->fOption);
  }
  free (data);
}

struct xdata_option_t *
xdata_option_decode (xmlreader_t * reader)
{
  struct xdata_option_t *elm = NULL;
  elm = malloc (sizeof (struct xdata_option_t));
  if (elm == NULL)
    fatal ("xdata_option_t: malloc failed");
  memset (elm, 0, sizeof (struct xdata_option_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "label");
  if (avalue != NULL)
    {
      elm->fLabel = (char *) avalue;
    }
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "value") == 0)
	      && (strcmp (namespace, ns_xdata) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fValue = (char *) value;
	    }
	}
    }
  return elm;
}

int
xdata_option_encode (xmlwriter_t * writer, struct xdata_option_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_xdata, "option");
  if (err != 0)
    return err;
  if (elm->fLabel != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "label", elm->fLabel);
      if (err != 0)
	return err;
    }
  if (elm->fValue != NULL)
    {
      err = xmlwriter_simple_element (writer, ns_xdata, "value", elm->fValue);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
xdata_option_free (struct xdata_option_t *data)
{
  if (data == NULL)
    return;
  if (data->fLabel != NULL)
    {
      free (data->fLabel);
    }
  if (data->fValue != NULL)
    {
      free (data->fValue);
    }
  free (data);
}

enum xdata_x_type_t
enum_xdata_x_type_from_string (const char *value)
{
  if (strcmp (value, "cancel") == 0)
    return XDATA_X_TYPE_CANCEL;
  else if (strcmp (value, "form") == 0)
    return XDATA_X_TYPE_FORM;
  else if (strcmp (value, "result") == 0)
    return XDATA_X_TYPE_RESULT;
  else if (strcmp (value, "submit") == 0)
    return XDATA_X_TYPE_SUBMIT;
  return 0;
}

const char *
enum_xdata_x_type_to_string (enum xdata_x_type_t value)
{
  switch (value)
    {
    case XDATA_X_TYPE_CANCEL:
      return "cancel";
    case XDATA_X_TYPE_FORM:
      return "form";
    case XDATA_X_TYPE_RESULT:
      return "result";
    case XDATA_X_TYPE_SUBMIT:
      return "submit";
    }
  return NULL;
}

enum xdata_field_type_t
enum_xdata_field_type_from_string (const char *value)
{
  if (strcmp (value, "boolean") == 0)
    return XDATA_FIELD_TYPE_BOOLEAN;
  else if (strcmp (value, "fixed") == 0)
    return XDATA_FIELD_TYPE_FIXED;
  else if (strcmp (value, "hidden") == 0)
    return XDATA_FIELD_TYPE_HIDDEN;
  else if (strcmp (value, "jid-multi") == 0)
    return XDATA_FIELD_TYPE_JID_MULTI;
  else if (strcmp (value, "jid-single") == 0)
    return XDATA_FIELD_TYPE_JID_SINGLE;
  else if (strcmp (value, "list-multi") == 0)
    return XDATA_FIELD_TYPE_LIST_MULTI;
  else if (strcmp (value, "list-single") == 0)
    return XDATA_FIELD_TYPE_LIST_SINGLE;
  else if (strcmp (value, "text-multi") == 0)
    return XDATA_FIELD_TYPE_TEXT_MULTI;
  else if (strcmp (value, "text-private") == 0)
    return XDATA_FIELD_TYPE_TEXT_PRIVATE;
  else if (strcmp (value, "text-single") == 0)
    return XDATA_FIELD_TYPE_TEXT_SINGLE;
  return 0;
}

const char *
enum_xdata_field_type_to_string (enum xdata_field_type_t value)
{
  switch (value)
    {
    case XDATA_FIELD_TYPE_BOOLEAN:
      return "boolean";
    case XDATA_FIELD_TYPE_FIXED:
      return "fixed";
    case XDATA_FIELD_TYPE_HIDDEN:
      return "hidden";
    case XDATA_FIELD_TYPE_JID_MULTI:
      return "jid-multi";
    case XDATA_FIELD_TYPE_JID_SINGLE:
      return "jid-single";
    case XDATA_FIELD_TYPE_LIST_MULTI:
      return "list-multi";
    case XDATA_FIELD_TYPE_LIST_SINGLE:
      return "list-single";
    case XDATA_FIELD_TYPE_TEXT_MULTI:
      return "text-multi";
    case XDATA_FIELD_TYPE_TEXT_PRIVATE:
      return "text-private";
    case XDATA_FIELD_TYPE_TEXT_SINGLE:
      return "text-single";
    }
  return NULL;
}
<file_sep>#ifndef _XSTREAM_H_
#define _XSTREAM_H_
#include "xmppdata/extensions.h"

#include "xmlwriter.h"
#include "account.h"
#include "xmlreader.h"
#include "types.h"

struct xstream_extension_t {
  const char* namespace;
  const char* name;
  enum extension_type type;
  void *(*decode) (xmlreader_t* reader);
  int (*encode) (xmlwriter_t* writer, void *data);
  void (*free) (void* data);
};

extern struct xstream_extension_t extensions[];
extern int extensions_len;

int xstream_extension_decode (xmlreader_t* reader, extension_t* ext);
int xstream_extension_get_type(const char* space, const char* local);
int xstream_extension_encode (xmlwriter_t* writer, void* data, int type);
void xstream_extension_free (extension_t* ext);

int xstream_start (int fd, account_t* account);


#endif
<file_sep>#ifndef _XEP_XDATA_DATA_H_
#define  _XEP_XDATA_DATA_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <string.h>
#include "xstream.h"
#include "types.h"

struct xdata_field_t;
struct xdata_option_t;

extern const char *ns_xdata;

enum xdata_x_type_t
{
  XDATA_X_TYPE_CANCEL,
  XDATA_X_TYPE_FORM,
  XDATA_X_TYPE_RESULT,
  XDATA_X_TYPE_SUBMIT,
};

enum xdata_x_type_t enum_xdata_x_type_from_string (const char *value);
const char *enum_xdata_x_type_to_string (enum xdata_x_type_t);
enum xdata_field_type_t
{
  XDATA_FIELD_TYPE_BOOLEAN,
  XDATA_FIELD_TYPE_FIXED,
  XDATA_FIELD_TYPE_HIDDEN,
  XDATA_FIELD_TYPE_JID_MULTI,
  XDATA_FIELD_TYPE_JID_SINGLE,
  XDATA_FIELD_TYPE_LIST_MULTI,
  XDATA_FIELD_TYPE_LIST_SINGLE,
  XDATA_FIELD_TYPE_TEXT_MULTI,
  XDATA_FIELD_TYPE_TEXT_PRIVATE,
  XDATA_FIELD_TYPE_TEXT_SINGLE,
};

enum xdata_field_type_t enum_xdata_field_type_from_string (const char *value);
const char *enum_xdata_field_type_to_string (enum xdata_field_type_t);

struct xdata_x_t
{
  enum xdata_x_type_t fType;
  char *fTitle;
  array_t *fReported;
  array_t *fFields;
};


struct xdata_field_t
{
  char *fLabel;
  enum xdata_field_type_t fType;
  char *fVar;
  char *fDesc;
  bool fRequired;
  char *fValue;
  array_t *fOption;
};


struct xdata_option_t
{
  char *fLabel;
  char *fValue;
};


struct xdata_x_t *xdata_x_decode (xmlreader_t * reader);
int xdata_x_encode (xmlwriter_t * writer, struct xdata_x_t *data);
void xdata_x_free (struct xdata_x_t *data);
struct xdata_field_t *xdata_field_decode (xmlreader_t * reader);
int xdata_field_encode (xmlwriter_t * writer, struct xdata_field_t *data);
void xdata_field_free (struct xdata_field_t *data);
struct xdata_option_t *xdata_option_decode (xmlreader_t * reader);
int xdata_option_encode (xmlwriter_t * writer, struct xdata_option_t *data);
void xdata_option_free (struct xdata_option_t *data);
#endif
<file_sep>#ifndef _STARTTLS_DATA_H_
#define  _STARTTLS_DATA_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <string.h>
#include "xstream.h"
#include "types.h"


extern const char *ns_starttls;


struct starttls_starttls_t
{
  bool fRequired;
};


struct starttls_proceed_t
{
};


struct starttls_failure_t
{
};


struct starttls_starttls_t *starttls_starttls_decode (xmlreader_t * reader);
int starttls_starttls_encode (xmlwriter_t * writer,
			      struct starttls_starttls_t *data);
void starttls_starttls_free (struct starttls_starttls_t *data);
struct starttls_proceed_t *starttls_proceed_decode (xmlreader_t * reader);
int starttls_proceed_encode (xmlwriter_t * writer,
			     struct starttls_proceed_t *data);
void starttls_proceed_free (struct starttls_proceed_t *data);
struct starttls_failure_t *starttls_failure_decode (xmlreader_t * reader);
int starttls_failure_encode (xmlwriter_t * writer,
			     struct starttls_failure_t *data);
void starttls_failure_free (struct starttls_failure_t *data);
#endif
<file_sep>#ifndef _CONNECT_H_
#define _CONNECT_H_

#include "account.h"

#define DEFAULT_PORT 5222
#define SRV_PREFIX "_xmpp-client._tcp."


int tcp6_connect(const account_t *account);
int tcp4_connect(const account_t *account);

#endif
<file_sep>#include "xmppdata/starttls_data.h"
#include "stream.h"
#include "account.h"
#include "errors.h"
#include "xmppdata/extensions.h"

bool starttls_is_mandatory (stream_t* strm) {
  // todo: check config: required, enabled, disabled
  return false;
}

bool starttls_need_restart (void) {
  return true;
}

int starttls_negotate (stream_t* strm, account_t* account, void** data, extension_t* ext) {
  switch (ext->type) {
  case EXTENSION_TYPE_STARTTLS_STARTTLS: {
    // struct starttls_starttls_t* starttls = ext->data;

    struct starttls_starttls_t sp;
    int err = starttls_starttls_encode (&strm->writer, &sp);
    if (err != 0) return err;
  
    err = xmlwriter_flush (&strm->writer);
    if (err != 0) return err;
    return 1;
  }

  case EXTENSION_TYPE_STARTTLS_PROCEED: {
    return 0;
  }

  case EXTENSION_TYPE_STREAM_ERROR: {
    extension_t* error = malloc (sizeof (extension_t));
    memcpy (error, &ext, sizeof (extension_t));
    strm->xmpp_error = error;
    return ERR_XMPP_ERROR;
  }    
  }
  return ERR_BAD_PROTOCOL;
}

struct stream_feature_t starttls_feature = {
  EXTENSION_TYPE_STARTTLS_STARTTLS,
  starttls_is_mandatory,
  starttls_need_restart,
  starttls_negotate,
};
<file_sep>#ifndef _XEP_IQLAST_DATA_H_
#define  _XEP_IQLAST_DATA_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <string.h>
#include "xstream.h"
#include "types.h"


extern const char *ns_iqlast;


struct iqlast_last_t
{
  uint32_t *fSeconds;
  char *fExtra;
};


struct iqlast_last_t *iqlast_last_decode (xmlreader_t * reader);
int iqlast_last_encode (xmlwriter_t * writer, struct iqlast_last_t *data);
void iqlast_last_free (struct iqlast_last_t *data);
#endif
<file_sep>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ustring.h"
#include "xmpp_prep.h"

static ustring_t *of_hlist (const char* str) {
  int len = 0;
  char *p = (char*) str;

  while (*p != '\0') {
    if (*p == ' ')
      len++;
    p++;
  }
  len++;

  ustring_t *ustring = malloc (sizeof (ustring_t));
  ustring->ucs4= malloc (sizeof (uint32_t) * len);
  ustring->len = len;
  uint32_t *usc4 = ustring->ucs4;

  char *start = (char*) str;
  p = start;
  int i = 0;
  
  for (i = 0; i < len; i++) {
    p = strchr (start, (int) ' ');
    if (p != NULL)
      *p++ = '\0';
    
    *usc4++ = (uint32_t) strtol (start, NULL, 16);
    start = p;
  }
  return ustring;
}
    
int main (int argc, char *argv[]) {
  FILE *fh;

  fh = fopen (argv[1], "r+");
  if (fh == NULL) {
    perror ("fopen");
    exit (EXIT_FAILURE);
  }

  char line[1024];
  int count = 0;
  
  while (!feof (fh)) {
    fgets (line, 1024, fh);

    if (line[0] == '\0' || line[0] == '#' || line[0] == '@')
      continue;

    printf ("Line: %s\n", line);
    
    char *p = NULL;
    
    char *c1 = line;
    p = strchr (c1, (int) ';');
    if (p != NULL)
      *p = '\0';
    ustring_t *u1 = of_hlist (c1);
    
    char *c2 = ++p;
    p = strchr (c2, ';');
    if (p != NULL)
      *p = '\0';
    ustring_t *u2 = of_hlist (c2);

    char *c3 = ++p;
    p = strchr (c3, ';');
    if (p != NULL)
      *p = '\0';
    ustring_t *u3 = of_hlist (c3);

    char *c4 = ++p;
    p = strchr (c4, ';');
    if (p != NULL)
      *p = '\0';
    ustring_t *u4 = of_hlist (c4);

    ustring_t *r4 = malloc (sizeof (ustring_t));
    r4->len = u4->len;
    r4->ucs4 = malloc (sizeof (uint32_t) * r4->len);
    memcpy (r4->ucs4, u4->ucs4, sizeof (uint32_t) * r4->len);

    char *c5 = ++p;
    p = strchr (c5, ';');
    if (p != NULL)
      *p = '\0';
    ustring_t *u5 = of_hlist (c5);
    
              
    /*
     * NFKC
     * c4 == NFKC(c1) == NFKC(c2) == NFKC(c3) == NFKC(c4) == NFKC(c5)
     */

    nfkc (u1);
    nfkc (u2);
    nfkc (u3);
    nfkc (u4);
    nfkc (u5)
;
    int b1 = ustring_compare (r4, u1);
    int b2 = ustring_compare (r4, u2);
    int b3 = ustring_compare (r4, u3);
    int b4 = ustring_compare (r4, u4);
    int b5 = ustring_compare (r4, u5);

    if (b1 && b2 && b3 && b4 && b5)
      printf ("(%d) this line proceed\n", count);
    else {
      printf ("failed\n\n");
      printf ("c4 = ");
      ustring_print_hex (r4);
      if (!b1) {
        printf ("c4 != nfkc u1\n");
        ustring_print_hex (u1);
      }
      if (!b2) {
        printf ("c4 != nfkc u2\n");
        ustring_print_hex (u2);
      }
      if (!b3) {
        printf ("c4 != nfkc u3\n");
        ustring_print_hex (u3);
      }
      if (!b4) {
        printf ("c4 != nfkc u4\n");
        ustring_print_hex (u4);
      }
      if (!b5) {
        printf ("c4 != nfkc u5\n");
        ustring_print_hex (u5);
      }
      
      // exit (EXIT_FAILURE);
    }
    ustring_free (u1);
    ustring_free (u2);
    ustring_free (u3);
    ustring_free (u4);
    ustring_free (u5); 
    ustring_free (r4);
   
    count++;
  }

  printf ("Proceed %d lines\n\n", count);

  fclose (fh);
  return 0;
}
<file_sep>#include "xep_time_data.h"
#include "helpers.h"
#include "errors.h"

const char *ns_time = "urn:xmpp:time";

struct time_time_t *
time_time_decode (xmlreader_t * reader)
{
  struct time_time_t *elm = NULL;
  elm = malloc (sizeof (struct time_time_t));
  if (elm == NULL)
    fatal ("time_time_t: malloc failed");
  memset (elm, 0, sizeof (struct time_time_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "tz") == 0)
	      && (strcmp (namespace, ns_time) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fTz = (char *) value;
	    }
	  else if ((strcmp (name, "utc") == 0)
		   && (strcmp (namespace, ns_time) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fUtc = (char *) value;
	    }
	}
    }
  return elm;
}

int
time_time_encode (xmlwriter_t * writer, struct time_time_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_time, "time");
  if (err != 0)
    return err;
  if (elm->fTz != NULL)
    {
      err = xmlwriter_simple_element (writer, ns_time, "tz", elm->fTz);
      if (err != 0)
	return err;
    }
  if (elm->fUtc != NULL)
    {
      err = xmlwriter_simple_element (writer, ns_time, "utc", elm->fUtc);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
time_time_free (struct time_time_t *data)
{
  if (data == NULL)
    return;
  if (data->fTz != NULL)
    {
      free (data->fTz);
    }
  if (data->fUtc != NULL)
    {
      free (data->fUtc);
    }
  free (data);
}
<file_sep>#include <stdlib.h>
#include "utf8.h"
#include "errors.h"
#include "helpers.h"

int utf8_width (const uint8_t ch) {
  if (ch >= 000 && ch < 128)
    return 1;
  else if (ch > 191 && ch < 224) {
    return 2;
  } else if (ch > 223 && ch < 240) {
    return 3;
  } else if (ch > 239 && ch < 248) {
    return 4;
  } else
    return ERR_MALFORMED_UTF8;
}

int utf8_append (char* str, uint32_t u) {
  if (str == NULL)
    fatal ("utf8_append: str is null");
  
  if (u < 0x80)
    *str = (char) u;
  else if (u <= 0x7ff) {
    *str++ = (char) (0xc0 | (u >> 6));
    *str = (char) (0x80 | (u & 0x3f));
  } else if (u <= 0xffff) {
    if (u >= 0xd800 && u < 0xe000)
      return ERR_MALFORMED_UNICODE;
    *str++ = (char) (0xe0 | (u >> 12));
    *str++ = (char) (0x80 | ((u >> 6) & 0x3f));
    *str = (char) (0x80 | (u & 0x3f));
  } else if (u <= 0x10ffff) {
    *str++ = (char) (0xf0 | (u >> 18));
    *str++ = (char) (0x80 | ((u >> 12) & 0x3f));
    *str++ = (char) (0x80 | ((u >> 6)  & 0x3f));
    *str = (char) (0x80 | (u & 0x3f));
  } else 
    return ERR_MALFORMED_UNICODE;

  return 0;
}

int utf8_width_of_uint32 (uint32_t u) {
  if (u < 0x80)
    return 1;
  else if (u < 0x800)
    return 2;
  else if (u < 0x10000)
    return 3;
  else if (u < 0x110000)
    return 4;
  return ERR_MALFORMED_UNICODE;
}

<file_sep>#ifndef _XMLREADER_H_
#define _XMLREADER_H_

#include "bufio.h"
#include "array.h"
#include "stringpair.h"

typedef enum {
  XML_ERROR = -1,
  XML_START_ELEMENT = 1,
  XML_END_ELEMENT,
  XML_TEXT
} xmlreader_nodetype_enum;


typedef struct {
  int err;
  bufio_reader_t bufio;
  array_t* stack;
  int iterator;
  struct xmlreader_element_t* curr;
  int state;
  array_t* tags;
  char* tmpbuf;
} xmlreader_t;

void xmlreader_init (xmlreader_t* reader);
void xmlreader_free (xmlreader_t* reader);
void xmlreader_reset (xmlreader_t* reader);
int xmlreader_next (xmlreader_t* reader);
xmlreader_nodetype_enum xmlreader_nodetype (xmlreader_t* reader);
const char* xmlreader_get_name (xmlreader_t* reader);
const char* xmlreader_get_namespace (xmlreader_t* reader);
const char* xmlreader_attribute (xmlreader_t* reader, const char* space, const char* local);
const char* xmlreader_text (xmlreader_t* reader);
int xmlreader_skip_element (xmlreader_t* reader);
int xmlreader_base64 (xmlreader_t* reader, unsigned char** result, int* result_len);
void xmlreader_read (xmlreader_t* reader);
void xmlreader_stack_clean (xmlreader_t* reader, int start);

#endif
<file_sep>#include <stdlib.h>
#include <string.h>
#include "types.h"

const int jru_true = 1;
int jru_false = 0;

bool* strconv_parse_boolean(const char* value) {
  if (strcmp ((char*) value, "true") == 0 || strcmp ((char*) value, "1") == 0)
    return (bool*) &jru_false;
  else
    return (bool*) &jru_true;
}

int *strconv_parse_int (const char* value) {
  int* ret = malloc(sizeof (int));
  *ret = atoi ((const char*) value);
  return ret;
}

uint32_t *strconv_parse_uint (const char* value) {
  uint32_t* ret = malloc(sizeof (uint32_t));
  *ret = atol((const char*) value);
  return ret;
}

uint64_t *strconv_parse_int64 (const char* value) {
  uint64_t* ret = malloc(sizeof (uint64_t));
  *ret = atoll((const char*) value);
  return ret;
}

const char* strconv_format_boolean(bool* value) {
  return NULL;
}

const char* strconv_format_int(int32_t* value) {
  return NULL;
}

const char* strconv_format_uint(uint32_t* value) {
  return NULL;
}
<file_sep>#include "starttls_data.h"
#include "helpers.h"
#include "errors.h"

const char *ns_starttls = "urn:ietf:params:xml:ns:xmpp-tls";

struct starttls_starttls_t *
starttls_starttls_decode (xmlreader_t * reader)
{
  struct starttls_starttls_t *elm = NULL;
  elm = malloc (sizeof (struct starttls_starttls_t));
  if (elm == NULL)
    fatal ("starttls_starttls_t: malloc failed");
  memset (elm, 0, sizeof (struct starttls_starttls_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "required") == 0)
	      && (strcmp (namespace, ns_starttls) == 0))
	    {
	      elm->fRequired = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	}
    }
  return elm;
}

int
starttls_starttls_encode (xmlwriter_t * writer,
			  struct starttls_starttls_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_starttls, "starttls");
  if (err != 0)
    return err;
  if (elm->fRequired)
    {
      err = xmlwriter_simple_element (writer, ns_starttls, "required", NULL);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
starttls_starttls_free (struct starttls_starttls_t *data)
{
  if (data == NULL)
    return;
  if (data->fRequired)
    {
    }
  free (data);
}

struct starttls_proceed_t *
starttls_proceed_decode (xmlreader_t * reader)
{
  struct starttls_proceed_t *elm = NULL;
  elm = malloc (sizeof (struct starttls_proceed_t));
  if (elm == NULL)
    fatal ("starttls_proceed_t: malloc failed");
  memset (elm, 0, sizeof (struct starttls_proceed_t));
  if (xmlreader_skip_element (reader) == -1)
    return NULL;
  return elm;
}

int
starttls_proceed_encode (xmlwriter_t * writer, struct starttls_proceed_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_starttls, "proceed");
  if (err != 0)
    return err;
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
starttls_proceed_free (struct starttls_proceed_t *data)
{
  if (data == NULL)
    return;
  free (data);
}

struct starttls_failure_t *
starttls_failure_decode (xmlreader_t * reader)
{
  struct starttls_failure_t *elm = NULL;
  elm = malloc (sizeof (struct starttls_failure_t));
  if (elm == NULL)
    fatal ("starttls_failure_t: malloc failed");
  memset (elm, 0, sizeof (struct starttls_failure_t));
  if (xmlreader_skip_element (reader) == -1)
    return NULL;
  return elm;
}

int
starttls_failure_encode (xmlwriter_t * writer, struct starttls_failure_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_starttls, "failure");
  if (err != 0)
    return err;
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
starttls_failure_free (struct starttls_failure_t *data)
{
  if (data == NULL)
    return;
  free (data);
}
<file_sep>#ifndef _CONFIG_H_
#define _CONFIG_H_

#include "account.h"

typedef struct {
  account_t *accounts;
  size_t account_count;
} config_t;

config_t *config_load (const char* filename);
void config_destroy (config_t *config);

#endif
<file_sep>#ifndef _XEP_PRIVACY_DATA_H_
#define  _XEP_PRIVACY_DATA_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <string.h>
#include "xstream.h"
#include "types.h"

struct privacy_active_t;
struct privacy_default_t;
struct privacy_list_t;
struct privacy_item_t;

extern const char *ns_privacy;

enum privacy_item_action_t
{
  PRIVACY_ITEM_ACTION_ALLOW,
  PRIVACY_ITEM_ACTION_DENY,
};

enum privacy_item_action_t enum_privacy_item_action_from_string (const char
								 *value);
const char *enum_privacy_item_action_to_string (enum privacy_item_action_t);
enum privacy_item_type_t
{
  PRIVACY_ITEM_TYPE_GROUP,
  PRIVACY_ITEM_TYPE_JID,
  PRIVACY_ITEM_TYPE_SUBSCRIPTION,
};

enum privacy_item_type_t enum_privacy_item_type_from_string (const char
							     *value);
const char *enum_privacy_item_type_to_string (enum privacy_item_type_t);

struct privacy_privacy_t
{
  struct privacy_active_t *fActive;
  struct privacy_default_t *fDefault;
  array_t *fList;
};


struct privacy_active_t
{
  char *fName;
  char *fExtra;
};


struct privacy_default_t
{
  char *fName;
  char *fExtra;
};


struct privacy_list_t
{
  char *fName;
  array_t *fItems;
};


struct privacy_item_t
{
  enum privacy_item_action_t fAction;
  uint32_t *fOrder;
  enum privacy_item_type_t fType;
  char *fValue;
  bool fIq;
  bool fMessage;
  bool fPresence_in;
  bool fPresence_out;
};


struct privacy_privacy_t *privacy_privacy_decode (xmlreader_t * reader);
int privacy_privacy_encode (xmlwriter_t * writer,
			    struct privacy_privacy_t *data);
void privacy_privacy_free (struct privacy_privacy_t *data);
struct privacy_active_t *privacy_active_decode (xmlreader_t * reader);
int privacy_active_encode (xmlwriter_t * writer,
			   struct privacy_active_t *data);
void privacy_active_free (struct privacy_active_t *data);
struct privacy_default_t *privacy_default_decode (xmlreader_t * reader);
int privacy_default_encode (xmlwriter_t * writer,
			    struct privacy_default_t *data);
void privacy_default_free (struct privacy_default_t *data);
struct privacy_list_t *privacy_list_decode (xmlreader_t * reader);
int privacy_list_encode (xmlwriter_t * writer, struct privacy_list_t *data);
void privacy_list_free (struct privacy_list_t *data);
struct privacy_item_t *privacy_item_decode (xmlreader_t * reader);
int privacy_item_encode (xmlwriter_t * writer, struct privacy_item_t *data);
void privacy_item_free (struct privacy_item_t *data);
#endif
<file_sep>#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>

#include "srv.h"
#include "connect.h"
#include "account.h"
#include "jid/jid.h"

int tcp6_connect(const account_t *account) {
  int sock;
  struct sockaddr_in6 addr;
  struct hostent *hostento;

  char *hostname = account->jid->domain;
  int port = DEFAULT_PORT;
  if (account->port != 0)
    port = account->port;
  
  sock = socket (AF_INET6, SOCK_STREAM, 0);
  if (sock < 0)
    return -1;

  char *name = malloc (sizeof (char) * strlen (SRV_PREFIX) + strlen (hostname) + 1);
  memcpy(name, SRV_PREFIX, strlen (SRV_PREFIX));
  memcpy(name + strlen (SRV_PREFIX), hostname, strlen (hostname));
  name[strlen(SRV_PREFIX) + strlen(hostname)] = '\0';

  printf("Ready name: %s\n", name);

  srv_list *srvlist = srv_lookup(name);
  free (name);

  if (srvlist != NULL) {
    while (1) {
      srv_record *srv = srv_record_get (&srvlist);
      if (srv == NULL) {
        srv_list_destroy (srvlist);
        break;
      }
  
      hostento = gethostbyname2(srv->name, AF_INET6);
      free (srv->name);

      if (hostento == NULL) {
        free (srv);
        continue;
      }
      
      bzero ((char*) &addr, sizeof (addr));
      addr.sin6_flowinfo = 0;
      addr.sin6_family = AF_INET6;
      memmove ((char*) &addr.sin6_addr.s6_addr, (char*) hostento->h_addr, hostento->h_length);
      addr.sin6_port = htons (srv->port);
      free (srv);
      
      if (connect (sock, (struct sockaddr*)  &addr, sizeof (addr)) < 0)
        continue;
      else {
        srv_list_destroy (srvlist);
        return sock;
      }
    }
  }

  // No success connect via SRV, now try A

  hostento = gethostbyname2(hostname, AF_INET6);
  if (hostento == NULL)
    return -1;

  bzero ((char*) &addr, sizeof (addr));
  addr.sin6_flowinfo = 0;
  addr.sin6_family = AF_INET6;
  memmove ((char*) &addr.sin6_addr.s6_addr, (char*) hostento->h_addr, hostento->h_length);
  addr.sin6_port = htons (port);
  
  if (connect (sock, (struct sockaddr*)  &addr, sizeof (addr)) < 0)
    return -1;

  return sock;
}

int tcp4_connect(const account_t *account) {
  int sock;
  struct hostent *hostento;
  struct sockaddr_in addr;

  char *hostname = account->jid->domain;
  int port = DEFAULT_PORT;
  if (account->port != 0)
    port = account->port;

  sock = socket (AF_INET, SOCK_STREAM, 0);
  if (sock < 0)
    return -1;

  char *name = malloc (sizeof (char) * strlen (SRV_PREFIX) + strlen (hostname) + 1);
  memcpy(name, SRV_PREFIX, strlen (SRV_PREFIX));
  memcpy(name + strlen (SRV_PREFIX), hostname, strlen (hostname));
  name[strlen(SRV_PREFIX)+strlen(hostname)] = '\0';

  printf("Ready name: %s\n", name);

  srv_list *srvlist = srv_lookup(name);
  free (name);

  if (srvlist != NULL) {
    while (1) {
      srv_record *srv = srv_record_get (&srvlist);
      if (srv == NULL) {
        srv_list_destroy (srvlist);
        break;
      }
      
      hostento = gethostbyname2(srv->name, AF_INET);
      free (srv->name);

      if (hostento == NULL) {
        free (srv);
        continue;
      }

      bzero((char*) &addr, sizeof(addr));
      addr.sin_family = AF_INET;
      memmove ((char *) &addr.sin_addr.s_addr, (char *) hostento->h_addr, hostento->h_length);
      addr.sin_port = htons (srv->port);
      free (srv);
      
      if (connect(sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
        continue;
      else {
        srv_list_destroy (srvlist);
        return sock;
      }
    }
  }

  // No success connect via SRV, now try A

  hostento = gethostbyname2(hostname, AF_INET);
  if (hostento == NULL)
    return -1;

  bzero((char*) &addr, sizeof(addr));
  addr.sin_family = AF_INET;
  memmove ((char *) &addr.sin_addr.s_addr, (char *) hostento->h_addr, hostento->h_length);
  addr.sin_port = htons (port);
  
  if (connect(sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
    return -1;
  
  return sock;
}
<file_sep>#include "xep_captcha_data.h"
#include "helpers.h"
#include "errors.h"

const char *ns_captcha = "urn:xmpp:captcha";

struct captcha_captcha_t *
captcha_captcha_decode (xmlreader_t * reader)
{
  struct captcha_captcha_t *elm = NULL;
  elm = malloc (sizeof (struct captcha_captcha_t));
  if (elm == NULL)
    fatal ("captcha_captcha_t: malloc failed");
  memset (elm, 0, sizeof (struct captcha_captcha_t));
  if (xmlreader_skip_element (reader) == -1)
    return NULL;
  return elm;
}

int
captcha_captcha_encode (xmlwriter_t * writer, struct captcha_captcha_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_captcha, "captcha");
  if (err != 0)
    return err;
  if (elm->fXdata != NULL)
    {
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
captcha_captcha_free (struct captcha_captcha_t *data)
{
  if (data == NULL)
    return;
  if (data->fXdata != NULL)
    {
    }
  free (data);
}
<file_sep>#ifndef _STREAM_H_
#define _STREAM_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include "xstream.h"
#include "jid/jid.h"
#include "account.h"

struct _stream_t;

struct _stream_t {
  int fd;
  int state;
  xmlreader_t reader;
  xmlwriter_t writer;
  jid_t* jid;
  const char* content_namespace;
  const char* lang;
  void* userdata;
  bool logging;
  extension_t* xmpp_error;
  char id[32];
  int (*session_handler) (struct _stream_t* strm, account_t* account, extension_t* ext);
};

typedef struct _stream_t stream_t;

struct stream_feature_t {
  int extension_type;
  bool (*is_mandatory) (stream_t*);
  bool (*need_to_restart) (void);
  int (*negotate) (stream_t* strm, account_t* account, void** data, extension_t* ext);
};

stream_t* stream_new (int fd, const char* content_namespace, const char* lang,
                      bool logging, void* userdata);
const char* stream_get_id (stream_t* strm);
int stream_start (stream_t* strm, account_t* account);
int stream_process (stream_t* strm, account_t* account, extension_t* ext);
int xstream_read (stream_t* strm, extension_t* ext);

#endif
<file_sep>#include "xmlreader.h"
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <malloc.h>

#include "bufio.h"
#include "helpers.h"
#include "errors.h"
#include "utf8.h"
#include "array.h"
#include "base64.h"

enum xmlreader_state_enum {
  XMLREADER_STATE_TEXT,
  XMLREADER_STATE_LT,
  XMLREADER_STATE_LBRACKET,
  XMLREADER_STATE_EXLMN,
  XMLREADER_STATE_ELEMENT_NAME,
  XMLREADER_STATE_ATTRIBUTE_NAME,
  XMLREADER_STATE_AFTER_ATTRIBUTE_NAME,
  XMLREADER_STATE_BEFORE_ATTRIBUTE_VALUE,
  XMLREADER_STATE_ATTRIBUTE_VALUE_QUOT,
  XMLREADER_STATE_ATTRIBUTE_VALUE_APOS,
  XMLREADER_STATE_AFTER_ATTRIBUTE_VALUE,
  XMLREADER_STATE_BEFORE_ATTRIBUTE,
  XMLREADER_STATE_EMPTY_ELEMENT_CLOSE,
  XMLREADER_STATE_ELEMENT_END,
  XMLREADER_STATE_ELEMENT_END_CLOSE,
  XMLREADER_STATE_PI,
  XMLREADER_STATE_PI_AFTER_NAME,
  XMLREADER_STATE_PI_CLOSE,
  XMLREADER_STATE_PI_DATA,
  XMLREADER_STATE_PI_SKIP_DATA,
};

struct xmlreader_attribute_t {
  char* name;
  char* namespace;
  char* value;
};

struct xmlreader_element_t {
  char* name;
  char* namespace;
  array_t* attributes;
};

struct xmlreader_token_t {
  int type;
  union {
    struct xmlreader_element_t* el;
    char* cdata;
  } u;
};

struct xmlreader_tag_t {
  char* name;
  struct xmlreader_element_t* el;
};

void xmlreader_init (xmlreader_t* reader) {
  memset (reader, 0, sizeof (xmlreader_t));
  bufio_reader_init (&reader->bufio);
  reader->iterator = -1;
  reader->stack = array_new (sizeof (struct xmlreader_token_t), 5);
  reader->state = XMLREADER_STATE_TEXT;
  reader->tags = array_new (sizeof (struct xmlreader_tag_t), 5);
}

static void xmlreader_element_free (struct xmlreader_element_t* el) {
  free (el->name);
  if (el->attributes != NULL) {
    int i = 0;
    int len = array_length (el->attributes);
    for (i = 0; i < len; i++) {
      struct xmlreader_attribute_t* attribute = array_get (el->attributes, i);
      free (attribute->name);
      if (attribute->value != NULL)
        free (attribute->value);
    }
    array_free (el->attributes);
  }
  free (el);
}

void xmlreader_stack_clean (xmlreader_t* reader, int start) {
  int len = array_length (reader->stack);
  if (len == 0 || len == start) return;
  int i = len;
  for (i = start; i < len; i++) {
    struct xmlreader_token_t* child = array_get (reader->stack, i);
    switch (child->type) {
    case XML_START_ELEMENT: {
      struct xmlreader_element_t* el = child->u.el;
      xmlreader_element_free (el);
      break;
    }
    case XML_TEXT:
      if (child->u.cdata != NULL)
        free (child->u.cdata);
    }
  }
  reader->stack->length = start;
}

void xmlreader_reset (xmlreader_t* reader) {
  if (reader == NULL)
    fatal ("xmlreader_reset: reader is null");
  reader->iterator = -1;
  bufio_reader_reset (&reader->bufio);
  reader->state = XMLREADER_STATE_TEXT;
  xmlreader_stack_clean (reader, 0);
  if (reader->tags != NULL) {
    int len = array_length (reader->tags);
    int i = 0;
    for (i = 0; i < len; i++) {
      struct xmlreader_tag_t* tag = array_get (reader->tags, i);
      free (tag->name);
    }
    reader->tags->length = 0;
  }
}

static inline bool is_space (uint32_t u) {
  return (u == ' ' || u == '\t' || u == '\r' || u == '\n');
}

static inline bool is_name_start_char (uint32_t u) {
  return ((u >= 0x0061 && u <= 0x007A) || u == ':' || u == '_' ||
          (u >= 0x0041 && u <= 0x005A) || (u >= 0xC0 && u <= 0xD6) ||
          (u >= 0xD8 && u <= 0xF6) || (u >= 0xF8 && u <= 0x2FF) ||
          (u >= 0x370 && u <= 0x37D) || (u >= 0x37F && u <= 0x1FFF) ||
          (u >= 0x200C && u <= 0x200D) || (u >= 0x2070 && u <= 0x218F) ||
          (u >= 0x2C00 && u <= 0x2FEF) || (u >= 0x3001 && u <= 0xD7FF) ||
          (u >= 0xF900 && u <= 0xFDCF) || (u >= 0xFDF0 && u <= 0xFFFD) ||
          (u >= 0x10000 && u <= 0xEFFFF));
}

static inline bool is_name_char (uint32_t u) {
  return (is_name_start_char (u) || u == '-' || u == '.' ||
          (u >= 0x0030 && u <= 0x0039) || (u >= 0x0300 && u <= 0x036F) ||
          (u >= 0x203F && u <= 0x2040));
}

static uint32_t xmlreader_internal_name (xmlreader_t* reader) {
  uint32_t c = 0;
  
  if (reader->tmpbuf == NULL) {
    reader->tmpbuf = malloc (255);
    if (reader->tmpbuf == NULL)
      fatal ("xmlreader_internal_name: malloc failed");
    *reader->tmpbuf = 0;
  }
  int len = strlen (reader->tmpbuf);
  char* ptr = reader->tmpbuf+len;
  int err = 0;
  int width = 0;

  if (len == 0) {
    c = bufio_reader_get_rune (&reader->bufio);
    if (reader->bufio.err != 0) {
      reader->err = reader->bufio.err;
      return 0;
    }
    if (!is_name_start_char (c)) {
      reader->err = ERR_XML_SYNTAX;
      return 0;
    }
    
    err = utf8_append (ptr, c);
    if (err != 0) {
      reader->err = err;
      return 0;
    }
    width = utf8_width_of_uint32 (c);
    len += width;
    ptr += width;
  }

  while (1) {
    c = bufio_reader_get_rune (&reader->bufio);
    if (reader->bufio.err != 0) {
      reader->err = reader->bufio.err;
      return 0;
    }
    if (!is_name_char (c))
      break;
    width = utf8_width_of_uint32 (c);
    if (len % 255 + width >= 254) {
      reader->tmpbuf = realloc (reader->tmpbuf, (len / 255 + 1) * 255);
      if (reader->tmpbuf == NULL)
        fatal ("xmlreader_internal_name: realloc failed");
      ptr = reader->tmpbuf + len;
    }
    err = utf8_append (ptr, c);
    if (err != 0) {
      reader->err = err;
      return 0;
    }
    len += width;
    ptr += width;
  }
  *ptr = 0;

  return c;
}

static void xmlreader_internal_text (xmlreader_t* reader) {
  bool skip = false;
  if (array_length (reader->tags) < 2)
    skip = true;
  
  char* text = NULL;
  int len = 0;
  
  uint8_t c = 0;

  while (1) {
    c = bufio_reader_get_byte (&reader->bufio);
    if (reader->bufio.err != 0) {
      reader->err = reader->bufio.err;
      return;
    }
    
    if (c == '<') {
      reader->state = XMLREADER_STATE_LT;
      return;
    }
      
    if (!skip) {
      if (text == NULL) {
        struct xmlreader_token_t* child = array_get_last (reader->stack);
        if (child->type == XML_TEXT) 
          text = child->u.cdata;
        else {
          text = malloc (4096);
          if (text == NULL)
            fatal ("xmlreader_internal_text: malloc failed");
          *text = 0;
          struct xmlreader_token_t child;
          child.type = XML_TEXT;
          child.u.cdata = text;
          array_append (reader->stack, &child);
        }
        len = strlen (text);
      }
      if (len % 4096 == 4095) {
        text = realloc (text, len + 4096);
        if (text == NULL)
          fatal ("xmlreader_internal_text: realloc failed");
        struct xmlreader_token_t* child = array_get_last (reader->stack);
        if (child->type != XML_TEXT)
          fatal ("xmlreader_internal_text: wrong child");
        child->u.cdata = text;
      }
      *(text + len++) = c;
      *(text + len) = 0;
    }
  }
}

static void xmlreader_internal_attribute_value (xmlreader_t* reader, const char delim) {
  if (reader->tmpbuf == NULL) {
    reader->tmpbuf = malloc (255);
    if (reader->tmpbuf == NULL)
      fatal ("xmlreader_internal_attribute_value: malloc failed");
    *reader->tmpbuf = 0;
  }
  int len = strlen (reader->tmpbuf);
  char* ptr = reader->tmpbuf + len;
  uint32_t c = 0;
  
  while (1) {
    c = bufio_reader_get_byte (&reader->bufio);
    if (reader->bufio.err != 0) {
      *ptr = 0;
      reader->err = reader->bufio.err;
      return;
    }
    if (c == delim) {
      *ptr = 0;
      break;
    }
    if (len % 255 == 254) {
      reader->tmpbuf = realloc (reader->tmpbuf, len + 255);
      if (reader->tmpbuf == NULL)
        fatal ("xmlreader_internal_attribute_value: realloc failed");
      ptr = reader->tmpbuf + len;
    }
    *ptr++ = c;
    len++;
  }
}

static char* xmlreader_internal_resolve_namespace (xmlreader_t* reader, char* prefix, int prefix_len) {
  int len = array_length (reader->tags);
  int i = 0, j = 0;
  for (i = len-1; i >= 0; i--) {
    struct xmlreader_tag_t* tag = array_get (reader->tags, i);
    if (tag->el->attributes != NULL) {
      int llen = array_length (tag->el->attributes);
      for (j = 0; j < llen; j++) {
        struct xmlreader_attribute_t* attribute = array_get (tag->el->attributes, j);
        if (prefix == NULL) {
          if (strcmp ("xmlns", attribute->name) == 0)
            return attribute->value;
        } else {
          if (strlen (attribute->name) == prefix_len + 6 &&
              strncmp (attribute->name, "xmlns:", 6) == 0 &&
              strncmp (attribute->name + 6, prefix, prefix_len) == 0)
            return attribute->value;
        }
      }
    }
  }
  return NULL;
}

static void xmlreader_internal_process_namespaces (xmlreader_t* reader, struct xmlreader_element_t* el) {
  char* ns = NULL;
  char* colon = strchr (el->name, ':');
  int prefix_len = 0;
  if (colon != NULL) {
    prefix_len = colon - el->name;
    ns = xmlreader_internal_resolve_namespace (reader, el->name, prefix_len);
    if (ns != NULL) {
      el->namespace = ns;
      memmove (el->name, el->name + prefix_len+1, strlen (el->name) - prefix_len);
    }
  } else {
    ns = xmlreader_internal_resolve_namespace (reader, NULL, 0);
    if (ns != NULL)
      el->namespace = ns;
  }
  
  if (el->attributes != NULL) {
    int len = array_length (el->attributes);
    int i = 0;
    for (i = 0; i < len; i++) {
      struct xmlreader_attribute_t* attribute = array_get (el->attributes, i);
      colon = strchr (attribute->name, ':');
      if (colon != NULL) {
        prefix_len = colon - attribute->name;
        ns = xmlreader_internal_resolve_namespace (reader, attribute->name, prefix_len);
        if (ns != NULL) {
          attribute->namespace = ns;
          memmove (attribute->name, attribute->name + prefix_len + 1,
                   strlen (attribute->name) - prefix_len);
        }
      }
    }
  }
}

void xmlreader_read (xmlreader_t* reader) {
  if (reader == NULL)
    fatal ("xmlreader_read: reader is null");
  
  uint8_t c = 0;
  
  while (1) {
    c = bufio_reader_get_byte (&reader->bufio);
    if (reader->bufio.err != 0) {
      reader->err = reader->bufio.err;
      return;
    }
    
    switch (reader->state) {
    case XMLREADER_STATE_TEXT:
      bufio_reader_unget_byte (&reader->bufio);
      xmlreader_internal_text (reader);
      if (reader->err != 0) return;
      break;

    case XMLREADER_STATE_LT:
      switch (c) {
      case '/':
        reader->state = XMLREADER_STATE_ELEMENT_END;
        if (array_length (reader->stack) == 0) {
          reader->err = ERR_XML_SYNTAX;
          return;
        }
        break;

      case '?':
        reader->state = XMLREADER_STATE_PI;
        break;

      case '!':
        reader->state = XMLREADER_STATE_EXLMN;
        break;

      case '[':
        reader->state = XMLREADER_STATE_LBRACKET;
        break;

      default:
        reader->state = XMLREADER_STATE_ELEMENT_NAME;
        bufio_reader_unget_byte (&reader->bufio);
        break;
        
      }
      break;
    
    case XMLREADER_STATE_ELEMENT_NAME: {
      bufio_reader_unget_byte (&reader->bufio);
      uint32_t nextc = xmlreader_internal_name (reader);
      if (reader->err != 0) return;
      
      struct xmlreader_element_t* el = malloc (sizeof (struct xmlreader_element_t));
      if (el == NULL)
        fatal ("xmlreader_read: malloc failed");
      memset (el, 0, sizeof (struct xmlreader_element_t));

      struct xmlreader_tag_t tag = { strdup (reader->tmpbuf), el };
      array_append (reader->tags, &tag);

      el->name = reader->tmpbuf;
      reader->tmpbuf = NULL;

      struct xmlreader_token_t child;
      child.type = XML_START_ELEMENT;
      child.u.el = el;
      array_append (reader->stack, &child);
      
      if (is_space (nextc))
        reader->state = XMLREADER_STATE_BEFORE_ATTRIBUTE;
      else if (nextc == '/')
        reader->state = XMLREADER_STATE_EMPTY_ELEMENT_CLOSE;
      else if (nextc == '>') {
        reader->state = XMLREADER_STATE_TEXT;
        xmlreader_internal_process_namespaces (reader, el);
        if (array_length (reader->tags) == 1)
          return;
      } else {
        reader->err = ERR_XML_SYNTAX;
        return;
      }
      break;
    }
      
    case XMLREADER_STATE_ELEMENT_END: {
      bufio_reader_unget_byte (&reader->bufio);
      uint32_t nextc = xmlreader_internal_name (reader);
      if (reader->err != 0) return;

      struct xmlreader_tag_t* tag = array_get_last (reader->tags);
      if (strcmp (tag->name, reader->tmpbuf) != 0) {
        printf ("wrong end element %s %s\n", tag->name, reader->tmpbuf);
        reader->err = ERR_XML_SYNTAX;
        return;
      }
      free (reader->tmpbuf);
      reader->tmpbuf = NULL;
      
      free (tag->name);
      array_delete_last (reader->tags);
      struct xmlreader_token_t child;
      child.type = XML_END_ELEMENT;
      child.u.el = NULL;
      array_append (reader->stack, &child);

      if (is_space (nextc))
        reader->state = XMLREADER_STATE_ELEMENT_END_CLOSE;
      else if (nextc == '>') {
        reader->state = XMLREADER_STATE_TEXT;

        int len = array_length (reader->tags);
        if (len < 2)
          return;
      } else {
        reader->err = ERR_XML_SYNTAX;
        return;
      }
      break;
    }

    case XMLREADER_STATE_ELEMENT_END_CLOSE:
      if (is_space (c))
        ; // same state
      else if (c == '>') {
        reader->state = XMLREADER_STATE_TEXT;

        int len = array_length (reader->tags);
        if (len < 2)
          return;
      } else {
        reader->err = ERR_XML_SYNTAX;
        return;
      }
      break;
      
    case XMLREADER_STATE_EMPTY_ELEMENT_CLOSE: {
      if (c != '>') {
        reader->err = ERR_XML_SYNTAX;
        return;
      }
      reader->state = XMLREADER_STATE_TEXT;

      struct xmlreader_token_t* child = array_get_last (reader->stack);
      if (child->type != XML_START_ELEMENT)
        fatal ("xmlreader_read: wrong stack");
      struct xmlreader_element_t* el = child->u.el;
      xmlreader_internal_process_namespaces (reader, el);

      struct xmlreader_token_t cchild;
      cchild.type = XML_END_ELEMENT;
      cchild.u.el = NULL;
      array_append (reader->stack, &cchild);

      struct xmlreader_tag_t* tag = array_get_last (reader->tags);
      free (tag->name);
      array_delete_last (reader->tags);

      int len = array_length (reader->tags);
      if (len < 2)
        return;
      break;
    }
      
    case XMLREADER_STATE_BEFORE_ATTRIBUTE:
      if (is_space (c))
        ; // same stat
      else if (c == '/')
        reader->state = XMLREADER_STATE_EMPTY_ELEMENT_CLOSE;
      else if (c == '>') {
        reader->state = XMLREADER_STATE_TEXT;
        struct xmlreader_token_t* child = array_get_last (reader->stack);
        if (child->type != XML_START_ELEMENT)
          fatal ("xmlreader_read: wrong stack");
        struct xmlreader_element_t* el = child->u.el;
        xmlreader_internal_process_namespaces (reader, el);
        struct xmlreader_token_t cchild;
        cchild.type = XML_END_ELEMENT;
        cchild.u.el = NULL;
        array_append (reader->stack, &cchild);
        int len = array_length (reader->tags);
        if (len == 1)
          return;
      } else {
        bufio_reader_unget_byte (&reader->bufio);
        reader->state = XMLREADER_STATE_ATTRIBUTE_NAME;
      }
      break;
      
    case XMLREADER_STATE_ATTRIBUTE_NAME: {
      bufio_reader_unget_byte (&reader->bufio);
      uint32_t nextc = xmlreader_internal_name (reader);
      if (reader->err != 0) return;

      if (is_space (nextc))
        reader->state = XMLREADER_STATE_AFTER_ATTRIBUTE_NAME;
      else if (nextc == '=')
        reader->state = XMLREADER_STATE_BEFORE_ATTRIBUTE_VALUE;
      else {
        reader->err = ERR_XML_SYNTAX;
        return;
      }

      struct xmlreader_token_t* child = array_get_last (reader->stack);
      if (child->type != XML_START_ELEMENT)
        fatal ("xmlreader_read: wrong stack");
      struct xmlreader_element_t* el = child->u.el;
      struct xmlreader_attribute_t attribute = { reader->tmpbuf, NULL, NULL};
      if (el->attributes == NULL)
        el->attributes = array_new (sizeof (struct xmlreader_attribute_t), 6);
      array_append (el->attributes, &attribute);
      reader->tmpbuf = NULL;
      break;
    }
      
    case XMLREADER_STATE_AFTER_ATTRIBUTE_NAME:
      if (is_space (c))
        ; // same state
      else if (c == '=')
        reader->state = XMLREADER_STATE_BEFORE_ATTRIBUTE_VALUE;
      else {
        reader->err = ERR_XML_SYNTAX;
        return;
      }
      break;
      
    case XMLREADER_STATE_BEFORE_ATTRIBUTE_VALUE:
      if (is_space (c))
        ; // same state
      else if (c == '\'')
        reader->state = XMLREADER_STATE_ATTRIBUTE_VALUE_APOS;
      else if (c == '"')
        reader->state = XMLREADER_STATE_ATTRIBUTE_VALUE_QUOT;
      else {
        reader->err = ERR_XML_SYNTAX;
        return;
      }
      break;

    case XMLREADER_STATE_ATTRIBUTE_VALUE_APOS:
      bufio_reader_unget_byte (&reader->bufio);
      xmlreader_internal_attribute_value (reader, '\'');
      if (reader->err != 0) return;
      struct xmlreader_token_t* child = array_get_last (reader->stack);
      if (child->type != XML_START_ELEMENT)
        fatal ("xmlreader_read: wrong stack");
      struct xmlreader_element_t* el = child->u.el;
      struct xmlreader_attribute_t* attribute = array_get_last (el->attributes);
      attribute->value = reader->tmpbuf;
      reader->tmpbuf = NULL;
      reader->state = XMLREADER_STATE_AFTER_ATTRIBUTE_VALUE;
      break;

    case XMLREADER_STATE_ATTRIBUTE_VALUE_QUOT: {
      bufio_reader_unget_byte (&reader->bufio);
      xmlreader_internal_attribute_value (reader, '"');
      if (reader->err != 0) return;
      struct xmlreader_attribute_t* attribute = array_get_last (el->attributes);
      attribute->value = reader->tmpbuf;
      reader->tmpbuf = NULL;
      reader->state = XMLREADER_STATE_AFTER_ATTRIBUTE_VALUE;
      break;
    }
      
    case XMLREADER_STATE_AFTER_ATTRIBUTE_VALUE: {
      if (is_space (c))
        reader->state = XMLREADER_STATE_BEFORE_ATTRIBUTE;
      else if (c == '/')
        reader->state = XMLREADER_STATE_EMPTY_ELEMENT_CLOSE;
      else if (c == '>') {
        reader->state = XMLREADER_STATE_TEXT;
        xmlreader_internal_process_namespaces (reader, el);
        if (array_length (reader->tags) == 1)
          return;
      } else {
        reader->err = ERR_XML_SYNTAX;
        return;
      }
      break;
    }

    case XMLREADER_STATE_PI: {
      bufio_reader_unget_byte (&reader->bufio);
      uint32_t nextc = xmlreader_internal_name (reader);
      if (reader->err != 0) return;

      if (is_space (nextc))
        reader->state = XMLREADER_STATE_PI_AFTER_NAME;
      else if (nextc == '?')
        reader->state = XMLREADER_STATE_PI_CLOSE;
      else {
        reader->err = ERR_XML_SYNTAX;
        return;
      }
      break;
    }

    case XMLREADER_STATE_PI_AFTER_NAME:
      if (is_space (c))
        ; // same state
      else {
        if (strcmp ("xml", reader->tmpbuf) == 0) {
          reader->state = XMLREADER_STATE_PI_DATA;
          *reader->tmpbuf = c;
          *(reader->tmpbuf + 1) = 0;
        } else {
          free (reader->tmpbuf);
          reader->tmpbuf = NULL;
          reader->state = XMLREADER_STATE_PI_SKIP_DATA;
        }
      }        
      break;

    case XMLREADER_STATE_PI_DATA:
      if (c == '?') {
        int len = strlen (reader->tmpbuf);
        char* ptr = reader->tmpbuf;
        if (len < 12 || strncmp ("version", ptr, 7) != 0) {
          reader->err = ERR_XML_SYNTAX;
          return;
        }
        len -= 7;
        ptr += 7;
        while (len > 0 && is_space (*ptr)) { len--; ptr++; }
        if (len-- > 0 && *ptr++ != '=') {
          reader->err = ERR_XML_SYNTAX;
          return;
        }
        while (len > 0 && is_space (*ptr)) { len--; ptr++; }
        char delim = *ptr++; len--;
        if (len < 4 || (delim != '\'' && delim != '"')) {
          reader->err = ERR_XML_SYNTAX;
          return;
        }
        if (strncmp ("1.0", ptr, 3) != 0 || *(ptr+3) != delim) {
          reader->err = ERR_XML_SYNTAX;
          return;
        }
        len -= 4;
        ptr += 4;
        while (len > 0 && is_space (*ptr)) { len--; ptr++; }
        if (len > 0) {
          if (len < 8 || strncmp ("encoding", ptr, 8) != 0) {
            reader->err = ERR_XML_SYNTAX;
            return;
          }
          len -= 8;
          ptr += 8;
          while (len >0 && is_space (*ptr)) { len--; ptr++; }
          if (len == 0) {
            reader->err = ERR_XML_SYNTAX;
            return;
          }
          delim = *ptr++;
          len--;
          if (len < 1 || delim != '\'' || delim != '"') {
            reader->err = ERR_XML_SYNTAX;
            return;
          }
          if (len < 6 || strncasecmp ("utf-8", ptr, 3) != 0 || *(ptr+3) != delim) {
            reader->err = ERR_XML_SYNTAX;
            return;
          }        
        }
        free (reader->tmpbuf);
        reader->tmpbuf = NULL;
        reader->state = XMLREADER_STATE_PI_CLOSE;
      } else {
        int len = strlen (reader->tmpbuf);
        if (len % 255 == 254) {
          reader->tmpbuf = realloc (reader->tmpbuf, len + 255);
          if (reader->tmpbuf == NULL)
            fatal ("xmlreader_read: realloc failed");
        }
        *(reader->tmpbuf + len) = c;
        *(reader->tmpbuf + len+1) = 0;
      }
      break;

    case XMLREADER_STATE_PI_SKIP_DATA:
      if (c == '?')
        reader->state = XMLREADER_STATE_PI_CLOSE;
      else {
        reader->err = ERR_XML_SYNTAX;
        return;
      }
      break;

    case XMLREADER_STATE_PI_CLOSE:
      if (c == '>')
        reader->state = XMLREADER_STATE_TEXT;
      else {
        reader->err = ERR_XML_SYNTAX;
        return;
      }
      break;
      
    default:
      fatal ("xmlreader_read: unknown state");
    }
  }
}

const char* xmlreader_get_name (xmlreader_t* reader) {
  if (reader == NULL)
    fatal ("xmlreader_get_name: reader is null");
  
  struct xmlreader_token_t* child = array_get (reader->stack, reader->iterator);
  if (child->type != XML_START_ELEMENT)
    fatal ("xmlreader_get_name: wrong state 1");

  struct xmlreader_element_t* el = child->u.el;
  return el->name;
}

const char* xmlreader_get_namespace (xmlreader_t* reader) {
  if (reader == NULL)
    fatal ("xmlreader_get_name: reader is null");

  struct xmlreader_token_t* child = array_get (reader->stack, reader->iterator);
  if (child->type != XML_START_ELEMENT)
    fatal ("xmlreader_get_name: wrong state 2");
  struct xmlreader_element_t* el = child->u.el;

  if (el->namespace == NULL) {
    return NULL;
  }
  return el->namespace;
}
 
const char* xmlreader_attribute (xmlreader_t* reader, const char* namespace, const char* name) {
  if (reader == NULL)
    fatal ("xmlreader_attribute: reader is null");

  struct xmlreader_token_t* child = array_get (reader->stack, reader->iterator);
  if (child->type != XML_START_ELEMENT)
    fatal ("xmlreader_attribute: wrong nodetype");

  struct xmlreader_element_t* el = child->u.el;
  
  if (el->attributes == NULL)
    return NULL;

  char* value = NULL;
  int len = array_length (el->attributes);
  int i = 0;
  for (i = 0; i < len; i++) {
    struct xmlreader_attribute_t* attribute = array_get (el->attributes, i);
    if (namespace == NULL && attribute->namespace == NULL &&
        strcmp (name, attribute->name) == 0) {
      value = attribute->value;
      attribute->value = NULL;
    } else if (namespace != NULL && attribute->namespace != NULL &&
               strcmp (namespace, attribute->namespace) == 0) {
      value = attribute->value;
      attribute->value = NULL;
    }
  }
  return value;
}

int xmlreader_skip_element (xmlreader_t* reader) {
  if (reader == NULL)
    fatal ("xmlreader_skip_element: reader is null");
  
  struct xmlreader_token_t* child = NULL;

  while (1) {
    reader->iterator++;
    child = array_get (reader->stack, reader->iterator);
    
    switch (child->type) {
    case XML_START_ELEMENT:
      xmlreader_skip_element (reader);
      break;
    case XML_END_ELEMENT:
      return 0;
    case XML_TEXT:
      break;
    case XML_ERROR:
      return -1;
    }
  }
}

const char* xmlreader_text (xmlreader_t* reader) {
  if (reader == NULL)
    fatal ("xmlreader_text: reader is null");

  char* text = NULL;
  struct xmlreader_token_t* child;

  while (1) {
    reader->iterator++;
    child = array_get (reader->stack, reader->iterator);
    
    switch (child->type) {
    case XML_START_ELEMENT:
      xmlreader_skip_element (reader);
      break;
    case XML_END_ELEMENT:
      return text;
    case XML_TEXT:
      text = child->u.cdata;
      child->u.cdata = NULL;
      break;
    case XML_ERROR:
      return NULL;
    }
  }
  return text;
}

int xmlreader_base64 (xmlreader_t* reader, unsigned char** result, int* result_len) {
  if (reader == NULL)
    fatal ("xmlreader_base64: reader is null");

  char* data = (char*) xmlreader_text (reader);
  if (reader->err != 0) return -1;

  if (data == NULL) {
    *result = NULL;
    *result = 0;
    return 0;
  }

  char* src = data;
  int len = strlen (src);

  *result = malloc (len / 4 * 3);
  if (*result == NULL)
    fatal ("xmlreader_base64: malloc failed");

  unsigned char* dst = *result;
  int dst_len = 0;
  
  while (len > 0) {
    int dlen = 4;
    unsigned char dbuf[4];
    int j = 0;
    for (j = 0; j < 4; j++) {
      if (len == 0) {
        reader->err = ERR_BASE64_DECODE;
        break;
      }

      unsigned char in = src[0];
      src++;
      len--;
      if (in == '=') {
        if (j == 0 || j == 1) {
          // incorrect padding
          reader->err = ERR_BASE64_DECODE;
          break;
        }
        if (j == 2) {
          // "==" is expected, the first "=" is already consumed.
          if (len == 0) {
            reader->err = ERR_BASE64_DECODE;
            break;
          }
          if (src[0] != '=') {
            // incorrect padding
            reader->err = ERR_BASE64_DECODE;
            break;
          }
          src++;
          len--;
        }
        if (len > 0) {
          // trailing garbage
          reader->err = ERR_BASE64_DECODE;
        }
        dlen = j;
        break;
      }
      dbuf[j] = (unsigned char) decoding_table[(int) in];
      if (dbuf[j] == 0xFF) {
        reader->err = ERR_BASE64_DECODE;
        break;
      }
    }
    if (reader->err != 0)
      break;
    
    switch (dlen) {
    case 4:
      dst[2] = (unsigned char) (dbuf[2] << 6 | dbuf[3]);
    case 3:
      dst[1] = (unsigned char) dbuf[1] << 4 | dbuf[2] >> 2;
    case 2:
      dst[0] = (unsigned char) dbuf[0]<< 2 | dbuf[1] >> 4;
    }
    dst += 3;
    dst_len += dlen - 1;
  }
  *result_len = dst_len;
  free (data);
  if (reader->err != 0) {
    return -1;
  }
  return 0;
}

xmlreader_nodetype_enum xmlreader_next (xmlreader_t* reader) {
  if (reader == NULL)
    fatal ("xmlreader_next: reader is null");

  reader->iterator++;
  if (reader->iterator == array_length (reader->stack))
    fatal ("xmlreader_next: iterator %d  exceeded stack's length %d", reader->iterator,
           array_length (reader->stack));
  
  struct xmlreader_token_t* child = array_get (reader->stack, reader->iterator);
  return child->type;
}
<file_sep>#ifndef _TYPES_H_
#define _TYPES_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <time.h>

#include <stdint.h>
#include <stdbool.h>

#include "stringpair.h"
#include "array.h"

enum extension_type;

typedef struct {
  int type;
  void* data;
} extension_t;

typedef stringpair_t langstring_t;

#define langstring_add(a,b,c) (stringpair_set((stringpair_t**) &(a), (b), (c)))

int langstring_decode (xmlreader_t* reader, langstring_t *map);
int langstring_encode (xmlwriter_t* writer, const char* space, const char* local, langstring_t *map);
void langstring_free (langstring_t* map);

struct tm* datetime_parse(const char* value);
const char* datetime_to_string(struct tm* data);

bool* strconv_parse_boolean(const char* value);
int *strconv_parse_int (const char* value);
uint32_t *strconv_parse_uint (const char* value);
uint64_t *strconv_parse_int64 (const char* value);

const char* strconv_format_boolean(bool* value);
const char* strconv_format_int(int32_t* value);
const char* strconv_format_uint(uint32_t* value);

#endif
<file_sep>#ifndef _ROSTER_DATA_H_
#define  _ROSTER_DATA_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <string.h>
#include "xstream.h"
#include "types.h"
#include "jid/jid.h"

struct roster_item_t;

extern const char *ns_roster;

enum roster_item_ask_t
{
  ROSTER_ITEM_ASK_SUBSCRIBE,
};

enum roster_item_ask_t enum_roster_item_ask_from_string (const char *value);
const char *enum_roster_item_ask_to_string (enum roster_item_ask_t);
enum roster_item_subscription_t
{
  ROSTER_ITEM_SUBSCRIPTION_BOTH,
  ROSTER_ITEM_SUBSCRIPTION_FROM,
  ROSTER_ITEM_SUBSCRIPTION_NONE,
  ROSTER_ITEM_SUBSCRIPTION_REMOVE,
  ROSTER_ITEM_SUBSCRIPTION_TO,
};

enum roster_item_subscription_t
enum_roster_item_subscription_from_string (const char *value);
const char *enum_roster_item_subscription_to_string (enum
						     roster_item_subscription_t);

struct roster_roster_t
{
  char *fVer;
  array_t *fItems;
};


struct roster_item_t
{
  bool *fApproved;
  enum roster_item_ask_t fAsk;
  jid_t *fJid;
  char *fName;
  enum roster_item_subscription_t fSubscription;
  array_t *fGroup;
};


struct roster_roster_t *roster_roster_decode (xmlreader_t * reader);
int roster_roster_encode (xmlwriter_t * writer, struct roster_roster_t *data);
void roster_roster_free (struct roster_roster_t *data);
struct roster_item_t *roster_item_decode (xmlreader_t * reader);
int roster_item_encode (xmlwriter_t * writer, struct roster_item_t *data);
void roster_item_free (struct roster_item_t *data);
#endif
<file_sep>#include "xep_disco_data.h"
#include "helpers.h"
#include "errors.h"

const char *ns_disco_info = "http://jabber.org/protocol/disco#info";
const char *ns_disco_items = "http://jabber.org/protocol/disco#items";

struct disco_info_info_t *
disco_info_info_decode (xmlreader_t * reader)
{
  struct disco_info_info_t *elm = NULL;
  elm = malloc (sizeof (struct disco_info_info_t));
  if (elm == NULL)
    fatal ("disco_info_info_t: malloc failed");
  memset (elm, 0, sizeof (struct disco_info_info_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "node");
  if (avalue != NULL)
    {
      elm->fNode = (char *) avalue;
    }
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (namespace, ns_disco_info) == 0)
	      && (strcmp (name, "identity") == 0))
	    {
	      struct disco_info_identity_t *newel =
		disco_info_identity_decode (reader);
	      if (newel == NULL)
		{
		  return NULL;
		}
	      if (elm->fIdentities == NULL)
		elm->fIdentities = array_new (sizeof (extension_t), 0);
	      array_append (elm->fIdentities, newel);
	    }
	  else if ((strcmp (namespace, ns_disco_info) == 0)
		   && (strcmp (name, "feature") == 0))
	    {
	      struct disco_info_feature_t *newel =
		disco_info_feature_decode (reader);
	      if (newel == NULL)
		{
		  return NULL;
		}
	      if (elm->fFeatures == NULL)
		elm->fFeatures = array_new (sizeof (extension_t), 0);
	      array_append (elm->fFeatures, newel);
	    }
	}
    }
  return elm;
}

int
disco_info_info_encode (xmlwriter_t * writer, struct disco_info_info_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_disco_info, "query");
  if (err != 0)
    return err;
  if (elm->fNode != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "node", elm->fNode);
      if (err != 0)
	return err;
    }
  {
    int len = array_length (elm->fIdentities);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	extension_t *ext = array_get (elm->fIdentities, i);
	err = disco_info_identity_encode (writer, ext->data);
	if (err != 0)
	  return err;
      }
  }
  {
    int len = array_length (elm->fFeatures);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	extension_t *ext = array_get (elm->fFeatures, i);
	err = disco_info_feature_encode (writer, ext->data);
	if (err != 0)
	  return err;
      }
  }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
disco_info_info_free (struct disco_info_info_t *data)
{
  if (data == NULL)
    return;
  if (data->fNode != NULL)
    {
      free (data->fNode);
    }
  {
    int len = array_length (data->fIdentities);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	disco_info_identity_free (array_get (data->fIdentities, i));
      }
    array_free (data->fIdentities);
  }
  {
    int len = array_length (data->fFeatures);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	disco_info_feature_free (array_get (data->fFeatures, i));
      }
    array_free (data->fFeatures);
  }
  free (data);
}

struct disco_info_identity_t *
disco_info_identity_decode (xmlreader_t * reader)
{
  struct disco_info_identity_t *elm = NULL;
  elm = malloc (sizeof (struct disco_info_identity_t));
  if (elm == NULL)
    fatal ("disco_info_identity_t: malloc failed");
  memset (elm, 0, sizeof (struct disco_info_identity_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "category");
  if (avalue != NULL)
    {
      elm->fCategory = (char *) avalue;
    }
  avalue = xmlreader_attribute (reader, NULL, "type");
  if (avalue != NULL)
    {
      elm->fType = (char *) avalue;
    }
  if (xmlreader_skip_element (reader) == -1)
    return NULL;
  return elm;
}

int
disco_info_identity_encode (xmlwriter_t * writer,
			    struct disco_info_identity_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_disco_info, "identity");
  if (err != 0)
    return err;
  if (elm->fCategory != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "category", elm->fCategory);
      if (err != 0)
	return err;
    }
  if (elm->fType != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "type", elm->fType);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
disco_info_identity_free (struct disco_info_identity_t *data)
{
  if (data == NULL)
    return;
  if (data->fCategory != NULL)
    {
      free (data->fCategory);
    }
  if (data->fType != NULL)
    {
      free (data->fType);
    }
  free (data);
}

struct disco_info_feature_t *
disco_info_feature_decode (xmlreader_t * reader)
{
  struct disco_info_feature_t *elm = NULL;
  elm = malloc (sizeof (struct disco_info_feature_t));
  if (elm == NULL)
    fatal ("disco_info_feature_t: malloc failed");
  memset (elm, 0, sizeof (struct disco_info_feature_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "var");
  if (avalue != NULL)
    {
      elm->fVar = (char *) avalue;
    }
  if (xmlreader_skip_element (reader) == -1)
    return NULL;
  return elm;
}

int
disco_info_feature_encode (xmlwriter_t * writer,
			   struct disco_info_feature_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_disco_info, "feature");
  if (err != 0)
    return err;
  if (elm->fVar != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "var", elm->fVar);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
disco_info_feature_free (struct disco_info_feature_t *data)
{
  if (data == NULL)
    return;
  if (data->fVar != NULL)
    {
      free (data->fVar);
    }
  free (data);
}
<file_sep>#include "xmppdata/session_data.h"
#include "iq.h"
#include "errors.h"

bool session_is_mandatory (stream_t* strm) {
  return false;
}

bool session_need_restart (void) {
  return false;
}

int session_negotate (stream_t* strm, account_t* account, void** data, extension_t* ext) {
  switch (ext->type) {
  case EXTENSION_TYPE_SESSION_SESSION: {
    struct session_session_t session;
    iq_t* iq = iq_new (strm, strm->jid, NULL, CLIENT_IQ_TYPE_SET, &session,
                       EXTENSION_TYPE_SESSION_SESSION);
    int err = client_iq_encode (&strm->writer, iq);
    if (err != 0) return err;
    iq_free (iq);
  
    err = xmlwriter_flush (&strm->writer);
    if (err != 0) return err;
    return 1;
  }
    
  case EXTENSION_TYPE_CLIENT_IQ: {
    iq_t* resp = ext->data;
    if (resp->fType == CLIENT_IQ_TYPE_RESULT) {
      return 0;
    }
    return ERR_BAD_PROTOCOL;
  }
  case EXTENSION_TYPE_STREAM_ERROR: {
    extension_t* error = malloc (sizeof (extension_t));
    memcpy (error, &ext, sizeof (extension_t));
    strm->xmpp_error = error;
    return ERR_XMPP_ERROR;
  }
  }
  return ERR_BAD_PROTOCOL;
}

struct stream_feature_t session_feature = {
  EXTENSION_TYPE_SESSION_SESSION,
  session_is_mandatory,
  session_need_restart,
  session_negotate
};
<file_sep>#include <string.h>
#include <malloc.h>

#include "stream.h"
#include "helpers.h"
#include "jid/jid.h"
#include "errors.h"
#include "helpers.h"
#include "hex.h"
#include "array.h"

#include "xmppdata/stream_data.h"

enum stream_state_enum {
  STREAM_STATE_NONE,
  STREAM_STATE_START,
  STREAM_STATE_WANT_FEATURES,
  STREAM_STATE_NEGOTATE,
  STREAM_STATE_ESTABLISHED
};

struct stream_features_data_t {
  uint8_t iterator;
  void* data;
  array_t* features;
};

stream_t* stream_new (int fd, const char* content_namespace, const char* lang,
                      bool logging, void* userdata) {
  stream_t* strm = malloc (sizeof (stream_t));
  if (strm == NULL)
    fatal ("stream_new: malloc failed");
  memset (strm, 0, sizeof (stream_t));

  strm->fd = fd;
  strm->state = STREAM_STATE_NONE;
  xmlwriter_init (&strm->writer, fd);
  xmlreader_init (&strm->reader);

  strm->content_namespace = content_namespace;
  int err = xmlwriter_set_prefix (&strm->writer, NULL, content_namespace);
  if (err != 0)
    fatal ("stream_new: cannot set default namespace");
  
  strm->lang = lang;
  strm->logging = logging;
  strm->userdata = userdata;
  memcpy (strm->id, "0", 1);

  strm->userdata = malloc (sizeof (struct stream_features_data_t));
  if (strm->userdata == NULL)
    fatal ("stream_new: malloc failed");
  memset (strm->userdata, 0, sizeof (struct stream_features_data_t));

  return strm;
}

const char* stream_get_id (stream_t* strm) {
  uint64_t id = hex_to_int (strm->id);
  id++;
  hex_of_int (strm->id, id);
  return strm->id;
}

int stream_start (stream_t* strm, account_t* account) {
  if (strm == NULL)
    fatal ("stream_start: strm is null");
  if (account == NULL)
    fatal ("stream_start: account is null");

  if (strm->state != STREAM_STATE_NONE)
    fatal ("stream_start: strm->state is not STREAM_STATE_NONE");
  
  int err = 0;
  
  err = xmlwriter_start_stream (&strm->writer);
  if (err != 0) return err;

  struct stream_start_t sst;
  sst.fTo = jid_of_string (account->jid->domain);
  sst.fFrom = NULL;
  sst.fId = NULL;
  sst.fLang = strm->lang;
  sst.fVersion = "1.0";
  
  err = stream_start_encode (&strm->writer, &sst);
  if (err != 0) return err;
  jid_free (sst.fTo);

  err = xmlwriter_flush (&strm->writer);
  if (err != 0) return err;

  strm->state = STREAM_STATE_START;
  return 0;
}

static extension_t* array_find (array_t* array, int type) {
  int len = array_length (array);
  int i = 0;
  extension_t* ext = NULL;
  for (i = 0; i < len; i++) {
    ext = array_get (array, i);
    if (ext->type == type)
      return ext;
  }
  return NULL;
}

struct stream_feature_t starttls_feature;
struct stream_feature_t sasl_feature;
struct stream_feature_t bind_feature;
struct stream_feature_t session_feature;

static struct stream_feature_t* knownfeatures[4] = {
  //  &starttls_feature,
  &sasl_feature,
  &bind_feature,
  &session_feature
};
static const int knownfeatures_len = 3;

int stream_process (stream_t* strm, account_t* account, extension_t* ext) {
  if (strm == NULL)
    fatal ("stream_start: strm is null");
  if (account == NULL)
    fatal ("stream_start: account is null");


  int err = 0;
  
  switch (strm->state) {
  case STREAM_STATE_NONE:
    fatal ("stream_process: strm->state is STREAM_STATE_NONE");
    
  case STREAM_STATE_START: {
    if (ext->type != EXTENSION_TYPE_STREAM_START) return ERR_BAD_PROTOCOL;
  
    struct stream_start_t* s = (struct stream_start_t*) ext->data;
    if (s->fVersion != NULL && strcmp (s->fVersion, "1.0") != 0) return ERR_XMPP_VERSION;
    stream_start_free (ext->data);
    strm->state = STREAM_STATE_WANT_FEATURES;
    break;
  }

  case STREAM_STATE_WANT_FEATURES: {
    if (ext->type != EXTENSION_TYPE_STREAM_FEATURES) return ERR_BAD_PROTOCOL;

    struct stream_features_data_t* stream_data = strm->userdata;
    stream_data->features = ext->data;

    uint8_t i = 0;
    for (i = stream_data->iterator; i < knownfeatures_len; i++ ) {
      extension_t* feature = array_find (stream_data->features, knownfeatures[i]->extension_type);
      if (feature == NULL) {
        if (knownfeatures[i]->is_mandatory(strm))
          return ERR_FEATURE_IS_REQUIRED;
        else
          continue;
      }
      strm->state = STREAM_STATE_NEGOTATE;
      stream_data->iterator = i;
      err = knownfeatures[i]->negotate (strm, account, &stream_data->data, feature);
      if (err == 1) return 0;
      if (err != 0) return err;
      return 0;
    }
    stream_features_free (stream_data->features);
    free (strm->userdata);
    strm->userdata = NULL;
    strm->state = STREAM_STATE_ESTABLISHED;
    break;
  }

  case STREAM_STATE_NEGOTATE: {
    struct stream_features_data_t* stream_data = strm->userdata;
    err = knownfeatures[stream_data->iterator]->negotate (strm, account, &stream_data->data, ext);
    xstream_extension_free (ext);
    if (err == 1) return 0;
    if (err != 0) return err;
    
    if (knownfeatures[stream_data->iterator]->need_to_restart()) {
      stream_features_free (stream_data->features);
      xmlreader_reset (&strm->reader);
      xmlwriter_reset (&strm->writer);
      int err = xmlwriter_set_prefix (&strm->writer, NULL, strm->content_namespace);
      if (err != 0)
        fatal ("stream_new: cannot set default namespace");
      stream_data->iterator++;
      strm->state = STREAM_STATE_NONE;
      return stream_start (strm, account);
    }

    stream_data->iterator++;

    uint8_t i = 0;
    for (i = stream_data->iterator; i < knownfeatures_len; i++) {
      extension_t* feature = array_find (stream_data->features, knownfeatures[i]->extension_type);
      if (feature == NULL) {
        if (knownfeatures[i]->is_mandatory(strm))
          return ERR_FEATURE_IS_REQUIRED;
        else
          continue;
      }
      strm->state = STREAM_STATE_NEGOTATE;
      stream_data->iterator = i;
      err = knownfeatures[i]->negotate (strm, account, &stream_data->data, feature);
      if (err == 1) return 0;
      if (err != 0) return err;
      break;
    }

    stream_features_free (stream_data->features);
    free (strm->userdata);
    strm->userdata = NULL;
    strm->state = STREAM_STATE_ESTABLISHED;
    return 0;
  }
    
  case STREAM_STATE_ESTABLISHED:
    if (strm->session_handler != NULL)
      strm->session_handler (strm, account, ext);
    xstream_extension_free (ext);
    // break;
    
  default:
    fatal ("Unknown stream state");
  }
  return 0;
}
<file_sep>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ustring.h"
#include "xmpp_prep.h"

int main(int argc, char *argv[]) {
  if (argc < 2)
    return -1;

  char *text = argv[1];
  ustring_t *ustring = malloc (sizeof (ustring_t));
  ustring->ucs4 = NULL;

  if (decode_utf8 (ustring, text, strlen(text)) < 0)
    printf ("error!\n");

  resourceprep (ustring);
  ustring_print (ustring);
  
  ustring_free (ustring);

  return 0;
}
      
<file_sep>#include "session_data.h"
#include "helpers.h"
#include "errors.h"

const char *ns_session = "urn:ietf:params:xml:ns:xmpp-session";

struct session_session_t *
session_session_decode (xmlreader_t * reader)
{
  struct session_session_t *elm = NULL;
  elm = malloc (sizeof (struct session_session_t));
  if (elm == NULL)
    fatal ("session_session_t: malloc failed");
  memset (elm, 0, sizeof (struct session_session_t));
  if (xmlreader_skip_element (reader) == -1)
    return NULL;
  return elm;
}

int
session_session_encode (xmlwriter_t * writer, struct session_session_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_session, "session");
  if (err != 0)
    return err;
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
session_session_free (struct session_session_t *data)
{
  if (data == NULL)
    return;
  free (data);
}
<file_sep>#include "client_data.h"
#include "helpers.h"
#include "errors.h"

const char *ns_client = "jabber:client";

struct client_iq_t *
client_iq_decode (xmlreader_t * reader)
{
  struct client_iq_t *elm = NULL;
  elm = malloc (sizeof (struct client_iq_t));
  if (elm == NULL)
    fatal ("client_iq_t: malloc failed");
  memset (elm, 0, sizeof (struct client_iq_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "from");
  if (avalue != NULL)
    {
      jid_t *jid = jid_of_string (avalue);
      elm->fFrom = jid;
    }
  avalue = xmlreader_attribute (reader, NULL, "to");
  if (avalue != NULL)
    {
      jid_t *jid = jid_of_string (avalue);
      elm->fTo = jid;
    }
  avalue = xmlreader_attribute (reader, NULL, "id");
  if (avalue != NULL)
    {
      elm->fId = (char *) avalue;
    }
  avalue = xmlreader_attribute (reader, NULL, "type");
  if (avalue != NULL)
    {
      elm->fType = enum_client_iq_type_from_string (avalue);
    }
  avalue = xmlreader_attribute (reader, NULL, "lang");
  if (avalue != NULL)
    {
      elm->fLang = (char *) avalue;
    }
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if (strcmp (namespace, ns_client) != 0)
	    {
	      extension_t *newel = malloc (sizeof (extension_t));
	      int err = xstream_extension_decode (reader, newel);
	      if (reader->err != 0)
		return NULL;
	      if (err == ERR_EXTENSION_NOT_FOUND)
		{
		  if (xmlreader_skip_element (reader) == -1)
		    return NULL;
		}
	      else
		{
		  elm->fPayload = newel;
		}
	    }
	  else
	    if ((strcmp (namespace, "urn:ietf:params:xml:ns:xmpp-stanzas") ==
		 0) && (strcmp (name, "error") == 0))
	    {
	      struct stanza_error_t *newel = stanza_error_decode (reader);
	      if (newel == NULL)
		{
		  return NULL;
		}
	      elm->fError = newel;
	    }
	}
    }
  return elm;
}

int
client_iq_encode (xmlwriter_t * writer, struct client_iq_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_client, "iq");
  if (err != 0)
    return err;
  if (elm->fFrom != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "from",
			     jid_to_string (elm->fFrom));
      if (err != 0)
	return err;
    }
  if (elm->fTo != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "to", jid_to_string (elm->fTo));
      if (err != 0)
	return err;
    }
  if (elm->fId != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "id", elm->fId);
      if (err != 0)
	return err;
    }
  if (elm->fType != 0)
    {
      err =
	xmlwriter_attribute (writer, NULL, "type",
			     enum_client_iq_type_to_string (elm->fType));
      if (err != 0)
	return err;
    }
  if (elm->fLang != NULL)
    {
      err = xmlwriter_attribute (writer, ns_xml, "lang", elm->fLang);
      if (err != 0)
	return err;
    }
  if (elm->fPayload != NULL)
    {
      err =
	xstream_extension_encode (writer, elm->fPayload->data,
				  elm->fPayload->type);
      if (err != 0)
	return err;
    }
  if (elm->fError != NULL)
    {
      err = stanza_error_encode (writer, elm->fError);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
client_iq_free (struct client_iq_t *data)
{
  if (data == NULL)
    return;
  if (data->fFrom != NULL)
    {
      jid_free (data->fFrom);
    }
  if (data->fTo != NULL)
    {
      jid_free (data->fTo);
    }
  if (data->fId != NULL)
    {
      free (data->fId);
    }
  if (data->fLang != NULL)
    {
      free (data->fLang);
    }
  if (data->fPayload != NULL)
    {
      xstream_extension_free (data->fPayload);
      free (data->fPayload);
    }
  if (data->fError != NULL)
    {
      stanza_error_free (data->fError);
    }
  free (data);
}

struct client_presence_t *
client_presence_decode (xmlreader_t * reader)
{
  struct client_presence_t *elm = NULL;
  elm = malloc (sizeof (struct client_presence_t));
  if (elm == NULL)
    fatal ("client_presence_t: malloc failed");
  memset (elm, 0, sizeof (struct client_presence_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "from");
  if (avalue != NULL)
    {
      jid_t *jid = jid_of_string (avalue);
      elm->fFrom = jid;
    }
  avalue = xmlreader_attribute (reader, NULL, "to");
  if (avalue != NULL)
    {
      jid_t *jid = jid_of_string (avalue);
      elm->fTo = jid;
    }
  avalue = xmlreader_attribute (reader, NULL, "id");
  if (avalue != NULL)
    {
      elm->fId = (char *) avalue;
    }
  avalue = xmlreader_attribute (reader, NULL, "type");
  if (avalue != NULL)
    {
      elm->fType = enum_client_presence_type_from_string (avalue);
    }
  avalue = xmlreader_attribute (reader, NULL, "lang");
  if (avalue != NULL)
    {
      elm->fLang = (char *) avalue;
    }
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "show") == 0)
	      && (strcmp (namespace, ns_client) == 0))
	    {
	      const char *s = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fShow = enum_client_presence_show_from_string (s);
	    }
	  else if ((strcmp (name, "status") == 0)
		   && (strcmp (namespace, ns_client) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fStatus = (char *) value;
	    }
	  else if ((strcmp (name, "priority") == 0)
		   && (strcmp (namespace, ns_client) == 0))
	    {
	      const char *s = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fPriority = strconv_parse_int (s);
	    }
	  else if (strcmp (namespace, ns_client) != 0)
	    {
	      extension_t ext;
	      int err = xstream_extension_decode (reader, &ext);
	      if (reader->err != 0)
		return NULL;
	      if (err == ERR_EXTENSION_NOT_FOUND)
		{
		  if (xmlreader_skip_element (reader) == -1)
		    return NULL;
		}
	      else
		{
		  if (elm->fX == NULL)
		    elm->fX = array_new (sizeof (extension_t), 0);
		  array_append (elm->fX, &ext);
		}
	    }
	  else
	    if ((strcmp (namespace, "urn:ietf:params:xml:ns:xmpp-stanzas") ==
		 0) && (strcmp (name, "error") == 0))
	    {
	      struct stanza_error_t *newel = stanza_error_decode (reader);
	      if (newel == NULL)
		{
		  return NULL;
		}
	      elm->fError = newel;
	    }
	}
    }
  return elm;
}

int
client_presence_encode (xmlwriter_t * writer, struct client_presence_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_client, "presence");
  if (err != 0)
    return err;
  if (elm->fFrom != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "from",
			     jid_to_string (elm->fFrom));
      if (err != 0)
	return err;
    }
  if (elm->fTo != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "to", jid_to_string (elm->fTo));
      if (err != 0)
	return err;
    }
  if (elm->fId != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "id", elm->fId);
      if (err != 0)
	return err;
    }
  if (elm->fType != 0)
    {
      err =
	xmlwriter_attribute (writer, NULL, "type",
			     enum_client_presence_type_to_string (elm->
								  fType));
      if (err != 0)
	return err;
    }
  if (elm->fLang != NULL)
    {
      err = xmlwriter_attribute (writer, ns_xml, "lang", elm->fLang);
      if (err != 0)
	return err;
    }
  if (elm->fShow != 0)
    {
      err =
	xmlwriter_simple_element (writer, ns_client, "show",
				  enum_client_presence_show_to_string (elm->
								       fShow));
      if (err != 0)
	return err;
    }
  if (elm->fStatus != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_client, "status", elm->fStatus);
      if (err != 0)
	return err;
    }
  if (elm->fPriority != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_client, "priority",
				  strconv_format_int (elm->fPriority));
      if (err != 0)
	return err;
    }
  {
    int len = array_length (elm->fX);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	extension_t *ext = array_get (elm->fX, i);
	err = xstream_extension_encode (writer, ext->data, ext->type);
	if (err != 0)
	  return err;
      }
  }
  if (elm->fError != NULL)
    {
      err = stanza_error_encode (writer, elm->fError);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
client_presence_free (struct client_presence_t *data)
{
  if (data == NULL)
    return;
  if (data->fFrom != NULL)
    {
      jid_free (data->fFrom);
    }
  if (data->fTo != NULL)
    {
      jid_free (data->fTo);
    }
  if (data->fId != NULL)
    {
      free (data->fId);
    }
  if (data->fLang != NULL)
    {
      free (data->fLang);
    }
  if (data->fShow != 0)
    {
    }
  if (data->fStatus != NULL)
    {
      free (data->fStatus);
    }
  if (data->fPriority != NULL)
    {
      free (data->fPriority);
    }
  {
    int len = array_length (data->fX);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	extension_t *ext = array_get (data->fX, i);
	xstream_extension_free (ext);
      }
    array_free (data->fX);
  }
  if (data->fError != NULL)
    {
      stanza_error_free (data->fError);
    }
  free (data);
}

struct client_message_t *
client_message_decode (xmlreader_t * reader)
{
  struct client_message_t *elm = NULL;
  elm = malloc (sizeof (struct client_message_t));
  if (elm == NULL)
    fatal ("client_message_t: malloc failed");
  memset (elm, 0, sizeof (struct client_message_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "from");
  if (avalue != NULL)
    {
      jid_t *jid = jid_of_string (avalue);
      elm->fFrom = jid;
    }
  avalue = xmlreader_attribute (reader, NULL, "to");
  if (avalue != NULL)
    {
      jid_t *jid = jid_of_string (avalue);
      elm->fTo = jid;
    }
  avalue = xmlreader_attribute (reader, NULL, "id");
  if (avalue != NULL)
    {
      elm->fId = (char *) avalue;
    }
  avalue = xmlreader_attribute (reader, NULL, "type");
  if (avalue != NULL)
    {
      elm->fType = enum_client_message_type_from_string (avalue);
    }
  avalue = xmlreader_attribute (reader, NULL, "lang");
  if (avalue != NULL)
    {
      elm->fLang = (char *) avalue;
    }
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "thread") == 0)
	      && (strcmp (namespace, ns_client) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fThread = (char *) value;
	    }
	  else if ((strcmp (name, "subject") == 0)
		   && (strcmp (namespace, ns_client) == 0))
	    {
	      langstring_decode (reader, elm->fSubject);
	    }
	  else if ((strcmp (name, "body") == 0)
		   && (strcmp (namespace, ns_client) == 0))
	    {
	      langstring_decode (reader, elm->fBody);
	    }
	  else if (strcmp (namespace, ns_client) != 0)
	    {
	      extension_t ext;
	      int err = xstream_extension_decode (reader, &ext);
	      if (reader->err != 0)
		return NULL;
	      if (err == ERR_EXTENSION_NOT_FOUND)
		{
		  if (xmlreader_skip_element (reader) == -1)
		    return NULL;
		}
	      else
		{
		  if (elm->fX == NULL)
		    elm->fX = array_new (sizeof (extension_t), 0);
		  array_append (elm->fX, &ext);
		}
	    }
	  else
	    if ((strcmp (namespace, "urn:ietf:params:xml:ns:xmpp-stanzas") ==
		 0) && (strcmp (name, "error") == 0))
	    {
	      struct stanza_error_t *newel = stanza_error_decode (reader);
	      if (newel == NULL)
		{
		  return NULL;
		}
	      elm->fError = newel;
	    }
	}
    }
  return elm;
}

int
client_message_encode (xmlwriter_t * writer, struct client_message_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_client, "message");
  if (err != 0)
    return err;
  if (elm->fFrom != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "from",
			     jid_to_string (elm->fFrom));
      if (err != 0)
	return err;
    }
  if (elm->fTo != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "to", jid_to_string (elm->fTo));
      if (err != 0)
	return err;
    }
  if (elm->fId != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "id", elm->fId);
      if (err != 0)
	return err;
    }
  if (elm->fType != 0)
    {
      err =
	xmlwriter_attribute (writer, NULL, "type",
			     enum_client_message_type_to_string (elm->fType));
      if (err != 0)
	return err;
    }
  if (elm->fLang != NULL)
    {
      err = xmlwriter_attribute (writer, ns_xml, "lang", elm->fLang);
      if (err != 0)
	return err;
    }
  if (elm->fThread != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_client, "thread", elm->fThread);
      if (err != 0)
	return err;
    }
  if (elm->fSubject != NULL)
    {
      err = langstring_encode (writer, ns_client, "subject", elm->fSubject);
      if (err != 0)
	return err;
    }
  if (elm->fBody != NULL)
    {
      err = langstring_encode (writer, ns_client, "body", elm->fBody);
      if (err != 0)
	return err;
    }
  {
    int len = array_length (elm->fX);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	extension_t *ext = array_get (elm->fX, i);
	err = xstream_extension_encode (writer, ext->data, ext->type);
	if (err != 0)
	  return err;
      }
  }
  if (elm->fError != NULL)
    {
      err = stanza_error_encode (writer, elm->fError);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
client_message_free (struct client_message_t *data)
{
  if (data == NULL)
    return;
  if (data->fFrom != NULL)
    {
      jid_free (data->fFrom);
    }
  if (data->fTo != NULL)
    {
      jid_free (data->fTo);
    }
  if (data->fId != NULL)
    {
      free (data->fId);
    }
  if (data->fLang != NULL)
    {
      free (data->fLang);
    }
  if (data->fThread != NULL)
    {
      free (data->fThread);
    }
  if (data->fSubject != NULL)
    {
      langstring_free (data->fSubject);
    }
  if (data->fBody != NULL)
    {
      langstring_free (data->fBody);
    }
  {
    int len = array_length (data->fX);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	extension_t *ext = array_get (data->fX, i);
	xstream_extension_free (ext);
      }
    array_free (data->fX);
  }
  if (data->fError != NULL)
    {
      stanza_error_free (data->fError);
    }
  free (data);
}

enum client_iq_type_t
enum_client_iq_type_from_string (const char *value)
{
  if (strcmp (value, "get") == 0)
    return CLIENT_IQ_TYPE_GET;
  else if (strcmp (value, "set") == 0)
    return CLIENT_IQ_TYPE_SET;
  else if (strcmp (value, "result") == 0)
    return CLIENT_IQ_TYPE_RESULT;
  else if (strcmp (value, "error") == 0)
    return CLIENT_IQ_TYPE_ERROR;
  return 0;
}

const char *
enum_client_iq_type_to_string (enum client_iq_type_t value)
{
  switch (value)
    {
    case CLIENT_IQ_TYPE_GET:
      return "get";
    case CLIENT_IQ_TYPE_SET:
      return "set";
    case CLIENT_IQ_TYPE_RESULT:
      return "result";
    case CLIENT_IQ_TYPE_ERROR:
      return "error";
    }
  return NULL;
}

enum client_presence_type_t
enum_client_presence_type_from_string (const char *value)
{
  if (strcmp (value, "subscribe") == 0)
    return CLIENT_PRESENCE_TYPE_SUBSCRIBE;
  else if (strcmp (value, "subscribed") == 0)
    return CLIENT_PRESENCE_TYPE_SUBSCRIBED;
  else if (strcmp (value, "unsubscribe") == 0)
    return CLIENT_PRESENCE_TYPE_UNSUBSCRIBE;
  else if (strcmp (value, "unsubscribed") == 0)
    return CLIENT_PRESENCE_TYPE_UNSUBSCRIBED;
  else if (strcmp (value, "unavailable") == 0)
    return CLIENT_PRESENCE_TYPE_UNAVAILABLE;
  return 0;
}

const char *
enum_client_presence_type_to_string (enum client_presence_type_t value)
{
  switch (value)
    {
    case CLIENT_PRESENCE_TYPE_SUBSCRIBE:
      return "subscribe";
    case CLIENT_PRESENCE_TYPE_SUBSCRIBED:
      return "subscribed";
    case CLIENT_PRESENCE_TYPE_UNSUBSCRIBE:
      return "unsubscribe";
    case CLIENT_PRESENCE_TYPE_UNSUBSCRIBED:
      return "unsubscribed";
    case CLIENT_PRESENCE_TYPE_UNAVAILABLE:
      return "unavailable";
    }
  return NULL;
}

enum client_presence_show_t
enum_client_presence_show_from_string (const char *value)
{
  if (strcmp (value, "chat") == 0)
    return CLIENT_PRESENCE_SHOW_CHAT;
  else if (strcmp (value, "away") == 0)
    return CLIENT_PRESENCE_SHOW_AWAY;
  else if (strcmp (value, "xa") == 0)
    return CLIENT_PRESENCE_SHOW_XA;
  else if (strcmp (value, "dnd") == 0)
    return CLIENT_PRESENCE_SHOW_DND;
  return 0;
}

const char *
enum_client_presence_show_to_string (enum client_presence_show_t value)
{
  switch (value)
    {
    case CLIENT_PRESENCE_SHOW_CHAT:
      return "chat";
    case CLIENT_PRESENCE_SHOW_AWAY:
      return "away";
    case CLIENT_PRESENCE_SHOW_XA:
      return "xa";
    case CLIENT_PRESENCE_SHOW_DND:
      return "dnd";
    }
  return NULL;
}

enum client_message_type_t
enum_client_message_type_from_string (const char *value)
{
  if (strcmp (value, "normal") == 0)
    return CLIENT_MESSAGE_TYPE_NORMAL;
  else if (strcmp (value, "chat") == 0)
    return CLIENT_MESSAGE_TYPE_CHAT;
  else if (strcmp (value, "groupchat") == 0)
    return CLIENT_MESSAGE_TYPE_GROUPCHAT;
  else if (strcmp (value, "headline") == 0)
    return CLIENT_MESSAGE_TYPE_HEADLINE;
  return 0;
}

const char *
enum_client_message_type_to_string (enum client_message_type_t value)
{
  switch (value)
    {
    case CLIENT_MESSAGE_TYPE_NORMAL:
      return "normal";
    case CLIENT_MESSAGE_TYPE_CHAT:
      return "chat";
    case CLIENT_MESSAGE_TYPE_GROUPCHAT:
      return "groupchat";
    case CLIENT_MESSAGE_TYPE_HEADLINE:
      return "headline";
    }
  return NULL;
}
<file_sep>#include <stdio.h>
#include <string.h>
#include "utf8.h"
#include "errors.h"

#include "ustring.h"
#include "helpers.h"

int ustring_decode_utf8 (ustring_t *ustring, const char *str, const size_t len) {
  if (ustring == NULL)
    fatal ("ustring_decode_utf8: ustring is null");
  if  (ustring->ucs4 != NULL)
    fatal ("ustring_decode_utf8: ustring->ucs4 is not null");
  
  int i = 0;
  int ulen = 0;
  
  for (i = 0; i < len; ) {
    int width = utf8_width ((uint8_t) str[i]);
    if (width < 1) return width;
    ulen += width;
    i += width;
  }
    
  ustring->ucs4 = malloc (sizeof (uint32_t) * ulen);
  if (ustring->ucs4 == NULL)
    fatal ("decode_utf8: malloc failed");

  ustring->len = ulen;

  uint32_t *p = ustring->ucs4;
  
  for (i = 0; i < len; i++) {
    uint8_t u1 = (uint8_t) str[i];
    int width = utf8_width (u1);
    switch (width) {
    case 1:
      *p++ = (uint32_t) u1;
      break;
    case 2: {
      uint8_t u2 = (uint8_t) str[++i];
      if (u2 >> 6 != 0b10)
        return ERR_MALFORMED_UTF8;
      else
        *p++ = ((u1 & 0x1f)  << 6) | (u2 & 0x3f);
      break;
    }
    case 3: {
      uint8_t u2 = (uint8_t) str[++i];
      uint8_t u3 = (uint8_t) str[++i];
      if ((u2 >> 6 != 0b10) || (u3 >> 6 != 0b10))
        return ERR_MALFORMED_UTF8;
      else {
        uint32_t code = 
          ((u1 & 0x0f) << 12) | ((u2 & 0x3f) < 6) | (u3 & 0x3f);
        if (code >= 0xd800 && code <= 0xdf00)
          return ERR_MALFORMED_UTF8;
        else
          *p++ = code;
      }
      break;
    }
    case 4: {
      uint8_t u2 = (uint8_t) str[++i];
      uint8_t u3 = (uint8_t) str[++i];
      uint8_t u4 = (uint8_t) str[++i];
      if ((u2 >> 6 != 0b10) || (u3 >> 6 != 0b10) || (u4 >> 6 != 0b10))
        return ERR_MALFORMED_UTF8;
      else
        *p++ = ((u1 & 0x07) << 18) | ((u2 & 0x3f) << 12) | ((u3 & 0x3f) << 6) | (u4 & 0x3f);
      break;
    }
    default:
      return ERR_MALFORMED_UTF8;
    }
  }
  return 0;
}
            
int ustring_encode_utf8 (ustring_t *ustring, char **out) {
  int i = 0;
  int len = 0;

  if (ustring == NULL)
    fatal ("ustring_encode_utf8: ustring is null");
  if (ustring->ucs4 == NULL || ustring->len == 0)
    fatal ("ustring_encode_utf8: ustring->ucs4 is null");

  for (i = 0; i < ustring->len; i++) {
    int width = utf8_width_of_uint32 (ustring->ucs4[i]);
    if (width < 1)
      return width;
    len += width;
  }

  *out = malloc (sizeof (uint8_t) * len + 1);
  if (*out == NULL)
    fatal ("ustring_encode_ut8: malloc failed");
  
  char* ptr = *out;
  
  for (i = 0; i < ustring->len; i++) {
    uint32_t ucs4 = ustring->ucs4[i];
  
    if (ucs4 < 0x80)
      *ptr++ = (char) ucs4;
    else if (ucs4 <= 0x7ff) {
      *ptr++ = (char) (0xc0 | (ucs4 >> 6));
      *ptr++ = (char) (0x80 | (ucs4 & 0x3f));
    } else if (ucs4 <= 0xffff) {
      if (ucs4 >= 0xd800 && ucs4 < 0xe000)
        return ERR_MALFORMED_UNICODE;
      *ptr++ = (char) (0xe0 | (ucs4 >> 12));
      *ptr++ = (char) (0x80 | ((ucs4 >> 6) & 0x3f));
      *ptr++ = (char) (0x80 | (ucs4 & 0x3f));
    }
    else if (ucs4 <= 0x10ffff) {
      *ptr++ = (char) (0xf0 | (ucs4 >> 18));
      *ptr++ = (char) (0x80 | ((ucs4 >> 12) & 0x3f));
      *ptr++ = (char) (0x80 | ((ucs4 >> 6)  & 0x3f));
      *ptr++ = (char) (0x80 | (ucs4 & 0x3f));
    }
    else 
      return ERR_MALFORMED_UNICODE;
  }
  *ptr = 0;
  return len;
}

void ustring_free (ustring_t *ustring) {
  if (ustring != NULL) {
    if (ustring->ucs4 != NULL)
      free (ustring->ucs4);
    free (ustring);
  }
}

void ustring_print_hex (ustring_t *ustring) {
  if (ustring == NULL)
    fatal ("ustring_print_hex: ustring is null");
  if (ustring->ucs4 == NULL)
    fatal ("ustring_print_hex: ustring->ucs4 is null");

  int i = 0;
  for (i = 0; i < ustring->len; i++)
    printf("%04X ", ustring->ucs4[i]);

  printf("\n");
}

void ustring_print (ustring_t *ustring) {
  if (ustring == NULL)
    fatal ("ustring_print: ustring is null");
  if (ustring->ucs4 == NULL)
    fatal ("ustring_print: ustring->ucs4 is null");
  
  char *result = NULL;
  size_t ret = ustring_encode_utf8 (ustring, &result);

  if (result == NULL || ret < 0) {
    printf ("another error!\n");
    return;
  }

  char *text2 = strndup (result, ret);
  printf ("result: %d %d '%s'\n", (int) ret, (int) ustring->len, text2);

  free (text2);
  free (result);
}

int ustring_compare (ustring_t *u1, ustring_t *u2) {
  if (u1 == NULL || u2 == NULL || u1->ucs4 == NULL || u2->ucs4 == NULL)
    return 0;
  if (u1->len != u2->len)
    return 0;

  if (memcmp (u1->ucs4, u2->ucs4, u1->len) == 0)
    return 1;
  return 0;
}
<file_sep>#include <yaml.h>

#include "config.h"
#include "jid/jid.h"

static void process_accounts(yaml_document_t *yaml_document, yaml_node_t *node, config_t *config) {
  int i;
  
  if (node->type == YAML_SEQUENCE_NODE) {
    // count
    for (i = 0; node->data.sequence.items.start + i < node->data.sequence.items.top; i++);
    if (i == 0)
      return;

    config->account_count = i;
    config->accounts = malloc (sizeof (account_t) * i);
    memset (config->accounts, 0, (sizeof (account_t) * i));
    account_t *accounts = config->accounts;
      
    for (i = 0; node->data.sequence.items.start + i < node->data.sequence.items.top; i++) {
      yaml_node_t *subnode =
        yaml_document_get_node (yaml_document, node->data.sequence.items.start[i]);
      if (subnode->type == YAML_MAPPING_NODE) {
        yaml_node_pair_t *pair = subnode->data.mapping.pairs.start;
        do {
          yaml_node_t *key_node = yaml_document_get_node (yaml_document, pair->key);
          if (strcmp ("jid", (char *) key_node->data.scalar.value) == 0) {
            yaml_node_t *value_node = yaml_document_get_node (yaml_document, pair->value);
            jid_t *jid = jid_of_string ((char *) value_node->data.scalar.value);
            accounts[i].jid = jid;
          } else if (strcmp ("password", (char *) key_node->data.scalar.value) == 0) {
            yaml_node_t *value_node = yaml_document_get_node (yaml_document, pair->value);
            accounts[i].password = strdup ((char *) value_node->data.scalar.value);
          } else if (strcmp ("ip", (char *) key_node->data.scalar.value) == 0) {
            yaml_node_t *value_node = yaml_document_get_node (yaml_document, pair->value);
            accounts[i].ip = strdup ((char *) value_node->data.scalar.value);
          } else if (strcmp ("port", (char *) key_node->data.scalar.value) == 0) {
            yaml_node_t *value_node = yaml_document_get_node (yaml_document, pair->value);
            accounts[i].port = atoi ((char *) value_node->data.scalar.value);
          }
        } while (pair++, pair < subnode->data.mapping.pairs.top);
      } 
    }
  }
}

config_t *config_load (const char* filename) {
  FILE *fh;
  yaml_parser_t yaml_parser;
  yaml_document_t yaml_document;
  config_t *config;

  fh = fopen ("config.yaml", "r");
  if (fh == NULL) {
    fputs ("Failed to open file!\n", stderr);
    return NULL;
  }

  if (!yaml_parser_initialize (&yaml_parser)) {
    fputs ("Failed to initialize parser!\n", stderr);
    goto error;
  }
  yaml_parser_set_input_file (&yaml_parser, fh);
  yaml_parser_load(&yaml_parser, &yaml_document);

  config = malloc (sizeof (config_t));

  yaml_node_t *root = yaml_document_get_root_node (&yaml_document);
  if (!root)
    goto error;
  
  if (root->type == YAML_MAPPING_NODE) {
    yaml_node_pair_t *pair = root->data.mapping.pairs.start;
    do {
      yaml_node_t *key_node = yaml_document_get_node (&yaml_document, pair->key);
      if (strcmp ("accounts", (char *) key_node->data.scalar.value) >= 0) {
        yaml_node_t *node = yaml_document_get_node (&yaml_document, pair->value);
        process_accounts (&yaml_document, node, config);
      }

    } while (pair++, pair < root->data.mapping.pairs.top);
  } 

  fclose (fh);
  yaml_document_delete( &yaml_document);
  yaml_parser_delete (&yaml_parser);

  return config;

 error:

  fclose (fh);
  yaml_document_delete( &yaml_document);
  yaml_parser_delete (&yaml_parser);
  config_destroy (config);
  return NULL;
}

void config_destroy (config_t *config) {
  if (config != NULL) {
    if (config->accounts != NULL) {
      int i;
      for (i = 0; i < config->account_count; i++) {
        account_t *account = &config->accounts[i];
        if (account->jid != NULL)
          jid_free (account->jid);
        if (account->password != NULL)
          free (account->password);
        if (account->ip != NULL)
          free (account->ip);
      }
      free (config->accounts);
    }
    free (config);
  }
}
<file_sep>#include "hex.h"
#include "helpers.h"

void hex_of_binary (char* out, unsigned char* in, int in_len) {
  static const char* hextable = "0123456789abcdef";

  int i = 0;
  for (i = 0; i < in_len; i++) {
    *out++ = hextable[(*in >> 4) & 0xF];
    *out++ = hextable[(*in++) & 0xF];
  }
  *out = '\0';
}

void hex_of_int (char* out, uint64_t in) {
  static const char* hextable = "0123456789abcdef";

  int i = 0;
  for (i = 0; i < 64; i += 4) {
    if ((in >> i) == 0) break;
  }
  if (i > 4)
    i -= 4;
  
  for (; i >= 0; i -= 4) {
    *out++ = hextable[(in >> i) & 0xF];
  }
  *out = '\0';
}

uint64_t hex_to_int (const char* str) {
  uint64_t out = 0;
  char* ptr = (char*) str;

  while (1) {
    uint8_t i = 0;
    if (*ptr >= '0' && *ptr <= '9')
      i = *ptr - 48;
    else if (*ptr >= 'a' && *ptr <= 'f')
      i = *ptr - 39;
    else if (*ptr >= 'A' && *ptr <= 'F')
      i = *ptr - 55;
    else
      fatal ("hex_to_int: invalid input: %c", *ptr);
    out |= i;
    ptr++;
    if (*ptr == 0)
      break;
    out <<= 4;
  }
    
  return out;
}
<file_sep>#ifndef _XEP_CAPTCHA_DATA_H_
#define  _XEP_CAPTCHA_DATA_H_

#include "xmlreader.h"
#include "xmlwriter.h"
#include <string.h>
#include "xstream.h"
#include "types.h"
#include "xep_xdata_data.h"


extern const char *ns_captcha;


struct captcha_captcha_t
{
  struct xdata_x_t *fXdata;
};


struct captcha_captcha_t *captcha_captcha_decode (xmlreader_t * reader);
int captcha_captcha_encode (xmlwriter_t * writer,
			    struct captcha_captcha_t *data);
void captcha_captcha_free (struct captcha_captcha_t *data);
#endif
<file_sep>#include "xep_muc_data.h"
#include "helpers.h"
#include "errors.h"

const char *ns_muc = "http://jabber.org/protocol/muc";
const char *ns_muc_user = "http://jabber.org/protocol/muc#user";
const char *ns_muc_owner = "http://jabber.org/protocol/muc#owner";
const char *ns_muc_admin = "http://jabber.org/protocol/muc#admin";

struct muc_enter_t *
muc_enter_decode (xmlreader_t * reader)
{
  struct muc_enter_t *elm = NULL;
  elm = malloc (sizeof (struct muc_enter_t));
  if (elm == NULL)
    fatal ("muc_enter_t: malloc failed");
  memset (elm, 0, sizeof (struct muc_enter_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "history") == 0)
	      && (strcmp (namespace, ns_muc) == 0))
	    {
	      const char *avalue;
	      avalue = xmlreader_attribute (reader, NULL, "maxchars");
	      if (avalue != NULL)
		{
		  elm->fHistory.fMaxchars = strconv_parse_int (avalue);
		}
	      avalue = xmlreader_attribute (reader, NULL, "maxstanzas");
	      if (avalue != NULL)
		{
		  elm->fHistory.fMaxstanzas = strconv_parse_int (avalue);
		}
	      avalue = xmlreader_attribute (reader, NULL, "seconds");
	      if (avalue != NULL)
		{
		  elm->fHistory.fSeconds = strconv_parse_int (avalue);
		}
	      avalue = xmlreader_attribute (reader, NULL, "since");
	      if (avalue != NULL)
		{
		  elm->fHistory.fSince = datetime_parse (avalue);
		}
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	    }
	  else if ((strcmp (name, "password") == 0)
		   && (strcmp (namespace, ns_muc) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fPassword = (char *) value;
	    }
	}
    }
  return elm;
}

int
muc_enter_encode (xmlwriter_t * writer, struct muc_enter_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_muc, "x");
  if (err != 0)
    return err;
  err = xmlwriter_start_element (writer, ns_muc, "history");
  if (err != 0)
    return err;
  if (elm->fHistory.fMaxchars != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "maxchars",
			     strconv_format_int (elm->fHistory.fMaxchars));
      if (err != 0)
	return err;
    }
  if (elm->fHistory.fMaxstanzas != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "maxstanzas",
			     strconv_format_int (elm->fHistory.fMaxstanzas));
      if (err != 0)
	return err;
    }
  if (elm->fHistory.fSeconds != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "seconds",
			     strconv_format_int (elm->fHistory.fSeconds));
      if (err != 0)
	return err;
    }
  if (elm->fHistory.fSince != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "since",
			     datetime_to_string (elm->fHistory.fSince));
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  if (elm->fPassword != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_muc, "password", elm->fPassword);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
muc_enter_free (struct muc_enter_t *data)
{
  if (data == NULL)
    return;
  if (data->fHistory.fMaxchars != NULL)
    {
      free (data->fHistory.fMaxchars);
    }
  if (data->fHistory.fMaxstanzas != NULL)
    {
      free (data->fHistory.fMaxstanzas);
    }
  if (data->fHistory.fSeconds != NULL)
    {
      free (data->fHistory.fSeconds);
    }
  if (data->fHistory.fSince != NULL)
    {
      free (data->fHistory.fSince);
    }
  if (data->fPassword != NULL)
    {
      free (data->fPassword);
    }
  free (data);
}

struct muc_user_action_t *
muc_user_action_decode (xmlreader_t * reader)
{
  struct muc_user_action_t *elm = NULL;
  elm = malloc (sizeof (struct muc_user_action_t));
  if (elm == NULL)
    fatal ("muc_user_action_t: malloc failed");
  memset (elm, 0, sizeof (struct muc_user_action_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (namespace, ns_muc_user) == 0)
	      && (strcmp (name, "invite") == 0))
	    {
	      struct muc_user_invite_t *newel =
		muc_user_invite_decode (reader);
	      if (newel == NULL)
		{
		  return NULL;
		}
	      if (elm->fInvite == NULL)
		elm->fInvite = array_new (sizeof (extension_t), 0);
	      array_append (elm->fInvite, newel);
	    }
	  else if ((strcmp (name, "password") == 0)
		   && (strcmp (namespace, ns_muc_user) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fPassword = (char *) value;
	    }
	  else if ((strcmp (namespace, ns_muc_user) == 0)
		   && (strcmp (name, "status") == 0))
	    {
	      struct muc_user_status_t *newel =
		muc_user_status_decode (reader);
	      if (newel == NULL)
		{
		  return NULL;
		}
	      if (elm->fStatus == NULL)
		elm->fStatus = array_new (sizeof (extension_t), 0);
	      array_append (elm->fStatus, newel);
	    }
	}
    }
  return elm;
}

int
muc_user_action_encode (xmlwriter_t * writer, struct muc_user_action_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_muc_user, "x");
  if (err != 0)
    return err;
  if (elm->fDecline != NULL)
    {
      err = muc_user_decline_encode (writer, elm->fDecline);
      if (err != 0)
	return err;
    }
  if (elm->fDestroy != NULL)
    {
      err = muc_user_destroy_encode (writer, elm->fDestroy);
      if (err != 0)
	return err;
    }
  {
    int len = array_length (elm->fInvite);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	extension_t *ext = array_get (elm->fInvite, i);
	err = muc_user_invite_encode (writer, ext->data);
	if (err != 0)
	  return err;
      }
  }
  if (elm->fItem != NULL)
    {
      err = muc_user_item_encode (writer, elm->fItem);
      if (err != 0)
	return err;
    }
  if (elm->fPassword != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_muc_user, "password",
				  elm->fPassword);
      if (err != 0)
	return err;
    }
  {
    int len = array_length (elm->fStatus);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	extension_t *ext = array_get (elm->fStatus, i);
	err = muc_user_status_encode (writer, ext->data);
	if (err != 0)
	  return err;
      }
  }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
muc_user_action_free (struct muc_user_action_t *data)
{
  if (data == NULL)
    return;
  if (data->fDecline != NULL)
    {
    }
  if (data->fDestroy != NULL)
    {
    }
  {
    int len = array_length (data->fInvite);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	muc_user_invite_free (array_get (data->fInvite, i));
      }
    array_free (data->fInvite);
  }
  if (data->fItem != NULL)
    {
    }
  if (data->fPassword != NULL)
    {
      free (data->fPassword);
    }
  {
    int len = array_length (data->fStatus);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	muc_user_status_free (array_get (data->fStatus, i));
      }
    array_free (data->fStatus);
  }
  free (data);
}

struct muc_user_status_t *
muc_user_status_decode (xmlreader_t * reader)
{
  struct muc_user_status_t *elm = NULL;
  elm = malloc (sizeof (struct muc_user_status_t));
  if (elm == NULL)
    fatal ("muc_user_status_t: malloc failed");
  memset (elm, 0, sizeof (struct muc_user_status_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "code");
  if (avalue != NULL)
    {
      elm->fCode = strconv_parse_int (avalue);
    }
  if (xmlreader_skip_element (reader) == -1)
    return NULL;
  return elm;
}

int
muc_user_status_encode (xmlwriter_t * writer, struct muc_user_status_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_muc_user, "status");
  if (err != 0)
    return err;
  if (elm->fCode != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "code",
			     strconv_format_int (elm->fCode));
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
muc_user_status_free (struct muc_user_status_t *data)
{
  if (data == NULL)
    return;
  if (data->fCode != NULL)
    {
      free (data->fCode);
    }
  free (data);
}

struct muc_user_decline_t *
muc_user_decline_decode (xmlreader_t * reader)
{
  struct muc_user_decline_t *elm = NULL;
  elm = malloc (sizeof (struct muc_user_decline_t));
  if (elm == NULL)
    fatal ("muc_user_decline_t: malloc failed");
  memset (elm, 0, sizeof (struct muc_user_decline_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "from");
  if (avalue != NULL)
    {
      jid_t *jid = jid_of_string (avalue);
      elm->fFrom = jid;
    }
  avalue = xmlreader_attribute (reader, NULL, "to");
  if (avalue != NULL)
    {
      jid_t *jid = jid_of_string (avalue);
      elm->fTo = jid;
    }
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "reason") == 0)
	      && (strcmp (namespace, ns_muc_user) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fReason = (char *) value;
	    }
	}
    }
  return elm;
}

int
muc_user_decline_encode (xmlwriter_t * writer, struct muc_user_decline_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_muc_user, "decline");
  if (err != 0)
    return err;
  if (elm->fFrom != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "from",
			     jid_to_string (elm->fFrom));
      if (err != 0)
	return err;
    }
  if (elm->fTo != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "to", jid_to_string (elm->fTo));
      if (err != 0)
	return err;
    }
  if (elm->fReason != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_muc_user, "reason",
				  elm->fReason);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
muc_user_decline_free (struct muc_user_decline_t *data)
{
  if (data == NULL)
    return;
  if (data->fFrom != NULL)
    {
      jid_free (data->fFrom);
    }
  if (data->fTo != NULL)
    {
      jid_free (data->fTo);
    }
  if (data->fReason != NULL)
    {
      free (data->fReason);
    }
  free (data);
}

struct muc_user_destroy_t *
muc_user_destroy_decode (xmlreader_t * reader)
{
  struct muc_user_destroy_t *elm = NULL;
  elm = malloc (sizeof (struct muc_user_destroy_t));
  if (elm == NULL)
    fatal ("muc_user_destroy_t: malloc failed");
  memset (elm, 0, sizeof (struct muc_user_destroy_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "jid");
  if (avalue != NULL)
    {
      jid_t *jid = jid_of_string (avalue);
      elm->fJid = jid;
    }
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "reason") == 0)
	      && (strcmp (namespace, ns_muc_user) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fReason = (char *) value;
	    }
	}
    }
  return elm;
}

int
muc_user_destroy_encode (xmlwriter_t * writer, struct muc_user_destroy_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_muc_user, "destroy");
  if (err != 0)
    return err;
  if (elm->fJid != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "jid", jid_to_string (elm->fJid));
      if (err != 0)
	return err;
    }
  if (elm->fReason != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_muc_user, "reason",
				  elm->fReason);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
muc_user_destroy_free (struct muc_user_destroy_t *data)
{
  if (data == NULL)
    return;
  if (data->fJid != NULL)
    {
      jid_free (data->fJid);
    }
  if (data->fReason != NULL)
    {
      free (data->fReason);
    }
  free (data);
}

struct muc_user_invite_t *
muc_user_invite_decode (xmlreader_t * reader)
{
  struct muc_user_invite_t *elm = NULL;
  elm = malloc (sizeof (struct muc_user_invite_t));
  if (elm == NULL)
    fatal ("muc_user_invite_t: malloc failed");
  memset (elm, 0, sizeof (struct muc_user_invite_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "from");
  if (avalue != NULL)
    {
      jid_t *jid = jid_of_string (avalue);
      elm->fFrom = jid;
    }
  avalue = xmlreader_attribute (reader, NULL, "to");
  if (avalue != NULL)
    {
      jid_t *jid = jid_of_string (avalue);
      elm->fTo = jid;
    }
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "reason") == 0)
	      && (strcmp (namespace, ns_muc_user) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fReason = (char *) value;
	    }
	}
    }
  return elm;
}

int
muc_user_invite_encode (xmlwriter_t * writer, struct muc_user_invite_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_muc_user, "invite");
  if (err != 0)
    return err;
  if (elm->fFrom != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "from",
			     jid_to_string (elm->fFrom));
      if (err != 0)
	return err;
    }
  if (elm->fTo != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "to", jid_to_string (elm->fTo));
      if (err != 0)
	return err;
    }
  if (elm->fReason != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_muc_user, "reason",
				  elm->fReason);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
muc_user_invite_free (struct muc_user_invite_t *data)
{
  if (data == NULL)
    return;
  if (data->fFrom != NULL)
    {
      jid_free (data->fFrom);
    }
  if (data->fTo != NULL)
    {
      jid_free (data->fTo);
    }
  if (data->fReason != NULL)
    {
      free (data->fReason);
    }
  free (data);
}

struct muc_user_item_t *
muc_user_item_decode (xmlreader_t * reader)
{
  struct muc_user_item_t *elm = NULL;
  elm = malloc (sizeof (struct muc_user_item_t));
  if (elm == NULL)
    fatal ("muc_user_item_t: malloc failed");
  memset (elm, 0, sizeof (struct muc_user_item_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "affiliation");
  if (avalue != NULL)
    {
      elm->fAffiliation = enum_muc_user_item_affiliation_from_string (avalue);
    }
  avalue = xmlreader_attribute (reader, NULL, "jid");
  if (avalue != NULL)
    {
      jid_t *jid = jid_of_string (avalue);
      elm->fJid = jid;
    }
  avalue = xmlreader_attribute (reader, NULL, "nick");
  if (avalue != NULL)
    {
      elm->fNick = (char *) avalue;
    }
  avalue = xmlreader_attribute (reader, NULL, "role");
  if (avalue != NULL)
    {
      elm->fRole = enum_muc_user_item_role_from_string (avalue);
    }
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "actor") == 0)
	      && (strcmp (namespace, ns_muc_user) == 0))
	    {
	      const char *avalue;
	      avalue = xmlreader_attribute (reader, NULL, "jid");
	      if (avalue != NULL)
		{
		  jid_t *jid = jid_of_string (avalue);
		  elm->fActor.fJid = jid;
		}
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	    }
	  else if ((strcmp (name, "reason") == 0)
		   && (strcmp (namespace, ns_muc_user) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fReason = (char *) value;
	    }
	  else if ((strcmp (name, "continue") == 0)
		   && (strcmp (namespace, ns_muc_user) == 0))
	    {
	      elm->fContinue = true;
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	      continue;
	    }
	}
    }
  return elm;
}

int
muc_user_item_encode (xmlwriter_t * writer, struct muc_user_item_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_muc_user, "item");
  if (err != 0)
    return err;
  if (elm->fAffiliation != 0)
    {
      err =
	xmlwriter_attribute (writer, NULL, "affiliation",
			     enum_muc_user_item_affiliation_to_string (elm->
								       fAffiliation));
      if (err != 0)
	return err;
    }
  if (elm->fJid != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "jid", jid_to_string (elm->fJid));
      if (err != 0)
	return err;
    }
  if (elm->fNick != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "nick", elm->fNick);
      if (err != 0)
	return err;
    }
  if (elm->fRole != 0)
    {
      err =
	xmlwriter_attribute (writer, NULL, "role",
			     enum_muc_user_item_role_to_string (elm->fRole));
      if (err != 0)
	return err;
    }
  err = xmlwriter_start_element (writer, ns_muc_user, "actor");
  if (err != 0)
    return err;
  if (elm->fActor.fJid != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "jid",
			     jid_to_string (elm->fActor.fJid));
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  if (elm->fReason != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_muc_user, "reason",
				  elm->fReason);
      if (err != 0)
	return err;
    }
  if (elm->fContinue)
    {
      err = xmlwriter_simple_element (writer, ns_muc_user, "continue", NULL);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
muc_user_item_free (struct muc_user_item_t *data)
{
  if (data == NULL)
    return;
  if (data->fJid != NULL)
    {
      jid_free (data->fJid);
    }
  if (data->fNick != NULL)
    {
      free (data->fNick);
    }
  if (data->fActor.fJid != NULL)
    {
      jid_free (data->fActor.fJid);
    }
  if (data->fReason != NULL)
    {
      free (data->fReason);
    }
  if (data->fContinue)
    {
    }
  free (data);
}

enum muc_user_item_affiliation_t
enum_muc_user_item_affiliation_from_string (const char *value)
{
  if (strcmp (value, "admin") == 0)
    return MUC_USER_ITEM_AFFILIATION_ADMIN;
  else if (strcmp (value, "member") == 0)
    return MUC_USER_ITEM_AFFILIATION_MEMBER;
  else if (strcmp (value, "none") == 0)
    return MUC_USER_ITEM_AFFILIATION_NONE;
  else if (strcmp (value, "outcast") == 0)
    return MUC_USER_ITEM_AFFILIATION_OUTCAST;
  else if (strcmp (value, "owner") == 0)
    return MUC_USER_ITEM_AFFILIATION_OWNER;
  return 0;
}

const char *
enum_muc_user_item_affiliation_to_string (enum muc_user_item_affiliation_t
					  value)
{
  switch (value)
    {
    case MUC_USER_ITEM_AFFILIATION_ADMIN:
      return "admin";
    case MUC_USER_ITEM_AFFILIATION_MEMBER:
      return "member";
    case MUC_USER_ITEM_AFFILIATION_NONE:
      return "none";
    case MUC_USER_ITEM_AFFILIATION_OUTCAST:
      return "outcast";
    case MUC_USER_ITEM_AFFILIATION_OWNER:
      return "owner";
    }
  return NULL;
}

enum muc_user_item_role_t
enum_muc_user_item_role_from_string (const char *value)
{
  if (strcmp (value, "moderator") == 0)
    return MUC_USER_ITEM_ROLE_MODERATOR;
  else if (strcmp (value, "none") == 0)
    return MUC_USER_ITEM_ROLE_NONE;
  else if (strcmp (value, "participant") == 0)
    return MUC_USER_ITEM_ROLE_PARTICIPANT;
  else if (strcmp (value, "visitor") == 0)
    return MUC_USER_ITEM_ROLE_VISITOR;
  return 0;
}

const char *
enum_muc_user_item_role_to_string (enum muc_user_item_role_t value)
{
  switch (value)
    {
    case MUC_USER_ITEM_ROLE_MODERATOR:
      return "moderator";
    case MUC_USER_ITEM_ROLE_NONE:
      return "none";
    case MUC_USER_ITEM_ROLE_PARTICIPANT:
      return "participant";
    case MUC_USER_ITEM_ROLE_VISITOR:
      return "visitor";
    }
  return NULL;
}

muc_owner_configure_t *
muc_owner_configure_decode (xmlreader_t * reader)
{
  muc_owner_configure_t *elm = NULL;
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *name = xmlreader_get_name (reader);
	  const char *namespace = xmlreader_get_namespace (reader);
	  if ((strcmp (namespace, "jabber:x:data") == 0)
	      && (strcmp (name, "x") == 0))
	    {
	      muc_owner_configure_t *newel = xdata_x_decode (reader);
	      if (newel == NULL)
		return NULL;
	      elm = (muc_owner_configure_t *) newel;
	    }
	  else
	    {
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	    }
	}
    }
  return elm;
}

int
muc_owner_configure_encode (xmlwriter_t * writer, muc_owner_configure_t * elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_muc_owner, "query");
  if (err != 0)
    return err;
  err = xdata_x_encode (writer, elm);
  if (err != 0)
    return err;
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
muc_owner_configure_free (muc_owner_configure_t * data)
{
  if (data == NULL)
    return;
  xdata_x_free (data);
  free (data);
}

struct muc_admin_query_t *
muc_admin_query_decode (xmlreader_t * reader)
{
  struct muc_admin_query_t *elm = NULL;
  elm = malloc (sizeof (struct muc_admin_query_t));
  if (elm == NULL)
    fatal ("muc_admin_query_t: malloc failed");
  memset (elm, 0, sizeof (struct muc_admin_query_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (namespace, ns_muc_admin) == 0)
	      && (strcmp (name, "item") == 0))
	    {
	      struct muc_admin_item_t *newel = muc_admin_item_decode (reader);
	      if (newel == NULL)
		{
		  return NULL;
		}
	      if (elm->fItems == NULL)
		elm->fItems = array_new (sizeof (extension_t), 0);
	      array_append (elm->fItems, newel);
	    }
	}
    }
  return elm;
}

int
muc_admin_query_encode (xmlwriter_t * writer, struct muc_admin_query_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_muc_admin, "query");
  if (err != 0)
    return err;
  {
    int len = array_length (elm->fItems);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	extension_t *ext = array_get (elm->fItems, i);
	err = muc_admin_item_encode (writer, ext->data);
	if (err != 0)
	  return err;
      }
  }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
muc_admin_query_free (struct muc_admin_query_t *data)
{
  if (data == NULL)
    return;
  {
    int len = array_length (data->fItems);
    int i = 0;
    for (i = 0; i < len; i++)
      {
	muc_admin_item_free (array_get (data->fItems, i));
      }
    array_free (data->fItems);
  }
  free (data);
}

struct muc_admin_item_t *
muc_admin_item_decode (xmlreader_t * reader)
{
  struct muc_admin_item_t *elm = NULL;
  elm = malloc (sizeof (struct muc_admin_item_t));
  if (elm == NULL)
    fatal ("muc_admin_item_t: malloc failed");
  memset (elm, 0, sizeof (struct muc_admin_item_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "affiliation");
  if (avalue != NULL)
    {
      elm->fAffiliation =
	enum_muc_admin_item_affiliation_from_string (avalue);
    }
  avalue = xmlreader_attribute (reader, NULL, "jid");
  if (avalue != NULL)
    {
      jid_t *jid = jid_of_string (avalue);
      elm->fJid = jid;
    }
  avalue = xmlreader_attribute (reader, NULL, "nick");
  if (avalue != NULL)
    {
      elm->fNick = (char *) avalue;
    }
  avalue = xmlreader_attribute (reader, NULL, "role");
  if (avalue != NULL)
    {
      elm->fRole = enum_muc_admin_item_role_from_string (avalue);
    }
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "actor") == 0)
	      && (strcmp (namespace, ns_muc_admin) == 0))
	    {
	      const char *avalue;
	      avalue = xmlreader_attribute (reader, NULL, "jid");
	      if (avalue != NULL)
		{
		  jid_t *jid = jid_of_string (avalue);
		  elm->fActor.fJid = jid;
		}
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	    }
	  else if ((strcmp (name, "reason") == 0)
		   && (strcmp (namespace, ns_muc_admin) == 0))
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fReason = (char *) value;
	    }
	}
    }
  return elm;
}

int
muc_admin_item_encode (xmlwriter_t * writer, struct muc_admin_item_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_muc_admin, "item");
  if (err != 0)
    return err;
  if (elm->fAffiliation != 0)
    {
      err =
	xmlwriter_attribute (writer, NULL, "affiliation",
			     enum_muc_admin_item_affiliation_to_string (elm->
									fAffiliation));
      if (err != 0)
	return err;
    }
  if (elm->fJid != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "jid", jid_to_string (elm->fJid));
      if (err != 0)
	return err;
    }
  if (elm->fNick != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "nick", elm->fNick);
      if (err != 0)
	return err;
    }
  if (elm->fRole != 0)
    {
      err =
	xmlwriter_attribute (writer, NULL, "role",
			     enum_muc_admin_item_role_to_string (elm->fRole));
      if (err != 0)
	return err;
    }
  err = xmlwriter_start_element (writer, ns_muc_admin, "actor");
  if (err != 0)
    return err;
  if (elm->fActor.fJid != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "jid",
			     jid_to_string (elm->fActor.fJid));
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  if (elm->fReason != NULL)
    {
      err =
	xmlwriter_simple_element (writer, ns_muc_admin, "reason",
				  elm->fReason);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
muc_admin_item_free (struct muc_admin_item_t *data)
{
  if (data == NULL)
    return;
  if (data->fJid != NULL)
    {
      jid_free (data->fJid);
    }
  if (data->fNick != NULL)
    {
      free (data->fNick);
    }
  if (data->fActor.fJid != NULL)
    {
      jid_free (data->fActor.fJid);
    }
  if (data->fReason != NULL)
    {
      free (data->fReason);
    }
  free (data);
}

enum muc_admin_item_affiliation_t
enum_muc_admin_item_affiliation_from_string (const char *value)
{
  if (strcmp (value, "admin") == 0)
    return MUC_ADMIN_ITEM_AFFILIATION_ADMIN;
  else if (strcmp (value, "member") == 0)
    return MUC_ADMIN_ITEM_AFFILIATION_MEMBER;
  else if (strcmp (value, "none") == 0)
    return MUC_ADMIN_ITEM_AFFILIATION_NONE;
  else if (strcmp (value, "outcast") == 0)
    return MUC_ADMIN_ITEM_AFFILIATION_OUTCAST;
  else if (strcmp (value, "owner") == 0)
    return MUC_ADMIN_ITEM_AFFILIATION_OWNER;
  return 0;
}

const char *
enum_muc_admin_item_affiliation_to_string (enum muc_admin_item_affiliation_t
					   value)
{
  switch (value)
    {
    case MUC_ADMIN_ITEM_AFFILIATION_ADMIN:
      return "admin";
    case MUC_ADMIN_ITEM_AFFILIATION_MEMBER:
      return "member";
    case MUC_ADMIN_ITEM_AFFILIATION_NONE:
      return "none";
    case MUC_ADMIN_ITEM_AFFILIATION_OUTCAST:
      return "outcast";
    case MUC_ADMIN_ITEM_AFFILIATION_OWNER:
      return "owner";
    }
  return NULL;
}

enum muc_admin_item_role_t
enum_muc_admin_item_role_from_string (const char *value)
{
  if (strcmp (value, "moderator") == 0)
    return MUC_ADMIN_ITEM_ROLE_MODERATOR;
  else if (strcmp (value, "none") == 0)
    return MUC_ADMIN_ITEM_ROLE_NONE;
  else if (strcmp (value, "participant") == 0)
    return MUC_ADMIN_ITEM_ROLE_PARTICIPANT;
  else if (strcmp (value, "visitor") == 0)
    return MUC_ADMIN_ITEM_ROLE_VISITOR;
  return 0;
}

const char *
enum_muc_admin_item_role_to_string (enum muc_admin_item_role_t value)
{
  switch (value)
    {
    case MUC_ADMIN_ITEM_ROLE_MODERATOR:
      return "moderator";
    case MUC_ADMIN_ITEM_ROLE_NONE:
      return "none";
    case MUC_ADMIN_ITEM_ROLE_PARTICIPANT:
      return "participant";
    case MUC_ADMIN_ITEM_ROLE_VISITOR:
      return "visitor";
    }
  return NULL;
}
<file_sep>#include "stream_data.h"
#include "helpers.h"
#include "errors.h"

const char *ns_stream = "http://etherx.jabber.org/streams";

struct stream_start_t *
stream_start_decode (xmlreader_t * reader)
{
  struct stream_start_t *elm = NULL;
  elm = malloc (sizeof (struct stream_start_t));
  if (elm == NULL)
    fatal ("stream_start_t: malloc failed");
  memset (elm, 0, sizeof (struct stream_start_t));
  const char *avalue;
  avalue = xmlreader_attribute (reader, NULL, "to");
  if (avalue != NULL)
    {
      jid_t *jid = jid_of_string (avalue);
      elm->fTo = jid;
    }
  avalue = xmlreader_attribute (reader, NULL, "from");
  if (avalue != NULL)
    {
      jid_t *jid = jid_of_string (avalue);
      elm->fFrom = jid;
    }
  avalue = xmlreader_attribute (reader, NULL, "id");
  if (avalue != NULL)
    {
      elm->fId = (char *) avalue;
    }
  avalue = xmlreader_attribute (reader, NULL, "version");
  if (avalue != NULL)
    {
      elm->fVersion = (char *) avalue;
    }
  avalue = xmlreader_attribute (reader, NULL, "lang");
  if (avalue != NULL)
    {
      elm->fLang = (char *) avalue;
    }
  return elm;
}

int
stream_start_encode (xmlwriter_t * writer, struct stream_start_t *elm)
{
  int err = 0;
  err = xmlwriter_set_prefix (writer, "stream", ns_stream);
  if (err != 0)
    return err;
  err = xmlwriter_start_element (writer, ns_stream, "stream");
  if (err != 0)
    return err;
  if (elm->fTo != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "to", jid_to_string (elm->fTo));
      if (err != 0)
	return err;
    }
  if (elm->fFrom != NULL)
    {
      err =
	xmlwriter_attribute (writer, NULL, "from",
			     jid_to_string (elm->fFrom));
      if (err != 0)
	return err;
    }
  if (elm->fId != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "id", elm->fId);
      if (err != 0)
	return err;
    }
  if (elm->fVersion != NULL)
    {
      err = xmlwriter_attribute (writer, NULL, "version", elm->fVersion);
      if (err != 0)
	return err;
    }
  if (elm->fLang != NULL)
    {
      err = xmlwriter_attribute (writer, ns_xml, "lang", elm->fLang);
      if (err != 0)
	return err;
    }
  return 0;
}

void
stream_start_free (struct stream_start_t *data)
{
  if (data == NULL)
    return;
  if (data->fTo != NULL)
    {
      jid_free (data->fTo);
    }
  if (data->fFrom != NULL)
    {
      jid_free (data->fFrom);
    }
  if (data->fId != NULL)
    {
      free (data->fId);
    }
  if (data->fVersion != NULL)
    {
      free (data->fVersion);
    }
  if (data->fLang != NULL)
    {
      free (data->fLang);
    }
  free (data);
}

array_t *
stream_features_decode (xmlreader_t * reader)
{
  array_t *elm = array_new (sizeof (extension_t), 0);
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  extension_t ext;
	  int err = xstream_extension_decode (reader, &ext);
	  if (reader->err != 0)
	    return NULL;
	  if (err == ERR_EXTENSION_NOT_FOUND)
	    {
	      if (xmlreader_skip_element (reader) == -1)
		return NULL;
	    }
	  else
	    {
	      array_append (elm, &ext);
	    }
	}
    }
  return elm;
}

int
stream_features_encode (xmlwriter_t * writer, array_t * elm)
{
  int err = 0;
  err = xmlwriter_set_prefix (writer, "stream", ns_stream);
  if (err != 0)
    return err;
  err = xmlwriter_start_element (writer, ns_stream, "features");
  if (err != 0)
    return err;
  int len = array_length (elm);
  int i = 0;
  for (i = 0; i < len; i++)
    {
      extension_t *ext = array_get (elm, i);
      err = xstream_extension_encode (writer, ext->data, ext->type);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
stream_features_free (array_t * data)
{
  if (data == NULL)
    return;
  int len = array_length (data);
  int i = 0;
  for (i = 0; i < len; i++)
    {
      extension_t *ext = array_get (data, i);
      xstream_extension_free (ext);
    }
  array_free (data);
}

struct stream_error_t *
stream_error_decode (xmlreader_t * reader)
{
  struct stream_error_t *elm = NULL;
  elm = malloc (sizeof (struct stream_error_t));
  if (elm == NULL)
    fatal ("stream_error_t: malloc failed");
  memset (elm, 0, sizeof (struct stream_error_t));
  int type = 0;
  while (1)
    {
      type = xmlreader_next (reader);
      if (type == XML_END_ELEMENT)
	break;
      if (type == XML_ERROR)
	return NULL;
      if (type == XML_START_ELEMENT)
	{
	  const char *namespace = xmlreader_get_namespace (reader);
	  const char *name = xmlreader_get_name (reader);
	  if ((strcmp (name, "text") == 0)
	      && (strcmp (namespace, ns_stream) == 0))
	    {
	      langstring_decode (reader, elm->fText);
	    }
	  else if (strcmp (namespace, ns_stream) != 0)
	    {
	      const char *value = xmlreader_text (reader);
	      if (reader->err != 0)
		return NULL;
	      elm->fCondition.fExtra = (char *) value;
	    }
	}
    }
  return elm;
}

int
stream_error_encode (xmlwriter_t * writer, struct stream_error_t *elm)
{
  int err = 0;
  err = xmlwriter_set_prefix (writer, "stream", ns_stream);
  if (err != 0)
    return err;
  err = xmlwriter_start_element (writer, ns_stream, "error");
  if (err != 0)
    return err;
  if (elm->fText != NULL)
    {
      err = langstring_encode (writer, ns_stream, "text", elm->fText);
      if (err != 0)
	return err;
    }
  const char *name =
    enum_stream_error_condition_name_to_string (elm->fCondition.fName);
  err = xmlwriter_start_element (writer, ns_stream, name);
  if (err != 0)
    return err;
  if (elm->fCondition.fExtra != NULL)
    {
      err = xmlwriter_text (writer, elm->fCondition.fExtra);
      if (err != 0)
	return err;
    }
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
stream_error_free (struct stream_error_t *data)
{
  if (data == NULL)
    return;
  if (data->fText != NULL)
    {
      langstring_free (data->fText);
    }
  if (data->fCondition.fExtra != NULL)
    {
      free (data->fCondition.fExtra);
    }
  free (data);
}

enum stream_error_condition_name_t
enum_stream_error_condition_name_from_string (const char *value)
{
  if (strcmp (value, "bad-format") == 0)
    return STREAM_ERROR_CONDITION_NAME_BAD_FORMAT;
  else if (strcmp (value, "bad-namespace-prefix") == 0)
    return STREAM_ERROR_CONDITION_NAME_BAD_NAMESPACE_PREFIX;
  else if (strcmp (value, "conflict") == 0)
    return STREAM_ERROR_CONDITION_NAME_CONFLICT;
  else if (strcmp (value, "connection-timeout") == 0)
    return STREAM_ERROR_CONDITION_NAME_CONNECTION_TIMEOUT;
  else if (strcmp (value, "host-gone") == 0)
    return STREAM_ERROR_CONDITION_NAME_HOST_GONE;
  else if (strcmp (value, "host-unknown") == 0)
    return STREAM_ERROR_CONDITION_NAME_HOST_UNKNOWN;
  else if (strcmp (value, "improper-addressing") == 0)
    return STREAM_ERROR_CONDITION_NAME_IMPROPER_ADDRESSING;
  else if (strcmp (value, "internal-server-error") == 0)
    return STREAM_ERROR_CONDITION_NAME_INTERNAL_SERVER_ERROR;
  else if (strcmp (value, "invalid-from") == 0)
    return STREAM_ERROR_CONDITION_NAME_INVALID_FROM;
  else if (strcmp (value, "invalid-namespace") == 0)
    return STREAM_ERROR_CONDITION_NAME_INVALID_NAMESPACE;
  else if (strcmp (value, "invalid-xml") == 0)
    return STREAM_ERROR_CONDITION_NAME_INVALID_XML;
  else if (strcmp (value, "not-authorized") == 0)
    return STREAM_ERROR_CONDITION_NAME_NOT_AUTHORIZED;
  else if (strcmp (value, "not-well-formed") == 0)
    return STREAM_ERROR_CONDITION_NAME_NOT_WELL_FORMED;
  else if (strcmp (value, "policy-violation") == 0)
    return STREAM_ERROR_CONDITION_NAME_POLICY_VIOLATION;
  else if (strcmp (value, "remote-connection-failed") == 0)
    return STREAM_ERROR_CONDITION_NAME_REMOTE_CONNECTION_FAILED;
  else if (strcmp (value, "reset") == 0)
    return STREAM_ERROR_CONDITION_NAME_RESET;
  else if (strcmp (value, "resource-constraint") == 0)
    return STREAM_ERROR_CONDITION_NAME_RESOURCE_CONSTRAINT;
  else if (strcmp (value, "restricted-xml") == 0)
    return STREAM_ERROR_CONDITION_NAME_RESTRICTED_XML;
  else if (strcmp (value, "see-other-host") == 0)
    return STREAM_ERROR_CONDITION_NAME_SEE_OTHER_HOST;
  else if (strcmp (value, "system-shutdown") == 0)
    return STREAM_ERROR_CONDITION_NAME_SYSTEM_SHUTDOWN;
  else if (strcmp (value, "undefined-condition") == 0)
    return STREAM_ERROR_CONDITION_NAME_UNDEFINED_CONDITION;
  else if (strcmp (value, "unsupported-encoding") == 0)
    return STREAM_ERROR_CONDITION_NAME_UNSUPPORTED_ENCODING;
  else if (strcmp (value, "unsupported-feature") == 0)
    return STREAM_ERROR_CONDITION_NAME_UNSUPPORTED_FEATURE;
  else if (strcmp (value, "unsupported-stanza-type") == 0)
    return STREAM_ERROR_CONDITION_NAME_UNSUPPORTED_STANZA_TYPE;
  else if (strcmp (value, "unsupported-version") == 0)
    return STREAM_ERROR_CONDITION_NAME_UNSUPPORTED_VERSION;
  return 0;
}

const char *
enum_stream_error_condition_name_to_string (enum stream_error_condition_name_t
					    value)
{
  switch (value)
    {
    case STREAM_ERROR_CONDITION_NAME_BAD_FORMAT:
      return "bad-format";
    case STREAM_ERROR_CONDITION_NAME_BAD_NAMESPACE_PREFIX:
      return "bad-namespace-prefix";
    case STREAM_ERROR_CONDITION_NAME_CONFLICT:
      return "conflict";
    case STREAM_ERROR_CONDITION_NAME_CONNECTION_TIMEOUT:
      return "connection-timeout";
    case STREAM_ERROR_CONDITION_NAME_HOST_GONE:
      return "host-gone";
    case STREAM_ERROR_CONDITION_NAME_HOST_UNKNOWN:
      return "host-unknown";
    case STREAM_ERROR_CONDITION_NAME_IMPROPER_ADDRESSING:
      return "improper-addressing";
    case STREAM_ERROR_CONDITION_NAME_INTERNAL_SERVER_ERROR:
      return "internal-server-error";
    case STREAM_ERROR_CONDITION_NAME_INVALID_FROM:
      return "invalid-from";
    case STREAM_ERROR_CONDITION_NAME_INVALID_NAMESPACE:
      return "invalid-namespace";
    case STREAM_ERROR_CONDITION_NAME_INVALID_XML:
      return "invalid-xml";
    case STREAM_ERROR_CONDITION_NAME_NOT_AUTHORIZED:
      return "not-authorized";
    case STREAM_ERROR_CONDITION_NAME_NOT_WELL_FORMED:
      return "not-well-formed";
    case STREAM_ERROR_CONDITION_NAME_POLICY_VIOLATION:
      return "policy-violation";
    case STREAM_ERROR_CONDITION_NAME_REMOTE_CONNECTION_FAILED:
      return "remote-connection-failed";
    case STREAM_ERROR_CONDITION_NAME_RESET:
      return "reset";
    case STREAM_ERROR_CONDITION_NAME_RESOURCE_CONSTRAINT:
      return "resource-constraint";
    case STREAM_ERROR_CONDITION_NAME_RESTRICTED_XML:
      return "restricted-xml";
    case STREAM_ERROR_CONDITION_NAME_SEE_OTHER_HOST:
      return "see-other-host";
    case STREAM_ERROR_CONDITION_NAME_SYSTEM_SHUTDOWN:
      return "system-shutdown";
    case STREAM_ERROR_CONDITION_NAME_UNDEFINED_CONDITION:
      return "undefined-condition";
    case STREAM_ERROR_CONDITION_NAME_UNSUPPORTED_ENCODING:
      return "unsupported-encoding";
    case STREAM_ERROR_CONDITION_NAME_UNSUPPORTED_FEATURE:
      return "unsupported-feature";
    case STREAM_ERROR_CONDITION_NAME_UNSUPPORTED_STANZA_TYPE:
      return "unsupported-stanza-type";
    case STREAM_ERROR_CONDITION_NAME_UNSUPPORTED_VERSION:
      return "unsupported-version";
    }
  return NULL;
}
<file_sep>#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "helpers.h"
#include "base64.h"
#include "errors.h"

uint8_t decoding_table[256] = {
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, 52, 
  53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255, 255, 
  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 
  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, 255, 
  26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 
  42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255, 255, 
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
};
  
int base64_decode(const char* data, int data_len, unsigned char** result, int* result_len) {
  if (data_len % 4 != 0)
    return ERR_BASE64_DECODE;
  
  char* src = (char*) data;
  int len = data_len;

  *result = malloc (len / 4 * 3 + 1);
  if (*result == NULL)
    fatal ("base64_decode: malloc failed");

  unsigned char* dst = *result;
  int dst_len = 0;
  int err = 0;
  
  while (len > 0) {
    int dlen = 4;
    uint8_t dbuf[4];
    int j = 0;
    for (j = 0; j < 4; j++) {
      if (len == 0) {
        err = ERR_BASE64_DECODE;
        break;
      }

      char in = src[0];
      src++;
      len--;
      if (in == '=') {
        if (j == 0 || j == 1) {
          // incorrect padding
          err = ERR_BASE64_DECODE;
          break;
        }
        if (j == 2) {
          // "==" is expected, the first "=" is already consumed.
          if (len == 0) {
            err = ERR_BASE64_DECODE;
            break;
          }
          if (src[0] != '=') {
            // incorrect padding
            err = ERR_BASE64_DECODE;
            break;
          }
          src++;
          len--;
        }
        if (len > 0) {
          // trailing garbage
          err = ERR_BASE64_DECODE;
        }
        dlen = j;
        break;
      }
      dbuf[j] = (unsigned char) decoding_table[(int) in];
      if (dbuf[j] == 0xFF) {
        err = ERR_BASE64_DECODE;
        break;
      }
    }
    if (err != 0)
      break;
    
    switch (dlen) {
    case 4:
      dst[2] = (dbuf[2] << 6 | dbuf[3]);
    case 3:
      dst[1] = dbuf[1] << 4 | dbuf[2] >> 2;
    case 2:
      dst[0] = dbuf[0] << 2 | dbuf[1] >> 4;
    }
    dst += 3;
    dst_len += dlen - 1;
  }
  *result_len = dst_len;
  
  return err;
}

char* base64_encode (const unsigned char* src, size_t src_len) {
  int dst_len = 4 * ((src_len + 2) / 3);
  
  char* dst = malloc(dst_len + 1);
  if (dst == NULL)
    fatal ("base64_encode: malloc failed");

  static const char* encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

  int len = src_len;
  unsigned char* ptr = (unsigned char*) src;
  char* dst_ptr = dst;

  while (len > 0) {
    uint8_t b0 = 0, b1 = 0, b2 = 0, b3 = 0;
    
    if (len > 2) {
      b3 = ptr[2] & 0x3F;
      b2 = ptr[2] >> 6;
    }
    if (len >= 2) {
      b2 |= (ptr[1] << 2) & 0x3F;
      b1 = ptr[1] >> 4;
    }
    if (len >= 1) {
      b1 |= (ptr[0] << 4) & 0x3F;
      b0 = ptr[0] >> 2;
    }

    dst_ptr[0] = encodeStd[b0];
    dst_ptr[1] = encodeStd[b1];
    dst_ptr[2] = encodeStd[b2];
    dst_ptr[3] = encodeStd[b3];

    if (len < 3) {
      dst_ptr[3] = '=';
      if (len < 2) {
        dst_ptr[2] = '=';
      }
    }

    ptr += 3;
    dst_ptr += 4;

    if (len < 3) {
      break;
    }
    len -= 3;
  }
  
  *dst_ptr = '\0';
  return dst;
}
<file_sep>#ifndef _XMPP_PREP_H_
#define _XMPP_PREP_H_

#include "ustring.h"

void nodeprep (ustring_t *ustring);
int resourceprep (ustring_t *ustring);
void nameprep (ustring_t *ustring);

int strong_nodeprep (ustring_t *ustring);
void strong_resourceprep (ustring_t *ustring);
int strong_nameprep (ustring_t *ustring);
void nfkc (ustring_t *ustring);

#endif
<file_sep>#include "xep_ping_data.h"
#include "helpers.h"
#include "errors.h"

const char *ns_ping = "urn:xmpp:ping";

struct ping_ping_t *
ping_ping_decode (xmlreader_t * reader)
{
  struct ping_ping_t *elm = NULL;
  elm = malloc (sizeof (struct ping_ping_t));
  if (elm == NULL)
    fatal ("ping_ping_t: malloc failed");
  memset (elm, 0, sizeof (struct ping_ping_t));
  if (xmlreader_skip_element (reader) == -1)
    return NULL;
  return elm;
}

int
ping_ping_encode (xmlwriter_t * writer, struct ping_ping_t *elm)
{
  int err = 0;
  err = xmlwriter_start_element (writer, ns_ping, "ping");
  if (err != 0)
    return err;
  err = xmlwriter_end_element (writer);
  if (err != 0)
    return err;
  return 0;
}

void
ping_ping_free (struct ping_ping_t *data)
{
  if (data == NULL)
    return;
  free (data);
}
