📄 client.cpp
字号:
mailBoxName=string(".\\")+mailBoxName;
hSearch = FindFirstFile(mailBoxName.c_str(), &FileData);
if (hSearch == INVALID_HANDLE_VALUE||
FileData.dwFileAttributes!=FILE_ATTRIBUTE_DIRECTORY)
{
CreateDirectory(mailBoxName.c_str(),NULL);
}
mailBoxName=username+"."+server;
FindClose(hSearch);
}
void GivenUniqueFileName(const string& dir,
const string& subject,
string& name,
string postfix)
{
//if subject is NULL,
WIN32_FIND_DATA FileData;
HANDLE hSearch;
char buffer[BUFFER_BLOCK_SIZE];
int count=1;
string curdir=".\\";
string title=subject;
RenameFileName(title);
sprintf(buffer,"%s",postfix.c_str());
while(1)
{
name=curdir+dir+"\\"+title+buffer;
hSearch = FindFirstFile(name.c_str(), &FileData);
if (hSearch == INVALID_HANDLE_VALUE)
break;
if(FileData.dwFileAttributes==FILE_ATTRIBUTE_DIRECTORY)
{
hSearch = FindFirstFile(name.c_str(), &FileData);
if (hSearch == INVALID_HANDLE_VALUE)
break;
}
sprintf(buffer,"(%d)%s",count++,postfix.c_str());
}
FindClose(hSearch);
}
void ResolveOneLineWords(const char* text, string& buffer)
{
char *tP;
string src;
if((tP=strstr(text,"?B?"))==NULL)
{
if(text[0]==' ')
buffer=text+1;
else
buffer=text;
return;
}
else
{
if(strstr(text,"=?")==NULL ||strstr(text,"?=")==NULL)
{
buffer=text;
return;
}
tP+=3;
while(*tP!='?')
src+=*tP++;
assert(src.length()%4==0);
tP= new char[(src.length()/4+1)*3];
DecodingBase64(src.c_str(),tP);
std::string des;
UTF8Decode(tP, des);
buffer=tP;
delete[] tP;
tP=strstr(text,"?=");
tP+=2;
buffer+=tP;
}
}
void UTF8Decode(const std::string& src, std::string& des)
{
char str[BUFFER_BLOCK_SIZE];
std::string::size_type pos=0;
BOOL bBase64=FALSE;
WCHAR wszUserName[BUFFER_BLOCK_SIZE/2]; // Unicode user name
// int length=MultiByteToWideChar( CP_ACP, 0, addr.c_str(),addr.length()+1, wszUserName,
// sizeof(wszUserName)/sizeof(WCHAR));
int length=MultiByteToWideChar( CP_ACP, 0, src.c_str(),src.length()+1, wszUserName,
sizeof(wszUserName)/sizeof(WCHAR));
WideCharToMultiByte(CP_UTF8, 0, wszUserName, wcslen(wszUserName),
str, BUFFER_BLOCK_SIZE,NULL,NULL);
des=des;
}
int RetrieveAllEmail(SOCKET& sock,const string& mailboxname, BOOL bDel)
{
int numOfMails;
string content;
string filename;
int i;
int retCode;
vector<int> newMailID;
vector<string> newMailUID;
retCode=STAT(sock,numOfMails);
DEAL_RETURN_CODE(retCode);
retCode=GetAllNewMailsID(sock, mailboxname, newMailID, newMailUID);
//RETR
for(i=0; i<newMailID.size(); i++)
{
retCode=RETR(sock, newMailID[i], content);
DEAL_RETURN_CODE(retCode);
if(bDel)
{
retCode=DELE(sock,newMailID[i]);
DEAL_RETURN_CODE(retCode);
}
WriteMailToFile(mailboxname, content,filename);
PrintMail(mailboxname, filename);
WriteDownloadMailUID(mailboxname,newMailUID[i]);
}
// retCode=RSET(sock);
// DEAL_RETURN_CODE(retCode);
retCode=QUIT(sock); //leave transaction state, enter UPDATE state, all deleted files are removed
DEAL_RETURN_CODE(retCode);
return 0;
}
int STAT(SOCKET sock, int& numOfMails)
{
char buffer[BUFFER_BLOCK_SIZE];
int retCode;
sprintf(buffer,"STAT\r\n");
cout<<buffer;
send(sock,buffer,strlen(buffer),0);
retCode=recv(sock,buffer,BUFFER_BLOCK_SIZE,0);
DEAL_SOCK_ERROR(retCode,sock);
buffer[retCode]='\0';
cout<<buffer;
DEAL_RETURN_CODE(buffer[0]);
sscanf(buffer+3,"%d",&numOfMails);
return 0;
}
int RETR(SOCKET sock, int mailID,string& content)
{
char buffer[BUFFER_BLOCK_SIZE*10+1];
char *tP;
int retCode;
int length;
if(LIST(sock, mailID, length)!=0)
return 1;
sprintf(buffer,"RETR %d\r\n",mailID);
cout<<buffer;
send(sock,buffer,strlen(buffer),0);
retCode=recv(sock,buffer,BUFFER_BLOCK_SIZE*10,0);
DEAL_SOCK_ERROR(retCode,sock);
buffer[retCode]='\0';
cout<<buffer;
DEAL_RETURN_CODE(buffer[0]);
cout.flush();
tP=strchr(buffer,int('\n'));
tP++;
content=tP;
length-=content.length();
while(length>0)
{
retCode=recv(sock,buffer,BUFFER_BLOCK_SIZE*10,0);
DEAL_SOCK_ERROR(retCode,sock);
buffer[retCode]='\0';
content+=buffer;
length-=retCode;
}
return 0;
}
int DELE(SOCKET sock,int mailID)
{
char buffer[BUFFER_BLOCK_SIZE+1];
int retCode;
sprintf(buffer,"DELE %d\r\n",mailID);
cout<<buffer;
send(sock,buffer,strlen(buffer),0);
retCode=recv(sock,buffer,BUFFER_BLOCK_SIZE,0);
DEAL_SOCK_ERROR(retCode,sock);
buffer[retCode]='\0';
cout<<buffer;
DEAL_RETURN_CODE(buffer[0]);
return 0;
}
int LIST(SOCKET sock,int mailID, int& length)
{
char buffer[BUFFER_BLOCK_SIZE+1];
int retCode;
sprintf(buffer,"LIST %d\r\n",mailID);
cout<<buffer;
send(sock,buffer,strlen(buffer),0);
retCode=recv(sock,buffer,BUFFER_BLOCK_SIZE*10,0);
DEAL_SOCK_ERROR(retCode,sock);
buffer[retCode]='\0';
cout<<buffer;
DEAL_RETURN_CODE(buffer[0]);
sscanf(buffer+3,"%d%d",&mailID,&length);
return 0;
}
//cancel all mail tags which maked as deleted
int RSET(SOCKET sock)
{
char buffer[BUFFER_BLOCK_SIZE+1];
int retCode;
strcpy(buffer,"RSET\r\n");
cout<<buffer;
send(sock,buffer,strlen(buffer),0);
retCode=recv(sock,buffer,BUFFER_BLOCK_SIZE,0);
DEAL_SOCK_ERROR(retCode,sock);
buffer[retCode]='\0';
cout<<buffer;
DEAL_RETURN_CODE(buffer[0]);
return 0;
}
int QUIT(SOCKET sock)
{
char buffer[BUFFER_BLOCK_SIZE];
int retCode;
strcpy(buffer,"QUIT\r\n");
cout<<buffer;
send(sock,buffer,strlen(buffer),0);
retCode=recv(sock,buffer,BUFFER_BLOCK_SIZE,0);
DEAL_SOCK_ERROR(retCode,sock);
buffer[retCode]='\0';
cout<<buffer;
DEAL_RETURN_CODE(buffer[0]);
return 0;
}
int GetAllNewMailsID( SOCKET sock,
const string& mailboxname,
vector<int>& newMailID,
vector<string>& newMailUID)
{
char buffer[BUFFER_BLOCK_SIZE];
string str,substr;
int retCode;
string::size_type pos,lastpos;
vector<string> UIDList;
int i;
newMailID.clear();
newMailUID.clear();
strcpy(buffer,"UIDL\r\n");
cout<<buffer;
send(sock,buffer,strlen(buffer),0);
while(1)
{
retCode=recv(sock,buffer,BUFFER_BLOCK_SIZE,0);
DEAL_SOCK_ERROR(retCode,sock);
buffer[retCode]='\0';
cout<<buffer;
cout.flush();
str+=buffer;
DEAL_RETURN_CODE(str[0]);
if(strcmp(str.c_str()+str.length()-5,"\r\n.\r\n")==0)
break;
}
lastpos=0;
pos=0;
//omit +OK\r\n
pos=str.find("\r\n",pos);
pos+=2;
lastpos=pos;
while((pos=str.find("\r\n",pos))!=string::npos)
{
substr=str.substr(lastpos,pos-lastpos);
pos+=2;
lastpos=pos;
sscanf(substr.c_str(),"%d%s",&retCode,buffer);
newMailID.push_back(retCode);
newMailUID.push_back(buffer);
}
//pop the dot tag
newMailID.pop_back();
newMailUID.pop_back();
GetMailsUIDList(mailboxname,UIDList);
for(i=0; i<UIDList.size(); i++)
{
vector<string>::iterator ite;
if((ite=std::find(newMailUID.begin(),newMailUID.end(),UIDList[i]))!=newMailUID.end())
{
newMailID.erase(newMailID.begin()+(ite-newMailUID.begin()));
newMailUID.erase(ite);
}
}
cout<<"New Mail Num: "<<newMailID.size()<<endl;
return 0;
}
//write to file
void WriteMailToFile(const string& mailboxname, const string& content, string& filename)
{
string title;
string str;
string::size_type pos=0,endPos=0;
if((pos=content.find("\r\n\r\n",pos))!=string::npos)
{
str=content.substr(0,pos);
pos=0;
if((pos=str.find("Subject:",pos))!=string::npos)
{
if(pos==0 || str[pos-1]=='\n')
{
endPos=pos;
if((endPos=str.find('\r',endPos))!=string::npos)
{
title=str.substr(pos+8,endPos-pos-8);
}
}
}
}
if(title.length()==0)
title="1";
ResolveOneLineWords(title.c_str(),str);
title=str;
GivenUniqueFileName(mailboxname,title,filename);
ofstream file(filename.c_str(),ios::binary);
assert(!file.fail());
if(file.fail())
{
GivenUniqueFileName(mailboxname,"1",filename);
file.open(filename.c_str(),ios::binary);
}
file.write(content.c_str(),content.length());
file.close();
filename=filename.substr(mailboxname.length()+3,filename.length()-3-mailboxname.length());
}
void RenameFileName(string& filename)
{
char illegalChar[]="\\/:*?\"<>|";
int i=0;
string::size_type pos=0;
while((pos=filename.find_first_of(illegalChar, pos))!=string::npos)
{
filename.replace(pos,1,"_");
}
}
void PrintMail(const string& mailboxname, const string& filename)
{
string sender;
string date;
string from,to,cc;
string subject;
string bodytext;
string bodyhtml;
map<string, string> attachmentNames;
int iResult;
iResult=ResolveMail(mailboxname,filename,sender,date,from,to,cc,subject,bodytext,bodyhtml,attachmentNames);
cout<<"MailBox: "<<mailboxname.c_str()<<endl;
cout<<"Subject:"<<subject.c_str()<<endl;
cout<<"From:"<<from.c_str()<<endl;
if(to.length())
cout<<"From:"<<to.c_str()<<endl;
if(cc.length())
cout<<"Cc:"<<cc.c_str()<<endl;
if(bodytext.length())
cout<<"Mail content lists as follows:"<<endl<<bodytext.c_str()<<endl;
if(bodyhtml.length())
cout<<"Mail's html content lists as follows:"<<endl<<bodyhtml.c_str()<<endl;
if(attachmentNames.size())
{
cout<<"Mail's attachments file names list as follows:"<<endl;
for(map<string, string>::iterator pos=attachmentNames.begin() ;
pos!=attachmentNames.end() ; pos++)
cout<<(*pos).first.c_str()<<endl;
}
}
//contentType 0: only text/plain
// 1: only text/html
// 2: only attachment
// 3: mixed boundary majorSplitTag
int DataHead(ifstream& file,
string& senderAddr,
string& date,
string& from, //for most mail server, it only support youself address
string& to,
string& cc,
string & subject,
string & tagStr, //majorSplitTag or filename
int& contentType,
BOOL& bBase64) //this parameters make effect only when contentType is 0,1,2
{
string str;
char buffer[BUFFER_BLOCK_SIZE];
string::size_type pos=0;
string command,result;
BOOL bContextTypeState=FALSE;
senderAddr="";
from="";
to="";
cc="";
subject="";
tagStr="";
//data head
while(1)
{
file.getline(buffer,BUFFER_BLOCK_SIZE);
str=buffer;
if(str.length()==0)
break;
pos=0;
if((pos=str.find(':',pos))!=string::npos)
{
bContextTypeState=FALSE;
command=str.substr(0,pos);
str=str.substr(pos+1,str.length()); //space
if(command=="From")
ResolveOneLineWords(str.c_str(),from);
else if(command=="To")
ResolveOneLineWords(str.c_str(),to);
else if(command=="Subject")
ResolveOneLineWords(str.c_str(),subject);
else if(command=="Cc")
ResolveOneLineWords(str.c_str(),cc);
else if(command=="Date")
date=str;
else if(command=="Reply-To")
ResolveOneLineWords(str.c_str(),senderAddr);
else if(command=="Content-Type")
{
//here we deal three types
//text/plain, multipart/alternative, multipart/mixed
pos=0;
if((pos=str.find("text/plain",pos))!=string::npos)
contentType=0;
else if((pos=str.find("text/html",pos))!=string::npos)
contentType=1;
else
contentType=3;
bContextTypeState=TRUE;
}
else if(command=="Content-Transfer-Encoding")
{
if(strstr(str.c_str(),"base64")!=NULL)
bBase64=TRUE;
else
bBase64=FALSE;
}
}
else
{
if(bContextTypeState)
{
pos=0;
if(str.find("filename=",pos)!=string::npos)
{
if(str[0]=='\t')
{
pos=str.find("\"",pos);
tagStr=str.substr(pos+1,str.length()-1);
contentType=2; //only attachment
}
}
else if(contentType==3)
{
if(strstr(str.c_str(),"boundary=")!=NULL && str[0]=='\t')
{
pos=0;
pos=str.find('\"',pos);
str=str.substr(pos+1,str.length());
pos=0;
pos=str.find('\"',pos);
tagStr=str.substr(0,pos);
tagStr=string("--") + tagStr;
}
}
}
}
}
return 0;
}
//A simple token analysis function. Using automatic finite machine.
BOOL ResolveMail(const string& mailboxname,
const string& filename,
string& senderAddr,
string& date,
string& from, //for most mail server, it only support youself address
string& to,
string& cc,
string & subject,
string & bodytext,
string & bodyhtml,
map<string, string> & attachmentNames)
{
string str=".\\";
ifstream file;
int contentType;
string tagStr;
BOOL bBase64;
ofstream downloadFile;
str=str+mailboxname+"\\"+filename;
file.open(str.c_str());
if(file.fail())
{
cout<<"Cannot open the specified mail."<<endl;
return FALSE;
}
DataHead(file,senderAddr,date, from,to,cc,subject,tagStr,contentType,bBase64);
//if content==2 , it standards the filename else majorSplitTag
DataBody(file,mailboxname, bBase64, contentType, tagStr, bodytext, bodyhtml,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -