Пример #1
0
int	main(int argc, char* argv[])
{
	int i;

	if((EzxmlBase = OpenLibrary("ezxml.library", 8)))
	{
		ezxml_t xml;
		char *s;

		if (argc != 2) return Printf("usage: %s xmlfile\n", argv[0]);

		xml = ezxml_parse_file(argv[1]);
		Printf("%s\n", (s = ezxml_toxml(xml)));
		FreeVec(s);
		i = Printf("%s", ezxml_error(xml));

		ezxml_free(xml);

		CloseLibrary(EzxmlBase);
	}
	else
		PutStr("Error: Could not open ezxml.library\n");

	return (i) ? 1 : 0;
}
Пример #2
0
/* ------------------------------------------------------------------------- */
void Servant_OnMessageReceived(TServant *const servant, const ezxml_t message)
{
    s_on_message_received++;

    switch(s_test_case)
    {
    case 6:
        assert('\0' != ezxml_error(message)[0]); /* error */
        break;
    case 7:
        assert('\0' == ezxml_error(message)[0]); /* no error */
        {
            const char *const s = ezxml_name(message);
            assert(strcmp(s, "retrieve") == 0);
        }
        break;
    }
}
Пример #3
0
int config_load()
{
	ezxml_t config_xml, root;

	// Clear configuration structure
	memset(import_patch_map, 0, sizeof(import_patch_map));
	memset(import_percussion_map, 0, sizeof(import_percussion_map));

	// Attempt to load configuration XML
	if((config_xml = ezxml_parse_file(CONFIG_XML)) == NULL)
	{
		if(errno == ENOENT || errno == EACCES)
			// Handle file errors
			fprintf(stderr, "Unable to open " CONFIG_XML);
		else
			fprintf(stderr, ezxml_error(config_xml));
		return 0;
	}

	if((root = required_child(config_xml, "patches")) == NULL)
		return 0;

	process_import_map(root, import_patch_map, "patch");

	if((root = required_child(config_xml, "noises")) == NULL)
		return 0;

	process_import_map(root, import_noise_map, "noise");

	if((root = required_child(config_xml, "percussions")) == NULL)
		return 0;

	process_import_map(root, import_percussion_map, "percussion");

	ezxml_free(config_xml);
	return 1;
}
Пример #4
0
/* Load a BSDF struct from the given file (free first and keep name) */
SDError
SDloadFile(SDData *sd, const char *fname)
{
	SDError		lastErr;
	ezxml_t		fl, wtl;

	if ((sd == NULL) | (fname == NULL || !*fname))
		return SDEargument;
				/* free old data, keeping name */
	SDfreeBSDF(sd);
				/* parse XML file */
	fl = ezxml_parse_file(fname);
	if (fl == NULL) {
		sprintf(SDerrorDetail, "Cannot open BSDF \"%s\"", fname);
		return SDEfile;
	}
	if (ezxml_error(fl)[0]) {
		sprintf(SDerrorDetail, "BSDF \"%s\" %s", fname, ezxml_error(fl));
		ezxml_free(fl);
		return SDEformat;
	}
	if (strcmp(ezxml_name(fl), "WindowElement")) {
		sprintf(SDerrorDetail,
			"BSDF \"%s\": top level node not 'WindowElement'",
				sd->name);
		ezxml_free(fl);
		return SDEformat;
	}
	wtl = ezxml_child(fl, "FileType");
	if (wtl != NULL && strcmp(ezxml_txt(wtl), "BSDF")) {
		sprintf(SDerrorDetail,
			"XML \"%s\": wrong FileType (must be 'BSDF')",
				sd->name);
		ezxml_free(fl);
		return SDEformat;
	}
	wtl = ezxml_child(ezxml_child(fl, "Optical"), "Layer");
	if (wtl == NULL) {
		sprintf(SDerrorDetail, "BSDF \"%s\": no optical layers'",
				sd->name);
		ezxml_free(fl);
		return SDEformat;
	}
				/* load geometry if present */
	lastErr = SDloadGeometry(sd, wtl);
	if (lastErr) {
		ezxml_free(fl);
		return lastErr;
	}
				/* try loading variable resolution data */
	lastErr = SDloadTre(sd, wtl);
				/* check our result */
	if (lastErr == SDEsupport)	/* try matrix BSDF if not tree data */
		lastErr = SDloadMtx(sd, wtl);
		
				/* done with XML file */
	ezxml_free(fl);
	
	if (lastErr) {		/* was there a load error? */
		SDfreeBSDF(sd);
		return lastErr;
	}
				/* remove any insignificant components */
	if (sd->rf != NULL && sd->rf->maxHemi <= .001) {
		SDfreeSpectralDF(sd->rf); sd->rf = NULL;
	}
	if (sd->rb != NULL && sd->rb->maxHemi <= .001) {
		SDfreeSpectralDF(sd->rb); sd->rb = NULL;
	}
	if (sd->tf != NULL && sd->tf->maxHemi <= .001) {
		SDfreeSpectralDF(sd->tf); sd->tf = NULL;
	}
	if (sd->tb != NULL && sd->tb->maxHemi <= .001) {
		SDfreeSpectralDF(sd->tb); sd->tb = NULL;
	}
				/* return success */
	return SDEnone;
}
Пример #5
0
/* ------------------------------------------------------------------------- */
static int OnMessageReceived(TServant *const servant, ezxml_t message)
{
    int ret = -EXIT_SUCCESS;

#ifdef UNIT_TESTS
    if (g_Servant_OnMessageReceived)
        g_Servant_OnMessageReceived(servant, message);
#endif
    assert(message);

    do
    {
        const char *req;
        const char *error;

        error = ezxml_error(message);
        if ('\0' != error[0])
        {
            LOG2_ERROR("servant", "the session (%u) received an invalid "
                "formated xml message: %s", servant->m_session.m_id, error);
            ret = -EXIT_FAILURE;
            break;
        }


        req = ezxml_name(message);
        LOG2_DEBUG("servant", "the session (%u) received '%s' request",
            servant->m_session.m_id, req);

        if (strcmp(req, "update") == 0)
        {
            if (servant->m_reg)
            {
                if ((ret = Reg_Update(servant->m_reg, message)))
                    LOG2_ERROR("servant", "the session (%u) failed to update "
                        "the registry", servant->m_session.m_id, req);
            }
        }
        else if (strcmp(req, "retrieve") == 0)
        {
            if (servant->m_reg)
            {
                ezxml_t status = ezxml_new("status");
                ret = Reg_Get(servant->m_reg, message, status);
                TxMessage(servant, status);
                ezxml_free(status);

                LOG2_DEBUG("servant", "the session (%u) replied to '%s' request",
                    servant->m_session.m_id, req);
            }
        }
        else
        {
            LOG2_WARNING("servant", "the session (%u) received an undefined "
                "request (%s)", servant->m_session.m_id, req);
            ret = -EXIT_FAILURE;
        }
    } while(0);

    ezxml_free(message);
    return ret;
}
Пример #6
0
struct governor_config *
config_init (const char *path)
{
  ezxml_t xml = ezxml_parse_file (path);
  ezxml_t tmp_xml, inner_xml, tmp_xml_limit;
  const char *error_str;
  const char *ptr;

  if (xml == NULL)
    {
      fprintf (stderr, "Error reading config file %s\n", path);
      exit (-1);
    }

  if (strlen (error_str = ezxml_error (xml)))
    {
      fprintf (stderr, "Error in config file (%s): %s\n", path, error_str);
      ezxml_free (xml);
      exit (-1);
    }

  cfg = calloc (1, sizeof (struct governor_config));
  memset (cfg, 0, sizeof (struct governor_config));

  cfg->is_gpl = check_liblve();
  cfg->account_limits = g_hash_table_new_full (g_str_hash, g_str_equal,
					       (GDestroyNotify) free,
					       (GDestroyNotify) free);

  tmp_xml = ezxml_child (xml, "log");
  if (tmp_xml == NULL)
    {
      fprintf (stderr, "No log path\n");
      exit (-1);
    }
  cfg->log = strdup (ezxml_attr (tmp_xml, "file"));
  cfg->log_mode =
    ((ptr =
      ezxml_attr (tmp_xml,
		  "mode")) ==
     NULL) ? ERROR_MODE : mode_type_str_to_enum (ptr);

  tmp_xml = ezxml_child (xml, "intervals");
  if (tmp_xml == NULL)
    {
      fprintf (stderr, "No 'intervals' parameter\n");
      exit (-1);
    }
  cfg->interval_short =
    ((ptr = ezxml_attr (tmp_xml, "short")) == NULL) ? 5 : atoi (ptr);
  cfg->interval_mid =
    ((ptr = ezxml_attr (tmp_xml, "mid")) == NULL) ? 15 : atoi (ptr);
  cfg->interval_long =
    ((ptr = ezxml_attr (tmp_xml, "long")) == NULL) ? 30 : atoi (ptr);

  tmp_xml = ezxml_child (xml, "lve");
  cfg->use_lve = 0;
  cfg->all_lve = 0;
  cfg->separate_lve = 0;
  if(tmp_xml != NULL){
	  if (ezxml_attr (tmp_xml, "use")){
		  if(!strcasecmp(ezxml_attr (tmp_xml, "use"),"On") || 
             !strcasecmp(ezxml_attr (tmp_xml, "use"),"Single")){
			  cfg->use_lve = 1;
		  }
		  if(!strcasecmp(ezxml_attr (tmp_xml, "use"),"AbUsers")){
			  cfg->use_lve = 1;
              cfg->separate_lve = 1;
		  }
		  if(!strcasecmp(ezxml_attr (tmp_xml, "use"),"All")){
			  cfg->use_lve = 1;
			  cfg->all_lve = 1;
			  cfg->separate_lve = 1;
		  }
	  }
  }

  tmp_xml = ezxml_child (xml, "statistic");
  cfg->statistic_mode = 1;
  if( tmp_xml != NULL )
  {
    if( ezxml_attr( tmp_xml, "mode" ) )
    {
      if( !strcasecmp( ezxml_attr( tmp_xml, "mode" ), "Off" ) )
      {
        cfg->statistic_mode = 0;
      }
	}
  }

  tmp_xml = ezxml_child (xml, "debug_user");
  cfg->debug_user = NULL;
    if( tmp_xml != NULL )
    {
      if( ezxml_attr( tmp_xml, "name" ) )
      {
    	  cfg->debug_user = strdup (ezxml_attr (tmp_xml, "name"));
  	}
  }

  tmp_xml = ezxml_child( xml, "logqueries" );
  cfg->logqueries_use = 0;
  if( tmp_xml != NULL )
  {
    if( ezxml_attr( tmp_xml, "use" ) )
    {
      if( !strcasecmp( ezxml_attr( tmp_xml, "use" ), "On" ) )
      {
        cfg->logqueries_use = 1;
      }
      if( !strcasecmp( ezxml_attr( tmp_xml, "use" ), "Before" ) )
      {
        cfg->logqueries_use = 2;
      }
    }
  }

  tmp_xml = ezxml_child (xml, "daemon");
  cfg->daemon_monitor = 1;
  if( tmp_xml != NULL )
  {
    if( ezxml_attr( tmp_xml, "monitor" ) )
    {
      if( !strcasecmp( ezxml_attr( tmp_xml, "monitor" ), "Off" ) )
      {
        cfg->daemon_monitor = 0;
      }
	}
  }

  tmp_xml = ezxml_child (xml, "slow_queries");
  cfg->slow_queries = 0;
  if( tmp_xml != NULL )
  {
    if( ezxml_attr( tmp_xml, "run" ) )
    {
      if( !strcasecmp( ezxml_attr( tmp_xml, "run" ), "On" ) )
      {
        cfg->slow_queries = 1;
      }
    }
    if( ezxml_attr( tmp_xml, "log" ) )
    {
      cfg->slow_queries_log = strdup( ezxml_attr( tmp_xml, "log" ) );
    }
    else
    {
      cfg->slow_queries_log = NULL;
    }
  }

  tmp_xml = ezxml_child( xml, "restrict_mode" );
  cfg->restrict_mode = 1;
  cfg->l_unlimit = parse_period( "60s" );
  if( tmp_xml != NULL )
  {
    if( ezxml_attr( tmp_xml, "use" ) )
    {
      if( !strcasecmp( ezxml_attr( tmp_xml, "use" ), "period" ) )
      {
        cfg->restrict_mode = 0;
      }
    }
    if( ( ptr = ezxml_attr( tmp_xml, "unlimit" ) ) != NULL )
    {
      cfg->l_unlimit = parse_period( ptr );
    }
  }

  cfg->killuser = 0;
  cfg->max_user_connections = 30;

  tmp_xml = ezxml_child (xml, "restrict");
  if (tmp_xml == NULL)
    {
      fprintf (stderr, "No 'restrict' parameter\n");
      exit (-1);
    }
  if (ezxml_attr (tmp_xml, "log"))
    {
      cfg->restrict_log = strdup (ezxml_attr (tmp_xml, "log"));
    }
  else
    {
      cfg->restrict_log = NULL;
    }

  if(ezxml_attr (tmp_xml, "killuser")){
         if(!strcasecmp(ezxml_attr (tmp_xml, "killuser"), "on")){
               cfg->killuser = 1;
         }
    }

  if(ezxml_attr (tmp_xml, "user_max_connections")){
	  cfg->max_user_connections = atoi(ezxml_attr (tmp_xml, "user_max_connections"));
	  if(cfg->max_user_connections<0) cfg->max_user_connections = 30;
  }

  cfg->restrict_format = getRestrictFormat (ezxml_attr (tmp_xml, "format"));

  cfg->level1 =
    ((ptr =
      ezxml_attr (tmp_xml,
		  "level1")) ==
     NULL) ? parse_period ("60s") : parse_period (ptr);
  cfg->level2 =
    ((ptr =
      ezxml_attr (tmp_xml,
		  "level2")) ==
     NULL) ? parse_period ("15m") : parse_period (ptr);
  cfg->level3 =
    ((ptr =
      ezxml_attr (tmp_xml,
		  "level3")) ==
     NULL) ? parse_period ("1h") : parse_period (ptr);
  cfg->level4 =
    ((ptr =
      ezxml_attr (tmp_xml,
		  "level4")) ==
     NULL) ? parse_period ("1d") : parse_period (ptr);
  cfg->timeout =
    ((ptr =
      ezxml_attr (tmp_xml,
		  "timeout")) ==
     NULL) ? parse_period ("1h") : parse_period (ptr);

  if (ezxml_attr (tmp_xml, "script"))
    {
      cfg->exec_script = strdup (ezxml_attr (tmp_xml, "script"));
      if (cfg->exec_script)
	{
	  int status_script;
	  struct stat buffer_script;
	  status_script = stat (cfg->exec_script, &buffer_script);
	  if (status_script)
	    {
	      fprintf (stderr, "Wrong script name - %s\n", cfg->exec_script);
	      exit (-1);
	    }
	  else
	    {
	      if (S_ISDIR (buffer_script.st_mode))
		{
		  fprintf (stderr, "Script is directory - %s\n",
			   cfg->exec_script);
		  exit (-1);
		}
	    }
	}
    }
  else
    {
      cfg->exec_script = NULL;
    }

  tmp_xml = ezxml_child (xml, "connector");
  if (tmp_xml == NULL)
    {
      fprintf (stderr, "No connector parameter");
      exit (-1);
    }
  cfg->db_login =
    strdup (!ezxml_attr (tmp_xml, "login") ? "" :
	    ezxml_attr (tmp_xml, "login"));
  cfg->db_password =
    strdup (!ezxml_attr (tmp_xml, "password") ? "" :
	    ezxml_attr (tmp_xml, "password"));
  cfg->host =
    strdup (!ezxml_attr (tmp_xml, "host") ? "" :
	    ezxml_attr (tmp_xml, "host"));
  cfg->separator =
    !ezxml_attr (tmp_xml,
		 "prefix_separator") ? '_' : *(ezxml_attr (tmp_xml,
							   "prefix_separator"));

  tmp_xml = ezxml_child (xml, "default");
  if (tmp_xml == NULL)
    {
      fprintf (stderr, "No default limits");
      exit (-1);
    }

  cfg->default_limit.mode = RESTRICT_MODE;

  for (tmp_xml_limit = ezxml_child (tmp_xml, "limit"); tmp_xml_limit;
       tmp_xml_limit = tmp_xml_limit->next)
    {
      set_stats_limit (tmp_xml_limit, &cfg->default_limit);
    }
  cfg->default_limit.mode = RESTRICT_MODE;
  cfg->default_limit.account_flag = true;

  for (tmp_xml = ezxml_child (xml, "user"); tmp_xml; tmp_xml = tmp_xml->next)
    {
      const char *account = ezxml_attr (tmp_xml, "name");
      const char *mysql_name = ezxml_attr (tmp_xml, "mysql_name");
      if ((account == NULL) && (mysql_name == NULL))
	{
	  fprintf (stderr,
		   "Error: both 'name' and 'mysql_name' attributes are absent\n");
	  exit (-1);
	}
      if ((account != NULL) && (mysql_name != NULL))
	{
	  fprintf (stderr,
		   "Error: both 'name' and 'mysql_name' attributes are present\n");
	  exit (-1);
	}
      stats_limit_cfg *l = calloc (1, sizeof (stats_limit_cfg));

      // inheritance of limits from default
      memcpy (l, &cfg->default_limit, sizeof (stats_limit_cfg));

      l->account_flag = account != NULL;
      l->mode =
	((ptr =
	  ezxml_attr (tmp_xml,
		      "mode")) ==
	 NULL) ? RESTRICT_MODE : mode_type_str_to_enum (ptr);
      for (tmp_xml_limit = ezxml_child (tmp_xml, "limit"); tmp_xml_limit;
	   tmp_xml_limit = tmp_xml_limit->next)
	{
	  set_stats_limit (tmp_xml_limit, l);
	}
      g_hash_table_replace (cfg->account_limits,
			    (gpointer) strdup ((account == NULL) ? mysql_name
					       : account), l);
    }

  ezxml_free (xml);
  return cfg;
}
Пример #7
0
int post_passwd_server(int client, char *ibuf, int len, char *torken)
{
        if(torken){
                return response_state(client, NO_SERVICE, err_msg[NO_SERVICE]);
        }

        ezxml_t root = NULL, name=NULL, oldpasswd=NULL, passwd=NULL;

        root = ezxml_parse_str(ibuf, len);
        if(!root){
                ezxml_free(root);
                return response_state(client, FORMAT_ERR, err_msg[FORMAT_ERR]);
        }
        if(root && *ezxml_error(root)) {
                ezxml_free(root);
                return response_state(client, FORMAT_ERR, err_msg[FORMAT_ERR]);
        }

        name = ezxml_child(root, "USER_NAME");
        oldpasswd = ezxml_child(root, "OLD_PASSWD");
        passwd = ezxml_child(root, "PASSWD");

        if(!name || !name->txt[0] ||
                        !oldpasswd ||!oldpasswd->txt[0] ||
                        !passwd || !passwd->txt[0]){
                return response_state(client, FORMAT_ERR,
                                "Need name oldpasswd and new passwd"
                                );
        }

        char salt[128] = {0}, *ptr = 0;
        struct spwd *pw = getspnam(name->txt);
        if(!pw){
                return response_state(client, SYS_ERR,
                                "Invalid name");
        }

        ptr = strchr(pw->sp_pwdp+1, '$');
        if(!ptr){
                return response_state(client, SYS_ERR,
                                "Unkonw passwd format");
        }
        ptr = strchr(ptr+1, '$');
        if(!ptr){
                return response_state(client, SYS_ERR,
                                "Unkonw passwd format");
        }
        strncpy(salt, pw->sp_pwdp, ptr-pw->sp_pwdp);

        ptr = crypt(oldpasswd->txt, salt);
        if(strcmp(ptr, pw->sp_pwdp)){
                return response_state(client, SYS_ERR, "Invalid old passwd");
        }

        char cmd[XMLLEN] = {0};
        snprintf(cmd, sizeof(cmd), "echo -e '%s\n%s'|/usr/bin/passwd",
                        passwd->txt, passwd->txt);
        system(cmd);
        return 0;

}
const char *clParserError(ClParserPtrT xml)
{
    return ezxml_error(xml);
}
/*
 * parse_automaton_set_xml_file
 *
 * Parse the entire of an automaton set xml file.
 *
 * This is called once per xml file. It creates the automaton structure and 
 * fills it in joining up the links. Any error is considered fatal and will
 * cause a return code along with debug remarks.
 *
 * Parameters: filename - If this cannot be read then the function will fail.
 *             automaton_set - The set to fill in a structure for.
 *             state_callback - Callback to generate the states.
 *             event_callback - Callback to generate the events.
 *             match_state - Used to set up lua globals.
 */
int parse_automaton_set_xml_file(char *filename,
                                 AUTOMATON_SET *automaton_set,
                                 int (*state_callback)(AUTOMATON_STATE ***,int),
                                 int (*event_callback)(AUTOMATON_EVENT ***),
                                 MATCH_STATE *match_state)
{
  /*
   * Local Variables.
   */
  int ret_code = AUTOMATON_XML_FILE_OK;
  ezxml_t xml_file;
  ezxml_t xml_automaton;
  ezxml_t xml_start_automaton;
  int ii;
  int rc;

  /*
   * The transition file is strictly an xml file so we use an external xml
   * library to load it and look for values.
   *
   * If the file comes back null then it failed to load for some reason.
   */
  xml_file = ezxml_parse_file(filename);
  if (NULL == xml_file)
  {
    DT_DEBUG_LOG("Failed to load xml_automaton file %s: error %s\n", 
                 filename,
                 ezxml_error(xml_file));
    ret_code = AUTOMATON_XML_FILE_LOAD_FAIL;
    goto EXIT_LABEL;
  }

  /*
   * This allocates the memory required for the automaton array and creates 
   * the automaton structures. It does not fill in any information.
   */
  create_automatons_from_xml(&xml_file, 
                             automaton_set, 
                             state_callback, 
                             event_callback);

  /*
   * Fill in the names of the automatons and transitions from the file. This
   * is required so that we can refer to them from each other when building
   * up the links later.
   */
  ret_code = parse_automaton_names(&xml_file, automaton_set);
  if (AUTOMATON_XML_FILE_OK != ret_code)
  {
    DT_DEBUG_LOG("Failed to parse automaton names\n");
    goto EXIT_LABEL;
  }

  /*
   * Finally now that the automatons are created and have their names filled in
   * we can set up all the links between transitions, states, events and other
   * automatons.
   */
  ii = 0;
  for (xml_automaton = ezxml_child(xml_file, "automaton");
       xml_automaton;
       xml_automaton = xml_automaton->next)
  {
    /*
     * Attempt to set up the automaton links.
     */
    rc = init_automaton_links(automaton_set->automaton_array[ii],
                              xml_automaton,
                              automaton_set,
                              match_state);
    if (INIT_AUTOMATON_LINKS_OK != rc)
    {
      DT_DEBUG_LOG("Failed setting up automaton links for automaton %s\n",
                   automaton_set->automaton_array[ii]->name);
      ret_code = AUTOMATON_XML_FILE_LINKS_FAIL;
      goto EXIT_LABEL;
    }

    ii++;
  }

  /*
   * The automaton that this set starts in is hardcoded into the xml file so
   * retrieve it now and verify that it exists.
   */
  xml_start_automaton = ezxml_child(xml_file, "start_automaton");
  if (NULL == xml_start_automaton)
  {
    DT_DEBUG_LOG("There is no starting automaton in the set.\n");
    ret_code = AUTOMATON_XML_FILE_START_AUTOMATON_BAD;
    goto EXIT_LABEL;
  }

  /*
   * There was a starting automaton so retrieve it by name.
   */
  automaton_set->start_automaton = get_automaton_by_name(
                                                      automaton_set,
                                                      xml_start_automaton->txt);
  if (NULL == automaton_set->start_automaton)
  {
    DT_DEBUG_LOG("The starting automaton listed (%s) does not exist in the " \
                 "set.\n",
                 xml_start_automaton->txt);
    ret_code = AUTOMATON_XML_FILE_START_AUTOMATON_BAD;
    goto EXIT_LABEL;
  }

EXIT_LABEL:

  return(ret_code);
}
Пример #10
0
void mapcache_configuration_parse_xml(mapcache_context *ctx, const char *filename, mapcache_cfg *config) {
   ezxml_t doc, node;
   const char *mode;
   doc = ezxml_parse_file(filename);
   if (doc == NULL) {
      ctx->set_error(ctx,400, "failed to parse file %s. Is it valid XML?", filename);
      goto cleanup;
   } else {
      const char *err = ezxml_error(doc);
      if(err && *err) {
         ctx->set_error(ctx,400, "failed to parse file %s: %s", filename, err);
         goto cleanup;
      }
   }

   if(strcmp(doc->name,"mapcache")) {
      ctx->set_error(ctx,400, "failed to parse file %s. first node is not <mapcache>", filename);
      goto cleanup;
   }
   mode = ezxml_attr(doc,"mode");
   if(mode) {
      if(!strcmp(mode,"combined_mirror")) {
         config->mode = MAPCACHE_MODE_MIRROR_COMBINED;
      } else if(!strcmp(mode,"split_mirror")) {
         config->mode = MAPCACHE_MODE_MIRROR_SPLIT;
      } else if(!strcmp(mode,"normal")) {
         config->mode = MAPCACHE_MODE_NORMAL;
      } else {
         ctx->set_error(ctx,400,"unknown mode \"%s\" for <mapcache>",mode);
         goto cleanup;
      }
   } else {
         config->mode = MAPCACHE_MODE_NORMAL;
   }

   for(node = ezxml_child(doc,"metadata"); node; node = node->next) {
      parseMetadata(ctx, node, config->metadata);
      if(GC_HAS_ERROR(ctx)) goto cleanup;
   }

   for(node = ezxml_child(doc,"source"); node; node = node->next) {
      parseSource(ctx, node, config);
      if(GC_HAS_ERROR(ctx)) goto cleanup;
   }

   for(node = ezxml_child(doc,"grid"); node; node = node->next) {
      parseGrid(ctx, node, config);
      if(GC_HAS_ERROR(ctx)) goto cleanup;
   }

   for(node = ezxml_child(doc,"format"); node; node = node->next) {
      parseFormat(ctx, node, config);
      if(GC_HAS_ERROR(ctx)) goto cleanup;
   }

   for(node = ezxml_child(doc,"cache"); node; node = node->next) {
      parseCache(ctx, node, config);
      if(GC_HAS_ERROR(ctx)) goto cleanup;
   }

   for(node = ezxml_child(doc,"tileset"); node; node = node->next) {
      parseTileset(ctx, node, config);
      if(GC_HAS_ERROR(ctx)) goto cleanup;
   }

   if ((node = ezxml_child(doc,"service")) != NULL) {
      ezxml_t service_node;
      for(service_node = node; service_node; service_node = service_node->next) {
         char *enabled = (char*)ezxml_attr(service_node,"enabled");
         char *type = (char*)ezxml_attr(service_node,"type");
         if(!strcasecmp(enabled,"true")) {
            if (!strcasecmp(type,"wms")) {
               mapcache_service *new_service = mapcache_service_wms_create(ctx);
               if(new_service->configuration_parse_xml) {
                  new_service->configuration_parse_xml(ctx,service_node,new_service,config);
               }
               config->services[MAPCACHE_SERVICE_WMS] = new_service;
            }
            else if (!strcasecmp(type,"tms")) {
               mapcache_service *new_service = mapcache_service_tms_create(ctx);
               if(new_service->configuration_parse_xml) {
                  new_service->configuration_parse_xml(ctx,service_node,new_service,config);
               }
               config->services[MAPCACHE_SERVICE_TMS] = new_service;
            }
            else if (!strcasecmp(type,"wmts")) {
               mapcache_service *new_service = mapcache_service_wmts_create(ctx);
               if(new_service->configuration_parse_xml) {
                  new_service->configuration_parse_xml(ctx,service_node,new_service,config);
               }
               config->services[MAPCACHE_SERVICE_WMTS] = new_service;
            }
            else if (!strcasecmp(type,"kml")) {
               mapcache_service *new_service = mapcache_service_kml_create(ctx);
               if(new_service->configuration_parse_xml) {
                  new_service->configuration_parse_xml(ctx,service_node,new_service,config);
               }
               config->services[MAPCACHE_SERVICE_KML] = new_service;
            }
            else if (!strcasecmp(type,"gmaps")) {
               mapcache_service *new_service = mapcache_service_gmaps_create(ctx);
               if(new_service->configuration_parse_xml) {
                  new_service->configuration_parse_xml(ctx,service_node,new_service,config);
               }
               config->services[MAPCACHE_SERVICE_GMAPS] = new_service;
            }
            else if (!strcasecmp(type,"ve")) {
               mapcache_service *new_service = mapcache_service_ve_create(ctx);
               if(new_service->configuration_parse_xml) {
                  new_service->configuration_parse_xml(ctx,service_node,new_service,config);
               }
               config->services[MAPCACHE_SERVICE_VE] = new_service;
            }
            else if (!strcasecmp(type,"demo")) {
               mapcache_service *new_service = mapcache_service_demo_create(ctx);
               if(new_service->configuration_parse_xml) {
                  new_service->configuration_parse_xml(ctx,service_node,new_service,config);
               }
               config->services[MAPCACHE_SERVICE_DEMO] = new_service;
            } else {
               ctx->set_error(ctx,400,"unknown <service> type %s",type);
            }
            if(GC_HAS_ERROR(ctx)) goto cleanup;
         }
      }
   }
   else if ((node = ezxml_child(doc,"services")) != NULL) {
      ctx->log(ctx,MAPCACHE_WARN,"<services> tag is deprecated, use <service type=\"wms\" enabled=\"true|false\">");
      parseServices(ctx, node, config);
   } else {
      ctx->set_error(ctx, 400, "no <services> configured");
   }
   if(GC_HAS_ERROR(ctx)) goto cleanup;


   node = ezxml_child(doc,"default_format");
   if(!node)
      node = ezxml_child(doc,"merge_format");
   if (node) {
      mapcache_image_format *format = mapcache_configuration_get_image_format(config,node->txt);
      if(!format) {
         ctx->set_error(ctx, 400, "default_format tag references format %s but it is not configured",
               node->txt);
         goto cleanup;
      }
      config->default_image_format = format;
   }

   if ((node = ezxml_child(doc,"errors")) != NULL) {
      if(!strcmp(node->txt,"log")) {
         config->reporting = MAPCACHE_REPORT_LOG;
      } else if(!strcmp(node->txt,"report")) {
         config->reporting = MAPCACHE_REPORT_MSG;
      } else if(!strcmp(node->txt,"empty_img")) {
         config->reporting = MAPCACHE_REPORT_EMPTY_IMG;
         mapcache_image_create_empty(ctx, config);
         if(GC_HAS_ERROR(ctx)) goto cleanup;
      } else if(!strcmp(node->txt, "report_img")) {
         config->reporting = MAPCACHE_REPORT_ERROR_IMG;
         ctx->set_error(ctx,501,"<errors>: report_img not implemented");
         goto cleanup;
      } else {
         ctx->set_error(ctx,400,"<errors>: unknown value %s (allowed are log, report, empty_img, report_img)",
               node->txt);
         goto cleanup;
      }
   }

   if((node = ezxml_child(doc,"lock_dir")) != NULL) {
      config->lockdir = apr_pstrdup(ctx->pool, node->txt);
   } else {
      config->lockdir = apr_pstrdup(ctx->pool,"/tmp");
   }

   if((node = ezxml_child(doc,"lock_retry")) != NULL) {
      char *endptr;
      config->lock_retry_interval = (unsigned int)strtol(node->txt,&endptr,10);
      if(*endptr != 0 || config->lock_retry_interval < 0) {
         ctx->set_error(ctx, 400, "failed to parse lock_retry microseconds \"%s\". Expecting a positive integer",
               node->txt);
         return;
      }
   }
   
   if((node = ezxml_child(doc,"threaded_fetching")) != NULL) {
      if(!strcasecmp(node->txt,"true")) {
         config->threaded_fetching = 1;
      } else if(strcasecmp(node->txt,"false")) {
         ctx->set_error(ctx, 400, "failed to parse threaded_fetching \"%s\". Expecting true or false",node->txt);
         return;
      }
   }

   if((node = ezxml_child(doc,"log_level")) != NULL) {
      if(!strcasecmp(node->txt,"debug")) {
         config->loglevel = MAPCACHE_DEBUG;
      } else if(!strcasecmp(node->txt,"info")) {
         config->loglevel = MAPCACHE_INFO;
      } else if(!strcasecmp(node->txt,"notice")) {
         config->loglevel = MAPCACHE_NOTICE;
      } else if(!strcasecmp(node->txt,"warn")) {
         config->loglevel = MAPCACHE_WARN;
      } else if(!strcasecmp(node->txt,"error")) {
         config->loglevel = MAPCACHE_ERROR;
      } else if(!strcasecmp(node->txt,"crit")) {
         config->loglevel = MAPCACHE_CRIT;
      } else if(!strcasecmp(node->txt,"alert")) {
         config->loglevel = MAPCACHE_ALERT;
      } else if(!strcasecmp(node->txt,"emerg")) {
         config->loglevel = MAPCACHE_EMERG;
      } else {
         ctx->set_error(ctx,500,"failed to parse <log_level> \"%s\". Expecting debug, info, notice, warn, error, crit, alert or emerg",node->txt);
         return;
      }
   }
   if((node = ezxml_child(doc,"auto_reload")) != NULL) {
      if(!strcasecmp(node->txt,"true")) {
         config->autoreload = 1;
      } else if(!strcasecmp(node->txt,"false")) {
         config->autoreload = 0;
      } else {
         ctx->set_error(ctx,500,"failed to parse <auto_reload> \"%s\". Expecting true or false",node->txt);
         return;
      }
   }


cleanup:
   ezxml_free(doc);
   return;
}