private string AddItemContent(QueryBase query, string returnData)
        {
            if (string.IsNullOrEmpty(returnData))
                return returnData;

            bool addItemData = false;
            int itemDataSnipLen = -1;
            bool snipMatchKeywords = true;
            int keywordMatchOffset = 25;
            List<string> keywords = new List<string>();

            if (query is GeneralQuery) {
                GeneralQuery generalQuery = query as GeneralQuery;
                addItemData = generalQuery.QueryParams.ResultData.HasFlag(QResultData.itemData);
                itemDataSnipLen = generalQuery.QueryParams.ItemDataSnipLen;
                snipMatchKeywords = generalQuery.QueryParams.SnipMatchKeywords;
                keywordMatchOffset = generalQuery.QueryParams.KeywordMatchOffset;
                foreach (QKeywordCond kwCond in from arg in generalQuery.QueryArgs.Conditions where arg is QKeywordCond select arg)
                    keywords.AddRange(from kw in kwCond.Keywords select kw.Keyword);
            }
            else if (query is CustomQuery) {
                CustomQuery customQuery = query as CustomQuery;
                if (customQuery.QueryParams is QSimilarThreadsParam) {
                    addItemData = (customQuery.QueryParams as QSimilarThreadsParam).IncludeItemData;
                    itemDataSnipLen = (customQuery.QueryParams as QSimilarThreadsParam).ItemDataSnipLen;
                }
                else if (customQuery.QueryParams is QSimilarItemsParam) {
                    addItemData = (customQuery.QueryParams as QSimilarItemsParam).IncludeItemData;
                    itemDataSnipLen = (customQuery.QueryParams as QSimilarItemsParam).ItemDataSnipLen;
                }
                foreach (QKeywordCond kwCond in from arg in customQuery.QueryArgs.Conditions where arg is QKeywordCond select arg)
                    keywords.AddRange(from kw in kwCond.Keywords select kw.Keyword);
            }

            if (!addItemData)
                return returnData;

            HtmlAgilityPack.XmlDocument returnDoc = new HtmlAgilityPack.XmlDocument();
            returnDoc.LoadXml(returnData);

            foreach (HtmlAgilityPack.HtmlNode itemNode in returnDoc.DocumentNode.SelectNodes("//item") ?? new HtmlNodeCollection(null)) {
                try {
                    int itemId = itemNode.GetAttributeValue("id", -1);
                    if (itemId == -1)
                        continue;
                    Tuple<string, string, string> subjectBodyMeta = SQLGetItemSubjectBodyMeta(itemId);
                    string subject = subjectBodyMeta.Item1;
                    string body = subjectBodyMeta.Item2;
                    string meta = subjectBodyMeta.Item3;

                    int firstIndex = -1;
                    string title;

                    if (itemDataSnipLen != -1) {
                        for (int i = 0; i < keywords.Count && i < 10; i++) {
                            int index = body.IndexOf(keywords[i], StringComparison.InvariantCultureIgnoreCase);
                            if (index >= 0 && (firstIndex == -1 || index < firstIndex))
                                firstIndex = index;
                        }
                        if (firstIndex > 0)
                            firstIndex -= keywordMatchOffset;
                        while (firstIndex > 0 && !char.IsWhiteSpace(body[firstIndex]))
                            firstIndex--;
                        if (firstIndex + itemDataSnipLen > body.Length)
                            firstIndex = body.Length - itemDataSnipLen;
                        firstIndex = Math.Max(0, firstIndex);
                        body = body.Substring(firstIndex, Math.Min(itemDataSnipLen, body.Length - firstIndex));
                        title = "shortContent";
                    }
                    else
                        title = "fullContent";
                    HtmlNode bodyNode = returnDoc.CreateElement(title);
                    bodyNode.AppendChild(returnDoc.CreateTextNode(body.EncodeXMLString()));
                    itemNode.AppendChild(bodyNode);

                    HtmlNode subjectNode = returnDoc.CreateElement("subject");
                    subjectNode.AppendChild(returnDoc.CreateTextNode(subject.EncodeXMLString()));
                    itemNode.AppendChild(subjectNode);

                    HtmlNode metaNode = returnDoc.CreateElement("metaData");
                    metaNode.AppendChild(returnDoc.CreateTextNode(meta));
                    itemNode.AppendChild(metaNode);
                }
                catch (Exception ex) {
                    GenLib.Log.LogService.LogException("MailData. AddItemContent: ", ex);
                }
            }

            returnData = returnDoc.DocumentNode.InnerHtml;
            return returnData;
        }
        public string MinerQuery(QueryBase query)
        {
            if (ProfileHandle == -1) return null;
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            if (Settings.StoreToFileQueryRequest)
                StoreToFile("request", query.ToString());
            string ret = null;
            try {
                DateTime start = DateTime.Now;
                lock (_serviceLock) {
                    ret = ItemMinerControl.ItemMiner.Query(ProfileHandle, query.ToString());
                }
            }
            catch (Exception ex) {
                GenLib.Log.LogService.LogException("MailData. MinerQuery: ", ex);
                LogInfo("MailData. MinerQuery: " + ex.Message);
            }

            ret = AddItemContent(query, ret);

            bool includePeopleData = false;
            if (query is GeneralQuery) includePeopleData = (query as GeneralQuery).QueryParams.IncludePeopleData;
            else if (query is CustomQuery) includePeopleData = (query as CustomQuery).QueryParams.IncludePeopleData;
            if (includePeopleData)
                ret = AddPeopleInfoToResults(ret);
            if (Settings.StoreToFileQueryResponse)
                StoreToFile("response", ret);
            string queryType = "";
            if (query is GeneralQuery) queryType = (query as GeneralQuery).QueryParams.ResultData.ToString();
            else if (query is CustomQuery) queryType = (query as CustomQuery).QueryParams.GetType().Name;
            //LogInfo(String.Format("MailData. MinerQuery for query type {0} took {1} ms", queryType, stopwatch.ElapsedMilliseconds));
            return ret;
        }