#ifndef __WPUT_H
#define __WPUT_H

#include "../config.h"
#if SIZEOF_INT != 4
#error "sizeof(int) must be 4"
#endif
#if SIZEOF_SHORT != 2
#error "sizeof(short) must be 2"
#endif

#include <fcntl.h>

#ifdef WIN32

#  include "windows.h"

/* WINDOWS defines its UINT64 in basetsd.h */
#  include <basetsd.h>
/* WINDOWS does not know how to converte unsigned __int64 to double
 * therefore we have to cast it to signed first... */
#  define WINCONV (signed __int64)
#  define WPUTRC_FILENAME "wput.ini"

#else /* def WIN32 */

#  include <unistd.h>
#  include <dirent.h>
#  include <strings.h>
#  include <pwd.h>

#  ifdef __VMS
	
#    include <in.h>
#    include <inet.h>
#    include <socket.h>
#    include <uio.h>
#    include <errno.h>
#    include <types.h>
#    include <stat.h>

#  else /* def __VMS */
	
#    include <netinet/in.h>
#    include <arpa/inet.h>
#    include <sys/socket.h>
#    include <sys/select.h>
#    include <sys/uio.h>
#    include <sys/errno.h>
#    include <sys/types.h>
/* TODO USS i read about stat64 / seek64. make wput use it, if possible */
#    include <sys/stat.h>

#  endif /* def __VMS */

#  ifdef HAVE_LONG_LONG 
#    define UINT64 unsigned long long int
#  else /* fall back and use at least long ints */
#    define UINT64 unsigned long int
#  endif

#  define WINCONV
	
#  ifdef __VMS

#    define WPUTRC_FILENAME ".wputrc"
#    define SYSTEM_WPUTRC "/etc/wputrc"

#  else /* def __VMS */

#    define WPUTRC_FILENAME ".wputrc"
#    define SYSTEM_WPUTRC "sys$manager/wputrc"

#  endif /* def __VMS */

#  define win32_replace_dirsep(x) x
	
#  define closesocket(x) close(x)
#  define WPUT_EINTR EINTR

#endif /* def WIN32 */



#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

/* definitions to find memory leaks and causes for segfaults. linked with memdbg.c */
//#define MEMDBG 

#ifdef MEMDBG

void dbg_free(void * ptr, char * file, int line);
void * dbg_realloc(void * ptr, size_t size, char * file, int line);
void * dbg_malloc(size_t size, char * file, int line);
int dbg_socket(int domain, int type, int protocol, char * file, int line);
int dbg_shutdown(int s, int how, char * file, int line);
int dbg_open(const char *path, int flags, char * file, int line);
int dbg_close(int fd, char * file, int line);
char * dbg_strcat(char * s, const char * p, char * file, int line);
char * dbg_cpy(char * s, char * file, int line);

#define malloc(x)       dbg_malloc(x, __FILE__, __LINE__)
#define realloc(x,y)    dbg_realloc(x,y, __FILE__, __LINE__)
#define free(x)         dbg_free(x, __FILE__, __LINE__)
#define socket(x,y,z)   dbg_socket(x,y,z, __FILE__, __LINE__)
#define shutdown(x,y)   dbg_shutdown(x,y, __FILE__, __LINE__)
#define open(x,y)       dbg_open(x,y, __FILE__, __LINE__)
//#define close(x)        dbg_close(x, __FILE__, __LINE__)
#undef closesocket
#define closesocket(x)  dbg_close(x, __FILE__, __LINE__)
#define strcat(x,y)     dbg_strcat(x,y, __FILE__, __LINE__)
#define cpy(x)          dbg_cpy(x, __FILE__, __LINE__)

void print_unfree(void);
#endif
/* / */

extern int errno;

#define BUFLEN 4096
#define TBUFLEN 64
#define FNLEN 768
/* TODO definitions:
   TODO URG urgent		no execuses! this needs to be done NOW
   TODO IMP important		put effort on getting this done.
   TODO PRI primary objective	i want this to work!
   TODO USS usual suspects	do it if you can afford getting it done or st. like that
   TODO NRV nonrelevant		might be done some day, if you feel lucky
 */
 
/* verbosity options */
#define vLESS   1
#define vNORMAL 2
#define vMORE   3
#define vDEBUG	4

#define ERR_NOERROR 0
#define ERR_OK 0

#define SOCKET_ERROR(x) (x == ERR_RECONNECT || x == ERR_TIMEOUT)
#define FTP_ERROR(x) (x == ERR_RETRY || x == ERR_PERMANENT)

#define ERR_FAILED -1 //general failure
#define ERR_POSITIVE_PRELIMARY -2
#define ERR_RETRY -3
#define ERR_PERMANENT -4
#define ERR_RECONNECT -10
#define ERR_TIMEOUT -11

#define PROXY_OFF   0
#define PROXY_SOCKS 1
#define PROXY_HTTP  2

#define TYPE_UNDEFINED -1
#define TYPE_A          0
#define TYPE_I          1

enum ftype
{
  FT_PLAINFILE,
  FT_DIRECTORY,
  FT_SYMLINK,
  FT_UNKNOWN
};
enum stype
{
  ST_UNIX,
  ST_VMS,
  ST_WINNT,
  ST_MACOS,
  ST_OS400,
  ST_OTHER,
  ST_UNDEFINED
};

struct file_timestamp{
  int year;
  int month;
  int day;
  int hour;
  int minute;
  int second;
};

typedef struct _skipd_list {
  int					ip;
  char *				host;
  unsigned short int	port;
  char *				user;
  char *				pass;
  char *				dir;
  struct _skipd_list *	next;
} skipd_list;

struct fileinfo
{
  enum ftype type;		    /* file type */
  char * name;			    /* file name */
  UINT64 size;			    /* file size */
  time_t tstamp;			    /* time-stamp */
  int perms;                    /* file permissions */
  char *linkto;                 /* link to which file points */
  struct fileinfo *prev;        /* previous... */
  struct fileinfo *next;	/* ...and next structure. */
};

typedef struct _directory_list {
  char * name;
  struct fileinfo * list;
  struct _directory_list * next;
} directory_list;
typedef struct _password_list {
  char * host;
  char * user;
  char * pass;
  struct _password_list * next;
} password_list;

typedef struct __resume_table {
	#define RESUME_TABLE_SKIP	 0
	#define RESUME_TABLE_UPLOAD  1
	#define RESUME_TABLE_RESUME  2
	unsigned char small_large:1;
	unsigned char large_large:1;
	unsigned char large_small:2;
} _resume_table;

typedef struct _ftp_reply {
	unsigned short int code;
	char * reply;
	char * message;
} ftp_reply;

struct _current_connection {
	int csock;       /* ftp client socket */
	int s_socket;    /* port mode client server socket */
	int data_socket;
	
	char *             hostname;
	unsigned int       ip;
	unsigned short int port;
	
	directory_list * directorylist;
    char *           current_directory;
	
	ftp_reply r; /* current reply */
	
	unsigned char needcwd:1;
	unsigned char loggedin:1;
	         char current_type:2; /* -1 (undefined), 0 (ascii), 1 binary */
	
	enum stype OS;
} cc;

struct global_options {
  char * sbuf;
  int sbuflen;
  int bindaddr;

  int proxy_ip;
  unsigned short int proxy_port;
  char * proxy_user;
  char * proxy_pass;
  
  char * email_address; /* used as password when loggin in anonymously */
  
  int local_ip;
  skipd_list     * skipdlist;
  char * last_url;

  password_list * pl;
  /* default table. can change for each fsession */
  _resume_table resume_table;
  
  /* flags */
  unsigned char random_wait	:1;
  unsigned char force		:1;
  unsigned char portmode	:1;
           char binary		:2; /* -1 (autoprobe), 0, 1 */
  unsigned char proxy		:2; 
  unsigned char sorturls	:1;
  unsigned char unlink		:1;
  unsigned char proxy_bind	:1;
  unsigned char relative_cwds	:1;
  unsigned char timestamping	:1;
           char time_offset	:6; /* +-24 (2^5 = 32 + signed) */
#ifndef WIN32
  unsigned char background	:1;
#endif
  unsigned char barstyle	:1; /* 0 -> old wget-style, 1 -> new one... */
  //unsigned char done		:1;
  unsigned char verbose		:3;

  short time_deviation;

  FILE * output;
  FILE * input;
  char * input_pipe;

  short int wait;
  short int retry;

  struct wput_timer * session_start;
  UINT64 transfered_bytes;
  int    files_transfered;

  unsigned short int retry_interval;
  unsigned       int speed_limit;
  unsigned short int timeout;
} opt;

typedef struct ftp_session{
  char * user;
  char * pass;
  char shname[64];
  unsigned short int port; /* remote port */
  int ip;
  char * hostname;


  //char * local_dname;
  char * local_fname;
  //char * target_rdname; /* target root directory name */
  char * target_dname;
  char * target_fname;

  UINT64 local_fsize;
  UINT64 target_fsize;

  time_t local_ftime;
  time_t target_ftime;

  short int retry;
  /* flags */
  _resume_table resume_table;

  unsigned char portmode:1;
  unsigned char done	:1;
           char binary	:2;

  struct fileinfo * directory;
  struct ftp_session * next;
} _fsession;

extern _fsession * fsession_queue_entry_point;
extern char * email_address;
#ifdef WIN32
  #define dirsep '\\'
  #define dirsepstr "\\"
#else
  #define dirsep '/'
  #define dirsepstr "/"
#endif

void readwputrc(char * f);
void read_password_file(char * f);
int read_urls(void);
int set_option(char * com, char * val);

#endif /* ndef __WPUT_H */
