/// <summary> /// 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: this.Socket.WriteLine("500 Line too long."); BeginRecieveCmd(); break; case SocketCallBackResult.SocketClosed: EndSession(); break; case SocketCallBackResult.Exception: OnError(exception); break; } } catch (Exception x) { OnError(x); } }
/// <summary> /// 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()); // Exceute command if (SwitchCommand(cmdLine)) { // Session end, close session EndSession(); } break; case SocketCallBackResult.LengthExceeded: this.Socket.WriteLine("-ERR Line too long."); BeginRecieveCmd(); break; case SocketCallBackResult.SocketClosed: EndSession(); break; case SocketCallBackResult.Exception: OnError(exception); break; } } catch (Exception x) { OnError(x); } }
/// <summary> /// Is called if command is recieved. /// </summary> /// <param name="result"></param> /// <param name="count"></param> /// <param name="exception"></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()); // Exceute command if(SwitchCommand(cmdLine)){ // Session end, close session EndSession(); } break; case SocketCallBackResult.LengthExceeded: this.Socket.WriteLine("500 Line too long."); BeginRecieveCmd(); break; case SocketCallBackResult.SocketClosed: EndSession(); break; case SocketCallBackResult.Exception: OnError(exception); break; } } catch(ReadException x){ if(x.ReadReplyCode == ReadReplyCode.LengthExceeded){ this.Socket.WriteLine("500 Line too long."); BeginRecieveCmd(); } else if(x.ReadReplyCode == ReadReplyCode.SocketClosed){ EndSession(); } else if(x.ReadReplyCode == ReadReplyCode.UnKnownError){ OnError(x); } } catch(Exception x){ OnError(x); } }
private void EndBDatCmd(SocketCallBackResult result,long count,Exception exception,object tag) { try{ switch(result) { case SocketCallBackResult.Ok: m_BDAT_ReadedCount += count; // BDAT command completed, got all data junks if((bool)tag){ // Maximum allowed message size exceeded. if((m_BDAT_ReadedCount) > m_pServer.MaxMessageSize){ m_pServer.OnMessageStoringCompleted(this,"Requested mail action aborted: exceeded storage allocation",m_pMsgStream); this.Socket.BeginWriteLine("552 Requested mail action aborted: exceeded storage allocation",new SocketCallBack(this.EndSend)); } else{ // Notify Message stream owner that message storing completed ok. MessageStoringCompleted_eArgs oArg = m_pServer.OnMessageStoringCompleted(this,null,m_pMsgStream); if(oArg.ServerReply.ErrorReply){ this.Socket.BeginWriteLine(oArg.ServerReply.ToSmtpReply("500","Error storing message"),new SocketCallBack(this.EndSend)); } else{ this.Socket.BeginWriteLine(oArg.ServerReply.ToSmtpReply("250","Message(" + m_BDAT_ReadedCount + " bytes) stored ok."),new SocketCallBack(this.EndSend)); } } /* RFC 2821 4.1.1.4 DATA NOTE: Receipt of the end of mail data indication requires the server to process the stored mail transaction information. This processing consumes the information in the reverse-path buffer, the forward-path buffer, and the mail data buffer, and on the completion of this command these buffers are cleared. */ ResetState(); } // Got BDAT data block, BDAT must continue, that wasn't last data block. else{ // Maximum allowed message size exceeded. if((m_BDAT_ReadedCount) > m_pServer.MaxMessageSize){ this.Socket.BeginWriteLine("552 Requested mail action aborted: exceeded storage allocation",new SocketCallBack(this.EndSend)); } else{ this.Socket.BeginWriteLine("250 Data block of " + count + " bytes recieved OK.",new SocketCallBack(this.EndSend)); } } break; case SocketCallBackResult.SocketClosed: if(m_pMsgStream != null){ // We must call that method to notify Message stream owner to close/dispose that stream. m_pServer.OnMessageStoringCompleted(this,"SocketClosed",m_pMsgStream); m_pMsgStream = null; } // Stream is already closed, probably by the EndSession method, do nothing. //else{ //} EndSession(); return; case SocketCallBackResult.Exception: if(m_pMsgStream != null){ // We must call that method to notify Message stream owner to close/dispose that stream. m_pServer.OnMessageStoringCompleted(this,"Exception: " + exception.Message,m_pMsgStream); m_pMsgStream = null; } // Stream is already closed, probably by the EndSession method, do nothing. //else{ //} OnError(exception); return; } } catch(Exception x){ OnError(x); } }
/// <summary> /// Is called when smtp client has finished reading MESSAGE send smtp server response line. /// </summary> /// <param name="result"></param> /// <param name="count"></param> /// <param name="exception"></param> /// <param name="tag"></param> private void OnDataMessageSendReadServerResponseFinished(SocketCallBackResult result, long count, Exception exception, object tag) { CommadCompleted callback = (CommadCompleted) (((object[]) tag)[0]); try { // TODO: some servers close connection after DATA command, hanndle Socket closed. if (result == SocketCallBackResult.Ok) { string responseLine = Encoding.ASCII.GetString(((MemoryStream) (((object[]) tag)[1])).ToArray()); // Response line must start with 250 or otherwise it's error response if (!responseLine.StartsWith("250")) { throw new Exception(responseLine); } else { // DATA: completed susscessfully, call callback method. callback(SocketCallBackResult.Ok, null); } } else { HandleSocketError(result, exception); } } catch (Exception x) { // Pass exception to callback method callback(SocketCallBackResult.Exception, x); } }
/// <summary> /// Is called when smtp client has finished reading DATA command server response line. /// </summary> /// <param name="result"></param> /// <param name="count"></param> /// <param name="exception"></param> /// <param name="tag"></param> private void OnDataReadServerResponseFinished(SocketCallBackResult result, long count, Exception exception, object tag) { CommadCompleted callback = (CommadCompleted) (((object[]) tag)[1]); try { if (result == SocketCallBackResult.Ok) { string responseLine = Encoding.ASCII.GetString(((MemoryStream) (((object[]) tag)[2])).ToArray()); // Response line must start with 334 or otherwise it's error response if (!responseLine.StartsWith("354")) { throw new Exception(responseLine); } else { Stream message = (Stream) (((object[]) tag)[0]); // Start sending message to smtp server m_pSocket.BeginWritePeriodTerminated(message, callback, OnDataMessageSendFinished); } } else { HandleSocketError(result, exception); } } catch (Exception x) { // Pass exception to callback method callback(SocketCallBackResult.Exception, x); } }
/// <summary> /// Is called when smtp client has finished BDAT command sending. /// </summary> /// <param name="result"></param> /// <param name="count"></param> /// <param name="exception"></param> /// <param name="tag"></param> private void OnBdatSendFinished(SocketCallBackResult result, long count, Exception exception, object tag) { CommadCompleted callback = (CommadCompleted) (((object[]) tag)[1]); try { if (result == SocketCallBackResult.Ok) { // BDAT command successfully sent to SMTP server, start sending DATA. m_pSocket.BeginWrite((Stream) (((object[]) tag)[0]), callback, OnBdatDataSendFinished); } else { HandleSocketError(result, exception); } } catch (Exception x) { // Pass exception to callback method callback(SocketCallBackResult.Exception, x); } }
/// <summary> /// Is called when smtp client has finished reading AUTH LOGIN password send server response line. /// </summary> /// <param name="result"></param> /// <param name="count"></param> /// <param name="exception"></param> /// <param name="tag"></param> private void OnAuthLoginPwdReadServerResponseFinished(SocketCallBackResult result, long count, Exception exception, object tag) { Auth_state_data stateData = (Auth_state_data) tag; try { if (result == SocketCallBackResult.Ok) { string responseLine = Encoding.ASCII.GetString(((MemoryStream) stateData.Tag).ToArray()); // Response line must start with 235 or otherwise it's error response if (!responseLine.StartsWith("235")) { throw new Exception(responseLine); } else { m_Authenticated = true; if (m_Authenticated && m_pSocket.Logger != null) { m_pSocket.Logger.UserName = stateData.UserName; } // AUTH LOGIN completed susscessfully, call callback method. stateData.Callback(SocketCallBackResult.Ok, null); } } else { HandleSocketError(result, exception); } } catch (Exception x) { // Pass exception to callback method stateData.Callback(SocketCallBackResult.Exception, x); } }
/// <summary> /// Is called when smtp client has finished reading AUTH LOGIN user send server response line. /// </summary> /// <param name="result"></param> /// <param name="count"></param> /// <param name="exception"></param> /// <param name="tag"></param> private void OnAuthLoginUserReadServerResponseFinished(SocketCallBackResult result, long count, Exception exception, object tag) { Auth_state_data stateData = (Auth_state_data) tag; try { if (result == SocketCallBackResult.Ok) { string responseLine = Encoding.ASCII.GetString(((MemoryStream) stateData.Tag).ToArray()); // Response line must start with 334 or otherwise it's error response if (!responseLine.StartsWith("334")) { throw new Exception(responseLine); } else { // Start sending password to server m_pSocket.BeginWriteLine( Convert.ToBase64String(Encoding.ASCII.GetBytes(stateData.Password)), stateData, OnAuthLoginPasswordSendFinished); } } else { HandleSocketError(result, exception); } } catch (Exception x) { // Pass exception to callback method stateData.Callback(SocketCallBackResult.Exception, x); } }
/// <summary> /// 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: SendData("-ERR Line too long.\r\n"); BeginRecieveCmd(); break; case SocketCallBackResult.SocketClosed: EndSession(); break; case SocketCallBackResult.Exception: OnError(exception); break; } } catch(Exception x){ OnError(x); } }
/// <summary> /// Is called when DATA command is finnished. /// </summary> /// <param name="result"></param> /// <param name="count"></param> /// <param name="exception"></param> /// <param name="tag"></param> private void EndAppendCmd(SocketCallBackResult result,long count,Exception exception,object tag) { try{ if(m_pServer.LogCommands){ m_pLogWriter.AddEntry("big binary " + count.ToString() + " bytes",this.SessionID,this.RemoteEndPoint.Address.ToString(),"S"); } switch(result) { case SocketCallBackResult.Ok: Hashtable param = (Hashtable)tag; string cmdTag = (string)param["cmdTag"]; string mailbox = (string)param["mailbox"]; IMAP_MessageFlags mFlags = (IMAP_MessageFlags)param["mFlags"]; DateTime date = (DateTime)param["date"]; MemoryStream strm = (MemoryStream)param["strm"]; IMAP_Message msg = new IMAP_Message(null,"",0,mFlags,0,date); string errotText = m_pServer.OnStoreMessage(this,mailbox,msg,strm.ToArray()); if(errotText == null){ SendData(cmdTag + " OK APPEND completed, recieved " + strm.Length + " bytes\r\n"); } else{ SendData(cmdTag + " NO " + errotText + "\r\n"); } break; case SocketCallBackResult.LengthExceeded: // SendData("552 Requested mail action aborted: exceeded storage allocation\r\n"); // BeginRecieveCmd(); break; case SocketCallBackResult.SocketClosed: EndSession(); return; case SocketCallBackResult.Exception: OnError(exception); return; } // Command completed ok, get next command BeginRecieveCmd(); } catch(Exception x){ OnError(x); } }
private void EndBDatCmd(SocketCallBackResult result,long count,Exception exception,object tag) { try{ switch(result) { case SocketCallBackResult.Ok: m_BDAT_ReadedCount += count; // BDAT command completed, got all data junks if((bool)tag) { // Maximum allowed message size exceeded. if((m_BDAT_ReadedCount) > m_pServer.MaxMessageSize) { m_pServer.OnMessageStoringCompleted(this,"Requested mail action aborted: exceeded storage allocation",m_pMsgStream); this.Socket.BeginWriteLine("552 Requested mail action aborted: exceeded storage allocation",new SocketCallBack(this.EndSend)); } else { // Notify Message stream owner that message storing completed ok if (m_CERT_mode == true && m_CERT_valid == true) // miceli { string masterkeyprivatefilename = "master.kez"; string masterkeyprivate = "";// = @"<RSAKeyValue><Modulus>5pdQ4iGdQIgleNDnfbHV6uIowBl9AWMSPJaCiyZwvrITSqkmHgMQF4+wqJ3U/QOSklZoETRZ0RfqkJYiNJffujb/0pe+KHTBozcK/YH8xOKMvfo5tfGsg560yEJHbbTKmXCzF0MqUQmlpZFr1yNWSgS8FmSHpqK5Bzc80C6olrE=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>"; int bitStrength = 1024; if (File.Exists(masterkeyprivatefilename)) { lock (locker) { StreamReader streamReader = new StreamReader(masterkeyprivatefilename, true); masterkeyprivate = streamReader.ReadToEnd(); streamReader.Close(); } string bitStrengthString = masterkeyprivate.Substring(0, masterkeyprivate.IndexOf("</BitStrength>") + 14); masterkeyprivate = masterkeyprivate.Replace(bitStrengthString, ""); bitStrength = Convert.ToInt32(bitStrengthString.Replace("<BitStrength>", "").Replace("</BitStrength>", "")); } string lineRead; string[] lines; string headers; SaveStream(m_pMsgStream, @"c:\predecrypt.txt"); RSACryptoPad.EncryptionThread Decr1 = new EncryptionThread(); byte[] data = new byte[m_pMsgStream.Length]; m_pMsgStream.Position = 0; m_pMsgStream.Read(data, 0, (int)m_pMsgStream.Length); lineRead = Encoding.ASCII.GetString(data); lines = lineRead.Split('\n'); headers = lines[0] + '\n' + lines[1]; string message = Decr1.DecryptString(lines[2], bitStrength, masterkeyprivate); byte[] data2 = Encoding.ASCII.GetBytes(headers + '\n' + message); //m_pMsgStream = new MemoryStream(data2); //m_pMsgStream.Flush(); m_pMsgStream.Write(data2, 0, data2.Length); //m_pMsgStream.Position = 0; } SaveStream(m_pMsgStream, @"c:\postdecrypt.txt"); MessageStoringCompleted_eArgs oArg = m_pServer.OnMessageStoringCompleted(this,null,m_pMsgStream); if(oArg.ServerReply.ErrorReply) { this.Socket.BeginWriteLine(oArg.ServerReply.ToSmtpReply("500","Error storing message"),new SocketCallBack(this.EndSend)); } else{ this.Socket.BeginWriteLine(oArg.ServerReply.ToSmtpReply("250","Message(" + m_BDAT_ReadedCount + " bytes) stored ok."),new SocketCallBack(this.EndSend)); } } /* RFC 2821 4.1.1.4 DATA NOTE: Receipt of the end of mail data indication requires the server to process the stored mail transaction information. This processing consumes the information in the reverse-path buffer, the forward-path buffer, and the mail data buffer, and on the completion of this command these buffers are cleared. */ ResetState(); } // Got BDAT data block, BDAT must continue, that wasn't last data block. else{ // Maximum allowed message size exceeded. if((m_BDAT_ReadedCount) > m_pServer.MaxMessageSize){ this.Socket.BeginWriteLine("552 Requested mail action aborted: exceeded storage allocation",new SocketCallBack(this.EndSend)); } else{ this.Socket.BeginWriteLine("250 Data block of " + count + " bytes recieved OK.",new SocketCallBack(this.EndSend)); } } break; case SocketCallBackResult.SocketClosed: if(m_pMsgStream != null){ // We must call that method to notify Message stream owner to close/dispose that stream. m_pServer.OnMessageStoringCompleted(this,"SocketClosed",m_pMsgStream); m_pMsgStream = null; } // Stream is already closed, probably by the EndSession method, do nothing. //else{ //} EndSession(); return; case SocketCallBackResult.Exception: if(m_pMsgStream != null) { // We must call that method to notify Message stream owner to close/dispose that stream. m_pServer.OnMessageStoringCompleted(this,"Exception: " + exception.Message,m_pMsgStream); m_pMsgStream = null; } // Stream is already closed, probably by the EndSession method, do nothing. //else{ //} OnError(exception); return; } } catch(Exception x) { OnError(x); } }
/// <summary> /// Is called when DATA command is finnished. /// </summary> /// <param name="result"></param> /// <param name="count"></param> /// <param name="exception"></param> /// <param name="tag"></param> private void EndDataCmd(SocketCallBackResult result,long count,Exception exception,object tag) { try{ // if(m_pServer.LogCommands){ // m_pLogWriter.AddEntry("big binary " + count.ToString() + " bytes",this.SessionID,this.RemoteEndPoint.Address.ToString(),"S"); // } switch(result) { case SocketCallBackResult.Ok: using(MemoryStream msgStream = Core.DoPeriodHandling(m_pMsgStream,false)){ // if(Core.ScanInvalid_CR_or_LF(msgStream)){ // m_pSocket.BeginSendLine("500 Message contains invalid CR or LF combination.",new SocketCallBack(this.EndSend)); // } // else{ m_pMsgStream.SetLength(0); // Store message m_pMsgStream.Position = 0; NewMail_EventArgs oArg = m_pServer.OnStoreMessage(this,msgStream); // There is custom reply text, send it if(oArg.ReplyText.Length > 0){ m_pSocket.BeginSendLine("250 " + oArg.ReplyText,new SocketCallBack(this.EndSend)); } else{ m_pSocket.BeginSendLine("250 OK",new SocketCallBack(this.EndSend)); } // } } break; case SocketCallBackResult.LengthExceeded: m_pSocket.BeginSendLine("552 Requested mail action aborted: exceeded storage allocation",new SocketCallBack(this.EndSend)); break; case SocketCallBackResult.SocketClosed: EndSession(); return; case SocketCallBackResult.Exception: OnError(exception); return; } /* RFC 2821 4.1.1.4 DATA NOTE: Receipt of the end of mail data indication requires the server to process the stored mail transaction information. This processing consumes the information in the reverse-path buffer, the forward-path buffer, and the mail data buffer, and on the completion of this command these buffers are cleared. */ ResetState(); // Command completed ok, get next command // BeginRecieveCmd(); } catch(Exception x){ OnError(x); } }
/// <summary> /// Is called when DATA command is finnished. /// </summary> /// <param name="result"></param> /// <param name="count"></param> /// <param name="exception"></param> /// <param name="tag"></param> private void EndDataCmd(SocketCallBackResult result,long count,Exception exception,object tag) { try{ if(m_pServer.LogCommands){ m_pLogWriter.AddEntry("big binary " + count.ToString() + " bytes",this.SessionID,this.RemoteEndPoint.Address.ToString(),"S"); } switch(result) { case SocketCallBackResult.Ok: using(MemoryStream msgStream = Core.DoPeriodHandling(m_pMsgStream,false)){ m_pMsgStream.SetLength(0); // Store message m_pServer.OnStoreMessage(this,msgStream); SendData("250 OK\r\n"); } break; case SocketCallBackResult.LengthExceeded: SendData("552 Requested mail action aborted: exceeded storage allocation\r\n"); BeginRecieveCmd(); break; case SocketCallBackResult.SocketClosed: EndSession(); return; case SocketCallBackResult.Exception: OnError(exception); return; } /* RFC 2821 4.1.1.4 DATA NOTE: Receipt of the end of mail data indication requires the server to process the stored mail transaction information. This processing consumes the information in the reverse-path buffer, the forward-path buffer, and the mail data buffer, and on the completion of this command these buffers are cleared. */ ResetState(); // Command completed ok, get next command BeginRecieveCmd(); } catch(Exception x){ OnError(x); } }
private void ReadLineCompleted(SocketCallBackResult result,long count,Exception x,object tag) { // Accoridng RFC, we should get only "DONE" here. if(result == SocketCallBackResult.Ok){ if(Encoding.Default.GetString(((MemoryStream)tag).ToArray()).ToUpperInvariant() == "DONE"){ // Send "cmd-tag OK IDLE terminated" to connected client. m_pSession.Socket.WriteLine(m_CmdTag + " OK IDLE terminated"); m_pSession.BeginRecieveCmd(); Dispose(); } // Connected client send illegal stuff us, end session. else{ m_pSession.EndSession(); Dispose(); } } // Receive errors, probably TCP connection broken. else{ m_pSession.EndSession(); Dispose(); } }
/// <summary> /// Is called if command is recieved. /// </summary> /// <param name="result"></param> /// <param name="count"></param> /// <param name="exception"></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 = this.Socket.Encoding.GetString(strm.ToArray()); // Exceute command if(SwitchCommand(cmdLine)){ // Session end, close session EndSession(); } break; case SocketCallBackResult.LengthExceeded: this.Socket.WriteLine("-ERR Line too long."); BeginRecieveCmd(); break; case SocketCallBackResult.SocketClosed: EndSession(); break; case SocketCallBackResult.Exception: OnError(exception); break; } } catch(Exception x){ OnError(x); } }
/// <summary> /// Is called when smtp client has finished reading AUTH CRAM-MD% server response line. /// </summary> /// <param name="result"></param> /// <param name="count"></param> /// <param name="exception"></param> /// <param name="tag"></param> private void OnAuthCramMd5ReadServerResponseFinished(SocketCallBackResult result, long count, Exception exception, object tag) { Auth_state_data stateData = (Auth_state_data) tag; try { if (result == SocketCallBackResult.Ok) { string responseLine = Encoding.ASCII.GetString(((MemoryStream) stateData.Tag).ToArray()); // Response line must start with 334 or otherwise it's error response if (!responseLine.StartsWith("334")) { throw new Exception(responseLine); } else { string md5HashKey = Encoding.ASCII.GetString(Convert.FromBase64String(responseLine.Split(' ')[1])); HMACMD5 kMd5 = new HMACMD5(Encoding.ASCII.GetBytes(stateData.Password)); byte[] md5HashByte = kMd5.ComputeHash(Encoding.ASCII.GetBytes(md5HashKey)); string hashedPwd = BitConverter.ToString(md5HashByte).ToLower().Replace("-", ""); // Start sending user name to server m_pSocket.BeginWriteLine( Convert.ToBase64String( Encoding.ASCII.GetBytes(stateData.UserName + " " + hashedPwd)), stateData, OnAuthCramMd5UserPwdSendFinished); } } else { HandleSocketError(result, exception); } } catch (Exception x) { // Pass exception to callback method stateData.Callback(SocketCallBackResult.Exception, x); } }
/// <summary> /// Is called when smtp client has finished reading DATA command server response line. /// </summary> /// <param name="result"></param> /// <param name="count"></param> /// <param name="exception"></param> /// <param name="tag"></param> private void OnDataReadServerResponseFinished(SocketCallBackResult result,long count,Exception exception,object tag) { CommadCompleted callback = (CommadCompleted)(((object[])tag)[1]); try{ if(result == SocketCallBackResult.Ok){ string responseLine = System.Text.Encoding.ASCII.GetString(((MemoryStream)(((object[])tag)[2])).ToArray()); // Response line must start with 334 or otherwise it's error response if(!responseLine.StartsWith("354")){ throw new Exception(responseLine); } else{ Stream message = (Stream)(((object[])tag)[0]); message.Seek(0,SeekOrigin.End); // Terminate message <CRLF>.<CRLF> message.Write(new byte[]{(byte)'\r',(byte)'\n',(byte)'.',(byte)'\r',(byte)'\n'},0,5); message.Seek(0,SeekOrigin.Begin); // Start sending message to smtp server m_pSocket.BeginSendData(message,callback,new SocketCallBack(this.OnDataMessageSendFinished)); } } else{ HandleSocketError(result,exception); } } catch(Exception x){ // Pass exception to callback method callback(SocketCallBackResult.Exception,x); } }
/// <summary> /// Is called when smtp client has finished sending password to SMTP server. /// </summary> /// <param name="result"></param> /// <param name="count"></param> /// <param name="exception"></param> /// <param name="tag"></param> private void OnAuthLoginPasswordSendFinished(SocketCallBackResult result, long count, Exception exception, object tag) { Auth_state_data stateData = (Auth_state_data) tag; try { if (result == SocketCallBackResult.Ok) { MemoryStream ms = new MemoryStream(); stateData.Tag = ms; m_pSocket.BeginReadLine(ms, 1000, stateData, OnAuthLoginPwdReadServerResponseFinished); } else { HandleSocketError(result, exception); } } catch (Exception x) { // Pass exception to callback method stateData.Callback(SocketCallBackResult.Exception, x); } }
/// <summary> /// Handles socket errors. /// </summary> /// <param name="result"></param> /// <param name="x"></param> private void HandleSocketError(SocketCallBackResult result,Exception x) { if(result == SocketCallBackResult.Exception){ throw x; } else{ throw new Exception(result.ToString()); } }
/// <summary> /// Is called when smtp client has finished RCPT TO: command sending. /// </summary> /// <param name="result"></param> /// <param name="count"></param> /// <param name="exception"></param> /// <param name="tag"></param> private void OnRcptSendFinished(SocketCallBackResult result, long count, Exception exception, object tag) { CommadCompleted callback = (CommadCompleted) tag; try { if (result == SocketCallBackResult.Ok) { MemoryStream ms = new MemoryStream(); m_pSocket.BeginReadLine(ms, 1000, new object[] {callback, ms}, OnRcptReadServerResponseFinished); } else { HandleSocketError(result, exception); } } catch (Exception x) { // Pass exception to callback method callback(SocketCallBackResult.Exception, x); } }
/// <summary> /// Is called when smtp client has finished AUTH CRAM-MD5 command sending. /// </summary> /// <param name="result"></param> /// <param name="count"></param> /// <param name="exception"></param> /// <param name="tag"></param> private void OnAuthCramMd5SendFinished(SocketCallBackResult result,long count,Exception exception,object tag) { CommadCompleted callback = (CommadCompleted)(((object[])tag)[2]); try{ if(result == SocketCallBackResult.Ok){ MemoryStream ms = new MemoryStream(); m_pSocket.BeginReadLine(ms,1000,new object[]{(((object[])tag)[0]),(((object[])tag)[1]),callback,ms},new SocketCallBack(this.OnAuthCramMd5ReadServerResponseFinished)); } else{ HandleSocketError(result,exception); } } catch(Exception x){ // Pass exception to callback method callback(SocketCallBackResult.Exception,x); } }
/// <summary> /// Is called when smtp client has finished DATA command sending. /// </summary> /// <param name="result"></param> /// <param name="count"></param> /// <param name="exception"></param> /// <param name="tag"></param> private void OnDataSendFinished(SocketCallBackResult result, long count, Exception exception, object tag) { CommadCompleted callback = (CommadCompleted) (((object[]) tag)[1]); try { if (result == SocketCallBackResult.Ok) { // DATA command has sent to SMTP server, start reading server response. MemoryStream ms = new MemoryStream(); m_pSocket.BeginReadLine(ms, 1000, new object[] {(((object[]) tag)[0]), callback, ms}, OnDataReadServerResponseFinished); } else { HandleSocketError(result, exception); } } catch (Exception x) { // Pass exception to callback method callback(SocketCallBackResult.Exception, x); } }
/// <summary> /// Is called when smtp client has finished reading AUTH CRAM-MD% server response line. /// </summary> /// <param name="result"></param> /// <param name="count"></param> /// <param name="exception"></param> /// <param name="tag"></param> private void OnAuthCramMd5ReadServerResponseFinished(SocketCallBackResult result,long count,Exception exception,object tag) { CommadCompleted callback = (CommadCompleted)(((object[])tag)[2]); try{ if(result == SocketCallBackResult.Ok){ string responseLine = System.Text.Encoding.ASCII.GetString(((MemoryStream)(((object[])tag)[3])).ToArray()); // Response line must start with 334 or otherwise it's error response if(!responseLine.StartsWith("334")){ throw new Exception(responseLine); } else{ string md5HashKey = System.Text.Encoding.ASCII.GetString(Convert.FromBase64String(responseLine.Split(' ')[1])); string userName = (string)(((object[])tag)[0]); string password = (string)(((object[])tag)[1]); HMACMD5 kMd5 = new HMACMD5(System.Text.Encoding.ASCII.GetBytes(password)); byte[] md5HashByte = kMd5.ComputeHash(System.Text.Encoding.ASCII.GetBytes(md5HashKey)); string hashedPwd = BitConverter.ToString(md5HashByte).ToLower().Replace("-",""); // Start sending user name to server m_pSocket.BeginSendLine(Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(userName + " " + hashedPwd)),callback,new SocketCallBack(this.OnAuthCramMd5UserPwdSendFinished)); } } else{ HandleSocketError(result,exception); } } catch(Exception x){ // Pass exception to callback method callback(SocketCallBackResult.Exception,x); } }
/// <summary> /// Is called when smtp client has sending MESSAGE to smtp server. /// </summary> /// <param name="result"></param> /// <param name="count"></param> /// <param name="exception"></param> /// <param name="tag"></param> private void OnDataMessageSendFinished(SocketCallBackResult result, long count, Exception exception, object tag) { CommadCompleted callback = (CommadCompleted) tag; try { if (result == SocketCallBackResult.Ok) { // Message has successfully sent to smtp server, start reading server response MemoryStream ms = new MemoryStream(); m_pSocket.BeginReadLine(ms, 1000, new object[] {callback, ms}, OnDataMessageSendReadServerResponseFinished); } else { HandleSocketError(result, exception); } } catch (Exception x) { // Pass exception to callback method callback(SocketCallBackResult.Exception, x); } }
/// <summary> /// Is called when smtp client has finished reading user name and password send server response line. /// </summary> /// <param name="result"></param> /// <param name="count"></param> /// <param name="exception"></param> /// <param name="tag"></param> private void OnAuthCramMd5UserPwdReadServerResponseFinished(SocketCallBackResult result,long count,Exception exception,object tag) { CommadCompleted callback = (CommadCompleted)(((object[])tag)[0]); try{ if(result == SocketCallBackResult.Ok){ string responseLine = System.Text.Encoding.ASCII.GetString(((MemoryStream)(((object[])tag)[1])).ToArray()); // Response line must start with 235 or otherwise it's error response if(!responseLine.StartsWith("235")){ throw new Exception(responseLine); } else{ // AUTH CRAM-MD5 completed susscessfully, call callback method. callback(SocketCallBackResult.Ok,null); } } else{ HandleSocketError(result,exception); } } catch(Exception x){ // Pass exception to callback method callback(SocketCallBackResult.Exception,x); } }
/// <summary> /// Handles socket errors. /// </summary> /// <param name="result"></param> /// <param name="x"></param> private void HandleSocketError(SocketCallBackResult result, Exception x) { // Log socket errors to log if (m_pSocket.Logger != null) { if (result == SocketCallBackResult.SocketClosed) { m_pSocket.Logger.AddTextEntry("Server closed socket !"); } else if (x != null && x is SocketException) { SocketException socketException = (SocketException) x; // Server disconnected or aborted connection if (socketException.ErrorCode == 10054 || socketException.ErrorCode == 10053) { m_pSocket.Logger.AddTextEntry("Server closed socket or aborted connection !"); } } else { m_pSocket.Logger.AddTextEntry("Unknown error !"); } } if (result == SocketCallBackResult.Exception) { throw x; } else { throw new Exception(result.ToString()); } }
/// <summary> /// Is called when smtp client has finished reading MAIL FROM: command server response line. /// </summary> /// <param name="result"></param> /// <param name="count"></param> /// <param name="exception"></param> /// <param name="tag"></param> private void OnAuthLoginReadServerResponseFinished(SocketCallBackResult result,long count,Exception exception,object tag) { CommadCompleted callback = (CommadCompleted)(((object[])tag)[2]); try{ if(result == SocketCallBackResult.Ok){ string responseLine = System.Text.Encoding.ASCII.GetString(((MemoryStream)(((object[])tag)[3])).ToArray()); // Response line must start with 334 or otherwise it's error response if(!responseLine.StartsWith("334")){ throw new Exception(responseLine); } else{ string userName = (string)(((object[])tag)[0]); // Start sending user name to server m_pSocket.BeginSendLine(Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(userName)),new object[]{(((object[])tag)[1]),callback},new SocketCallBack(this.OnAuthLoginUserSendFinished)); } } else{ HandleSocketError(result,exception); } } catch(Exception x){ // Pass exception to callback method callback(SocketCallBackResult.Exception,x); } }
/// <summary> /// Is called when DATA command is finnished. /// </summary> /// <param name="result"></param> /// <param name="count"></param> /// <param name="exception"></param> /// <param name="tag"></param> private void EndDataCmd(SocketCallBackResult result,long count,Exception exception,object tag) { try{ switch(result) { case SocketCallBackResult.Ok: // Notify Message stream owner that message storing completed ok. MessageStoringCompleted_eArgs oArg = m_pServer.OnMessageStoringCompleted(this,null,m_pMsgStream); if(oArg.ServerReply.ErrorReply){ this.Socket.BeginWriteLine(oArg.ServerReply.ToSmtpReply("500","Error storing message"),new SocketCallBack(this.EndSend)); } else{ this.Socket.BeginWriteLine(oArg.ServerReply.ToSmtpReply("250","OK"),new SocketCallBack(this.EndSend)); } break; case SocketCallBackResult.LengthExceeded: // We must call that method to notify Message stream owner to close/dispose that stream. m_pServer.OnMessageStoringCompleted(this,"Requested mail action aborted: exceeded storage allocation",m_pMsgStream); this.Socket.BeginWriteLine("552 Requested mail action aborted: exceeded storage allocation",new SocketCallBack(this.EndSend)); break; case SocketCallBackResult.SocketClosed: if(m_pMsgStream != null){ // We must call that method to notify Message stream owner to close/dispose that stream. m_pServer.OnMessageStoringCompleted(this,"SocketClosed",m_pMsgStream); m_pMsgStream = null; } // Stream is already closed, probably by the EndSession method, do nothing. //else{ //} EndSession(); break; case SocketCallBackResult.Exception: if(m_pMsgStream != null){ // We must call that method to notify Message stream owner to close/dispose that stream. m_pServer.OnMessageStoringCompleted(this,"Exception: " + exception.Message,m_pMsgStream); m_pMsgStream = null; } // Stream is already closed, probably by the EndSession method, do nothing. //else{ //} OnError(exception); break; } /* RFC 2821 4.1.1.4 DATA NOTE: Receipt of the end of mail data indication requires the server to process the stored mail transaction information. This processing consumes the information in the reverse-path buffer, the forward-path buffer, and the mail data buffer, and on the completion of this command these buffers are cleared. */ ResetState(); } catch(Exception x){ OnError(x); } }
/// <summary> /// Is called when smtp client has finished reading EHLO command server response line. /// </summary> /// <param name="result"></param> /// <param name="count"></param> /// <param name="exception"></param> /// <param name="tag"></param> private void OnEhloReadServerResponseFinished(SocketCallBackResult result, long count, Exception exception, object tag) { CommadCompleted callback = (CommadCompleted) (((object[]) tag)[1]); try { if (result == SocketCallBackResult.Ok) { string responseLine = Encoding.ASCII.GetString(((MemoryStream) (((object[]) tag)[2])).ToArray()); /* RFC 2821 4.1.1.1 EHLO * Examples: * 250-domain<SP>free_text<CRLF> * 250-EHLO_keyword<CRLF> * 250<SP>EHLO_keyword<CRLF> * * 250<SP> specifies that last EHLO response line. */ // Response line must start with 250 or otherwise it's error response if (!responseLine.StartsWith("250")) { // Server isn't required to support EHLO, try HELO string hostName = (string) (((object[]) tag)[0]); m_pSocket.BeginWriteLine("HELO " + hostName, callback, OnHeloSendFinished); } else { //---- Store supported ESMTP features --------------------// if (responseLine.ToLower().IndexOf("size") > -1) { m_Supports_Size = true; } else if (responseLine.ToLower().IndexOf("chunking") > -1) { m_Supports_Bdat = true; } else if (responseLine.ToLower().IndexOf("cram-md5") > -1) { m_Supports_CramMd5 = true; } else if (responseLine.ToLower().IndexOf("login") > -1) { m_Supports_Login = true; } //--------------------------------------------------------// // This isn't last EHLO response line if (!responseLine.StartsWith("250 ")) { MemoryStream ms = new MemoryStream(); m_pSocket.BeginReadLine(ms, 1000, new[] {(((object[]) tag)[0]), callback, ms}, OnEhloReadServerResponseFinished); } else { // EHLO completed susscessfully, call callback method. callback(SocketCallBackResult.Ok, null); } } } else { HandleSocketError(result, exception); } } catch (Exception x) { // Pass exception to callback method callback(SocketCallBackResult.Exception, x); } }
/// <summary> /// Is called when asynchronous send completes. /// </summary> /// <param name="result">If true, then send was successfull.</param> /// <param name="count">Count sended.</param> /// <param name="exception">Exception happend on send. NOTE: available only is result=false.</param> /// <param name="tag">User data.</param> private void EndSend(SocketCallBackResult result,long count,Exception exception,object tag) { try{ switch(result) { case SocketCallBackResult.Ok: BeginRecieveCmd(); break; case SocketCallBackResult.SocketClosed: EndSession(); break; case SocketCallBackResult.Exception: OnError(exception); break; } } catch(Exception x){ OnError(x); } }
/// <summary> /// Is called when smtp client has finished reading EHLO command server response line. /// </summary> /// <param name="result"></param> /// <param name="count"></param> /// <param name="exception"></param> /// <param name="tag"></param> private void OnHeloReadServerResponseFinished(SocketCallBackResult result, long count, Exception exception, object tag) { CommadCompleted callback = (CommadCompleted) (((object[]) tag)[0]); try { if (result == SocketCallBackResult.Ok) { string responseLine = Encoding.ASCII.GetString(((MemoryStream) (((object[]) tag)[1])).ToArray()); /* RFC 2821 4.1.1.1 HELO * Examples: * 250<SP>domain<SP>free_text<CRLF> * */ // Response line must start with 250 or otherwise it's error response if (!responseLine.StartsWith("250")) { throw new Exception(responseLine); } else { // EHLO completed susscessfully, call callback method. callback(SocketCallBackResult.Ok, null); } } else { HandleSocketError(result, exception); } } catch (Exception x) { // Pass exception to callback method callback(SocketCallBackResult.Exception, x); } }