mime.c
来自「LINUX下的收发E-MAIL的程序」· C语言 代码 · 共 569 行
C
569 行
#include "mime.h"
static char base64_chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
char *eml_mime_decode_base64(char *data, int *length)
{
// This function is Copyright (C) 1999 by Jussi Junni of GnoMail
char *workspace, *p;
unsigned long pos = 0;
int i, a[4], len = 0;
unsigned int kk;
if (data == NULL)
return NULL;
kk = (unsigned) sizeof(char) * ((strlen(data) / 4) * 3 + 1);
workspace = (char *) malloc(kk);
memset(workspace, 0, (strlen(data) / 4) * 3 + 1);
while (*data && len < *length) {
for (i = 0; i < 4; i++, data++, len++) {
if ((p = strchr(base64_chars, *data)))
a[i] = (int) (p - base64_chars);
else
i--;
}
workspace[pos] = (((a[0] << 2) & 0xfc) | ((a[1] >> 4) & 0x03));
workspace[pos + 1] = (((a[1] << 4) & 0xf0) | ((a[2] >> 2) & 0x0f));
workspace[pos + 2] = (((a[2] << 6) & 0xc0) | (a[3] & 0x3f));
if (a[2] == 64 && a[3] == 64) {
workspace[pos + 1] = 0;
pos -= 2;
} else {
if (a[3] == 64) {
workspace[pos + 2] = 0;
pos--;
}
}
pos += 3;
}
workspace[kk - 1] = '\0';
*length = pos;
return workspace;
}
char *eml_mime_encode_base64(char *message, int *length, int flag)
{
char *encoded, *index, buffer[3];
int pos, len;
encoded = malloc(sizeof(char) * (int) (*length * 1.40)); // it gets 33% larger
pos = 0;
len = 0;
index = message;
while (index - message < *length) {
memcpy(buffer, index, 3);
*(encoded + pos) = base64_chars[(buffer[0] >> 2) & 0x3f];
*(encoded + pos + 1) = base64_chars[((buffer[0] << 4) & 0x30) |
((buffer[1] >> 4) & 0xf)];
*(encoded + pos + 2) = base64_chars[((buffer[1] << 2) & 0x3c) |
((buffer[2] >> 6) & 0x3)];
*(encoded + pos + 3) = base64_chars[buffer[2] & 0x3f];
len += 4;
// base64 can only have 76 chars per line
if (len >= 76) {
*(encoded + pos + 4) = '\n';
pos++;
len = 0;
}
pos += 4;
index += 3;
}
// if there were less then a full triplet left, we pad the remaining
// encoded bytes with =
if (*length % 3 == 1) {
*(encoded + pos - 1) = '=';
*(encoded + pos - 2) = '=';
}
if (*length % 3 == 2) {
*(encoded + pos - 1) = '=';
}
if (flag) {
*(encoded + pos) = '\n';
*(encoded + pos + 1) = '\0';
} else
*(encoded + pos) = '\0';
*length = strlen(encoded);
return encoded;
}
char *eml_mime_decode_quoted_printable(char *message, int *length)
{
char *buffer, *index, ch[2];
int i = 0, temp;
if ((buffer = malloc(*length + 1)) == NULL) {
printf("Cann't malloc memory\n");
return NULL;
}
index = message;
while (index - message < *length) {
if (*index == '=') {
index++;
if (*index != '\n') {
sscanf(index, "%2x", &temp);
sprintf(ch, "%c", temp);
buffer[i] = ch[0];
i++;
index += 2;
} else {
index++;
}
} else {
buffer[i] = *index;
i++;
index++;
}
}
buffer[i] = '\0';
*length = strlen(buffer);
return buffer;
}
int eml_mime_detect(char *message)
{
char *version;
char *buffer;
int major, minor;
// if we detect the MIME-Version: field, this message is mime formatted
version = eml_mail_get_header_field(message, "MIME-Version:");
if (version == NULL)
return 0;
buffer = get_field(version, 1, '.');
major = atoi(buffer);
if (buffer != NULL)
free(buffer);
else
return 0;
buffer = get_field(version, 2, '.');
minor = atoi(buffer);
if (buffer != NULL)
free(buffer);
else
return 0;
// if the version isn't 1.0 this is either some old mail or in the future
// a mail with a newer mime spec that we dont support. We just output
// a warning and try to parse it anyway.
if (major != 1 || minor != 0)
printf("Warning: unknown Mime-Version %d.%d\n", major, minor);
return 1;
}
int eml_mime_parse(char *message, Rmail * rmail)
{
char *content_type, *content_transfer_e, *index, *body, *boundary_pos;
char *content_disp;
char type[64], subtype[64], parameter[128], boundary[128],
filename[20];
int i, pos, ret, ii, bindex = 0;
struct mime_part *part;
char *bps = NULL, *bps1 = NULL;
int in_len;
bindex = 1;
if ((bps = strstr(message, "boundary=")) != NULL) {
bps += 1;
bps1 = strstr(bps, "boundary=");
if (bps1 != NULL)
bindex++;
}
rmail->attach_file = NULL;
rmail->content = NULL;
for (ii = 0; ii < bindex; ii++) {
if (ii == 0) {
content_type =
eml_mail_get_header_field(message, "Content-Type:");
} else {
content_type =
eml_mail_get_header_field(bps1 - 50, "Content-Type:");
}
if (content_type != NULL) {
eml_mime_parse_content_type(content_type, type, subtype,
parameter);
} else {
strcpy(type, "text");
strcpy(subtype, "plain");
}
if (!strcasecmp(type, "multipart")) {
ret =
eml_mime_get_parameter_value(parameter, "boundary",
boundary);
// no boundary? if this happens someone is sending us broken mail
if (!ret)
return 0;
body = strstr(message, "\n\n") + 2;
i = 0;
while ((index = strstr(body + i, boundary)) != NULL) {
// this is the end marking boundary, which has two - appended.
if (*(index + strlen(boundary)) == '-'
&& *(index + strlen(boundary) + 1) == '-')
break;
part = g_malloc0(sizeof(struct mime_part));
part->pos = strstr(index, "\n\n") + 2 - message;
content_type =
eml_mail_get_header_field(index + strlen(boundary),
"Content-Type:");
content_disp =
eml_mail_get_header_field(index + strlen(boundary),
"Content-Disposition:");
if (content_type != NULL)
eml_mime_parse_content_type(content_type, type,
subtype, parameter);
else {
strcpy(type, "text");
strcpy(subtype, "plain");
}
content_transfer_e =
eml_mail_get_header_field(index + strlen(boundary),
"Content-Transfer-Encoding:");
if (content_transfer_e != NULL)
strncpy(part->encoding, content_transfer_e, 63);
else
strcpy(part->encoding, "7bits");
strncpy(part->type, type, 63);
strncpy(part->subtype, subtype, 63);
strncpy(part->parameter, parameter, 127);
i = index - body + strlen(boundary);
boundary_pos = strstr(body + i, boundary);
// some mailers apperently doesn't put an end boundary marker
if (boundary_pos == NULL) {
boundary_pos = body + i;
while (*boundary_pos != '\0')
boundary_pos++;
}
part->len = boundary_pos - (strstr(index, "\n\n") + 2) - 2;
if (content_disp != NULL) {
part->attachment = 1;
} else
part->attachment = 0;
if (strstr(part->type, "attachment")) {
if (search_filename_from_buffer(filename, part->type)
>= 0)
if (ii == 0) {
rmail->attach_file =
malloc(strlen(filename) + 1);
strcpy(rmail->attach_file, filename);
} else {
ret = strlen(rmail->attach_file);
rmail->attach_file =
realloc(rmail->attach_file,
ret + strlen(filename) + 2);
strcat(rmail->attach_file, ";");
strcat(rmail->attach_file, filename);
} else;
} else if ((strstr(part->type, "text"))
&& (strstr(part->subtype, "plain"))
&& (part->len > 0)) {
rmail->content =
eml_mime_get_part(message, &in_len, part);
}
}
} else {
part = g_malloc0(sizeof(struct mime_part));
pos = strstr(message, "\n\n") - message;
strncpy(part->type, type, 63);
strncpy(part->subtype, subtype, 63);
strncpy(part->parameter, parameter, 127);
content_transfer_e =
eml_mail_get_header_field(message,
"Content-Transfer-Encoding:");
if (content_transfer_e != NULL)
strncpy(part->encoding, content_transfer_e, 63);
else
strcpy(part->encoding, "7bits");
part->pos = pos + 2;
index = message + part->pos;
i = 0;
while (*index != '\0') {
i++;
index++;
}
part->len = i;
part->attachment = 0;
if (part->len > 0)
rmail->content = eml_mime_get_part(message, &in_len, part);
}
}
return 0;
}
char *eml_mime_get_part(char *message, int *in_len, struct mime_part *tmp)
{
char *part, *index, *temp, *ptr, *decoded;
int i, len = 0, loop = 0;
if (tmp == NULL)
return (char *) NULL;
part = malloc(tmp->len + 1);
index = message + tmp->pos;
if (!strcasecmp(tmp->encoding, "base64")) {
len = tmp->len;
printf("have enter:\n%s\n",index);
// remove all enters, decode_base64 doesn't like them
for (temp = index, i = 0; *temp != '\0' && i < tmp->len;
temp++, i++) {
while (*temp == '\n') {
for (ptr = temp; *ptr != '\0'; ptr++)
*ptr = *(ptr + 1);
len--;
}
}
decoded = eml_mime_decode_base64(index, &len);
memcpy(part, decoded, len);
part[len] = '\0';
printf("have not enter:\n%s\n",part);
free(decoded);
*in_len = len;
} else if (!strcasecmp(tmp->encoding, "quoted-printable")) {
len = tmp->len;
decoded = eml_mime_decode_quoted_printable(index, &len);
strcpy(part, decoded);
free(decoded);
*in_len = len;
} else {
i = 0;
while (*index != '\0' && i < tmp->len) {
part[i] = *index;
index++;
i++;
}
part[i] = '\0';
*in_len = strlen(part);
}
return (char *) (part);
}
int eml_mime_parse_content_type(char *content_type, char *type,
char *subtype, char *parameter)
{
char *index, *start;
int len, i;
if (content_type == NULL)
return 0;
len = strlen(content_type);
start = index = content_type;
// copy the type
i = 0;
while (*index != '/' && index - start < len) {
type[i] = *index;
i++;
index++;
}
type[i] = '\0';
// copy the subtype
index++;
i = 0;
while (*index != ';' && index - start < len) {
subtype[i] = *index;
index++;
i++;
}
subtype[i] = '\0';
index++;
while (isspace(*index))
index++;
// copy the parameters
i = 0;
while (*index != '\0' && index - start < len) {
parameter[i] = *index;
index++;
i++;
}
parameter[i] = '\0';
return 1;
}
int eml_mime_get_parameter_value(char *parameter, char *in_name, char *out)
{
char *index, name[64], val[128];
int i, found, len;
index = parameter;
len = strlen(parameter);
while (*index != '\0' && index - parameter < len) {
found = 0;
// skip until a ascii char
while (!isalnum(*index)) {
index++;
}
i = 0;
while (*index != '=' && i < 63) {
name[i] = *index;
index++;
i++;
}
name[i] = '\0';
if (!strcasecmp(in_name, name)) {
found = 1;
}
index++;
// parameters can be either name=val or name="val", we can handle both
if (*index != '"') {
i = 0;
while (*index != ';' && i < 127) {
val[i] = *index;
index++;
i++;
}
val[i] = '\0';
if (found) {
strncpy(out, val, 127);
out[127] = '\0';
parse_8bit(out);
return 1;
}
} else {
index++;
i = 0;
while (*index != '"' && i < 127) {
val[i] = *index;
index++;
i++;
}
val[i] = '\0';
if (found) {
strncpy(out, val, 127);
out[127] = '\0';
parse_8bit(out);
return 1;
}
}
index += 2;
}
return 0;
}
// generates a random boundary
char *eml_mime_get_boundary(void)
{
static char boundary[128];
char *index;
int i;
srand(time(NULL) + getpid());
memset(boundary, 0, sizeof(boundary));
sprintf(boundary, "animail");
index = boundary + 7;
i = 0;
while (i < 20) {
*(index + i) = (rand() % 26) + 65;
i++;
}
*(index + i) = '\0';
return boundary;
}
int eml_mime_insert_part(char **message, int index, char *boundary,
char *file)
{
FILE *fp;
struct stat st;
int ret, i, x;
unsigned int size;
char *buffer, *encoded;
char content_type[64];
char content_transfer_encoding[64];
ret = stat(file, &st);
if (ret < 0) {
printf("Couldn't stat %s", file);
return 0;
}
size = st.st_size;
// this should be autodetected , so we would use text/plain and quoted-printable
// for attached text files and so on
snprintf(content_type, 64, "application/octet-stream; name=\"%s\"",
g_basename(file));
strcpy(content_transfer_encoding, "base64");
fp = fopen(file, "rt");
if (fp == NULL) {
printf("Couldn't open %s\n", file);
return 0;
}
// todo: it isn't very convinient to load all the file into memory at once
// if the file is very large, 10 meg or something. (But who
// would attach such a file?)
buffer = g_malloc0(sizeof(char) * (size + 1));
fread(buffer, 1, size, fp);
fclose(fp);
buffer[size] = '\0';
encoded = eml_mime_encode_base64(buffer, &size, 0);
free(buffer);
// we realloc the string so it can hold the encoded data + the boundary +
// the part header
message[0] =
realloc(message[0],
strlen(message[0]) + strlen(boundary) + strlen(encoded) +
strlen(content_type) + strlen(content_transfer_encoding) +
strlen(g_basename(file)) + 100);
i = x = 0;
// ok, here goes the part header
i += sprintf(message[0] + index + i, "--%s\n", boundary);
i += sprintf(message[0] + index + i,
"Content-Type: %s\nContent-Transfer-Encoding: %s\n",
content_type, content_transfer_encoding);
i += sprintf(message[0] + index + i,
"Content-Disposition: attachment; filename=\"%s\"\n\n",
g_basename(file));
while (*(encoded + x) != '\0') {
*(message[0] + index + i) = *(encoded + x);
i++;
x++;
}
*(message[0] + index + i) = '\0';
free(encoded);
return strlen(message[0] + index);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?