/// <summary> /// Parse body part information /// </summary> /// <param name="partInfo"> /// A list that contains at least 7 tokens (not checked - DANGER) /// </param> /// <param name="level"> /// The nesting level. /// </param> private static BodyPart ParseBodyInfo(ZIMapParser.Token partInfo, uint level) { ZIMapParser.Token[] list = partInfo.List; BodyPart part = new BodyPart(); part.Part = partInfo.Text; part.Level = level; // 0 := Type part.Type = list[0].QuotedText; // 1 := Subtype part.Subtype = list[1].QuotedText; // 2 := body parameter list (value pairs) ... if(list[2].Type == ZIMapParser.TokenType.List) { ZIMapParser.Token[] pars = list[2].List; for(int ipar=0; ipar+1 < pars.Length; ipar+=2) if(pars[ipar].Text.ToUpper() == "CHARSET") part.Charset = pars[ipar+1].Text; else part.Filename = pars[ipar+1].Text; } // 3 := id part.ID = list[3].QuotedText; // 4 := desciption part.Description = list[4].QuotedText; // 5 := encoding part.Encoding = list[5].QuotedText; // 6 := size if(list[6].Type == ZIMapParser.TokenType.Number) part.Size = list[6].Number; return part; }
public static BodyInfo ParseBodyInfo(string partList) { if(string.IsNullOrEmpty(partList)) return null; ZIMapParser parser = new ZIMapParser(partList); if(parser.Length <= 0 || parser[0].Type != ZIMapParser.TokenType.List) return null; BodyInfo info = new BodyInfo(); info.Info = partList; List<BodyPart> plis = new List<BodyPart>(); List<string> pother = new List<string>(); ParseBodyInfo(plis, pother, parser[0], 0); if(plis.Count > 0) info.Parts = plis.ToArray(); if(pother.Count > 0) info.Other = pother.ToArray(); return info; }
private static void ParseBodyInfo(List<BodyPart> plis, List<string> pother, ZIMapParser.Token list, uint level) { if(list.Type != ZIMapParser.TokenType.List) { string text = list.Text.ToUpper(); if(text == "ALTERNATIVE") { for(int irun=0; irun < plis.Count; irun++) if(plis[irun].Level != level) continue; else plis[irun].Alternative = true; } if(text == "RELATED") { for(int irun=0; irun < plis.Count; irun++) if(plis[irun].Level != level) continue; else plis[irun].Related = true; } else { //Console.WriteLine("{0} Final: {1}", level, list.Text); pother.Add(list.Text); } return; } uint ulen = (uint)list.List.Length; if(ulen >= 7 && list.List[2].Type == ZIMapParser.TokenType.List) { plis.Add(ParseBodyInfo(list, level)); return; } foreach(ZIMapParser.Token tok in list.List) ParseBodyInfo(plis, pother, tok, level+1); }
protected override bool Parse(bool reset) { if(reset) { items = null; return true; } ZIMapProtocol.ReceiveData data = Result; if(data.Infos == null) return false; items = new Item[data.Infos.Length]; int ilit=0; // literal index for(int irun=0; irun < items.Length; irun++) { uint sequ; if(!uint.TryParse(data.Infos[irun].Status, out sequ)) continue; // status not a number items[irun].Index = sequ; ZIMapParser parser = new ZIMapParser(data.Infos[irun].Message); if(parser.Length < 2 || parser[0].Text != command) continue; // not for "FETCH" if(parser[1].Type != ZIMapParser.TokenType.List) continue; // server error ZIMapParser.Token[] tokens = parser[1].List; List<string> parts = null; uint ulit = 0; for(int itok=0; itok < tokens.Length; itok++) { ZIMapParser.Token token = tokens[itok]; if(token.Type == ZIMapParser.TokenType.Literal) { if(ulit == 0) // count literals { for(int icnt=itok+1; icnt < tokens.Length; icnt++) if(tokens[icnt].Type == ZIMapParser.TokenType.Literal) ulit++; if(ulit > 0) { items[irun].Data = new byte[ulit+1][]; ulit = 1; } else ulit = uint.MaxValue; } if(data.Literals == null || ilit >= data.Literals.Length) MonitorError("Fetch: literal missing: " + ilit); else { if(data.Literals[ilit].Length == token.Number) { if(ulit == uint.MaxValue) items[irun].Data = Result.Literals[ilit]; else { ((byte[][])items[irun].Data)[ulit-1] = Result.Literals[ilit]; ulit++; } } else MonitorError("Fetch: literal invalid: " + ilit); ilit++; } } else if(token.Text == "UID") { if(itok+1 >= tokens.Length) continue; // server bug token = tokens[itok+1]; // should be a number if(token.Type == ZIMapParser.TokenType.Number) { items[irun].UID = token.Number; itok++; } } else if(token.Text == "FLAGS") { if(itok+1 >= tokens.Length) continue; // server bug token = tokens[itok+1]; // should be a list if(token.Type == ZIMapParser.TokenType.List) { string[] flis = ZIMapConverter.StringArray(token.List.Length); items[irun].Flags = flis; int isub=0; foreach(ZIMapParser.Token flag in token.List) flis[isub++] = flag.Text; itok++; } } else if(token.Text == "RFC822.SIZE") { if(itok+1 >= tokens.Length) continue; // server bug token = tokens[itok+1]; // should be a number if(token.Type == ZIMapParser.TokenType.Number) { items[irun].Size = token.Number; itok++; } } else { if(parts == null) parts = new List<string>(); parts.Add(token.ToString()); } } if(parts != null) items[irun].Parts = parts.ToArray(); } return true; }
protected override bool Parse(bool reset) { if(reset) { roots = null; return base.Parse(reset); } ZIMapProtocol.ReceiveData data = Result; if(data.Infos == null) return false; List<Item> list = new List<Item>(); foreach(ZIMapProtocol.ReceiveInfo info in data.Infos) { ZIMapParser parser = new ZIMapParser(info.Message); if(parser.Length < 1) continue; // server bug if(info.Status == "QUOTAROOT") // not for us { int icnt = parser.Length; roots = new string[icnt]; for(int irun=0; irun < icnt; irun++) roots[irun] = parser[irun].Text; } if(info.Status != "QUOTA") continue; // not for us... if(parser.Length < 2 || parser[1].Type != ZIMapParser.TokenType.List) continue; // ignore this ZIMapParser.Token[] triplet = parser[1].List; for(int irun=0; irun < triplet.Length; irun += 3) { if(triplet.Length - irun < 3 || triplet[irun+1].Type != ZIMapParser.TokenType.Number || triplet[irun+2].Type != ZIMapParser.TokenType.Number) { MonitorError("Invalid data: " + info); break; } Item item = new Item(); item.RootName = parser[0].Text; item.Resource = triplet[irun].Text; item.Usage = triplet[irun+1].Number; item.Limit = triplet[irun+2].Number; list.Add(item); } } if(roots == null) return false; // got no QUOTAROOT quota = list.ToArray(); return true; }
protected override bool Parse(bool reset) { base.Parse(reset); if(reset) { messages = recent = unseen = 0; args = null; return true; } ZIMapProtocol.ReceiveData data = Result; if(data.Infos == null) return false; if(!IsReady) return false; // get flags. exists and recent are special... foreach(ZIMapProtocol.ReceiveInfo i in data.Infos) { if(i.Status == "FLAGS") flags = i.Message; else if(i.Message == "EXISTS") uint.TryParse(i.Status, out messages); else if(i.Message == "RECENT") uint.TryParse(i.Status, out recent); } // search for unseen ... foreach(ZIMapProtocol.ReceiveInfo i in data.Infos) { if(i.Status != "OK") continue; ZIMapParser parser = new ZIMapParser(i.Message); if(parser.Length < 1) continue; if(parser[0].Type != ZIMapParser.TokenType.Bracketed) continue; parser = new ZIMapParser(parser[0].Text); if(parser.Length < 2) continue; if(parser[0].Text == "UNSEEN") { unseen = parser[1].Number; break; } } // get the readonly flag ZIMapParser.Token access = data.Parser[0]; if(access.Type == ZIMapParser.TokenType.Bracketed) { if(access.Text == "READ-ONLY") readOnly = true; else if(access.Text == "READ-WRITE") readOnly = false; } data.Parser = null; return true; }
protected override bool Parse(bool reset) { if(reset) { items = null; return true; } ZIMapProtocol.ReceiveData data = Result; if(data.Infos == null) return false; items = new Item[data.Infos.Length]; for(int irun=0; irun < items.Length; irun++) { uint sequ; if(!uint.TryParse(data.Infos[irun].Status, out sequ)) continue; // status not a number ZIMapParser parser = new ZIMapParser(data.Infos[irun].Message); if(parser.Length < 2 || parser[0].Text != "FETCH") continue; // not for "FETCH" if(parser[1].Type != ZIMapParser.TokenType.List) continue; // server error ZIMapParser.Token[] tokens = parser[1].List; List<string> parts = null; for(int itok=0; itok < tokens.Length; itok++) { ZIMapParser.Token token = tokens[itok]; if(token.Text == "UID") { if(itok+1 >= tokens.Length) continue; // server bug token = tokens[itok+1]; // should be a number if(token.Type == ZIMapParser.TokenType.Number) { items[irun].UID = token.Number; itok++; } } else if(token.Text == "FLAGS") { if(itok+1 >= tokens.Length) continue; // server bug token = tokens[itok+1]; // should be a list if(token.Type == ZIMapParser.TokenType.List) { string[] flis = ZIMapConverter.StringArray(token.List.Length); items[irun].Flags = flis; int isub=0; foreach(ZIMapParser.Token flag in token.List) flis[isub++] = flag.Text; itok++; } } else { if(parts == null) parts = new List<string>(); parts.Add(token.ToString()); } } if(parts != null) items[irun].Parts = parts.ToArray(); } return true; }
/// <summary> /// Return information from the parsed reply of the NAMESPACE command. /// </summary> /// <param name="nsIndex"> /// Selects the returned <see cref="Namespace"/> information<para/> /// <list type="table"><listheader> /// <term>nsIndex Value</term> /// <description>Selected Namespace</description> /// </listheader><item> /// <term>Personal (0)</term> /// <description>The current user's namepace (INBOX)</description> /// </item><item> /// <term>Others (1)</term> /// <description>Other users</description> /// </item><item> /// <term>Shared (2)</term> /// <description>Shared folders</description> /// </item><item> /// <term>Search (3)</term> /// <description>Pseudo-Namespace for search results</description> /// </item><item> /// <term>Nothing (uint.MaxValue)</term> /// <description>Invalid, returns <c>null</c></description> /// </item></list> /// </param> /// <returns> /// A <see cref="Namespace"/> item that contains parsed data. /// The server may have sent items that get ignored by this /// parser (multiple entries for a namespace and annotations). /// <para/> /// When the <paramref name="nsIndex"/> argument is invalid, the method /// returns <c>null</c>. /// </returns> public virtual Namespace NamespaceData(uint nsIndex) { if(nsIndex > Search) return null; if(namespdata == null) namespdata = new Namespace[Search+1]; if(namespdata[nsIndex] != null) return namespdata[nsIndex]; // Preinit: namespace not valid namespdata[nsIndex] = new Namespace(); namespdata[nsIndex].Prefix = ""; namespdata[nsIndex].Qualifier = ""; namespdata[nsIndex].Index = nsIndex; // Get namespace info if namespaces are enabled ... if(namespaceOK) { string list = NamespaceList(nsIndex); if(list != null) { ZIMapParser parser = new ZIMapParser(list); if(parser.Length > 0 && parser[0].Type == ZIMapParser.TokenType.List) { ZIMapParser.Token[] toks = parser[0].List; if(toks.Length > 0) namespdata[nsIndex].Prefix = toks[0].Text; if(toks.Length > 1) { string del = toks[1].Text; if(!string.IsNullOrEmpty(del)) { namespdata[nsIndex].Delimiter = del[0]; namespdata[nsIndex].Valid = true; } } } } } // Postinit: fix-up if(!namespdata[nsIndex].Valid) namespdata[nsIndex].Delimiter = factory.HierarchyDelimiter; string pref = namespdata[nsIndex].Prefix; int plen = pref.Length; if(plen > 0 && pref[plen-1] == namespdata[nsIndex].Delimiter) namespdata[nsIndex].Qualifier = pref.Substring(0, plen - 1); else namespdata[nsIndex].Qualifier = pref; return namespdata[nsIndex]; }
// helper used for lists private void Parse(string message, ref int start) { TokenType state = TokenType.Void; bool skip = false; StringBuilder sb = new StringBuilder(); int len = message.Length; // dummy space at the end int idx = start; for(; idx <= len; idx++) { char curr = (idx >= len) ? ' ' : message[idx]; switch(state) { case TokenType.Void: if(curr == ' ') continue; skip = false; sb.Length = 0; if(curr == '"') state = TokenType.Quoted; else if(curr >= '0' && curr <= '9') { state = TokenType.Number; sb.Append(curr); } else if(curr == '(') { idx++; List<Token> list = new ZIMapParser(message, ref idx).tokens; tokens.Add(new Token(list.ToArray(), TokenType.List)); idx--; // should be ')' continue; } else if(curr == ')' && start > 0) { len=0; break; } else if(curr == '{') state = TokenType.Literal; else if(curr == '[') state = TokenType.Bracketed; else { state = TokenType.Text; sb.Append(curr); } break; case TokenType.Bracketed: if(curr == ']') { tokens.Add(new Token(sb.ToString(), state)); state = TokenType.Void; continue; } sb.Append(curr); break; case TokenType.Literal: if(curr == '}') { tokens.Add(new Token(sb.ToString(), state)); state = TokenType.Void; continue; } if(curr < '0' || curr > '9') state = TokenType.Text; sb.Append(curr); break; case TokenType.Number: if(curr == ')' || curr == ']') { curr = ' '; idx--; } if(curr == ' ' || curr == '[') { tokens.Add(new Token(sb.ToString(), state)); state = TokenType.Void; if(curr == '[') idx--; continue; } if(curr < '0' || curr > '9') state = TokenType.Text; sb.Append(curr); break; case TokenType.Quoted: if(skip) skip = false; else if(curr == '\\') skip = true; else if(curr == '"') { tokens.Add(new Token(sb.ToString(), state)); state = TokenType.Void; } else sb.Append(curr); break; default: // text if(curr == ')' || curr == ']') { curr = ' '; idx--; } if(curr == ' ' || curr == '[') { tokens.Add(new Token(sb.ToString(), state)); state = TokenType.Void; if(curr == '[') idx--; continue; } sb.Append(curr); break; } } start = idx; }
/// <summary> /// Search a string array of partially parserd data for an item. /// </summary> /// <param name="parts"> /// The string array to be searched. /// </param> /// <param name="item"> /// The item to be searched for. /// </param> /// <param name="text"> /// Returns the text from array element that follows the item on success. /// Will return an empty string on error. Should never return <c>null</c>. /// </param> /// <returns> /// On success a value of <c>true</c> is returned. /// </returns> /// <remarks> /// The commands FETCH and STORE can return data that is only partially parsed in /// their Item arrays. This function is provided to help searching such data. /// The following example tries to retrieve 'INTERNALDATE' from a FETCH:<para /> /// <example><code lang="C#"> /// DateTime date; /// string sdat; /// if (ZIMapFactory.FindInParts(item.Parts, "INTERNALDATE", out sdat)) /// date = ZIMapConverter.DecodeIMapTime(sdat, true); /// else /// date = msg.DateBinary; /// </code></example> /// </remarks> public static bool FindInParts(string[] parts, string item, out string text) { text = ""; int idx = FindInStrings(parts, 0, item, false); if(idx < 0) return false; // item not found if(++idx >= parts.Length) return false; // no value text = parts[idx]; if(text.Length > 0 && text[0] == '"') // must unquote { ZIMapParser parser = new ZIMapParser(text); text = parser[0].Text; } return true; }
// ============================================================================= // Command execution // ============================================================================= /// <summary> /// A simple overload for <see cref="Execute(string, string[], string[])"/> /// </summary> /// <param name="cmd"> /// Comand string to be executed. /// </param> /// <returns> /// <c>true</c> on success. /// </returns> public static bool Execute(string cmd) { UnparsedCommand = cmd; // Debug stuff #if DEBUG if(cmd == "xxx") { ZIMapFactory.Bulk bulk = new ZIMapFactory.Bulk(App.Factory, "Examine", 8, false); uint urub = 0; uint urdy = 0; uint umax = 5000; ZIMapCommand.Generic cmdb = null; while(urdy < umax) { if(bulk.NextCommand(ref cmdb)) { cmdb.CheckSuccess(); urdy++; ProgressReporting.Update(urdy, umax); cmdb.Reset(); } if(urub++ < umax) { //cmdb.AddLiteral("unfug"); cmdb.AddString("unfug"); cmdb.AddString("unfugxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); cmdb.Queue(); } } bulk.Dispose(); return true; } #endif List<string> opts = new List<string>(); List<string> args = new List<string>(); if(!string.IsNullOrEmpty(cmd)) { ZIMapParser parser = new ZIMapParser(cmd); cmd = parser[0].ToString(); bool bimap = cmd == "imap"; for(int irun=1; irun < parser.Length; irun++) { ZIMapParser.Token token = parser[irun]; if(!bimap && token.Type == ZIMapParser.TokenType.Quoted) args.Add(token.Text); else if(token.Type != ZIMapParser.TokenType.Text || token.Text.Length <= 1 || !(token.Text[0] == '-' || token.Text[0] == '/')) args.Add(token.ToString()); else opts.Add(token.Text.Substring(1)); } } ErrorCalled = false; bool bok = Execute(ref cmd, opts.ToArray(), args.ToArray()); UnparsedCommand = null; if(bok) return true; if(!ErrorCalled) Error("Command failed: {0}", cmd); return false; }
/// <summary> /// Resets the structure to it's initial state /// </summary> /// <remarks> /// Call this method to release resources (mostly the parser). /// </remarks> public void Reset() { Status = Message = null; parser = null; }