Wincap抓取邮件的程序,邮件解析出现非常大的文件
Wincap抓取邮件的程序,用了一个线程,把抓取的邮件解析出来,但点暂定后过一段时间点继续,目录下会出现一个非常大的文件,删除要很长时间,大家看一看……
//看见有人编辑了,但是没看到改动啊……不太熟悉德问这种方式……
//主要函数
//write_to_file
//packet_handler
//pcap_loop
//CreateThread SuspendThread TerminateThread
//我觉得出错的地方应该在这几个地方,请大家耐心看一下吧
//我觉得错误不好找,大牛一眼就看出来了……非常感谢
//架构很差,不要见笑,因为是从控制台程序直接转过来的,没办法封装了……
//大家有此经验的不妨说一下,把纯C++的代码转到MFC下如果保持封装
#include "stdafx.h"
#include "MailCap.h"
#include "MailCapDlg.h"
#include "afxdialogex.h"
#include "SelectAdapter.h"
#include "Function.h"
#include "IPGram.h"
#include "TCPGram.h"
#include <iostream>
#include "Linklist.h"
#include <fstream>
#include <stdio.h>
#include "Base64.h"
//#include <string>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
long ip_saddr,ip_daddr;
Linklist link;
//char key[20];
IPGram *ip;
TCPGram *tcp;
ip_header *ih;
tcp_header *th;
u_short ip_tlen;
u_int ip_len;
pcap_t *adhandle=NULL;
HANDLE hThread;
u_int netmask;
CMailCapDlg *pMailCap=NULL;
bool write_to_file(std::string fileName);
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 对话框数据
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CMailCapDlg 对话框
CMailCapDlg::CMailCapDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CMailCapDlg::IDD, pParent)
, m_capter(TRUE)
, m_columnIndex(0)
, m_stop(false)
, m_RowIndex(0)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
CMailCapDlg::~CMailCapDlg()
{
}
void CMailCapDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_LIST, m_list);
}
BEGIN_MESSAGE_MAP(CMailCapDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_STOPCAP, &CMailCapDlg::OnBnClickedStopcap)
ON_BN_CLICKED(IDC_STARTCAP, &CMailCapDlg::OnBnClickedStartcap)
ON_BN_CLICKED(IDC_PAUSECAP, &CMailCapDlg::OnBnClickedPausecap)
ON_BN_CLICKED(IDC_QUERY, &CMailCapDlg::OnBnClickedQuery)
END_MESSAGE_MAP()
// CMailCapDlg 消息处理程序
BOOL CMailCapDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
pMailCap=this;
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
m_list.InsertColumn(this->m_columnIndex++,"文件",LVCFMT_CENTER,170);
m_list.SetExtendedStyle(LVS_EX_FULLROWSELECT
|LVS_EX_GRIDLINES //网格线
|LVS_EDITLABELS //可编辑
|LVS_EX_FULLROWSELECT//高亮
|LVS_REPORT
);
m_list.SetTextBkColor(RGB(204,255,204));
m_list.SetBkColor(RGB(204,255,204));
//UpdateData(false);
char errbuf[PCAP_ERRBUF_SIZE+1];
/* Retrieve the device list */
if(pcap_findalldevs(&m_alldevs, errbuf) == -1)
{
CString ErrInfo;
ErrInfo.Format("Error in pcap_findalldevs: %s\n", errbuf);
MessageBox(ErrInfo,"Error",MB_OK|MB_ICONERROR);
exit(1);
}
this->m_selectDev=this->m_alldevs;
CSelectAdapter Adapter(this->m_alldevs,NULL);
/* Scan the list printing every entry */
if(Adapter.DoModal() == IDOK)
{
pcap_if_t *d=m_alldevs;
for(int i=0;i <= Adapter.m_currentSel;i++)
{
this->m_selectDev=d;
d=d->next;
}
}
else
{
exit (0);
}
if((adhandle=pcap_open_live(m_selectDev->name,65536,1,1000,errbuf)) == NULL)
{
MessageBox(_T("打开适配器失败!"),_T("错误"),MB_OK|MB_ICONERROR);
}
if(pcap_datalink(adhandle) != DLT_EN10MB)
{
MessageBox(_T("此程序只对以太网有效!"),_T("错误"),MB_OK|MB_ICONERROR);
pcap_freealldevs(this->m_alldevs);
return NULL;
}
if(this->m_selectDev->addresses != NULL)
////////////////////////////////////////////////获取接口首地址的掩码
netmask=((struct sockaddr_in *)(this->m_selectDev->addresses->netmask))->sin_addr.S_un.S_addr;
else
//////////////////////////////////////////////////如果接口没有地址,我们设定为c网
netmask=0xffffff;
////////////////////////////////////////////////编辑筛选器
struct bpf_program fcode;
char packet_filter[] = "ip and tcp";
if(pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) <0 )
{
MessageBox(_T("不能编译包筛选器. 请检查语法."),_T("错误"),MB_OK|MB_ICONERROR);
pcap_freealldevs(this->m_alldevs);
return NULL;
}
////////////////////////////////////////////////设定筛选器
if(pcap_setfilter(adhandle, &fcode)<0)
{
MessageBox(_T("错误设置筛选器."),_T("错误"),MB_OK|MB_ICONERROR);
pcap_freealldevs(this->m_alldevs);
return NULL;
}
GetDlgItem(IDC_QUERY)->EnableWindow(FALSE);
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CMailCapDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CMailCapDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CMailCapDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
ih = (ip_header *) (pkt_data +14); /////////////14 是以太网头的长度
ip_len = (ih->ver_ihl & 0xf) * 4; /////////////IP 头的长度
//////////////////////////////////////////////获取tcp头的位置
th = (tcp_header *) ((u_char*)ih + ip_len);
ip_tlen=ntohs(ih->tlen);
//////////////////////////////////////////////构造IP头
ip=new IPGram(pkt_data +14,ip_tlen);
//////////////////////////////////////////////
tcp=new TCPGram(pkt_data +14+ip_len,ip_tlen-ip_len);
if(25 == tcp->destport || 110 == tcp->srcport)
{
if(tcp->datalen > 0 )
{
if(link.m_listLength==0)
{
if(link.InsertNode(*ip,*tcp))
{
ip_saddr=ip->srcaddr;
ip_daddr=ip->destaddr;
}
else
{
return;
}
}
else
{
if(ip_saddr==ip->srcaddr && ip_daddr==ip->destaddr )
{
if(!link.InsertNode(*ip,*tcp))
{
return;
}
}
}
}
if(tcp->FIN && ip_saddr==ip->srcaddr && ip_daddr==ip->destaddr)
{
std::string str="capEmail";
CTime now=now.GetTickCount();
std::string time=now.Format(_T("%Y%m%d%H%M%S"));
std::string fileName=str+"-"+time+".eml";
write_to_file(fileName);
pMailCap->Insert2List(fileName);
}
}
delete []ip;
delete []tcp;
}
bool CMailCapDlg::findKeyWord(std::string file,std::string kword)
{
int handle;
handle = open(file.c_str(), 0x0100); //open file for read
long length = filelength(handle); //get length of file
char *readData=new char[length];
if(0 != handle)
{
read(handle,readData,length);
if(strstr(readData,kword.c_str())!= NULL)
{
return true;
}
else
{
return false;
}
}
else
{
MessageBox("打开文件出错","错误",MB_OK|MB_ICONERROR);
return false;
}
close(handle);
}
bool write_to_file(std::string fileName)
{
int i=0,j=0;
unsigned char ch;
FILE *fp=NULL;
unsigned char *buf=NULL;
LNode *pTemp=NULL;
unsigned int startNum=0,endNum=0;
int bufLen=0;
fp=fopen(fileName.c_str(),"w+"); //打开文件
if(fp==NULL)
{
return 0;
}
pTemp=link.m_pList->next;
startNum=pTemp->tcp->seqnum;
while(pTemp->next!=NULL)
{
pTemp=pTemp->next;
}
endNum=pTemp->tcp->seqnum;
bufLen=endNum-startNum+pTemp->tcp->datalen;
buf=new unsigned char[bufLen];
pTemp=link.m_pList->next;
while(pTemp!=NULL)
{
i=pTemp->tcp->seqnum-startNum;
for(j=0;j<pTemp->tcp->datalen;j++)
{
buf[i+j]=pTemp->tcp->data[j];
}
pTemp=pTemp->next;
}
for(i=0;i < bufLen;i++)
{
ch=buf[i];
fputc(ch,fp);
}
fputc('\n',fp);
fclose(fp);
delete []buf;
return 1;
}
DWORD WINAPI CMailCapDlg:: Listening(LPVOID lparam)
{
if(adhandle == NULL)
{
AfxMessageBox(_T("初始化失败"),MB_OK|MB_ICONERROR);
return 0;
}
while(1) {
pcap_loop(adhandle,1,packet_handler,NULL);
}
return 0;
}
void CMailCapDlg::OnBnClickedStopcap()
{
// TODO: 在此添加控件通知处理程序代码
this->m_stop=true;
if(this->m_capter){
MessageBox(_T("没有开始监听!"),_T("错误"),MB_OK);
}
else {
TerminateThread(hThread,0);
this->m_capter=GetDlgItem(IDC_STARTCAP)->EnableWindow(TRUE);
GetDlgItem(IDC_QUERY)->EnableWindow(TRUE);
link.ClearList();
delete []ip;
delete []tcp;
}
}
void CMailCapDlg::OnBnClickedStartcap()
{
// TODO: 在此添加控件通知处理程序代码
this->m_capter=GetDlgItem(IDC_STARTCAP)->EnableWindow(FALSE);
SetDlgItemText(IDC_PAUSECAP,_T("暂停监听"));
GetDlgItem(IDC_QUERY)->EnableWindow(FALSE);
hThread=CreateThread(NULL,0,CMailCapDlg::Listening,(LPVOID)this,0,NULL);
}
void CMailCapDlg::OnBnClickedPausecap()
{
// TODO: 在此添加控件通知处理程序代码
CString str;
GetDlgItemText(IDC_PAUSECAP,str);
if(this->m_capter)
{
MessageBox(_T("没有开始监听!"),_T("错误"),MB_OK);
}
else
{
if(str == _T("暂停监听"))
{
SetDlgItemText(IDC_PAUSECAP,_T("继续监听"));
SuspendThread(hThread);
GetDlgItem(IDC_QUERY)->EnableWindow(TRUE);
}
else
{
SetDlgItemText(IDC_PAUSECAP,_T("暂停监听"));
GetDlgItem(IDC_QUERY)->EnableWindow(FALSE);
ResumeThread(hThread);
}
}
}
void CMailCapDlg::Insert2List(std::string str)
{
int nRow=this->m_list.InsertItem(0,"");
this->m_list.SetItemText(m_RowIndex++,0,str.c_str());
}
CMailCapDlg * CMailCapDlg::GetThis(void)
{
return this;
}
void CMailCapDlg::OnBnClickedQuery()
{
// TODO: 在此添加控件通知处理程序代码
GetDlgItem(IDC_STARTCAP)->EnableWindow(FALSE);
int count=this->m_list.GetItemCount();
if(0 == count)
{
MessageBox(_T("没有获取到邮件!"),_T("提示"),MB_OK);
return;
}
CString keyWord,file;
GetDlgItemText(IDC_KEYWORD,keyWord);
this->m_list.InsertColumn(this->m_columnIndex,"关键字:"+keyWord,LVCFMT_CENTER,155);
for(int i=0;i<count;i++)
{
file=this->m_list.GetItemText(i,0);
if(this->findKeyWord(file.GetBuffer(),keyWord.GetBuffer()))
{
// this->m_list.InsertItem(this->m_columnIndex,"");
this->m_list.SetItemText(i,this->m_columnIndex,"包含此关键字");
}
}
file.ReleaseBuffer();
keyWord.ReleaseBuffer();
if(this->m_stop)GetDlgItem(IDC_STARTCAP)->EnableWindow(TRUE);
}
lzqyydy
12 years, 7 months ago