summaryrefslogtreecommitdiff
path: root/decoders/mail
diff options
context:
space:
mode:
authorzhuzhenjun <[email protected]>2024-11-27 08:26:41 +0000
committerzhuzhenjun <[email protected]>2024-11-27 08:26:41 +0000
commit3694c142d974ab35f55bde4a8519525b9afcbc84 (patch)
treece92ad91f08e6ec8c81e2899d6ff93327ef7bff1 /decoders/mail
parentd0a868591470a4a9d71a65a5d540058e72c8d92c (diff)
tmp
Diffstat (limited to 'decoders/mail')
-rw-r--r--decoders/mail/CMakeLists.txt13
-rw-r--r--decoders/mail/mail_decoder_codec.c695
-rw-r--r--decoders/mail/mail_decoder_codec.h18
-rw-r--r--decoders/mail/mail_decoder_email.c1487
-rw-r--r--decoders/mail/mail_decoder_email.h275
-rw-r--r--decoders/mail/mail_decoder_imap.h92
-rw-r--r--decoders/mail/mail_decoder_mime.c663
-rw-r--r--decoders/mail/mail_decoder_mime.h122
-rw-r--r--decoders/mail/mail_decoder_module.c498
-rw-r--r--decoders/mail/mail_decoder_module.h96
-rw-r--r--decoders/mail/mail_decoder_pop3.h35
-rw-r--r--decoders/mail/mail_decoder_smtp.c573
-rw-r--r--decoders/mail/mail_decoder_smtp.h67
-rw-r--r--decoders/mail/mail_decoder_util.c568
-rw-r--r--decoders/mail/mail_decoder_util.h61
-rw-r--r--decoders/mail/mail_imap.c1440
-rw-r--r--decoders/mail/mail_pop3.c489
-rw-r--r--decoders/mail/version.map10
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: *;
+};