summaryrefslogtreecommitdiff
path: root/decoders/mail/mail_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'decoders/mail/mail_util.c')
-rw-r--r--decoders/mail/mail_util.c1453
1 files changed, 1453 insertions, 0 deletions
diff --git a/decoders/mail/mail_util.c b/decoders/mail/mail_util.c
new file mode 100644
index 0000000..aa1a776
--- /dev/null
+++ b/decoders/mail/mail_util.c
@@ -0,0 +1,1453 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <assert.h>
+#include <sys/uio.h>
+
+#include "mail_util.h"
+
+void line_buffer_clear(struct stream_buffer *line_buffer)
+{
+ stream_buffer_slide(line_buffer);
+}
+
+void line_buffer_write(struct stream_buffer *line_buffer, const char *payload, size_t payload_len)
+{
+ stream_buffer_append(line_buffer, payload, payload_len);
+}
+
+int line_buffer_readln(struct stream_buffer *line_buffer, const char **line_start, size_t *line_len)
+{
+ size_t buf_len;
+ const char *buf;
+ const char *line_end;
+
+ *line_start = NULL;
+ *line_len = 0;
+
+ if (stream_buffer_is_full(line_buffer)) {
+ stream_buffer_reset(line_buffer);
+ return -1;
+ }
+
+ stream_buffer_get_data(line_buffer, &buf, &buf_len, 0);
+ line_end = (const char *)memmem(buf, buf_len, SMTP_LINE_END, strlen(SMTP_LINE_END));
+ if (line_end == NULL) {
+ return 0;
+ }
+
+ *line_start = buf;
+ *line_len = line_end - buf + strlen(SMTP_LINE_END);
+
+ stream_buffer_shift(line_buffer, *line_len);
+
+ return 1;
+}
+
+static inline void stream_buffer_deinit(struct stream_buffer *sb)
+{
+ sb->buf_size = 0;
+ sb->buf_len = 0;
+ sb->buf_off = 0;
+ if (sb->buf) {
+ free(sb->buf);
+ }
+}
+
+static inline void stream_buffer_init(struct stream_buffer *sb, size_t size)
+{
+ sb->buf_size = size;
+ sb->buf_len = 0;
+ sb->buf_off = 0;
+ sb->buf = NULL;
+}
+
+static inline int stream_buffer_is_full(struct stream_buffer *sb)
+{
+ if (sb->buf && sb->buf_off + sb->buf_len == sb->buf_size) {
+ return 1;
+ }
+ return 0;
+}
+
+static inline int stream_buffer_is_empty(struct stream_buffer *sb)
+{
+ if (sb->buf == NULL || sb->buf_off + sb->buf_len == 0) {
+ return 1;
+ }
+ return 0;
+}
+
+static inline void stream_buffer_reset(struct stream_buffer *sb)
+{
+ if (sb->buf && sb->buf_off + sb->buf_len > 0) {
+ sb->buf_len = 0;
+ sb->buf_off = 0;
+ }
+}
+
+static inline void stream_buffer_append(struct stream_buffer *sb, const char *data, size_t data_len)
+{
+ if (sb->buf == NULL && sb->buf_size > 0) {
+ sb->buf = (char *)malloc(sb->buf_size);
+ sb->buf_len = 0;
+ sb->buf_off = 0;
+ }
+ if (sb->buf_off + sb->buf_len + data_len > sb->buf_size) {
+ data_len = sb->buf_size - sb->buf_off - sb->buf_len;
+ }
+ memcpy(sb->buf + sb->buf_off + sb->buf_len, data, data_len);
+}
+
+static inline void stream_buffer_shift(struct stream_buffer *sb, size_t offset)
+{
+ if (sb->buf) {
+ if (sb->buf_len > offset) {
+ sb->buf_len -= offset;
+ sb->buf_off += offset;
+ } else {
+ sb->buf_off += sb->buf_len;
+ sb->buf_len = 0;
+ }
+ }
+}
+
+static inline void stream_buffer_slide(struct stream_buffer *sb)
+{
+ if (sb->buf && sb->buf_off > 0) {
+ if (sb->buf_len > 0) {
+ memmove(sb->buf, sb->buf + sb->buf_off, sb->buf_len);
+ sb->buf_off = 0;
+ } else {
+ stream_buffer_reset(sb);
+ }
+ }
+}
+
+static inline void stream_buffer_get_data(struct stream_buffer *sb, const char **data, size_t *data_len, size_t offset)
+{
+ *data = NULL;
+ *data_len = 0;
+ if (sb->buf && sb->buf_len > offset) {
+ *data = sb->buf + sb->buf_off + offset;
+ *data_len = sb->buf_len - offset;
+ }
+}
+
+static char* strntrim_sp(char *str, size_t *len) {
+ char *end;
+
+ while (*str == ' ' && *len > 0) {
+ str++;
+ (*len)--;
+ }
+
+ if (*len == 0) {
+ return str;
+ }
+
+ end = str + *len - 1;
+ while (end > str && *end == ' ') {
+ end--;
+ (*len)--;
+ }
+
+ return str;
+}
+
+int strnsplit(struct iovec *out, size_t n_out, char delimiter, const char *data, size_t data_len)
+{
+ size_t i;
+ size_t offset;
+ size_t part_len;
+ const char *data_end;
+ const char *part_start;
+ const char *part_end;
+
+ if (out == NULL || n_out == 0 || data == NULL || data_len == 0) {
+ return -1;
+ }
+
+ offset = 0;
+ data_end = data + data_len;
+
+ for (i = 0; i < n_out - 1; i++) {
+ part_start = data + offset;
+ part_end = memchr(part_start, delimiter, data_end - part_start);
+
+ if (part_end != NULL) {
+ // Found a delimiter
+ part_len = part_end - part_start;
+ out[i].iov_base = strntrim_sp((char*)part_start, &part_len);
+ out[i].iov_len = part_len;
+ offset += part_len + 1;
+ } else {
+ // Last part, no delimiter found
+ part_len = data_end - part_start;
+ out[i].iov_base = strntrim_sp((char*)part_start, &part_len);
+ out[i].iov_len = part_len;
+ offset += part_len;
+ return i + 1;
+ }
+
+ if (offset >= data_len) {
+ return i + 1;
+ }
+ }
+
+ // last part
+ part_start = data + offset;
+ part_len = data_end - part_start;
+ out[i].iov_base = strntrim_sp((char*)part_start, &part_len);
+ out[i].iov_len = part_len;
+
+ return n_out;
+}
+
+int mail_xoauth2_get_username(const char *buf, size_t len, char **username, size_t *username_len) {
+ if (!buf || len == 0 || !username || !username_len) {
+ return -1;
+ }
+
+ const char *user_prefix = "user=";
+ size_t prefix_len = strlen(user_prefix);
+
+ const char *username_start = NULL;
+ for (size_t i = 0; i <= len - prefix_len; i++) {
+ if (strncasecmp(buf + i, user_prefix, prefix_len) == 0) {
+ username_start = buf + i + prefix_len;
+ break;
+ }
+ }
+
+ if (!username_start) {
+ return -1;
+ }
+
+ const char *username_end = username_start;
+ while (username_end < buf + len && *username_end != ';') {
+ username_end++;
+ }
+
+ *username_len = username_end - username_start;
+ *username = (char *)username_start;
+
+ return 0;
+}
+
+int mail_extract_email_address(const char *buffer, size_t length, struct iovec *email_address)
+{
+ if (email_address == NULL) {
+ return -1;
+ }
+
+ email_address->iov_base = NULL;
+ email_address->iov_len = 0;
+
+ const char *start = (const char *)memchr(buffer, '<', length);
+ if (!start) {
+ return -2;
+ }
+ start++;
+
+ const char *end = (const char *)memchr(start, '>', buffer + length - start);
+ if (!end) {
+ return -3;
+ }
+
+ const char *at_sign = (const char *)memchr(start, '@', end - start);
+ if (!at_sign) {
+ return -4;
+ }
+
+ email_address->iov_base = (void *)start;
+ email_address->iov_len = end - start;
+
+ return 0;
+}
+
+int mail_publish_command(struct mail_env *mail_env, struct session *sess,
+ enum MAIL_PROTOCOL mail_protocol, size_t mail_seq,
+ enum MAIL_COMMAND command,
+ char *command_param, size_t command_param_len,
+ char *command_line, size_t command_line_len)
+{
+ struct mq_runtime *runtime;
+ struct mail_message *msg;
+
+ runtime = module_manager_get_mq_runtime(mail_env->mod_mgr_ref);
+ if (runtime == NULL) {
+ return -1;
+ }
+
+ msg = (struct mail_message *)calloc(1, sizeof(struct mail_message));
+ msg->sess_ref = sess;
+ msg->mail_seq = mail_seq;
+ msg->mail_protocol = mail_protocol;
+ msg->command = command;
+ msg->command_param = command_param;
+ msg->command_param_len = command_param_len;
+ msg->command_line = command_line;
+ msg->command_line_len = command_line_len;
+
+ return mq_runtime_publish_message(runtime, mail_env->command_topic_id, msg);
+}
+
+int mail_publish_header(struct mail_env *mail_env, struct session *sess,
+ enum MAIL_PROTOCOL mail_protocol, size_t mail_seq,
+ struct mail_header *header)
+{
+ struct mq_runtime *runtime;
+ struct mail_message *msg;
+
+ runtime = module_manager_get_mq_runtime(mail_env->mod_mgr_ref);
+ if (runtime == NULL) {
+ return -1;
+ }
+
+ msg = (struct mail_message *)calloc(1, sizeof(struct mail_message));
+ msg->sess_ref = sess;
+ msg->mail_seq = mail_seq;
+ msg->mail_protocol = mail_protocol;
+ msg->header = *header;
+
+ return mq_runtime_publish_message(runtime, mail_env->header_topic_id, msg);
+}
+
+int mail_publish_body(struct mail_env *mail_env, struct session *sess,
+ enum MAIL_PROTOCOL mail_protocol, size_t mail_seq,
+ char *body, size_t body_len,
+ size_t body_offset, int is_finished)
+{
+ struct mq_runtime *runtime;
+ struct mail_message *msg;
+
+ runtime = module_manager_get_mq_runtime(mail_env->mod_mgr_ref);
+ if (runtime == NULL) {
+ return -1;
+ }
+
+ msg = (struct mail_message *)calloc(1, sizeof(struct mail_message));
+ msg->sess_ref = sess;
+ msg->mail_seq = mail_seq;
+ msg->mail_protocol = mail_protocol;
+ msg->body = body;
+ msg->body_len = body_len;
+ msg->body_offset = body_offset;
+ msg->is_body_finished = is_finished;
+
+ return mq_runtime_publish_message(runtime, mail_env->body_topic_id, msg);
+}
+
+int mail_publish_attachment(struct mail_env *mail_env, struct session *sess,
+ enum MAIL_PROTOCOL mail_protocol, size_t mail_seq,
+ char *attachment_name, size_t attachment_name_len,
+ char *attachment, size_t attachment_len,
+ size_t attachment_offset, int is_finished)
+{
+ struct mq_runtime *runtime;
+ struct mail_message *msg;
+
+ runtime = module_manager_get_mq_runtime(mail_env->mod_mgr_ref);
+ if (runtime == NULL) {
+ return -1;
+ }
+
+ msg = (struct mail_message *)calloc(1, sizeof(struct mail_message));
+ msg->sess_ref = sess;
+ msg->mail_seq = mail_seq;
+ msg->mail_protocol = mail_protocol;
+ msg->attachment_name = attachment_name;
+ msg->attachment_name_len = attachment_name_len;
+ msg->attachment = attachment;
+ msg->attachment_len = attachment_len;
+ msg->attachment_offset = attachment_offset;
+ msg->is_attachment_finished = is_finished;
+
+ return mq_runtime_publish_message(runtime, mail_env->attachment_topic_id, msg);
+}
+
+int mail_publish_eml(struct mail_env *mail_env, struct session *sess,
+ enum MAIL_PROTOCOL mail_protocol,
+ char *eml, size_t eml_len,
+ size_t eml_offset, int is_eml_finished)
+{
+ struct mq_runtime *runtime;
+ struct mail_message *msg;
+
+ runtime = module_manager_get_mq_runtime(mail_env->mod_mgr_ref);
+ if (runtime == NULL) {
+ return -1;
+ }
+
+ msg = (struct mail_message *)calloc(1, sizeof(struct mail_message));
+ msg->sess_ref = sess;
+ msg->mail_protocol = mail_protocol;
+ msg->eml = eml;
+ msg->eml_len = eml_len;
+ msg->eml_offset = eml_offset;
+ msg->is_eml_finished = is_eml_finished;
+
+ return mq_runtime_publish_message(runtime, mail_env->eml_topic_id, msg);
+}
+
+int mail_message_process(struct mail_env *mail_env, struct mail_session_ctx *session_ctx)
+{
+ size_t mail_seq;
+ enum MAIL_PROTOCOL mail_protocol;
+
+ mail_seq = mail_parser_get_seq(session_ctx->smtp);
+ mail_protocol = mail_parser_get_protocol(session_ctx->parser);
+
+ enum MAIL_COMMAND cmd;
+ char *cmd_param;
+ size_t cmd_param_len;
+ char *cmd_line;
+ size_t cmd_line_len;
+
+ ret = mail_parser_get_command(session_ctx->parser, &cmd, &cmd_param, &cmd_param_len, &cmd_line, &cmd_line_len);
+ if (ret == 0) {
+ mail_publish_command(mail_env, sess, mail_protocol, mail_seq, cmd, cmd_param, cmd_param_len, cmd_line, cmd_line_len);
+ }
+
+ struct mail_header *header;
+
+ header = mail_parser_get_header(session_ctx->parser);
+ if (header) {
+ mail_publish_header(mail_env, sess, mail_protocol, mail_seq, header);
+ }
+
+ char *body;
+ size_t body_len;
+ size_t body_offset;
+ int is_body_finished;
+
+ ret = mail_parser_get_body(session_ctx->parser, &body, &body_len, &body_offset, &is_body_finished);
+ if (ret == 0) {
+ mail_publish_body(mail_env, sess, mail_protocol, mail_seq,
+ body, body_len,
+ body_offset, is_body_finished);
+ }
+
+ char *attachment_name;
+ size_t attachment_name_len;
+ char *attachment;
+ size_t attachment_len;
+ size_t attachment_offset;
+ int is_attachment_finished;
+
+ ret = mail_parser_get_attachment(session_ctx->parser, &attachment_name, &attachment_name_len, &attachment, &attachment_len, &attachment_offset, &is_attachment_finished);
+ if (ret == 0) {
+ mail_publish_attachment(mail_env, sess, mail_protocol, mail_seq,
+ attachment_name, attachment_name_len,
+ attachment, attachment_len,
+ attachment_offset, is_attachment_finished);
+ }
+
+ char *eml;
+ size_t eml_len;
+ size_t eml_offset;
+ int is_eml_finished;
+
+ ret = mail_parser_get_eml(session_ctx->parser, &eml, &eml_len, &eml_offset, &is_eml_finished);
+ if (ret == 0) {
+ mail_publish_eml(mail_env, sess, mail_protocol,
+ eml, eml_len,
+ eml_offset, is_eml_finished);
+ }
+
+}
+
+
+
+
+/*-
+ * 64 char lines
+ * pad input with 0
+ * left over chars are set to =
+ * 1 byte => xx==
+ * 2 bytes => xxx=
+ * 3 bytes => xxxx
+ */
+static const char data_bin2ascii[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+#define conv_bin2ascii(a) (data_bin2ascii[(a)&0x3f])
+
+/*-
+ * 0xF0 is a EOLN
+ * 0xF1 is ignore but next needs to be 0xF0 (for \r\n processing).
+ * 0xF2 is EOF
+ * 0xE0 is ignore at start of line.
+ * 0xFF is error
+ */
+#define B64_EOLN 0xF0
+#define B64_CR 0xF1
+#define B64_EOF 0xF2
+#define B64_WS 0xE0
+#define B64_ERROR 0xFF
+#define B64_NOT_BASE64(a) (((a)|0x13) == 0xF3)
+#define B64_BASE64(a) !B64_NOT_BASE64(a)
+
+static const unsigned char data_ascii2bin[128] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xE0, 0xF0, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xF2, 0xFF, 0x3F,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
+ 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
+ 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
+ 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+ 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
+ 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+};
+
+//切记不可以如此调用: conv_ascii2bin(x++); 因为会++两次
+#define conv_ascii2bin(aa) (((aa) & 0x80)?(0xFF):data_ascii2bin[(aa)])
+
+/*static unsigned char conv_ascii2bin(unsigned char a)
+{
+ if (a & 0x80)
+ return B64_ERROR;
+ return data_ascii2bin[a];
+ //return (((a) & 0x80)?B64_ERROR:data_ascii2bin[(a)]);
+}
+*/
+
+/*********************************************************************
+函数名称:Base64_EncodeBlock
+功能简介:对一完整BASE64编码块进行编码
+输入参数:in:待编码的字符;
+ inl:in的长度
+输出参数:out:编码后存储的缓冲区;
+返回值:编码后的长度
+*********************************************************************/
+int Base64_EncodeBlock(const unsigned char *in, int inl, unsigned char *out)
+{
+ int i, ret = 0;
+ unsigned long l;
+
+ for (i = inl; i > 0; i -= 3) {
+ if (i >= 3) {
+ l = (((unsigned long)in[0]) << 16L) |
+ (((unsigned long)in[1]) << 8L) | in[2];
+ *(out++) = conv_bin2ascii(l >> 18L);
+ *(out++) = conv_bin2ascii(l >> 12L);
+ *(out++) = conv_bin2ascii(l >> 6L);
+ *(out++) = conv_bin2ascii(l);
+ } else {
+ l = ((unsigned long)in[0]) << 16L;
+ if (i == 2)
+ l |= ((unsigned long)in[1] << 8L);
+
+ *(out++) = conv_bin2ascii(l >> 18L);
+ *(out++) = conv_bin2ascii(l >> 12L);
+ *(out++) = (i == 1) ? '=' : conv_bin2ascii(l >> 6L);
+ *(out++) = '=';
+ }
+ ret += 4;
+ in += 3;
+ }
+
+ *out = '\0';
+ return (ret);
+}
+
+/*********************************************************************
+函数名称:Base64_DecodeBlock
+功能简介:对一完整BASE64编码块进行解析,自动忽略首尾非BASE64编码字符
+输入参数:in:待解码的字符;
+ inl:in的长度
+输出参数:out:解码后存储的缓冲区;
+ 必须保证有足够的空间,一般达到@inl大小即可;
+返回值:<0:失败;>=0:解码后的长度
+*********************************************************************/
+int Base64_DecodeBlock(const unsigned char *in, int inl, unsigned char *out, int outsize)
+{
+ int i, ret = 0;
+ unsigned char a, b, c, d;
+ unsigned long l;
+
+ /* ignore not-base64-encoded charactor. */
+ while ((conv_ascii2bin(*in) == B64_WS) && (inl > 0))
+ {
+ in++;
+ inl--;
+ }
+ while ((inl > 3) && (B64_NOT_BASE64(conv_ascii2bin(in[inl - 1]))))
+ inl--;
+
+ if (inl % 4 != 0)
+ return -1;
+
+ if(outsize < (inl*3)/4)
+ return -2;
+
+ for (i = 0; i < inl; i += 4)
+ {
+ a = conv_ascii2bin(*(in));
+ b = conv_ascii2bin(*(in+1));
+ c = conv_ascii2bin(*(in+2));
+ d = conv_ascii2bin(*(in+3));
+ if ((a & 0x80) || (b & 0x80) || (c & 0x80) || (d & 0x80))
+ return (-1);
+ l = ((((unsigned long)a) << 18L) | (((unsigned long)b) << 12L) |
+ (((unsigned long)c) << 6L) | (((unsigned long)d)));
+ *(out++) = (unsigned char)(l >> 16L) & 0xff;
+ *(out++) = (unsigned char)(l >> 8L) & 0xff;
+ *(out++) = (unsigned char)(l) & 0xff;
+ ret += 3;
+ in+=4;
+ }
+
+ for(i = inl; i > 0; i -= 4)
+ {
+ if(*(in-3) == '=')
+ {
+ in -= 4;
+ ret -= 3;
+ continue;
+ }
+
+ while(*(--in) == '=')
+ ret -= 1;
+
+ break;
+ }
+
+ return ret;
+}
+
+void Base64_DecodeInit(decode_handle_t *handle)
+{
+ handle->length = 0;
+}
+
+/*********************************************************************
+函数名称:Base64_DecodeFeed
+功能简介:对部分BASE64编码块进行解析,自动忽略首尾非BASE64编码字符
+输入参数:in:待解码的字符;
+ inl:in的长度,可能不是4的倍数,对于小于4的部分,会转存一下,
+ 下次解码时将其拼接到输入数据的头部;转存的最大长度为3,
+ 因为如果达到了4,就可以将该部分解码出来;
+输出参数:out:解码后存储的缓冲区;
+返回值:-1:失败;0:需要更多的数据;>0:解码后的长度
+*********************************************************************/
+int Base64_DecodeFeed(decode_handle_t *handle, const unsigned char *in, int inl, unsigned char *out, int outsize)
+{
+ int i, j=0, dst_len = 0;
+ const unsigned char *pc=in, *pend=in+inl;
+ unsigned char de[4];
+ unsigned long l;
+
+ /* ignore not-base64-encoded charactor. */
+ while(pc<pend && (conv_ascii2bin(*pc) == B64_WS))
+ {
+ pc++;
+ }
+ while(pend>pc && B64_NOT_BASE64(conv_ascii2bin(*(pend-1))))
+ pend--;
+
+ if(handle->length>0)
+ {
+ while(pc<pend && handle->length<4)
+ {
+ handle->enc_data[handle->length++] = *pc;
+ pc++;
+ }
+ if(handle->length < 4)
+ {
+ return 0;
+ }
+ else
+ {
+ for(i=0; i<4; i++)
+ {
+ de[j++] = conv_ascii2bin(handle->enc_data[i]);
+ }
+ }
+ }
+
+ do
+ {
+ while(j < 4 && pc<pend)
+ {
+ de[j++] = conv_ascii2bin(*pc);
+ pc++;
+ }
+ if(j < 4)
+ break;
+ j = 0;
+
+ if(dst_len + 3 > outsize)
+ return -2;
+
+ if ((de[0] & 0x80) || (de[1] & 0x80) || (de[2] & 0x80) || (de[3] & 0x80))
+ return (-1);
+ l = ((((unsigned long)de[0]) << 18L) | (((unsigned long)de[1]) << 12L) |
+ (((unsigned long)de[2]) << 6L) | (((unsigned long)de[3])));
+ *(out++) = (unsigned char)(l >> 16L) & 0xff;
+ *(out++) = (unsigned char)(l >> 8L) & 0xff;
+ *(out++) = (unsigned char)(l) & 0xff;
+
+ dst_len += 3;
+ }while(pc < pend);
+
+ pc--;
+ //有残留,进行缓存,不要存换行符
+ if(j>0)
+ {
+ handle->length = j;
+ while(j>0 && pc>=in)
+ {
+ handle->enc_data[j-1] = *pc;
+ pc--;
+ j--;
+ }
+ return dst_len;
+ }
+ //无解码残留
+ else if(pc>=in && *pc == '=')
+ {
+ dst_len -= 1;
+ pc--;
+ if((pc>=in && *pc == '=') ||(handle->length>0 && handle->enc_data[handle->length-1]=='='))
+ dst_len -= 1;
+ }
+ handle->length = 0;
+
+ return dst_len;
+}
+
+/*********************************************************************
+函数名称:Base64_DecodeFeed_r_n
+功能简介:与Base64_DecodeFeed不同之处在于:
+ 输入数据任何位置有可能出现'\r'或'\n',或一起出现;
+输入参数:同Base64_DecodeFeed
+输出参数:同Base64_DecodeFeed
+返回值:同Base64_DecodeFeed
+*********************************************************************/
+int Base64_DecodeFeed_r_n(decode_handle_t *handle, const unsigned char *in, int inl, unsigned char *out, int outsize)
+{
+ int i, j=0, dst_len = 0;
+ const unsigned char *pc=in, *pend=in+inl;
+ unsigned char de[4];
+ unsigned long l;
+
+ /* ignore not-base64-encoded charactor. */
+ while(pc<pend && (conv_ascii2bin(*pc) == B64_WS))
+ {
+ pc++;
+ }
+ while(pend>pc && B64_NOT_BASE64(conv_ascii2bin(*(pend-1))))
+ pend--;
+
+ //上一次有残留,先补齐4个字符到handle(为了结尾处判断残留是否是换行符)
+ if(handle->length>0)
+ {
+ while(pc<pend && handle->length<4)
+ {
+ if(*pc=='\r' || *pc=='\n' || *pc==' ' || *pc=='\t')
+ {
+ pc++;
+ continue;
+ }
+ handle->enc_data[handle->length++] = *pc;
+ pc++;
+ }
+ if(handle->length < 4)
+ {
+ return 0;
+ }
+ else
+ {
+ for(i=0; i<4; i++)
+ {
+ de[j++] = conv_ascii2bin(handle->enc_data[i]);
+ }
+ }
+ }
+
+ do
+ {
+ while(j < 4)
+ {
+ while(pc<pend && (*pc == '\r' || *pc == '\n' || *pc==' ' || *pc=='\t'))
+ {
+ pc++;
+ continue;
+ }
+ if(pc >= pend)
+ break;
+
+ de[j++] = conv_ascii2bin(*pc);
+ pc++;
+ }
+ if(j < 4)
+ break;
+ j = 0;
+
+ if(dst_len + 3 > outsize)
+ return -2;
+
+ if ((de[0] & 0x80) || (de[1] & 0x80) || (de[2] & 0x80) || (de[3] & 0x80))
+ return (-1);
+ l = ((((unsigned long)de[0]) << 18L) | (((unsigned long)de[1]) << 12L) |
+ (((unsigned long)de[2]) << 6L) | (((unsigned long)de[3])));
+ *(out++) = (unsigned char)(l >> 16L) & 0xff;
+ *(out++) = (unsigned char)(l >> 8L) & 0xff;
+ *(out++) = (unsigned char)(l) & 0xff;
+
+ dst_len += 3;
+ }while(pc < pend);
+
+ pc--;
+ //有残留,进行缓存,不要存换行符
+ if(j>0)
+ {
+ handle->length = j;
+ while(j>0)
+ {
+ while(pc>=in && (*pc == '\r' || *pc == '\n' || *pc==' ' || *pc=='\t'))
+ {
+ pc--;
+ continue;
+ }
+ handle->enc_data[j-1] = *pc;
+ pc--;
+ j--;
+ }
+ return dst_len;
+ }
+ //无解码残留,如果尾部是=,修正实际的解码后长度
+ else if(pc>=in && *pc == '=')
+ {
+ dst_len -= 1;
+ pc--;
+ if((pc>=in && *pc == '=') ||(handle->length>0 && handle->enc_data[handle->length-1]=='='))
+ dst_len -= 1;
+ }
+ handle->length = 0;
+
+ return dst_len;
+}
+
+static unsigned char decode_hex( char *streamptr )
+{
+ unsigned char result = 0;
+ char blivit;
+
+ blivit = *streamptr++;
+ if ( blivit >= 'a' )
+ blivit -= ' ';
+ if ( blivit > '9' )
+ blivit -= 0x07;
+
+ result = blivit & 0x0F;
+ result <<= 4;
+
+ blivit = *streamptr++;
+ if ( blivit >= 'a' )
+ blivit -= ' ';
+ if ( blivit > '9' )
+ blivit -= 0x07;
+
+ result |= blivit & 0x0F;
+
+ return result;
+}
+
+/*********************************************************************
+函数名称:QP_DecodeBlock
+功能简介:对一完整QP编码块进行解析,会忽略'\r''\n'字符
+输入参数:in:待解码的字符;
+ inl:in的长度
+输出参数:out:解码后存储的缓冲区,
+ 必须保证有足够的空间,一般达到@inl大小即可;
+返回值:解码后的长度
+*********************************************************************/
+//"PPPPPP=X",如果X是一16进制数,是否保留"=X"?目前是保留。
+int QP_DecodeBlock(const unsigned char *in, int inl, unsigned char *out)
+{
+ int index=0, index2=0; //分别是buf、enc_data里内容长度
+ const unsigned char *temp=in, *inputend=in+inl;
+ unsigned char value;
+ int state=0;
+ char buf[2];
+ int dst_len=0;
+
+ if(inl == 0)
+ return 0;
+
+ while(temp<inputend)
+ {
+ switch(state)
+ {
+ case 0:
+ if(*temp == '=')
+ {
+ index2++;
+ state=1;
+ }
+ else
+ {
+ out[dst_len++]=(unsigned char)(*temp);
+ out[dst_len]='\0';
+ }
+ temp=temp+1;
+ break;
+
+ case 1:
+ if(*temp=='\n' || *temp=='\r')
+ {
+ index2++;
+ state = 2;
+ }
+ //不是可解码的字符
+ else if (((*temp < '0') || (*temp > '9')) && ((*temp < 'A') || (*temp > 'F')) && ((*temp < 'a') || (*temp > 'f')))
+ {
+ out[dst_len++] = '=';
+ out[dst_len] = '\0';
+
+ if(index!=0) //遇到了=XY串,其中X是16进制数,Y不是
+ {
+ out[dst_len++] = buf[0];
+ out[dst_len] = '\0';
+ }
+ if(*temp== '=')
+ {
+ state = 1;
+ }
+ else
+ {
+ out[dst_len++] = *temp;
+ out[dst_len] = '\0';
+ state=0;
+ index2=0;
+ }
+ index=0;
+ }
+ //是可解码的字符,但是不够
+ else if(index<1)
+ {
+ buf[index++]=*temp;
+ }
+ //进行解码
+ else
+ {
+ buf[index++]=*temp;
+ value=decode_hex(buf);
+ out[dst_len++] = value;
+ out[dst_len]='\0';
+ index=0;
+ state=0;
+ index2=0;
+ }
+ temp=temp+1;
+ break;
+
+ case 2:
+ state = 0;
+ index = 0;
+ index2 = 0;
+
+ if(*temp == '=')
+ {
+ index2++;
+ state=1;
+ }
+ else if(*temp!='\n' && *temp!='\r')
+ {
+ out[dst_len++] = *temp;
+ out[dst_len]='\0';
+ }
+ temp++;
+ break;
+
+ default: break;
+ }
+ }
+
+ //保留最后不足以进行解码的数据
+ if(index2!=0)
+ {
+ out[dst_len++] = '=';
+ out[dst_len]='\0';
+
+ if(index!=0)
+ {
+ out[dst_len++] = buf[0];
+ out[dst_len]='\0';
+ }
+ }
+
+ return dst_len;
+}
+
+void QP_DecodeInit(decode_handle_t *handle)
+{
+ handle->length = 0;
+}
+
+/*********************************************************************
+函数名称:QP_DecodeFeed
+功能简介:对部分QP编码块进行解析
+输入参数:in:待解码的字符;
+ inl:in的长度,可能不足以解码出来,对于不足以解码的部分,
+ 会转存一下,下次解码时优先解决该部分,转存的最大长度为2;
+ 如果为1,必然是'=';如果为2,必然是"=X";X是一个16进制数;
+输出参数:out:解码后存储的缓冲区;
+返回值:-1:失败;0:需要更多的数据;>0:解码后的长度
+*********************************************************************/
+int QP_DecodeFeed(decode_handle_t *handle,const unsigned char *in, int inl, unsigned char *out)
+{
+ int index=0, index2=0; //分别是buf、enc_data里内容长度
+ const unsigned char *temp=in, *inputend=in+inl;
+ unsigned char value;
+ int state=0;
+ char buf[2];
+ int dst_len=0;
+
+ if(inl == 0)
+ return 0;
+
+ if(handle->length > 0)
+ {
+ if(handle->length == 1)
+ {
+ state = 1;
+ index2 = 1;
+ }
+ else if(handle->length == 2)
+ {
+ if(handle->enc_data[1] == '\n')
+ {
+ state = 2;
+ index2 = 2;
+ }
+ else
+ {
+ state = 1;
+ index2 = 1;
+ index = 1;
+ buf[0] = handle->enc_data[1];
+ }
+ }
+
+ handle->length = 0;
+ }
+
+ while(temp<inputend)
+ {
+ switch(state)
+ {
+ case 0:
+ if(*temp == '=')
+ {
+ index2++;
+ state=1;
+ }
+ else
+ {
+ out[dst_len++]=(unsigned char)(*temp);
+ out[dst_len]='\0';
+ }
+ temp=temp+1;
+ break;
+
+ case 1:
+ if(*temp=='\n' || *temp=='\r')
+ {
+ index2++;
+ state = 2;
+ }
+ //不是可解码的字符
+ else if (((*temp < '0') || (*temp > '9')) && ((*temp < 'A') || (*temp > 'F')) && ((*temp < 'a') || (*temp > 'f')))
+ {
+ out[dst_len++] = '=';
+ out[dst_len] = '\0';
+
+ if(index!=0) //遇到了=XY串,其中X是16进制数,Y不是
+ {
+ out[dst_len++] = buf[0];
+ out[dst_len] = '\0';
+ }
+ if(*temp== '=')
+ {
+ state = 1;
+ }
+ else
+ {
+ out[dst_len++] = *temp;
+ out[dst_len] = '\0';
+ state=0;
+ index2=0;
+ }
+ index=0;
+ }
+ //是可解码的字符,但是不够
+ else if(index<1)
+ {
+ buf[index++]=*temp;
+ }
+ //进行解码
+ else
+ {
+ buf[index++]=*temp;
+ value=decode_hex(buf);
+ out[dst_len++] = value;
+ out[dst_len]='\0';
+ index=0;
+ state=0;
+ index2=0;
+ }
+ temp=temp+1;
+ break;
+
+ case 2:
+ state = 0;
+ index = 0;
+ index2 = 0;
+
+ if(*temp == '=')
+ {
+ index2++;
+ state=1;
+ }
+ else if(*temp!='\n' && *temp!='\r')
+ {
+ out[dst_len++] = *temp;
+ out[dst_len]='\0';
+ }
+ temp++;
+ break;
+
+ default: break;
+ }
+ }
+
+ if(index2!=0)
+ {
+ handle->enc_data[0] = '=';
+ handle->length = 1;
+
+ if(index2 == 2)
+ handle->enc_data[handle->length++] = '\n';
+ else if(index!=0)
+ {
+ handle->enc_data[1] = buf[0];
+ handle->length = 2;
+ }
+ }
+
+ return dst_len;
+}
+
+
+int strncasecmp_one_word_mesa(const char *str1, size_t len1, const char *str2, size_t len2)
+{
+ if (len2 != len1 || len1==0)
+ return 0;
+
+ do {
+ if(*str1 - 'a' > 0) //str1小写
+ {
+ if (*str1 == *str2 || toupper(*str1) == *str2)
+ {
+ ++str1;
+ ++str2;
+ continue;
+ }
+ }
+ else
+ {
+ if (*str1 == *str2 || tolower(*str1) == *str2)
+ {
+ ++str1;
+ ++str2;
+ continue;
+ }
+ }
+ return 0;
+ } while (--len1);
+
+ return 1;
+}
+
+
+int strncmp_one_word_mesa(const char *s1_lowercase, const char *s1_uppercase, size_t len1, const char *s2, size_t len2)
+{
+ if (len1 > len2)
+ return 0;
+
+ const unsigned char *s1, *s12;
+
+ if (islower(s2[len1-1]))
+ {
+ s1 = (const unsigned char *)s1_lowercase;
+ s12= (const unsigned char *)s1_uppercase;
+ }
+ else
+ {
+ s1 = (const unsigned char *)s1_uppercase;
+ s12= (const unsigned char *)s1_lowercase;
+ }
+
+ while(len1--) {
+ if (*s1 == *s2 || *s12 == *s2)
+ {
+ ++s1;
+ ++s12;
+ ++s2;
+ continue;
+ }
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/*
+* mesa_memicmp2
+* FUNCTION
+* compare s2 with s1, ignorance of case
+* INPUT
+* @s1_lowercase MUST be lowercase
+* @s1_uppercase MUST be uppercase
+* @len1 is the length of s1
+* @s2 is the string you want to be compared
+* @len2 is the length of s2
+* OUTPUT:
+* 0:s1==s2
+* -1:s1!=s2
+*/
+int strcmp_one_word_mesa(const char *s1_lowercase, const char *s1_uppercase, size_t len1, const char *s2, size_t len2)
+{
+ unsigned char *s1,*s12;
+
+ if (len1 != len2)
+ return 0;
+
+ if (s2[len2-1]-'a'>=0)
+ {
+ s1 = (unsigned char *)s1_lowercase;
+ s12= (unsigned char *)s1_uppercase;
+ }
+ else
+ {
+ s1 = (unsigned char *)s1_uppercase;
+ s12= (unsigned char *)s1_lowercase;
+ }
+
+ do {
+ if (*s1 == *s2 || *s12 == *s2)
+ {
+ ++s1;
+ ++s12;
+ ++s2;
+ continue;
+ }
+ return 0;
+ } while (--len1);
+
+ return 1;
+}
+
+//相对于strcmp_one_word_mesa仅仅去掉了长度相等的比较
+int strcmp_one_word_mesa_equal_len(const char *s1_lowercase, const char *s1_uppercase, const char *s2, size_t len)
+{
+ unsigned char *s1,*s12;
+
+ if (s2[len-1]-'a'>=0)
+ {
+ s1 = (unsigned char *)s1_lowercase;
+ s12= (unsigned char *)s1_uppercase;
+ }
+ else
+ {
+ s1 = (unsigned char *)s1_uppercase;
+ s12= (unsigned char *)s1_lowercase;
+ }
+
+ do {
+ if (*s1 == *s2 || *s12 == *s2)
+ {
+ ++s1;
+ ++s12;
+ ++s2;
+ continue;
+ }
+ return 0;
+ } while (--len);
+
+ return 1;
+}
+
+int strncmp_two_word_mesa(const char *s1_lower, const char *s1_upper, size_t len1,
+ const char *s2_lower, const char *s2_upper, size_t len2, const char *data, int dlen)
+{
+ int matchlen=0;
+
+ if(!strncmp_one_word_mesa(s1_lower, s1_upper, len1, data, dlen))
+ {
+ return 0;
+ }
+ data += len1; dlen-=len1; matchlen+=len1;
+ while(dlen>0 && *data==' ')
+ {
+ data++;dlen--;matchlen++;
+ }
+ if(dlen == 0) return 0;
+
+ if(!strncmp_one_word_mesa(s2_lower, s2_upper, len2, data, dlen))
+ {
+ return 0;
+ }
+ data += len2; dlen-=len2; matchlen+=len2;
+ while(dlen>0 && *data==' ')
+ {
+ data++;dlen--;matchlen++;
+ }
+ return matchlen;
+}
+
+/*********************************************************************
+函数名称:mail_strcmp_two_word
+功能简介:判断一个由2个单词组成的字符串是不是目标SMTP命令字符串,含':',
+ 忽略目标字符串2个单词及':'之间的空格,如"mail from :",忽略大小写
+输入参数:srcdata:
+输出参数:无
+返回值: 1:是
+ 0:不是
+*********************************************************************/
+int strcmp_two_word(char *srcdata,int datalen, const char *first, int flen, const char *second, int slen)
+{
+ char * tok;
+
+ if(datalen < flen+slen+1)
+ return 0;
+
+ if(strncasecmp(srcdata, first, flen) != 0)
+ {
+ return 0;
+ }
+
+ tok = srcdata + flen;
+ while(*tok==' ')
+ tok++;
+
+ if(strncasecmp(tok, second, slen) != 0)
+ return 0;
+
+ tok += slen;
+ while(*tok==' ')
+ tok++;
+ if( *tok != ':' )
+ return 0;
+
+ return 1;
+}
+
+
+//查找开始位置
+const void *mail_memmem(const void *start, unsigned int s_len, const void *find, unsigned int f_len)
+{
+ const char *p, *q;
+ unsigned int len;
+
+ p = (const char *)start, q = (const char *)find;
+ len = 0;
+ while((p - (const char *)start + f_len) <= s_len)
+ {
+ while(*p++ == *q++)
+ {
+ len++;
+ if(len == f_len)
+ return(p - f_len);
+ };
+ q = (const char *)find;
+ len = 0;
+ };
+
+ return NULL;
+}
+
+/*
+* mesa_memncasemem3
+* FUNCTION
+* find needle in haystack, ignorance of case
+* INPUT
+* @needle MUST be lowercase
+* @needlelen is the length of needle
+* OUTPUT
+* NULL if not found
+*/
+char *mesa_memncasemem(const char *haystack, size_t haystacklen,const char *needle, size_t needlelen)
+{
+ unsigned char *psub,*psrc,*p,*pendsrc,*pendsubstr;
+ int diff=-32; //A=a-32;
+
+ if ((haystack==NULL) || needle==NULL)
+ return NULL;
+ if (haystacklen<needlelen)
+ return NULL;
+
+ pendsrc = (unsigned char *)haystack + haystacklen - needlelen + 1;
+ pendsubstr = (unsigned char *)needle + needlelen;
+ for (psrc =(unsigned char *)haystack; psrc != pendsrc; psrc++)
+ {
+ for (p = psrc,psub = (unsigned char *)needle; psub != pendsubstr; psub++,p++)
+ {
+ if (*p!=*psub && *p!=*psub + diff)
+ break;
+ }
+ if (psub == pendsubstr)
+ {
+ return (char *)psrc;
+ }
+ }
+ return NULL;
+}
+
+
+/*
+* FUNCTION
+* find last needle in haystack, ignorance of case
+* INPUT
+* @needle MUST be lowercase
+* @needlelen is the length of needle
+* OUTPUT
+* NULL if not found
+*/
+char *mesa_memncasemem_reverse(const char *haystack, size_t haystacklen,const char *needle, size_t needlelen)
+{
+ unsigned char *p,*psrc,*psub,*pendsubstr;
+ int diff=-32; //A=a-32;
+
+ if ((haystack==NULL) || needle==NULL)
+ return NULL;
+ if (haystacklen<needlelen)
+ return NULL;
+
+ pendsubstr = (unsigned char *)needle + needlelen;
+ for (psrc = (unsigned char *)haystack + haystacklen - needlelen; psrc != (unsigned char *)haystack-1; psrc--)
+ {
+ for (p = psrc,psub = (unsigned char *)needle; psub != pendsubstr; p++,psub++)
+ {
+ if (*p!=*psub && *p!=*psub + diff)
+ break;
+ }
+ if (psub == pendsubstr)
+ {
+ return (char *)psrc;
+ }
+ }
+ return NULL;
+}