/*
  sshfilecopy.h

  Author: Sami Lehtinen <sjl@ssh.fi>

  Copyright (C) 1999-2000 SSH Communications Security Oy, Espoo, Finland
  All rights reserved.

  Functions common for both scp and sftp.
 */

#ifndef SSHFILECOPY_H
#define SSHFILECOPY_H

#include "sshfilexfer.h"
#include "sshdllist.h"
#include "sshoperation.h"

typedef struct SshFileCopyConnectionRec *SshFileCopyConnection;
typedef struct SshFileCopyFileRec *SshFileCopyFile;
typedef struct SshFileCopyLocationRec *SshFileCopyLocation;
typedef struct SshFileCopyFileListItemRec *SshFileCopyFileListItem;

/* Record that holds the parameters needed to make a connection. */
struct SshFileCopyConnectionRec
{
  char *user;
  char *host;
  char *port;
  SshFileClient client;
};

/* Return values for SshFileCopy functions. */
typedef enum
{
  /* operation was successful.*/
  SSH_FC_OK,
  /* operation resulted in an undetermined error within sshfilecopy. */
  SSH_FC_ERROR,
  /* Destination is not directory, but it should be. */
  SSH_FC_ERROR_DEST_NOT_DIR,
  /* Maximum symlink level exceeded. */
  SSH_FC_ERROR_ELOOP,
  /* Connecting to host failed. */
  SSH_FC_ERROR_CONNECTION_FAILED,
  /* Connection broke for some reason. */
  SSH_FC_ERROR_CONNECTION_LOST,
  /* File doesn't exist. */
  SSH_FC_ERROR_NO_SUCH_FILE,
  /* No permission to access file. */
  SSH_FC_ERROR_PERMISSION_DENIED,
  /* Undetermined error from sshfilexfer. */
  SSH_FC_ERROR_FAILURE,
  /* File transfer protocol mismatch. */
  SSH_FC_ERROR_PROTOCOL_MISMATCH
} SshFileCopyError;

typedef struct 
{
  SshFileCopyError error;
  char *error_name;
} SshFileCopyErrorName;

extern SshFileCopyErrorName ssh_file_copy_errors[];
  
/*****************************************************************************
 * Generic functions
 *****************************************************************************/

/* Get basedir from 'filename'. 'filename' may contain wildcards and
   escapes. Only the most basic directory is returned, so the returned
   directory will not contain wildcards. A returned empty string will
   indicate that the 'filename' is as basic as it gets. This need not
   be checked, however, as then 'return_filename' will contain the
   whole filename. 'return_filename' will contain the rest of the
   filename. This function never fails.

   Example:

   'filename' ssh/ssh-2*12/foobar

   returned basedir will be "ssh"
   'return_filename' will be "ssh-2*12/foobar"
   
*/
char *ssh_file_copy_get_basedir(const char *filename,
                                char **return_filename);

/* Removes escape characters before slashes ('\/' and the
   like). Returns a newly mallocated stripped string.*/
char *ssh_file_copy_strip_escapes_before_slashes(const char *filename);

/* Removes extra slashes ('//' and the like) from filename. This also
   does the strip_escapes_before_slashes (those could be used to fool
   this). Returns a newly mallocated stripped string. */
char *ssh_file_copy_strip_extra_slashes(const char *filename);

/* Strip foo/../bar/../ combinations from filename to prevent
   malicious, or misguided, users from trashing some systems, and
   bringing the load up in others. This does also the
   strip_extra_slashes (those could be used to fool this). Returns a
   newly mallocated stripped string. */
char *ssh_file_copy_strip_dot_dots(const char *filename);

/*****************************************************************************
 * SshFileCopyFile structure manipulating functions.
 *****************************************************************************/

/* Allocate a new SshFileCopyFile structure. */
SshFileCopyFile ssh_file_copy_file_allocate(void);

/* Destroy SshFileCopyFile structure. This should be of type
   SshAppListNodeDeleteProc, because it used to destroy list items.*/
void ssh_file_copy_file_destroy(void *item);

/* Registers a filename to a SshFileCopyFile structure. The filename
   is not copied to the struct, it's pointer is just registered. So it
   shouldn't be freed by itself. Use ssh_file_copy_file_destroy()
   instead. It is legal to call this functions multiple times for a
   single SshFileCopyFile structure _before_ it is used in any
   transfers. */
void ssh_file_copy_file_register_filename(SshFileCopyFile file, char *name);

/* Get the attributes struct of a SshFileCopyFile structure. If file
   has no attributes (it's not statted yet) returns NULL. */
const SshFileAttributes
ssh_file_copy_file_get_attributes(SshFileCopyFile file);

/* Get filename from a SshFileCopyFile structure. */
const char *ssh_file_copy_file_get_name(SshFileCopyFile file);

/* Get long filename from a SshFileCopyFile structure. (It could very
   well be NULL) */
const char *ssh_file_copy_file_get_long_name(SshFileCopyFile file);

/* Internal functions to SshFileCopy, don't use these directly. */

/* Duplicate a SshFileCopyFile structure. Notice, however, that if the
   file had bee opened in the original struct, it will be closed now
   (ie. the SshFileHandle is NULL in the copy). */
SshFileCopyFile ssh_file_copy_file_dup(SshFileCopyFile file);

/* Registers a long filename to a SshFileCopyFile structure. The filename
   is not copied to the struct, it's pointer is just registered. So it
   shouldn't be freed by itself. Use ssh_file_copy_file_destroy()
   instead. */
void ssh_file_copy_file_register_long_name(SshFileCopyFile file,
                                           char *long_name);

/* Register the attributes struct of a SshFileCopyFile structure. The
   attrs are not copied to the struct, the pointer is just
   registered. So the attrs shouldn't be freed by themselves. Use
   ssh_file_copy_file_destroy() instead.*/
void ssh_file_copy_file_register_attributes(SshFileCopyFile file,
                                            SshFileAttributes attrs);

/*****************************************************************************
 * SshFileCopyConnection structure manipulating functions.
 *****************************************************************************/

/* Allocate a new SshFileCopyConnection structure. */
SshFileCopyConnection ssh_file_copy_connection_allocate(void);

/* Free a SshFileCopyConnection-structure. */
void ssh_file_copy_connection_destroy(SshFileCopyConnection connection);

/* Compare whether two SshFileCopyConnection structures are
   identical. Note that the 'client' part is not compared. Return TRUE
   if these match, or FALSE if not. Both arguments must be valid. */
Boolean ssh_file_copy_connection_compare(SshFileCopyConnection conn1,
                                         SshFileCopyConnection conn2);

/*****************************************************************************
 * SshFileCopyLocation structure manipulating functions.
 *****************************************************************************/

/* Allocate a new SshFileCopyLocation structure. If 'source' is TRUE,
   this structure is used to represent the source file(s). Otherwise
   this is a destination location. */
SshFileCopyLocation ssh_file_copy_location_allocate(Boolean source);

/* Destroy a SshFileCopyLocation structure.*/
void ssh_file_copy_location_destroy(SshFileCopyLocation location);

/* Add a filename to 'location->file_list' and/or 'location->file',
   depending on whether 'location' is source or destination. Only
   tranformation that is done is stripping unnecessary slashes, and
   escape characters before slashes and stripping of 'foo/../'
   constrcuts. 'filename' is copied to the struct. Returned
   SshFileCopyFile can be used to add things to the structure;
   ie. like file attributes etc. */
SshFileCopyFile
ssh_file_copy_location_add_raw_file(SshFileCopyLocation location,
                                    const char *filename);

/* Add a file to a SshFileCopyLocation structure. If this is done more
   than once to a destination file structure, the former filename gets
   freed and overwritten. The filename can contain escapes, as these
   are treated internally in sshfilecopy.c. 'filename' is copied to
   the struct. 'attrs' contains the files attributes. If it is NULL,
   the file is considered "raw", and if location->file is empty, the
   location is marked raw. (which means, that during copying it is
   checked) */
void ssh_file_copy_location_add_file(SshFileCopyLocation location,
                                     SshFileAttributes attrs,
                                     const char *filename);

typedef void (*SshFileCopyFileListMapCarFunc)(SshFileCopyFile file,
                                              void *context);

void ssh_file_copy_file_list_mapcar(SshDlList file_list,
                                    SshFileCopyFileListMapCarFunc func,
                                    void *context);

/*****************************************************************************
 * SshFileCopyFileListItem structure manipulating functions.
 *****************************************************************************/

/* Allocate a new SshFileCopyFileListItem item. */
SshFileCopyFileListItem ssh_file_copy_file_list_item_allocate(void);

/* Destroy a SshFileCopyFileListItem item. */
void ssh_file_copy_file_list_item_destroy(SshFileCopyFileListItem item);

/* Destroy an entire SshFileCopyFileListItem list. */
void ssh_file_copy_file_list_destroy(SshDlList list);

/* Get a filename from the list item. */
unsigned char *ssh_file_copy_file_list_item_get_name(SshFileCopyFileListItem item);

/*****************************************************************************
 * File transfer functions.
 *****************************************************************************/

/* Callback, which will be called when connection is done. If 'stream'
   is NULL, connection was failed. */
typedef void (*SshFileCopyStreamReturnCB)(SshStream stream,
                                          void *context);

/* This callback is used to make the connection to the remote
   host. The stream is later wrapped to a SshFileClient, so it should
   not be used outside SshFileCopy. */
typedef void (*SshFileCopyConnectCallback)
     (SshFileCopyConnection connection, void *context,
      SshFileCopyStreamReturnCB completion_cb,
      void *completion_context);

/* Register a callback, which is used to connect to the remote host by
   SshFileCopy. 'context' is given to the callback as an
   argument. This _must_ be called before using the other functions
   (which require the ability to form connections). */
void ssh_file_copy_register_connect_callback(SshFileCopyConnectCallback
                                             callback,
                                             void *context);

/* Attributes, which control how the globbing is done. */
typedef struct SshFileCopyGlobAttrsRec
{
  /* Currently empty. Will be used in the future, possibly for
     following symlinks etc. etc. */
  int dummy;
} *SshFileCopyGlobAttrs;

typedef void (*SshFileCopyGlobReadyCallback)(SshFileCopyError error,
                                             const char *error_message,
                                             SshFileCopyConnection
                                             connection,
                                             /* List of items of type
                                                SshFileCopyFileListItem. */
                                             SshDlList file_list,
                                             void *context);

typedef void (*SshFileCopyGlobErrorCallback)(SshFileCopyError error,
                                             const char *error_message,
                                             void *context);

void ssh_file_copy_glob(SshFileCopyConnection connection,
                        SshFileCopyLocation orig_location,
                        SshFileCopyGlobAttrs attrs,
                        SshFileCopyGlobReadyCallback ready_cb,
                        SshFileCopyGlobErrorCallback error_cb,
                        void *context);

/* Attributes, which control how the directory recursion is done. */
typedef struct SshFileCopyRecurseAttrsRec
{
  /* If TRUE, ssh_file_copy_recurse_dirs() tries it's best to follow
     symlinks. */
  Boolean follow_symlinks;  
} *SshFileCopyRecurseAttrs;

/* If not NULL, called for each file and directory. If file is not
   directory, files are not returned in the file_list in the
   ready_cb. Instead, this func can do whatever it likes with them. In
   this case SshFileCopy ignores the return value. If the file is a
   directory, then the return value is used to determine whether that
   directory will be recursed. */
typedef Boolean (*SshFileCopyRecurseFileFunc)(const char *filename,
                                              const char *long_name,
                                              SshFileAttributes
                                              file_attributes,
                                              SshFileCopyRecurseAttrs attrs,
                                              void *context);

typedef void (*SshFileCopyRecurseReadyCallback)(SshFileCopyError error,
                                                const char *error_message,
                                                SshFileCopyConnection
                                                connection,
                                                /* List of items of type
                                                   SshFileCopyFileListItem. */
                                                SshDlList file_list,
                                                void *context);

typedef void (*SshFileCopyRecurseErrorCallback)(SshFileCopyError error,
                                                const char *error_message,
                                                void *context);

void ssh_file_copy_recurse_dirs(SshFileCopyConnection source,
                                SshDlList file_list,
                                SshFileCopyRecurseAttrs attrs,
                                SshFileCopyRecurseFileFunc func,
                                SshFileCopyRecurseReadyCallback ready_cb,
                                SshFileCopyRecurseErrorCallback error_cb,
                                void *context);

typedef void (*SshFileCopyTransferReadyCallback)(SshFileCopyError error,
                                                 const char *error_message,
                                                 void *context);

typedef void (*SshFileCopyTransferErrorCallback)(SshFileCopyError error,
                                                 const char *error_message,
                                                 void *context);

typedef void (*SshFileCopyTransferProgressCallback)
     (SshFileCopyConnection source,
      SshFileCopyFile source_file,
      SshFileCopyConnection dest,
      SshFileCopyFile dest_file,
      off_t read_bytes,
      off_t written_bytes,
      SshUInt64 elapsed_time,
      void *context);

typedef void (*SshFileCopyTransferAbortNotifyCallback)(void *context);

/* Attributes, which control how the transfer is done. */
typedef struct SshFileCopyTransferAttrsRec
{
  Boolean destination_must_be_dir;
  Boolean preserve_attributes;
  Boolean unlink_source;
  Boolean recurse_dirs;
} *SshFileCopyTransferAttrs;

SshOperationHandle
ssh_file_copy_transfer_files (SshFileCopyConnection source,
                              SshDlList file_list,
                              SshFileCopyConnection destination,
                              SshFileCopyLocation dest_location,
                              SshFileCopyTransferAttrs attrs,
                              SshFileCopyTransferReadyCallback ready_cb,
                              SshFileCopyTransferErrorCallback error_cb,
                              SshFileCopyTransferProgressCallback
                              progress_cb,
                              SshFileCopyTransferAbortNotifyCallback
                              abort_notify_cb,
                              void *context);

/* Internal definitions. Don't call these directly. */

/* Callback, which will be called when connection is done, and the
   stream is wrapped. NULL is returned, if connection failed. */
typedef void (*SshFileCopyConnectCompleteCB)(SshFileClient client,
                                             void *context);
/* Make a connection to the remote host, or, if 'host' is NULL,
   create streampair for local action. */
SshOperationHandle
ssh_file_copy_connect(SshFileCopyConnection connection,
                      SshFileCopyConnectCompleteCB completion_cb,
                      void *completion_context);

#endif /* SSHFILECOPY_H */
