/*
elmo - Electronic Mail Operator
Copyright (C) 2003, 2004 rzyjontko
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; version 2.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
----------------------------------------------------------------------
*/
/****************************************************************************
* IMPLEMENTATION HEADERS
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <regex.h>
#include <errno.h>
#ifdef HAVE_ICONV
# include <iconv.h>
#endif
#include "mime.h"
#include "xmalloc.h"
#include "file.h"
#include "memchunk.h"
#include "ask.h"
#include "error.h"
#include "str.h"
#include "misc.h"
#include "gettext.h"
#include "debug.h"
#include "rmime.h"
#include "pgp.h"
/****************************************************************************
* IMPLEMENTATION PRIVATE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS
****************************************************************************/
#define isupper(a) ((a) >= 'A' && (a) <= 'Z')
#define islower(a) ((a) >= 'a' && (a) <= 'z')
#define isdigit(a) ((a) >= '0' && (a) <= '9')
#define isxdigit(a) (isdigit (a) || ((a) >= 'A' && (a) <= 'F') \
|| ((a) >= 'a' && (a) <= 'f'))
#define isbase64(a) (isupper (a) || islower (a) || isdigit (a) || (a) == '+' \
|| (a) == '/' || (a) == '=')
#define BASE64_VAL(a) (isupper (a) ? ((a) - 'A') \
: (islower (a) ? ((a) - 'a' + 26) \
: (isdigit (a) ? ((a) - '0' + 52) \
: ((a) == '+' ? 62 \
: ((a) == '/' ? 63 : 0)))))
#define BASE64_SIGN(a) (((a) < 26) ? ('A' + (a)) \
: (((a) < 52) ? ('a' + (a) - 26) \
: (((a) < 62) ? ('0' + (a) - 52) \
: (((a) == 62) ? '+' \
: (((a) == 63) ? '/' : 0)))))
#define DECRYPTED(m) (((m)->decrypted) ? ((m)->decrypted) : ((m)->mime))
/****************************************************************************
* IMPLEMENTATION PRIVATE CLASS PROTOTYPES / EXTERNAL CLASS REFERENCES
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE STRUCTURES / UTILITY CLASSES
****************************************************************************/
struct pair_list {
struct pair_list *next;
char *from;
char *to;
};
struct rfc2047 {
int special_; /* 1 if _ means a space */
char *charset; /* charset used in first occurence */
char *str; /* header string */
str_t *inter; /* intermediate buffer */
str_t *result; /* resulting buffer */
regmatch_t matches[5]; /* 0 - all, 2 - charset,
3 - Q/B, 4 - content */
};
struct mime_handler {
struct mime_handler *next;
char *type;
char *handler;
};
struct mime_type {
struct mime_type *next;
char *type;
regex_t re;
};
/****************************************************************************
* IMPLEMENTATION REQUIRED EXTERNAL REFERENCES (AVOID)
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE DATA
****************************************************************************/
/* These are used to find occurences of something like: =?...?Q?...?= */
static int encoded_compiled = 0;
static regex_t encoded_string_re;
/* These are used to find mime types like "text/plain; charset=iso-8859-2" */
static int mime_type_compiled = 0;
static regex_t mime_type_re;
static int mime_charset_compiled = 0;
static regex_t mime_charset_re;
/* List of charset conversions */
static struct pair_list *conversions = NULL;
static struct pair_list *prepared = NULL;
/* List of MIME handlers. */
static struct mime_handler *handlers = NULL;
/* List of MIME types. */
static struct mime_type *types = NULL;
/****************************************************************************
* INTERFACE DATA
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE FUNCTION PROTOTYPES
****************************************************************************/
/****************************************************************************
* QP / BASE64 FUNCTIONS (RFC 2045)
****************************************************************************/
/**
* to -- inclusive
*/
static void
decode_qp (str_t *dest, char *from, char *to, int special_)
{
char buf[3];
buf[2] = '\0';
while (*from && from <= to){
switch (*from){
case '_':
if (special_){
str_put_char (dest, ' ');
}
else {
str_put_char (dest, '_');
}
from++;
break;
case '=':
if (isxdigit (from[1]) && isxdigit (from[2])){
buf[0] = from[1];
buf[1] = from[2];
str_put_char (dest,
strtol (buf, NULL, 16));
from += 3;
}
else if (from[1] == '\n'){
from += 2;
}
else {
from += 3;
}
break;
default:
str_put_char (dest, *from);
from++;
break;
}
}
}
static void
decode_base64 (str_t *dest, char *from, char *to)
{
while (from <= to && ! isbase64 (*to))
to--;
while (*from && from <= to){
while (*from == '\n' || *from == '\r')
from++;
str_put_char (dest, (BASE64_VAL (from[0]) << 2)
| (BASE64_VAL (from[1]) >> 4));
if (from[2] == '=')
break;
str_put_char (dest, (BASE64_VAL (from[1]) << 4)
| (BASE64_VAL (from[2]) >> 2));
if (from[3] == '=')
break;
str_put_char (dest, (BASE64_VAL (from[2]) << 6)
| (BASE64_VAL (from[3]) >> 0));
from += 4;
}
}
static void
encode_base64 (str_t *dest, unsigned char *from, unsigned char *to)
{
int line_len = 0;
while (from <= to){
str_put_char (dest, BASE64_SIGN (0x3f & (from[0] >> 2)));
if (from + 1 > to){
str_put_char (dest, BASE64_SIGN (0x3f & (from[0] << 4)));
str_put_nchar (dest, '=', 2);
break;
}
str_put_char (dest, BASE64_SIGN (0x3f & ((from[0] << 4)
| (from[1] >> 4))));
if (from + 2 > to){
str_put_char (dest, BASE64_SIGN (0x3f & (from[1] << 2)));
str_put_char (dest, '=');
break;
}
str_put_char (dest, BASE64_SIGN (0x3f & ((from[1] << 2)
| (from[2] >> 6))));
str_put_char (dest, BASE64_SIGN (0x3f & (from[2])));
if (line_len == 76){
str_put_char (dest, '\n');
line_len = 0;
}
else {
line_len += 4;
}
from += 3;
}
}
/****************************************************************************
* LIST FUNCTIONS
****************************************************************************/
static void
list_destroy (struct pair_list *list)
{
if (list == NULL)
return;
list_destroy (list->next);
if (list->from)
xfree (list->from);
if (list->to)
xfree (list->to);
xfree (list);
}
static struct pair_list *
list_find (struct pair_list *list, char *from)
{
if (list == NULL)
return NULL;
if (strcasecmp (list->from, from) == 0)
return list;
return list_find (list->next, from);
}
static void
destroy_handler (struct mime_handler *list)
{
if (list == NULL)
return;
destroy_handler (list->next);
if (list->type)
xfree (list->type);
if (list->handler)
xfree (list->handler);
xfree (list);
}
static void
destroy_type (struct mime_type *list)
{
if (list == NULL)
return;
destroy_type (list->next);
if (list->type)
xfree (list->type);
regfree (& list->re);
xfree (list);
}
static struct mime_type *
find_type (struct mime_type *list, const char *fname)
{
int ret;
if (list == NULL)
return NULL;
ret = regexec (& list->re, fname, 0, NULL, 0);
if (ret && ret != REG_NOMATCH){
error_regex (ret, & list->re, NULL);
return NULL;
}
else if (ret)
return find_type (list->next, fname);
return list;
}
static int
simple_match (const char *pattern, const char *type)
{
if (strcmp (pattern, "*") == 0)
return 1;
return strcasecmp (pattern, type) == 0;
}
static int
type_match (const char *pattern, const char *type)
{
char *p_slash = strchr (pattern, '/');
char *t_slash = strchr (type, '/');
int ret;
if (p_slash == NULL)
return simple_match (pattern, type);
if (t_slash == NULL)
return 0;
*p_slash = '\0';
*t_slash = '\0';
ret = simple_match (pattern, type);
*p_slash = '/';
*t_slash = '/';
if (ret == 0)
return 0;
return simple_match (p_slash + 1, t_slash + 1);
}
static struct mime_handler *
find_mime (struct mime_handler *list, const char *type)
{
if (list == NULL)
return NULL;
if (type_match (list->type, type))
return list;
return find_mime (list->next, type);
}
/****************************************************************************
* IMPLEMENTATION PRIVATE FUNCTIONS
****************************************************************************/
static int
is_text_trivial (mime_t *mime)
{
if (mime == NULL)
return 0;
if (mime->type == NULL)
return 1;
return 0;
}
static int
is_text (mime_t *mime)
{
char *handler;
if (is_text_trivial (mime))
return 1;
handler = mime_get_handler (mime);
if (handler == NULL)
return 0;
if (strcmp (handler, "elmo") == 0)
return 1;
return 0;
}
static int
find_encoded_string (struct rfc2047 *x)
{
int ret;
if (! encoded_compiled)
return 0;
ret = regexec (& encoded_string_re, x->str, 5, x->matches, 0);
if (ret && ret != REG_NOMATCH){
error_regex (ret, & encoded_string_re, NULL);
return 0;
}
return ! ret;
}
static void
save_charset (struct rfc2047 *s)
{
int len = s->matches[2].rm_eo - s->matches[2].rm_so;
s->charset = xmalloc (len + 1);
memcpy (s->charset, s->str + s->matches[2].rm_so, len);
s->charset[len] = '\0';
}
static void
get_intermediate (struct rfc2047 *s)
{
char *from;
char *to;
if (s->inter)
str_clear (s->inter);
else
s->inter = str_create ();
str_put_string_len (s->inter, s->str, s->matches[0].rm_so);
while (1) {
from = s->str + s->matches[4].rm_so;
to = s->str + s->matches[4].rm_eo - 1;
switch (s->str[s->matches[3].rm_so]){
case 'q':
case 'Q':
decode_qp (s->inter, from, to, s->special_);
break;
case 'b':
case 'B':
decode_base64 (s->inter, from, to);
break;
}
s->str += s->matches[0].rm_eo;
if (! find_encoded_string (s))
break;
str_put_string_len (s->inter, s->str, s->matches[0].rm_so);
}
str_put_string (s->inter, s->str);
}
#ifdef HAVE_ICONV
static void
translate (struct rfc2047 *s, char *to)
{
int ret;
iconv_t id = iconv_open (to, s->charset);
char *inptr, *outptr, *result;
int insize, outsize, ressize;
int bad_chars = 0;
if (id == (iconv_t) -1){
if (errno == EINVAL)
error_ (0,
_("conversion from %s to %s not available"),
s->charset, to);
else
error_ (errno, _("couldn't convert from %s to %s"),
s->charset, to);
return;
}
inptr = s->inter->str;
insize = s->inter->len;
result = xmalloc (insize + 1);
outptr = result;
outsize = ressize = insize;
while (insize > 0){
ret = iconv (id, & inptr, & insize, & outptr, & outsize);
if (ret == (size_t) -1 && errno != E2BIG){
bad_chars++;
inptr++;
insize--;
}
if (errno == E2BIG){
result = xrealloc (result, ressize * 2);
outptr += ressize - outsize;
outsize += ressize;
ressize *= 2;
}
}
if (bad_chars){
error_ (0, _("some characters were not converted from %s "
"to %s due to invalid multibyte sequence"),
s->charset, to);
}
*outptr = '\0';
s->result = str_dup (result);
xfree (result);
iconv_close (id);
}
#endif
static void
get_result (struct rfc2047 *s)
{
struct pair_list *list = list_find (conversions, s->charset);
if (list == NULL)
return;
#ifdef HAVE_ICONV
translate (s, list->to);
#else
error_ (0, _("conversions are unavailable on your system"));
#endif
}
static char *
get_file_name (char *header)
{
char *seek = strstr (header, "name=");
char *start;
char *result;
if (seek == NULL)
seek = strstr (header, "NAME=");
if (seek == NULL)
return NULL;
start = seek + 5;
if (*start == '"')
start++;
seek = start;
while (*seek != '"' && *seek != '\r' && *seek != '\n' && *seek
&& *seek != ';'){
seek++;
}
result = xmalloc (seek - start + 1);
result[seek - start] = '\0';
memcpy (result, start, seek - start);
return mime_decode_header (result, seek - start, 1);
}
static void
get_type (mime_t *mime, char *str)
{
int ret;
int len;
regmatch_t matches[2];
if (! mime_type_compiled)
return;
ret = regexec (& mime_type_re, str, 2, matches, 0);
if (ret && ret != REG_NOMATCH){
error_regex (ret, & mime_type_re, NULL);
return;
}
if (ret == REG_NOMATCH){
error_ (0, _("invalid mime type '%s'"), str);
return;
}
len = matches[0].rm_eo - matches[0].rm_so;
mime->type = xmalloc (len + 1);
memcpy (mime->type, str + matches[0].rm_so, len);
mime->type[len] = '\0';
if (! mime_charset_compiled)
return;
ret = regexec (& mime_charset_re, str, 2, matches, 0);
if (ret && ret != REG_NOMATCH){
error_regex (ret, & mime_charset_re, NULL);
return;
}
if (ret == REG_NOMATCH || matches[1].rm_so < 0)
return;
len = matches[1].rm_eo - matches[1].rm_so;
mime->charset = xmalloc (len + 1);
memcpy (mime->charset, str + matches[1].rm_so, len);
mime->charset[len] = '\0';
}
static void
destroy_s (struct rfc2047 *s)
{
if (s->inter && s->result){
str_destroy (s->inter);
}
else if (s->inter){
s->result = s->inter;
}
if (s->charset)
xfree (s->charset);
}
static void
determine_type (mime_t *mime)
{
struct mime_type *type = find_type (types, mime->file_name);
if (type == NULL){
mime->type = xstrdup ("application/octet-stream");
mime->encoding = MENC_BASE64;
}
else {
mime->type = xstrdup (type->type);
if (is_text (mime))
mime->encoding = MENC_NONE;
else
mime->encoding = MENC_BASE64;
}
}
static void
register_new_type (char *type, char *re)
{
int ret;
struct mime_type *new;
new = xmalloc (sizeof (struct mime_type));
new->type = type;
ret = regcomp (& new->re, re,
REG_ICASE | REG_EXTENDED | REG_NEWLINE);
if (ret){
error_regex (ret, & new->re, re);
regfree (& new->re);
xfree (type);
xfree (re);
return;
}
new->next = types;
types = new;
}
static void
register_new_handler (char *type, char *handler)
{
struct mime_handler *new;
new = xmalloc (sizeof (struct mime_handler));
new->type = type;
new->handler = handler;
new->next = handlers;
handlers = new;
}
static int
leaf_count (mime_t *mime)
{
int i;
int result = 0;
if (mime == NULL)
return 0;
if (mime->parts == NULL)
return 1;
for (i = 0; i < mime->parts->count; i++){
result += leaf_count (mime->parts->array[i]);
}
return result;
}
static mime_t *
first_leaf (mime_t *mime)
{
if (mime == NULL)
return NULL;
if (mime->parts == NULL)
return mime;
return first_leaf (mime->parts->array[0]);
}
static mime_t *
last_leaf (mime_t *mime)
{
if (mime == NULL)
return NULL;
if (mime->parts == NULL)
return mime;
return last_leaf (mime->parts->array[mime->parts->count - 1]);
}
static mime_t *
nth_leaf (mime_t *mime, int *index)
{
int i;
mime_t *result;
rmime_t *parts;
if (mime == NULL)
return NULL;
if (*index == 0)
return first_leaf (mime);
parts = mime->parts;
if (parts == NULL){
(*index)--;
return NULL;
}
for (i = 0; i < parts->count; i++){
result = nth_leaf (parts->array[i], index);
if (result != NULL)
return result;
}
return NULL;
}
static mime_t *
first_text (mime_t *mime)
{
int i;
mime_t *result;
if (is_text (mime))
return mime;
if (mime->parts == NULL)
return NULL;
for (i = 0; i < mime->parts->count; i++){
result = first_text (mime->parts->array[i]);
if (result != NULL)
return result;
}
return NULL;
}
static int
has_attachment (mime_t *mime)
{
int i;
if (mime == NULL)
return 0;
if (mime->file_name != NULL)
return 1;
if (mime->parts == NULL)
return 0;
for (i = 0; i < mime->parts->count; i++){
if (has_attachment (mime->parts->array[i]))
return 1;
}
return 0;
}
/****************************************************************************
* INTERFACE FUNCTIONS
****************************************************************************/
void
mime_init (void)
{
int ret;
ret = regcomp (& encoded_string_re,
"(\n[ \t])?=\\?([^?]+)\\?([QB])\\?([^?]+)\\?=",
REG_ICASE | REG_EXTENDED | REG_NEWLINE);
if (ret){
encoded_compiled = 0;
error_regex (ret, & encoded_string_re, "internal re");
regfree (& encoded_string_re);
}
else {
encoded_compiled = 1;
}
ret = regcomp (& mime_type_re,
"[a-z\\-]+(/[a-z0-9\\.\\-]+)?",
REG_ICASE | REG_EXTENDED | REG_NEWLINE);
if (ret){
mime_type_compiled = 0;
error_regex (ret, & mime_type_re, "internal re");
regfree (& mime_type_re);
}
else {
mime_type_compiled = 1;
}
ret = regcomp (& mime_charset_re,
"charset=\"?([a-z0-9\\-]+)\"?",
REG_ICASE | REG_EXTENDED | REG_NEWLINE);
if (ret){
mime_charset_compiled = 1;
error_regex (ret, & mime_charset_re, "internal re");
regfree (& mime_charset_re);
}
else {
mime_charset_compiled = 1;
}
}
void
mime_post_setup (void)
{
register_new_handler (xstrdup ("text/plain"), xstrdup ("elmo"));
register_new_handler (xstrdup ("message/rfc822"), xstrdup ("elmo"));
register_new_handler (xstrdup ("text/html"), xstrdup ("elmo"));
register_new_handler (xstrdup ("multipart/encrypted"),
xstrdup ("elmo-pgp"));
register_new_handler (xstrdup ("multipart/signed"),
xstrdup ("elmo-pgp"));
register_new_type (xstrdup ("text/plain"),
"(\\.txt$)|(README)|(\\.diff$)|(\\.asc$)"
"|(\\.[ch]$)|(\\.cpp$)|(\\.cc$)|(\\.java$)"
"|(\\.sh$)|(\\.tex$)|(\\.pl$)|(\\.po$)"
"|(\\.dsc$)");
register_new_type (xstrdup ("text/html"), "\\.[dsx]?html?$");
register_new_type (xstrdup ("text/rtf"), "\\.rtf$");
register_new_type (xstrdup ("text/xml"), "\\.x[ms]l$");
register_new_type (xstrdup ("text/css"), "\\.css$");
register_new_type (xstrdup ("image/gif"), "\\.gif$");
register_new_type (xstrdup ("image/jpeg"), "\\.jpe?g?$");
register_new_type (xstrdup ("image/png"), "\\.png$");
register_new_type (xstrdup ("image/bmp"), "\\.bmp$");
register_new_type (xstrdup ("image/pcx"), "\\.pcx$");
register_new_type (xstrdup ("image/tiff"), "\\.tiff?$");
register_new_type (xstrdup ("audio/mpeg"),
"(\\.mp[23]$)|(\\.mpe?ga$)");
register_new_type (xstrdup ("audio/midi"), "\\.midi?$");
register_new_type (xstrdup ("video/mpeg"), "\\.mp[eg]g?$");
}
void
mime_free_resources (void)
{
if (encoded_compiled)
regfree (& encoded_string_re);
encoded_compiled = 0;
if (mime_type_compiled)
regfree (& mime_type_re);
mime_type_compiled = 0;
if (mime_charset_compiled)
regfree (& mime_charset_re);
mime_charset_compiled = 0;
list_destroy (conversions);
conversions = NULL;
list_destroy (prepared);
prepared = NULL;
destroy_handler (handlers);
handlers = NULL;
destroy_type (types);
types = NULL;
}
void
mime_add_charset (char *str)
{
if (prepared){
prepared->to = str;
prepared->next = conversions;
conversions = prepared;
prepared = NULL;
}
else {
prepared = xmalloc (sizeof (struct pair_list));
prepared->from = str;
prepared->to = NULL;
prepared->next = NULL;
}
}
void
mime_register_type (char *type, char *re)
{
register_new_type (type, re);
xfree (re);
}
void
mime_register_handler (char *type, char *handler)
{
register_new_handler (type, handler);
}
char *
mime_get_handler (mime_t *mime)
{
struct mime_handler *handler;
if (mime->type == NULL)
return NULL;
handler = find_mime (handlers, mime->type);
if (handler == NULL || handler->handler == NULL){
return NULL;
}
return handler->handler;
}
void
mime_decrypt (mime_info_t *mime_info)
{
char *handler;
if (mime_info == NULL || mime_info->mime == NULL)
return;
if (mime_info->decrypted)
return;
handler = mime_get_handler (mime_info->mime);
if (handler == NULL)
return;
if (strcmp (handler, "elmo-pgp") == 0){
pgp_decrypt_verify (mime_info);
}
}
/* RFC2047 */
char *
mime_decode_header (char *str, int len, int free_s)
{
int ret;
struct rfc2047 s;
s.str = str;
s.inter = NULL;
s.result = NULL;
s.special_ = 1;
ret = find_encoded_string (& s);
if (! ret && free_s){
return str;
}
else if (! ret){
return xstrdup (str);
}
save_charset (& s);
get_intermediate (& s);
get_result (& s);
if (free_s)
xfree (str);
destroy_s (& s);
return str_finished (s.result);
}
char *
mime_decode_utf8 (char *str)
{
struct rfc2047 s;
s.str = NULL;
s.inter = NULL;
s.charset = xstrdup ("utf-8");
s.inter = str_dup (str);
get_result (& s);
destroy_s (& s);
return str_finished (s.result);
}
str_t *
mime_decode (mime_t *mime, char *str, int free_s)
{
int len;
str_t *result = NULL;
struct rfc2047 s;
if (mime == NULL || str == NULL)
return NULL;
len = mime->off_end - mime->off_start;
switch (mime->encoding){
case MENC_NONE:
case MENC_7BIT:
case MENC_8BIT:
result = str_from_str (str, len);
break;
case MENC_QP:
result = str_create_size (len + 1);
decode_qp (result, str, str + len - 1, 0);
break;
case MENC_BASE64:
result = str_create_size (len + 1);
decode_base64 (result, str, str + len - 1);
break;
case MENC_UUENCODE:
error_ (0, _("uudecode unimplemented yet"));
return str_from_str (str, len);
default:
debug_msg (DEBUG_ERROR, "invalid encoding in mime_decode");
error_ (0, "%s", _("You have found a bug. Please submit a bug report"));
return NULL;
}
if (result->str != str && free_s)
xfree (str);
if (mime->charset == NULL)
return result;
s.charset = mime->charset;
s.inter = result;
s.result = NULL;
get_result (& s);
s.charset = NULL;
destroy_s (& s);
return s.result;
}
str_t *
mime_encode (mime_t *mime, char *bytes, int len)
{
int rlen;
str_t *result;
switch (mime->encoding){
case MENC_NONE:
case MENC_7BIT:
case MENC_8BIT:
return str_from_str (bytes, len);
case MENC_QP:
error_ (0, _("q-p encoding unimplemented yet"));
return str_from_str (bytes, len);
case MENC_BASE64:
rlen = (4 * len) / 3;
rlen += rlen / 76 + 1;
rlen += 5;
result = str_create_size (rlen + 1);
encode_base64 (result, bytes, bytes + len - 1);
xfree (bytes);
return result;
case MENC_UUENCODE:
error_ (0, _("uuencode unimplemented yet"));
return str_from_str (bytes, len);
default:
debug_msg (DEBUG_ERROR, "invalid encoding in mime_encode");
error_ (0, "%s", _("You have found a bug. Please submit a bug report"));
return NULL;
}
}
mime_info_t *
mime_info_create (void)
{
mime_info_t *mime_info;
mime_info = xmalloc (sizeof (mime_info_t));
mime_info->file = NULL;
mime_info->mime = mime_create ();
mime_info->d_file = NULL;
mime_info->decrypted = NULL;
mime_info->sig = SIG_NOT_SIGNED;
mime_info->sig_text = NULL;
return mime_info;
}
mime_t *
mime_create (void)
{
mime_t *mime;
mime = xmalloc (sizeof (mime_t));
mime->encoding = MENC_NONE;
mime->type = NULL;
mime->charset = NULL;
mime->off_header = -1;
mime->off_start = -1;
mime->off_end = -1;
mime->off_bound = -1;
mime->file_name = NULL;
mime->parts = NULL;
return mime;
}
mime_t *
mime_from_file_name (const char *fname)
{
mime_t *mime;
mime = mime_create ();
mime->file_name = xstrdup (fname);
determine_type (mime);
return mime;
}
void
mime_destroy (mime_t *mime)
{
rmime_destroy (mime->parts);
if (mime->file_name)
xfree (mime->file_name);
if (mime->type)
xfree (mime->type);
if (mime->charset)
xfree (mime->charset);
xfree (mime);
}
void
mime_info_destroy (mime_info_t *mime_info)
{
if (mime_info->mime)
mime_destroy (mime_info->mime);
if (mime_info->d_file){
unlink (mime_info->d_file);
xfree (mime_info->d_file);
}
if (mime_info->decrypted)
mime_destroy (mime_info->decrypted);
if (mime_info->sig_text)
xfree (mime_info->sig_text);
xfree (mime_info);
}
void
mime_set_from_header (mime_t *mime, char *str)
{
mime->file_name = get_file_name (str);
get_type (mime, str);
}
void
mime_complete_file_name (mime_t *mime, char *str)
{
if (mime->file_name)
return;
mime->file_name = get_file_name (str);
}
char *
mime_encoding_str (mime_t *mime)
{
switch (mime->encoding){
case MENC_NONE:
return NULL;
case MENC_7BIT:
return "7bit";
case MENC_8BIT:
return "8bit";
case MENC_QP:
return "quoted-printable";
case MENC_BASE64:
return "base64";
case MENC_UUENCODE:
return "uuencode";
}
return NULL;
}
void
mime_dump (memchunk_t *memchunk, mime_t *mime)
{
memchunk_intdump (memchunk, mime->encoding);
memchunk_strdump (memchunk, mime->type);
memchunk_strdump (memchunk, mime->charset);
memchunk_intdump (memchunk, mime->off_header);
memchunk_intdump (memchunk, mime->off_start);
memchunk_intdump (memchunk, mime->off_end);
memchunk_intdump (memchunk, mime->off_bound);
memchunk_strdump (memchunk, mime->file_name);
rmime_dump (memchunk, mime->parts);
}
mime_info_t *
mime_info_read (memchunk_t *memchunk)
{
mime_info_t *mime_info;
mime_info = mime_info_create ();
mime_read (memchunk, mime_info->mime);
return mime_info;
}
void
mime_read (memchunk_t *memchunk, mime_t *mime)
{
mime->encoding = memchunk_intget (memchunk);
mime->type = memchunk_strget (memchunk);
mime->charset = memchunk_strget (memchunk);
mime->off_header = memchunk_intget (memchunk);
mime->off_start = memchunk_intget (memchunk);
mime->off_end = memchunk_intget (memchunk);
mime->off_bound = memchunk_intget (memchunk);
mime->file_name = memchunk_strget (memchunk);
mime->parts = rmime_read (memchunk);
}
mime_t *
mime_last (mime_info_t *mime_info)
{
mime_t *mime;
mime = DECRYPTED (mime_info);
return last_leaf (mime);
}
mime_t *
mime_first (mime_info_t *mime_info)
{
mime_t *mime;
mime = DECRYPTED (mime_info);
return first_leaf (mime);
}
mime_t *
mime_nth_leaf (mime_info_t *mime_info, int index)
{
mime_t *mime;
mime = DECRYPTED (mime_info);
return nth_leaf (mime, & index);
}
int
mime_leaf_count (mime_info_t *mime_info)
{
mime_t *mime;
mime = DECRYPTED (mime_info);
return leaf_count (mime);
}
mime_t *
mime_first_text (mime_info_t *mime_info)
{
mime_t *mime;
mime = DECRYPTED (mime_info);
return first_text (mime);
}
char
mime_attachment_indicator (mime_info_t *mime_info)
{
mime_t *mime;
if (mime_info == NULL)
return ' ';
mime = DECRYPTED (mime_info);
if (mime == NULL || mime->type == NULL)
return ' ';
if (strcasecmp (mime->type, "multipart/encrypted") == 0){
return 'e';
}
if (strcasecmp (mime->type, "multipart/signed") == 0){
return 's';
}
if (has_attachment (mime))
return '+';
return ' ';
}
/****************************************************************************
* INTERFACE CLASS BODIES
****************************************************************************/
/****************************************************************************
*
* END MODULE mime.c
*
****************************************************************************/
syntax highlighted by Code2HTML, v. 0.9.1