/*
 * backend.c,v 1.3 1994/01/30 17:10:35 franktor Exp
 */

#include "client.h"
#include <malloc.h>
extern elemDesc desc_HC_Packet[];

void
add_client(int fd)
{
  Client *client = (Client *) malloc(sizeof(Client));

  client->fd = fd;
  client->next = first_client;
  first_client = client;

  client->servers = (ServerConnection *) NULL;
  client->selectOnWrite = False;
  client->loopcount = 0;
}

void
remove_client(Client *client)
{
  Client *tmp, *prev = NULL;
  ServerConnection *conn, *next;

  for (tmp = first_client; tmp; prev = tmp, tmp = tmp->next)
    if (tmp == client)
      break;
  if (prev == NULL)
    first_client = client->next;
  else
    prev->next = client->next;
  for (conn = client->servers; conn; conn = next)
  {
    next = conn->next;
    free(conn);
  }
  free(client);
}

void
remove_server_connection(Client *client, ServerConnection *conn)
{
  ServerConnection *tmp, *prev = NULL;
  for (tmp = client->servers; tmp; prev = tmp, tmp = tmp->next)
    if (tmp == conn)
      break;
  if (prev == NULL)
    client->servers = conn->next;
  else
    prev->next = conn->next;
  free(conn);
}

Client *
fd2client(int fd)
{
  Client *client;

  for (client = first_client; client; client = client->next)
    if (client->fd == fd)
      break;
  return client;
}

Client *
find_client(int ref)
{
  Client *client;
  ServerConnection *conn;

  for (client = first_client; client; client = client->next)
    for(conn = client->servers; conn; conn = conn->next)
      if(conn->client_ref == ref)
        return client;
  return (Client *) NULL;
}

Client *
find_client_from_SR_ref(int ref)
{
  Client *client;
  ServerConnection *conn;

  for (client = first_client; client; client = client->next)
    for(conn = client->servers; conn; conn = conn->next)
      if(conn->server_ref == ref)
        return client;
  return (Client *) NULL;
}

ServerConnection *
find_connection_from_SR_ref(Client *client, int ref)
{
  ServerConnection *conn;
  for (conn = client->servers; conn; conn = conn->next)
    if (conn->server_ref == ref)
      return conn;
  return (ServerConnection *) NULL;
}

ServerConnection *
find_connection(Client *client, int ref)
{
  ServerConnection *conn;
  for (conn = client->servers; conn; conn = conn->next)
    if (conn->client_ref == ref)
      return conn;
  return (ServerConnection *) NULL;
}

void free_packet(HC_Packet *pk) {
  free_struct(pk, desc_HC_Packet);
}

void
abortClient(Client *client)
{
  ServerConnection *tmp;

  LOG(facHigh, llevTrace, "Entering abortClient(%d)", client->fd);

  for (tmp = client->servers; tmp; tmp = tmp->next)
    abortServerConnection(client, tmp);
  closeConnection(client->fd);
  remove_client(client);
}

/*
 * void sendErrorResponse (Client *client, ServerConnection *conn,
 *
 * Sends an hcErrorResponse to the client.
 */

void sendErrorResponse (Client *client, ServerConnection *conn,
                        const char *message, Boolean abort)
{
  HC_Packet             *resp = (HC_Packet *) malloc (sizeof(HC_Packet));
  resp->type            = hcErrorMsg;
  resp->ref             = conn->client_ref;
  resp->u.error_msg     = (HC_ErrorMsg *) malloc (sizeof(HC_ErrorMsg));
  resp->u.error_msg->message    = (char *) safe_strdup ( message );
  resp->u.error_msg->abort      = abort;

  send_struct(client->fd, (void *) resp, &client->selectOnWrite);
}

void
abortServerConnection(Client *client, ServerConnection *conn)
{
  LOG(facHigh, llevTrace, "Entering abortServerConnection(%d,%d)",
      client->fd, conn->client_ref);
  SR_AbortAssociation(conn->server_ref);
  switch(conn->last_packet)
  {
  case hcOpenRequest:
  case hcSearchRequest:
  case hcPresentRequest:
  case hcDeleteResultSetRequest:
  case hcCloseRequest:
    sendErrorResponse (client, conn, (char *)NULL, True);
    LOG(facHigh, llevTrace, "Sent hcErrorMsg(abort) to client.");
    remove_server_connection(client, conn);
    break;
  default:
    conn->aborted = True;
    return;
  }
}

/*
 * abort_connection (Client *client, ServerConnection *conn)
 *
 * Assumes connection to server has already been done (in
 * the abortServerConnection() function), and sends an
 * abort message to the client, to tell it that something went wrong.
 * This function is only called when handling a packet from the
 * client, never when handling a packet from the SR server, so
 * one can safely assume that the client is already waiting for
 * a packet.
 */

void
abort_connection (Client *client, ServerConnection *conn)
{
  HC_Packet *pk;

  LOG(facHigh, llevTrace, "Aborted server connection.");
  sendErrorResponse(client, conn, "Connection aborted by SR-server.", False);

  remove_server_connection(client, conn);
}
