diff options
Diffstat (limited to 'decoders/mail/mail_util.c')
| -rw-r--r-- | decoders/mail/mail_util.c | 1453 |
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; +} |
