#ifndef IMUTIL_HH_
#define IMUTIL_HH_
#include <vector>
#include <string>
#include <sys/types.h>
#include "basictype.hh"
#include "IMBasicObject.hh"

struct DirectoryEntry {
    string filename;
    string dirname;
    string fullname;
    bool readable_p;
    bool writable_p;
    bool directory_p;
};
typedef vector<DirectoryEntry> DirectoryInfoVec;

class DirectoryInfo
{
    string path;
    bool subdirp;
    bool unreadablep;
    DirectoryInfoVec dirvec;

    bool addfile(const char *filename);

  public:
    DirectoryInfoVec* get_directory_info() { return &dirvec; }
    bool refresh(
	const char *path = NULL
    );
    DirectoryInfo(
	bool include_subdir_p = false, 
	bool include_unreable_p = false
    );
};


class IMSocketAddress;
class IMSocketTrans;
class IMSocket;
typedef vector<IMSocketAddress> IMSocketAddressVec;
typedef vector<IMSocket*> IMSocketVec;

class IMSocketAddress
{
  public:
    enum ADDRESS_TYPE {
	    INET,
	    UNIX_DOMAIN,
	    UNIX_DOMAIN_PER_USER
    };
    enum TRANSPORT_TYPE {
            NORMAL,
            TLS
    };

  private:
    ADDRESS_TYPE type;
    TRANSPORT_TYPE trans_type;
    string address;
    string service;
    void *addrinfo;

    void* get_addrinfo();
    void configure_socket(
	int fd
    );
    void bind_fail(
	int fd
    );
    int setup_inet(
	void *paddressinfo
    );
    int setup_unix();

  public:
    int create_sockets(
	IMSocketVec &sockvec
    );

    IMSocketAddress(
	ADDRESS_TYPE type,
	const string &address,
	const string &service
    );
    IMSocketAddress(
        ADDRESS_TYPE type,
        TRANSPORT_TYPE trans_type,
        const string &address,
        const string &service
    );
    ~IMSocketAddress();
};

class IMSocket
{
  public:
    enum LISTEN_STATUS {
	    CLOSED,
	    OPEN,
	    ERROR
    };
  private:
    int fd;
    int trans_type;
    enum LISTEN_STATUS status;

    bool do_listen();

    // inhibit duplication
    IMSocket(
	const IMSocket& a
    );
    IMSocket& operator=(
	const IMSocket& a
    );

  public:
    bool listen();
    IMSocketTrans* accept();
    int get_fd();

    enum LISTEN_STATUS get_status() const
    { return status; }

    IMSocket(
	int fd
    );
    IMSocket(
        int fd,
        int trans_type
    );
    ~IMSocket();
};

class IMSocketTrans
{
    int fd;
    // inhibit duplication.
    IMSocketTrans(
	const IMSocketTrans& a
    );
    IMSocketTrans& operator=(
	const IMSocketTrans& a
    );
  public:
    int get_fd() const
    { return fd; }
    virtual int send(
	const void *,
	size_t n
    );
    virtual int recv(
	void*,
	size_t n
    );
    IMSocketTrans(int fd);
    ~IMSocketTrans();

  // friend class IMSocket;
};

class IMSocketListen
{
    enum IMSocket::LISTEN_STATUS status;
    IMSocketVec sockvec;

    // inhibit duplication.
    IMSocketListen(
	const IMSocketListen& a
    );
    IMSocketListen& operator=(
	const IMSocketListen& a
    );

  public:
    bool errorp()
    { return (status == IMSocket::ERROR); }
    bool listen(
	IMSocketAddressVec &endvec
    );
    IMSocketTrans* accept();
    IMSocketListen();
    ~IMSocketListen();
};

// singleton class
class IMDaemon
{
    bool already_finished;
    static IMDaemon *pimdaemon;
    void closefd();
    bool discard_parent();
    bool daemonize();
    
    IMDaemon();
  public:
    static IMDaemon* get_instance();
    static void cleanup();
    void setup(
	const char *todir
    );
};

/* file manipulation fuctions */

// return NULL if error occurs.
extern CARD8BIT* IM_read_file(
    const char* filename,
    int size
);
// return -1 if error occurs.
extern int IM_file_size(
    const char* filename
);

class IMKeyParser
{
    IMKeySpecList keys;

    IMKeySpec *IMKeyParser::parse_key(string s);
  public:
    string generate_key(IMKeySpec &spec);
    IMKeySpecList& get_parsedkeys()
    { return keys; }
    IMKeyParser(const char *strings);
    ~IMKeyParser();
};

#endif /* not IMUTIL_HH_ */

/* Local Variables: */
/* c-file-style: "iiim-project" */
/* End: */
