#ifndef IMAPLIB_HEADER
#define IMAPLIB_HEADER
#ifdef WIN32
#define USING_STATIC_LIBICONV 1
#endif 
#include "ziconv.h"
#include "tcplib.h"
#include "defines.h"
#include "dstr.h"

#include "imap_flags.h"


#define TAGSZ 5

struct imap_connection;
typedef struct imap_connection ImapCon;

struct imap_connection {
	Chan *c;
	
	char *user;

	void (*cb)(void*,ImapCon*);
	void *data;

	char *result;
	char *ptr;

	char tag[TAGSZ];
	int itag;

	int loggedin;
	int idling, idling2;
	int stop_idle;
    int stop_idle_pending;
    int dropout_type;    
    int last_idle_tick, last_idle_response;

	FILE *log;			// Debug logging of communications on this IMAP channel
	int (*imsg)(const char *, ...);		// Logging to normal log file
	
	int expect_long;	// Expect long lines so use alloc based buffers
	char smallbf[BFSZ];
	char *bigbf;		// buffer that needs to be freed
    Dstr *outbf;			// dynamic string for any length output commands

    int exiting;
};

/**/
ImapCon *im_new();
void im_free(ImapCon **i);

void im_set_cb(ImapCon *i, void (*cb)(void*,ImapCon*), void *data);

int im_connect(ImapCon *i, char *host, int port);
void im_disconnect(ImapCon *i);

int im_login(ImapCon *i, char *user, char *pass);
int im_login_sm(ImapCon *i, char *user, char *pass);
int im_logout(ImapCon *i);

int im_command(ImapCon *i, int read_response, char *format, ...);

int im_capability(ImapCon *i);

int im_select(ImapCon *i, char *mbx);
int im_examine(ImapCon *i, char *mbx);
int im_create(ImapCon *i, char *mbx);
int im_delete(ImapCon *i, char *mbx);
int im_rename(ImapCon *i, char *ombx, char *nmbx);
int im_subscribe(ImapCon *i, char *mbx);
int im_unsubscribe(ImapCon *i, char *mbx);

int im_list(ImapCon *i, char *ref, char *mbx);
int im_lsub(ImapCon *i, char *ref, char *mbx);

int im_status(ImapCon *i, char *mbx, char *itms);

int im_append(ImapCon *i, char *mbx, char *flags, char *date, int length, int(*lines)(void*,ImapCon*), void *data);

int im_check(ImapCon *i);
int im_close(ImapCon *i);
int im_expunge(ImapCon *i);

int im_search(ImapCon *i, char *charset, char *criteria);
int im_uid_search(ImapCon *i, char *charset, char *criteria);

int im_fetch(ImapCon *i, char *msgset, char *items);
int im_store(ImapCon *i, char *msgset, char *item, char *value);
int im_copy(ImapCon *i, char *msgset, char *mbx);

int im_uid_fetch(ImapCon *i, char *uidset, char *items);
int im_uid_store(ImapCon *i, char *uidset, char *item, char *value);
int im_uid_copy(ImapCon *i, char *uidset, char *mbx);
int im_idle(ImapCon *i);

int im_rawcmd(ImapCon *i, char *cmd);

/**/
char *im_tag(ImapCon *i);
int im_send_command(ImapCon *i, char *bf, int bfsz, int x);
int im_read_response(ImapCon *i);
int im_end(ImapCon *i);
int im_ok(ImapCon *i);
int im_no(ImapCon *i);
int im_bad(ImapCon *i);
int im_err(ImapCon *i);
int im_plus(ImapCon *i);
int im_star(ImapCon *i);
int im_idle_response(ImapCon *i);

int im_decode_folder_old(char *folder, char *res, int bfsz);
int im_decode_folder(char *folder, char *res, int bfsz);
int im_encode_folder(unsigned char *folder, char *res, int bfsz);

int im_parse(ImapCon *i, char *res, int bfsz);
char *im_rest(ImapCon *i);

int im_parse_fetch(ImapCon *i, char *item, char *value, int bfsz);
int im_parse_append_uid(ImapCon *i, char *item, char *value, int bfsz);
int im_parse_copy_uid(ImapCon *i, char *new_uids, int bfsz);
int im_parse_bodystructure(ImapCon *i, PartAllocator *pa);
int im_parse_envelope(ImapCon *i, int foo);

int im_parse_flags(char *string);
int im_parse_flags_real(char *string, char *extra);
char *im_make_flags(int flags, char *bf, int bfsz);

int im_read_data_direct(ImapCon *i, char *mem, int bytes);
int im_read_data(ImapCon *i, int bytes, int(*xwrite)(void*,int,int,void*), void *xp);
int im_skip_data(ImapCon *i, int bytes);

int im_rawcmd_large(ImapCon *i, char *cmd, int(*cb)(void*,ImapCon*), void *data);
char *mime_header_decode(char *header, char *res, int len);

void im_logimsg_init(ImapCon *i, int (*fn)(const char *, ...));
int im_expect_long(ImapCon *i, int expect_long);

#define IMAP_DROPOUT_UNKNOWN 1
#define IMAP_DROPOUT_SLEEP 2
#define IMAP_DROPOUT_HEARTBEAT 3


int im_idle_setup(ImapCon *i);
int im_idle_tick(ImapCon *i, int *data_ready);
int im_idle_fix(ImapCon *i);
int im_idle_exit(ImapCon *i);

void im_exit(ImapCon *i);

#endif
