/* 
 * $Id: util.c,v 1.14 1999/01/21 23:44:06 labovit Exp $
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <irr_notify.h>


/*
 * Could have an email user or TCP user.
 * In case of a TCP user set the email fields
 * to single space for uniform treatment.
 */
void chk_email_fields (trans_info_t *ti) {

  if (ti->subject == NULL)
    ti->subject = strdup (" ");

  if (ti->date == NULL)
    ti->date = strdup (" ");

  if (ti->msg_id == NULL)
    ti->msg_id = strdup (" ");

  ti->hdr_fields |= (SUBJECT_F|DATE_F|MSG_ID_F);
}

/*
 * Return 0 if something wrong is found , ie, a malformed
 * transaction header has been detected.
 * Else return 1.
 */
int chk_hdr_flds (u_int hdr_flds) {

  return ((int) !((~hdr_flds) & NOTIFY_REQUIRED_FLDS));
}
  
void remove_sender (char *sender, char *addr_buf, char **next) {
  char buf[MAXLINE];
  char *q, *bnext;
  int found = 0;

  bnext = buf;
  for (q = addr_buf; q < *next; q += strlen (q) + 1) {
    if (strcasecmp (sender, q)) {
      strcpy (bnext, q);
      bnext += strlen (q) + 1;
    }
    else
      found = 1;
  }

  if (found) {
    memcpy (addr_buf, buf, bnext - buf);
    *next = (addr_buf + (bnext - buf));
  }
}

/* Interpret the IRRd return code and place the result in the 
 * 'irrd_result_t' struct.  IRRd will return 'C\n' for success
 * or an error otherwise (IRRd should give a text msg indicating
 * what the error was).
 *
 * Return:
 *  void
 */
void put_transaction_code (trace_t *tr, irrd_result_t *p, char *irrd_ret_code) {

  /*fprintf (dfile, "put_transaction_code () irrd result: %s", irrd_ret_code);*/

  if (irrd_ret_code != NULL && *irrd_ret_code == 'C')
    p->svr_res = SUCCESS_RESULT;
  else {
    p->svr_res = IRRD_ERROR_RESULT;
    /* Skip the 'F' or whatever machine return code
     * but do get the text error msg
     */
    if (irrd_ret_code != NULL)
      p->err_msg = strdup (++irrd_ret_code);
    else
      p->err_msg = strdup ("Error message not available!\n");
  }
}

/* JW get rid of */
int put_transaction_code_old (trace_t *tr, FILE *fin, char code, long fpos) {
  long restore_pos;

  if ((restore_pos = ftell (fin)) == -1L)
    return 0;

  if (fseek (fin, fpos, SEEK_SET)) {
    fprintf (stderr, "ERROR: put_transaction_code() fseek(%ld) error!\n", fpos);
    return 0;
  }
  else {
    if (fputc ((int) code, fin) == EOF)
      /*fprintf (dfile, "put_transaction_code() fputc(%c) error\n", code);*/

    if (fseek (fin, restore_pos, SEEK_SET)) {
      /*fprintf (dfile, "ERROR: put_transaction_code() fseek(%ld) restore fpos error!\n", restore_pos);*/
      return 0;
    }
  }

  return 1;
}

void skip_transaction (FILE *fin, long *offset) {
  char buf[MAXLINE];

  while (fgets (buf, MAXLINE - 1, fin) != NULL) {
    *offset += strlen (buf);
    if (buf[0] == '\n')
      break;
  }
}



/* Add the element pointed to by 'obj' to the end of the linked list.
 *
 * Return:
 *  void
 */
void add_outcome_list_obj (trace_t *tr, ret_info_t *start, irrd_result_t *obj) {

  obj->next = NULL;
  if (start->first == NULL)
    start->first = obj;
  else
    start->last->next = obj;

  start->last = obj;
}

/* Initialize an irrd_result_t struct.  If an INTERNAL_ERROR_RESULT, NOOP_RESULT, or
 * USER_ERROR occurs the 'svr_res' field is initialized.  Otherwise 'svr_res'
 * will be uninitialized.  In this case, 'svr_res' will be initialized when
 * the update is applied to IRRd from the IRRd return code.  The 'op', 'source' 
 * and 'offset' fields are used to send the transaction to IRRd.
 *
 * Return:
 *  void
 */
/*
  obj = (irrd_result_t *) calloc (1, sizeof (irrd_result_t));
  */
void update_trans_outcome_list (trace_t *tr, ret_info_t *start, 
				trans_info_t *ti, long offset, 
				enum SERVER_RES svr_res, char *err_msg) {
  irrd_result_t *obj;

  /* fprintf (dfile, "enter update_trans_outcome_list ()...\n");*/
  obj = (irrd_result_t *) malloc (sizeof (irrd_result_t));
  memset ((char *) obj, 0, sizeof (irrd_result_t));
  if (err_msg != NULL) {
    obj->err_msg = strdup (err_msg);
    obj->svr_res = svr_res;
  }
  else if (svr_res == NULL_SUBMISSION)
    obj->svr_res = NULL_SUBMISSION;
  else if ((ti->hdr_fields & OP_F) && !strcmp (ti->op, NOOP_OP))
    obj->svr_res = NOOP_RESULT;
  else if (ti->hdr_fields & ERROR_FLDS)
    obj->svr_res = USER_ERROR;

  obj->hdr_fields = ti->hdr_fields;
  if (ti->hdr_fields & OP_F)
    obj->op = strdup (ti->op);

  if (ti->hdr_fields & SOURCE_F)
    obj->source = strdup (ti->source);

  obj->offset = offset;
  /* fprintf (dfile, "update_trans_outcome (): offset (%ld)\n", obj->offset);*/

  add_outcome_list_obj (tr, start, obj);
  /* fprintf (dfile, "exit update_trans_outcome_list ()...\n");*/
}

/* Set all unset elements in the 'irrd_result_t' list to 'res'.  This
 * function should be called when an error of any kind has been
 * found (eg, syntax error, network error, internal error, ...).
 * The reason is to support transaction semactics which calls for
 * a transaction to be aborted if the entire trans cannot be applied.
 * So this routine will set the proper trans outcome to those updates
 * that would have been sent to IRRd if it were not for the error occuring.
 * 
 * Return:
 *  void
 */
void reinit_return_list (trace_t *tr, ret_info_t *start, enum SERVER_RES res) {
  irrd_result_t *p;

  for (p = start->first; p != NULL; p = p->next)
    if (p->svr_res == 0)
      p->svr_res = res;
}
