Created SILC Client Libary by moving stuff from silc/ directory.
[silc.git] / apps / silc / client.c
diff --git a/apps/silc/client.c b/apps/silc/client.c
deleted file mode 100644 (file)
index b3a6d39..0000000
+++ /dev/null
@@ -1,1993 +0,0 @@
-/*
-
-  client.c
-
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
-
-  Copyright (C) 1997 - 2000 Pekka Riikonen
-
-  This program 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 2 of the License, or
-  (at your option) any later version.
-  
-  This program 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.
-
-*/
-/*
- * $Id$
- * $Log$
- * Revision 1.13  2000/07/20 10:17:25  priikone
- *     Added dynamic protocol registering/unregistering support.  The
- *     patch was provided by cras.
- *
- * Revision 1.12  2000/07/19 07:07:34  priikone
- *     Save packet on private message's command context.
- *
- * Revision 1.11  2000/07/18 12:20:39  priikone
- *     Added ^U functionality, clears input line (patch form cras).
- *
- * Revision 1.10  2000/07/18 06:53:15  priikone
- *     Allow partial command strings in comparison.
- *
- * Revision 1.9  2000/07/14 06:13:19  priikone
- *     Moved all the generic packet sending, encryption, reception,
- *     decryption and processing functions to library as they were
- *     duplicated code with the server. Now client uses the generic
- *     routines which is a lot cleaner.
- *
- * Revision 1.8  2000/07/12 05:56:32  priikone
- *     Major rewrite of ID Cache system. Support added for the new
- *     ID cache system.
- *
- * Revision 1.7  2000/07/10 05:40:33  priikone
- *     Minor bug fixes.
- *
- * Revision 1.6  2000/07/07 06:54:16  priikone
- *     Print channel name when receiving channel message to non-current
- *     channel.
- *
- * Revision 1.5  2000/07/06 07:14:36  priikone
- *     Fixes to NAMES command handling.
- *     Fixes when leaving from channel.
- *
- * Revision 1.4  2000/07/05 06:12:05  priikone
- *     Global cosmetic changes.
- *
- * Revision 1.3  2000/07/04 08:29:12  priikone
- *     Added support for PING command. The ping times are calculated
- *     and showed to the user.
- *
- * Revision 1.2  2000/07/03 05:49:48  priikone
- *     Implemented LEAVE command.  Minor bug fixes.
- *
- * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
- *     Imported from internal CVS/Added Log headers.
- *
- *
- */
-
-#include "clientincludes.h"
-
-/* Static function prototypes */
-static int silc_client_bad_keys(unsigned char key);
-static void silc_client_clear_input(SilcClient client);
-static void silc_client_process_message(SilcClient client);
-static char *silc_client_parse_command(unsigned char *buffer);
-
-/* Static task callback prototypes */
-SILC_TASK_CALLBACK(silc_client_update_clock);
-SILC_TASK_CALLBACK(silc_client_run_commands);
-SILC_TASK_CALLBACK(silc_client_process_key_press);
-SILC_TASK_CALLBACK(silc_client_connect_to_server_start);
-SILC_TASK_CALLBACK(silc_client_connect_to_server_second);
-SILC_TASK_CALLBACK(silc_client_connect_to_server_final);
-SILC_TASK_CALLBACK(silc_client_packet_process);
-SILC_TASK_CALLBACK(silc_client_packet_parse_real);
-
-SilcClientWindow silc_client_create_main_window(SilcClient client);
-SilcClientWindow silc_client_add_window(SilcClient client,
-                                       int is_current);
-void silc_client_packet_parse(SilcPacketParserContext *parser_context);
-void silc_client_packet_parse_type(SilcClient client, 
-                                  SilcSocketConnection sock,
-                                  SilcPacketContext *packet);
-void silc_client_private_message_process(SilcClient client,
-                                        SilcSocketConnection sock,
-                                        SilcPacketContext *packet);
-
-/* Definitions from version.h */
-extern char *silc_version;
-extern char *silc_name;
-extern char *silc_fullname;
-
-/* Allocates new client object. This has to be done before client may
-   work. After calling this one must call silc_client_init to initialize
-   the client. */
-
-int silc_client_alloc(SilcClient *new_client)
-{
-
-  *new_client = silc_calloc(1, sizeof(**new_client));
-  (*new_client)->input_buffer = NULL;
-  (*new_client)->screen = NULL;
-  (*new_client)->windows = NULL;
-  (*new_client)->windows_count = 0;
-  (*new_client)->current_win = NULL;
-
-  return TRUE;
-}
-
-/* Free's client object */
-
-void silc_client_free(SilcClient client)
-{
-  if (client) {
-    silc_free(client);
-  }
-}
-
-/* Initializes the client. This makes all the necessary steps to make
-   the client ready to be run. One must call silc_client_run to run the
-   client. */
-
-int silc_client_init(SilcClient client)
-{
-
-  SILC_LOG_DEBUG(("Initializing client"));
-  assert(client);
-
-  client->username = silc_get_username();
-  client->realname = silc_get_real_name();
-
-  /* Register all configured ciphers, PKCS and hash functions. */
-  client->config->client = (void *)client;
-  silc_client_config_register_ciphers(client->config);
-  silc_client_config_register_pkcs(client->config);
-  silc_client_config_register_hashfuncs(client->config);
-
-  /* Initialize hash functions for client to use */
-  silc_hash_alloc("md5", &client->md5hash);
-  silc_hash_alloc("sha1", &client->sha1hash);
-
-  /* Initialize none cipher */
-  silc_cipher_alloc("none", &client->none_cipher);
-
-  /* Initialize random number generator */
-  client->rng = silc_rng_alloc();
-  silc_rng_init(client->rng);
-  silc_math_primegen_init(); /* XXX */
-
-  /* Load public and private key */
-  if (silc_client_load_keys(client) == FALSE)
-    goto err0;
-
-  /* Register the task queues. In SILC we have by default three task queues. 
-     One task queue for non-timeout tasks which perform different kind of 
-     I/O on file descriptors, timeout task queue for timeout tasks, and,
-     generic non-timeout task queue whose tasks apply to all connections. */
-  silc_task_queue_alloc(&client->io_queue, TRUE);
-  if (!client->io_queue) {
-    goto err0;
-  }
-  silc_task_queue_alloc(&client->timeout_queue, TRUE);
-  if (!client->timeout_queue) {
-    goto err1;
-  }
-  silc_task_queue_alloc(&client->generic_queue, TRUE);
-  if (!client->generic_queue) {
-    goto err1;
-  }
-
-  /* Register protocols */
-  silc_client_protocols_register();
-
-  /* Initialize the scheduler */
-  silc_schedule_init(client->io_queue, client->timeout_queue, 
-                    client->generic_queue, 5000);
-
-  /* Register the main task that is used in client. This received
-     the key pressings. */
-  if (silc_task_register(client->io_queue, fileno(stdin), 
-                        silc_client_process_key_press,
-                        (void *)client, 0, 0, 
-                        SILC_TASK_FD,
-                        SILC_TASK_PRI_NORMAL) == NULL) {
-    goto err2;
-  }
-
-  /* Register timeout task that updates clock every minute. */
-  if (silc_task_register(client->timeout_queue, 0,
-                        silc_client_update_clock,
-                        (void *)client, 
-                        silc_client_time_til_next_min(), 0,
-                        SILC_TASK_TIMEOUT,
-                        SILC_TASK_PRI_LOW) == NULL) {
-    goto err2;
-  }
-
-  if (client->config->commands) {
-    /* Run user configured commands with timeout */
-    if (silc_task_register(client->timeout_queue, 0,
-                          silc_client_run_commands,
-                          (void *)client, 0, 1,
-                          SILC_TASK_TIMEOUT,
-                          SILC_TASK_PRI_LOW) == NULL) {
-      goto err2;
-    }
-  }
-
-  /* Allocate the input buffer used to save typed characters */
-  client->input_buffer = silc_buffer_alloc(SILC_SCREEN_INPUT_WIN_SIZE);
-  silc_buffer_pull_tail(client->input_buffer, 
-                       SILC_BUFFER_END(client->input_buffer));
-
-  /* Initialize the screen */
-  client->screen = silc_screen_init();
-  silc_client_create_main_window(client);
-  client->screen->input_buffer = client->input_buffer->data;
-  silc_screen_print_coordinates(client->screen, 0);
-
-  return TRUE;
-
- err0:
-  silc_task_queue_free(client->timeout_queue);
- err1:
-  silc_task_queue_free(client->io_queue);
- err2:
-  return FALSE;
-}
-
-/* Stops the client. This is called to stop the client and thus to stop
-   the program. */
-
-void silc_client_stop(SilcClient client)
-{
-  SILC_LOG_DEBUG(("Stopping client"));
-
-  /* Stop the scheduler, although it might be already stopped. This
-     doesn't hurt anyone. This removes all the tasks and task queues,
-     as well. */
-  silc_schedule_stop();
-  silc_schedule_uninit();
-
-  silc_client_protocols_unregister();
-
-  SILC_LOG_DEBUG(("Client client"));
-}
-
-/* Runs the client. */
-
-void silc_client_run(SilcClient client)
-{
-  SILC_LOG_DEBUG(("Running client"));
-
-  /* Start the scheduler, the heart of the SILC client. When this returns
-     the program will be terminated. */
-  silc_schedule();
-}
-
-/* Creates the main window used in SILC client. This is called always
-   at the initialization of the client. If user wants to create more
-   than one windows a new windows are always created by calling 
-   silc_client_add_window. */
-
-SilcClientWindow silc_client_create_main_window(SilcClient client)
-{
-  SilcClientWindow win;
-  void *screen;
-
-  SILC_LOG_DEBUG(("Creating main window"));
-
-  assert(client->screen != NULL);
-
-  client->screen->u_stat_line.program_name = silc_name;
-  client->screen->u_stat_line.program_version = silc_version;
-
-  /* Create windows */
-  win = silc_calloc(1, sizeof(*win));
-  win->nickname = silc_get_username();
-  win->local_id = NULL;
-  win->local_id_data = NULL;
-  win->local_id_data_len = 0;
-  win->remote_host = NULL;
-  win->remote_port = -1;
-  win->sock = NULL;
-
-  /* Initialize ID caches */
-  win->client_cache = silc_idcache_alloc(0);
-  win->channel_cache = silc_idcache_alloc(0);
-  win->server_cache = silc_idcache_alloc(0);
-
-  /* Create the actual screen */
-  screen = (void *)silc_screen_create_output_window(client->screen);
-  silc_screen_create_input_window(client->screen);
-  silc_screen_init_upper_status_line(client->screen);
-  silc_screen_init_output_status_line(client->screen);
-  win->screen = screen;
-
-  client->screen->bottom_line->nickname = win->nickname;
-  silc_screen_print_bottom_line(client->screen, 0);
-
-  /* Add the window to windows table */
-  client->windows = silc_calloc(1, sizeof(*client->windows));
-  client->windows[client->windows_count] = win;
-  client->windows_count = 1;
-
-  /* Automatically becomes the current active window */
-  client->current_win = win;
-
-  return win;
-}
-
-/* Allocates and adds new window to the client. This allocates new
-   physical window and internal window for connection specific data. 
-   All the connection specific data is always saved into a window
-   since connection is always associated to a active window. */
-
-SilcClientWindow silc_client_add_window(SilcClient client,
-                                       int is_current)
-{
-  SilcClientWindow win;
-
-  assert(client->screen != NULL);
-
-  win = silc_calloc(1, sizeof(*win));
-
-  /* Add the pointers */
-  win->screen = silc_screen_add_output_window(client->screen);
-  win->sock = NULL;
-
-  /* Initialize ID caches */
-  win->client_cache = silc_idcache_alloc(0);
-  win->channel_cache = silc_idcache_alloc(0);
-  win->server_cache = silc_idcache_alloc(0);
-
-  /* Add the window to windows table */
-  client->windows = silc_realloc(client->windows, sizeof(*client->windows)
-                                * (client->windows_count + 1));
-  client->windows[client->windows_count] = win;
-  client->windows_count++;
-
-  if (is_current == TRUE)
-    client->current_win = win;
-
-  return win;
-}
-
-/* The main task on SILC client. This processes the key pressings user
-   has made. */
-
-SILC_TASK_CALLBACK(silc_client_process_key_press)
-{
-  SilcClient client = (SilcClient)context;
-  int c;
-
-  /* There is data pending in stdin, this gets it directly */
-  c = wgetch(client->screen->input_win);
-  if (silc_client_bad_keys(c))
-    return;
-
-  SILC_LOG_DEBUG(("Pressed key: %d", c));
-
-  switch(c) {
-    /* 
-     * Special character handling
-     */
-  case KEY_UP: 
-  case KEY_DOWN:
-    break;
-  case KEY_RIGHT:
-    /* Right arrow */
-    SILC_LOG_DEBUG(("RIGHT"));
-    silc_screen_input_cursor_right(client->screen);
-    break;
-  case KEY_LEFT:
-    /* Left arrow */
-    SILC_LOG_DEBUG(("LEFT"));
-    silc_screen_input_cursor_left(client->screen);
-    break;
-  case KEY_BACKSPACE:
-  case KEY_DC:
-  case '\177':
-  case '\b':
-    /* Backspace */
-    silc_screen_input_backspace(client->screen);
-    break;
-  case '\011':
-    /* Tabulator */
-    break;
-  case KEY_IC:
-    /* Insert switch. Turns on/off insert on input window */
-    silc_screen_input_insert(client->screen);
-    break;
-  case CTRL('j'):
-  case '\r':
-    /* Enter, Return. User pressed enter we are ready to
-       process the message. */
-    silc_client_process_message(client);
-    break;
-  case CTRL('l'):
-    /* Refresh screen, Ctrl^l */
-    silc_screen_refresh_all(client->screen);
-    break;
-  case CTRL('a'):
-  case KEY_HOME:
-  case KEY_BEG:
-    /* Beginning, Home */
-    silc_screen_input_cursor_home(client->screen);
-    break;
-  case CTRL('e'):
-  case KEY_END:
-    /* End */
-    silc_screen_input_cursor_end(client->screen);
-    break;
-  case KEY_LL:
-    /* End */
-    break;
-  case CTRL('g'):
-    /* Bell, Ctrl^g */
-    beep();
-    break;
-  case KEY_DL:
-  case CTRL('u'):
-    /* Delete line */
-    silc_client_clear_input(client);
-    break;
-  default:
-    /* 
-     * Other characters 
-     */
-    if (c < 32) {
-      /* Control codes are printed as reversed */
-      c = (c & 127) | 64;
-      wattron(client->screen->input_win, A_REVERSE);
-      silc_screen_input_print(client->screen, c);
-      wattroff(client->screen->input_win, A_REVERSE);
-    } else  {
-      /* Normal character */
-      silc_screen_input_print(client->screen, c);
-    }
-  }
-
-  silc_screen_print_coordinates(client->screen, 0);
-  silc_screen_refresh_win(client->screen->input_win);
-}
-
-static int silc_client_bad_keys(unsigned char key)
-{
-  /* these are explained in curses.h */
-  switch(key) {
-  case KEY_SF:
-  case KEY_SR:
-  case KEY_NPAGE:
-  case KEY_PPAGE:
-  case KEY_PRINT:
-  case KEY_A1:
-  case KEY_A3:
-  case KEY_B2:
-  case KEY_C1:
-  case KEY_C3:
-  case KEY_UNDO:
-  case KEY_EXIT:
-  case '\v':           /* VT */
-  case '\E':           /* we ignore ESC */
-    return TRUE;
-  default: 
-    return FALSE; 
-  }
-}
-
-/* Clears input buffer */
-
-static void silc_client_clear_input(SilcClient client)
-{
-  silc_buffer_clear(client->input_buffer);
-  silc_buffer_pull_tail(client->input_buffer,
-                       SILC_BUFFER_END(client->input_buffer));
-  silc_screen_input_reset(client->screen);
-}
-
-/* Processes messages user has typed on the screen. This either sends
-   a packet out to network or if command were written executes it. */
-
-static void silc_client_process_message(SilcClient client)
-{
-  unsigned char *data;
-  unsigned int len;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  data = client->input_buffer->data;
-  len = strlen(data);
-
-  if (data[0] == '/' && data[1] != ' ') {
-    /* Command */
-    unsigned int argc = 0;
-    unsigned char **argv, *tmpcmd;
-    unsigned int *argv_lens, *argv_types;
-    SilcClientCommand *cmd;
-    SilcClientCommandContext ctx;
-
-    /* Get the command */
-    tmpcmd = silc_client_parse_command(data);
-
-    /* Find command match */
-    for (cmd = silc_command_list; cmd->name; cmd++) {
-      if (!strncmp(cmd->name, tmpcmd, strlen(tmpcmd)))
-       break;
-    }
-
-    if (cmd->name == NULL) {
-      silc_say(client, "Invalid command: %s", tmpcmd);
-      silc_free(tmpcmd);
-      goto out;
-    }
-
-    /* Now parse all arguments */
-    silc_client_parse_command_line(data, &argv, &argv_lens, 
-                                  &argv_types, &argc, cmd->max_args);
-    silc_free(tmpcmd);
-
-    SILC_LOG_DEBUG(("Exeuting command: %s", cmd->name));
-
-    /* Allocate command context. This and its internals must be free'd 
-       by the command routine receiving it. */
-    ctx = silc_calloc(1, sizeof(*ctx));
-    ctx->client = client;
-    ctx->sock = client->current_win->sock;
-    ctx->argc = argc;
-    ctx->argv = argv;
-    ctx->argv_lens = argv_lens;
-    ctx->argv_types = argv_types;
-
-    /* Execute command */
-    (*cmd->cb)(ctx);
-
-  } else {
-    /* Normal message to a channel */
-    if (len && client->current_win->current_channel &&
-       client->current_win->current_channel->on_channel == TRUE) {
-      silc_print(client, "> %s", data);
-      silc_client_packet_send_to_channel(client, 
-                                        client->current_win->sock,
-                                        client->current_win->current_channel,
-                                        data, strlen(data), TRUE);
-    }
-  }
-
- out:
-  /* Clear the input buffer */
-  silc_client_clear_input(client);
-}
-
-/* Returns the command fetched from user typed command line */
-
-static char *silc_client_parse_command(unsigned char *buffer)
-{
-  char *ret;
-  const char *cp = buffer;
-  int len;
-
-  len = strcspn(cp, " ");
-  ret = silc_to_upper((char *)++cp);
-  ret[len - 1] = 0;
-
-  return ret;
-}
-
-/* Parses user typed command line. At most `max_args' is taken. Rest
-   of the line will be allocated as the last argument if there are more
-   than `max_args' arguments in the line. Note that the command name
-   is counted as one argument and is saved. */
-
-void silc_client_parse_command_line(unsigned char *buffer, 
-                                   unsigned char ***parsed,
-                                   unsigned int **parsed_lens,
-                                   unsigned int **parsed_types,
-                                   unsigned int *parsed_num,
-                                   unsigned int max_args)
-{
-  int i, len = 0;
-  int argc = 0;
-  const char *cp = buffer;
-
-  /* Take the '/' away */
-  cp++;
-
-  *parsed = silc_calloc(1, sizeof(**parsed));
-  *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
-
-  /* Get the command first */
-  len = strcspn(cp, " ");
-  (*parsed)[0] = silc_to_upper((char *)cp);
-  (*parsed_lens)[0] = len;
-  cp += len + 1;
-  argc++;
-
-  /* Parse arguments */
-  if (strchr(cp, ' ') || strlen(cp) != 0) {
-    for (i = 1; i < max_args; i++) {
-
-      if (i != max_args - 1)
-       len = strcspn(cp, " ");
-      else
-       len = strlen(cp);
-      
-      *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
-      *parsed_lens = silc_realloc(*parsed_lens, 
-                                 sizeof(**parsed_lens) * (argc + 1));
-      (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
-      memcpy((*parsed)[argc], cp, len);
-      (*parsed_lens)[argc] = len;
-      argc++;
-
-      cp += len;
-      if (strlen(cp) == 0)
-       break;
-      else
-       cp++;
-    }
-  }
-
-  /* Save argument types. Protocol defines all argument types but
-     this implementation makes sure that they are always in correct
-     order hence this simple code. */
-  *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
-  for (i = 0; i < argc; i++)
-    (*parsed_types)[i] = i;
-
-  *parsed_num = argc;
-}
-
-/* Updates clock on the screen every minute. */
-
-SILC_TASK_CALLBACK(silc_client_update_clock)
-{
-  SilcClient client = (SilcClient)context;
-
-  /* Update the clock on the screen */
-  silc_screen_print_clock(client->screen);
-
-  /* Re-register this same task */
-  silc_task_register(qptr, 0, silc_client_update_clock, context, 
-                    silc_client_time_til_next_min(), 0,
-                    SILC_TASK_TIMEOUT,
-                    SILC_TASK_PRI_LOW);
-
-  silc_screen_refresh_win(client->screen->input_win);
-}
-
-/* Runs commands user configured in configuration file. This is
-   called when initializing client. */
-
-SILC_TASK_CALLBACK(silc_client_run_commands)
-{
-  SilcClient client = (SilcClient)context;
-  SilcClientConfigSectionCommand *cs;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  cs = client->config->commands;
-  while(cs) {
-    unsigned int argc = 0;
-    unsigned char **argv, *tmpcmd;
-    unsigned int *argv_lens, *argv_types;
-    SilcClientCommand *cmd;
-    SilcClientCommandContext ctx;
-
-    /* Get the command */
-    tmpcmd = silc_client_parse_command(cs->command);
-
-    for (cmd = silc_command_list; cmd->name; cmd++) {
-      if (!strcmp(cmd->name, tmpcmd))
-       break;
-    }
-    
-    if (cmd->name == NULL) {
-      silc_say(client, "Invalid command: %s", tmpcmd);
-      silc_free(tmpcmd);
-      continue;
-    }
-    
-    /* Now parse all arguments */
-    silc_client_parse_command_line(cs->command, &argv, &argv_lens, 
-                                  &argv_types, &argc, cmd->max_args);
-    silc_free(tmpcmd);
-
-    SILC_LOG_DEBUG(("Exeuting command: %s", cmd->name));
-
-    /* Allocate command context. This and its internals must be free'd 
-       by the command routine receiving it. */
-    ctx = silc_calloc(1, sizeof(*ctx));
-    ctx->client = client;
-    ctx->sock = client->current_win->sock;
-    ctx->argc = argc;
-    ctx->argv = argv;
-    ctx->argv_lens = argv_lens;
-    ctx->argv_types = argv_types;
-
-    /* Execute command */
-    (*cmd->cb)(ctx);
-
-    cs = cs->next;
-  }
-}
-
-/* Internal context for connection process. This is needed as we
-   doing asynchronous connecting. */
-typedef struct {
-  SilcClient client;
-  SilcTask task;
-  int sock;
-  char *host;
-  int port;
-  int tries;
-} SilcClientInternalConnectContext;
-
-static int 
-silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
-{
-  int sock;
-
-  /* XXX In the future we should give up this non-blocking connect all
-     together and use threads instead. */
-  /* Create connection to server asynchronously */
-  sock = silc_net_create_connection_async(ctx->port, ctx->host);
-  if (sock < 0)
-    return -1;
-
-  /* Register task that will receive the async connect and will
-     read the result. */
-  ctx->task = silc_task_register(ctx->client->io_queue, sock, 
-                                silc_client_connect_to_server_start,
-                                (void *)ctx, 0, 0, 
-                                SILC_TASK_FD,
-                                SILC_TASK_PRI_NORMAL);
-  silc_task_reset_iotype(ctx->task, SILC_TASK_WRITE);
-  silc_schedule_set_listen_fd(sock, ctx->task->iomask);
-
-  ctx->sock = sock;
-
-  return sock;
-}
-
-/* Connects to remote server */
-
-int silc_client_connect_to_server(SilcClient client, int port,
-                                 char *host)
-{
-  SilcClientInternalConnectContext *ctx;
-
-  SILC_LOG_DEBUG(("Connecting to port %d of server %s",
-                 port, host));
-
-  silc_say(client, "Connecting to port %d of server %s", port, host);
-
-  client->current_win->remote_host = strdup(host);
-  client->current_win->remote_port = port;
-
-  /* Allocate internal context for connection process. This is
-     needed as we are doing async connecting. */
-  ctx = silc_calloc(1, sizeof(*ctx));
-  ctx->client = client;
-  ctx->host = strdup(host);
-  ctx->port = port;
-  ctx->tries = 0;
-
-  /* Do the actual connecting process */
-  return silc_client_connect_to_server_internal(ctx);
-}
-
-/* Start of the connection to the remote server. This is called after
-   succesful TCP/IP connection has been established to the remote host. */
-
-SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
-{
-  SilcClientInternalConnectContext *ctx =
-    (SilcClientInternalConnectContext *)context;
-  SilcClient client = ctx->client;
-  SilcProtocol protocol;
-  SilcClientKEInternalContext *proto_ctx;
-  int opt, opt_len = sizeof(opt);
-
-  SILC_LOG_DEBUG(("Start"));
-
-  /* Check the socket status as it might be in error */
-  getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
-  if (opt != 0) {
-    if (ctx->tries < 2) {
-      /* Connection failed but lets try again */
-      silc_say(ctx->client, "Could not connect to server %s: %s",
-              ctx->host, strerror(opt));
-      silc_say(client, "Connecting to port %d of server %s resumed", 
-              ctx->port, ctx->host);
-
-      /* Unregister old connection try */
-      silc_schedule_unset_listen_fd(fd);
-      silc_net_close_connection(fd);
-      silc_task_unregister(client->io_queue, ctx->task);
-
-      /* Try again */
-      silc_client_connect_to_server_internal(ctx);
-      ctx->tries++;
-    } else {
-      /* Connection failed and we won't try anymore */
-      silc_say(ctx->client, "Could not connect to server %s: %s",
-              ctx->host, strerror(opt));
-      silc_schedule_unset_listen_fd(fd);
-      silc_net_close_connection(fd);
-      silc_task_unregister(client->io_queue, ctx->task);
-      silc_free(ctx);
-    }
-    return;
-  }
-
-  silc_schedule_unset_listen_fd(fd);
-  silc_task_unregister(client->io_queue, ctx->task);
-  silc_free(ctx);
-
-  /* Allocate new socket connection object */
-  silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, 
-                   (void *)client->current_win, 
-                   &client->current_win->sock);
-  if (client->current_win->sock == NULL) {
-    silc_say(client, "Error: Could not allocate connection socket");
-    silc_net_close_connection(fd);
-    return;
-  }
-  client->current_win->sock->hostname = client->current_win->remote_host;
-  client->current_win->sock->port = client->current_win->remote_port;
-
-  /* Allocate internal Key Exchange context. This is sent to the
-     protocol as context. */
-  proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
-  proto_ctx->client = (void *)client;
-  proto_ctx->sock = client->current_win->sock;
-  proto_ctx->rng = client->rng;
-  proto_ctx->responder = FALSE;
-
-  /* Perform key exchange protocol. silc_client_connect_to_server_final
-     will be called after the protocol is finished. */
-  silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE, 
-                     &protocol, (void *)proto_ctx,
-                     silc_client_connect_to_server_second);
-  if (!protocol) {
-    silc_say(client, "Error: Could not start authentication protocol");
-    return;
-  }
-  client->current_win->sock->protocol = protocol;
-
-  /* Register the connection for network input and output. This sets
-     that scheduler will listen for incoming packets for this connection 
-     and sets that outgoing packets may be sent to this connection as well.
-     However, this doesn't set the scheduler for outgoing traffic, it will 
-     be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
-     later when outgoing data is available. */
-  context = (void *)client;
-  SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd);
-
-  /* Execute the protocol */
-  protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
-}
-
-/* Second part of the connecting to the server. This executed 
-   authentication protocol. */
-
-SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
-{
-  SilcProtocol protocol = (SilcProtocol)context;
-  SilcClientKEInternalContext *ctx = 
-    (SilcClientKEInternalContext *)protocol->context;
-  SilcClient client = (SilcClient)ctx->client;
-  SilcSocketConnection sock = NULL;
-  SilcClientConnAuthInternalContext *proto_ctx;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
-    /* Error occured during protocol */
-    SILC_LOG_DEBUG(("Error during KE protocol"));
-    silc_protocol_free(protocol);
-    if (ctx->ske)
-      silc_ske_free(ctx->ske);
-    if (ctx->dest_id)
-      silc_free(ctx->dest_id);
-    ctx->sock->protocol = NULL;
-    silc_free(ctx);
-    return;
-  }
-
-  /* Allocate internal context for the authentication protocol. This
-     is sent as context for the protocol. */
-  proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
-  proto_ctx->client = (void *)client;
-  proto_ctx->sock = sock = ctx->sock;
-  proto_ctx->ske = ctx->ske;   /* Save SKE object from previous protocol */
-  proto_ctx->dest_id_type = ctx->dest_id_type;
-  proto_ctx->dest_id = ctx->dest_id;
-
-  /* Resolve the authentication method to be used in this connection */
-  proto_ctx->auth_meth = SILC_PROTOCOL_CONN_AUTH_NONE;
-  if (client->config->conns) {
-    SilcClientConfigSectionConnection *conn = NULL;
-
-    /* Check if we find a match from user configured connections */
-    conn = silc_client_config_find_connection(client->config,
-                                             sock->hostname,
-                                             sock->port);
-    if (conn) {
-      /* Match found. Use the configured authentication method */
-      proto_ctx->auth_meth = conn->auth_meth;
-      if (conn->auth_data) {
-       proto_ctx->auth_data = strdup(conn->auth_data);
-       proto_ctx->auth_data_len = strlen(conn->auth_data);
-      }
-    } else {
-      /* No match found. Resolve by sending AUTH_REQUEST to server */
-      proto_ctx->auth_meth = SILC_PROTOCOL_CONN_AUTH_NONE;
-    }
-  } else {
-    /* XXX Resolve by sending AUTH_REQUEST to server */
-    proto_ctx->auth_meth = SILC_PROTOCOL_CONN_AUTH_NONE;
-  }
-
-  /* Free old protocol as it is finished now */
-  silc_protocol_free(protocol);
-  if (ctx->packet)
-    silc_buffer_free(ctx->packet);
-  silc_free(ctx);
-  /* silc_free(ctx->keymat....); */
-  sock->protocol = NULL;
-
-  /* Allocate the authentication protocol. This is allocated here
-     but we won't start it yet. We will be receiving party of this
-     protocol thus we will wait that connecting party will make
-     their first move. */
-  silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH, 
-                     &sock->protocol, (void *)proto_ctx, 
-                     silc_client_connect_to_server_final);
-
-  /* Execute the protocol */
-  sock->protocol->execute(client->timeout_queue, 0, sock->protocol, fd, 0, 0);
-}
-
-/* Finalizes the connection to the remote SILC server. This is called
-   after authentication protocol has been completed. This send our
-   user information to the server to receive our client ID from
-   server. */
-
-SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
-{
-  SilcProtocol protocol = (SilcProtocol)context;
-  SilcClientConnAuthInternalContext *ctx = 
-    (SilcClientConnAuthInternalContext *)protocol->context;
-  SilcClient client = (SilcClient)ctx->client;
-  SilcClientWindow win = (SilcClientWindow)ctx->sock->user_data;
-  SilcBuffer packet;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
-    /* Error occured during protocol */
-    SILC_LOG_DEBUG(("Error during authentication protocol"));
-    silc_protocol_free(protocol);
-    if (ctx->auth_data)
-      silc_free(ctx->auth_data);
-    if (ctx->ske)
-      silc_ske_free(ctx->ske);
-    if (ctx->dest_id)
-      silc_free(ctx->dest_id);
-    silc_free(ctx);
-    win->sock->protocol = NULL;
-    return;
-  }
-
-  /* Send NEW_CLIENT packet to the server. We will become registered
-     to the SILC network after sending this packet and we will receive
-     client ID from the server. */
-  packet = silc_buffer_alloc(2 + 2 + strlen(client->username) + 
-                            strlen(client->realname));
-  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
-  silc_buffer_format(packet,
-                    SILC_STR_UI_SHORT(strlen(client->username)),
-                    SILC_STR_UI_XNSTRING(client->username,
-                                         strlen(client->username)),
-                    SILC_STR_UI_SHORT(strlen(client->realname)),
-                    SILC_STR_UI_XNSTRING(client->realname,
-                                         strlen(client->realname)),
-                    SILC_STR_END);
-
-  /* Send the packet */
-  silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
-                         NULL, 0, NULL, NULL, 
-                         packet->data, packet->len, TRUE);
-  silc_buffer_free(packet);
-
-  /* Save remote ID. */
-  win->remote_id = ctx->dest_id;
-  win->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_CHANNEL);
-  win->remote_id_data_len = SILC_ID_CHANNEL_LEN;
-
-  silc_say(client, "Connected to port %d of host %s",
-          win->remote_port, win->remote_host);
-
-  client->screen->bottom_line->connection = win->remote_host;
-  silc_screen_print_bottom_line(client->screen, 0);
-
-  silc_protocol_free(protocol);
-  if (ctx->auth_data)
-    silc_free(ctx->auth_data);
-  if (ctx->ske)
-    silc_ske_free(ctx->ske);
-  if (ctx->dest_id)
-    silc_free(ctx->dest_id);
-  silc_free(ctx);
-  win->sock->protocol = NULL;
-}
-
-/* Internal routine that sends packet or marks packet to be sent. This
-   is used directly only in special cases. Normal cases should use
-   silc_server_packet_send. Returns < 0 on error. */
-
-static int silc_client_packet_send_real(SilcClient client,
-                                       SilcSocketConnection sock,
-                                       int force_send)
-{
-  int ret;
-
-  /* Send the packet */
-  ret = silc_packet_send(sock, force_send);
-  if (ret != -2)
-    return ret;
-
-  /* Mark that there is some outgoing data available for this connection. 
-     This call sets the connection both for input and output (the input
-     is set always and this call keeps the input setting, actually). 
-     Actual data sending is performed by silc_client_packet_process. */
-  SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(sock->sock);
-
-  /* Mark to socket that data is pending in outgoing buffer. This flag
-     is needed if new data is added to the buffer before the earlier
-     put data is sent to the network. */
-  SILC_SET_OUTBUF_PENDING(sock);
-
-  return 0;
-}
-
-/* Packet processing callback. This is used to send and receive packets
-   from network. This is generic task. */
-
-SILC_TASK_CALLBACK(silc_client_packet_process)
-{
-  SilcClient client = (SilcClient)context;
-  SilcSocketConnection sock = NULL;
-  SilcClientWindow win;
-  int ret;
-
-  SILC_LOG_DEBUG(("Processing packet"));
-
-  SILC_CLIENT_GET_SOCK(client, fd, sock);
-  if (sock == NULL)
-    return;
-
-  win = (SilcClientWindow)sock->user_data;
-
-  /* Packet sending */
-  if (type == SILC_TASK_WRITE) {
-    SILC_LOG_DEBUG(("Writing data to connection"));
-
-    if (sock->outbuf->data - sock->outbuf->head)
-      silc_buffer_push(sock->outbuf, 
-                      sock->outbuf->data - sock->outbuf->head);
-
-    ret = silc_client_packet_send_real(client, sock, TRUE);
-
-    /* If returned -2 could not write to connection now, will do
-       it later. */
-    if (ret == -2)
-      return;
-    
-    /* The packet has been sent and now it is time to set the connection
-       back to only for input. When there is again some outgoing data 
-       available for this connection it will be set for output as well. 
-       This call clears the output setting and sets it only for input. */
-    SILC_CLIENT_SET_CONNECTION_FOR_INPUT(fd);
-    SILC_UNSET_OUTBUF_PENDING(sock);
-
-    silc_buffer_clear(sock->outbuf);
-    return;
-  }
-
-  /* Packet receiving */
-  if (type == SILC_TASK_READ) {
-    SILC_LOG_DEBUG(("Reading data from connection"));
-
-    /* Read data from network */
-    ret = silc_packet_receive(sock);
-    if (ret < 0)
-      return;
-    
-    /* EOF */
-    if (ret == 0) {
-      SILC_LOG_DEBUG(("Read EOF"));
-
-      /* If connection is disconnecting already we will finally
-        close the connection */
-      if (SILC_IS_DISCONNECTING(sock)) {
-       silc_client_close_connection(client, sock);
-       return;
-      }
-      
-      silc_say(client, "Connection closed: premature EOF");
-      SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock));
-
-      silc_client_close_connection(client, sock);
-      return;
-    }
-
-    /* Process the packet. This will call the parser that will then
-       decrypt and parse the packet. */
-    if (!silc_packet_receive_process(sock, win->receive_key, win->hmac,
-                                    silc_client_packet_parse, client)) {
-      silc_buffer_clear(sock->inbuf);
-      return;
-    }
-  }
-}
-
-/* Parses whole packet, received earlier. */
-
-SILC_TASK_CALLBACK(silc_client_packet_parse_real)
-{
-  SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
-  SilcClient client = (SilcClient)parse_ctx->context;
-  SilcPacketContext *packet = parse_ctx->packet;
-  SilcBuffer buffer = packet->buffer;
-  SilcSocketConnection sock = parse_ctx->sock;
-  SilcClientWindow win = (SilcClientWindow)sock->user_data;
-  int ret;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  /* Decrypt the received packet */
-  ret = silc_packet_decrypt(win->receive_key, win->hmac, buffer, packet);
-  if (ret < 0)
-    goto out;
-
-  if (ret == 0) {
-    /* Parse the packet. Packet type is returned. */
-    ret = silc_packet_parse(packet);
-  } else {
-    /* Parse the packet header in special way as this is "special"
-       packet type. */
-    ret = silc_packet_parse_special(packet);
-  }
-
-  if (ret == SILC_PACKET_NONE)
-    goto out;
-
-  /* Parse the incoming packet type */
-  silc_client_packet_parse_type(client, sock, packet);
-
- out:
-  silc_buffer_clear(buffer);
-  silc_free(packet);
-  silc_free(parse_ctx);
-}
-
-/* Parser callback called by silc_packet_receive_process. Thie merely
-   registers timeout that will handle the actual parsing when appropriate. */
-
-void silc_client_packet_parse(SilcPacketParserContext *parser_context)
-{
-  SilcClient client = (SilcClient)parser_context->context;
-  SilcClientWindow win = (SilcClientWindow)parser_context->sock->user_data;
-
-  /* If this packet is for the current active connection we will
-     parse the packet right away to get it quickly on the screen.
-     Otherwise, it will be parsed with a timeout as the data is
-     for inactive window (which might not be visible at all). */
-  if (SILC_CLIENT_IS_CURRENT_WIN(client, win)) {
-    /* Parse it real soon */
-    silc_task_register(client->timeout_queue, parser_context->sock->sock, 
-                      silc_client_packet_parse_real,
-                      (void *)parser_context, 0, 1, 
-                      SILC_TASK_TIMEOUT,
-                      SILC_TASK_PRI_NORMAL);
-  } else {
-    /* Parse the packet with timeout */
-    silc_task_register(client->timeout_queue, parser_context->sock->sock, 
-                      silc_client_packet_parse_real,
-                      (void *)parser_context, 0, 200000, 
-                      SILC_TASK_TIMEOUT,
-                      SILC_TASK_PRI_NORMAL);
-  }
-}
-  
-/* Parses the packet type and calls what ever routines the packet type
-   requires. This is done for all incoming packets. */
-
-void silc_client_packet_parse_type(SilcClient client, 
-                                  SilcSocketConnection sock,
-                                  SilcPacketContext *packet)
-{
-  SilcBuffer buffer = packet->buffer;
-  SilcPacketType type = packet->type;
-
-  SILC_LOG_DEBUG(("Parsing packet type %d", type));
-
-  /* Parse the packet type */
-  switch(type) {
-  case SILC_PACKET_DISCONNECT:
-    silc_client_disconnected_by_server(client, sock, buffer);
-    break;
-  case SILC_PACKET_SUCCESS:
-    /*
-     * Success received for something. For now we can have only
-     * one protocol for connection executing at once hence this
-     * success message is for whatever protocol is executing currently.
-     */
-    if (sock->protocol) {
-      sock->protocol->execute(client->timeout_queue, 0,
-                             sock->protocol, sock->sock, 0, 0);
-    }
-    break;
-  case SILC_PACKET_FAILURE:
-    /*
-     * Failure received for some protocol. Set the protocol state to 
-     * error and call the protocol callback. This fill cause error on
-     * protocol and it will call the final callback.
-     */
-    if (sock->protocol) {
-      sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
-      sock->protocol->execute(client->timeout_queue, 0,
-                             sock->protocol, sock->sock, 0, 0);
-    }
-    break;
-  case SILC_PACKET_REJECT:
-    break;
-
-  case SILC_PACKET_NOTIFY:
-    /*
-     * Received notify message 
-     */
-    silc_client_notify_by_server(client, sock, buffer);
-    break;
-
-  case SILC_PACKET_ERROR:
-    /*
-     * Received error message
-     */
-    silc_client_error_by_server(client, sock, buffer);
-    break;
-
-  case SILC_PACKET_CHANNEL_MESSAGE:
-    /*
-     * Received message to (from, actually) a channel
-     */
-    silc_client_channel_message(client, sock, packet);
-    break;
-  case SILC_PACKET_CHANNEL_KEY:
-    /*
-     * Received key for a channel. By receiving this key the client will be
-     * able to talk to the channel it has just joined. This can also be
-     * a new key for existing channel as keys expire peridiocally.
-     */
-    silc_client_receive_channel_key(client, sock, buffer);
-    break;
-
-  case SILC_PACKET_PRIVATE_MESSAGE:
-    /*
-     * Received private message
-     */
-    {
-      SilcClientCommandReplyContext ctx;
-      ctx = silc_calloc(1, sizeof(*ctx));
-      ctx->client = client;
-      ctx->sock = sock;
-      ctx->packet = packet;
-      silc_client_command_reply_msg((void *)ctx);
-    }
-    break;
-  case SILC_PACKET_PRIVATE_MESSAGE_KEY:
-    /*
-     * Received private message key
-     */
-    break;
-
-  case SILC_PACKET_COMMAND_REPLY:
-    /*
-     * Recived reply for a command
-     */
-    silc_client_command_reply_process(client, sock, packet);
-    break;
-
-  case SILC_PACKET_KEY_EXCHANGE:
-    if (sock->protocol) {
-      SilcClientKEInternalContext *proto_ctx = 
-       (SilcClientKEInternalContext *)sock->protocol->context;
-
-      proto_ctx->packet = buffer;
-      proto_ctx->dest_id_type = packet->src_id_type;
-      proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_type);
-
-      /* Let the protocol handle the packet */
-      sock->protocol->execute(client->timeout_queue, 0,
-                             sock->protocol, sock->sock, 0, 0);
-    } else {
-      SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
-                     "protocol active, packet dropped."));
-
-      /* XXX Trigger KE protocol?? Rekey actually! */
-    }
-    break;
-
-  case SILC_PACKET_KEY_EXCHANGE_1:
-    if (sock->protocol) {
-
-    } else {
-      SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
-                     "protocol active, packet dropped."));
-    }
-    break;
-  case SILC_PACKET_KEY_EXCHANGE_2:
-    if (sock->protocol) {
-      SilcClientKEInternalContext *proto_ctx = 
-       (SilcClientKEInternalContext *)sock->protocol->context;
-
-      if (proto_ctx->packet)
-       silc_buffer_free(proto_ctx->packet);
-
-      proto_ctx->packet = buffer;
-      proto_ctx->dest_id_type = packet->src_id_type;
-      proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_type);
-
-      /* Let the protocol handle the packet */
-      sock->protocol->execute(client->timeout_queue, 0,
-                             sock->protocol, sock->sock, 0, 0);
-    } else {
-      SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
-                     "protocol active, packet dropped."));
-    }
-    break;
-
-  case SILC_PACKET_NEW_ID:
-    {
-      /*
-       * Received new ID from server. This packet is received at
-       * the connection to the server.  New ID is also received when 
-       * user changes nickname but in that case the new ID is received
-       * as command reply and not as this packet type.
-       */
-      unsigned char *id_string;
-      unsigned short id_type;
-      
-      silc_buffer_unformat(buffer,
-                          SILC_STR_UI_SHORT(&id_type),
-                          SILC_STR_UI16_STRING_ALLOC(&id_string),
-                          SILC_STR_END);
-      
-      if ((SilcIdType)id_type != SILC_ID_CLIENT)
-       break;
-
-      silc_client_receive_new_id(client, sock, id_string);
-      silc_free(id_string);
-      break;
-    }
-
-  default:
-    SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
-    break;
-  }
-}
-
-/* Sends packet. This doesn't actually send the packet instead it assembles
-   it and marks it to be sent. However, if force_send is TRUE the packet
-   is sent immediately. if dst_id, cipher and hmac are NULL those parameters
-   will be derived from sock argument. Otherwise the valid arguments sent
-   are used. */
-
-void silc_client_packet_send(SilcClient client, 
-                            SilcSocketConnection sock,
-                            SilcPacketType type, 
-                            void *dst_id,
-                            SilcIdType dst_id_type,
-                            SilcCipher cipher,
-                            SilcHmac hmac,
-                            unsigned char *data, 
-                            unsigned int data_len, 
-                            int force_send)
-{
-  SilcPacketContext packetdata;
-
-  SILC_LOG_DEBUG(("Sending packet, type %d", type));
-
-  /* Get data used in the packet sending, keys and stuff */
-  if ((!cipher || !hmac || !dst_id) && sock->user_data) {
-    if (!cipher && ((SilcClientWindow)sock->user_data)->send_key)
-      cipher = ((SilcClientWindow)sock->user_data)->send_key;
-
-    if (!hmac && ((SilcClientWindow)sock->user_data)->hmac)
-      hmac = ((SilcClientWindow)sock->user_data)->hmac;
-
-    if (!dst_id && ((SilcClientWindow)sock->user_data)->remote_id) {
-      dst_id = ((SilcClientWindow)sock->user_data)->remote_id;
-      dst_id_type = SILC_ID_SERVER;
-    }
-  }
-
-  /* Set the packet context pointers */
-  packetdata.flags = 0;
-  packetdata.type = type;
-  if (((SilcClientWindow)sock->user_data)->local_id_data)
-    packetdata.src_id = ((SilcClientWindow)sock->user_data)->local_id_data;
-  else 
-    packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
-  packetdata.src_id_len = SILC_ID_CLIENT_LEN;
-  packetdata.src_id_type = SILC_ID_CLIENT;
-  if (dst_id) {
-    packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
-    packetdata.dst_id_len = silc_id_get_len(dst_id_type);
-    packetdata.dst_id_type = dst_id_type;
-  } else {
-    packetdata.dst_id = NULL;
-    packetdata.dst_id_len = 0;
-    packetdata.dst_id_type = SILC_ID_NONE;
-  }
-  packetdata.rng = client->rng;
-  packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
-    packetdata.src_id_len + packetdata.dst_id_len;
-  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
-
-  /* Prepare outgoing data buffer for packet sending */
-  silc_packet_send_prepare(sock, 
-                          SILC_PACKET_HEADER_LEN +
-                          packetdata.src_id_len + 
-                          packetdata.dst_id_len,
-                          packetdata.padlen,
-                          data_len);
-
-  SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
-
-  packetdata.buffer = sock->outbuf;
-
-  /* Put the data to the buffer */
-  if (data && data_len)
-    silc_buffer_put(sock->outbuf, data, data_len);
-
-  /* Create the outgoing packet */
-  silc_packet_assemble(&packetdata);
-
-  /* Encrypt the packet */
-  if (cipher)
-    silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
-
-  SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
-                  sock->outbuf->data, sock->outbuf->len);
-
-  /* Now actually send the packet */
-  silc_client_packet_send_real(client, sock, force_send);
-}
-
-/* Sends packet to a channel. Packet to channel is always encrypted
-   differently from "normal" packets. SILC header of the packet is 
-   encrypted with the next receiver's key and the rest of the packet is
-   encrypted with the channel specific key. Padding and HMAC is computed
-   with the next receiver's key. */
-
-void silc_client_packet_send_to_channel(SilcClient client, 
-                                       SilcSocketConnection sock,
-                                       SilcChannelEntry channel,
-                                       unsigned char *data, 
-                                       unsigned int data_len, 
-                                       int force_send)
-{
-  int i;
-  SilcClientWindow win = (SilcClientWindow)sock->user_data;
-  SilcBuffer payload;
-  SilcPacketContext packetdata;
-  SilcCipher cipher;
-  SilcHmac hmac;
-  unsigned char *id_string;
-
-  SILC_LOG_DEBUG(("Sending packet to channel"));
-
-  if (!channel || !channel->key) {
-    silc_say(client, "Cannot talk to channel: key does not exist");
-    return;
-  }
-
-  /* Generate IV */
-  if (!channel->iv)
-    for (i = 0; i < 16; i++)
-      channel->iv[i] = silc_rng_get_byte(client->rng);
-  else
-    silc_hash_make(client->md5hash, channel->iv, 16, channel->iv);
-
-  /* Encode the channel payload */
-  payload = silc_channel_encode_payload(strlen(win->nickname), win->nickname,
-                                       data_len, data, 16, channel->iv, 
-                                       client->rng);
-  if (!payload) {
-    silc_say(client, 
-            "Error: Could not create packet to be sent to the channel");
-    return;
-  }
-
-  /* Get data used in packet header encryption, keys and stuff. Rest
-     of the packet (the payload) is, however, encrypted with the 
-     specified channel key. */
-  cipher = win->send_key;
-  hmac = win->hmac;
-  id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
-
-  /* Set the packet context pointers. The destination ID is always
-     the Channel ID of the channel. Server and router will handle the
-     distribution of the packet. */
-  packetdata.flags = 0;
-  packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
-  packetdata.src_id = win->local_id_data;
-  packetdata.src_id_len = SILC_ID_CLIENT_LEN;
-  packetdata.src_id_type = SILC_ID_CLIENT;
-  packetdata.dst_id = id_string;
-  packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
-  packetdata.dst_id_type = SILC_ID_CHANNEL;
-  packetdata.rng = client->rng;
-  packetdata.truelen = payload->len + SILC_PACKET_HEADER_LEN + 
-    packetdata.src_id_len + packetdata.dst_id_len;
-  packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
-                                         packetdata.src_id_len +
-                                         packetdata.dst_id_len));
-
-  /* Prepare outgoing data buffer for packet sending */
-  silc_packet_send_prepare(sock, 
-                          SILC_PACKET_HEADER_LEN +
-                          packetdata.src_id_len + 
-                          packetdata.dst_id_len,
-                          packetdata.padlen,
-                          payload->len);
-
-  packetdata.buffer = sock->outbuf;
-
-  /* Encrypt payload of the packet. This is encrypted with the channel key. */
-  channel->channel_key->cipher->encrypt(channel->channel_key->context,
-                                       payload->data, payload->data,
-                                       payload->len - 16, /* -IV_LEN */
-                                       channel->iv);
-
-  /* Put the actual encrypted payload data into the buffer. */
-  silc_buffer_put(sock->outbuf, payload->data, payload->len);
-
-  /* Create the outgoing packet */
-  silc_packet_assemble(&packetdata);
-
-  /* Encrypt the header and padding of the packet. This is encrypted 
-     with normal session key shared with our server. */
-  silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN + 
-                     packetdata.src_id_len + packetdata.dst_id_len +
-                     packetdata.padlen);
-
-  SILC_LOG_HEXDUMP(("Packet to channel, len %d", sock->outbuf->len),
-                  sock->outbuf->data, sock->outbuf->len);
-
-  /* Now actually send the packet */
-  silc_client_packet_send_real(client, sock, force_send);
-  silc_buffer_free(payload);
-  silc_free(id_string);
-}
-
-/* Sends private message to remote client. If private message key has
-   not been set with this client then the message will be encrypted using
-   normal session keys. Private messages are special packets in SILC
-   network hence we need this own function for them. This is similiar
-   to silc_client_packet_send_to_channel except that we send private
-   message. */
-
-void silc_client_packet_send_private_message(SilcClient client,
-                                            SilcSocketConnection sock,
-                                            SilcClientEntry client_entry,
-                                            unsigned char *data, 
-                                            unsigned int data_len, 
-                                            int force_send)
-{
-  SilcClientWindow win = (SilcClientWindow)sock->user_data;
-  SilcBuffer buffer;
-  SilcPacketContext packetdata;
-  unsigned int nick_len;
-  SilcCipher cipher;
-  SilcHmac hmac;
-
-  SILC_LOG_DEBUG(("Sending private message"));
-
-  /* Create private message payload */
-  nick_len = strlen(client->current_win->nickname);
-  buffer = silc_buffer_alloc(2 + nick_len + data_len);
-  silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
-  silc_buffer_format(buffer,
-                    SILC_STR_UI_SHORT(nick_len),
-                    SILC_STR_UI_XNSTRING(client->current_win->nickname,
-                                         nick_len),
-                    SILC_STR_UI_XNSTRING(data, data_len),
-                    SILC_STR_END);
-
-  /* If we don't have private message specific key then private messages
-     are just as any normal packet thus call normal packet sending.  If
-     the key exist then the encryption process is a bit different and
-     will be done in the rest of this function. */
-  if (!client_entry->send_key) {
-    silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
-                           client_entry->id, SILC_ID_CLIENT, NULL, NULL,
-                           buffer->data, buffer->len, force_send);
-    goto out;
-  }
-
-  /* We have private message specific key */
-
-  /* Get data used in the encryption */
-  cipher = client_entry->send_key;
-  hmac = win->hmac;
-
-  /* Set the packet context pointers. */
-  packetdata.flags = 0;
-  packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
-  packetdata.src_id = win->local_id_data;
-  packetdata.src_id_len = SILC_ID_CLIENT_LEN;
-  packetdata.src_id_type = SILC_ID_CLIENT;
-  if (client_entry)
-    packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
-  else
-    packetdata.dst_id = win->local_id_data;
-  packetdata.dst_id_len = SILC_ID_CLIENT_LEN;
-  packetdata.dst_id_type = SILC_ID_CLIENT;
-  packetdata.rng = client->rng;
-  packetdata.truelen = buffer->len + SILC_PACKET_HEADER_LEN + 
-    packetdata.src_id_len + packetdata.dst_id_len;
-  packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
-                                         packetdata.src_id_len +
-                                         packetdata.dst_id_len));
-
-  /* Prepare outgoing data buffer for packet sending */
-  silc_packet_send_prepare(sock, 
-                          SILC_PACKET_HEADER_LEN +
-                          packetdata.src_id_len + 
-                          packetdata.dst_id_len,
-                          packetdata.padlen,
-                          buffer->len);
-  
-  packetdata.buffer = sock->outbuf;
-
-  /* Encrypt payload of the packet. Encrypt with private message specific
-     key if it exist, otherwise with session key. */
-  cipher->cipher->encrypt(cipher->context, buffer->data, buffer->data,
-                         buffer->len, cipher->iv);
-      
-  /* Put the actual encrypted payload data into the buffer. */
-  silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
-
-  /* Create the outgoing packet */
-  silc_packet_assemble(&packetdata);
-
-  /* Encrypt the header and padding of the packet. */
-  silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN + 
-                     packetdata.src_id_len + packetdata.dst_id_len +
-                     packetdata.padlen);
-
-  SILC_LOG_HEXDUMP(("Private message packet, len %d", sock->outbuf->len),
-                  sock->outbuf->data, sock->outbuf->len);
-
-  /* Now actually send the packet */
-  silc_client_packet_send_real(client, sock, force_send);
-  silc_free(packetdata.dst_id);
-
- out:
-  silc_free(buffer);
-}     
-
-/* Closes connection to remote end. Free's all allocated data except
-   for some information such as nickname etc. that are valid at all time. */
-
-void silc_client_close_connection(SilcClient client,
-                                 SilcSocketConnection sock)
-{
-  SilcClientWindow win;
-
-  /* We won't listen for this connection anymore */
-  silc_schedule_unset_listen_fd(sock->sock);
-
-  /* Unregister all tasks */
-  silc_task_unregister_by_fd(client->io_queue, sock->sock);
-  silc_task_unregister_by_fd(client->timeout_queue, sock->sock);
-
-  /* Close the actual connection */
-  silc_net_close_connection(sock->sock);
-
-  silc_say(client, "Closed connection to host %s", sock->hostname ?
-          sock->hostname : sock->ip);
-
-  /* Free everything */
-  if (sock->user_data) {
-    win = (SilcClientWindow)sock->user_data;
-
-    /* XXX Free all client entries and channel entries. */
-
-    /* Clear ID caches */
-    silc_idcache_del_all(win->client_cache);
-    silc_idcache_del_all(win->channel_cache);
-
-    /* Free data */
-    if (win->remote_host)
-      silc_free(win->remote_host);
-    if (win->local_id)
-      silc_free(win->local_id);
-    if (win->local_id_data)
-      silc_free(win->local_id_data);
-    if (win->send_key)
-      silc_cipher_free(win->send_key);
-    if (win->receive_key)
-      silc_cipher_free(win->receive_key);
-    if (win->hmac)
-      silc_hmac_free(win->hmac);
-    if (win->hmac_key) {
-      memset(win->hmac_key, 0, win->hmac_key_len);
-      silc_free(win->hmac_key);
-    }
-
-    win->sock = NULL;
-    win->remote_port = 0;
-    win->remote_type = 0;
-    win->send_key = NULL;
-    win->receive_key = NULL;
-    win->hmac = NULL;
-    win->hmac_key = NULL;
-    win->hmac_key_len = 0;
-    win->local_id = NULL;
-    win->local_id_data = NULL;
-    win->remote_host = NULL;
-    win->current_channel = NULL;
-  }
-
-  if (sock->protocol) {
-    silc_protocol_free(sock->protocol);
-    sock->protocol = NULL;
-  }
-  silc_socket_free(sock);
-}
-
-/* Called when we receive disconnection packet from server. This 
-   closes our end properly and displays the reason of the disconnection
-   on the screen. */
-
-void silc_client_disconnected_by_server(SilcClient client,
-                                       SilcSocketConnection sock,
-                                       SilcBuffer message)
-{
-  char *msg;
-
-  SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
-
-  msg = silc_calloc(message->len + 1, sizeof(char));
-  memcpy(msg, message->data, message->len);
-  silc_say(client, msg);
-  silc_free(msg);
-
-  SILC_SET_DISCONNECTED(sock);
-  silc_client_close_connection(client, sock);
-}
-
-/* Received error message from server. Display it on the screen. 
-   We don't take any action what so ever of the error message. */
-
-void silc_client_error_by_server(SilcClient client,
-                                SilcSocketConnection sock,
-                                SilcBuffer message)
-{
-  char *msg;
-
-  msg = silc_calloc(message->len + 1, sizeof(char));
-  memcpy(msg, message->data, message->len);
-  silc_say(client, msg);
-  silc_free(msg);
-}
-
-/* Received notify message from server */
-
-void silc_client_notify_by_server(SilcClient client,
-                                 SilcSocketConnection sock,
-                                 SilcBuffer message)
-{
-  char *msg;
-
-  msg = silc_calloc(message->len + 1, sizeof(char));
-  memcpy(msg, message->data, message->len);
-  silc_say(client, msg);
-  silc_free(msg);
-}
-
-/* Processes the received new Client ID from server. Old Client ID is
-   deleted from cache and new one is added. */
-
-void silc_client_receive_new_id(SilcClient client,
-                               SilcSocketConnection sock,
-                               unsigned char *id_string)
-{
-  SilcClientWindow win = (SilcClientWindow)sock->user_data;
-
-  /* Delete old ID from ID cache */
-  silc_idcache_del_by_id(win->client_cache, SILC_ID_CLIENT, win->local_id);
-  
-  /* Save the new ID */
-  if (win->local_id)
-    silc_free(win->local_id);
-  win->local_id = silc_id_str2id(id_string, SILC_ID_CLIENT);
-  if (win->local_id_data)
-    silc_free(win->local_id_data);
-  win->local_id_data = 
-    silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
-  memcpy(win->local_id_data, id_string, SILC_ID_CLIENT_LEN);
-  win->local_id_data_len = SILC_ID_CLIENT_LEN;
-  if (!win->local_entry)
-    win->local_entry = silc_calloc(1, sizeof(*win->local_entry));
-  win->local_entry->nickname = win->nickname;
-  win->local_entry->id = win->local_id;
-  
-  /* Put it to the ID cache */
-  silc_idcache_add(win->client_cache, win->nickname, SILC_ID_CLIENT,
-                  win->local_id, (void *)win->local_entry, TRUE);
-}
-
-/* Processed received Channel ID for a channel. This is called when client
-   joins to channel and server replies with channel ID. The ID is cached. */
-
-void silc_client_new_channel_id(SilcClient client,
-                               SilcSocketConnection sock,
-                               char *channel_name,
-                               unsigned int mode,
-                               unsigned char *id_string)
-{
-  SilcClientWindow win = (SilcClientWindow)sock->user_data;
-  SilcChannelID *id;
-  SilcChannelEntry channel;
-
-  SILC_LOG_DEBUG(("New channel ID"));
-
-  id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
-  channel = silc_calloc(1, sizeof(*channel));
-  channel->channel_name = channel_name;
-  channel->id = id;
-  channel->mode = mode;
-  win->current_channel = channel;
-  
-  /* Put it to the ID cache */
-  silc_idcache_add(win->channel_cache, channel_name, SILC_ID_CHANNEL,
-                  (void *)id, (void *)channel, TRUE);
-}
-
-/* Processes received key for channel. The received key will be used
-   to protect the traffic on the channel for now on. Client must receive
-   the key to the channel before talking on the channel is possible. 
-   This is the key that server has generated, this is not the channel
-   private key, it is entirely local setting. */
-
-void silc_client_receive_channel_key(SilcClient client,
-                                    SilcSocketConnection sock,
-                                    SilcBuffer packet)
-{
-  unsigned char *id_string, *key, *cipher;
-  unsigned int key_len;
-  SilcClientWindow win = (SilcClientWindow)sock->user_data;
-  SilcChannelID *id;
-  SilcIDCacheEntry id_cache = NULL;
-  SilcChannelEntry channel;
-  SilcChannelKeyPayload payload;
-
-  SILC_LOG_DEBUG(("Received key for channel"));
-  
-  payload = silc_channel_key_parse_payload(packet);
-  if (!payload)
-    return;
-
-  id_string = silc_channel_key_get_id(payload, NULL);
-  if (!id_string) {
-    silc_channel_key_free_payload(payload);
-    return;
-  }
-  id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
-
-  /* Find channel. */
-  if (!silc_idcache_find_by_id_one(win->channel_cache, (void *)id,
-                                  SILC_ID_CHANNEL, &id_cache))
-    goto out;
-  
-  /* Save the key */
-  key = silc_channel_key_get_key(payload, &key_len);
-  cipher = silc_channel_key_get_cipher(payload, NULL);
-
-  channel = (SilcChannelEntry)id_cache->context;
-  channel->key_len = key_len;
-  channel->key = silc_calloc(key_len, sizeof(*channel->key));
-  memcpy(channel->key, key, key_len);
-
-  silc_cipher_alloc(cipher, &channel->channel_key);
-  if (!channel->channel_key) {
-    silc_say(client, "Cannot talk to channel: unsupported cipher %s", cipher);
-    goto out;
-  }
-  channel->channel_key->cipher->set_key(channel->channel_key->context, 
-                                       key, key_len);
-
-  /* Client is now joined to the channel */
-  channel->on_channel = TRUE;
-
- out:
-  silc_free(id);
-  silc_channel_key_free_payload(payload);
-}
-
-/* Process received message to a channel (or from a channel, really). This
-   decrypts the channel message with channel specific key and parses the
-   channel payload. Finally it displays the message on the screen. */
-
-void silc_client_channel_message(SilcClient client, 
-                                SilcSocketConnection sock, 
-                                SilcPacketContext *packet)
-{
-  SilcClientWindow win = (SilcClientWindow)sock->user_data;
-  SilcBuffer buffer = packet->buffer;
-  SilcChannelPayload payload = NULL;
-  SilcChannelID *id = NULL;
-  SilcChannelEntry channel;
-  SilcIDCacheEntry id_cache = NULL;
-
-  /* Sanity checks */
-  if (packet->dst_id_type != SILC_ID_CHANNEL)
-    goto out;
-
-  id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
-
-  /* Find the channel entry from channels on this window */
-  if (!silc_idcache_find_by_id_one(win->channel_cache, (void *)id,
-                                  SILC_ID_CHANNEL, &id_cache))
-    goto out;
-
-  channel = (SilcChannelEntry)id_cache->context;
-
-  /* Decrypt the channel message payload. Push the IV out of the way,
-     since it is not encrypted (after pushing buffer->tail has the IV). */
-  silc_buffer_push_tail(buffer, 16);
-  channel->channel_key->cipher->decrypt(channel->channel_key->context,
-                                       buffer->data, buffer->data,
-                                       buffer->len, buffer->tail);
-  silc_buffer_pull_tail(buffer, 16);
-
-  /* Parse the channel message payload */
-  payload = silc_channel_parse_payload(buffer);
-  if (!payload)
-    goto out;
-
-  /* Display the message on screen */
-  if (packet->src_id_type == SILC_ID_CLIENT) {
-    /* Message from client */
-    if (channel == win->current_channel)
-      silc_print(client, "<%s> %s", 
-                silc_channel_get_nickname(payload, NULL),
-                silc_channel_get_data(payload, NULL));
-    else
-      silc_print(client, "<%s:%s> %s", 
-                silc_channel_get_nickname(payload, NULL),
-                channel->channel_name,
-                silc_channel_get_data(payload, NULL));
-  } else {
-    /* Message from server */
-    silc_say(client, "%s", silc_channel_get_data(payload, NULL));
-  }
-
- out:
-  if (id)
-    silc_free(id);
-  if (payload)
-    silc_channel_free_payload(payload);
-}