/*!
 * @file message.c
 *
 * vim: expandtab:ts=2:sts=2:sw=2
 *
 * @authors
 * Copyright (C) 2020 Anoxinon e.V. 
 *
 * @copyright 
 * This file is part of xmppc.
 *
 * xmppc is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * xmppc is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
 *
 * German
 *
 * Diese Datei ist Teil von xmppc.
 *
 * xmppc ist Freie Software: Sie können es unter den Bedingungen
 * der GNU General Public License, wie von der Free Software Foundation,
 * Version 3 der Lizenz oder (nach Ihrer Wahl) jeder neueren
 * veröffentlichten Version, weiter verteilen und/oder modifizieren.
 *
 * xmppc wird in der Hoffnung, dass es nützlich sein wird, aber
 * OHNE JEDE GEWÄHRLEISTUNG, bereitgestellt; sogar ohne die implizite
 * Gewährleistung der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK.
 * Siehe die GNU General Public License für weitere Details.
 *
 * Sie sollten eine Kopie der GNU General Public License zusammen mit diesem
 * Programm erhalten haben. Wenn nicht, siehe <https://www.gnu.org/licenses/>.
 */

#include "message.h"
#include "mam.h"
#include "glib.h"
#include "stdbool.h"
#include "stdlib.h"
#include "string.h"

#define SID_NS "urn:xmpp:sid:0"

typedef struct {
  char *to;
  char *message_id;
  char *archive_id;
  bool done;
} message_send_t;

static void _message_send_text(xmppc_t *xmppc, char* to, char* message);
static void _message_archive_id_found(xmpp_conn_t *conn, const char *archive_id, void *userdata);
static void _message_finish_sent(xmpp_conn_t *conn, message_send_t *sent);
static void _message_send_free(message_send_t *sent);
static void _message_print_sent(message_send_t *sent);
static void _message_print_escaped_attr(const char *text);

void message_execute_command(xmppc_t *xmppc, int argc, char *argv[]) {
  if( argc == 3 && ( strcmp("chat", argv[0] ) == 0)) {
    _message_send_text(xmppc, argv[1],argv[2]);
  } else {
    logError(xmppc, "Befehl unbekannt");
    xmpp_disconnect(xmppc->conn);
  }
}

void _message_send_text(xmppc_t *xmppc, char* to, char* text) {
  xmpp_conn_t *conn = xmppc->conn;
  xmpp_ctx_t *ctx = xmpp_conn_get_context(conn);
  xmpp_stanza_t *message;
  char* id = xmpp_uuid_gen(xmppc->ctx);
  message = xmpp_message_new(ctx, "chat", to, id);
  int res = xmpp_message_set_body(message, text);
  if(res == 0) {
    xmpp_stanza_t *origin = xmpp_stanza_new(ctx);
    xmpp_stanza_set_name(origin, "origin-id");
    xmpp_stanza_set_ns(origin, SID_NS);
    xmpp_stanza_set_attribute(origin, "id", id);
    xmpp_stanza_add_child(message, origin);
    xmpp_stanza_release(origin);

    message_send_t *sent = g_new0(message_send_t, 1);
    sent->to = g_strdup(to);
    sent->message_id = g_strdup(id);

    xmpp_send(conn, message);
    mam_lookup_message_archive_id(xmppc, to, id, _message_archive_id_found, sent);
  } else {
    xmpp_disconnect(conn);
  }
  xmpp_stanza_release(message);
  free(id);
}

static void _message_archive_id_found(xmpp_conn_t *conn, const char *archive_id, void *userdata) {
  message_send_t *sent = (message_send_t *)userdata;

  if (archive_id) {
    sent->archive_id = g_strdup(archive_id);
  }

  _message_finish_sent(conn, sent);
}

static void _message_finish_sent(xmpp_conn_t *conn, message_send_t *sent) {
  if (sent->done) {
    return;
  }

  sent->done = true;
  _message_print_sent(sent);
  _message_send_free(sent);
  xmpp_disconnect(conn);
}

static void _message_send_free(message_send_t *sent) {
  g_free(sent->to);
  g_free(sent->message_id);
  g_free(sent->archive_id);
  g_free(sent);
}

static void _message_print_sent(message_send_t *lookup) {
  printf("<sent archive-id=\"");
  _message_print_escaped_attr(lookup->archive_id ? lookup->archive_id : "");
  printf("\" message-id=\"");
  _message_print_escaped_attr(lookup->message_id);
  printf("\" to=\"");
  _message_print_escaped_attr(lookup->to);
  printf("\"/>\n");
  fflush(stdout);
}

static void _message_print_escaped_attr(const char *text) {
  const unsigned char *p = (const unsigned char *)(text ? text : "");

  while (*p) {
    switch (*p) {
      case '&':
        printf("&amp;");
        break;
      case '<':
        printf("&lt;");
        break;
      case '>':
        printf("&gt;");
        break;
      case '"':
        printf("&quot;");
        break;
      case '\n':
        printf("&#10;");
        break;
      case '\r':
        printf("&#13;");
        break;
      case '\t':
        printf("&#9;");
        break;
      default:
        if (*p < 0x20) {
          printf("&#x%02X;", *p);
        } else {
          putchar(*p);
        }
        break;
    }
    p++;
  }
}
