csmaild-cvs Mailing List for C# Mail Server (Page 4)
Brought to you by:
tamc
You can subscribe to this list here.
2003 |
Jan
|
Feb
|
Mar
|
Apr
(7) |
May
|
Jun
|
Jul
(79) |
Aug
(49) |
Sep
|
Oct
|
Nov
|
Dec
|
---|
From: <ta...@us...> - 2003-07-27 19:33:02
|
Update of /cvsroot/csmaild/csmaild/src/Common In directory sc8-pr-cvs1:/tmp/cvs-serv29411/src/Common Modified Files: Common.csproj User.cs Added Files: MailboxCollection.cs Log Message: CREATE command should work now --- NEW FILE: MailboxCollection.cs --- using Common.MailstoreProviders; using System; using System.Collections; namespace Common { /// <summary> /// Custom class representing a mailbox collection /// </summary> public class MailboxCollection : IEnumerable { private User mUser; private ArrayList mIndexedList = new ArrayList(); private Hashtable mNamedList = new Hashtable(); private IMailstoreProvider mProvider; internal MailboxCollection(IMailstoreProvider provider, User usr) { mProvider = provider; mUser = usr; } public Mailbox this[int idx] { get { return (Mailbox)mIndexedList[idx]; } } public Mailbox this[string name] { get { return (Mailbox)mNamedList[name.ToUpper()]; } } internal void Add(Mailbox box) { mIndexedList.Add(box); mNamedList.Add(box.Name.ToUpper(), box); } public Mailbox Add(string name) { // TODO: gather the uidvalidity to be unique for this name (suggested in the rfc to have 32-bit representation of day/time) Mailbox mbx = new Mailbox(mProvider, name, name, 1, 1, mUser); if(mProvider.InsertMailbox(mUser, mbx)) { Add(mbx); return mbx; } else return null; } #region IEnumerable public IEnumerator GetEnumerator() { return mIndexedList.GetEnumerator(); } #endregion } } Index: Common.csproj =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Common/Common.csproj,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** Common.csproj 25 Jul 2003 03:39:12 -0000 1.3 --- Common.csproj 27 Jul 2003 19:32:58 -0000 1.4 *************** *** 100,103 **** --- 100,108 ---- /> <File + RelPath = "MailboxCollection.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "Message.cs" SubType = "Code" Index: User.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Common/User.cs,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** User.cs 25 Jul 2003 03:39:12 -0000 1.1 --- User.cs 27 Jul 2003 19:32:58 -0000 1.2 *************** *** 13,16 **** --- 13,17 ---- private string mUsername; private string mPassword; + private MailboxCollection mMailboxes; #endregion *************** *** 38,46 **** } ! public Mailbox[] Mailboxes { get { ! return mMailstoreProvider.GetMailboxes(this); } } --- 39,49 ---- } ! public MailboxCollection Mailboxes { get { ! if(mMailboxes == null) ! mMailboxes = mMailstoreProvider.GetMailboxes(this); ! return mMailboxes; } } |
From: <ta...@us...> - 2003-07-27 17:27:20
|
Update of /cvsroot/csmaild/csmaild/src/Imap/Commands In directory sc8-pr-cvs1:/tmp/cvs-serv1918/src/Imap/Commands Modified Files: SelectExamineCommand.cs Log Message: Oops. Index: SelectExamineCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/SelectExamineCommand.cs,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** SelectExamineCommand.cs 27 Jul 2003 17:26:24 -0000 1.1 --- SelectExamineCommand.cs 27 Jul 2003 17:27:17 -0000 1.2 *************** *** 12,16 **** private bool mIsSelect; // true if we're actually SELECT false if we're EXAMINE ! public SelectExamineCommand(bool isSelect, ImapServer svr) : base(svr, "SELECT", ImapCommand.AuthSelectedState, ArgumentType.AString) { mIsSelect = isSelect; --- 12,16 ---- private bool mIsSelect; // true if we're actually SELECT false if we're EXAMINE ! public SelectExamineCommand(bool isSelect, ImapServer svr) : base(svr, (isSelect ? "SELECT" : "EXAMINE") , ImapCommand.AuthSelectedState, ArgumentType.AString) { mIsSelect = isSelect; |
From: <ta...@us...> - 2003-07-27 17:26:27
|
Update of /cvsroot/csmaild/csmaild/src/Imap/Commands In directory sc8-pr-cvs1:/tmp/cvs-serv1812/src/Imap/Commands Added Files: SelectExamineCommand.cs Removed Files: ExamineCommand.cs SelectCommand.cs Log Message: SELECT and EXAMINE are nearly identical commands so I've combined the handlers into one. --- NEW FILE: SelectExamineCommand.cs --- using Common; using System; namespace Imap.Commands { /// <summary> /// Summary description for SelectExamineCommand. /// </summary> public class SelectExamineCommand : ImapCommand { private bool mIsSelect; // true if we're actually SELECT false if we're EXAMINE public SelectExamineCommand(bool isSelect, ImapServer svr) : base(svr, "SELECT", ImapCommand.AuthSelectedState, ArgumentType.AString) { mIsSelect = isSelect; } override protected bool InternalProcess() { mConnection.Mailbox = Server.MailstoreProvider.GetMailbox(mConnection.User, mParsedArguments[0] as string); if(mConnection.Mailbox == null) { mConnection.State = ImapConnectionState.Authenticated; mConnection.SendTaggedMessage("NO"); } else { mConnection.State = ImapConnectionState.Selected; Mailbox mbx = mConnection.Mailbox; mConnection.SendUntaggedMessage("FLAGS (\\Seen \\Answered \\Flagged \\Deleted \\Draft \\Recent)"); mConnection.SendUntaggedMessage(mbx.MessageCount.ToString() + " EXISTS"); mConnection.SendUntaggedMessage(mbx.MessageRecentCount.ToString() + " RECENT"); if(mbx.FirstUnseenMessageSeqNum != 0) mConnection.SendUntaggedMessage("OK [UNSEEN " + mbx.FirstUnseenMessageSeqNum + "]"); if(mIsSelect) mConnection.SendUntaggedMessage("OK [PERMANENTFLAGS (\\Seen \\Answered \\Flagged \\Deleted \\Draft)]"); else mConnection.SendUntaggedMessage("OK [PERMANENTFLAGS ()]"); mConnection.SendUntaggedMessage("OK [UIDVALIDITY " + mbx.UniqueIdValidity.ToString() + "]"); mConnection.SendUntaggedMessage("OK [UIDNEXT " + mbx.NextUniqueId + "]"); mConnection.SendTaggedMessage(mIsSelect ? "OK [READ-WRITE]" : "OK [READ-ONLY]"); } return true; } } } --- ExamineCommand.cs DELETED --- --- SelectCommand.cs DELETED --- |
From: <ta...@us...> - 2003-07-27 17:26:27
|
Update of /cvsroot/csmaild/csmaild/src/Imap In directory sc8-pr-cvs1:/tmp/cvs-serv1812/src/Imap Modified Files: Imap.csproj Server.cs Log Message: SELECT and EXAMINE are nearly identical commands so I've combined the handlers into one. Index: Imap.csproj =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Imap.csproj,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** Imap.csproj 24 Jul 2003 04:32:14 -0000 1.5 --- Imap.csproj 27 Jul 2003 17:26:22 -0000 1.6 *************** *** 150,158 **** /> <File - RelPath = "Commands\ExamineCommand.cs" - SubType = "Code" - BuildAction = "Compile" - /> - <File RelPath = "Commands\ExpungeCommand.cs" SubType = "Code" --- 150,153 ---- *************** *** 205,209 **** /> <File ! RelPath = "Commands\SelectCommand.cs" SubType = "Code" BuildAction = "Compile" --- 200,204 ---- /> <File ! RelPath = "Commands\SelectExamineCommand.cs" SubType = "Code" BuildAction = "Compile" Index: Server.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Server.cs,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** Server.cs 25 Jul 2003 03:39:12 -0000 1.6 --- Server.cs 27 Jul 2003 17:26:22 -0000 1.7 *************** *** 35,39 **** mImapCommands.Add("CREATE", new CreateCommand(this)); mImapCommands.Add("DELETE", new DeleteCommand(this)); ! mImapCommands.Add("EXAMINE", new ExamineCommand(this)); mImapCommands.Add("EXPUNGE", new ExpungeCommand(this)); mImapCommands.Add("FETCH", new FetchCommand(this)); --- 35,39 ---- mImapCommands.Add("CREATE", new CreateCommand(this)); mImapCommands.Add("DELETE", new DeleteCommand(this)); ! mImapCommands.Add("EXAMINE", new SelectExamineCommand(false, this)); mImapCommands.Add("EXPUNGE", new ExpungeCommand(this)); mImapCommands.Add("FETCH", new FetchCommand(this)); *************** *** 45,49 **** mImapCommands.Add("RENAME", new RenameCommand(this)); mImapCommands.Add("SEARCH", new SearchCommand(this)); ! mImapCommands.Add("SELECT", new SelectCommand(this)); mImapCommands.Add("STARTTLS", new StarttlsCommand(this)); mImapCommands.Add("STATUS", new StatusCommand(this)); --- 45,49 ---- mImapCommands.Add("RENAME", new RenameCommand(this)); mImapCommands.Add("SEARCH", new SearchCommand(this)); ! mImapCommands.Add("SELECT", new SelectExamineCommand(true, this)); mImapCommands.Add("STARTTLS", new StarttlsCommand(this)); mImapCommands.Add("STATUS", new StatusCommand(this)); |
From: <ta...@us...> - 2003-07-27 17:07:08
|
Update of /cvsroot/csmaild/csmaild/src/Imap/Commands In directory sc8-pr-cvs1:/tmp/cvs-serv31192/src/Imap/Commands Modified Files: ImapCommand.cs Log Message: Modified the parsing of the sequence set to include the asterix character. Rewrote it to use regular expressions for easier parsing. Index: ImapCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/ImapCommand.cs,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** ImapCommand.cs 26 Jul 2003 23:55:47 -0000 1.7 --- ImapCommand.cs 27 Jul 2003 17:07:05 -0000 1.8 *************** *** 93,102 **** { // parse and validate the arguments ! if(!ParseArguments() || mUnparsedArgumentIdx < mUnparsedArguments.Length || !InternalProcess()) ! { ! mConnection.SendTaggedMessage("BAD"); ! return false; ! } ! return true; } --- 93,106 ---- { // parse and validate the arguments ! if(!ParseArguments()) ! mConnection.SendTaggedMessage("BAD Invalid arguments"); ! else if(mUnparsedArgumentIdx < mUnparsedArguments.Length) ! mConnection.SendTaggedMessage("BAD Too many arguments"); ! else if(!InternalProcess()) ! mConnection.SendTaggedMessage("BAD Processing problems"); ! else ! return true; ! ! return false; } *************** *** 250,326 **** private SequenceSet ParseSequenceSet() { ! bool isGood = false; // will determine whether we've read a valid quoted string SequenceSet sequenceSet = new SequenceSet(); // will store the sequenceSet string as we "read" it ! uint startNumber = 0; ! uint sequenceNumber = 0; ! for(; mUnparsedArgumentIdx < mUnparsedArguments.Length; ++mUnparsedArgumentIdx) { ! if(sequenceNumber == 0) // haven't started yet, need to read a non-zero digit ! { ! if(CommandPart.DigitNz.IndexOf(mUnparsedArguments[mUnparsedArgumentIdx]) == -1) ! return null; ! else ! { ! sequenceNumber = uint.Parse(mUnparsedArguments[mUnparsedArgumentIdx] + string.Empty); ! isGood = true; ! } ! } ! else if(mUnparsedArguments[mUnparsedArgumentIdx] == ':') // making a range ! { ! isGood = false; ! if(startNumber != 0) // we started a range earlier, can't start another so soon ! return null; ! startNumber = sequenceNumber; ! sequenceNumber = 0; ! } ! else if(mUnparsedArguments[mUnparsedArgumentIdx] == ',') // next sequence set { ! isGood = false; ! if(startNumber != 0) // we started a range earlier { ! sequenceSet.AddRange(startNumber, sequenceNumber); ! startNumber = 0; } - else // make a range of size 1 - sequenceSet.AddRange(sequenceNumber); - sequenceNumber = 0; - } - else if(mUnparsedArguments[mUnparsedArgumentIdx] == '*') // largest possible message - { - if(sequenceNumber != 0) // * can't be part of a number - return null; - sequenceNumber = int.MaxValue; - } - else if(mUnparsedArguments[mUnparsedArgumentIdx] == ' ') // a space, done with the argument - break; - else - { - if(CommandPart.Digit.IndexOf(mUnparsedArguments[mUnparsedArgumentIdx]) == -1) - return null; else ! { ! sequenceNumber *= 10; ! sequenceNumber += uint.Parse(mUnparsedArguments[mUnparsedArgumentIdx] + string.Empty); ! } } ! } ! ! if(isGood) ! { ! // add the last range ! if(startNumber != 0) // we started a range earlier { ! sequenceSet.AddRange(startNumber, sequenceNumber); ! startNumber = 0; } - else // make a range of size 1 - sequenceSet.AddRange(sequenceNumber); ! return sequenceSet; } ! return null; } --- 254,303 ---- private SequenceSet ParseSequenceSet() { ! int endIdx = mUnparsedArguments.IndexOf(' ', mUnparsedArgumentIdx); ! string sequenceSetString = string.Empty; SequenceSet sequenceSet = new SequenceSet(); // will store the sequenceSet string as we "read" it ! if(endIdx == -1) ! sequenceSetString = mUnparsedArguments.Substring(mUnparsedArgumentIdx); ! else ! sequenceSetString = mUnparsedArguments.Substring(mUnparsedArgumentIdx, endIdx - mUnparsedArgumentIdx); ! string[] parts = sequenceSetString.Split(' '); ! foreach(string part in parts) { ! Match m = Regex.Match(part, @"^(?:(?:([1-9][0-9]{0,9})(?::([1-9][0-9]{0,9}|\*))?)|(?:(\*):([1-9][0-9]{0,9})))$"); ! if(!m.Success) ! return null; ! uint startNum = 0; ! uint endNum = 0; ! ! if(m.Groups[1].Success) { ! startNum = uint.Parse(m.Groups[1].Value); ! if(m.Groups[2].Success) { ! if(m.Groups[2].Value == "*") ! endNum = uint.MaxValue; ! else ! endNum = uint.Parse(m.Groups[2].Value); } else ! endNum = startNum; } ! else if(m.Groups[3].Success) { ! if(m.Groups[3].Value == "*") ! startNum = uint.MaxValue; ! else ! startNum = uint.Parse(m.Groups[3].Value); ! endNum = uint.Parse(m.Groups[4].Value); } ! sequenceSet.AddRange(startNum, endNum); } ! mUnparsedArgumentIdx += sequenceSetString.Length; ! ! return sequenceSet; } *************** *** 429,433 **** public override string ToString() { ! return mLow + ":" + mHigh + (mNext != null ? "," + mNext.ToString() : string.Empty); } } --- 406,410 ---- public override string ToString() { ! return mLow + ":" + (mHigh == uint.MaxValue ? "*" : mHigh.ToString()) + (mNext != null ? "," + mNext.ToString() : string.Empty); } } |
From: <ta...@us...> - 2003-07-27 16:52:22
|
Update of /cvsroot/csmaild/csmaild/src/Imap/Commands In directory sc8-pr-cvs1:/tmp/cvs-serv28711/src/Imap/Commands Modified Files: SelectCommand.cs Log Message: MailStoreProvider now requires insertion capabilities of a mailbox Mailbox has some accessor properties for getting some information IMAP likes to send out SELECT command uses new accessors Index: SelectCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/SelectCommand.cs,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** SelectCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 --- SelectCommand.cs 27 Jul 2003 16:52:19 -0000 1.5 *************** *** 1,2 **** --- 1,4 ---- + using Common; + using System; *************** *** 24,34 **** mConnection.State = ImapConnectionState.Selected; mConnection.SendUntaggedMessage("FLAGS (\\Seen \\Answered \\Flagged \\Deleted \\Draft \\Recent)"); ! mConnection.SendUntaggedMessage(mConnection.Mailbox.Messages.Length.ToString() + " EXISTS"); ! mConnection.SendUntaggedMessage("0 RECENT"); ! mConnection.SendUntaggedMessage("OK [UNSEEN 0]"); mConnection.SendUntaggedMessage("OK [PERMANENTFLAGS (\\Seen \\Answered \\Flagged \\Deleted \\Draft)]"); ! mConnection.SendUntaggedMessage("OK [UIDVALIDITY " + mConnection.Mailbox.UniqueIdValidity.ToString() + "]"); ! mConnection.SendUntaggedMessage("OK [UIDNEXT " + mConnection.Mailbox.NextUniqueId + "]"); mConnection.SendTaggedMessage("OK [READ-WRITE]"); } --- 26,41 ---- mConnection.State = ImapConnectionState.Selected; + Mailbox mbx = mConnection.Mailbox; + mConnection.SendUntaggedMessage("FLAGS (\\Seen \\Answered \\Flagged \\Deleted \\Draft \\Recent)"); ! mConnection.SendUntaggedMessage(mbx.MessageCount.ToString() + " EXISTS"); ! mConnection.SendUntaggedMessage(mbx.MessageRecentCount.ToString() + " RECENT"); ! ! if(mbx.FirstUnseenMessageSeqNum != 0) ! mConnection.SendUntaggedMessage("OK [UNSEEN " + mbx.FirstUnseenMessageSeqNum + "]"); ! mConnection.SendUntaggedMessage("OK [PERMANENTFLAGS (\\Seen \\Answered \\Flagged \\Deleted \\Draft)]"); ! mConnection.SendUntaggedMessage("OK [UIDVALIDITY " + mbx.UniqueIdValidity.ToString() + "]"); ! mConnection.SendUntaggedMessage("OK [UIDNEXT " + mbx.NextUniqueId + "]"); mConnection.SendTaggedMessage("OK [READ-WRITE]"); } |
From: <ta...@us...> - 2003-07-27 16:52:22
|
Update of /cvsroot/csmaild/csmaild/src/Common/MailstoreProviders In directory sc8-pr-cvs1:/tmp/cvs-serv28711/src/Common/MailstoreProviders Modified Files: IMailstoreProvider.cs XmlMailstoreProvider.cs Log Message: MailStoreProvider now requires insertion capabilities of a mailbox Mailbox has some accessor properties for getting some information IMAP likes to send out SELECT command uses new accessors Index: IMailstoreProvider.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Common/MailstoreProviders/IMailstoreProvider.cs,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** IMailstoreProvider.cs 25 Jul 2003 03:39:12 -0000 1.2 --- IMailstoreProvider.cs 27 Jul 2003 16:52:19 -0000 1.3 *************** *** 18,21 **** --- 18,23 ---- #endregion + #region Mailbox stuff + #region Mailbox accessors /// <summary> *************** *** 39,42 **** --- 41,50 ---- /// <returns>An array containing the mailboxes (valid array of size 0 if none)</returns> Mailbox[] GetMailboxes(Mailbox parent); + #endregion + + #region Mailbox modifieres + bool InsertMailbox(Mailbox mbx); + #endregion + #endregion Index: XmlMailstoreProvider.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Common/MailstoreProviders/XmlMailstoreProvider.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** XmlMailstoreProvider.cs 25 Jul 2003 23:35:24 -0000 1.3 --- XmlMailstoreProvider.cs 27 Jul 2003 16:52:19 -0000 1.4 *************** *** 34,37 **** --- 34,39 ---- #endregion + #region Mailbox stuff + #region Mailbox accessors public Mailbox GetMailbox(User user, string absoluteHiearchicalName) *************** *** 39,43 **** DataSet ds = new DataSet(); ds.ReadXml(mFolderPath + "Mailboxes.xml"); ! DataRow[] boxes = ds.Tables[0].Select("FullName = '" + absoluteHiearchicalName + "'"); if(boxes.Length == 0) --- 41,45 ---- DataSet ds = new DataSet(); ds.ReadXml(mFolderPath + "Mailboxes.xml"); ! DataRow[] boxes = ds.Tables[0].Select("FullName = '" + absoluteHiearchicalName + "' AND UserIdentifier = '" + user.Username + "'"); if(boxes.Length == 0) *************** *** 47,51 **** return new Mailbox(this, box["Name"] as string, box["FullName"] as string, uint.Parse(box["NextUniqueId"] as string), uint.Parse(box["UniqueIdValidity"] as string), user); } ! public Mailbox[] GetMailboxes(User user) { --- 49,53 ---- return new Mailbox(this, box["Name"] as string, box["FullName"] as string, uint.Parse(box["NextUniqueId"] as string), uint.Parse(box["UniqueIdValidity"] as string), user); } ! public Mailbox[] GetMailboxes(User user) { *************** *** 53,61 **** ds.ReadXml(mFolderPath + "Mailboxes.xml"); ! Mailbox[] boxes = new Mailbox[ds.Tables[0].Rows.Count]; ! for(int idx = 0; idx < boxes.Length; ++idx) { ! DataRow box = ds.Tables[0].Rows[idx]; boxes[idx] = new Mailbox(this, box["Name"] as string, box["FullName"] as string, uint.Parse(box["NextUniqueId"] as string), uint.Parse(box["UniqueIdValidity"] as string), user); } --- 55,64 ---- ds.ReadXml(mFolderPath + "Mailboxes.xml"); ! DataRow[] rows = ds.Tables[0].Select("UserIdentifier = '" + user.Username + "'"); ! Mailbox[] boxes = new Mailbox[rows.Length]; ! for(int idx = 0; idx < rows.Length; ++idx) { ! DataRow box = rows[idx]; boxes[idx] = new Mailbox(this, box["Name"] as string, box["FullName"] as string, uint.Parse(box["NextUniqueId"] as string), uint.Parse(box["UniqueIdValidity"] as string), user); } *************** *** 63,71 **** return boxes; } ! public Mailbox[] GetMailboxes(Mailbox parent) { return null; } #endregion --- 66,96 ---- return boxes; } ! public Mailbox[] GetMailboxes(Mailbox parent) { return null; } + #endregion + + #region Mailbox modifieres + public bool InsertMailbox(Mailbox mbx) + { + DataSet ds = new DataSet(); + ds.ReadXml(mFolderPath + "Mailboxes.xml"); + + DataRow newMbx = ds.Tables[0].NewRow(); + + newMbx["Name"] = mbx.Name; + newMbx["FullName"] = mbx.Name; + newMbx["NextUniqueId"] = mbx.NextUniqueId; + newMbx["UniqueIdValidity"] = mbx.UniqueIdValidity; + + ds.Tables[0].Rows.Add(newMbx); + ds.WriteXml(mFolderPath + "Mailboxes.xml"); + + return true; + } + #endregion + #endregion |
From: <ta...@us...> - 2003-07-27 16:52:22
|
Update of /cvsroot/csmaild/csmaild/src/Common In directory sc8-pr-cvs1:/tmp/cvs-serv28711/src/Common Modified Files: Mailbox.cs Log Message: MailStoreProvider now requires insertion capabilities of a mailbox Mailbox has some accessor properties for getting some information IMAP likes to send out SELECT command uses new accessors Index: Mailbox.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Common/Mailbox.cs,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** Mailbox.cs 25 Jul 2003 23:35:24 -0000 1.4 --- Mailbox.cs 27 Jul 2003 16:52:19 -0000 1.5 *************** *** 67,74 **** return mParent; } - set - { - mParent = value; - } } --- 67,70 ---- *************** *** 82,89 **** return mChildren; } - set - { - mChildren = value; - } } --- 78,81 ---- *************** *** 96,99 **** --- 88,133 ---- { return mMailstoreProvider.GetMessages(this); + } + } + + /// <summary> + /// The number of messages in this mailbox + /// </summary> + public int MessageCount + { + get + { + // TODO: make this more efficient then having to load all the messages + return Messages.Length; + } + } + + /// <summary> + /// The number of messages in this mailbox that have the Recent bit set + /// </summary> + public int MessageRecentCount + { + get + { + // TODO: make this more efficient then having to load all the messages + Message[] msgs = Messages; + int rv = 0; + foreach(Message msg in msgs) + if(msg.Recent) + ++rv; + return rv; + } + } + + public int FirstUnseenMessageSeqNum + { + get + { + // TODO: make this more efficient then having to load all the messages + Message[] msgs = Messages; + for(int idx = 0; idx < msgs.Length; ++idx) + if(!msgs[idx].Seen) + return idx; + return 0; } } |
From: <ta...@us...> - 2003-07-27 16:50:50
|
Update of /cvsroot/csmaild/csmaild/src/Engine/bin In directory sc8-pr-cvs1:/tmp/cvs-serv28443/src/Engine/bin Added Files: .cvsignore Log Message: Added sample mail store, changed reference of the server engine to load the sample --- NEW FILE: .cvsignore --- Debug |
From: <ta...@us...> - 2003-07-27 16:50:50
|
Update of /cvsroot/csmaild/csmaild/src/Engine/bin/SampleXmlMailstore In directory sc8-pr-cvs1:/tmp/cvs-serv28443/src/Engine/bin/SampleXmlMailstore Added Files: Mailboxes.xml Messages.xml Users.xml Log Message: Added sample mail store, changed reference of the server engine to load the sample --- NEW FILE: Mailboxes.xml --- <?xml version="1.0" standalone="yes" ?> <Mailstore> <Mailboxes> <UserIdentifier>csmaild_test</UserIdentifier> <Name>INBOX</Name> <FullName>INBOX</FullName> <NextUniqueId>1</NextUniqueId> <UniqueIdValidity>1</UniqueIdValidity> </Mailboxes> <Mailboxes> <Username>csmaild_test</Username> <Name>Drafts</Name> <FullName>Drafts</FullName> <NextUniqueId>1</NextUniqueId> <UniqueIdValidity>1</UniqueIdValidity> </Mailboxes> <Mailboxes> <UserIdentifier>csmaild_test</UserIdentifier> <Name>Sent Items</Name> <FullName>Sent Items</FullName> <NextUniqueId>1</NextUniqueId> <UniqueIdValidity>1</UniqueIdValidity> </Mailboxes> </Mailstore> --- NEW FILE: Messages.xml --- <?xml version="1.0" standalone="yes" ?> <Mailstore> <Messages> <MailboxIdentifier>INBOX</MailboxIdentifier> <UniqueIdentifier>1</UniqueIdentifier> <Seen>True</Seen> <Answered>False</Answered> <Flagged>False</Flagged> <Deleted>False</Deleted> <Draft>False</Draft> <Size>0</Size> </Messages> </Mailstore> --- NEW FILE: Users.xml --- <?xml version="1.0" standalone="yes" ?> <Mailstore> <Users> <Username>csmaild_test</Username> <Password>csmaild_test</Password> </Users> </Mailstore> |
From: <ta...@us...> - 2003-07-27 16:50:50
|
Update of /cvsroot/csmaild/csmaild/src/Engine In directory sc8-pr-cvs1:/tmp/cvs-serv28443/src/Engine Modified Files: .cvsignore Engine.cs Log Message: Added sample mail store, changed reference of the server engine to load the sample Index: .cvsignore =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Engine/.cvsignore,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** .cvsignore 25 Jul 2003 14:50:31 -0000 1.2 --- .cvsignore 27 Jul 2003 16:50:46 -0000 1.3 *************** *** 1,3 **** *.csproj.user - bin obj --- 1,2 ---- Index: Engine.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Engine/Engine.cs,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** Engine.cs 24 Jul 2003 04:32:13 -0000 1.4 --- Engine.cs 27 Jul 2003 16:50:46 -0000 1.5 *************** *** 26,30 **** System.Diagnostics.Trace.Listeners.Add(tWriter); ! ImapServer svr = new ImapServer(new XmlMailstoreProvider(@"C:\Mailstore")); svr.Start(); --- 26,30 ---- System.Diagnostics.Trace.Listeners.Add(tWriter); ! ImapServer svr = new ImapServer(new XmlMailstoreProvider(@"..\SampleXmlMailstore")); svr.Start(); |
From: <ta...@us...> - 2003-07-27 16:49:59
|
Update of /cvsroot/csmaild/csmaild/src/Engine/bin/SampleXmlMailstore In directory sc8-pr-cvs1:/tmp/cvs-serv28258/SampleXmlMailstore Log Message: Directory /cvsroot/csmaild/csmaild/src/Engine/bin/SampleXmlMailstore added to the repository |
From: <ta...@us...> - 2003-07-27 16:49:55
|
Update of /cvsroot/csmaild/csmaild/src/Engine/bin In directory sc8-pr-cvs1:/tmp/cvs-serv28241/bin Log Message: Directory /cvsroot/csmaild/csmaild/src/Engine/bin added to the repository |
From: <ta...@us...> - 2003-07-27 05:00:39
|
Update of /cvsroot/csmaild/csmaild/docs/rfcs/imap In directory sc8-pr-cvs1:/tmp/cvs-serv16320/docs/rfcs/imap Added Files: 2180 - Multi-Accessed Mailbox Practice.txt Log Message: Interesting read, seeing as we'll want to implement it ;). --- NEW FILE: 2180 - Multi-Accessed Mailbox Practice.txt --- Network Working Group M. Gahrns Request for Comments: 2180 Microsoft Category: Informational July 1997 IMAP4 Multi-Accessed Mailbox Practice Status of this Memo This memo provides information for the Internet community. This memo does not specify an Internet standard of any kind. Distribution of this memo is unlimited. 1. Abstract IMAP4[RFC-2060] is rich client/server protocol that allows a client to access and manipulate electronic mail messages on a server. Within the protocol framework, it is possible to have differing results for particular client/server interactions. If a protocol does not allow for this, it is often unduly restrictive. For example, when multiple clients are accessing a mailbox and one attempts to delete the mailbox, an IMAP4 server may choose to implement a solution based upon server architectural constraints or individual preference. With this flexibility comes greater client responsibility. It is not sufficient for a client to be written based upon the behavior of a particular IMAP server. Rather the client must be based upon the behavior allowed by the protocol. By documenting common IMAP4 server practice for the case of simultaneous client access to a mailbox, we hope to ensure the widest amount of inter-operation between IMAP4 clients and servers. The behavior described in this document reflects the practice of some existing servers or behavior that the consensus of the IMAP mailing list has deemed to be reasonable. The behavior described within this document is believed to be [RFC-2060] compliant. However, this document is not meant to define IMAP4 compliance, nor is it an exhaustive list of valid IMAP4 behavior. [RFC-2060] must always be consulted to determine IMAP4 compliance, especially for server behavior not described within this document. Gahrns Informational [Page 1] RFC 2180 IMAP4 Multi-Accessed Mailbox Practice July 1997 2. Conventions used in this document In examples,"C1:", "C2:" and "C3:" indicate lines sent by 3 different clients (client #1, client #2 and client #3) that are connected to a server. "S1:", "S2:" and "S3:" indicated lines sent by the server to client #1, client #2 and client #3 respectively. A shared mailbox, is a mailbox that can be used by multiple users. A multi-accessed mailbox, is a mailbox that has multiple clients simultaneously accessing it. A client is said to have accessed a mailbox after a successful SELECT or EXAMINE command. The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC-2119]. 3. Deletion/Renaming of a multi-accessed mailbox If an external agent or multiple clients are accessing a mailbox, care must be taken when handling the deletion or renaming of the mailbox. Following are some strategies an IMAP server may choose to use when dealing with this situation. 3.1. The server MAY fail the DELETE/RENAME command of a multi-accessed mailbox In some cases, this behavior may not be practical. For example, if a large number of clients are accessing a shared mailbox, the window in which no clients have the mailbox accessed may be small or non- existent, effectively rendering the mailbox undeletable or unrenamable. Example: <Client #1 and Client #2 have mailbox FOO accessed. Client #1 tries to DELETE the mailbox and is refused> C1: A001 DELETE FOO S1: A001 NO Mailbox FOO is in use by another user. Gahrns Informational [Page 2] RFC 2180 IMAP4 Multi-Accessed Mailbox Practice July 1997 3.2. The server MAY allow the DELETE command of a multi-accessed mailbox, but keep the information in the mailbox available for those clients that currently have access to the mailbox. When all clients have finished accessing the mailbox, it is permanently removed. For clients that do not already have access to the mailbox, the 'ghosted' mailbox would not be available. For example, it would not be returned to these clients in a subsequent LIST or LSUB command and would not be a valid mailbox argument to any other IMAP command until the reference count of clients accessing the mailbox reached 0. In some cases, this behavior may not be desirable. For example if someone created a mailbox with offensive or sensitive information, one might prefer to have the mailbox deleted and all access to the information contained within removed immediately, rather than continuing to allow access until the client closes the mailbox. Furthermore, this behavior, may prevent 'recycling' of the same mailbox name until all clients have finished accessing the original mailbox. Example: <Client #1 and Client #2 have mailbox FOO selected. Client #1 DELETEs mailbox FOO> C1: A001 DELETE FOO S1: A001 OK Mailbox FOO is deleted. <Client #2 is still able to operate on the deleted mailbox> C2: B001 STORE 1 +FLAGS (\Seen) S2: * 1 FETCH FLAGS (\Seen) S2: B001 OK STORE completed <Client #3 which did not have access to the mailbox prior to the deletion by client #1 does not have access to the mailbox> C3: C001 STATUS FOO (MESSAGES) S3: C001 NO Mailbox does not exist <Nor is client #3 able to create a mailbox with the name FOO, while the reference count is non zero> C3: C002 CREATE FOO S3: C002 NO Mailbox FOO is still in use. Try again later. Gahrns Informational [Page 3] RFC 2180 IMAP4 Multi-Accessed Mailbox Practice July 1997 <Client #2 closes its access to the mailbox, no other clients have access to the mailbox FOO and reference count becomes 0> C2: B002 CLOSE S2: B002 OK CLOSE Completed <Now that the reference count on FOO has reached 0, the mailbox name can be recycled> C3: C003 CREATE FOO S3: C003 OK CREATE Completed 3.3. The server MAY allow the DELETE/RENAME of a multi-accessed mailbox, but disconnect all other clients who have the mailbox accessed by sending a untagged BYE response. A server may often choose to disconnect clients in the DELETE case, but may choose to implement a "friendlier" method for the RENAME case. Example: <Client #1 and Client #2 have mailbox FOO accessed. Client #1 DELETEs the mailbox FOO> C1: A002 DELETE FOO S1: A002 OK DELETE completed. <Server disconnects all other users of the mailbox> S2: * BYE Mailbox FOO has been deleted. 3.4. The server MAY allow the RENAME of a multi-accessed mailbox by simply changing the name attribute on the mailbox. Other clients that have access to the mailbox can continue issuing commands such as FETCH that do not reference the mailbox name. Clients would discover the renaming the next time they referred to the old mailbox name. Some servers MAY choose to include the [NEWNAME] response code in their tagged NO response to a command that contained the old mailbox name, as a hint to the client that the operation can succeed if the command is issued with the new mailbox name. Gahrns Informational [Page 4] RFC 2180 IMAP4 Multi-Accessed Mailbox Practice July 1997 Example: <Client #1 and Client #2 have mailbox FOO accessed. Client #1 RENAMEs the mailbox.> C1: A001 RENAME FOO BAR S1: A001 OK RENAME completed. <Client #2 is still able to do operations that do not reference the mailbox name> C2: B001 FETCH 2:4 (FLAGS) S2: * 2 FETCH . . . S2: * 3 FETCH . . . S2: * 4 FETCH . . . S2: B001 OK FETCH completed <Client #2 is not able to do operations that reference the mailbox name> C2: B002 APPEND FOO {300} C2: Date: Mon, 7 Feb 1994 21:52:25 0800 (PST) C2: . . . S2: B002 NO [NEWNAME FOO BAR] Mailbox has been renamed 4. Expunging of messages on a multi-accessed mailbox If an external agent or multiple clients are accessing a mailbox, care must be taken when handling the EXPUNGE of messages. Other clients accessing the mailbox may be in the midst of issuing a command that depends upon message sequence numbers. Because an EXPUNGE response can not be sent while responding to a FETCH, STORE or SEARCH command, it is not possible to immediately notify the client of the EXPUNGE. This can result in ambiguity if the client issues a FETCH, STORE or SEARCH operation on a message that has been EXPUNGED. 4.1. Fetching of expunged messages Following are some strategies an IMAP server may choose to use when dealing with a FETCH command on expunged messages. Gahrns Informational [Page 5] RFC 2180 IMAP4 Multi-Accessed Mailbox Practice July 1997 Consider the following scenario: - Client #1 and Client #2 have mailbox FOO selected. - There are 7 messages in the mailbox. - Messages 4:7 are marked for deletion. - Client #1 issues an EXPUNGE, to expunge messages 4:7 4.1.1. The server MAY allow the EXPUNGE of a multi-accessed mailbox but keep the messages available to satisfy subsequent FETCH commands until it is able to send an EXPUNGE response to each client. In some cases, the behavior of keeping "ghosted" messages may not be desirable. For example if a message contained offensive or sensitive information, one might prefer to instantaneously remove all access to the information, regardless of whether another client is in the midst of accessing it. Example: (Building upon the scenario outlined in 4.1.) <Client #2 is still able to access the expunged messages because the server has kept a 'ghosted' copy of the messages until it is able to notify client #2 of the EXPUNGE> C2: B001 FETCH 4:7 RFC822 S2: * 4 FETCH RFC822 . . . (RFC822 info returned) S2: * 5 FETCH RFC822 . . . (RFC822 info returned) S2: * 6 FETCH RFC822 . . . (RFC822 info returned) S2: * 7 FETCH RFC822 . . . (RFC822 info returned) S2: B001 OK FETCH Completed <Client #2 issues a command where it can get notified of the EXPUNGE> C2: B002 NOOP S2: * 4 EXPUNGE S2: * 4 EXPUNGE S2: * 4 EXPUNGE S2: * 4 EXPUNGE S2: * 3 EXISTS S2: B002 OK NOOP Complete <Client #2 no longer has access to the expunged messages> C2: B003 FETCH 4:7 RFC822 S2: B003 NO Messages 4:7 are no longer available. Gahrns Informational [Page 6] RFC 2180 IMAP4 Multi-Accessed Mailbox Practice July 1997 4.1.2 The server MAY allow the EXPUNGE of a multi-accessed mailbox, and on subsequent FETCH commands return FETCH responses only for non-expunged messages and a tagged NO. After receiving a tagged NO FETCH response, the client SHOULD issue a NOOP command so that it will be informed of any pending EXPUNGE responses. The client may then either reissue the failed FETCH command, or by examining the EXPUNGE response from the NOOP and the FETCH response from the FETCH, determine that the FETCH failed because of pending expunges. Example: (Building upon the scenario outlined in 4.1.) <Client #2 attempts to FETCH a mix of expunged and non-expunged messages. A FETCH response is returned only for then non-expunged messages along with a tagged NO> C2: B001 FETCH 3:5 ENVELOPE S2: * 3 FETCH ENVELOPE . . . (ENVELOPE info returned) S2: B001 NO Some of the requested messages no longer exist <Upon receiving a tagged NO FETCH response, Client #2 issues a NOOP to be informed of any pending EXPUNGE responses> C2: B002 NOOP S2: * 4 EXPUNGE S2: * 4 EXPUNGE S2: * 4 EXPUNGE S2: * 4 EXPUNGE S2: * 3 EXISTS S2: B002 OK NOOP Completed. <By receiving a FETCH response for message 3, and an EXPUNGE response that indicates messages 4:7 have been expunged, the client does not need to re-issue the FETCH> Gahrns Informational [Page 7] RFC 2180 IMAP4 Multi-Accessed Mailbox Practice July 1997 4.1.3 The server MAY allow the EXPUNGE of a multi-accessed mailbox, and on subsequent FETCH commands return the usual FETCH responses for non-expunged messages, "NIL FETCH Responses" for expunged messages, and a tagged OK response. If all of the messages in the subsequent FETCH command have been expunged, the server SHOULD return only a tagged NO. In this case, the client SHOULD issue a NOOP command so that it will be informed of any pending EXPUNGE responses. The client may then either reissue the failed FETCH command, or by examining the EXPUNGE response from the NOOP, determine that the FETCH failed because of pending expunges. "NIL FETCH responses" are a representation of empty data as appropriate for the FETCH argument specified. Example: * 1 FETCH (ENVELOPE (NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)) * 1 FETCH (FLAGS ()) * 1 FETCH (INTERNALDATE "00-Jan-0000 00:00:00 +0000") * 1 FETCH (RFC822 "") * 1 FETCH (RFC822.HEADER "") * 1 FETCH (RFC822.TEXT "") * 1 FETCH (RFC822.SIZE 0) * 1 FETCH (BODY ("TEXT" "PLAIN" NIL NIL NIL "7BIT" 0 0) * 1 FETCH (BODYSTRUCTURE ("TEXT" "PLAIN" NIL NIL NIL "7BIT" 0 0) * 1 FETCH (BODY[<section>] "") * 1 FETCH (BODY[<section>]<partial> "") In some cases, a client may not be able to distinguish between "NIL FETCH responses" received because a message was expunged and those received because the data actually was NIL. For example, a * 5 FETCH (FLAGS ()) response could be received if no flags were set on message 5, or because message 5 was expunged. In a case of potential ambiguity, the client SHOULD issue a command such as NOOP to force the sending of the EXPUNGE responses to resolve any ambiguity. Example: (Building upon the scenario outlined in 4.1.) <Client #2 attempts to access a mix of expunged and non-expunged messages. Normal data is returned for non-expunged message, "NIL FETCH responses" are returned for expunged messages> Gahrns Informational [Page 8] RFC 2180 IMAP4 Multi-Accessed Mailbox Practice July 1997 C2: B002 FETCH 3:5 ENVELOPE S2: * 3 FETCH ENVELOPE . . . (ENVELOPE info returned) S2: * 4 FETCH ENVELOPE (NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL) S2: * 5 FETCH ENVELOPE (NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL) S2: B002 OK FETCH Completed <Client #2 attempts to FETCH only expunged messages and receives a tagged NO response> C2: B002 FETCH 4:7 ENVELOPE S2: B002 NO Messages 4:7 have been expunged. 4.1.4 To avoid the situation altogether, the server MAY fail the EXPUNGE of a multi-accessed mailbox In some cases, this behavior may not be practical. For example, if a large number of clients are accessing a shared mailbox, the window in which no clients have the mailbox accessed may be small or non- existent, effectively rendering the message unexpungeable. 4.2. Storing of expunged messages Following are some strategies an IMAP server may choose to use when dealing with a STORE command on expunged messages. 4.2.1 If the ".SILENT" suffix is used, and the STORE completed successfully for all the non-expunged messages, the server SHOULD return a tagged OK. Example: (Building upon the scenario outlined in 4.1.) <Client #2 tries to silently STORE flags on expunged and non- expunged messages. The server sets the flags on the non-expunged messages and returns OK> C2: B001 STORE 1:7 +FLAGS.SILENT (\SEEN) S2: B001 OK Gahrns Informational [Page 9] RFC 2180 IMAP4 Multi-Accessed Mailbox Practice July 1997 4.2.2. If the ".SILENT" suffix is not used, and only expunged messages are referenced, the server SHOULD return only a tagged NO. Example: (Building upon the scenario outlined in 4.1.) <Client #2 tries to STORE flags only on expunged messages> C2: B001 STORE 5:7 +FLAGS (\SEEN) S2: B001 NO Messages have been expunged 4.2.3. If the ".SILENT" suffix is not used, and a mixture of expunged and non-expunged messages are referenced, the server MAY set the flags and return a FETCH response for the non-expunged messages along with a tagged NO. After receiving a tagged NO STORE response, the client SHOULD issue a NOOP command so that it will be informed of any pending EXPUNGE responses. The client may then either reissue the failed STORE command, or by examining the EXPUNGE responses from the NOOP and FETCH responses from the STORE, determine that the STORE failed because of pending expunges. Example: (Building upon the scenario outlined in 4.1.) <Client #2 tries to STORE flags on a mixture of expunged and non- expunged messages> C2: B001 STORE 1:7 +FLAGS (\SEEN) S2: * FETCH 1 FLAGS (\SEEN) S2: * FETCH 2 FLAGS (\SEEN) S2: * FETCH 3 FLAGS (\SEEN) S2: B001 NO Some of the messages no longer exist. C2: B002 NOOP S2: * 4 EXPUNGE S2: * 4 EXPUNGE S2: * 4 EXPUNGE S2: * 4 EXPUNGE S2: * 3 EXISTS S2: B002 OK NOOP Completed. <By receiving FETCH responses for messages 1:3, and an EXPUNGE response that indicates messages 4:7 have been expunged, the client does not need to re-issue the STORE> Gahrns Informational [Page 10] RFC 2180 IMAP4 Multi-Accessed Mailbox Practice July 1997 4.2.4. If the ".SILENT" suffix is not used, and a mixture of expunged and non-expunged messages are referenced, the server MAY return an untagged NO and not set any flags. After receiving a tagged NO STORE response, the client SHOULD issue a NOOP command so that it will be informed of any pending EXPUNGE responses. The client would then re-issue the STORE command after updating its message list per any EXPUNGE response. If a large number of clients are accessing a shared mailbox, the window in which there are no pending expunges may be small or non- existent, effectively disallowing a client from setting the flags on all messages at once. Example: (Building upon the scenario outlined in 4.1.) <Client #2 tries to STORE flags on a mixture of expunged and non- expunged messages> C2: B001 STORE 1:7 +FLAGS (\SEEN) S2: B001 NO Some of the messages no longer exist. <Client #2 issues a NOOP to be informed of the EXPUNGED messages> C2: B002 NOOP S2: * 4 EXPUNGE S2: * 4 EXPUNGE S2: * 4 EXPUNGE S2: * 4 EXPUNGE S2: * 3 EXISTS S2: B002 OK NOOP Completed. <Client #2 updates its message list and re-issues the STORE on only those messages that have not been expunged> C2: B003 STORE 1:3 +FLAGS (\SEEN) S2: * FETCH 1 FLAGS (\SEEN) S2: * FETCH 2 FLAGS (\SEEN) S2: * FETCH 3 FLAGS (\SEEN) S2: B003 OK STORE Completed 4.3. Searching of expunged messages A server MAY simply not return a search response for messages that have been expunged and it has not been able to inform the client about. If a client was expecting a particular message to be returned in a search result, and it was not, the client SHOULD issue a NOOP command to see if the message was expunged by another client. Gahrns Informational [Page 11] RFC 2180 IMAP4 Multi-Accessed Mailbox Practice July 1997 4.4 Copying of expunged messages COPY is the only IMAP4 sequence number command that is safe to allow an EXPUNGE response on. This is because a client is not permitted to cascade several COPY commands together. A client is required to wait and confirm that the copy worked before issuing another one. 4.4.1 The server MAY disallow the COPY of messages in a multi-access mailbox that contains expunged messages. Pending EXPUNGE response(s) MUST be returned to the COPY command. Example: C: A001 COPY 2,4,6,8 FRED S: * 4 EXPUNGE S: A001 NO COPY rejected, because some of the requested messages were expunged Note: Non of the above messages are copied because if a COPY command is unsuccessful, the server MUST restore the destination mailbox to its state before the COPY attempt. 4.4.2 The server MAY allow the COPY of messages in a multi-access mailbox that contains expunged messages. Pending EXPUNGE response(s) MUST be returned to the COPY command. Messages that are copied are messages corresponding to sequence numbers before any EXPUNGE response. Example: C: A001 COPY 2,4,6,8 FRED S: * 3 EXPUNGE S: A001 OK COPY completed In the above example, the messages that are copied to FRED are messages 2,4,6,8 at the start of the COPY command. These are equivalent to messages 2,3,5,7 at the end of the COPY command. The EXPUNGE response can't take place until after the messages from the COPY command are identified (because of the "no expunge while no commands in progress" rule). Gahrns Informational [Page 12] RFC 2180 IMAP4 Multi-Accessed Mailbox Practice July 1997 Example: C: A001 COPY 2,4,6,8 FRED S: * 4 EXPUNGE S: A001 OK COPY completed In the above example, message 4 was copied before it was expunged, and MUST appear in the destination mailbox FRED. 5. Security Considerations This document describes behavior of servers that use the IMAP4 protocol, and as such, has the same security considerations as described in [RFC-2060]. In particular, some described server behavior does not allow for the immediate deletion of information when a mailbox is accessed by multiple clients. This may be a consideration when dealing with sensitive information where immediate deletion would be preferred. 6. References [RFC-2060], Crispin, M., "Internet Message Access Protocol - Version 4rev1", RFC 2060, University of Washington, December 1996. [RFC-2119], Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", RFC 2119, Harvard University, March 1997. 7. Acknowledgments This document is the result of discussions on the IMAP4 mailing list and is meant to reflect consensus of this group. In particular, Raymond Cheng, Mark Crispin, Jim Evans, Erik Forsberg, Steve Hole, Mark Keasling, Barry Leiba, Syd Logan, John Mani, Pat Moran, Larry Osterman, Chris Newman, Bart Schaefer, Vladimir Vulovic, and Jack De Winter were active participants in this discussion or made suggestions to this document. Gahrns Informational [Page 13] RFC 2180 IMAP4 Multi-Accessed Mailbox Practice July 1997 8. Author's Address Mike Gahrns Microsoft One Microsoft Way Redmond, WA, 98072 Phone: (206) 936-9833 EMail: mi...@mi... Gahrns Informational [Page 14] |
From: <ta...@us...> - 2003-07-26 23:55:50
|
Update of /cvsroot/csmaild/csmaild/src/Imap/Commands In directory sc8-pr-cvs1:/tmp/cvs-serv6574/src/Imap/Commands Modified Files: FetchCommand.cs ImapCommand.cs Log Message: FETCH *should* be working, more testing to ensue but need to eat. Oh, did I mention that the code fricken sucks and it should be rewritten, but it works for now ;) Index: FetchCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/FetchCommand.cs,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** FetchCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 --- FetchCommand.cs 26 Jul 2003 23:55:47 -0000 1.5 *************** *** 1,4 **** --- 1,5 ---- using System; using System.Collections; + using System.Text.RegularExpressions; namespace Imap.Commands *************** *** 19,23 **** { mConnection.SendUntaggedMessage(mParsedArguments[0].ToString()); ! mConnection.SendTaggedMessage(mParsedArguments[1].ToString()); if(mParsedArguments[1] is string) --- 20,24 ---- { mConnection.SendUntaggedMessage(mParsedArguments[0].ToString()); ! mConnection.SendUntaggedMessage(mParsedArguments[1].ToString()); if(mParsedArguments[1] is string) *************** *** 33,37 **** if(parts != null) { ! // process fetch } else --- 34,38 ---- if(parts != null) { ! mConnection.SendTaggedMessage("OK"); } else *************** *** 123,127 **** private FetchParts ParseBodySection(FetchParts rv, string section) { - bool isGood = false; int idx = 0; if(CommandPart.DigitNz.IndexOf(section[idx]) != -1) // a section part --- 124,127 ---- *************** *** 181,185 **** if(!ParseHeaderList(rv.BodySectionPartHeaderFields)) return null; ! ++mListIdx; // move into closing item break; case "HEADER.FIELDS.NOT": --- 181,186 ---- if(!ParseHeaderList(rv.BodySectionPartHeaderFields)) return null; ! section = mList[++mListIdx].ToString(); ! idx = -1; break; case "HEADER.FIELDS.NOT": *************** *** 187,194 **** if(!ParseHeaderList(rv.BodySectionPartHeaderFieldsNot)) return null; ! ++mListIdx; // move into closing item break; default: ! return null; } } --- 188,200 ---- if(!ParseHeaderList(rv.BodySectionPartHeaderFieldsNot)) return null; ! section = mList[++mListIdx].ToString(); ! idx = -1; break; default: ! if(section[idx] != ']') ! return null; ! else ! ++idx; ! break; } } *************** *** 198,205 **** else // must be a named section { - // section-msgtext = "HEADER" / "HEADER.FIELDS" [".NOT"] SP header-list / "TEXT" ; top-level or MESSAGE/RFC822 part - // header-fld-name = astring - // header-list = "(" header-fld-name *(SP header-fld-name) ")" - string left = section.Substring(idx); switch(left) --- 204,207 ---- *************** *** 217,221 **** if(!ParseHeaderList(rv.BodySectionPartHeaderFields)) return null; ! ++mListIdx; // move into closing item break; case "HEADER.FIELDS.NOT": --- 219,228 ---- if(!ParseHeaderList(rv.BodySectionPartHeaderFields)) return null; ! section = mList[++mListIdx].ToString(); ! idx = 0; ! if(section[idx] != ']') ! return null; ! else ! ++idx; break; case "HEADER.FIELDS.NOT": *************** *** 223,243 **** if(!ParseHeaderList(rv.BodySectionPartHeaderFieldsNot)) return null; ! ++mListIdx; // move into closing item break; default: ! return null; } } ! // ["<" number "." nz-number ">"] ! // if(isGood && idx < pieceOfItem.Length) ! // { ! // if(pieceOfItem[idx] == '<') ! // { ! // // TODO: this ! // } ! // else // if their is more, and it's not this, oops ! // return null; ! // } return rv; --- 230,267 ---- if(!ParseHeaderList(rv.BodySectionPartHeaderFieldsNot)) return null; ! section = mList[++mListIdx].ToString(); ! idx = 0; ! if(section[idx] != ']') ! return null; ! else ! ++idx; break; default: ! if(section[idx] != ']') ! return null; ! else ! ++idx; ! break; } } ! // ["<" number "." nz-number ">"] ! if(idx < section.Length) ! { ! if(section[idx] == '<' && section[section.Length-1] == '>') ! { ! string offsetLengthString = section.Substring(idx+1, section.Length-idx-2); ! Match match = Regex.Match(offsetLengthString, @"^([0-9]{0,10}).([1-9][0-9]{0,9})$"); ! if(!match.Success) ! return null; ! ! // TODO: some where we need to make sure that this isn't bigger then uint.Max (4,294,967,295) before we put it into the variable ! rv.BodySectionOffsetLength = true; ! rv.BodySectionOffset = uint.Parse(match.Groups[1].ToString()); ! rv.BodySectionLength = uint.Parse(match.Groups[2].ToString()); ! } ! else // if their is more, and it's not this, oops ! return null; ! } return rv; *************** *** 246,250 **** private bool ParseHeaderList(ArrayList destinationList) { ! return true; } --- 270,287 ---- private bool ParseHeaderList(ArrayList destinationList) { ! if(mList[mListIdx].IsNestedList) ! { ! ParenthesizedList headerList = mList[mListIdx].NestedList; ! for(int idx = 0; idx < headerList.Count; ++idx) ! { ! if(headerList[idx].IsNestedList) ! return false; ! else ! destinationList.Add(headerList[idx].ToString()); ! } ! return true; ! } ! else ! return false; } *************** *** 253,256 **** --- 290,297 ---- public bool Body; public bool BodyPeek; + + public bool BodySectionOffsetLength; + public uint BodySectionOffset; + public uint BodySectionLength; private ArrayList mBodySectionParts; // TODO: make this a strongly typed for ints Index: ImapCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/ImapCommand.cs,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** ImapCommand.cs 26 Jul 2003 23:09:25 -0000 1.6 --- ImapCommand.cs 26 Jul 2003 23:55:47 -0000 1.7 *************** *** 528,531 **** --- 528,539 ---- } + public bool IsNestedList + { + get + { + return (mNestedList != null); + } + } + public ParenthesizedListItem(object data) { |
From: <ta...@us...> - 2003-07-26 23:55:50
|
Update of /cvsroot/csmaild/csmaild/src/TestClient/bin In directory sc8-pr-cvs1:/tmp/cvs-serv6574/src/TestClient/bin Modified Files: Commands.xml Log Message: FETCH *should* be working, more testing to ensue but need to eat. Oh, did I mention that the code fricken sucks and it should be rewritten, but it works for now ;) Index: Commands.xml =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/TestClient/bin/Commands.xml,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** Commands.xml 26 Jul 2003 23:09:25 -0000 1.3 --- Commands.xml 26 Jul 2003 23:55:47 -0000 1.4 *************** *** 31,34 **** --- 31,38 ---- <Commands> <Command>4 FETCH 1 (BODY[HEADER.FIELDS (To From)])</Command> + <Process>False</Process> + </Commands> + <Commands> + <Command>5 FETCH 1 (BODY[]<0.1500>)</Command> <Process>True</Process> </Commands> |
Update of /cvsroot/csmaild/csmaild/src/Imap/Commands In directory sc8-pr-cvs1:/tmp/cvs-serv31922/src/Imap/Commands Modified Files: AppendCommand.cs AuthenticateCommand.cs CapabilityCommand.cs CheckCommand.cs CloseCommand.cs CommandPart.cs CopyCommand.cs CreateCommand.cs DeleteCommand.cs ExamineCommand.cs ExpungeCommand.cs FetchCommand.cs ImapCommand.cs ListCommand.cs LoginCommand.cs LogoutCommand.cs LsubCommand.cs NoopCommand.cs RenameCommand.cs SearchCommand.cs SelectCommand.cs StarttlsCommand.cs StatusCommand.cs StoreCommand.cs SubscribeCommand.cs UidCommand.cs UnsubscribeCommand.cs Log Message: Modified network model to be asynchronous for idle times and synchronous during the processing of the command. This cleans up the code a bit, while still keeping some of the theoretical benefits of doing it asynchronously. Reworked some of the argument parsing Started work on the FETCH command The test client got some work to, nothing significant yet. Index: AppendCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/AppendCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** AppendCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- AppendCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 12,21 **** } ! override protected void InternalProcess() { ! mConnection.SendTaggedMessage("BAD"); ! ! // done ! mConnection.ReadCommand(); } } --- 12,18 ---- } ! override protected bool InternalProcess() { ! return false; } } Index: AuthenticateCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/AuthenticateCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** AuthenticateCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- AuthenticateCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 12,21 **** } ! override protected void InternalProcess() { ! mConnection.SendTaggedMessage("BAD"); ! ! // done ! mConnection.ReadCommand(); } } --- 12,18 ---- } ! override protected bool InternalProcess() { ! return false; } } Index: CapabilityCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/CapabilityCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** CapabilityCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- CapabilityCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 13,20 **** } ! override protected void InternalProcess() { StringBuilder sb = new StringBuilder(); ! sb.Append("* CAPABILITY "); for(int idx=0; idx < Server.Capabilities.Length; ++idx) --- 13,20 ---- } ! override protected bool InternalProcess() { StringBuilder sb = new StringBuilder(); ! sb.Append("CAPABILITY "); for(int idx=0; idx < Server.Capabilities.Length; ++idx) *************** *** 25,33 **** sb.Append(" "); } ! mConnection.Connection.WriteLine(sb.ToString()); mConnection.SendTaggedMessage("OK CAPABILITY completed"); ! // done ! mConnection.ReadCommand(); } } --- 25,33 ---- sb.Append(" "); } ! mConnection.SendUntaggedMessage(sb.ToString()); ! mConnection.SendTaggedMessage("OK CAPABILITY completed"); ! return true; } } Index: CheckCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/CheckCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** CheckCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- CheckCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 12,21 **** } ! override protected void InternalProcess() { ! mConnection.SendTaggedMessage("BAD"); ! ! // done ! mConnection.ReadCommand(); } } --- 12,18 ---- } ! override protected bool InternalProcess() { ! return false; } } Index: CloseCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/CloseCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** CloseCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- CloseCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 12,21 **** } ! override protected void InternalProcess() { ! mConnection.SendTaggedMessage("BAD"); ! ! // done ! mConnection.ReadCommand(); } } --- 12,18 ---- } ! override protected bool InternalProcess() { ! return false; } } Index: CommandPart.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/CommandPart.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** CommandPart.cs 25 Jul 2003 03:39:12 -0000 1.3 --- CommandPart.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 5,15 **** namespace Imap.Commands { ! /// <summary> ! /// Base class for all command part types ! /// </summary> ! abstract public class CommandPart { ! abstract override public string ToString(); ! abstract public void Parse(TextReader input); #region 'Valid characters for different string types' definitions --- 5,14 ---- namespace Imap.Commands { ! public class CommandPart { ! public object Parse(string line) ! { ! return null; ! } #region 'Valid characters for different string types' definitions *************** *** 100,227 **** } #endregion ! } ! ! /// <summary> ! /// Represents an atom ! /// </summary> ! public class CommandAtom : CommandPart ! { ! private string mString; ! ! override public string ToString() { - return mString; } ! override public void Parse(TextReader input) { - // TODO: implement sytax rules for atoms - mString = input.ReadToEnd(); } - } - - /// <summary> - /// Represents a number - /// </summary> - public class CommandNumber : CommandPart - { - private int mNumber; ! override public string ToString() { - return mNumber.ToString(); } ! override public void Parse(TextReader input) { - // TODO: implement sytax rules for numbers - mNumber = int.Parse(input.ReadToEnd()); } - } - - /// <summary> - /* - 4.3. String - - A string is in one of two forms: either literal or quoted - string. The literal form is the general form of string. The - quoted string form is an alternative that avoids the overhead of - processing a literal at the cost of limitations of characters - which may be used. - - A literal is a sequence of zero or more octets (including CR and - LF), prefix-quoted with an octet count in the form of an open - brace ("{"), the number of octets, close brace ("}"), and CRLF. - In the case of literals transmitted from server to client, the - CRLF is immediately followed by the octet data. In the case of - literals transmitted from client to server, the client MUST wait - to receive a command continuation request (described later in - this document) before sending the octet data (and the remainder - of the command). ! A quoted string is a sequence of zero or more 7-bit characters, ! excluding CR and LF, with double quote (<">) characters at each ! end. ! ! The empty string is represented as either "" (a quoted string ! with zero characters between double quotes) or as {0} followed ! by CRLF (a literal with an octet count of 0). ! ! Note: Even if the octet count is 0, a client transmitting a ! literal MUST wait to receive a command continuation request. ! */ ! /// </summary> ! public class CommandString : CommandPart ! { ! private string mString; ! ! override public string ToString() { - return mString; } ! override public void Parse(TextReader input) { - // astring = 1*ASTRING-CHAR / string - // string = quoted / literal - // literal = "{" number "}" CRLF *CHAR8 ; Number represents the number of CHAR8s - // quoted = DQUOTE *QUOTED-CHAR DQUOTE - - // it's gotta start with a '"' - if(input.Peek() != '"') - throw new Exception("Not a string"); - - input.Read(); // skip the quote - - // TODO: implement sytax rules for strings - while(input.Peek() != '"' && input.Peek() != -1) - mString += (char)input.Read(); - - // it must end with a '"' - if(input.Peek() != '"') - throw new Exception("Not a string"); - - input.Read(); // skip the quote } - } - - public class CommandAtomString : CommandPart - { - private CommandPart mCommandPart; ! override public string ToString() { - return mCommandPart.ToString(); } ! override public void Parse(TextReader input) { ! if(input.Peek() == '"') ! mCommandPart = new CommandString(); ! else ! mCommandPart = new CommandAtom(); ! mCommandPart.Parse(input); } } } --- 99,143 ---- } #endregion ! /* ! private class CommandArgumentCombination : CommandArgumentParser { } ! private class CommandQuotedString : CommandArgumentParser { } ! private class CommandAtomString : CommandArgumentParser { } ! private class CommandLiteralString : CommandArgumentParser { } ! private class CommandListChars : CommandArgumentParser { } ! private class CommandSequenceSet : CommandArgumentParser { } ! private class CommandParenthesizedList : CommandArgumentParser { } ! private class CommandAString : CommandArgumentCombination { ! } ! ! private class CommandListString : CommandArgumentCombination ! { ! } ! private class CommandParenthesizedListAtom : CommandArgumentCombination ! { } + */ } } Index: CopyCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/CopyCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** CopyCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- CopyCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 12,21 **** } ! override protected void InternalProcess() { ! mConnection.SendTaggedMessage("BAD"); ! ! // done ! mConnection.ReadCommand(); } } --- 12,18 ---- } ! override protected bool InternalProcess() { ! return false; } } Index: CreateCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/CreateCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** CreateCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- CreateCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 12,21 **** } ! override protected void InternalProcess() { ! mConnection.SendTaggedMessage("BAD"); ! ! // done ! mConnection.ReadCommand(); } } --- 12,18 ---- } ! override protected bool InternalProcess() { ! return false; } } Index: DeleteCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/DeleteCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** DeleteCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- DeleteCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 12,21 **** } ! override protected void InternalProcess() { ! mConnection.SendTaggedMessage("BAD"); ! ! // done ! mConnection.ReadCommand(); } } --- 12,18 ---- } ! override protected bool InternalProcess() { ! return false; } } Index: ExamineCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/ExamineCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** ExamineCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- ExamineCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 12,16 **** } ! override protected void InternalProcess() { mConnection.Mailbox = Server.MailstoreProvider.GetMailbox(mConnection.User, mParsedArguments[0] as string); --- 12,16 ---- } ! override protected bool InternalProcess() { mConnection.Mailbox = Server.MailstoreProvider.GetMailbox(mConnection.User, mParsedArguments[0] as string); *************** *** 35,39 **** // done ! mConnection.ReadCommand(); } } --- 35,39 ---- // done ! return true; } } Index: ExpungeCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/ExpungeCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** ExpungeCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- ExpungeCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 12,21 **** } ! override protected void InternalProcess() { ! mConnection.SendTaggedMessage("BAD"); ! ! // done ! mConnection.ReadCommand(); } } --- 12,18 ---- } ! override protected bool InternalProcess() { ! return false; } } Index: FetchCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/FetchCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** FetchCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- FetchCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 1,3 **** --- 1,4 ---- using System; + using System.Collections; namespace Imap.Commands *************** *** 8,22 **** public class FetchCommand : ImapCommand { ! public FetchCommand(ImapServer svr) : base(svr, "FETCH", ImapConnectionState.Selected) { } ! override protected void InternalProcess() { ! mConnection.SendTaggedMessage("BAD"); // done ! mConnection.ReadCommand(); } } ! } --- 9,354 ---- public class FetchCommand : ImapCommand { ! private int mListIdx = 0; ! private ParenthesizedList mList = null; ! ! public FetchCommand(ImapServer svr) : base(svr, "FETCH", ImapConnectionState.Selected, ArgumentType.SequenceSet, ArgumentType.ParenthesizedListAtom) { } ! override protected bool InternalProcess() { ! mConnection.SendUntaggedMessage(mParsedArguments[0].ToString()); ! mConnection.SendTaggedMessage(mParsedArguments[1].ToString()); ! ! if(mParsedArguments[1] is string) ! { ! ParenthesizedList l = new ParenthesizedList(); ! l.AddItem(mParsedArguments[1]); ! mParsedArguments[1] = l; ! } ! ! mList = mParsedArguments[1] as ParenthesizedList; ! FetchParts parts = ParseList(); ! ! if(parts != null) ! { ! // process fetch ! } ! else ! mConnection.SendTaggedMessage("BAD"); // done ! return true; ! } ! ! private FetchParts ParseList() ! { ! FetchParts rv = new FetchParts(); ! for(mListIdx = 0; mListIdx < mList.Count; ++mListIdx) ! { ! string item = mList[mListIdx].ToString(); ! switch(item) ! { ! case "ALL": ! if(mList.Count != 1) ! return null; ! else ! { ! rv.AllMacro = true; ! return rv; ! } ! case "FULL": ! if(mList.Count != 1) ! return null; ! else ! { ! rv.FullMacro = true; ! return rv; ! } ! case "FAST": ! if(mList.Count != 1) ! return null; ! else ! { ! rv.FastMacro = true; ! return rv; ! } ! case "ENVELOPE": ! rv.Envelope = true; ! break; ! case "FLAGS": ! rv.Flags = true; ! break; ! case "INTERNALDATE": ! rv.InternalDate = true; ! break; ! case "RFC822.HEADER": ! rv.Rfc822Header = true; ! break; ! case "RFC822.SIZE": ! rv.Rfc822Size = true; ! break; ! case "RFC822.TEXT": ! rv.Rfc822Text = true; ! break; ! case "BODY": ! rv.Body = true; ! break; ! case "BODYSTRUCTURE": ! rv.BodyStructure = true; ! break; ! case "UID": ! rv.Uid = true; ! break; ! default: ! int sectionIdx; ! if(item.StartsWith("BODY[")) ! { ! rv.Body = true; ! sectionIdx = 5; ! } ! else if(item.StartsWith("BODY.PEEK[")) ! { ! rv.BodyPeek = true; ! sectionIdx = 10; ! } ! else ! return null; ! return ParseBodySection(rv, item.Substring(sectionIdx)); ! } ! } ! return rv; ! } ! ! private FetchParts ParseBodySection(FetchParts rv, string section) ! { ! bool isGood = false; ! int idx = 0; ! if(CommandPart.DigitNz.IndexOf(section[idx]) != -1) // a section part ! { ! int part = int.Parse(section[idx] + string.Empty); ! ! for(++idx; idx < section.Length; ++idx) ! { ! if(section[idx] == '.') // moving on to the next section ! { ! rv.BodySectionParts.Add(part); ! part = 0; ! } ! else if(section[idx] == ']') ! { ! ++idx; ! part = 0; ! break; ! } ! else if(CommandPart.Digit.IndexOf(section[idx]) != -1) ! { ! if(part == 0) // just starting ! { ! if(section[idx] == '0') // can't start with '0' ! return null; ! part = int.Parse(section[idx] + string.Empty); ! } ! else // next digit ! { ! part *= 10; ! part += int.Parse(section[idx] + string.Empty); ! } ! } ! else ! { ! if(part != 0) // previous parts must be seperated by '.' ! return null; ! else // must be the named section ! { ! string left = section.Substring(idx); ! switch(left) ! { ! case "HEADER]": ! rv.BodySectionPartHeader = true; ! idx += 6; ! break; ! case "TEXT]": ! rv.BodySectionPartText = true; ! idx += 4; ! break; ! case "MIME]": ! rv.BodySectionPartMime = true; ! idx += 4; ! break; ! case "HEADER.FIELDS": ! ++mListIdx; // move into header list ! if(!ParseHeaderList(rv.BodySectionPartHeaderFields)) ! return null; ! ++mListIdx; // move into closing item ! break; ! case "HEADER.FIELDS.NOT": ! ++mListIdx; // move into header list ! if(!ParseHeaderList(rv.BodySectionPartHeaderFieldsNot)) ! return null; ! ++mListIdx; // move into closing item ! break; ! default: ! return null; ! } ! } ! } ! } ! } ! else // must be a named section ! { ! // section-msgtext = "HEADER" / "HEADER.FIELDS" [".NOT"] SP header-list / "TEXT" ; top-level or MESSAGE/RFC822 part ! // header-fld-name = astring ! // header-list = "(" header-fld-name *(SP header-fld-name) ")" ! ! string left = section.Substring(idx); ! switch(left) ! { ! case "HEADER]": ! rv.BodySectionPartHeader = true; ! idx += 6; ! break; ! case "TEXT]": ! rv.BodySectionPartText = true; ! idx += 4; ! break; ! case "HEADER.FIELDS": ! ++mListIdx; // move into header list ! if(!ParseHeaderList(rv.BodySectionPartHeaderFields)) ! return null; ! ++mListIdx; // move into closing item ! break; ! case "HEADER.FIELDS.NOT": ! ++mListIdx; // move into header list ! if(!ParseHeaderList(rv.BodySectionPartHeaderFieldsNot)) ! return null; ! ++mListIdx; // move into closing item ! break; ! default: ! return null; ! } ! } ! ! // ["<" number "." nz-number ">"] ! // if(isGood && idx < pieceOfItem.Length) ! // { ! // if(pieceOfItem[idx] == '<') ! // { ! // // TODO: this ! // } ! // else // if their is more, and it's not this, oops ! // return null; ! // } ! ! return rv; ! } ! ! private bool ParseHeaderList(ArrayList destinationList) ! { ! return true; ! } ! ! public class FetchParts ! { ! public bool Body; ! public bool BodyPeek; ! ! private ArrayList mBodySectionParts; // TODO: make this a strongly typed for ints ! public ArrayList BodySectionParts ! { ! get ! { ! if(mBodySectionParts == null) ! mBodySectionParts = new ArrayList(); ! return mBodySectionParts; ! } ! } ! public bool BodySectionPartHeader; ! public bool BodySectionPartMime; ! public bool BodySectionPartText; ! private ArrayList mBodySectionPartHeaderFields; // TODO: make this a StringSet such that we don't have duplicates ! public ArrayList BodySectionPartHeaderFields ! { ! get ! { ! if(mBodySectionPartHeaderFields == null) ! mBodySectionPartHeaderFields = new ArrayList(); ! return mBodySectionPartHeaderFields; ! } ! } ! private ArrayList mBodySectionPartHeaderFieldsNot; // TODO: make this a StringSet such that we don't have duplicates ! public ArrayList BodySectionPartHeaderFieldsNot ! { ! get ! { ! if(mBodySectionPartHeaderFieldsNot == null) ! mBodySectionPartHeaderFieldsNot = new ArrayList(); ! return mBodySectionPartHeaderFieldsNot; ! } ! } ! public bool BodySectionHeader; ! public bool BodySectionText; ! private ArrayList mBodySectionHeaderFields; // TODO: make this a StringSet such that we don't have duplicates ! public ArrayList BodySectionHeaderFields ! { ! get ! { ! if(mBodySectionHeaderFields == null) ! mBodySectionHeaderFields = new ArrayList(); ! return mBodySectionHeaderFields; ! } ! } ! private ArrayList mBodySectionHeaderFieldsNot; // TODO: make this a StringSet such that we don't have duplicates ! public ArrayList BodySectionHeaderFieldsNot ! { ! get ! { ! if(mBodySectionHeaderFieldsNot == null) ! mBodySectionHeaderFieldsNot = new ArrayList(); ! return mBodySectionHeaderFieldsNot; ! } ! } ! ! public bool BodyStructure; ! public bool Envelope; ! public bool Flags; ! public bool InternalDate; ! public bool Rfc822; ! public bool Rfc822Header; ! public bool Rfc822Size; ! public bool Rfc822Text; ! public bool Uid; ! ! public bool AllMacro ! { ! set ! { ! Flags = value; ! InternalDate = value; ! Rfc822Size = value; ! Envelope = value; ! } ! } ! public bool FullMacro ! { ! set ! { ! Flags = value; ! InternalDate = value; ! Rfc822Size = value; ! Envelope = value; ! Body = value; ! } ! } ! public bool FastMacro ! { ! set ! { ! Flags = value; ! InternalDate = value; ! Rfc822Size = value; ! } ! } } } ! } \ No newline at end of file Index: ImapCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/ImapCommand.cs,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** ImapCommand.cs 25 Jul 2003 23:35:24 -0000 1.5 --- ImapCommand.cs 26 Jul 2003 23:09:25 -0000 1.6 *************** *** 3,6 **** --- 3,8 ---- using System; using System.Collections; + using System.Text; + using System.Text.RegularExpressions; namespace Imap.Commands *************** *** 11,14 **** --- 13,17 ---- abstract public class ImapCommand { + #region Variables public static ImapConnectionState AnyState = ImapConnectionState.Authenticated | ImapConnectionState.Selected | ImapConnectionState.NotAuthenticated; public static ImapConnectionState AuthSelectedState = ImapConnectionState.Authenticated | ImapConnectionState.Selected; *************** *** 19,31 **** private ArgumentType[] mArgumentTypes; - private bool mReadLiteralSuccess; - private string mReadLiteralString; - protected string mUnparsedArguments; - protected object[] mParsedArguments; - private int mCurrentArgument; protected int mUnparsedArgumentIdx; protected ImapConnection mConnection; public string Command { --- 22,33 ---- private ArgumentType[] mArgumentTypes; protected string mUnparsedArguments; protected int mUnparsedArgumentIdx; + protected object[] mParsedArguments; + protected ImapConnection mConnection; + #endregion + #region Properties public string Command { *************** *** 43,47 **** --- 45,51 ---- } } + #endregion + #region Constructing/Initialization /// <summary> /// Initializes a new ImapCommand *************** *** 70,81 **** // initialize couples as the uninitialize of the previous call - mReadLiteralSuccess = false; - mReadLiteralString = string.Empty; mUnparsedArgumentIdx = 0; - mCurrentArgument = 0; for(int idx = 0; idx < mParsedArguments.Length; ++idx) mParsedArguments[idx] = null; } public bool ValidateState() { --- 74,84 ---- // initialize couples as the uninitialize of the previous call mUnparsedArgumentIdx = 0; for(int idx = 0; idx < mParsedArguments.Length; ++idx) mParsedArguments[idx] = null; } + #endregion + #region Processing public bool ValidateState() { *************** *** 84,117 **** /// <summary> ! /// Processes the command, may return before the command is actually finished /// </summary> ! /// <param name="arguments">The arguments read in for processing</param> ! /// <param name="con">The connection that needs this command handled</param> ! public void Process() { ! // no arguments ... ! if(mArgumentTypes.Length == 0) ! { ! // ... and they gave us some ! if(mUnparsedArguments != string.Empty) ! InvalidArguments(); ! else ! InternalProcess(); ! } ! else // we need some arguments { ! ParseArgument(); } } ! abstract protected void InternalProcess(); ! ! protected void InvalidArguments() ! { ! mConnection.SendTaggedMessage("BAD"); ! mConnection.ReadCommand(); ! } #region Argument parsing stuff [Flags()] protected enum ArgumentType { --- 87,110 ---- /// <summary> ! /// Processes the command to its entirety /// </summary> ! /// <returns>True if successfully processed, false otherwise</returns> ! public bool Process() { ! // parse and validate the arguments ! if(!ParseArguments() || mUnparsedArgumentIdx < mUnparsedArguments.Length || !InternalProcess()) { ! mConnection.SendTaggedMessage("BAD"); ! return false; } + return true; } ! abstract protected bool InternalProcess(); ! #endregion #region Argument parsing stuff + + #region Global argument stuff [Flags()] protected enum ArgumentType { *************** *** 119,327 **** QuotedString = 1, AtomString = 2, ! LiteralString = 4, ! AString = 7, // quoted(1) + atom(2) + literal(4) ! ListChars = 8, ! ListString = 13, // quoted(1) + literal(4) + listchars(8) ! SequenceSet = 16, ! ParenthesizedList = 32, ! ParenthesizedListAtom = 34, // paren(32) + atom(2) } ! private void ParseArgumentHandler(bool valid, object parsedArgument) { ! if(valid) // yay, we got a good argument ! { ! mParsedArguments[mCurrentArgument++] = parsedArgument; // save and move to next ! if(mCurrentArgument == mArgumentTypes.Length) // if we're done, then send it over to custom processing ! InternalProcess(); ! else // need more arguments ! ParseArgument(); ! } ! else { ! mConnection.SendTaggedMessage("BAD"); ! mConnection.ReadCommand(); } } ! private void ParseArgument() { - ++mUnparsedArgumentIdx; // move past the space at the beginning - if(mUnparsedArgumentIdx >= mUnparsedArguments.Length) // no more string to parse ! ParseArgumentHandler(false, string.Empty); else if(mUnparsedArguments == string.Empty) ! ParseArgumentHandler(false, string.Empty); ! else if(((mArgumentTypes[mCurrentArgument] & ArgumentType.LiteralString) == ArgumentType.LiteralString) && mUnparsedArguments[mUnparsedArgumentIdx] == '{') // literal string ! ParseLiteralString(); ! else if(((mArgumentTypes[mCurrentArgument] & ArgumentType.QuotedString) == ArgumentType.QuotedString) && mUnparsedArguments[mUnparsedArgumentIdx] == '"') // quoted string ! { ! string str; ! if(ParseQuotedString(out str)) ! ParseArgumentHandler(true, str); ! else ! ParseArgumentHandler(false, string.Empty); ! } ! else if(((mArgumentTypes[mCurrentArgument] & ArgumentType.ParenthesizedList) == ArgumentType.ParenthesizedList) && mUnparsedArguments[mUnparsedArgumentIdx] == '(') // paren list ! { ! ParenthesizedList list; ! if(ParseParenthesizedList(out list)) ! ParseArgumentHandler(true, list); ! else ! ParseArgumentHandler(false, string.Empty); ! } ! else if(((mArgumentTypes[mCurrentArgument] & ArgumentType.ListChars) == ArgumentType.ListChars)) ! { ! string str; ! if(ParseListCharString(out str)) ! ParseArgumentHandler(true, str); ! else ! ParseArgumentHandler(false, string.Empty); ! } ! else if((mArgumentTypes[mCurrentArgument] & ArgumentType.AtomString) == ArgumentType.AtomString) // atom ! { ! string str; ! if(ParseAtom(out str)) ! ParseArgumentHandler(true, str); ! else ! ParseArgumentHandler(false, string.Empty); ! } ! else if((mArgumentTypes[mCurrentArgument] & ArgumentType.SequenceSet) == ArgumentType.SequenceSet) // sequence set ! { ! SequenceSet seq; ! if(ParseSequenceSet(out seq)) ! ParseArgumentHandler(true, seq); ! else ! ParseArgumentHandler(false, string.Empty); ! } ! } ! ! #region Literal string ! private void ParseLiteralString() ! { ! ++mUnparsedArgumentIdx; // move past '{' ! ! uint literalSize; ! ! // read digit-nz ! if(CommandPart.DigitNz.IndexOf(mUnparsedArguments[mUnparsedArgumentIdx]) != -1) ! { ! literalSize = uint.Parse(mUnparsedArguments[mUnparsedArgumentIdx] + string.Empty); ! ! // read the rest of the digits ! for(++mUnparsedArgumentIdx; mUnparsedArgumentIdx < mUnparsedArguments.Length; ++mUnparsedArgumentIdx) ! { ! if(mUnparsedArguments[mUnparsedArgumentIdx] == '}') ! { ! ++mUnparsedArgumentIdx; ! if(mUnparsedArgumentIdx != mUnparsedArguments.Length) ! ParseArgumentHandler(false, string.Empty); // literal size line must end after the '}' ! else ! { ! // TODO: need to chunk the blocks somehow, as creating a uint.MaxVal buffer throws some pretty errors ! // probably should also allow the command to specify how big is too big (for example, somebody typing ! // in a 20 thousand character username probably is trying to break stuff ! mConnection.SendContinueMessage("Ready"); ! mConnection.Connection.ReadBlock(new byte[literalSize], 0, literalSize, new ReceivedBlockDelegate(ReceivedLiteralString)); ! break; ! } ! } ! else if(CommandPart.Digit.IndexOf(mUnparsedArguments[mUnparsedArgumentIdx]) != -1) ! { ! // TODO: this will overflow the size , so we'll need to check for that ! // we can set a compilation option that will throw exceptions on overflow, ! // but I would imagine that this would make things very inefficient ! // it won't error as is, just roll around ! literalSize *= 10; ! literalSize += uint.Parse(mUnparsedArguments[mUnparsedArgumentIdx] + string.Empty); ! } ! else // not a valid digit ! ParseArgumentHandler(false, string.Empty); ! } ! } ! else // not a valid digit ! ParseArgumentHandler(false, string.Empty); } ! private void ReceivedLiteralString(Connection con, byte[] block) { ! mReadLiteralSuccess = true; ! mReadLiteralString = System.Text.Encoding.ASCII.GetString(block); ! for(int idx = 0; idx < mReadLiteralString.Length; ++idx) { ! if(CommandPart.CHAR8.IndexOf(mReadLiteralString[idx]) == -1) ! { ! mReadLiteralSuccess = false; break; ! } } ! mConnection.Connection.ReadLine(new ReceivedLineDelegate(ReceivedLineAfterLiteral)); ! } ! ! private void ReceivedLineAfterLiteral(Connection con, string line) ! { ! mUnparsedArgumentIdx = 0; ! mUnparsedArguments = line; ! if(mReadLiteralSuccess) ! ParseArgumentHandler(true, mReadLiteralString); ! else ! ParseArgumentHandler(false, string.Empty); } #endregion ! #region List char string ! private bool ParseListCharString(out string listCharString) { ! bool isGood = true; // will determing whether we've read a valid atom ! listCharString = string.Empty; // will store the list char string as we "read" it ! for(; mUnparsedArgumentIdx < mUnparsedArguments.Length; ++mUnparsedArgumentIdx) ! { ! if(CommandPart.ListChar.IndexOf(mUnparsedArguments[mUnparsedArgumentIdx]) != -1) ! listCharString += mUnparsedArguments[mUnparsedArgumentIdx]; ! else // not found, bad char ! { ! isGood = false; ! ++mUnparsedArgumentIdx; ! break; ! } ! } ! return isGood; ! } ! #endregion ! #region Atom string ! private bool ParseAtom(out string atomString) ! { ! bool isGood = true; // will determine whether we've read a valid atom ! atomString = string.Empty; // will store the atom as we "read" it ! for(; mUnparsedArgumentIdx < mUnparsedArguments.Length; ++ mUnparsedArgumentIdx) ! { ! if(CommandPart.AtomChar.IndexOf(mUnparsedArguments[mUnparsedArgumentIdx]) != -1) ! atomString += mUnparsedArguments[mUnparsedArgumentIdx]; ! else if(mUnparsedArguments[mUnparsedArgumentIdx] == ' ') // a space, done with this argument ! break; ! else // not found, bad char ! { ! isGood = false; ! ++mUnparsedArgumentIdx; ! break; ! } ! } ! return isGood; } #endregion #region Quoted sring ! private bool ParseQuotedString(out string quotedString) { bool readEscape = false; // keeps track of whether or not we just read the escape character "\" ! bool isGood = false; // will determine whether we've read a valid quoted string ! quotedString = string.Empty; // will store the quoted string as we "read" it for(++mUnparsedArgumentIdx; mUnparsedArgumentIdx < mUnparsedArguments.Length; ++mUnparsedArgumentIdx) --- 112,214 ---- QuotedString = 1, AtomString = 2, ! AStringChar = 4, ! LiteralString = 8, ! AString = 13, // quoted(1) + astringchar(4) + literal(8) ! ListChars = 16, ! ListString = 25, // quoted(1) + literal(8) + listchars(16) ! SequenceSet = 32, ! ParenthesizedList = 64, ! ParenthesizedListAtom = 66, // paren(64) + atom(2) } ! private bool ParseArguments() { ! for(int idx = 0; idx < mArgumentTypes.Length; ++idx) { ! if(mUnparsedArguments[mUnparsedArgumentIdx++] != ' ') ! return false; ! object arg = ParseArgument(mArgumentTypes[idx]); ! if(arg == null) ! return false; ! mParsedArguments[idx] = arg; } + return true; } ! private object ParseArgument(ArgumentType argType) { if(mUnparsedArgumentIdx >= mUnparsedArguments.Length) // no more string to parse ! return null; else if(mUnparsedArguments == string.Empty) ! return null; ! else if(((argType & ArgumentType.LiteralString) == ArgumentType.LiteralString) && mUnparsedArguments[mUnparsedArgumentIdx] == '{') // literal string ! return ParseLiteralString(); ! else if(((argType & ArgumentType.ParenthesizedList) == ArgumentType.ParenthesizedList) && mUnparsedArguments[mUnparsedArgumentIdx] == '(') // paren list ! return ParseParenthesizedList(); ! else if(((argType & ArgumentType.QuotedString) == ArgumentType.QuotedString) && mUnparsedArguments[mUnparsedArgumentIdx] == '"') // quoted string ! return ParseQuotedString(); ! else if(((argType & ArgumentType.ListChars) == ArgumentType.ListChars)) ! return ParseWhileGood(CommandPart.ListChar); ! else if((argType & ArgumentType.AtomString) == ArgumentType.AtomString) // atom ! return ParseWhileGood(CommandPart.AtomChar); ! else if((argType & ArgumentType.AStringChar) == ArgumentType.AStringChar) // astring-char ! return ParseWhileGood(CommandPart.AStringChar); ! else if((argType & ArgumentType.SequenceSet) == ArgumentType.SequenceSet) // sequence set ! return ParseSequenceSet(); ! return null; } ! private string ParseWhileGood(string validChars) { ! StringBuilder strBuilder = new StringBuilder(); ! for(; mUnparsedArgumentIdx < mUnparsedArguments.Length; ++mUnparsedArgumentIdx) { ! if(validChars.IndexOf(mUnparsedArguments[mUnparsedArgumentIdx]) == -1) break; ! else ! strBuilder.Append(mUnparsedArguments[mUnparsedArgumentIdx]); } ! string str = strBuilder.ToString(); ! if(str == string.Empty) ! return null; ! return str; } #endregion ! #region Literal string ! private string ParseLiteralString() { ! string literalSizeString = mUnparsedArguments.Substring(mUnparsedArgumentIdx); ! mUnparsedArgumentIdx += literalSizeString.Length; ! Match match = Regex.Match(literalSizeString, @"^\{([1-9][0-9]{0,9})\}$"); ! if(!match.Success) ! return null; ! // TODO: some where we need to make sure that this isn't bigger then uint.Max (4,294,967,295) before we put it into the variable ! uint literalSize = uint.Parse(match.Groups[1].ToString()); ! mConnection.SendContinueMessage("More"); ! // TODO: if literalSize is big, need to adjust, and do something more intelligent for "chunking" as we read ! string literalString = mConnection.ReadBlockAsString((int)literalSize); ! // make sure it's a valid literal string (any ascii character besides \0 ! if(!Regex.IsMatch(literalString, @"^[\x01-\xFF]$")) ! return null; ! // got possibly new arguments, finish the line off and make them uparsed as well ! mUnparsedArguments += mConnection.ReadLine(); ! ! return literalString; } #endregion #region Quoted sring ! private string ParseQuotedString() { bool readEscape = false; // keeps track of whether or not we just read the escape character "\" ! StringBuilder quotedString = new StringBuilder(); // will store the quoted string as we "read" it for(++mUnparsedArgumentIdx; mUnparsedArgumentIdx < mUnparsedArguments.Length; ++mUnparsedArgumentIdx) *************** *** 330,339 **** { if(readEscape) ! quotedString += mUnparsedArguments[mUnparsedArgumentIdx]; else { - isGood = true; // only good when we read an unescaped quote ++mUnparsedArgumentIdx; ! break; // done } } --- 217,225 ---- { if(readEscape) ! quotedString.Append(mUnparsedArguments[mUnparsedArgumentIdx]); else { ++mUnparsedArgumentIdx; ! return quotedString.ToString(); } } *************** *** 341,345 **** { if(readEscape) ! quotedString += mUnparsedArguments[mUnparsedArgumentIdx]; else readEscape = true; --- 227,231 ---- { if(readEscape) ! quotedString.Append(mUnparsedArguments[mUnparsedArgumentIdx]); else readEscape = true; *************** *** 348,352 **** { if(CommandPart.TextChar.IndexOf(mUnparsedArguments[mUnparsedArgumentIdx]) != -1) // it's found, good char ! quotedString += mUnparsedArguments[mUnparsedArgumentIdx]; else // not found, bad char { --- 234,238 ---- { if(CommandPart.TextChar.IndexOf(mUnparsedArguments[mUnparsedArgumentIdx]) != -1) // it's found, good char ! quotedString.Append(mUnparsedArguments[mUnparsedArgumentIdx]); else // not found, bad char { *************** *** 357,369 **** } ! return isGood; } #endregion #region Sequence string ! private bool ParseSequenceSet(out SequenceSet sequenceSet) { bool isGood = false; // will determine whether we've read a valid quoted string ! sequenceSet = new SequenceSet(); // will store the sequenceSet string as we "read" it uint startNumber = 0; uint sequenceNumber = 0; --- 243,255 ---- } ! return null; } #endregion #region Sequence string ! private SequenceSet ParseSequenceSet() { bool isGood = false; // will determine whether we've read a valid quoted string ! SequenceSet sequenceSet = new SequenceSet(); // will store the sequenceSet string as we "read" it uint startNumber = 0; uint sequenceNumber = 0; *************** *** 374,378 **** { if(CommandPart.DigitNz.IndexOf(mUnparsedArguments[mUnparsedArgumentIdx]) == -1) ! return false; else { --- 260,264 ---- { if(CommandPart.DigitNz.IndexOf(mUnparsedArguments[mUnparsedArgumentIdx]) == -1) ! return null; else { *************** *** 385,389 **** isGood = false; if(startNumber != 0) // we started a range earlier, can't start another so soon ! return false; startNumber = sequenceNumber; --- 271,275 ---- isGood = false; if(startNumber != 0) // we started a range earlier, can't start another so soon ! return null; startNumber = sequenceNumber; *************** *** 405,409 **** { if(sequenceNumber != 0) // * can't be part of a number ! return false; sequenceNumber = int.MaxValue; } --- 291,295 ---- { if(sequenceNumber != 0) // * can't be part of a number ! return null; sequenceNumber = int.MaxValue; } *************** *** 413,417 **** { if(CommandPart.Digit.IndexOf(mUnparsedArguments[mUnparsedArgumentIdx]) == -1) ! return false; else { --- 299,303 ---- { if(CommandPart.Digit.IndexOf(mUnparsedArguments[mUnparsedArgumentIdx]) == -1) ! return null; else { *************** *** 422,435 **** } ! // add the last range ! if(startNumber != 0) // we started a range earlier { ! sequenceSet.AddRange(startNumber, sequenceNumber); ! startNumber = 0; } - else // make a range of size 1 - sequenceSet.AddRange(sequenceNumber); ! return isGood; } --- 308,326 ---- } ! if(isGood) { ! // add the last range ! if(startNumber != 0) // we started a range earlier ! { ! sequenceSet.AddRange(startNumber, sequenceNumber); ! startNumber = 0; ! } ! else // make a range of size 1 ! sequenceSet.AddRange(sequenceNumber); ! ! return sequenceSet; } ! return null; } *************** *** 570,582 **** #region Parenthesized list string ! /// <summary> ! /// Default implementation does not handle anything but atoms as elements ! /// Which means as of IMAP4rev1 it should handle all input except for the SEARCH command ! /// </summary> ! protected virtual bool ParseParenthesizedList(out ParenthesizedList list) { - bool isGood = false; // will determine whether we've read a valid parenthesized list string dataItem = string.Empty; // stores the data item as we're reading it ! list = new ParenthesizedList(); for(++mUnparsedArgumentIdx; mUnparsedArgumentIdx < mUnparsedArguments.Length; ++mUnparsedArgumentIdx) --- 461,468 ---- #region Parenthesized list string ! protected virtual ParenthesizedList ParseParenthesizedList() { string dataItem = string.Empty; // stores the data item as we're reading it ! ParenthesizedList list = new ParenthesizedList(); for(++mUnparsedArgumentIdx; mUnparsedArgumentIdx < mUnparsedArguments.Length; ++mUnparsedArgumentIdx) *************** *** 584,621 **** if(mUnparsedArguments[mUnparsedArgumentIdx] == ')') { - isGood = true; if(dataItem != string.Empty) list.AddItem(dataItem); ! break; } else if(mUnparsedArguments[mUnparsedArgumentIdx] == '(') { ! ParenthesizedList nestedList; ! if(ParseParenthesizedList(out nestedList)) ! list.AddItem(list); ! else ! return false; ! } ! else if(mUnparsedArguments[mUnparsedArgumentIdx] == ' ') ! { ! if(dataItem != string.Empty) ! { ! list.AddItem(dataItem); ! dataItem = string.Empty; ! } ! else // getting a space after an empty item is not permitted ! return false; } else { ! if(CommandPart.AtomChar.IndexOf(mUnparsedArguments[mUnparsedArgumentIdx]) == -1) ! return false; ! else ! dataItem += mUnparsedArguments[mUnparsedArgumentIdx]; } } ! ++mUnparsedArgumentIdx; ! return isGood; } --- 470,504 ---- if(mUnparsedArguments[mUnparsedArgumentIdx] == ')') { if(dataItem != string.Empty) list.AddItem(dataItem); ! ! ++mUnparsedArgumentIdx; ! ! return list; } else if(mUnparsedArguments[mUnparsedArgumentIdx] == '(') { ! if(dataItem != string.Empty) // can't start a list in the middle of an item ! return null; ! ParenthesizedList nestedList = ParseParenthesizedList(); ! ! if(nestedList == null) ! return null; ! ! list.AddItem(nestedList); ! ! --mUnparsedArgumentIdx; } else { ! if(mUnparsedArguments[mUnparsedArgumentIdx] == ' ') ! ++mUnparsedArgumentIdx; ! list.AddItem(ParseArgument(ArgumentType.AString)); ! if(mUnparsedArguments[mUnparsedArgumentIdx] == ')') ! --mUnparsedArgumentIdx; } } ! return null; } *************** *** 688,691 **** --- 571,595 ---- rv += mItems[idx].ToString() + (idx != mItems.Count-1 ? " " : string.Empty); return rv + ")"; + } + + public ParenthesizedListItem this[int idx] + { + get + { + return mItems[idx] as ParenthesizedListItem; + } + } + + public int Count + { + get + { + return mItems.Count; + } + } + + public void Clear() + { + mItems.Clear(); } } Index: ListCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/ListCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** ListCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- ListCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 14,18 **** } ! override protected void InternalProcess() { // TODO: actually handle the arguments --- 14,18 ---- } ! override protected bool InternalProcess() { // TODO: actually handle the arguments *************** *** 22,27 **** mConnection.SendTaggedMessage("OK LIST completed"); ! // done ! mConnection.ReadCommand(); } } --- 22,26 ---- mConnection.SendTaggedMessage("OK LIST completed"); ! return true; } } Index: LoginCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/LoginCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** LoginCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- LoginCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 10,18 **** public class LoginCommand : ImapCommand { ! public LoginCommand(ImapServer svr) : base(svr, "LOGIN", ImapConnectionState.NotAuthenticated, ArgumentType.AString, ArgumentType.ListString) { } ! override protected void InternalProcess() { mConnection.User = Server.MailstoreProvider.GetUser(mParsedArguments[0] as String, mParsedArguments[1] as String); --- 10,18 ---- public class LoginCommand : ImapCommand { ! public LoginCommand(ImapServer svr) : base(svr, "LOGIN", ImapConnectionState.NotAuthenticated, ArgumentType.AString, ArgumentType.AString) { } ! override protected bool InternalProcess() { mConnection.User = Server.MailstoreProvider.GetUser(mParsedArguments[0] as String, mParsedArguments[1] as String); *************** *** 26,30 **** } ! mConnection.ReadCommand(); } } --- 26,30 ---- } ! return true; } } Index: LogoutCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/LogoutCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** LogoutCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- LogoutCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 12,22 **** } ! override protected void InternalProcess() { mConnection.SendUntaggedMessage("BYE"); mConnection.SendTaggedMessage("OK"); ! // done ! mConnection.Close(); } } --- 12,21 ---- } ! override protected bool InternalProcess() { mConnection.SendUntaggedMessage("BYE"); mConnection.SendTaggedMessage("OK"); ! return true; } } Index: LsubCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/LsubCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** LsubCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- LsubCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 14,18 **** } ! override protected void InternalProcess() { // TODO: actually handle the arguments --- 14,18 ---- } ! override protected bool InternalProcess() { // TODO: actually handle the arguments *************** *** 22,27 **** mConnection.SendTaggedMessage("OK LSUB completed"); ! // done ! mConnection.ReadCommand(); } } --- 22,26 ---- mConnection.SendTaggedMessage("OK LSUB completed"); ! return true; } } Index: NoopCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/NoopCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** NoopCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- NoopCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 12,21 **** } ! override protected void InternalProcess() { ! mConnection.SendTaggedMessage("OK"); ! ! // done ! mConnection.ReadCommand(); } } --- 12,18 ---- } ! override protected bool InternalProcess() { ! return false; } } Index: RenameCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/RenameCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** RenameCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- RenameCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 12,21 **** } ! override protected void InternalProcess() { ! mConnection.SendTaggedMessage("BAD"); ! ! // done ! mConnection.ReadCommand(); } } --- 12,18 ---- } ! override protected bool InternalProcess() { ! return false; } } Index: SearchCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/SearchCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** SearchCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- SearchCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 12,21 **** } ! override protected void InternalProcess() { ! mConnection.SendTaggedMessage("BAD"); ! ! // done ! mConnection.ReadCommand(); } } --- 12,18 ---- } ! override protected bool InternalProcess() { ! return false; } } Index: SelectCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/SelectCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** SelectCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- SelectCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 12,16 **** } ! override protected void InternalProcess() { mConnection.Mailbox = Server.MailstoreProvider.GetMailbox(mConnection.User, mParsedArguments[0] as string); --- 12,16 ---- } ! override protected bool InternalProcess() { mConnection.Mailbox = Server.MailstoreProvider.GetMailbox(mConnection.User, mParsedArguments[0] as string); *************** *** 34,39 **** } ! // done ! mConnection.ReadCommand(); } } --- 34,38 ---- } ! return true; } } Index: StarttlsCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/StarttlsCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** StarttlsCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- StarttlsCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 12,21 **** } ! override protected void InternalProcess() { ! mConnection.SendTaggedMessage("BAD"); ! ! // done ! mConnection.ReadCommand(); } } --- 12,18 ---- } ! override protected bool InternalProcess() { ! return false; } } Index: StatusCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/StatusCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** StatusCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- StatusCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 12,21 **** } ! override protected void InternalProcess() { ! mConnection.SendTaggedMessage("BAD"); ! ! // done ! mConnection.ReadCommand(); } } --- 12,18 ---- } ! override protected bool InternalProcess() { ! return false; } } Index: StoreCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/StoreCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** StoreCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- StoreCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 12,21 **** } ! override protected void InternalProcess() { ! mConnection.SendTaggedMessage("BAD"); ! ! // done ! mConnection.ReadCommand(); } } --- 12,18 ---- } ! override protected bool InternalProcess() { ! return false; } } Index: SubscribeCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/SubscribeCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** SubscribeCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- SubscribeCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 12,21 **** } ! override protected void InternalProcess() { ! mConnection.SendTaggedMessage("BAD"); ! ! // done ! mConnection.ReadCommand(); } } --- 12,18 ---- } ! override protected bool InternalProcess() { ! return false; } } Index: UidCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/UidCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** UidCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- UidCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 12,21 **** } ! override protected void InternalProcess() { ! mConnection.SendTaggedMessage("BAD"); ! ! // done ! mConnection.ReadCommand(); } } --- 12,18 ---- } ! override protected bool InternalProcess() { ! return false; } } Index: UnsubscribeCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/UnsubscribeCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** UnsubscribeCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- UnsubscribeCommand.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 12,21 **** } ! override protected void InternalProcess() { ! mConnection.SendTaggedMessage("BAD"); ! ! // done ! mConnection.ReadCommand(); } } --- 12,18 ---- } ! override protected bool InternalProcess() { ! return false; } } |
From: <ta...@us...> - 2003-07-26 23:09:28
|
Update of /cvsroot/csmaild/csmaild/src/Imap In directory sc8-pr-cvs1:/tmp/cvs-serv31922/src/Imap Modified Files: Connection.cs Log Message: Modified network model to be asynchronous for idle times and synchronous during the processing of the command. This cleans up the code a bit, while still keeping some of the theoretical benefits of doing it asynchronously. Reworked some of the argument parsing Started work on the FETCH command The test client got some work to, nothing significant yet. Index: Connection.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Connection.cs,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** Connection.cs 25 Jul 2003 03:39:12 -0000 1.5 --- Connection.cs 26 Jul 2003 23:09:25 -0000 1.6 *************** *** 49,60 **** } - public Connection Connection - { - get - { - return mConnection; - } - } - public ImapServer Server { --- 49,52 ---- *************** *** 100,105 **** mConnection.ReceivedLineEvent += new ReceivedLineDelegate(Connection_ReceivedLine); - mConnection.SentDataEvent += new SentDataDelegate(Connection_SentData); - ReadCommand(); } --- 92,95 ---- *************** *** 107,132 **** public void SendTaggedMessage(string msg) { ! SendTaggedMessage(mCurrentTag, msg); ! } ! public void SendTaggedMessage(string tag, string msg) ! { ! SendMessage(tag + " " + msg); } - public void SendUntaggedMessage(string msg) { SendMessage("* " + msg); } - public void SendContinueMessage(string msg) { SendMessage("+ " + msg); } - private void SendMessage(string msg) { mConnection.WriteLine(msg); } - public void ReadCommand() { --- 97,114 ---- public void SendTaggedMessage(string msg) { ! SendMessage(mCurrentTag + " " + msg); } public void SendUntaggedMessage(string msg) { SendMessage("* " + msg); } public void SendContinueMessage(string msg) { SendMessage("+ " + msg); } private void SendMessage(string msg) { mConnection.WriteLine(msg); } public void ReadCommand() { *************** *** 135,139 **** mCurrentCommand = null; ! mConnection.ReadLine(); } --- 117,133 ---- mCurrentCommand = null; ! mConnection.BeginReadLine(); ! } ! ! public string ReadLine() ! { ! return mConnection.ReadLine(); ! } ! ! public string ReadBlockAsString(int length) ! { ! byte[] buf = new byte[length]; ! mConnection.ReadBlock(buf, 0, length); ! return System.Text.Encoding.ASCII.GetString(buf); } *************** *** 195,216 **** // this command will parse through the incoming line and make sure it's valid ! if(ParseAndValidate(line)) ! { ! // good, leave the rest of the work up to the actual command handler ! mCurrentCommand.Process(); ! } ! else ! { ! // move on ! ReadCommand(); ! } ! } ! ! private void Connection_SentData(Connection con) ! { } public void Close() { } } --- 189,200 ---- // this command will parse through the incoming line and make sure it's valid ! if(ParseAndValidate(line) && mCurrentCommand.Process()) ! ;// good processing ! ReadCommand(); } public void Close() { + // TODO: gracefully handle closing of the connection } } |
From: <ta...@us...> - 2003-07-26 23:09:28
|
Update of /cvsroot/csmaild/csmaild/src/Imap/NetworkManager In directory sc8-pr-cvs1:/tmp/cvs-serv31922/src/Imap/NetworkManager Modified Files: Connection.cs Log Message: Modified network model to be asynchronous for idle times and synchronous during the processing of the command. This cleans up the code a bit, while still keeping some of the theoretical benefits of doing it asynchronously. Reworked some of the argument parsing Started work on the FETCH command The test client got some work to, nothing significant yet. Index: Connection.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/NetworkManager/Connection.cs,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** Connection.cs 25 Jul 2003 23:35:24 -0000 1.6 --- Connection.cs 26 Jul 2003 23:09:25 -0000 1.7 *************** *** 10,15 **** { public delegate void ReceivedLineDelegate(Connection con, string line); - public delegate void ReceivedBlockDelegate(Connection con, byte[] block); - public delegate void SentDataDelegate(Connection con); public delegate void ConnectionClosedDelegate(Connection con); --- 10,13 ---- *************** *** 23,35 **** private NetworkStream mSocketStream; // a stream wrapping the communication socket ! private byte[] mReceiveLineBuffer; // a small storage place for receiving bytes for the line ! private string mLineString; // used to store the line the client sends ! ! private byte[] mReceiveBlockBuffer; // used to receive the buffer requested ! private int mReceiveBlockOffset; // the current offset into the receive block buffer ! private int mReceiveBlockSize; // the number of bytes left to read into the receive block buffer ! ! private Queue mWriteQueue = Queue.Synchronized(new Queue()); // the queue for writes (so we do them in order) ! private bool mCurrentlyWriting; private Listener mListener; // the listener that created us --- 21,26 ---- private NetworkStream mSocketStream; // a stream wrapping the communication socket ! private byte[] mReceiveBuffer; // a small storage place for receiving bytes for the line ! private StringBuilder mReceivedString; // used to store the line that we have received private Listener mListener; // the listener that created us *************** *** 38,47 **** #region Events private event ReceivedLineDelegate mReceivedLineEvent; - private event ReceivedBlockDelegate mReceivedBlockEvent; - private event SentDataDelegate mSentDataEvent; private event ConnectionClosedDelegate mConnectionClosedEvent; /// <summary> ! /// Fires when the requested line has been received from the client /// </summary> public event ReceivedLineDelegate ReceivedLineEvent --- 29,36 ---- #region Events private event ReceivedLineDelegate mReceivedLineEvent; private event ConnectionClosedDelegate mConnectionClosedEvent; /// <summary> ! /// Fires when the asynchronously requested line has been received from the client /// </summary> public event ReceivedLineDelegate ReceivedLineEvent *************** *** 58,91 **** /// <summary> - /// Fires when the requested block has been received from the client - /// </summary> - public event ReceivedBlockDelegate ReceivedBlockEvent - { - add - { - mReceivedBlockEvent += value; - } - remove - { - mReceivedBlockEvent -= value; - } - } - - /// <summary> - /// Fires when sending is complete - /// </summary> - public event SentDataDelegate SentDataEvent - { - add - { - mSentDataEvent += value; - } - remove - { - mSentDataEvent -= value; - } - } - - /// <summary> /// Fires when the connection is closed remotely /// </summary> --- 47,50 ---- *************** *** 114,122 **** mListener = listener; - mWriteQueue = Queue.Synchronized(new Queue()); // the queue for writes (so we do them in order) - mCurrentlyWriting = false; - mSocketStream = new NetworkStream(mClient, true); ! mReceiveLineBuffer = new byte[8192]; } #endregion --- 73,79 ---- mListener = listener; mSocketStream = new NetworkStream(mClient, true); ! mReceiveBuffer = new byte[8192]; ! mReceivedString = new StringBuilder(1024); // so the initial few growings don't have to happen } #endregion *************** *** 124,151 **** #region Public methods /// <summary> ! /// Writes the message to the socket asynchronously /// </summary> /// <param name="msg">The message to write</param> public void Write(string msg) { ! Monitor.Enter(mWriteQueue); ! if(mCurrentlyWriting) ! mWriteQueue.Enqueue(msg); ! else { byte[] b = Encoding.ASCII.GetBytes(msg); ! if(mClient.Connected) ! mSocketStream.BeginWrite(b, 0, b.Length, new AsyncCallback(SendCallback), msg); ! mCurrentlyWriting = true; } - Monitor.Exit(mWriteQueue); } /// <summary> ! /// Writes the message to the socket asynchronosously /// </summary> /// <param name="msg">The message to write (it will be suffixed with a CRLF)</param> public void WriteLine(string msg) { Write(msg + "\r\n"); } --- 81,103 ---- #region Public methods /// <summary> ! /// Writes the message to the socket /// </summary> /// <param name="msg">The message to write</param> public void Write(string msg) { ! if(mClient.Connected) { byte[] b = Encoding.ASCII.GetBytes(msg); ! mSocketStream.Write(b, 0, b.Length); } } /// <summary> ! /// Writes the message to the socket /// </summary> /// <param name="msg">The message to write (it will be suffixed with a CRLF)</param> public void WriteLine(string msg) { + System.Diagnostics.Trace.WriteLine(ToString() + " <- " + msg); Write(msg + "\r\n"); } *************** *** 154,185 **** /// Reads a line from the socket asynchronously /// </summary> ! public void ReadLine() ! { ! ReadLine(mReceivedLineEvent); ! } ! ! public void ReadLine(ReceivedLineDelegate callback) { if(mClient.Connected) ! mSocketStream.BeginRead(mReceiveLineBuffer, 0, mReceiveLineBuffer.Length, new AsyncCallback(ReceiveLineCallback), callback); } ! /// <summary> ! /// Reads a block from the socket asynchronously ! /// </summary> ! /// <param name="block">The buffer to place the bytes read</param> ! /// <param name="offset">The offset into this buffer</param> ! /// <param name="size">The number of bytes to read into the buffer</param> ! public void ReadBlock(byte[] block, uint offset, uint length) { ! // TODO: really need to handle bigger values, will need to split this up too, because an presumed 4 gigabyte buffer probably won't slide ! if(length > int.MaxValue) ! ReadBlock(block, offset, int.MaxValue, mReceivedBlockEvent); ! else ! ReadBlock(block, offset, length, mReceivedBlockEvent); } /// <summary> ! /// Reads a block from the socket asynchronously calling the passed in delegate instead of the subscribed handler /// </summary> /// <param name="block">The buffer to place the bytes read</param> --- 106,150 ---- /// Reads a line from the socket asynchronously /// </summary> ! public void BeginReadLine() { if(mClient.Connected) ! mSocketStream.BeginRead(mReceiveBuffer, 0, mReceiveBuffer.Length, new AsyncCallback(ReceiveLineCallback), null); } ! public string ReadLine() { ! while(true) ! { ! // we may have enough information for a line from the last read ! string currentData = mReceivedString.ToString(); // TODO: this happening everytime could be a performance hit ! int idx = currentData.IndexOf("\r\n"); // yay, found the line ! if(idx != -1) ! { ! // we quite possibly got too much data for this line ! // get the line, leave the rest in the string builder ! string line = currentData.Substring(0, idx); ! mReceivedString.Remove(0, idx+2); // remove the line and the \r\n ! ! return line; ! } ! else // read more ! { ! int read = mSocketStream.Read(mReceiveBuffer, 0, mReceiveBuffer.Length); ! if(read == 0) // connection was closed ! { ! OnClosed(); ! return null; ! } ! else ! { ! string incoming = Encoding.ASCII.GetString(mReceiveBuffer, 0, read); ! mReceivedString.Append(incoming); ! } ! } ! } } /// <summary> ! /// Reads a block from the socket /// </summary> /// <param name="block">The buffer to place the bytes read</param> *************** *** 187,230 **** /// <param name="size">The number of bytes to read into the buffer</param> /// <param name="callback">The callback function to call after done reading</param> ! public void ReadBlock(byte[] block, uint offset, uint length, ReceivedBlockDelegate callback) { ! // TODO: really need to handle bigger values, will need to split this up too, because an presumed 4 gigabyte buffer probably won't slide ! if(length > int.MaxValue) { ! mReceiveBlockBuffer = block; ! mReceiveBlockOffset = (int)offset; ! mReceiveBlockSize = int.MaxValue; } ! else { ! mReceiveBlockBuffer = block; ! mReceiveBlockOffset = (int)offset; ! mReceiveBlockSize = (int)length; } - - ReadBlock(callback); } #endregion #region Protected methods ! private void FireReadLineDelegate(string line, ReceivedLineDelegate func) ! { ! if(func != null) ! func(this, line); ! } ! ! private void FireReadBlockDelegate(byte[] block, ReceivedBlockDelegate func) ! { ! if(func != null) ! func(this, block); ! } ! ! /// <summary> ! /// Fires the related event, called called when the data has been sent ! /// </summary> ! protected virtual void OnSent() { ! if(mSentDataEvent != null) ! mSentDataEvent(this); } --- 152,189 ---- /// <param name="size">The number of bytes to read into the buffer</param> /// <param name="callback">The callback function to call after done reading</param> ! public void ReadBlock(byte[] block, int offset, int length) { ! int read = 0; ! if(mReceivedString.Length > 0) { ! // TODO: this could probably be made slightly more efficient ! byte[] currentData = System.Text.Encoding.ASCII.GetBytes(mReceivedString.ToString()); ! int toCopy = Math.Min(length, currentData.Length); // get the number of bytes we'll need ! ! mReceivedString.Remove(0, toCopy); ! ! Array.Copy(currentData, 0, block, offset, toCopy); ! read += toCopy; } ! ! while(read != length) { ! int readThisTime = mSocketStream.Read(block, offset+read, length-read); ! if(readThisTime == 0) // connection was closed ! { ! OnClosed(); ! return; ! } ! else ! read += readThisTime; } } #endregion #region Protected methods ! protected void OnReadLine(string line) { ! if(mReceivedLineEvent != null) ! mReceivedLineEvent(this, line); } *************** *** 240,271 **** #region Private methods - private void ReadBlock(ReceivedBlockDelegate callback) - { - if(mClient.Connected) - mSocketStream.BeginRead(mReceiveBlockBuffer, mReceiveBlockOffset, mReceiveBlockSize, new AsyncCallback(ReceiveBlockCallback), callback); - } - - private void SendCallback(IAsyncResult result) - { - mSocketStream.EndWrite(result); - - Monitor.Enter(mWriteQueue); - mCurrentlyWriting = false; - if(mWriteQueue.Count != 0) - { - string msg = (string)mWriteQueue.Dequeue(); - byte[] b = Encoding.ASCII.GetBytes(msg); - if(mClient.Connected) - mSocketStream.BeginWrite(b, 0, b.Length, new AsyncCallback(SendCallback), msg); - mCurrentlyWriting = true; - } - System.Diagnostics.Trace.Write(ToString() + " <- " + (string)result.AsyncState); - - Monitor.Exit(mWriteQueue); - - // spill event - OnSent(); - } - private void ReceiveLineCallback(IAsyncResult result) { --- 199,202 ---- *************** *** 279,293 **** { // if we're reading a line ! mLineString += Encoding.ASCII.GetString(mReceiveLineBuffer, 0, read); ! // we're reading a line and we found the eof!! ! int idx = mLineString.IndexOf("\r\n"); if(idx != -1) { // we quite possibly got too much data for this line ! // stuff everything before the <CRLF> in this ! string line = mLineString.Substring(0, idx); ! // and everything after back here ! mLineString = mLineString.Substring(idx+2); if(line != string.Empty) --- 210,225 ---- { // if we're reading a line ! string incoming = Encoding.ASCII.GetString(mReceiveBuffer, 0, read); ! mReceivedString.Append(incoming); ! // we're reading a line and we found the end of the line!! ! string currentData = mReceivedString.ToString(); // TODO: this happening everytime could be a performance hit ! int idx = currentData.IndexOf("\r\n"); if(idx != -1) { // we quite possibly got too much data for this line ! // get the line, leave the rest in the string builder ! string line = currentData.Substring(0, idx); ! mReceivedString.Remove(0, idx+2); // remove the line and the \r\n if(line != string.Empty) *************** *** 295,331 **** // spill event ! FireReadLineDelegate(line, (ReceivedLineDelegate)result.AsyncState); ! } ! else ! { ! // read some more bytes ! ReadLine(); ! } ! } ! } ! ! private void ReceiveBlockCallback(IAsyncResult result) ! { ! int read = mSocketStream.EndRead(result); ! if(read == 0) // connection was closed ! { ! // spill event ! OnClosed(); ! } ! else ! { ! // move offset by the amount we read ! mReceiveBlockOffset += read; ! // decrease the amount we have left to read by the amount we read ! mReceiveBlockSize -= read; ! ! if(mReceiveBlockSize == 0) ! { ! System.Diagnostics.Trace.WriteLine(ToString() + " -> " + System.Text.Encoding.ASCII.GetString(mReceiveBlockBuffer)); ! ! FireReadBlockDelegate(mReceiveBlockBuffer, (ReceivedBlockDelegate)result.AsyncState); } ! else ! ReadBlock((ReceivedBlockDelegate)result.AsyncState); } } --- 227,234 ---- // spill event ! OnReadLine(line); } ! else // read more ! BeginReadLine(); } } |
From: <ta...@us...> - 2003-07-26 23:09:28
|
Update of /cvsroot/csmaild/csmaild/src/TestClient/bin In directory sc8-pr-cvs1:/tmp/cvs-serv31922/src/TestClient/bin Modified Files: Commands.xml Log Message: Modified network model to be asynchronous for idle times and synchronous during the processing of the command. This cleans up the code a bit, while still keeping some of the theoretical benefits of doing it asynchronously. Reworked some of the argument parsing Started work on the FETCH command The test client got some work to, nothing significant yet. Index: Commands.xml =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/TestClient/bin/Commands.xml,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** Commands.xml 25 Jul 2003 23:35:24 -0000 1.2 --- Commands.xml 26 Jul 2003 23:09:25 -0000 1.3 *************** *** 2,21 **** <NewDataSet> <Commands> ! <Command>CAPABILITY</Command> </Commands> <Commands> ! <Command>LOGIN csmaild_test csmaild_test</Command> </Commands> <Commands> ! <Command>LIST "" "*"</Command> </Commands> <Commands> ! <Command>LSUB "" "*"</Command> </Commands> <Commands> ! <Command>SELECT INBOX</Command> </Commands> <Commands> ! <Command>FETCH (item1 item2 (item3 item4))</Command> </Commands> </NewDataSet> --- 2,35 ---- <NewDataSet> <Commands> ! <Command>1 CAPABILITY</Command> ! <Process>True</Process> </Commands> <Commands> ! <Command>2 LOGIN csmaild_test csmaild_test</Command> ! <Process>False</Process> </Commands> <Commands> ! <Command>2 LOGIN "csmaild_test" "csmaild_test"</Command> ! <Process>True</Process> </Commands> <Commands> ! <Command>2 LOGIN {12}</Command> ! <Process>False</Process> </Commands> <Commands> ! <Command>csmaild_test {12}</Command> ! <Process>False</Process> </Commands> <Commands> ! <Command>csmaild_test</Command> ! <Process>False</Process> ! </Commands> ! <Commands> ! <Command>3 SELECT INBOX</Command> ! <Process>True</Process> ! </Commands> ! <Commands> ! <Command>4 FETCH 1 (BODY[HEADER.FIELDS (To From)])</Command> ! <Process>True</Process> </Commands> </NewDataSet> |
From: <ta...@us...> - 2003-07-26 23:09:28
|
Update of /cvsroot/csmaild/csmaild/src/TestClient In directory sc8-pr-cvs1:/tmp/cvs-serv31922/src/TestClient Modified Files: ClientHelper.cs Main.cs Main.resx Log Message: Modified network model to be asynchronous for idle times and synchronous during the processing of the command. This cleans up the code a bit, while still keeping some of the theoretical benefits of doing it asynchronously. Reworked some of the argument parsing Started work on the FETCH command The test client got some work to, nothing significant yet. Index: ClientHelper.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/TestClient/ClientHelper.cs,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** ClientHelper.cs 24 Jul 2003 04:32:14 -0000 1.1 --- ClientHelper.cs 26 Jul 2003 23:09:25 -0000 1.2 *************** *** 59,62 **** --- 59,64 ---- System.Threading.Thread.Sleep(10); } + if(retval == string.Empty) + return retval; return retval.Substring(0, retval.Length-2); } Index: Main.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/TestClient/Main.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** Main.cs 25 Jul 2003 19:30:28 -0000 1.3 --- Main.cs 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 20,24 **** private System.Windows.Forms.Button cmdChegg; private System.Windows.Forms.ListBox lstCommunicationLog; - private System.Windows.Forms.ListBox lstCommandsToProcess; private System.Windows.Forms.TextBox txtAddCommands; private System.Windows.Forms.Button cmdAdd; --- 20,23 ---- *************** *** 28,31 **** --- 27,31 ---- private System.Windows.Forms.NumericUpDown numPause; private System.Windows.Forms.Label label1; + private System.Windows.Forms.CheckedListBox lstCommandsToProcess; /// <summary> /// Required designer variable. *************** *** 72,76 **** this.cmdChegg = new System.Windows.Forms.Button(); this.lstCommunicationLog = new System.Windows.Forms.ListBox(); - this.lstCommandsToProcess = new System.Windows.Forms.ListBox(); this.txtAddCommands = new System.Windows.Forms.TextBox(); this.cmdAdd = new System.Windows.Forms.Button(); --- 72,75 ---- *************** *** 80,83 **** --- 79,83 ---- this.numPause = new System.Windows.Forms.NumericUpDown(); this.label1 = new System.Windows.Forms.Label(); + this.lstCommandsToProcess = new System.Windows.Forms.CheckedListBox(); ((System.ComponentModel.ISupportInitialize)(this.numPause)).BeginInit(); this.SuspendLayout(); *************** *** 111,127 **** this.lstCommunicationLog.Location = new System.Drawing.Point(8, 40); this.lstCommunicationLog.Name = "lstCommunicationLog"; ! this.lstCommunicationLog.Size = new System.Drawing.Size(696, 432); this.lstCommunicationLog.TabIndex = 3; // - // lstCommandsToProcess - // - this.lstCommandsToProcess.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.lstCommandsToProcess.Font = new System.Drawing.Font("Verdana", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0))); - this.lstCommandsToProcess.Location = new System.Drawing.Point(712, 40); - this.lstCommandsToProcess.Name = "lstCommandsToProcess"; - this.lstCommandsToProcess.Size = new System.Drawing.Size(208, 405); - this.lstCommandsToProcess.TabIndex = 4; - this.lstCommandsToProcess.SelectedIndexChanged += new System.EventHandler(this.lstCommandsToProcess_SelectedIndexChanged); - // // txtAddCommands // --- 111,117 ---- this.lstCommunicationLog.Location = new System.Drawing.Point(8, 40); this.lstCommunicationLog.Name = "lstCommunicationLog"; ! this.lstCommunicationLog.Size = new System.Drawing.Size(600, 432); this.lstCommunicationLog.TabIndex = 3; // // txtAddCommands // *************** *** 201,208 **** --- 191,210 ---- this.label1.Text = "Pause between commands (tenths of a second)"; // + // lstCommandsToProcess + // + this.lstCommandsToProcess.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.lstCommandsToProcess.CheckOnClick = true; + this.lstCommandsToProcess.Font = new System.Drawing.Font("Verdana", 8.25F); + this.lstCommandsToProcess.Location = new System.Drawing.Point(616, 40); + this.lstCommandsToProcess.Name = "lstCommandsToProcess"; + this.lstCommandsToProcess.Size = new System.Drawing.Size(304, 386); + this.lstCommandsToProcess.TabIndex = 12; + this.lstCommandsToProcess.SelectedIndexChanged += new System.EventHandler(this.lstCommandsToProcess_SelectedIndexChanged); + // // MainF // this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.ClientSize = new System.Drawing.Size(928, 485); + this.Controls.Add(this.lstCommandsToProcess); this.Controls.Add(this.label1); this.Controls.Add(this.numPause); *************** *** 212,216 **** this.Controls.Add(this.cmdAdd); this.Controls.Add(this.txtAddCommands); - this.Controls.Add(this.lstCommandsToProcess); this.Controls.Add(this.lstCommunicationLog); this.Controls.Add(this.cmdChegg); --- 214,217 ---- *************** *** 237,255 **** { string line = mHelper.ReceiveLine(); ! lstCommunicationLog.Items.Add(mCounter++.ToString().PadLeft(4, ' ') + " <- " + line); ! lstCommunicationLog.SelectedIndex = lstCommunicationLog.Items.Count-1; ! Application.DoEvents(); - return line; } private void SendReceiveCommand(string command) { string line = string.Empty; ! string tag = mCounter.ToString(); ! SendLine(tag + " " + command); ! while(!line.StartsWith(tag)) line = ReadLine(); } --- 238,274 ---- { string line = mHelper.ReceiveLine(); ! if(line != string.Empty) ! { ! lstCommunicationLog.Items.Add(mCounter++.ToString().PadLeft(4, ' ') + " <- " + line); ! lstCommunicationLog.SelectedIndex = lstCommunicationLog.Items.Count-1; ! } Application.DoEvents(); return line; } + private string mLastTag = string.Empty; + private bool mChangeLastTag = true; private void SendReceiveCommand(string command) { string line = string.Empty; ! ! if(command.IndexOf(' ') != -1 && mChangeLastTag) ! mLastTag = command.Substring(0, command.IndexOf(' ')); ! SendLine(command); ! while(true) ! { line = ReadLine(); + + if(line.StartsWith(mLastTag)) + { + mChangeLastTag = true; + break; + } + else if(line.StartsWith("+")) + { + mChangeLastTag = false; + break; + } + } } *************** *** 270,276 **** for(int idx = 0; idx < lstCommandsToProcess.Items.Count; ++idx) { ! lstCommandsToProcess.SelectedIndex = idx; ! SendReceiveCommand(lstCommandsToProcess.SelectedItem as string); ! System.Threading.Thread.Sleep((int)numPause.Value * 100); } --- 289,298 ---- for(int idx = 0; idx < lstCommandsToProcess.Items.Count; ++idx) { ! if(lstCommandsToProcess.CheckedIndices.IndexOf(idx) != -1) ! { ! lstCommandsToProcess.SelectedIndex = idx; ! SendReceiveCommand(lstCommandsToProcess.SelectedItem as string); ! System.Threading.Thread.Sleep((int)numPause.Value * 100); ! } } *************** *** 296,300 **** { foreach(DataRow r in ds.Tables[0].Rows) ! lstCommandsToProcess.Items.Add(r["Command"] as string); } catch{} --- 318,322 ---- { foreach(DataRow r in ds.Tables[0].Rows) ! lstCommandsToProcess.Items.Add(r["Command"] as string, ((r["Process"] as string) == "True" ? CheckState.Checked : CheckState.Unchecked)); } catch{} *************** *** 307,310 **** --- 329,333 ---- { mHelper = new ClientHelper("localhost", 143); + SaveCommands(); Go(); } *************** *** 313,316 **** --- 336,340 ---- { mHelper = new ClientHelper("chegg.com", 143); + SaveCommands(); Go(); } *************** *** 386,392 **** DataSet ds = new DataSet(); ds.Tables.Add("Commands").Columns.Add("Command"); ! foreach(object o in lstCommandsToProcess.Items) ! ds.Tables[0].Rows.Add(new object[]{o as String}); ds.WriteXml("..\\Commands.xml"); --- 410,417 ---- DataSet ds = new DataSet(); ds.Tables.Add("Commands").Columns.Add("Command"); + ds.Tables[0].Columns.Add("Process"); ! for(int idx = 0; idx < lstCommandsToProcess.Items.Count; ++idx) ! ds.Tables[0].Rows.Add(new object[]{lstCommandsToProcess.Items[idx] as String, (lstCommandsToProcess.CheckedIndices.IndexOf(idx) != -1 ? "True" : "False")}); ds.WriteXml("..\\Commands.xml"); Index: Main.resx =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/TestClient/Main.resx,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** Main.resx 25 Jul 2003 19:30:28 -0000 1.3 --- Main.resx 26 Jul 2003 23:09:25 -0000 1.4 *************** *** 125,137 **** <value>Private</value> </data> - <data name="lstCommandsToProcess.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> - <value>Private</value> - </data> - <data name="lstCommandsToProcess.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> - <value>False</value> - </data> - <data name="lstCommandsToProcess.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> - <value>Private</value> - </data> <data name="txtAddCommands.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>Private</value> --- 125,128 ---- *************** *** 161,167 **** <value>Private</value> </data> - <data name="cmdMoveDown.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> - <value>Private</value> - </data> <data name="cmdMoveDown.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>False</value> --- 152,155 ---- *************** *** 170,173 **** --- 158,164 ---- <value>Private</value> </data> + <data name="cmdMoveDown.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> + <value>Private</value> + </data> <data name="cmdDelete.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>False</value> *************** *** 195,198 **** --- 186,198 ---- </data> <data name="label1.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> + <value>Private</value> + </data> + <data name="lstCommandsToProcess.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> + <value>Private</value> + </data> + <data name="lstCommandsToProcess.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> + <value>False</value> + </data> + <data name="lstCommandsToProcess.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>Private</value> </data> |
From: <ta...@us...> - 2003-07-26 19:54:15
|
Update of /cvsroot/csmaild/csmaild/src/Imap In directory sc8-pr-cvs1:/tmp/cvs-serv25794/src/Imap Modified Files: .cvsignore Added Files: Imap.2002.csproj Log Message: Added VS.NET 2002 solution and project files (they have a 2002 in the name) Updated ignore files to be less specific to ignore all user setting files Minor updates to crappy testclient --- NEW FILE: Imap.2002.csproj --- <VisualStudioProject> <CSHARP ProjectType = "Local" ProductVersion = "7.0.9466" SchemaVersion = "1.0" ProjectGuid = "{B1B51646-3745-489A-B0A8-630013E5E44E}" > <Build> <Settings ApplicationIcon = "" AssemblyKeyContainerName = "" AssemblyName = "Imap" AssemblyOriginatorKeyFile = "" DefaultClientScript = "JScript" DefaultHTMLPageLayout = "Grid" DefaultTargetSchema = "IE50" DelaySign = "false" OutputType = "Library" RootNamespace = "Imap" StartupObject = "" > <Config Name = "Debug" AllowUnsafeBlocks = "false" BaseAddress = "285212672" CheckForOverflowUnderflow = "false" ConfigurationOverrideFile = "" DefineConstants = "DEBUG;TRACE" DocumentationFile = "" DebugSymbols = "true" FileAlignment = "4096" IncrementalBuild = "true" Optimize = "false" OutputPath = "bin\Debug\" RegisterForComInterop = "false" RemoveIntegerChecks = "false" TreatWarningsAsErrors = "false" WarningLevel = "4" /> <Config Name = "Release" AllowUnsafeBlocks = "false" BaseAddress = "285212672" CheckForOverflowUnderflow = "false" ConfigurationOverrideFile = "" DefineConstants = "TRACE" DocumentationFile = "" DebugSymbols = "false" FileAlignment = "4096" IncrementalBuild = "false" Optimize = "true" OutputPath = "bin\Release\" RegisterForComInterop = "false" RemoveIntegerChecks = "false" TreatWarningsAsErrors = "false" WarningLevel = "4" /> </Settings> <References> <Reference Name = "System" AssemblyName = "System" HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.dll" /> <Reference Name = "System.Data" AssemblyName = "System.Data" HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Data.dll" /> <Reference Name = "System.XML" AssemblyName = "System.Xml" HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.XML.dll" /> <Reference Name = "Common.2002" Project = "{19D49838-BF7A-4432-9C84-F50AE399077B}" Package = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}" /> </References> </Build> <Files> <Include> <File RelPath = "AssemblyInfo.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Connection.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Server.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\AppendCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\AuthenticateCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\CapabilityCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\CheckCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\CloseCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\CommandPart.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\CopyCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\CreateCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\DeleteCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\ExamineCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\ExpungeCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\FetchCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\ImapCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\ListCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\LoginCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\LogoutCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\LsubCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\NoopCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\RenameCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\SearchCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\SelectCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\StarttlsCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\StatusCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\StoreCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\SubscribeCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\UidCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "Commands\UnsubscribeCommand.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "NetworkManager\Connection.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "NetworkManager\Listener.cs" SubType = "Code" BuildAction = "Compile" /> <File RelPath = "NetworkManager\NetworkManager.cs" SubType = "Code" BuildAction = "Compile" /> </Include> </Files> </CSHARP> </VisualStudioProject> Index: .cvsignore =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/.cvsignore,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** .cvsignore 8 Apr 2003 02:58:21 -0000 1.1 --- .cvsignore 25 Jul 2003 14:50:31 -0000 1.2 *************** *** 1,3 **** ! Imap.csproj.user bin obj --- 1,3 ---- ! *.csproj.user bin obj |
From: <ta...@us...> - 2003-07-26 06:24:38
|
Update of /cvsroot/csmaild/csmaild/src/TestClient In directory sc8-pr-cvs1:/tmp/cvs-serv22878/src/TestClient Modified Files: .cvsignore Main.cs Main.resx Log Message: Made the crappy test client a little less crappy. Index: .cvsignore =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/TestClient/.cvsignore,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** .cvsignore 25 Jul 2003 14:50:31 -0000 1.2 --- .cvsignore 25 Jul 2003 19:30:28 -0000 1.3 *************** *** 1,3 **** *.csproj.user - bin obj --- 1,2 ---- Index: Main.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/TestClient/Main.cs,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** Main.cs 25 Jul 2003 14:50:31 -0000 1.2 --- Main.cs 25 Jul 2003 19:30:28 -0000 1.3 *************** *** 1,6 **** --- 1,8 ---- using System; using System.Drawing; + using System.Data; using System.Collections; using System.ComponentModel; + using System.IO; using System.Windows.Forms; *************** *** 12,21 **** public class MainF : System.Windows.Forms.Form { ! private System.Windows.Forms.ListBox listBox1; ! int counter = 0; ! private System.Windows.Forms.Button button1; ! private System.Windows.Forms.Button button2; ! private System.Windows.Forms.ListBox listBox2; ! private System.Windows.Forms.Button button3; /// <summary> /// Required designer variable. --- 14,31 ---- public class MainF : System.Windows.Forms.Form { ! ClientHelper mHelper; ! int mCounter = 0; ! ! private System.Windows.Forms.Button cmdLocalhost; ! private System.Windows.Forms.Button cmdChegg; ! private System.Windows.Forms.ListBox lstCommunicationLog; ! private System.Windows.Forms.ListBox lstCommandsToProcess; ! private System.Windows.Forms.TextBox txtAddCommands; ! private System.Windows.Forms.Button cmdAdd; ! private System.Windows.Forms.Button cmdMoveUp; ! private System.Windows.Forms.Button cmdMoveDown; ! private System.Windows.Forms.Button cmdDelete; ! private System.Windows.Forms.NumericUpDown numPause; ! private System.Windows.Forms.Label label1; /// <summary> /// Required designer variable. *************** *** 59,130 **** private void InitializeComponent() { ! this.listBox1 = new System.Windows.Forms.ListBox(); ! this.button1 = new System.Windows.Forms.Button(); ! this.button2 = new System.Windows.Forms.Button(); ! this.listBox2 = new System.Windows.Forms.ListBox(); ! this.button3 = new System.Windows.Forms.Button(); this.SuspendLayout(); // ! // listBox1 // ! this.listBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) ! | System.Windows.Forms.AnchorStyles.Left) ! | System.Windows.Forms.AnchorStyles.Right))); ! this.listBox1.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0))); ! this.listBox1.ItemHeight = 16; ! this.listBox1.Location = new System.Drawing.Point(8, 40); ! this.listBox1.Name = "listBox1"; ! this.listBox1.Size = new System.Drawing.Size(352, 340); ! this.listBox1.TabIndex = 0; ! this.listBox1.SelectedIndexChanged += new System.EventHandler(this.listBox1_SelectedIndexChanged); // ! // button1 // ! this.button1.Location = new System.Drawing.Point(16, 8); ! this.button1.Name = "button1"; ! this.button1.TabIndex = 1; ! this.button1.Text = "Test Localhost"; ! this.button1.Click += new System.EventHandler(this.button1_Click); // ! // button2 // ! this.button2.Location = new System.Drawing.Point(632, 8); ! this.button2.Name = "button2"; ! this.button2.TabIndex = 2; ! this.button2.Text = "Test Chegg"; ! this.button2.Click += new System.EventHandler(this.button2_Click); // ! // listBox2 // ! this.listBox2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) ! | System.Windows.Forms.AnchorStyles.Left) ! | System.Windows.Forms.AnchorStyles.Right))); ! this.listBox2.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0))); ! this.listBox2.ItemHeight = 16; ! this.listBox2.Location = new System.Drawing.Point(368, 40); ! this.listBox2.Name = "listBox2"; ! this.listBox2.Size = new System.Drawing.Size(336, 340); ! this.listBox2.TabIndex = 3; ! this.listBox2.SelectedIndexChanged += new System.EventHandler(this.listBox2_SelectedIndexChanged); // ! // button3 // ! this.button3.Location = new System.Drawing.Point(328, 8); ! this.button3.Name = "button3"; ! this.button3.TabIndex = 4; ! this.button3.Text = "Test Both"; ! this.button3.Click += new System.EventHandler(this.button3_Click); // // MainF // this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); ! this.ClientSize = new System.Drawing.Size(712, 389); ! this.Controls.Add(this.button3); ! this.Controls.Add(this.listBox2); ! this.Controls.Add(this.button2); ! this.Controls.Add(this.button1); ! this.Controls.Add(this.listBox1); this.Name = "MainF"; this.Text = "Main"; this.ResumeLayout(false); --- 69,223 ---- private void InitializeComponent() { ! this.cmdLocalhost = new System.Windows.Forms.Button(); ! this.cmdChegg = new System.Windows.Forms.Button(); ! this.lstCommunicationLog = new System.Windows.Forms.ListBox(); ! this.lstCommandsToProcess = new System.Windows.Forms.ListBox(); ! this.txtAddCommands = new System.Windows.Forms.TextBox(); ! this.cmdAdd = new System.Windows.Forms.Button(); ! this.cmdMoveUp = new System.Windows.Forms.Button(); ! this.cmdMoveDown = new System.Windows.Forms.Button(); ! this.cmdDelete = new System.Windows.Forms.Button(); ! this.numPause = new System.Windows.Forms.NumericUpDown(); ! this.label1 = new System.Windows.Forms.Label(); ! ((System.ComponentModel.ISupportInitialize)(this.numPause)).BeginInit(); this.SuspendLayout(); // ! // cmdLocalhost // ! this.cmdLocalhost.FlatStyle = System.Windows.Forms.FlatStyle.Flat; ! this.cmdLocalhost.Location = new System.Drawing.Point(8, 8); ! this.cmdLocalhost.Name = "cmdLocalhost"; ! this.cmdLocalhost.Size = new System.Drawing.Size(64, 20); ! this.cmdLocalhost.TabIndex = 1; ! this.cmdLocalhost.Text = "Localhost"; ! this.cmdLocalhost.Click += new System.EventHandler(this.cmdLocalhost_Click); // ! // cmdChegg // ! this.cmdChegg.FlatStyle = System.Windows.Forms.FlatStyle.Flat; ! this.cmdChegg.Location = new System.Drawing.Point(80, 8); ! this.cmdChegg.Name = "cmdChegg"; ! this.cmdChegg.Size = new System.Drawing.Size(64, 20); ! this.cmdChegg.TabIndex = 2; ! this.cmdChegg.Text = "Chegg"; ! this.cmdChegg.Click += new System.EventHandler(this.cmdChegg_Click); // ! // lstCommunicationLog // ! this.lstCommunicationLog.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; ! this.lstCommunicationLog.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0))); ! this.lstCommunicationLog.IntegralHeight = false; ! this.lstCommunicationLog.ItemHeight = 16; ! this.lstCommunicationLog.Location = new System.Drawing.Point(8, 40); ! this.lstCommunicationLog.Name = "lstCommunicationLog"; ! this.lstCommunicationLog.Size = new System.Drawing.Size(696, 432); ! this.lstCommunicationLog.TabIndex = 3; // ! // lstCommandsToProcess // ! this.lstCommandsToProcess.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; ! this.lstCommandsToProcess.Font = new System.Drawing.Font("Verdana", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0))); ! this.lstCommandsToProcess.Location = new System.Drawing.Point(712, 40); ! this.lstCommandsToProcess.Name = "lstCommandsToProcess"; ! this.lstCommandsToProcess.Size = new System.Drawing.Size(208, 405); ! this.lstCommandsToProcess.TabIndex = 4; ! this.lstCommandsToProcess.SelectedIndexChanged += new System.EventHandler(this.lstCommandsToProcess_SelectedIndexChanged); // ! // txtAddCommands // ! this.txtAddCommands.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; ! this.txtAddCommands.Location = new System.Drawing.Point(712, 456); ! this.txtAddCommands.Name = "txtAddCommands"; ! this.txtAddCommands.Size = new System.Drawing.Size(152, 20); ! this.txtAddCommands.TabIndex = 5; ! this.txtAddCommands.Text = ""; ! this.txtAddCommands.Enter += new System.EventHandler(this.txtAddCommands_Enter); ! // ! // cmdAdd ! // ! this.cmdAdd.FlatStyle = System.Windows.Forms.FlatStyle.Flat; ! this.cmdAdd.Location = new System.Drawing.Point(872, 456); ! this.cmdAdd.Name = "cmdAdd"; ! this.cmdAdd.Size = new System.Drawing.Size(48, 20); ! this.cmdAdd.TabIndex = 6; ! this.cmdAdd.Text = "Add"; ! this.cmdAdd.Click += new System.EventHandler(this.cmdAdd_Click); ! // ! // cmdMoveUp ! // ! this.cmdMoveUp.FlatStyle = System.Windows.Forms.FlatStyle.Flat; ! this.cmdMoveUp.Location = new System.Drawing.Point(712, 8); ! this.cmdMoveUp.Name = "cmdMoveUp"; ! this.cmdMoveUp.Size = new System.Drawing.Size(48, 20); ! this.cmdMoveUp.TabIndex = 7; ! this.cmdMoveUp.Text = "Up"; ! this.cmdMoveUp.Click += new System.EventHandler(this.cmdMoveUp_Click); ! // ! // cmdMoveDown ! // ! this.cmdMoveDown.FlatStyle = System.Windows.Forms.FlatStyle.Flat; ! this.cmdMoveDown.Location = new System.Drawing.Point(792, 8); ! this.cmdMoveDown.Name = "cmdMoveDown"; ! this.cmdMoveDown.Size = new System.Drawing.Size(48, 20); ! this.cmdMoveDown.TabIndex = 8; ! this.cmdMoveDown.Text = "Down"; ! this.cmdMoveDown.Click += new System.EventHandler(this.cmdMoveDown_Click); ! // ! // cmdDelete ! // ! this.cmdDelete.FlatStyle = System.Windows.Forms.FlatStyle.Flat; ! this.cmdDelete.Location = new System.Drawing.Point(872, 8); ! this.cmdDelete.Name = "cmdDelete"; ! this.cmdDelete.Size = new System.Drawing.Size(48, 20); ! this.cmdDelete.TabIndex = 9; ! this.cmdDelete.Text = "Delete"; ! this.cmdDelete.Click += new System.EventHandler(this.cmdDelete_Click); ! // ! // numPause ! // ! this.numPause.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; ! this.numPause.Location = new System.Drawing.Point(184, 8); ! this.numPause.Maximum = new System.Decimal(new int[] { ! 50, ! 0, ! 0, ! 0}); ! this.numPause.Name = "numPause"; ! this.numPause.Size = new System.Drawing.Size(40, 20); ! this.numPause.TabIndex = 10; ! this.numPause.Value = new System.Decimal(new int[] { ! 5, ! 0, ! 0, ! 0}); ! // ! // label1 ! // ! this.label1.AutoSize = true; ! this.label1.Location = new System.Drawing.Point(224, 8); ! this.label1.Name = "label1"; ! this.label1.Size = new System.Drawing.Size(243, 16); ! this.label1.TabIndex = 11; ! this.label1.Text = "Pause between commands (tenths of a second)"; // // MainF // this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); ! this.ClientSize = new System.Drawing.Size(928, 485); ! this.Controls.Add(this.label1); ! this.Controls.Add(this.numPause); ! this.Controls.Add(this.cmdDelete); ! this.Controls.Add(this.cmdMoveDown); ! this.Controls.Add(this.cmdMoveUp); ! this.Controls.Add(this.cmdAdd); ! this.Controls.Add(this.txtAddCommands); ! this.Controls.Add(this.lstCommandsToProcess); ! this.Controls.Add(this.lstCommunicationLog); ! this.Controls.Add(this.cmdChegg); ! this.Controls.Add(this.cmdLocalhost); this.Name = "MainF"; this.Text = "Main"; + this.Load += new System.EventHandler(this.MainF_Load); + ((System.ComponentModel.ISupportInitialize)(this.numPause)).EndInit(); this.ResumeLayout(false); *************** *** 132,147 **** #endregion ! private void SendLine(string msg, ClientHelper h, ListBox box) { ! h.Send(msg + "\r\n"); ! box.Items.Add(counter++.ToString().PadLeft(4, ' ') + " -> " + msg); Application.DoEvents(); } ! private string ReadLine(ClientHelper h, ListBox box) { ! string line = h.ReceiveLine(); ! box.Items.Add(counter++.ToString().PadLeft(4, ' ') + " <- " + line); Application.DoEvents(); --- 225,242 ---- #endregion ! private void SendLine(string msg) { ! mHelper.Send(msg + "\r\n"); ! lstCommunicationLog.Items.Add(mCounter++.ToString().PadLeft(4, ' ') + " -> " + msg); ! lstCommunicationLog.SelectedIndex = lstCommunicationLog.Items.Count-1; Application.DoEvents(); } ! private string ReadLine() { ! string line = mHelper.ReceiveLine(); ! lstCommunicationLog.Items.Add(mCounter++.ToString().PadLeft(4, ' ') + " <- " + line); ! lstCommunicationLog.SelectedIndex = lstCommunicationLog.Items.Count-1; Application.DoEvents(); *************** *** 150,229 **** } ! private void button1_Click(object sender, System.EventArgs e) { ! listBox1.Items.Clear(); ! ClientHelper localhost = new ClientHelper("localhost", 143); ! Go(localhost, listBox1); } ! private void button2_Click(object sender, System.EventArgs e) { ! listBox1.Items.Clear(); ! ClientHelper chegg = new ClientHelper("chegg.com", 143); ! Go(chegg, listBox2); } ! private void button3_Click(object sender, System.EventArgs e) { ! listBox1.Items.Clear(); ! listBox2.Items.Clear(); ! ClientHelper localhost = new ClientHelper("localhost", 143); ! Go(localhost, listBox1); ! ClientHelper chegg = new ClientHelper("chegg.com", 143); ! Go(chegg, listBox2); } ! private void Go(ClientHelper h, ListBox box) { ! ReadLine(h, box); // read welcome msg ! string a1 = string.Empty; ! SendLine("a1 CAPABILITY", h, box); ! while(!a1.StartsWith("a1")) ! a1 = ReadLine(h, box); ! string a2 = string.Empty; ! SendLine("a2 LOGIN {12}", h, box); ! a2 = ReadLine(h, box); ! SendLine("csmaild_test {12}", h, box); ! a2 = ReadLine(h, box); ! SendLine("csmaild_test", h, box); ! while(!a2.StartsWith("a2")) ! a2 = ReadLine(h, box); ! /* string a2 = string.Empty; ! SendLine("a2 LOGIN \"csmaild_test\" \"csmaild_test\""); ! while(!a2.StartsWith("a2")) ! a2 = ReadLine();*/ ! string a3 = string.Empty; ! SendLine("a3 LIST \"\" \"*\"", h, box); ! while(!a3.StartsWith("a3")) ! a3 = ReadLine(h, box); ! string a4 = string.Empty; ! SendLine("a4 LSUB \"\" \"*\"", h, box); ! while(!a4.StartsWith("a4")) ! a4 = ReadLine(h, box); ! string a5 = string.Empty; ! SendLine("a5 SELECT \"INBOX\"", h, box); ! while(!a5.StartsWith("a5")) ! a5 = ReadLine(h, box); ! string zz = string.Empty; ! SendLine("zz LOGOUT", h, box); ! while(!zz.StartsWith("zz")) ! zz = ReadLine(h, box); } ! private void listBox1_SelectedIndexChanged(object sender, System.EventArgs e) { ! listBox2.SelectedIndex = listBox1.SelectedIndex; } ! private void listBox2_SelectedIndexChanged(object sender, System.EventArgs e) { ! listBox1.SelectedIndex = listBox2.SelectedIndex; } } --- 245,396 ---- } ! private void SendReceiveCommand(string command) { ! string line = string.Empty; ! string tag = mCounter.ToString(); ! SendLine(tag + " " + command); ! while(!line.StartsWith(tag)) ! line = ReadLine(); } ! private void Go() { ! lstCommunicationLog.Items.Clear(); ! ! cmdAdd.Enabled = false; ! cmdDelete.Enabled = false; ! cmdMoveUp.Enabled = false; ! cmdMoveDown.Enabled = false; ! lstCommandsToProcess.Enabled = false; ! cmdLocalhost.Enabled = false; ! cmdChegg.Enabled = false; ! ! ReadLine(); // read welcome msg ! ! for(int idx = 0; idx < lstCommandsToProcess.Items.Count; ++idx) ! { ! lstCommandsToProcess.SelectedIndex = idx; ! SendReceiveCommand(lstCommandsToProcess.SelectedItem as string); ! System.Threading.Thread.Sleep((int)numPause.Value * 100); ! } ! ! cmdAdd.Enabled = true; ! cmdDelete.Enabled = true; ! cmdMoveUp.Enabled = true; ! cmdMoveDown.Enabled = true; ! lstCommandsToProcess.Enabled = true; ! cmdLocalhost.Enabled = true; ! cmdChegg.Enabled = true; } ! private void MainF_Load(object sender, System.EventArgs e) { ! lstCommandsToProcess_SelectedIndexChanged(sender, e); ! ! if(File.Exists("..\\Commands.xml")) ! { ! DataSet ds = new DataSet(); ! ds.ReadXml("..\\Commands.xml"); ! ! try ! { ! foreach(DataRow r in ds.Tables[0].Rows) ! lstCommandsToProcess.Items.Add(r["Command"] as string); ! } ! catch{} ! ! ds.Dispose(); ! } } ! private void cmdLocalhost_Click(object sender, System.EventArgs e) { ! mHelper = new ClientHelper("localhost", 143); ! Go(); ! } ! private void cmdChegg_Click(object sender, System.EventArgs e) ! { ! mHelper = new ClientHelper("chegg.com", 143); ! Go(); ! } ! private void lstCommandsToProcess_SelectedIndexChanged(object sender, System.EventArgs e) ! { ! if(lstCommandsToProcess.SelectedIndex == -1) ! { ! cmdMoveDown.Enabled = false; ! cmdMoveUp.Enabled = false; ! cmdDelete.Enabled = false; ! } ! else ! { ! cmdMoveUp.Enabled = (lstCommandsToProcess.SelectedIndex != 0); ! cmdMoveDown.Enabled = (lstCommandsToProcess.SelectedIndex != lstCommandsToProcess.Items.Count-1); ! cmdDelete.Enabled = true; ! } ! } ! private void cmdAdd_Click(object sender, System.EventArgs e) ! { ! lstCommandsToProcess.Items.Add(txtAddCommands.Text); ! txtAddCommands.SelectionStart = 0; ! txtAddCommands.SelectionLength = txtAddCommands.Text.Length; ! SaveCommands(); ! } ! private void cmdMoveUp_Click(object sender, System.EventArgs e) ! { ! object toMove = lstCommandsToProcess.SelectedItem; ! int idx = lstCommandsToProcess.SelectedIndex; ! lstCommandsToProcess.Items.RemoveAt(idx); ! --idx; ! lstCommandsToProcess.Items.Insert(idx, toMove); ! lstCommandsToProcess.SelectedIndex = idx; ! SaveCommands(); ! } ! private void cmdMoveDown_Click(object sender, System.EventArgs e) ! { ! object toMove = lstCommandsToProcess.SelectedItem; ! int idx = lstCommandsToProcess.SelectedIndex; ! lstCommandsToProcess.Items.RemoveAt(idx); ! ++idx; ! lstCommandsToProcess.Items.Insert(idx, toMove); ! lstCommandsToProcess.SelectedIndex = idx; ! ! SaveCommands(); } ! private void cmdDelete_Click(object sender, System.EventArgs e) { ! int idx = lstCommandsToProcess.SelectedIndex; ! lstCommandsToProcess.Items.RemoveAt(idx); ! if(idx < lstCommandsToProcess.Items.Count) ! lstCommandsToProcess.SelectedIndex = idx; ! else if(idx > 0) ! lstCommandsToProcess.SelectedIndex = idx--; ! ! SaveCommands(); } ! private void txtAddCommands_Enter(object sender, System.EventArgs e) { ! this.AcceptButton = cmdAdd; ! } ! ! private void SaveCommands() ! { ! DataSet ds = new DataSet(); ! ds.Tables.Add("Commands").Columns.Add("Command"); ! ! foreach(object o in lstCommandsToProcess.Items) ! ds.Tables[0].Rows.Add(new object[]{o as String}); ! ! ds.WriteXml("..\\Commands.xml"); ! ! ds.Dispose(); } } Index: Main.resx =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/TestClient/Main.resx,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** Main.resx 25 Jul 2003 14:50:31 -0000 1.2 --- Main.resx 25 Jul 2003 19:30:28 -0000 1.3 *************** *** 98,144 **** <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> </resheader> ! <data name="listBox1.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>Private</value> </data> ! <data name="listBox1.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>False</value> </data> ! <data name="listBox1.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>Private</value> </data> ! <data name="button1.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>False</value> </data> ! <data name="button1.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>Private</value> </data> ! <data name="button1.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>Private</value> </data> ! <data name="button2.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>False</value> </data> ! <data name="button2.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>Private</value> </data> ! <data name="button2.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>Private</value> </data> ! <data name="listBox2.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>Private</value> </data> ! <data name="listBox2.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>False</value> </data> ! <data name="listBox2.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>Private</value> </data> ! <data name="button3.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>False</value> </data> ! <data name="button3.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>Private</value> </data> ! <data name="button3.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>Private</value> </data> --- 98,198 ---- <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> </resheader> ! <data name="cmdLocalhost.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> ! <value>False</value> ! </data> ! <data name="cmdLocalhost.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>Private</value> </data> ! <data name="cmdLocalhost.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> ! <value>Private</value> ! </data> ! <data name="cmdChegg.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>False</value> </data> ! <data name="cmdChegg.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>Private</value> </data> ! <data name="cmdChegg.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> ! <value>Private</value> ! </data> ! <data name="lstCommunicationLog.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> ! <value>Private</value> ! </data> ! <data name="lstCommunicationLog.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>False</value> </data> ! <data name="lstCommunicationLog.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>Private</value> </data> ! <data name="lstCommandsToProcess.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>Private</value> </data> ! <data name="lstCommandsToProcess.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>False</value> </data> ! <data name="lstCommandsToProcess.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>Private</value> </data> ! <data name="txtAddCommands.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>Private</value> </data> ! <data name="txtAddCommands.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> ! <value>False</value> ! </data> ! <data name="txtAddCommands.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>Private</value> </data> ! <data name="cmdAdd.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>False</value> </data> ! <data name="cmdAdd.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>Private</value> </data> ! <data name="cmdAdd.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> ! <value>Private</value> ! </data> ! <data name="cmdMoveUp.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>False</value> </data> ! <data name="cmdMoveUp.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>Private</value> </data> ! <data name="cmdMoveUp.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> ! <value>Private</value> ! </data> ! <data name="cmdMoveDown.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> ! <value>Private</value> ! </data> ! <data name="cmdMoveDown.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> ! <value>False</value> ! </data> ! <data name="cmdMoveDown.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> ! <value>Private</value> ! </data> ! <data name="cmdDelete.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> ! <value>False</value> ! </data> ! <data name="cmdDelete.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> ! <value>Private</value> ! </data> ! <data name="cmdDelete.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> ! <value>Private</value> ! </data> ! <data name="numPause.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> ! <value>False</value> ! </data> ! <data name="numPause.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> ! <value>Private</value> ! </data> ! <data name="numPause.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> ! <value>Private</value> ! </data> ! <data name="label1.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> ! <value>False</value> ! </data> ! <data name="label1.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> ! <value>Private</value> ! </data> ! <data name="label1.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>Private</value> </data> *************** *** 146,149 **** --- 200,206 ---- <value>False</value> </data> + <data name="$this.Language" type="System.Globalization.CultureInfo, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> + <value>(Default)</value> + </data> <data name="$this.TrayLargeIcon" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>False</value> *************** *** 155,167 **** <value>8, 8</value> </data> - <data name="$this.Language" type="System.Globalization.CultureInfo, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> - <value>(Default)</value> - </data> <data name="$this.DrawGrid" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>True</value> </data> - <data name="$this.Name"> - <value>MainF</value> - </data> <data name="$this.TrayHeight" type="System.Int32, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>80</value> --- 212,218 ---- *************** *** 169,172 **** --- 220,226 ---- <data name="$this.SnapToGrid" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <value>True</value> + </data> + <data name="$this.Name"> + <value>MainF</value> </data> <data name="$this.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> |
From: <ta...@us...> - 2003-07-26 06:20:45
|
Update of /cvsroot/csmaild/csmaild/src/TestClient/bin In directory sc8-pr-cvs1:/tmp/cvs-serv22878/src/TestClient/bin Added Files: .cvsignore Commands.xml Log Message: Made the crappy test client a little less crappy. --- NEW FILE: .cvsignore --- Debug --- NEW FILE: Commands.xml --- <?xml version="1.0" standalone="yes"?> <NewDataSet> <Commands> <Command>CAPABILITY</Command> </Commands> <Commands> <Command>LOGIN csmaild_test csmaild_test</Command> </Commands> <Commands> <Command>LIST "" "*"</Command> </Commands> <Commands> <Command>LSUB "" "*"</Command> </Commands> <Commands> <Command>SELECT INBOX</Command> </Commands> <Commands> <Command>LOGOUT</Command> </Commands> </NewDataSet> |
From: <ta...@us...> - 2003-07-26 05:48:07
|
Update of /cvsroot/csmaild/csmaild/src/Imap/Commands In directory sc8-pr-cvs1:/tmp/cvs-serv6209/src/Imap/Commands Modified Files: ImapCommand.cs Log Message: Parsing and optimizations of sequence strings should actually work now Index: ImapCommand.cs =================================================================== RCS file: /cvsroot/csmaild/csmaild/src/Imap/Commands/ImapCommand.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** ImapCommand.cs 25 Jul 2003 03:39:12 -0000 1.3 --- ImapCommand.cs 25 Jul 2003 18:46:40 -0000 1.4 *************** *** 147,151 **** ++mUnparsedArgumentIdx; // move past the space at the beginning ! if(mUnparsedArguments == string.Empty) ParseArgumentHandler(false, string.Empty); else if(((mArgumentTypes[mCurrentArgument] & ArgumentType.LiteralString) == ArgumentType.LiteralString) && mUnparsedArguments[mUnparsedArgumentIdx] == '{') // literal string --- 147,153 ---- ++mUnparsedArgumentIdx; // move past the space at the beginning ! if(mUnparsedArgumentIdx >= mUnparsedArguments.Length) // no more string to parse ! ParseArgumentHandler(false, string.Empty); ! else if(mUnparsedArguments == string.Empty) ParseArgumentHandler(false, string.Empty); else if(((mArgumentTypes[mCurrentArgument] & ArgumentType.LiteralString) == ArgumentType.LiteralString) && mUnparsedArguments[mUnparsedArgumentIdx] == '{') // literal string *************** *** 365,369 **** { isGood = false; ! if(startNumber == 0) // we started a range earlier, can't start another so soon return false; --- 367,371 ---- { isGood = false; ! if(startNumber != 0) // we started a range earlier, can't start another so soon return false; *************** *** 384,397 **** } else if(mUnparsedArguments[mUnparsedArgumentIdx] == ' ') // a space, done with the argument - { - if(startNumber != 0) // we started a range earlier - { - sequenceSet.AddRange(startNumber, sequenceNumber); - startNumber = 0; - } - else // make a range of size 1 - sequenceSet.AddRange(sequenceNumber); break; - } else { --- 386,390 ---- *************** *** 406,409 **** --- 399,411 ---- } + // add the last range + if(startNumber != 0) // we started a range earlier + { + sequenceSet.AddRange(startNumber, sequenceNumber); + startNumber = 0; + } + else // make a range of size 1 + sequenceSet.AddRange(sequenceNumber); + return isGood; } *************** *** 411,503 **** protected class SequenceSet { ! private ArrayList mStartRange = new ArrayList(); ! private ArrayList mEndRange = new ArrayList(); ! ! public void AddRange(int num) { ! AddRange(num, num); ! } ! public void AddRange(int start, int end) ! { ! int low = Math.Min(start, end); ! int high = Math.Max(start, end); ! if(mStartRange.Count == 0) { ! mStartRange.Add(low); ! mEndRange.Add(high); } - else - AddHelper(low, high); - } ! private void AddHelper(int lowVal, int highVal) ! { ! for(int idx = 0; idx < mStartRange.Count; ++idx) { ! if(lowVal == (int)mStartRange[idx]) // we start on the same value, wee! ! { ! if(highVal > (int)mEndRange[idx]) // we end higher, change some stuff ! AddHelperHelper(idx, highVal); ! break; ! } ! else if(lowVal > (int)mStartRange[idx]) // we start higher then this guy starts { ! if(lowVal < (int)mEndRange[idx]) // we start lower than this guy ends ! if(highVal > (int)mEndRange[idx]) // we end higher, change some stuff ! AddHelperHelper(idx, highVal); ! break; // done no matter what } ! else // we start lower then this guy starts { ! if(highVal > (int)mStartRange[idx]) // we end higher then this guy starts { ! // need to adjust start ! mStartRange[idx] = lowVal; ! if(highVal > (int)mEndRange[idx]) // we end higher then this guy ends ! AddHelperHelper(idx, highVal); ! break; } - continue; } } - } - - private void AddHelperHelper(int idx, int highVal) - { - // firstly, adjust the end - mEndRange[idx] = Math.Max(highVal, (int)mEndRange[idx]); ! ++idx; ! // while we haven't exhausted the array and we can combine sequences ! while(idx < mStartRange.Count && highVal > (int)mStartRange[idx]) { ! // this range can consume the entire next range ! if(highVal >= (int)mEndRange[idx]) { ! mStartRange.RemoveAt(idx); ! mEndRange.RemoveAt(idx); ! continue; // still need to see how much more we can eat } ! else // we need to combine the ranges { ! // make previous range all inclusive ! mEndRange[idx-1] = mEndRange[idx]; ! mStartRange.RemoveAt(idx); ! mEndRange.RemoveAt(idx); ! break; // done } } } public override string ToString() { ! string rv = string.Empty; ! for(int idx = 0; idx < mStartRange.Count; ++idx) ! rv += mStartRange[idx].ToString() + ":" + mEndRange[idx].ToString(); ! return rv; } } --- 413,610 ---- protected class SequenceSet { ! public class SequenceRange { ! private int mLow; ! private int mHigh; ! private SequenceRange mPrevious; ! private SequenceRange mNext; ! public int Low { ! get ! { ! return mLow; ! } ! set ! { ! if(value < mLow) ! { ! mLow = value; ! ! // we should combine with the previous ! while(mPrevious != null && value <= mPrevious.mHigh+1) ! { ! mLow = mPrevious.mLow; ! mPrevious = mPrevious.mPrevious; ! if(mPrevious != null) ! mPrevious.mNext = this; ! } ! } ! } } ! public int High { ! get { ! return mHigh; } ! set { ! if(value > mHigh) { ! mHigh = value; ! // we should combine with the next ! while(mNext != null && value >= mNext.mLow-1) ! { ! mHigh = mNext.mHigh; ! mNext = mNext.mNext; ! if(mNext != null) ! mNext.mPrevious = this; ! } } } } ! public SequenceRange(int low, int high) ! { ! mLow = low; ! mHigh = high; ! mPrevious = null; ! mNext = null; ! } ! public SequenceRange AddRange(int low, int high) { ! if(low <= mHigh + 1 && high >= mLow - 1) // they can combine with us { ! Low = low; ! High = high; ! return this; } ! else // they cannot combine with us (move to the next guy) { ! if(low < mLow) // taking our spot ! { ! SequenceRange rng = new SequenceRange(low, high); ! rng.mNext = this; // new guy is prior to us ! rng.mPrevious = mPrevious; // after our old previous ! if(mPrevious != null) ! mPrevious.mNext = rng; ! mPrevious = rng; ! return rng; // new root node ! } ! else if(mNext == null) // nobody is after us ! { ! SequenceRange rng = new SequenceRange(low, high); ! rng.mPrevious = this; ! mNext = rng; ! return this; ! } ! else ! { ! mNext.AddRange(low, high); ! return this; ! } } } + + public override string ToString() + { + return mLow + ":" + mHigh + (mNext != null ? "," + mNext.ToString() : string.Empty); + } + } + + private SequenceRange mRootNode; + + public void AddRange(int num) + { + AddRange(num, num); } + public void AddRange(int start, int end) + { + int low = Math.Min(start, end); + int high = Math.Max(start, end); + + if(mRootNode == null) + mRootNode = new SequenceRange(low, high); + else + mRootNode = mRootNode.AddRange(low, high); + } + + // private void AddHelper(int lowVal, int highVal) + // { + // for(int idx = 0; idx < mStartRange.Count; ++idx) + // { + // if(lowVal == (int)mStartRange[idx]) // we start on the same value, wee! + // { + // if(highVal > (int)mEndRange[idx]) // we end higher, change some stuff + // AddHelperHelper(idx, highVal); + // break; + // } + // else if(lowVal > (int)mStartRange[idx]) // we start higher then this guy starts + // { + // if(lowVal <= (int)mEndRange[idx]+1) // we start lower or on this guys end+1 + // { + // if(highVal > (int)mEndRange[idx]) // we end higher, change some stuff + // AddHelperHelper(idx, highVal); + // break; + // } + // else if(idx == mStartRange.Count-1) // start higher then end and at the end of ranges, just add + // { + // mStartRange.Insert(idx+1, lowVal); + // mEndRange.Insert(idx+1, highVal); + // } + // } + // else // we start lower then this guy starts + // { + // if(highVal > (int)mStartRange[idx]) // we end higher or on this guys start+1 + // { + // // need to adjust start + // mStartRange[idx] = lowVal; + // + // if(highVal > (int)mEndRange[idx]) // we end higher then this guy ends + // AddHelperHelper(idx, highVal); + // break; + // } + // continue; + // } + // } + // } + // + // private void AddHelperHelper(int idx, int highVal) + // { + // // firstly, adjust the end + // mEndRange[idx] = Math.Max(highVal, (int)mEndRange[idx]); + // + // ++idx; + // + // // while we haven't exhausted the array and we can combine sequences + // while(idx < mStartRange.Count && highVal > (int)mStartRange[idx]) + // { + // // this range can consume the entire next range + // if(highVal >= (int)mEndRange[idx]) + // { + // mStartRange.RemoveAt(idx); + // mEndRange.RemoveAt(idx); + // continue; // still need to see how much more we can eat + // } + // else // we need to combine the ranges + // { + // // make previous range all inclusive + // mEndRange[idx-1] = mEndRange[idx]; + // mStartRange.RemoveAt(idx); + // mEndRange.RemoveAt(idx); + // break; // done + // } + // } + // } + public override string ToString() { ! return mRootNode.ToString(); } } |