环境:xp系统,vc6.0、c语言
这里是代码的草稿,原本设计的结构跟现在撸出来的结构相差比较大
实现的部分:
smtp协议,可以完成最简邮件格式的发送,收件人可以正常收到
base64编码,可以完成对任意长度的字符串进行base64编码
base64解码,只是完成了对单个字节解码
pop协议,只是完成了基本的服务器交互指令,对于data部分的接收没有实现
我的想法是摸索阶段的代码一定不会使用c++,进行整合优化的时候会考虑使用c++封装
还有看的时候,可能会感觉代码比较乱,如果愿意的话,可以给我一些建议
#include <Winsock2.h>
#include <stdio.h>
#include <windows.h>
#pragma comment(lib,"ws2_32.lib")
#define PORTPOP 110
#define PORTSMTP 25
#define BUFF_BASE64 1024*1024*4 //开辟4M的base64编码的存储区,2M发送的数据,2M接收的数据
char *buff_begin;//缓冲区的起始指针
unsigned long num_now;//缓冲区当前字节数
char *point_now;//指向当前缓冲区的可用部分
struct base64{
char result;//base64加密后的结果
char residue;//原数据剩下的部分
int number;//位移的位数
};
char base64_char[64]={'A','B','C','D','E','F','G','H',
'I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X',
'Y','Z','a','b','c','d','e','f',
'g','h','i','j','k','l','m','n',
'o','p','q','r','s','t','u','v',
'w','x','y','z','0','1','2','3',
'4','5','6','7','8','9','+','/',};
int chartonumber(base64 *data); //编码:数字转换为对应字母
int transformtobase64(base64 *data); //编码:对单字节编码
int transformstring(char *strings); //编码:对字符串编码
//套接字是否已经连接
int condition_pop3=0;
int tcp_pop(SOCKET pop,sockaddr_in saddr,char *r_buffer,char *s_buffer);
int tcp_smtp(char *r_buffer,char *s_buffer);
char *name="servertss"; //用户名
char *pasw="12345zxcvb";//密码
char *capa="CAPA";
char *user="USER";//用户名
char *pass="PASS";//密码
char *apop="APOP";//指定邮箱和MD5摘要串
char *stat="STAT";//请求邮件总数和总字节数
char *uidl="UIDL";//返回邮件的唯一标识符
char *list="LIST";//返回邮件数量和每个邮件的大小
char *retr="RETR";//返回由参数标识的邮件的全部文本
char *dele="DELE";//服务器将由参数标识的邮件标记为删除
char *rset="RSET";//服务器将重置所有标记为删除的邮件,用于撤销DELE命令
char *top="TOP";//服务器将返回由参数标识的邮件前n行内容,n必须是正整数
char *noop="NOOP";//服务器返回一个肯定的响应
char *quit="QUIT";//结束会话
char *ok="+OK";//服务器确认标识
char crlf[2]={'\r','\n'};//结束标志
char *ehlo="EHLO";//开始SMTP会话
char *auth="AUTH";
char *login="LOGIN";
char *mail="MAIL";//邮件开始
char *from="FROM";//发件方地址
char *rcpt="RCPT";//收件方地址
char *data="DATA";//邮件正文开始
char *vrfy="VRFY";//用于验证指定的用户/邮箱是否存在
char *expn="EXPN";//验证给定的邮箱列表是否存在,扩充邮箱列表,常被禁用
char *help="HELP";//查询服务器支持什么命令
int senddata(char *begin);
int main()
{
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested=MAKEWORD(2,2);
int err=WSAStartup(wVersionRequested,&wsaData);
if(err!=0)
{
printf("WSAStartup函数加载失败\n");
return 0;
}
buff_begin=(char *)malloc(BUFF_BASE64);
if(!buff_begin)
return 0;
num_now=0;
point_now=buff_begin;
char request[512];//客户端请求缓冲
char respond[512];//服务器回应缓冲
//memset(request,'\0',512);
//memset(respond,'\0',512);
sockaddr_in saddr_pop;
saddr_pop.sin_family=AF_INET;
saddr_pop.sin_port=htons(PORTPOP);
saddr_pop.sin_addr.s_addr= inet_addr("123.125.50.29");
SOCKET client_pop;
client_pop=socket(AF_INET,SOCK_STREAM,0);
/*
char *s="这是一份测试邮件";
transformstring(s);
for(int i=0;i<num_now;i++)
{
printf("%c",*(buff_begin+i));
}
printf("\n");
*/
int n=10;
while(n)
{
tcp_smtp(request,respond);
Sleep(30000);
n--;
}
/*
int ii=senddata(buff_begin);
printf("%d",ii);
for(int i=0;i<ii;i++)
{
printf("%c",*(buff_begin+i));
}
*/
/*
tcp_pop(client_pop,saddr_pop,request,respond);
bool brk=1;
while(brk)//主循环会一直对是否有新邮件进行查询
{
Sleep(5000);
}
*/
WSACleanup();
return 1;
}
//POP连接
int tcp_pop(SOCKET pop,sockaddr_in saddr,char *r_buffer,char *s_buffer)
{
int con=connect(pop,(struct sockaddr *)&saddr,sizeof(saddr));
if(con==0)
printf("TCP已经连接\n");
else
return 0;
//TCP连接完成之后会受到服务的第一次确认
memset(r_buffer,'\0',512);
int rec=recv(pop,r_buffer,512,0);
printf("%s\n",r_buffer);
//CAPA指令
memset(s_buffer,'\0',512);
memcpy(s_buffer,capa,4);
memcpy(s_buffer+4,crlf,2);
printf("%s\n",s_buffer);
send(pop,s_buffer,6,0);
//CAPA指令之后接收服务器回应
memset(r_buffer,'\0',512);
rec=recv(pop,r_buffer,512,0);
printf("%s",r_buffer);
//USER指令
memset(s_buffer,'\0',512);
memcpy(s_buffer,user,4);
*(s_buffer+4)=' ';
memcpy(s_buffer+5,name,9);
memcpy(s_buffer+14,crlf,2);
printf("%s\n",s_buffer);
send(pop,s_buffer,16,0);
//USER指令之后接收服务器回应
memset(r_buffer,'\0',512);
rec=recv(pop,r_buffer,512,0);
printf("%s",r_buffer);
//PASS指令
memset(s_buffer,'\0',512);
memcpy(s_buffer,pass,4);
*(s_buffer+4)=' ';
memcpy(s_buffer+5,pasw,10);
memcpy(s_buffer+15,crlf,2);
printf("%s\n",s_buffer);
send(pop,s_buffer,17,0);
//PASS指令之后,服务器返回邮箱邮件总数
memset(r_buffer,'\0',512);
rec=recv(pop,r_buffer,512,0);
printf("%s",r_buffer);
//STAT指令
memset(s_buffer,'\0',512);
memcpy(s_buffer,stat,4);
memcpy(s_buffer+4,crlf,2);
printf("%s\n",s_buffer);
send(pop,s_buffer,6,0);
//STAT指令之后接收服务器回应,请求邮件总数和总字节数
memset(r_buffer,'\0',512);
rec=recv(pop,r_buffer,512,0);
printf("%s",r_buffer);
//UIDL指令
memset(s_buffer,'\0',512);
memcpy(s_buffer,uidl,4);
memcpy(s_buffer+4,crlf,2);
printf("%s\n",s_buffer);
send(pop,s_buffer,6,0);
//UIDL指令之后接收服务器回应,返回邮件的唯一标识符
memset(r_buffer,'\0',512);
rec=recv(pop,r_buffer,512,0);
printf("%s",r_buffer);
//LIST指令
memset(s_buffer,'\0',512);
memcpy(s_buffer,list,4);
memcpy(s_buffer+4,crlf,2);
printf("%s\n",s_buffer);
send(pop,s_buffer,6,0);
//LIST指令之后接收服务器回应,返回邮件数量和每个邮件的大小
memset(r_buffer,'\0',512);
rec=recv(pop,r_buffer,512,0);
printf("%s",r_buffer);
//QUIT指令
memset(s_buffer,'\0',512);
memcpy(s_buffer,quit,4);
memcpy(s_buffer+4,crlf,2);
printf("%s\n",s_buffer);
send(pop,s_buffer,6,0);
//QUIT指令之后接收服务器回应,返回邮件数量和每个邮件的大小
memset(r_buffer,'\0',512);
rec=recv(pop,r_buffer,512,0);
printf("%s",r_buffer);
return 1;
}
//SMTP连接
int tcp_smtp(char *r_buffer,char *s_buffer)
{
sockaddr_in saddr_smtp;
saddr_smtp.sin_family=AF_INET;
saddr_smtp.sin_port=htons(PORTSMTP);
saddr_smtp.sin_addr.s_addr= inet_addr("123.125.50.134");
SOCKET smtp;
smtp=socket(AF_INET,SOCK_STREAM,0);
int con=connect(smtp,(struct sockaddr *)&saddr_smtp,sizeof(saddr_smtp));
if(con==0)
printf("TCP已经连接\n");
else
{
return 0;
}
//TCP连接完成之后会受到服务的第一次确认
memset(r_buffer,'\0',512);
int rec=recv(smtp,r_buffer,512,0);
printf("%s",r_buffer);
//EHLO指令
memset(s_buffer,'\0',512);
memcpy(s_buffer,ehlo,4);
memcpy(s_buffer+5,name,9);
memcpy(s_buffer+14,crlf,2);
printf("%s",s_buffer);
send(smtp,s_buffer,16,0);
//EHLO指令之后接收服务器回应
memset(r_buffer,'\0',512);
rec=recv(smtp,r_buffer,512,0);
printf("%s",r_buffer);
//AUTH指令
memset(s_buffer,'\0',512);
memcpy(s_buffer,auth,4);
*(s_buffer+4)=' ';
memcpy(s_buffer+5,login,5);
memcpy(s_buffer+10,crlf,2);
printf("%s",s_buffer);
send(smtp,s_buffer,12,0);
//AUTH指令之后接收服务器回应
memset(r_buffer,'\0',512);
rec=recv(smtp,r_buffer,512,0);
printf("%s",r_buffer);
//USER
memset(s_buffer,'\0',512);
memcpy(s_buffer,"c2VydmVydHNz",12);
memcpy(s_buffer+12,crlf,2);
printf("%s",s_buffer);
send(smtp,s_buffer,14,0);
//USER之后接收服务器回应
memset(r_buffer,'\0',512);
rec=recv(smtp,r_buffer,512,0);
printf("%s",r_buffer);
//PASS
memset(s_buffer,'\0',512);
memcpy(s_buffer,"MTIzNDV6eGN2Yg==",16);
memcpy(s_buffer+16,crlf,2);
printf("%s",s_buffer);
send(smtp,s_buffer,18,0);
//PASS之后
memset(r_buffer,'\0',512);
rec=recv(smtp,r_buffer,512,0);
printf("%s",r_buffer);
//MAIL指令
memset(s_buffer,'\0',512);
memcpy(s_buffer,mail,4);
*(s_buffer+4)=' ';
memcpy(s_buffer+5,"FROM: <);
memcpy(s_buffer+30,crlf,2);
printf("%s\n",s_buffer);
send(smtp,s_buffer,32,0);
//MAIL指令之后
memset(r_buffer,'\0',512);
rec=recv(smtp,r_buffer,512,0);
printf("%s",r_buffer);
//RCPT指令
memset(s_buffer,'\0',512);
memcpy(s_buffer,rcpt,4);
*(s_buffer+4)=' ';
memcpy(s_buffer+5,"TO: <);
memcpy(s_buffer+28,crlf,2);
printf("%s",s_buffer);
send(smtp,s_buffer,30,0);
//RCPT指令之后
memset(r_buffer,'\0',512);
rec=recv(smtp,r_buffer,512,0);
printf("%s",r_buffer);
//DATA指令
memset(s_buffer,'\0',512);
memcpy(s_buffer,data,4);
memcpy(s_buffer+4,crlf,2);
printf("%s",s_buffer);
send(smtp,s_buffer,6,0);
//DATA指令之后
int ii=senddata(buff_begin);
send(smtp,buff_begin,ii,0);
memset(r_buffer,'\0',512);
rec=recv(smtp,r_buffer,512,0);
printf("%s",r_buffer);
//QUIT指令
memset(s_buffer,'\0',512);
memcpy(s_buffer,quit,4);
memcpy(s_buffer+4,crlf,2);
printf("%s\n",s_buffer);
send(smtp,s_buffer,6,0);
//QUIT指令之后接收服务器回应,返回邮件数量和每个邮件的大小
memset(r_buffer,'\0',512);
rec=recv(smtp,r_buffer,512,0);
printf("%s",r_buffer);
closesocket(smtp);
return 1;
}
//在2M缓冲区组建需要发送的数据
int senddata(char *begin)
{
int num=0;
memcpy(begin,"Date: Sat,8 Mar 2014 22:36:04 +0800 (CST)",41);
memcpy(begin+41,crlf,2);
num+=43;
memcpy(begin+num,"From: \"" <);
memcpy(begin+num+45,crlf,2);
num+=45+2;
memcpy(begin+num,"To: servertss <);
memcpy(begin+num+33,crlf,2);
num+=33+2;
memcpy(begin+num,"Subject: =?GB2312?B?YysrtcTEx7G+yunE47fF1NrExMDvwcs=?=",54);
memcpy(begin+num+54,crlf,2);
num+=54+2;
memcpy(begin+num,"Mime-Version: 1.0",17);
memcpy(begin+num+17,crlf,2);
num+=17+2;
memcpy(begin+num,"Message-ID: <);
memcpy(begin+num+43,crlf,2);
num+=43+2;
memcpy(begin+num,"Content-Type: multipart/alternative;",36);
*(begin+num+36)='\n';
*(begin+num+37)='\t';
memcpy(begin+num+36+2,"boundary=\"----=_001_NextPart674370231387_=----\"",48);
memcpy(begin+num+36+2+48,crlf,2);
num+=36+2+48+2;
memcpy(begin+num,crlf,2);
num+=2;
memcpy(begin+num,"------=_001_NextPart674370231387_=----",38);
memcpy(begin+num+38,crlf,2);
num+=38+2;
memcpy(begin+num,"Content-Type: text/plain;",25);
*(begin+num+25)='\n';
*(begin+num+26)='\t';
memcpy(begin+num+25+2,"charset=\"GB2312\"",16);
memcpy(begin+num+25+2+16,crlf,2);
num+=25+2+16+2;
memcpy(begin+num,"Content-Transfer-Encoding: base64",33);
memcpy(begin+num+33,crlf,2);
*(begin+num+33+2)='\n';
num+=33+2+1;
memcpy(begin+num,"CgoKYysrtcTEx7G+yunE47fF1NrExMDvwcsKy9m2yLjmy9/O0goK",52);
num+=52;
memcpy(begin+num,crlf,2);
num+=2;
memcpy(begin+num,"------=_001_NextPart674370231387_=----",38);
memcpy(begin+num+38,crlf,2);
num+=38+2;
memcpy(begin+num,crlf,2);
*(begin+num+2)='.';
memcpy(begin+num+2+1,crlf,2);
num+=2+1+2;
return num;
}
//接收到服务器的消息,需要进行检验是否为“+OK”和其他确认标识,以及后面的字符集
/*
int check_id(char *buff)
{
char id[4];
char characters[500];
memset(id,'\0',4);
memset(characters,'\0',500);
int i=0;
for(i=0;i<4;i++)
{
id[i]=*(buff+i);
i++;
}
switch(id)
{
case "+OK":
break;
}
return 1;
}
*/
//对字符串进行base64编码
int transformstring(char *strings)
{
int num=0; //记录字节数目
int buf=0; //临时单字节存储
base64 buf_transfer; //base64转换的中转
memset(&buf_transfer,'\0',sizeof(buf_transfer));
buf_transfer.result=*strings;
buf_transfer.number=0;
while(buf_transfer.result!='\0')//字符串结束,则程序结束
{
if((0<=buf)&&(buf<6))
{
buf=transformtobase64(&buf_transfer);
memcpy(point_now,&(buf_transfer.result),1);
num++;
buf_transfer.result=*(strings+num);
}
else
{
if(buf==6)
{
*point_now=base64_char[(unsigned int)buf_transfer.residue];
buf_transfer.number=0;
buf_transfer.residue='\0';
buf=0;
}
else
return buf;
}
point_now=point_now+1;
num_now++;
}
if(buf_transfer.residue)
{
*point_now=base64_char[(unsigned int)(buf_transfer.residue<<(6-buf_transfer.number))];
point_now++;
num_now++;
}
buf=num%3;
switch(buf)
{
case 0:
break;
case 1:
memset(point_now,'=',2);
point_now=point_now+2;
num_now=num_now+2;
break;
case 2:
*point_now='=';
point_now++;
num_now++;
break;
}
return num;
}
int transformtobase64(base64 *data)//对单字节数据进行base64编码
{
if(data->number<0)
return -1;
if(data->number>6)
return 8;
char buf='\0',back='\0';
buf=data->residue<<(6-data->number);
back=data->result>>(2+data->number);
buf=back^buf;
buf&=63;
back='\0';
back=data->result<<(6-data->number);
data->residue=back>>(6-data->number);
data->result=base64_char[(unsigned int)buf];
data->residue&=63;
data->number=2+data->number;
return data->number;
}
//对字符串进行base64解码
int transformbase64(char *strings)
{
return 1;
}
int base64totransform(base64 *data)//对单字节数据进行base64解码
{
if(data->number<0)
return -1;
if(data->number>6)
return 8;
if(!chartonumber(data))//转换为6位
return 0;
char buf='0',back='0';
buf=data->residue<<(8-data->number);
if(data->number<3)
{
back=data->result;
data->number+=6;
}
else{
if(data->number<9)
{
back=data->result>>(data->number-2);
data->result=data->result<<(10-data->number);
data->residue=data->result>>(10-data->number);
data->number=data->number-2;
data->result=buf^back;
}
}
data->residue=back^buf;
if(data->number>7)
{
data->result=data->residue;
data->residue='0';
data->number=0;
}
return data->number;
}
int chartonumber(base64 *data)
{
//65-90:A-Z
//97-122:a-z
//48-57:0-9
//43,47:+,/
int cod=0;
if(64<(int)(data->result)&&91>(int)(data->result))
{
cod=1;
data->result=char((int)(data->result)-65);
}
if(96<(int)(data->result)&&123>(int)(data->result))
{
cod=1;
data->result=char((int)(data->result)-97+26);
}
if(47<(int)(data->result)&&58>(int)(data->result))
{
cod=1;
data->result=char((int)(data->result)-48+52);
}
if(43==(int)(data->result))
{
cod=1;
data->result=0x2B;
}
if(47==(int)(data->result))
{
cod=1;
data->result=0x2F;
}
if(cod)
return 1;
else
return 0;
}