/*
** 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 <roth@feep.net>
*/
#include <internal.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdarg.h>
#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
}
syntax highlighted by Code2HTML, v. 0.9.1