/* ** Copyright 2000-2004 University of Illinois Board of Trustees ** Copyright 2000-2004 Mark D. Roth ** All rights reserved. ** ** options.c - libfget option code ** ** Mark D. Roth */ #include #include #ifdef STDC_HEADERS # include #endif /****************************************************************************** *** boolean type ******************************************************************************/ /* ** (ab)uses field_offset to indicate the option's bit value ** within the ftp_flags bitmask */ static void _opt_get_boolean(FTP *ftp, int option, size_t field_offset, size_t field_size, void *arg_ptr) { unsigned short us; us = (BIT_ISSET(ftp->ftp_flags, field_offset) ? 1 : 0); memcpy(arg_ptr, &us, sizeof(us)); } static void _opt_set_boolean(FTP *ftp, int option, size_t field_offset, va_list *argsp) { unsigned int ui; /* ** NOTE: we use int instead of short when calling va_arg(), ** because short will be promoted to int when passed to a ** varags function */ ui = va_arg(*argsp, unsigned int); #ifdef DEBUG printf("==> _opt_set_boolean(option=%d, field_offset=%d, value=%u)\n", option, (int)field_offset, ui); #endif if (ui) BIT_SET(ftp->ftp_flags, field_offset); else BIT_CLEAR(ftp->ftp_flags, field_offset); } /****************************************************************************** *** time_t type ******************************************************************************/ static void _opt_set_time_t(FTP *ftp, int option, size_t field_offset, va_list *argsp) { time_t *ptr; ptr = (time_t *)((char *)ftp + field_offset); *ptr = va_arg(*argsp, time_t); } /****************************************************************************** *** long type ******************************************************************************/ static void _opt_set_long(FTP *ftp, int option, size_t field_offset, va_list *argsp) { long *ptr; ptr = (long *)((char *)ftp + field_offset); *ptr = va_arg(*argsp, long); } /****************************************************************************** *** pointer type ******************************************************************************/ static void _opt_set_ptr(FTP *ftp, int option, size_t field_offset, va_list *argsp) { void **ptr; ptr = (void **)((char *)ftp + field_offset); *ptr = va_arg(*argsp, void *); } /****************************************************************************** *** generic field get function ******************************************************************************/ static void _opt_get_field(FTP *ftp, int option, size_t field_offset, size_t field_size, void *arg_ptr) { void *opt_ptr; opt_ptr = (void *)((char *)ftp + field_offset); memcpy(arg_ptr, opt_ptr, field_size); } /****************************************************************************** *** option description information ******************************************************************************/ /* ** finds the offset within the FTP handle of a given field */ #define ftp_field_offset(field) \ ((unsigned int) (((char *) (&(((FTP *)NULL)->field))) - ((char *)NULL))) /* ** typedefs for get/set functions */ typedef void (*option_get_func_t)(FTP *, int, size_t, size_t, void *); typedef void (*option_set_func_t)(FTP *, int, size_t, va_list *); /* ** description of an option */ struct ftp_option_description { int o_option; /* option number */ option_get_func_t o_get_func; /* get function */ option_set_func_t o_set_func; /* set function */ size_t o_offset; /* offset of field into FTP structure */ size_t o_size; /* size of field's data type */ }; typedef struct ftp_option_description ftp_option_description_t; /* ** here's the actual table of option descriptions */ static const ftp_option_description_t ftp_option_descriptions[] = { { FTP_OPT_PASSIVE, _opt_get_boolean, _opt_set_boolean, FTP_FLAG_USE_PASV, 0 }, { FTP_OPT_USE_MLST, _opt_get_boolean, _opt_set_boolean, FTP_FLAG_USE_MLST, 0 }, { FTP_OPT_USE_ABOR, _opt_get_boolean, _opt_set_boolean, FTP_FLAG_USE_ABOR, 0 }, { FTP_OPT_IO_TIMEOUT, _opt_get_field, _opt_set_time_t, ftp_field_offset(ftp_io_timeout), sizeof(time_t) }, { FTP_OPT_CACHE_MAXSIZE, _opt_get_field, _opt_set_long, ftp_field_offset(ftp_cache_maxsize), sizeof(long) }, { FTP_OPT_CACHE_EXPIRE, _opt_get_field, _opt_set_long, ftp_field_offset(ftp_cache_expire), sizeof(long) }, { FTP_OPT_SEND_HOOK, _opt_get_field, _opt_set_ptr, ftp_field_offset(ftp_send_hook), sizeof(ftp_hookfunc_t) }, { FTP_OPT_RECV_HOOK, _opt_get_field, _opt_set_ptr, ftp_field_offset(ftp_recv_hook), sizeof(ftp_hookfunc_t) }, { FTP_OPT_HOOK_DATA, _opt_get_field, _opt_set_ptr, ftp_field_offset(ftp_hook_data), sizeof(void *) }, { 0, NULL, NULL, 0, 0 } }; /* ** utility function for finding the right option description in the table */ static const ftp_option_description_t * _find_option_description(int option) { int i; for (i = 0; ftp_option_descriptions[i].o_option != 0; i++) { if (ftp_option_descriptions[i].o_option == option) return &(ftp_option_descriptions[i]); } return NULL; } /****************************************************************************** *** code for setting options ******************************************************************************/ void _vftp_set_options(FTP *ftp, va_list args) { const ftp_option_description_t *opt_desc; int option; while ((option = va_arg(args, int)) != 0) { #ifdef DEBUG printf(" _vftp_set_options(): option=%d\n", option); #endif opt_desc = _find_option_description(option); if (opt_desc == NULL) continue; (*(opt_desc->o_set_func))(ftp, option, opt_desc->o_offset, &args); } } /* ** set options */ void ftp_set_options(FTP *ftp, ...) { va_list args; va_start(args, ftp); _vftp_set_options(ftp, args); va_end(args); } /****************************************************************************** *** code for getting options ******************************************************************************/ static void _vftp_get_options(FTP *ftp, va_list args) { const ftp_option_description_t *opt_desc; int option; void *arg_ptr; while ((option = va_arg(args, int)) != 0) { opt_desc = _find_option_description(option); if (opt_desc == NULL) return; arg_ptr = va_arg(args, void *); (*(opt_desc->o_get_func))(ftp, option, opt_desc->o_offset, opt_desc->o_size, arg_ptr); } } /* ** get options */ void ftp_get_options(FTP *ftp, ...) { va_list args; va_start(args, ftp); _vftp_get_options(ftp, args); va_end(args); } /****************************************************************************** *** initialize options to default values ******************************************************************************/ /* ** set option defaults */ void _ftp_init_options(FTP *ftp) { #ifdef DEBUG printf("==> _ftp_init_options(ftp=%p)\n", ftp); #endif /* ** ftp_connect() uses calloc(3) to create the FTP handle, ** so we only need to set those options that have a non-zero ** default value */ ftp_set_options( ftp, FTP_OPT_PASSIVE, (unsigned short)1, FTP_OPT_IO_TIMEOUT, (time_t)-1, FTP_OPT_CACHE_MAXSIZE, (long)-1, FTP_OPT_CACHE_EXPIRE, (long)-1, 0 ); #ifdef DEBUG printf("<== _ftp_init_options()\n"); #endif }