/* Manage an ftp connection Copyright (C) 1997,2001,02 Free Software Foundation, Inc. Written by Miles Bader This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, 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, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __FTPCONN_H__ #define __FTPCONN_H__ #include #include #include #include #include #define __need_error_t #include #ifndef __error_t_defined typedef int error_t; #define __error_t_defined #endif #ifndef FTP_CONN_EI # define FTP_CONN_EI extern inline #endif struct ftp_conn; struct ftp_conn_params; struct ftp_conn_stat; /* The type of the function called by ...get_stats to add each new stat. NAME is the file in question, STAT is stat info about it, and if NAME is a symlink, SYMLINK_TARGET is what it is linked to, or 0 if it's not a symlink. NAME and SYMLINK_TARGET should be copied if they are used outside of this function. HOOK is as passed into ...get_stats. */ typedef error_t (*ftp_conn_add_stat_fun_t) (const char *name, # if _FILE_OFFSET_BITS == 64 const struct stat *stat, # else const struct stat64 *stat, # endif const char *symlink_target, void *hook); /* Hooks that customize behavior for particular types of remote system. */ struct ftp_conn_syshooks { /* Should return in ADDR a malloced struct sockaddr containing the address of the host referenced by the PASV reply contained in TXT. */ error_t (*pasv_addr) (struct ftp_conn *conn, const char *txt, struct sockaddr **addr); /* Look at the error string in TXT, and try to guess an error code to return. If POSS_ERRS is non-zero, it contains a list of errors that are likely to occur with the previous command, terminated with 0. If no match is found and POSS_ERRS is non-zero, the first error in POSS_ERRS should be returned by default. */ error_t (*interp_err) (struct ftp_conn *conn, const char *txt, const error_t *poss_errs); /* Start an operation to get a list of file-stat structures for NAME (this is often similar to ftp_conn_start_dir, but with OS-specific flags), and return a file-descriptor for reading on, and a state structure in STATE suitable for passing to cont_get_stats. If CONTENTS is true, NAME must refer to a directory, and the contents will be returned, otherwise, the (single) result will refer to NAME. */ error_t (*start_get_stats) (struct ftp_conn *conn, const char *name, int contents, int *fd, void **state); /* Read stats information from FD, calling ADD_STAT for each new stat (HOOK is passed to ADD_STAT). FD and STATE should be returned from start_get_stats. If this function returns EAGAIN, then it should be called again to finish the job (possibly after calling select on FD); if it returns 0, then it is finishe,d and FD and STATE are deallocated. */ error_t (*cont_get_stats) (struct ftp_conn *conn, int fd, void *state, ftp_conn_add_stat_fun_t add_stat, void *hook); /* Give a name which refers to a directory file, and a name in that directory, this should return in COMPOSITE the composite name refering to that name in that directory, in malloced storage. */ error_t (*append_name) (struct ftp_conn *conn, const char *dir, const char *name, char **composite); /* If the name of a file *NAME is a composite name (containing both a filename and a directory name), this function should change *NAME to be the name component only; if the result is shorter than the original *NAME, the storage pointed to it may be modified, otherwise, *NAME should be changed to point to malloced storage holding the result, which will be freed by the caller. */ error_t (*basename) (struct ftp_conn *conn, char **name); }; /* Type parameter for the cntl_debug hook. */ #define FTP_CONN_CNTL_DEBUG_CMD 1 #define FTP_CONN_CNTL_DEBUG_REPLY 2 /* Type parameter for the get_login_param hook. */ #define FTP_CONN_GET_LOGIN_PARAM_USER 1 #define FTP_CONN_GET_LOGIN_PARAM_PASS 2 #define FTP_CONN_GET_LOGIN_PARAM_ACCT 3 /* General connection customization. */ struct ftp_conn_hooks { /* If non-zero, should look at the SYST reply in SYST, and fill in CONN's syshooks (with ftp_conn_set_hooks) appropriately; SYST may be zero if the remote system doesn't support that command. If zero, then the default ftp_conn_choose_syshooks is used. */ void (*choose_syshooks) (struct ftp_conn *conn, const char *syst); /* If non-zero, called during io on the ftp control connection -- TYPE is FTP_CONN_CNTL_DEBUG_CMD for commands, and FTP_CONN_CNTL_DEBUG_REPLY for replies; TXT is the actual text. */ void (*cntl_debug) (struct ftp_conn *conn, int type, const char *txt); /* Called after CONN's connection the server has been opened (or reopened). */ void (*opened) (struct ftp_conn *conn); /* If the remote system requires some login parameter that isn't available, this hook is called to try and get it, returning a value in TXT. The return value should be in a malloced block of memory. The returned value will only be used once; if it's desired that it should `stick', the user may modify the value stored in CONN's params field, but that is an issue outside of the scope of this interface -- params are only read, never written. */ error_t (*get_login_param) (struct ftp_conn *conn, int type, char **txt); /* Called after CONN's connection the server has closed for some reason. */ void (*closed) (struct ftp_conn *conn); /* Called when CONN is initially created before any other hook calls. An error return causes the creation to fail with that error code. */ error_t (*init) (struct ftp_conn *conn); /* Called when CONN is about to be destroyed. No hook calls are ever made after this one. */ void (*fini) (struct ftp_conn *conn); /* This hook should return true if the current thread has been interrupted in some way, and EINTR (or a short count in some cases) should be returned from a blocking function. */ int (*interrupt_check) (struct ftp_conn *conn); }; /* A single ftp connection. */ struct ftp_conn { const struct ftp_conn_params *params; /* machine, user, &c */ const struct ftp_conn_hooks *hooks; /* Customization hooks. */ struct ftp_conn_syshooks syshooks; /* host-dependent hook functions */ int syshooks_valid : 1; /* True if the system type has been determined. */ int control; /* fd for ftp control connection */ char *line; /* buffer for reading control replies */ size_t line_sz; /* allocated size of LINE */ size_t line_offs; /* Start of unread input in LINE. */ size_t line_len; /* End of the contents in LINE. */ char *reply_txt; /* A buffer for the text of entire replies */ size_t reply_txt_sz; /* size of it */ char *cwd; /* Last know CWD, or 0 if unknown. */ const char *type; /* Connection type, or 0 if default. */ void *hook; /* Random user data. */ int use_passive : 1; /* If true, first try passive data conns. */ struct sockaddr *actv_data_addr;/* Address of port for active data conns. */ }; /* Parameters for an ftp connection; doesn't include any actual connection state. */ struct ftp_conn_params { void *addr; /* Address. */ size_t addr_len; /* Length in bytes of ADDR. */ int addr_type; /* Type of ADDR (AF_*). */ char *user, *pass, *acct; /* Parameters for logging into ftp. */ }; /* Unix hooks */ extern error_t ftp_conn_unix_pasv_addr (struct ftp_conn *conn, const char *txt, struct sockaddr **addr); extern error_t ftp_conn_unix_interp_err (struct ftp_conn *conn, const char *txt, const error_t *poss_errs); extern error_t ftp_conn_unix_start_get_stats (struct ftp_conn *conn, const char *name, int contents, int *fd, void **state); extern error_t ftp_conn_unix_cont_get_stats (struct ftp_conn *conn, int fd, void *state, ftp_conn_add_stat_fun_t add_stat, void *hook); error_t ftp_conn_unix_append_name (struct ftp_conn *conn, const char *dir, const char *name, char **composite); error_t ftp_conn_unix_basename (struct ftp_conn *conn, char **name); extern struct ftp_conn_syshooks ftp_conn_unix_syshooks; error_t ftp_conn_get_raw_reply (struct ftp_conn *conn, int *reply, const char **reply_txt); error_t ftp_conn_get_reply (struct ftp_conn *conn, int *reply, const char **reply_txt); error_t ftp_conn_cmd (struct ftp_conn *conn, const char *cmd, const char *arg, int *reply, const char **reply_txt); error_t ftp_conn_cmd_reopen (struct ftp_conn *conn, const char *cmd, const char *arg, int *reply, const char **reply_txt); void ftp_conn_abort (struct ftp_conn *conn); /* Sets CONN's syshooks to a copy of SYSHOOKS. */ void ftp_conn_set_syshooks (struct ftp_conn *conn, struct ftp_conn_syshooks *syshooks); error_t ftp_conn_open (struct ftp_conn *conn); void ftp_conn_close (struct ftp_conn *conn); /* Makes sure that CONN's syshooks are set according to the remote system type. */ FTP_CONN_EI error_t ftp_conn_validate_syshooks (struct ftp_conn *conn) { if (conn->syshooks_valid) return 0; else /* Opening the connection should set the syshooks. */ return ftp_conn_open (conn); } /* Create a new ftp connection as specified by PARAMS, and return it in CONN; HOOKS contains customization hooks used by the connection. Neither PARAMS nor HOOKS is copied, so a copy of it should be made if necessary before calling this function; if it should be freed later, a FINI hook may be used to do so. */ error_t ftp_conn_create (const struct ftp_conn_params *params, const struct ftp_conn_hooks *hooks, struct ftp_conn **conn); /* Free the ftp connection CONN, closing it first, and freeing all resources it uses. */ void ftp_conn_free (struct ftp_conn *conn); /* Start a transfer command CMD (and optional args ...), returning a file descriptor in DATA. POSS_ERRS is a list of errnos to try matching against any resulting error text. */ error_t ftp_conn_start_transfer (struct ftp_conn *conn, const char *cmd, const char *arg, const error_t *poss_errs, int *data); /* Wait for the reply signalling the end of a data transfer. */ error_t ftp_conn_finish_transfer (struct ftp_conn *conn); /* Start retreiving file NAME over CONN, returning a file descriptor in DATA over which the data can be read. */ error_t ftp_conn_start_retrieve (struct ftp_conn *conn, const char *name, int *data); /* Start retreiving a list of files in NAME over CONN, returning a file descriptor in DATA over which the data can be read. */ error_t ftp_conn_start_list (struct ftp_conn *conn, const char *name, int *data); /* Start retreiving a directory listing of NAME over CONN, returning a file descriptor in DATA over which the data can be read. */ error_t ftp_conn_start_dir (struct ftp_conn *conn, const char *name, int *data); /* Start storing into file NAME over CONN, returning a file descriptor in DATA into which the data can be written. */ error_t ftp_conn_start_store (struct ftp_conn *conn, const char *name, int *data); /* Transfer the output of SRC_CMD/SRC_NAME on SRC_CONN to DST_NAME on DST_CONN, moving the data directly between servers. */ error_t ftp_conn_rmt_transfer (struct ftp_conn *src_conn, const char *src_cmd, const char *src_name, const int *src_poss_errs, struct ftp_conn *dst_conn, const char *dst_name); /* Copy the SRC_NAME on SRC_CONN to DST_NAME on DST_CONN, moving the data directly between servers. */ error_t ftp_conn_rmt_copy (struct ftp_conn *src_conn, const char *src_name, struct ftp_conn *dst_conn, const char *dst_name); /* Return a malloced string containing CONN's working directory in CWD. */ error_t ftp_conn_get_cwd (struct ftp_conn *conn, char **cwd); /* Return a malloced string containing CONN's working directory in CWD. */ error_t ftp_conn_cwd (struct ftp_conn *conn, const char *cwd); /* Return a malloced string containing CONN's working directory in CWD. */ error_t ftp_conn_cdup (struct ftp_conn *conn); /* Set the ftp connection type of CONN to TYPE, or return an error. */ error_t ftp_conn_set_type (struct ftp_conn *conn, const char *type); /* Start an operation to get a list of file-stat structures for NAME (this is often similar to ftp_conn_start_dir, but with OS-specific flags), and return a file-descriptor for reading on, and a state structure in STATE suitable for passing to cont_get_stats. If CONTENTS is true, NAME must refer to a directory, and the contents will be returned, otherwise, the (single) result will refer to NAME. */ error_t ftp_conn_start_get_stats (struct ftp_conn *conn, const char *name, int contents, int *fd, void **state); /* Read stats information from FD, calling ADD_STAT for each new stat (HOOK is passed to ADD_STAT). FD and STATE should be returned from start_get_stats. If this function returns EAGAIN, then it should be called again to finish the job (possibly after calling select on FD); if it returns 0, then it is finishe,d and FD and STATE are deallocated. */ error_t ftp_conn_cont_get_stats (struct ftp_conn *conn, int fd, void *state, ftp_conn_add_stat_fun_t add_stat, void *hook); /* Get a list of file-stat structures for NAME, calling ADD_STAT for each one (HOOK is passed to ADD_STAT). If CONTENTS is true, NAME must refer to a directory, and the contents will be returned, otherwise, the (single) result will refer to NAME. This function may block. */ error_t ftp_conn_get_stats (struct ftp_conn *conn, const char *name, int contents, ftp_conn_add_stat_fun_t add_stat, void *hook); /* The type of the function called by ...get_names to add each new name. NAME is the name in question and HOOK is as passed into ...get_stats. */ typedef error_t (*ftp_conn_add_name_fun_t) (const char *name, void *hook); /* Start an operation to get a list of filenames in the directory NAME, and return a file-descriptor for reading on, and a state structure in STATE suitable for passing to cont_get_names. */ error_t ftp_conn_start_get_names (struct ftp_conn *conn, const char *name, int *fd, void **state); /* Read filenames from FD, calling ADD_NAME for each new NAME (HOOK is passed to ADD_NAME). FD and STATE should be returned from start_get_stats. If this function returns EAGAIN, then it should be called again to finish the job (possibly after calling select on FD); if it returns 0, then it is finishe,d and FD and STATE are deallocated. */ error_t ftp_conn_cont_get_names (struct ftp_conn *conn, int fd, void *state, ftp_conn_add_name_fun_t add_name, void *hook); /* Get a list of names in the directory NAME, calling ADD_NAME for each one (HOOK is passed to ADD_NAME). This function may block. */ error_t ftp_conn_get_names (struct ftp_conn *conn, const char *name, ftp_conn_add_name_fun_t add_name, void *hook); /* Give a name which refers to a directory file, and a name in that directory, this should return in COMPOSITE the composite name refering to that name in that directory, in malloced storage. */ error_t ftp_conn_append_name (struct ftp_conn *conn, const char *dir, const char *name, char **composite); /* If the name of a file COMPOSITE is a composite name (containing both a filename and a directory name), this function will return the name component only in BASE, in malloced storage, otherwise it simply returns a newly malloced copy of COMPOSITE in BASE. */ error_t ftp_conn_basename (struct ftp_conn *conn, const char *composite, char **base); #endif /* __FTPCONN_H__ */