Created SILC Crypto Toolkit git repository.
[crypto.git] / lib / silcclient / client_ftp.c
diff --git a/lib/silcclient/client_ftp.c b/lib/silcclient/client_ftp.c
deleted file mode 100644 (file)
index a38d03c..0000000
+++ /dev/null
@@ -1,1093 +0,0 @@
-/*
-
-  client_ftp.c
-
-  Author: Pekka Riikonen <priikone@silcnet.org>
-
-  Copyright (C) 2001 - 2007 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; version 2 of the License.
-
-  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$ */
-
-#include "silc.h"
-#include "silcclient.h"
-#include "client_internal.h"
-
-/************************** Types and definitions ***************************/
-
-/* File transmission session */
-struct SilcClientFtpSessionStruct {
-  SilcClient client;                 /* Client */
-  SilcClientConnection server_conn;   /* Connection to server */
-  SilcClientConnection conn;         /* Connection to remote host */
-  SilcClientEntry client_entry;              /* The client entry */
-  SilcClientListener listener;       /* Listener */
-  SilcAsyncOperation op;             /* Operation for connecting */
-  SilcClientConnectionParams params;  /* Connection params */
-  SilcPublicKey public_key;          /* Public key used in key exchange */
-  SilcPrivateKey private_key;        /* Private key used in key exchange */
-  SilcUInt32 session_id;             /* File transfer ID */
-
-  SilcClientFileMonitor monitor;      /* File transfer monitor callback */
-  void *monitor_context;
-  SilcClientFileAskName ask_name;     /* File name asking callback */
-  void *ask_name_context;
-  char *filepath;                    /* The remote filename */
-  char *path;                        /* User given path to save the file  */
-
-  SilcStream stream;                 /* Wrapped SilcPacketStream */
-  SilcSFTP sftp;                     /* SFTP server/client */
-  SilcSFTPFilesystem fs;             /* SFTP memory file system */
-  SilcSFTPHandle dir_handle;         /* SFTP session directory handle */
-  SilcSFTPHandle read_handle;        /* SFTP session file handles */
-
-  char *hostname;                    /* Remote host */
-  SilcUInt16 port;                   /* Remote port */
-  SilcUInt64 filesize;               /* File size */
-  SilcUInt64 read_offset;            /* Current read offset */
-  int fd;                            /* File descriptor */
-  unsigned int initiator : 1;        /* File sender sets this to TRUE */
-  unsigned int closed    : 1;        /* silc_client_file_close called */
-};
-
-/************************* SFTP Server Callbacks ****************************/
-
-/* SFTP monitor callback for SFTP server. This reports the application
-   how the transmission is going along. This function is for the client
-   who made the file available for download. */
-
-static void silc_client_ftp_monitor(SilcSFTP sftp,
-                                   SilcSFTPMonitors type,
-                                   const SilcSFTPMonitorData data,
-                                   void *context)
-{
-  SilcClientFtpSession session = (SilcClientFtpSession)context;
-
-  if (type == SILC_SFTP_MONITOR_READ) {
-    /* Call the monitor for application */
-    if (session->monitor)
-      (*session->monitor)(session->client, session->conn,
-                         SILC_CLIENT_FILE_MONITOR_SEND,
-                         SILC_CLIENT_FILE_OK,
-                         data->offset, session->filesize,
-                         session->client_entry, session->session_id,
-                         session->filepath, session->monitor_context);
-  }
-}
-
-/************************* SFTP Client Callbacks ****************************/
-
-/* Returns the read data. This is the downloader's function (client side)
-   to receive the read data and read more until EOF is received from
-   the other side. This will also monitor the transmission and notify
-   the application. */
-
-static void silc_client_ftp_data(SilcSFTP sftp,
-                                SilcSFTPStatus status,
-                                const unsigned char *data,
-                                SilcUInt32 data_len,
-                                void *context)
-{
-  SilcClientFtpSession session = (SilcClientFtpSession)context;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (status == SILC_SFTP_STATUS_EOF) {
-    /* EOF received */
-
-    /* Close the handle */
-    silc_sftp_close(sftp, session->read_handle, NULL, NULL);
-    session->read_handle = NULL;
-
-    /* Close the real file descriptor */
-    silc_file_close(session->fd);
-    return;
-  }
-
-  if (status != SILC_SFTP_STATUS_OK) {
-    /* Call monitor callback */
-    if (session->monitor)
-      (*session->monitor)(session->client, session->conn,
-                         SILC_CLIENT_FILE_MONITOR_ERROR,
-                         (status == SILC_SFTP_STATUS_NO_SUCH_FILE ?
-                          SILC_CLIENT_FILE_NO_SUCH_FILE :
-                          status == SILC_SFTP_STATUS_PERMISSION_DENIED ?
-                          SILC_CLIENT_FILE_PERMISSION_DENIED :
-                          SILC_CLIENT_FILE_ERROR), 0, 0,
-                         session->client_entry, session->session_id,
-                         session->filepath, session->monitor_context);
-
-    /* Close the handle */
-    silc_sftp_close(sftp, session->read_handle, NULL, NULL);
-    session->read_handle = NULL;
-
-    /* Close the real file descriptor */
-    silc_file_close(session->fd);
-    return;
-  }
-
-  /* Read more, until EOF is received */
-  session->read_offset += data_len;
-  silc_sftp_read(sftp, session->read_handle, session->read_offset,
-                 SILC_PACKET_MAX_LEN - 1024,
-                silc_client_ftp_data, session);
-
-  /* Write the read data to the real file */
-  silc_file_write(session->fd, data, data_len);
-
-  /* Call monitor callback */
-  if (session->monitor)
-    (*session->monitor)(session->client, session->conn,
-                       SILC_CLIENT_FILE_MONITOR_RECEIVE,
-                       SILC_CLIENT_FILE_OK,
-                       session->read_offset, session->filesize,
-                       session->client_entry, session->session_id,
-                       session->filepath, session->monitor_context);
-}
-
-/* Returns handle for the opened file. This is the downloader's function.
-   This will begin reading the data from the file. */
-
-static void silc_client_ftp_open_handle(SilcSFTP sftp,
-                                       SilcSFTPStatus status,
-                                       SilcSFTPHandle handle,
-                                       void *context)
-{
-  SilcClientFtpSession session = (SilcClientFtpSession)context;
-  char path[512];
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (status != SILC_SFTP_STATUS_OK) {
-    /* Call monitor callback */
-    if (session->monitor)
-      (*session->monitor)(session->client, session->conn,
-                         SILC_CLIENT_FILE_MONITOR_ERROR,
-                         (status == SILC_SFTP_STATUS_NO_SUCH_FILE ?
-                          SILC_CLIENT_FILE_NO_SUCH_FILE :
-                          status == SILC_SFTP_STATUS_PERMISSION_DENIED ?
-                          SILC_CLIENT_FILE_PERMISSION_DENIED :
-                          SILC_CLIENT_FILE_ERROR), 0, 0,
-                         session->client_entry, session->session_id,
-                         session->filepath, session->monitor_context);
-    return;
-  }
-
-  /* Open the actual local file */
-  memset(path, 0, sizeof(path));
-  silc_snprintf(path, sizeof(path) - 1, "%s%s", session->path ?
-               session->path : "", session->filepath);
-  session->fd = silc_file_open(path, O_RDWR | O_CREAT | O_EXCL);
-  if (session->fd < 0) {
-    /* Call monitor callback */
-    session->client->internal->ops->say(session->client, session->conn,
-                                       SILC_CLIENT_MESSAGE_ERROR,
-                                       "File `%s' open failed: %s",
-                                       session->filepath,
-                                       strerror(errno));
-
-    if (session->monitor)
-      (*session->monitor)(session->client, session->conn,
-                         SILC_CLIENT_FILE_MONITOR_ERROR,
-                         SILC_CLIENT_FILE_PERMISSION_DENIED, 0, 0,
-                         session->client_entry, session->session_id,
-                         session->filepath, session->monitor_context);
-    return;
-  }
-
-  session->read_handle = handle;
-
-  /* Now, start reading the file */
-  silc_sftp_read(sftp, session->read_handle, session->read_offset,
-                 SILC_PACKET_MAX_LEN - 1024,
-                silc_client_ftp_data, session);
-
-  /* Call monitor callback */
-  if (session->monitor)
-    (*session->monitor)(session->client, session->conn,
-                       SILC_CLIENT_FILE_MONITOR_RECEIVE,
-                       SILC_CLIENT_FILE_OK,
-                       session->read_offset, session->filesize,
-                       session->client_entry, session->session_id,
-                       session->filepath, session->monitor_context);
-}
-
-/* Ask filename completion callback.  Delivers the filepath selected by
-   user. */
-
-static void silc_client_ftp_ask_name(const char *filepath,
-                                    void *context)
-{
-  SilcClientFtpSession session = (SilcClientFtpSession)context;
-  SilcSFTPAttributesStruct attr;
-  char *remote_file = NULL;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (filepath) {
-    remote_file = session->filepath;
-    session->filepath = NULL;
-    silc_free(session->path);
-    session->path = NULL;
-    session->filepath = strdup(filepath);
-  } else {
-    remote_file = strdup(session->filepath);
-  }
-
-  /* Now open the file */
-  memset(&attr, 0, sizeof(attr));
-  silc_sftp_open(session->sftp, remote_file, SILC_SFTP_FXF_READ, &attr,
-                silc_client_ftp_open_handle, session);
-
-  /* Close the directory handle */
-  silc_sftp_close(session->sftp, session->dir_handle, NULL, NULL);
-  session->dir_handle = NULL;
-
-  silc_free(remote_file);
-}
-
-/* Returns the file name available for download. This is the downloader's
-   function. */
-
-static void silc_client_ftp_readdir_name(SilcSFTP sftp,
-                                        SilcSFTPStatus status,
-                                        const SilcSFTPName name,
-                                        void *context)
-{
-  SilcClientFtpSession session = (SilcClientFtpSession)context;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (status != SILC_SFTP_STATUS_OK) {
-    /* Call monitor callback */
-    if (session->monitor)
-      (*session->monitor)(session->client, session->conn,
-                         SILC_CLIENT_FILE_MONITOR_ERROR,
-                         (status == SILC_SFTP_STATUS_NO_SUCH_FILE ?
-                          SILC_CLIENT_FILE_NO_SUCH_FILE :
-                          status == SILC_SFTP_STATUS_PERMISSION_DENIED ?
-                          SILC_CLIENT_FILE_PERMISSION_DENIED :
-                          SILC_CLIENT_FILE_ERROR), 0, 0,
-                         session->client_entry, session->session_id,
-                         session->filepath, session->monitor_context);
-    return;
-  }
-
-  /* Save the important attributes like filename and file size */
-  session->filepath = strdup(name->filename[0]);
-  session->filesize = name->attrs[0]->size;
-
-  /* If the path was not provided, ask from application where to save the
-     downloaded file. */
-  if (!session->path && session->ask_name) {
-    session->ask_name(session->client, session->conn, session->session_id,
-                     name->filename[0], silc_client_ftp_ask_name, session,
-                     session->ask_name_context);
-    return;
-  }
-
-  /* Start downloading immediately to current directory. */
-  silc_client_ftp_ask_name(NULL, session);
-}
-
-/* Returns the file handle after giving opendir command. This is the
-   downloader's function. */
-
-static void silc_client_ftp_opendir_handle(SilcSFTP sftp,
-                                          SilcSFTPStatus status,
-                                          SilcSFTPHandle handle,
-                                          void *context)
-{
-  SilcClientFtpSession session = (SilcClientFtpSession)context;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (status != SILC_SFTP_STATUS_OK) {
-    /* Call monitor callback */
-    if (session->monitor)
-      (*session->monitor)(session->client, session->conn,
-                         SILC_CLIENT_FILE_MONITOR_ERROR,
-                         (status == SILC_SFTP_STATUS_NO_SUCH_FILE ?
-                          SILC_CLIENT_FILE_NO_SUCH_FILE :
-                          status == SILC_SFTP_STATUS_PERMISSION_DENIED ?
-                          SILC_CLIENT_FILE_PERMISSION_DENIED :
-                          SILC_CLIENT_FILE_ERROR), 0, 0,
-                         session->client_entry, session->session_id,
-                         session->filepath, session->monitor_context);
-    return;
-  }
-
-  /* Now, read the directory */
-  silc_sftp_readdir(sftp, handle, silc_client_ftp_readdir_name, session);
-  session->dir_handle = handle;
-}
-
-/* SFTP version callback for SFTP client. This is the downloader's function
-   after initializing the SFTP connection to the remote client. This will
-   find out the filename available for download. */
-
-static void silc_client_ftp_version(SilcSFTP sftp,
-                                   SilcSFTPStatus status,
-                                   SilcSFTPVersion version,
-                                   void *context)
-{
-  SilcClientFtpSession session = (SilcClientFtpSession)context;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (status != SILC_SFTP_STATUS_OK) {
-    /* Call monitor callback */
-    if (session->monitor)
-      (*session->monitor)(session->client, session->conn,
-                         SILC_CLIENT_FILE_MONITOR_ERROR,
-                         (status == SILC_SFTP_STATUS_NO_SUCH_FILE ?
-                          SILC_CLIENT_FILE_NO_SUCH_FILE :
-                          status == SILC_SFTP_STATUS_PERMISSION_DENIED ?
-                          SILC_CLIENT_FILE_PERMISSION_DENIED :
-                          SILC_CLIENT_FILE_ERROR), 0, 0,
-                         session->client_entry, session->session_id,
-                         session->filepath, session->monitor_context);
-    return;
-  }
-
-  /* The SFTP session is open, now retrieve the info about available file. */
-  silc_sftp_opendir(sftp, "", silc_client_ftp_opendir_handle, session);
-}
-
-/* SFTP stream error callback */
-
-static void silc_client_ftp_error(SilcSFTP sftp, SilcSFTPStatus status,
-                                 void *context)
-{
-
-}
-
-/************************ Static utility functions **************************/
-
-/* Free session resources.   Connection must be closed before getting
-   here. */
-
-static void silc_client_ftp_session_free(SilcClientFtpSession session)
-{
-  SILC_LOG_DEBUG(("Free session %d", session->session_id));
-
-  silc_schedule_task_del_by_context(session->client->schedule, session);
-
-  silc_dlist_del(session->client->internal->ftp_sessions, session);
-
-  /* Abort connecting  */
-  if (session->op)
-    silc_async_abort(session->op, NULL, NULL);
-
-  /* Destroy SFTP */
-  if (session->sftp) {
-    if (session->initiator)
-      silc_sftp_server_shutdown(session->sftp);
-    else
-      silc_sftp_client_shutdown(session->sftp);
-  }
-  if (session->fs)
-    silc_sftp_fs_memory_free(session->fs);
-
-  /* Destroy listener */
-  if (session->listener)
-    silc_client_listener_free(session->listener);
-
-  /* Destroy wrapped stream */
-  if (session->stream)
-    silc_stream_destroy(session->stream);
-
-  silc_client_unref_client(session->client, session->server_conn,
-                          session->client_entry);
-  silc_free(session->hostname);
-  silc_free(session->filepath);
-  silc_free(session->path);
-  silc_free(session);
-}
-
-/* File transfer session timeout */
-
-SILC_TASK_CALLBACK(silc_client_ftp_timeout)
-{
-  SilcClientFtpSession session = context;
-
-  SILC_LOG_DEBUG(("Timeout"));
-
-  /* Close connection (destroyes the session context later).  If it is
-     already closed, destroy the session now. */
-  if (session->conn) {
-    silc_client_close_connection(session->client, session->conn);
-    session->conn = NULL;
-  } else {
-    /* Call monitor callback */
-    if (session->monitor)
-      (*session->monitor)(session->client, session->conn,
-                         SILC_CLIENT_FILE_MONITOR_ERROR,
-                         SILC_CLIENT_FILE_TIMEOUT, 0, 0,
-                         session->client_entry, session->session_id,
-                         session->filepath, session->monitor_context);
-
-    silc_client_ftp_session_free(context);
-  }
-}
-
-/* File transfer session closing task callback */
-
-SILC_TASK_CALLBACK(silc_client_file_close_final)
-{
-  SilcClientFtpSession session = context;
-
-  /* Close connection (destroyes the session context later).  If it is
-     already closed, destroy the session now. */
-  if (session->conn) {
-    silc_client_close_connection(session->client, session->conn);
-    session->conn = NULL;
-  } else {
-    silc_client_ftp_session_free(context);
-  }
-}
-
-/* Client resolving callback.  Continues with the FTP packet processing */
-
-static void silc_client_ftp_client_resolved(SilcClient client,
-                                           SilcClientConnection conn,
-                                           SilcStatus status,
-                                           SilcDList clients,
-                                           void *context)
-{
-  SilcFSMThread thread = context;
-  SilcPacket packet = silc_fsm_get_state_context(thread);
-
-  /* If no client found, ignore the packet, a silent error */
-  if (!clients) {
-    silc_packet_free(packet);
-    silc_fsm_finish(thread);
-    return;
-  }
-
-  /* Continue processing the packet */
-  SILC_FSM_CALL_CONTINUE(context);
-}
-
-/* FTP packet payload encoder/decoder.  This is called for every FTP packet.
-   We add/remove FTP payload in this function, because SFTP library does not
-   add/remove it. */
-
-static SilcBool
-silc_client_ftp_coder(SilcStream stream, SilcStreamStatus status,
-                     SilcBuffer buffer, void *context)
-{
-  /* Pull FTP type in the payload, revealing SFTP payload */
-  if (status == SILC_STREAM_CAN_READ) {
-    if (silc_buffer_len(buffer) >= 1)
-      silc_buffer_pull(buffer, 1);
-    return TRUE;
-  }
-
-  /* Add FTP type before SFTP data */
-  if (status == SILC_STREAM_CAN_WRITE) {
-    if (silc_buffer_format(buffer,
-                          SILC_STR_UI_CHAR(1),
-                          SILC_STR_END) < 0)
-      return FALSE;
-    return TRUE;
-  }
-
-  return FALSE;
-}
-
-/* FTP Connection callback.  The SFTP session is started here. */
-
-static void
-silc_client_ftp_connect_completion(SilcClient client,
-                                  SilcClientConnection conn,
-                                  SilcClientConnectionStatus status,
-                                  SilcStatus error,
-                                  const char *message,
-                                  void *context)
-{
-  SilcClientFtpSession session = context;
-
-  session->conn = conn;
-  session->op = NULL;
-
-  silc_schedule_task_del_by_context(client->schedule, session);
-
-  switch (status) {
-  case SILC_CLIENT_CONN_SUCCESS:
-    SILC_LOG_DEBUG(("Connected, conn %p", conn));
-
-    /* Wrap the connection packet stream */
-    session->stream = silc_packet_stream_wrap(conn->stream, SILC_PACKET_FTP,
-                                             0, FALSE,
-                                             silc_client_ftp_coder, session);
-    if (!session->stream) {
-      /* Call monitor callback */
-      if (session->monitor)
-       (*session->monitor)(session->client, session->conn,
-                           SILC_CLIENT_FILE_MONITOR_ERROR,
-                           SILC_CLIENT_FILE_ERROR, 0, 0,
-                           session->client_entry, session->session_id,
-                           session->filepath, session->monitor_context);
-      silc_client_close_connection(client, conn);
-      session->conn = NULL;
-      return;
-    }
-
-    if (!session->initiator) {
-      /* If we are the SFTP client then start the SFTP session and retrieve
-        the info about the file available for download. */
-      session->sftp = silc_sftp_client_start(session->stream,
-                                            conn->internal->schedule,
-                                            silc_client_ftp_version,
-                                            silc_client_ftp_error, session);
-    } else {
-      /* Start SFTP server */
-      session->sftp = silc_sftp_server_start(session->stream,
-                                            conn->internal->schedule,
-                                            silc_client_ftp_error, session,
-                                            session->fs);
-
-      /* Monitor transmission */
-      silc_sftp_server_set_monitor(session->sftp, SILC_SFTP_MONITOR_READ,
-                                  silc_client_ftp_monitor, session);
-    }
-
-    break;
-
-  case SILC_CLIENT_CONN_DISCONNECTED:
-    SILC_LOG_DEBUG(("Disconnected %p", conn));
-
-    /* Call monitor callback */
-    if (session->monitor)
-      (*session->monitor)(session->client, session->conn,
-                         SILC_CLIENT_FILE_MONITOR_DISCONNECT,
-                         SILC_CLIENT_FILE_ERROR, 0, 0,
-                         session->client_entry, session->session_id,
-                         session->filepath, session->monitor_context);
-
-    /* Connection already closed */
-    session->conn = NULL;
-
-    /* If closed by user, destroy the session now */
-    if (session->closed)
-      silc_client_ftp_session_free(session);
-    break;
-
-  case SILC_CLIENT_CONN_ERROR_TIMEOUT:
-    SILC_LOG_DEBUG(("Connecting timeout"));
-
-    /* Call monitor callback */
-    if (session->monitor)
-      (*session->monitor)(session->client, session->conn,
-                         SILC_CLIENT_FILE_MONITOR_ERROR,
-                         SILC_CLIENT_FILE_TIMEOUT, 0, 0,
-                         session->client_entry, session->session_id,
-                         session->filepath, session->monitor_context);
-
-    /* Connection already closed */
-    session->conn = NULL;
-    break;
-
-  default:
-    SILC_LOG_DEBUG(("Connecting error %d", status));
-
-    /* Call monitor callback */
-    if (session->monitor)
-      (*session->monitor)(session->client, session->conn,
-                         SILC_CLIENT_FILE_MONITOR_ERROR,
-                         status != SILC_CLIENT_CONN_ERROR ?
-                         SILC_CLIENT_FILE_KEY_AGREEMENT_FAILED :
-                         SILC_CLIENT_FILE_CONNECT_FAILED, 0, 0,
-                         session->client_entry, session->session_id,
-                         session->filepath, session->monitor_context);
-
-    /* Connection already closed */
-    session->conn = NULL;
-    break;
-  }
-}
-
-/*************************** File Transfer API ******************************/
-
-/* Free all file transfer sessions. */
-
-void silc_client_ftp_free_sessions(SilcClient client)
-{
-  SilcClientFtpSession session;
-
-  if (!client->internal->ftp_sessions)
-    return;
-
-  silc_dlist_start(client->internal->ftp_sessions);
-  while ((session = silc_dlist_get(client->internal->ftp_sessions)))
-    silc_client_ftp_session_free(session);
-  silc_dlist_del(client->internal->ftp_sessions, session);
-}
-
-/* Free file transfer session by client entry. */
-
-void silc_client_ftp_session_free_client(SilcClient client,
-                                        SilcClientEntry client_entry)
-{
-  SilcClientFtpSession session;
-
-  if (!client->internal->ftp_sessions)
-    return;
-
-  /* Get the session */
-  silc_dlist_start(client->internal->ftp_sessions);
-  while ((session = silc_dlist_get(client->internal->ftp_sessions)))
-    if (session->client_entry == client_entry)
-      silc_client_ftp_session_free(session);
-}
-
-/* Sends a file indicated by the `filepath' to the remote client
-   indicated by the `client_entry'.  This will negotiate a secret key
-   with the remote client before actually starting the transmission of
-   the file.  The `monitor' callback will be called to monitor the
-   transmission of the file. */
-
-SilcClientFileError
-silc_client_file_send(SilcClient client,
-                     SilcClientConnection conn,
-                     SilcClientEntry client_entry,
-                     SilcClientConnectionParams *params,
-                     SilcPublicKey public_key,
-                     SilcPrivateKey private_key,
-                     SilcClientFileMonitor monitor,
-                     void *monitor_context,
-                     const char *filepath,
-                     SilcUInt32 *session_id)
-{
-  SilcClientFtpSession session;
-  SilcBuffer keyagr;
-  char *filename, *path;
-  int fd;
-
-  SILC_LOG_DEBUG(("File send request (file: %s)", filepath));
-
-  if (!client || !client_entry || !filepath || !params ||
-      !public_key || !private_key)
-    return SILC_CLIENT_FILE_ERROR;
-
-  /* Check for existing session for `filepath'. */
-  silc_dlist_start(client->internal->ftp_sessions);
-  while ((session = silc_dlist_get(client->internal->ftp_sessions))) {
-    if (session->filepath && !strcmp(session->filepath, filepath) &&
-       session->client_entry == client_entry)
-      return SILC_CLIENT_FILE_ALREADY_STARTED;
-  }
-
-  /* See whether the file exists and can be opened */
-  fd = silc_file_open(filepath, O_RDONLY);
-  if (fd < 0)
-    return SILC_CLIENT_FILE_NO_SUCH_FILE;
-  silc_file_close(fd);
-
-  /* Add new session */
-  session = silc_calloc(1, sizeof(*session));
-  if (!session)
-    return SILC_CLIENT_FILE_ERROR;
-  session->session_id = ++client->internal->next_session_id;
-  session->client = client;
-  session->server_conn = conn;
-  session->initiator = TRUE;
-  session->client_entry = silc_client_ref_client(client, conn, client_entry);
-  session->monitor = monitor;
-  session->monitor_context = monitor_context;
-  session->filepath = strdup(filepath);
-  session->params = *params;
-  session->public_key = public_key;
-  session->private_key = private_key;
-
-  if (silc_asprintf(&path, "file://%s", filepath) < 0) {
-    silc_free(session);
-    return SILC_CLIENT_FILE_NO_MEMORY;
-  }
-
-  /* Allocate memory filesystem and put the file to it */
-  if (strrchr(path, '/'))
-    filename = strrchr(path, '/') + 1;
-  else
-    filename = (char *)path;
-  session->fs = silc_sftp_fs_memory_alloc(SILC_SFTP_FS_PERM_READ |
-                                         SILC_SFTP_FS_PERM_EXEC);
-  silc_sftp_fs_memory_add_file(session->fs, NULL, SILC_SFTP_FS_PERM_READ,
-                              filename, path);
-
-  session->filesize = silc_file_size(filepath);
-
-  /* If local IP is provided, create listener for incoming key exchange */
-  if (params->local_ip || params->bind_ip) {
-    session->listener =
-      silc_client_listener_add(client,
-                              conn->internal->schedule,
-                              params, public_key, private_key,
-                              silc_client_ftp_connect_completion,
-                              session);
-    if (!session->listener) {
-      client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
-                                "Cannot create listener for file transfer: "
-                                "%s", strerror(errno));
-      silc_free(session);
-      return SILC_CLIENT_FILE_NO_MEMORY;
-    }
-
-    session->hostname = (params->bind_ip ? strdup(params->bind_ip) :
-                        strdup(params->local_ip));
-    session->port = silc_client_listener_get_local_port(session->listener);
-  }
-
-  SILC_LOG_DEBUG(("Sending key agreement for file transfer"));
-
-  /* Send the key agreement inside FTP packet */
-  keyagr = silc_key_agreement_payload_encode(session->hostname, 0,
-                                            session->port);
-  if (!keyagr) {
-    if (session->listener)
-      silc_client_listener_free(session->listener);
-    silc_free(session);
-    return SILC_CLIENT_FILE_NO_MEMORY;
-  }
-  silc_packet_send_va_ext(conn->stream, SILC_PACKET_FTP, 0, 0, NULL,
-                         SILC_ID_CLIENT, &client_entry->id, NULL, NULL,
-                         SILC_STR_UI_CHAR(1),
-                         SILC_STR_DATA(silc_buffer_data(keyagr),
-                                       silc_buffer_len(keyagr)),
-                         SILC_STR_END);
-
-  silc_buffer_free(keyagr);
-  silc_free(path);
-
-  silc_dlist_add(client->internal->ftp_sessions, session);
-  if (session_id)
-    *session_id = session->session_id;
-
-  /* Add session request timeout */
-  if (params && params->timeout_secs)
-    silc_schedule_task_add_timeout(client->schedule,
-                                  silc_client_ftp_timeout, session,
-                                  params->timeout_secs, 0);
-
-  return SILC_CLIENT_FILE_OK;
-}
-
-/* Receives a file from a client indicated by the `client_entry'.  The
-   `session_id' indicates the file transmission session and it has been
-   received in the `ftp' client operation function.  This will actually
-   perform the key agreement protocol with the remote client before
-   actually starting the file transmission.  The `monitor' callback
-   will be called to monitor the transmission. */
-
-SilcClientFileError
-silc_client_file_receive(SilcClient client,
-                        SilcClientConnection conn,
-                        SilcClientConnectionParams *params,
-                        SilcPublicKey public_key,
-                        SilcPrivateKey private_key,
-                        SilcClientFileMonitor monitor,
-                        void *monitor_context,
-                        const char *path,
-                        SilcUInt32 session_id,
-                        SilcClientFileAskName ask_name,
-                        void *ask_name_context)
-{
-  SilcClientFtpSession session;
-  SilcBuffer keyagr;
-
-  if (!client || !conn)
-    return SILC_CLIENT_FILE_ERROR;
-
-  SILC_LOG_DEBUG(("Start, Session ID: %d", session_id));
-
-  /* Get the session */
-  silc_dlist_start(client->internal->ftp_sessions);
-  while ((session = silc_dlist_get(client->internal->ftp_sessions))
-        != SILC_LIST_END) {
-    if (session->session_id == session_id) {
-      break;
-    }
-  }
-
-  if (session == SILC_LIST_END) {
-    SILC_LOG_DEBUG(("Unknown session ID: %d\n", session_id));
-    return SILC_CLIENT_FILE_UNKNOWN_SESSION;
-  }
-
-  /* See if we have this session running already */
-  if (session->sftp || session->listener) {
-    SILC_LOG_DEBUG(("Session already started"));
-    return SILC_CLIENT_FILE_ALREADY_STARTED;
-  }
-
-  session->monitor = monitor;
-  session->monitor_context = monitor_context;
-  session->ask_name = ask_name;
-  session->ask_name_context = ask_name_context;
-  session->path = path ? strdup(path) : NULL;
-
-  /* If the hostname and port already exists then the remote client did
-     provide the connection point to us and we won't create listener, but
-     create the connection ourselves. */
-  if (session->hostname && session->port) {
-    SILC_LOG_DEBUG(("Connecting to remote client"));
-    /* Connect to the remote client.  Performs key exchange automatically. */
-    session->op =
-      silc_client_connect_to_client(client, params, public_key, private_key,
-                                   session->hostname, session->port,
-                                   silc_client_ftp_connect_completion,
-                                   session);
-    if (!session->op) {
-      silc_free(session);
-      return SILC_CLIENT_FILE_ERROR;
-    }
-  } else {
-    /* Add the listener for the key agreement */
-    SILC_LOG_DEBUG(("Creating listener for file transfer"));
-    if (!params || (!params->local_ip && !params->bind_ip)) {
-      session->client->internal->ops->say(session->client, session->conn,
-                                         SILC_CLIENT_MESSAGE_ERROR,
-                                         "Cannot create listener for file "
-                                         "transfer; IP address and/or port "
-                                         "not provided");
-      silc_free(session);
-      return SILC_CLIENT_FILE_ERROR;
-    }
-    session->listener =
-      silc_client_listener_add(client, conn->internal->schedule, params,
-                              public_key, private_key,
-                              silc_client_ftp_connect_completion,
-                              session);
-    if (!session->listener) {
-      client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
-                                "Cannot create listener for file transfer: "
-                                "%s", strerror(errno));
-      silc_free(session);
-      return SILC_CLIENT_FILE_NO_MEMORY;
-    }
-    session->hostname = (params->bind_ip ? strdup(params->bind_ip) :
-                        strdup(params->local_ip));
-    session->port = silc_client_listener_get_local_port(session->listener);
-
-    /* Send the key agreement inside FTP packet */
-    SILC_LOG_DEBUG(("Sending key agreement for file transfer"));
-    keyagr = silc_key_agreement_payload_encode(session->hostname, 0,
-                                              session->port);
-    if (!keyagr) {
-      silc_client_listener_free(session->listener);
-      silc_free(session);
-      return SILC_CLIENT_FILE_NO_MEMORY;
-    }
-    silc_packet_send_va_ext(conn->stream, SILC_PACKET_FTP, 0, 0, NULL,
-                           SILC_ID_CLIENT, &session->client_entry->id,
-                           NULL, NULL,
-                           SILC_STR_UI_CHAR(1),
-                           SILC_STR_DATA(silc_buffer_data(keyagr),
-                                         silc_buffer_len(keyagr)),
-                           SILC_STR_END);
-    silc_buffer_free(keyagr);
-
-    /* Add session request timeout */
-    if (params && params->timeout_secs)
-      silc_schedule_task_add_timeout(client->schedule,
-                                    silc_client_ftp_timeout, session,
-                                    params->timeout_secs, 0);
-  }
-
-  return SILC_CLIENT_FILE_OK;
-}
-
-/* Closes file transmission session indicated by the `session_id'.
-   If file transmission is being conducted it will be aborted
-   automatically. This function is also used to close the session
-   after successful file transmission. This function can be used
-   also to reject incoming file transmission request. */
-
-SilcClientFileError silc_client_file_close(SilcClient client,
-                                          SilcClientConnection conn,
-                                          SilcUInt32 session_id)
-{
-  SilcClientFtpSession session;
-
-  if (!client || !conn)
-    return SILC_CLIENT_FILE_ERROR;
-
-  SILC_LOG_DEBUG(("Closing file transer session %d", session_id));
-
-  /* Get the session */
-  silc_dlist_start(client->internal->ftp_sessions);
-  while ((session = silc_dlist_get(client->internal->ftp_sessions))
-        != SILC_LIST_END) {
-    if (session->session_id == session_id)
-      break;
-  }
-
-  if (session == SILC_LIST_END) {
-    SILC_LOG_DEBUG(("Unknown session ID: %d\n", session_id));
-    return SILC_CLIENT_FILE_UNKNOWN_SESSION;
-  }
-
-  if (session->monitor) {
-    (*session->monitor)(session->client, session->conn,
-                       SILC_CLIENT_FILE_MONITOR_CLOSED,
-                       SILC_CLIENT_FILE_OK, 0, 0,
-                       session->client_entry, session->session_id,
-                       session->filepath, session->monitor_context);
-
-    /* No more callbacks to application */
-    session->monitor = NULL;
-  }
-
-  silc_schedule_task_del_by_context(client->schedule, session);
-
-  session->closed = TRUE;
-
-  /* Destroy via timeout */
-  silc_schedule_task_add_timeout(conn->internal->schedule,
-                                silc_client_file_close_final, session,
-                                0, 1);
-
-  return SILC_CLIENT_FILE_OK;
-}
-
-/************************** FTP Request Processing **************************/
-
-/* Received file transfer packet.  Only file transfer requests get here.
-   The actual file transfer is handled by the SFTP library when we give it
-   the packet stream wrapped into SilcStream context. */
-
-SILC_FSM_STATE(silc_client_ftp)
-{
-  SilcClientConnection conn = fsm_context;
-  SilcClient client = conn->client;
-  SilcPacket packet = state_context;
-  SilcClientFtpSession session;
-  SilcClientID remote_id;
-  SilcClientEntry remote_client;
-  SilcKeyAgreementPayload payload = NULL;
-  char *hostname;
-  SilcUInt16 port;
-
-  SILC_LOG_DEBUG(("Process file transfer packet"));
-
-  if (silc_buffer_len(&packet->buffer) < 1)
-    goto out;
-
-  /* We support file transfer type number 1 (== SFTP) */
-  if (packet->buffer.data[0] != 0x01) {
-    SILC_LOG_DEBUG(("Unsupported file transfer type %d",
-                   packet->buffer.data[0]));
-    goto out;
-  }
-
-  if (!silc_id_str2id(packet->src_id, packet->src_id_len,
-                     SILC_ID_CLIENT, &remote_id, sizeof(remote_id))) {
-    SILC_LOG_DEBUG(("Invalid client ID"));
-    goto out;
-  }
-
-  /* Check whether we know this client already */
-  remote_client = silc_client_get_client_by_id(client, conn, &remote_id);
-  if (!remote_client || !remote_client->internal.valid) {
-    /** Resolve client info */
-    silc_client_unref_client(client, conn, remote_client);
-    SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
-                                        client, conn, &remote_id, NULL,
-                                        silc_client_ftp_client_resolved,
-                                        fsm));
-    /* NOT REACHED */
-  }
-
-  /* Get session */
-  silc_dlist_start(client->internal->ftp_sessions);
-  while ((session = silc_dlist_get(client->internal->ftp_sessions))) {
-    if (session->client_entry == remote_client &&
-       (!session->initiator || !session->listener))
-      break;
-  }
-
-  /* Parse the key agreement payload */
-  payload =
-    silc_key_agreement_payload_parse(silc_buffer_data(&packet->buffer) + 1,
-                                    silc_buffer_len(&packet->buffer) - 1);
-  if (!payload) {
-    SILC_LOG_DEBUG(("Invalid key agreement payload"));
-    goto out;
-  }
-
-  hostname = silc_key_agreement_get_hostname(payload);
-  port = silc_key_agreement_get_port(payload);
-  if (!hostname || !port) {
-    hostname = NULL;
-    port = 0;
-  }
-
-  /* If session doesn't exist, we create new one.  If session exists, but
-     we are responder it means that the remote sent another request and user
-     hasn't even accepted the first one yet.  We assume this session is new
-     session as well. */
-  if (!session || !hostname || !session->initiator) {
-    /* New file transfer session */
-    SILC_LOG_DEBUG(("New file transfer session %d",
-                   client->internal->next_session_id + 1));
-
-    session = silc_calloc(1, sizeof(*session));
-    if (!session)
-      goto out;
-    session->session_id = ++client->internal->next_session_id;
-    session->client = client;
-    session->server_conn = conn;
-    session->client_entry = silc_client_ref_client(client, conn,
-                                                  remote_client);
-    if (hostname && port) {
-      session->hostname = strdup(hostname);
-      session->port = port;
-    }
-    silc_dlist_add(client->internal->ftp_sessions, session);
-
-    /* Notify application of incoming FTP request */
-    client->internal->ops->ftp(client, conn, remote_client,
-                              session->session_id, hostname, port);
-    goto out;
-  }
-
-  /* Session exists, continue with key agreement protocol. */
-  SILC_LOG_DEBUG(("Session %d exists, connecting to remote client",
-                 session->session_id));
-
-  session->hostname = strdup(hostname);
-  session->port = port;
-
-  /* Connect to the remote client.  Performs key exchange automatically. */
-  session->op =
-    silc_client_connect_to_client(client, &session->params,
-                                 session->public_key, session->private_key,
-                                 session->hostname, session->port,
-                                 silc_client_ftp_connect_completion,
-                                 session);
-  if (!session->op) {
-    /* Call monitor callback */
-    if (session->monitor)
-      (*session->monitor)(session->client, session->conn,
-                         SILC_CLIENT_FILE_MONITOR_ERROR,
-                         SILC_CLIENT_FILE_ERROR, 0, 0,
-                         session->client_entry, session->session_id,
-                         session->filepath, session->monitor_context);
-  }
-
- out:
-  if (payload)
-    silc_key_agreement_payload_free(payload);
-  silc_packet_free(packet);
-  return SILC_FSM_FINISH;
-}