/*
 * LibSylph -- E-Mail client library
 * Copyright (C) 1999-2013 Hiroyuki Yamamoto
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#include <glib.h>
#include <glib/gi18n.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <sys/stat.h>

#include "procheader.h"
#include "procmsg.h"
#include "codeconv.h"
#include "displayheader.h"
#include "prefs_common.h"
#include "utils.h"

#define BUFFSIZE	8192

gint procheader_get_one_field(gchar *buf, size_t len, FILE *fp,
			      HeaderEntry hentry[])
{
	gint nexthead;
	gint hnum = 0;
	HeaderEntry *hp = NULL;

	if (hentry != NULL) {
		/* skip non-required headers */
		do {
			do {
				if (fgets(buf, len, fp) == NULL)
					return -1;
				if (buf[0] == '\r' || buf[0] == '\n')
					return -1;
			} while (buf[0] == ' ' || buf[0] == '\t');

			for (hp = hentry, hnum = 0; hp->name != NULL;
			     hp++, hnum++) {
				if (!g_ascii_strncasecmp(hp->name, buf,
							 strlen(hp->name)))
					break;
			}
		} while (hp->name == NULL);
	} else {
		if (fgets(buf, len, fp) == NULL) return -1;
		if (buf[0] == '\r' || buf[0] == '\n') return -1;
	}

	/* unfold the specified folded line */
	if (hp && hp->unfold) {
		gboolean folded = FALSE;
		gchar *bufp = buf + strlen(buf);

		for (; bufp > buf &&
		     (*(bufp - 1) == '\n' || *(bufp - 1) == '\r');
		     bufp--)
			*(bufp - 1) = '\0';

		while (1) {
			nexthead = fgetc(fp);

			/* folded */
			if (nexthead == ' ' || nexthead == '\t')
				folded = TRUE;
			else if (nexthead == EOF)
				break;
			else if (folded == TRUE) {
				if ((len - (bufp - buf)) <= 2) break;

				if (nexthead == '\n') {
					folded = FALSE;
					continue;
				}

				/* replace return code on the tail end
				   with space */
				*bufp++ = ' ';
				*bufp++ = nexthead;
				*bufp = '\0';

				/* concatenate next line */
				if (fgets(bufp, len - (bufp - buf), fp)
				    == NULL) break;
				bufp += strlen(bufp);

				for (; bufp > buf &&
				     (*(bufp - 1) == '\n' || *(bufp - 1) == '\r');
				     bufp--)
					*(bufp - 1) = '\0';

				folded = FALSE;
			} else {
				ungetc(nexthead, fp);
				break;
			}
		}

		return hnum;
	}

	while (1) {
		nexthead = fgetc(fp);
		if (nexthead == ' ' || nexthead == '\t') {
			size_t buflen = strlen(buf);

			/* concatenate next line */
			if ((len - buflen) > 2) {
				gchar *p = buf + buflen;

				*p++ = nexthead;
				*p = '\0';
				buflen++;
				if (fgets(p, len - buflen, fp) == NULL)
					break;
			} else
				break;
		} else {
			if (nexthead != EOF)
				ungetc(nexthead, fp);
			break;
		}
	}

	/* remove trailing return code */
	strretchomp(buf);

	return hnum;
}

gchar *procheader_get_unfolded_line(gchar *buf, size_t len, FILE *fp)
{
	gboolean folded = FALSE;
	gint nexthead;
	gchar *bufp;

	if (fgets(buf, len, fp) == NULL) return NULL;
	if (buf[0] == '\r' || buf[0] == '\n') return NULL;
	bufp = buf + strlen(buf);

	for (; bufp > buf &&
	     (*(bufp - 1) == '\n' || *(bufp - 1) == '\r');
	     bufp--)
		*(bufp - 1) = '\0';

	while (1) {
		nexthead = fgetc(fp);

		/* folded */
		if (nexthead == ' ' || nexthead == '\t')
			folded = TRUE;
		else if (nexthead == EOF)
			break;
		else if (folded == TRUE) {
			if ((len - (bufp - buf)) <= 2) break;

			if (nexthead == '\n') {
				folded = FALSE;
				continue;
			}

			/* replace return code on the tail end
			   with space */
			*bufp++ = ' ';
			*bufp++ = nexthead;
			*bufp = '\0';

			/* concatenate next line */
			if (fgets(bufp, len - (bufp - buf), fp)
			    == NULL) break;
			bufp += strlen(bufp);

			for (; bufp > buf &&
			     (*(bufp - 1) == '\n' || *(bufp - 1) == '\r');
			     bufp--)
				*(bufp - 1) = '\0';

			folded = FALSE;
		} else {
			ungetc(nexthead, fp);
			break;
		}
	}

	/* remove trailing return code */
	strretchomp(buf);

	return buf;
}

GSList *procheader_get_header_list_from_file(const gchar *file)
{
	FILE *fp;
	GSList *hlist;

	if ((fp = g_fopen(file, "rb")) == NULL) {
		FILE_OP_ERROR(file, "procheader_get_header_list_from_file: fopen");
		return NULL;
	}

	hlist = procheader_get_header_list(fp);

	fclose(fp);
	return hlist;
}

GSList *procheader_get_header_list(FILE *fp)
{
	gchar *p;
	GSList *hlist = NULL;
	Header *header;

    g_return_val_if_fail(fp != NULL, NULL);
    gchar *buf = (gchar *)malloc(BUFFSIZE * sizeof (gchar));
    memset(buf, 0, BUFFSIZE * sizeof (gchar));

    while (procheader_get_unfolded_line(buf, BUFFSIZE * sizeof (gchar), fp) != NULL) {
		if (*buf == ':') continue;
		for (p = buf; *p && *p != ' '; p++) {
			if (*p == ':') {
				header = g_new(Header, 1);
				header->name = g_strndup(buf, p - buf);
				p++;
				while (*p == ' ' || *p == '\t') p++;
				header->body = conv_unmime_header(p, NULL);

				hlist = g_slist_append(hlist, header);
				break;
			}
		}
	}
    free(buf);
	return hlist;
}

GSList *procheader_get_header_list_from_msginfo(MsgInfo *msginfo)
{
	GSList *hlist = NULL;

	g_return_val_if_fail(msginfo != NULL, NULL);

	if (msginfo->subject)
		hlist = procheader_add_header_list(hlist, "Subject",
						   msginfo->subject);
	if (msginfo->from)
		hlist = procheader_add_header_list(hlist, "From",
						   msginfo->from);
	if (msginfo->to)
		hlist = procheader_add_header_list(hlist, "To", msginfo->to);
	if (msginfo->cc)
		hlist = procheader_add_header_list(hlist, "Cc", msginfo->cc);
	if (msginfo->newsgroups)
		hlist = procheader_add_header_list(hlist, "Newsgroups",
						   msginfo->newsgroups);
	if (msginfo->date)
		hlist = procheader_add_header_list(hlist, "Date",
						   msginfo->date);

	return hlist;
}

GSList *procheader_add_header_list(GSList *hlist, const gchar *header_name,
				  const gchar *body)
{
	Header *header;

	g_return_val_if_fail(header_name != NULL, hlist);

	header = g_new(Header, 1);
	header->name = g_strdup(header_name);
	header->body = g_strdup(body);

	return g_slist_append(hlist, header);
}

GSList *procheader_copy_header_list(GSList *hlist)
{
	GSList *newlist = NULL, *cur;

	for (cur = hlist; cur != NULL; cur = cur->next) {
		Header *header = (Header *)cur->data;
		newlist = procheader_add_header_list(newlist, header->name,
						     header->body);
	}

	return newlist;
}

GSList *procheader_merge_header_list(GSList *hlist1, GSList *hlist2)
{
	GSList *cur;

	for (cur = hlist2; cur != NULL; cur = cur->next) {
		Header *header = (Header *)cur->data;
		if (procheader_find_header_list(hlist1, header->name) < 0)
			hlist1 = g_slist_append(hlist1, header);
	}

	return hlist1;
}

GSList *procheader_merge_header_list_dup(GSList *hlist1, GSList *hlist2)
{
	GSList *list, *cur;

	list = procheader_copy_header_list(hlist1);

	for (cur = hlist2; cur != NULL; cur = cur->next) {
		Header *header = (Header *)cur->data;
		if (procheader_find_header_list(list, header->name) < 0)
			list = procheader_add_header_list(list, header->name,
							  header->body);
	}

	return list;
}

gint procheader_find_header_list(GSList *hlist, const gchar *header_name)
{
	GSList *cur;
	gint index = 0;
	Header *header;

	g_return_val_if_fail(header_name != NULL, -1);

	for (cur = hlist; cur != NULL; cur = cur->next, index++) {
		header = (Header *)cur->data;
		if (g_ascii_strcasecmp(header->name, header_name) == 0)
			return index;
	}

	return -1;
}

GPtrArray *procheader_get_header_array(FILE *fp, const gchar *encoding)
{
	gchar *p;
	GPtrArray *headers;
	Header *header;

	g_return_val_if_fail(fp != NULL, NULL);

    gchar *buf = (gchar *)malloc(BUFFSIZE * sizeof (gchar));
    memset(buf, 0, BUFFSIZE * sizeof (gchar));
	headers = g_ptr_array_new();

    while (procheader_get_unfolded_line(buf, BUFFSIZE * sizeof (gchar), fp) != NULL) {
		if (*buf == ':') continue;
		for (p = buf; *p && *p != ' '; p++) {
			if (*p == ':') {
				header = g_new(Header, 1);
				header->name = g_strndup(buf, p - buf);
				p++;
				while (*p == ' ' || *p == '\t') p++;
				header->body = conv_unmime_header(p, encoding);

				g_ptr_array_add(headers, header);
				break;
			}
		}
    }
    free(buf);
	return headers;
}

GPtrArray *procheader_get_header_array_asis(FILE *fp, const gchar *encoding)
{
	gchar *p;
	GPtrArray *headers;
	Header *header;

	g_return_val_if_fail(fp != NULL, NULL);

	headers = g_ptr_array_new();
    gchar *buf = (gchar *)malloc(BUFFSIZE * sizeof (gchar));
    memset(buf, 0, BUFFSIZE * sizeof (gchar));
    while (procheader_get_one_field(buf, BUFFSIZE * sizeof (gchar), fp, NULL) != -1) {
		if (*buf == ':') continue;
		for (p = buf; *p && *p != ' '; p++) {
			if (*p == ':') {
				header = g_new(Header, 1);
				header->name = g_strndup(buf, p - buf);
				p++;
				header->body = conv_unmime_header(p, encoding);

				g_ptr_array_add(headers, header);
				break;
			}
		}
	}
    free(buf);
	return headers;
}

GPtrArray *procheader_get_header_array_for_display(FILE *fp,
						   const gchar *encoding)
{
	GPtrArray *headers, *sorted_headers;
	GSList *disphdr_list;
	Header *header;
	gint i;

	g_return_val_if_fail(fp != NULL, NULL);

	headers = procheader_get_header_array_asis(fp, encoding);

	sorted_headers = g_ptr_array_new();

	for (disphdr_list = prefs_common.disphdr_list; disphdr_list != NULL;
	     disphdr_list = disphdr_list->next) {
		DisplayHeaderProp *dp =
			(DisplayHeaderProp *)disphdr_list->data;

		for (i = 0; i < headers->len; i++) {
			header = g_ptr_array_index(headers, i);

			if (!g_ascii_strcasecmp(header->name, dp->name)) {
				if (dp->hidden)
					procheader_header_free(header);
				else
					g_ptr_array_add(sorted_headers, header);

				g_ptr_array_remove_index(headers, i);
				i--;
			}
		}
	}

	if (prefs_common.show_other_header) {
		for (i = 0; i < headers->len; i++) {
			header = g_ptr_array_index(headers, i);
			g_ptr_array_add(sorted_headers, header);
		}
		g_ptr_array_free(headers, TRUE);
	} else
		procheader_header_array_destroy(headers);

	return sorted_headers;
}

void procheader_header_list_destroy(GSList *hlist)
{
	Header *header;

	while (hlist != NULL) {
		header = hlist->data;
		procheader_header_free(header);
		hlist = g_slist_remove(hlist, header);
	}
}

void procheader_header_array_destroy(GPtrArray *harray)
{
	gint i;
	Header *header;

	for (i = 0; i < harray->len; i++) {
		header = g_ptr_array_index(harray, i);
		procheader_header_free(header);
	}

	g_ptr_array_free(harray, TRUE);
}

void procheader_header_free(Header *header)
{
	if (!header) return;

	g_free(header->name);
	g_free(header->body);
	g_free(header);
}

void procheader_get_header_fields(FILE *fp, HeaderEntry hentry[])
{
	HeaderEntry *hp;
	gint hnum;
	gchar *p;

	if (hentry == NULL) return;

    gchar *buf = (gchar *)malloc(BUFFSIZE * sizeof (gchar));
    memset(buf, 0, BUFFSIZE * sizeof (gchar));

    while ((hnum = procheader_get_one_field(buf, BUFFSIZE * sizeof(gchar), fp, hentry))
	       != -1) {
		hp = hentry + hnum;

		p = buf + strlen(hp->name);
		while (*p == ' ' || *p == '\t') p++;

		if (hp->body == NULL)
			hp->body = g_strdup(p);
		else if (!g_ascii_strcasecmp(hp->name, "To:") ||
			 !g_ascii_strcasecmp(hp->name, "Cc:")) {
			gchar *tp = hp->body;
			hp->body = g_strconcat(tp, ", ", p, NULL);
			g_free(tp);
		}
	}
    free(buf);
}

MsgInfo *procheader_parse_file(const gchar *file, MsgFlags flags,
			       gboolean full)
{
	GStatBuf s;
	FILE *fp;
	MsgInfo *msginfo;

	if (g_stat(file, &s) < 0) {
		FILE_OP_ERROR(file, "stat");
		return NULL;
	}
	if (!S_ISREG(s.st_mode))
		return NULL;

	if ((fp = g_fopen(file, "rb")) == NULL) {
		FILE_OP_ERROR(file, "procheader_parse_file: fopen");
		return NULL;
	}

	msginfo = procheader_parse_stream(fp, flags, full);
	fclose(fp);

	if (msginfo) {
		msginfo->size = s.st_size;
		msginfo->mtime = s.st_mtime;
	}

	return msginfo;
}

MsgInfo *procheader_parse_str(const gchar *str, MsgFlags flags, gboolean full)
{
	FILE *fp;
	MsgInfo *msginfo;

//    g_print("------str:%s\n",str);
	if ((fp = str_open_as_stream(str)) == NULL)
		return NULL;

	msginfo = procheader_parse_stream(fp, flags, full);
	fclose(fp);
	return msginfo;
}

enum
{
	H_DATE		= 0,
	H_FROM		= 1,
	H_TO		= 2,
	H_NEWSGROUPS	= 3,
	H_SUBJECT	= 4,
	H_MSG_ID	= 5,
	H_REFERENCES	= 6,
	H_IN_REPLY_TO	= 7,
	H_CONTENT_TYPE	= 8,
	H_SEEN		= 9,
    H_X_PRIORITY	= 10,
    UOS_SendResultFlags	= 11,//add shui
    H_RECEIVED = 12,      //add shui
//    H_BEGIN = 13,      //add shui
    H_CC		= 13,
    UOS_MsgId	= 14,//add shui
    H_Disposition_Notification_To	= 15,//add shui
    UOS_DateTimeSend	= 16,
    UOS_SeparateSend	= 17,//add shui
    H_X_FACE	        = 18,//add shui
    H_BCC	= 19//add shui
};
//added by shangxiudong
/**
 * @brief procheader_get_one_field的改进版 根据实际内容大小，动态调整内存申请
 * @param buf 空指针，返回申请了内存的字符串
 * @param fp 邮件本地文件句柄
 * @param hentry 要获取的头列表
 * @return hentry的索引
 */
static gint procheader_get_one_field_enhanced(char **buf, FILE *fp,HeaderEntry hentry[])
{
    if(*buf != NULL) {
        g_free(*buf);
    }
    gsize len = 1024;
    gint hnum = 0;
    long int pos = ftell(fp);
    while(1) {
        *buf = g_malloc0(len);
        hnum = procheader_get_one_field(*buf, len, fp, hentry);
        if(hnum == -1) {
            g_free(*buf);
            *buf = NULL;
            return hnum;
        }
        if ((len - strlen(*buf)) > 2) {
            return hnum;
        } else {
            len = len << 1;
            g_free(*buf);
            *buf = NULL;
            fseek(fp, pos, SEEK_SET);

        }
        if(len >= (BUFFSIZE * 1000)) {
            g_warning("function %s bufsize was too large.\n", __func__);
            return -1;
        }
    }
}

MsgInfo *procheader_parse_stream(FILE *fp, MsgFlags flags, gboolean full)
{
	static HeaderEntry hentry_full[] = {{"Date:",		NULL, FALSE},
					   {"From:",		NULL, TRUE},
					   {"To:",		NULL, TRUE},
					   {"Newsgroups:",	NULL, TRUE},
					   {"Subject:",		NULL, TRUE},
					   {"Message-Id:",	NULL, FALSE},
					   {"References:",	NULL, FALSE},
					   {"In-Reply-To:",	NULL, FALSE},
					   {"Content-Type:",	NULL, FALSE},
					   {"Seen:",		NULL, FALSE},
                       {"X-Priority:",		NULL, TRUE},
                       {"UOS-SendResultFlags:",		NULL, TRUE},
                       {"Received:",		NULL, TRUE},
					   {"Cc:",		NULL, TRUE},
                       {"UOS-MsgId:",	NULL, FALSE},
                       {"Disposition-Notification-To:",		NULL, TRUE},
                       {"UOS-DateTimeSend:",		NULL, FALSE},
                       {"UOS-SeparateSend:",		NULL, FALSE},
                       {"X-Face:",		NULL, FALSE},
                       {"Bcc:",		NULL, TRUE},
					   {NULL,		NULL, FALSE}};

	static HeaderEntry hentry_short[] = {{"Date:",		NULL, FALSE},
					    {"From:",		NULL, TRUE},
					    {"To:",		NULL, TRUE},
					    {"Newsgroups:",	NULL, TRUE},
					    {"Subject:",	NULL, TRUE},
					    {"Message-Id:",	NULL, FALSE},
					    {"References:",	NULL, FALSE},
					    {"In-Reply-To:",	NULL, FALSE},
					    {"Content-Type:",	NULL, FALSE},
                        {"Seen:",		NULL, FALSE},
                        {"X-Priority:",		NULL, TRUE},
                        {"UOS-SendResultFlags:",		NULL, TRUE},
                        {"Received:",		NULL, TRUE},
                        {"Cc:",		NULL, TRUE},
                        {"UOS-MsgId:",	NULL, FALSE},
                        {"Disposition-Notification-To:",		NULL, TRUE},
                        {"UOS-DateTimeSend:",		NULL, TRUE},
					    {NULL,		NULL, FALSE}};

	MsgInfo *msginfo;
    gchar *buf = (gchar *)malloc(BUFFSIZE * sizeof (gchar));
    memset(buf, 0, BUFFSIZE * sizeof (gchar));
	gchar *p;
	gchar *hp;
	HeaderEntry *hentry;
	gint hnum;
    gchar *from = NULL, *to = NULL, *subject = NULL, *cc = NULL, *bcc = NULL, *dnt = NULL, *separatesend = NULL;
	gchar *charset = NULL;

	hentry = full ? hentry_full : hentry_short;

	if (MSG_IS_QUEUED(flags)) {
        while (fgets(buf, BUFFSIZE * sizeof (gchar), fp) != NULL)
			if (buf[0] == '\r' || buf[0] == '\n') break;
	}
    free(buf);
    buf = NULL;

	msginfo = g_new0(MsgInfo, 1);
	msginfo->flags = flags;
    msginfo->references = NULL;
    msginfo->receivedtime = 0;
    msginfo->encinfo = NULL;
    msginfo->xface = NULL;
    msginfo->fromname = NULL;
    msginfo->date = NULL;
    msginfo->from = NULL;
    msginfo->to = NULL;
    msginfo->cc = NULL;
    msginfo->newsgroups = NULL;
    msginfo->subject = NULL;
    msginfo->msgid = NULL;
    msginfo->inreplyto = NULL;
    msginfo->xpriority = NULL;
    msginfo->uos_msgid = NULL;
    msginfo->disposition_notification_to = NULL;
    msginfo->separatesend = NULL;
    msginfo->datetimesend = NULL;
    msginfo->sendresultflags = NULL;
    msginfo->references = NULL;
    msginfo->file_path = NULL;
    msginfo->bcc = NULL;
    msginfo->attachmentnum = 0;
    msginfo->fetch_large = FALSE;
    msginfo->calendarflag=CALENDAR_NONE;

    char *tmpbuf = NULL;
	while ((hnum = procheader_get_one_field_enhanced(&tmpbuf, fp, hentry))
           != -1) {
        if(tmpbuf == NULL)
            continue;
        hp = tmpbuf + strlen(hentry[hnum].name);
		while (*hp == ' ' || *hp == '\t') hp++;

        gchar **gt=NULL;
		switch (hnum) {
        case H_RECEIVED:
            gt = g_strsplit(hp, ";", 2);
            if(gt[1] != NULL)
            msginfo->receivedtime =
                procheader_date_parse(NULL, gt[1], 0);
            g_strfreev(gt);
            break;
		case H_DATE:
			if (msginfo->date) break;
			msginfo->date_t =
				procheader_date_parse(NULL, hp, 0);
			msginfo->date = g_strdup(hp);
            break;
		case H_FROM:
			if (from) break;
			from = g_strdup(hp);
			break;
		case H_TO:
			if (to) {
				p = to;
				to = g_strconcat(p, ", ", hp, NULL);
				g_free(p);
			} else
				to = g_strdup(hp);
			break;
        case UOS_SeparateSend:
            if (separatesend) {
                p = separatesend;
                separatesend = g_strconcat(p, ", ", hp, NULL);
                g_free(p);
            } else
                separatesend = g_strdup(hp);
            break;
        case UOS_SendResultFlags:
             if (msginfo->sendresultflags) break;
             msginfo->sendresultflags = g_strdup(hp);
             break;
        case UOS_DateTimeSend:
            if (msginfo->datetimesend) break;
            msginfo->datetimesend = g_strdup(hp);
            break;
		case H_NEWSGROUPS:
			if (msginfo->newsgroups) {
				p = msginfo->newsgroups;
				msginfo->newsgroups =
					g_strconcat(p, ",", hp, NULL);
				g_free(p);
			} else
				msginfo->newsgroups = g_strdup(tmpbuf + 12);
			break;
		case H_SUBJECT:
			if (msginfo->subject) break;
			subject = g_strdup(hp);
			break;
//        case H_BEGIN:
//            if (!g_ascii_strncasecmp(hp, "VCALENDAR", 9)||!g_ascii_strncasecmp(hp, "ICALENDAR", 9)) {
//               msginfo->valendar=TRUE;
//            }
//            break;
		case H_MSG_ID:
			if (msginfo->msgid) break;

			extract_parenthesis(hp, '<', '>');
			remove_space(hp);
			msginfo->msgid = g_strdup(hp);
			break;
        case UOS_MsgId:
            if (msginfo->uos_msgid) break;

            extract_parenthesis(hp, '<', '>');
            remove_space(hp);
            msginfo->uos_msgid = g_strdup(hp);
            break;
		case H_REFERENCES:
			msginfo->references =
				references_list_prepend(msginfo->references,
							hp);
			break;
		case H_IN_REPLY_TO:
			if (msginfo->inreplyto) break;

			eliminate_parenthesis(hp, '(', ')');
			if ((p = strrchr(hp, '<')) != NULL &&
			    strchr(p + 1, '>') != NULL) {
				extract_parenthesis(p, '<', '>');
				remove_space(p);
				if (*p != '\0')
					msginfo->inreplyto = g_strdup(p);
			}
			break;
		case H_CONTENT_TYPE:
			if (!g_ascii_strncasecmp(hp, "multipart", 9)) {
				MSG_SET_TMP_FLAGS(msginfo->flags, MSG_MIME);
			} else {
				if (!g_ascii_strncasecmp(hp, "text/html", 9)) {
					MSG_SET_TMP_FLAGS(msginfo->flags, MSG_MIME_HTML);
				}
				if (!charset) {
					procmime_scan_content_type_str
                        (hp, NULL, &charset, NULL, NULL, NULL);
				}
			}
			break;
		case H_SEEN:
			/* mnews Seen header */
			MSG_UNSET_PERM_FLAGS(msginfo->flags, MSG_NEW|MSG_UNREAD);
			break;
        case H_X_PRIORITY:
            msginfo->xpriority = g_strdup(hp);
            break;
		case H_CC:
			if (cc) {
				p = cc;
				cc = g_strconcat(p, ", ", hp, NULL);
				g_free(p);
			} else
				cc = g_strdup(hp);
            break;
        case H_BCC:
            if (bcc) {
                p = bcc;
                bcc = g_strconcat(p, ", ", hp, NULL);
                g_free(p);
            } else
                bcc = g_strdup(hp);
            break;
		case H_X_FACE:
			if (msginfo->xface) break;
			msginfo->xface = g_strdup(hp);
			break;
        case H_Disposition_Notification_To:
            if (dnt) {
                p = dnt;
                dnt = g_strconcat(p, ", ", hp, NULL);
                g_free(dnt);
                dnt=NULL;
            } else
                dnt = g_strdup(hp);
            break;
		default:
			break;
		}
            g_free(tmpbuf);
            tmpbuf = NULL;
	}

	if (from) {
		msginfo->from = conv_unmime_header(from, charset);
		subst_control(msginfo->from, ' ');
		msginfo->fromname = procheader_get_fromname(msginfo->from);
        g_free(from);
	}
	if (to) {
		msginfo->to = conv_unmime_header(to, charset);
		subst_control(msginfo->to, ' ');
		g_free(to);
	}
    if (separatesend) {
        msginfo->separatesend = conv_unmime_header(separatesend, charset);
        subst_control(msginfo->separatesend, ' ');
        g_free(separatesend);
    }
	if (subject) {
//        gchar *charsetself=NULL;
//        if(!charset){
////            CharSet cs=conv_guess_ja_encoding		(subject);
////            const gchar *ct=conv_get_charset_str(cs);
////            charset=g_strdup(/*"GB2312"*/ct);
////            g_print("%s\n",charset);
//            charsetself=g_strdup(CS_GBK);
//        }else {
//            charsetself=g_strdup(charset);
//        }
        msginfo->subject = conv_unmime_header(subject, /*charsetself*/charset);
        subst_control(msginfo->subject, ' ');
		g_free(subject);
//        g_free(charsetself);
	}
	if (cc) {
		msginfo->cc = conv_unmime_header(cc, charset);
		subst_control(msginfo->cc, ' ');
		g_free(cc);
	}
    if (bcc) {
        msginfo->bcc = conv_unmime_header(bcc, charset);
        subst_control(msginfo->bcc, ' ');
        g_free(bcc);
    }
    if (dnt) {
        msginfo->disposition_notification_to = conv_unmime_header(dnt, charset);
        subst_control(msginfo->disposition_notification_to, ' ');
        g_free(dnt);
        dnt=NULL;
    }

	if (!msginfo->inreplyto && msginfo->references)
		msginfo->inreplyto =
			g_strdup((gchar *)msginfo->references->data);

    if (MSG_IS_MIME(msginfo->flags)) {
		MimeInfo *mimeinfo, *part;
		gboolean has_html = FALSE;

		part = mimeinfo = procmime_scan_message_stream(fp);
		while (part) {
            if (part->content_disposition&&!g_ascii_strncasecmp(part->content_disposition, "attachment", 10))
                msginfo->attachmentnum++;
            //会议信息
            if (part->mime_type == MIME_CALENDAR) {
                if(part->method && !g_ascii_strcasecmp(part->method, "REQUEST"))
                    msginfo->calendarflag = CALENDAR_REQUEST;
                else if(part->method && !g_ascii_strcasecmp(part->method, "REPLY"))
                    msginfo->calendarflag = CALENDAR_Reply;
                else
                    msginfo->calendarflag = CALENDAR_NONE;
            }
			if (part->mime_type != MIME_TEXT &&
			    part->mime_type != MIME_TEXT_HTML &&
			    part->mime_type != MIME_MULTIPART)
				break;
			if (part->mime_type == MIME_TEXT_HTML)
				has_html = TRUE;
			part = procmime_mimeinfo_next(part);
		}

		if (has_html && !part) {
			MSG_SET_TMP_FLAGS(msginfo->flags, MSG_MIME_HTML);
		}

		procmime_mimeinfo_free_all(mimeinfo);
    }

	g_free(charset);

	return msginfo;
}

gchar *procheader_get_fromname(const gchar *str)
{
	gchar *tmp, *name;

	tmp = g_strdup(str);

	if (*tmp == '\"') {
		extract_quote_with_escape(tmp, '\"');
		g_strstrip(tmp);
	} else if (strchr(tmp, '<')) {
		eliminate_parenthesis(tmp, '<', '>');
		g_strstrip(tmp);
		if (*tmp == '\0') {
			strcpy(tmp, str);
			extract_parenthesis(tmp, '<', '>');
			g_strstrip(tmp);
		}
	} else if (strchr(tmp, '(')) {
		extract_parenthesis_with_escape(tmp, '(', ')');
		g_strstrip(tmp);
	}

	if (*tmp == '\0') {
		g_free(tmp);
		name = g_strdup(str);
	} else
		name = tmp;

	return name;
}

gchar *procheader_get_toname(const gchar *str)
{
	GSList *addr_list, *cur;
	GString *toname;
	gchar *name;

	if (strchr(str, ',') == NULL)
		return procheader_get_fromname(str);

	addr_list = address_list_append_orig(NULL, str);
	toname = g_string_new(NULL);

	for (cur = addr_list; cur != NULL; cur = cur->next) {
		name = procheader_get_fromname((gchar *)cur->data);
		g_string_append(toname, name);
		g_free(name);
		if (cur->next)
			g_string_append(toname, ", ");
	}

	slist_free_strings(addr_list);

	return g_string_free(toname, FALSE);
}

static gint procheader_scan_date_string(const gchar *str,
					gchar *weekday, gint *day,
					gchar *month, gint *year,
					gint *hh, gint *mm, gint *ss,
					gchar *zone)
{
	gint result;

	*zone = '\0';
	result = sscanf(str, "%10s %d %9s %d %2d:%2d:%2d %5s",
			weekday, day, month, year, hh, mm, ss, zone);
	if (result >= 7) return 0;

	result = sscanf(str, "%3s,%d %9s %d %2d:%2d:%2d %5s",
			weekday, day, month, year, hh, mm, ss, zone);
	if (result >= 7) return 0;

	result = sscanf(str, "%3s,%d %9s %d %2d.%2d.%2d %5s",
			weekday, day, month, year, hh, mm, ss, zone);
	if (result >= 7) return 0;

	result = sscanf(str, "%3s %d, %9s %d %2d:%2d:%2d %5s",
			weekday, day, month, year, hh, mm, ss, zone);
	if (result >= 7) return 0;

	result = sscanf(str, "%d %9s %d %2d:%2d:%2d %5s",
			day, month, year, hh, mm, ss, zone);
	if (result >= 6) return 0;

	result = sscanf(str, "%d-%2s-%2d %2d:%2d:%2d",
			year, month, day, hh, mm, ss);
	if (result == 6) return 0;

	*ss = 0;
	result = sscanf(str, "%10s %d %9s %d %2d:%2d %5s",
			weekday, day, month, year, hh, mm, zone);
	if (result >= 6) return 0;

	result = sscanf(str, "%d %9s %d %2d:%2d %5s",
			day, month, year, hh, mm, zone);
	if (result >= 5) return 0;

	return -1;
}

stime_t procheader_date_parse(gchar *dest, const gchar *src, gint len)
{
	static gchar monthstr[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
	gchar weekday[11];
	gint day;
	gchar month[10];
	gint year;
	gint hh, mm, ss;
	gchar zone[6];
	GDateMonth dmonth = G_DATE_BAD_MONTH;
	struct tm t;
	gchar *p;
	time_t timer_;
	time_t tz_offset;
	stime_t timer;

	if (procheader_scan_date_string(src, weekday, &day, month, &year,
					&hh, &mm, &ss, zone) < 0) {
		g_warning("procheader_scan_date_string: date parse failed: %s", src);
		if (dest && len > 0)
			strncpy2(dest, src, len);
		return 0;
	}

	/* Y2K compliant :) */
	if (year < 1000) {
		if (year < 50)
			year += 2000;
		else
			year += 1900;
	}

	month[3] = '\0';
	if (g_ascii_isdigit(month[0])) {
		dmonth = atoi(month);
	} else {
		for (p = monthstr; *p != '\0'; p += 3) {
			if (!g_ascii_strncasecmp(p, month, 3)) {
				dmonth = (gint)(p - monthstr) / 3 + 1;
				break;
			}
		}
	}

	t.tm_sec = ss;
	t.tm_min = mm;
	t.tm_hour = hh;
	t.tm_mday = day;
	t.tm_mon = dmonth - 1;
	t.tm_year = year - 1900;
	t.tm_wday = 0;
	t.tm_yday = 0;
	t.tm_isdst = -1;

	timer_ = mktime(&t);
	if (timer_ == -1) {
		if (year >= 2038) {
			g_warning("mktime: date overflow: %s", src);
			timer_ = G_MAXINT - 12 * 3600;
		} else {
			g_warning("mktime: can't convert date: %s", src);
			if (dest)
				dest[0] = '\0';
			return 0;
		}
	}

	timer = timer_;
	if (timer < G_MAXINT - 12 * 3600) {
		tz_offset = remote_tzoffset_sec(zone);
		if (tz_offset != -1)
			timer += tzoffset_sec(&timer) - tz_offset;
	}

	if (dest)
		procheader_date_get_localtime(dest, len, timer);

	return timer;
}

void procheader_date_get_localtime(gchar *dest, gint len, const stime_t timer)
{
	time_t timer_ = timer;
	struct tm *lt;
	gchar *default_format = "%y/%m/%d(%a) %H:%M";
	gchar *buf;

	lt = localtime(&timer_);
	if (!lt) {
		g_warning("can't get localtime of %ld\n", timer);
		dest[0] = '\0';
		return;
	}

    gchar *tmp = (gchar *)malloc(BUFFSIZE * sizeof (gchar));
	if (prefs_common.date_format)
        strftime(tmp, BUFFSIZE * sizeof (gchar), prefs_common.date_format, lt);
	else
        strftime(tmp, BUFFSIZE * sizeof (gchar), default_format, lt);

	buf = conv_localetodisp(tmp, NULL);
	strncpy2(dest, buf, len);
	g_free(buf);
}
