/*
 *
 */

#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/locks.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/file.h>
#include <linux/dcache.h>
#include <linux/smp_lock.h>

#include <asm/system.h>
#include <asm/uaccess.h>

enum {
        PVFSHOSTLEN = 64,
        PVFSDIRLEN = 1023
};

enum {
	DAV_SUPER_MAGIC = 0x7890abcd
};


enum {
        DAV_HOSTLEN = 1024,
        DAV_PATHLEN = 1024,
	DAV_IDLEN = 80,
	DAV_PASSLEN = 80,
};

/*
 * Data from mount.davfs command
 * 
 * You should keep same copy of mount module
 */
struct dav_mount_data {
    unsigned info_magic;
    int flags;
    int port;
    char host[DAV_HOSTLEN];
    char path[DAV_PATHLEN];
    char id  [DAV_IDLEN];
    char pass[DAV_PASSLEN];
    char mpoint[DAV_PATHLEN];
    /* 'r' or 'rw' */
    char amode[3];
    /* socket */
    unsigned int dav_fd;

    /* mount demonized pid */
    long pid;

    /* user id ang group id */
    umode_t         mode;
    uid_t           uid;
    gid_t           gid;

    /* SSL mode */
    int ssl_mode;

    /* for Proxy */
    char proxy[DAV_HOSTLEN];
};

struct dav_sb_info {
    int flags;

    /* Initial path */
    char *path;
    
    /* server */
    int  state;
    struct file * sock_file;
    struct socket *sock;
    pid_t conn_pid;
    struct smb_conn_opt opt;

    /* general buff */
    char *req;
    char *buf;

    char *connect;
    int ret_code;
    int length;

    int ttl;
    
    struct semaphore sem;
    wait_queue_head_t wait;

    struct super_block *sb;
    int rcls, err;

    uid_t           uid;
    gid_t           gid;

    umode_t         file_mode;
    umode_t         dir_mode;
  
};

struct dav_i_info {
    /*
     * file handles are local to a connection. A file is open if
     * (open == generation).
     */ 
    unsigned int open;      /* open generation */
    unsigned long fileid;   /* What id to handle a file with? */
    __u16 attr;             /* Attribute fields, DOS value */
    
    __u16 access;           /* Access mode */
    __u16 flags;            /* status flags */
    unsigned long oldmtime; /* last time refreshed */
    unsigned long closed;   /* timestamp when closed */
    unsigned openers;       /* number of fileid users */
};

/* metadata associated defines */
typedef uint64_t pvfs_handle_t;
typedef uint64_t pvfs_off_t;
typedef uint64_t pvfs_size_t;
typedef time_t pvfs_time_t;
typedef uint32_t pvfs_uid_t;
typedef uint32_t pvfs_gid_t;
typedef uint32_t pvfs_mode_t;
typedef uint32_t bitfield_t;


#define DAV_MAXNAMELEN 255
#define DAV_MAXPATHLEN 1024
#define DAV_HEAD_SIZE 20

#define DAV_SERVER(inode)    ((inode->i_sb->u.generic_sbp))
#define DAV_INOP(inode)      ((inode->u.generic_ip))


/*
 * Contains all relevant data on a DAV networked file.
 */
struct dav_fattr {
    __u16 attr;
    
    char	    f_name[DAV_MAXNAMELEN];
    int		    f_name_len;	
    unsigned long   f_ino;
    umode_t         f_mode;
    nlink_t         f_nlink;
    uid_t           f_uid;
    gid_t           f_gid;
    kdev_t          f_rdev;
    off_t           f_size;
    time_t          f_atime;
    time_t          f_mtime;
    time_t          f_ctime;
    unsigned long   f_blksize;
    unsigned long   f_blocks;
};

/*
** data struct to communicate to davfsd
** it should keep same size with davfsd 
*/
struct dav_finfo {
    char            f_name[DAV_MAXNAMELEN];
    int             f_name_len; 
    int             f_isdir;
    off_t           f_size;
    time_t          f_atime;
    time_t          f_mtime;
    time_t          f_ctime;
};

/*
** data struct to communicate to davfsd for quota
** it should keep same size with davfsd 
*/
struct dav_statfs {
    long f_blocks;
    long f_bfree;
};


/*      
 * This is the time we allow an inode, dentry or dir cache to live. It is bad
 * for performance to have shorter ttl on an inode than on the cache. It can
 * cause refresh on each inode for a dir listing ... one-by-one
 */             
#define DAV_MAX_AGE(server) (((server)->ttl * HZ) / 1000)
      
struct dav_cache_head {
        time_t          mtime;  /* unused */
        unsigned long   time;   /* cache age */
        unsigned long   end;    /* last valid fpos in cache */
        int             eof;
};

#define DAV_DIRCACHE_SIZE       ((int)(PAGE_CACHE_SIZE/sizeof(struct dentry *)))

#define DAV_FIRSTCACHE_SIZE     ((int)((DAV_DIRCACHE_SIZE * \
        sizeof(struct dentry *) - sizeof(struct dav_cache_head)) / \
        sizeof(struct dentry *)))

#define DAV_DIRCACHE_START      (DAV_DIRCACHE_SIZE - DAV_FIRSTCACHE_SIZE)
union dav_dir_cache {
        struct dav_cache_head   head;
        struct dentry           *dentry[DAV_DIRCACHE_SIZE];
};


struct dav_cache_control {
        struct  dav_cache_head          head;
        struct  page                    *page;
        union   dav_dir_cache           *cache;
        unsigned long                   fpos, ofs;
        int                             filled, valid, idx;
};

/*
 * Flags for the in-memory inode
 */
#define DAV_F_LOCALWRITE        0x02    /* file modified locally */


/* From apache source code                                              */
/* ----------------------- HTTP Status Codes  ------------------------- */

/* The size of the static array in http_protocol.c for storing
 * all of the potential response status-lines (a sparse table).
 * A future version should dynamically generate the apr_table_t at startup.
 */

#define RESPONSE_CODES 55

#define HTTP_CONTINUE                      100
#define HTTP_SWITCHING_PROTOCOLS           101
#define HTTP_PROCESSING                    102
#define HTTP_OK                            200
#define HTTP_CREATED                       201
#define HTTP_ACCEPTED                      202
#define HTTP_NON_AUTHORITATIVE             203
#define HTTP_NO_CONTENT                    204
#define HTTP_RESET_CONTENT                 205
#define HTTP_PARTIAL_CONTENT               206
#define HTTP_MULTI_STATUS                  207
#define HTTP_MULTIPLE_CHOICES              300
#define HTTP_MOVED_PERMANENTLY             301
#define HTTP_MOVED_TEMPORARILY             302
#define HTTP_SEE_OTHER                     303
#define HTTP_NOT_MODIFIED                  304
#define HTTP_USE_PROXY                     305
#define HTTP_TEMPORARY_REDIRECT            307
#define HTTP_BAD_REQUEST                   400
#define HTTP_UNAUTHORIZED                  401
#define HTTP_PAYMENT_REQUIRED              402
#define HTTP_FORBIDDEN                     403
#define HTTP_NOT_FOUND                     404
#define HTTP_METHOD_NOT_ALLOWED            405
#define HTTP_NOT_ACCEPTABLE                406
#define HTTP_PROXY_AUTHENTICATION_REQUIRED 407
#define HTTP_REQUEST_TIME_OUT              408
#define HTTP_CONFLICT                      409
#define HTTP_GONE                          410
#define HTTP_LENGTH_REQUIRED               411
#define HTTP_PRECONDITION_FAILED           412
#define HTTP_REQUEST_ENTITY_TOO_LARGE      413
#define HTTP_REQUEST_URI_TOO_LARGE         414
#define HTTP_UNSUPPORTED_MEDIA_TYPE        415
#define HTTP_RANGE_NOT_SATISFIABLE         416
#define HTTP_EXPECTATION_FAILED            417
#define HTTP_UNPROCESSABLE_ENTITY          422
#define HTTP_LOCKED                        423
#define HTTP_FAILED_DEPENDENCY             424
#define HTTP_INTERNAL_SERVER_ERROR         500
#define HTTP_NOT_IMPLEMENTED               501
#define HTTP_BAD_GATEWAY                   502
#define HTTP_SERVICE_UNAVAILABLE           503
#define HTTP_GATEWAY_TIME_OUT              504
#define HTTP_VERSION_NOT_SUPPORTED         505
#define HTTP_VARIANT_ALSO_VARIES           506
#define HTTP_INSUFFICIENT_STORAGE          507
#define HTTP_NOT_EXTENDED                  510

/*
 * Access modes when opening a file
 */
#define DAV_ACCMASK     0x0003
#define DAV_O_RDONLY    0x0000
#define DAV_O_WRONLY    0x0001
#define DAV_O_RDWR      0x0002

/* structure access macros */
#define dav_server_from_inode(inode) ((inode)->i_sb->u.generic_sbp)
#define dav_server_from_dentry(dentry) ((dentry)->d_sb->u.generic_sbp)
#define dav_SB_of(server) (server->sb)
    
/* linux/fs/smbfs/file.c */
extern struct inode_operations dav_file_inode_operations;
extern struct file_operations dav_file_operations;
extern struct address_space_operations dav_file_aops;

/* dir.c */
extern struct inode_operations dav_dir_inode_operations;
extern struct file_operations dav_dir_operations;
void dav_new_dentry(struct dentry *dentry);
void dav_renew_times(struct dentry *);

/* linux/fs/smbfs/ioctl.c */
int dav_ioctl (struct inode *, struct file *, unsigned int, unsigned long);

/* linux/fs/smbfs/inode.c */
struct super_block *dav_read_super(struct super_block *, void *, int);
void dav_get_inode_attr(struct inode *, struct dav_fattr *);
void dav_set_inode_attr(struct inode *, struct dav_fattr *);
void dav_invalidate_inodes(struct dav_sb_info *);
int  dav_revalidate_inode(struct dentry *);
int  dav_notify_change(struct dentry *, struct iattr *);
struct inode *dav_iget(struct super_block *, struct dav_fattr *);


/* cache.c */
void dav_invalid_dir_cache(struct inode * dir);
void dav_invalidate_dircache_entries(struct dentry *parent);
struct dentry * dav_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos);
int dav_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
		   struct dav_cache_control *ctrl, struct qstr *qname,
		   struct dav_fattr *entry);

/* proc */
int dav_get_rsize(struct dav_sb_info *server);
int dav_get_wsize(struct dav_sb_info *server);
int dav_proc_readdir(struct file *filp, void *dirent, filldir_t filldir,
		     struct dav_cache_control *ctl);

int dav_proc_getattr(struct dentry *dir, struct dav_fattr *fattr);
int dav_proc_mv(struct dentry *old_dentry, struct dentry *new_dentry);
int dav_proc_mkdir(struct dentry *dentry);
int dav_proc_rmdir(struct dentry *dentry);
int dav_proc_unlink(struct dentry *dentry);
int dav_proc_trunc(struct dav_sb_info *server, long fid, __u32 length);
int dav_proc_setattr(struct dentry *dir, struct dav_fattr *fattr);
int dav_proc_settime(struct dentry *dentry, struct dav_fattr *fattr);
int dav_proc_open(struct dav_sb_info *server, struct dentry *dentry, int wish);
int dav_open(struct dentry *dentry, int wish);
int dav_close(struct inode *ino);
int dav_close_fileid(struct dentry *dentry, long fileid);
int dav_proc_create(struct dentry *dentry, __u16 attr, time_t ctime, long *fileid);
int dav_proc_read(struct inode  *inode, off_t offset, int count, char *data);
int dav_proc_write(struct inode *inode, off_t offset, int count, const char *data);
void dav_init_root_dirent(struct dav_sb_info *server, struct dav_fattr *fattr);
int dav_proc_disconnect(struct dav_sb_info *server);
int dav_proc_statfs(struct dentry *dentry, struct statfs *buf);
static inline void
dav_age_dentry(struct dav_sb_info *server, struct dentry *dentry)
{
    dentry->d_time = jiffies - DAV_MAX_AGE(server);
}


/* socket.c */
int _recvfrom(struct socket *socket, unsigned char *ubuf, int size, unsigned flags);
int dav_send_raw(struct socket *socket, unsigned char *source, int length);
int dav_receive_raw(struct socket *socket, unsigned char *target, int length);
int do_tcp_rcv(struct dav_sb_info *server, void *buffer, size_t len);
int dav_sendline_raw(struct socket *socket, unsigned char *target);
int dav_readline_raw(struct dav_sb_info *server, unsigned char *target, int length);
struct socket *dav_get_sock(struct dav_sb_info *server, unsigned int fd);





