#define CUR_VERSION "4.3"

#define inline __inline__ 			/* inline is not an ANSI keyword */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <utime.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/mtio.h>
#include <sys/types.h>
#include <curses.h>

#include "select_box.h"
#include "memory.h"

#define DEFAULT_TAPE "/dev/ftape"		 /* default tape name (rewinding device) */
#define DEFAULT_NTAPE "/dev/nftape"		 /* default tape name (non-rewinding device) */
#define DEFAULT_TAPER_INFO_FILES ".taper_info"	 /* directory containing info files */
#define DEFAULT_GLOBAL_PREFS "/usr/local/etc"	 /* location of global preference files */
#define DEFAULT_PREFS ".taper_prefs"		 /* default preference file name  */
#define DEFAULT_LOG_FILE ".taper_log"		 /* default log file name  */

#define TAPE_ENVIRON "TAPE"			 /* name of environment variable of rewinding tape */
#define NTAPE_ENVIRON "NTAPE"			 /* name of environment variable of non-rewinding tape device */
#define PREFS_ENVIRON "TAPER_PREFS"		 /* name of environment variable of preferences file */
#define LOGFILE_ENVIRON "TAPER_LOG_FILE"	 /* name of environment variable of log file */
#define LOGLEVEL_ENVIRON "TAPER_LOG_LEVEL"	 /* name of environment variable of logging level */
#define TAPER_INFO_FILES_ENVIRON "TAPER_INFO_FILES"/* name of environment variable of information file directories  */

#define COMPRESS_PROG "gzip -c"			 /* Compression to use */
						 /* Note that compression programme must return 0
						  * to indicate successful completion. If it doesn't
						  *  modify code in backup_file accordingly */

/*---------- Shouldn't need to change anything now ----------------------------- */
#define ERROR_NONE 0				 /* no error - clean exit */
#define ERROR_ILLEGAL_DIR -1			 /* Can't open directory */
#define ERROR_GETINFO -2		         /* Can't get stat info */
#define ERROR_MEMORY -3				 /* Unable to allocate memory*/
#define ERROR_OPENING_BACKUP -4			 /* Can't open backup device */
#define ERROR_USAGE -5				 /* Usage error */
#define ERROR_MAGIC -6				 /* Illegal magic number */
#define ERROR_REWIND -7				 /* Rewinding tape error */
#define ERROR_NO_INFO -8			 /* no info file found  */
#define ERROR_CREATING_INFO -9			 /* unable to create info file */
#define ERROR_WRITING -10			 /* Writing to backup device */
#define ERROR_READING -11			 /* Error reading from backup device */
#define ERROR_CONFIGURATION -12			 /* Error opening configuration file */
#define ERROR_OPENING_LOG -13			 /* Error opening log file */
#define ERROR_WRITING_INFO -14			 /* Error writing to info file */
#define ERROR_TRSIZE -15			 /* Error in size of maximum transfer block */
#define ERROR_NEW_TAPE -16			 /* Error getting new tape */
#define ERROR_EMPTY_ARCHIVE -17			 /* No archive on tape */

#define MAX_FNAME 1024				 /* max pathname length */
#define MAX_ARCHIVETITLE 50			 /* max size of archive title */

#define TAPER_MAGIC_NUMBER 0x729123			  
#define VOLUME_MAGIC 0x136213

#define TAPE_EXIST 0				 /* return values for */
#define BAD_MAGIC 1				 /* read vol dir routine */
#define TAPE_NOEXIST 2				 /* tape doesn't exist */
#define INFO_MISMATCH 4				 /* info file doesn't match archive */
#define TAPE_EXIST_EMPTY 5			 /* tape exists but is empty */

#define COLOR_DIRECTORY 5
#define COLOR_ONVOL 6
#define COLOR_SELECTED 7
#define COLOR_BOTTOM 8
#define COLOR_TITLE 9


/* Tape header information */
struct tape_header {
    long  magic;
    long  archive_id;
    int   tape_number;
    char  archive_title[MAX_ARCHIVETITLE];
};

/* Header of info file */
struct info_file_header {
    long archive_id;
    int  number_tapes;
    long info_file_size;			 /* note that this doesn't include the */
    int  number_volumes;			 /* volume/tape info at end of info file */
    long no_in_archive;
    char archive_title[MAX_ARCHIVETITLE];
};

/* Information for each file on tape */
struct file_info {
    long    act_size;	 
    int     volume;
    long    pos_in_archive;
    dev_t   dev;
    uid_t   uid;				 
    gid_t   gid;
    umode_t mode;				 /* mode of the file (if link, mode of link file) */
    umode_t org_mode;				 /* mode of the original file */
    long    size;
    time_t  atime;
    time_t  mtime;
    time_t  ctime;
    time_t  backup_time;
    char    name_len;
    char    compressed;
    long    checksum;				 /* just the sum of all the bytes in the file */
      						 /* if =-1, then problem backing up this file */
};


/* Information about which tape each volume is on */
struct volume_tape_info {
    int volume;					 /* volume */
    int tape;					 /* which tape it's on */
};


/* Representation in memory of a file in sel_restore */
struct file_entry {
    struct file_info    i;
    char                name[MAXNAMLEN];
    char                selected;		 /* 1 if selected directly, 2 if selected indirectly, 0 if not */
    struct file_entry   *in_vol_files;		 /* when used by sel_restore. For sel_backup, 1 = directly select */
    long                dirsize;		 /* size if directory */
};						 /* 2 = selected via update */

/* Representation in memory of a file in sel_backup  */
struct direntry {	
    struct stat     info;
    struct stat     org_info;
    struct dirent   entry;
};


/* Global options */
extern char  append;
extern char  hard_links;
extern char  compression;
extern int   lstrip;
extern char  sort_dir;
extern char  archive_title[MAX_ARCHIVETITLE];
extern char  ovrwrite;
extern char  rel_path[MAXNAMLEN];
extern char  pr_dir;
extern char  taper_info_files[MAXNAMLEN];
extern char  dir_selection;
extern char  log_file[MAXNAMLEN];
extern char  log_level;
extern int   max_tr_size;
extern int   block_size;
extern int   update;
extern dev_t proc_dev;
extern int   limit_vols;

/* Color defaults */
extern char color_title_foreground;
extern char color_title_background;
extern char color_main_foreground;
extern char color_main_background;
extern char color_dialog_foreground;
extern char color_dialog_background;
extern char color_status_foreground;
extern char color_status_background;
extern char color_selected_foreground;
extern char color_selected_background;
extern char color_directory_foreground;
extern char color_directory_background;
extern char color_onvol_foreground;
extern char color_onvol_background;
extern char color_bottom_foreground;
extern char color_bottom_background;

/* Variables (counts, pointers etc..) used by both backup/restore */
extern long no_sel;				 /* # files selected */
extern long no_in_archive;			 /* # files in archive */

extern long total_selected;			 /* # bytes selected */
extern long total_compressed;			 /* # file bytes in volume - compressed */
extern long total_uncompressed;			 /* # file bytes in volume - uncompressed */

extern int  dv;					 /* handle of backup device */
extern FILE *lf;				 /* handle of logfile */
extern int log_errors;
extern int log_warnings;

#ifdef MONITOR_TAPE
extern FILE *tl;
#endif
extern char tape[MAXNAMLEN];			 /* filename of rewinding tape device */
extern char ntape[MAXNAMLEN];			 /* filename of non-rewinding tape device */

extern char cf[MAXNAMLEN];			 /* common pathname prefix */
extern char stripped_cf[MAXNAMLEN];		 /* portion of common pathname prefix that is not stripped */

extern char *tr_buffer;				 /* transfer buffer */
extern char *info;				 /* pointer to information */
extern char *cp;				 /* offset used into above */

extern char *read_buffer;			 /* read buffer */
extern int read_offset;				 /* position in read buffer */
extern int read_buffer_count;			 /* how many bytes in read buffer */
extern char *write_buffer;			 /* write buffer */
extern int write_buffer_count;			 /* how many bytes in write buffer */
extern int write_offset;			 /* position in write buffer */
extern int block_size;				 /* size of buffer */

extern struct file_entry *vol_files;		 /* files on volume */
extern struct file_entry *sel_files;		 /* files selected by user */
extern struct file_entry *dirs;			 /* used by restore */
extern struct volume_tape_info *vt_info;	 /* which tape each volume is on */

extern struct tape_header tdh;			 /* headers for tape & */
extern struct info_file_header ifd;		 /* info file */

extern char cur_dir[MAXNAMLEN];			 

extern int vols_passed;				 /* number of volumes passed on this tape */


/* Common variables */
extern WINDOW    *win_main, *title, *files, *selection, *bottom;
extern int       screen_ylen_files, screen_ylen_selection;/* length of screens */
extern int       left_width, right_width;	 /* width of panels */
extern int       screen_ylen, screen_xlen;	 /* physical dims of screen */


typedef int (*file_passed_action) (struct file_info *fi, char *fn);
typedef void (*print_status) (WINDOW *mes_box, long cur_in_vol, long file_size,
			      char *fn, time_t start, time_t t_current);

/* Functions in common.c */
extern void read_environment();
extern void read_prefs_file(int argc, char *argv[]);
extern void setup_colors();
extern void do_exit(int c);
extern char *convert(char *s, long num);
extern inline void add_perm_string(char *s, char *a, int perm);
extern void tape_readheader(struct tape_header *t, int allowz);
extern int check_tape(int tape_required);
extern int tape_rewind();
extern int tape_fsf(int count);
extern int tape_erase();
extern int tape_create(int mode, int perms);
extern int ntape_open(int mode);
extern int tape_open(int mode);
extern int flush_buffers();
extern int tape_read(char *buf, size_t count);
extern int tape_write(char *buf, size_t count);
extern int tape_close();
extern int make_dirs(char *s);
extern int open_info_file(int must_exist, long archive_id);
extern void make_fn(char *dest, char *src, long no_in_vol);
extern int do_read_vol_dir(char *tape, int mess, int mode, int rvdir, int exist);
extern void mt_status(int dv, struct mtget *status);
extern inline int is_regfile(int dv);
extern void file_type(char *s, umode_t mode);
extern char *convtime(time_t t1, time_t t2);
extern void fixup_device_names();
extern long calc_checksum(int fd);
extern void open_logfile(char *prog);
extern void close_logfile(char *prog);
extern void write_log(char *s);
extern void write_error_log(char *s);
extern void write_warning_log(char *);
extern void write_fatal_log(char *s);
extern void read_volheader(long *no_in_vol);
extern char on_or_off(char *arg);
extern char common_parse_args(int argc, char *argv[], int *c);
extern void common_usage();
extern void mktape_usage();
extern void calc_tape_pos(int vol_no, int *tape, int *pos);
extern int traverse_volume(file_passed_action action, long no_in_vol,
			   time_t t_start, WINDOW *mes_box, int full_traverse, 
			   int doing_mkinfo, print_status ps);
extern void common_restore_loop(file_passed_action action, int doing_mkinfo,
				print_status ps);
extern void change_dollar(char *s);
extern void init_buffers();
extern void final_message(char *prog);
extern void print_title_line();
