/* $Id: cue.h,v 1.110 2015/09/29 13:17:42 onoe Exp $ */

/*-
 * Copyright (c) 1998-2001 Atsushi Onoe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>

#include "conf.h"
#include "curses.h"

#undef CTRL
#define	CTRL(x)		(((x) & ~0x20) - '@')

typedef struct cbuf {
	char	*ptr;
	int	len;
} cbuf_t;
typedef struct ccbuf {
	const char	*ptr;
	int	len;
} ccbuf_t;

/* cbuf_t access macros */
#define	CP(cb)		((cb)->ptr)
#define	CL(cb)		((cb)->len)
#define	CE(cb)		(CP(cb) + CL(cb))
#define	CSETP(cb, p)	(CL(cb) = 0, CP(cb) = (p))
#define	CSETE(cb, p)	(CL(cb) = (p) - CP(cb))
#define	CADDP(cb, n)	(CL(cb) -= (n), CP(cb) += (n))
#define	CADDE(cb, n)	(CL(cb) += (n))
#define	CSETSTR(cb, s)	(CL(cb) = strlen(s), CP(cb) = (s))
#define	CSETBUF(cb, b)	(CL(cb) = sizeof(b), CP(cb) = (b))

struct clist {
	struct clist *next;
	cbuf_t	buf;
};

#define	HT_UNKNOWN	0
#define	HT_SUBJECT	1
#define	HT_FROM		2
#define	HT_DATE		3
#define	HT_TO		4
#define	HT_REPLIED	5
#define	HT_FORWARDED	6
#define	HT_MIME		7
#define	HT_CTYPE	8
#define	HT_CTE		9
#define	HT_MSGID	10
#define	HT_CC		11
#define	HT_REPLYTO	12
#define	HT_CDESC	13
#define	HT_CDISP	14
#define	HT_RESENT	15
#define	HT_MAX		16

#define	HTF_HIDDEN	0x01	/* hide at initial */
#define	HTF_NOENCODE	0x02	/* no mime encoded */
#define	HTF_OVERWRITE	0x04	/* overwritten when inline */
#define	HTF_NOSEND	0x08	/* strip when forward */
#define	HTF_STRUCT	0x10	/* structured header */
#define	HTF_MATCHLINE	0x20	/* match against whole line */

struct header_type {
	char	*key;
	short	flags;
	u_char	type;
	char	keylen;
};

struct header {
	ccbuf_t	buf;	/* one line (non decoded) */
	cbuf_t	dbuf;	/* decoded buf */
	ccbuf_t	val;	/* decoded value (part of dbuf) for non-struct */
	struct header_type *type;
};

struct filedb {
	struct filedb *next;
	struct filedb *prev;
	struct linedb *lhead;
	struct linedb *ltail;
	struct linedb *lcur;
	char	*name;
	int	msgnum;
	const char *ptr;
	const char *eptr;
	int	lines;
	int	flags;
	int	skip_lines;
	struct	kbuf *kbuf;
	cbuf_t	mmap;
	ccbuf_t	buf_mhdr;		/* MIME header */
	ccbuf_t	buf_hdr;		/* Mail header */
	ccbuf_t	buf_body;		/* Body */
	struct stat stbuf;
	/* header */
	struct	header *hdr;
	int	hdrs;
	int	hdr_size;
	int	hdr_lines;
	ccbuf_t	hdr_val[HT_MAX];
	/* mime/multipart */
	ccbuf_t	type;
	ccbuf_t	boundary;
	ccbuf_t	sproto;
	ccbuf_t	separator;
	int	partnum;
	int	partdepth;
	ccbuf_t	filename;
	time_t	filetime;
	struct filedb *uppart;
	struct filedb *nextpart;
	struct filedb *prevpart;
};

/* filedb.flags */
#define	FDB_CHARSET	0x0000003f
#define	FDB_NOTEXT	0x00000040
#define	FDB_NOCONV	0x00000080
#define	FDB_ENCODE	0x00000700
#define	FDB_EOF		0x00000800
#define	FDB_INLINE	0x00001000
#define	FDB_MULTIPART	0x00002000
#define	FDB_SUBPART	0x00004000
#define	FDB_ALTERNATIVE	0x00008000
#define	FDB_HIDDEN	0x00010000
#define	FDB_MAIL	0x00020000
#define	FDB_PARSED	0x00040000
#define	FDB_PURGED	0x00080000
#define	FDB_DRAFT	0x00100000
#define	FDB_SIGNED	0x00200000
#define	FDB_ENCRYPTED	0x00400000
#define	FDB_VERIFIED	0x00800000
#define	FDB_DECRYPTED	0x01000000
#define	FDB_NOMMAP	0x02000000
#define	FDB_TARFILE	0x04000000
#define	FDB_FORCEDISP	0x08000000
#define	FDB_NOMIME	0x10000000
#define	FDB_HTML	0x20000000
#define	FDB_CALENDAR	0x40000000
#define	FDB_GUESSED	0x80000000

/* These 8 charset MUST match the definition in decode.c */
#define	FDB_CS_DEFAULT	0
#define	FDB_CS_JP	1
#define	FDB_CS_SJIS	2
#define	FDB_CS_UTF8	3
#define	FDB_CS_ASCII	4
#define	FDB_CS_JP2	5
#define	FDB_CS_SJIS2	6
#define	FDB_CS_GBK	7

#define	FDB_ENC_NONE	0x00000000
#define	FDB_ENC_Q	0x00000100
#define	FDB_ENC_B64	0x00000200
#define	FDB_ENC_GZ64	0x00000300
#define	FDB_ENC_UU	0x00000400
#define	FDB_ENC_BINHEX	0x00000500
#define	FDB_ENC_ZIP	0x00000600

struct kbuf {
	struct kbuf *next;
	int inuse;
	char buf[CHARBLOCK];
};

struct abuf {
	int	size;
	cbuf_t	buf;
};

struct linedb {
	struct linedb *next;
	struct linedb *prev;
	int	index;
	int	inuse;
	ccbuf_t	line[LINEBLOCK];
	u_char	more[(LINEBLOCK+7)/8];
};

struct window {
	int	y;	/* start y position */
	int	lines;	/* lines for content */
	int	off;	/* offset within content */
};

struct config {
	int	moption;
	/* config file update */
	char	*path;
	int	notfound;
	struct stat statbuf;
	/* %refile */
	struct refile_list {
		struct refile_list *next;
		cbuf_t	hdr;
		cbuf_t	pat;
		cbuf_t	fol;
	} *refile_list;
	/* %default */
	struct clist *myaddr;
	char	*bcc;
	char	*inc;
	char	*send;
	char	*editor;
	char	*folder;
	char	*statfile;
	char	*spam;
	int	statbackup;
	int	numwidth;
	int	lines;
	int	linesall;
	int	disptime;
	char	*mailcap;
	char	*addrbook;
};

struct state {
	struct window	folwin;	/* summary */
	struct window	msgwin;	/* message */
	struct window	hlpwin;	/* help */
	struct folder *folder;
	struct filedb *message;
	struct filedb *help;
	char	*helptitle;
	int	msgmode;
	int	nomime;
	int	prevdir;	/* previous move direction */
	int	mxoff;		/* current x offset for I-search */
	int	myoff;		/* current y offset for I-search, -1 for fol */
	int	mlen;		/* current match length for I-search */
	char	status[LINE_WIDTH+1];
	struct config config;
	char	*refile[MAX_REFILE];	/* last refile */
};

struct folder {
	cbuf_t	name;		/* null terminated */
	int	pos;
	int	nmsg;
	int	szmsg;
	int	incpos;		/* pos of new message */
	int	nmark;
	int	flags;
	struct stat stbuf;
	struct msginfo {
		int	num;
		char	mark;
		char	unused[3];
		cbuf_t	scan;
		time_t	date;
		char	*refile[MAX_REFILE];
	}	*msg;
};

/* folder.flags */
#define	FOL_DRAFT	0x0001
#define	FOL_POSAVAIL	0x0002
#define	FOL_TAR		0x0004
#define	FOL_SORT	0x0008


/* mode for comp_edit() */
#define	COMP_NEW	0
#define	COMP_REPL	1
#define	COMP_REPLYANK	2
#define	COMP_REPLORIG	3
#define	COMP_REPLYMARK	4
#define	COMP_FORW	5
#define	COMP_FORWMARK	6

/* direction for message_multipart_next() */
#define	MPART_NONE	0
#define	MPART_NEW	1
#define	MPART_NEXT	2
#define	MPART_END	3

/* type for proc */
#define	PTYPE_ANY	-1
#define	PTYPE_OTHER	0
#define	PTYPE_INC	1
#define	PTYPE_SEND	2
#define	PTYPE_EDITOR	3
#define	PTYPE_SYNC	4
#define	PTYPE_TEST	5

/* useful macros */
#define	CMATCH(str, buf)	((buf)->len == sizeof(str)-1 && \
				 strncasecmp((buf)->ptr, str, sizeof(str)-1) == 0)
#define	CSUBMATCH(str, buf)	((buf)->len >= sizeof(str)-1 && \
				 strncasecmp((buf)->ptr, str, sizeof(str)-1) == 0)
#define	CSUBST(str1, str2, buf)	csubst(str1, str2, buf)

/* conf.c */
void conf_update(struct state *state);
int conf_myaddr(struct state *state, ccbuf_t *buf);

/* decode.c */
void decode_init(void);
int decode_header(cbuf_t *hdr, int flags);
int decode_param(ccbuf_t *param, int seq, int ext);
int decode_text(const char **pp, const char *ep, cbuf_t *res, int flags);
int charset_id(const ccbuf_t *name);
const char *charset_name(int id);
int charset_completion(char *candidate, void (*callback)(void *arg, const char *entry), void *arg);
int charset_guess(const char *p, const char *ep);
void print_jis(FILE *fp, const char *fmt, ...);
void print_hdr(FILE *fp, const char *fmt, ...);
void save_part(struct state *state, int all);
void save_base64_encode(FILE *fp, cbuf_t *buf);

/* disp.c */
void disp_update(struct state *state);
void disp_msgmode(struct state *state, int on);
void disp_time(struct state *state);
void disp_center(struct state *state);
void disp_init(void);
void disp_redraw(struct state *state);
void disp_setlines(struct state *state);
void disp_help(struct state *state);
int disp_getmore(struct filedb *fdb, int last);

/* edit.c */
char *edit_stline(struct state *state, char *buf, int size, int (*completion)(char *candidate, void (*callback)(void *arg, const char *entry), void *arg));
int edit_yn(struct state *state, const char *fmt, ...);
int read_passwd(const char *prompt, char *buf, int size);

/* exec.c */
int exec_del(struct folder *folder, int pos);
void exec_mark(struct state *state);
void exec_pack(struct state *state);
void exec_sort(struct state *state);
void exec_inc(struct state *state);
void exec_inc_wait(struct state *state);
void exec_send(struct state *state, int marked);
int exec_editor(struct state *state, const char *folname, int num, const char *suf);

/* helper.c */
void helper_exec(struct state *state);

/* file.c */
struct filedb *fdb_open(const char *name);
struct filedb *fdb_mkpart(ccbuf_t *buf);
void fdb_replace(struct filedb *fdb, cbuf_t *buf);
ccbuf_t *fdb_read(struct filedb *fdb, int linenum);
int fdb_ismore(struct filedb *fdb, int linenum);
void fdb_getline(struct filedb *fdb, ccbuf_t *buf);
void fdb_reload(struct filedb *fdb, int linenum, const char *ptr);
void fdb_clear(struct filedb *fdb);
void fdb_purge(const char *name);

/* folder.c */
int folder_completion(char *candidate, void (*callback)(void *arg, const char *entry), void *arg);
struct folder *folder_open(const char *name, int doupdate);
ccbuf_t *folder_read(struct state *state, int n);
void folder_purge(struct state *state, int num);
struct folder *folder_modified(void);
void folder_update(struct folder *fl, int force);
void folder_change(struct state *state);
int export_mark(struct state *state);
int import_mark(struct state *state);

/* message.c */
void message_open(struct state *state, int force);
void message_parseall(struct filedb *fdb);
ccbuf_t *message_ctype_param(struct filedb *fdb, const char *name, const char *p, const char *ep);
void message_header_settype(struct header *hdr);
const char *message_parse_addr(const char *p, const char *ep, ccbuf_t *rbuf);
int message_note(struct filedb *fdb);
void message_scan(struct state *state, struct msginfo *msg);
void message_multipart_next(struct filedb *fdb, int dir);
void message_header(struct filedb *fdb);
void message_jump(struct state *state);
void message_next(struct state *state, int n, int ismark);
void message_debug(struct state *state);
void message_encoding(struct state *state);

/* refile.c */
int refile_guess(struct state *state, struct msginfo *msg);
int refile_folder(struct state *state);
int refile_again(struct state *state, struct msginfo *msg);

/* reply.c */
void compose(struct state *state);
void reply(struct state *state, int mode);
void reply_mark(struct state *state, FILE *fp);
void forward(struct state *state, int mpart);
void forward_mark(struct state *state);
void exec_anno(struct state *state, char *path, size_t);

/* search.c */
void isearch(struct state *state, struct filedb *fdb, int dir);
void search_mark_folder(struct state *state, int dir);
void rguess_mark_folder(struct state *state, int dir);
void pick_mark_folder(struct state *state, int dir);

/* medit.c */
void medit_parse(struct filedb *fdb);
int mpart_issep(const char *p, const char *ep, ccbuf_t *sep);
int mpart_edit(struct state *state, int subflag);
int mpart_undo(struct state *state);
int mpart_single(struct state *state);
int mpart_multi(struct state *state);
int mpart_append(struct state *state, char *insert, char *file);
int mpart_delete(struct state *state);
int mpart_sign(struct state *state, const char *proto, int (*smime_enter)(FILE *fp, void *arg, ccbuf_t *cb), int (*smime_sign_part)(FILE *fp, void *arg), void *arg);
int mpart_unsign(struct state *state);

/* date.c */
time_t parse_date(ccbuf_t *cb);

/* util.c */
char *copy_kbuf(struct kbuf **kbufp, const char *buf, int len);
char *copy_abuf(struct abuf *abuf, const char *buf, int len);
int csubst(char *str1, char *str2, cbuf_t *buf);
void fname_expand(char *name, char *buf);
int fname_completion(char *candidate, void (*callback)(void *arg, const char *entry), void *arg);
int builddir(char *path, mode_t omode);

#ifdef MALIAS
/* malias.c */
int malias_completion(char *candidate, void (*callback)(void *arg, const char *entry), void *arg);
int malias_expand(char *addr, int addrlen);
#endif

/* banner.c */
char *banner(const char *str);

/* proc.c */
int proc_running(int type);
int proc_getstate(int type, int *status, char *buf, int bufsize);
int proc_exec(int type, int infd, int outfd, void (*cbfunc)(void *, int), void *cbarg, const char *fmt, ...);

#ifdef USE_SMIME
/* smime.c */
int smime_verify(struct state *state);
int smime_sign(struct state *state);
int smime_encrypt(struct state *state);
#endif /* USE_SMIME */

#ifdef USE_PGPMIME
int pgpmime_verify(struct state *state);
int pgpmime_sign(struct state *state);
int pgpmime_encrypt(struct state *state);
#endif /* USE_PGPMIME */

#ifdef USE_UUDES
int uudes_decrypt(struct state *state);
#endif /* USE_UUDES */
