📄 2003-01-05_email.cpp
字号:
conn->srvmail[conn->srvmaillen] = 0;
// check now
bool chkmail = (bool)CheckMsg(conn->srvmail, mainset.emailsettings.rules);
// now of all generate (hopefully) unique file name
CHARPTR sfile = GetFilename();
// check if messages passes
if (chkmail == true)
{
// message passes
// connect filename and dir
spath = ConnectStrings(conn->msgdir, sfile);
// set terminating zero-byte
(conn->srvmail)[conn->srvmaillen] = 0;
// write
WriteToFile(spath, conn->srvmail);
}
else
{
// message being blocked
// connect filename and dir
spath = ConnectStrings(mainset.emailsettings.trashdir , sfile);
// set terminating zero-byte
(conn->srvmail)[conn->srvmaillen] = 0;
// write
WriteToFile(spath, conn->srvmail);
}
// delete pointer
delete conn->srvmail;
// free memory
delete sfile;
delete spath;
// now we need to delete the mail on the server
CHARPTR delecmd = new char[11];
sprintf(delecmd,"DELE %d\x0D\x0A\0",conn->srvcurmsg);
emailscks->Sendsz(conn->serversock,delecmd);
delete delecmd;
conn->state = ECS_SDELETE;
}
else
{
// copy line to the end of current buffer
memcpy(&(conn->srvmail)[conn->srvmaillen], msgstart,msgend-msgstart+1);
// increate length counter
(conn->srvmaillen) += (msgend-msgstart+1);
// copy crlf
memcpy(&(conn->srvmail)[conn->srvmaillen],CRLF,2);
// increase counter again
(conn->srvmaillen) += 2;
}
}
break;
case ECS_SDELETE:
// proceed with nxt message
GetNextMsg(conn);
break;
default:
;
}
}
int GetNumOfMails(CHARPTR msgstart, CHARPTR msgend)
// extracts the number of emails on the server from STAT response
{
CHARPTR seek = msgstart;
CHARPTR seek2;
UINT temp;
// first 4 bytes are "+OK ", skip them
seek += 4;
// next byte should be first byte of number of emails
// ensure that seek doesn't point to a space anyway
while (*seek == 32) seek++;
// now find end of number by searching next space
seek2 = seek;
while (*seek2 != 32) seek2++;
// extract number and convert to integer
CHARPTR result = (CHARPTR)CopyAndPtr(seek,seek2-seek);
temp = atoi(result);
delete result;
return temp;
}
void ProcessClientMsg(EMAILCONN* conn, CHARPTR msgstart, CHARPTR msgend)
// this procedure processes incoming messages from the email
// client of the specific socket
{
UINT inum;
CHARPTR snum;
// now extract the first 4 character which represent the POP command
// and convert to lowercase
CHARPTR cmd = (CHARPTR)CopyAndPtr(msgstart,4);
strlwr(cmd);
// convert to integer
UINT icmd = *(UINT*)cmd;
// first of check if QUIT command was sent
if (icmd == POP_QUIT)
{
// send goodbye & close connection and leave procedure
emailscks->Sendsz(conn->clientsock, "+OK good bye\x0D\x0A\0");
emailscks->Close(conn->clientsock);
// if connected to server, disconnect
if (conn->serversock !=0)
emailscks->Sendsz(conn->serversock, "QUIT\x0D\x0A\0");
// call close handler manually, it contains important functions
// for cleanup
CloseHandler(conn->clientsock);
return;
}
// in which state is this connection?
switch (conn->state)
{
case ECS_CSENTHELLO:
// sent hello to client, waiting for username
if (icmd == POP_USER)
{
// now extract server, port and real username info
SERVERUSER* srvuser = ExtractUsernameInfo(msgstart+5,msgend);
// if zero was returned then username has wrong format
if (srvuser == 0)
{
emailscks->Sendsz(conn->clientsock,
"-ERR send username in format username@host[:port]\0");
}
else
{
// ensure that directory exists
conn->msgdir = EnsureDirectory(srvuser);
// store username and connect to server
conn->username = srvuser->user;
conn->serversock = emailscks->Connect(srvuser->server,srvuser->port);
// create mapping
(*connmap)[conn->serversock] = conn;
// now delete info which we don't need anymore
delete srvuser->server;
delete srvuser;
// set state
conn->state = ECS_SCONNECT;
}
}
else
// wrong command at this state
emailscks->Sendsz(conn->clientsock,
"-ERR awaiting USER command\x0D\x0A\0");
break;
case ECS_CWAITPASS:
// password should arrive now
if (icmd == POP_PASS)
{
// forward password to server
ForwardMessage(conn->serversock,msgstart,msgend);
conn->state = ECS_SSENTPASS;
}
else
// wrong command at this state
emailscks->Sendsz(conn->clientsock,
"-ERR awaiting PASS command\x0D\x0A\0");
break;
case ECS_READY:
// which command was sent?
switch (icmd)
{
case POP_STAT:
// STAT command
if (conn->mailschecked == true)
STATResponse(conn);
else
{ conn->savecommand = POP_STAT;
GetMails(conn);
}
break;
case POP_LIST:
// LIST command
if (conn->mailschecked == true)
LISTResponse(conn);
else
{
conn->savecommand = POP_LIST;
GetMails(conn);
}
break;
case POP_RETR:
// extract mail number
snum = (CHARPTR)CopyAndPtr(msgstart+5,msgend-(msgstart+5)+1);
// convert to int
inum = atoi(snum);
// RETR command
if (conn->mailschecked == true)
RETRResponse(conn, inum);
else
{
conn->savecommand = POP_RETR;
conn->savenum = inum;
GetMails(conn);
}
break;
case POP_DELE:
// extract mail number
snum = (CHARPTR)CopyAndPtr(msgstart+5,msgend-(msgstart+5)+1);
// convert to int
inum = atoi(snum);
// DELE command
if (conn->mailschecked == true)
DELEResponse(conn, inum);
else
{
conn->savecommand = POP_DELE;
conn->savenum = inum;
GetMails(conn);
}
break;
}
default:
;
}
}
CHARPTR EnsureDirectory(SERVERUSER* user)
{
// ensures that the archive directory for a certain user exists
// and returns string
// first of all connect host and user to a string (without port)
CHARPTR temp = (CHARPTR)CopyAndPtr(user->user, strlen(user->user) + 1);
temp[strlen(temp)] = '@';
CHARPTR fullusr = ConnectStrings(temp,user->server);
CHARPTR dir = ConnectStrings(mainset.emailsettings.archivedir,fullusr);
// create dir
CreateDir(dir);
// return directory string
return dir;
delete temp;
delete fullusr;
delete dir;
}
void GetNextMsg(EMAILCONN* conn)
// retrieves next email msg from server
{
// next msg
(conn->srvcurmsg)++;
// done?
if (conn->srvcurmsg > conn->srvnummails)
{
// done receiving emails
conn->mailschecked = true;
conn->state = ECS_READY;
// now get information about all emails in that folder
conn->srvm = MailDirInfo(conn->msgdir);
// now process the command which the client originally sent
switch (conn->savecommand)
{
case POP_STAT:
STATResponse(conn);
break;
case POP_LIST:
LISTResponse(conn);
break;
case POP_RETR:
RETRResponse(conn, conn->savenum);
}
}
else
{
// get next mail
// create buffer which is large enough to hold email
// use + 1 for zero
conn->srvmail = new char[conn->srvmsglen[conn->srvcurmsg-1]+10];
conn->srvmaillen = 0;
// build string
char tmp[12];
sprintf(tmp,"RETR %u\x0D\x0A\0",conn->srvcurmsg);
// send
emailscks->Sendsz(conn->serversock,tmp);
// set state
conn->state = ECS_SMSG;
// indicate that next msg is status line
conn->first = true;
}
}
void GetMails(EMAILCONN* conn)
// this procedure initiates the receiving of emails from the server
{
// send STAT command
emailscks->Sendsz(conn->serversock,"STAT\x0D\x0A\0");
conn->state = ECS_SSENTSTAT;
}
SERVERMAILS* MailDirInfo(CHARPTR dir)
// retrieves information about email files in a directory
// and returns a SERVERMAILS struct
{
// create SERVERMAILS struct
SERVERMAILS* ret = new SERVERMAILS;
ret->nummails = 0;
ret->paths = 0;
ret->fullsize = 0;
ret->sizes = 0;
// add wildcard * to dir
CHARPTR dirw = ConnectStrings(dir,"/*\0");
#ifdef WIN32
// *** WIN32 implementation start
WIN32_FIND_DATA find;
// now we need to iterate through all files to count the number of file
HANDLE search = FindFirstFile(dirw,&find);
while (true)
{
// only increase counter if not "." or ".." (check for single
// period at the beginning of file string
if (find.cFileName[0] != '.')
ret->nummails++;
if (FindNextFile(search,&find) == 0) break;
}
FindClose(search);
// now that we know the number of files we can create
// the array of pointers
ret->paths = new CHARPTR [ret->nummails];
// create array to save sizes of files
ret->sizes = new UINT [ret->nummails];
// walk through all files again, but this time, save
// file paths in array
search = FindFirstFile(dirw,&find);
UINT i=0;
while (true)
{
// only save in array if not "." or ".." (check for single
// period at the beginning of file string
if (find.cFileName[0] != '.')
{
// copy to new string and save pointer
ret->paths[i] = (CHARPTR)CopyAndPtr(find.cFileName, strlen(find.cFileName));
// connect path and filename again for filesize argument
CHARPTR tmp = ConnectStrings(dir,"/");
CHARPTR tmp2 = ConnectStrings(tmp,ret->paths[i]);
// get file size and save in array
ret->sizes[i] = GetFileLength(tmp2);
// add to full size
ret->fullsize += ret->sizes[i];
// deallocate memory
delete tmp2;
i++;
}
if (FindNextFile(search,&find) == 0) break;
}
FindClose(search);
// *** WIN32 implementation end
#endif
// delete connected string
delete dirw;
// return struct
return ret;
}
void STATResponse(EMAILCONN* conn)
// creates and sends a response to a STAT command from client
{
// we reserve 22 bytes for the response string
// response is in form:
// +OK xxxx yyyyyyyyyy[CR][LF][0]
// i think 4 digits for the number of emails and 10 digits
// for the total size should be more than enough
CHARPTR res = new char[22];
// fill string
sprintf(res,"+OK %d %d\x0D\x0A\0", conn->srvm->nummails, conn->srvm->fullsize);
// send message to client
emailscks->Sendsz(conn->clientsock, res);
conn->state = ECS_READY;
}
void LISTResponse(EMAILCONN* conn)
// creates and sends a response to a LIST command from client
{
// we reserve 40 bytes for the initial status response:
// +OK xxxx messages (yyyyyyyyyy octets)[CR][LF]
// then we need an additional 17 bytes for each message
// xxxx yyyyyyyyyy[CR][LF]
// plus 4 bytes for finishing line .[CR][LF][0]
// i know the digit lengths for message numbers and message
// size are way to huge but this way there won't be any complications
CHARPTR res = new char[40 + (17 * conn->srvm->nummails) + 4];
UINT pos=0;
// write status line
pos += sprintf(res, "+OK %d messages (%d octets)\x0D\x0A",
conn->srvm->nummails, conn->srvm->fullsize);
// now write line for each message
for (UINT i=0;i<conn->srvm->nummails;i++)
{
pos += sprintf(&res[pos], "%d %d\x0D\x0A",
(i+1),conn->srvm->sizes[i]);
}
// write finishing line
sprintf(&res[pos], ".\x0D\x0A\0");
// send response
emailscks->Sendsz(conn->clientsock, res);
conn->state = ECS_READY;
}
void RETRResponse(EMAILCONN* conn, UINT inum)
// sends a message to the client (if existing)
{
// check if message is in correct range
if ((inum < 0) || (inum > conn->srvm->nummails))
{
// error! return error msg
emailscks->Sendsz(conn->clientsock,
"-ERR no such message\x0D\x0A\0");
return;
}
// ok, now try to get file contents
CHARPTR filecont;
UINT filelen;
// connect path and file
CHARPTR tmp = (CHARPTR)ConnectStrings(conn->msgdir, "/\0");
CHARPTR tmp2 = (CHARPTR)ConnectStrings(tmp, conn->srvm->paths[inum-1]);
GetFileCont(tmp2, &filecont, &filelen);
filelen; // [DBG]
// if filecont == zero -> failed, file probably deleted
if (filecont == 0)
{
// error! return error msg
emailscks->Sendsz(conn->clientsock,
"-ERR no such message\x0D\x0A\0");
return;
}
// send ok + number of octets
CHARPTR res = new CHAR[17];
sprintf(res,"+OK %d\x0D\x0A\0",conn->srvm->sizes[inum-1]);
emailscks->Sendsz(conn->clientsock, res);
// file contents seems to be loaded correctly, send now
emailscks->Send(conn->clientsock, filecont, strlen(filecont));
// and send finishing line
emailscks->Sendsz(conn->clientsock, "\x0D\x0A.\x0D\x0A\0");
conn->state = ECS_READY;
}
void DELEResponse(EMAILCONN* conn, UINT inum)
// deletes a message and sends response to client
{
// connect path and file
CHARPTR tmp = (CHARPTR)ConnectStrings(conn->msgdir, "/\0");
CHARPTR tmp2 = (CHARPTR)ConnectStrings(tmp, conn->srvm->paths[inum-1]);
// check if file exists
if (FileExists(tmp2) == false)
{
emailscks->Sendsz(conn->clientsock,
"-ERR no such message\x0D\x0A\0");
return;
}
// delete file
KillFile(tmp2);
// send response
emailscks->Sendsz(conn->clientsock,
"+OK message deleted\x0D\x0A\0");
conn->state = ECS_READY;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -