/*
    cssh - cluster secure shell
    Copyright (C) 2015-2026  Andreas Baumann

    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 3 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.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef _COPY_COMMON_HEADER_INCLUDED
#define _COPY_COMMON_HEADER_INCLUDED

#include <libssh/libssh.h>

#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>

#include "progressbar.h"

typedef enum copy_direction_e {
	CSSH_COPY_DIRECTION_UPLOAD,
	CSSH_COPY_DIRECTION_DOWNLOAD
} copy_direction_e;

// used only by the SSH exec/CLI mode in cssh.c, kept here so 'finalize'
// can be shared by that mode and both copy engines without a void *
typedef struct ssh_data_t {
	ssh_channel channel;
	char *stdout_buf;
	char *stdout_bptr;
	char *stderr_buf;
	char *stderr_bptr;
	bool eof_sent;
	bool is_eof;
} ssh_data_t;

// protocol-neutral "virtual current directory" stack, used to reconstruct
// the local (download) or remote (upload) directory being worked on while
// walking a recursive tree that is delivered/consumed as a flat stream of
// enter/leave events rather than as real filesystem recursion
typedef struct dir_stack_entry_t {
	char *dir;
	struct dir_stack_entry_t *next;
} dir_stack_entry_t;

typedef struct dir_stack_t {
	struct dir_stack_entry_t *head;
} dir_stack_t;

void create_dir_stack( dir_stack_t *stack );
int push_dir_stack( dir_stack_t *stack, const char *dir );
void pop_dir_stack( dir_stack_t *stack );
char *top_dir_stack( dir_stack_t *stack );
void free_dir_stack( dir_stack_t *stack );

// small path helpers shared by both engines
char *join_path( const char *dir, const char *name );
bool is_directory( const char *path );
char *path_basename( const char *path );

// iterative walk over a local filesystem tree, used by both engines' upload
// side. Symlinks are skipped with a WARNING, never followed, so both engines
// behave identically (the legacy scp wire protocol has no symlink primitive
// at all, only sftp does).
typedef enum walk_event_type_e {
	CSSH_WALK_ENTER_DIR,
	CSSH_WALK_LEAVE_DIR,
	CSSH_WALK_FILE
} walk_event_type_e;

typedef struct walk_event_t {
	walk_event_type_e type;
	char *name;       // basename of the entry
	char *full_path;  // full local filesystem path of the entry
	mode_t mode;      // permission bits only (mode & 07777)
	uint64_t size;    // valid for CSSH_WALK_FILE only
} walk_event_t;

typedef struct local_walk_t local_walk_t;

// 'root_path' may be a plain file (recursive is then irrelevant) or a
// directory (recursive must be true, checked by the caller beforehand)
local_walk_t *walk_local_tree_open( const char *root_path, bool recursive );

// returns 1 and fills 'event' when an event was produced, 0 when the walk
// is exhausted, -1 on a fatal I/O error (partial/skippable errors are
// logged as WARNING and simply produce the next event instead)
int walk_local_tree_next( local_walk_t *walk, walk_event_t *event );

void free_walk_event( walk_event_t *event );
void walk_local_tree_close( local_walk_t *walk );

// prints "done: <path> (<size>) [<host>]" to stderr; called by both copy
// engines when a single file's transfer completes and progress bars are
// enabled, so completed transfers leave a permanent trace once their bar
// is removed from the pool
void print_transfer_done( const char *host, const char *path, uint64_t size );

// makes 'local_directory' (as parsed from the cscp command line) the
// download destination: chdir()s into it (creating it first if needed).
// A NULL/empty/"." local_directory is a no-op (download stays in cwd).
// Returns 0 on success, -1 on failure (already reported via fprintf).
int resolve_local_download_root( const char *local_directory );

// shared cleanup for all execution modes; ssh_data is non-NULL only for
// the SSH exec/CLI mode, pool is non-NULL only for the copy engines
void cssh_finalize( ssh_session **session, ssh_data_t **ssh_data, char **host, unsigned int *port,
	const unsigned int nof_sessions, bool verbose, cssh_progressbar_pool_t *pool );

#endif
