using System;
using System.IO;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Xiaoxiao.Net;namespace Xiaoxiao.Net.POP3.Server
{
/// <summary>
/// POP3 Session.
/// </summary>
public class POP3_Session : ISocketServerSession
{
private BufferedSocket m_pSocket = null; // Referance to client Socket.
private POP3_Server m_pServer = null; // Referance to POP3 server.
private string m_SessionID = ""; // Holds session ID.
private string m_UserName = ""; // Holds loggedIn UserName.
private string m_Password = ""; // Holds loggedIn Password.
private bool m_Authenticated = false; // Holds authentication flag.
private string m_MD5_prefix = ""; // Session MD5 prefix for APOP command
private int m_BadCmdCount = 0; // Holds number of bad commands.
private POP3_Messages m_POP3_Messages = null;
private DateTime m_SessionStartTime;
private DateTime m_LastDataTime;
// private _LogWriter m_pLogWriter = null;
private object m_Tag = null;
/// <summary>
/// Default constructor.
/// </summary>
/// <param name="clientSocket">Referance to socket.</param>
/// <param name="server">Referance to POP3 server.</param>
/// <param name="logWriter">Log writer.</param>
public POP3_Session(Socket clientSocket,POP3_Server server,SocketLogger logWriter)
{
m_pSocket = new BufferedSocket(clientSocket);
m_pServer = server; m_SessionID = Guid.NewGuid().ToString();
m_POP3_Messages = new POP3_Messages();
m_SessionStartTime = DateTime.Now;
m_LastDataTime = DateTime.Now; if(m_pServer.LogCommands){
m_pSocket.Logger = logWriter;
m_pSocket.Logger.SessionID = m_SessionID;
} m_pSocket.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.NoDelay,1);
m_pSocket.Activity += new EventHandler(OnSocketActivity); // Start session proccessing
StartSession();
} #region method StartSession /// <summary>
/// Starts session.
/// </summary>
private void StartSession()
{
// Add session to session list
m_pServer.AddSession(this); if(m_pServer.LogCommands){
// m_pSocket.Logger.AddTextEntry();
// m_pLogWriter.AddEntry("//----- Sys: 'Session:'" + this.SessionID + " added " + DateTime.Now);
}
try{
// Check if ip is allowed to connect this computer
if(m_pServer.OnValidate_IpAddress(this.RemoteEndPoint)){
// Notify that server is ready
m_MD5_prefix = "<" + Guid.NewGuid().ToString().ToLower() + ">";
m_pSocket.SendLine("+OK " + m_pServer.HostName + " POP3 Server ready " + m_MD5_prefix); BeginRecieveCmd();
}
else{
EndSession();
}
}
catch(Exception x){
OnError(x);
}
} #endregion #region method EndSession /// <summary>
/// Ends session, closes socket.
/// </summary>
private void EndSession()
{
// Write logs to log file, if needed
if(m_pServer.LogCommands){
// m_pLogWriter.AddEntry("//----- Sys: 'Session:'" + this.SessionID + " removed " + DateTime.Now);
// m_pLogWriter.Flush(); m_pSocket.Logger.Flush();
} if(m_pSocket != null){
m_pSocket.Shutdown(SocketShutdown.Both);
m_pSocket.Close();
m_pSocket = null;
} m_pServer.RemoveSession(this);
} #endregion
#region method OnSessionTimeout /// <summary>
/// Is called by server when session has timed out.
/// </summary>
public void OnSessionTimeout()
{
try{
m_pSocket.SendLine("-ERR Session timeout, closing transmission channel");
}
catch{
} EndSession();
} #endregion #region method OnSocketActivity /// <summary>
/// Is called if there was some activity on socket, some data sended or received.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnSocketActivity(object sender,EventArgs e)
{
m_LastDataTime = DateTime.Now;
} #endregion #region method OnError /// <summary>
/// Is called when error occures.
/// </summary>
/// <param name="x"></param>
private void OnError(Exception x)
{
try{
if(x is SocketException){
SocketException xs = (SocketException)x; // Client disconnected without shutting down
if(xs.ErrorCode == 10054 || xs.ErrorCode == 10053){
if(m_pServer.LogCommands){
// m_pLogWriter.AddEntry("Client aborted/disconnected",this.SessionID,this.RemoteEndPoint.Address.ToString(),"C"); m_pSocket.Logger.AddTextEntry("Client aborted/disconnected");
} EndSession(); // Exception handled, return
return;
}
} m_pServer.OnSysError("",x);
}
catch(Exception ex){
m_pServer.OnSysError("",ex);
}
} #endregion
#region method BeginRecieveCmd
/// <summary>
/// Starts recieveing command.
/// </summary>
private void BeginRecieveCmd()
{
MemoryStream strm = new MemoryStream();
// AsyncSocketHelper.BeginRecieve(m_pSocket,strm,1024,"\r\n","\r\n",strm,new SocketCallBack(this.EndRecieveCmd),new SocketActivityCallback(this.OnSocketActivity));
m_pSocket.BeginReadLine(strm,1024,strm,new SocketCallBack(this.EndRecieveCmd));
} #endregion
using System.IO;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Xiaoxiao.Net;namespace Xiaoxiao.Net.POP3.Server
{
/// <summary>
/// POP3 Session.
/// </summary>
public class POP3_Session : ISocketServerSession
{
private BufferedSocket m_pSocket = null; // Referance to client Socket.
private POP3_Server m_pServer = null; // Referance to POP3 server.
private string m_SessionID = ""; // Holds session ID.
private string m_UserName = ""; // Holds loggedIn UserName.
private string m_Password = ""; // Holds loggedIn Password.
private bool m_Authenticated = false; // Holds authentication flag.
private string m_MD5_prefix = ""; // Session MD5 prefix for APOP command
private int m_BadCmdCount = 0; // Holds number of bad commands.
private POP3_Messages m_POP3_Messages = null;
private DateTime m_SessionStartTime;
private DateTime m_LastDataTime;
// private _LogWriter m_pLogWriter = null;
private object m_Tag = null;
/// <summary>
/// Default constructor.
/// </summary>
/// <param name="clientSocket">Referance to socket.</param>
/// <param name="server">Referance to POP3 server.</param>
/// <param name="logWriter">Log writer.</param>
public POP3_Session(Socket clientSocket,POP3_Server server,SocketLogger logWriter)
{
m_pSocket = new BufferedSocket(clientSocket);
m_pServer = server; m_SessionID = Guid.NewGuid().ToString();
m_POP3_Messages = new POP3_Messages();
m_SessionStartTime = DateTime.Now;
m_LastDataTime = DateTime.Now; if(m_pServer.LogCommands){
m_pSocket.Logger = logWriter;
m_pSocket.Logger.SessionID = m_SessionID;
} m_pSocket.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.NoDelay,1);
m_pSocket.Activity += new EventHandler(OnSocketActivity); // Start session proccessing
StartSession();
} #region method StartSession /// <summary>
/// Starts session.
/// </summary>
private void StartSession()
{
// Add session to session list
m_pServer.AddSession(this); if(m_pServer.LogCommands){
// m_pSocket.Logger.AddTextEntry();
// m_pLogWriter.AddEntry("//----- Sys: 'Session:'" + this.SessionID + " added " + DateTime.Now);
}
try{
// Check if ip is allowed to connect this computer
if(m_pServer.OnValidate_IpAddress(this.RemoteEndPoint)){
// Notify that server is ready
m_MD5_prefix = "<" + Guid.NewGuid().ToString().ToLower() + ">";
m_pSocket.SendLine("+OK " + m_pServer.HostName + " POP3 Server ready " + m_MD5_prefix); BeginRecieveCmd();
}
else{
EndSession();
}
}
catch(Exception x){
OnError(x);
}
} #endregion #region method EndSession /// <summary>
/// Ends session, closes socket.
/// </summary>
private void EndSession()
{
// Write logs to log file, if needed
if(m_pServer.LogCommands){
// m_pLogWriter.AddEntry("//----- Sys: 'Session:'" + this.SessionID + " removed " + DateTime.Now);
// m_pLogWriter.Flush(); m_pSocket.Logger.Flush();
} if(m_pSocket != null){
m_pSocket.Shutdown(SocketShutdown.Both);
m_pSocket.Close();
m_pSocket = null;
} m_pServer.RemoveSession(this);
} #endregion
#region method OnSessionTimeout /// <summary>
/// Is called by server when session has timed out.
/// </summary>
public void OnSessionTimeout()
{
try{
m_pSocket.SendLine("-ERR Session timeout, closing transmission channel");
}
catch{
} EndSession();
} #endregion #region method OnSocketActivity /// <summary>
/// Is called if there was some activity on socket, some data sended or received.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnSocketActivity(object sender,EventArgs e)
{
m_LastDataTime = DateTime.Now;
} #endregion #region method OnError /// <summary>
/// Is called when error occures.
/// </summary>
/// <param name="x"></param>
private void OnError(Exception x)
{
try{
if(x is SocketException){
SocketException xs = (SocketException)x; // Client disconnected without shutting down
if(xs.ErrorCode == 10054 || xs.ErrorCode == 10053){
if(m_pServer.LogCommands){
// m_pLogWriter.AddEntry("Client aborted/disconnected",this.SessionID,this.RemoteEndPoint.Address.ToString(),"C"); m_pSocket.Logger.AddTextEntry("Client aborted/disconnected");
} EndSession(); // Exception handled, return
return;
}
} m_pServer.OnSysError("",x);
}
catch(Exception ex){
m_pServer.OnSysError("",ex);
}
} #endregion
#region method BeginRecieveCmd
/// <summary>
/// Starts recieveing command.
/// </summary>
private void BeginRecieveCmd()
{
MemoryStream strm = new MemoryStream();
// AsyncSocketHelper.BeginRecieve(m_pSocket,strm,1024,"\r\n","\r\n",strm,new SocketCallBack(this.EndRecieveCmd),new SocketActivityCallback(this.OnSocketActivity));
m_pSocket.BeginReadLine(strm,1024,strm,new SocketCallBack(this.EndRecieveCmd));
} #endregion
/// Is called if command is recieved.
/// </summary>
/// <param name="result"></param>
/// <param name="exception"></param>
/// <param name="count"></param>
/// <param name="tag"></param>
private void EndRecieveCmd(SocketCallBackResult result,long count,Exception exception,object tag)
{
try{
switch(result)
{
case SocketCallBackResult.Ok:
MemoryStream strm = (MemoryStream)tag; string cmdLine = System.Text.Encoding.Default.GetString(strm.ToArray()); // if(m_pServer.LogCommands){
// m_pLogWriter.AddEntry(cmdLine + "<CRLF>",this.SessionID,this.RemoteEndPoint.Address.ToString(),"C");
// } // Exceute command
if(SwitchCommand(cmdLine)){
// Session end, close session
EndSession();
}
break; case SocketCallBackResult.LengthExceeded:
m_pSocket.SendLine("-ERR Line too long."); BeginRecieveCmd();
break; case SocketCallBackResult.SocketClosed:
EndSession();
break; case SocketCallBackResult.Exception:
OnError(exception);
break;
}
}
catch(Exception x){
OnError(x);
}
} #endregion
#region function SwitchCommand /// <summary>
/// Parses and executes POP3 commmand.
/// </summary>
/// <param name="POP3_commandTxt">POP3 command text.</param>
/// <returns>Returns true,if session must be terminated.</returns>
private bool SwitchCommand(string POP3_commandTxt)
{
//---- Parse command --------------------------------------------------//
string[] cmdParts = POP3_commandTxt.TrimStart().Split(new char[]{' '});
string POP3_command = cmdParts[0].ToUpper().Trim();
string argsText = Core.GetArgsText(POP3_commandTxt,POP3_command);
//---------------------------------------------------------------------// bool getNextCmd = true; switch(POP3_command)
{
case "USER":
USER(argsText);
getNextCmd = false;
break; case "PASS":
PASS(argsText);
getNextCmd = false;
break;
case "STAT":
STAT();
getNextCmd = false;
break; case "LIST":
LIST(argsText);
getNextCmd = false;
break; case "RETR":
RETR(argsText);
getNextCmd = false;
break; case "DELE":
DELE(argsText);
getNextCmd = false;
break; case "NOOP":
NOOP();
getNextCmd = false;
break; case "RSET":
RSET();
getNextCmd = false;
break; case "QUIT":
QUIT();
getNextCmd = false;
return true;
//----- Optional commands ----- //
case "UIDL":
UIDL(argsText);
getNextCmd = false;
break; case "APOP":
APOP(argsText);
getNextCmd = false;
break; case "TOP":
TOP(argsText);
getNextCmd = false;
break; case "AUTH":
AUTH(argsText);
getNextCmd = false;
break;
default:
m_pSocket.SendLine("-ERR Invalid command"); //---- Check that maximum bad commands count isn't exceeded ---------------//
if(m_BadCmdCount > m_pServer.MaxBadCommands-1){
m_pSocket.SendLine("-ERR Too many bad commands, closing transmission channel");
return true;
}
m_BadCmdCount++;
//-------------------------------------------------------------------------//
break;
}
if(getNextCmd){
BeginRecieveCmd();
}
return false;
} #endregion
#region function USER private void USER(string argsText)
{
/* RFC 1939 7. USER
Arguments:
a string identifying a mailbox (required), which is of
significance ONLY to the server
NOTE:
If the POP3 server responds with a positive
status indicator ("+OK"), then the client may issue
either the PASS command to complete the authentication,
or the QUIT command to terminate the POP3 session.
*/ if(m_Authenticated){
m_pSocket.BeginSendLine("-ERR You are already authenticated",new SocketCallBack(this.EndSend));
return;
}
if(m_UserName.Length > 0){
m_pSocket.BeginSendLine("-ERR username is already specified, please specify password",new SocketCallBack(this.EndSend));
return;
} string[] param = argsText.Split(new char[]{' '}); // There must be only one parameter - userName
if(argsText.Length > 0 && param.Length == 1){
string userName = param[0];
// Check if user isn't logged in already
if(!m_pServer.IsUserLoggedIn(userName)){
m_pSocket.BeginSendLine("+OK User:'" + userName + "' ok",new SocketCallBack(this.EndSend));
m_UserName = userName;
}
else{
m_pSocket.BeginSendLine("-ERR User:'" + userName + "' already logged in",new SocketCallBack(this.EndSend));
}
}
else{
m_pSocket.BeginSendLine("-ERR Syntax error. Syntax:{USER username}",new SocketCallBack(this.EndSend));
}
} #endregion #region function PASS
我就要连pop3检查有多少封信的部分,太多我找不到