nmailserver-commits Mailing List for NMail (Page 11)
Brought to you by:
dframpton-oss,
tmyroadctfig
You can subscribe to this list here.
| 2006 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(13) |
Jun
(14) |
Jul
(8) |
Aug
|
Sep
|
Oct
(8) |
Nov
(22) |
Dec
(9) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2007 |
Jan
(21) |
Feb
(31) |
Mar
(24) |
Apr
(8) |
May
(23) |
Jun
(40) |
Jul
(14) |
Aug
(5) |
Sep
(7) |
Oct
(10) |
Nov
|
Dec
|
| 2008 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(1) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
|
From: <tmy...@us...> - 2006-05-14 08:09:08
|
Revision: 33 Author: tmyroadctfig Date: 2006-05-14 01:09:03 -0700 (Sun, 14 May 2006) ViewCVS: http://svn.sourceforge.net/nmailserver/?rev=33&view=rev Log Message: ----------- Committed patch from Jared Hodges - minor change to unit tests. Modified Paths: -------------- NMail/trunk/NMail.UnitTests/SmtpServiceTests.cs Modified: NMail/trunk/NMail.UnitTests/SmtpServiceTests.cs =================================================================== --- NMail/trunk/NMail.UnitTests/SmtpServiceTests.cs 2006-05-14 08:04:49 UTC (rev 32) +++ NMail/trunk/NMail.UnitTests/SmtpServiceTests.cs 2006-05-14 08:09:03 UTC (rev 33) @@ -39,7 +39,12 @@ /// </summary> private void Open() { this.connection = new TcpTextConnection(log); - this.connection.Open(new Host(IPAddress.Loopback), 25); + try { + this.connection.Open(new Host(IPAddress.Loopback), 25); + } catch (System.Net.Sockets.SocketException e) { + Assert.Fail(e.Message + + "\n(These tests are not standalone - you may need to manually start the SMTP Service.)"); + } // Should get a 220 response string welcome = this.connection.ReadLine(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <tmy...@us...> - 2006-05-14 08:05:15
|
Revision: 32 Author: tmyroadctfig Date: 2006-05-14 01:04:49 -0700 (Sun, 14 May 2006) ViewCVS: http://svn.sourceforge.net/nmailserver/?rev=32&view=rev Log Message: ----------- Committed patch from Jared Hodges - refactoring of the SMTP service. Modified Paths: -------------- NMail/trunk/NMail.SmtpService/Command/HeloCommand.cs NMail/trunk/NMail.SmtpService/Command/RecipientCommand.cs NMail/trunk/NMail.SmtpService/Command/SenderCommand.cs NMail/trunk/NMail.SmtpService/NMail.SmtpService.csproj NMail/trunk/NMail.SmtpService/SmtpSession.cs NMail/trunk/NMail.SmtpService/State/AbstractSmtpState.cs NMail/trunk/NMail.SmtpService/State/ConnectedState.cs NMail/trunk/NMail.SmtpService/State/NegotiatedState.cs NMail/trunk/NMail.SmtpService/State/RecipientRecievedState.cs NMail/trunk/NMail.SmtpService/State/SenderRecievedState.cs Added Paths: ----------- NMail/trunk/NMail.SmtpService/Command/DataCommand.cs NMail/trunk/NMail.SmtpService/Command/EhloCommand.cs NMail/trunk/NMail.SmtpService/Command/ISmtpCommand.cs NMail/trunk/NMail.SmtpService/Command/NoopCommand.cs NMail/trunk/NMail.SmtpService/Command/QuitCommand.cs NMail/trunk/NMail.SmtpService/Command/ResetCommand.cs NMail/trunk/NMail.SmtpService/Command/StartTlsCommand.cs Removed Paths: ------------- NMail/trunk/NMail.SmtpService/Command/AbstractCommand.cs NMail/trunk/NMail.SmtpService/State/DataState.cs NMail/trunk/NMail.SmtpService/State/SmtpState.cs Deleted: NMail/trunk/NMail.SmtpService/Command/AbstractCommand.cs =================================================================== --- NMail/trunk/NMail.SmtpService/Command/AbstractCommand.cs 2006-05-14 06:36:32 UTC (rev 31) +++ NMail/trunk/NMail.SmtpService/Command/AbstractCommand.cs 2006-05-14 08:04:49 UTC (rev 32) @@ -1,48 +0,0 @@ -/* - * Copyright 2004-2006 Luke Quinane and Daniel Frampton - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -using System; - -namespace NMail.SmtpService.Command { - /// <summary> - /// Provides an abstract SMTP command. - /// </summary> - public abstract class AbstractCommand { - /// <summary> - /// Creates the command from the given command string. Any parameters are - /// extracted at this point. - /// </summary> - /// <param name="command">The command string.</param> - protected AbstractCommand(string command) { - this.command = command; - } - - /// <summary> - /// The full command string. - /// </summary> - private string command; - - /// <summary> - /// The full command string. - /// </summary> - public string Command { - get { - return this.command; - } - } - } -} Added: NMail/trunk/NMail.SmtpService/Command/DataCommand.cs =================================================================== --- NMail/trunk/NMail.SmtpService/Command/DataCommand.cs (rev 0) +++ NMail/trunk/NMail.SmtpService/Command/DataCommand.cs 2006-05-14 08:04:49 UTC (rev 32) @@ -0,0 +1,138 @@ +/* + * Copyright 2004-2006 Luke Quinane, Daniel Frampton and Jared Hodges. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Collections.Specialized; +using System.Collections.Generic; +using System.Text; +using System.Globalization; +using System.Text.RegularExpressions; + +using NMail.DataTypes; +using NMail.Helper; +using NMail.Configuration; +using NMail.SmtpService.State; +using NMail.SmtpService.Configuration; + +namespace NMail.SmtpService.Command { + /// <summary> + /// Represents the logic for handling the SMTP command DATA. + /// This command does not expect any arguments. + /// If no arguments are provided to the DATA command server will: + /// <list> + /// <item>Send a continuation response.</item> + /// <item>Read lines of message data until a single period is received (".")</item> + /// <item>Append any required headers.</item> + /// <item>Attempt to spool the message.</item> + /// <item>Send a 250 Ok response if successful.</item> + /// <item>The SMTP session will be transitioned to the NegotiatedState.</item> + /// </list> + /// </summary> + class DataCommand : ISmtpCommand { + #region ISmtpCommand Members + + public void Execute(SmtpSession session, string[] tokens) { + if (tokens.Length != 1) { + throw new ApplicationException("Invalid command syntax"); + } + + session.Connection.OkWaitingData(); + + int maximumMessageSize = SmtpServiceConfiguration.Current.MaximumMessageSize; + IDnsClient dns = NMailConfiguration.Current.DnsClient; + int currentMaxReadLength = session.Connection.MaximumReadLength; + ByteStringBuilder messageData = new ByteStringBuilder( + session.MessageEncoding, + session.SizeEstimate, + maximumMessageSize); + + try { + // Temporarily allow lines of any length + session.Connection.MaximumReadLength = maximumMessageSize; + + // Data is a special case where we don't want to split each incoming line + while (true) { + string dataLine = session.Connection.ReadLine( + session.MessageEncoding, + SmtpServiceConfiguration.Current.Timeout); + + if (dataLine == ".") { + break; + } else { + try { + // TODO: take action if a line is too long? + + messageData.Append(dataLine + session.Connection.Terminator); + } catch (ArgumentOutOfRangeException) { + // Message is too large + session.Connection.ErrorMessageTooLarge(); + + // All bets are off? + session.Message = null; + session.CurrentState = new NegotiatedState(session); + return; + } + } + } + } finally { + // Reset the maximum read line length + session.Connection.MaximumReadLength = currentMaxReadLength; + } + + // Parse the message headers + session.Message.Data = new Message(messageData.ToByteString()); + MessageHeaders headers = session.Message.Data.Headers; + + // Prepare details for the headers + string currentTime = DateTime.Now.ToString("r", DateTimeFormatInfo.InvariantInfo); + Host clientHost = dns.ResolveHost(session.ClientAddress); + string transport = (session.Esmtp) ? "ESMTP" : "SMTP"; + + // Add the received header + string recievedHeader = string.Format(RecievedHeader, session.ReportedHost, + clientHost, session.ClientAddress, SmtpServiceConfiguration.Current.VisibleHost, transport, currentTime); + headers.AppendStart("Recieved", recievedHeader); + + // All message must have a from address and a date. + if (headers["From"] == null) { + headers["From"] = session.Message.Sender.ToString(true); + } + if (headers["Date"] == null) { + headers["Date"] = currentTime; + } + + try { + // Attempt to spool the message + NMailConfiguration.Current.Router.SpoolMessage(session.Message); + session.Connection.Ok(); + } catch (Exception ex) { + session.Log.Warn("Error spooling message.", ex); + session.Connection.TemporaryBadResponse(ex.Message); + } + + session.Message = null; + session.CurrentState = new NegotiatedState(session); + } + + /// <summary> + /// The format of the "Received:" header line that must be added to the message. + /// </summary> + public const string RecievedHeader = "from {0} ({1} [{2}])\r\n\tby NMail ({3}) with {4} {5}"; + + #endregion + } +} Added: NMail/trunk/NMail.SmtpService/Command/EhloCommand.cs =================================================================== --- NMail/trunk/NMail.SmtpService/Command/EhloCommand.cs (rev 0) +++ NMail/trunk/NMail.SmtpService/Command/EhloCommand.cs 2006-05-14 08:04:49 UTC (rev 32) @@ -0,0 +1,50 @@ +/* + * Copyright 2004-2006 Luke Quinane, Daniel Frampton and Jared Hodges. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Collections.Generic; +using System.Text; + +using NMail.SmtpService.Configuration; + +namespace NMail.SmtpService.Command { + /// <summary> + /// Represents the logic for handling the SMTP command EHLO. + /// This command expects the connecting host's name as its sole argument. + /// The execution of a valid EHLO command will result in the following: + /// <list> + /// <item>The session will be marked as Extended SMTP (ESMTP)</item> + /// <item>The hostname of the client will be attached to the session</item> + /// <item>A 250 response will be sent to the client, with a list of the + /// SMTP server's capabilities. + /// </item> + /// <item>The SMTP session will be transitioned to the NegotiatedState.</item> + /// </list> + /// </summary> + class EhloCommand : HeloCommand { + #region ISmtpCommand Members + + public override void Execute(SmtpSession session, string[] tokens) { + ExecuteNoResponse(session, tokens); + session.Esmtp = true; + session.Connection.OkCapabilities(SmtpServiceConfiguration.Current.VisibleHost, + SmtpServiceConfiguration.Current.MaximumMessageSize); + } + + #endregion + } +} Modified: NMail/trunk/NMail.SmtpService/Command/HeloCommand.cs =================================================================== --- NMail/trunk/NMail.SmtpService/Command/HeloCommand.cs 2006-05-14 06:36:32 UTC (rev 31) +++ NMail/trunk/NMail.SmtpService/Command/HeloCommand.cs 2006-05-14 08:04:49 UTC (rev 32) @@ -1,5 +1,5 @@ /* - * Copyright 2004-2006 Luke Quinane and Daniel Frampton + * Copyright 2004-2006 Luke Quinane, Daniel Frampton and Jared Hodges. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,40 +19,51 @@ using NMail.DataTypes; using NMail.Helper; +using NMail.SmtpService.Configuration; +using NMail.SmtpService.State; namespace NMail.SmtpService.Command { /// <summary> - /// Provides parsing for the HELO command. + /// Represents the logic for handling the SMTP command HELO. + /// This command expects the connecting host's name as its sole argument. + /// The execution of a valid HELO command will result in the following: + /// <list> + /// <item>The session will be marked as NOT Extended SMTP (ESMTP)</item> + /// <item>The hostname of the client will be attached to the session</item> + /// <item>A 250 response will be sent to the client</item> + /// <item>The SMTP session will be transitioned to the NegotiatedState</item> + /// </list> /// </summary> - public class HeloCommand : AbstractCommand { - /// <summary> - /// The extracted hostname. - /// </summary> - private Host hostname; + public class HeloCommand : ISmtpCommand { + #region ISmtpCommand Members + + public virtual void Execute(SmtpSession session, string[] tokens) { + ExecuteNoResponse(session, tokens); + session.Connection.OkHelo(SmtpServiceConfiguration.Current.VisibleHost); + } + + #endregion + /// <summary> - /// Attempts to extract a hostname from a HELO command. + /// A helper that executes all command logic except for response to the client /// </summary> - /// <param name="command">The full command string.</param> - public HeloCommand(string command) : base(command) { - string[] tokens = command.Split(' '); + /// <param name="session"></param> + /// <param name="tokens"></param> + protected void ExecuteNoResponse(SmtpSession session, string[] tokens) { + Host hostname = null; if (tokens.Length == 2) { string hostStr = tokens[1]; hostStr = StringTokenizer.UnBracketString(hostStr); - this.hostname = new Host(hostStr); + hostname = new Host(hostStr); } else { throw new ApplicationException("Invalid command syntax"); } - } - /// <summary> - /// The extracted hostname. - /// </summary> - public Host Hostname { - get { - return this.hostname; - } + session.ReportedHost = hostname; + session.Esmtp = false; + session.CurrentState = new NegotiatedState(session); } } } Added: NMail/trunk/NMail.SmtpService/Command/ISmtpCommand.cs =================================================================== --- NMail/trunk/NMail.SmtpService/Command/ISmtpCommand.cs (rev 0) +++ NMail/trunk/NMail.SmtpService/Command/ISmtpCommand.cs 2006-05-14 08:04:49 UTC (rev 32) @@ -0,0 +1,34 @@ +/* + * Copyright 2004-2006 Luke Quinane, Daniel Frampton and Jared Hodges. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; + +namespace NMail.SmtpService.Command { + /// <summary> + /// Interface for SMTP commands. + /// </summary> + public interface ISmtpCommand { + /// <summary> + /// Executes the command and sends a response to the client. + /// </summary> + /// <param name="session">The current command's session, including the connection + /// for delivering a response</param> + /// <param name="tokens">The arguments supplied to the command. tokens[0] is the command + /// name itself</param> + void Execute(SmtpSession session, string [] tokens); + } +} Added: NMail/trunk/NMail.SmtpService/Command/NoopCommand.cs =================================================================== --- NMail/trunk/NMail.SmtpService/Command/NoopCommand.cs (rev 0) +++ NMail/trunk/NMail.SmtpService/Command/NoopCommand.cs 2006-05-14 08:04:49 UTC (rev 32) @@ -0,0 +1,35 @@ +/* + * Copyright 2004-2006 Luke Quinane, Daniel Frampton and Jared Hodges. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace NMail.SmtpService.Command { + /// <summary> + /// Represents the logic for handling the SMTP command NOOP. + /// </summary> + class NoopCommand : ISmtpCommand { + #region ISmtpCommand Members + + public void Execute(SmtpSession session, string[] tokens) { + session.Connection.Ok(); + } + + #endregion + } +} Added: NMail/trunk/NMail.SmtpService/Command/QuitCommand.cs =================================================================== --- NMail/trunk/NMail.SmtpService/Command/QuitCommand.cs (rev 0) +++ NMail/trunk/NMail.SmtpService/Command/QuitCommand.cs 2006-05-14 08:04:49 UTC (rev 32) @@ -0,0 +1,37 @@ +/* + * Copyright 2004-2006 Luke Quinane, Daniel Frampton and Jared Hodges. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace NMail.SmtpService.Command { + /// <summary> + /// Represents the logic for handling the SMTP command QUIT. + /// Executing this command causes the connection to the client to be closed. + /// </summary> + class QuitCommand : ISmtpCommand { + + #region ISmtpCommand Members + + public void Execute(SmtpSession session, string[] tokens) { + session.Connection.Close(); + } + + #endregion + } +} Modified: NMail/trunk/NMail.SmtpService/Command/RecipientCommand.cs =================================================================== --- NMail/trunk/NMail.SmtpService/Command/RecipientCommand.cs 2006-05-14 06:36:32 UTC (rev 31) +++ NMail/trunk/NMail.SmtpService/Command/RecipientCommand.cs 2006-05-14 08:04:49 UTC (rev 32) @@ -1,5 +1,5 @@ /* - * Copyright 2004-2006 Luke Quinane and Daniel Frampton + * Copyright 2004-2006 Luke Quinane, Daniel Frampton and Jared Hodges. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,23 +18,19 @@ using System; using NMail.DataTypes; +using NMail.Configuration; +using NMail.SmtpService.Configuration; +using NMail.SmtpService.State; namespace NMail.SmtpService.Command { /// <summary> /// Provides parsing for the "RCPT TO:" command. /// </summary> - public class RecipientCommand : AbstractCommand { - /// <summary> - /// The extracted recipient. - /// </summary> - private EmailAddress recipient; + public class RecipientCommand : ISmtpCommand { + #region ISmtpCommand Members - /// <summary> - /// Attempts to extract a recipient from a "RCPT TO:" command. - /// </summary> - /// <param name="command">The full command string.</param> - public RecipientCommand(string command) : base(command) { - string[] tokens = command.Split(' '); + public void Execute(SmtpSession session, string[] tokens) { + EmailAddress recipientEmail = null; if (tokens[1].ToLower().StartsWith("to:")) { // Extract the recipient address @@ -43,28 +39,48 @@ if (tokens.Length != 2) { throw new ApplicationException("Bad command syntax."); } else { - this.recipient = new EmailAddress(tokens[1].Remove(0, 3), true); + recipientEmail = new EmailAddress(tokens[1].Remove(0, 3), true); } } else { if (tokens.Length != 3) { throw new ApplicationException("Bad command syntax."); } else { - this.recipient = new EmailAddress(tokens[2], true); + recipientEmail = new EmailAddress(tokens[2], true); } } } else { // Missing the correct "TO:" part of the command throw new ApplicationException("Bad command syntax."); } - } - /// <summary> - /// The extracted recipient. - /// </summary> - public EmailAddress Recipient { - get { - return this.recipient; + SmtpMessageRecipient recipient = + new SmtpMessageRecipient(session.Message, recipientEmail); + + // Check the recipient + DeliveryResult result = NMailConfiguration.Current.Router.ValidateRecipient(recipient); + switch (result.Type) { + case DeliveryResultType.PermanentError: + session.Connection.ErrorBadRecipient(recipient); + session.IncrementBadRecipientCount(); + break; + + case DeliveryResultType.TemporaryError: + session.Connection.TemporaryBadRecipient(recipient); + break; + + case DeliveryResultType.Success: + if (session.Message.RecipientCount <= SmtpServiceConfiguration.Current.RecipientLimit) { + session.Message.AddRecipient(recipient); + session.Connection.OkRecipient(recipient); + session.CurrentState = new RecipientRecievedState(session); + } else { + session.Connection.TemporaryBadRecipient(recipient); + } + break; } + } + + #endregion } } Added: NMail/trunk/NMail.SmtpService/Command/ResetCommand.cs =================================================================== --- NMail/trunk/NMail.SmtpService/Command/ResetCommand.cs (rev 0) +++ NMail/trunk/NMail.SmtpService/Command/ResetCommand.cs 2006-05-14 08:04:49 UTC (rev 32) @@ -0,0 +1,63 @@ +/* + * Copyright 2004-2006 Luke Quinane, Daniel Frampton and Jared Hodges. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Collections.Generic; +using System.Text; +using NMail.SmtpService.State; + +namespace NMail.SmtpService.Command { + /// <summary> + /// Represents the logic for handling the SMTP command RSET. + /// This command expects no arguments. + /// The execution of a valid RSET command will result in the following: + /// <list> + /// <item>A 250 response will be sent to the client</item> + /// <item>The SMTP session will be transitioned to the either the + /// ConnectedState or the NegotiatedState depending on how + /// the command was created.</item> + /// </list> + /// </summary> + class ResetCommand : ISmtpCommand { + private bool isNegotiated; + + public ResetCommand(bool isNegotiated) { + this.isNegotiated = isNegotiated; + } + + #region ISmtpCommand Members + + public void Execute(SmtpSession session, string[] tokens) { + + if (tokens.Length == 1) { + // Reset state to negotiated unless we have not yet negotiated + if (isNegotiated) { + session.CurrentState = new NegotiatedState(session); + } else { + session.CurrentState = new ConnectedState(session); + } + + session.Message = null; + session.Connection.Ok(); + } else { + throw new ApplicationException("Invalid command syntax"); + } + } + + #endregion + } +} Modified: NMail/trunk/NMail.SmtpService/Command/SenderCommand.cs =================================================================== --- NMail/trunk/NMail.SmtpService/Command/SenderCommand.cs 2006-05-14 06:36:32 UTC (rev 31) +++ NMail/trunk/NMail.SmtpService/Command/SenderCommand.cs 2006-05-14 08:04:49 UTC (rev 32) @@ -1,5 +1,5 @@ /* - * Copyright 2004-2006 Luke Quinane and Daniel Frampton + * Copyright 2004-2006 Luke Quinane, Daniel Frampton and Jared Hodges. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,41 +19,30 @@ using System.Text; using NMail.DataTypes; +using NMail.SmtpService.Configuration; +using NMail.SmtpService.State; namespace NMail.SmtpService.Command { /// <summary> /// Provides parsing for the "MAIL FROM:" command. /// </summary> - public class SenderCommand : AbstractCommand { - /// <summary> - /// The extracted sender. - /// </summary> - private EmailAddress sender; + public class SenderCommand : ISmtpCommand { + #region ISmtpCommand Members - /// <summary> - /// The encoding for the message as reported by the client. - /// </summary> - private Encoding encoding; + public void Execute(SmtpSession session, string[] tokens) { + int sizeEstimate = 0; + Encoding encoding = Encoding.ASCII; + EmailAddress sender = null; - /// <summary> - /// The estimated size of the message in bytes as given by the client. - /// </summary> - private int sizeEstimate; - - public SenderCommand(string command) : base(command) { - this.sizeEstimate = 0; - this.encoding = Encoding.ASCII; - string[] tokens = command.Split(' '); - - if (tokens[1].ToLower().StartsWith("from:")) { + if (tokens.Length > 1 && tokens[1].ToLower().StartsWith("from:")) { // Handle the case where the "FROM:" and email address aren't seperated by whitespace int i; if (tokens[1].Length > 5) { i = 2; - this.sender = new EmailAddress(tokens[1].Remove(0, 5), true); + sender = new EmailAddress(tokens[1].Remove(0, 5), true); } else { i = 3; - this.sender = new EmailAddress(tokens[2], true); + sender = new EmailAddress(tokens[2], true); } #region Parameter Parsing @@ -66,17 +55,17 @@ } else if (parameter.StartsWith("size=")) { // Get the size estimate parameter = parameter.Remove(0, 5); - this.sizeEstimate = Int32.Parse(parameter); + sizeEstimate = Int32.Parse(parameter); } else if (parameter.StartsWith("body=")) { // Get the body type parameter = parameter.Remove(0, 5); switch (parameter) { case "7bit": - this.encoding = Encoding.ASCII; + encoding = Encoding.ASCII; break; case "8bitmime": - this.encoding = Encoding.UTF8; + encoding = Encoding.UTF8; break; default: @@ -94,33 +83,18 @@ // Missing the correct "FROM:" part of the command throw new ApplicationException("Bad command syntax."); } - } - /// <summary> - /// The extracted sender. - /// </summary> - public EmailAddress Sender { - get { - return this.sender; + if (sizeEstimate > SmtpServiceConfiguration.Current.MaximumMessageSize) { + session.Connection.ErrorMessageTooLarge(); + } else { + session.Message.Sender = sender; + session.SizeEstimate = sizeEstimate; + session.MessageEncoding = encoding; + session.Connection.Ok(); + session.CurrentState = new SenderRecievedState(session); } } - /// <summary> - /// The extracted size estimate for the message. - /// </summary> - public int SizeEstimate { - get { - return this.sizeEstimate; - } - } - - /// <summary> - /// The extracted encoding for the message data. - /// </summary> - public Encoding MessageEncoding { - get { - return this.encoding; - } - } + #endregion } } Added: NMail/trunk/NMail.SmtpService/Command/StartTlsCommand.cs =================================================================== --- NMail/trunk/NMail.SmtpService/Command/StartTlsCommand.cs (rev 0) +++ NMail/trunk/NMail.SmtpService/Command/StartTlsCommand.cs 2006-05-14 08:04:49 UTC (rev 32) @@ -0,0 +1,42 @@ +/* + * Copyright 2004-2006 Luke Quinane, Daniel Frampton and Jared Hodges. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace NMail.SmtpService.Command { + /// <summary> + /// Represents the logic for handling the SMTP command STARTTLS. + /// This command expects no arguments. + /// The execution of a valid STARTTLS command will result in the following: + /// <list> + /// <item>A 250 response will be sent to the client</item> + /// <item>TLS negotiation will begin.</item> + /// </list> + /// </summary> + class StartTlsCommand : ISmtpCommand { + #region ISmtpCommand Members + + public void Execute(SmtpSession session, string[] tokens) { + session.Connection.Ok(); + session.Connection.StartTlsAsServer(); + } + + #endregion + } +} Modified: NMail/trunk/NMail.SmtpService/NMail.SmtpService.csproj =================================================================== --- NMail/trunk/NMail.SmtpService/NMail.SmtpService.csproj 2006-05-14 06:36:32 UTC (rev 31) +++ NMail/trunk/NMail.SmtpService/NMail.SmtpService.csproj 2006-05-14 08:04:49 UTC (rev 32) @@ -35,8 +35,7 @@ <ConfigurationOverrideFile> </ConfigurationOverrideFile> <DefineConstants>DEBUG;TRACE</DefineConstants> - <DocumentationFile> - </DocumentationFile> + <DocumentationFile>bin\Debug\NMail.SmtpService.XML</DocumentationFile> <DebugSymbols>true</DebugSymbols> <FileAlignment>4096</FileAlignment> <NoStdLib>false</NoStdLib> @@ -98,18 +97,22 @@ <Compile Include="AssemblyInfo.cs"> <SubType>Code</SubType> </Compile> - <Compile Include="Command\AbstractCommand.cs"> - <SubType>Code</SubType> - </Compile> + <Compile Include="Command\DataCommand.cs" /> + <Compile Include="Command\EhloCommand.cs" /> <Compile Include="Command\HeloCommand.cs"> <SubType>Code</SubType> </Compile> + <Compile Include="Command\ISmtpCommand.cs" /> + <Compile Include="Command\NoopCommand.cs" /> + <Compile Include="Command\QuitCommand.cs" /> <Compile Include="Command\RecipientCommand.cs"> <SubType>Code</SubType> </Compile> + <Compile Include="Command\ResetCommand.cs" /> <Compile Include="Command\SenderCommand.cs"> <SubType>Code</SubType> </Compile> + <Compile Include="Command\StartTlsCommand.cs" /> <Compile Include="Configuration\SmtpServiceConfiguration.cs"> <SubType>Code</SubType> </Compile> @@ -128,9 +131,6 @@ <Compile Include="State\ConnectedState.cs"> <SubType>Code</SubType> </Compile> - <Compile Include="State\DataState.cs"> - <SubType>Code</SubType> - </Compile> <Compile Include="State\NegotiatedState.cs"> <SubType>Code</SubType> </Compile> @@ -140,9 +140,6 @@ <Compile Include="State\SenderRecievedState.cs"> <SubType>Code</SubType> </Compile> - <Compile Include="State\SmtpState.cs"> - <SubType>Code</SubType> - </Compile> <Content Include="NMail.SmtpService.build" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> @@ -152,4 +149,4 @@ <PostBuildEvent> </PostBuildEvent> </PropertyGroup> -</Project> \ No newline at end of file +</Project> Modified: NMail/trunk/NMail.SmtpService/SmtpSession.cs =================================================================== --- NMail/trunk/NMail.SmtpService/SmtpSession.cs 2006-05-14 06:36:32 UTC (rev 31) +++ NMail/trunk/NMail.SmtpService/SmtpSession.cs 2006-05-14 08:04:49 UTC (rev 32) @@ -1,5 +1,5 @@ /* - * Copyright 2004-2006 Luke Quinane and Daniel Frampton + * Copyright 2004-2006 Luke Quinane, Daniel Frampton and Jared Hodges. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -131,7 +131,7 @@ this.connection.StartIdleTimeout(); // Change to initial state and start processing commands - this.ChangeState(SmtpState.Connected); + this.currentState = new ConnectedState(this); this.CommandLoop(); } catch (Exception e) { // Probably an IO exception, ignore... @@ -161,47 +161,8 @@ command = this.connection.ReadLine(this.config.Timeout).Trim(); cmdTokens = command.Split(' '); - // attempt to process the command - switch (cmdTokens[0].ToLower()) { - case "quit": - this.connection.Close(); - break; - - case "noop": - this.currentState.Noop(command); - break; - - case "ehlo": - this.currentState.Ehlo(command); - break; - - case "helo": - this.currentState.Helo(command); - break; - - case "mail": - this.currentState.MailFrom(command); - break; - - case "rcpt": - this.currentState.RcptTo(command); - break; - - case "data": - this.currentState.Data(command); - break; - - case "rset": - this.currentState.Rset(command); - break; - - case "starttls": - this.currentState.StartTls(command); - break; - - default: - throw new ApplicationException("Invalid command."); - } + // process the command + this.currentState.Execute(command); } catch (TimeoutException) { // Timedout reading data from client this.connection.ErrorReadTimedout(); @@ -232,32 +193,11 @@ } /// <summary> - /// Changes the current state for the session. + /// Gets or set the current state of the session /// </summary> - /// <param name="newState">The new state to change to.</param> - internal void ChangeState(SmtpState newState) { - switch (newState) { - case SmtpState.Connected: - this.currentState = new ConnectedState(this); - break; - - case SmtpState.Negotiated: - this.currentState = new NegotiatedState(this); - break; - - case SmtpState.SenderRecieved: - this.currentState = new SenderRecievedState(this); - break; - - case SmtpState.RecipientRecieved: - this.currentState = new RecipientRecievedState(this); - break; - - case SmtpState.Data: - // The data state is a special case. - new DataState(this); - break; - } + internal AbstractSmtpState CurrentState { + get { return this.currentState; } + set { this.currentState = value; } } /// <summary> Modified: NMail/trunk/NMail.SmtpService/State/AbstractSmtpState.cs =================================================================== --- NMail/trunk/NMail.SmtpService/State/AbstractSmtpState.cs 2006-05-14 06:36:32 UTC (rev 31) +++ NMail/trunk/NMail.SmtpService/State/AbstractSmtpState.cs 2006-05-14 08:04:49 UTC (rev 32) @@ -1,5 +1,5 @@ /* - * Copyright 2004-2006 Luke Quinane and Daniel Frampton + * Copyright 2004-2006 Luke Quinane, Daniel Frampton and Jared Hodges. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,16 +16,31 @@ */ using System; +using System.Collections.Generic; using NMail; using NMail.Configuration; using NMail.DataTypes; using NMail.SmtpService; using NMail.SmtpService.Configuration; +using NMail.SmtpService.Command; namespace NMail.SmtpService.State { /// <summary> - /// Provides common SMTP session state functions. + /// <para> + /// Base class for SMTP session states, which provides common SMTP session + /// state functions. To implement a state, extend this class and add supported + /// commands to the <see cref="Commands">Commands</see> collection. Common + /// commands supported in all states have already been added. + /// </para> + /// <para> + /// Example (add this to your subclass constructor): + /// <code> + /// this.Commands["helo"] = new HeloCommand(); + /// this.Commands["ehlo"] = new EhloCommand(); + /// this.Commands["rset"] = new ResetCommand(false); + /// </code> + /// </para> /// </summary> public abstract class AbstractSmtpState { /// <summary> @@ -49,7 +64,14 @@ protected SmtpMessage message; /// <summary> + /// The collection of valid commands for this state, indexed by command name + /// </summary> + private IDictionary<string, ISmtpCommand> commands; + + /// <summary> /// Creates a new instance of the state using the given session. + /// Adds common QUIT, NOOP, and STARTTLS commands to collection of + /// supported commands. /// </summary> /// <param name="session">The session that owns this state.</param> protected AbstractSmtpState(SmtpSession session) { @@ -57,79 +79,48 @@ this.message = this.session.Message; this.messageRouter = NMailConfiguration.Current.Router; this.config = SmtpServiceConfiguration.Current; + + this.commands = new Dictionary<string, ISmtpCommand>(); + this.Commands["quit"] = new QuitCommand(); + this.Commands["noop"] = new NoopCommand(); + this.Commands["starttls"] = new StartTlsCommand(); } - #region Default Smtp Commands /// <summary> - /// The default action to perform for a NOOP command. + /// The collection of valid commands for this state. + /// Keys are command names (as provided by the client), in lowercase. + /// Values are the command to be supported by the name given as key. /// </summary> - /// <param name="command">The full command string.</param> - public virtual void Noop(string command) { - string[] tokens = command.Split(' '); - - if (tokens.Length == 1) { - session.Connection.Ok(); - } else { - throw new ApplicationException("Invalid command syntax."); + public IDictionary<string, ISmtpCommand> Commands { + get { + return this.commands; } } /// <summary> - /// The default action to perform for a RSET command. + /// Attempts to parse and execute <code>commandString</code>. + /// First word (delimited by space or end of line) is interpreted as + /// command name. If the command name corresponds to a supported command + /// in the <see cref="Commands">Commands</see> collection, the appropriate + /// command is executed. Otherwise, an <code>ApplicationException</code> + /// is thrown. /// </summary> - /// <param name="command">The full command string.</param> - public virtual void Rset(string command) { - throw new ApplicationException("Invalid state."); - } + /// <param name="commandString"></param> + /// <exception cref="ApplicationException">Application Exception thrown for + /// invalid command syntax or an unsupported command</exception> + public virtual void Execute(string commandString) { + string [] tokens = commandString.Split(' '); - /// <summary> - /// The default action to perform for a HELO command. - /// </summary> - /// <param name="command">The full command string.</param> - public virtual void Helo(string command) { - throw new ApplicationException("Invalid state."); - } + if (tokens.Length == 0) { + throw new ApplicationException("Invalid command syntax."); + } - /// <summary> - /// The default action to perform for a EHLO command. - /// </summary> - /// <param name="command">The full command string.</param> - public virtual void Ehlo(string command) { - throw new ApplicationException("Invalid state."); - } + string commandName = tokens[0].ToLower(); + if (!this.Commands.ContainsKey(commandName)) { + throw new ApplicationException("Invalid Command."); + } - /// <summary> - /// The default action to perform for a "MAIL FROM:" command. - /// </summary> - /// <param name="command">The full command string.</param> - public virtual void MailFrom(string command) { - throw new ApplicationException("Invalid state."); + this.Commands[commandName].Execute(session, tokens); } - - /// <summary> - /// The default action to perform for a "RCPT TO:" command. - /// </summary> - /// <param name="command">The full command string.</param> - public virtual void RcptTo(string command) { - throw new ApplicationException("Invalid state."); - } - - /// <summary> - /// The default action to perform for a DATA command. - /// </summary> - /// <param name="command">The full command string.</param> - public virtual void Data(string command) { - throw new ApplicationException("Invalid state."); - } - - /// <summary> - /// The default action to perform for a STARTTLS command. - /// </summary> - /// <param name="command">The full command string.</param> - public virtual void StartTls(string command) { - this.session.Connection.Ok(); - this.session.Connection.StartTlsAsServer(); - } - #endregion } } Modified: NMail/trunk/NMail.SmtpService/State/ConnectedState.cs =================================================================== --- NMail/trunk/NMail.SmtpService/State/ConnectedState.cs 2006-05-14 06:36:32 UTC (rev 31) +++ NMail/trunk/NMail.SmtpService/State/ConnectedState.cs 2006-05-14 08:04:49 UTC (rev 32) @@ -1,5 +1,5 @@ /* - * Copyright 2004-2006 Luke Quinane and Daniel Frampton + * Copyright 2004-2006 Luke Quinane, Daniel Frampton and Jared Hodges. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,46 +30,11 @@ /// </summary> /// <param name="session">The session the owns this state.</param> public ConnectedState(SmtpSession session) : base(session) { + this.Commands["helo"] = new HeloCommand(); + this.Commands["ehlo"] = new EhloCommand(); + this.Commands["rset"] = new ResetCommand(false); + this.session.Connection.Welcome(this.config.VisibleHost); } - - /// <summary> - /// The HELO command for this state. - /// </summary> - /// <param name="command">The full command string.</param> - public override void Helo(string command) { - HeloCommand heloCommand = new HeloCommand(command); - this.session.ReportedHost = heloCommand.Hostname; - this.session.Esmtp = false; - this.session.Connection.OkHelo(this.config.VisibleHost); - this.session.ChangeState(SmtpState.Negotiated); - } - - /// <summary> - /// The EHLO command for this state. - /// </summary> - /// <param name="command">The full command string.</param> - public override void Ehlo(string command) { - HeloCommand heloCommand = new HeloCommand(command); - this.session.ReportedHost = heloCommand.Hostname; - this.session.Esmtp = true; - this.session.Connection.OkCapabilities(this.config.VisibleHost, - this.config.MaximumMessageSize); - this.session.ChangeState(SmtpState.Negotiated); - } - - /// <summary> - /// The RSET command for this state. - /// </summary> - /// <param name="command">The full command string.</param> - public override void Rset(string command) { - string[] tokens = command.Split(' '); - - if (tokens.Length == 1) { - this.session.Connection.Ok(); - } else { - throw new ApplicationException("Invalid command syntax"); - } - } } } Deleted: NMail/trunk/NMail.SmtpService/State/DataState.cs =================================================================== --- NMail/trunk/NMail.SmtpService/State/DataState.cs 2006-05-14 06:36:32 UTC (rev 31) +++ NMail/trunk/NMail.SmtpService/State/DataState.cs 2006-05-14 08:04:49 UTC (rev 32) @@ -1,124 +0,0 @@ -/* - * Copyright 2004-2006 Luke Quinane and Daniel Frampton - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -using System; -using System.Collections.Specialized; -using System.Text; -using System.Globalization; -using System.Text.RegularExpressions; - -using NMail.Configuration; -using NMail.DataTypes; -using NMail.Helper; - -namespace NMail.SmtpService.State { - /// <summary> - /// Defines command behaviour in the data state. - /// </summary> - public class DataState : AbstractSmtpState { - /// <summary> - /// The name server for this state. - /// </summary> - private IDnsClient dns; - - /// <summary> - /// Creates a new instance of the state. - /// </summary> - /// <param name="session">The session the owns this state.</param> - public DataState(SmtpSession session) : base(session) { - int maximumMessageSize = this.config.MaximumMessageSize; - this.dns = NMailConfiguration.Current.DnsClient; - int currentMaxReadLength = this.session.Connection.MaximumReadLength; - ByteStringBuilder messageData = new ByteStringBuilder( - this.session.MessageEncoding, - this.session.SizeEstimate, - maximumMessageSize); - - try { - // Temporarily allow lines of any length - this.session.Connection.MaximumReadLength = maximumMessageSize; - - // Data is a special case where we don't want to split each incoming line - while (true) { - string dataLine = this.session.Connection.ReadLine( - this.session.MessageEncoding, - this.config.Timeout); - - if (dataLine == ".") { - break; - } else { - try { - // TODO: take action if a line is too long? - - messageData.Append(dataLine + this.session.Connection.Terminator); - } catch (ArgumentOutOfRangeException) { - // Message is too large - this.session.Connection.ErrorMessageTooLarge(); - - // All bets are off? - this.session.Message = null; - this.session.ChangeState(SmtpState.Negotiated); - return; - } - } - } - } finally { - // Reset the maximum read line length - this.session.Connection.MaximumReadLength = currentMaxReadLength; - } - - // Parse the message headers - this.message.Data = new Message(messageData.ToByteString()); - MessageHeaders headers = this.message.Data.Headers; - - // Prepare details for the headers - string currentTime = DateTime.Now.ToString("r", DateTimeFormatInfo.InvariantInfo); - Host clientHost = dns.ResolveHost(this.session.ClientAddress); - string transport = (this.session.Esmtp) ? "ESMTP" : "SMTP"; - - // Add the received header - string recievedHeader = string.Format(DataState.RecievedHeader, this.session.ReportedHost, - clientHost, this.session.ClientAddress, this.config.VisibleHost, transport, currentTime); - headers.AppendStart("Recieved", recievedHeader); - - // All message must have a from address and a date. - if (headers["From"] == null) { - headers["From"] = this.message.Sender.ToString(true); - } - if (headers["Date"] == null) { - headers["Date"] = currentTime; - } - - try { - // Attempt to spool the message - this.messageRouter.SpoolMessage(this.message); - this.session.Connection.Ok(); - } catch (Exception ex) { - this.session.Log.Warn("Error spooling message.", ex); - this.session.Connection.TemporaryBadResponse(ex.Message); - } - - this.session.Message = null; - this.session.ChangeState(SmtpState.Negotiated); - } - - /// <summary> - /// The format of the "Received:" header line that must be added to the message. - /// </summary> - public const string RecievedHeader = "from {0} ({1} [{2}])\r\n\tby NMail ({3}) with {4} {5}"; - } -} Modified: NMail/trunk/NMail.SmtpService/State/NegotiatedState.cs =================================================================== --- NMail/trunk/NMail.SmtpService/State/NegotiatedState.cs 2006-05-14 06:36:32 UTC (rev 31) +++ NMail/trunk/NMail.SmtpService/State/NegotiatedState.cs 2006-05-14 08:04:49 UTC (rev 32) @@ -1,5 +1,5 @@ /* - * Copyright 2004-2006 Luke Quinane and Daniel Frampton + * Copyright 2004-2006 Luke Quinane, Daniel Frampton and Jared Hodges. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,41 +30,14 @@ /// </summary> /// <param name="session">The session the owns this state.</param> public NegotiatedState(SmtpSession session) : base(session) { + this.Commands["mail"] = new SenderCommand(); + this.Commands["rset"] = new ResetCommand(true); + // Create a new message this.session.Message = new SmtpMessage(); this.message = this.session.Message; this.message.ReportedHost = this.session.ReportedHost; this.message.SourceAddress = session.ClientAddress; } - - public override void MailFrom(string command) { - // Parse mail from, extracting sender and parameters - SenderCommand senderCommand = new SenderCommand(command); - - // Check the message size is ok - if (senderCommand.SizeEstimate > this.config.MaximumMessageSize) { - this.session.Connection.ErrorMessageTooLarge(); - } else { - this.message.Sender = senderCommand.Sender; - this.session.SizeEstimate = senderCommand.SizeEstimate; - this.session.MessageEncoding = senderCommand.MessageEncoding; - this.session.Connection.Ok(); - this.session.ChangeState(SmtpState.SenderRecieved); - } - } - - /// <summary> - /// The RSET command for this state. - /// </summary> - /// <param name="command">The full command string.</param> - public override void Rset(string command) { - string[] tokens = command.Split(' '); - - if (tokens.Length == 1) { - this.session.Connection.Ok(); - } else { - throw new ApplicationException("Invalid command syntax"); - } - } } } Modified: NMail/trunk/NMail.SmtpService/State/RecipientRecievedState.cs =================================================================== --- NMail/trunk/NMail.SmtpService/State/RecipientRecievedState.cs 2006-05-14 06:36:32 UTC (rev 31) +++ NMail/trunk/NMail.SmtpService/State/RecipientRecievedState.cs 2006-05-14 08:04:49 UTC (rev 32) @@ -1,5 +1,5 @@ /* - * Copyright 2004-2006 Luke Quinane and Daniel Frampton + * Copyright 2004-2006 Luke Quinane, Daniel Frampton and Jared Hodges. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,70 +29,10 @@ /// Creates a new instance of the state. /// </summary> /// <param name="session">The session the owns this state.</param> - public RecipientRecievedState(SmtpSession session) : base(session) { } - - /// <summary> - /// The "RCPT TO:" command for this state. - /// </summary> - /// <param name="command">The full command string.</param> - public override void RcptTo(string command) { - // Get the recipient address - RecipientCommand recipientCommand = new RecipientCommand(command); - SmtpMessageRecipient recipient = - new SmtpMessageRecipient(this.message, recipientCommand.Recipient); - - // Check the recipient - DeliveryResult result = this.messageRouter.ValidateRecipient(recipient); - switch (result.Type) { - case DeliveryResultType.PermanentError: - this.session.Connection.ErrorBadRecipient(recipient); - this.session.IncrementBadRecipientCount(); - break; - - case DeliveryResultType.TemporaryError: - this.session.Connection.TemporaryBadRecipient(recipient); - break; - - case DeliveryResultType.Success: - if (this.message.RecipientCount <= this.config.RecipientLimit) { - this.message.AddRecipient(recipient); - this.session.Connection.OkRecipient(recipient); - } else { - this.session.Connection.TemporaryBadRecipient(recipient); - } - break; - } + public RecipientRecievedState(SmtpSession session) : base(session) { + this.Commands["rcpt"] = new RecipientCommand(); + this.Commands["data"] = new DataCommand(); + this.Commands["rset"] = new ResetCommand(true); } - - /// <summary> - /// The DATA command for this state. - /// </summary> - /// <param name="command">The full command string.</param> - public override void Data(string command) { - string[] tokens = command.Split(' '); - - if (tokens.Length == 1) { - this.session.Connection.OkWaitingData(); - this.session.ChangeState(SmtpState.Data); - } else { - throw new ApplicationException("Invalid command syntax"); - } - } - - /// <summary> - /// The RSET command for this state. - /// </summary> - /// <param name="command">The full command string.</param> - public override void Rset(string command) { - string[] tokens = command.Split(' '); - - if (tokens.Length == 1) { - this.session.Message = null; - this.session.Connection.Ok(); - this.session.ChangeState(SmtpState.Negotiated); - } else { - throw new ApplicationException("Invalid command syntax"); - } - } } } Modified: NMail/trunk/NMail.SmtpService/State/SenderRecievedState.cs =================================================================== --- NMail/trunk/NMail.SmtpService/State/SenderRecievedState.cs 2006-05-14 06:36:32 UTC (rev 31) +++ NMail/trunk/NMail.SmtpService/State/SenderRecievedState.cs 2006-05-14 08:04:49 UTC (rev 32) @@ -1,5 +1,5 @@ /* - * Copyright 2004-2006 Luke Quinane and Daniel Frampton + * Copyright 2004-2006 Luke Quinane, Daniel Frampton and Jared Hodges. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,52 +31,9 @@ /// Creates a new instance of the state. /// </summary> /// <param name="session">The session the owns this state.</param> - public SenderRecievedState(SmtpSession session) : base(session) { } - - /// <summary> - /// The "RCPT TO:" command for this state. - /// </summary> - /// <param name="command">The full command string.</param> - public override void RcptTo(string command) { - // Get the recipient address - RecipientCommand recipientCommand = new RecipientCommand(command); - SmtpMessageRecipient recipient = - new SmtpMessageRecipient(this.message, recipientCommand.Recipient); - - // Check the recipient - DeliveryResult result = this.messageRouter.ValidateRecipient(recipient); - switch (result.Type) { - case DeliveryResultType.PermanentError: - this.session.Connection.ErrorBadRecipient(recipient); - this.session.IncrementBadRecipientCount(); - break; - - case DeliveryResultType.TemporaryError: - this.session.Connection.TemporaryBadRecipient(recipient); - break; - - case DeliveryResultType.Success: - this.message.AddRecipient(recipient); - this.session.Connection.OkRecipient(recipient); - this.session.ChangeState(SmtpState.RecipientRecieved); - break; - } + public SenderRecievedState(SmtpSession session) : base(session) { + this.Commands["rcpt"] = new RecipientCommand(); + this.Commands["rset"] = new ResetCommand(true); } - - /// <summary> - /// The RSET command for this state. - /// </summary> - /// <param name="command">The full command string.</param> - public override void Rset(string command) { - string[] tokens = command.Split(' '); - - if (tokens.Length == 1) { - this.session.Message = null; - this.session.Connection.Ok(); - this.session.ChangeState(SmtpState.Negotiated); - } else { - throw new ApplicationException("Invalid command syntax"); - } - } } } Deleted: NMail/trunk/NMail.SmtpService/State/SmtpState.cs =================================================================== --- NMail/trunk/NMail.SmtpService/State/SmtpState.cs 2006-05-14 06:36:32 UTC (rev 31) +++ NMail/trunk/NMail.SmtpService/State/SmtpState.cs 2006-05-14 08:04:49 UTC (rev 32) @@ -1,50 +0,0 @@ -/* - * Copyright 2004-2006 Luke Quinane and Daniel Frampton - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -using System; - -namespace NMail.SmtpService.State { - /// <summary> - /// Describes the current state of an SMTP connection. - /// </summary> - public enum SmtpState { - /// <summary> - /// The client has connected but not said "HELO". - /// </summary> - Connected, - - /// <summary> - /// The client has said "HELO" and supplied a valid hostname - /// </summary> - Negotiated, - - /// <summary> - /// The client has given a valid sender - /// </summary> - SenderRecieved, - - /// <summary> - /// The client has given one or more valid recipients - /// </summary> - RecipientRecieved, - - /// <summary> - /// The client has sent a data command - /// </summary> - Data - }; -} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <tmy...@us...> - 2006-05-14 06:36:41
|
Revision: 31 Author: tmyroadctfig Date: 2006-05-13 23:36:32 -0700 (Sat, 13 May 2006) ViewCVS: http://svn.sourceforge.net/nmailserver/?rev=31&view=rev Log Message: ----------- made a copy Added Paths: ----------- NMail/branches/luke-dev/ Copied: NMail/branches/luke-dev (from rev 30, NMail/trunk) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <tmy...@us...> - 2006-05-14 06:33:03
|
Revision: 30 Author: tmyroadctfig Date: 2006-05-13 23:32:21 -0700 (Sat, 13 May 2006) ViewCVS: http://svn.sourceforge.net/nmailserver/?rev=30&view=rev Log Message: ----------- Work on installer and local store. Modified Paths: -------------- NMail/trunk/Installer/NMail-Installer.wxs NMail/trunk/Installer/NMail-installer.build NMail/trunk/NMail/DataTypes/ACLs/MailDomainPrivilege.cs NMail/trunk/NMail/DataTypes/ACLs/StoreFolderPrivilege.cs NMail/trunk/NMail/DataTypes/EmailAddress.cs NMail/trunk/NMail/DataTypes/LocalStore/MailDomain.cs NMail/trunk/NMail/DataTypes/Mailbox.cs NMail/trunk/NMail/ILocalStore.cs NMail/trunk/NMail/ILocalStoreData.cs NMail/trunk/NMail.Administration.Console/Command/AddUserCommand.cs NMail/trunk/NMail.Administration.Console/Context/LocalStoreContext.cs NMail/trunk/NMail.Administration.Console/NMail.Administration.Console.csproj NMail/trunk/NMail.ImapService/State/ConnectedState.cs NMail/trunk/NMail.LocalStore/LocalStore.cs NMail/trunk/NMail.LocalStoreData.MySql/MySqlLocalStore.sql NMail/trunk/NMail.LocalStoreData.MySql/MySqlLocalStoreData.cs NMail/trunk/NMail.MessageRouter/Configuration/MessageRouterConfiguration.cs NMail/trunk/NMail.MessageRouter/MessageRouter.cs NMail/trunk/NMail.Server/RemoteAdministration.cs NMail/trunk/NMail.Server.Console/NMail.config NMail/trunk/NMail.Server.Console/NMailConsoleServer.cs Added Paths: ----------- NMail/trunk/NMail.Administration.Console/Command/ListMailDomainsCommand.cs NMail/trunk/doc/ntlm.html Removed Paths: ------------- NMail/trunk/NDns/NDns.xml Modified: NMail/trunk/Installer/NMail-Installer.wxs =================================================================== --- NMail/trunk/Installer/NMail-Installer.wxs 2006-05-06 15:33:43 UTC (rev 29) +++ NMail/trunk/Installer/NMail-Installer.wxs 2006-05-14 06:32:21 UTC (rev 30) @@ -1,6 +1,12 @@ <?xml version="1.0"?> <Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi"> - <Product Id="3EEDBE2D-3E7A-44b1-B4AA-1DDD2EB0068E" Name="NMail Server" Language="1033" Version="1.0.0.0" Manufacturer="NMailServer.SourceForge.net"> + + <Product Id="3EEDBE2D-3E7A-44b1-B4AA-1DDD2EB0068E" + UpgradeCode="01CC30D2-B022-4e6c-A63B-7DD7ACCCCCE2" + Name="NMail Server" + Language="1033" + Version="1.0.0.0" + Manufacturer="NMailServer.SourceForge.net"> <Package Id="????????-????-????-????-????????????" Description="NMail Server 1.0 Installer." @@ -9,6 +15,9 @@ <Media Id="1" Cabinet="Product.cab" EmbedCab="yes" /> + <!-- <Upgrade Id="01CC30D2-B022-4e6c-A63B-7DD7ACCCCCE2"> + <UpgradeVersion /> + </Upgrade> --> <!-- == @@ -60,6 +69,7 @@ <ServiceInstall Id="S_NMail.Server.Service.exe" DisplayName="NMail Server" Description="The NMail mail service." Name="NMail.Server.Service.exe" ErrorControl="normal" Start="demand" Type="ownProcess" Vital="yes" /> + <!-- Account="NetworkService" --> </Component> @@ -163,14 +173,10 @@ <File Id="NMail.config" Name="NMail.cfg" LongName="NMail.config" DiskId="1" Source="obj\NMail.config" Vital="yes" /> </Component> - <Component Id="C_NMail.cer" Guid="36D552F8-A50A-44e3-9669-83E34BF3A359"> - <File Id="NMail.cer" Name="NMail.cer" LongName="NMail.cer" DiskId="1" Source="obj\NMail.cer" Vital="yes" /> + <Component Id="C_NMail.pfx" Guid="93D43655-6B2D-4539-850E-9063F20B0E69"> + <File Id="NMail.pfx" Name="NMail.pfx" LongName="NMail.pfx" DiskId="1" Source="obj\NMail.pfx" Vital="yes" /> </Component> - <Component Id="C_NMail.pvk" Guid="9DE97934-C943-4e27-9C07-0EA12CAF01EB"> - <File Id="NMail.pvk" Name="NMail.pvk" LongName="NMail.pvk" DiskId="1" Source="obj\NMail.pvk" Vital="yes" /> - </Component> - <Component Id="C_MySqlLocalStore.sql" Guid="5CA6F74D-AC23-45f6-B2B6-93C85E5EC1A7"> <File Id="MySqlLocalStore.sql" Name="MySqlLS.sql" LongName="MySqlLocalStore.sql" DiskId="1" Source="obj\MySqlLocalStore.sql" Vital="yes" /> </Component> @@ -237,8 +243,7 @@ <ComponentRef Id="C_Warning.txt" /> <ComponentRef Id="C_Bounce.txt" /> <ComponentRef Id="C_NMail.config" /> - <ComponentRef Id="C_NMail.cer" /> - <ComponentRef Id="C_NMail.pvk" /> + <ComponentRef Id="C_NMail.pfx" /> <ComponentRef Id="C_MySqlLocalStore.sql" /> <ComponentRef Id="C_MySqlSpoolData.sql" /> Modified: NMail/trunk/Installer/NMail-installer.build =================================================================== --- NMail/trunk/Installer/NMail-installer.build 2006-05-06 15:33:43 UTC (rev 29) +++ NMail/trunk/Installer/NMail-installer.build 2006-05-14 06:32:21 UTC (rev 30) @@ -45,8 +45,7 @@ <include name="Warning.txt" /> <include name="Bounce.txt" /> <include name="NMail.config" /> - <include name="nmail.cer" /> - <include name="nmail.pvk" /> + <include name="NMail.pfx" /> </fileset> </copy> <copy todir="${build.dir}"> Deleted: NMail/trunk/NDns/NDns.xml =================================================================== --- NMail/trunk/NDns/NDns.xml 2006-05-06 15:33:43 UTC (rev 29) +++ NMail/trunk/NDns/NDns.xml 2006-05-14 06:32:21 UTC (rev 30) @@ -1,921 +0,0 @@ -<?xml version="1.0"?> -<doc> - <assembly> - <name>NDns</name> - </assembly> - <members> - <member name="T:NDns.Message.Header"> - <summary> - Represents the header component of a DNS message. - </summary> - </member> - <member name="F:NDns.Message.Header.id"> - <summary> - A 16 bit Id number to identify this message. - </summary> - </member> - <member name="F:NDns.Message.Header.response"> - <summary> - Was this message a query or a response? - </summary> - </member> - <member name="F:NDns.Message.Header.opcode"> - <summary> - A four bit field that specifies query type in the message. - </summary> - </member> - <member name="F:NDns.Message.Header.authoritative"> - <summary> - Is the answer authoritative? - </summary> - </member> - <member name="F:NDns.Message.Header.truncated"> - <summary> - Was the message truncated due to size constraints? - </summary> - </member> - <member name="F:NDns.Message.Header.recursionDesired"> - <summary> - Is recursion desired? - </summary> - </member> - <member name="F:NDns.Message.Header.recursionAvailable"> - <summary> - Is recursion available? - </summary> - </member> - <member name="F:NDns.Message.Header.rcode"> - <summary> - The response code for this message. - </summary> - </member> - <member name="F:NDns.Message.Header.questionEntries"> - <summary> - An unsigned 16 bit integer specifying the number of entries in the - question section. - </summary> - </member> - <member name="F:NDns.Message.Header.answerEntries"> - <summary> - An unsigned 16 bit integer specifying the number of resource - records in the answer section. - </summary> - </member> - <member name="F:NDns.Message.Header.nameServerEntries"> - <summary> - An unsigned 16 bit integer specifying the number of name server - resource records in the authority records section. - </summary> - </member> - <member name="F:NDns.Message.Header.additionalEntries"> - <summary> - An unsigned 16 bit integer specifying the number of resource records in - the additional records section. - </summary> - </member> - <member name="F:NDns.Message.Header.lastId"> - <summary> - The last Id number assigned to a DNS message. - </summary> - </member> - <member name="M:NDns.Message.Header.#ctor"> - <summary> - Creates a new DNS message header with a unique Id number. - </summary> - </member> - <member name="M:NDns.Message.Header.#ctor(System.Byte[],System.UInt16,System.UInt16@)"> - <summary> - Creates a new DNS message header using the given data. This data is - typically the response from a DNS server. - </summary> - <param name="data">The data to create the message header from.</param> - <param name="start">The position to start reading the byte array from.</param> - <param name="length">The number of bytes read from the byte array.</param> - </member> - <member name="M:NDns.Message.Header.GetId"> - <summary> - Gets the next available Id number. - </summary> - <returns>The Id number.</returns> - </member> - <member name="M:NDns.Message.Header.ToByteArray"> - <summary> - Converts the header to a byte array ready to send in a DNS message. - </summary> - <returns>The header as a byte array.</returns> - </member> - <member name="M:NDns.Message.Header.CreateOpCode(System.Byte)"> - <summary> - Creates the opcode that corresponds to the given byte. - </summary> - <param name="opcode">The data to create the opcode from.</param> - <returns>The opcode.</returns> - </member> - <member name="M:NDns.Message.Header.CreateResponseCode(System.Byte)"> - <summary> - Creates the response code that corresponds to the given byte. - </summary> - <param name="rcode">The data to create the response code from.</param> - <returns>The response code.</returns> - </member> - <member name="P:NDns.Message.Header.Id"> - <summary> - Gets the Id number for this header (and thus message). - </summary> - </member> - <member name="T:NDns.Message.AnswerSection"> - <summary> - A answer section entry in a DNS message. - </summary> - </member> - <member name="F:NDns.Message.AnswerSection.answerName"> - <summary> - The string name in this answer. - </summary> - </member> - <member name="F:NDns.Message.AnswerSection.answerType"> - <summary> - The type of record. - </summary> - </member> - <member name="F:NDns.Message.AnswerSection.answerClass"> - <summary> - The query class. - </summary> - </member> - <member name="F:NDns.Message.AnswerSection.answerTTL"> - <summary> - The time to live for the answer. - </summary> - </member> - <member name="F:NDns.Message.AnswerSection.answerRecord"> - <summary> - The record data associated with this record. - </summary> - </member> - <member name="M:NDns.Message.AnswerSection.#ctor(System.Byte[],System.UInt16,System.UInt16@,NDns.Message.DomainCoder)"> - <summary> - Creates a answer section from the given byte data. - </summary> - <param name="data">The data to create the answer section from.</param> - <param name="start">The position to start reading the byte array from.</param> - <param name="length">The number of bytes read from the byte array.</param> - <param name="coder">The coder to use when parsing the data.</param> - </member> - <member name="P:NDns.Message.AnswerSection.Record"> - <summary> - The answer record associated with this answer entry. - </summary> - </member> - <member name="T:NDns.Message.Records.Record"> - <summary> - A DNS record. - </summary> - </member> - <member name="F:NDns.Message.Records.Record.type"> - <summary> - The type of this record. - </summary> - </member> - <member name="F:NDns.Message.Records.Record.recordTTL"> - <summary> - The time to live for this record (in seconds). - </summary> - </member> - <member name="F:NDns.Message.Records.Record.creationTime"> - <summary> - The time this record was created. - </summary> - </member> - <member name="M:NDns.Message.Records.Record.#ctor"> - <summary> - Creates a new DNS record. - </summary> - </member> - <member name="P:NDns.Message.Records.Record.Type"> - <summary> - Returns the type for this record. - </summary> - </member> - <member name="P:NDns.Message.Records.Record.Data"> - <summary> - The data associated with this record as a user readable string. - </summary> - </member> - <member name="P:NDns.Message.Records.Record.TTL"> - <summary> - Gets and sets the time to live for this record (in seconds). - </summary> - </member> - <member name="T:NDns.Message.QuestionSection"> - <summary> - A question section entry in a DNS message. - </summary> - </member> - <member name="F:NDns.Message.QuestionSection.queryName"> - <summary> - The string name being looked up. - </summary> - </member> - <member name="F:NDns.Message.QuestionSection.queryType"> - <summary> - The type of query being performed. - </summary> - </member> - <member name="F:NDns.Message.QuestionSection.queryClass"> - <summary> - The class of query. - </summary> - </member> - <member name="M:NDns.Message.QuestionSection.#ctor(System.String,NDns.Message.QType)"> - <summary> - Creates a new question section with the given string and type. - </summary> - <param name="queryName">The string to query.</param> - <param name="queryType">The type of query to perform.</param> - </member> - <member name="M:NDns.Message.QuestionSection.#ctor(System.Byte[],System.UInt16,System.UInt16@,NDns.Message.DomainCoder)"> - <summary> - Creates a question section from the given byte data. - </summary> - <param name="data">The data to create the question section from.</param> - <param name="start">The position to start reading the byte array from.</param> - <param name="length">The number of bytes read from the byte array.</param> - <param name="coder">The coder to use when parsing the data.</param> - </member> - <member name="M:NDns.Message.QuestionSection.ToByteArray(NDns.Message.DomainCoder,System.UInt16)"> - <summary> - Converts the question section into a byte array. - </summary> - <param name="coder">The string coder used to compress queries with.</param> - <param name="reference">A reference to the location of this entry in the message.</param> - <returns>The question section as a byte array.</returns> - </member> - <member name="T:NDns.Configuration.NDnsConfiguration"> - <summary> - Provides configuration settings for this package. - </summary> - </member> - <member name="M:NDns.Configuration.NDnsConfiguration.#ctor(System.Net.IPAddress[],System.Int32,System.Int32,System.Int32)"> - <summary> - Creates a new NDns configuration from the arguments. - </summary> - <param name="dnsServers">The list of DNS servers to query (in order).</param> - <param name="maxMXCacheSize">The maximum number of MX records to the cache.</param> - <param name="maxDomainCacheSize">The maximum number of domain records to the cache.</param> - <param name="maxAddressCacheSize">The maximum number of address records to the cache.</param> - </member> - <member name="P:NDns.Configuration.NDnsConfiguration.DnsServers"> - <summary> - The list of DNS servers to query (in order of perference). - </summary> - </member> - <member name="P:NDns.Configuration.NDnsConfiguration.MaximumMXCacheSize"> - <summary> - Returns the maximum cache for MX records size in entries. - </summary> - </member> - <member name="P:NDns.Configuration.NDnsConfiguration.MaximumDomainCacheSize"> - <summary> - Returns the maximum cache for domain records size in entries. - </summary> - </member> - <member name="P:NDns.Configuration.NDnsConfiguration.MaximumAddressCacheSize"> - <summary> - Returns the maximum cache for address records size in entries. - </summary> - </member> - <member name="T:NDns.Message.Records.MXRecord"> - <summary> - A DNS Mail eXchanger record. - </summary> - </member> - <member name="F:NDns.Message.Records.MXRecord.preference"> - <summary> - The preference associated with this MX record. - </summary> - </member> - <member name="F:NDns.Message.Records.MXRecord.mxName"> - <summary> - The name of the MX server. - </summary> - </member> - <member name="M:NDns.Message.Records.MXRecord.#ctor(System.String,System.UInt16)"> - <summary> - Creates a MX record from the given string and preference. - </summary> - <param name="mxName">The string of the MX record.</param> - <param name="perference">The preference of the MX record.</param> - </member> - <member name="M:NDns.Message.Records.MXRecord.#ctor(System.Byte[],System.UInt16,System.UInt16@,NDns.Message.DomainCoder)"> - <summary> - Creates a MX record from the given byte data. - </summary> - <param name="data">The data to create the MX record from.</param> - <param name="start">The position to start reading the byte array from.</param> - <param name="length">The number of bytes read from the byte array.</param> - <param name="coder">The coder to use when parsing the data.</param> - </member> - <member name="M:NDns.Message.Records.MXRecord.CompareTo(System.Object)"> - <summary> - Compares this MX record to another MX record, sorting by perference. - </summary> - <param name="obj">The other MX to compare to.</param> - <returns>-1 if this MX is perferable, 1 otherwise.</returns> - </member> - <member name="P:NDns.Message.Records.MXRecord.MX"> - <summary> - Returns the MX string for this record. - </summary> - </member> - <member name="P:NDns.Message.Records.MXRecord.Preference"> - <summary> - Returns the preference for this record. - </summary> - </member> - <member name="P:NDns.Message.Records.MXRecord.Data"> - <summary> - The data associated with this record as a user readable string. - </summary> - </member> - <member name="T:NDns.Message.QType"> - <summary> - The DNS query type. - </summary> - </member> - <member name="F:NDns.Message.QType.A"> - <summary> - A host address. - </summary> - </member> - <member name="F:NDns.Message.QType.NS"> - <summary> - An authoritative name server. - </summary> - </member> - <member name="F:NDns.Message.QType.CNAME"> - <summary> - The canonical name for an alias. - </summary> - </member> - <member name="F:NDns.Message.QType.SOA"> - <summary> - Marks the start of a zone of authority. - </summary> - </member> - <member name="F:NDns.Message.QType.PTR"> - <summary> - A string name pointer. - </summary> - </member> - <member name="F:NDns.Message.QType.HINFO"> - <summary> - Host information. - </summary> - </member> - <member name="F:NDns.Message.QType.MINFO"> - <summary> - Mailbox or mail list information. - </summary> - </member> - <member name="F:NDns.Message.QType.MX"> - <summary> - Mail exchange. - </summary> - </member> - <member name="F:NDns.Message.QType.TXT"> - <summary> - Text strings. - </summary> - </member> - <member name="T:NDns.Message.DNSMessage"> - <summary> - A DNS message used in DNS communications. - </summary> - </member> - <member name="F:NDns.Message.DNSMessage.header"> - <summary> - The header for this DNS message. - </summary> - </member> - <member name="F:NDns.Message.DNSMessage.questionEntries"> - <summary> - The question sections associated with this DNS message. - </summary> - </member> - <member name="F:NDns.Message.DNSMessage.answerEntries"> - <summary> - The answer sections associated with the DNS message. - </summary> - </member> - <member name="M:NDns.Message.DNSMessage.#ctor"> - <summary> - Creates a new DNS message. - </summary> - </member> - <member name="M:NDns.Message.DNSMessage.#ctor(System.Byte[])"> - <summary> - Creates a new DNS message using the given data. This data is typically the - response from a DNS server. - </summary> - <param name="data">The data to create the message from.</param> - </member> - <member name="M:NDns.Message.DNSMessage.ToByteArray"> - <summary> - Converts the DNS message into a byte array. - </summary> - <returns>The DNS message as a byte array.</returns> - </member> - <member name="P:NDns.Message.DNSMessage.QuestionEntries"> - <summary> - Gets and sets the question section entries for this DNS message. - </summary> - </member> - <member name="P:NDns.Message.DNSMessage.AnswerEntries"> - <summary> - Gets and sets the answer section entries for this DNS message. - </summary> - </member> - <member name="P:NDns.Message.DNSMessage.Id"> - <summary> - Gets the Id for this DNS message. - </summary> - </member> - <member name="P:NDns.Message.DNSMessage.Response"> - <summary> - Was this message a response or a query? - </summary> - </member> - <member name="P:NDns.Message.DNSMessage.Authoritative"> - <summary> - Is the answer authoritative? - </summary> - </member> - <member name="P:NDns.Message.DNSMessage.Truncated"> - <summary> - Was the message truncated due to size constraints? - </summary> - </member> - <member name="P:NDns.Message.DNSMessage.Recursive"> - <summary> - Is recursion desired? - </summary> - </member> - <member name="P:NDns.Message.DNSMessage.RecursionAvailable"> - <summary> - Is recursion available? - </summary> - </member> - <member name="P:NDns.Message.DNSMessage.Opcode"> - <summary> - A four bit field that specifies query type in the message. - </summary> - </member> - <member name="P:NDns.Message.DNSMessage.Rcode"> - <summary> - The response code for this message. - </summary> - </member> - <member name="T:NDns.DnsCache"> - <summary> - Provides a cache for DNS information. - </summary> - </member> - <member name="F:NDns.DnsCache.DnsPort"> - <summary> - The port to query remote dns servers on. - </summary> - </member> - <member name="F:NDns.DnsCache.log"> - <summary> - Logging support for this class. - </summary> - </member> - <member name="F:NDns.DnsCache.mxServers"> - <summary> - A hash table of arrays of MX records indexed by string name - (e.g. an array of MX records for "anu.edu.au"). - </summary> - </member> - <member name="F:NDns.DnsCache.mxQueue"> - <summary> - A list of MX records ordered according to last use. - </summary> - </member> - <member name="F:NDns.DnsCache.domains"> - <summary> - A hash table of string records indexed by IP address - </summary> - </member> - <member name="F:NDns.DnsCache.domainQueue"> - <summary> - A list of string records ordered according to last use. - </summary> - </member> - <member name="F:NDns.DnsCache.addresses"> - <summary> - A hash table of ip address record arrays indexed by string name - (e.g. an array of A records for "www.anu.edu.au"). - </summary> - </member> - <member name="F:NDns.DnsCache.addressQueue"> - <summary> - A list of address records ordered according to last use. - </summary> - </member> - <member name="F:NDns.DnsCache.MXCacheSize"> - <summary> - The maximum number of MX record arrays to store. - </summary> - </member> - <member name="F:NDns.DnsCache.DomainCacheSize"> - <summary> - The maximum number of string names to store. - </summary> - </member> - <member name="F:NDns.DnsCache.AddressCacheSize"> - <summary> - The maximum number of A record arrays to store. - </summary> - </member> - <member name="F:NDns.DnsCache.config"> - <summary> - The configuration for this DNS cache. - </summary> - </member> - <member name="M:NDns.DnsCache.#ctor(NDns.Configuration.NDnsConfiguration)"> - <summary> - Creates a new instance of the DNS this. - </summary> - </member> - <member name="M:NDns.DnsCache.DomainMatchesAddress(System.Net.IPAddress,System.String)"> - <summary> - Checks if the given string and address match. - </summary> - <param name="address">The address to check.</param> - <param name="domain">The string to check.</param> - <returns>True if the string corresponds to the address.</returns> - </member> - <member name="M:NDns.DnsCache.GetHostName(System.Net.EndPoint)"> - <summary> - Gets a hostname for the specified end point. - </summary> - <param name="endPoint">The end point to lookup</param> - <returns>The hostname.</returns> - </member> - <member name="M:NDns.DnsCache.GetHostName(System.Net.IPAddress)"> - <summary> - Gets a hostname for the specified address. - </summary> - <param name="address">The address to lookup</param> - <returns>The hostname.</returns> - </member> - <member name="M:NDns.DnsCache.GetHostNames(System.Net.IPAddress)"> - <summary> - Gets a hostnames for the specified address. - </summary> - <param name="address">The address to lookup</param> - <returns>The address.</returns> - </member> - <member name="M:NDns.DnsCache.GetIPAddress(System.String)"> - <summary> - Gets the first IP address associated with the given domain name. - </summary> - <param name="domainName">The domain name to resolve.</param> - <returns>The IP address.</returns> - </member> - <member name="M:NDns.DnsCache.GetIPAddresses(System.String)"> - <summary> - Looks up IP addresses for the given string name. - </summary> - <param name="domainName">The string name to lookup the addresses for.</param> - <returns>The IP addresses for the string name.</returns> - </member> - <member name="M:NDns.DnsCache.LookupRecords(System.String,NDns.Message.QType)"> - <summary> - Looks up DNS records using the specified query string and query type. - </summary> - <param name="queryString">The query to send.</param> - <param name="queryType">The query type.</param> - <returns>The array of records from the DNS server.</returns> - </member> - <member name="M:NDns.DnsCache.GetPTRRecords(System.Net.IPAddress)"> - <summary> - Gets the PTR records for the specified IP address caching the results. - This method also respects TTL for the records. - </summary> - <param name="address">The address to lookup</param> - <returns>The PTR records.</returns> - </member> - <member name="M:NDns.DnsCache.GetARecords(System.String)"> - <summary> - Gets address records for the specified hostname caching the results. - This method also respects TTL for the records. - </summary> - <param name="domainName">The hostname to lookup</param> - <returns>The address records.</returns> - </member> - <member name="M:NDns.DnsCache.GetMXRecords(System.String)"> - <summary> - Looks up MX records for the given string name caching the results. - This method also respects TTL for the records. - </summary> - <param name="domainName">The string to get the MX records for.</param> - <returns>The MX records</returns> - </member> - <member name="M:NDns.DnsCache.LookupMXRecords(System.String)"> - <summary> - Looks up MX records from the DNS server handling empty answer - sections but not caching records. - </summary> - <param name="domainName">The string to look up the MX records for.</param> - <returns>The MX records for the given domain.</returns> - </member> - <member name="M:NDns.DnsCache.LookupPTRRecords(System.Net.IPAddress)"> - <summary> - Looks up PTR records from the DNS server but does not cache records. - </summary> - <param name="address">The string to look up the PTR records for.</param> - <returns>The PTR records for the given domain.</returns> - </member> - <member name="M:NDns.DnsCache.LookupARecords(System.String)"> - <summary> - Looks up address records from the DNS server but does not cache records. - </summary> - <param name="domainName">The string name to lookup the addresses for.</param> - <returns>The addresses records for the given domain.</returns> - </member> - <member name="M:NDns.DnsCache.ConvertToIPAddresses(NDns.Message.Records.ARecord[])"> - <summary> - Converts an array of address records into an array of IP addresses. - </summary> - <param name="records">The records to convert.</param> - <returns>The IP addresses.</returns> - </member> - <member name="M:NDns.DnsCache.ConvertToHostnames(NDns.Message.Records.PTRRecord[])"> - <summary> - Converts an array of PTR records into an array of hostnames. - </summary> - <param name="records">The records to convert.</param> - <returns>The hostnames.</returns> - </member> - <member name="M:NDns.DnsCache.PerformQuery(NDns.Message.DNSMessage)"> - <summary> - Queries a DNS server using the given DNS query. - </summary> - <param name="queryMessage">The query to send to the server.</param> - <returns>The response from the server.</returns> - </member> - <member name="T:NDns.Message.Records.NSRecord"> - <summary> - A DNS NS record. - </summary> - </member> - <member name="F:NDns.Message.Records.NSRecord.ns"> - <summary> - The name server name for this record. - </summary> - </member> - <member name="M:NDns.Message.Records.NSRecord.#ctor(System.String)"> - <summary> - Creates a NS record from the given domain. - </summary> - <param name="ns">The string of the name server name.</param> - </member> - <member name="M:NDns.Message.Records.NSRecord.#ctor(System.Byte[],System.UInt16,System.UInt16@,NDns.Message.DomainCoder)"> - <summary> - Creates a NS record from the given byte data. - </summary> - <param name="data">The data to create the CName record from.</param> - <param name="start">The position to start reading the byte array from.</param> - <param name="length">The number of bytes read from the byte array.</param> - <param name="coder">The coder to use when parsing the data.</param> - </member> - <member name="P:NDns.Message.Records.NSRecord.NS"> - <summary> - Returns the name server name for this record. - </summary> - </member> - <member name="P:NDns.Message.Records.NSRecord.Data"> - <summary> - The data associated with this record as a user readable string. - </summary> - </member> - <member name="T:NDns.QueryFactory"> - <summary> - A factory class for creating DNS query and response messages. - </summary> - </member> - <member name="M:NDns.QueryFactory.CreateQuery(System.String,NDns.Message.QType)"> - <summary> - Creates a new DNS query to look up the record for the query string and type. - </summary> - <param name="queryString">The query string to pack.</param> - <param name="queryType">The type of the query.</param> - <returns>The DNS message.</returns> - </member> - <member name="T:NDns.Message.Records.PTRRecord"> - <summary> - A DNS PTR record. - </summary> - </member> - <member name="F:NDns.Message.Records.PTRRecord.name"> - <summary> - The name for this record. - </summary> - </member> - <member name="M:NDns.Message.Records.PTRRecord.#ctor(System.String)"> - <summary> - Creates a PTR record from the given domain. - </summary> - <param name="name">The string of the name.</param> - </member> - <member name="M:NDns.Message.Records.PTRRecord.#ctor(System.Byte[],System.UInt16,System.UInt16@,NDns.Message.DomainCoder)"> - <summary> - Creates a PTR record from the given byte data. - </summary> - <param name="data">The data to create the CName record from.</param> - <param name="start">The position to start reading the byte array from.</param> - <param name="length">The number of bytes read from the byte array.</param> - <param name="coder">The coder to use when parsing the data.</param> - </member> - <member name="P:NDns.Message.Records.PTRRecord.Name"> - <summary> - Returns the name for this record. - </summary> - </member> - <member name="P:NDns.Message.Records.PTRRecord.Data"> - <summary> - The data associated with this record as a user readable string. - </summary> - </member> - <member name="T:NDns.Message.OpCode"> - <summary> - The opcode is a four bit field that specifies query type in the message. - This value is set by the originator of a query and copied into the response. - </summary> - </member> - <member name="F:NDns.Message.OpCode.StandardQuery"> - <summary> - A standard query (QUERY). - </summary> - </member> - <member name="F:NDns.Message.OpCode.InverseQuery"> - <summary> - An inverse query (IQUERY). - </summary> - </member> - <member name="F:NDns.Message.OpCode.StatusRequest"> - <summary> - A server status request (STATUS). - </summary> - </member> - <member name="T:NDns.Message.ResponseCode"> - <summary> - The response code is a 4 bit field is set as part of responses. - </summary> - </member> - <member name="F:NDns.Message.ResponseCode.NoError"> - <summary> - No error condition. - </summary> - </member> - <member name="F:NDns.Message.ResponseCode.FormatError"> - <summary> - The name server was unable to interpret the query. - </summary> - </member> - <member name="F:NDns.Message.ResponseCode.ServerFailure"> - <summary> - The name server was unable to process this query due to a problem - with the name server. - </summary> - </member> - <member name="F:NDns.Message.ResponseCode.NameError"> - <summary> - Meaningful only for responses from an authoritative name server, - this code signifies that the string name referenced in the query - does not exist. - </summary> - </member> - <member name="F:NDns.Message.ResponseCode.NotImplemented"> - <summary> - The name server does not support the requested kind of query. - </summary> - </member> - <member name="F:NDns.Message.ResponseCode.Refused"> - <summary> - The name server refuses to perform the specified operation for - policy reasons. - </summary> - </member> - <member name="T:NDns.Message.DomainCoder"> - <summary> - This class encodes and decodes DNS string names in or for DNS messages. - </summary> - </member> - <member name="F:NDns.Message.DomainCoder.references"> - <summary> - A hash table of references indexed by string names. - </summary> - </member> - <member name="M:NDns.Message.DomainCoder.EncodeDomain(System.String,System.UInt16)"> - <summary> - Encodes a string entry or a reference to the string entry for the given - domain. - </summary> - <param name="domainName">The string to create the entry for.</param> - <param name="start">The reference to the start of this entry in the message.</param> - <returns>The string name or a reference to the first occurence.</returns> - </member> - <member name="M:NDns.Message.DomainCoder.DecodeDomain(System.Byte[],System.UInt16,System.UInt16@)"> - <summary> - Decodes the data to retrieve a string name. - </summary> - <param name="data">The data to process.</param> - <param name="start">The position to start processing from.</param> - <param name="length">The length of data read.</param> - <returns>The string decoded.</returns> - </member> - <member name="T:NDns.Message.Records.CNameRecord"> - <summary> - A DNS Canonical NAME record. - </summary> - </member> - <member name="F:NDns.Message.Records.CNameRecord.cName"> - <summary> - The canonical name for this record. - </summary> - </member> - <member name="M:NDns.Message.Records.CNameRecord.#ctor(System.String)"> - <summary> - Creates a CName record from the given domain. - </summary> - <param name="cName">The string of the canonical name.</param> - </member> - <member name="M:NDns.Message.Records.CNameRecord.#ctor(System.Byte[],System.UInt16,System.UInt16@,NDns.Message.DomainCoder)"> - <summary> - Creates a CName record from the given byte data. - </summary> - <param name="data">The data to create the CName record from.</param> - <param name="start">The position to start reading the byte array from.</param> - <param name="length">The number of bytes read from the byte array.</param> - <param name="coder">The coder to use when parsing the data.</param> - </member> - <member name="P:NDns.Message.Records.CNameRecord.CName"> - <summary> - Returns the canonical name for this record. - </summary> - </member> - <member name="P:NDns.Message.Records.CNameRecord.Data"> - <summary> - The data associated with this record as a user readable string. - </summary> - </member> - <member name="T:NDns.Message.Records.ARecord"> - <summary> - A DNS Address record. - </summary> - </member> - <member name="F:NDns.Message.Records.ARecord.address"> - <summary> - The address for this record. - </summary> - </member> - <member name="M:NDns.Message.Records.ARecord.#ctor(System.Net.IPAddress)"> - <summary> - Creates an address record using the address record. - </summary> - <param name="address">The address to create the record from.</param> - </member> - <member name="M:NDns.Message.Records.ARecord.#ctor(System.Byte[],System.UInt16,System.UInt16@,NDns.Message.DomainCoder)"> - <summary> - Creates an Address record from the given byte data. - </summary> - <param name="data">The data to create the Address record from.</param> - <param name="start">The position to start reading the byte array from.</param> - <param name="length">The number of bytes read from the byte array.</param> - <param name="coder">The coder to use when parsing the data.</param> - </member> - <member name="P:NDns.Message.Records.ARecord.Address"> - <summary> - The address for this record. - </summary> - </member> - <member name="P:NDns.Message.Records.ARecord.Data"> - <summary> - The data associated with this record as a user readable string. - </summary> - </member> - <member name="T:NDns.Message.QClass"> - <summary> - The class of records. - </summary> - </member> - <member name="F:NDns.Message.QClass.IN"> - <summary> - The Internet. - </summary> - </member> - </members> -</doc> Modified: NMail/trunk/NMail/DataTypes/ACLs/MailDomainPrivilege.cs =================================================================== --- NMail/trunk/NMail/DataTypes/ACLs/MailDomainPrivilege.cs 2006-05-06 15:33:43 UTC (rev 29) +++ NMail/trunk/NMail/DataTypes/ACLs/MailDomainPrivilege.cs 2006-05-14 06:32:21 UTC (rev 30) @@ -3,16 +3,44 @@ using System.Text; namespace NMail.DataTypes.ACLs { + /// <summary> + /// The possible privileges that can be listed on a mail domain ACL entry. + /// </summary> [FlagsAttribute] - public enum MailDomainPrivilege { + public enum MailDomainPrivilege : uint { + /// <summary> + /// No rights are granted. + /// </summary> None = 0, + /// <summary> + /// The mail domain can be deleted. + /// </summary> Delete, + /// <summary> + /// The mail domain can be modified. + /// </summary> Modify, + /// <summary> + /// Existing user's can be added to the mail domain. + /// </summary> AddUser, - RemoveUser + /// <summary> + /// Existing user's can be removed from the mail domain. + /// </summary> + RemoveUser, + + /// <summary> + /// Existing groups can be added to the mail domain. + /// </summary> + AddGroup, + + /// <summary> + /// Existing groups can be removed from the mail domain. + /// </summary> + RemoveGroup } } Modified: NMail/trunk/NMail/DataTypes/ACLs/StoreFolderPrivilege.cs =================================================================== --- NMail/trunk/NMail/DataTypes/ACLs/StoreFolderPrivilege.cs 2006-05-06 15:33:43 UTC (rev 29) +++ NMail/trunk/NMail/DataTypes/ACLs/StoreFolderPrivilege.cs 2006-05-14 06:32:21 UTC (rev 30) @@ -24,7 +24,7 @@ /// The possible privileges that can be listed on a store folder ACL entry. /// </summary> [FlagsAttribute] - public enum StoreFolderPrivilege { + public enum StoreFolderPrivilege : uint { /// <summary> /// No rights are granted. /// </summary> Modified: NMail/trunk/NMail/DataTypes/EmailAddress.cs =================================================================== --- NMail/trunk/NMail/DataTypes/EmailAddress.cs 2006-05-06 15:33:43 UTC (rev 29) +++ NMail/trunk/NMail/DataTypes/EmailAddress.cs 2006-05-14 06:32:21 UTC (rev 30) @@ -113,7 +113,7 @@ } // create (and validate) the mailbox. - this.mailbox = new Mailbox(parts[0]); + this.mailbox = new Mailbox(parts[0], true); if (parts[1].StartsWith("[") && parts[1].EndsWith("]")) { // this IS an IP address Modified: NMail/trunk/NMail/DataTypes/LocalStore/MailDomain.cs =================================================================== --- NMail/trunk/NMail/DataTypes/LocalStore/MailDomain.cs 2006-05-06 15:33:43 UTC (rev 29) +++ NMail/trunk/NMail/DataTypes/LocalStore/MailDomain.cs 2006-05-14 06:32:21 UTC (rev 30) @@ -29,6 +29,8 @@ /// </summary> public class MailDomain { public MailDomain(int mailDomainId, Host primaryHost) { + this.mailDomainId = mailDomainId; + this.primaryHost = primaryHost; } int mailDomainId; @@ -50,7 +52,7 @@ /// <summary> /// The main host that this domain accepts mail for. /// </summary> - Host PrimaryHost { + public Host PrimaryHost { get { return this.primaryHost; } @@ -64,7 +66,7 @@ /// <summary> /// Other hosts that this domain accepts mail for. /// </summary> - WildcardHost[] AdditionalHosts { + public WildcardHost[] AdditionalHosts { get { return this.additionalHosts; } @@ -78,7 +80,7 @@ /// <summary> /// Gets the mailbox mappings for this domain. /// </summary> - ILocalStoreUserMap[] MailboxMappings { + public ILocalStoreUserMap[] MailboxMappings { get { return this.mailboxMappings; } @@ -92,7 +94,7 @@ /// <summary> /// The actions that user's of this domain are allowed to use. /// </summary> - ILocalStoreDeliveryAction[] AllowedActions { + public ILocalStoreDeliveryAction[] AllowedActions { get { return this.allowedActions; } @@ -106,7 +108,7 @@ /// <summary> /// The validators that user's of this domain are allowed to use. /// </summary> - ILocalStoreRecipientValidator[] AllowedValidators { + public ILocalStoreRecipientValidator[] AllowedValidators { get { return this.allowedValidators; } @@ -120,7 +122,7 @@ /// <summary> /// The default set of actions to apply to incoming messages. /// </summary> - ILocalStoreDeliveryAction[] DefaultActions { + public ILocalStoreDeliveryAction[] DefaultActions { get { return this.defaultActions; } Modified: NMail/trunk/NMail/DataTypes/Mailbox.cs =================================================================== --- NMail/trunk/NMail/DataTypes/Mailbox.cs 2006-05-06 15:33:43 UTC (rev 29) +++ NMail/trunk/NMail/DataTypes/Mailbox.cs 2006-05-14 06:32:21 UTC (rev 30) @@ -57,6 +57,8 @@ throw new FormatException("Empty Mailbox not allowed."); } this.rawMailbox = null; + return; + } else { this.rawMailbox = mailbox.Trim(); Modified: NMail/trunk/NMail/ILocalStore.cs =================================================================== --- NMail/trunk/NMail/ILocalStore.cs 2006-05-06 15:33:43 UTC (rev 29) +++ NMail/trunk/NMail/ILocalStore.cs 2006-05-14 06:32:21 UTC (rev 30) @@ -293,7 +293,34 @@ /// privileges or invalid folder. /// </returns> int[] PurgeDeletedMessages(IAuthenticationToken authToken, StoreFolder folder); + + #region Folder ACLs + /// <summary> + /// Sets the privileges on the folder. If no ACE exists for the associated + /// identifier one is added. + /// </summary> + /// <param name="authToken">The authentication credentials.</param> + /// <param name="folder">The folder to set the ACE on.</param> + /// <param name="ace">The privileges and the identifier to put.</param> + void SetStoreFolderAce(IAuthenticationToken authToken, StoreFolder folder, StoreFolderAce ace); + /// <summary> + /// Removes any ACE associated with the given user. + /// </summary> + /// <param name="authToken">The authentication credentials.</param> + /// <param name="folder">The folder to remove the ACE from.</param> + /// <param name="identifier">The identifier to remove from the ACL.</param> + void RemoveStoreFolderAce(IAuthenticationToken authToken, StoreFolder folder, string identifier); + + /// <summary> + /// Gets the ACL for the given folder. + /// </summary> + /// <param name="authToken">The authentication credentials.</param> + /// <param name="folder">The folder to get the ACL for.</param> + /// <returns>The folder ACL or null if insufficient privileges.</returns> + StoreFolderAcl GetStoreFolderAcl(IAuthenticationToken authToken, StoreFolder folder); + #endregion + #region Load and Save Object /// <summary> /// Gets a serialized object that can be used by either an validation or a delivery action. @@ -344,9 +371,8 @@ /// <param name="userName">The name of the new user.</param> /// <param name="warnQuota">The warning quota level.</param> /// <param name="hardQuota">The hard quota.</param> - /// <param name="mailDomain">The mail domain to add the user to.</param> /// <returns>The result of the attemp to create a new user.</returns> - LocalStoreUserResult CreateUser(IAuthenticationToken authToken, string userName, int? warnQuota, int? hardQuota, Host mailDomain); + LocalStoreUserResult CreateUser(IAuthenticationToken authToken, string userName, int? warnQuota, int? hardQuota); /// <summary> /// Removes a user from the local store. @@ -387,6 +413,22 @@ /// <param name="userId">The Id of the user to remove the address from.</param> /// <param name="address">The address to remove.</param> void RemoveUserAddress(IAuthenticationToken authToken, int userId, EmailAddress address); + + /// <summary> + /// Adds a user to the given mail domain. + /// </summary> + /// <param name="authToken">The authentication credentials.</param> + /// <param name="userId">The Id of the user to add.</param> + /// <param name="mailDomainId">The Id of the mail domain to add the user to.</param> + void AddUserToMailDomain(IAuthenticationToken authToken, int userId, int mailDomainId); + + /// <summary> + /// Removes user from the given mail domain. + /// </summary> + /// <param name="authToken">The authentication credentials.</param> + /// <param name="userId">The Id of the user to remove.</param> + /// <param name="mailDomainId">The Id of the mail domain to revome the user from.</param> + void RemoveUserFromMailDomain(IAuthenticationToken authToken, int userId, int mailDomainId); #endregion #region Group Management @@ -436,33 +478,22 @@ /// <param name="group">The group details to update.</param> /// <returns>The result of the attempt to update the group.</returns> LocalStoreGroupResult UpdateGroup(IAuthenticationToken authToken, LocalStoreGroup group); - #endregion - #region Folder ACLs /// <summary> - /// Sets the privileges on the folder. If no ACE exists for the associated - /// identifier one is added. + /// Adds a group to the given mail domain. /// </summary> /// <param name="authToken">The authentication credentials.</param> - /// <param name="folder">The folder to set the ACE on.</param> - /// <param name="ace">The privileges and the identifier to put.</param> - void SetStoreFolderAce(IAuthenticationToken authToken, StoreFolder folder, StoreFolderAce ace); + /// <param name="groupId">The Id of the group to add.</param> + /// <param name="mailDomainId">The Id of the mail domain to add the group to.</param> + void AddGroupToMailDomain(IAuthenticationToken authToken, int groupId, int mailDomainId); /// <summary> - /// Removes any ACE associated with the given user. + /// Removes group from the given mail domain. /// </summary> /// <param name="authToken">The authentication credentials.</param> - /// <param name="folder">The folder to remove the ACE from.</param> - /// <param name="identifier">The identifier to remove from the ACL.</param> - void RemoveStoreFolderAce(IAuthenticationToken authToken, StoreFolder folder, string identifier); - - /// <summary> - /// Gets the ACL for the given folder. - /// </summary> - /// <param name="authToken">The authentication credentials.</param> - /// <param name="folder">The folder to get the ACL for.</param> - /// <returns>The folder ACL or null if insufficient privileges.</returns> - StoreFolderAcl GetStoreFolderAcl(IAuthenticationToken authToken, StoreFolder folder); + /// <param name="groupId">The Id of the group to remove.</param> + /// <param name="mailDomainId">The Id of the mail domain to revome the group from.</param> + void RemoveGroupFromMailDomain(IAuthenticationToken authToken, int groupId, int mailDomainId); #endregion #region Mail Domain Management @@ -496,6 +527,24 @@ /// <param name="updatedMailDomain">The updated mail domain.</param> /// <returns>The result of the attempt to update the mail domain.</returns> LocalStoreMailDomainResult UpdateMailDomain(IAuthenticationToken authToken, MailDomain updatedMailDomain); + + /// <summary> + /// Gets a list of group Ids for groups that are associated with the given + /// mail domain Id. + /// </summary> + /// <param name="authToken">The authentication credentials.</param> + /// <param name="mailDomainId">The mail domain to look up the groups for.</param> + /// <returns>The list of group Ids.</returns> + int[] GetMailDomainGroups(IAuthenticationToken authToken, int mailDomainId); + + /// <summary> + /// Gets a list of user Ids for groups that are associated with the given + /// mail domain Id. + /// </summary> + /// <param name="authToken">The authentication credentials.</param> + /// <param name="mailDomainId">The mail domain to look up the users for.</param> + /// <returns>The list of user Ids.</returns> + int[] GetMailDomainUsers(IAuthenticationToken authToken, int mailDomainId); #endregion } Modified: NMail/trunk/NMail/ILocalStoreData.cs =================================================================== --- NMail/trunk/NMail/ILocalStoreData.cs 2006-05-06 15:33:43 UTC (rev 29) +++ NMail/trunk/NMail/ILocalStoreData.cs 2006-05-14 06:32:21 UTC (rev 30) @@ -260,6 +260,30 @@ void SaveObject(object o, string key); #endregion + #region Folder ACLs + /// <summary> + /// Sets the privileges on the folder. If no ACE exists for the associated + /// identifier one is added. + /// </summary> + /// <param name="folder">The folder to set the ACE on.</param> + /// <param name="ace">The privileges and the identifier to put.</param> + void SetStoreFolderAce(StoreFolder folder, StoreFolderAce ace); + + /// <summary> + /// Removes any ACE associated with the given user. + /// </summary> + /// <param name="folder">The folder to remove the ACE from.</param> + /// <param name="identifier">The identifier to remove from the ACL.</param> + void RemoveStoreFolderAce(StoreFolder folder, string identifier); + + /// <summary> + /// Gets the ACL for the given folder. + /// </summary> + /// <param name="folder">The folder to get the ACL for.</param> + /// <returns>The folder ACL.</returns> + StoreFolderAcl GetStoreFolderAcl(StoreFolder folder); + #endregion + #region User Management /// <summary> /// Gets the user for the given username. @@ -317,6 +341,20 @@ /// <param name="user">The user details to update.</param> /// <returns>The result of the attempt to update the user.</returns> LocalStoreUserResult UpdateUser(LocalStoreUser user); + + /// <summary> + /// Adds a user to the given mail domain. + /// </summary> + /// <param name="userId">The Id of the user to add.</param> + /// <param name="mailDomainId">The Id of the mail domain to add the user to.</param> + void AddUserToMailDomain(int userId, int mailDomainId); + + /// <summary> + /// Removes user from the given mail domain. + /// </summary> + /// <param name="userId">The Id of the user to remove.</param> + /// <param name="mailDomainId">The Id of the mail domain to revome the user from.</param> + void RemoveUserFromMailDomain(int userId, int mailDomainId); #endregion #region Group Management @@ -360,30 +398,20 @@ /// <param name="group">The group details to update.</param> /// <returns>The result of the attempt to update the group.</returns> LocalStoreGroupResult UpdateGroup(LocalStoreGroup group); - #endregion - - #region Folder ACLs + /// <summary> - /// Sets the privileges on the folder. If no ACE exists for the associated - /// identifier one is added. + /// Adds a group to the given mail domain. /// </summary> - /// <param name="folder">The folder to set the ACE on.</param> - /// <param name="ace">The privileges and the identifier to put.</param> - void SetStoreFolderAce(StoreFolder folder, StoreFolderAce ace); + /// <param name="groupId">The Id of the group to add.</param> + /// <param name="mailDomainId">The Id of the mail domain to add the group to.</param> + void AddGroupToMailDomain(int groupId, int mailDomainId); /// <summary> - /// Removes any ACE associated with the given user. + /// Removes group from the given mail domain. /// </summary> - /// <param name="folder">The folder to remove the ACE from.</param> - /// <param name="identifier">The identifier to remove from the ACL.</param> - void RemoveStoreFolderAce(StoreFolder folder, string identifier); - - /// <summary> - /// Gets the ACL for the given folder. - /// </summary> - /// <param name="folder">The folder to get the ACL for.</param> - /// <returns>The folder ACL.</returns> - StoreFolderAcl GetStoreFolderAcl(StoreFolder folder); + /// <param name="groupId">The Id of the group to remove.</param> + /// <param name="mailDomainId">The Id of the mail domain to revome the group from.</param> + void RemoveGroupFromMailDomain(int groupId, int mailDomainId); #endregion #region Mail Domain Management @@ -413,6 +441,22 @@ /// <param name="updatedMailDomain">The updated mail domain.</param> /// <returns>The result of the attempt to update the mail domain.</returns> LocalStoreMailDomainResult UpdateMailDomain(MailDomain updatedMailDomain); + + /// <summary> + /// Gets a list of group Ids... [truncated message content] |
|
From: <tmy...@us...> - 2006-05-09 00:53:23
|
Revision: 29 Author: tmyroadctfig Date: 2006-05-06 08:33:43 -0700 (Sat, 06 May 2006) ViewCVS: http://svn.sourceforge.net/nmailserver/?rev=29&view=rev Log Message: ----------- Work on TCP remoting channel. Changes to connection TLS. Work on authentication and ACLs. Modified Paths: -------------- NMail/trunk/NMail/Authentication/BasicAuthToken.cs NMail/trunk/NMail/Authentication/IAuthenticationProvider.cs NMail/trunk/NMail/Authentication/IAuthenticationToken.cs NMail/trunk/NMail/Authentication/IHashAuthProvider.cs NMail/trunk/NMail/Authentication/NullAuthentication.cs NMail/trunk/NMail/ILocalStoreData.cs NMail/trunk/NMail/IO/TcpChannel.cs NMail/trunk/NMail/IO/TcpClientChannel.cs NMail/trunk/NMail/IO/TcpClientTransportSink.cs NMail/trunk/NMail/IO/TcpClientTransportSinkProvider.cs NMail/trunk/NMail/IO/TcpServerChannel.cs NMail/trunk/NMail/IO/TcpServerTransportSink.cs NMail/trunk/NMail/IO/TcpTextConnection.cs NMail/trunk/NMail/NMail.csproj NMail/trunk/NMail.Administration.Console/Command/AddUserCommand.cs NMail/trunk/NMail.Administration.Console/Command/ListUsersCommand.cs NMail/trunk/NMail.Administration.Console/Context/LocalStoreContext.cs NMail/trunk/NMail.Administration.Console/Context/TopLevelContext.cs NMail/trunk/NMail.Administration.Console/NMail.Administration.Console.csproj NMail/trunk/NMail.ImapService/ImapServiceConnection.cs NMail/trunk/NMail.ImapService/State/ConnectedState.cs NMail/trunk/NMail.LocalStore/LocalStore.cs NMail/trunk/NMail.LocalStoreData.MySql/MySqlLocalStore.sql NMail/trunk/NMail.LocalStoreData.MySql/MySqlLocalStoreData.cs NMail/trunk/NMail.Server/RemoteAdministration.cs Removed Paths: ------------- NMail/trunk/NMail/Authentication/IPasswordAuthProvider.cs Modified: NMail/trunk/NMail/Authentication/BasicAuthToken.cs =================================================================== --- NMail/trunk/NMail/Authentication/BasicAuthToken.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/Authentication/BasicAuthToken.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -21,15 +21,32 @@ /// <summary> /// A simple authentication token. /// </summary> + [Serializable] public class BasicAuthToken : IAuthenticationToken { /// <summary> /// Creates a new basic authentication token with the given username. /// </summary> /// <param name="username">The username associated with then authentication token.</param> - public BasicAuthToken(string username) { + /// <param name="credentialsExpiry">The date and time that the user's credentials expire.</param> + public BasicAuthToken(string username, DateTime credentialsExpiry) { this.username = username; + this.credentialsExpiry = credentialsExpiry; } + private Guid tokenId; + + /// <summary> + /// The Id for this token. + /// </summary> + public Guid TokenId { + get { + return this.tokenId; + } + set { + this.tokenId = value; + } + } + #region IAuthenticationToken Members private string username; @@ -38,6 +55,14 @@ return this.username; } } + + private DateTime credentialsExpiry; + + public DateTime CredentialsExpiry { + get { + return this.credentialsExpiry; + } + } #endregion } } Modified: NMail/trunk/NMail/Authentication/IAuthenticationProvider.cs =================================================================== --- NMail/trunk/NMail/Authentication/IAuthenticationProvider.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/Authentication/IAuthenticationProvider.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -19,18 +19,52 @@ namespace NMail.Authentication { /// <summary> - /// A top level interface for the password and hash authentication types. + /// The interface for an authentication provider that operates on username and + /// password pairs. /// </summary> + /// <remarks> + /// This interface is for a provider that will compute a hash based on the given + /// username and password and then compare it to a previously generated hash. + /// </remarks> public interface IAuthenticationProvider { /// <summary> - /// Gets the date and time that the user's credentials will expire. E.g. Their - /// password expires and needs changing. + /// Attempts to authenticate the user with the given password. /// </summary> - /// <param name="user">The details of the user to get the expiry time for.</param> + /// <param name="username">The username for the user to authenticate.</param> + /// <param name="password">The given password to attempt authentication with.</param> + /// <returns>The authentication token or null if authentication fails.</returns> + IAuthenticationToken Authenticate(string username, string password); + + /// <summary> + /// Creates an authentication token for a trusted party, e.g. a part of the + /// NMail system. + /// </summary> + /// <param name="username">The username to create the token for.</param> + /// <returns>The token or null if the user is invalid</returns> + IAuthenticationToken CreateAuthToken(string username); + + /// <summary> + /// Gets the date and time that the given token will expire. + /// </summary> + /// <param name="user">The token to check the expire time for.</param> /// <returns>The expiry time.</returns> - DateTime GetCredentialsExpiry(IAuthenticationToken user); + DateTime GetTokenExpiry(IAuthenticationToken user); /// <summary> + /// Checks if the given token has expired. + /// </summary> + /// <param name="user">The token to check the expire time for.</param> + /// <returns>True if the token has expired.</returns> + bool TokenExpired(IAuthenticationToken user); + + /// <summary> + /// Checks if the given authentication token is valid. + /// </summary> + /// <param name="user">The token to check.</param> + /// <returns>True if the token is valid.</returns> + bool ValidToken(IAuthenticationToken user); + + /// <summary> /// Checks if the user's account is currently locked out. /// </summary> /// <param name="user">The user to check.</param> Modified: NMail/trunk/NMail/Authentication/IAuthenticationToken.cs =================================================================== --- NMail/trunk/NMail/Authentication/IAuthenticationToken.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/Authentication/IAuthenticationToken.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -26,5 +26,11 @@ /// Returns the username for the authenticated user. /// </summary> string Username { get; } + + /// <summary> + /// Gets the date and time that the user's credentials will expire. E.g. Their + /// password expires and needs changing. + /// </summary> + DateTime CredentialsExpiry { get; } } } Modified: NMail/trunk/NMail/Authentication/IHashAuthProvider.cs =================================================================== --- NMail/trunk/NMail/Authentication/IHashAuthProvider.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/Authentication/IHashAuthProvider.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -31,7 +31,7 @@ /// A provider that is able to authenticate multiple hash types will typically store /// the passwords with reversible encryption. /// </remarks> - public interface IHashAuthProvider : IPasswordAuthProvider { + public interface IHashAuthProvider : IAuthenticationProvider { /// <summary> /// Attempts to authenticate the user with the given password. /// </summary> Deleted: NMail/trunk/NMail/Authentication/IPasswordAuthProvider.cs =================================================================== --- NMail/trunk/NMail/Authentication/IPasswordAuthProvider.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/Authentication/IPasswordAuthProvider.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -1,39 +0,0 @@ -/* - * Copyright 2004-2006 Luke Quinane and Daniel Frampton - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -using System; -using System.Security; - -namespace NMail.Authentication { - /// <summary> - /// The interface for an authentication provider that operates on username and - /// password pairs. - /// </summary> - /// <remarks> - /// This interface is for a provider that will compute a hash based on the given - /// username and password and then compare it to a previously generated hash. - /// </remarks> - public interface IPasswordAuthProvider : IAuthenticationProvider { - /// <summary> - /// Attempts to authenticate the user with the given password. - /// </summary> - /// <param name="username">The username for the user to authenticate.</param> - /// <param name="password">The given password to attempt authentication with.</param> - /// <returns>The authentication token or null if authentication fails.</returns> - IAuthenticationToken Authenticate(string username, string password); - } -} Modified: NMail/trunk/NMail/Authentication/NullAuthentication.cs =================================================================== --- NMail/trunk/NMail/Authentication/NullAuthentication.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/Authentication/NullAuthentication.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -23,22 +23,33 @@ /// An authentication provider that performs no checks. <b>Should only be used for /// developement purposes.</b> /// </summary> - public class NullAuthentication : IPasswordAuthProvider { + public class NullAuthentication : IAuthenticationProvider { - #region IPasswordAuthProvider Members + #region IAuthenticationProvider Members public IAuthenticationToken Authenticate(string username, string password) { - return new BasicAuthToken(username); + return new BasicAuthToken(username, DateTime.MaxValue); } - public DateTime GetCredentialsExpiry(IAuthenticationToken user) { + public IAuthenticationToken CreateAuthToken(string username) { + return new BasicAuthToken(username, DateTime.MaxValue); + } + + public DateTime GetTokenExpiry(IAuthenticationToken user) { return DateTime.MaxValue; } + public bool TokenExpired(IAuthenticationToken user) { + return false; + } + + public bool ValidToken(IAuthenticationToken user) { + return true; + } + public bool IsLockedOut(IAuthenticationToken user) { return false; } - #endregion } } Modified: NMail/trunk/NMail/ILocalStoreData.cs =================================================================== --- NMail/trunk/NMail/ILocalStoreData.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/ILocalStoreData.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -362,7 +362,7 @@ LocalStoreGroupResult UpdateGroup(LocalStoreGroup group); #endregion - #region ACLs + #region Folder ACLs /// <summary> /// Sets the privileges on the folder. If no ACE exists for the associated /// identifier one is added. Modified: NMail/trunk/NMail/IO/TcpChannel.cs =================================================================== --- NMail/trunk/NMail/IO/TcpChannel.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/IO/TcpChannel.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -18,14 +18,14 @@ using System; using System.Collections; using System.IO; +using System.Net.Security; using System.Runtime.Remoting; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Messaging; using System.Security.Cryptography.X509Certificates; using System.Text; -using Mono.Security.Authenticode; - +using NMail.Authentication; using NMail.DataTypes; namespace NMail.IO { @@ -39,20 +39,35 @@ private TcpServerChannel serverChannel; public TcpChannel(IDictionary properties, IClientChannelSinkProvider clientSinkProvider, IServerChannelSinkProvider serverSinkProvider) { + // Create the client sink provider if needed if (clientSinkProvider == null) { clientSinkProvider = new BinaryClientFormatterSinkProvider(); } - this.clientChannel = new TcpClientChannel(clientSinkProvider); + // Parse the client properties + RemoteCertificateValidationCallback certValidationCallback = (RemoteCertificateValidationCallback) properties["certificateValidation"]; + GetAuthDetailsDelegate getAuthDetailsCallback = (GetAuthDetailsDelegate) properties["authDetailCallback"]; + ChannelAuthComplete authCompleteCallback = (ChannelAuthComplete) properties["authCompleteCallback"]; + this.clientChannel = new TcpClientChannel(clientSinkProvider, + getAuthDetailsCallback, + certValidationCallback, + authCompleteCallback); + if (properties["isServer"] != null && ((string) properties["isServer"]) == "yes") { + // Create the server sink provider if needed if (serverSinkProvider == null) { serverSinkProvider = new BinaryServerFormatterSinkProvider(); } + // Parse the server properties int port = Int32.Parse((string) properties["port"]); + X509Certificate2 certificate = (X509Certificate2) properties["certificate"]; + IAuthenticationProvider authProvider = (IAuthenticationProvider) properties["authProvider"]; + this.serverChannel = new TcpServerChannel(port, - (X509Certificate2) properties["certificate"], + certificate, + authProvider, serverSinkProvider); } } @@ -215,8 +230,7 @@ /// <param name="objectURI">The object URI in the URL or null if the URL is invalid.</param> /// <returns>True if the URL is valid.</returns> public static bool ParseUrl(string url, out Host host, out int port, out string objectURI) { - url = url.Trim(); - + if (url == null || !url.StartsWith(UrlPrefix) || url.IndexOf(':') == -1 || url.IndexOf('/') == -1) { // Invalid URL host = null; @@ -225,11 +239,16 @@ return false; } + url = url.Trim(); + // Remove the "nmtcp://" url = url.Remove(0, UrlPrefix.Length); int cIndex = url.IndexOf(':'); int sIndex = url.IndexOf('/'); + if (sIndex == -1) { + sIndex = url.Length; + } host = new Host(url.Substring(0, cIndex)); port = Int32.Parse(url.Substring(cIndex + 1, sIndex - cIndex - 1)); objectURI = url.Substring(sIndex); @@ -319,4 +338,28 @@ } } #endregion + + [Serializable] + public class TcpUserPasswordPair { + public TcpUserPasswordPair(string username, string password) { + this.username = username; + this.password = password; + } + + private string username; + + public string Username { + get { + return this.username; + } + } + + private string password; + + public string Password { + get { + return this.password; + } + } + } } \ No newline at end of file Modified: NMail/trunk/NMail/IO/TcpClientChannel.cs =================================================================== --- NMail/trunk/NMail/IO/TcpClientChannel.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/IO/TcpClientChannel.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -17,13 +17,16 @@ using System; using System.Collections; +using System.Collections.Generic; using System.IO; using System.Net; +using System.Net.Security; using System.Net.Sockets; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Messaging; using System.Text; +using NMail.Authentication; using NMail.DataTypes; namespace NMail.IO { @@ -34,16 +37,38 @@ /// <summary> /// The provider to use. /// </summary> - IClientChannelSinkProvider clientSinkProvider; + private IClientChannelSinkProvider clientSinkProvider; /// <summary> + /// The tranport sink provider. + /// </summary> + private TcpClientTransportSinkProvider transportSinkProvider; + + /// <summary> /// Creates a new client channel with the given provider. /// </summary> /// <param name="clientSinkProvider">The provider to use.</param> - public TcpClientChannel(IClientChannelSinkProvider clientSinkProvider) { + public TcpClientChannel(IClientChannelSinkProvider clientSinkProvider, GetAuthDetailsDelegate getAuthDetailsCallback, ChannelAuthComplete authCompleteCallback) { this.clientSinkProvider = clientSinkProvider; + + this.transportSinkProvider = new TcpClientTransportSinkProvider(getAuthDetailsCallback, null, authCompleteCallback); } + /// <summary> + /// Creates a new client channel with the given provider. + /// </summary> + /// <param name="clientSinkProvider">The provider to use.</param> + /// <param name="certValidationCallback">The certificate to use to validate the remote server's certificate.</param> + public TcpClientChannel(IClientChannelSinkProvider clientSinkProvider, GetAuthDetailsDelegate getAuthDetailsCallback, RemoteCertificateValidationCallback certValidationCallback, ChannelAuthComplete authCompleteCallback) { + this.clientSinkProvider = clientSinkProvider; + + this.transportSinkProvider = new TcpClientTransportSinkProvider(getAuthDetailsCallback, certValidationCallback, authCompleteCallback); + + if (this.clientSinkProvider == null) { + this.clientSinkProvider = new BinaryClientFormatterSinkProvider(); + } + } + #region IChannelSender Members /// <summary> /// Returns a channel message sink that delivers messages to the specified URL @@ -73,6 +98,9 @@ } if (TcpChannel.ValidUrl(url)) { + // Parse the object URI + TcpChannel.ParseUrl(url, out objectURI); + // Find the last provider IClientChannelSinkProvider provider = this.clientSinkProvider; while (provider.Next != null) { @@ -80,19 +108,16 @@ } // Add our transport to the end of the chain - provider.Next = new TcpClientTransportSinkProvider(); + provider.Next = this.transportSinkProvider; - // Parse out the object URI - TcpChannel.ParseUrl(url, out objectURI); - - // Return the new sink return (IMessageSink) this.clientSinkProvider.CreateSink(this, url, remoteChannelData); + } else { // The URL is not for our channel. objectURI = null; return null; } - } + } #endregion #region IChannel Members @@ -132,4 +157,8 @@ } #endregion } + + public delegate TcpUserPasswordPair GetAuthDetailsDelegate(object sender); + + public delegate void ChannelAuthComplete(IAuthenticationToken authToken); } Modified: NMail/trunk/NMail/IO/TcpClientTransportSink.cs =================================================================== --- NMail/trunk/NMail/IO/TcpClientTransportSink.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/IO/TcpClientTransportSink.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -20,6 +20,7 @@ using System.Collections.Generic; using System.IO; using System.Net; +using System.Net.Security; using System.Net.Sockets; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Messaging; @@ -28,6 +29,7 @@ using log4net; +using NMail.Authentication; using NMail.DataTypes; using NMail.Helper; @@ -52,11 +54,25 @@ private int port; /// <summary> + /// The callback to use to validate the remote certificate. + /// </summary> + RemoteCertificateValidationCallback certValidationCallback; + + GetAuthDetailsDelegate getAuthDetailsCallback; + + ChannelAuthComplete authCompleteCallback; + + /// <summary> /// Creates a new sink with the given url. /// </summary> /// <param name="url">The URL to connect to.</param> /// <param name="remoteChannelData">Channel data optionally containing the URL.</param> - public TcpClientTransportSink(string url, object remoteChannelData) { + /// <param name="certValidationCallback">The callback to use to validate the remote certificate.</param> + public TcpClientTransportSink(string url, object remoteChannelData, GetAuthDetailsDelegate getAuthDetailsCallback, RemoteCertificateValidationCallback certValidationCallback, ChannelAuthComplete authCompleteCallback) { + this.getAuthDetailsCallback = getAuthDetailsCallback; + this.certValidationCallback = certValidationCallback; + this.authCompleteCallback = authCompleteCallback; + if (TcpChannel.ValidUrl(url)) { string objectURI; TcpChannel.ParseUrl(url, out this.host, out this.port, out objectURI); @@ -176,6 +192,20 @@ } #endregion + IAuthenticationToken authToken; + + public IAuthenticationToken AuthToken { + get { + return this.authToken; + } + } + + public bool Connected { + get { + return this.connection.Connected; + } + } + /// <summary> /// The connection used to communicate with the server. /// </summary> @@ -194,7 +224,34 @@ string response = connection.ReadLine(); if (response.Trim().ToLower() == "nmail remoting channel") { this.connection.WriteLine("OK"); - this.connection.StartTlsAsClient(this.host.ToString()); + + // Go encrypted... + if (this.certValidationCallback == null) { + this.connection.StartTlsAsClient(this.host.ToString()); + } else { + this.connection.StartTlsAsClient(this.host.ToString(), this.certValidationCallback); + } + + if (this.connection.Encrypted) { + while (this.connection.Connected && this.authToken == null) { + // Get the auth details + TcpUserPasswordPair authDetails = this.getAuthDetailsCallback(this); + + // Send them to the server + this.connection.Write(authDetails); + this.authToken = (IAuthenticationToken) this.connection.Read(); + } + + if (this.authToken == null) { + throw new InvalidOperationException("Failed to authenticated to the server."); + } + + // Notify the caller that the auth token has arrived + this.authCompleteCallback(authToken); + + } else { + throw new InvalidOperationException("Failed to establish a secure connection to the server."); + } } } } Modified: NMail/trunk/NMail/IO/TcpClientTransportSinkProvider.cs =================================================================== --- NMail/trunk/NMail/IO/TcpClientTransportSinkProvider.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/IO/TcpClientTransportSinkProvider.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -17,18 +17,43 @@ using System; using System.Collections; +using System.Collections.Generic; using System.IO; using System.Net; +using System.Net.Security; using System.Net.Sockets; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Messaging; using System.Text; +using NMail.Authentication; +using NMail.DataTypes; + namespace NMail.IO { /// <summary> /// A client transport sink provider for the NMail TCP channel. /// </summary> public class TcpClientTransportSinkProvider : IClientChannelSinkProvider { + + /// <summary> + /// The callback to use to validate the remote server's certificate. + /// </summary> + private RemoteCertificateValidationCallback certValidationCallback; + + private GetAuthDetailsDelegate getAuthDetailsCallback; + + private ChannelAuthComplete authCompleteCallback; + + /// <summary> + /// Creates a new provider with the given certificate validation callback. + /// </summary> + /// <param name="certValidationCallback">The callback to use to validation teh remote server's certificate null for the default.</param> + public TcpClientTransportSinkProvider(GetAuthDetailsDelegate getAuthDetailsCallback, RemoteCertificateValidationCallback certValidationCallback, ChannelAuthComplete authCompleteCallback) { + this.getAuthDetailsCallback = getAuthDetailsCallback; + this.certValidationCallback = certValidationCallback; + this.authCompleteCallback = authCompleteCallback; + } + #region IClientChannelSinkProvider Members /// <summary> /// Creates a sink chain. @@ -50,9 +75,31 @@ /// this endpoint. /// </returns> public IClientChannelSink CreateSink(IChannelSender channel, string url, object remoteChannelData) { - return new TcpClientTransportSink(url, remoteChannelData); + Host host; + int port; + string objectUri; + + TcpChannel.ParseUrl(url, out host, out port, out objectUri); + + string key = host.ToString() + ":" + port; + + lock (this) { + if (sinkMap.ContainsKey(key) && !sinkMap[key].Connected) { + // Transport has lost its connection + this.sinkMap.Remove(key); + } + + // Create a transport if needed + if (!sinkMap.ContainsKey(key)) { + this.sinkMap.Add(key, new TcpClientTransportSink(url, remoteChannelData, this.getAuthDetailsCallback, this.certValidationCallback, this.authCompleteCallback)); + } + + return this.sinkMap[key]; + } } + private Dictionary<string, TcpClientTransportSink> sinkMap = new Dictionary<string, TcpClientTransportSink>(); + /// <summary> /// Gets or sets the next sink provider in the channel sink provider chain. /// </summary> @@ -61,7 +108,7 @@ return null; } set { - throw new ArgumentException("This provider has to be the last in the chain."); + // Ignore: this provider has to be the last in the chain. } } #endregion Modified: NMail/trunk/NMail/IO/TcpServerChannel.cs =================================================================== --- NMail/trunk/NMail/IO/TcpServerChannel.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/IO/TcpServerChannel.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -29,6 +29,7 @@ using log4net; +using NMail.Authentication; using NMail.DataTypes; using NMail.Helper; @@ -48,11 +49,21 @@ private int port; /// <summary> + /// The bind IP address to report to report clients. + /// </summary> + private string bindAddress; + + /// <summary> /// The certificate to use for SSL. /// </summary> private X509Certificate2 certificate; /// <summary> + /// The authentication provider to use. + /// </summary> + private IAuthenticationProvider authProvider; + + /// <summary> /// The sink to pass any incoming messages to. /// </summary> private IServerChannelSink nextSink; @@ -63,11 +74,20 @@ /// <param name="port">The port to listen on.</param> /// <param name="certificate">The certificate to use for SSL.</param> /// <param name="serverSinkProvider">The provider.</param> - public TcpServerChannel(int port, X509Certificate2 certificate, IServerChannelSinkProvider serverSinkProvider) { + public TcpServerChannel(int port, X509Certificate2 certificate, IAuthenticationProvider authProvider, IServerChannelSinkProvider serverSinkProvider) { this.port = port; this.certificate = certificate; + this.authProvider = authProvider; - string[] urls = { TcpChannel.UrlPrefix + "0.0.0.0:" + this.port }; + // This is needed to report a valid IP to clients asking for channel data + IPHostEntry hostEntry = Dns.GetHostEntry(Dns.GetHostName()); + if (hostEntry.AddressList.Length == 0) { + throw new Exception("IP address could not be determined for this host."); + } + this.bindAddress = hostEntry.AddressList[0].ToString(); + + string[] urls = new string[1]; + urls[0] = GetUrlForChannel(); this.channelData = new ChannelDataStore(urls); // Collect channel data for all providers @@ -108,10 +128,14 @@ objectURI = '/' + objectURI; } - urls[0] = TcpChannel.UrlPrefix + "0.0.0.0:" + this.port + objectURI; + urls[0] = GetUrlForChannel() + objectURI; return urls; } + public string GetUrlForChannel() { + return TcpChannel.UrlPrefix + this.bindAddress + ":" + this.port; + } + /// <summary> /// Instructs the current channel to start listening for requests. /// </summary> @@ -214,7 +238,7 @@ while (true) { Socket client = socket.AcceptSocket(); - new TcpServerTransportSink(this.nextSink, this.certificate, client); + new TcpServerTransportSink(this.nextSink, this.certificate, this.authProvider, client); } } catch (SocketException e) { // Ignore interrupted exception during shutdown Modified: NMail/trunk/NMail/IO/TcpServerTransportSink.cs =================================================================== --- NMail/trunk/NMail/IO/TcpServerTransportSink.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/IO/TcpServerTransportSink.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -28,6 +28,7 @@ using log4net; +using NMail.Authentication; using NMail.DataTypes; using NMail.Helper; @@ -51,17 +52,20 @@ /// </summary> protected IServerChannelSink nextSink; + protected IAuthenticationProvider authProvider; + /// <summary> /// Creates a new transport sink with the given details. /// </summary> /// <param name="nextSink">The next sink in the chain.</param> /// <param name="certificate">The certificate to use in SSL.</param> /// <param name="client">The socket to the remote client.</param> - public TcpServerTransportSink(IServerChannelSink nextSink, X509Certificate2 certificate, Socket client) { + public TcpServerTransportSink(IServerChannelSink nextSink, X509Certificate2 certificate, IAuthenticationProvider authProvider, Socket client) { this.nextSink = nextSink; this.connection.Create(client); this.connection.Certificate = certificate; - + this.authProvider = authProvider; + // Create a new thread to read requests with ThreadHelper th = new ThreadHelper(new WaitCallback(processConnection), null); Thread processThread = new Thread(new ThreadStart(th.CallDelegate)); @@ -74,56 +78,89 @@ /// </summary> /// <param name="unused">An unused argument.</param> private void processConnection(object unused) { - // Present the welcome message and await a valid response - this.connection.WriteLine("NMail Remoting Channel"); - string response = this.connection.ReadLine(); + Thread.CurrentThread.Name = "NMail TCP server remoting thread."; - // Check that we have a valid client - if (response.Trim().ToLower() != "ok") { - this.connection.Close(); - } + try { + // Present the welcome message and await a valid response + this.connection.WriteLine("NMail Remoting Channel"); + string response = this.connection.ReadLine(); - // Go encrypted... - this.connection.StartTlsAsServer(); + // Check that we have a valid client + if (response.Trim().ToLower() != "ok") { + this.connection.Close(); + } - while (this.connection.Connected) { - // Get the next request from the client - TcpMessage request = (TcpMessage) this.connection.Read(); - MemoryStream requestStream = new MemoryStream(request.Data); + // Go encrypted... + this.connection.StartTlsAsServer(); - // Get the message Id - string messageId = (string) request.Headers["__Id"]; + int authAttempts = 0; + bool authenticated = false; - // Strip off all of the Url except the object Uri - string uri = (string) request.Headers[CommonTransportKeys.RequestUri]; - TcpChannel.ParseUrl(uri, out uri); - if (uri != null) { - request.Headers[CommonTransportKeys.RequestUri] = uri; + // Try to authenticate the user + while (this.connection.Connected && !authenticated && authAttempts < 3) { + TcpUserPasswordPair authDetails = (TcpUserPasswordPair) this.connection.Read(); + + // Attempt to authenticate the user + IAuthenticationToken authToken = this.authProvider.Authenticate(authDetails.Username, authDetails.Password); + + authAttempts++; + authenticated = (authToken != null); + this.connection.Write(authToken); } - ServerChannelSinkStack sinkStack = new ServerChannelSinkStack(); - sinkStack.Push(this, messageId); + if (authAttempts >= 3) { + // Auth failed + this.connection.Close(); + return; + } - IMessage responseMessage; - ITransportHeaders responseHeaders; - Stream responseStream; + while (this.connection.Connected) { + // Get the next request from the client + TcpMessage request = (TcpMessage) this.connection.Read(); + MemoryStream requestStream = new MemoryStream(request.Data); - // Send the request down the chain - ServerProcessing processing = this.nextSink.ProcessMessage(sinkStack, - null, - request.Headers, - requestStream, - out responseMessage, - out responseHeaders, - out responseStream); + // Get the message Id + string messageId = (string) request.Headers["__Id"]; - // Check if a response is needed - if (processing == ServerProcessing.Complete) { - responseHeaders["__Id"] = messageId; + // Strip off all of the Url except the object Uri + string uri = (string) request.Headers[CommonTransportKeys.RequestUri]; + TcpChannel.ParseUrl(uri, out uri); + if (uri != null) { + request.Headers[CommonTransportKeys.RequestUri] = uri; + } - TcpMessage.SendMessage(this.connection, responseStream, responseHeaders); - this.connection.Flush(); + ServerChannelSinkStack sinkStack = new ServerChannelSinkStack(); + sinkStack.Push(this, messageId); + + IMessage responseMessage; + ITransportHeaders responseHeaders; + Stream responseStream; + + // Send the request down the chain + ServerProcessing processing = this.nextSink.ProcessMessage(sinkStack, + null, + request.Headers, + requestStream, + out responseMessage, + out responseHeaders, + out responseStream); + + // Check if a response is needed + if (processing == ServerProcessing.Complete) { + responseHeaders["__Id"] = messageId; + + TcpMessage.SendMessage(this.connection, responseStream, responseHeaders); + this.connection.Flush(); + } } + } catch (SocketException) { + // Ignore + + } catch (IOException) { + // Ignore + + } catch (Exception ex) { + log.Debug("Unhandled exception.", ex); } } Modified: NMail/trunk/NMail/IO/TcpTextConnection.cs =================================================================== --- NMail/trunk/NMail/IO/TcpTextConnection.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/IO/TcpTextConnection.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -524,21 +524,35 @@ } } + #region TLS + /// <summary> + /// Starts TLS negotiation as a client. + /// </summary> + /// <param name="host">The name of the remote host.</param> public void StartTlsAsClient(string host) { - this.sslStream = new SslStream(this.networkStream, true, new RemoteCertificateValidationCallback(certificateValidationCallback)); + this.sslStream = new SslStream(this.networkStream, true); this.sslStream.AuthenticateAsClient(host); } + /// <summary> + /// Starts TLS negotiation as a client. + /// </summary> + /// <param name="host">The name of the remote host.</param> + /// <param name="certValidationCallback">The callback used to validate the remote certificate.</param> + public void StartTlsAsClient(string host, RemoteCertificateValidationCallback certValidationCallback) { + this.sslStream = new SslStream(this.networkStream, true, certValidationCallback); + this.sslStream.AuthenticateAsClient(host); + } + + /// <summary> + /// Starts TLS negotiation as a server. + /// </summary> public void StartTlsAsServer() { - this.sslStream = new SslStream(this.networkStream, true, new RemoteCertificateValidationCallback(certificateValidationCallback)); + this.sslStream = new SslStream(this.networkStream, true); this.sslStream.AuthenticateAsServer(this.certificate); } + #endregion - private bool certificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { - - return true; - } - #region Properties /// <summary> /// Returns if the connection is encrypted. Modified: NMail/trunk/NMail/NMail.csproj =================================================================== --- NMail/trunk/NMail/NMail.csproj 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/NMail.csproj 2006-05-06 15:33:43 UTC (rev 29) @@ -78,10 +78,6 @@ <Name>log4net</Name> <HintPath>..\References\log4net.dll</HintPath> </Reference> - <Reference Include="Mono.Security"> - <Name>Mono.Security</Name> - <HintPath>..\References\Mono.Security.dll</HintPath> - </Reference> <Reference Include="nunit.framework"> <Name>nunit.framework</Name> <HintPath>..\References\nunit.framework.dll</HintPath> @@ -113,7 +109,6 @@ <SubType>Code</SubType> </Compile> <Compile Include="Authentication\IHashAuthProvider.cs" /> - <Compile Include="Authentication\IPasswordAuthProvider.cs" /> <Compile Include="Authentication\NullAuthentication.cs"> <SubType>Code</SubType> </Compile> Modified: NMail/trunk/NMail.Administration.Console/Command/AddUserCommand.cs =================================================================== --- NMail/trunk/NMail.Administration.Console/Command/AddUserCommand.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail.Administration.Console/Command/AddUserCommand.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -20,6 +20,7 @@ using System.Text; using NMail; +using NMail.Authentication; using NMail.DataTypes; namespace NMail.Administration.Console.Command { @@ -27,8 +28,11 @@ private ILocalStore localStore; - internal AddUserCommand(ILocalStore localStore) { + private IAuthenticationToken authToken; + + internal AddUserCommand(ILocalStore localStore, IAuthenticationToken authToken) { this.localStore = localStore; + this.authToken = authToken; } #region IConsoleCommand Members @@ -89,7 +93,7 @@ } } - LocalStoreUserResult result = this.localStore.CreateUser(null, username, warnQuota, hardQuota, null); + LocalStoreUserResult result = this.localStore.CreateUser(this.authToken, username, warnQuota, hardQuota, null); if (result == LocalStoreUserResult.AlreadyExists) { System.Console.WriteLine("User with the the same username already exists."); Modified: NMail/trunk/NMail.Administration.Console/Command/ListUsersCommand.cs =================================================================== --- NMail/trunk/NMail.Administration.Console/Command/ListUsersCommand.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail.Administration.Console/Command/ListUsersCommand.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -20,6 +20,7 @@ using System.Text; using NMail; +using NMail.Authentication; using NMail.DataTypes; namespace NMail.Administration.Console.Command { @@ -27,8 +28,11 @@ private ILocalStore localStore; - internal ListUsersCommand(ILocalStore localStore) { + private IAuthenticationToken authToken; + + internal ListUsersCommand(ILocalStore localStore, IAuthenticationToken authToken) { this.localStore = localStore; + this.authToken = authToken; } #region IConsoleCommand Members @@ -50,7 +54,7 @@ } public void Process(string[] commandTokens) { - LocalStoreUser[] users = this.localStore.GetUsers(null); + LocalStoreUser[] users = this.localStore.GetUsers(this.authToken); System.Console.WriteLine(); System.Console.WriteLine(string.Format("{0,-7} {1,-25} {2,-10} {3,-10}", "User Id", "Username", "Warn Quota", "Hard Quota")); Modified: NMail/trunk/NMail.Administration.Console/Context/LocalStoreContext.cs =================================================================== --- NMail/trunk/NMail.Administration.Console/Context/LocalStoreContext.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail.Administration.Console/Context/LocalStoreContext.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -20,18 +20,19 @@ using System.Text; using NMail.Administration.Console.Command; +using NMail.Authentication; namespace NMail.Administration.Console.Context { class LocalStoreContext : AbstractContext { - internal LocalStoreContext(AbstractContext parentContext, ILocalStore localStore) { + internal LocalStoreContext(AbstractContext parentContext, ILocalStore localStore, IAuthenticationToken authToken) { this.parentContext = parentContext; this.localStore = localStore; this.name = "Local Store"; - this.commands.Add("listusers", new ListUsersCommand(this.localStore)); + this.commands.Add("listusers", new ListUsersCommand(this.localStore, authToken)); this.commands.Add("listaddresses", new ListUsersAddressesCommand(this.localStore)); - this.commands.Add("adduser", new AddUserCommand(this.localStore)); + this.commands.Add("adduser", new AddUserCommand(this.localStore, authToken)); this.commands.Add("deleteuser", new DeleteUserCommand(this.localStore)); } Modified: NMail/trunk/NMail.Administration.Console/Context/TopLevelContext.cs =================================================================== --- NMail/trunk/NMail.Administration.Console/Context/TopLevelContext.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail.Administration.Console/Context/TopLevelContext.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -16,26 +16,71 @@ */ using System; +using System.Collections; using System.Collections.Generic; +using System.Net.Security; using System.Runtime.Remoting; +using System.Runtime.Remoting.Channels; +using System.Security.Cryptography.X509Certificates; using System.Text; +using System.Threading; using NMail; using NMail.Administration.Console.Command; +using NMail.Authentication; +using NMail.IO; using NMail.Server; namespace NMail.Administration.Console.Context { public class TopLevelContext : AbstractContext { protected RemoteAdministration remoteAdmin; + protected IAuthenticationToken authToken; + + private ManualResetEvent authCompleteEvent = new ManualResetEvent(false); + public TopLevelContext() { - this.remoteAdmin = (RemoteAdministration)RemotingServices.Connect(Type.GetType("NMail.Server.RemoteAdministration, NMail.Server"), "ipc://NMailAdministration/RemoteAdministration.rem"); + // Setup the remoting channel + IDictionary props = new Hashtable(); + props["port"] = "7877"; + props["certificateValidation"] = new RemoteCertificateValidationCallback(remoteCertificateValidation); + //TcpChannel channel = new TcpChannel(props, null, null); + TcpClientChannel channel = new TcpClientChannel(null, new GetAuthDetailsDelegate(GetAuthDetails), new RemoteCertificateValidationCallback(remoteCertificateValidation), new ChannelAuthComplete(AuthCompleteCallback)); + ChannelServices.RegisterChannel(channel, false); + + string url = "nmtcp://127.0.0.1:7877/RemoteAdministration.rem"; + this.remoteAdmin = (RemoteAdministration)RemotingServices.Connect(Type.GetType("NMail.Server.RemoteAdministration, NMail.Server"), url); + // Wait until the channel gives us an authentication token + this.authCompleteEvent.WaitOne(); + this.name = "NMail"; this.commands.Add("exit", new ExitCommand()); - this.contexts.Add("localstore", new LocalStoreContext(this, this.remoteAdmin.NMailServer.LocalStore)); + this.contexts.Add("localstore", new LocalStoreContext(this, this.remoteAdmin.NMailServer.LocalStore, this.authToken)); } + + public bool remoteCertificateValidation(object sender, X509Certificate certificate, X509Chain x509Chain, SslPolicyErrors policyErrors) { + // TODO: check with the user if the cert if ok... + return true; + } + + public TcpUserPasswordPair GetAuthDetails(object sender) { + System.Console.Write("Username: "); + string username = System.Console.ReadLine(); + + System.Console.Write("Password (will be visible): "); + string password = System.Console.ReadLine(); + + return new TcpUserPasswordPair(username, password); + } + + public void AuthCompleteCallback(IAuthenticationToken authToken) { + this.authToken = authToken; + + // Notify the main thread that we have a token + this.authCompleteEvent.Set(); + } } } Modified: NMail/trunk/NMail.Administration.Console/NMail.Administration.Console.csproj =================================================================== --- NMail/trunk/NMail.Administration.Console/NMail.Administration.Console.csproj 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail.Administration.Console/NMail.Administration.Console.csproj 2006-05-06 15:33:43 UTC (rev 29) @@ -30,6 +30,7 @@ <ItemGroup> <Reference Include="System" /> <Reference Include="System.Data" /> + <Reference Include="System.Runtime.Remoting" /> <Reference Include="System.Xml" /> </ItemGroup> <ItemGroup> Modified: NMail/trunk/NMail.ImapService/ImapServiceConnection.cs =================================================================== --- NMail/trunk/NMail.ImapService/ImapServiceConnection.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail.ImapService/ImapServiceConnection.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -32,7 +32,7 @@ string certFile = ImapServiceConfiguration.Current.CertificateFile; if (certFile != null && certFile.Trim() != string.Empty) { - this.Certificate = new X509Certificate2(certFile); + this.Certificate = new X509Certificate2(certFile, ""); } // TODO: setup IMap specific options, eg line length = ????, etc Modified: NMail/trunk/NMail.ImapService/State/ConnectedState.cs =================================================================== --- NMail/trunk/NMail.ImapService/State/ConnectedState.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail.ImapService/State/ConnectedState.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -85,7 +85,7 @@ public override void ProcessCommand(LoginCommand cmd) { if (Session.Connection.Encrypted) { - IPasswordAuthProvider authProvider = (IPasswordAuthProvider) NMailConfiguration.Current.AuthenticationProvider; + IAuthenticationProvider authProvider = (IAuthenticationProvider) NMailConfiguration.Current.AuthenticationProvider; IAuthenticationToken authToken = authProvider.Authenticate(cmd.Username, cmd.Password); if (authToken != null) { Modified: NMail/trunk/NMail.LocalStore/LocalStore.cs =================================================================== --- NMail/trunk/NMail.LocalStore/LocalStore.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail.LocalStore/LocalStore.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -68,7 +68,7 @@ return new DeliveryResult(DeliveryResultType.PermanentError, "Invalid Folder."); } - BasicAuthToken authToken = new BasicAuthToken(username); + IAuthenticationToken authToken = NMailConfiguration.Current.AuthenticationProvider.CreateAuthToken(username); // Pass through the default chain DeliveryResult result; @@ -153,7 +153,8 @@ "User has no inbox in the local store."); } - BasicAuthToken authToken = new BasicAuthToken(username); + IAuthenticationToken authToken = NMailConfiguration.Current.AuthenticationProvider.CreateAuthToken(username); + LocalStoreDelivery lsd = new LocalStoreDelivery(recipient, inboxFolder); // Pass through the default chain Modified: NMail/trunk/NMail.LocalStoreData.MySql/MySqlLocalStore.sql =================================================================== --- NMail/trunk/NMail.LocalStoreData.MySql/MySqlLocalStore.sql 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail.LocalStoreData.MySql/MySqlLocalStore.sql 2006-05-06 15:33:43 UTC (rev 29) @@ -61,7 +61,7 @@ Identifier VARCHAR(100) NOT NULL, FolderId INT NOT NULL, Allow BOOLEAN NOT NULL, - Privilege INT NOT NULL, + Privilege INT UNSIGNED NOT NULL, PRIMARY KEY(FolderAclId), UNIQUE KEY (FolderId, Identifier), FOREIGN KEY (FolderId) REFERENCES Folder (FolderId) ON DELETE CASCADE @@ -73,7 +73,7 @@ Identifier VARCHAR(100) NOT NULL, Resource VARCHAR(100) NOT NULL, Allow BOOLEAN NOT NULL, - Privilege INT NOT NULL, + Privilege INT UNSIGNED NOT NULL, PRIMARY KEY (AclId), UNIQUE KEY (Resource, Identifier) ) TYPE=InnoDB; @@ -126,6 +126,6 @@ INSERT INTO User (UserName, Password, UserFolderId) VALUES ("Administrator", "changeme", 2); INSERT INTO Folder (NamespaceId, Name, OwnerUserId, NextMessageId) VALUES (1, "Administrator", 1, 1); INSERT INTO Folder (NamespaceId, Name, OwnerUserId, NextMessageId, ParentFolderId) VALUES (1, "Administrator.INBOX", 1, 1, 1); -INSERT INTO Acl (FolderId, Identifier, AllowPrivs, LookupPriv, ReadPriv, SeenPriv, WritePriv, InsertPriv, PostPriv, CreatePriv, DeletePriv, AdminPriv) VALUES (1, "Administrator", 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); -INSERT INTO Acl (FolderId, Identifier, AllowPrivs, LookupPriv, ReadPriv, SeenPriv, WritePriv, InsertPriv, PostPriv, CreatePriv, DeletePriv, AdminPriv) VALUES (2, "Administrator", 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); +INSERT INTO FolderAcl (FolderId, Identifier, Allow, Privilege) VALUES (1, "Administrator", 1, 0xffffff); -- All privs +INSERT INTO FolderAcl (FolderId, Identifier, Allow, Privilege) VALUES (2, "Administrator", 1, 0xffffff); -- All privs INSERT INTO Subscription (UserId, FolderId) VALUES (1, 2); \ No newline at end of file Modified: NMail/trunk/NMail.LocalStoreData.MySql/MySqlLocalStoreData.cs =================================================================== --- NMail/trunk/NMail.LocalStoreData.MySql/MySqlLocalStoreData.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail.LocalStoreData.MySql/MySqlLocalStoreData.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -1274,20 +1274,10 @@ private void setStoreFolderAce(StoreFolder folder, StoreFolderAce ace, MySqlConnection cnn, MySqlTransaction transaction) { using (MySqlCommand cmd = cnn.CreateCommand()) { - cmd.CommandText = "REPLACE Acl (FolderId, Identifier, AllowPrivs, LookupPriv, ReadPriv, SeenPriv, WritePriv, InsertPriv, PostPriv, CreatePriv, DeletePriv, AdminPriv) VALUES (?FolderId, ?Identifier, ?AllowPrivs, ?LookupPriv, ?ReadPriv, ?SeenPriv, ?WritePriv, ?InsertPriv, ?PostPriv, ?CreatePriv, ?DeletePriv, ?AdminPriv)"; + cmd.CommandText = "REPLACE Acl (FolderId, Identifier, Allow, Privilege) VALUES (?FolderId, ?Identifier, ?AllowPrivs, ?LookupPriv, ?ReadPriv, ?SeenPriv, ?WritePriv, ?InsertPriv, ?PostPriv, ?CreatePriv, ?DeletePriv, ?AdminPriv)"; cmd.Parameters.Add("FolderId", folder.FolderId); cmd.Parameters.Add("Identifier", ace.Identifier); - cmd.Parameters.Add("AllowPrivs", (ace.AceType == AcePrivilegeType.Allow)); - cmd.Parameters.Add("LookupPriv", ((ace.Privilege & StoreFolderPrivilege.Lookup) != StoreFolderPrivilege.None)); - cmd.Parameters.Add("ReadPriv", ((ace.Privilege & StoreFolderPrivilege.Read) != StoreFolderPrivilege.None)); - cmd.Parameters.Add("SeenPriv", ((ace.Privilege & StoreFolderPrivilege.AlterSeenFlag) != StoreFolderPrivilege.None)); - cmd.Parameters.Add("WritePriv", ((ace.Privilege & StoreFolderPrivilege.Write) != StoreFolderPrivilege.None)); - cmd.Parameters.Add("InsertPriv", ((ace.Privilege & StoreFolderPrivilege.Insert) != StoreFolderPrivilege.None)); - cmd.Parameters.Add("PostPriv", ((ace.Privilege & StoreFolderPrivilege.Post) != StoreFolderPrivilege.None)); - cmd.Parameters.Add("CreatePriv", ((ace.Privilege & StoreFolderPrivilege.CreateFolders) != StoreFolderPrivilege.None)); - cmd.Parameters.Add("DeletePriv", ((ace.Privilege & StoreFolderPrivilege.Delete) != StoreFolderPrivilege.None)); - cmd.Parameters.Add("AdminPriv", ((ace.Privilege & StoreFolderPrivilege.Admin) != StoreFolderPrivilege.None)); - + cmd.Parameters.Add("Privilege", Convert.ToUInt32(ace.Privilege)); int count = cmd.ExecuteNonQuery(); if (count != 1 && count != 2) { // Replace returns a count of 2 @@ -1319,43 +1309,15 @@ using (MySqlConnection cnn = GetConnection()) { using (MySqlCommand cmd = cnn.CreateCommand()) { - cmd.CommandText = "SELECT Identifier, AllowPrivs, LookupPriv, ReadPriv, SeenPriv, WritePriv, InsertPriv, PostPriv, CreatePriv, DeletePriv, AdminPriv FROM Acl WHERE FolderId = ?FolderId"; + cmd.CommandText = "SELECT Identifier, Allow, Privilege FROM Acl WHERE FolderId = ?FolderId"; cmd.Parameters.Add("FolderId", folder.FolderId); using (MySqlDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { string identifier = (string) reader["Identifier"]; - AcePrivilegeType aceType = (((sbyte)reader["AllowPrivs"]) == 1)? AcePrivilegeType.Allow : AcePrivilegeType.Deny; + AcePrivilegeType aceType = (((sbyte)reader["Allow"]) == 1)? AcePrivilegeType.Allow : AcePrivilegeType.Deny; + StoreFolderPrivilege privilege = (StoreFolderPrivilege) reader["Privilege"]; - StoreFolderPrivilege privilege = StoreFolderPrivilege.None; - if ((sbyte)reader["LookupPriv"] == 1) { - privilege |= StoreFolderPrivilege.Lookup; - } - if ((sbyte)reader["ReadPriv"] == 1) { - privilege |= StoreFolderPrivilege.Read; - } - if ((sbyte)reader["SeenPriv"] == 1) { - privilege |= StoreFolderPrivilege.AlterSeenFlag; - } - if ((sbyte)reader["WritePriv"] == 1) { - privilege |= StoreFolderPrivilege.Write; - } - if ((sbyte)reader["InsertPriv"] == 1) { - privilege |= StoreFolderPrivilege.Insert; - } - if ((sbyte)reader["PostPriv"] == 1) { - privilege |= StoreFolderPrivilege.Post; - } - if ((sbyte)reader["CreatePriv"] == 1) { - privilege |= StoreFolderPrivilege.CreateFolders; - } - if ((sbyte)reader["DeletePriv"] == 1) { - privilege |= StoreFolderPrivilege.Delete; - } - if ((sbyte)reader["AdminPriv"] == 1) { - privilege |= StoreFolderPrivilege.Admin; - } - StoreFolderAce ace = new StoreFolderAce(identifier, privilege, aceType); result.SetAce(ace); } @@ -1409,16 +1371,25 @@ #region Auth Provider #region IAuthProvider - public DateTime GetCredentialsExpiry(IAuthenticationToken user) { + public DateTime GetTokenExpiry(IAuthenticationToken user) { // TODO: fix this! return DateTime.MaxValue; } + public bool TokenExpired(IAuthenticationToken user) { + // TODO: fix this!! + return false; + } + + public bool ValidToken(IAuthenticationToken user) { + // TODO: fix this!! + return true; + } + public bool IsLockedOut(IAuthenticationToken user) { // TODO: fix this! return false; } - #endregion #region IHashAuthProvider Members @@ -1439,7 +1410,8 @@ if (dbHash == hash) { // Hashes match, return a valid token - return new BasicAuthToken(username); + // TODO: get the password expiry details + return new BasicAuthToken(username, DateTime.MaxValue); } } } @@ -1454,7 +1426,7 @@ #endregion - #region IPasswordAuthProvider Members + #region IAuthenticationProvider Members public IAuthenticationToken Authenticate(string username, string password) { // Get the hash stored in the database. @@ -1466,7 +1438,8 @@ if (dbHash == password) { // Hashes match, return a valid token - return new BasicAuthToken(username); + // TODO: get the password expiry details + return new BasicAuthToken(username, DateTime.MaxValue); } } } @@ -1475,6 +1448,24 @@ return null; } + public IAuthenticationToken CreateAuthToken(string username) { + // Get the hash stored in the database. + using (MySqlConnection cnn = GetConnection()) { + using (MySqlCommand cmd = cnn.CreateCommand()) { + cmd.CommandText = "SELECT COUNT(*) FROM User WHERE Username = ?Username"; + cmd.Parameters.Add("Username", username); + long count = (long) cmd.ExecuteScalar(); + + if (count == 1) { + // TODO: get the password expiry details + return new BasicAuthToken(username, DateTime.MaxValue); + } + } + } + + // No such user + return null; + } #endregion #endregion Modified: NMail/trunk/NMail.Server/RemoteAdministration.cs =================================================================== --- NMail/trunk/NMail.Server/RemoteAdministration.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail.Server/RemoteAdministration.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -17,11 +17,13 @@ using System; using System.Collections; +using System.Net.Security; using System.Runtime.Remoting; using System.Runtime.Remoting.Channels; using System.Runtime.Serialization.Formatters; using System.Security.Cryptography.X509Certificates; +using NMail.Configuration; using NMail.IO; namespace NMail.Server { @@ -61,15 +63,15 @@ props["port"] = "7877"; props["isServer"] = "yes"; props["certificate"] = new X509Certificate2("NMail.pfx", ""); + props["authProvider"] = NMailConfiguration.Current.AuthenticationProvider; TcpChannel channel = new TcpChannel(props, null, provider); ChannelServices.RegisterChannel(channel, false); // Register our remote administration interface - RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemoteAdministration), "RemoteAdministration.rem", WellKnownObjectMode.Singleton); + RemoteAdministration ra = new RemoteAdministration(); + ra.NMailServer = server; + RemotingServices.Marshal(ra, "RemoteAdministration.rem", typeof(RemoteAdministration)); - // Connect to the remote admin object to ensure we link in the singleton into our server object. - RemoteAdministration ra = (RemoteAdministration) RemotingServices.Connect(typeof(RemoteAdministration), "nmtcp://127.0.0.1:7877/RemoteAdministration.rem"); - ra.NMailServer = server; return ra; } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <tmy...@us...> - 2006-05-08 17:25:56
|
Revision: 28 Author: tmyroadctfig Date: 2006-05-06 07:52:35 -0700 (Sat, 06 May 2006) ViewCVS: http://svn.sourceforge.net/nmailserver/?rev=28&view=rev Log Message: ----------- Committed patch from Jared Hodges - fixes defects in unit tests. Modified Paths: -------------- NMail/trunk/NMail.UnitTests/DomainTests.cs NMail/trunk/NMail.UnitTests/SmtpServiceTests.cs Modified: NMail/trunk/NMail.UnitTests/DomainTests.cs =================================================================== --- NMail/trunk/NMail.UnitTests/DomainTests.cs 2006-05-03 14:02:03 UTC (rev 27) +++ NMail/trunk/NMail.UnitTests/DomainTests.cs 2006-05-06 14:52:35 UTC (rev 28) @@ -1,5 +1,5 @@ /* - * Copyright 2004-2006 Luke Quinane and Daniel Frampton + * Copyright 2004-2006 Luke Quinane, Daniel Frampton and Jared Hodges. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,7 +50,6 @@ /// Checks if a domain that starts with numbers is rejected. /// </summary> [Test] - [ExpectedException(typeof(FormatException))] public void CheckNumbersAtStartName() { Domain d = new Domain("123abc.dom.tld"); } Modified: NMail/trunk/NMail.UnitTests/SmtpServiceTests.cs =================================================================== --- NMail/trunk/NMail.UnitTests/SmtpServiceTests.cs 2006-05-03 14:02:03 UTC (rev 27) +++ NMail/trunk/NMail.UnitTests/SmtpServiceTests.cs 2006-05-06 14:52:35 UTC (rev 28) @@ -1,5 +1,5 @@ /* - * Copyright 2004-2006 Luke Quinane and Daniel Frampton + * Copyright 2004-2006 Luke Quinane, Daniel Frampton and Jared Hodges. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,19 +37,30 @@ /// <summary> /// Opens a connection to the server. /// </summary> - [TestFixtureSetUp] - public void Init() { + private void Open() { this.connection = new TcpTextConnection(log); this.connection.Open(new Host(IPAddress.Loopback), 25); + + // Should get a 220 response + string welcome = this.connection.ReadLine(); + Assert.IsTrue(welcome.StartsWith("220 "), "Welcome starts with '220 '"); } /// <summary> + /// Closes the connection to the server + /// </summary> + private void Close() { + this.connection.WriteLine("QUIT"); + this.connection.Close(); + } + + /// <summary> /// Tests that the server sends a "220" welcome message. /// </summary> [Test] public void WelcomeTest() { - string welcome = this.connection.ReadLine(); - Assert.IsTrue(welcome.StartsWith("220 "), "Welcome starts with '220 '"); + Open(); + Close(); } /// <summary> @@ -57,9 +68,11 @@ /// </summary> [Test] public void NoopTest() { + Open(); this.connection.WriteLine("noop"); string response = this.connection.ReadLine(); Assert.IsTrue(response.StartsWith("250 "), "NOOP response starts with '250 '"); + Close(); } /// <summary> @@ -68,19 +81,12 @@ /// </summary> [Test] public void HeloTest() { + Open(); this.connection.WriteLine("helo test.domain"); string response = this.connection.ReadLine(); Assert.IsTrue(response.StartsWith("250 "), "HELO response starts with '250 '"); Host h1 = new Host(response.Split(' ')[1]); + Close(); } - - /// <summary> - /// Closes the connection to the server - /// </summary> - [TestFixtureTearDown] - public void Close() { - this.connection.WriteLine("QUIT"); - this.connection.Close(); - } } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <tmy...@us...> - 2006-05-03 14:02:25
|
Revision: 27 Author: tmyroadctfig Date: 2006-05-03 07:02:03 -0700 (Wed, 03 May 2006) ViewCVS: http://svn.sourceforge.net/nmailserver/?rev=27&view=rev Log Message: ----------- Changed the SMTP client to handle multiple 3xx messages after a DATA command. Modified Paths: -------------- NMail/trunk/NMail.SmtpClient/SmtpClient.cs Modified: NMail/trunk/NMail.SmtpClient/SmtpClient.cs =================================================================== --- NMail/trunk/NMail.SmtpClient/SmtpClient.cs 2006-05-03 13:48:24 UTC (rev 26) +++ NMail/trunk/NMail.SmtpClient/SmtpClient.cs 2006-05-03 14:02:03 UTC (rev 27) @@ -391,6 +391,11 @@ blocks = (blocks > 0) ? blocks : 1; this.response = this.connection.GetResponse(TimeSpan.FromSeconds(this.config.TimeoutDataBlock.TotalSeconds * blocks)); + // Discard any extra 3xx messages + while (this.response.Continue) { + this.response = this.connection.GetResponse(TimeSpan.FromSeconds(this.config.TimeoutDataBlock.TotalSeconds * blocks)); + } + return this.response.OK; } catch (TimeoutException) { log.Debug("Timed out communicating with remote server while sending data."); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <tmy...@us...> - 2006-05-03 13:48:37
|
Revision: 26 Author: tmyroadctfig Date: 2006-05-03 06:48:24 -0700 (Wed, 03 May 2006) ViewCVS: http://svn.sourceforge.net/nmailserver/?rev=26&view=rev Log Message: ----------- Fixed case of database names. Modified Paths: -------------- NMail/trunk/NMail.Server.Console/NMail.config Modified: NMail/trunk/NMail.Server.Console/NMail.config =================================================================== --- NMail/trunk/NMail.Server.Console/NMail.config 2006-05-01 09:35:44 UTC (rev 25) +++ NMail/trunk/NMail.Server.Console/NMail.config 2006-05-03 13:48:24 UTC (rev 26) @@ -119,8 +119,8 @@ </AcceptCases> </NMail.LocalStore> - <NMail.SpoolData.MySql ConnectionString="Database=NmailSpool;Uid=NMail;Password=moo" /> + <NMail.SpoolData.MySql ConnectionString="Database=NMailSpool;Uid=NMail;Password=moo" /> - <NMail.LocalStoreData.MySql ConnectionString="Database=NmailLocalStore;Uid=NMail;Password=moo"/> + <NMail.LocalStoreData.MySql ConnectionString="Database=NMailLocalStore;Uid=NMail;Password=moo"/> </configuration> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |