claws-mail/src/procheader.c
Colin Leroy 68cec9a28f 2006-05-12 [colin] 2.2.0cvs3
* src/folder.c
	* src/mainwindow.c
	* src/mainwindow.h
	* src/messageview.c
	* src/prefs_spelling.c
	* src/procheader.c
	* src/procmsg.c
	* src/procmsg.h
	* src/summaryview.c
	* src/toolbar.c
	* src/toolbar.h
		Add contextual menu on Compose toolbar
                button. Fixes bug #944 (Automatic
                addresses not applied when changing account
                from compose window)
                add Mailing List support
                based on the old 0.6.5claws25 patch by
                Melvin Hadasht, with finishing touches
                by Colin
                Fix "ignore thread" when mails are threaded by
                subject (and weren't ignored although appearing
                in the thread).
                GUI rework.
                Both patches by Pawel.
2006-05-12 17:42:48 +00:00

905 lines
22 KiB
C

/*
* Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
* Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Sylpheed-Claws team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, 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 "prefs_common.h"
#include "utils.h"
#define BUFFSIZE 8192
typedef char *(*getlinefunc) (char *, size_t, void *);
typedef int (*peekcharfunc) (void *);
typedef int (*getcharfunc) (void *);
typedef gint (*get_one_field_func) (gchar *, size_t, void *, HeaderEntry[]);
static gint string_get_one_field(gchar *buf, size_t len, char **str,
HeaderEntry hentry[]);
static char *string_getline(char *buf, size_t len, char **str);
static int string_peekchar(char **str);
static int file_peekchar(FILE *fp);
static gint generic_get_one_field(gchar *buf, size_t len, void *data,
HeaderEntry hentry[],
getlinefunc getline,
peekcharfunc peekchar,
gboolean unfold);
static MsgInfo *parse_stream(void *data, gboolean isstring, MsgFlags flags,
gboolean full, gboolean decrypted);
gint procheader_get_one_field(gchar *buf, size_t len, FILE *fp,
HeaderEntry hentry[])
{
return generic_get_one_field(buf, len, fp, hentry,
(getlinefunc)fgets, (peekcharfunc)file_peekchar,
TRUE);
}
static gint string_get_one_field(gchar *buf, size_t len, char **str,
HeaderEntry hentry[])
{
return generic_get_one_field(buf, len, str, hentry,
(getlinefunc)string_getline,
(peekcharfunc)string_peekchar,
TRUE);
}
static char *string_getline(char *buf, size_t len, char **str)
{
if (!*str || !**str)
return NULL;
for (; **str && len > 1; --len)
if ((*buf++ = *(*str)++) == '\n')
break;
*buf = '\0';
return buf;
}
static int string_peekchar(char **str)
{
return **str;
}
static int file_peekchar(FILE *fp)
{
return ungetc(getc(fp), fp);
}
static gint generic_get_one_field(gchar *buf, size_t len, void *data,
HeaderEntry *hentry,
getlinefunc getline, peekcharfunc peekchar,
gboolean unfold)
{
gint nexthead;
gint hnum = 0;
HeaderEntry *hp = NULL;
if (hentry != NULL) {
/* skip non-required headers */
do {
do {
if (getline(buf, len, data) == 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 (getline(buf, len, data) == NULL) return -1;
if (buf[0] == '\r' || buf[0] == '\n') return -1;
}
/* unfold line */
while (1) {
nexthead = peekchar(data);
/* ([*WSP CRLF] 1*WSP) */
if (nexthead == ' ' || nexthead == '\t') {
size_t buflen;
/* trim previous trailing \n if requesting one header or
* unfolding was requested */
if ((!hentry && unfold) || (hp && hp->unfold))
strretchomp(buf);
buflen = strlen(buf);
/* concatenate next line */
if ((len - buflen) > 2) {
if (getline(buf + buflen, len - buflen, data) == NULL)
break;
} else
break;
} else {
/* remove trailing new line */
strretchomp(buf);
break;
}
}
return hnum;
}
gint procheader_get_one_field_asis(gchar *buf, size_t len, FILE *fp)
{
return generic_get_one_field(buf, len, fp, NULL,
(getlinefunc)fgets,
(peekcharfunc)file_peekchar,
FALSE);
}
GPtrArray *procheader_get_header_array_asis(FILE *fp)
{
gchar buf[BUFFSIZE];
GPtrArray *headers;
Header *header;
g_return_val_if_fail(fp != NULL, NULL);
headers = g_ptr_array_new();
while (procheader_get_one_field_asis(buf, sizeof(buf), fp) != -1) {
if ((header = procheader_parse_header(buf)) != NULL)
g_ptr_array_add(headers, header);
/*
if (*buf == ':') continue;
for (p = buf; *p && *p != ' '; p++) {
if (*p == ':') {
header = g_new(Header, 1);
header->name = g_strndup(buf, p - buf);
p++;
conv_unmime_header(tmp, sizeof(tmp), p, NULL);
header->body = g_strdup(tmp);
g_ptr_array_add(headers, header);
break;
}
}
*/
}
return headers;
}
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);
}
/*
tests whether two headers' names are equal
remove the trailing ':' or ' ' before comparing
*/
gboolean procheader_headername_equal(char * hdr1, char * hdr2)
{
int len1;
int len2;
len1 = strlen(hdr1);
len2 = strlen(hdr2);
if (hdr1[len1 - 1] == ':')
len1--;
if (hdr2[len2 - 1] == ':')
len2--;
if (len1 != len2)
return 0;
return (g_ascii_strncasecmp(hdr1, hdr2, len1) == 0);
}
/*
parse headers, for example :
From: dinh@enseirb.fr becomes :
header->name = "From:"
header->body = "dinh@enseirb.fr"
*/
Header * procheader_parse_header(gchar * buf)
{
gchar *p = buf;
Header * header;
if ((*buf == ':') || (*buf == ' '))
return NULL;
for (p = buf; *p ; p++) {
if ((*p == ':') || (*p == ' ')) {
header = g_new(Header, 1);
header->name = g_strndup(buf, p - buf + 1);
p++;
while (*p == ' ' || *p == '\t') p++;
header->body = conv_unmime_header(p, NULL);
return header;
}
}
return NULL;
}
void procheader_get_header_fields(FILE *fp, HeaderEntry hentry[])
{
gchar buf[BUFFSIZE];
HeaderEntry *hp;
gint hnum;
gchar *p;
if (hentry == NULL) return;
while ((hnum = procheader_get_one_field(buf, sizeof(buf), 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 (procheader_headername_equal(hp->name, "To") ||
procheader_headername_equal(hp->name, "Cc")) {
gchar *tp = hp->body;
hp->body = g_strconcat(tp, ", ", p, NULL);
g_free(tp);
}
}
}
MsgInfo *procheader_parse_file(const gchar *file, MsgFlags flags,
gboolean full, gboolean decrypted)
{
struct stat s;
FILE *fp;
MsgInfo *msginfo;
if (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, "fopen");
return NULL;
}
msginfo = procheader_parse_stream(fp, flags, full, decrypted);
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,
gboolean decrypted)
{
return parse_stream(&str, TRUE, flags, full, decrypted);
}
enum
{
H_DATE = 0,
H_FROM = 1,
H_TO = 2,
H_CC = 3,
H_NEWSGROUPS = 4,
H_SUBJECT = 5,
H_MSG_ID = 6,
H_REFERENCES = 7,
H_IN_REPLY_TO = 8,
H_CONTENT_TYPE = 9,
H_SEEN = 10,
H_STATUS = 11,
H_X_STATUS = 12,
H_FROM_SPACE = 13,
H_SC_PLANNED_DOWNLOAD = 14,
H_SC_MESSAGE_SIZE = 15,
H_FACE = 16,
H_X_FACE = 17,
H_DISPOSITION_NOTIFICATION_TO = 18,
H_RETURN_RECEIPT_TO = 19,
H_SC_PARTIALLY_RETRIEVED = 20,
H_SC_ACCOUNT_SERVER = 21,
H_SC_ACCOUNT_LOGIN = 22,
H_LIST_POST = 23,
H_LIST_SUBSCRIBE = 24,
H_LIST_UNSUBSCRIBE = 25,
H_LIST_HELP = 26,
H_LIST_ARCHIVE = 27,
H_LIST_OWNER = 28,
};
static HeaderEntry hentry_full[] = {{"Date:", NULL, FALSE},
{"From:", NULL, TRUE},
{"To:", NULL, TRUE},
{"Cc:", 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},
{"Status:", NULL, FALSE},
{"X-Status:", NULL, FALSE},
{"From ", NULL, FALSE},
{"SC-Marked-For-Download:", NULL, FALSE},
{"SC-Message-Size:", NULL, FALSE},
{"Face:", NULL, FALSE},
{"X-Face:", NULL, FALSE},
{"Disposition-Notification-To:", NULL, FALSE},
{"Return-Receipt-To:", NULL, FALSE},
{"SC-Partially-Retrieved:", NULL, FALSE},
{"SC-Account-Server:", NULL, FALSE},
{"SC-Account-Login:",NULL, FALSE},
{"List-Post:", NULL, TRUE},
{"List-Subscribe:", NULL, TRUE},
{"List-Unsubscribe:",NULL, TRUE},
{"List-Help:", NULL, TRUE},
{"List-Archive:", NULL, TRUE},
{"List-Owner:", NULL, TRUE},
{NULL, NULL, FALSE}};
static HeaderEntry hentry_short[] = {{"Date:", NULL, FALSE},
{"From:", NULL, TRUE},
{"To:", NULL, TRUE},
{"Cc:", 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},
{"Status:", NULL, FALSE},
{"X-Status:", NULL, FALSE},
{"From ", NULL, FALSE},
{"SC-Marked-For-Download:", NULL, FALSE},
{"SC-Message-Size:",NULL, FALSE},
{NULL, NULL, FALSE}};
HeaderEntry* procheader_get_headernames(gboolean full)
{
return full ? hentry_full : hentry_short;
}
MsgInfo *procheader_parse_stream(FILE *fp, MsgFlags flags, gboolean full,
gboolean decrypted)
{
return parse_stream(fp, FALSE, flags, full, decrypted);
}
static MsgInfo *parse_stream(void *data, gboolean isstring, MsgFlags flags,
gboolean full, gboolean decrypted)
{
MsgInfo *msginfo;
gchar buf[BUFFSIZE];
gchar *p, *tmp;
gchar *hp;
HeaderEntry *hentry;
gint hnum;
get_one_field_func get_one_field =
isstring ? (get_one_field_func)string_get_one_field
: (get_one_field_func)procheader_get_one_field;
hentry = procheader_get_headernames(full);
if (MSG_IS_QUEUED(flags) || MSG_IS_DRAFT(flags)) {
while (get_one_field(buf, sizeof(buf), data, NULL) != -1)
; /* loop */
}
msginfo = procmsg_msginfo_new();
if (flags.tmp_flags || flags.perm_flags)
msginfo->flags = flags;
else
MSG_SET_PERM_FLAGS(msginfo->flags, MSG_NEW | MSG_UNREAD);
msginfo->inreplyto = NULL;
while ((hnum = get_one_field(buf, sizeof(buf), data, hentry))
!= -1) {
hp = buf + strlen(hentry[hnum].name);
while (*hp == ' ' || *hp == '\t') hp++;
switch (hnum) {
case H_DATE:
if (msginfo->date) break;
msginfo->date_t =
procheader_date_parse(NULL, hp, 0);
if (g_utf8_validate(hp, -1, NULL)) {
msginfo->date = g_strdup(hp);
} else {
gchar *utf = conv_codeset_strdup(
hp,
conv_get_locale_charset_str_no_utf8(),
CS_INTERNAL);
if (utf == NULL ||
!g_utf8_validate(utf, -1, NULL)) {
g_free(utf);
utf = g_malloc(strlen(buf)*2+1);
conv_localetodisp(utf,
strlen(hp)*2+1, hp);
}
msginfo->date = utf;
}
break;
case H_FROM:
if (msginfo->from) break;
msginfo->from = conv_unmime_header(hp, NULL);
msginfo->fromname = procheader_get_fromname(msginfo->from);
replace_returns(msginfo->from);
replace_returns(msginfo->fromname);
break;
case H_TO:
tmp = conv_unmime_header(hp, NULL);
if (msginfo->to) {
p = msginfo->to;
msginfo->to =
g_strconcat(p, ", ", tmp, NULL);
g_free(p);
} else
msginfo->to = g_strdup(tmp);
g_free(tmp);
break;
case H_CC:
tmp = conv_unmime_header(hp, NULL);
if (msginfo->cc) {
p = msginfo->cc;
msginfo->cc =
g_strconcat(p, ", ", tmp, NULL);
g_free(p);
} else
msginfo->cc = g_strdup(tmp);
g_free(tmp);
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(hp);
break;
case H_SUBJECT:
if (msginfo->subject) break;
msginfo->subject = conv_unmime_header(hp, NULL);
replace_returns(msginfo->subject);
break;
case H_MSG_ID:
if (msginfo->msgid) break;
extract_parenthesis(hp, '<', '>');
remove_space(hp);
msginfo->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/", 10))
MSG_SET_TMP_FLAGS(msginfo->flags, MSG_MULTIPART);
break;
#ifdef ALLOW_HEADER_HINT
case H_SEEN:
/* mnews Seen header */
MSG_UNSET_PERM_FLAGS(msginfo->flags, MSG_NEW|MSG_UNREAD);
break;
#endif
case H_FACE:
if (msginfo->face) break;
msginfo->face = g_strdup(hp);
break;
case H_X_FACE:
if (msginfo->xface) break;
msginfo->xface = g_strdup(hp);
break;
case H_DISPOSITION_NOTIFICATION_TO:
if (msginfo->dispositionnotificationto) break;
msginfo->dispositionnotificationto = g_strdup(hp);
break;
case H_RETURN_RECEIPT_TO:
if (msginfo->returnreceiptto) break;
msginfo->returnreceiptto = g_strdup(hp);
break;
case H_SC_PARTIALLY_RETRIEVED:
if (msginfo->partial_recv) break;
msginfo->partial_recv = g_strdup(hp);
break;
case H_SC_ACCOUNT_SERVER:
if (msginfo->account_server) break;
msginfo->account_server = g_strdup(hp);
break;
case H_SC_ACCOUNT_LOGIN:
if (msginfo->account_login) break;
msginfo->account_login = g_strdup(hp);
break;
case H_SC_MESSAGE_SIZE:
if (msginfo->total_size) break;
msginfo->total_size = atoi(hp);
break;
case H_SC_PLANNED_DOWNLOAD:
msginfo->planned_download = atoi(hp);
break;
#ifdef ALLOW_HEADER_HINT
case H_STATUS:
if (strchr(hp, 'R') != NULL)
MSG_UNSET_PERM_FLAGS(msginfo->flags, MSG_UNREAD);
if (strchr(hp, 'O') != NULL)
MSG_UNSET_PERM_FLAGS(msginfo->flags, MSG_NEW);
if (strchr(hp, 'U') != NULL)
MSG_SET_PERM_FLAGS(msginfo->flags, MSG_UNREAD);
break;
case H_X_STATUS:
if (strchr(hp, 'D') != NULL)
MSG_SET_PERM_FLAGS(msginfo->flags,
MSG_REALLY_DELETED);
if (strchr(hp, 'F') != NULL)
MSG_SET_PERM_FLAGS(msginfo->flags, MSG_MARKED);
if (strchr(hp, 'd') != NULL)
MSG_SET_PERM_FLAGS(msginfo->flags, MSG_DELETED);
if (strchr(hp, 'r') != NULL)
MSG_SET_PERM_FLAGS(msginfo->flags, MSG_REPLIED);
if (strchr(hp, 'f') != NULL)
MSG_SET_PERM_FLAGS(msginfo->flags, MSG_FORWARDED);
break;
#endif
case H_FROM_SPACE:
if (msginfo->fromspace) break;
msginfo->fromspace = g_strdup(hp);
break;
case H_LIST_POST:
msginfo->list_post = g_strdup(hp);
break;
case H_LIST_SUBSCRIBE:
msginfo->list_subscribe = g_strdup(hp);
break;
case H_LIST_UNSUBSCRIBE:
msginfo->list_unsubscribe = g_strdup(hp);
break;
case H_LIST_HELP:
msginfo->list_help = g_strdup(hp);
break;
case H_LIST_ARCHIVE:
msginfo->list_archive = g_strdup(hp);
break;
case H_LIST_OWNER:
msginfo->list_owner = g_strdup(hp);
default:
break;
}
}
if (!msginfo->inreplyto && msginfo->references)
msginfo->inreplyto =
g_strdup((gchar *)msginfo->references->data);
return msginfo;
}
gchar *procheader_get_fromname(const gchar *str)
{
gchar *tmp, *name;
Xstrdup_a(tmp, str, return NULL);
if (*tmp == '\"') {
extract_quote(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(tmp, '(', ')');
g_strstrip(tmp);
}
if (*tmp == '\0')
name = g_strdup(str);
else
name = g_strdup(tmp);
return name;
}
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;
result = sscanf(str, "%10s %d %9s %d %2d:%2d:%2d %5s",
weekday, day, month, year, hh, mm, ss, zone);
if (result == 8) return 0;
result = sscanf(str, "%3s,%d %9s %d %2d:%2d:%2d %5s",
weekday, day, month, year, hh, mm, ss, zone);
if (result == 8) return 0;
result = sscanf(str, "%d %9s %d %2d:%2d:%2d %5s",
day, month, year, hh, mm, ss, zone);
if (result == 7) return 0;
*zone = '\0';
result = sscanf(str, "%10s %d %9s %d %2d:%2d:%2d",
weekday, day, month, year, hh, mm, ss);
if (result == 7) return 0;
result = sscanf(str, "%d %9s %d %2d:%2d:%2d",
day, month, year, 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 == 7) return 0;
result = sscanf(str, "%d %9s %d %2d:%2d %5s",
day, month, year, hh, mm, zone);
if (result == 6) return 0;
*zone = '\0';
result = sscanf(str, "%10s %d %9s %d %2d:%2d",
weekday, day, month, year, hh, mm);
if (result == 6) return 0;
result = sscanf(str, "%d %9s %d %2d:%2d",
day, month, year, hh, mm);
if (result == 5) return 0;
return -1;
}
/*
* Hiro, most UNIXen support this function:
* http://www.mcsr.olemiss.edu/cgi-bin/man-cgi?getdate
*/
gboolean procheader_date_parse_to_tm(const gchar *src, struct tm *t, char *zone)
{
static gchar monthstr[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
gchar weekday[11];
gint day;
gchar month[10];
gint year;
gint hh, mm, ss;
GDateMonth dmonth;
gchar *p;
if (!t)
return FALSE;
memset(t, 0, sizeof *t);
if (procheader_scan_date_string(src, weekday, &day, month, &year,
&hh, &mm, &ss, zone) < 0) {
g_warning("Invalid date: %s\n", src);
return FALSE;
}
/* Y2K compliant :) */
if (year < 100) {
if (year < 70)
year += 2000;
else
year += 1900;
}
month[3] = '\0';
if ((p = strstr(monthstr, month)) != NULL)
dmonth = (gint)(p - monthstr) / 3 + 1;
else {
g_warning("Invalid month: %s\n", month);
dmonth = G_DATE_BAD_MONTH;
}
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;
mktime(t);
return TRUE;
}
time_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;
if (procheader_scan_date_string(src, weekday, &day, month, &year,
&hh, &mm, &ss, zone) < 0) {
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';
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);
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 time_t timer)
{
struct tm *lt;
gchar *default_format = "%y/%m/%d(%a) %H:%M";
gchar *str;
const gchar *src_codeset, *dest_codeset;
lt = localtime(&timer);
if (prefs_common.date_format)
strftime(dest, len, prefs_common.date_format, lt);
else
strftime(dest, len, default_format, lt);
src_codeset = conv_get_locale_charset_str();
dest_codeset = CS_UTF_8;
str = conv_codeset_strdup(dest, src_codeset, dest_codeset);
if (str) {
g_snprintf(dest, len, "%s", str);
strncpy2(dest, str, len);
g_free(str);
}
}
/* Added by Mel Hadasht on 27 Aug 2001 */
/* Get a header from msginfo */
gint procheader_get_header_from_msginfo(MsgInfo *msginfo, gchar *buf, gint len, gchar *header)
{
gchar *file;
FILE *fp;
HeaderEntry hentry[]={ { NULL, NULL, TRUE },
{ NULL, NULL, FALSE } };
gint val;
hentry[0].name = header;
g_return_val_if_fail(msginfo != NULL, -1);
file = procmsg_get_message_file_path(msginfo);
if ((fp = g_fopen(file, "rb")) == NULL) {
FILE_OP_ERROR(file, "fopen");
g_free(file);
return -1;
}
val = procheader_get_one_field(buf,len, fp, hentry);
if (fclose(fp) == EOF) {
FILE_OP_ERROR(file, "fclose");
g_unlink(file);
g_free(file);
return -1;
}
g_free(file);
if (val == -1)
return -1;
return 0;
}