POP邮件服务器

/*****************************************************************************************************
Program File Name: popserver.cpp
Program Begin Date: 2007-4-16
Program Description: A Simple pop3 server
Author: wangjianlin
*****************************************************************************************************/
#include <stdio.h>
#include <time.h>
#include <winsock.h>
#include <windows.h>
#pragma comment(lib, "ws2_32.lib")
/*****************************************************************************************************/
#define MAX_CONNECTION_NUM 50         //定义最大连接数
#define POP_SERVER_PORT 110          //定义服务器端口
#define BUFFER_SIZE 1024             //定义缓冲区大小
/*****************************************************************************************************/
u_short serverPort=POP_SERVER_PORT;                     //定义服务器端口为默认端口
char *readBuf;                                           //定义接受数据缓冲区
WSAData wsaData;                                         //定义WSAData结构
SOCKET clientSocket[MAX_CONNECTION_NUM];                 //定义所有客户端socket
SOCKET serverSocket;                                     //定义服务器监听socket
struct sockaddr_in clientSockAddr[MAX_CONNECTION_NUM];   //定义所有客户端信息
struct sockaddr_in server;                               //保存要设置的服务器信息
/*****************************************************************************************************/
struct UserInfo                                          //定义用户信息结构
{                                                      
  char username[20];                                   //用户名
 char password[30];                                   //密码
};
struct ClientContent                                     //客户端输入的信息                       
{
 char command[10];                                    //保存命令字符串
 char *param;                                         //指向命令参数
};
struct CommandFinished                                   //命令执行状态结构,共2条命令
{
 char USER;                                           //如果该命令已经成功执行的话
 char PASS;                                           //就为字符'Y',否则为0
};
/*****************************************************************************************************/
DWORD WINAPI PopBeginService(LPVOID lpParam);            //对客户进行服务的函数,其中lpParam传入服务Socket序号
void WriteClientInfo(int index);                         //index为传入的客户Socket序号
void CommandHandle(int index);                           //对index位置的客户命令进行处理
void GetCommandAndContent(char *buf,ClientContent *clientContent); //分析buf指向的信息为命令和参数
int GetFileSize(char *fileName,struct UserInfo *userInfo); //得到文件fileName的大小
int GetMailFileTotalSize(UserInfo *userInfo);           //得到某个用户邮件总大小
int GetMailFileNum(UserInfo *userInfo);                  //得到某个用户邮件数目
void SortMailFile(UserInfo *userInfo);                  //对删除后的邮件重新排序
void USER_Handle(int index,CommandFinished *commandFinished,char *param,UserInfo *userInfo); //处理USER命令
void PASS_Handle(int index,CommandFinished *commandFinished,char *param,UserInfo *userInfo); //处理PASS命令
void STAT_Handle(int index,CommandFinished *commandFinished,char *param,UserInfo *userInfo); //处理STAT命令
void UIDL_Handle(int index,CommandFinished *commandFinished,char *param); //处理UIDL命令
void DELE_Handle(int index,CommandFinished *commandFinished,char *param,UserInfo *userInfo); //处理DELE命令
void LIST_Handle(int index,CommandFinished *commandFinished,char *param,UserInfo *userInfo); //处理LIST命令
void RETR_Handle(int index,CommandFinished *commandFinished,char *param,UserInfo *userInfo); //处理RETR命令
void RSET_Handle(int index,CommandFinished *commandFinished,char *param,UserInfo *userInfo); //处理RSET命令
void TOP_Handle(int index,CommandFinished *commandFinished,char *param);  //处理TOP命令
void NOOP_Handle(int index,CommandFinished *commandFinished,char *param); //处理NOOP命令
void QUIT_Handle(int index,CommandFinished *commandFinished,char *param,UserInfo *userInfo); //处理QUIT命令
/*****************************************************************************************************/

/*****************************************************************************************************
Function_Name: main
Used To: 在110端口监听客户连接并创建新线程为客户服务
Date: 2007-4-16
*****************************************************************************************************/
int main(int argc,char *argv[])
{
/*****************************************************************************************************/
    struct sockaddr_in tempSockAddr;                             //保存临时接受的客户信息
    SOCKET tempSocket;                                           //保存临时接受的SOCKET
 
    for(int i=0;i<MAX_CONNECTION_NUM;i++)clientSocket[i]=NULL;   //初始化所有客户端socket为无连接状态
 server.sin_family=AF_INET;                                   //填充服务器端信息
 server.sin_port=htons(serverPort);                   
 server.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
 int sockAddrLen=sizeof(tempSockAddr);
/*****************************************************************************************************/
 if(-1==WSAStartup(MAKEWORD(2,0),&wsaData))
 {
  printf("加载Winsock连接库失败!错误号为%d",WSAGetLastError());
  WSACleanup();
  return -1;
 }

 serverSocket=socket(AF_INET,SOCK_STREAM,0);                 //服务器建立socket并开始监听,tcp
 if(INVALID_SOCKET ==serverSocket)
 {
  printf("服务器创建socket失败!错误号为%d",WSAGetLastError());
  WSACleanup();
  return -1;
 }

 
 if(SOCKET_ERROR==bind(serverSocket,(struct sockaddr*)&server,sizeof(server)))
 {
  printf("服务器套接字绑定发生错误!错误号为:%d",WSAGetLastError());
  WSACleanup();
  return -1;
 }

 if(SOCKET_ERROR==listen(serverSocket,MAX_CONNECTION_NUM+1))
 {
  printf("服务器套接字监听失败!错误号为:%d",WSAGetLastError());
  WSACleanup();
  return -1;
 }
 printf("Pop Server is running.....");
/*****************************************************************************************************/
 while(true)                                 //服务器进入无限监听状态
 {
  
  tempSocket=accept(serverSocket,(struct sockaddr*)&tempSockAddr,&sockAddrLen);
  for(i=0;i<MAX_CONNECTION_NUM;i++)       //查找队列中有没有空位
  {
   if(NULL!=clientSocket[i])continue;  //该位置不为空,被占用了,继续看下一个
   else                                //有空位就把临时客户信息保存
   {
    clientSocket[i]=tempSocket;
    clientSockAddr[i]=tempSockAddr;
    tempSocket=NULL;
    memset((void *)(struct sockaddr*)&tempSockAddr,0,sizeof(tempSockAddr));
    int index=i;                    //保存空位号
    DWORD dwThreadID;
    HANDLE handle;                  //下面创建一个服务线程,SmtpBeginService为线程入口
    handle=::CreateThread(NULL,NULL,PopBeginService,&index,CREATE_SUSPENDED,&dwThreadID);//函数成功,返回线程句柄;函数失败返回false
                ::ResumeThread(handle);
    break;
   }
  }
  if(NULL!=tempSocket)                    //如果没有找到空位,即队列满了则发送人数满了并关闭连接
  {
   send(tempSocket,"Sorry,the server queue is full,please wait",sizeof("Sorry,the server queue is full,please wait"),0);
         closesocket(tempSocket);
   tempSocket=NULL;
  }
 }
}
/*****************************************************************************************************/


/*****************************************************************************************************
Function_Name: SmtpBeginService
Used To: 为客户服务的线程入口点
Params: lpParam--主线程传入的客户服务号
Date: 2007-4-16
*****************************************************************************************************/
DWORD WINAPI PopBeginService(LPVOID lpParam)
{
 
 int *index=(int *)lpParam;      //首先取得客户服务号,以下发送欢迎信息 
 printf("begin.../n");////////////////
 send(clientSocket[*index],"+OK POP3 server ready /r/n",sizeof("Welcome to LinLin POP3 Server.../r/n"),0);
 WriteClientInfo(*index);       //把第*index位置客户登录信息存入日志文件
 CommandHandle(*index);         //进入与客户命令响应函数
 return 0;
}
/*****************************************************************************************************/

/*****************************************************************************************************
Function_Name: CommandHandle
Used To: 接受客户命令并处理命令
Params: index--客户服务号
Date: 2007-4-16
*****************************************************************************************************/
void CommandHandle(int index)
{
/*****************************************************************************************************/ 
 UserInfo userInfo;                                         //保存用户名及密码
 struct ClientContent clientContent;                        //保存接受的信息内容(包含命令和参数)
 struct CommandFinished commandFinished;                    //保存命令完成状态

 readBuf=(char *)malloc(BUFFER_SIZE+1);                     //分配接收数据的缓冲区,最后为/0结束符
 memset(readBuf,0,BUFFER_SIZE+1);                           //清空接受数据的缓冲区 
 
 memset(&userInfo,0,sizeof(struct UserInfo));               //清空用户名和密码
 memset(&commandFinished,0,sizeof(struct CommandFinished)); //初始化每个命令未执行
 memset(&clientContent,0,sizeof(struct ClientContent));     //清空命令字和参数

/*****************************************************************************************************/
 //第一步
 recv(clientSocket[index],readBuf,BUFFER_SIZE,0);           //读取客户发送的命令信息
 GetCommandAndContent(readBuf,&clientContent);              //获得命令信息保存到clientContent中
/*****************************************************************************************************/

 while(0!=strcmp("QUIT",clientContent.command))               //当客户发送的命令不为QUIT时
 {
  if(0==strcmp("USER",clientContent.command))              //处理USER命令
  {
   USER_Handle(index,&commandFinished,clientContent.param,&userInfo);
   memset(readBuf,0,BUFFER_SIZE+1);                   //readBuf清0接受下个命令
         recv(clientSocket[index],readBuf,BUFFER_SIZE,0);
            memset(&clientContent,0,sizeof(struct ClientContent)); //清空客户命令参数信息结构
         GetCommandAndContent(readBuf,&clientContent);      //重新获得命令信息
  }
  else if(0==strcmp("PASS",clientContent.command))       //处理PASS命令
  {
   PASS_Handle(index,&commandFinished,clientContent.param,&userInfo);
   memset(readBuf,0,BUFFER_SIZE+1);                   //readBuf清0准备重新接受数据
         recv(clientSocket[index],readBuf,BUFFER_SIZE,0);
         memset(&clientContent,0,sizeof(struct ClientContent)); //清空客户命令参数信息结构
         GetCommandAndContent(readBuf,&clientContent);      //重新获得命令信息
  }
  else if(0==strcmp("STAT",clientContent.command))    //处理STAT命令
  {
   STAT_Handle(index,&commandFinished,clientContent.param,&userInfo);
   memset(readBuf,0,BUFFER_SIZE+1);                   //readBuf清0准备重新接受数据
         recv(clientSocket[index],readBuf,BUFFER_SIZE,0);
         memset(&clientContent,0,sizeof(struct ClientContent)); //清空客户命令参数信息结构
         GetCommandAndContent(readBuf,&clientContent);      //重新获得命令信息
  }
  else if(0==strcmp("UIDL",clientContent.command))      //处理UIDL命令
  {
   UIDL_Handle(index,&commandFinished,clientContent.param);
   memset(readBuf,0,BUFFER_SIZE+1);                   //readBuf清0准备重新接受数据
         recv(clientSocket[index],readBuf,BUFFER_SIZE,0);
         memset(&clientContent,0,sizeof(struct ClientContent)); //清空客户命令参数信息结构
         GetCommandAndContent(readBuf,&clientContent);      //重新获得命令信息
  }
  else if(0==strcmp("LIST",clientContent.command))      //处理LIST命令
  {
      LIST_Handle(index,&commandFinished,clientContent.param,&userInfo);
   memset(readBuf,0,BUFFER_SIZE+1);                   //readBuf清0准备重新接受数据
         recv(clientSocket[index],readBuf,BUFFER_SIZE,0);
         memset(&clientContent,0,sizeof(struct ClientContent)); //清空客户命令参数信息结构
         GetCommandAndContent(readBuf,&clientContent);      //重新获得命令信息
  }
  else if(0==strcmp("RETR",clientContent.command))       //处理RETR命令
  {
   RETR_Handle(index,&commandFinished,clientContent.param,&userInfo);
   memset(readBuf,0,BUFFER_SIZE+1);                   //readBuf清0准备重新接受数据
         recv(clientSocket[index],readBuf,BUFFER_SIZE,0);
         memset(&clientContent,0,sizeof(struct ClientContent)); //清空客户命令参数信息结构
         GetCommandAndContent(readBuf,&clientContent);      //重新获得命令信息
  }
  else if(0==strcmp("RSET",clientContent.command))       //处理RSET命令
  {
   RSET_Handle(index,&commandFinished,clientContent.param,&userInfo);
   memset(readBuf,0,BUFFER_SIZE+1);                   //readBuf清0准备重新接受数据
         recv(clientSocket[index],readBuf,BUFFER_SIZE,0);
         memset(&clientContent,0,sizeof(struct ClientContent)); //清空客户命令参数信息结构
         GetCommandAndContent(readBuf,&clientContent);      //重新获得命令信息
  }
  else if(0==strcmp("TOP",clientContent.command))       //处理TOP命令
  {
   TOP_Handle(index,&commandFinished,clientContent.param);
   memset(readBuf,0,BUFFER_SIZE+1);                   //readBuf清0准备重新接受数据
         recv(clientSocket[index],readBuf,BUFFER_SIZE,0);
         memset(&clientContent,0,sizeof(struct ClientContent)); //清空客户命令参数信息结构
         GetCommandAndContent(readBuf,&clientContent);      //重新获得命令信息
  }
  else if(0==strcmp("NOOP",clientContent.command))       //处理NOOP命令
  {
   NOOP_Handle(index,&commandFinished,clientContent.param);
   memset(readBuf,0,BUFFER_SIZE+1);                   //readBuf清0准备重新接受数据
         recv(clientSocket[index],readBuf,BUFFER_SIZE,0);
         memset(&clientContent,0,sizeof(struct ClientContent)); //清空客户命令参数信息结构
         GetCommandAndContent(readBuf,&clientContent);      //重新获得命令信息
  }
  else if(0==strcmp("DELE",clientContent.command))       //处理DELE命令
  {
   DELE_Handle(index,&commandFinished,clientContent.param,&userInfo);
   memset(readBuf,0,BUFFER_SIZE+1);                   //readBuf清0准备重新接受数据
         recv(clientSocket[index],readBuf,BUFFER_SIZE,0);
         memset(&clientContent,0,sizeof(struct ClientContent)); //清空客户命令参数信息结构
         GetCommandAndContent(readBuf,&clientContent);      //重新获得命令信息
  }
  else                                                   //处理不认识的命令;
  {
   send(clientSocket[index],"502 Command not implemented",sizeof("502 Command not implemented"),0);
            memset(readBuf,0,BUFFER_SIZE+1);                    //readBuf清0准备重新接受数据
         recv(clientSocket[index],readBuf,BUFFER_SIZE,0);
         memset(&clientContent,0,sizeof(struct ClientContent)); //清空客户命令参数信息结构
         GetCommandAndContent(readBuf,&clientContent);      //重新获得命令信息
  }
 }
 //以下处理QUIT命令
    QUIT_Handle(index,&commandFinished,clientContent.param,&userInfo);
}
/****************************************************************************************************/

/*****************************************************************************************************
Function_Name: USER_HANDLE
Used TO: 处理USER命令(从用户文件中查找用户名是否存在,并保存用户名)
Date: 2007-4-16
/*****************************************************************************************************/
void USER_Handle( int index,                          //客户服务号
      CommandFinished *commandFinished,   //命令执行状态
      char *param,                        //指向命令参数
      UserInfo *userInfo)                 //指向保存用户信息的内存
{
 int fileLength;                                  //定义文件长度
 int usercount;                                    //定义用户数量
 UserInfo tempUserInfo;                                //保存用户名和密码
 FILE *fp=NULL;                                         //用户文件指针

 memset(&tempUserInfo,0,sizeof(struct UserInfo));  //清空用户信息
 while(' '==*param)param++;                        //去掉USER命令后面的空格
 if((fp=fopen("user.txt","r"))==NULL)///////////
  return;///////////
 fseek(fp,0,2);////////////
 fileLength=ftell(fp);   //得到文件长度////////////
    usercount=fileLength/(sizeof(struct UserInfo));//得到用户数量//////////////
 fseek(fp,0,0);////////////////
 for(int i=0;i<usercount;i++)/////////
 {////////////
     fread(&tempUserInfo,sizeof(UserInfo),1,fp);//将该记录读入结构userInfo中///////////
  if(strlen(tempUserInfo.username)!=strlen(param))continue; ///////////
  if(0==strcmp(tempUserInfo.username,param))//////////
  {///////////////////
   memcpy(userInfo,&tempUserInfo,sizeof(struct UserInfo));   //保存用户名///////////
   commandFinished->USER='Y';                //修改USER命令为执行状态并发送成功信息////////
   send(clientSocket[index],"+OK USER Command Finished",sizeof("+OK USER Command Finished"),0);///
   fclose(fp);/////////////
   return ;///////////
  }//////////////
 }//////////////
 send(clientSocket[index],"-ERR User does not exit",sizeof("-ERR User does not exit"),0);
}
/*****************************************************************************************************/

/*****************************************************************************************************
Function_Name: PASS_HANDLE
Used TO: 处理PASS命令(得到客户的密码并检查密码是否正确)
Date: 2007-4-17
/*****************************************************************************************************/
void PASS_Handle( int index,                          //客户服务号
      CommandFinished *commandFinished,   //命令执行状态
      char *param,                        //指向命令参数
      UserInfo *userInfo)                 //指向保存用户信息的内存
{
 if('Y'!=commandFinished->USER)                    //USER没有
 {
  send(clientSocket[index],"-ERR Please enter user command first",sizeof("-ERR Please enter user command first"),0);
  return ;
 }
 else
 {
  while(' '==*param) param++;                   //去掉密码前面的空格
  if(0!=strcmp(userInfo->password,param))
  {
   send(clientSocket[index],"-ERR Password is not right",sizeof("-ERR Password is not right"),0);
   return ;
  }
  commandFinished->PASS='Y';                    //设置PASS命令成功执行
  send(clientSocket[index],"+OK PASS Command Finished",sizeof("+OK PASS Command Finished"),0);
 }
}
/*****************************************************************************************************/

/*****************************************************************************************************
Function_Name: STAT_HANDLE
Used To: 处理客户STAT命令(统计用户邮箱信息并发送给用户)
Date: 2004-4-17
*****************************************************************************************************/
void STAT_Handle( int index,                          //客户服务id号
      CommandFinished *commandFinished,   //命令完成状态结构
      char *param,                        //命令参数
      UserInfo *userInfo)                 //指向用户信息
{

 int mailNum;                                      //定义该用户邮件数 
 int totalSize;                                    //定义邮件总大小
 char mailNumString[4];                            //保存邮件数的字符串
 char totalSizeString[10];                         //保存总大小的字符串
 char sendData[100];                               //将发送给客户的信息字符串

 memset(mailNumString,0,4);                        //清空信息
 memset(totalSizeString,0,10);
 memset(sendData,0,100);
   
 if('Y'!=commandFinished->USER || 'Y'!=commandFinished->PASS)
 {
  send(clientSocket[index],"-ERR USER and PASS Command should be finished before",sizeof("-ERR USER and PASS Command should be finished before"),0);
  return ;
 }
 else
 {
  mailNum=GetMailFileNum(userInfo);              //得到该用户邮件数
  totalSize=GetMailFileTotalSize(userInfo);      //得到邮件总大小
  itoa(mailNum,mailNumString,10);                //将邮件数目转换为字符串
  itoa(totalSize,totalSizeString,10);            //将邮件总大小转换为字符串

  strcat(sendData,"+OK ");                      
  strcat(sendData,mailNumString);                //构造待发送的字符串
  strcat(sendData," ");
  strcat(sendData,totalSizeString);
     strcat(sendData,"/r/n");
  send(clientSocket[index],sendData,strlen(sendData),0); //发送总的信息数据
 }

}
/*****************************************************************************************************/

/*****************************************************************************************************
Function_Name: UIDL_Handle
Used To: 还没实现,待SMTP添加该功能后在说吧
Date: 2004-4-17
*****************************************************************************************************/
void UIDL_Handle( int index,
         CommandFinished *commandFinished,
      char *param)                          //处理UIDL命令
{
 return ;
}
/*****************************************************************************************************/

/*****************************************************************************************************
Function_Name: LIST_Handle
Used To: 处理List命令,无参数时给出所有邮件信息,带参数时给出某个邮件信息
Date: 2004-4-18
*****************************************************************************************************/
void LIST_Handle( int index,
    CommandFinished *commandFinished,
    char *param,
    UserInfo *userInfo) //处理LIST命令
{

 int mailNum;                                   //定义该用户的邮件数
 int totalSize;                                 //定义总邮件大小
 int fileSize;                                  // 保存某个邮件的大小

 char mailNumString[4];                         //保存邮件数的字符串
 char totalSizeString[10];                      //保存总大小的字符串
 char fileSizeStr[10];                          //保存文件大小的字符串
 
 char path[50];                                 //待打开的文件路径
 char sendData[1024];                            //将发送给客户的总信息字符串
    FILE *fp=NULL;                                 //定义文件指针

 
 memset(mailNumString,0x00,sizeof(mailNumString));
 memset(totalSizeString,0x00,sizeof(totalSizeString));
 memset(fileSizeStr,0x00,sizeof(fileSizeStr));
 memset(path,0,50);                             //路径清空
 memset(sendData,0,1024);                        //清空总信息


 if('Y'!=commandFinished->USER || 'Y'!=commandFinished->PASS)
 {
  send(clientSocket[index],"-ERR USER and PASS Command should be finished before",sizeof("-ERR USER and PASS Command should be finished before"),0);
  return ;
 }
 else
 {
  mailNum=GetMailFileNum(userInfo);          //得到用户邮件数
     totalSize=GetMailFileTotalSize(userInfo);  //得到邮件总大小为
  param++;                                    //param指向命令参数
  if(0!=*param)                             //如果List命令带参数
  {
   for(int i=0;i<strlen(param);i++)        //判断param参数是否正确
   {
    if(!isdigit(*(param+i)))//isdigit判断字符*(param+i)是否为数字,*(param+i)为数字0-9时,返回非零值,否则返回零
    {
     send(clientSocket[index],"-ERR LIST command params error",sizeof("-ERR LIST command params error"),0);
     return ;
    }
   }

   strcat(path,userInfo->username);        //构造路径字符串
   strcat(path,"//RecieveBox//");
   strcat(path,param);
   strcat(path,".eml");

   fp=fopen(path,"r");
   fseek(fp,0,2);
   fileSize=ftell(fp);//得到邮件总大小
   fclose(fp);

   itoa(fileSize,fileSizeStr,10);

   strcat(sendData,"+OK ");                 //构造待发送的字符串
   strcat(sendData,param);
   strcat(sendData," ");
   strcat(sendData,fileSizeStr);

   send(clientSocket[index],sendData,strlen(sendData),0);

  }
  else                                        //LIST命令不带参数时处理
  {
   
      itoa(mailNum,mailNumString,10);                //将邮件数目转换为字符串
      itoa(totalSize,totalSizeString,10);            //将邮件总大小转换为字符串

      strcat(sendData,"+OK ");                      
      strcat(sendData,mailNumString);                //构造待发送的字符串
      strcat(sendData," ");
      strcat(sendData,totalSizeString);
   strcat(sendData,"/r/n");


   char numStr[4];
   memset(numStr,0,4);
   for(int i=1;i<=mailNum;i++)                        //发送每个邮件的信息
   {
    strcat(path,userInfo->username);              //构造路径字符串
       strcat(path,"//RecieveBox//");
       itoa(i,numStr,10);
    strcat(path,numStr);
       strcat(path,".mil");

       fp=fopen(path,"rb");
       fseek(fp,0,2);
       fileSize=ftell(fp);
    fclose(fp);
       itoa(fileSize,fileSizeStr,10);

       strcat(sendData,numStr);                    //构造待发送的字符串
       strcat(sendData," ");
       strcat(sendData,fileSizeStr);
    strcat(sendData,"/r/n");

      
    
    memset(path,0x00,sizeof(path));
    memset(numStr,0x00,sizeof(numStr));
    memset(fileSizeStr,0x00,sizeof(fileSizeStr));

   }
   strcat(sendData,"./r/n");
   send(clientSocket[index],sendData,strlen(sendData),0);
  }

 }

}
/****************************************************************************************************/

/*****************************************************************************************************
Function_Name: RETR_Handle
Used To: 处理RETR命令
Param: index-客户服务号,用于访问客户socket和客户机信息
Date: 2004-4-19
*****************************************************************************************************/
void RETR_Handle( int index,
      CommandFinished *commandFinished,
      char *param,
      UserInfo *userInfo)   //处理RETR命令
{
 FILE *fp=NULL;                                 //待打开的文件指针
 char path[50];                                 //待打开的文件路径
 int fileSize;                                  //保存邮件大小
 char fileSizeStr[10];                          //保存邮件大小的字符;
 char *sendData;                                //待发送的数据指针
 int sendDataLength=0;                          //待发送的数据长度
 memset(path,0,50);
 memset(fileSizeStr,0,10);

 if('Y'!=commandFinished->USER || 'Y'!=commandFinished->PASS)
 {
  send(clientSocket[index],"-ERR USER and PASS Command should be finished before",sizeof("-ERR USER and PASS Command should be finished before"),0);
  return ;
 }
 else
 {
  
  param++;                                    //param指向命令参数
  if(0==*param)
  {
   send(clientSocket[index],"-ERR RETR Command needed param",sizeof("-ERR RETR Command needed param"),0);
   return ;
  }
  for(int i=0;i<strlen(param);i++)        //判断param参数是否正确
  {
   if(!isdigit(*(param+i)))
   {
    send(clientSocket[index],"-ERR RETR command params error",sizeof("-ERR RETR command params error"),0);
    return ;
   }
  }
  strcat(path,param);    ////////////////               
  strcat(path,".eml");//////////////////

  fileSize=GetFileSize(path,userInfo);
  itoa(fileSize,fileSizeStr,10);

  sendDataLength+=strlen(param);       //计算发送数据长度
  sendDataLength+=strlen(fileSizeStr); 
  sendDataLength+=7;
  sendDataLength+=fileSize;
   
  sendData=(char *)malloc(sizeof(char)*sendDataLength+1);//分配发送数据的缓冲区
  memset(sendData,0,sendDataLength+1);  //清空发送数据缓冲区
  strcat(sendData,"+OK ");
  strcat(sendData,param);
  strcat(sendData," ");
  strcat(sendData,fileSizeStr);
  strcat(sendData,"/r/n");

  memset(path,0x00,sizeof(path));
  strcat(path,userInfo->username);  
  strcat(path,"//RecieveBox//");
  strcat(path,param);                   
  strcat(path,".eml");

  fp=fopen(path,"r");
  fread(sendData+strlen(param)+strlen(fileSizeStr)+7,1,fileSize,fp);
  fclose(fp);

  send(clientSocket[index],sendData,strlen(sendData),0);
  
 }
}
/****************************************************************************************************/                 

/*****************************************************************************************************
Function_Name: DELE_Handle
Used To: 标记某个邮件为删除标记记录到文件dele.dat中以备quit命令执行时更新
Param: index-客户服务号,用于访问客户socket和客户机信息
Date: 2004-4-19
*****************************************************************************************************/
void DELE_Handle( int index,
      CommandFinished *commandFinished,
      char *param,
      UserInfo *userInfo) //处理DELE命令
{
 FILE *fpDele;                                  //保存已删除标记邮件信息的文件指针
 char delePath[50];                             //上述文件的路径(用户名/dele.dat)

 memset(delePath,0,50);

 if('Y'!=commandFinished->USER || 'Y'!=commandFinished->PASS)
 {
  send(clientSocket[index],"-ERR USER and PASS Command should be finished before",sizeof("-ERR USER and PASS Command should be finished before"),0);
  return ;
 }
 else
 {
  param++;                                    //param指向命令参数
  if(0==*param)
  {
   send(clientSocket[index],"-ERR DELE command need param",sizeof("-ERR DELE command need param"),0);
   return ;
  }
  for(int i=0;i<strlen(param);i++)        //判断param参数是否正确
  {
   if(!isdigit(*(param+i)))
   {
    send(clientSocket[index],"-ERR DELE command params error",sizeof("-ERR DELE command params error"),0);
    return ;
   }
  }
  strcat(delePath,userInfo->username);   //构造dele.dat的路径
  strcat(delePath,"//dele.dat");

  if((fpDele=fopen(delePath,"a"))==NULL)//打开文件写邮件删除标记
   return ;          
  fputs(param,fpDele);
  fputs(",",fpDele);
  fclose(fpDele);
  send(clientSocket[index],"+OK Delete Command Finished",sizeof("+OK Delete Command Finished"),0);
 }
}
/****************************************************************************************************/

/****************************************************************************************************
Function_Name: RSET_Handle
Used To: 处理RSET命令
Param: index-客户服务号,用于访问客户socket和客户机信息
Date: 2004-4-19
*****************************************************************************************************/
void RSET_Handle( int index,
      CommandFinished *commandFinished,
      char *param,
      UserInfo *userInfo) //处理RSET命令
{
 char delePath[50];                             //用户名/dele.dat 文件路径
 WIN32_FIND_DATA FindFileData; 
 HANDLE hFind;
 
 memset(delePath,0,50);

 strcat(delePath,userInfo->username);
 strcat(delePath,"//dele.dat");
 hFind=FindFirstFile(delePath,&FindFileData);
 if(INVALID_HANDLE_VALUE!=hFind)    //假如找到该文件,说明该文件存在,就删除
    remove(delePath);                             //删除该文件
 FindClose(hFind);
 send(clientSocket[index],"+OK Rset Command Finished",sizeof("+OK Rset Command Finished"),0);
  
   
}
/****************************************************************************************************/

/****************************************************************************************************
Function_Name: NOOP_Handle
Used To: 仅仅返回肯定响应,不做任何操作
Param: index-客户服务号,用于访问客户socket和客户机信息
Date: 2004-4-19
*****************************************************************************************************/
void NOOP_Handle( int index,
      CommandFinished *commandFinished,
      char *param) //处理NOOP命令  

 send(clientSocket[index],"+OK Connection is OK!",sizeof("+OK Connection is OK!"),0);
 return ;
}
/****************************************************************************************************/

/*****************************************************************************************************
Function_Name: TOP_Handle
Used To: 还没实现
Date: 2004-4-17
*****************************************************************************************************/
void TOP_Handle(int index,
    CommandFinished *commandFinished,
    char *param)
{
 return;
}
/****************************************************************************************************
Function_Name: QUIT_Handle
Used To: 处理QUIT命令(执行删除标记为dele的邮件并关闭客户端连接)
Param: index-客户服务号,用于访问客户socket和客户机信息
Date: 2004-4-19
*****************************************************************************************************/
void QUIT_Handle( int index,
      CommandFinished *commandFinished,
      char *param,
      UserInfo *userInfo) //处理QUIT命令
{
 WIN32_FIND_DATA FindFileData;                  
    HANDLE hFind;
 FILE *fpDele=NULL;                 //指向username/dele.dat的文件指针
 int deleFileLength;                //保存dele.dat的长度   
    char *deleFileData;                //保存dele.dat的内容

 char delePath[50];                 //用户名/dele.dat 文件路径
 char deleFilePath[50];             //保存欲删除文件的路径
 
    memset(delePath,0,50);
 memset(deleFilePath,0,50);

 strcat(delePath,userInfo->username);
 strcat(delePath,"//dele.dat");

 strcat(deleFilePath,userInfo->username);
 strcat(deleFilePath,"//RecieveBox//");

 //如果dele.dat存在就删除里面标记的邮件并删除username/dele.dat并重新调整邮件的名字
    hFind=FindFirstFile(delePath,&FindFileData);
 if(INVALID_HANDLE_VALUE!=hFind)    //假如找到该文件,说明该文件存在,就必须删除某些邮件
 {
  if((fpDele=fopen(delePath,"rb"))==NULL)
   return;
  
  fseek(fpDele,0,2);
  deleFileLength=ftell(fpDele);
  fseek(fpDele,0,0);
  deleFileData=(char *)malloc(sizeof(char)*deleFileLength+1);
  memset(deleFileData,0,sizeof(char)*deleFileLength+1);
  fread(deleFileData,1,deleFileLength,fpDele);                //读入dele.dat内容
  fclose(fpDele);
  ::DeleteFile(delePath);

  for(int i=0;i<strlen(deleFileData);i++)
  {
   if(','!=deleFileData[i])                               //当前字符不为','
   {
    deleFilePath[strlen(deleFilePath)]=deleFileData[i];//复制欲删除的文件路径
   }
   else
   {
    strcat(deleFilePath,".eml");                       //补全文件路径扩展名
    DeleteFile(deleFilePath);                          //删除该文件
    memset(deleFilePath,0,50);                         //清空以保存下个文件路径
    strcat(deleFilePath,userInfo->username);
             strcat(deleFilePath,"//RecieveBox//");
   }
  }
 }
 FindClose(hFind);
 SortMailFile(userInfo);
 send(clientSocket[index],"+OK Good Bye!",sizeof("+OK Good Bye"),0);
 closesocket(clientSocket[index]);
 clientSocket[index]=NULL;

}
/****************************************************************************************************/
void SortMailFile(UserInfo *userInfo) //对邮件重新按顺序命名

 WIN32_FIND_DATA FindFileData;                  
    HANDLE hFind;

 int mailNum=1;
 char mailNumStr[4];
 char newNamePath[50];    //保存新的临时文件名
 char oldNamePath[50];
 char filter[50];                   //重命令.eml邮件的过滤字符串
 
 memset(newNamePath,0,50);
 memset(mailNumStr,0,4);
 memset(oldNamePath,0,50);
 memset(filter,0x00,sizeof(filter));

 strcat(filter,userInfo->username);
 strcat(filter,"//RecieveBox//*.eml");

 itoa(mailNum,mailNumStr,10);
 strcat(oldNamePath,userInfo->username);
 strcat(oldNamePath,"//RecieveBox//");
 strcat(newNamePath,userInfo->username);
 strcat(newNamePath,"//RecieveBox//");
 strcat(newNamePath,mailNumStr);
 strcat(newNamePath,".tmp");
 
 hFind=FindFirstFile(filter,&FindFileData);                 //重新命名每个邮件的名称
 if(INVALID_HANDLE_VALUE!=hFind)
 {
  strcat(oldNamePath,FindFileData.cFileName);
  ::MoveFile(oldNamePath,newNamePath);
  while(FindNextFile(hFind,&FindFileData))
  {
   mailNum++;
   memset(mailNumStr,0,4);
   memset(newNamePath,0,50);
   memset(oldNamePath,0,50);
   itoa(mailNum,mailNumStr,10);
            strcat(oldNamePath,userInfo->username);
      strcat(oldNamePath,"//RecieveBox//");
   strcat(oldNamePath,FindFileData.cFileName);
   strcat(newNamePath,userInfo->username);
      strcat(newNamePath,"//RecieveBox//");
      strcat(newNamePath,mailNumStr);
      strcat(newNamePath,".tmp");
   ::MoveFile(oldNamePath,newNamePath);
  }
 }
 FindClose(hFind);

 memset(filter,0x00,sizeof(filter));
 memset(oldNamePath,0x00,sizeof(oldNamePath));
 memset(newNamePath,0x00,sizeof(newNamePath));

 mailNum=1;
 itoa(mailNum,mailNumStr,10);

 strcat(filter,userInfo->username);
 strcat(filter,"//RecieveBox//*.tmp");
 strcat(oldNamePath,userInfo->username);
 strcat(oldNamePath,"//RecieveBox//");

 strcat(newNamePath,userInfo->username);
 strcat(newNamePath,"//RecieveBox//");
 strcat(newNamePath,mailNumStr);
 strcat(newNamePath,".eml");
    hFind=FindFirstFile(filter,&FindFileData);                 //重新命名每个邮件的名称
 if(INVALID_HANDLE_VALUE!=hFind)
 {
  strcat(oldNamePath,FindFileData.cFileName);
     ::MoveFile(oldNamePath,newNamePath);
  while(FindNextFile(hFind,&FindFileData))
  {
   mailNum++;
   memset(mailNumStr,0,4);
   memset(newNamePath,0,50);
   memset(oldNamePath,0,50);
   itoa(mailNum,mailNumStr,10);
            strcat(oldNamePath,userInfo->username);
      strcat(oldNamePath,"//RecieveBox//");
   strcat(oldNamePath,FindFileData.cFileName);
   strcat(newNamePath,userInfo->username);
      strcat(newNamePath,"//RecieveBox//");
      strcat(newNamePath,mailNumStr);
      strcat(newNamePath,".eml");
      ::MoveFile(oldNamePath,newNamePath);
  }
 }
 FindClose(hFind);
 
}
/****************************************************************************************************
Function_Name: WriteClientIpInfo
Used To: 记录客户登录的ip信息和登录时间信息等
Param: index-客户服务号,用于访问客户socket和客户机信息
Date: 2004-4-16
*****************************************************************************************************/
void WriteClientInfo(int index)
{
    char *clientAddr;
 char *timestr=(char *)malloc(sizeof(char)*40);
 FILE *fp;
 time_t ttime;
 time(&ttime);//返回当前日历
 tm *tmtime=localtime(&ttime); //将日历转换为当地时间
 strftime(timestr,50,"%Y年%m月%d日%H时%M分%S秒",tmtime);

  
 clientAddr=inet_ntoa(clientSockAddr[index].sin_addr);//inet_ntoa将网络地址转换成.间隔的字符串
 fp=fopen("ServerLog.txt","a");
 fputs(clientAddr,fp);
 fputs(" ",fp);
 fputs(timestr,fp);
 fputs("/r/n",fp);
 fclose(fp);

}
/*****************************************************************************************************/

/*****************************************************************************************************
Function_Name: GetCommandAndContent
Used To: 分析从客户接收的buf数据,分离出命令和参数并保存到clientContent中
Params: buf--传入从客户接收到数据的开始位置 clientContent--分析后保存命令和参数的结构
Date: 2007-4-19
*****************************************************************************************************/
void GetCommandAndContent( char *buf,
         ClientContent *clientContent)
{
    if(0==strncmp(buf,"USER",4))//如果buf接收数据的前4个字符为USER
 {
  strcpy(clientContent->command,"USER");
  clientContent->param=buf+4;
 }
 else if(0==strncmp(buf,"PASS",4))         //如果buf接收数据的前4个字符为PASS
 {
  strcpy(clientContent->command,"PASS"); //保存命令为PASS
  clientContent->param=buf+4;               //命令参数指向buf命令后的位置
 }
 else if(0==strncmp(buf,"LIST",4))//如果buf接收数据的前4个字符为LIST
 {
  strcpy(clientContent->command,"LIST");
  clientContent->param=buf+4;
 }
 else if(0==strncmp(buf,"STAT",4))//如果buf接收数据的前4个字符为STAT
 {
  strcpy(clientContent->command,"STAT");
  clientContent->param=buf+4;
 }
 else if(0==strncmp(buf,"UIDL",4))//如果buf接收数据的前4个字符为UIDL
 {
  strcpy(clientContent->command,"UIDL");
  clientContent->param=buf+4;
 }
 else if(0==strncmp(buf,"RETR",4))
 {
  strcpy(clientContent->command,"RETR");
  clientContent->param=buf+4;
 }
 else if(0==strncmp(buf,"DELE",4))
 {
  strcpy(clientContent->command,"DELE");
  clientContent->param=buf+4;
 }
 else if(0==strncmp(buf,"RSET",4))
 {
  strcpy(clientContent->command,"RSET");
  clientContent->param=NULL;
 }
 else if(0==strncmp(buf,"NOOP",4))
 {
  strcpy(clientContent->command,"NOOP");
  clientContent->param=NULL;
 }
 else if(0==strncmp(buf,"QUIT",4))
 {
  strcpy(clientContent->command,"QUIT");
  clientContent->param=NULL;
 }
 else
 {
  strcpy(clientContent->command,"UNKNOWN");
  clientContent->param=NULL;
 }
}
/*****************************************************************************************************/

/*****************************************************************************************************
Function_Name: GetFileSize
Used To: 根据参数fileName得到文件userInfo->username/RecieveBox/fileName的大小
Date: 2004-4-17
*****************************************************************************************************/
int GetFileSize(char *fileName,struct UserInfo *userInfo)
{
 FILE *fp=NULL;
 int fileSize=0;
 char filePath[50];
 memset(filePath,0,50);
 strcat(filePath,userInfo->username);
 strcat(filePath,"//RecieveBox//");
 strcat(filePath,fileName);

 fp=fopen(filePath,"r");
 if(NULL==fp)return 0;
    fseek(fp,0,2);                                              //将文件指针指向最后
 fileSize=ftell(fp);
 fclose(fp);
 return fileSize;
}
/*****************************************************************************************************/

/*****************************************************************************************************
Function_Name: GetMailFileNum
Used To: 根据参数userInfo返回userInfo->username/RecieveBox下邮件的数目
Date: 2004-4-20
*****************************************************************************************************/
int GetMailFileNum(UserInfo *userInfo)
{
 WIN32_FIND_DATA FindFileData;                  
    HANDLE hFind;
 int mailNum=0;
 char *filter;                                  //文件过滤条件
 
 filter=(char *)malloc(sizeof(char)*40);        //构造过滤条件
 memset(filter,0x00,40);
 strcat(filter,userInfo->username);
 memcpy(filter+strlen(userInfo->username),"//RecieveBox//*.eml",17);
    hFind=FindFirstFile(filter,&FindFileData);
 if(INVALID_HANDLE_VALUE!=hFind)
 {
  mailNum++;
  while(FindNextFile(hFind,&FindFileData))mailNum++;
 }
    FindClose(hFind);

 free(filter);

 return mailNum;
}
/*****************************************************************************************************/

/*****************************************************************************************************
Function_Name: GetMailFileTotalSize
Used To: 根据参数userInfo返回userInfo->username/RecieveBox下邮件总大小
Date: 2004-4-20
*****************************************************************************************************/
int GetMailFileTotalSize(UserInfo *userInfo)
{
 WIN32_FIND_DATA FindFileData;                  
    HANDLE hFind;
 char *filter;                                  //文件过滤条件
 int totalMailSize=0;                          //初始化总的邮件大小为0
 
 filter=(char *)malloc(sizeof(char)*40);        //构造过滤条件
 memset(filter,0x00,40);
 strcat(filter,userInfo->username);
 memcpy(filter+strlen(userInfo->username),"//RecieveBox//*.eml",17);

    hFind=FindFirstFile(filter,&FindFileData);
 if(INVALID_HANDLE_VALUE!=hFind)
 {
  totalMailSize+=GetFileSize(FindFileData.cFileName,userInfo);
  while(FindNextFile(hFind,&FindFileData))
   totalMailSize+=GetFileSize(FindFileData.cFileName,userInfo);
 }
    FindClose(hFind);
 free(filter);

 return totalMailSize;
}
/*****************************************************************************************************/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值