//**************************************************************************
//*                     This file is part of the                           *
//*                      Mpxplay - audio player.                           *
//*                  The source code of Mpxplay is                         *
//*        (C) copyright 1998-2012 by PDSoft (Attila Padar)                *
//*                http://mpxplay.sourceforge.net                          *
//*                  email: mpxplay@freemail.hu                            *
//**************************************************************************
//*  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.                  *
//*  Please contact with the author (with me) if you want to use           *
//*  or modify this source.                                                *
//**************************************************************************
//function: common defs and funcs for ftp and http (dir and sock handling)

#ifndef tcpcomon_h
#define tcpcomon_h

#ifdef __cplusplus
extern "C" {
#endif

//#define MPXPLAY_DRVFTP_DEBUGFILE "d:\\work\\mpxplay\\httplog.txt"

#define DRVFTP_MAX_VIRTUAL_DRIVES ('7'-'0'+1)
#define DRVFTP_MAX_SESSIONS       (DRVFTP_MAX_VIRTUAL_DRIVES+1) // +1 ftpfile
#define DRVFTP_VIRTUALDRV_FTPFILE DRVFTP_MAX_VIRTUAL_DRIVES

#define DRVFTP_DEFAULT_RCVBUFSIZE 65536

// ftp://user:pasw@servername:port/dir
#define DRVFTP_PATHSEPARATOR_USER     '@'
#define DRVFTP_PATHSEPARATOR_PASSWORD ':'
#define DRVFTP_PATHSEPARATOR_PORTNUM  ':'

#define DRVFTP_IP4_LEN 4

// dirs and direntries (ftpi->cached_dir_datas)
#define DRVFTP_CACHED_DIRS_INITSTEP    512 // initial and expand-step
#define DRVFTP_CACHED_DIRS_MAX        4096 // to not eat all memory
#define DRVFTP_CACHED_DIRENT_INITSTEP 1024
#define DRVFTP_CACHED_DIRENT_MAX     16384

// inside control in ftpi->flags
//#define DRVFTP_FTPDRIVE_FLAG_HTTP       (1<<16)
#define DRVFTP_FTPDRIVE_FLAG_CONNECTED    (1<<17)
#define DRVFTP_FTPDRIVE_FLAG_RECONNECT    (1<<18)

// respcontrol
#define DRVFTP_RESPCNTR_NONE             0
#define DRVFTP_RESPCNTR_NORETCODECHK (1<<0)
#define DRVFTP_RESPCNTR_INSTANT      (1<<1)
#define DRVFTP_RESPCNTR_SHORTWAIT    (1<<2)
#define DRVFTP_RESPCNTR_LONGWAIT     (1<<3)

// socketinfo->flags
#define DRVFTP_SOCKINFO_FLAG_SSL_DISABLED   (1 << 0)
#define DRVFTP_SOCKINFO_FLAG_DIRECTION_SEND (1 << 1)

// socket_select checkmode
#define DRVFTP_SOCKSELECT_MODE_READ  1
#define DRVFTP_SOCKSELECT_MODE_WRITE 2
#define DRVFTP_SOCKSELECT_MODE_ERROR 4

// timeouts
#define DRVFTP_DEFAULT_TIMEOUTRETRY_SESSION    3  //
#define DRVFTP_DEFAULT_TIMEOUTRETRY_DATACONN   3  //
#define DRVFTP_DEFAULT_REDIRECTRETRY_SESSION   8  //
#define DRVFTP_DEFAULT_TIMEOUTMS_ACCEPT      100  // in msec
#define DRVFTP_DEFAULT_TIMEOUTMS_RESPONSE  15000  // connect(), send()
#define DRVFTP_DEFAULT_TIMEOUTMS_LONGWAIT  30000
#define DRVFTP_DEFAULT_TIMEOUTMS_SHORTWAIT  2000
#define DRVFTP_DEFAULT_TIMEOUTMS_READ      10000
#define DRVFTP_DEFAULT_TIMEOUTMS_EOF        1000  // !!!
#define DRVFTP_DEFAULT_TIMEOUTMS_DISP       1500

// ftfi->flags
#define DRVFTP_FTPFILE_FLAG_SEEK         (1<< 0)   // do seeking
#define DRVFTP_FTPFILE_FLAG_WRITE        (1<< 1)   // ftp file write
#define DRVFTP_FTPFILE_FLAG_READWAIT     (1<< 2)   // wait for response / read data (blocking read)
#define DRVFTP_FTPFILE_FLAG_NOKEEPALIVE  (1<< 3)   // disable keep alive (auto reconnect at connection lost/end) (in HTTP/1.1 the default is keep-alive)
#define DRVFTP_FTPFILE_FLAG_PLAY         (1<< 4)   // play mode open (else copy/record)
#define DRVFTP_FTPFILE_FLAG_NONSEEKABLE  (1<< 8)   // internet radio (or http file on an old server)
#define DRVFTP_FTPFILE_FLAG_LIVESTREAM   (1<< 9)   // internet radio
#define DRVFTP_FTPFILE_FLAG_PARTIALCONTENT (1<<10) // after http seeking
#define DRVFTP_FTPFILE_FLAG_CHUNKED      (1<<11)   // special content text type (every odd line is a length of next line in hex format)
#define DRVFTP_FTPFILE_FLAG_META_CHECK   (1<<12)   // stream reading is in metadata head
#define DRVFTP_FTPFILE_FLAG_META_READ    (1<<13)   // stream reading is in metadata
#define DRVFTP_FTPFILE_FLAG_CONNECTED    (1<<16)   // the connection was already successfull once
#define DRVFTP_FTPFILE_FLAG_TERMINATE    (1<<17)   // terminate file handling (pre-close sign)
#define DRVFTP_FTPFILE_FLAGS_RESET_AT_RECONNECT (DRVFTP_FTPFILE_FLAG_PARTIALCONTENT | DRVFTP_FTPFILE_FLAG_CHUNKED | DRVFTP_FTPFILE_FLAG_META_CHECK | DRVFTP_FTPFILE_FLAG_META_READ)

// ftfi->opentype
#define DRVFTP_FTPFILE_OPENTYPE_READ   1
#define DRVFTP_FTPFILE_OPENTYPE_WRITE  2
#define DRVFTP_FTPFILE_OPENTYPE_CREATE 4
#define DRVFTP_FTPFILE_OPENTYPE_TEXT   8

// hfti->subprotocol_type
#define DRVHTTP_HTTPFILE_SUBPROTOCOL_HTTP  0
#define DRVHTTP_HTTPFILE_SUBPROTOCOL_RTSP  1

#define DRVHTTP_HTTPFILE_READBUF_SIZE 32768

typedef struct tcpcomon_cached_direntry_info_s{
 char *filename;
// char *metadata;
 unsigned long attrib;
 mpxp_filesize_t filesize;
 pds_fdate_t fdate;
}tcpcomon_cached_direntry_info_s;

typedef struct tcpcomon_cached_directory_info_s{
 char *dirname;
 unsigned long cached_entries_num;
 unsigned long cached_entries_max;
 struct tcpcomon_cached_direntry_info_s *entrydatas;
}tcpcomon_cached_directory_info_s;

typedef struct tcpcomon_cached_drive_info_s{
 unsigned long cached_dirs_num;
 unsigned long cached_dirs_max;
 struct tcpcomon_cached_directory_info_s *cached_dir_datas;
}tcpcomon_cached_drive_info_s;

typedef struct ftpdrive_filefind_s{
 unsigned long entrynum_curr;
 unsigned long entrynum_end;
 struct tcpcomon_cached_direntry_info_s *entry;
 char searchfilemask[MAX_PATHNAMELEN];
}ftpdrive_filefind_s;

typedef struct fptdrive_timeoutmsg_s{
 mpxp_uint64_t endtime_response,begintime_disp,lasttime_disp;
 char msgmask[128];
}ftpdrive_timeoutmsg_s;

typedef int ftpdrive_socket_t;

typedef struct ftpdrive_socket_info_s{
 ftpdrive_socket_t socknum;
 mpxp_uint8_t conn_ip_addr[DRVFTP_IP4_LEN];
 unsigned int portnum;
 void *sslhand;
 unsigned int flags;
}ftpdrive_socket_info_s;

typedef struct ftpdrive_lowlevel_func_s{
 char *name;
 unsigned int def_portnum;
 int   (*global_init)(void);
 void  (*global_deinit)(void);
 int   (*addressinfo_init)(struct ftpdrive_socket_info_s *socketinfo_session,char *servername,mpxp_uint8_t *ip_local,mpxp_uint8_t *ip_remote);
 int   (*login_preprocess)(void *ftpi,struct ftpdrive_socket_info_s *socketinfo_session);
 int   (*socket_open)(struct ftpdrive_socket_info_s *socketinfo_any,unsigned long bufsize);
 void  (*socket_shutdown)(struct ftpdrive_socket_info_s *socketinfo_any);
 void  (*socket_close)(struct ftpdrive_socket_info_s *socketinfo_any,unsigned int full);
 int   (*socket_select)(struct ftpdrive_socket_info_s *socketinfo_any,unsigned int checkmode);
 int   (*socket_connect)(struct ftpdrive_socket_info_s *socketinfo_any);
 int   (*socket_ssl_connect)(struct ftpdrive_socket_info_s *socketinfo_any);
 int   (*socket_listen)(struct ftpdrive_socket_info_s *socketinfo_filehand,mpxp_uint8_t *ip_local);
 int   (*socket_accept)(struct ftpdrive_socket_info_s *socketinfo_filehand);
 long  (*send)(struct ftpdrive_socket_info_s *socket_info,char *data,unsigned long bytes_to_send);
 long  (*bytes_buffered)(struct ftpdrive_socket_info_s *socket_info);
 long  (*receive)(struct ftpdrive_socket_info_s *socket_info,char *data,unsigned long buflen);
}ftpdrive_lowlevel_func_s;

typedef struct ftpdrive_info_s{
 mpxp_uint32_t flags;
 struct ftpdrive_info_s **ftpdrive_info_ptr;
 long connect_id_num;
 //unsigned int system_type;
 unsigned int server_features;
 unsigned int connection_retry;
 struct ftpdrive_lowlevel_func_s *lowfunc;
 struct ftpdrive_socket_info_s socket_info_session;
 struct ftpdrive_socket_info_s socket_info_filehand; // one filehand (data connect) per session
 long file_open_id_num;      // id of last opened file
 unsigned long socket_bufsize;

 struct tcpcomon_cached_drive_info_s cdrvi;

 unsigned int lastrespcode;
 unsigned int lastdatatype;
 mpxp_uint8_t ip_local[DRVFTP_IP4_LEN];
 mpxp_uint8_t ip_remote[DRVFTP_IP4_LEN];

 unsigned long message_bufbytes;
 char message_buffer[MAX_PATHNAMELEN];

 char currremotedir_selected[MAX_PATHNAMELEN];
 char currremotedir_real[MAX_PATHNAMELEN];

 char lastresptext[256];

 char servername[256];
 char username[128];
 char password[128];
 char hostname[256]; // for http url redirect (to keep 1st server infos)
 unsigned int host_portnum; //
}ftpdrive_info_s;

typedef struct ftpfile_info_s{
 mpxp_uint32_t flags;
 unsigned int opentype;
 long connect_id_num;
 long open_id_num;
 unsigned long file_bufsize;
 mpxp_filesize_t filepos;
 mpxp_filesize_t filesize;
 mpxp_uint64_t timeout_at_read;
 const char *content_type_fileext; // http content-type to file-extension
 struct ftpdrive_info_s **ftpi_ftpdrives_ptr;
 struct ftpdrive_info_s ftpi_infos;
 char remotefilename[MAX_PATHNAMELEN];
 char singleftpfilename[MAX_PATHNAMELEN];
}ftpfile_info_s;

typedef struct httpfile_info_s{
 mpxp_uint32_t flags;                // FTPFILE_FLAG_nnnn
 unsigned long  opentype;
 unsigned long file_bufsize;
 unsigned long  port_number_default; // http=80 RTSP=554
 mpxp_filesize_t filepos;
 mpxp_filesize_t filesize;
 mpxp_uint64_t timeout_at_read;
 const char *content_type_fileext;   // http content-type to file-extension
 unsigned long subprotocol_type;     // HTTPFILE_SUBPROTOCOL_nnnn
 unsigned long rtsp_cseq_number;     // RTSP CSeq: num
 mpxp_int32_t (*control_cb)(void *mdds,mpxp_uint32_t funcnum,void *argp1,void *argp2);
 void *cb_data;
 long chunk_size;
 long chunk_bytecount;
 long icy_bitrate;                   // icy-br in kbits/sec
 unsigned long metadata_interval;    // Icy-Metaint in bytes
 long metadata_intrv_count;          // in bytes
 long metadata_length;               // the 1st byte of metadata * 16 in bytes
 long metadata_read_pos;             //
 struct ftpdrive_info_s ftpi_infos;  // low level (socket/drive) infos
 long readbuf_leftbytes;             //
 long readbuf_readpos;               //
 char *read_buffer;                  // respond line and data buffer
 char openfilename[1024];            // http opened with this url/filename
 char remotefilename[1024];
 char singleftpfilename[1024];
 char cookiename[512];        // Set-Cookie: cookiename
 char icy_name[256];          // usually the name of radio channel
 char icy_genre[128];
 char session_name[256];      // RTSP Session: number
 char metadata_stream_title[256]; // Icy StreamTitle=' ';
}httpfile_info_s;

extern void drvftp_message_write_error(char *message);
extern void drvftp_message_timeout_init(struct fptdrive_timeoutmsg_s *tos,unsigned long endtime,char *msgmask);
extern void drvftp_message_timeout_reset(struct fptdrive_timeoutmsg_s *tos,unsigned long endtime);
extern void drvftp_message_timeout_write(struct fptdrive_timeoutmsg_s *tos);
extern void drvftp_message_timeout_close(struct fptdrive_timeoutmsg_s *tos);

extern void tcpcomon_str_localname_to_remote(char *remotename,char *pathname,unsigned int maxlen);
extern void tcpcomon_str_remotename_to_local(char *localname,char *remotename,unsigned int buflen);

extern struct tcpcomon_cached_directory_info_s *tcpcomon_dircache_dir_realloc(struct tcpcomon_cached_drive_info_s *drvi,struct tcpcomon_cached_directory_info_s *dirdatas,char *dirname);
extern void tcpcomon_dircache_dir_dealloc(struct tcpcomon_cached_directory_info_s *diri);
extern void tcpcomon_dircache_alldirs_dealloc(struct tcpcomon_cached_drive_info_s *drvi);
extern struct tcpcomon_cached_directory_info_s *tcpcomon_dircache_dir_searchby_name(struct tcpcomon_cached_drive_info_s *drvi,char *dirname);
extern struct tcpcomon_cached_direntry_info_s *tcpcomon_dircache_entry_alloc(struct tcpcomon_cached_directory_info_s *diri,char *filename);
//extern int tcpcomon_dircache_entry_add_metadata(struct tcpcomon_cached_direntry_info_s *ed, char *data);
extern char *tcpcomon_str_getpath_from_fullname(char *path,char *fullname);
extern struct tcpcomon_cached_direntry_info_s *tcpcomon_dircache_entry_searchby_fullname(struct tcpcomon_cached_drive_info_s *drvi,char *fullname);
extern struct tcpcomon_cached_direntry_info_s *tcpcomon_dircache_entry_removeby_fullname(struct tcpcomon_cached_drive_info_s *drvi,char *fullname);
extern struct tcpcomon_cached_direntry_info_s *tcpcomon_dircache_entry_addby_fullname(struct tcpcomon_cached_drive_info_s *drvi,char *fullname);
extern void tcpcomon_dircache_entry_copyto_ffblk(struct pds_find_t *ffblk,struct tcpcomon_cached_direntry_info_s *ed);

extern void mpxplay_tcpcommon_socket_reset(struct ftpdrive_socket_info_s *socketinfo_any);
extern unsigned int mpxplay_tcpcommon_socket_check(struct ftpdrive_socket_info_s *socketinfo_any);
extern void tcpcommon_socket_sleep(ftpdrive_socket_t socknum);

// drv_ftp.c
extern unsigned int diskdriv_drvftp_cmdctrl_sendcommand(struct ftpdrive_info_s *ftpi,struct ftpdrive_socket_info_s *socketinfo_session,char *command);
extern unsigned int diskdriv_drvftp_cmdctrl_read_respline(struct ftpdrive_info_s *ftpi,struct ftpdrive_socket_info_s *socketinfo_session,char *response,unsigned int respbufsize,unsigned int respcontrol);
extern unsigned int diskdriv_drvftp_cmdctrl_read_response(struct ftpdrive_info_s *ftpi,struct ftpdrive_socket_info_s *socketinfo_session,char *response,unsigned int respbufsize,unsigned int respcontrol);
extern unsigned int diskdriv_ftpdrive_findnext(void *drivehand_data,struct pds_find_t *ffblk);
extern void diskdriv_ftpdrive_findclose(void *drivehand_data,struct pds_find_t *ffblk);

#ifdef __cplusplus
}
#endif

#endif // tcpcomon_h
