/**
 * inf_adopted_session_write_request_info:
 * @session: A #InfAdoptedSession.
 * @diff_vec: A reference state vector, or %NULL.
 * @request: The #InfAdoptedRequest whose info to write.
 * @xml: The XML node to write the data into.
 * @operation: An XML node representing the operation of the request, or
 * %NULL.
 *
 * This function writes common data from @request, such as the user that
 * issued the request and the state in which the request was made into @xml.
 * If @diff_vec is given, then the state is written as a diff to this vector,
 * see inf_adopted_state_vector_to_string_diff(). Deserializing this data
 * again (via inf_adopted_session_read_request_info()) requires the same
 * @diff_vec then.
 *
 * This function is most likely to be used by implementations of the
 * request_to_xml virtual function.
 */
void
inf_adopted_session_write_request_info(InfAdoptedSession* session,
                                       InfAdoptedRequest* request,
                                       InfAdoptedStateVector* diff_vec,
                                       xmlNodePtr xml,
                                       xmlNodePtr operation)
{
  InfAdoptedStateVector* vector;
  guint user_id;
  gchar* vec_str;

  vector = inf_adopted_request_get_vector(request);
  user_id = inf_adopted_request_get_user_id(request);

  inf_xml_util_set_attribute_uint(xml, "user", user_id);

  if(diff_vec == NULL)
    vec_str = inf_adopted_state_vector_to_string(vector);
  else
    vec_str = inf_adopted_state_vector_to_string_diff(vector, diff_vec);

  inf_xml_util_set_attribute(xml, "time", vec_str);
  g_free(vec_str);
  
  if(operation != NULL)
    xmlAddChild(xml, operation);
}
static void
infd_note_plugin_text_session_write_foreach_user_func(InfUser* user,
                                                      gpointer user_data)
{
  xmlNodePtr parent;
  xmlNodePtr node;

  parent = (xmlNodePtr)user_data;
  node = xmlNewChild(parent, NULL, (const xmlChar*)"user", NULL);

  inf_xml_util_set_attribute_uint(node, "id", inf_user_get_id(user));
  inf_xml_util_set_attribute(node, "name", inf_user_get_name(user));
  inf_xml_util_set_attribute_double(
    node,
    "hue",
    inf_text_user_get_hue(INF_TEXT_USER(user))
  );
}
static void
inf_adopted_session_set_xml_user_props(InfSession* session,
                                       const GParameter* params,
                                       guint n_params,
                                       xmlNodePtr xml)
{
  const GParameter* time;
  InfAdoptedStateVector* vector;
  gchar* time_string;

  INF_SESSION_CLASS(parent_class)->set_xml_user_props(
    session,
    params,
    n_params,
    xml
  );

  time = inf_session_lookup_user_property(params, n_params, "vector");
  if(time != NULL)
  {
    vector = (InfAdoptedStateVector*)g_value_get_boxed(&time->value);
    time_string = inf_adopted_state_vector_to_string(vector);
    inf_xml_util_set_attribute(xml, "time", time_string);
    g_free(time_string);
  }

  /* log-begin is not in the spec */
#if 0
  log = inf_session_lookup_user_property(params, n_params, "request-log");
  if(log != NULL)
  {
    log_begin = inf_adopted_request_log_get_begin(
      INF_ADOPTED_REQUEST_LOG(g_value_get_object(&log->value))
    );

    inf_xml_util_set_attribute_uint(xml, "log-begin", log_begin);
  }
#endif
}
/**
 * infd_acl_account_info_to_xml:
 * @info: A #InfdAclAccountInfo.
 * @xml: XML node to write the account information to.
 *
 * Serializes a #InfdAclAccountInfo object into an XML node. The account
 * information can be deserialized again with
 * infd_acl_account_info_from_xml().
 */
void
infd_acl_account_info_to_xml(const InfdAclAccountInfo* info,
                             xmlNodePtr xml)
{
  guint i;

  gnutls_datum_t datum;
  size_t out_size;
  gchar* out;
  int res;

  g_return_if_fail(info != NULL);
  g_return_if_fail(xml != NULL);

  inf_acl_account_to_xml(&info->account, xml);

  for(i = 0; i < info->n_certificates; ++i)
  {
    xmlNewChild(
      xml,
      NULL,
      (const xmlChar*)"certificate",
      (const xmlChar*)info->certificates[i]
    );
  }

  if(info->password_salt != NULL)
  {
    datum.data = info->password_salt;
    datum.size = 32;

    res = gnutls_hex_encode(&datum, NULL, &out_size);
    g_assert(res == GNUTLS_E_SHORT_MEMORY_BUFFER);

    out = g_malloc(out_size + 1);
    res = gnutls_hex_encode(&datum, out, &out_size);
    g_assert(res == GNUTLS_E_SUCCESS);

    out[out_size] = '\0';
    inf_xml_util_set_attribute(xml, "password-salt", out);
    g_free(out);
  }

  if(info->password_hash != NULL)
  {
    datum.data = info->password_hash;
    datum.size = gnutls_hash_get_len(GNUTLS_DIG_SHA256);

    res = gnutls_hex_encode(&datum, NULL, &out_size);
    g_assert(res == GNUTLS_E_SHORT_MEMORY_BUFFER);

    out = g_malloc(out_size + 1);
    res = gnutls_hex_encode(&datum, out, &out_size);
    g_assert(res == GNUTLS_E_SUCCESS);

    out[out_size] = '\0';
    inf_xml_util_set_attribute(xml, "password-hash", out);
    g_free(out);
  }

  if(info->first_seen != 0)
  {
    inf_xml_util_set_attribute_double(
      xml,
      "first-seen",
      info->first_seen / 1e6
    );
  }

  if(info->last_seen != 0)
  {
    inf_xml_util_set_attribute_double(
      xml,
      "last-seen",
      info->last_seen / 1e6
    );
  }
}