diff options
| author | zhuzhenjun <[email protected]> | 2024-11-27 08:26:41 +0000 |
|---|---|---|
| committer | zhuzhenjun <[email protected]> | 2024-11-27 08:26:41 +0000 |
| commit | 3694c142d974ab35f55bde4a8519525b9afcbc84 (patch) | |
| tree | ce92ad91f08e6ec8c81e2899d6ff93327ef7bff1 /decoders/mail | |
| parent | d0a868591470a4a9d71a65a5d540058e72c8d92c (diff) | |
tmp
Diffstat (limited to 'decoders/mail')
| -rw-r--r-- | decoders/mail/CMakeLists.txt | 13 | ||||
| -rw-r--r-- | decoders/mail/mail_decoder_codec.c | 695 | ||||
| -rw-r--r-- | decoders/mail/mail_decoder_codec.h | 18 | ||||
| -rw-r--r-- | decoders/mail/mail_decoder_email.c | 1487 | ||||
| -rw-r--r-- | decoders/mail/mail_decoder_email.h | 275 | ||||
| -rw-r--r-- | decoders/mail/mail_decoder_imap.h | 92 | ||||
| -rw-r--r-- | decoders/mail/mail_decoder_mime.c | 663 | ||||
| -rw-r--r-- | decoders/mail/mail_decoder_mime.h | 122 | ||||
| -rw-r--r-- | decoders/mail/mail_decoder_module.c | 498 | ||||
| -rw-r--r-- | decoders/mail/mail_decoder_module.h | 96 | ||||
| -rw-r--r-- | decoders/mail/mail_decoder_pop3.h | 35 | ||||
| -rw-r--r-- | decoders/mail/mail_decoder_smtp.c | 573 | ||||
| -rw-r--r-- | decoders/mail/mail_decoder_smtp.h | 67 | ||||
| -rw-r--r-- | decoders/mail/mail_decoder_util.c | 568 | ||||
| -rw-r--r-- | decoders/mail/mail_decoder_util.h | 61 | ||||
| -rw-r--r-- | decoders/mail/mail_imap.c | 1440 | ||||
| -rw-r--r-- | decoders/mail/mail_pop3.c | 489 | ||||
| -rw-r--r-- | decoders/mail/version.map | 10 |
18 files changed, 7202 insertions, 0 deletions
diff --git a/decoders/mail/CMakeLists.txt b/decoders/mail/CMakeLists.txt new file mode 100644 index 0000000..807849b --- /dev/null +++ b/decoders/mail/CMakeLists.txt @@ -0,0 +1,13 @@ +set(DECODER_NAME mail) + +file(GLOB DECODER_SRC "${CMAKE_CURRENT_SOURCE_DIR}/${DECODER_NAME}_decoder_*.c") + +add_library( + ${DECODER_NAME} + ${DECODER_SRC} +) + +set_target_properties( + ${DECODER_NAME} PROPERTIES + LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/version.map" +) diff --git a/decoders/mail/mail_decoder_codec.c b/decoders/mail/mail_decoder_codec.c new file mode 100644 index 0000000..c79b37c --- /dev/null +++ b/decoders/mail/mail_decoder_codec.c @@ -0,0 +1,695 @@ +#include <stdio.h> +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include "mail_decoder_codec.h" + +/*- + * 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, +}; + +//�мDz�������˵���: 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�ij��� +���������out�������洢�Ļ������� +����ֵ�������ij��� +*********************************************************************/ +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�ij��� +���������out�������洢�Ļ������� + ���뱣֤���㹻�Ŀռ䣬һ��ﵽ@inl��С���ɣ� +����ֵ��<0��ʧ�ܣ�>=0�������ij��� +*********************************************************************/ +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�ij��ȣ����ܲ���4�ı���������С��4�IJ��֣���ת��һ�£� + �´ν���ʱ����ƴ�ӵ��������ݵ�ͷ����ת������Ϊ3�� + ��Ϊ����ﵽ��4���Ϳ��Խ��ò��ֽ�������� +���������out�������洢�Ļ������� +����ֵ��-1��ʧ�ܣ�0����Ҫ��������ݣ�>0�������ij��� +*********************************************************************/ +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�ij��� +���������out�������洢�Ļ������� + ���뱣֤���㹻�Ŀռ䣬һ��ﵽ@inl��С���ɣ� +����ֵ�������ij��� +*********************************************************************/ +//"PPPPPP=X"�����X��һ16���������Ƿ���"=X"��Ŀǰ�DZ����� +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; + } + //�ǿɽ�����ַ������Dz��� + 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�ij��ȣ����ܲ����Խ�����������ڲ����Խ���IJ��֣� + ��ת��һ�£��´ν���ʱ���Ƚ���ò��֣�ת������Ϊ2�� + ���Ϊ1����Ȼ��'='�����Ϊ2����Ȼ��"=X"��X��һ��16�������� +���������out�������洢�Ļ������� +����ֵ��-1��ʧ�ܣ�0����Ҫ��������ݣ�>0�������ij��� +*********************************************************************/ +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; + } + //�ǿɽ�����ַ������Dz��� + 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; +} + diff --git a/decoders/mail/mail_decoder_codec.h b/decoders/mail/mail_decoder_codec.h new file mode 100644 index 0000000..b9ff716 --- /dev/null +++ b/decoders/mail/mail_decoder_codec.h @@ -0,0 +1,18 @@ +#ifndef __MAIL_DECODER_CODEC_H__ +#define __MAIL_DECODER_CODEC_H__ + +typedef struct __decode_handle { + int length; + unsigned char enc_data[4]; +} decode_handle_t; + +int Base64_EncodeBlock(const unsigned char *in, int inl, unsigned char *out); +void Base64_DecodeInit(decode_handle_t *handle); +int Base64_DecodeFeed(decode_handle_t *handle, const unsigned char *in, int inl, unsigned char *out, int outsize); +int Base64_DecodeFeed_r_n(decode_handle_t *handle, const unsigned char *in, int inl, unsigned char *out, int outsize); +int Base64_DecodeBlock(const unsigned char *in, int inl, unsigned char *out, int outsize); +void QP_DecodeInit(decode_handle_t *handle); +int QP_DecodeFeed(decode_handle_t *handle,const unsigned char *in, int inl, unsigned char *out); +int QP_DecodeBlock(const unsigned char *in, int inl, unsigned char *out); + +#endif diff --git a/decoders/mail/mail_decoder_email.c b/decoders/mail/mail_decoder_email.c new file mode 100644 index 0000000..d6963a4 --- /dev/null +++ b/decoders/mail/mail_decoder_email.c @@ -0,0 +1,1487 @@ +#include "mail_decoder_util.h" +#include "mail_decoder_module.h" +#include "mail_decoder_email.h" + +#include "stellar/mq.h" +#include "stellar/module.h" + +int is_eml_header_field(enum EML_LINE_TYPE field) +{ + switch (field) { + case EML_DATA_HEAD_IN: + case EML_DATA_FROM: + case EML_DATA_TO: + case EML_DATA_CC: + case EML_DATA_BCC: + case EML_DATA_SUBJECT: + case EML_DATA_RETURN_PATH: + case EML_DATA_DELIVERED_TO: + case EML_DATA_RECEIVED: + case EML_DATA_DATE: + case EML_DATA_REPLY_TO: + return 1; + default: + break; + } + return 0; +} + +static int process_srcdata_r(char **p_srcdata,int *p_srclen,char **output_line,int *plinelen,struct email_parser * eml_parser) +{ + int len; + char *poss_n = NULL; + char *srcdata = *p_srcdata; + int srclen = *p_srclen; + + poss_n = (char *)memchr(srcdata, '\n', srclen); + if(poss_n != NULL && poss_n >= srcdata + srclen) + { + poss_n = NULL; + } + + if(poss_n == NULL || poss_n + 1 >= srcdata + srclen) //�����Զ϶����۵��У��������� + { + while(eml_parser->pDataLineBuf.len >0 && (*((char *)eml_parser->pDataLineBuf.buf + eml_parser->pDataLineBuf.len-1)=='\r' || *((char *)eml_parser->pDataLineBuf.buf + eml_parser->pDataLineBuf.len-1)=='\n')) + eml_parser->pDataLineBuf.len--; + + if(buf_cache_check_size(&eml_parser->pDataLineBuf, srclen)<0) + { + return MAIL_GETLINE_ERR; + } + memcpy((char *)eml_parser->pDataLineBuf.buf + eml_parser->pDataLineBuf.len, srcdata, srclen); + eml_parser->pDataLineBuf.len += srclen; + return MAIL_INPUT_END; + } + else if(*(poss_n+1) != '\t' && *(poss_n+1) != ' ') //a fold line + { + len = poss_n - srcdata + 1; //�������з����� + eml_parser->iDataPointer += len; + + if(eml_parser->pDataLineBuf.len > 0) + { + while(eml_parser->pDataLineBuf.len >0 && (*((char *)eml_parser->pDataLineBuf.buf + eml_parser->pDataLineBuf.len-1)=='\r' || *((char *)eml_parser->pDataLineBuf.buf + eml_parser->pDataLineBuf.len-1)=='\n')) + eml_parser->pDataLineBuf.len--; + + if(buf_cache_check_size(&eml_parser->pDataLineBuf, len)<0) + { + return MAIL_GETLINE_ERR; + } + + memcpy((char *)eml_parser->pDataLineBuf.buf + eml_parser->pDataLineBuf.len, srcdata, len); + eml_parser->pDataLineBuf.len += len; + + *output_line = (char *)eml_parser->pDataLineBuf.buf; + *plinelen = eml_parser->pDataLineBuf.len; + } + else + { + *output_line = srcdata; + *plinelen = len; + } + return MAIL_FOLD_LINE_END; + } + else //δ�ҵ����з������۵��У�����֮ + { + len = poss_n - srcdata + 1; + + while(eml_parser->pDataLineBuf.len>0 && (*((char *)eml_parser->pDataLineBuf.buf + eml_parser->pDataLineBuf.len-1)=='\r' || *((char *)eml_parser->pDataLineBuf.buf + eml_parser->pDataLineBuf.len-1)=='\n')) + eml_parser->pDataLineBuf.len--; + + if(buf_cache_check_size(&eml_parser->pDataLineBuf, len)<0) + { + return MAIL_GETLINE_ERR; + } + + memcpy((char *)eml_parser->pDataLineBuf.buf + eml_parser->pDataLineBuf.len, srcdata, len); + eml_parser->pDataLineBuf.len += len; + srcdata += len; + srclen -= len; + eml_parser->iDataPointer += len; + + *p_srcdata = srcdata; + *p_srclen = srclen; + return MAIL_FOLD_LINE_START; + } +} + +int get_one_tcpline(struct email_parser * eml_parser, char *srcdata,int srclen,char **output_line,int *plinelen, int rn) +{ + char *pos_n = NULL; + int datalen; + + pos_n = (char *)memchr(srcdata, '\n', srclen); + if(pos_n == NULL) //ֱ�ӻ��棬���ܴ�С����һ�л�û�����ꣻ + { + if(buf_cache_check_size(&eml_parser->pDataLineBuf, srclen)<0) + { + *output_line = (char *)eml_parser->pDataLineBuf.buf; + *plinelen = eml_parser->pDataLineBuf.len; + return MAIL_LINE_END; + } + + memcpy((char *)eml_parser->pDataLineBuf.buf + eml_parser->pDataLineBuf.len, srcdata, srclen); + eml_parser->pDataLineBuf.len += srclen; + eml_parser->iDataPointer += srclen; + return MAIL_INPUT_END; + } + else //�ҵ���һ�������� + { + if(rn) + { + datalen = pos_n - srcdata + 1; + eml_parser->iDataPointer += datalen; + } + else + { + datalen = pos_n - srcdata; + eml_parser->iDataPointer += datalen + 1; //include \n + } + + //��һ���������˲������ݣ������Ƚ���ƴ�� + if(eml_parser->pDataLineBuf.len > 0) + { + if(buf_cache_check_size(&eml_parser->pDataLineBuf, datalen)<0) + { + *output_line = (char *)eml_parser->pDataLineBuf.buf; + *plinelen = eml_parser->pDataLineBuf.len; + eml_parser->iDataPointer -= rn?datalen:(datalen+1); + return MAIL_LINE_END; + } + memcpy((char *)eml_parser->pDataLineBuf.buf + eml_parser->pDataLineBuf.len, srcdata, datalen); + eml_parser->pDataLineBuf.len += datalen; + + if(rn==0) + { + pos_n = (char *)eml_parser->pDataLineBuf.buf + eml_parser->pDataLineBuf.len - 1; + if(*pos_n == '\r') //100% properly + eml_parser->pDataLineBuf.len -= 1; + } + + *output_line = (char *)eml_parser->pDataLineBuf.buf; + *plinelen = eml_parser->pDataLineBuf.len; + return MAIL_LINE_END; + } + + if(rn==0 && datalen > 0) + { + if(*(srcdata+datalen-1) == '\r') + datalen = datalen - 1; + } + *output_line = srcdata; + *plinelen = datalen; + return MAIL_LINE_END; + } +} + +static int get_complete_region(struct email_parser * eml_parser, char *srcdata,int srclen,char **output_line,int *plinelen) +{ + char *pos_n = NULL; + char *srcend = srcdata + srclen, *pc=srcdata; + int datalen; + + //�ҽ�ֹ��: \r\n#, where # is '\r' or '-' + while(pc < srcend && (pos_n = (char *)memchr(pc, '\n', srcend-pc)) != NULL) + { + eml_parser->iDataPointer += pos_n - pc + 1; + pc = pos_n + 1; + datalen = pc-srcdata; + + if(eml_parser->pDataLineBuf.len>0)//��ͷ�������ַ���������һ�β����������� + { + if(buf_cache_check_size(&eml_parser->pDataLineBuf, datalen)<0) + { + *output_line = (char *)eml_parser->pDataLineBuf.buf; + *plinelen = eml_parser->pDataLineBuf.len; + eml_parser->iDataPointer -= datalen; + return MAIL_LINE_END; + } + memcpy((char *)eml_parser->pDataLineBuf.buf + eml_parser->pDataLineBuf.len, srcdata, datalen); + eml_parser->pDataLineBuf.len += datalen; + + *output_line = (char *)eml_parser->pDataLineBuf.buf; + *plinelen = eml_parser->pDataLineBuf.len; + return MAIL_LINE_END; + } + //����BODY���¸�BOUNDARY֮�����û�п��У�����Ҫ�Ƚ�'-'�� + //������"."��ǰ������������һ�������Ҫ��BODY�з������POP3������ + //����')'��IMAP����Ϊ������ + else if(pc < srcend && (*pc=='-' || (*pc=='.' && eml_parser->protocol!=MAIL_PROTOCOL_IMAP) || (*pc==')' && eml_parser->protocol==MAIL_PROTOCOL_IMAP))) //--BB\r\n)\r\n + { + *output_line = srcdata; + *plinelen = datalen; + return MAIL_LINE_END; + } + else if((srclen>=2 && *srcdata=='-' && *(srcdata+1)=='-') || ((pc-srcdata<=3) && (*srcdata=='.' || *srcdata==')'))) + { + *output_line = srcdata; + *plinelen = datalen; + return MAIL_LINE_END; + } + else if(pc-srcdata>=3 && *(pc-3)==')' && eml_parser->protocol==MAIL_PROTOCOL_IMAP) //')'֮ǰû�л��У�����һ��if���˳���ܱ䣬��Ϊ')'֮ǰ�����л��� + { + eml_parser->iDataPointer -= 3; //��')'���ڻ������ȴ��´δ��� + pc = pc-3; //����')'������ᵱ��'\n'�����������;����POPͷ��Ҳ�� + *output_line = srcdata; + *plinelen = pc-srcdata; + return MAIL_LINE_END; + } + } + + datalen = pc - srcdata; + if(datalen > 0) //�ҵ���\n + { + eml_parser->iDataPointer += srcend - pc; + *output_line = srcdata; + *plinelen = srclen; + return MAIL_PACKET_END; + } + else + { + //�ܳ���һ��ֱ�ӷ��أ��е�����û���� + //�洢��ԭ���ǣ���ʱ�������β����ʣ��Ƚ�С��Э��ȽϹؼ���ʱ���ܻ������� + if(buf_cache_check_size(&eml_parser->pDataLineBuf, srclen)<0) + { + *output_line = (char *)eml_parser->pDataLineBuf.buf; + *plinelen = eml_parser->pDataLineBuf.len; + return MAIL_LINE_END; + } + memcpy((char *)eml_parser->pDataLineBuf.buf + eml_parser->pDataLineBuf.len, srcdata, srclen); + eml_parser->pDataLineBuf.len += srclen; + eml_parser->iDataPointer += srclen; + + *output_line = NULL; + *plinelen = 0; + return MAIL_INPUT_END; + } + + return MAIL_INPUT_END; +} + +static int get_fold_line(struct email_parser *eml_parser, char *srcdata,int srclen,char **output_line,int *plinelen) +{ + char *posd_n = NULL; + int ret, flag=0; + + if(srclen == 0) + return MAIL_INPUT_END; + + while(srclen > 0) + { + if(eml_parser->pDataLineBuf.len > 0) + { + posd_n = (char *)memrchr(eml_parser->pDataLineBuf.buf, '\n', eml_parser->pDataLineBuf.len); + if(posd_n != NULL && posd_n >= (char *)eml_parser->pDataLineBuf.buf + eml_parser->pDataLineBuf.len) + { + posd_n = NULL; + } + } + else + posd_n = NULL; + + if(posd_n != NULL) + { + if(posd_n+1 < (char *)eml_parser->pDataLineBuf.buf + eml_parser->pDataLineBuf.len && *(posd_n+1)=='\t') + { + eml_parser->pDataLineBuf.len -= 1;//\t + ret = process_srcdata_r(&srcdata, &srclen, output_line, plinelen, eml_parser); + if(ret == MAIL_FOLD_LINE_START) + continue; + else + return ret; + } + else if(*srcdata != '\t' && *srcdata != ' ') + { + *output_line = (char *)eml_parser->pDataLineBuf.buf; + *plinelen = eml_parser->pDataLineBuf.len; + return MAIL_FOLD_LINE_END; + } + else + { + while(srclen>0 && (*srcdata == '\t' || *srcdata == ' ')) + { + srcdata++; + srclen--; + eml_parser->iDataPointer++; + flag = 1; + } + if(srclen == 0) + { + if(flag) + { + if(buf_cache_check_size(&eml_parser->pDataLineBuf, 1)<0) + return MAIL_GETLINE_ERR; + *((char*)eml_parser->pDataLineBuf.buf + eml_parser->pDataLineBuf.len) = '\t'; + eml_parser->pDataLineBuf.len += 1; + } + return MAIL_INPUT_END; + } + flag = 0; + + ret = process_srcdata_r(&srcdata, &srclen, output_line, plinelen, eml_parser); + if(ret == MAIL_FOLD_LINE_START) + continue; + else + return ret; + } + } + else + { + if(eml_parser->pDataLineBuf.len == 0) + { + if(*srcdata=='\n') //һ��\n���� + { + eml_parser->iDataPointer += 1; + *output_line = srcdata; + *plinelen = 1; + return MAIL_FOLD_LINE_END; + } + else if(srclen>=2 && *srcdata=='\r' && *(srcdata+1) == '\n') //һ��\r\n���� + { + eml_parser->iDataPointer += 2; + *output_line = srcdata; + *plinelen = 2; + return MAIL_FOLD_LINE_END; + } + } + + ret = process_srcdata_r(&srcdata, &srclen, output_line, plinelen, eml_parser); + if(ret == MAIL_FOLD_LINE_START) + continue; + else + return ret; + } + } + + return MAIL_INPUT_END; +} + +char *mail_message_to_json(struct mail_message *msg) +{ + cJSON *json_msg = cJSON_CreateObject(); + if (!json_msg) return NULL; + + cJSON_AddNumberToObject(json_msg, "type", msg ? msg->type : 0); + cJSON_AddNumberToObject(json_msg, "mail_protocol", msg ? msg->mail_protocol : 0); + cJSON_AddNumberToObject(json_msg, "mail_seq", msg ? msg->mail_seq : 0); + + if (msg->command) { + cJSON *json_command = cJSON_CreateObject(); + if (json_command) { + cJSON_AddNumberToObject(json_command, "cmd", msg->command->cmd); + cJSON_AddStringToObject(json_command, "arg", msg->command->arg && msg->command->arg_len ? msg->command->arg : ""); + cJSON_AddNumberToObject(json_command, "arg_len", msg->command->arg_len); + cJSON_AddStringToObject(json_command, "cmd_line", msg->command->cmd_line && msg->command->cmd_line_len ? msg->command->cmd_line : ""); + cJSON_AddNumberToObject(json_command, "cmd_line_len", msg->command->cmd_line_len); + } + cJSON_AddItemToObject(json_msg, "command", json_command); + } + + if (msg->header) { + cJSON *json_header = cJSON_CreateObject(); + if (json_header) { + cJSON_AddStringToObject(json_header, "from", + msg->header->from && msg->header->from->field_value ? msg->header->from->field_value : ""); + cJSON_AddStringToObject(json_header, "to", + msg->header->to && msg->header->to->field_value ? msg->header->to->field_value : ""); + cJSON_AddStringToObject(json_header, "cc", + msg->header->cc && msg->header->cc->field_value ? msg->header->cc->field_value : ""); + cJSON_AddStringToObject(json_header, "bcc", + msg->header->bcc && msg->header->bcc->field_value ? msg->header->bcc->field_value : ""); + cJSON_AddStringToObject(json_header, "reply_to", + msg->header->reply_to && msg->header->reply_to->field_value ? msg->header->reply_to->field_value : ""); + cJSON_AddStringToObject(json_header, "date", + msg->header->date && msg->header->date->field_value ? msg->header->date->field_value : ""); + cJSON_AddStringToObject(json_header, "subject", + msg->header->subject && msg->header->subject->field_value ? msg->header->subject->field_value : ""); + + if (msg->header->header_fields && msg->header->n_header_fields > 0) { + cJSON *json_header_fields = cJSON_CreateArray(); + for (size_t i = 0; i < msg->header->n_header_fields; i++) { + cJSON *json_field = cJSON_CreateObject(); + if (json_field) { + cJSON_AddStringToObject(json_field, "field_name", + msg->header->header_fields[i].field_name ? msg->header->header_fields[i].field_name : ""); + cJSON_AddStringToObject(json_field, "field_value", + msg->header->header_fields[i].field_value ? msg->header->header_fields[i].field_value : ""); + cJSON_AddItemToArray(json_header_fields, json_field); + } + } + cJSON_AddItemToObject(json_header, "header_fields", json_header_fields); + } + } + cJSON_AddItemToObject(json_msg, "header", json_header); + } + + if (msg->body) { + cJSON *json_body = cJSON_CreateObject(); + if (json_body) { + cJSON_AddStringToObject(json_body, "body", msg->body->body && msg->body->body_len ? msg->body->body : ""); + cJSON_AddNumberToObject(json_body, "body_len", msg->body->body_len); + cJSON_AddNumberToObject(json_body, "body_offset", msg->body->body_offset); + cJSON_AddBoolToObject(json_body, "is_body_finished", msg->body->is_body_finished); + } + cJSON_AddItemToObject(json_msg, "body", json_body); + } + + if (msg->attachment) { + cJSON *json_attachment = cJSON_CreateObject(); + if (json_attachment) { + cJSON_AddStringToObject(json_attachment, "attachment_name", + msg->attachment->attachment_name && msg->attachment->attachment_name_len? msg->attachment->attachment_name : ""); + cJSON_AddNumberToObject(json_attachment, "attachment_name_len", msg->attachment->attachment_name_len); + cJSON_AddStringToObject(json_attachment, "attachment", + msg->attachment->attachment && msg->attachment->attachment_len ? msg->attachment->attachment : ""); + cJSON_AddNumberToObject(json_attachment, "attachment_len", msg->attachment->attachment_len); + cJSON_AddNumberToObject(json_attachment, "attachment_offset", msg->attachment->attachment_offset); + cJSON_AddBoolToObject(json_attachment, "is_attachment_finished", msg->attachment->is_attachment_finished); + } + cJSON_AddItemToObject(json_msg, "attachment", json_attachment); + } + + if (msg->eml) { + cJSON *json_eml = cJSON_CreateObject(); + if (json_eml) { + cJSON_AddStringToObject(json_eml, "eml", msg->eml->eml && msg->eml->eml_len ? msg->eml->eml : ""); + cJSON_AddNumberToObject(json_eml, "eml_len", msg->eml->eml_len); + cJSON_AddNumberToObject(json_eml, "eml_offset", msg->eml->eml_offset); + cJSON_AddBoolToObject(json_eml, "is_eml_finished", msg->eml->is_eml_finished); + } + cJSON_AddItemToObject(json_msg, "eml", json_eml); + } + + char *json_string = cJSON_Print(json_msg); + cJSON_Delete(json_msg); + + return json_string; +} + +int mail_command_update(struct mail_command *command, enum MAIL_COMMAND cmd, const char *cmd_arg, size_t cmd_arg_len, const char *cmd_line, size_t cmd_line_len) +{ + command->cmd = cmd; + if (cmd_arg && cmd_arg_len > 0) { + cmd_arg_len = MIN(cmd_arg_len, MAIL_COMMAND_BUFFER_MAX); + command->arg_len = cmd_arg_len; + memcpy(command->arg, cmd_arg, cmd_arg_len); + } + if (cmd_line && cmd_line_len > 0) { + cmd_line_len = MIN(cmd_line_len, MAIL_COMMAND_BUFFER_MAX); + command->cmd_line_len = cmd_line_len; + memcpy(command->cmd_line, cmd_line, cmd_line_len); + } + return 0; +} + +struct mail_command *mail_command_clone(struct mail_command *cmd) +{ + struct mail_command *clone; + clone = (struct mail_command *)calloc(1, sizeof(struct mail_command)); + clone->cmd = cmd->cmd; + if (cmd->arg && cmd->arg_len > 0) { + clone->arg = (char *)malloc(cmd->arg_len); + clone->arg_len = cmd->arg_len; + memcpy(clone->arg, cmd->arg, cmd->arg_len); + } + if (cmd->cmd_line && cmd->cmd_line_len > 0) { + clone->cmd_line = (char *)malloc(cmd->cmd_line_len); + clone->cmd_line_len = cmd->cmd_line_len; + memcpy(clone->cmd_line, cmd->cmd_line, cmd->cmd_line_len); + } + return clone; +} + +void mail_command_free(struct mail_command *cmd) +{ + if (cmd) { + if (cmd->arg) { + free(cmd->arg); + } + if (cmd->cmd_line) { + free(cmd->cmd_line); + } + free(cmd); + } +} +struct mail_command * mail_command_new() +{ + struct mail_command *command; + command = (struct mail_command *)calloc(1, sizeof(struct mail_command)); + command->cmd = MAIL_CMD_MAX; + command->arg = (char *)calloc(1, MAIL_COMMAND_BUFFER_MAX); + command->cmd_line = (char *)calloc(1, MAIL_COMMAND_BUFFER_MAX); + return command; +} + +void mail_header_free(struct mail_header *header) +{ + int i; + struct mail_header_field *field; + + if (header) { + if (header->header_fields) { + for (i = 0; i < (int)header->n_header_fields; i++) { + field = &header->header_fields[i]; + if (field->field_name) { + free(field->field_name); + } + if (field->field_value) { + free(field->field_value); + } + } + free(header->header_fields); + } + free(header); + } +} + +struct mail_header *mail_header_new(void) +{ + struct mail_header *header; + header = (struct mail_header *)calloc(1, sizeof(struct mail_header)); + header->header_fields = (struct mail_header_field *)calloc(MAIL_HEADER_FIELDS_MAX, sizeof(struct mail_header_field)); + return header; +} + +int mail_header_add_field(struct mail_header *header, const char *line, size_t len, int enable_mime_decode) +{ + int ret; + struct iovec *iov_name; + struct iovec *iov_value; + struct iovec split[MAIL_HEADER_FIELD_SPLIT_PART_MAX]; + + if (header->n_header_fields >= MAIL_HEADER_FIELDS_MAX) { + return -1; + } + + // delete line endding + while(len > 0 && (*(line + len -1)=='\n' || *(line + len -1)=='\r')) { + len -= 1; + } + + ret = mail_strnsplit(split, MAIL_HEADER_FIELD_SPLIT_PART_MAX, ':', line, len); + if (ret != MAIL_HEADER_FIELD_SPLIT_PART_MAX) { + return -1; + } + + iov_name = &split[MAIL_HEADER_FIELD_SPLIT_PART_NAME]; + header->header_fields[header->n_header_fields].field_name = strndup(iov_name->iov_base, iov_name->iov_len); + header->header_fields[header->n_header_fields].field_name_len = iov_name->iov_len; + + iov_value = &split[MAIL_HEADER_FIELD_SPLIT_PART_VALUE]; + if (enable_mime_decode) { + char decode_buf[MAX_ORDER_LINE_SIZE+1]; + char charset_str_buf[MAIL_MAX_CHARSET_LEN]; + int decoded_len; + decoded_len = sizeof(decode_buf); + mime_header_decode(iov_value->iov_base, iov_value->iov_len, decode_buf, &decoded_len, charset_str_buf, sizeof(charset_str_buf), NULL); + header->header_fields[header->n_header_fields].field_value = strndup(decode_buf, decoded_len); + header->header_fields[header->n_header_fields].field_value_len = decoded_len; + } else { + header->header_fields[header->n_header_fields].field_value = strndup(iov_value->iov_base, iov_value->iov_len); + header->header_fields[header->n_header_fields].field_value_len = iov_value->iov_len; + } + header->n_header_fields++; + return 0; +} + +int mail_header_add_date(struct mail_header *header, const char *line, size_t len, int enable_mime_decode) +{ + int ret; + ret = mail_header_add_field(header, line, len, enable_mime_decode); + if (ret != 0) { + return -1; + } + header->date = &header->header_fields[header->n_header_fields - 1]; + return 0; +} + +int mail_header_add_from(struct mail_header *header, const char *line, size_t len, int enable_mime_decode) +{ + int ret; + ret = mail_header_add_field(header, line, len, enable_mime_decode); + if (ret != 0) { + return -1; + } + header->from = &header->header_fields[header->n_header_fields - 1]; + return 0; +} + +int mail_header_add_to(struct mail_header *header, const char *line, size_t len, int enable_mime_decode) +{ + int ret; + ret = mail_header_add_field(header, line, len, enable_mime_decode); + if (ret != 0) { + return -1; + } + header->to = &header->header_fields[header->n_header_fields - 1]; + return 0; +} + +int mail_header_add_cc(struct mail_header *header, const char *line, size_t len, int enable_mime_decode) +{ + int ret; + ret = mail_header_add_field(header, line, len, enable_mime_decode); + if (ret != 0) { + return -1; + } + header->cc = &header->header_fields[header->n_header_fields - 1]; + return 0; +} + +int mail_header_add_bcc(struct mail_header *header, const char *line, size_t len, int enable_mime_decode) +{ + int ret; + ret = mail_header_add_field(header, line, len, enable_mime_decode); + if (ret != 0) { + return -1; + } + header->bcc = &header->header_fields[header->n_header_fields - 1]; + return 0; +} + +int mail_header_add_reply_to(struct mail_header *header, const char *line, size_t len, int enable_mime_decode) +{ + int ret; + ret = mail_header_add_field(header, line, len, enable_mime_decode); + if (ret != 0) { + return -1; + } + header->reply_to = &header->header_fields[header->n_header_fields - 1]; + return 0; +} + +int mail_header_add_subject(struct mail_header *header, const char *line, size_t len, int enable_mime_decode) +{ + int ret; + ret = mail_header_add_field(header, line, len, enable_mime_decode); + if (ret != 0) { + return -1; + } + header->subject = &header->header_fields[header->n_header_fields - 1]; + return 0; +} + +struct mail_body * mail_body_clone(struct mail_body *body) +{ + struct mail_body *clone; + + clone = (struct mail_body *)calloc(1, sizeof(struct mail_body)); + if (body->body && body->body_len > 0) { + clone->body = (char *)malloc(body->body_len); + clone->body_len = body->body_len; + memcpy(clone->body, body->body, body->body_len); + } + clone->body_offset = body->body_offset; + clone->is_body_finished = body->is_body_finished; + return clone; +} + +int mail_body_update(struct mail_body *body, const char *line, size_t len, int is_finished) +{ + len = MIN(len, MAIL_BODY_BUFFER_MAX); + if (line) { + memcpy(body->body, line, len); + } + body->body_len = len; + body->body_offset += len; + body->is_body_finished = is_finished; + return 0; +} + +int mail_body_reset(struct mail_body *body) +{ + body->body_len = 0; + body->body_offset = 0; + body->is_body_finished = 0; + return 0; +} + +void mail_body_free(struct mail_body *body) +{ + if (body) { + if (body->body) { + free(body->body); + } + free(body); + } +} + +struct mail_body * mail_body_new(void) +{ + struct mail_body *body; + body = (struct mail_body *)calloc(1, sizeof(struct mail_body)); + body->body = (char *)calloc(1, MAIL_BODY_BUFFER_MAX); + body->body_len = 0; + body->body_offset = 0; + return body; +} + +int mail_attachment_set_filename(struct mail_attachment *attachment, const char *name, size_t len) +{ + if (attachment->attachment_name_len == 0) { + len = MIN(len, MAIL_ATTACHMENT_NAME_BUFFER_MAX); + if (name) { + memcpy(attachment->attachment_name, name, len); + } + attachment->attachment_name_len = len; + } + return 0; +} + +struct mail_attachment *mail_attachment_clone(struct mail_attachment *attachment) +{ + struct mail_attachment *clone; + + clone = (struct mail_attachment *)calloc(1, sizeof(struct mail_attachment)); + if (attachment->attachment_name && attachment->attachment_name_len > 0) { + clone->attachment_name = (char *)malloc(attachment->attachment_name_len); + clone->attachment_name_len = attachment->attachment_name_len; + memcpy(clone->attachment_name, attachment->attachment_name, attachment->attachment_name_len); + } + if (attachment->attachment && attachment->attachment_len > 0) { + clone->attachment = (char *)malloc(attachment->attachment_len); + clone->attachment_len = attachment->attachment_len; + memcpy(clone->attachment, attachment->attachment, attachment->attachment_len); + } + clone->attachment_offset = attachment->attachment_offset; + clone->is_attachment_finished = attachment->is_attachment_finished; + return clone; +} + +int mail_attachment_update(struct mail_attachment *attachment, const char *line, size_t len, int is_attachment_finished) +{ + len = MIN(len, MAIL_ATTACHMENT_BUFFER_MAX); + if (line) { + memcpy(attachment->attachment, line, len); + } + attachment->attachment_len = len; + attachment->attachment_offset += len; + attachment->is_attachment_finished = is_attachment_finished; + return 0; +} + +int mail_attachment_reset(struct mail_attachment *attachment) +{ + attachment->attachment_name_len = 0; + attachment->attachment_len = 0; + attachment->attachment_offset = 0; + attachment->is_attachment_finished = 0; + return 0; +} + +void mail_attachment_free(struct mail_attachment *attachment) +{ + if (attachment) { + if (attachment->attachment) { + free(attachment->attachment); + } + if (attachment->attachment_name) { + free(attachment->attachment_name); + } + free(attachment); + } +} + +struct mail_attachment * mail_attachment_new(void) +{ + struct mail_attachment *attachment; + attachment = (struct mail_attachment *)calloc(1, sizeof(struct mail_attachment)); + attachment->attachment_name = (char *)calloc(1, MAIL_ATTACHMENT_NAME_BUFFER_MAX); + attachment->attachment = (char *)calloc(1, MAIL_BODY_BUFFER_MAX); + return attachment; +} + +struct mail_eml *mail_eml_clone(struct mail_eml *eml) +{ + struct mail_eml *clone; + + clone = (struct mail_eml *)calloc(1, sizeof(struct mail_eml)); + if (eml->eml && eml->eml_len > 0) { + clone->eml = (char *)malloc(eml->eml_len); + clone->eml_len = eml->eml_len; + memcpy(clone->eml, eml->eml, eml->eml_len); + } + clone->eml_offset = eml->eml_offset; + clone->is_eml_finished = eml->is_eml_finished; + return clone; +} + +int mail_eml_update(struct mail_eml *eml, const char *data, size_t len, int is_eml_finished) +{ + len = MIN(len, MAIL_EML_BUFFER_MAX); + if (data) { + memcpy(eml->eml, data, len); + } + eml->eml_len = len; + eml->eml_offset += len; + eml->is_eml_finished = is_eml_finished; + return 0; +} + +int mail_eml_reset(struct mail_eml *eml) +{ + eml->eml_len = 0; + eml->eml_offset = 0; + eml->is_eml_finished = 0; + return 0; +} + +void mail_eml_free(struct mail_eml *eml) +{ + if (eml) { + if (eml->eml) { + free(eml->eml); + } + free(eml); + } +} + +struct mail_eml *mail_eml_new(void) +{ + struct mail_eml *eml; + eml = (struct mail_eml *)calloc(1, sizeof(struct mail_eml)); + eml->eml = (char *)calloc(1, MAIL_EML_BUFFER_MAX); + return eml; +} + +int mail_publish_command(struct mail_decoder *env, struct session *sess, + enum MAIL_PROTOCOL protocol, size_t mail_seq, struct mail_command *cmd) +{ + struct mq_runtime *runtime; + struct mail_message *msg; + + if ((cmd->arg == NULL && cmd->cmd_line == NULL) || (cmd->arg_len == 0 && cmd->cmd_line_len == 0)) { + return -1; + } + + runtime = module_manager_get_mq_runtime(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 = protocol; + msg->command = mail_command_clone(cmd); + + mq_runtime_publish_message(runtime, env->command_topic_id, msg); + return 0; +} + +int mail_publish_header(struct mail_decoder *env, struct session *sess, enum MAIL_PROTOCOL protocol, size_t mail_seq, struct mail_header *header) +{ + struct mq_runtime *runtime; + struct mail_message *msg; + + if (header == NULL || header->n_header_fields == 0) { + return -1; + } + + runtime = module_manager_get_mq_runtime(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 = protocol; + msg->header = header; + + mq_runtime_publish_message(runtime, env->header_topic_id, msg); + return 0; +} + +int mail_publish_body(struct mail_decoder *env, struct session *sess, enum MAIL_PROTOCOL protocol, size_t mail_seq, struct mail_body *body) +{ + struct mq_runtime *runtime; + struct mail_message *msg; + + if (body == NULL || body->body_offset == 0) { + return -1; + } + + runtime = module_manager_get_mq_runtime(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 = protocol; + msg->body = mail_body_clone(body); + + mq_runtime_publish_message(runtime, env->body_topic_id, msg); + return 0; +} + +int mail_publish_attachment(struct mail_decoder *env, struct session *sess, enum MAIL_PROTOCOL protocol, size_t mail_seq, struct mail_attachment *attachment) +{ + struct mq_runtime *runtime; + struct mail_message *msg; + + if (attachment == NULL || attachment->attachment_name_len == 0 || attachment->attachment_offset == 0) { + return -1; + } + + runtime = module_manager_get_mq_runtime(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 = protocol; + msg->attachment = mail_attachment_clone(attachment); + + mq_runtime_publish_message(runtime, env->attachment_topic_id, msg); + return 0; +} + +int mail_publish_eml(struct mail_decoder *env, struct session *sess, enum MAIL_PROTOCOL protocol, struct mail_eml *eml) +{ + struct mq_runtime *runtime; + struct mail_message *msg; + + if (eml == NULL || eml->eml_offset == 0) { + return -1; + } + + runtime = module_manager_get_mq_runtime(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 = protocol; + msg->eml = mail_eml_clone(eml); + + mq_runtime_publish_message(runtime, env->eml_topic_id, msg); + return 0; +} + +void mail_message_free(void *msg, void *arg) +{ + (void)(arg); + struct mail_message *mail_msg; + mail_msg = (struct mail_message *)msg; + if (mail_msg) { + if (mail_msg->command) { + mail_command_free(mail_msg->command); + } + if (mail_msg->header) { + mail_header_free(mail_msg->header); + } + if (mail_msg->body) { + mail_body_free(mail_msg->body); + } + if (mail_msg->attachment) { + mail_attachment_free(mail_msg->attachment); + } + if (mail_msg->eml) { + mail_eml_free(mail_msg->eml); + } + free(mail_msg); + } +} + +static void mail_mailinfo_clear(tdMailInfo *plug_mailinfo) +{ + if(plug_mailinfo->pMailInfo->username->buf) + free(plug_mailinfo->pMailInfo->username->buf); + if(plug_mailinfo->pMailInfo->password->buf) + free(plug_mailinfo->pMailInfo->password->buf); + if(plug_mailinfo->pMailInfo->sendaddr->buf) + free(plug_mailinfo->pMailInfo->sendaddr->buf); + if(plug_mailinfo->pMailInfo->recvaddr->buf) + free(plug_mailinfo->pMailInfo->recvaddr->buf); + if(plug_mailinfo->pMailInfo->subject->buf) + free(plug_mailinfo->pMailInfo->subject->buf); + if(plug_mailinfo->pMailInfo->date->buf) + free(plug_mailinfo->pMailInfo->date->buf); + if(plug_mailinfo->elem) + free(plug_mailinfo->elem); +} + +static int mail_mailinfo_init(struct email_parser *email) +{ + tdMailInfo *pmailinfo = &email->plug_mailinfo; + + memset(pmailinfo, 0, sizeof(tdMailInfo)); + + pmailinfo->pMailInfo = &email->pMailinfo; + pmailinfo->pMailInfo->username = &email->keyinfo.username; + pmailinfo->pMailInfo->password = &email->keyinfo.password; + pmailinfo->pMailInfo->sendaddr= &email->keyinfo.sendaddr; + pmailinfo->pMailInfo->recvaddr = &email->keyinfo.recvaddr; + pmailinfo->pMailInfo->subject = &email->keyinfo.subject; + pmailinfo->pMailInfo->date = &email->keyinfo.date; + + pmailinfo->elem = (stFieldElem *)malloc(sizeof(stFieldElem)*MAIL_ELEM_NUM); + email->max_elem_num = MAIL_ELEM_NUM; + + return 0; +} + +static void mail_mailinfo_reset(tdMailInfo *pmailinfo) +{ + /*if(pmailinfo->pMailInfo->username->buf != NULL) //ͬһ��������������û������룬�����ĻỰ���Լ�������� + { + pmailinfo->pMailInfo->username->buflen = 0; + pmailinfo->pMailInfo->username->buf[0] = '\0'; + } + if(pmailinfo->pMailInfo->password->buf != NULL) + { + pmailinfo->pMailInfo->password->buflen = 0; + pmailinfo->pMailInfo->password->buf[0] = '\0'; + }*/ + if(pmailinfo->pMailInfo->sendaddr->buf != NULL) + { + pmailinfo->pMailInfo->sendaddr->buflen = 0; + pmailinfo->pMailInfo->sendaddr->buf[0] = '\0'; + } + if(pmailinfo->pMailInfo->recvaddr->buf != NULL) + { + pmailinfo->pMailInfo->recvaddr->buflen = 0; + pmailinfo->pMailInfo->recvaddr->buf[0] = '\0'; + } + if(pmailinfo->pMailInfo->subject->buf != NULL) + { + pmailinfo->pMailInfo->subject->buflen = 0; + pmailinfo->pMailInfo->subject->buf[0] = '\0'; + } + if(pmailinfo->pMailInfo->date->buf != NULL) + { + pmailinfo->pMailInfo->date->buflen = 0; + pmailinfo->pMailInfo->date->buf[0] = '\0'; + } + + pmailinfo->trans_enc = MAIL_TRANS_ENC_UNKNOWN; + pmailinfo->session_seq++; + pmailinfo->buflen = 0; + pmailinfo->buf = NULL; + pmailinfo->current_charset = NULL; + pmailinfo->lostlen = 0; + + if(pmailinfo->elem_num > 0) + { + pmailinfo->elem_num = 0; + } +} + +static int email_process_body(char *a_mail_line, int datalen,struct email_parser * eml_parser) +{ + int ret; + MimeParse_t * mimeinfo = eml_parser->mimeinfo; + + mimeinfo->src = a_mail_line; + mimeinfo->srcLen = datalen; + + if (buf_cache_check_size(&eml_parser->pMimeDecodeBuf, mimeinfo->srcLen+1) < 0) + { + return -1; + } + mimeinfo->dst = (char *)eml_parser->pMimeDecodeBuf.buf; + mimeinfo->dstSize = eml_parser->pMimeDecodeBuf.max_len; + eml_parser->pMimeDecodeBuf.len = 0; + + ret = mime_parse_feed(mimeinfo, 1); + if (ret<0) + { + return -1; + } + + if ((ret == MIME_LINE_CONT_TYPE || ret == MIME_LINE_CONT_DISP) && mimeinfo->filename != NULL) + { + eml_parser->MailInfoState = MAIL_GET_FILENAME; + } + else if (ret == MIME_LINE_CONT_BODY) + { + if (mimeinfo->is_attachment) + { + eml_parser->MailInfoState = MAIL_GET_FILECOUNT; + } + else + { + eml_parser->MailInfoState = MAIL_GET_COUNT; + } + } + else if (ret == MIME_LINE_BOUNARY || ret == MIME_LINE_BOUNARY_END) + { + if (mimeinfo->is_attachment) + { + eml_parser->MailInfoState = MAIL_GET_FILECOUNT_END; + } else { + eml_parser->MailInfoState = MAIL_GET_COUNT_END; + } + } else { + eml_parser->MailInfoState = MAIL_GET_OTHER; + } + + return 0; +} + +enum EML_LINE_TYPE email_parser_parse_line(const char *a_mail_line,int datalen,int EmlAnalyseState) +{ + if (EmlAnalyseState == MAIL_STAT_BODY) + return EML_DATA_BODY_IN; + + const char *pos_colon; + + pos_colon = (const char *)memchr(a_mail_line, ':', datalen>26?26:datalen); + if (pos_colon != NULL) + { + datalen = pos_colon-a_mail_line; + + switch(datalen) + { + case 2: + if (strcmp_one_word_mesa_equal_len("to", "TO", a_mail_line, 2)) + return EML_DATA_TO; + if (strcmp_one_word_mesa_equal_len("cc", "CC", a_mail_line, 2)) + return EML_DATA_CC; + break; + + case 3: + if (strcmp_one_word_mesa_equal_len("bcc", "BCC", a_mail_line, 3)) + return EML_DATA_BCC; + break; + + case 4: + if (strcmp_one_word_mesa_equal_len("date", "DATE", a_mail_line, 4)) + return EML_DATA_DATE; + if (strcmp_one_word_mesa_equal_len("from", "FROM", a_mail_line, 4)) + return EML_DATA_FROM; + break; + + case 7: + if (strcmp_one_word_mesa_equal_len("subject", "SUBJECT", a_mail_line, 7)) + return EML_DATA_SUBJECT; + break; + + case 8: + if (strcmp_one_word_mesa_equal_len("received", "RECEIVED", a_mail_line, 8)) + return EML_DATA_RECEIVED; + if (strcmp_one_word_mesa_equal_len("reply-to", "REPLY-TO", a_mail_line, 8)) + return EML_DATA_REPLY_TO; + break; + + case 11: + if (strcmp_one_word_mesa_equal_len("return-path", "RETURN-PATH", a_mail_line, 11)) + return EML_DATA_RETURN_PATH; + break; + + case 12: + if (strcmp_one_word_mesa_equal_len("delivered-to", "DELIVERED-TO", a_mail_line, 12)) + return EML_DATA_DELIVERED_TO; + if (MAIL_STAT_HEADER == EmlAnalyseState) + { + if (strcmp_one_word_mesa_equal_len("content-type", "CONTENT-TYPE", a_mail_line, 12)) + return EML_DATA_CONTENTTYPE; + return EML_DATA_HEAD_IN; + } + break; + + case 25: + if (MAIL_STAT_HEADER == EmlAnalyseState) + { + if (strcmp_one_word_mesa_equal_len("content-transfer-encoding", "CONTENT-TRANSFER-ENCODING", a_mail_line, 25)) + return EML_DATA_CONTENTTRANSFERENCODING; + return EML_DATA_HEAD_IN; + } + break; + + default: + if (MAIL_STAT_HEADER != EmlAnalyseState && strncmp_one_word_mesa("x-", "X-", 2, a_mail_line, datalen)) + return EML_DATA_HEAD_IN; + break; + } + + if (MAIL_STAT_HEADER == EmlAnalyseState) + { + return EML_DATA_HEAD_IN; + } + } + else if (MAIL_STAT_HEADER == EmlAnalyseState) + { + if ((datalen==2 && !strncmp(a_mail_line, "\r\n", 2))||(datalen==1 && *a_mail_line=='\n')) + return EML_DATA_HEAD_BODY_BORDER; + + return EML_DATA_HEAD_IN; + } + + return EML_UNKNOWN; +} + +int email_parser_get_tcpdata(struct email_parser* eml_parser, const char *payload, size_t payload_len, int need_folding, char ** output_buf,int *output_len) +{ + char* curpointer = (char*)(payload) + eml_parser->iDataPointer; + + if((unsigned int)(eml_parser->iDataPointer) >= (unsigned int)(payload_len)) + return MAIL_INPUT_END; + + if(need_folding == 1) + { + return get_fold_line(eml_parser, curpointer, payload_len-eml_parser->iDataPointer, output_buf, output_len); + } + else if(eml_parser->EmlAnalyseState != MAIL_STAT_BODY || eml_parser->obtain_line) + { + if(eml_parser->obtain_line) + eml_parser->obtain_line = 0; + return get_one_tcpline(eml_parser, curpointer, payload_len-eml_parser->iDataPointer, output_buf, output_len, 1); + } + else + { + return get_complete_region(eml_parser, curpointer, payload_len-eml_parser->iDataPointer, output_buf, output_len); + } +} + +int email_parser_get_atcpline_c2s(struct email_parser* eml_parser, const char *payload, size_t payload_len, char ** output_buf,int *output_len) +{ + char* curpointer = (char*)(payload) + eml_parser->iDataPointer; + + if((unsigned int)(eml_parser->iDataPointer) >= (unsigned int)(payload_len)) + return MAIL_INPUT_END; + + return get_one_tcpline(eml_parser, curpointer, payload_len-eml_parser->iDataPointer, output_buf, output_len, 0); +} + +void email_parser_set_drop(struct email_parser* eml_parser) +{ + eml_parser->is_drop = 1; + eml_parser->EmlAnalyseState = MAIL_STAT_BODY; + eml_parser->mimeinfo->text_begin = 1; +} + +size_t email_parser_get_seq(struct email_parser *eml_parser) +{ + return eml_parser->mail_seq; +} + +int email_parser_reset(struct email_parser * eml_parser) +{ + mail_eml_reset(eml_parser->eml); + mail_body_reset(eml_parser->body); + mail_attachment_reset(eml_parser->current_attachment); + + mail_mailinfo_reset(&eml_parser->plug_mailinfo); + reset_mime_info(eml_parser->mimeinfo, 0); + + eml_parser->pDataLineBuf.len = 0; + eml_parser->pOriginalData.len = 0; + eml_parser->pMimeDecodeBuf.len = 0; + eml_parser->pBizRegion.len = 0; + + eml_parser->subject_charset[0] = '\0'; + eml_parser->EmlAnalyseState = MAIL_STAT_INIT; + eml_parser->MailInfoState = MAIL_NO_USER; + + eml_parser->maybe_end = 0; //IMAPЭ�飬��һ��MAYBE_END����һ����FETCH����������Ҫ��ո�״̬ + eml_parser->is_drop = 0; + eml_parser->is_called = 0; + eml_parser->pending_state = 1; + return 0; +} + +void email_parser_free(struct email_parser *eml_parser) +{ + if (eml_parser->is_called) + { + eml_parser->plug_mailinfo.buf = (char *)eml_parser->pOriginalData.buf; + eml_parser->plug_mailinfo.buflen = eml_parser->pOriginalData.len; + + } + mail_mailinfo_clear(&eml_parser->plug_mailinfo); + clear_mime_info(eml_parser->mimeinfo); + + mail_header_free(eml_parser->header); + mail_body_free(eml_parser->body); + mail_attachment_free(eml_parser->current_attachment); + mail_eml_free(eml_parser->eml); + + if (eml_parser->pDataLineBuf.buf) + free(eml_parser->pDataLineBuf.buf); + if (eml_parser->pOriginalData.buf) + free(eml_parser->pOriginalData.buf); + if (eml_parser->pMimeDecodeBuf.buf) + free(eml_parser->pMimeDecodeBuf.buf); + if (eml_parser->pBizRegion.buf) + free(eml_parser->pBizRegion.buf); + free(eml_parser); +} + +struct email_parser *email_parser_new(struct mail_decoder *env, enum MAIL_PROTOCOL protocol, int is_c2s) +{ + struct email_parser* eml_parser = NULL; + + eml_parser = (struct email_parser *)calloc(1, sizeof(struct email_parser)); + + //session_info->app_info: eml_parser->plug_mailinfo + if (mail_mailinfo_init(eml_parser)) + { + free(eml_parser); + return NULL; + } + + //mimeinfo + if (init_mime_info(&eml_parser->mimeinfo, NULL) < 0) + { + mail_mailinfo_clear(&eml_parser->plug_mailinfo); + free(eml_parser); + return NULL; + } + + //other info + eml_parser->EmlAnalyseState=MAIL_STAT_INIT; + eml_parser->MailInfoState=MAIL_NO_USER; + eml_parser->pre_dir = is_c2s; + eml_parser->pending_state = 1; + + eml_parser->mail_seq = 0; + eml_parser->protocol = protocol; + eml_parser->header = mail_header_new(); + eml_parser->body = mail_body_new(); + eml_parser->current_attachment = mail_attachment_new(); + eml_parser->eml = mail_eml_new(); + eml_parser->mail_env_ref = env; + return eml_parser; +} + +int email_parser_entry(struct email_parser *eml_parser, struct session *sess, const char *email_line, size_t line_len, enum EML_LINE_TYPE line_type) +{ + int ret; + + if (line_type != EML_DATA_END) { + mail_eml_update(eml_parser->eml, email_line, line_len, 0); + } else { + mail_eml_update(eml_parser->eml, NULL, 0, 1); + } + mail_publish_eml(eml_parser->mail_env_ref, sess, eml_parser->protocol, eml_parser->eml); + + if (is_eml_header_field(line_type) && eml_parser->header == NULL) { + eml_parser->header = mail_header_new(); + eml_parser->mail_seq++; + } + + switch (line_type) { + case EML_DATA_DATE: + if (eml_parser->EmlAnalyseState != MAIL_STAT_HEADER) { + eml_parser->EmlAnalyseState = MAIL_STAT_HEADER; + } + eml_parser->MailInfoState = MAIL_GET_DATE; + + mail_header_add_date(eml_parser->header, email_line, line_len, 1); + break; + case EML_DATA_FROM: + if (eml_parser->EmlAnalyseState != MAIL_STAT_HEADER) { + eml_parser->EmlAnalyseState = MAIL_STAT_HEADER; + } + eml_parser->MailInfoState = MAIL_GET_FROM; + + mail_header_add_from(eml_parser->header, email_line, line_len, 1); + break; + case EML_DATA_TO: + if (eml_parser->EmlAnalyseState != MAIL_STAT_HEADER) { + eml_parser->EmlAnalyseState = MAIL_STAT_HEADER; + } + eml_parser->MailInfoState = MAIL_GET_TO; + + mail_header_add_to(eml_parser->header, email_line, line_len, 1); + break; + case EML_DATA_CC: + if (eml_parser->EmlAnalyseState != MAIL_STAT_HEADER) { + eml_parser->EmlAnalyseState = MAIL_STAT_HEADER; + } + eml_parser->MailInfoState = MAIL_GET_TO; //TODO + + mail_header_add_cc(eml_parser->header, email_line, line_len, 1); + break; + case EML_DATA_BCC: + if (eml_parser->EmlAnalyseState != MAIL_STAT_HEADER) { + eml_parser->EmlAnalyseState = MAIL_STAT_HEADER; + } + eml_parser->MailInfoState = MAIL_GET_TO; //TODO + + mail_header_add_bcc(eml_parser->header, email_line, line_len, 1); + break; + case EML_DATA_REPLY_TO: + if (eml_parser->EmlAnalyseState != MAIL_STAT_HEADER) { + eml_parser->EmlAnalyseState = MAIL_STAT_HEADER; + } + eml_parser->MailInfoState = MAIL_GET_TO; + + mail_header_add_to(eml_parser->header, email_line, line_len, 1); + break; + case EML_DATA_SUBJECT: + if (eml_parser->EmlAnalyseState != MAIL_STAT_HEADER) { + eml_parser->EmlAnalyseState = MAIL_STAT_HEADER; + } + eml_parser->MailInfoState = MAIL_GET_SUB; + + mail_header_add_subject(eml_parser->header, email_line, line_len, 1); + break; + case EML_DATA_CONTENTTYPE: + case EML_DATA_CONTENTTRANSFERENCODING: + case EML_DATA_BODY_IN: + ret = email_process_body((char *)email_line, line_len, eml_parser); + if (ret < 0) { + return -1; + } + + // body + if (eml_parser->MailInfoState == MAIL_GET_COUNT) { + mail_body_update(eml_parser->body, eml_parser->mimeinfo->dst, eml_parser->mimeinfo->actLen, 0); + mail_publish_body(eml_parser->mail_env_ref, sess, eml_parser->protocol, eml_parser->mail_seq, eml_parser->body); + } + if (eml_parser->MailInfoState == MAIL_GET_COUNT_END) { + mail_body_update(eml_parser->body, NULL, 0, 1); + mail_publish_body(eml_parser->mail_env_ref, sess, eml_parser->protocol, eml_parser->mail_seq,eml_parser->body); + mail_body_reset(eml_parser->body); + } + + // attachment + if (eml_parser->MailInfoState == MAIL_GET_FILENAME) { + if (eml_parser->mimeinfo->filenameLen > 0) { + mail_attachment_set_filename(eml_parser->current_attachment, eml_parser->mimeinfo->filename, eml_parser->mimeinfo->filenameLen); + } + } + if (eml_parser->MailInfoState == MAIL_GET_FILECOUNT) { + mail_attachment_update(eml_parser->current_attachment, eml_parser->mimeinfo->dst, eml_parser->mimeinfo->actLen, 0); + mail_publish_attachment(eml_parser->mail_env_ref, sess, eml_parser->protocol, eml_parser->mail_seq, eml_parser->current_attachment); + } + + if (eml_parser->MailInfoState == MAIL_GET_FILECOUNT_END) { + mail_attachment_update(eml_parser->current_attachment, NULL, 0, 1); + mail_publish_attachment(eml_parser->mail_env_ref, sess, eml_parser->protocol, eml_parser->mail_seq, eml_parser->current_attachment); + mail_attachment_reset(eml_parser->current_attachment); + } + break; + case EML_DATA_HEAD_BODY_BORDER: + mail_publish_header(eml_parser->mail_env_ref, sess, eml_parser->protocol, eml_parser->mail_seq, eml_parser->header); + eml_parser->header = NULL; + + eml_parser->EmlAnalyseState = MAIL_STAT_BODY; + body_update_text_begin(eml_parser->mimeinfo); + break; + case EML_DATA_RETURN_PATH: + case EML_DATA_RECEIVED: + case EML_DATA_DELIVERED_TO: + case EML_DATA_HEAD_IN: + if (eml_parser->EmlAnalyseState != MAIL_STAT_HEADER) { + eml_parser->EmlAnalyseState = MAIL_STAT_HEADER; + } + mail_header_add_field(eml_parser->header, email_line, line_len, 1); + break; + case EML_DATA_END: + email_parser_reset(eml_parser); + break; + default: + break; + } + return 0; +} + + diff --git a/decoders/mail/mail_decoder_email.h b/decoders/mail/mail_decoder_email.h new file mode 100644 index 0000000..f6a2e7a --- /dev/null +++ b/decoders/mail/mail_decoder_email.h @@ -0,0 +1,275 @@ +#ifndef H_MAILNEW_ANALYZE +#define H_MAILNEW_ANALYZE + +#include "stellar/session.h" +#include "stellar/mail.h" +#include "mail_decoder_util.h" +#include "mail_decoder_mime.h" + +#define MAIL_GETLINE_ERR -1 +#define MAIL_INPUT_END 0 +#define MAIL_FOLD_LINE_END 1 +#define MAIL_FOLD_LINE_START 2 +#define MAIL_LINE_END 3 +#define MAIL_PACKET_END 4 +#define MAILAMALYZE_MODULE "[MAIL_ANALYZE]" +#define NULL_FILENAME "UNKNOWN_FILENAME.UNKNOWN" +#define NULL_FILENAME_LEN 24 + +#define MAIL_HEADER_FIELD_SPLIT_PART_NAME 0 +#define MAIL_HEADER_FIELD_SPLIT_PART_VALUE 1 +#define MAIL_HEADER_FIELD_SPLIT_PART_MAX 2 +#define MAIL_HEADER_FIELDS_MAX 16 +#define MAIL_COMMAND_BUFFER_MAX 1024 +#define MAIL_BODY_BUFFER_MAX 4096 +#define MAIL_ATTACHMENT_BUFFER_MAX 4096 +#define MAIL_ATTACHMENT_NAME_BUFFER_MAX 256 +#define MAIL_EML_BUFFER_MAX 4096 + +#define MAIL_STAT_INIT 0x10//�ʼ���δ״̬ +#define MAIL_STAT_HEADER 0x11//�ʼ�ͷ������״̬ +#define MAIL_STAT_BODY 0x12//�ʼ��崦��״̬ +#define MAIL_STAT_END 0x13//�ʼ�����״̬ + +#define MAIL_NO_USER 0 +#define MAIL_HAVE_USER (1<<0) +#define MAIL_BEFORE_USER (1<<1) +#define MAIL_BEFORE_PASS (1<<2) +#define MAIL_AFTER_PASS (1<<3) +#define MAIL_AUTH_PLAIN (1<<4) + +#define MAIL_GET_NONE -1 +#define MAIL_GET_FROM 9 +#define MAIL_GET_TO 10 +#define MAIL_GET_SUB 11 +#define MAIL_GET_DATE 12 +#define MAIL_GET_COUNT 13 +#define MAIL_GET_FILENAME 14 +#define MAIL_GET_FILECOUNT 15 +#define MAIL_GET_OTHER 16 +#define MAIL_GET_FILECOUNT_END 17 +#define MAIL_GET_COUNT_END 18 + +#define MAIL_TRANS_ENC_UNKNOWN 0 +#define MAIL_TRANS_ENC_BASE64 1 +#define MAIL_TRANS_ENC_QP 2 + +enum EML_LINE_TYPE +{ + EML_DATA_HEAD_IN=1, + EML_DATA_BODY_IN, + EML_DATA_FROM, + EML_DATA_TO, + EML_DATA_CC, + EML_DATA_BCC, /*6*/ + EML_DATA_SUBJECT, + EML_DATA_CONTENTTYPE, + EML_DATA_CONTENTTRANSFERENCODING, + EML_DATA_HEAD_BODY_BORDER, + EML_DATA_END, /*11*/ + EML_DATA_RETURN_PATH, + EML_DATA_DELIVERED_TO, + EML_DATA_RECEIVED, + EML_DATA_DATE, /*15*/ + EML_DATA_REPLY_TO, + EML_UNKNOWN, +}; + +enum MAIL_MESSAGE_TYPE { + MAIL_MESSAGE_TYPE_COMMAND, + MAIL_MESSAGE_TYPE_HEADER, + MAIL_MESSAGE_TYPE_BODY, + MAIL_MESSAGE_TYPE_ATTACHMENT, + MAIL_MESSAGE_TYPE_EML, + MAIL_MESSAGE_TYPE_MAX, +}; + +struct mail_command { + enum MAIL_COMMAND cmd; + char *arg; + size_t arg_len; + char *cmd_line; + size_t cmd_line_len; +}; + +struct mail_body { + char *body; + size_t body_len; + size_t body_offset; + int is_body_finished; +}; + +struct mail_attachment { + char *attachment_name; + size_t attachment_name_len; + char *attachment; + size_t attachment_len; + size_t attachment_offset; + int is_attachment_finished; +}; + +struct mail_eml { + char *eml; + size_t eml_len; + size_t eml_offset; + int is_eml_finished; +}; + +struct mail_message { + enum MAIL_MESSAGE_TYPE type; + enum MAIL_PROTOCOL mail_protocol; + size_t mail_seq; + + struct mail_command *command; + struct mail_header *header; + struct mail_body *body; + struct mail_attachment *attachment; + struct mail_eml *eml; + + struct session *sess_ref; +}; + +typedef struct _new_mail_key_info +{ + stMailElem username; //�û��� + stMailElem password; //�û����� + stMailElem sendaddr; // ���ŵ�ַ + stMailElem recvaddr; // ���ŵ�ַ + stMailElem subject; //�ʼ����� + stMailElem date; //����ʱ�� +}new_stKeyInfo; + +typedef struct _mail_key_info +{ + stMailElem *username; //用户名 + stMailElem *password; //用户密码 + stMailElem *sendaddr; //发信地址 + stMailElem *recvaddr; //收信地址 + stMailElem *subject; //邮件主题 + stMailElem *date; //发信时间 +} stKeyInfo; + +typedef struct _field_element +{ + long long prot_flag; + char* current_charset; //当前字符集编码格式 ;可能为NULL; + void *buf; //当前字段对应原始数据内容, 经过传输编码解析 + int buflen; //当前字段对应原始数据长度 +}stFieldElem; + +typedef struct _mail_pme_info +{ + char protocol; //邮件协议SMTP_PROTOCOL/POP3_PROTOCOL/IMAP_PROTOCOL + char trans_enc; //传输编码,只有邮件正文、附件有;主题和附件名中是否有传输编码需要业务插件自行解析 + short session_seq; //当前会话是TCP链接中的第几个会话,从0开始; + int buflen; //邮件原始数据长度 + char* buf; //邮件原始数据内容,不经过传输编码解析 + char* current_charset; //当前字符集编码格式 ;可能为NULL; + stKeyInfo *pMailInfo; //保留邮件的关键信息 + + //NEXT: ADD BY ZCW + int cur_offset; //当前字段在原始数据buf中的的偏移 + int lostlen; + stFieldElem *elem; + int elem_num; +} tdMailInfo; + +struct email_parser +{ + stBufCache pDataLineBuf; //��ȡ���ݰ������� + stBufCache pOriginalData; //ԭʼ�ʼ���Ϣ + stBufCache pMimeDecodeBuf; //MIME�����Ĵ洢�� + stBufCache pBizRegion; //�����ص�ҵ�����ֶ�buf������ + + tdMailInfo plug_mailinfo; //session_info->app_info + stKeyInfo pMailinfo; //plug_mailinfo.pMailinfo + new_stKeyInfo keyinfo; //plug_mailinfo.pMailinfo�ij�Ա + stFieldElem elem; + + MimeParse_t *mimeinfo; // mime����ṹ + char subject_charset[MAIL_MAX_CHARSET_LEN]; //�����ַ��������ʽ + + int iDataPointer; // ��ǰ��ȡ������ƫ�ƣ����ڰ��ж�ȡ�� + int max_elem_num; + + int EmlAnalyseState;// ��־�ʼ�����״̬ + int MailInfoState; //zcw add, from stMailInfoOld + + int iProtoType; //�ʼ��Ự�ṹ��Э������ + int thread_num; + + char is_drop; //��ǰ�ʼ��Ự��ҵ���DROP + char pending_state; //1-Ϊ�µĻỰ�����������ģ�0-�»Ự�ѵ��� + char is_called; //��ǰ�Ự�ص���ҵ��� + char pre_dir; //��һ�����ķ�������˫�������ݵ�ʱ��ʹ�ã�����SMTPֻ���ǵ�����ĺ��Դ˱��� + + //NEXT ONLY IMAP4 + char is_continue; + char maybe_end; //')'����ȷ����������ʱ�����ñ�� + short obtain_line; //������������ȡһ�У���������۵��� + int pre_opsate; //')'����ȷ����������ʱ������һ�ε������� + long pre_uid; //IMAPЭ�鰴���ֽ�����ȡ�ʼ����ݵ���� + long uid; + + struct mail_decoder *mail_env_ref; + size_t mail_seq; + enum MAIL_PROTOCOL protocol; + struct mail_header *header; + struct mail_body *body; + struct mail_attachment *current_attachment; + struct mail_eml *eml; +}; + +int mail_command_update(struct mail_command *command, enum MAIL_COMMAND cmd, const char *cmd_arg, size_t cmd_arg_len, const char *cmd_line, size_t cmd_line_len); +void mail_command_free(struct mail_command *command); +struct mail_command *mail_command_clone(struct mail_command *command); +struct mail_command * mail_command_new(void); +void mail_header_free(struct mail_header *header); +struct mail_header *mail_header_new(void); +int mail_header_add_field(struct mail_header *header, const char *line, size_t len, int enable_mime_decode); +int mail_header_add_date(struct mail_header *header, const char *line, size_t len, int enable_mime_decode); +int mail_header_add_from(struct mail_header *header, const char *line, size_t len, int enable_mime_decode); +int mail_header_add_to(struct mail_header *header, const char *line, size_t len, int enable_mime_decode); +int mail_header_add_cc(struct mail_header *header, const char *line, size_t len, int enable_mime_decode); +int mail_header_add_bcc(struct mail_header *header, const char *line, size_t len, int enable_mime_decode); +int mail_header_add_reply_to(struct mail_header *header, const char *line, size_t len, int enable_mime_decode); +int mail_header_add_subject(struct mail_header *header, const char *line, size_t len, int enable_mime_decode); +int mail_body_update(struct mail_body *body, const char *line, size_t len, int is_finished); +int mail_body_reset(struct mail_body *body); +void mail_body_free(struct mail_body *body); +struct mail_body * mail_body_clone(struct mail_body *body); +struct mail_body * mail_body_new(void); +int mail_attachment_set_filename(struct mail_attachment *attachment, const char *name, size_t len); +int mail_attachment_update(struct mail_attachment *attachment, const char *line, size_t len, int is_attachment_finished); +int mail_attachment_reset(struct mail_attachment *attachment); +void mail_attachment_free(struct mail_attachment *attachment); +struct mail_attachment *mail_attachment_clone(struct mail_attachment *attachment); +struct mail_attachment * mail_attachment_new(void); +int mail_eml_update(struct mail_eml *eml, const char *data, size_t len, int is_eml_finished); +int mail_eml_reset(struct mail_eml *eml); +void mail_eml_free(struct mail_eml *eml); +struct mail_eml *mail_eml_clone(struct mail_eml *eml); +struct mail_eml *mail_eml_new(void); +int mail_publish_command(struct mail_decoder *env, struct session *sess, enum MAIL_PROTOCOL protocol, size_t mail_seq, struct mail_command *cmd); +int mail_publish_header(struct mail_decoder *env, struct session *sess, enum MAIL_PROTOCOL protocol, size_t mail_seq, struct mail_header *header); +int mail_publish_body(struct mail_decoder *env, struct session *sess, enum MAIL_PROTOCOL protocol, size_t mail_seq, struct mail_body *body); +int mail_publish_attachment(struct mail_decoder *env, struct session *sess, enum MAIL_PROTOCOL protocol, size_t mail_seq, struct mail_attachment *attachment); +int mail_publish_eml(struct mail_decoder *env, struct session *sess, enum MAIL_PROTOCOL protocol, struct mail_eml *eml); +void mail_message_free(void *msg, void *arg); +char *mail_message_to_json(struct mail_message *msg); + + +void email_parser_set_drop(struct email_parser* eml_parser); +size_t email_parser_get_seq(struct email_parser *eml_parser); + +enum EML_LINE_TYPE email_parser_parse_line(const char *a_mail_line,int datalen,int EmlAnalyseState); +int email_parser_get_atcpline_c2s(struct email_parser* eml_parser, const char *payload, size_t payload_len, char ** output_buf,int *output_len); +int email_parser_get_tcpdata(struct email_parser* eml_parser, const char *payload, size_t payload_len, int need_folding, char ** output_buf,int *output_len); + +int email_parser_entry(struct email_parser *eml_parser, struct session *sess, const char *email_line, size_t line_len, enum EML_LINE_TYPE line_type); +int email_parser_reset(struct email_parser * eml_parser); +void email_parser_free(struct email_parser *eml_parser); +struct email_parser * email_parser_new(struct mail_decoder *env, enum MAIL_PROTOCOL protocol, int is_c2s); + +#endif + diff --git a/decoders/mail/mail_decoder_imap.h b/decoders/mail/mail_decoder_imap.h new file mode 100644 index 0000000..3b0c36d --- /dev/null +++ b/decoders/mail/mail_decoder_imap.h @@ -0,0 +1,92 @@ +#ifndef __MAIL_IMAP4_H__ +#define __MAIL_IMAP4_H__ + +#include "mail_global.h" + +#define MAILIMAP4_MODULE "[MAIL_IMAP4]" + +#define RESPONSE_FETCH_MAX_LEN 32 //ȡ��FETCH��Ӧ��2���ո���� + +#define CONT_TYPE_TEXT 1 +#define CONT_TYPE_MESSAGE 2 +#define CONT_TYPE_RFC822 3 +#define CONT_TYPE_OTHER 4 + +//����BODYSTRUCTUREһ��ʱ�Ĺ���״̬ +typedef enum +{ + STAT_BLOCK_IDLE=0, + STAT_BLOCK_START, + STAT_BLOCK_PROC, + STAT_BLOCK_END, +}STAT_BODYSTRUCT_t; + +//multipart�����е��ֶ�˳�� +typedef enum +{ + MULTI_SUBTYPE=0, + MULTI_PARENTHESIS, //��������б����Ӹ��ֶ���������չ�ֶ� + MULTI_DISPOSITION, + MULTI_LANGUAGE, + MULTI_LOCATION, + MULTI_NUM, +}MULTI_FIELD_t; + +//��multipart�����е��ֶ�˳�� +typedef enum +{ + NOTMUL_TYPE=0, + NOTMUL_SUBTYPE, + NOTMUL_PARENTHESIS, + NOTMUL_ID, + NOTMUL_DESCR, /*5*/ + NOTMUL_ENCODE, + NOTMUL_SIZE, + NOTMUL_EVENLOP, //MESSAGE/RFC822���У��Ӹ��ֶ���������չ�ֶ� + NOTMUL_BODYSTRUCT, //MESSAGE/RFC822���� + NOTMUL_LINES, //������NOTMUL_TYPEΪ"TEXT"������ΪMESSAGE/RFC822���и��ֶΣ� + NOTMUL_MD5, + NOTMUL_DISPOSITION, /*10*/ + NOTMUL_LANGUAGE, + NOTMUL_LOCATION, + NOTMUL_NUM, +}NOTMUL_FIELD_t; + +#define IMAP_OK_CMD_LEN 30 //IMAPЭ��FETCH��Ӧ�����ij��ȣ���"B00964 OK Fetch completed" +#define IMAP_LABEL_OK_MAX_LEN 100 + + +//�ʼ������Ŵ�20��ʼ +typedef enum IMAP_CMD_STATE +{ + IMAP_CMD_ANS=20, + IMAP_CMD_FETCH_ANS, //����Ҫ���и�λ����Ӧ + IMAP_CMD_DATA_END, + IMAP_CMD_MAYBE_END, //����")\r\n"��״̬ + IMAP_CMD_NOT_END, //�ж���һ��')'�������IMAP_CMD_MAYBE_END���������Ľ��� + IMAP_CMD_DATA_CONTINUE, //���ֽڻ�ȡ�ʼ��ĺ����� + IMAP_CMD_DATA_BORDER, //������һ����Ŀ�ʼ����BODY���� + IMAP_CMD_DROP, //����һ����ſ�ʱ�����и��������ص�ҵ���֮��ҵ����DROP + IMAP_CMD_UNKNOWN, +}IMAP_CMD_STATE_t; + +//Ϊbody/bodystructure�������õĹ�ϣ�ڵ� +typedef struct __mime_item +{ + stBufCache mime_header; //���ڴ洢����MIMEͷ�� + char charset[MAIL_MAX_CHARSET_LEN]; + char filename_charset[MAIL_MAX_CHARSET_LEN]; + char *attach_filename; + char *boundary; + int filename_len; + int bound_len; + int trans_enc; //������� + int is_multi; //�Ƿ���MULTIPART�� + int thread_id; +}mime_item_t; + +char imap4_entry_fun(struct streaminfo *a_tcp, void **pme, int thread_seq,const void *raw_pkt); +void imap_free_htable_cb(void *data); +int mail_identify_imap(struct streaminfo *a_tcp, char *payload, int payload_len, int thread_seq); + +#endif diff --git a/decoders/mail/mail_decoder_mime.c b/decoders/mail/mail_decoder_mime.c new file mode 100644 index 0000000..2d638d1 --- /dev/null +++ b/decoders/mail/mail_decoder_mime.c @@ -0,0 +1,663 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include "mail_decoder_util.h" +#include "mail_decoder_codec.h" +#include "mail_decoder_mime.h" + +static void urldecode2(char *dst, const char *src) +{ + char a, b; + while (*src) { + if ((*src == '%') && + ((a = src[1]) && (b = src[2])) && + (isxdigit(a) && isxdigit(b))) { + if (a >= 'a') + a -= 'a'-'A'; + if (a >= 'A') + a -= ('A' - 10); + else + a -= '0'; + if (b >= 'a') + b -= 'a'-'A'; + if (b >= 'A') + b -= ('A' - 10); + else + b -= '0'; + *dst++ = 16*a+b; + src+=3; + } else if (*src == '+') { + *dst++ = ' '; + src++; + } else { + *dst++ = *src++; + } + } + *dst++ = '\0'; +} + +static int check_mem_size(int wantedlen, char **pmem, int *len) +{ + if(wantedlen < *len) + return 0; + + if(*pmem == NULL) + *pmem = (char *)malloc(wantedlen); + else + *pmem = (char *)realloc(*pmem, wantedlen); + *len = wantedlen; + + return 0; +} + +#ifdef __cplusplus + extern "C" + { +#endif +int decode_mime_header(const char *in, int inl, char *out, int *outl, char* charset, int max_charset_len) +{ + return mime_header_decode(in, inl, out, outl, charset, max_charset_len, NULL); +} +#ifdef __cplusplus +} +#endif + + +int mime_header_decode(const char *in, int inl, char *out, int *outl, char* charset, int max_charset_len, void *log_handle) +{ + const char *in_end=in+inl, *begin, *chset_end, *encode_end, *end; + int outsize = *outl, total_len=0; + int ret, charset_len; + + begin = (char *)mail_memmem(in, inl, "=?", 2); + if(begin == NULL) + goto out_cp; + + chset_end = (char *)memchr(begin+2, '?', in_end-begin-2); + if(chset_end == NULL) + goto out_cp; + + encode_end = (char *)memchr(chset_end+1, '?', in_end-chset_end-1); + if(encode_end == NULL) + goto out_cp; + + end = (char *)mail_memmem(encode_end+1, in_end-encode_end-1, "?=", 2); + if(end == NULL) + goto out_cp; + + charset_len = (chset_end-begin-2)>=max_charset_len?(max_charset_len-1):(chset_end-begin-2); + memcpy(charset, begin+2, charset_len); + charset[charset_len] = '\0'; + + if(*(encode_end-1) == 'B' || *(encode_end-1) == 'b') + { + if(begin - in > 0) + { + memcpy(out, in, begin-in); + total_len = begin-in; + } + + ret = Base64_DecodeBlock((const unsigned char *)(encode_end+1), end-encode_end-1, (unsigned char *)out+total_len, outsize-total_len); + if(ret < 0) + { + char buf[128]={0}; + int datalen = (end-encode_end-1)>=128?127:(end-encode_end-1); + memcpy(buf, encode_end+1, datalen); + buf[datalen] = '\0'; + goto out_cp; + } + total_len += ret; + } + else if(*(encode_end-1) == 'Q' || *(encode_end-1) == 'q') + { + if(begin - in > 0) + { + memcpy(out, in, begin-in); + total_len = begin-in; + } + + ret = QP_DecodeBlock((const unsigned char *)(encode_end+1), end-encode_end-1, (unsigned char *)out+total_len); + if(ret < 0) + { + char buf[128]={0}; + int datalen = (end-encode_end-1)>=128?127:(end-encode_end-1); + memcpy(buf, encode_end+1, datalen); + buf[datalen] = '\0'; + goto out_cp; + } + total_len += ret; + } + else + goto out_cp; + + if(in_end - end - 2 > 0) + { + outsize -= total_len; + mime_header_decode(end+2, in_end-end-2, out+total_len, &outsize, charset, max_charset_len, log_handle); + total_len += outsize; + } + + *outl = total_len; + + return 0; + +out_cp: + memcpy(out, in, inl); + *outl = inl; + return 0; +} + +int add_boundary(const char *src, int n, boundary_list **Head) +{ + boundary_list *p; + int len; + + if(src == NULL || n <= 0) + return -1; + + p = (boundary_list *)calloc(1, sizeof(boundary_list)); + if(*Head==NULL) + { + p->main_bound = BOUNDARY_TYPE_MAIN; + } + else + { + p->main_bound = BOUNDARY_TYPE_OTHER; + } + len = (n>=BOUNDARY_SIZE)?(BOUNDARY_SIZE-1):n; + memcpy(p->str, src, len); + p->str_len = len; + + p->next = *Head; + *Head = p; + + return 0; +} + +static boundary_list *get_boundary(char *src, int srclen, boundary_list *head) +{ + boundary_list *p; + + for(p=head; p!=NULL; p=p->next) + { + if(srclen != p->str_len) + continue; + + if (strncmp(src, p->str, srclen) == 0) { + return p; + } + } + return NULL; +} + +static int search_boundary(char *src, int srclen, boundary_list *head) +{ + boundary_list *p; + + for(p=head; p!=NULL; p=p->next) + { + if(srclen != p->str_len) + continue; + + if (strncmp(src, p->str, srclen) == 0) { + p->matched_count++; + return p->main_bound; + } + } + return 0; +} + +/********************************************************************* +�������ƣ�boundary_free +���ܼ�飺�ͷŽ������� +���������head:ָ���������ͷ��ָ�� +����������� +����ֵ�� �� +*********************************************************************/ +static void free_boundary( boundary_list *head) +{ + boundary_list *p = head, *q; + + while(p != NULL) + { + q = p; + p = p->next; + + free(q); + } +} + +static int get_value_th(char *temp, int len,char **ppval,int *val_len) +{ + char *temp2=NULL; + char *tp=NULL; + char *tpend=NULL; + + tp=temp; + tpend=tp+len; + while((tp[0]==' ')&&(tp<tpend)) + tp=tp+1; + + if(tp==tpend) + { + *ppval = tp; + *val_len = 0; + return 0; + } + + if(tp[0]=='"') + { + tp=tp+1; + *ppval = tp; + + temp2=(char *)memchr(tp,'"',tpend-tp); + if(temp2!=NULL) + { + *val_len = temp2-tp; + } + else + *val_len = tpend-tp; + } + else //eg. charset=us-ascii (Plain Text) + { + if(((temp2=(char *)memchr(tp,';',tpend-tp))!=NULL)||((temp2=(char *)memchr(tp,' ',tpend-tp))!=NULL)||\ + ((temp2=(char *)memchr(tp,'\r',tpend-tp))!=NULL) || ((temp2=(char *)memchr(tp,'\n',tpend-tp))!=NULL)) + *val_len = temp2-tp; + else + *val_len = tpend-tp; + + *ppval = tp; + } + + return 0; +} + +static int check_name_th(char *input, int inputlen, const char *name, char **ppval,int *val_len) +{ + char *temp=NULL; + int tmplen=strlen(name); + + //ע��memncasemem_sub128�Ե�2���Ӵ��ij������ƣ�Ϊ���ٶȣ�Ϊ�˲������ڴ� + if((temp=(char*)mesa_memncasemem(input,inputlen,name,tmplen))!=NULL)//adjust by lqy 09-01 + { + temp=temp+tmplen; + if(get_value_th(temp,inputlen-(temp-input),ppval,val_len)==0) + return 0; + } + + return -1; +} + +/********************************************************************* +�������ƣ�init_mimeinfo +���ܼ�飺��ʼ���ʼ�MIME�������ݽṹ +���������mimeinfo��ָ��MimeParse_t�ṹ��ָ���ָ�룬Ϊ������ڴ� +����������� +����ֵ�� -1:���� + 0������ +*********************************************************************/ +int init_mime_info(MimeParse_t **mimeinfo, void *log_handle) +{ + MimeParse_t *pmimeinfo; + + pmimeinfo = (MimeParse_t *)malloc(sizeof(MimeParse_t)); + memset(pmimeinfo, 0, sizeof(MimeParse_t)); + + pmimeinfo->TransferEnc = MIME_TRANSENC_UNKNOWN; + pmimeinfo->log_handle = log_handle; + + pmimeinfo->handle.length=0; //handle_init(); + pmimeinfo->line_type = MIME_LINE_NULL; + + *mimeinfo = pmimeinfo; + + return 0; +} + +void clear_mime_info(MimeParse_t *mimeinfo) +{ + free_boundary(mimeinfo->b_header); + + if(mimeinfo->filename!=NULL) + free(mimeinfo->filename); + + free(mimeinfo); +} + +void reset_mime_info(MimeParse_t * mimeinfo,int PartEnd) +{ + if(PartEnd==0) + { + free_boundary(mimeinfo->b_header); + mimeinfo->b_header = NULL; + mimeinfo->bound_comes = 0; + } + + mimeinfo->src = NULL; + mimeinfo->dst = NULL; + mimeinfo->srcLen = 0; + mimeinfo->dstSize = 0; + mimeinfo->actLen = 0; + mimeinfo->text_begin = 0; + mimeinfo->filenameLen = 0; + mimeinfo->is_attachment = 0; + if(mimeinfo->filename!=NULL) + { + free(mimeinfo->filename); + mimeinfo->filename = NULL; + } + + mimeinfo->filename_charset[0] = 0; + mimeinfo->charset[0] = 0; + + mimeinfo->TransferEnc = MIME_TRANSENC_UNKNOWN; + mimeinfo->line_type = MIME_LINE_NULL; + + mimeinfo->handle.length=0; +} + +static int detect_transenc(char * transenc, int len) +{ + while(*transenc == ' ') + { + transenc++; + len--; + } + + if(strncmp_one_word_mesa("base64", "BASE64", 6, transenc, len)) + return MIME_TRANSENC_BASE64; + if(strncmp_one_word_mesa("quoted-printable", "QUOTED-PRINTABLE", 16, transenc, len)) + return MIME_TRANSENC_QP; + + return MIME_TRANSENC_UNKNOWN; +} + +static int mime_line_identify(MimeParse_t *pInfo) +{ + if(pInfo->srcLen==0 || (pInfo->srcLen==2 && pInfo->src[0]=='\r' && pInfo->src[1]=='\n')||(pInfo->srcLen==1 && pInfo->src[0]=='\n')) + { + return MIME_LINE_NULL; + } + + if(pInfo->srcLen>2 && strncmp(pInfo->src, "--", 2) == 0) + { + int len = pInfo->srcLen; + + while(len>2 && (*(pInfo->src+len-1)=='\r' || *(pInfo->src+len-1)=='\n')) + len--; + + if(!search_boundary(pInfo->src + 2, len-2, pInfo->b_header)) + { + int type; + if(len >=4 && pInfo->src[len-1] == '-' && pInfo->src[len-2] == '-' && \ + (type=search_boundary(pInfo->src + 2, len-4, pInfo->b_header))>0) + { + if(type==BOUNDARY_TYPE_MAIN) + { + pInfo->bound_comes = 0; + pInfo->line_type = MIME_LINE_COMMENT; + } + return MIME_LINE_BOUNARY_END; + } + if(pInfo->bound_comes==0 && pInfo->b_header != NULL) + return MIME_LINE_COMMENT; + else + return MIME_LINE_CONT_BODY; + } + boundary_list *b = get_boundary(pInfo->src + 2, len-2, pInfo->b_header); + if (b && b->matched_count == 0) { + return MIME_LINE_BOUNARY_START; + } + return MIME_LINE_BOUNARY; + } + + if(pInfo->line_type == MIME_LINE_CONT_BODY || pInfo->line_type == MIME_LINE_COMMENT) + return pInfo->line_type; + + if(strncmp_one_word_mesa("content-type:", "CONTENT-TYPE:", PARTHEAD_CONTTYPE_LEN, pInfo->src, pInfo->srcLen)) + return MIME_LINE_CONT_TYPE; + if(strncmp_one_word_mesa("content-transfer-encoding:", "CONTENT-TRANSFER-ENCODING:", PARTHEAD_TRANSENC_LEN, pInfo->src, pInfo->srcLen)) + return MIME_LINE_CONT_ENC; + if(strncmp_one_word_mesa("content-disposition:", "CONTENT-DISPOSITION:", PARTHEAD_CONTENTDISPOSITION_LEN, pInfo->src, pInfo->srcLen)) + return MIME_LINE_CONT_DISP; +// if(check_str_begin(pInfo->src, pInfo->srcLen, "Content")) +// return MIME_LINE_CONT_OTHR; + + if(pInfo->bound_comes==0 && pInfo->b_header != NULL) + return MIME_LINE_COMMENT; + if(pInfo->boundary_pending) + return MIME_LINE_CONT_OTHR; + + return MIME_LINE_CONT_BODY; +} + +int mime_parse_feed(MimeParse_t *pInfo, int decode) +{ + int ret; + char *pout = NULL, *pc; + int outlen=0, pclen; + int len; + + if(pInfo->dst==NULL) + return -10; + + pInfo->actLen = 0; + + pInfo->line_type = mime_line_identify(pInfo); + switch(pInfo->line_type) + { + case MIME_LINE_ERR: + return -2; + + case MIME_LINE_NULL: + pInfo->text_begin = 1; + pInfo->boundary_pending = 0; + + if(pInfo->bound_comes==0 && pInfo->b_header != NULL) + pInfo->line_type = MIME_LINE_COMMENT; + else + pInfo->line_type = MIME_LINE_CONT_BODY; //TODO: �����г���"\r\n---anystr"��ǰ��Ŀ��б������� + break; + + case MIME_LINE_BOUNARY_START: + reset_mime_info(pInfo, 1); //set text_begin=0 + pInfo->boundary_pending = 1; + + if(pInfo->bound_comes == 0) + pInfo->bound_comes = 1; + return MIME_LINE_BOUNARY_START; + + case MIME_LINE_BOUNARY: + reset_mime_info(pInfo, 1); //set text_begin=0 + pInfo->boundary_pending = 1; + + if(pInfo->bound_comes == 0) + pInfo->bound_comes = 1; + return MIME_LINE_BOUNARY; + + case MIME_LINE_BOUNARY_END: + pInfo->text_begin = 0; //һ�����Ҫô������Ҫô���µ�BOUNARY��Ϊ��IMAP��β��')' + break; + + case MIME_LINE_CONT_TYPE: + pc = pInfo->src + PARTHEAD_CONTTYPE_LEN; + pclen = pInfo->srcLen - PARTHEAD_CONTTYPE_LEN; + + if(check_name_th(pc, pclen, PARTHEAD_CHARSET, &pout, &outlen)==0) + { + len = (outlen>=MAIL_MAX_CHARSET_LEN)?(MAIL_MAX_CHARSET_LEN-1):outlen; + memcpy(pInfo->charset, pout, len); + pInfo->charset[len] = '\0'; + } + + if(pInfo->filename != NULL) + { + free(pInfo->filename); + pInfo->filename = NULL; + pInfo->filenameLen = 0; + } + else if(check_name_th(pc, pclen, PARTHEAD_NAME, &pout, &outlen)==0) + { + //tmplenΪ0�������pInfo->filename!=NULL && pInfo->filenameLen==0, ���������д��� + if(check_mem_size(outlen+1, &pInfo->filename, &pInfo->filenameLen)) + return -3; + + mime_header_decode(pout, outlen, pInfo->filename, &pInfo->filenameLen, pInfo->filename_charset, MAIL_MAX_CHARSET_LEN, pInfo->log_handle); + pInfo->filename[pInfo->filenameLen] = '\0'; //ENDPART resetʱ���������ͷ� + } + + if(check_name_th(pc, pclen, PARTHEAD_BOUNDARY, &pout, &outlen)==0) + { + if(search_boundary(pout, outlen, pInfo->b_header)==0) + { + if(add_boundary(pout, outlen, &pInfo->b_header)) + return -4; + } + } + break; + + case MIME_LINE_CONT_DISP: + pInfo->is_attachment = 1; + if (pInfo->filename != NULL) // && strlen(pInfo->filename)>0) + { + free(pInfo->filename); + pInfo->filename = NULL; //�����ظ�����ҵ��� + pInfo->filenameLen = 0; + break; + } + + pc = pInfo->src + PARTHEAD_CONTENTDISPOSITION_LEN; + pclen = pInfo->srcLen - PARTHEAD_CONTENTDISPOSITION_LEN; + + if (check_name_th(pc, pclen, PARTHEAD_FILENAME, &pout, &outlen) == 0) + { + //tmplenΪ0�������pInfo->filename!=NULL && pInfo->filenameLen==0, ���������д��� + if (check_mem_size(outlen + 1, &pInfo->filename, &pInfo->filenameLen)) + return -5; + + mime_header_decode(pout, outlen, pInfo->filename, &pInfo->filenameLen, pInfo->filename_charset, MAIL_MAX_CHARSET_LEN, pInfo->log_handle); + pInfo->filename[pInfo->filenameLen] = '\0'; //ENDPART resetʱ���������ͷ� + } + else if (check_name_th(pc, pclen, PARTHEAD_FILENAME_EXT, &pout, &outlen) == 0) + { + // support RFC 6266, ext value, like filename*=utf-8''%e2%82%ac%20rates + const char *p_first_quote = NULL, *p_second_quote = NULL, *p_actual_value = NULL; + int actual_value_len = 0; + // define in RFC 2231.section 4, filename ext value format [charset'language'actual value] + for (int i = 0; i < outlen; i++) + { + if (pout[i] == '\'') + { + if (p_first_quote == NULL) + { + p_first_quote = (pout + i); + } + else + { + p_second_quote = (pout + i); + break; + } + } + } + // must include two single quote + if (p_first_quote == NULL || p_second_quote == NULL) + { + p_actual_value = pout; + actual_value_len = outlen; + } + else + // copy charset if possible + { + p_actual_value = (p_second_quote + 1); + actual_value_len = outlen - (p_actual_value - pout); + if (p_first_quote != pout && (p_first_quote - pout) < MAIL_MAX_CHARSET_LEN) + { + memcpy(pInfo->filename_charset, pout, (p_first_quote - pout)); + } + } + if (check_mem_size(actual_value_len + 1, &pInfo->filename, &pInfo->filenameLen)) + return -3; + memset(pInfo->filename, 0, actual_value_len + 1); + memcpy(pInfo->filename, p_actual_value, actual_value_len); + char *decode_buff = (char *)malloc(actual_value_len + 1); + urldecode2(decode_buff, pInfo->filename); + memset(pInfo->filename, 0, actual_value_len + 1); + memcpy(pInfo->filename, decode_buff, strlen(decode_buff)); + pInfo->filenameLen = strlen(decode_buff); + free(decode_buff); + } + else + { + while (pclen > 0 && (*pc == ' ' || *pc == '\t')) + { + pc++; + pclen--; + } + + if (pclen > 0 && strncmp_one_word_mesa("attachment", "ATTACHMENT", 10, pc, pclen)) + { + pInfo->filename = (char *)malloc(1); + pInfo->filenameLen = 0; + pInfo->filename[0] = '\0'; + } + } + break; + + case MIME_LINE_CONT_ENC: + pInfo->TransferEnc = detect_transenc(pInfo->src + PARTHEAD_TRANSENC_LEN, pInfo->srcLen-PARTHEAD_TRANSENC_LEN); + break; + + case MIME_LINE_CONT_OTHR: + pInfo->dst = pInfo->src; + pInfo->actLen = pInfo->srcLen; + break; + + case MIME_LINE_COMMENT: + break; + + case MIME_LINE_CONT_BODY: + if((pInfo->TransferEnc==MIME_TRANSENC_BASE64 || pInfo->TransferEnc==MIME_TRANSENC_QP) && decode!=0) + { + if(pInfo->TransferEnc==MIME_TRANSENC_BASE64) + { + ret = Base64_DecodeFeed_r_n(&pInfo->handle, (unsigned char *)pInfo->src, pInfo->srcLen, (unsigned char *)pInfo->dst, pInfo->dstSize); + if(ret < 0) + { + char buf[128]={0}; + memcpy(buf, pInfo->src, pInfo->srcLen>=128?127:pInfo->srcLen); + return ret; + } + } + else + { + ret = QP_DecodeFeed(&pInfo->handle, (unsigned char *)pInfo->src, pInfo->srcLen, (unsigned char *)pInfo->dst); + if(ret < 0) + { + return ret; + } + } + + pInfo->actLen = ret; + } + else + { + pInfo->dst = pInfo->src; + pInfo->actLen = pInfo->srcLen; + //pInfo->text_begin=1; + } + break; + + default: + break; + } + + return pInfo->line_type; +} + +void body_update_text_begin(MimeParse_t *pInfo) +{ + if(pInfo->text_begin==0 && pInfo->b_header==NULL) + pInfo->text_begin = 1; +} diff --git a/decoders/mail/mail_decoder_mime.h b/decoders/mail/mail_decoder_mime.h new file mode 100644 index 0000000..752778d --- /dev/null +++ b/decoders/mail/mail_decoder_mime.h @@ -0,0 +1,122 @@ +#ifndef H_MAIL_MIME_PARSE +#define H_MAIL_MIME_PARSE + +#include "mail_decoder_codec.h" + +#ifndef MAIL_MAX_CHARSET_LEN +#define MAIL_MAX_CHARSET_LEN 32 +#endif + +#define MIME_MODULE "[MIME_PARSE]" + +//����MIME�л�ȡ״̬ +enum +{ + MIME_LINE_ERR=-1, + MIME_LINE_NULL, + MIME_LINE_BOUNARY_START, + MIME_LINE_BOUNARY, + MIME_LINE_BOUNARY_END, + MIME_LINE_CONT_TYPE, + MIME_LINE_CONT_ENC, + MIME_LINE_CONT_DISP, + MIME_LINE_CONT_OTHR, + MIME_LINE_CONT_BODY, + MIME_LINE_COMMENT, +}; + +#define EML_LIEN_SIZE 128 + +// ����ת����������� +#define MIME_TRANSENC_UNKNOWN 0 +#define MIME_TRANSENC_BASE64 1 +#define MIME_TRANSENC_QP 2 + +// �����ַ��������� +#define MIME_CHARENC_UNKNOWN 0 +#define MIME_CHARENC_UTF7 1 +#define MIME_CHARENC_UTF8 2 + +// �����ַ������� +#define MIME_CHARSET_UNKNOWN 0 +#define MIME_CHARSET_ASCII 1 +#define MIME_CHARSET_ISO88591 2 +#define MIME_CHARSET_UNICODE 3 +#define MIME_CHARSET_GB2312 4 +#define MIME_CHARSET_BIG5 5 +#define MIME_CHARSET_UTF7 6 +#define MIME_CHARSET_UTF8 7 +#define MIME_CHARSET_GBK 8 +#define MIME_CHARSET_HZ 9 + +// multipart's header information +//#define PARTHEAD_CONTTYPE "Content-Type:" +//#define PARTHEAD_TRANSENC "Content-Transfer-Encoding:" +//#define PARTHEAD_CONTENTDISPOSITION "Content-Disposition:" +#define PARTHEAD_CHARSET "charset=" +#define PARTHEAD_NAME "name=" +#define PARTHEAD_FILENAME "filename=" +#define PARTHEAD_FILENAME_EXT "filename*=" +#define PARTHEAD_BOUNDARY "boundary=" + +#define PARTHEAD_CONTTYPE_LEN 13 +#define PARTHEAD_TRANSENC_LEN 26 +#define PARTHEAD_CONTENTDISPOSITION_LEN 20 + +#define MAIL_STRING_ALLOC_SIZE 16 + +#define BOUNDARY_SIZE 80 +#define BOUNDARY_TYPE_MAIN 1 +#define BOUNDARY_TYPE_OTHER 2 + +typedef struct _boundary_list +{ + struct _boundary_list *next; + char str[BOUNDARY_SIZE]; + int str_len; + int main_bound; + int matched_count; +} boundary_list; + + +typedef struct __MimeParse +{ + char *src; //Դ����������Ϊָ��ʹ�ã�����Ϊ������ڴ棬��Ϊ����ı���ָ + char *dst; //Ŀ�Ļ���������Ϊָ��ʹ�ã�����Ϊ������ڴ棬��Ϊ����ı���ָ + + int srcLen; + int dstSize; //Ŀ�Ļ��������д�СTODO + int actLen; //ʵ��ռ�õij��ȡ� + + int text_begin; //0:������Ҫ�����۵���; 1:���������۵��� + int line_type; //MIME������ + + int TransferEnc; // ����������� + decode_handle_t handle; + short bound_comes; //�Ƿ�����BOUNDARY���ֲ�������Ҫ���㣬��������ע���� + short boundary_pending; + + int is_attachment; + + int filenameLen; //filename�ij��� + char* filename; + + char filename_charset[MAIL_MAX_CHARSET_LEN]; //�������ַ����룬��'\0'��β + char charset[MAIL_MAX_CHARSET_LEN]; //���Ļ������ַ����룬��'\0'��β + + boundary_list * b_header; /*��ű߽�������ı�ͷָ��*/ + + void * log_handle; +} MimeParse_t; + +int init_mime_info(MimeParse_t **mimeinfo, void *log_handle); + +void reset_mime_info(MimeParse_t * mimeinfo,int PartEnd); +void clear_mime_info(MimeParse_t * mimeinfo); +int mime_parse_feed(MimeParse_t *pInfo, int decode); +void body_update_text_begin(MimeParse_t *pInfo); +int mime_header_decode(const char *in, int inl, char *out, int *outl, char* charset, int max_charset_len, void *log_handle); +int add_boundary(const char *src, int n, boundary_list **Head); + +#endif + diff --git a/decoders/mail/mail_decoder_module.c b/decoders/mail/mail_decoder_module.c new file mode 100644 index 0000000..343f792 --- /dev/null +++ b/decoders/mail/mail_decoder_module.c @@ -0,0 +1,498 @@ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <limits.h> +#include <assert.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> + +#include "stellar/packet.h" +#include "stellar/utils.h" +#include "stellar/mq.h" +#include "stellar/session.h" +#include "stellar/mail.h" + +#include "mail_decoder_util.h" +#include "mail_decoder_smtp.h" +//#include "mail_decoder_pop3.h" +//#include "mail_decoder_imap.h" +#include "mail_decoder_module.h" + +static unsigned short get_session_dest_port(struct session *sess) +{ + const struct layer *first_pkt_layer; + const struct packet *first_pkt; + int layer_count; + + first_pkt = session_get_current_packet(sess); + layer_count = packet_get_layer_count(first_pkt); + first_pkt_layer = packet_get_layer_by_idx(first_pkt, layer_count - 1); + + switch (first_pkt_layer->proto) { + case LAYER_PROTO_TCP: + return ntohs(first_pkt_layer->hdr.tcp->dest); + case LAYER_PROTO_UDP: + return ntohs(first_pkt_layer->hdr.udp->dest);; + default: + break; + } + return 0; +} + +static int is_current_packet_c2s(struct session *sess) +{ + const struct layer *first_pkt_layer, *curr_pkt_layer; + + const struct packet *first_pkt, *curr_pkt; + + first_pkt = session_get_first_packet(sess, FLOW_TYPE_C2S); + curr_pkt = session_get_current_packet(sess); + + int i = 0; + int layer_count = packet_get_layer_count(first_pkt); + + for (i = 0; i < 2 /* l3/l4 */; i++) { + first_pkt_layer = packet_get_layer_by_idx(first_pkt, layer_count - 1 -i); + curr_pkt_layer = packet_get_layer_by_idx(curr_pkt, layer_count - 1 -i); + + if (first_pkt_layer->proto != curr_pkt_layer->proto) { + return 0; + } + switch (first_pkt_layer->proto) { + case LAYER_PROTO_TCP: + if (first_pkt_layer->hdr.tcp->dest != curr_pkt_layer->hdr.tcp->dest) { + return 0; + } + break; + case LAYER_PROTO_UDP: + if (first_pkt_layer->hdr.udp->dest != curr_pkt_layer->hdr.udp->dest) { + return 0; + } + break; + case LAYER_PROTO_IPV4: + if (0 != memcmp(&first_pkt_layer->hdr.ip4->ip_dst, &curr_pkt_layer->hdr.ip4->ip_dst, sizeof(struct in_addr))) { + return 0; + } + break; + case LAYER_PROTO_IPV6: + if (0 != memcmp(&first_pkt_layer->hdr.ip6->ip6_dst, &curr_pkt_layer->hdr.ip6->ip6_dst, sizeof(struct in6_addr))) { + return 0; + } + break; + default: + return 0; + } + + } + + return 1; +} + +static int mail_subscribe_command(struct mail_decoder *mail_env, mail_command_callback_func *cb, void *arg) +{ + int topic; + struct mq_schema *schema; + + schema = module_manager_get_mq_schema(mail_env->mod_mgr_ref); + if (schema == NULL) { + return -1; + } + + topic = mq_schema_get_topic_id(schema, MAIL_COMMAND_TOPIC_NAME); + if (topic < 0) { + return -1; + } + + return mq_schema_subscribe(schema, topic, (on_msg_cb_func *)(void *)cb, arg); +} + +static int mail_subscribe_header(struct mail_decoder *mail_env, mail_header_callback_func *cb, void *arg) +{ + int topic; + struct mq_schema *schema; + + schema = module_manager_get_mq_schema(mail_env->mod_mgr_ref); + if (schema == NULL) { + return -1; + } + + topic = mq_schema_get_topic_id(schema, MAIL_HEADER_TOPIC_NAME); + if (topic < 0) { + return -1; + } + + return mq_schema_subscribe(schema, topic, (on_msg_cb_func *)(void *)cb, arg); +} + +static int mail_subscribe_body(struct mail_decoder *mail_env, mail_body_callback_func *cb, void *arg) +{ + int topic; + struct mq_schema *schema; + + schema = module_manager_get_mq_schema(mail_env->mod_mgr_ref); + if (schema == NULL) { + return -1; + } + + topic = mq_schema_get_topic_id(schema, MAIL_BODY_TOPIC_NAME); + if (topic < 0) { + return -1; + } + + return mq_schema_subscribe(schema, topic, (on_msg_cb_func *)(void *)cb, arg); +} + +static int mail_subscribe_attachment(struct mail_decoder *mail_env, mail_attachment_callback_func *cb, void *arg) +{ + int topic; + struct mq_schema *schema; + + schema = module_manager_get_mq_schema(mail_env->mod_mgr_ref); + if (schema == NULL) { + return -1; + } + + topic = mq_schema_get_topic_id(schema, MAIL_ATTACHMENT_TOPIC_NAME); + if (topic < 0) { + return -1; + } + + return mq_schema_subscribe(schema, topic, (on_msg_cb_func *)(void *)cb, arg); +} + +static int mail_subscribe_eml(struct mail_decoder *mail_env, mail_eml_callback_func *cb, void *arg) +{ + int topic; + struct mq_schema *schema; + + schema = module_manager_get_mq_schema(mail_env->mod_mgr_ref); + if (schema == NULL) { + return -1; + } + + topic = mq_schema_get_topic_id(schema, MAIL_EML_TOPIC_NAME); + if (topic < 0) { + return -1; + } + + return mq_schema_subscribe(schema, topic, (on_msg_cb_func *)(void *)cb, arg); +} + +static void mail_dispatch(int topic, void *msg, on_msg_cb_func *msg_cb, void *arg, void *dispatch_arg) +{ + struct mail_message *mail_msg; + struct mail_decoder *mail_env; + + mail_msg = (struct mail_message *)msg; + mail_env = (struct mail_decoder *)dispatch_arg; + + //char *msg_json = mail_message_to_json(mail_msg); + //printf("%s\n", msg_json); + //free(msg_json); + + if (topic == mail_env->command_topic_id) { + mail_command_callback_func *command_cb = (mail_command_callback_func *)(void *)msg_cb; + command_cb(mail_msg->sess_ref, mail_msg->mail_protocol, mail_msg->mail_seq, + mail_msg->command->cmd, (const char *)mail_msg->command->arg, mail_msg->command->arg_len, + (const char *)mail_msg->command->cmd_line, mail_msg->command->cmd_line_len, + arg); + return; + } + + if (topic == mail_env->header_topic_id) { + mail_header_callback_func *header_cb = (mail_header_callback_func *)(void *)msg_cb; + header_cb(mail_msg->sess_ref, mail_msg->mail_protocol, mail_msg->mail_seq, (const struct mail_header *)mail_msg->header, arg); + return; + } + + if (topic == mail_env->body_topic_id) { + mail_body_callback_func *body_cb = (mail_body_callback_func *)(void *)msg_cb; + body_cb(mail_msg->sess_ref, mail_msg->mail_protocol, mail_msg->mail_seq, + (const char *)mail_msg->body->body, mail_msg->body->body_len, + mail_msg->body->body_offset, mail_msg->body->is_body_finished, + arg); + return; + } + + if (topic == mail_env->attachment_topic_id) { + mail_attachment_callback_func *attachment_cb = (mail_attachment_callback_func *)(void *)msg_cb; + attachment_cb(mail_msg->sess_ref, mail_msg->mail_protocol, mail_msg->mail_seq, + (const char *)mail_msg->attachment->attachment_name, mail_msg->attachment->attachment_name_len, + (const char *)mail_msg->attachment->attachment, mail_msg->attachment->attachment_len, + mail_msg->attachment->attachment_offset, mail_msg->attachment->is_attachment_finished, + arg); + return; + } + + if (topic == mail_env->eml_topic_id) { + mail_eml_callback_func *eml_cb = (mail_eml_callback_func *)(void *)msg_cb; + eml_cb(mail_msg->sess_ref, mail_msg->mail_protocol, + (const char *)mail_msg->eml->eml, mail_msg->eml->eml_len, + mail_msg->eml->eml_offset, mail_msg->eml->is_eml_finished, + arg); + return; + } +} + +int mail_subscribe(struct mail_decoder *mail_env, + mail_command_callback_func command_cb, + mail_header_callback_func *header_cb, + mail_body_callback_func *body_cb, + mail_attachment_callback_func *attachment_cb, + mail_eml_callback_func *eml_cb, + void *arg) +{ + int ret; + + ret = mail_subscribe_command(mail_env, command_cb, arg); + if (ret < 0) { + return ret; + } + + ret = mail_subscribe_header(mail_env, header_cb, arg); + if (ret < 0) { + return ret; + } + + ret = mail_subscribe_body(mail_env, body_cb, arg); + if (ret < 0) { + return ret; + } + + ret = mail_subscribe_attachment(mail_env, attachment_cb, arg); + if (ret < 0) { + return ret; + } + + ret = mail_subscribe_eml(mail_env, eml_cb, arg); + if (ret < 0) { + return ret; + } + + return 0; +} + +static void mail_decoder_session_ctx_free(struct mail_session_ctx *session_ctx) +{ + switch (session_ctx->protocol) { + case MAIL_PROTOCOL_SMTP: + smtp_parser_free(session_ctx->smtp_parser); + break; + case MAIL_PROTOCOL_POP3: + //mail_decoder_pop3_exit(session_ctx->mail_pme); + break; + case MAIL_PROTOCOL_IMAP: + //mail_decoder_imap_exit(session_ctx->mail_pme); + break; + default: + break; + } + free(session_ctx); +} + +static struct mail_session_ctx *mail_decoder_session_ctx_new(void) +{ + struct mail_session_ctx *session_ctx; + session_ctx = (struct mail_session_ctx *)calloc(1, sizeof(struct mail_session_ctx)); + return session_ctx; +} + +//static int mail_decoder_imap_process(struct mail_decoder *env, struct mail_session_ctx *session_ctx, const char *payload, size_t payload_len, int is_c2s, int tid) +//{ +// return 0; +//} +// +//static int mail_decoder_pop3_process(struct mail_decoder *env, struct mail_session_ctx *session_ctx, const char *payload, size_t payload_len, int is_c2s, int tid) +//{ +// return 0; +//} + +static int mail_decoder_smtp_process(struct mail_decoder *env, struct mail_session_ctx *session_ctx, const char *payload, size_t payload_len, int is_c2s) +{ + char ret;; + + if (session_ctx->smtp_parser == NULL) { + session_ctx->smtp_parser = smtp_parser_new(env, is_c2s); + } + + ret = smtp_parser_entry(session_ctx->smtp_parser, session_ctx->sess_ref, payload, payload_len,is_c2s); + if (ret != 0) { + return -1; + } + + return 0; +} + +static void mail_decoder_on_tcp_payload(struct session *sess, enum session_state state, const char *payload, uint32_t payload_len, void *arg) +{ + (void)state; + int ret; + int is_packet_c2s; + struct mail_session_ctx *session_ctx; + struct mail_decoder *env = (struct mail_decoder *)arg; + + if (payload == NULL || payload_len == 0) { + return; + } + + is_packet_c2s = is_current_packet_c2s(sess); + + session_ctx = (struct mail_session_ctx *)session_get_exdata(sess, env->exdata_id); + if (session_ctx == NULL) { + session_ctx = mail_decoder_session_ctx_new(); + session_ctx->mail_env_ref = env; + session_ctx->sess_ref = sess; + session_ctx->protocol = MAIL_PROTOCOL_MAX; + session_ctx->is_droped = 0; + session_set_exdata(sess, env->exdata_id, session_ctx); + + unsigned short session_dest_port = get_session_dest_port(sess); + + switch (session_dest_port) { + case PORT_SMTP: + session_ctx->protocol = MAIL_PROTOCOL_SMTP; + break; + case PORT_POP3: + session_ctx->protocol = MAIL_PROTOCOL_POP3; + break; + case PORT_IMAP: + session_ctx->protocol = MAIL_PROTOCOL_IMAP; + break; + default: + if (smtp_identify(payload, payload_len, is_packet_c2s)) { + session_ctx->protocol = MAIL_PROTOCOL_SMTP; + break; + } + //if (pop3_identify((char *)payload, payload_len, is_packet_c2s)) { + // session_ctx->protocol = MAIL_PROTOCOL_POP3; + // break; + //} + //if (imap_identify((char *)payload, payload_len, is_packet_c2s)) { + // session_ctx->protocol = MAIL_PROTOCOL_IMAP; + // break; + //} + break; + } + } + + if (session_ctx->is_droped) { + return; + } + + switch (session_ctx->protocol) { + case MAIL_PROTOCOL_SMTP: + ret = mail_decoder_smtp_process(env, session_ctx, payload, payload_len, is_packet_c2s); + break; + case MAIL_PROTOCOL_POP3: + //ret = mail_decoder_pop3_process(decoder, session_ctx, payload, payload_len , is_packet_c2s); + break; + case MAIL_PROTOCOL_IMAP: + //ret = mail_decoder_imap_process(decoder, session_ctx, payload, payload_len , is_packet_c2s); + break; + default: + break; + } + + if (ret != 0) { + session_ctx->is_droped = 1; + } +} + +void mail_decoder_on_exdata_free(int idx, void *ex_ptr, void *arg) +{ + (void)(idx); + (void)(arg); + struct mail_session_ctx *session_ctx = (struct mail_session_ctx *)ex_ptr; + + if (session_ctx) { + mail_decoder_session_ctx_free(session_ctx); + } +} + +void mail_exit(struct module_manager *mod_mgr, struct module *mod) +{ + (void)(mod_mgr); + struct mail_decoder *mail_env; + struct mq_schema *schema; + + if (mod) { + mail_env = (struct mail_decoder *)module_get_ctx(mod); + if (mail_env) { + schema = module_manager_get_mq_schema(mod_mgr); + mq_schema_destroy_topic(schema, mail_env->command_topic_id); + mq_schema_destroy_topic(schema, mail_env->header_topic_id); + mq_schema_destroy_topic(schema, mail_env->body_topic_id); + mq_schema_destroy_topic(schema, mail_env->attachment_topic_id); + mq_schema_destroy_topic(schema, mail_env->eml_topic_id); + free(mail_env); + } + + module_free(mod); + } +} + +struct module* mail_init(struct module_manager *mod_mgr) +{ + int ret; + struct module *mod; + struct mq_schema *schema; + struct session_manager *sess_mgr; + struct mail_decoder *env; + + env = (struct mail_decoder *)calloc(1, sizeof(struct mail_decoder)); + env->mod_mgr_ref = mod_mgr; + mod = module_new(MAIL_MODULE_NAME, env); + sess_mgr = module_to_session_manager(module_manager_get_module(mod_mgr, SESSION_MANAGER_MODULE_NAME)); + schema = module_manager_get_mq_schema(mod_mgr); + + if (sess_mgr == NULL || schema == NULL) { + goto exit; + } + + ret = session_manager_subscribe_tcp_stream(sess_mgr, mail_decoder_on_tcp_payload, env); + if (ret < 0) { + goto exit; + } + + env->exdata_id = session_manager_new_session_exdata_index(sess_mgr, MAIL_EXDATA_NAME, mail_decoder_on_exdata_free, NULL); + if (env->exdata_id < 0) { + goto exit; + } + + env->command_topic_id = mq_schema_create_topic(schema, MAIL_COMMAND_TOPIC_NAME, mail_dispatch, env, mail_message_free, NULL); + if (env->command_topic_id < 0) { + goto exit; + } + env->header_topic_id = mq_schema_create_topic(schema, MAIL_HEADER_TOPIC_NAME, mail_dispatch, env, mail_message_free, NULL); + if (env->header_topic_id < 0) { + goto exit; + } + env->body_topic_id = mq_schema_create_topic(schema, MAIL_BODY_TOPIC_NAME, mail_dispatch, env, mail_message_free, NULL); + if (env->body_topic_id < 0) { + goto exit; + } + env->attachment_topic_id = mq_schema_create_topic(schema, MAIL_ATTACHMENT_TOPIC_NAME, mail_dispatch, env, mail_message_free, NULL); + if (env->attachment_topic_id < 0) { + goto exit; + } + env->eml_topic_id = mq_schema_create_topic(schema, MAIL_EML_TOPIC_NAME, mail_dispatch, env, mail_message_free, NULL); + if (env->eml_topic_id < 0) { + goto exit; + } + + return mod; +exit: + mail_exit(mod_mgr, mod); + return NULL; +} + +struct mail_decoder *module_to_mail_decoder(struct module *mod) +{ + assert(mod); + assert(strcmp(module_get_name(mod), MAIL_MODULE_NAME) == 0); + return module_get_ctx(mod); +} + + diff --git a/decoders/mail/mail_decoder_module.h b/decoders/mail/mail_decoder_module.h new file mode 100644 index 0000000..ddd4fa9 --- /dev/null +++ b/decoders/mail/mail_decoder_module.h @@ -0,0 +1,96 @@ +#ifndef __MAIL_DECODER_MODULE_H__ +#define __MAIL_DECODER_MODULE_H__ + +#include "mail_decoder_util.h" + +#define MAIL_EXDATA_NAME "MAIL_EXDATA" +#define MAIL_COMMAND_TOPIC_NAME "MAIL_COMMAND" +#define MAIL_HEADER_TOPIC_NAME "MAIL_HEADER" +#define MAIL_BODY_TOPIC_NAME "MAIL_BODY" +#define MAIL_ATTACHMENT_TOPIC_NAME "MAIL_ATTACHMENT" +#define MAIL_EML_TOPIC_NAME "MAIL_EML" + +#define PORT_SMTP 25 +#define PORT_POP3 110 +#define PORT_IMAP4 143 + +#define FLAGSTR_USRNAME "USERNAME" +#define FLAGSTR_PASSWRD "PASSWARD" +#define FLAGSTR_FROM "FROM" +#define FLAGSTR_TO "TO" +#define FLAGSTR_CC "CC" +#define FLAGSTR_BCC "BCC" +#define FLAGSTR_DATE "DATE" +#define FLAGSTR_SUB "SUBJECT" +#define FLAGSTR_CONT "CONTENT" +#define FLAGSTR_ATCHNAME "ATTACH_NAME" +#define FLAGSTR_ATCCONT "ATTACH_CONTENT" +#define FLAGSTR_OTHER "OTHER" +#define FLAGSTR_FROM_CMD "FROM_CMD" +#define FLAGSTR_TO_CMD "TO_CMD" +#define FLAGSTR_EHLO_CMD "EHLO_CMD" +#define FLAGSTR_REPLY_TO "REPLY_TO" +#define FLAGSTR_MIME_OTHER "MIME_OTHER" +#define FLAGSTR_ALL "ALL" + +#define PROFLAG_MAXNUM 8 +#define PROFLAG_MAILPASS 0x01 +#define PROFLAG_MAILSEND 0x02 +#define PROFLAG_MAILRECV 0x04 +#define PROFLAG_MAILSUB 0x08 +#define PROFLAG_MAILCONT 0x10 +#define PROFLAG_MAILOTHER 0x20 +#define PROFLAG_MAILDATE 0x40 +#define PROFLAG_MAILPENDING 0x80 +#define PROFLAG_MAILINIT 0x100 +#define PROFLAG_MAILEND 0x200 + +typedef struct __userdef_region +{ + char region_name[128]; + long long region_flag; + int region_len; +}userdef_region_t; + +struct mail_proto_tag_t +{ + char buf[8]; +}; + +typedef struct _mail_local_info +{ + unsigned short plugid; + unsigned int trans_decode_on; + unsigned int callback_per_line; + unsigned long long protocol_flag; + void * runtime_log; + userdef_region_t user_region[64]; + int user_region_num; + int proto_identify_id; +}stMailLocalInfo; + +struct mail_session_ctx { + enum MAIL_PROTOCOL protocol; + + struct smtp_parser *smtp_parser; + + int is_droped; + struct mail_decoder *mail_env_ref; + struct session *sess_ref; +}; + +struct mail_decoder { + int command_topic_id; + int header_topic_id; + int body_topic_id; + int attachment_topic_id; + int eml_topic_id; + int exdata_id; + + // tobe delete + stMailLocalInfo mail_local_info; + + struct module_manager *mod_mgr_ref; +}; + +#endif diff --git a/decoders/mail/mail_decoder_pop3.h b/decoders/mail/mail_decoder_pop3.h new file mode 100644 index 0000000..064bb6d --- /dev/null +++ b/decoders/mail/mail_decoder_pop3.h @@ -0,0 +1,35 @@ +#ifndef __MAIL_POP3_H__ +#define __MAIL_POP3_H__ + +#define POP3_STR_OK "+OK" +#define POP3_STR_ERR "-ERR" + +#define POP3MODULE "[MAIL_POP3]" + +#define POP_OK_CMD_LEN 25 +#define EML_HEADER_MAX_LEN 24 //EMLͷ��ð��֮ǰ����� + +//�ʼ������Ŵ�20��ʼ +typedef enum POP3_CMD_STATE +{ + POP3_CMD_ERR=20, + POP3_CMD_DATA_END, + POP3_CMD_USER, + POP3_CMD_PASS, + POP3_CMD_STAT, + POP3_CMD_UIDL, + POP3_CMD_RETR, + POP3_CMD_LIST, + POP3_CMD_QUIT, + POP3_CMD_RESET, + POP3_CMD_DROP, + POP3_CMD_XOAUTH2, + POP3_CMD_UNKNOWN, + POP3_CMD_OK, + POP3_CMD_STLS, +}POP3_CMD_STATE_t; + +char pop3_entry_fun(struct streaminfo *a_tcp, void **pme, int thread_seq,const void *raw_pkt); +int mail_identify_pop3(struct streaminfo *a_tcp, char *payload, int payload_len, int thread_seq); + +#endif diff --git a/decoders/mail/mail_decoder_smtp.c b/decoders/mail/mail_decoder_smtp.c new file mode 100644 index 0000000..e8a6fc1 --- /dev/null +++ b/decoders/mail/mail_decoder_smtp.c @@ -0,0 +1,573 @@ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <assert.h> + +#include "mail_decoder_util.h" +#include "mail_decoder_codec.h" +#include "mail_decoder_email.h" +#include "mail_decoder_smtp.h" + +const char* g_smtp_command[] = { + "unknown", + "ehlo", + "helo", + "auth", + "starttls", + "mail", + "send", + "soml", + "saml", + "rcpt", + "data", + "vrfy", + "expn", + "noop", + "rset", + "quit", +}; + +static enum SMTP_COMMAND smtp_str2command(const char *payload, size_t payload_len) +{ + int i; + if (payload == NULL || payload_len == 0) { + return SMTP_COMMAND_UNKNOWN; + } + for(i = 1; i < SMTP_COMMAND_MAX; i++) { + if(0 == SAFE_STRNCASECMP(payload, payload_len, g_smtp_command[i], strlen(g_smtp_command[i]))) { + break; + } + } + if (i == SMTP_COMMAND_MAX) { + return SMTP_COMMAND_UNKNOWN; + } + return (enum SMTP_COMMAND)i; +} + +static int is_smtp_cmd(const char *data, int datalen) +{ + if (SMTP_COMMAND_UNKNOWN == smtp_str2command(data, datalen)) { + return 0; + } + return 1; +} + +static int is_smtp_res(const char *data, size_t datalen) +{ + if (datalen >= strlen(SMTP_STR_220) && 0 == strncmp(data, SMTP_STR_220, strlen(SMTP_STR_220))) { + return 1; + } + return 0; +} + +static int is_wanted_line(struct smtp_parser *parser, char *a_smtp_line, int linelen, int apply_count, int *authmatchlen) +{ + enum EML_LINE_TYPE eml_line_type; + struct email_parser *email = parser->eml_parser; + + if((email->EmlAnalyseState == MAIL_STAT_INIT) || (apply_count < RSETQUIT_CMD_LEN)) + { + if(strncmp_one_word_mesa("rset", "RSET", 4, a_smtp_line, linelen)) //�������� + return SMTP_CMD_RSET; + if(strncmp_one_word_mesa("quit", "QUIT", 4, a_smtp_line, linelen)) //�˳����� + return SMTP_CMD_QUIT; + } + + if((email->EmlAnalyseState == MAIL_STAT_INIT) || (apply_count < MAIL_FROM_LEN)) + { + if(strcmp_two_word(a_smtp_line,linelen, "MAIL", 4, "FROM", 4)) + return SMTP_CMD_MAIL_FROM; + } + if(email->EmlAnalyseState == MAIL_STAT_INIT) + { + if(strcmp_two_word(a_smtp_line, linelen, "RCPT", 4, "TO", 2)) + return SMTP_CMD_RCPT_TO; + if(strncmp_one_word_mesa("ehlo", "EHLO", 4, a_smtp_line, linelen)) + { + if(email->MailInfoState==MAIL_NO_USER) + email->MailInfoState=MAIL_HAVE_USER; + return SMTP_CMD_EHLO; + } + if(strncmp_one_word_mesa("helo", "HELO", 4, a_smtp_line, linelen)) + { + if(email->MailInfoState==MAIL_NO_USER) + email->MailInfoState=MAIL_AFTER_PASS; + return SMTP_CMD_EHLO; + } + if(strncmp_one_word_mesa("data", "DATA", 4, a_smtp_line,linelen)) + return SMTP_CMD_DATA; + if(strncmp_one_word_mesa("starttls", "STARTTLS", 8, a_smtp_line,linelen)) + return SMTP_CMD_STARTTLS; + if(strcmp_two_word(a_smtp_line, linelen, "send", 4, "from", 4)) + return SMTP_CMD_MAIL_FROM; + if(strcmp_two_word(a_smtp_line,linelen, "soml", 4, "from", 4)) + return SMTP_CMD_MAIL_FROM; + if(strcmp_two_word(a_smtp_line,linelen, "saml", 4, "from", 4)) + return SMTP_CMD_MAIL_FROM; + if((*authmatchlen=strncmp_two_word_mesa("auth", "AUTH", 4, "xoauth2", "XOAUTH2", 7, a_smtp_line, linelen))!=0) + return SMTP_CMD_XOAUTH2; + } + + //if((apply_count < BDAT_CMD_LEN) && (strncmp_one_word_mesa("bdat", "BDAT", 4, a_smtp_line,linelen))) + // return SMTP_CMD_BDAT; + + if((email->EmlAnalyseState == MAIL_STAT_BODY) && ((linelen==3 && !strncmp(a_smtp_line, ".\r\n",3)) || (linelen==2 && !strncmp(a_smtp_line, ".\n",2)))) + return EML_DATA_END; + + if(email->is_drop) + return SMTP_CMD_DROP; + + eml_line_type = email_parser_parse_line(a_smtp_line, linelen, email->EmlAnalyseState); + if(eml_line_type != EML_UNKNOWN) + return eml_line_type; + + //add by lqy 060526 + if((email->EmlAnalyseState == MAIL_STAT_INIT)) + return SMTP_CMD_USER_PASS; //maybe AUTH XXXX, EHLO, HELO; ������������Ϊ����������ʼ�ͷ���� + + return SMTP_CMD_UNKNOWN; +} + +static int process_auth_plain(struct smtp_parser *parser, char * a_smtp_line,int datalen) +{ + int i, ret; + int user_flag=0, passward_flag=0; + char* point1=NULL, *point2=NULL, *point_tmp=NULL; + char* begin=NULL; + char decode[SMTP_PLAIN_MAXLEN]={0}; + struct email_parser *email = parser->eml_parser; + + begin = a_smtp_line; + + while(*begin == ' ') + { + begin++; + datalen--; + } + + while(datalen > 0 && (*(a_smtp_line + datalen -1)=='\n' || *(a_smtp_line + datalen -1)=='\r')) + datalen -= 1; + //now @decode is the BASE64 of user&pass---"AHpsdzM1NDI2MTc5MgB6bHdAMzU=" + ret = Base64_DecodeBlock((unsigned char *)begin, datalen, (unsigned char *)decode, SMTP_PLAIN_MAXLEN); + if(ret < 0) + { + char buf[128]={0}; + memcpy(buf, begin, datalen>=128?127:datalen); + return -1; + } + decode[ret] = '\0'; + + for(i=0;i<ret;i++) + { + point_tmp=decode+i; + + if((*point_tmp==0x0) && (user_flag == 0)) + { + point1 = point_tmp+1; + user_flag =1; + } + else if((*point_tmp == 0x0) && (user_flag == 1)) + { + point2 = point_tmp+1; + passward_flag=1; + break; + } + } + + if((user_flag == 1) && (passward_flag == 1)) + { + email->MailInfoState = MAIL_AFTER_PASS | MAIL_BEFORE_PASS; + + datalen = point2-point1-1; + email->plug_mailinfo.pMailInfo->username->buflen = 0; + mail_save_mail_elem(point1, datalen, email->plug_mailinfo.pMailInfo->username); + + datalen = strlen(point2); + email->plug_mailinfo.pMailInfo->password->buflen = 0; + mail_save_mail_elem(point2, datalen, email->plug_mailinfo.pMailInfo->password); + } + else + { + return -1; + } + + return SMTP_PLAIN_FLAG; +} + +static int process_user_pass(struct smtp_parser *parser, struct session *sess, char *a_smtp_line, int datalen) +{ + size_t mail_seq; + struct email_parser *email = parser->eml_parser; + + if(strncmp_one_word_mesa("auth login", "AUTH LOGIN", 10, a_smtp_line, datalen)) + { + email->MailInfoState=MAIL_BEFORE_USER; + return 0; + } + if(strncmp_one_word_mesa("auth plain", "AUTH PLAIN", SMTP_STR_PLAIN_LEN, a_smtp_line, datalen)) + { + if(email->MailInfoState!=MAIL_AUTH_PLAIN && datalen<=SMTP_STR_PLAIN_LEN+2) // sizeof(r\n)=2 + { + email->MailInfoState=MAIL_AUTH_PLAIN; + return 0; + } + + return process_auth_plain(parser, a_smtp_line+SMTP_STR_PLAIN_LEN+1,datalen-SMTP_STR_PLAIN_LEN-1); + } + + if(email->MailInfoState==MAIL_AUTH_PLAIN) + { + return process_auth_plain(parser, a_smtp_line,datalen); + } + + if(email->MailInfoState==MAIL_AFTER_PASS) + return 0; + if((email->MailInfoState==MAIL_BEFORE_USER)||(email->MailInfoState==MAIL_BEFORE_PASS)) + { + if(datalen >= MAX_MAIL_USER_LEN) + return -1; + + char cOutBuf[MAX_MAIL_USER_LEN]; + int linelen; + + while(datalen > 0 && (*(a_smtp_line + datalen -1)=='\n' || *(a_smtp_line + datalen -1)=='\r')) + datalen -= 1; + linelen = Base64_DecodeBlock((unsigned char *)a_smtp_line, datalen, (unsigned char *)cOutBuf, MAX_MAIL_USER_LEN); + if(linelen < 0) + { + char buf[128]={0}; + memcpy(buf, a_smtp_line, datalen>=128?127:datalen); + return -1; + } + + if(linelen > MAX_USER_PASS_LEN) + { + email->MailInfoState=MAIL_AFTER_PASS; + return 0; + } + + if(email->MailInfoState == MAIL_BEFORE_USER) + { + email->MailInfoState=MAIL_BEFORE_PASS; + email->plug_mailinfo.pMailInfo->username->buflen = 0; + mail_save_mail_elem(cOutBuf, linelen, email->plug_mailinfo.pMailInfo->username); + return 1; + } + else if(email->MailInfoState == MAIL_BEFORE_PASS) + { + email->MailInfoState = MAIL_AFTER_PASS; + email->plug_mailinfo.pMailInfo->password->buflen = 0; + mail_save_mail_elem(cOutBuf, linelen, email->plug_mailinfo.pMailInfo->password); + return 1; + } + } + + if((email->MailInfoState & MAIL_BEFORE_PASS) && email->plug_mailinfo.pMailInfo->username->buf != NULL) { + mail_command_update(parser->current_command, MAIL_CMD_USERNAME, + email->plug_mailinfo.pMailInfo->username->buf, email->plug_mailinfo.pMailInfo->username->buflen, + email->plug_mailinfo.pMailInfo->username->buf, email->plug_mailinfo.pMailInfo->username->buflen); + + mail_seq = email_parser_get_seq(parser->eml_parser); + mail_publish_command(parser->mail_env_ref, sess, MAIL_PROTOCOL_SMTP, mail_seq, parser->current_command); + } + if((email->MailInfoState & MAIL_AFTER_PASS) && email->plug_mailinfo.pMailInfo->password->buf != NULL) { + mail_command_update(parser->current_command, MAIL_CMD_PASSWORD, + email->plug_mailinfo.pMailInfo->password->buf, email->plug_mailinfo.pMailInfo->password->buflen, + email->plug_mailinfo.pMailInfo->password->buf, email->plug_mailinfo.pMailInfo->password->buflen); + + mail_seq = email_parser_get_seq(parser->eml_parser); + mail_publish_command(parser->mail_env_ref, sess, MAIL_PROTOCOL_SMTP, mail_seq, parser->current_command); + } + + return 0; +} + +int process_oauth2(struct smtp_parser *parser, struct session *sess, char *cmddata, int datalen) +{ + char *p, decode_buf[2048], username[128]; + int decoded_len, namelen=0; + size_t mail_seq; + struct email_parser *email = parser->eml_parser; + + if((decoded_len=Base64_DecodeBlock((unsigned char*)cmddata, datalen, (unsigned char*)decode_buf, 2048)) < 0) + { + return 0; + } + if(!strncmp_one_word_mesa("user=", "USER=", 5, decode_buf, decoded_len)) + { + return 0; + } + p=decode_buf; p += 5; decoded_len-=5; + while(decoded_len>0 && namelen<128 && *p!=0x1) + { + username[namelen++] = *p; + p++; decoded_len--; + } + + email->plug_mailinfo.pMailInfo->username->buflen = 0; + mail_save_mail_elem(username, namelen, parser->eml_parser->plug_mailinfo.pMailInfo->username); + + mail_command_update(parser->current_command, MAIL_CMD_USERNAME, + email->plug_mailinfo.pMailInfo->username->buf, email->plug_mailinfo.pMailInfo->username->buflen, + email->plug_mailinfo.pMailInfo->username->buf, email->plug_mailinfo.pMailInfo->username->buflen); + + mail_seq = email_parser_get_seq(parser->eml_parser); + mail_publish_command(parser->mail_env_ref, sess, MAIL_PROTOCOL_SMTP, mail_seq, parser->current_command); + + return 0; +} + +int process_ehlo(struct smtp_parser *parser, struct session *sess, const char *line, int len) +{ + const char *line_start; + const char *arg_start; + size_t line_len; + size_t arg_len; + size_t mail_seq; + + while(len > 0 && (*(line + len -1)=='\n' || *(line + len -1)=='\r')) { + len -= 1; + } + line_start = line; + line_len = len; + + len -= strlen("ehlo "); + line += strlen("echo "); + if(len <= 0) { + return -1; + } + arg_start = line; + arg_len = len; + + mail_command_update(parser->current_command, MAIL_CMD_EHLO, arg_start, arg_len, line_start, line_len); + + mail_seq = email_parser_get_seq(parser->eml_parser); + mail_publish_command(parser->mail_env_ref, sess, MAIL_PROTOCOL_SMTP, mail_seq, parser->current_command); + return 0; +} + +int process_mail_from(struct smtp_parser *parser, struct session *sess, char *line, int len) +{ + int ret; + const char *line_start; + const char *arg_start; + size_t line_len; + size_t arg_len; + size_t mail_seq; + + while(len > 0 && (*(line + len -1)=='\n' || *(line + len -1)=='\r')) { + len -= 1; + } + line_start = line; + line_len = len; + + len -= strlen("mail from:"); + line += strlen("mail from:"); + if(len <= 0) { + return -1; + } + parser->eml_parser->plug_mailinfo.pMailInfo->sendaddr->buflen = 0; + ret = mail_get_mailaddr(parser->eml_parser->plug_mailinfo.pMailInfo->sendaddr, line, len); + if(ret < 0) { + return -1; + } + arg_start = parser->eml_parser->plug_mailinfo.pMailInfo->sendaddr->buf; + arg_len = parser->eml_parser->plug_mailinfo.pMailInfo->sendaddr->buflen; + + mail_command_update(parser->current_command, MAIL_CMD_MAIL_FROM, arg_start, arg_len, line_start, line_len); + + mail_seq = email_parser_get_seq(parser->eml_parser); + mail_publish_command(parser->mail_env_ref, sess, MAIL_PROTOCOL_SMTP, mail_seq, parser->current_command); + + return 0; +} + +int process_rcpt_to(struct smtp_parser *parser, struct session *sess, char *line, int len) +{ + int ret; + const char *line_start; + const char *arg_start; + size_t line_len; + size_t arg_len; + size_t mail_seq; + + while(len > 0 && (*(line + len -1)=='\n' || *(line + len -1)=='\r')) { + len -= 1; + } + line_start = line; + line_len = len; + + len -= strlen("rcpt to:"); + line += strlen("rcpt to:"); + if(len <= 0) { + return -1; + } + + parser->eml_parser->plug_mailinfo.pMailInfo->recvaddr->buflen = 0; // clear recvaddr + ret = mail_get_mailaddr(parser->eml_parser->plug_mailinfo.pMailInfo->recvaddr, line, len); + if(ret < 0) { + return -1; + } + arg_start = parser->eml_parser->plug_mailinfo.pMailInfo->recvaddr->buf; + arg_len = parser->eml_parser->plug_mailinfo.pMailInfo->recvaddr->buflen; + + mail_command_update(parser->current_command, MAIL_CMD_RCPT_TO, arg_start, arg_len, line_start, line_len); + + mail_seq = email_parser_get_seq(parser->eml_parser); + mail_publish_command(parser->mail_env_ref, sess, MAIL_PROTOCOL_SMTP, mail_seq, parser->current_command); + return 0; +} + +int process_starttls(struct smtp_parser *parser, struct session *sess, char *line, int len) +{ + const char *line_start; + size_t line_len; + size_t mail_seq; + + while(len > 0 && (*(line + len -1)=='\n' || *(line + len -1)=='\r')) { + len -= 1; + } + line_start = line; + line_len = len; + + mail_command_update(parser->current_command, MAIL_CMD_STARTTLS, NULL, 0, line_start, line_len); + + mail_seq = email_parser_get_seq(parser->eml_parser); + mail_publish_command(parser->mail_env_ref, sess, MAIL_PROTOCOL_SMTP, mail_seq, parser->current_command); + return 0; +} + +int smtp_identify(const char *payload, size_t payload_len, int is_c2s) +{ + if (payload == NULL || payload_len < 4) { + return 0; + } + + if (is_c2s) { + if (is_smtp_cmd(payload, payload_len)) { + return 1; + } + } else { + if (is_smtp_res(payload, payload_len)) { + return 1; + } + } + return 0; +} + +int smtp_parser_entry(struct smtp_parser *parser, struct session *sess, const char *payload, size_t payload_len, int is_c2s) +{ + int ret; + int needfolding=0; + int line_status = MAIL_FOLD_LINE_START; + char *output_line = NULL; + int outputlen=0, matchlen; + struct email_parser *email = parser->eml_parser; + + if (!is_c2s) { + return 0; + } + + while(1) { + if(email->EmlAnalyseState == MAIL_STAT_HEADER || (email->EmlAnalyseState == MAIL_STAT_BODY && email->mimeinfo->text_begin==0)) + needfolding=1; + else + needfolding=0; + + line_status = email_parser_get_tcpdata(email, payload, payload_len, needfolding, &output_line, &outputlen); + if(line_status == MAIL_INPUT_END) { + break; + } + if(line_status == MAIL_GETLINE_ERR) { + return -1; + } + + email->pDataLineBuf.len = 0; + + line_status = is_wanted_line(parser, output_line, outputlen, payload_len, &matchlen); + + switch(line_status) { + case SMTP_CMD_EHLO: + process_ehlo(parser, sess, output_line, outputlen); + break; + case SMTP_CMD_USER_PASS: + if(email->pending_state) { + email->pending_state = 0; + } + process_user_pass(parser, sess, output_line,outputlen); + break; + case SMTP_CMD_XOAUTH2: + process_oauth2(parser, sess, output_line+matchlen, outputlen-matchlen); + break; + case SMTP_CMD_MAIL_FROM: + if(email->pending_state) { + email->pending_state = 0; + } + email->MailInfoState=MAIL_GET_FROM; + process_mail_from(parser, sess, output_line, outputlen); + break; + case SMTP_CMD_RCPT_TO: + if(email->pending_state) { + email->pending_state = 0; + } + email->MailInfoState = MAIL_GET_TO; + process_rcpt_to(parser, sess, output_line, outputlen); + break; + case SMTP_CMD_DATA: + if(email->pending_state) { + email->pending_state = 0; + } + email->EmlAnalyseState = MAIL_STAT_HEADER; + break; + case SMTP_CMD_BDAT: + case SMTP_CMD_UNKNOWN: + case SMTP_CMD_DROP: + break; + case SMTP_CMD_STARTTLS: + process_starttls(parser, sess, output_line, strlen("starttls")); + return -1; + case SMTP_CMD_RSET: + case SMTP_CMD_QUIT: + case EML_DATA_END: + if(email->pending_state == 0) { + ret = email_parser_entry(parser->eml_parser, sess, output_line, outputlen, EML_DATA_END); + if (ret != 0) { + return -1; + } + } + break; + default: + if(email->pending_state) { + email->pending_state = 0; + } + ret = email_parser_entry(parser->eml_parser, sess, output_line, outputlen, line_status); + if (ret != 0) { + return -1; + } + break; + } + } + email->iDataPointer = 0; + + return 0; +} + +void smtp_parser_free(struct smtp_parser *parser) +{ + if (parser->current_command) { + mail_command_free(parser->current_command); + } + email_parser_free(parser->eml_parser); + free(parser); +} + +struct smtp_parser *smtp_parser_new(struct mail_decoder *env, int is_c2s) +{ + struct smtp_parser *parser = (struct smtp_parser *)calloc(1, sizeof(struct smtp_parser)); + parser->mail_env_ref = env; + parser->current_command = mail_command_new(); + parser->eml_parser = email_parser_new(env, MAIL_PROTOCOL_SMTP, is_c2s); + return parser; +} + + diff --git a/decoders/mail/mail_decoder_smtp.h b/decoders/mail/mail_decoder_smtp.h new file mode 100644 index 0000000..7d3b18f --- /dev/null +++ b/decoders/mail/mail_decoder_smtp.h @@ -0,0 +1,67 @@ +#ifndef __MAIL_SMTP_H__ +#define __MAIL_SMTP_H__ + +#include "stellar/session.h" +#include "mail_decoder_email.h" + +#define SMTP_STR_220 "220" +#define SMTP_STR_HELO "HELO " +#define SMTP_STR_EHLO "EHLO " +#define SMTP_STR_PLAIN_LEN 10 +#define SMTP_PLAIN_MAXLEN 1024 +#define SMTP_PLAIN_FLAG 100 + +#define MAIL_FROM_LEN 120 +#define RSETQUIT_CMD_LEN 20 +#define BDAT_CMD_LEN 50 +#define MAX_MAIL_USER_LEN 512 + +enum SMTP_COMMAND { + SMTP_COMMAND_UNKNOWN, + SMTP_COMMAND_EHLO, + SMTP_COMMAND_HELO, + SMTP_COMMAND_AUTH, + SMTP_COMMAND_STARTTLS, + SMTP_COMMAND_MAIL, + SMTP_COMMAND_SEND, + SMTP_COMMAND_SOML, + SMTP_COMMAND_SAML, + SMTP_COMMAND_RCPT, + SMTP_COMMAND_DATA, + SMTP_COMMAND_VRFY, + SMTP_COMMAND_EXPN, + SMTP_COMMAND_NOOP, + SMTP_COMMAND_RSET, + SMTP_COMMAND_QUIT, + SMTP_COMMAND_MAX, +}; + +typedef enum SMTP_CMD_STATE +{ + SMTP_CMD_EHLO=20, + SMTP_CMD_AUTH, + SMTP_CMD_USER_PASS, + SMTP_CMD_MAIL_FROM, + SMTP_CMD_RCPT_TO, + SMTP_CMD_DATA, + SMTP_CMD_RSET, + SMTP_CMD_BDAT, + SMTP_CMD_QUIT, + SMTP_CMD_DROP, + SMTP_CMD_XOAUTH2, + SMTP_CMD_UNKNOWN, + SMTP_CMD_STARTTLS, +}SMTP_CMD_STATE_t; + +struct smtp_parser { + struct mail_command *current_command; + struct email_parser *eml_parser; + struct mail_decoder *mail_env_ref; +}; + +int smtp_identify(const char *payload, size_t payload_len, int is_c2s); +int smtp_parser_entry(struct smtp_parser *parser, struct session *sess, const char *payload, size_t payload_len, int is_c2s); +void smtp_parser_free(struct smtp_parser *parser); +struct smtp_parser * smtp_parser_new(struct mail_decoder *env, int is_c2s); + +#endif diff --git a/decoders/mail/mail_decoder_util.c b/decoders/mail/mail_decoder_util.c new file mode 100644 index 0000000..1e7781d --- /dev/null +++ b/decoders/mail/mail_decoder_util.c @@ -0,0 +1,568 @@ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <arpa/inet.h> +#include <ctype.h> +#include <sys/time.h> + +#include "mail_decoder_util.h" + +int buf_cache_check_size(stBufCache *pdstBuf, int wantedlen) +{ + int ret=0, needlen, block_num=0; + + if(pdstBuf->max_len > wantedlen + pdstBuf->len) + return 0; + + needlen = wantedlen + pdstBuf->len - pdstBuf->max_len; + block_num = needlen/REALLOC_BLOCK_SIZE; + if(needlen%REALLOC_BLOCK_SIZE) + block_num += 1; + + pdstBuf->max_len += block_num*REALLOC_BLOCK_SIZE; + + if(pdstBuf->max_len > MAX_MALLOC_SIZE) + { + pdstBuf->max_len -= block_num*REALLOC_BLOCK_SIZE; + return -1; + } + + if(pdstBuf->buf == NULL) + { + pdstBuf->buf = (char *)malloc(pdstBuf->max_len); + } + else + { + pdstBuf->buf = (char *)realloc(pdstBuf->buf, pdstBuf->max_len); + ret = 1; + } + + return ret; +} + +int buf_elem_check_size(stMailElem *pdstBuf, int wantedlen) +{ + int needlen, block_num=0; + + if(pdstBuf->max_len > wantedlen + pdstBuf->buflen) + return 0; + + needlen = wantedlen + pdstBuf->buflen + 1 - pdstBuf->max_len; // +1 for '\0' + block_num = needlen/BUF_ELEM_BLOCK; + if(needlen%BUF_ELEM_BLOCK) + block_num += 1; + + pdstBuf->max_len += block_num*BUF_ELEM_BLOCK; + + if(pdstBuf->buf == NULL) + { + pdstBuf->buf = (char *)malloc(pdstBuf->max_len); + } + else + { + pdstBuf->buf = (char *)realloc(pdstBuf->buf, pdstBuf->max_len); + } + + return 0; +} + +int mail_save_original_data(stBufCache *pbuf, const char *data, int datalen) +{ + if(buf_cache_check_size(pbuf, datalen) < 0) + { + return -1; + } + + memcpy((char *)pbuf->buf + pbuf->len, data, datalen); + pbuf->len += datalen; + + return 0; +} + +int mail_save_mail_elem(char *srcdata, int datalen, stMailElem *pelem) +{ + if(buf_elem_check_size(pelem, datalen)) + return -1; + + memcpy(pelem->buf+pelem->buflen, srcdata, datalen); + pelem->buflen += datalen; + pelem->buf[pelem->buflen] = '\0'; + + return 0; +} + +static int mail_get_only_mailaddr(char *srcstr,int srclen,char **addrbegin,int *addrlen) +{ + char *mailbegin=NULL, *mailend=NULL, *mailflag=NULL; + char *srcend; + + if(srclen<=0 || srcstr==NULL) + return -1; + srcend = srcstr + srclen; + + //add by lqy 20070529 + //������ִ������ݺܳ������Ƕ�û��<,Ҫ�����ݽ���ȫ��ɨ�裬 + //��Ϊ�ʼ���ַ��Ϣ��Ӧ�úܳ���ֻɨ��ǰ128���Ϳ����жϳ���û��< + if(srclen>128) + mailflag=(char *)memchr((void *)srcstr,'<',128); + else + mailflag=(char *)memchr((void *)srcstr,'<',srclen); + + if(mailflag!=NULL) + { + mailbegin = mailflag+1; + while(mailbegin<srcend && (*mailbegin==' ' || *mailbegin=='\t' ||*mailbegin=='<')) + mailbegin++; + + mailend = (char *)memchr((void *)mailbegin, '>', srcend-mailbegin+1); + if(mailend == NULL) + { + return -2; + } + if((mailend-mailbegin)>0 && memchr((void *)mailbegin, '@', mailend-mailbegin)!=NULL) + { + *addrbegin=mailbegin; + *addrlen=(int)(mailend-mailbegin); + return (mailend-srcstr); + } + else + { + //char p[128]={0}; + //memcpy(p, mailflag, (mailend-mailflag+1)>=128?127:(mailend-mailflag+1)); + //MESA_HANDLE_RUNTIME_LOG(g_mail_localinfo.runtime_log,RLOG_LV_INFO, MAIL_GLOBALMODULE, "mail_get_only_mailaddr,end unnormal new intput %s, %s", p, printaddr(&g_mail_localinfo.a_tcp->addr, 0)); + return -3; + } + } + else + { + mailflag=srcstr; + while(mailflag<srcend && (*mailflag)!='@') + { + mailflag++; + } + if(((*mailflag)!='@')||(mailflag==srcstr)) + { + return -2; + } + + mailbegin=mailflag-1; + while(mailbegin>srcstr && *mailbegin!=' ' && *mailbegin!='\t' && *mailbegin!=',' && *mailbegin!=';') + { + mailbegin--; + } + if(*mailbegin==' ' || *mailbegin=='\t' || *mailbegin==',' || *mailbegin==';') + mailbegin++; + + mailend=mailflag+1; + while(mailend<srcend && *mailend!=' ' && *mailbegin!='\t' && *mailend!=',' && *mailend!=';') + { + mailend++; + } + + if(mailend-mailbegin<3) + return -3; + + *addrbegin=mailbegin; + *addrlen=(int)(mailend-mailbegin); + } + return (mailend-srcstr); +} + +int mail_get_mailaddr(stMailElem *pdstBuf, char *srcstr, int datalen) +{ + int ret=0; + char *addrbuf=NULL; + int addrlen=0; + + if(pdstBuf==NULL || srcstr==NULL || datalen < 3) + return -5; + + while(datalen>0) + { + ret=mail_get_only_mailaddr(srcstr, datalen, &addrbuf, &addrlen); + if(ret<0) + break; + + if(buf_elem_check_size(pdstBuf, addrlen+2) < 0) + return -6; + + pdstBuf->buf[pdstBuf->buflen] = '<'; + pdstBuf->buflen += 1; + memcpy(pdstBuf->buf + pdstBuf->buflen, addrbuf, addrlen); + pdstBuf->buflen += addrlen; + pdstBuf->buf[pdstBuf->buflen] = '>'; + pdstBuf->buflen += 1; + + srcstr += ret; + datalen -= ret; + } + + if(pdstBuf->buf == NULL) + return -7; + + pdstBuf->buf[pdstBuf->buflen] = '\0'; + + return 0; +} + +char* mail_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 mail_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 = mail_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 = mail_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 = mail_strntrim_sp((char*)part_start, &part_len); + out[i].iov_len = part_len; + + return n_out; +} + +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; +} + +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; +} + +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; +} + + diff --git a/decoders/mail/mail_decoder_util.h b/decoders/mail/mail_decoder_util.h new file mode 100644 index 0000000..23f70ab --- /dev/null +++ b/decoders/mail/mail_decoder_util.h @@ -0,0 +1,61 @@ +#ifndef __MAIL_DECODER_UTIL_H__ +#define __MAIL_DECODER_UTIL_H__ + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <sys/uio.h> +#include "stellar/mail.h" +#include "cJSON.h" + +#define SAFE_STRNCASECMP(s1, s1_len, s2, s2_len) ((s1_len) >= (s2_len) ? strncasecmp(s1, s2, s2_len) : -1) +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#define PORT_SMTP 25 +#define PORT_POP3 110 +#define PORT_IMAP 143 + +#define MAX_MAIL_USER_LEN 512 +#define MAX_ORDER_LINE_SIZE 2048 +#define MAIL_LINE_MAX_LEN (20*1024) +#define MAX_USER_PASS_LEN 50 + +#define MAX_MALLOC_SIZE (64*1024) +#define REALLOC_BLOCK_SIZE 1024 +#define BUF_ELEM_BLOCK 128 +#define MAIL_MAX_CHARSET_LEN 32 +#define MAIL_ELEM_NUM 16 + +typedef struct _mail_elem_info +{ + int buflen; + int max_len; + char* buf; +}stMailElem; + +typedef struct _buf_cache +{ + void *buf; + int max_len; + int len; +}stBufCache; + +int buf_elem_check_size(stMailElem *pdstBuf, int wantedlen); +int buf_cache_check_size(stBufCache *pbuf, int wantedlen); +int mail_save_original_data(stBufCache *pbuf, const char *data, int datalen); +int mail_save_mail_elem(char *srcdata, int datalen, stMailElem *pelem); +int mail_get_mailaddr(stMailElem *pdstBuf,char *srcstr,int datalen); +int mail_strnsplit(struct iovec *out, size_t n_out, char delimiter, const char *data, size_t data_len); +int strncasecmp_one_word_mesa(const char *str1, size_t len1, const char *str2, size_t len2); +int strcmp_one_word_mesa(const char *s1_lowercase, const char *s1_uppercase, size_t len1, const char *s2, size_t len2); +int strncmp_one_word_mesa(const char *s1_lowercase, const char *s1_uppercase, size_t len1, const char *s2, size_t len2); +int strcmp_one_word_mesa_equal_len(const char *s1_lowercase, const char *s1_uppercase, const char *s2, size_t len); +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 strcmp_two_word(char *srcdata,int datalen, const char *first, int flen, const char *second, int slen); +const void *mail_memmem(const void *start, unsigned int s_len, const void *find, unsigned int f_len); +char *mesa_memncasemem(const char *haystack, size_t haystacklen,const char *needle, size_t needlelen); + +#endif diff --git a/decoders/mail/mail_imap.c b/decoders/mail/mail_imap.c new file mode 100644 index 0000000..62b7c56 --- /dev/null +++ b/decoders/mail/mail_imap.c @@ -0,0 +1,1440 @@ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/time.h> +#include <assert.h> + +#include <MESA/stream.h> +#include <MESA/MESA_handle_logger.h> +#include <MESA/MESA_list_queue.h> +#include <MESA/field_stat2.h> + +#include "mem_common.h" +#include "mail_entry.h" +#include "mail_imap4.h" +#include "mail_global.h" +#include "mail_analyze.h" +#include "mime_parse.h" +#include "mail.h" + +#include "base64.h" + +extern stMailLocalInfo g_mail_localinfo; + +static void imap_free_node(void *data) +{ + mime_item_t *pitem = (mime_item_t *)data; + + if(pitem!=NULL) + { + if(pitem->mime_header.buf != NULL) + dictator_free(pitem->thread_id, pitem->mime_header.buf); + if(pitem->attach_filename != NULL) + dictator_free(pitem->thread_id, pitem->attach_filename); + if(pitem->boundary != NULL) + dictator_free(pitem->thread_id, pitem->boundary); + dictator_free(pitem->thread_id, pitem); + } +} + +void imap_free_htable_cb(void *data) +{ + imap_free_node(data); + + if(g_mail_localinfo.stat_trig) + { + FS_operate(g_mail_localinfo.fsstat_handle, g_mail_localinfo.stat_id[STAT_ID_HTABLE_NUM], 0, FS_OP_ADD, -1); + } +} + +/********************************************************************* +�������ƣ�get_value_parenthesis +���ܼ�飺�Ӳ�������б���ȡ����Ӧ������ֵ +���������name1/name2���ܵı��� +���������out:������ֵ���ַ�����ʼָ�룻outl:�ַ������� +����ֵ��1-ȡ���˱���ֵ��0-δ�ҵ� +*********************************************************************/ +static int get_value_parenthesis(const char *ps, const char *p_end, const char *name1, int len1, const char *name2, int len2, const char **out, int *outl) +{ + const char *pe; + + if((ps = mesa_memncasemem(ps, p_end-ps, name1, len1)) != NULL) + { + ps += len1; + } + else if((ps = mesa_memncasemem(ps, p_end-ps, name2, len2)) != NULL) + { + ps += len2; + } + else + { + return 0; + } + + while(ps<p_end && *ps==' ') + ps++; + + if(*ps=='"') + { + pe = ps+1; + while(pe<p_end && *pe != '"') + pe++; + if(pe == p_end) + return 0; + pe++; + } + else + { + pe = ps; + while(pe<p_end && *pe!=' ') + pe++; + } + + *out = ps; + *outl = pe-ps; + return 1; +} + +/********************************************************************* +�������ƣ�look_for_parenthesis_end +���ܼ�飺����һ��Բ���ŵĽ���λ�ã����벻����1����Բ���ţ� +���������p��������ʼ������'('�ַ���p_end���������(����)�� +���������end������λ��(��������)�� +����ֵ��NULL-����ʧ�ܣ�����-����λ�� +*********************************************************************/ +static const char *look_for_parenthesis_end(const char *p, const char *p_end) +{ + int complete=1; //��Բ�����ڵ��ô����Թ� + + while(p<p_end) + { + if(*p == '"') + { + p = (const char *)memchr(p+1, '"', p_end-p-1); + if(p==NULL) + return NULL; + } + else if(*p == ')') + { + complete--; + } + else if(*p == '(') + { + complete++; + } + if(complete==0) + { + return p; + } + p++; + } + + return NULL; +} + +/********************************************************************* +�������ƣ�look_for_field_end +���ܼ�飺����һ���ַ�������ʼλ�ã����ܴ�"Ҳ���ܲ����� +���������p��������ʼ��p_end���������(����)�� +���������end������λ��(����)�� +����ֵ��NULL-����ʧ�ܣ�����-�ַ�����ʼλ�� +*********************************************************************/ +static const char *look_for_string_end(const char *p, const char *p_end, const char **end) +{ + const char *ps; + + if(*p == '"') + { + ps=p+1; + p = (const char *)memchr(ps, '"', p_end-ps); + if(p==NULL) + return NULL; + } + else + { + ps = p; + p = (const char *)memchr(ps, ' ', p_end-ps); + if(p==NULL) + return NULL; + } + *end = p; + + return ps; +} + +/********************************************************************* +�������ƣ�parse_not_multipart_line +���ܼ�飺����һ��multipart��ͷ��������Ӧ�Ľ��д��mime_item_t�ṹ�� +��������� +��������� +����ֵ��0-������-1-ʧ�� +*********************************************************************/ +static int parse_multipart_line(mime_item_t *pitem, const char *line, int linelen) +{ + int i, len; + const char *p=line, *p_end=line+linelen, *ps; + + for(i=MULTI_SUBTYPE; i<=MULTI_PARENTHESIS&&(p<p_end); i++) + { + while(*p==' ') + p++; + + switch(i) + { + case MULTI_SUBTYPE: + if((ps = look_for_string_end(p, p_end, &p)) == NULL) + { + return -1; + } +#ifdef DBG_FULL + save_original_data(&pitem->mime_header, "\r\nContent-Type:multipart/", 25, pitem->thread_id); +#else + save_original_data(&pitem->mime_header, "Content-Type:multipart/", 23, pitem->thread_id); +#endif + save_original_data(&pitem->mime_header, ps, p-ps, pitem->thread_id); + p++; + break; + + case MULTI_PARENTHESIS: + if(*p != '(') //û�в�������б��������IJ������ˣ�Ҳ���ܺ���û����չ�ֶ� + { + p = p_end; + break; + } + ps = p+1; + if((p=look_for_parenthesis_end(ps, p_end))==NULL || *p!=')') + { + MESA_HANDLE_RUNTIME_LOG(g_mail_localinfo.runtime_log,RLOG_LV_FATAL, MAILIMAP4_MODULE, "look_for_parenthesis_end error, input not complete()."); + break; + } + if(get_value_parenthesis(ps, p, "\"boundary\" ", 11, "boundary ", 9, &ps, &len)) + { + save_original_data(&pitem->mime_header, ";boundary=", 10, pitem->thread_id); + save_original_data(&pitem->mime_header, ps, len, pitem->thread_id); + + if(*ps == '"') + { + ps++; + len-=2; + } + pitem->boundary = (char *)dictator_malloc(pitem->thread_id, len+1); + memcpy(pitem->boundary, ps, len); + pitem->boundary[len] = '\0'; + pitem->bound_len = len; + } + p++; + break; + + case MULTI_DISPOSITION: + case MULTI_LANGUAGE: + case MULTI_LOCATION: + break; + default: return -1; + } + } + + save_original_data(&pitem->mime_header, "\r\n\r\n", 4, pitem->thread_id); //MIMEͷ�����ʼ�����֮����Ҫ�п��� + return 0; +} + +/********************************************************************* +�������ƣ�parse_not_multipart_line +���ܼ�飺����һ�з�multipart������Ӧ�Ľ��д��mime_item_t�ṹ�� +��������� +��������� +����ֵ��0-������-1-ʧ�� +*********************************************************************/ +static int parse_not_multipart_line(mime_item_t *pitem, const char *line, int linelen, int is_extend) +{ + int i, len, type=CONT_TYPE_OTHER; + const char *p=line, *p_end=line+linelen, *ps; + + for(i=NOTMUL_TYPE; i<=NOTMUL_DISPOSITION&&(p<p_end); i++) + { + while(*p==' ') + p++; + + switch(i) + { + case NOTMUL_TYPE: + if((ps = look_for_string_end(p, p_end, &p)) == NULL) + { + return -1; + } +#ifdef DBG_FULL + save_original_data(&pitem->mime_header, "\r\nContent-Type:", 15, pitem->thread_id); +#else + save_original_data(&pitem->mime_header, "Content-Type:", 13, pitem->thread_id); +#endif + save_original_data(&pitem->mime_header, ps, p-ps, pitem->thread_id); + save_original_data(&pitem->mime_header, "/", 1, pitem->thread_id); + if(is_extend) + { + if(strcmp_one_word_mesa("text", "TEXT", 4, ps, p-ps)) + type = CONT_TYPE_TEXT; + else if(strcmp_one_word_mesa("message", "MESSAGE", 7, ps, p-ps)) + type = CONT_TYPE_MESSAGE; + } + p++; + break; + + case NOTMUL_SUBTYPE: + if((ps = look_for_string_end(p, p_end, &p)) == NULL) + { + return -1; + } + save_original_data(&pitem->mime_header, ps, p-ps, pitem->thread_id); + if(type==CONT_TYPE_MESSAGE && strcmp_one_word_mesa("rfc822", "RFC822", 6, ps, p-ps)) + { + type = CONT_TYPE_RFC822; + } + p++; + break; + + case NOTMUL_PARENTHESIS: + if(*p != '(') //û�в�������б�����������������һ���ֶ� + { + p = (const char*)memchr(p, ' ', p_end-p); + if(p==NULL) + p=p_end; + break; + } + ps = p+1; + if((p=look_for_parenthesis_end(ps, p_end))==NULL || *p!=')') + { + MESA_HANDLE_RUNTIME_LOG(g_mail_localinfo.runtime_log,RLOG_LV_FATAL, MAILIMAP4_MODULE, "look_for_parenthesis_end error, input not complete()."); + i=NOTMUL_NUM; + break; + } + + if(get_value_parenthesis(ps, p, "\"charset\" ", 10, "charset ", 8, &ps, &len)) + { + save_original_data(&pitem->mime_header, ";charset=", 9, pitem->thread_id); + save_original_data(&pitem->mime_header, ps, len, pitem->thread_id); + + if(*ps == '"') + { + ps++; + len-=2; + } + if(len >= MAIL_MAX_CHARSET_LEN) + { + len = MAIL_MAX_CHARSET_LEN - 1; + } + memcpy(pitem->charset, ps, len); + pitem->charset[len] = '\0'; + } + if(get_value_parenthesis(ps, p, "\"name\" ", 7, "name ", 5, &ps, &len)) //���Ҹ����� + { + save_original_data(&pitem->mime_header, ";name=", 6, pitem->thread_id); + save_original_data(&pitem->mime_header, ps, len, pitem->thread_id); + + if(*ps == '"') + { + ps++; + len-=2; + } + pitem->attach_filename = (char *)dictator_malloc(pitem->thread_id, len+1); + mime_header_decode(ps, len, pitem->attach_filename, &len, pitem->filename_charset, MAIL_MAX_CHARSET_LEN, g_mail_localinfo.runtime_log); + pitem->attach_filename[len] = '\0'; + pitem->filename_len = len; + } + p++; + break; + + case NOTMUL_ID: + case NOTMUL_DESCR: + if((ps = look_for_string_end(p, p_end, &p)) == NULL) //��������ֶ� + { + return -1; + } + p++; + break; + + case NOTMUL_ENCODE: + if((ps = look_for_string_end(p, p_end, &p)) == NULL) + { + return -1; + } + if(strcmp_one_word_mesa("base64", "BASE64", 6, ps, p-ps)) + { + save_original_data(&pitem->mime_header, "\r\nContent-Transfer-Encoding:base64", 34, pitem->thread_id); + pitem->trans_enc = MIME_TRANSENC_BASE64; + } + else if(strcmp_one_word_mesa("quoted-printable", "QUOTED-PRINTABLE", 16, ps, p-ps)) + { + save_original_data(&pitem->mime_header, "\r\nContent-Transfer-Encoding:quoted-printable", 44, pitem->thread_id); + pitem->trans_enc = MIME_TRANSENC_QP; + } + else if(!strcmp_one_word_mesa("nil", "NIL", 3, ps, p-ps)) + { + save_original_data(&pitem->mime_header, "\r\nContent-Transfer-Encoding:", 28, pitem->thread_id); + save_original_data(&pitem->mime_header, ps, p-ps, pitem->thread_id); + } + p++; + break; + + case NOTMUL_SIZE://�п��������һ���ֶΣ�ȡ����λ�õ�ʱ��Ҫע������������ + if(is_extend==0)// || pitem->attach_filename != NULL) //����չ���ͺ���IJ����� + { + i=NOTMUL_NUM; //����ѭ�� + break; + } + else if((p = (const char *)memchr(p, ' ', p_end-p))==NULL) //��������ֶ� + { + return -1; + } + p++; + break; + + case NOTMUL_EVENLOP: + case NOTMUL_BODYSTRUCT: + if(type == CONT_TYPE_RFC822) //������MESSAGE/RFC822������2���ֶΣ���������ֶΣ� + { + if(*p == '(') + { + if((p=look_for_parenthesis_end(p+1, p_end))==NULL || *p!=')') + { + MESA_HANDLE_RUNTIME_LOG(g_mail_localinfo.runtime_log,RLOG_LV_FATAL, MAILIMAP4_MODULE, "message/rfc822 input error, not complete()."); + i=NOTMUL_NUM; + break; + } + } + else + { + p = (const char *)memchr(p, ' ', p_end-p); + if(p==NULL) + { + i=NOTMUL_NUM; + break; + } + } + p++; + break; + } + else //���Ͳ���MESSAGE/RFC822��û����2���ֶ� + { + i += 2; + } + //fall through + case NOTMUL_LINES: + if(type==CONT_TYPE_TEXT || type==CONT_TYPE_RFC822) //��������ֶ� + { + p = (const char *)memchr(p, ' ', p_end-p); + if(p==NULL) + return -1; + break; + } + else //�����Ͳ���TEXT�������Ͳ���MESSAGE/RFC822��û�и��ֶ� + { + i++; + } + //fall through + case NOTMUL_MD5: + if((ps = look_for_string_end(p, p_end, &p)) == NULL) //��������ֶ� + { + return -1; + } + p++; + break; + + case NOTMUL_DISPOSITION: + if(*p != '(') + { + i=NOTMUL_NUM; + break; + } + p++; + if((ps = look_for_string_end(p, p_end, &p)) == NULL) + { + i=NOTMUL_NUM; + break; + } + save_original_data(&pitem->mime_header, "\r\nContent-Disposition:", 22, pitem->thread_id); + save_original_data(&pitem->mime_header, ps, p-ps, pitem->thread_id); //����õ�����ATTATCHMENT + while(p<p_end && (*p=='"' || *p==' ')) + p++; + if(p==p_end || *p != '(') //û�в�������б����������� + { + i=NOTMUL_NUM; + break; + } + ps = p+1; + if((p=look_for_parenthesis_end(ps, p_end))==NULL || *p!=')') //���Ҳ�������б�����λ�� + { + p = p_end; + break; + } + if(get_value_parenthesis(ps, p, "\"filename\" ", 11, "filename ", 9, &ps, &len)) //���Ҹ����� + { + save_original_data(&pitem->mime_header, ";filename=", 10, pitem->thread_id); + save_original_data(&pitem->mime_header, ps, len, pitem->thread_id); + + if(*ps == '"') + { + ps++; + len-=2; + } + if(pitem->attach_filename==NULL) + { + pitem->attach_filename = (char *)dictator_malloc(pitem->thread_id, len+1); + mime_header_decode(ps, len, pitem->attach_filename, &len, pitem->filename_charset, MAIL_MAX_CHARSET_LEN, g_mail_localinfo.runtime_log); + pitem->attach_filename[len] = '\0'; + pitem->filename_len = len; + } + } + break; + case NOTMUL_LANGUAGE: + case NOTMUL_LOCATION: + break; + default:return -1; + } + } + + save_original_data(&pitem->mime_header, "\r\n\r\n", 4, pitem->thread_id); + return 0; +} + +/********************************************************************* +�������ƣ�process_bodystructure_block +���ܼ�飺����һ���飬�����ϣ�� +��������� +��������� +����ֵ��0-������-1-ʧ�ܣ�-2-�û���Ϊ�գ���ƴ��keyֵ +*********************************************************************/ +static int process_bodystructure_block(stMailPme* mailpme, const char *path, const char *block, int blocklen, long uid, int is_multi, int is_extend) +{ + stMailElem *pelem = mailpme->plug_mailinfo.pMailInfo->username; //TODO: S2C��Ӧ��ʱ���� + mime_item_t *pitem; + char key[256]; + long cb_ret; + + if(pelem->buflen==0) + return -2; + + snprintf(key, 256, "%s-%ld-%s", pelem->buf, uid, path); + + pitem = (mime_item_t *)MESA_htable_search(g_mail_localinfo.htable_imap[mailpme->thread_num], (unsigned char *)key, strlen(key)); + if(pitem == NULL) //Ӧ�ò��Ǻ�Ƶ������BODYSTRUCTURE����ʱ������CALL_BACK�������ˡ� + { + pitem = (mime_item_t *)dictator_malloc(mailpme->thread_num, sizeof(mime_item_t)); + memset(pitem, 0, sizeof(mime_item_t)); + pitem->thread_id = mailpme->thread_num; + pitem->is_multi = is_multi; +#ifdef DBG_FULL + save_original_data(&pitem->mime_header, block, blocklen, pitem->thread_id); +#endif + if(is_multi==0) + { + block += 1; //ȥ������ + blocklen -= 2; + if(parse_not_multipart_line(pitem, block, blocklen, is_extend)!=0) //����һ����multipart�� + { + char buf[512]; + memcpy(buf, block, blocklen>511?511:blocklen); + buf[blocklen>511?511:blocklen] = '\0'; + imap_free_node(pitem); + MESA_HANDLE_RUNTIME_LOG(g_mail_localinfo.runtime_log, RLOG_LV_FATAL, MAILIMAP4_MODULE, "parse_not_multipart_line failed, is_extend:%d, %d-%s", is_extend,blocklen, buf); + return -1; + } + } + else if(is_extend) + { + if(parse_multipart_line(pitem, block, blocklen)!=0)//����һ��multipart�� + { + char buf[512]; + memcpy(buf, block, blocklen>511?511:blocklen); + buf[blocklen>511?511:blocklen] = '\0'; + imap_free_node(pitem); + MESA_HANDLE_RUNTIME_LOG(g_mail_localinfo.runtime_log, RLOG_LV_FATAL, MAILIMAP4_MODULE, "parse_multipart_line failed, %d-%s", blocklen, buf); + return -1; + } + } + else //MULTIPART��������չ�ֶΣ������� + { + imap_free_node(pitem); + return 0; + } + + if((cb_ret = MESA_htable_add(g_mail_localinfo.htable_imap[mailpme->thread_num], (unsigned char *)key, strlen(key), pitem)) < 0) + { + MESA_HANDLE_RUNTIME_LOG(g_mail_localinfo.runtime_log, RLOG_LV_DEBUG, MAILIMAP4_MODULE, "in func process_bodystructure_block, MESA_htable_add failed: %d.", cb_ret); + imap_free_node(pitem); + return 0; + } + else if(g_mail_localinfo.stat_trig) + { + FS_operate(g_mail_localinfo.fsstat_handle, g_mail_localinfo.stat_id[STAT_ID_HTABLE_NUM], 0, FS_OP_ADD, 1); + } + } + + return 0; +} + +/********************************************************************* +�������ƣ�parse_bodystructure +���ܼ�飺����������body/bodystructure��Ӧ����ȡMIME�鼰���Ӧ�Ŀ�ţ������ϣ�� +��������� +��������� +����ֵ���������ش������ֽ�����<0-ʧ�� +*********************************************************************/ +static int parse_bodystructure(stMailPme* mailpme, const char *bodystruct, int bodylen, long uid, int is_extend) +{ + int single=0, depth=0;//depth:����� + long len; + const char *pc=bodystruct, *p_end=bodystruct+bodylen, *pstart=NULL; + int state=STAT_BLOCK_IDLE, pre_state=STAT_BLOCK_IDLE; + char path[128]="0", *ptmp; + MESA_lqueue_head lq_head; + + lq_head = MESA_lqueue_create(0, 1024); + if(lq_head==NULL) + { + MESA_HANDLE_RUNTIME_LOG(g_mail_localinfo.runtime_log,RLOG_LV_FATAL, MAILIMAP4_MODULE, "MESA_lqueue_create error."); + return -1; + } + + while(pc < p_end) + { + if(*pc == ' ') + { + pc++; + continue; + } + + switch(state) + { + case STAT_BLOCK_IDLE: + if(*pc != '(') + { + MESA_HANDLE_RUNTIME_LOG(g_mail_localinfo.runtime_log,RLOG_LV_FATAL, MAILIMAP4_MODULE, "input error1."); + MESA_lqueue_destroy(lq_head, NULL, NULL); + return -1; + } + pre_state = state; + state = STAT_BLOCK_START; + pstart=pc; //���ڵ�һ����Ҫ + pc++; + depth++; //ÿ����һ��'('����ȼ�1����ͬ�� + while(pc<p_end && *pc==' ') //�鿴�Ƿ��ǵ�һ�� + pc++; + if(pc<p_end && *pc != '(') + single = 1; + break; + + case STAT_BLOCK_START: + if(*pc == '(') + { + if(pre_state == STAT_BLOCK_START) + { + if(MESA_lqueue_join_head(lq_head, path, strlen(path)+1)) //����һ����pathѹջ + { + MESA_HANDLE_RUNTIME_LOG(g_mail_localinfo.runtime_log,RLOG_LV_FATAL, MAILIMAP4_MODULE, "MESA_lqueue_join_head error."); + MESA_lqueue_destroy(lq_head, NULL, NULL); + return -2; + } + snprintf(path+strlen(path), 128-strlen(path), "%s", ".1"); + } + else //++path + { + if(path[0]=='0' && MESA_lqueue_join_head(lq_head, path, strlen(path)+1)) //���������0ѹջ + { + MESA_HANDLE_RUNTIME_LOG(g_mail_localinfo.runtime_log,RLOG_LV_FATAL, MAILIMAP4_MODULE, "MESA_lqueue_join_head error."); + MESA_lqueue_destroy(lq_head, NULL, NULL); + return -2; + } + ptmp = strrchr(path, '.'); + if(ptmp == NULL) + sprintf(path, "%u", atoi(path)+1); + else + sprintf(ptmp+1, "%u", atoi(ptmp+1)+1); + } + + pstart = pc; + pre_state = state; + state = STAT_BLOCK_START; + pc++; + depth++; + break;//��һ��ѭ�� + } + else + { + pre_state = state; + state = STAT_BLOCK_PROC; + } + //fall through + + case STAT_BLOCK_PROC: + if((pc=look_for_parenthesis_end(pc, p_end))==NULL || *pc!=')') //ȡ�굱ǰ�� + { + MESA_HANDLE_RUNTIME_LOG(g_mail_localinfo.runtime_log,RLOG_LV_FATAL, MAILIMAP4_MODULE, "input error3"); + MESA_lqueue_destroy(lq_head, NULL, NULL); + return -4; + } + depth--; //ÿȡ��һ���飬��ǰ��ȼ�1 + pc++; + pre_state = state; + state = STAT_BLOCK_END; + + //���ڵ�һ�飬��С�����"1"���������ģ�ͬʱ���"0"Ϊbody[text]���� + if(single==1 && depth==0) + { + process_bodystructure_block(mailpme, "1", pstart, pc-pstart, uid, 0, is_extend); + } + process_bodystructure_block(mailpme, path, pstart, pc-pstart, uid, 0, is_extend); + break; + + case STAT_BLOCK_END: + if(*pc == '(') //��һ�����������һ��ͬһ������¿� + { + ptmp = strrchr(path, '.'); + if(ptmp == NULL) //++path + sprintf(path, "%u", atoi(path)+1); + else + sprintf(ptmp+1, "%u", atoi(ptmp+1)+1); + pre_state = state; + state = STAT_BLOCK_START; + pstart = pc; + pc++; + depth++; + } + else if(*pc != ' ') //��ʼ�ַ�����'('����MULTIPART��β����Ϣ + { + pstart = pc; + if((pc=look_for_parenthesis_end(pc, p_end))==NULL || *pc!=')') + { + MESA_HANDLE_RUNTIME_LOG(g_mail_localinfo.runtime_log,RLOG_LV_FATAL, MAILIMAP4_MODULE, "input error4."); + MESA_lqueue_destroy(lq_head, NULL, NULL); + return -5; + } + depth--; + len = 128; + if(MESA_lqueue_try_get_head(lq_head, path, &len) != 0) + { + MESA_HANDLE_RUNTIME_LOG(g_mail_localinfo.runtime_log,RLOG_LV_FATAL, MAILIMAP4_MODULE, "MESA_lqueue_try_get_head error."); + MESA_lqueue_destroy(lq_head, NULL, NULL); + return -6; + } + pre_state = state; + state = STAT_BLOCK_START; + + if(is_extend) //multipart�����û����չ�ֶΣ�ûʲô�ɴ����� + { + process_bodystructure_block(mailpme, path, pstart, pc-pstart, uid, 1, is_extend); //MULTIPART BLOCK has no () + } + pc++; + } + break; + default: + break; + } + + if(depth==0) //�����Ϊ0��˵���������Ѿ������꣬�������ܻ��б�Ŀ飬���ٴ��� + break; + } + + if(MESA_lqueue_try_get_head(lq_head, path, &len) == 0) //ջ�ﻹ�����ݣ������� + { + MESA_HANDLE_RUNTIME_LOG(g_mail_localinfo.runtime_log,RLOG_LV_FATAL, MAILIMAP4_MODULE, "queue error, it is not NULL."); + MESA_lqueue_destroy(lq_head, NULL, NULL); + return -7; + } + MESA_lqueue_destroy(lq_head, NULL, NULL); + + return pc-bodystruct; +} + +/********************************************************************* +�������ƣ�process_block_mime_header +���ܼ�飺����������һ���飬�����û���+uid+��Ŵӹ�ϣ���в���MIMEͷ�� +��������� +��������� +����ֵ�� -1-δ���ҵ���0-���ҵ��ˣ�PROT_SATE_XXX��ҵ��㷵��״̬ +*********************************************************************/ +static int get_block_mime_header(stMailPme *mailpme, long uid, const char *block_seq, struct streaminfo *a_tcp, const void *raw_pkt) +{ + char key[256]; + int len; + mime_item_t *pitem; + + if(mailpme->plug_mailinfo.pMailInfo->username->buflen==0) + return -1; + snprintf(key, 256, "%s-%ld-%s", mailpme->plug_mailinfo.pMailInfo->username->buf, uid, block_seq); + + pitem = (mime_item_t *)MESA_htable_search(g_mail_localinfo.htable_imap[mailpme->thread_num], (unsigned char *)key, strlen(key)); + if(pitem != NULL) + { + if(pitem->is_multi) + { + if(pitem->boundary) + add_boundary(pitem->boundary, pitem->bound_len, &mailpme->mimeinfo->b_header, mailpme->thread_num); + save_original_data(&mailpme->pOriginalData, (const char *)pitem->mime_header.buf, pitem->mime_header.len, mailpme->thread_num); + } + else + { + save_original_data(&mailpme->pOriginalData, (const char *)pitem->mime_header.buf, pitem->mime_header.len, mailpme->thread_num); + mailpme->mimeinfo->TransferEnc = pitem->trans_enc; + if((len = strlen(pitem->charset))>0) + { + memcpy(mailpme->mimeinfo->charset, pitem->charset, len); + mailpme->mimeinfo->charset[len] = '\0'; + } + if(pitem->filename_len>0 && (g_mail_localinfo.protocol_flag & MAIL_ATTACH_NAME)) + { + mailpme->MailInfoState = MAIL_GET_FILENAME; + len = call_biz_per_line(mailpme, MAIL_ATTACH_NAME, pitem->attach_filename, pitem->filename_len, pitem->filename_charset, a_tcp, raw_pkt); + if(len & PROT_STATE_DROPME) + { + drop_set_value(mailpme); + return IMAP_CMD_DROP; + } + } + } + + *((char *)pitem->mime_header.buf + pitem->mime_header.len) = '\0'; //TODO + DBG("SEARCH_HTABLE: %s\n%s\n", key, (char *)pitem->mime_header.buf); + return 0; + } + else + { + MESA_HANDLE_RUNTIME_LOG(g_mail_localinfo.runtime_log,RLOG_LV_INFO, MAILIMAP4_MODULE, "MESA_htable_search_cb %s, no result found.", key); + } + + return -1; +} + +/********************************************************************* +�������ƣ�imap4_reset_mailpme +���ܼ�飺��������¿�����и�λ +���������uid�����Ŀ��uid�� +��������� +����ֵ�� +*********************************************************************/ +static int imap4_reset_mailpme(stMailPme* mailpme, long uid, struct streaminfo *a_tcp, const void *raw_pkt) +{ + mailpme->pre_uid = mailpme->uid; + mailpme->uid = uid; + + if(mailpme->pending_state==0 && mailpme->uid != mailpme->pre_uid) + { + if(mailpme->is_drop) + mail_reset_mailpme_noclose(mailpme, a_tcp, raw_pkt); + else + mail_reset_mailpme(mailpme, a_tcp, raw_pkt); + } + mailpme->pending_state = 0; + + return 0; +} + +/********************************************************************* +�������ƣ�prepare_parse_bodystructure +���ܼ�飺������BODYSTRUCTURE���������ж��Ƿ���������������������� + ԭʼ���ݣ��ȴ���һ��������ƴ�Ӻ����ظ����������� +��������� + start��mail_get_tcpdata�������������ָ��output_line + linelen: mail_get_tcpdata������������ݳ���outputlen + src: BODYSTRUCTURE�ṹ��ʼָ�� + srclen: src���� +��������� +����ֵ�� 0-����������-���ݲ��������ȴ��´� +*********************************************************************/ +static int prepare_parse_bodystructure(stMailPme* mailpme, const char *start, int linelen, const char *src, int srclen, long uid, int is_extend) +{ + const char *ptmp, *srcend=src+srclen; + int ret; + + if(!strncmp(srcend-3, "}\r\n", 3) || !strncmp(srcend-2, "}\n", 2)) //���������������ܻ��У����û��Ҳ���ǽ���ʧ�ܶ��� + { + ptmp = (const char *)memrchr(src, '{', srclen-3); + if(ptmp != NULL) + { + linelen = ptmp - start; + if(start != mailpme->pDataLineBuf.buf) + { + if(buf_cache_check_size(&mailpme->pDataLineBuf, linelen, mailpme->thread_num)<0) + return IMAP_CMD_ANS; + memcpy(mailpme->pDataLineBuf.buf, start, linelen); + } + mailpme->pDataLineBuf.len = linelen; + mailpme->EmlAnalyseState = MAIL_STAT_HEADER; //�����п������۵��У��Һ���Ҳ���ʼ�ͷ��(����еĻ�) + return IMAP_CMD_FETCH_ANS; + } + } + + ret = parse_bodystructure(mailpme, src, srclen, uid, is_extend); //����ʧ��Ҳ�������أ���������BODYSTRUCTURE + + if(ret>0 && (srcend -(src+ret) < 5)) //the second 5 is lengh of "body[" + return IMAP_CMD_FETCH_ANS; + + return 0; +} + +/********************************************************************* +�������ƣ�imap_is_wanted_line +���ܼ�飺������������ݵ��������������ݳ��ȺͻỰ����״̬���жϲ����� + imapӦ����Ϣ���ͱ�� +��������� + apply_count�����ݰ��Ĵ�С + a_imap_line :�����ʼ����ݣ�������"\r\n" + mailpme:�ʼ����ݽṹ +���������������ʼ����ݿ�ʼ�������mailpme->EmlAnalyseState +����ֵ�� ��Ӧ������ı��� +*********************************************************************/ +static int imap_is_wanted_line(const char *a_imap_line,int linelen, struct tcpdetail *ptcpdetail, stMailPme* mailpme, struct streaminfo *a_tcp, const void *raw_pkt) +{ + const char *p=a_imap_line, *p_end=a_imap_line+linelen, *pp=NULL; + int tmplen, retCMD=0; + + if(linelen>0 && (p=(char *)memchr(a_imap_line, ' ', (linelen>RESPONSE_FETCH_MAX_LEN)?RESPONSE_FETCH_MAX_LEN:linelen))) + p++; + if(p!=NULL && (pp=(char *)memchr(p,' ',p_end-p))) //��ȡfetch response�еĹؼ��ʣ���"fetch (body[header" + pp++; + + //�����Ƕ��ʼ���ʼ���ж� + if(pp!=NULL && (pp+6)<p_end && strncmp_one_word_mesa("FETCH ", "fetch ", 6, pp, p_end-pp)) + { + char templine[MAX_ORDER_LINE_SIZE], block_seq[128], ch; + const char *ptmp1, *ptmp2; + int tmp; + long uid=-1; + + pp = pp+6; + tmplen = ((p_end-pp) >= (MAX_ORDER_LINE_SIZE-1))?(MAX_ORDER_LINE_SIZE-1):(p_end-pp); + memcpy(templine, pp, tmplen); + templine[tmplen]='\0'; + + ptmp2=mesa_memncasemem(templine, tmplen, "UID ", 4); + if(ptmp2==NULL || sscanf(ptmp2+3, "%*[ ]%ld%c", &uid, &ch)!=2 || ch!=' ') //TODO: �����ַ��� + { + uid = 0; + } + else if((ptmp1=mesa_memncasemem(pp, p_end-pp, "BODYSTRUCTURE (", 15))!=NULL && mailpme->plug_mailinfo.pMailInfo->username->buflen>0) //����BASE64�����ַ������Բ����Ա��Сд + { + //Ҫ����"BODYSTRUCTURE ("�е�'('����Ϊ�е�һ������ + if((tmp = prepare_parse_bodystructure(mailpme, a_imap_line, linelen, ptmp1+14, p_end-ptmp1-14, uid, 1)) != 0) + return tmp; + } + else if((ptmp1=mesa_memncasemem(pp, p_end-pp, "BODY (", 6))!=NULL && mailpme->plug_mailinfo.pMailInfo->username->buflen>0) + { + if((tmp = prepare_parse_bodystructure(mailpme, a_imap_line, linelen, ptmp1+5, p_end-ptmp1-5, uid, 0)) != 0) + return tmp; + } + + //��������Сд + for(tmp=0;tmp<tmplen;tmp++) + { + templine[tmp]=tolower(templine[tmp]); + } + + ptmp1 = strstr(templine, "body["); + ptmp2 = strstr(templine, "body.peek["); + //���ʼ�ͷ��ʼ���ж� + if((ptmp1!=NULL && (!strncmp(ptmp1+5, "header", 6) || !strncmp(ptmp1+5, "mime", 4))) \ + || (ptmp2!=NULL && (!strncmp(ptmp2+10, "header", 6) || !strncmp(ptmp2+10, "mime", 4))) || strstr(templine, "rfc822.header")) + { + mailpme->is_continue = 0; + imap4_reset_mailpme(mailpme, uid, a_tcp, raw_pkt); + mailpme->EmlAnalyseState=MAIL_STAT_HEADER; +#ifdef DBG_FULL + return EML_DATA_HEAD_IN; +#else + return IMAP_CMD_FETCH_ANS; +#endif + } + //�������ʼ���ʼ���ж���һ���յĿ�����ָ�������ʼ�������ͷ���� + else if((ptmp1!= NULL && *(ptmp1+5)==']' && *(ptmp1+6)==' ') || (ptmp2!=NULL && *(ptmp2+10)==']' && *(ptmp2+11)==' ') || strstr(templine, "rfc822 {")) + { + mailpme->is_continue = 0; + imap4_reset_mailpme(mailpme, uid, a_tcp, raw_pkt); + mailpme->EmlAnalyseState=MAIL_STAT_HEADER; +#ifdef DBG_FULL + return EML_DATA_HEAD_IN; +#else + return IMAP_CMD_FETCH_ANS; +#endif + } + //���ʼ�һ��Ƭ�ν����ж�����C2S:BODY.PEEK[]<262144.262144>; S2C:body[]<262144> + else if((ptmp1!= NULL && sscanf(ptmp1+5, "]<%[0-9]%c", block_seq, &ch)==2 && ch=='>') || (ptmp2!=NULL && sscanf(ptmp2+10, "]<%[0-9]%c", block_seq, &ch)==2 && ch=='>')) + { + DBG("A partial block: uid=%ld, start octet: %s\n", uid, block_seq); + mailpme->is_continue = 1; + imap4_reset_mailpme(mailpme, uid, a_tcp, raw_pkt); + + if(!strcmp(block_seq, "0")) + { + mailpme->EmlAnalyseState=MAIL_STAT_HEADER; +#ifdef DBG_FULL + return EML_DATA_HEAD_IN; +#else + return IMAP_CMD_FETCH_ANS; +#endif + } + else + { + return IMAP_CMD_DATA_CONTINUE; + } + } + //���ʼ���body��ʼ���ж������ʼ�������в��֣��������ʼ�ͷ + else if((ptmp1!=NULL && !strncmp(ptmp1+5, "text", 4)) || (ptmp2!=NULL && !strncmp(ptmp2+10, "text", 4)) || strstr(templine, "rfc822.text")) + { + mailpme->is_continue = 0; + imap4_reset_mailpme(mailpme, uid, a_tcp, raw_pkt); + + tmp = get_block_mime_header(mailpme, uid, "0", a_tcp, raw_pkt); + if(tmp<0) + { + return IMAP_CMD_FETCH_ANS; + } + else if(tmp==IMAP_CMD_DROP) + { + return IMAP_CMD_DROP; + } + return IMAP_CMD_DATA_BORDER; + } + //�ʼ���һ������ж�����body[1.2]��block_seq�洢���� + else if((ptmp1!=NULL && sscanf(ptmp1+5, "%[0-9.]%c", block_seq, &ch)==2 && ch==']') || (ptmp2!=NULL && sscanf(ptmp2+10, "%[0-9.]%c", block_seq, &ch)==2 && ch==']')) + { + DBG("An imap block found: uid=%ld, %s\n", uid, block_seq); + mailpme->is_continue = 0; + imap4_reset_mailpme(mailpme, uid, a_tcp, raw_pkt); + + tmp = get_block_mime_header(mailpme, uid, block_seq, a_tcp, raw_pkt); + if(tmp<0) + { + return IMAP_CMD_FETCH_ANS; + } + else if(tmp==IMAP_CMD_DROP) + { + return IMAP_CMD_DROP; + } + return IMAP_CMD_DATA_BORDER; + } + } + + if(mailpme->maybe_end == 1) + { + mailpme->maybe_end = 0; + if(p && ((strncmp_one_word_mesa("ok fetch ", "OK FETCH ", 9, p, p_end-p))||(strncmp_one_word_mesa("ok uid fetch ", "OK UID FETCH ", 13, p, p_end-p)))) + { + return IMAP_CMD_DATA_END; + } + else + { + return IMAP_CMD_NOT_END; + } + } + else if((linelen==3 && !strncmp(a_imap_line, ")\r\n", 3)) || (linelen==2 && !strncmp(a_imap_line, ")\n", 2))) + { + mailpme->maybe_end = 1; + mailpme->obtain_line = 1; //�п������ɸ�ͷ��һ��')'֮�����FETCH�����������еĿ��б�MIME��ȥ�� + return IMAP_CMD_MAYBE_END; + } + + if(((!strncmp(a_imap_line, "* ", 2) || !strncmp(a_imap_line, "+ ", 2)) || + (p && linelen<IMAP_LABEL_OK_MAX_LEN && NULL==memchr(a_imap_line, ':', linelen) && /*X-MAR: OK*/ + (strncmp_one_word_mesa("ok", "OK", 2, p, p_end-p) || strncmp_one_word_mesa("no ", "NO ",3, p, p_end-p) || strncmp_one_word_mesa("bad ", "BAD ",4, p, p_end-p))))) + { + if(mailpme->EmlAnalyseState==MAIL_STAT_INIT || ptcpdetail->datalen < IMAP_OK_CMD_LEN) + return IMAP_CMD_ANS; + else + retCMD = 1; + } + + if((mailpme->EmlAnalyseState!=MAIL_STAT_INIT) && + p && ((strncmp_one_word_mesa("ok fetch completed", "OK FETCH COMPLETED", 18, p, p_end-p))||(strncmp_one_word_mesa("ok uid fetch completed", "OK UID FETCH COMPLETED", 22, p, p_end-p)))) + { + return IMAP_CMD_DATA_END; + } + else if(retCMD==1) + { + return IMAP_CMD_ANS; + } + + //Ӧ�����ж�IMAP_CMD_DATA_END֮�� + //����Ự������������ά�ֵ���DROP��ʱ���EmlAnalyseState״̬����һ���ỰҪ���ȡ�� + if(mailpme->is_drop) + return IMAP_CMD_DROP; + + retCMD=mail_analy_emlheader(a_imap_line,linelen,mailpme->EmlAnalyseState); + if(retCMD!=EML_UNKNOWN) + { + return retCMD; + } + + return IMAP_CMD_UNKNOWN; +} + +/********************************************************************* +�������ƣ�imap_process_s2c +���ܼ�飺�����ʼ�IMAP�ỰS2C���ϵ�һ�����ݰ���ÿ��������1�θú��� +��������� + tcp_stream��tcp�Ự�� + mailpme���ʼ������ṹ�� +����������� +����ֵ��ҵ�����ķ���ֵ +*********************************************************************/ +static int imap_process_s2c(stMailPme* mailpme, struct streaminfo *a_stream, const void *raw_pkt) +{ + int rec=PROT_STATE_GIVEME, needfolding=0; + int line_status = MAIL_FOLD_LINE_START; + char *output_line = NULL; + int outputlen=0; + struct tcpdetail *ptcpdetail = a_stream->ptcpdetail; + + memset(&mailpme->session_info, 0, sizeof(stSessionInfo)); + mailpme->session_info.plugid = g_mail_localinfo.plugid; + mailpme->session_info.session_state = SESSION_STATE_DATA; + mailpme->session_info.app_info = &mailpme->plug_mailinfo; + + if(ptcpdetail->lostlen > 0) + { + mailpme->loss_flag = 1; + DBG("PROTOCOL_IMAP: lostlen: %d\n", ptcpdetail->lostlen); + } + + while(1) + { + if(mailpme->EmlAnalyseState == MAIL_STAT_HEADER || (mailpme->EmlAnalyseState == MAIL_STAT_BODY && mailpme->mimeinfo->text_begin==0)) + needfolding=1; + else + needfolding=0; + + line_status = mail_get_tcpdata(ptcpdetail, mailpme, needfolding, &output_line, &outputlen); + if(line_status == MAIL_INPUT_END) + break; + else if(line_status == MAIL_GETLINE_ERR) + { + MESA_HANDLE_RUNTIME_LOG(g_mail_localinfo.runtime_log,RLOG_LV_FATAL, MAILIMAP4_MODULE, "imap get a line error!!! drop now!\n"); + return PROT_STATE_DROPME; + } + mailpme->pDataLineBuf.len = 0; + + line_status = imap_is_wanted_line(output_line, outputlen, ptcpdetail, mailpme, a_stream, raw_pkt); + + switch(line_status) + { + case IMAP_CMD_DROP: + case IMAP_CMD_FETCH_ANS: + case IMAP_CMD_UNKNOWN: + case IMAP_CMD_MAYBE_END: + case IMAP_CMD_DATA_CONTINUE: //���ֽڻ�ȡ�ʼ�������FETCH��Ӧͷ�� + break; + + case IMAP_CMD_DATA_BORDER: //����TCP���ݲ���ԭʼ�ʼ��������л��� + mailpme->EmlAnalyseState = MAIL_STAT_BODY; + body_update_text_begin(mailpme->mimeinfo); + break; + + case IMAP_CMD_ANS: //������Ǻ����ʧ�����Խ�����Ӧ����ֹ�Ự + case EML_DATA_END: + case IMAP_CMD_DATA_END: + //��CONTINUE��Ͳ��ø�λ����һ�����ñ��ε�״̬����һ����ֻ�ܻ�ȡ��1�У� + //�����һ�����µĿ飬�����ж����¿�ĵط����и�λ�� + if(mailpme->is_continue) + mailpme->obtain_line = 1; + //�������CONTINUE�飬ҪΪ��һ���Ự��SESSION_PENDING��ͬʱ��ʱ����������飻 + else if(mailpme->pending_state==0) + { + if(mailpme->is_drop) + mail_reset_mailpme_noclose(mailpme, a_stream, raw_pkt); + else + mail_reset_mailpme(mailpme, a_stream, raw_pkt); + + //�ʼ��������ϣ���������һ���ʼ�ͷ����ӦҲ�п������۵���(BODYSTRUCTURE) + mailpme->EmlAnalyseState = MAIL_STAT_HEADER; + } + break; + + case IMAP_CMD_NOT_END: + if(mailpme->is_drop) + break; + line_status = mailpme->pre_opsate; + rec = process_mail_data(line_status, (char *)")\r\n", 3, mailpme, a_stream, raw_pkt); + if(rec & PROT_STATE_DROPME) + { + drop_set_value(mailpme); + break; + } + //fall through + default: + if(mailpme->is_drop) + break; + mailpme->pre_opsate = line_status; + rec = process_mail_data(line_status, output_line, outputlen, mailpme, a_stream, raw_pkt); + if(rec & PROT_STATE_DROPME) + { + drop_set_value(mailpme); + } + break; + } + } + mailpme->iDataPointer = 0; + mailpme->loss_flag = 0; + + //call biz per packet + if(!g_mail_localinfo.callback_per_line && mailpme->plug_mailinfo.elem_num>0) + { + rec = call_biz_per_packet(mailpme, a_stream, raw_pkt); + if(rec & PROT_STATE_DROPME) + { + drop_set_value(mailpme); + } + } + + return (rec&PROT_STATE_DROPPKT)?PROT_STATE_DROPPKT:PROT_STATE_GIVEME; +} + + +/********************************************************************* +�������ƣ�pop3_process_c2s +���ܼ�飺�����ʼ�IMAP�ỰC2S���ϵ�һ�����ݰ���ÿ��������1�θú��� +��������� + tcp_stream��tcp�Ự�� + mailpme���ʼ������ṹ�� +����������� +����ֵ��ҵ�����ķ���ֵ +*********************************************************************/ +static int imap_process_c2s(stMailPme* mailpme, struct streaminfo *a_stream, const void *raw_pkt) +{ + //ֻ�����û������룬ֻ�����״̬�� + if(mailpme->EmlAnalyseState!=MAIL_STAT_INIT || mailpme->is_drop) + return PROT_STATE_GIVEME; + + int rec=PROT_STATE_GIVEME; + int line_status = MAIL_FOLD_LINE_START; + char *output_line = NULL; + int outputlen=0, matchlen; + struct tcpdetail *ptcpdetail = a_stream->ptcpdetail; + char *p, *p_end; + + //���˷����ϸ���������������.TODO + if(mailpme->pre_dir != a_stream->curdir) + { + mailpme->pre_dir = a_stream->curdir; + mailpme->pDataLineBuf.len = 0; + } + + while(1) + { + line_status = mail_get_atcpline_c2s(ptcpdetail, mailpme, &output_line, &outputlen); + if(line_status == MAIL_INPUT_END) + break; + + if(line_status == MAIL_GETLINE_ERR) + { + MESA_HANDLE_RUNTIME_LOG(g_mail_localinfo.runtime_log,RLOG_LV_FATAL, MAILIMAP4_MODULE, "smtp get a line error!!! drop now!\n"); + return PROT_STATE_DROPME; + } + mailpme->pDataLineBuf.len = 0; + p_end = output_line+outputlen; + + if(outputlen>0 && (p=(char *)memchr(output_line, ' ', outputlen))) + { + char *pp1, *pp2; + p++; + if((matchlen=strncmp_two_word_mesa("authenticate", "AUTHENTICATE", 12, "xoauth2", "XOAUTH2", 7, p, p_end-p))!=0) + { + mailpme->iDataPointer = 0; + return oauth2_username_biz(mailpme, p+matchlen, p_end-p-matchlen, a_stream, raw_pkt); + } + if(strncmp_one_word_mesa("starttls", "STARTTLS", 8, p, p_end-p)!=0) + { + if(g_mail_localinfo.protocol_flag&MAIL_STARTTLS_CMD) + { + rec = call_biz_per_line(mailpme, MAIL_STARTTLS_CMD, p, 8, NULL, a_stream, raw_pkt);// 8 = strlen("STARTTLS") + if(rec & PROT_STATE_DROPME) + { + drop_set_value(mailpme); + } + return PROT_STATE_DROPME; + } + } + if(strncmp_one_word_mesa("login", "LOGIN", 5, p, p_end-p)==0) + { + mailpme->iDataPointer = 0; + return PROT_STATE_GIVEME; + } + p += 6; //length of "login " + while(*p==' ') + p++; + if(p>=p_end) + { + mailpme->iDataPointer = 0; + return PROT_STATE_GIVEME; + } + if(*p == '"') + pp1 = (char *)memchr(p+1, '"', p_end - p - 1); + else + pp1 = (char *)memchr(p, ' ', p_end - p); + if(pp1 == NULL) // ""�������û��� + { + mailpme->iDataPointer = 0; + return PROT_STATE_GIVEME; + } + pp2 = pp1+1; + + if(*p == '"') + p += 1; + if(*(pp1-1)=='"') + pp1 -= 1; + + while(*pp2 == ' ') + pp2++; + if(*pp2=='"') + pp2 += 1; + if(*(p_end-1)=='"') + p_end -= 1; + + if(pp1<=p || pp2>=p_end) + { + mailpme->iDataPointer = 0; + return PROT_STATE_GIVEME; + } + + mailpme->plug_mailinfo.pMailInfo->password->buflen = 0; + mailpme->plug_mailinfo.pMailInfo->username->buflen = 0; + mailpme->session_info.session_state = SESSION_STATE_DATA; + mail_save_mail_elem(p, pp1-p, mailpme->plug_mailinfo.pMailInfo->username, mailpme->thread_num); + if(g_mail_localinfo.protocol_flag&MAIL_USERNAME) + { + rec = call_biz_per_line(mailpme, MAIL_USERNAME, p, pp1-p, NULL, a_stream, raw_pkt); + if(rec & PROT_STATE_DROPME) + { + drop_set_value(mailpme); + break; + } + } + + mail_save_mail_elem(pp2, p_end-pp2, mailpme->plug_mailinfo.pMailInfo->password, mailpme->thread_num); + if(g_mail_localinfo.protocol_flag&MAIL_PASSWARD) + { + rec = call_biz_per_line(mailpme, MAIL_PASSWARD, pp2, p_end-pp2, NULL, a_stream, raw_pkt); + if(rec & PROT_STATE_DROPME) + { + drop_set_value(mailpme); + break; + } + } + } + + if(rec&PROT_STATE_DROPPKT) + { + break; + } + } + mailpme->iDataPointer = 0; + + return (rec&PROT_STATE_DROPPKT)?PROT_STATE_DROPPKT:PROT_STATE_GIVEME; +} + +/**************************************************************************** +������:line_is_imap_cmd() +���ܣ��ж�C->S���ͻ��������Ƿ���IMAP4������ +���룺 +����� +����ֵ: 0-���ǣ�1-�ǣ� +*****************************************************************************/ +static int line_is_imap_cmd(char *data, int datalen) +{ + if(strncmp_one_word_mesa("capability", "CAPABILITY", 10, data, datalen)) + return 1; + if(strncmp_one_word_mesa("authenticate ", "AUTHENTICATE ", 13, data, datalen)) + return 1; + if(strncmp_one_word_mesa("login ", "LOGIN ", 6, data, datalen)) + return 1; + if(strncmp_one_word_mesa("noop", "NOOP", 4, data, datalen)) + return 1; + if(strncmp_one_word_mesa("select ", "SELECT ", 7, data, datalen)) + return 1; + if(strncmp_one_word_mesa("status ", "STATUS ", 7, data, datalen)) + return 1; + if(strncmp_one_word_mesa("uid ", "UID ", 4, data, datalen)) + return 1; + if(strncmp_one_word_mesa("fetch ", "FETCH ", 6, data, datalen)) + return 1; + if(strncmp_one_word_mesa("store ", "STORE ", 6, data, datalen)) + return 1; + if(strncmp_one_word_mesa("append ", "APPEND ", 7, data, datalen)) + return 1; + if(strncmp_one_word_mesa("starttls ", "STARTTLS ", 9, data, datalen)) + return 1; + + return 0; +} + +/**************************************************************************** +������:imap4_entry_fun() +���ܣ�IMAP��ں��� +���룺stream.h +�����stream.h +����ֵ: APP_STATE_GIVEME/APP_STATE_DROPME/APP_STATE_DROPPKT +*****************************************************************************/ +char imap4_entry_fun(const char *payload, size_t payload_len, void **pme, int thread_seq,const void *raw_pkt) +{ + int rec = PROT_STATE_GIVEME; + stMailPme* mailpme = (stMailPme*)(*(pme)); + + switch(a_tcp->opstate) + { + case OP_STATE_PENDING: + if(IMAP_PROTOCOL == mail_identify_imap(a_tcp, (char *)payload, payload_len, thread_seq)) + { + rec = mail_init_mailpme(&mailpme,MAIL_SERVICE_IMAP4,a_tcp,raw_pkt); + if(rec < 0) + { + MESA_HANDLE_RUNTIME_LOG(g_mail_localinfo.runtime_log,RLOG_LV_FATAL, MAILIMAP4_MODULE, "mail_init_mailpme() error!"); + return APP_STATE_DROPME; + } + *pme = (void*)mailpme; + project_req_add_uint(a_tcp, g_mail_localinfo.proto_identify_id, IMAP_PROTOCOL); + } + else + { + return APP_STATE_DROPME; + } + //no break here. + + case OP_STATE_DATA: + if(a_tcp->curdir == DIR_S2C) + { + //if(ptcpdetail->lostlen>0) + //{ + // mailpme->s_total_loss += ptcpdetail->lostlen; + //} + + rec = imap_process_s2c(mailpme, a_tcp, raw_pkt); + if(rec & PROT_STATE_DROPME) + { + mail_clear_mailpme(mailpme, a_tcp, raw_pkt); + return APP_STATE_DROPME; + } + } + else if(a_tcp->curdir == DIR_C2S) + { + rec = imap_process_c2s(mailpme, a_tcp, raw_pkt); + if(rec & PROT_STATE_DROPME) + { + mail_clear_mailpme(mailpme, a_tcp, raw_pkt); + return APP_STATE_DROPME; + } + } + assert(mailpme->thread_num==a_tcp->threadnum); + break; + + case OP_STATE_CLOSE: + mail_clear_mailpme(mailpme,a_tcp,raw_pkt); + return APP_STATE_DROPME; + + default: + return APP_STATE_DROPME; + } + + if(rec & PROT_STATE_DROPME) + return APP_STATE_DROPME; + else if(rec & PROT_STATE_DROPPKT) + return APP_STATE_DROPPKT; + else + return APP_STATE_GIVEME; +} diff --git a/decoders/mail/mail_pop3.c b/decoders/mail/mail_pop3.c new file mode 100644 index 0000000..7d678e3 --- /dev/null +++ b/decoders/mail/mail_pop3.c @@ -0,0 +1,489 @@ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <assert.h> + +#include <MESA/stream.h> +#include <MESA/MESA_handle_logger.h> + +#include "mem_common.h" +#include "mail_entry.h" +#include "mail_pop3.h" +#include "mail_global.h" +#include "mail_analyze.h" +#include "mail.h" + +#include "base64.h" + +extern stMailLocalInfo g_mail_localinfo; +/**************************************************************************** +������:line_is_pop3_cmd() +���ܣ��ж�C->S���ͻ��������Ƿ���POP3������ +���룺 +����� +����ֵ: 0-���ǣ�1-�ǣ� +*****************************************************************************/ +static int line_is_pop3_cmd(const char *data, int datalen) +{ + if(strncmp_one_word_mesa("user ", "USER ", 5, data, datalen) || strncmp_one_word_mesa("user", "USER", 4, data, datalen)) + return 1; + if(strncmp_one_word_mesa("pass ", "PASS ", 5, data, datalen) || strncmp_one_word_mesa("pass", "PASS", 4, data, datalen)) + return 1; + if(strncmp_one_word_mesa("stat ", "STAT ", 5, data, datalen) || strncmp_one_word_mesa("stat", "STAT", 4, data, datalen)) + return 1; + if(strncmp_one_word_mesa("uidl ", "UIDL ", 5, data, datalen) || strncmp_one_word_mesa("uidl", "UIDL", 4, data, datalen)) + return 1; + if(strncmp_one_word_mesa("retr ", "RETR ", 5, data, datalen) || strncmp_one_word_mesa("retr", "RETR", 4, data, datalen)) + return 1; + if(strncmp_one_word_mesa("top ", "TOP ", 4, data, datalen) || strncmp_one_word_mesa("top", "TOP", 3, data, datalen)) + return 1; + if(strncmp_one_word_mesa("list ", "LIST ", 5, data, datalen) || strncmp_one_word_mesa("list", "LIST", 4, data, datalen)) + return 1; + if(strncmp_one_word_mesa("dele ", "DELE ", 5, data, datalen) || strncmp_one_word_mesa("dele", "DELE", 4, data, datalen)) + return 1; + if(strncmp_one_word_mesa("noop ", "NOOP ", 5, data, datalen) || strncmp_one_word_mesa("noop", "NOOP", 4, data, datalen)) + return 1; + if(strncmp_one_word_mesa("rset ", "RSET ", 5, data, datalen) || strncmp_one_word_mesa("rset", "RSET", 4, data, datalen)) + return 1; + if(strncmp_one_word_mesa("apop ", "APOP ", 5, data, datalen) ) + return 1; + if(strncmp_one_word_mesa("CAPA", "capa", 4, data, datalen)) + return 1; + if(strncmp_one_word_mesa("RESP-CODES", "resp-codes", 10, data, datalen)) + return 1; + if(strncmp_one_word_mesa("PIPELINING", "pipelining", 10, data, datalen)) + return 1; + if(strncmp_one_word_mesa("AUTH-RESP-CODE", "auth-resp-code", 14, data, datalen)) + return 1; + if(strncmp_one_word_mesa("STLS", "stls", 4, data, datalen)) + return 1; + if(strncmp_one_word_mesa("SASL PLAIN LOGIN", "sasl plain login", 16, data, datalen)) + return 1; + + return 0; +} +/********************************************************************* +�������ƣ�is_wanted_pop3_line +���ܼ�飺������������ݵ��������������ݳ��ȺͻỰ����״̬���жϲ����� + pop3Ӧ����Ϣ���ͱ�� +��������� + apply_count�����ݰ��Ĵ�С + a_pop3_line :�����ʼ����ݣ�����"\r\n" + mailpme:�ʼ����ݽṹ +���������������ʼ����ݿ�ʼ�������mailpme->EmlAnalyseState +����ֵ�� ��Ӧ������ı��� +*********************************************************************/ +static int pop3_is_wanted_line(char * a_pop3_line,int linelen, stMailPme* mailpme, struct streaminfo *a_stream, const void *raw_pkt) +{ + int retCMD; + + //POP_OK_CMD_LEN:��ʱ�����İ���ʼ������+OK��ͨ������������������Ӧ�� + if(mailpme->EmlAnalyseState==MAIL_STAT_INIT || linelen < POP_OK_CMD_LEN) + { + if(strncmp_one_word_mesa("-err", "-ERR", 4, a_pop3_line, linelen)) + return POP3_CMD_ERR; + if(strncmp_one_word_mesa("+ok ", "+OK ", 4, a_pop3_line, linelen) || \ + strcmp_one_word_mesa("+ok\r\n", "+OK\r\n", 5, a_pop3_line, linelen) || strcmp_one_word_mesa("+ok\n", "+OK\n", 4, a_pop3_line, linelen)) //���룬��������+OK��TODO�����з� + return POP3_CMD_OK; + if(line_is_pop3_cmd(a_pop3_line, linelen)) + return POP3_CMD_UNKNOWN; + } + + //��ʼ�ַ��������ֺ�'.'����Ϊ���ʼ���ʼ����������������ȷ + if(mailpme->EmlAnalyseState==MAIL_STAT_INIT) + { + if(isdigit(*a_pop3_line) || *a_pop3_line=='.')// || memchr(a_pop3_line, ':', (linelen>EML_HEADER_MAX_LEN)?EML_HEADER_MAX_LEN:linelen)==NULL) + { + return POP3_CMD_UNKNOWN; + } + //�»Ự���� + if(mailpme->pending_state==0) //֮ǰδ���� + { + if(mailpme->is_drop) + mail_reset_mailpme_noclose(mailpme, a_stream, raw_pkt); + else + mail_reset_mailpme(mailpme, a_stream, raw_pkt); + } + mailpme->pending_state = 0; + } + + if((mailpme->EmlAnalyseState == MAIL_STAT_BODY) && ((linelen==3 && !strncmp(a_pop3_line, ".\r\n",3))||(linelen==2 && !strncmp(a_pop3_line, ".\n",2)))) + return EML_DATA_END; + + if(mailpme->is_drop) + return POP3_CMD_DROP; + + retCMD=mail_analy_emlheader(a_pop3_line,linelen,mailpme->EmlAnalyseState); + if(retCMD!=EML_UNKNOWN) + { + return retCMD; + } + + return POP3_CMD_UNKNOWN; +} + +/********************************************************************* +�������ƣ�pop3_process_s2c +���ܼ�飺�����ʼ�POP3�ỰS2C���ϵ�һ�����ݰ���ÿ��������1�θú��� +��������� + tcp_stream��tcp�Ự�� + mailpme���ʼ������ṹ�� +����������� +����ֵ��ҵ�����ķ���ֵ +*********************************************************************/ +static int pop3_process_s2c(stMailPme* mailpme, struct streaminfo *a_stream, const void *raw_pkt) +{ + int rec=PROT_STATE_GIVEME, needfolding=0; + int line_status = MAIL_FOLD_LINE_START; + char *output_line = NULL; + int outputlen=0; + struct tcpdetail *ptcpdetail = a_stream->ptcpdetail; + + memset(&mailpme->session_info, 0, sizeof(stSessionInfo)); + mailpme->session_info.plugid = g_mail_localinfo.plugid; + mailpme->session_info.session_state = SESSION_STATE_DATA; + mailpme->session_info.app_info = &mailpme->plug_mailinfo; + + if(ptcpdetail->lostlen > 0) + { + mailpme->loss_flag = 1; + DBG("PROTOCOL_POP: lostlen: %d\n", ptcpdetail->lostlen); + } + + while(1) + { + if(mailpme->EmlAnalyseState == MAIL_STAT_HEADER || (mailpme->EmlAnalyseState == MAIL_STAT_BODY && mailpme->mimeinfo->text_begin==0)) + needfolding=1; + else + needfolding=0; + + line_status = mail_get_tcpdata(ptcpdetail, mailpme, needfolding, &output_line, &outputlen); + if(line_status == MAIL_INPUT_END) + break; + else if(line_status == MAIL_GETLINE_ERR) + { + MESA_HANDLE_RUNTIME_LOG(g_mail_localinfo.runtime_log,RLOG_LV_FATAL, POP3MODULE, "pop3 get a line error!!! drop now!\n"); + return PROT_STATE_DROPME; + } + mailpme->pDataLineBuf.len = 0; + + line_status = pop3_is_wanted_line(output_line, outputlen, mailpme, a_stream, raw_pkt); + + switch(line_status) + { + case POP3_CMD_DROP: + case POP3_CMD_UNKNOWN: + break; + + case POP3_CMD_ERR: //��ʱ����һ���Ự��ʧ�˽�����ǣ�����Ҫ��ֹ�����п�ʼ��+OK����� + case EML_DATA_END: + case POP3_CMD_DATA_END: + //֮ǰ�Ѿ��������»Ự���Ͳ����ٴο�����������һ�����ȴ��Ự������ + //ͬʱ�ܹ���ʱ�����������һ���Ự�� + if(mailpme->pending_state==0) + { + if(mailpme->is_drop) + mail_reset_mailpme_noclose(mailpme, a_stream, raw_pkt); + else + mail_reset_mailpme(mailpme, a_stream, raw_pkt); + + //���´λỰ�ֶε�ʶ����Ҫ��INIT״̬����Ϊ�ڴ�״̬�ж��»Ự��ʼ + mailpme->EmlAnalyseState = MAIL_STAT_INIT; + } + break; + + default: + if(mailpme->is_drop) + break; + rec = process_mail_data(line_status,output_line,outputlen,mailpme,a_stream,raw_pkt); + if(rec & PROT_STATE_DROPME) + { + drop_set_value(mailpme); + } + break; + } + } + mailpme->iDataPointer = 0; + mailpme->loss_flag = 0;//�е�ʱ��δ����BASE64�����ʱ������״̬��������ȴû����� + + //call biz per packet + if(!g_mail_localinfo.callback_per_line && mailpme->plug_mailinfo.elem_num>0) + { + rec = call_biz_per_packet(mailpme, a_stream, raw_pkt); + if(rec & PROT_STATE_DROPME) + { + drop_set_value(mailpme); + } + } + + return (rec&PROT_STATE_DROPPKT)?PROT_STATE_DROPPKT:PROT_STATE_GIVEME; +} + +/********************************************************************* +�������ƣ�is_wanted_pop3_line_cs +���ܼ�飺������������ݵ������жϲ�����pop3������ +��������� + a_pop3_line :�����ʼ����� +��������� +����ֵ�� ��Ӧ������ı��� +*********************************************************************/ +static int pop3_is_wanted_line_cs(char* mailline,int linelen, int *authmatchlen) +{ + if(strncmp_one_word_mesa("user ", "USER ", 5, mailline, linelen)) + return POP3_CMD_USER; + if(strncmp_one_word_mesa("pass ", "PASS ", 5, mailline, linelen)) + return POP3_CMD_PASS; + if(strncmp_one_word_mesa("quit", "QUIT", 4, mailline, linelen)) + return POP3_CMD_QUIT; + if(strncmp_one_word_mesa("retr", "RETR", 4, mailline, linelen)) + return POP3_CMD_RETR; + if(strncmp_one_word_mesa("reset", "RESET", 5, mailline, linelen)) + return POP3_CMD_RESET; + if((*authmatchlen=strncmp_two_word_mesa("auth", "AUTH", 4, "xoauth2", "XOAUTH2", 7, mailline, linelen))!=0) + return POP3_CMD_XOAUTH2; + if(strncmp_one_word_mesa("stls", "STLS", 4, mailline, linelen)) + return POP3_CMD_STLS; + + return POP3_CMD_UNKNOWN; +} + +/********************************************************************* +�������ƣ�pop3_process_c2s +���ܼ�飺�����ʼ�POP3�ỰC2S���ϵ�һ�����ݰ���ÿ��������1�θú��� +��������� + tcp_stream��tcp�Ự�� + mailpme���ʼ������ṹ�� +����������� +����ֵ��ҵ�����ķ���ֵ +*********************************************************************/ +static int pop3_process_c2s(stMailPme* mailpme, struct streaminfo *a_stream, const void *raw_pkt) +{ + //ֻ�����״̬���е�½���� + if(mailpme->EmlAnalyseState!=MAIL_STAT_INIT || mailpme->is_drop) + { + return PROT_STATE_GIVEME; + } + + int rec=PROT_STATE_GIVEME; + int line_status = MAIL_FOLD_LINE_START; + char *output_line = NULL; + int outputlen=0, matchlen; + struct tcpdetail *ptcpdetail = a_stream->ptcpdetail; + stMailElem *pelem; + + //���˷����ϸ���������������.TODO + if(mailpme->pre_dir != a_stream->curdir) + { + mailpme->pre_dir = a_stream->curdir; + mailpme->pDataLineBuf.len = 0; + } + mailpme->session_info.session_state = SESSION_STATE_DATA; + + while(1) + { + line_status = mail_get_atcpline_c2s(ptcpdetail, mailpme, &output_line, &outputlen); + if(line_status == MAIL_INPUT_END) + break; + + if(line_status == MAIL_GETLINE_ERR) + { + MESA_HANDLE_RUNTIME_LOG(g_mail_localinfo.runtime_log,RLOG_LV_FATAL, POP3MODULE, "smtp get a line error!!! drop now!\n"); + return PROT_STATE_DROPME; + } + mailpme->pDataLineBuf.len = 0; + + line_status = pop3_is_wanted_line_cs(output_line, outputlen, &matchlen); + switch(line_status) + { + case POP3_CMD_USER: + pelem = mailpme->plug_mailinfo.pMailInfo->username; + pelem->buflen = 0; + mail_save_mail_elem(output_line+5, outputlen-5, pelem, mailpme->thread_num); + + if((g_mail_localinfo.protocol_flag&MAIL_USERNAME) == 0) + { + break; + } + + if(pelem->buf != NULL) + { + rec = call_biz_per_line(mailpme, MAIL_USERNAME, pelem->buf, pelem->buflen, NULL, a_stream, raw_pkt); + if(rec & PROT_STATE_DROPME) + drop_set_value(mailpme); + } + break; + + case POP3_CMD_XOAUTH2: + rec = oauth2_username_biz(mailpme, output_line+matchlen, outputlen-matchlen, a_stream, raw_pkt); + break; + + case POP3_CMD_PASS: + pelem = mailpme->plug_mailinfo.pMailInfo->password; + pelem->buflen = 0; + mail_save_mail_elem(output_line+5, outputlen-5, pelem, mailpme->thread_num); + + if((g_mail_localinfo.protocol_flag&MAIL_PASSWARD) == 0) + { + break; + } + + if(pelem->buf != NULL) + { + rec = call_biz_per_line(mailpme, MAIL_PASSWARD, pelem->buf, pelem->buflen, NULL, a_stream, raw_pkt); + if(rec & PROT_STATE_DROPME) + drop_set_value(mailpme); + } + break; + + case POP3_CMD_RETR: + break; + case POP3_CMD_RESET: + case POP3_CMD_QUIT: + break; + + case POP3_CMD_STLS: + if(g_mail_localinfo.protocol_flag&MAIL_STARTTLS_CMD) + { + rec = call_biz_per_line(mailpme, MAIL_STARTTLS_CMD, output_line, 4, NULL, a_stream, raw_pkt); //4 = strlen("STLS"); + if(rec & PROT_STATE_DROPME) + { + drop_set_value(mailpme); + } + return PROT_STATE_DROPME; + } + break; + + default: + break; + } + + if(rec&PROT_STATE_DROPPKT) + { + break; + } + } + mailpme->iDataPointer = 0; + + return (rec&PROT_STATE_DROPPKT)?PROT_STATE_DROPPKT:PROT_STATE_GIVEME; +} + + + +/**************************************************************************** +������:pop3_entry_fun() +���ܣ�POP3��ں��� +���룺stream.h +�����stream.h +����ֵ: APP_STATE_GIVEME/APP_STATE_DROPME/APP_STATE_DROPPKT +*****************************************************************************/ +char pop3_entry_fun(struct streaminfo *a_tcp, void **pme, int thread_seq,const void *raw_pkt) +{ + int rec = PROT_STATE_GIVEME; + stMailPme* mailpme = (stMailPme*)(*(pme)); + struct tcpdetail *ptcpdetail = a_tcp->ptcpdetail; + + switch(a_tcp->opstate) + { + case OP_STATE_PENDING: + if(POP3_PROTOCOL == mail_identify_pop3(a_tcp, (char *)ptcpdetail->pdata, ptcpdetail->datalen, thread_seq)) + { + rec = mail_init_mailpme(&mailpme,MAIL_SERVICE_POP3,a_tcp,raw_pkt); + if(rec < 0) + { + MESA_HANDLE_RUNTIME_LOG(g_mail_localinfo.runtime_log,RLOG_LV_FATAL, POP3MODULE, "mail_init_mailpme() error!"); + return APP_STATE_DROPME; + } + *pme = (void*)mailpme; + } + else + { + return APP_STATE_DROPME; + } + project_req_add_uint(a_tcp, g_mail_localinfo.proto_identify_id, POP3_PROTOCOL); + //no break here. + + case OP_STATE_DATA: + if(a_tcp->curdir == DIR_S2C) + { + //if(ptcpdetail->lostlen>0) + //{ + // mailpme->s_total_loss += ptcpdetail->lostlen; + //} + + rec = pop3_process_s2c(mailpme, a_tcp, raw_pkt); + if(rec & PROT_STATE_DROPME) + { + mail_clear_mailpme(mailpme, a_tcp, raw_pkt); + return APP_STATE_DROPME; + } + } + else if(a_tcp->curdir == DIR_C2S) + { + rec = pop3_process_c2s(mailpme, a_tcp, raw_pkt); + if(rec & PROT_STATE_DROPME) + { + mail_clear_mailpme(mailpme, a_tcp, raw_pkt); + return APP_STATE_DROPME; + } + } + assert(mailpme->thread_num==a_tcp->threadnum); + break; + + case OP_STATE_CLOSE: + if(g_mail_localinfo.stat_trig) + { + FS_operate(g_mail_localinfo.fsstat_handle, g_mail_localinfo.stat_id[STAT_ID_MAIL_PKTS], 0, FS_OP_ADD, a_tcp->ptcpdetail->serverpktnum+a_tcp->ptcpdetail->clientpktnum); + FS_operate(g_mail_localinfo.fsstat_handle, g_mail_localinfo.stat_id[STAT_ID_MAIL_BYTES], 0, FS_OP_ADD, a_tcp->ptcpdetail->serverbytes+a_tcp->ptcpdetail->clientbytes); + } + mail_add_proto_tag(g_mail_localinfo.proto_tag_id, a_tcp, "MAIL", strlen("MAIL")); + mail_clear_mailpme(mailpme,a_tcp,raw_pkt); + return APP_STATE_DROPME; + + default: + return APP_STATE_DROPME; + } + + if(rec & PROT_STATE_DROPME) + return APP_STATE_DROPME; + else if(rec & PROT_STATE_DROPPKT) + return APP_STATE_DROPPKT; + else + return APP_STATE_GIVEME; +} + + +#define MATCHSTR(x,st) \ + (memcmp(&(x),(st),sizeof(x))==0) + + +int mail_identify_pop3(struct streaminfo *a_tcp, char *payload, int payload_len, int thread_seq) +{ + if (a_tcp->opstate == OP_STATE_PENDING) + { + if (a_tcp->curdir == DIR_S2C && ((payload_len >= 3 && (strncmp(payload, POP3_STR_OK, 3) == 0)) || (payload_len >= 4 && (strncmp(payload, POP3_STR_ERR, 4) == 0)))) + { + return POP3_PROTOCOL; + } + else if (a_tcp->curdir == DIR_C2S && payload_len >= 4 && line_is_pop3_cmd(payload, payload_len)) + { + + switch(a_tcp->addr.addrtype) + { + case ADDR_TYPE_IPV4: + if(a_tcp->addr.tuple4_v4->dest == ntohs(21) || a_tcp->addr.tuple4_v4->dest == ntohs(80) || a_tcp->addr.tuple4_v4->dest == ntohs(8080) || a_tcp->addr.tuple4_v4->dest == ntohs(8021) ) + return -1; + break; + case ADDR_TYPE_IPV6: + if(a_tcp->addr.tuple4_v6->dest == ntohs(21)|| a_tcp->addr.tuple4_v4->dest == ntohs(80) || a_tcp->addr.tuple4_v4->dest == ntohs(8080)|| a_tcp->addr.tuple4_v4->dest == ntohs(8021)) + return -1; + default: + break; + } + return POP3_PROTOCOL; + } + } + + return -1; +} + diff --git a/decoders/mail/version.map b/decoders/mail/version.map new file mode 100644 index 0000000..7b51c5d --- /dev/null +++ b/decoders/mail/version.map @@ -0,0 +1,10 @@ +VERS_3.0 { + global: + extern "C" { + mail_init; + mail_exit; + mail_subscribe; + module_to_mail_decoder; + }; + local: *; +}; |
