Memory leak fixes.
[silc.git] / apps / irssi / src / silc / core / silc-servers.c
index 476205d450e0cfcf3c00b81e9f4da307873bf1b2..eb70efd547f5b74790c3b7f1d98d57a6eff41742 100644 (file)
@@ -1,7 +1,7 @@
 /*
   silc-server.c : irssi
 
-  Copyright (C) 2000 - 2005 Timo Sirainen
+  Copyright (C) 2000 - 2007 Timo Sirainen
                             Pekka Riikonen <priikone@silcnet.org>
 
   This program is free software; you can redistribute it and/or modify
@@ -63,9 +63,9 @@ int silc_send_channel(SILC_SERVER_REC *server,
     cmd_return_error_value(CMDERR_NOT_JOINED, FALSE);
   }
 
-  silc_client_send_channel_message(silc_client, server->conn, rec->entry,
-                                  NULL, flags, msg, strlen(msg), TRUE);
-  return TRUE;
+  return silc_client_send_channel_message(silc_client, server->conn,
+                                         rec->entry, NULL, flags, sha1hash,
+                                         msg, strlen(msg));
 }
 
 typedef struct {
@@ -81,43 +81,42 @@ typedef struct {
 
 static void silc_send_msg_clients(SilcClient client,
                                  SilcClientConnection conn,
-                                 SilcClientEntry *clients,
-                                 SilcUInt32 clients_count,
+                                 SilcStatus status,
+                                 SilcDList clients,
                                  void *context)
 {
   PRIVMSG_REC *rec = context;
   SILC_SERVER_REC *server = rec->server;
   SilcClientEntry target;
-  char *nickname = NULL;
+  char nickname[128 + 1];
+  SilcDList lclients = NULL;
 
-  if (!clients_count) {
+  if (!clients) {
     printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
              "%s: There is no such client", rec->nick);
   } else {
-    if (clients_count > 1) {
-      silc_parse_userfqdn(rec->nick, &nickname, NULL);
+    if (silc_dlist_count(clients) > 1) {
+      silc_parse_userfqdn(rec->nick, nickname, sizeof(nickname), NULL, 0);
 
       /* Find the correct one. The rec->nick might be a formatted nick
         so this will find the correct one. */
-      clients = silc_client_get_clients_local(silc_client, server->conn,
-                                             nickname, rec->nick,
-                                             &clients_count);
+      clients = lclients =
+       silc_client_get_clients_local(silc_client, server->conn,
+                                     nickname, rec->nick);
       if (!clients) {
        printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
                  "%s: There is no such client", rec->nick);
-       silc_free(nickname);
        goto out;
       }
-      silc_free(nickname);
     }
 
-    target = clients[0];
+    target = silc_dlist_get(clients);
 
     /* Still check for exact math for nickname, this compares the
        real (formatted) nickname and the nick (maybe formatted) that
-       use gave. This is to assure that `nick' does not match
+       user gave. This is to assure that `nick' does not match
        `nick@host'. */
-    if (!silc_utf8_strcasecmp(rec->nick, clients[0]->nickname)) {
+    if (!silc_utf8_strcasecmp(rec->nick, target->nickname)) {
       printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
                "%s: There is no such client", rec->nick);
       goto out;
@@ -125,12 +124,12 @@ static void silc_send_msg_clients(SilcClient client,
 
     /* Send the private message */
     silc_client_send_private_message(client, conn, target,
-                                    rec->flags,
-                                    rec->msg, rec->len,
-                                    TRUE);
+                                    rec->flags, sha1hash,
+                                    rec->msg, rec->len);
   }
 
  out:
+  silc_client_list_free(silc_client, server->conn, lclients);
   g_free(rec->nick);
   g_free(rec->msg);
   g_free(rec);
@@ -140,11 +139,12 @@ int silc_send_msg(SILC_SERVER_REC *server, char *nick, char *msg,
                  int msg_len, SilcMessageFlags flags)
 {
   PRIVMSG_REC *rec;
-  SilcClientEntry *clients;
-  SilcUInt32 clients_count;
-  char *nickname = NULL;
+  char nickname[128 + 1];
+  SilcDList clients;
+  SilcClientEntry target;
+  int ret;
 
-  if (!silc_parse_userfqdn(nick, &nickname, NULL)) {
+  if (!silc_parse_userfqdn(nick, nickname, sizeof(nickname), NULL, 0)) {
     printformat_module("fe-common/silc", server, NULL,
                       MSGLEVEL_CRAP, SILCTXT_BAD_NICK, nick);
     return FALSE;
@@ -152,7 +152,7 @@ int silc_send_msg(SILC_SERVER_REC *server, char *nick, char *msg,
 
   /* Find client entry */
   clients = silc_client_get_clients_local(silc_client, server->conn,
-                                         nickname, nick, &clients_count);
+                                         nickname, nick);
   if (!clients) {
     rec = g_new0(PRIVMSG_REC, 1);
     rec->nick = g_strdup(nick);
@@ -162,18 +162,21 @@ int silc_send_msg(SILC_SERVER_REC *server, char *nick, char *msg,
     rec->len = msg_len;
 
     /* Could not find client with that nick, resolve it from server. */
-    silc_client_get_clients(silc_client, server->conn,
-                           nickname, NULL, silc_send_msg_clients, rec);
-    silc_free(nickname);
+    silc_client_get_clients_whois(silc_client, server->conn,
+                                 nickname, NULL, NULL,
+                                 silc_send_msg_clients, rec);
     return TRUE;
   }
 
   /* Send the private message directly */
-  silc_free(nickname);
-  silc_client_send_private_message(silc_client, server->conn,
-                                  clients[0], flags,
-                                  msg, msg_len, TRUE);
-  return TRUE;
+  target = silc_dlist_get(clients);
+  ret = silc_client_send_private_message(silc_client, server->conn,
+                                        target, flags, sha1hash,
+                                        msg, msg_len);
+
+  silc_client_list_free(silc_client, server->conn, clients);
+
+  return ret;
 }
 
 void silc_send_mime(SILC_SERVER_REC *server, int channel, const char *to,
@@ -206,7 +209,8 @@ void silc_send_mime(SILC_SERVER_REC *server, int channel, const char *to,
     silc_client_send_channel_message(silc_client, server->conn, rec->entry,
                                     NULL, SILC_MESSAGE_FLAG_DATA |
                                     (sign ? SILC_MESSAGE_FLAG_SIGNED : 0),
-                                    unescaped_data, unescaped_data_len, TRUE);
+                                    sha1hash, unescaped_data,
+                                    unescaped_data_len);
   } else {
     silc_send_msg(server, (char *)to, unescaped_data, unescaped_data_len,
                  SILC_MESSAGE_FLAG_DATA |
@@ -219,7 +223,7 @@ void silc_send_mime(SILC_SERVER_REC *server, int channel, const char *to,
   silc_free(unescaped_data);
 }
 
-static int isnickflag_func(char flag)
+static int isnickflag_func(SERVER_REC *server, char flag)
 {
   return flag == '@' || flag == '+';
 }
@@ -229,7 +233,7 @@ static int ischannel_func(SERVER_REC *server, const char *data)
   return FALSE;
 }
 
-const char *get_nick_flags(void)
+const char *get_nick_flags(SERVER_REC *server)
 {
   return "@\0\0";
 }
@@ -239,6 +243,7 @@ static void send_message(SILC_SERVER_REC *server, char *target,
 {
   char *message = NULL, *t = NULL;
   int len;
+  SilcBool sign;
 
   g_return_if_fail(server != NULL);
   g_return_if_fail(target != NULL);
@@ -251,10 +256,13 @@ static void send_message(SILC_SERVER_REC *server, char *target,
     silc_utf8_encode(msg, strlen(msg), SILC_STRING_LOCALE, message, len);
   }
 
-  if (target_type == SEND_TARGET_CHANNEL)
+  if (target_type == SEND_TARGET_CHANNEL) {
+    sign = settings_get_bool("sign_channel_messages");
     silc_send_channel(server, target, message ? message : msg,
-                     SILC_MESSAGE_FLAG_UTF8);
-  else {
+                     SILC_MESSAGE_FLAG_UTF8 |
+                     (sign ? SILC_MESSAGE_FLAG_SIGNED : 0));
+  } else {
+    sign = settings_get_bool("sign_private_messages");
     if (!silc_term_utf8()) {
       len = silc_utf8_encoded_len(target, strlen(target), SILC_STRING_LOCALE);
       t = silc_calloc(len + 1, sizeof(*t));
@@ -264,70 +272,172 @@ static void send_message(SILC_SERVER_REC *server, char *target,
 
     silc_send_msg(server, t ? t : target, message ? message : msg,
                  message ? strlen(message) : strlen(msg),
-                 SILC_MESSAGE_FLAG_UTF8);
+                 SILC_MESSAGE_FLAG_UTF8 |
+                 (sign ? SILC_MESSAGE_FLAG_SIGNED : 0));
   }
 
   silc_free(message);
   silc_free(t);
 }
 
-void silc_send_heartbeat(SilcSocketConnection sock,
-                        void *hb_context)
+/* Connection callback */
+
+static void silc_connect_cb(SilcClient client,
+                           SilcClientConnection conn,
+                           SilcClientConnectionStatus status,
+                           SilcStatus error,
+                           const char *message,
+                           void *context)
 {
-  SILC_SERVER_REC *server = SILC_SERVER(hb_context);
+  SILC_SERVER_REC *server = context;
+  char *file;
 
-  if (server == NULL)
-    return;
+  SILC_LOG_DEBUG(("Connection callback %p, status %d, error %d, message %s",
+                 conn, status, error, message ? message : "N/A"));
+
+  server->op = NULL;
+
+  switch (status) {
+  case SILC_CLIENT_CONN_SUCCESS:
+    if (server->disconnected) {
+      silc_client_close_connection(client, conn);
+      return;
+    }
+
+    /* We have successfully connected to server */
+
+    /* Enable queueing until we have our requested nick */
+    if (((opt_nickname &&
+         strcmp(opt_nickname, conn->local_entry->nickname)) ||
+        (settings_get_str("nick") &&
+         strcmp(settings_get_str("nick"), conn->local_entry->nickname))) &&
+       !strcmp(conn->local_entry->nickname, conn->local_entry->username))
+      silc_queue_enable(conn);
+
+    /* Put default attributes */
+    silc_query_attributes_default(silc_client, conn);
+
+    server->connected = TRUE;
+    server->conn = conn;
+    server->conn->context = server;
+    signal_emit("event connected", 1, server);
+    break;
+
+  case SILC_CLIENT_CONN_SUCCESS_RESUME:
+    if (server->disconnected) {
+      silc_client_close_connection(client, conn);
+      return;
+    }
+
+    /* We have successfully resumed old detached session */
+    server->connected = TRUE;
+    server->conn = conn;
+    server->conn->context = server;
+    signal_emit("event connected", 1, server);
+
+    /* Put default attributes */
+    silc_query_attributes_default(silc_client, conn);
 
-  silc_client_send_packet(silc_client, server->conn, SILC_PACKET_HEARTBEAT,
-                         NULL, 0);
+    /* Remove the detach data now */
+    file = silc_get_session_filename(server);
+    unlink(file);
+    silc_free(file);
+    break;
+
+  case SILC_CLIENT_CONN_DISCONNECTED:
+    /* Server disconnected */
+    if (server->conn && server->conn->local_entry) {
+      nicklist_rename_unique(SERVER(server),
+                            server->conn->local_entry, server->nick,
+                            server->conn->local_entry,
+                            silc_client->username);
+      silc_change_nick(server, silc_client->username);
+    }
+
+    if (message)
+      silc_say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+              "Server closed connection: %s (%d) %s",
+              silc_get_status_message(error), error,
+              message ? message : "");
+
+    if (server->conn)
+      server->conn->context = NULL;
+    server->conn = NULL;
+    server->connection_lost = TRUE;
+    if (!server->disconnected)
+      server_disconnect(SERVER(server));
+    server_unref(SERVER(server));
+    break;
+
+  default:
+    file = silc_get_session_filename(server);
+    if (silc_file_size(file) > 0)
+      printformat_module("fe-common/silc", server, NULL,
+                        MSGLEVEL_CRAP, SILCTXT_REATTACH_FAILED, file);
+    silc_free(file);
+
+    server->connection_lost = TRUE;
+    server->conn = NULL;
+    if (server->conn)
+      server->conn->context = NULL;
+    if (!server->disconnected)
+      server_disconnect(SERVER(server));
+    server_unref(SERVER(server));
+    break;
+  }
 }
 
-static void sig_connected(SILC_SERVER_REC *server)
+/* Called after TCP stream has been created */
+
+static void sig_connected_stream_created(SilcSocketStreamStatus status,
+                                        SilcStream stream, void *context)
 {
-  SilcClientConnection conn;
+  SILC_SERVER_REC *server = context;
   SilcClientConnectionParams params;
   char *file;
-  int fd;
 
-  if (!IS_SILC_SERVER(server))
+  if (!stream) {
+    server->connection_lost = TRUE;
+    server_disconnect(SERVER(server));
     return;
+  }
 
-  /* Try to read detached session data and use it if found. */
+  if (server->disconnected) {
+    silc_stream_destroy(stream);
+    return;
+  }
+
+  /* Set connection parameters */
   memset(&params, 0, sizeof(params));
+  params.nickname = (opt_nickname ? (char *)opt_nickname :
+                    (char *)settings_get_str("nick"));
+  params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
+  params.rekey_secs = settings_get_int("key_exchange_rekey_secs");
+  params.pfs = settings_get_bool("key_exchange_rekey_pfs");
+
+  /* Try to read detached session data and use it if found. */
   file = silc_get_session_filename(server);
   params.detach_data = silc_file_readfile(file, &params.detach_data_len);
   if (params.detach_data)
     params.detach_data[params.detach_data_len] = 0;
-
-  /* Add connection to the client library */
-  conn = silc_client_add_connection(silc_client, &params,
-                                   server->connrec->address,
-                                   server->connrec->port,
-                                   server);
-  server->conn = conn;
-
   if (params.detach_data)
     printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
                        SILCTXT_REATTACH, server->tag);
+  silc_free(file);
+
+  /* Start key exchange */
+  server->op = silc_client_key_exchange(silc_client, &params,
+                                       irssi_pubkey, irssi_privkey,
+                                       stream, SILC_CONN_SERVER,
+                                       silc_connect_cb, server);
+  if (!server->op) {
+    server->connection_lost = TRUE;
+    server_disconnect(SERVER(server));
+    silc_stream_destroy(stream);
+    return;
+  }
 
-  silc_free(params.detach_data);
-
-  fd = g_io_channel_unix_get_fd(net_sendbuffer_handle(server->handle));
-
-  /* Start key exchange with the server */
-  silc_client_start_key_exchange(silc_client, conn, fd);
-
-  /* Put default attributes */
-  silc_query_attributes_default(silc_client, conn);
-
-  /* initialize heartbeat sending */
-  if (settings_get_int("heartbeat") > 0)
-    silc_socket_set_heartbeat(conn->sock, settings_get_int("heartbeat"),
-                               (void *)server,
-                               (SilcSocketConnectionHBCb)silc_send_heartbeat,
-                               silc_client->schedule);
-
+  server_ref(SERVER(server));
   server->ftp_sessions = silc_dlist_init();
   server->isnickflag = isnickflag_func;
   server->ischannel = ischannel_func;
@@ -335,6 +445,19 @@ static void sig_connected(SILC_SERVER_REC *server)
   server->send_message = (void *) send_message;
 }
 
+static void sig_connected(SILC_SERVER_REC *server)
+{
+  int fd;
+
+  if (!IS_SILC_SERVER(server))
+    return;
+
+  /* Wrap the socket to TCP stream */
+  fd = g_io_channel_unix_get_fd(net_sendbuffer_handle(server->handle));
+  silc_socket_tcp_stream_create(fd, TRUE, FALSE, silc_client->schedule,
+                               sig_connected_stream_created, server);
+}
+
 static void sig_disconnected(SILC_SERVER_REC *server)
 {
   if (!IS_SILC_SERVER(server))
@@ -342,14 +465,19 @@ static void sig_disconnected(SILC_SERVER_REC *server)
 
   silc_dlist_uninit(server->ftp_sessions);
 
-  if (server->conn && server->conn->sock != NULL) {
+  if (server->conn) {
+    /* Close connection */
     silc_client_close_connection(silc_client, server->conn);
-
-    /* SILC closes the handle */
-    g_io_channel_unref(net_sendbuffer_handle(server->handle));
-    net_sendbuffer_destroy(server->handle, FALSE);
-    server->handle = NULL;
+  } else if (server->op) {
+    /* Abort on going connecting (key exchange) */
+    silc_async_abort(server->op, NULL, NULL);
+    server->op = NULL;
   }
+
+  /* SILC closes the handle */
+  g_io_channel_unref(net_sendbuffer_handle(server->handle));
+  net_sendbuffer_destroy(server->handle, FALSE);
+  server->handle = NULL;
 }
 
 SERVER_REC *silc_server_init_connect(SERVER_CONNECT_REC *conn)
@@ -432,7 +560,6 @@ char *silc_server_get_channels(SILC_SERVER_REC *server)
 /* SYNTAX: WHOIS [<nickname>[@<hostname>]] [-details] [-pubkey <pubkeyfile>] [<count>] */
 /* SYNTAX: WHOWAS <nickname>[@<hostname>] [<count>] */
 /* SYNTAX: CLOSE <server> [<port>] */
-/* SYNTAX: SHUTDOWN */
 /* SYNTAX: MOTD [<server>] */
 /* SYNTAX: LIST [<channel>] */
 /* SYNTAX: ME <message> */
@@ -443,7 +570,6 @@ char *silc_server_get_channels(SILC_SERVER_REC *server)
 /* SYNTAX: NOTICE [-sign] [-channel] <target> <message> */
 /* SYNTAX: PART [<channel>] */
 /* SYNTAX: PING */
-/* SYNTAX: SCONNECT <server> [<port>] */
 /* SYNTAX: USERS <channel> */
 /* SYNTAX: FILE SEND <filepath> <nickname> [<local IP> [<local port>]] [-no-listener]*/
 /* SYNTAX: FILE ACCEPT [<nickname>] */
@@ -492,21 +618,6 @@ static void command_self(const char *data, SILC_SERVER_REC *server,
   signal_stop();
 }
 
-/* SCONNECT command.  Calls actually SILC's CONNECT command since Irssi
-   has CONNECT command for other purposes. */
-
-static void command_sconnect(const char *data, SILC_SERVER_REC *server)
-{
-  CMD_SILC_SERVER(server);
-  if (!IS_SILC_SERVER(server) || !server->connected) {
-    printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Not connected to server");
-    return;
-  }
-
-  silc_command_exec(server, "CONNECT", data);
-  signal_stop();
-}
-
 /* SMSG command, to send digitally signed messages */
 
 static void command_smsg(const char *data, SILC_SERVER_REC *server,
@@ -632,7 +743,8 @@ static void silc_client_file_monitor(SilcClient client,
   if (ftp == SILC_LIST_END)
     return;
 
-  if (status == SILC_CLIENT_FILE_MONITOR_ERROR) {
+  if (status == SILC_CLIENT_FILE_MONITOR_ERROR ||
+      status == SILC_CLIENT_FILE_MONITOR_DISCONNECT) {
     if (error == SILC_CLIENT_FILE_NO_SUCH_FILE)
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_FILE_ERROR_NO_SUCH_FILE,
@@ -645,9 +757,9 @@ static void silc_client_file_monitor(SilcClient client,
     else
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_FILE_ERROR, client_entry->nickname);
-    silc_schedule_task_add(silc_client->schedule, 0,
-                          silc_client_file_close_later, ftp,
-                          1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+    silc_schedule_task_add_timeout(silc_client->schedule,
+                                  silc_client_file_close_later, ftp,
+                                  1, 0);
     silc_dlist_del(server->ftp_sessions, ftp);
     if (ftp == server->current_session) {
       server->current_session = NULL;
@@ -685,9 +797,9 @@ static void silc_client_file_monitor(SilcClient client,
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_FILE_TRANSMITTED, filepath, fsize,
                         client_entry->nickname, ftp->kps);
-      silc_schedule_task_add(silc_client->schedule, 0,
-                            silc_client_file_close_later, ftp,
-                            1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+      silc_schedule_task_add_timeout(silc_client->schedule,
+                                    silc_client_file_close_later, ftp,
+                                    1, 0);
       silc_dlist_del(server->ftp_sessions, ftp);
       if (ftp == server->current_session) {
        server->current_session = NULL;
@@ -710,9 +822,9 @@ static void silc_client_file_monitor(SilcClient client,
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_FILE_RECEIVED, filepath, fsize,
                         client_entry->nickname, ftp->kps);
-      silc_schedule_task_add(silc_client->schedule, 0,
-                            silc_client_file_close_later, ftp,
-                            1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+      silc_schedule_task_add_timeout(silc_client->schedule,
+                                    silc_client_file_close_later, ftp,
+                                    1, 0);
       silc_dlist_del(server->ftp_sessions, ftp);
       if (ftp == server->current_session) {
        server->current_session = NULL;
@@ -733,8 +845,8 @@ typedef struct {
 
 static void silc_client_command_file_get_clients(SilcClient client,
                                                 SilcClientConnection conn,
-                                                SilcClientEntry *clients,
-                                                SilcUInt32 clients_count,
+                                                SilcStatus status,
+                                                SilcDList clients,
                                                 void *context)
 {
   FileGetClients internal = (FileGetClients)context;
@@ -760,10 +872,10 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
                         WI_ITEM_REC *item)
 {
   SilcClientConnection conn;
-  SilcClientEntry *entrys, client_entry;
+  SilcClientEntry client_entry;
+  SilcDList entries;
   SilcClientFileError ret;
-  SilcUInt32 entry_count;
-  char *nickname = NULL, *tmp;
+  char nickname[128 + 1], *tmp;
   unsigned char **argv;
   SilcUInt32 argc;
   SilcUInt32 *argv_lens, *argv_types;
@@ -773,6 +885,7 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
   SilcUInt32 local_port = 0;
   SilcUInt32 session_id;
   bool do_not_bind = FALSE;
+  SilcClientConnectionParams params;
 
   CMD_SILC_SERVER(server);
   if (!server || !IS_SILC_SERVER(server) || !server->connected)
@@ -806,16 +919,16 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
       cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
 
     /* Parse the typed nickname. */
-    if (!silc_parse_userfqdn(argv[3], &nickname, NULL)) {
+    if (!silc_parse_userfqdn(argv[3], nickname, sizeof(nickname), NULL, 0)) {
       printformat_module("fe-common/silc", server, NULL,
                         MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[3]);
       goto out;
     }
 
     /* Find client entry */
-    entrys = silc_client_get_clients_local(silc_client, conn, nickname,
-                                          argv[3], &entry_count);
-    if (!entrys) {
+    entries = silc_client_get_clients_local(silc_client, conn, nickname,
+                                           argv[3]);
+    if (!entries) {
       FileGetClients inter = silc_calloc(1, sizeof(*inter));
       inter->server = server;
       inter->data = strdup(data);
@@ -825,8 +938,8 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
                              silc_client_command_file_get_clients, inter);
       goto out;
     }
-    client_entry = entrys[0];
-    silc_free(entrys);
+    silc_dlist_start(entries);
+    client_entry = silc_dlist_get(entries);
 
     if (argc >= 5) {
       if (!strcasecmp(argv[4], "-no-listener"))
@@ -845,10 +958,31 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
        do_not_bind = TRUE;
     }
 
-    ret =
-      silc_client_file_send(silc_client, conn, silc_client_file_monitor,
-                           server, local_ip, local_port, do_not_bind,
-                           client_entry, argv[2], &session_id);
+    memset(&params, 0, sizeof(params));
+    if (!do_not_bind) {
+      if (local_ip)
+        params.local_ip = strdup(local_ip);
+      params.local_port = local_port;
+      if (!params.local_ip && settings_get_bool("use_auto_addr")) {
+       params.local_ip = (char *)settings_get_str("auto_public_ip");
+       if ((params.local_ip) && (*params.local_ip == '\0')) {
+         params.local_ip = silc_net_localip();
+       } else {
+         params.bind_ip = (char *)settings_get_str("auto_bind_ip");
+         if ((params.bind_ip) && (*params.bind_ip == '\0'))
+           params.bind_ip = NULL;
+         params.local_port = settings_get_int("auto_bind_port");
+       }
+      }
+      if (!params.local_ip)
+       params.local_ip = silc_net_localip();
+    }
+    params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
+
+    ret = silc_client_file_send(silc_client, conn, client_entry, &params,
+                               irssi_pubkey, irssi_privkey,
+                               silc_client_file_monitor, server, argv[2],
+                               &session_id);
     if (ret == SILC_CLIENT_FILE_OK) {
       ftp = silc_calloc(1, sizeof(*ftp));
       ftp->session_id = session_id;
@@ -874,21 +1008,22 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
                           client_entry->nickname, argv[2]);
     }
 
+    silc_client_list_free(silc_client, server->conn, entries);
     break;
 
   case 2:
     /* Parse the typed nickname. */
     if (argc >= 3) {
-      if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
+      if (!silc_parse_userfqdn(argv[2], nickname, sizeof(nickname), NULL, 0)) {
        printformat_module("fe-common/silc", server, NULL,
                           MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
        goto out;
       }
 
       /* Find client entry */
-      entrys = silc_client_get_clients_local(silc_client, conn, nickname,
-                                            argv[2], &entry_count);
-      if (!entrys) {
+      entries = silc_client_get_clients_local(silc_client, conn, nickname,
+                                             argv[2]);
+      if (!entries) {
        FileGetClients inter = silc_calloc(1, sizeof(*inter));
        inter->server = server;
        inter->data = strdup(data);
@@ -898,8 +1033,9 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
                                silc_client_command_file_get_clients, inter);
        goto out;
       }
-      client_entry = entrys[0];
-      silc_free(entrys);
+      silc_dlist_start(entries);
+      client_entry = silc_dlist_get(entries);
+      silc_client_list_free(silc_client, server->conn, entries);
     } else {
       if (!server->current_session) {
        printformat_module("fe-common/silc", server, NULL,
@@ -907,7 +1043,24 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
        goto out;
       }
 
-      ret = silc_client_file_receive(silc_client, conn,
+      memset(&params, 0, sizeof(params));
+      if (settings_get_bool("use_auto_addr")) {
+       params.local_ip = (char *)settings_get_str("auto_public_ip");
+       if ((params.local_ip) && (*params.local_ip == '\0')) {
+         params.local_ip = silc_net_localip();
+       } else {
+         params.bind_ip = (char *)settings_get_str("auto_bind_ip");
+         if ((params.bind_ip) && (*params.bind_ip == '\0'))
+           params.bind_ip = NULL;
+         params.local_port = settings_get_int("auto_bind_port");
+       }
+      }
+      if (!params.local_ip)
+       params.local_ip = silc_net_localip();
+      params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
+
+      ret = silc_client_file_receive(silc_client, conn, &params,
+                                    irssi_pubkey, irssi_privkey,
                                     silc_client_file_monitor, server, NULL,
                                     server->current_session->session_id,
                                     NULL, NULL);
@@ -939,7 +1092,24 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
     silc_dlist_start(server->ftp_sessions);
     while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
       if (ftp->client_entry == client_entry && !ftp->filepath) {
-       ret = silc_client_file_receive(silc_client, conn,
+       memset(&params, 0, sizeof(params));
+       if (settings_get_bool("use_auto_addr")) {
+         params.local_ip = (char *)settings_get_str("auto_public_ip");
+         if ((params.local_ip) && (*params.local_ip == '\0')) {
+           params.local_ip = silc_net_localip();
+         } else {
+           params.bind_ip = (char *)settings_get_str("auto_bind_ip");
+           if ((params.bind_ip) && (*params.bind_ip == '\0'))
+             params.bind_ip = NULL;
+           params.local_port = settings_get_int("auto_bind_port");
+         }
+       }
+       if (!params.local_ip)
+         params.local_ip = silc_net_localip();
+       params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
+
+       ret = silc_client_file_receive(silc_client, conn, &params,
+                                      irssi_pubkey, irssi_privkey,
                                       silc_client_file_monitor, server,
                                       NULL, ftp->session_id, NULL, NULL);
        if (ret != SILC_CLIENT_FILE_OK) {
@@ -977,16 +1147,16 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
   case 3:
     /* Parse the typed nickname. */
     if (argc >= 3) {
-      if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
+      if (!silc_parse_userfqdn(argv[2], nickname, sizeof(nickname), NULL, 0)) {
        printformat_module("fe-common/silc", server, NULL,
                           MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
        goto out;
       }
 
       /* Find client entry */
-      entrys = silc_client_get_clients_local(silc_client, conn, nickname,
-                                            argv[2], &entry_count);
-      if (!entrys) {
+      entries = silc_client_get_clients_local(silc_client, conn, nickname,
+                                             argv[2]);
+      if (!entries) {
        FileGetClients inter = silc_calloc(1, sizeof(*inter));
        inter->server = server;
        inter->data = strdup(data);
@@ -996,8 +1166,9 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
                                silc_client_command_file_get_clients, inter);
        goto out;
       }
-      client_entry = entrys[0];
-      silc_free(entrys);
+      silc_dlist_start(entries);
+      client_entry = silc_dlist_get(entries);
+      silc_client_list_free(silc_client, server->conn, entries);
     } else {
       if (!server->current_session) {
        printformat_module("fe-common/silc", server, NULL,
@@ -1081,7 +1252,7 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
   }
 
  out:
-  silc_free(nickname);
+  return;
 }
 
 void silc_server_init(void)
@@ -1110,9 +1281,7 @@ void silc_server_init(void)
   command_bind_silc("ping", MODULE_NAME, (SIGNAL_FUNC) command_self);
   command_bind_silc("motd", MODULE_NAME, (SIGNAL_FUNC) command_self);
   command_bind_silc("close", MODULE_NAME, (SIGNAL_FUNC) command_self);
-  command_bind_silc("shutdown", MODULE_NAME, (SIGNAL_FUNC) command_self);
   command_bind_silc("getkey", MODULE_NAME, (SIGNAL_FUNC) command_self);
-  command_bind_silc("sconnect", MODULE_NAME, (SIGNAL_FUNC) command_sconnect);
   command_bind_silc("file", MODULE_NAME, (SIGNAL_FUNC) command_file);
   command_bind_silc("detach", MODULE_NAME, (SIGNAL_FUNC) command_self);
   command_bind_silc("watch", MODULE_NAME, (SIGNAL_FUNC) command_self);
@@ -1149,9 +1318,7 @@ void silc_server_deinit(void)
   command_unbind("motd", (SIGNAL_FUNC) command_self);
   command_unbind("ban", (SIGNAL_FUNC) command_self);
   command_unbind("close", (SIGNAL_FUNC) command_self);
-  command_unbind("shutdown", (SIGNAL_FUNC) command_self);
   command_unbind("getkey", (SIGNAL_FUNC) command_self);
-  command_unbind("sconnect", (SIGNAL_FUNC) command_sconnect);
   command_unbind("file", (SIGNAL_FUNC) command_file);
   command_unbind("detach", (SIGNAL_FUNC) command_self);
   command_unbind("watch", (SIGNAL_FUNC) command_self);
@@ -1178,7 +1345,7 @@ void silc_server_free_ftp(SILC_SERVER_REC *server,
 bool silc_term_utf8(void)
 {
   const char *str;
-  str = settings_get_str("term_type");
+  str = settings_get_str("term_charset");
   if (str)
     if (g_strcasecmp(str, "utf-8") == 0)
       return TRUE;