/***************************************
  $Revision: 1.16 $

  Reporting module.

  Status: REVIEWED, TESTED

 Author(s):       Tiago Antao

  ******************/ /******************
  Modification History:
        tiago (10/04/2003) Created.
  ******************/ /******************
  Copyright (c) 2003               RIPE NCC
 
  All Rights Reserved
  
  Permission to use, copy, modify, and distribute this software and its
  documentation for any purpose and without fee is hereby granted,
  provided that the above copyright notice appear in all copies and that
  both that copyright notice and this permission notice appear in
  supporting documentation, and that the name of the author not be
  used in advertising or publicity pertaining to distribution of the
  software without specific, written prior permission.
  
  THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
  AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
  DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 ***************************************/
#include <rip.h>
#include "rt_dbupdate.h"
#include <libxml/tree.h>

void rt_prepare_node(RT_context_t* ctx, xmlNodePtr node);
xmlNodePtr rt_generate_list(xmlNodePtr parent_node, gchar* tag, GList* list);

rpsl_object_t* rt_get_object(RT_context_t* ctx) {
  rpsl_object_t* obj;

  obj = (rpsl_object_t*)ctx->specific_data;
  return obj;
}

xmlNodePtr rt_get_object_id(RT_context_t* ctx) {
  xmlNodePtr node;
  rpsl_object_t* obj;

  obj = rt_get_object(ctx);
  node = xmlNewNode(NULL, (xmlChar*)"object_id");
  //this is wrong for Person/Roles/Routes
  rt_xml_node_add_content(node, (xmlChar*)strtok((rpsl_object_get_attr_by_ofs(obj, 0)->value), " "));

  return node;
}

typedef struct {
  GList* bad_creds;
  int    nblobs;
} analiser_struct;

void rt_blob(EP_blob_credential_t* data, gpointer user_data) {
  int* nblobs;
  GList* credentials;
  CR_credential_t* credential;
  analiser_struct* as;

  as = (analiser_struct*)user_data;

  as->nblobs += 1;
  credentials = EP_get_credentials(data);
  while (credentials) {
    credential = (CR_credential_t*) credentials->data;
    if (CR_credential_get_validity(credential) == FALSE) {
      //we have a bad credential
      as->bad_creds =
        g_list_append(as->bad_creds, CR_credential_duplicate(credential));
    }
    credentials = credentials->next;
  }
}

/*+
  RT_EP_analyse - Analizes the EP_input_structure

  RT_context_t* ctx - Context.

  EP_input_structure_t* input - The input structure.
  +*/
gchar* RT_EP_analyse(RT_context_t* ctx, EP_input_structure_t* input) {
  xmlNodePtr node;
  xmlNodePtr child_node;
  xmlNodePtr cred_node;
  xmlNodePtr gen_node;
  analiser_struct as;
  GList* creds;
  GList* list;

  node = xmlNewNode(NULL, (xmlChar*)"input_analyse");
  rt_prepare_node(ctx, node);
  as.nblobs    = 0;
  as.bad_creds = NULL;
  EP_blobs_foreach(input, rt_blob, &as);
  //PGP bad keys?
  if (as.nblobs == 0) {
    child_node = xmlNewNode(NULL, (xmlChar*)"no_valid_content");
    xmlAddChild(node, child_node);
    return "NO CONTENT";
  }
  else {
    creds = as.bad_creds;
    if (creds) {
      cred_node = xmlNewNode(NULL, (xmlChar*)"bad_credentials");

      list = creds;
      while (list) {
        gen_node = xmlNewNode(NULL, (xmlChar*)"list");
        xmlNodeSetContent(gen_node, (xmlChar*)CR_credential_get_value(list->data));
        xmlAddChild(cred_node, gen_node);
        list = g_list_next(list);
      }
      xmlAddChild(node, cred_node);
      CR_credential_list_free(creds);
      return "BAD CREDENTIALS";
    }
  }
  return "OK";
}

/*+
  RT_unparsable_input - Reports that a part of the input is not an object.

  RT_context_t* ctx - Context.

  gchar* object_candidate - Unparsable input.
  +*/
void RT_unparsable_input(RT_context_t* ctx, gchar* object_candidate) { //
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"unparsable_input");
  rt_xml_node_add_content(node, (xmlChar*)object_candidate);
  rt_prepare_node(ctx, node);
}

/*+
  RT_internal_error - Reports an internal error.

  RT_context_t* ctx - Context.

  +*/
void RT_internal_error(RT_context_t* ctx) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"internal_error");
  rt_prepare_node(ctx, node);
}

/*+
  RT_help_request - help requested.

  RT_context_t* ctx - Context.

  gchar* keyword - The keyword.
  +*/
void RT_help_request(RT_context_t* ctx) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"help_request");
  rt_prepare_node(ctx, node);
}


/*+
  RT_process_time - Reports process time of dbupdate execution.

  RT_context_t* ctx - Context.

  gchar* - date_stamp.
  +*/
void RT_process_time(RT_context_t* ctx, gchar* date_stamp) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"process_time");
  rt_add_text_node(node, "p_time", (xmlChar*) date_stamp);
  rt_prepare_node(ctx, node);
}


/*+
  RT_invalid_keyword - informs of invalid keyword.

  RT_context_t* ctx - Context.

  gchar* keyword - The keyword.
  +*/
void RT_invalid_keyword(RT_context_t* ctx, gchar* keyword) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"invalid_keyword");
  rt_xml_node_add_content(node, (xmlChar*)keyword);
  rt_prepare_node(ctx, node);
}

/*+
  RT_invalid_keyword_combination - informs of invalid keyword combo.

  RT_context_t* ctx - Context.

  gchar* keyword_comb - The keywords.
  +*/
void RT_invalid_keyword_combination(RT_context_t* ctx, gchar* keyword_comb) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"invalid_keyword_combination");
  rt_xml_node_add_content(node, (xmlChar*)keyword_comb);
  rt_prepare_node(ctx, node);
}

xmlNodePtr rt_process_attr(const rpsl_attr_t* attr) {
  xmlNodePtr node;
  const GList* errors;

  node = xmlNewNode(NULL, (xmlChar*)"attr");
  rt_xml_node_add_content(node, (xmlChar*)rpsl_attr_get_name(attr));
  rt_add_text_node(node, "value", (xmlChar*)rpsl_attr_get_value(attr));
  errors = rpsl_attr_errors(attr);
  while (errors) {
    if (((rpsl_error_t *)errors->data)->level >= RPSL_ERRLVL_ERROR) {
      rt_add_text_node(node, "syntax_error",
      (xmlChar*)((rpsl_error_t*)errors->data)->descr);
    }
    else {
      rt_add_text_node(node, "syntax_warn",
      (xmlChar*)((rpsl_error_t*)errors->data)->descr);
    }
    errors = errors->next;
  }

  return node;
} 


/*+
  RT_set_object - informs the system of the object being processed.

  RT_context_t* ctx - Context.

  rpsl_object_t* object - The object.
  +*/
void RT_set_object(RT_context_t* ctx, rpsl_object_t* object) {
  xmlNodePtr node;
  const GList* attrs;
  const GList* errs;
  gchar* attr_name;
  const rpsl_attr_t* attr;
  const rpsl_error_t* err;
  xmlChar* id;

  
  id = (xmlChar*)rpsl_object_get_key_value(object);
  if (id == NULL) {
    id = (xmlChar*)rpsl_object_get_attr_by_ofs(object, 0)->value;
  }
  node = xmlNewNode(NULL, (xmlChar*)"obj");
  rt_xml_set_prop(node, (xmlChar*)"id", id);
  ctx->specific_data = object;
  RT_request_level(ctx, node);

  attrs = rpsl_object_get_all_attr(object);
  while (attrs) {
    attr = (rpsl_attr_t*)attrs->data;
    node = rt_process_attr(attr);
    rt_prepare_node(ctx, node);
    attrs = g_list_next(attrs);
  };

  errs = rpsl_object_errors(object);
  while (errs) {
    err = (rpsl_error_t*)errs->data;
    if (err->code > RPSL_ERR_SYNERR) {
      if ( err->level > RPSL_ERRLVL_WARN ) {
        node = xmlNewNode(NULL, (xmlChar*)"object_syntax_error");
        rt_xml_node_add_content(node, (xmlChar*)(err->descr));
        rt_prepare_node(ctx, node);
      }
      else {
        node = xmlNewNode(NULL, (xmlChar*)"object_syntax_warn");
        rt_xml_node_add_content(node, (xmlChar*)(err->descr));
        rt_prepare_node(ctx, node);
      }
    }
    errs = g_list_next(errs);
  }
}

void RT_unset_object(RT_context_t* ctx, RT_upd_op operation, gboolean result) {
  gchar op[15];
  gchar res[15];
  xmlNodePtr node;

//  if (!result) {
    //  xmlNewProp(ctx->current_aggregate_node, (xmlChar*)"operation", (xmlChar*)op);
    node = xmlNewNode(NULL,
		      (xmlChar*)"class");

    xmlNewProp(node, (xmlChar*)"class",
	       (xmlChar*)rpsl_object_get_class((rpsl_object_t*)ctx->specific_data));
    rt_prepare_node(ctx, node);
//  }


  switch (operation) {
  case RT_UPD_ADD:
    sprintf(op, "Create");
    break;
  case RT_UPD_UPD:
    sprintf(op, "Modify");
    break;
  case RT_UPD_DEL:
    sprintf(op, "Delete");
    break;
  case RT_UPD_NOOP:
    sprintf(op, "No Operation");
    break;
  case RT_UPD_SYNTAX_ERR:
    sprintf(op, "Syntax Error");
    break;
  case RT_UPD_FWD:
    sprintf(op, "Forward");
    break;
  default:
    sprintf(op, "Unknown");
  }

  switch (result) {
  case TRUE:
    sprintf(res, "OK");
    break;
  case FALSE:
    sprintf(res, "ERR");
  }

  xmlNewProp(ctx->current_aggregate_node, (xmlChar*)"operation", (xmlChar*)op);
  xmlNewProp(ctx->current_aggregate_node, (xmlChar*)"result", (xmlChar*)res);
  RT_release_level(ctx);
}

/*+
  RT_syntax_error - Reports a syntax error.

  Note that the library might not even had been able to parse anything,
  so, in the worst case we need the verbatim copy of the object.

  One, and only one of object and object_candidate should be NULL.

  RT_context_t* ctx - Context.

  +*/
void RT_syntax_error(RT_context_t* ctx) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"syntax_error");
  rt_prepare_node(ctx, node);

}


/*+
  RT_syntax_ok - Reports syntax OK.

  Dual of RT_syntax_error.

  RT_context_t* ctx - Context.
  +*/
void RT_syntax_ok(RT_context_t* ctx) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"syntax_ok");
  rt_prepare_node(ctx, node);
}

/*+
  RT_invalid_source - Reports invalid source.

  RT_context_t* ctx - Context.
  +*/
void RT_invalid_source(RT_context_t* ctx) {
  xmlNodePtr node;
  rpsl_object_t* obj;
  GList* attr_list;
  gchar* source;

  obj = rt_get_object(ctx);
  attr_list = rpsl_object_get_attr(obj, "source");
  source = g_strdup(rpsl_attr_get_clean_value((rpsl_attr_t *)attr_list->data));
  rpsl_attr_delete_list(attr_list);


  node = xmlNewNode(NULL, (xmlChar*)"invalid_source");
  rt_add_text_node(node, "source", (xmlChar*) source);
  rt_prepare_node(ctx, node);
  g_free(source);
}


/*+
  RT_unknown_country - Reports that status check as failed

  RT_context_t* ctx - Context.

  gchar* reason - reason.
  +*/

void RT_status_check_failed(RT_context_t* ctx, gchar* reason) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"status_check_failed");
  rt_add_text_node(node, "reason", (xmlChar*) reason);
  rt_prepare_node(ctx, node);
}


/*+
  RT_unknown_country - Reports unknown courntry.

  RT_context_t* ctx - Context.

  gchar* - country.
  +*/
void RT_unknown_country(RT_context_t* ctx, gchar* country) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"unknown_country");
  rt_add_text_node(node, "country", (xmlChar*) country);
  rt_prepare_node(ctx, node);
}

/*+
  RT_unknown_nic_suffix - Reports unknown NIC suffix.

  RT_context_t* ctx - Context.
  +*/
void RT_unknown_nic_suffix(RT_context_t* ctx) { //
  xmlNodePtr node;
  rpsl_object_t* obj;
  GList* attr_list;
  gchar* hdl;
  gchar* suffix;

  obj = rt_get_object(ctx);
  attr_list = rpsl_object_get_attr(obj, "nic-hdl");
  hdl = g_strdup(rpsl_attr_get_value((rpsl_attr_t*)attr_list->data));
  for (suffix=hdl+strlen(hdl);suffix>hdl;suffix--) {
    if (*suffix == '-') {
      suffix++;
      break;
    }
  }
  rpsl_attr_delete_list(attr_list);

  node = xmlNewNode(NULL, (xmlChar*)"unknown_nic_suffix");
  rt_add_text_node(node, "suffix", (xmlChar*) suffix);
  rt_prepare_node(ctx, node);
  g_free(hdl);
}


/*+
  RT_auth_failure - Reports an authorization failure. 

  RT_context_t* ctx - Context.

  gchar* type - Type of failure, e.g. "MNT-BY", "MNT-ROUTES", "MNT-LOWER"...

  GList* mntner - List of maintainers that can authorize.

  gboolean has_auth - Some form of authentication was provided.

  has_auth should be replaced by credentials.

  +*/
void RT_auth_failure(RT_context_t* ctx,
		     gchar* type, GList* mntner,
		     gboolean has_auth) {
  xmlNodePtr node;
  xmlNodePtr mnt_node;

  node = xmlNewNode(NULL, (xmlChar*)"auth_failure");
  
  mnt_node = xmlNewNode(NULL, (xmlChar*)"possible_maintainers");
  rt_generate_list(mnt_node, "list", mntner);
  xmlAddChild(node, mnt_node);
  
  rt_prepare_node(ctx, node);
}


/*+
  RT_auth_ok - Reports an authorization OK. 

  RT_context_t* ctx - Context.

  gchar* type - Type of failure, e.g. "MNT-BY", "MNT-ROUTES", "MNT-LOWER"...

  Gchar* mntner - Maintainer associated with authorization (NULL OK).

  gboolean has_override - Authorization with override.
  +*/
void RT_auth_ok(RT_context_t* ctx,
		gchar* type, gchar* mntner,
		gboolean has_override) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"auth_ok");

  /*
  if (has_override) {
    xmlAddChild(node, xmlNewNode(NULL, (xmlChar*)"override"));
  }
  */

  rt_add_text_node(node, "mntner", (xmlChar*)mntner);
  rt_prepare_node(ctx, node);
}

/*+
  RT_enforcednew_exists - Its an update, but NEW was specified

  RT_context_t* ctx - Context.
 +*/
void RT_enforcednew_exists(RT_context_t* ctx) { //
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"enforced_new_exists");
  rt_prepare_node(ctx, node);
}

/*+
  RT_postproc_obj - Final state of the object after postprocessing.

  RT_context_t* ctx - Context.

  gchar* object - the postprocessed object.

  INFO
 +*/
void RT_postproc_obj(RT_context_t* ctx, rpsl_object_t* object) { //
  xmlNodePtr node;
  xmlChar* id;

  //XXX rpsl bug
  id = (xmlChar*)rpsl_object_get_key_value(object);
  if (id == NULL) {
    id = (xmlChar*)rpsl_object_get_attr_by_ofs(object, 0)->value;
  }
  rt_xml_set_prop(ctx->current_aggregate_node,
    (xmlChar*)"id", id);

}

void RT_no_objects_processed(RT_context_t* ctx) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"no_objects_processed");
  rt_prepare_node(ctx, node);
}

void RT_kc_gen_diff(RT_context_t* ctx, GList* attributes) {
  xmlNodePtr node;

  while (attributes) {
    node = xmlNewNode(NULL, (xmlChar*)"incorrect_generated");
    rt_xml_node_add_content(node, (xmlChar*)attributes->data);
    rt_prepare_node(ctx, node);
    attributes = attributes->next;
  }
}

/*+
  RT_changed_date_missing - The changed date is missing (WARNING)

  RT_context_t* ctx - Context.

  gchar* date - Current date.

  gchar* value - Current value.
 +*/
void RT_changed_date_missing(RT_context_t* ctx, gchar* date, gchar* value) { //
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"changed_date_missing");
  rt_add_text_node(node, "date", date);
  rt_add_text_node(node, "value", value);
  rt_prepare_node(ctx, node);
}

/*+
  RT_multiple_changed_date_missing - Multiple changed without date.

  RT_context_t* ctx - Context.
 +*/
void RT_multiple_changed_date_missing(RT_context_t* ctx) { //
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"multiple_changed_date_missing");
  rt_prepare_node(ctx, node);
}

/*+
  RT_changed_date_order - Changed date order is not correct.

  RT_context_t* ctx - Context.

  gchar* value - 2nd value.

  gchar* previous - previous value.
 +*/
void RT_changed_date_order(RT_context_t* ctx, gchar* value, gchar* previous) {
//
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"changed_date_order");
  rt_add_text_node(node, "value", value);
  rt_add_text_node(node, "previous", previous);
  rt_prepare_node(ctx, node);
}

/*+
  RT_changed_date_syntax - General syntax problem.

  RT_context_t* ctx - Context.

  gchar* msg - Message.

  gchar* date - Date.
 +*/
void RT_changed_date_syntax(RT_context_t* ctx, gchar* msg) { //
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"changed_date_syntax");
  rt_add_text_node(node, "message", msg);
  rt_prepare_node(ctx, node);
}

/*+
  RT_non_existent_object - Reports that an object doesn't exist.

  To be used when there is a deletion attempt on a non existent object.

  RT_context_t* ctx - Context.
  +*/
void RT_non_existent_object(RT_context_t* ctx) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"non_existent_object");
  rt_prepare_node(ctx, node);
}

/*+
  RT_object_exists - Dual of RT_non_existent_object

  RT_context_t* ctx - Context.
  +*/
void RT_object_exists(RT_context_t* ctx) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"object_exists");

  rt_prepare_node(ctx, node);
}

/*+
  RT_versions_dont_match - Reports that an object doesnt match another.

  To be used when an existent object doesn't match the supplied object
  for deletion.

  RT_context_t* ctx - Context.

  rpsl_object_t* existing_object - The current object on the database.
  +*/
void RT_versions_dont_match(RT_context_t* ctx,rpsl_object_t* existing_object) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"versions_dont_match");

  rt_add_text_node(node,
		   "object", rpsl_object_get_text(existing_object, 0));

  rt_prepare_node(ctx, node);
}

/*+
  RT_versions_match - Dual of RT_versions_dont_match
  RT_context_t* ctx - Context.
  +*/
void RT_versions_match(RT_context_t* ctx) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"versions_match");

  rt_prepare_node(ctx, node);
}

/*+
  RT_object_still_referenced - Reports that an object is still referenced.

  A referenced object cannot be deleted, this functions allow the
  reporting that an object is still referenced.

  RT_context_t* ctx - Context.
  +*/
void RT_object_still_referenced(RT_context_t* ctx) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"object_still_referenced");

  rt_prepare_node(ctx, node);
}

/*+
  RT_object_not_referenced - Dual of RT_object_still_referenced.

  RT_context_t* ctx - Context.
  +*/
void RT_object_not_referenced(RT_context_t* ctx) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"object_not_referenced");

  rt_prepare_node(ctx, node);
}

/*+
  RT_has_mail_from - reports MAIL-FROM references.

  To be used when that are MAIL-FROMs in maintainers.
  This might disapear and RT_message usage recommended.

  RT_context_t* ctx - Context.

  gboolean ok - This was not cause of failure (e.g. there are other auths).

  gboolean only_mfrom - mntner only has MAIL-FROM.
  +*/
void RT_has_mail_from(RT_context_t* ctx, gboolean ok, gboolean only_mfrom) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"mail_from");
  if (only_mfrom) {
    xmlAddChild(node, xmlNewNode(NULL, (xmlChar*)"only_mfrom"));
  }
  else if (ok){
    xmlAddChild(node, xmlNewNode(NULL, (xmlChar*)"ok"));
  }

  rt_prepare_node(ctx, node);
}

/*+
  RT_no_mail_from - Dual of RT_has_mail_from.

  RT_context_t* ctx - Context.
  +*/
void RT_no_mail_from(RT_context_t* ctx) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"no_mail_from");

  rt_prepare_node(ctx, node);
}

/*+
  RT_unknown_refered_object - Object points to unknown objects.

  To be used when an object has reference to non existing objects

  RT_context_t* ctx - Context.

  gchar* refered_name - The referenced name.
  +*/
void RT_unknown_refered_object(RT_context_t* ctx,
			       gchar* refered_name) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"unknown_refered_object");
  rt_add_text_node(node, "refered_object", refered_name);

  rt_prepare_node(ctx, node);
}

/*+
  RT_known_refered_object - Dual of RT_unknown_refered_object.

  RT_context_t* ctx - Context.
   +*/
void RT_known_refered_object(RT_context_t* ctx, gchar* refered_name){
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"known_refered_object");
  rt_add_text_node(node, "refered_object", refered_name);

  rt_prepare_node(ctx, node);
}


/*+
  RT_unknown_auto_nic_handle - A NIC handle is unknown.

  RT_context_t* ctx - Context.

  gchar* handle - The handle
  +*/
void RT_unknown_auto_nic_handle(RT_context_t* ctx,
				gchar* handle) { //
  xmlNodePtr     node;

  node = xmlNewNode(NULL, (xmlChar*)"unknown_auto_nic");
  rt_add_text_node(node, "nic", handle);

  rt_prepare_node(ctx, node);
}

void RT_report_key_info(RT_context_t* ctx, KM_key_return_t* info) { //
  KM_status_t    status;
  xmlNodePtr     node;
  xmlNodePtr     child;

  status = KM_key_return_get_status(info);
  node = xmlNewNode(NULL, (xmlChar*)"key_info");


  switch (status) {
  case KM_OK:
    child = xmlNewNode(NULL, (xmlChar*)"ok");
    break;
  case KM_MULTIPLE_KEYS:
    child = xmlNewNode(NULL, (xmlChar*)"multiple_keys");
    break;
  case KM_NO_KEY:
    child = xmlNewNode(NULL, (xmlChar*)"no_key");
    break;
  case KM_KEY_EXISTS:
    child = xmlNewNode(NULL, (xmlChar*)"keys_exists");
    break;
  case KM_SECRET_KEY:
    child = xmlNewNode(NULL, (xmlChar*)"secret_key");
    break;
  case KM_IDS_DONT_MATCH:
    child = xmlNewNode(NULL, (xmlChar*)"ids_dont_match");
    break;
  case KM_INTERNAL:
    child = xmlNewNode(NULL, (xmlChar*)"internal");
    break;
  case KM_UNEXISTENT_KEY:
    child = xmlNewNode(NULL, (xmlChar*)"unexistent_key");
    break;
  case KM_NOT_REMOVED:
    child = xmlNewNode(NULL, (xmlChar*)"not_removed");
    break;
  default:
    child = xmlNewNode(NULL, (xmlChar*)"unknown_error");
  }
  xmlAddChild(node, child);

  rt_prepare_node(ctx, node);
}

/*+
  RT_key_add_error - Reports an add key error.

  RT_context_t* ctx - Context.

  KM_status_t - status.
  +*/
void RT_key_add_error(RT_context_t* ctx, KM_status_t status) { //
  xmlNodePtr node;
  gchar*     error_string;

  node = xmlNewNode(NULL, (xmlChar*)"key_add_error");
  error_string = KM_return_string(status);
  rt_add_text_node(node, "error", error_string);

  rt_prepare_node(ctx, node);
}

/*+
  RT_key_modify_error - Reports a modify key error.

  RT_context_t* ctx - Context.

  KM_status_t - status.

  +*/
void RT_key_modify_error(RT_context_t* ctx, KM_status_t status) { //
  xmlNodePtr node;
  gchar*     error_string;

  node = xmlNewNode(NULL, (xmlChar*)"key_modify_error");
  error_string = KM_return_description(status);
  rt_add_text_node(node, "error", error_string);

  rt_prepare_node(ctx, node);
}

/*+
  RT_key_remove_error - Reports a remove key error.

  RT_context_t* ctx - Context.

  KM_status_t - status.

  +*/
void RT_key_remove_error(RT_context_t* ctx, KM_status_t status) { //
  xmlNodePtr node;
  gchar* error_string;

  node = xmlNewNode(NULL, (xmlChar*)"key_remove_error");
  error_string = KM_return_string(status);
  rt_add_text_node(node, "error", error_string);

  rt_prepare_node(ctx, node);
}

/*+
  RT_RIP_update_error - Reports an error from RIPUpdate

  RIPUpdate error, still to be thinked.

  RT_context_t* ctx - Context.
  +*/
void RT_RIP_update_error(RT_context_t* ctx, gchar* error) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"rip_update_error");
  rt_add_text_node(node, "error", error);

  rt_prepare_node(ctx, node);
}

/*+
  RT_RIP_update_ok - Dual of RT_RIP_update_ok.

  RT_context_t* ctx - Context.
  +*/
void RT_RIP_update_ok(RT_context_t* ctx) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"rip_update_ok");

  rt_prepare_node(ctx, node);
}


/*+
  RT_non_exist_mntner - Reports a non existent maintainer
  +*/
void RT_non_exist_mntner(RT_context_t* ctx, gchar* mntner) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"non_existent_maintainer");
  rt_xml_node_add_content(node, (xmlChar*)mntner);
  rt_prepare_node(ctx, node);
}


/*+
  RT_non_exist_irt - Reports a non existent irt
  +*/
void RT_non_exist_irt(RT_context_t* ctx, gchar* irt) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"non_existent_irt");
  rt_xml_node_add_content(node, (xmlChar*)irt);
  rt_prepare_node(ctx, node);
}


/*+
  RT_parent_not_exist - Report that object has no parent in the DB

  RT_context_t* ctx - Context.
  +*/
void RT_parent_not_exist(RT_context_t* ctx) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"non_existent_parent");

  rt_prepare_node(ctx, node);
}


/*+
  RT_origin_not_exist - Report that route object has no origin AS in the DB

  RT_context_t* ctx - Context.
  +*/
void RT_origin_not_exist(RT_context_t* ctx) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"non_existent_origin");

  rt_prepare_node(ctx, node);
}


/*+
  RT_manual_creation - Report that object requires manual creation.

  This is normally irt, mntner and AS.

  RT_context_t* ctx - Context.
  +*/
void RT_manual_creation(RT_context_t* ctx) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"manual_creation");

  rt_prepare_node(ctx, node);
}

/*+
  RT_automatic_creation - Dual of RT_is_manual_creation.

  RT_context_t* ctx - Context.
  +*/
void RT_automatic_creation(RT_context_t* ctx) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"automatic_creation");

  rt_prepare_node(ctx, node);
}


/*+
  RT_object_not_found - A certain object was not found.

  RT_context_t* ctx - Context.

  gchar* name - pkey.

  WARNING
  +*/
void RT_object_not_found(RT_context_t* ctx, gchar* name) { //
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"object_not_found");
  rt_add_text_node(node, "object", name);

  rt_prepare_node(ctx, node);
}

/*+
  RT_header - Report output headers.

  RT_context_t* ctx   - Context.

  gchar* to_address   - To address.

  gchar* from_address - From address.

  FATAL  -> not fatal but has always to go
  +*/
void RT_header(RT_context_t* ctx, gchar* to_address,
  gchar* from_address, gchar* subject) {
//
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"notification_header");
  rt_add_text_node(node, "to", to_address);
  rt_add_text_node(node, "from", from_address);
  rt_add_text_node(node, "subject", subject);

  rt_prepare_node(ctx, node);
}

/*+
  RT_from_mail - Report mail originator.

  RT_context_t* ctx - Context.

  mail_hdr_t* mail_info - Mail info.

  INFO
  +*/
void RT_from_mail(RT_context_t* ctx, mail_hdr_t* mail_info) { //
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"mail_origin_of_request");
  rt_add_text_node(node, "from", mail_info->from);
  rt_add_text_node(node, "from_email", mail_info->from_email);
  //rt_add_text_node(node, "cc", mail_info->cc);
  rt_add_text_node(node, "subject", mail_info->subject);
  rt_add_text_node(node, "date", mail_info->date);
  rt_add_text_node(node, "reply_to", mail_info->replyto);
  rt_add_text_node(node, "msgid", mail_info->msgid);

  rt_prepare_node(ctx, node);
}

/*+
  RT_notif_origin - Report originating IP address of a request.

  RT_context_t* ctx - Context.

  gchar* origin - IP.

  INFO
  +*/
void RT_notif_origin(RT_context_t* ctx, gchar* origin) { //
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"ip_origin_of_request");
  rt_add_text_node(node, "ip", origin);

  rt_prepare_node(ctx, node);
}

void RT_notif_add_msg(RT_context_t* ctx, gchar* message) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"notif_message");
  rt_add_text_node(node, "message", message);

  rt_prepare_node(ctx, node);
}

void RT_credentials(RT_context_t *ctx, GList *credentials) {
  xmlNodePtr node;
  CR_credential_t* cr;

  node = xmlNewNode(NULL, (xmlChar*)"credentials");
  while (credentials) {
    cr = (CR_credential_t*)(credentials->data);
    if (CR_credential_get_validity(cr)) {
      rt_add_text_node(node, "list", CR_credential_get_value(cr));
    }
    credentials = credentials->next;
  }
  rt_prepare_node(ctx, node);
}


void RT_full_input(RT_context_t* ctx, char *filename) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"full_input");
  rt_add_text_node(node, "message", filename);

  rt_prepare_node(ctx, node);
}


void RT_no_frwd_create(RT_context_t* ctx) {
}

void RT_operation(RT_context_t* ctx, gint operation, gboolean ok) {
  xmlNodePtr     node;
  char           op[10];

  if (ok) {
    node = xmlNewNode(NULL, (xmlChar*)"operation_ok");
  }
  else {
    node = xmlNewNode(NULL, (xmlChar*)"operation_failed");
  }

  switch (operation) {
  case RT_UPD_ADD:
    sprintf((char*)op, "ADD");
    break;
  case RT_UPD_UPD:
    sprintf((char*)op, "UPD");
    break;
  case RT_UPD_DEL:
    sprintf((char*)op, "DEL");
    break;
  }

  rt_add_text_node(node, "operation", op);

  if (ok) {
    rt_prepare_node(ctx, node);
    //Not an error, but with equal importance
  }
  else {
    rt_prepare_node(ctx, node);
  }
}

typedef xmlChar* (*rt_map_function)(rpsl_object_t* object);

xmlChar* rt_object_class(rpsl_object_t* object) {
  return (xmlChar*)rpsl_object_get_key_value(object);
}

void RT_multiple_parents(RT_context_t *ctx, GList *parents) {
  xmlNodePtr node;

  node = xmlNewNode(NULL, (xmlChar*)"multiple_parents");
  rt_generate_list_map(node, "list_line", parents, rt_object_class);
  rt_prepare_node(ctx, node);
}

/* auth check */
void RT_irt_auth(RT_context_t* ctx, gchar* key, gchar* type, gchar* attr_checked,
        GList* irt_ok, GList* irt_fail) {
  xmlNodePtr node;
  xmlNodePtr child;

  node = xmlNewNode(NULL, (xmlChar*)"irt_auth_info");
  rt_add_text_node(node, "key", key);
  rt_add_text_node(node, "type", type);
//  rt_add_text_node(node, "type", rpsl_object_get_class(rt_get_object(ctx)));
  if (!attr_checked) {
    child = xmlNewNode(NULL, (xmlChar*)"no_irt");
    xmlAddChild(node, child);
  }
  else {
    rt_add_text_node(node, "attribute_checked", attr_checked);
    if (irt_ok) {
      child = xmlNewNode(NULL, (xmlChar*)"irt_auth_ok");
      xmlAddChild(node, child);
      rt_generate_list_map(child, "list", irt_ok, rt_object_class);
    }
    if (irt_fail) {
      child = xmlNewNode(NULL, (xmlChar*)"irt_auth_fail");
      xmlAddChild(node, child);
      rt_generate_list_map(child, "list", irt_fail, rt_object_class);
    }
  }

  rt_prepare_node(ctx, node);
}

/* final result */
void RT_irt_auth_result(RT_context_t* ctx, gboolean result, gboolean override) {
  xmlNodePtr node;
  xmlNodePtr child;

  node = xmlNewNode(NULL, (xmlChar*)"irt_auth_result");
  if (override) {
    rt_xml_set_prop(node, (xmlChar*)"override", (xmlChar*)"yes");
  }
  if (result) {
    child = xmlNewNode(NULL, (xmlChar*)"ok");
  }
  else {
    child = xmlNewNode(NULL, (xmlChar*)"fail");
  }
  xmlAddChild(node, child);
  rt_prepare_node(ctx, node);
}

/* auth check */
void RT_auth(RT_context_t* ctx, gchar* key, gchar* type, gchar* attr_checked,
        GList* auth_ok, GList* auth_fail, gchar *parent_text) {
  xmlNodePtr node;
  xmlNodePtr child;

  node = xmlNewNode(NULL, (xmlChar*)"auth_info");
  rt_add_text_node(node, "key", key);
  rt_add_text_node(node, "type", type);
//  rt_add_text_node(node, "type", rpsl_object_get_class(rt_get_object(ctx)));
  rt_add_text_node(node, "parent_text", parent_text);
  if (!attr_checked) {
    child = xmlNewNode(NULL, (xmlChar*)"no_maintainer");
    xmlAddChild(node, child);
  }
  else {
    rt_add_text_node(node, "attribute_checked", attr_checked);
    if (auth_ok) {
      child = xmlNewNode(NULL, (xmlChar*)"mnt_auth_ok");
      xmlAddChild(node, child);
      rt_generate_list_map(child, "list", auth_ok, rt_object_class);
    }
    if (auth_fail) {
      child = xmlNewNode(NULL, (xmlChar*)"mnt_auth_fail");
      xmlAddChild(node, child);
      rt_generate_list_map(child, "list", auth_fail, rt_object_class);
    }
  }

  rt_prepare_node(ctx, node);
}

/* final result */
void RT_auth_result(RT_context_t* ctx, gboolean result, gboolean override) {
  xmlNodePtr node;
  xmlNodePtr child;

  node = xmlNewNode(NULL, (xmlChar*)"auth_result");
  if (override) {
    rt_xml_set_prop(node, (xmlChar*)"override", (xmlChar*)"yes");
  }
  if (result) {
    child = xmlNewNode(NULL, (xmlChar*)"ok");
  }
  else {
    child = xmlNewNode(NULL, (xmlChar*)"fail");
  }
  xmlAddChild(node, child);
  rt_prepare_node(ctx, node);
}





