Exemple #1
0
        /// <summary>
        /// 指定したスレッドのインデックスを作成
        /// </summary>
        /// <param name="cache"></param>
        /// <param name="header"></param>
        public static void Write(Cache cache, ThreadHeader header)
        {
            if (cache == null)
            {
                throw new ArgumentNullException("cache");
            }
            if (header == null)
            {
                throw new ArgumentNullException("header");
            }

            XmlDocument document    = new XmlDocument();
            string      indicesPath = GetIndicesPath(cache, header.BoardInfo);
            bool        overwrite   = false;

            lock (typeof(GotThreadListIndexer))
            {
                if (File.Exists(indicesPath))
                {
                    document.Load(indicesPath);
                    XmlNode node = document.SelectSingleNode("indices/item[@key=\"" + header.Key + "\"]");
                    if (node != null)
                    {
                        // レス数を更新
                        node.SelectSingleNode("resCount").InnerText = header.ResCount.ToString();
                        overwrite = true;
                    }
                }
                else
                {
                    // ルートを作成
                    document.AppendChild(
                        document.CreateElement("indices"));
                }

                // 存在しなければ新しく作成
                if (!overwrite)
                {
                    GotThreadListFormatter formatter = new GotThreadListFormatter();
                    formatter.AppendChild(document, document.DocumentElement, header);
                }

                // ドキュメントを保存
                XmlTextWriter writer = new XmlTextWriter(indicesPath, TwinDll.DefaultEncoding);
                writer.Formatting = Formatting.Indented;

                document.Save(writer);
                writer.Close();
            }
        }
Exemple #2
0
        private static void SaveValue(Cache cache, ThreadHeader header,
                                      string section, string key, object value)
        {
            lock (typeof(ThreadIndexer))
            {
                string filePath = cache.GetIndexPath(header);

                if (File.Exists(filePath))
                {
                    CSPrivateProfile.SetValue(section, key,
                                              value, filePath);
                }
            }
        }
Exemple #3
0
        /// <summary>
        /// スレッドの既得情報を記録するインデックスを作成します。
        /// </summary>
        /// <param name="filePath">作成するインデックス情報へのパス</param>
        /// <param name="header">作成するインデックス情報が格納されたThreadHeaderクラス</param>
        /// <returns>作成に成功すればtrue、失敗すればfalseを返す</returns>
        public static bool Write(string filePath, ThreadHeader header)
        {
            if (filePath == null)
            {
                throw new ArgumentNullException("filePath");
            }

            if (header == null)
            {
                throw new ArgumentNullException("header");
            }

            lock (typeof(ThreadIndexer))
            {
                CSPrivateProfile profile = new CSPrivateProfile();

                // 板情報
                profile.SetValue("Board", "Server", header.BoardInfo.Server);
                profile.SetValue("Board", "Path", header.BoardInfo.Path);
                profile.SetValue("Board", "Name", header.BoardInfo.Name);
                profile.SetValue("Board", "BBS", header.BoardInfo.Bbs);

                // スレッド情報
                profile.SetValue("Thread", "ETag", header.ETag);
                profile.SetValue("Thread", "LastModified", header.LastModified);
                profile.SetValue("Thread", "LastWritten", header.LastWritten);
                profile.SetValue("Thread", "Subject", header.Subject);
                profile.SetValue("Thread", "ResCount", header.ResCount);
                profile.SetValue("Thread", "GotResCount", header.GotResCount);
                profile.SetValue("Thread", "GotByteCount", header.GotByteCount);
                profile.SetValue("Thread", "NewResCount", header.NewResCount);
                profile.SetValue("Thread", "Key", header.Key);

                // 拡張情報
                profile.SetValue("Option", "UseGzip", header.UseGzip);
                profile.SetValue("Option", "Pastlog", header.Pastlog);
                profile.SetValue("Option", "Position", header.Position);
                profile.SetValue("Option", "Shiori", header.Shiori);
                profile.SetValue("Option", "RefCount", header.RefCount);
                profile.SetValue("Option", "Sirusi", header.Sirusi.ToArrayString());

                profile.Write(filePath);
            }

            return(true);
        }
Exemple #4
0
        /// <summary>
        /// 指定したスレッドのローカル上のパスを取得
        /// </summary>
        /// <param name="header"></param>
        /// <returns></returns>
        public virtual string GetDatPath(ThreadHeader header)
        {
            if (header == null)
            {
                throw new ArgumentNullException("header");
            }

            string extension = String.Empty;
            string folder    = GetFolderPath(header.BoardInfo, false);

            if (header.UseGzip)
            {
                extension = ".gz";
            }

            return(Path.Combine(folder, header.Key + ".dat" + extension));
        }
        /// <summary>
        /// 非同期でメッセージを投稿
        /// </summary>
        /// <param name="header">投稿先のスレッド</param>
        /// <param name="res">投稿する内容</param>
        /// <param name="callback">投稿完了時に呼ばれるコールバック</param>
        /// <param name="state">ユーザー指定のオブジェクト</param>
        /// <returns></returns>
        public virtual IAsyncResult BeginPost(ThreadHeader header, PostRes res,
                                              AsyncCallback callback, object state)
        {
            if (header == null)
            {
                throw new ArgumentNullException("header");
            }

            if (methodR != null ||
                methodT != null)
            {
                throw new InvalidOperationException("一度に複数の非同期呼び出しは出来ません");
            }

            methodR = new PostResHandler(Post);
            return(methodR.BeginInvoke(header, res, callback, state));
        }
Exemple #6
0
        /// <summary>
        /// 現在のインスタンスとheaderを比較
        /// </summary>
        /// <param name="header"></param>
        /// <returns></returns>
        public bool Equals(ThreadHeader header)
        {
            if (header == null)
            {
                return(false);
            }

            if (board.Path == header.board.Path && key == header.key)
            {
                return(true);
            }

            else
            {
                return(false);
            }
        }
Exemple #7
0
        /// <summary>
        /// 指定したスレッドのインデックスを削除
        /// </summary>
        public static void Delete(Cache cache, ThreadHeader header)
        {
            if (cache == null)
            {
                throw new ArgumentNullException("cache");
            }
            if (header == null)
            {
                throw new ArgumentNullException("header");
            }

            lock (typeof(ThreadIndexer))
            {
                // インデックスファイルへのパス
                string filePath = cache.GetIndexPath(header);
                File.Delete(filePath);
            }
        }
Exemple #8
0
        /// <summary>
        /// インデックスを作成
        /// </summary>
        /// <param name="cache"></param>
        /// <param name="header">作成するインデックス情報が格納されたThreadHeaderクラス</param>
        /// <returns>作成に成功すればtrue、失敗すればfalseを返す</returns>
        public static bool Write(Cache cache, ThreadHeader header)
        {
            if (cache == null)
            {
                throw new ArgumentNullException("cache");
            }

            string filePath = cache.GetIndexPath(header);

            // ディレクトリが存在しなければ作成
            string dir = Path.GetDirectoryName(filePath);

            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }

            return(Write(filePath, header));
        }
Exemple #9
0
        private void LoadRecursive(XmlNode node, BookmarkFolder folder)
        {
            // フォルダを作成
            folder.Name     = node.Attributes["Name"].Value;
            folder.Expanded = Boolean.Parse(node.Attributes["Expanded"].Value);

            XmlAttribute id = node.Attributes["ID"];

            if (id != null)
            {
                BookmarkEntry.SetEntryId(folder, Int32.Parse(id.Value));
            }

            // 子ノードを検索
            foreach (XmlNode subNode in node.SelectNodes("Children/Folder"))
            {
                BookmarkFolder subFolder = new BookmarkFolder();
                folder.Children.Add(subFolder);
                LoadRecursive(subNode, subFolder);
            }

            // お気に入りコレクションを検索
            foreach (XmlNode child in node.SelectNodes("Children/Item"))
            {
                string       url    = child.Attributes["URL"].Value;
                ThreadHeader header = URLParser.ParseThread(url);

                if (header != null)
                {
                    //XmlAttribute idattr = child.Attributes["ID"];
                    BookmarkEntry entry = null;

                    header.Subject = child.InnerText;

                    //if (idattr != null)
                    //	entry = new BookmarkThread(header, Int32.Parse(idattr.Value));
                    //else
                    entry = new BookmarkThread(header);

                    folder.Children.Add(entry);
                }
            }
        }
Exemple #10
0
        /// <summary>
        /// 指定したスレッドのインデックスを削除
        /// </summary>
        /// <param name="cache"></param>
        /// <param name="header"></param>
        public static void Remove(Cache cache, ThreadHeader header)
        {
            if (cache == null)
            {
                throw new ArgumentNullException("cache");
            }
            if (header == null)
            {
                throw new ArgumentNullException("header");
            }

            XmlDocument document    = new XmlDocument();
            string      indicesPath = GetIndicesPath(cache, header.BoardInfo);

            lock (typeof(GotThreadListIndexer))
            {
                if (File.Exists(indicesPath))
                {
                    document.Load(indicesPath);
                    XmlNode node = document.SelectSingleNode("indices/item[@key=\"" + header.Key + "\"]");

                    if (node != null)
                    {
                        document.DocumentElement.RemoveChild(node);
                    }

                    // 1つも要素が無くなったらファイル自体を削除
                    if (document.DocumentElement.ChildNodes.Count == 0)
                    {
                        File.Delete(indicesPath);
                    }
                    else
                    {
                        XmlTextWriter writer = new XmlTextWriter(indicesPath, TwinDll.DefaultEncoding);
                        writer.Formatting = Formatting.Indented;

                        document.Save(writer);
                        writer.Close();
                    }
                }
            }
        }
        public static string GetResponseHtml(ThreadHeader header)
        {
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(header.Url);

            req.UserAgent = String.Empty;

            HttpWebResponse res = (HttpWebResponse)req.GetResponse();

            try
            {
                using (StreamReader r = new StreamReader(res.GetResponseStream(), Encoding.GetEncoding("shift_jis")))
                {
                    return(r.ReadToEnd());
                }
            }
            finally
            {
                res.Close();
            }
        }
Exemple #12
0
        /// <summary>
        /// oldBoardからnewBoardにログを移動
        /// </summary>
        /// <param name="oldItems"></param>
        /// <param name="newBoard"></param>
        private void CopyDatFiles(BoardInfo oldItems, BoardInfo newBoard)
        {
            string fromFolder = cache.GetFolderPath(oldItems);
            string toFolder   = cache.GetFolderPath(newBoard, true);

            string[] fileNames = Directory.GetFiles(fromFolder, "*.dat*");            // .dat .dat.gz を検索

            foreach (string fromPath in fileNames)
            {
                try {
                    string fromName = Path.GetFileName(fromPath);
                    string destPath = Path.Combine(toFolder, fromName);

                    File.Copy(fromPath, destPath, true);
                    File.Delete(fromPath);

                    int token = fromName.IndexOf('.');
                    if (token != -1)
                    {
                        string key           = fromName.Substring(0, token);
                        string fromIndexFile = Path.Combine(fromFolder, key + ".idx");
                        string toIndexFile   = Path.Combine(toFolder, key + ".idx");

                        ThreadHeader h = ThreadIndexer.Read(fromIndexFile);

                        if (h != null)
                        {
                            h.BoardInfo.Server = newBoard.Server;

                            ThreadIndexer.Write(toIndexFile, h);

                            File.Delete(fromIndexFile);
                        }
                    }
                }
                catch (IOException ex)
                {
                    TwinDll.Output(ex);
                }
            }
        }
Exemple #13
0
        /// <summary>
        /// インデックスが存在するかどうかを判断
        /// </summary>
        /// <param name="header">基本的な情報が格納されたThreadHeader</param>
        /// <returns>存在すればtrue、存在しなければfalseを返す</returns>
        public static bool Exists(Cache cache, ThreadHeader header)
        {
            if (cache == null)
            {
                throw new ArgumentNullException("cache");
            }
            if (header == null)
            {
                throw new ArgumentNullException("header");
            }

            bool exists = false;

            lock (typeof(ThreadIndexer))
            {
                // インデックスファイルへのパス
                string filePath = cache.GetIndexPath(header);
                exists = File.Exists(filePath);
            }

            return(exists);
        }
        /// <summary>
        /// 過去ログが存在するかどうかを調べてみる
        /// </summary>
        /// <param name="header"></param>
        /// <returns></returns>
        public static bool KakologIsExist(ThreadHeader header, out bool gzipCompress)
        {
            X2chKakoThreadHeader kako = new X2chKakoThreadHeader();

            header.CopyTo(kako);

            // まず.dat.gzを取得してみて、だめなら.datヲ取得する。
            // それでもだめなら諦める。
            kako.GzipCompress = true;
            bool retried = false;

Retry:
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(kako.DatUrl);

            req.UserAgent = TwinDll.UserAgent;
            req.Headers.Add("Accept-Encoding", "gzip");
            req.Method            = "HEAD";
            req.AllowAutoRedirect = false;

            HttpWebResponse res = (HttpWebResponse)req.GetResponse();

            res.Close();

            if (res.StatusCode == HttpStatusCode.OK)
            {
                gzipCompress = kako.GzipCompress;
                return(true);
            }
            else if (!retried)
            {
                kako.GzipCompress = false;
                retried           = true;
                goto Retry;
            }

            gzipCompress = false;

            return(false);
        }
        /*
         * /// <summary>
         * /// 指定したスレッドの状態を確認
         * /// </summary>
         * /// <param name="header"></param>
         * /// <returns></returns>
         * public static ThreadState CheckState(ThreadHeader header)
         * {
         *      if (header == null)
         *              throw new ArgumentNullException("header");
         *
         *      HttpWebRequest req = (HttpWebRequest)WebRequest.Create(header.Url);
         *      req.UserAgent = TwinDll.IEUserAgent;
         *      HttpWebResponse res = (HttpWebResponse)req.GetResponse();
         *
         *      byte[] data = FileUtility.ReadBytes(res.GetResponseStream());
         *      string html = Encoding.GetEncoding("Shift_Jis").GetString(data);
         *
         *      if (html.IndexOf("そんな板orスレッドないです") >= 0)
         *      {
         *              if (html.IndexOf("隊長! 過去ログ倉庫で") >= 0)
         *                      return ThreadState.Kakolog;
         *
         *              if (html.IndexOf("過去ログ倉庫にもありませんでした") >= 0)
         *                      return ThreadState.NotExists;
         *      }
         *      else if (html.IndexOf("このスレッドは過去ログ倉庫に格納されています") >= 0 ||
         *                      html.IndexOf("もうずっと人大杉") >= 0)
         *      {
         *              return ThreadState.Pastlog;
         *      }
         *
         *      return ThreadState.None;
         * }*/

        /// <summary>
        /// 指定したスレッドのresStartからresEndまでの範囲を取得。
        /// 既得ログに存在すればローカルから読み込む。
        /// </summary>
        /// <param name="cache"></param>
        /// <param name="header"></param>
        /// <param name="resStart"></param>
        /// <param name="resEnd"></param>
        /// <returns></returns>
        public static ResSetCollection GetRange(Cache cache, ThreadHeader header, int resStart, int resEnd)
        {
            if (cache == null)
            {
                throw new ArgumentNullException("cache");
            }

            if (header == null)
            {
                throw new ArgumentNullException("header");
            }

            if (resStart > resEnd)
            {
                throw new ArgumentException("resStartはresEnd以下にしてください", "resStart");
            }

            string address = header.Url + ((resStart == resEnd) ?
                                           resStart.ToString() : String.Format("{0}-{1}", resStart, resEnd));

            // サーバーからデータをダウンロード
            WebClient webClient = new WebClient();

            webClient.Headers.Add("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT; DigExt)");

            byte[] data = webClient.DownloadData(address);
            int    byteParsed;

            // ResSet[]型に解析
            ThreadParser parser = new X2chHtmlThreadParser(BbsType.X2ch, Encoding.GetEncoding("Shift_Jis"));

            ResSet[] array = parser.Parse(data, data.Length, out byteParsed);

            ResSetCollection items = new ResSetCollection();

            items.AddRange(array);

            return(items);
        }
Exemple #16
0
        /// <summary>
        /// ヘッダーとフッター共通の置き換え関数
        /// </summary>
        /// <param name="skinhtml"></param>
        /// <param name="obj"></param>
        /// <returns></returns>
        protected virtual string ReplaceHeaderFooter(string skinhtml, ThreadHeader header)
        {
            ThreadHeader h      = header;
            BoardInfo    b      = h.BoardInfo;
            string       result = skinhtml;

            StringBuilder sb = new StringBuilder(512);

            sb.Append(result);
            sb.Replace("<BOARDNAME/>", b.Name);
            sb.Replace("<BOARDURL/>", b.Url);
            sb.Replace("<THREADNAME/>", h.Subject);
            sb.Replace("<THREADURL/>", h.Url);
            sb.Replace("<ALLRESCOUNT/>", h.ResCount.ToString());
            sb.Replace("<NEWRESCOUNT/>", h.NewResCount.ToString());
            sb.Replace("<GETRESCOUNT/>", (h.GotByteCount - h.NewResCount).ToString());
            sb.Replace("<SKINPATH/>", skinPath);
            sb.Replace("<LASTMODIFIED/>", h.LastModified.ToString());
            sb.Replace("<SIZEKB/>", (h.GotByteCount / 1024).ToString());
            sb.Replace("<SIZE/>", h.GotByteCount.ToString());
            result = sb.ToString();

            return(result);
        }
Exemple #17
0
 /// <summary>
 /// フッターを取得
 /// </summary>
 /// <param name="header"></param>
 /// <returns></returns>
 public abstract string GetFooter(ThreadHeader header);
Exemple #18
0
 /// <summary>
 /// NumberClickEventArgsクラスのインスタンスを初期化
 /// </summary>
 /// <param name="header"></param>
 /// <param name="res"></param>
 public NumberClickEventArgs(ThreadHeader header, ResSet res)
 {
     this.header = header;
     this.resSet = res;
 }
Exemple #19
0
 /// <summary>
 /// BookmarkThreadクラスのインスタンスを初期化
 /// </summary>
 /// <param name="header"></param>
 public BookmarkThread(ThreadHeader header) : this(header, -1)
 {
 }
Exemple #20
0
 public static void SaveLastWritten(Cache cache, ThreadHeader header)
 {
     SaveValue(cache, header, "Thread", "LastWritten", header.LastWritten);
 }
Exemple #21
0
 public static void SavePosition(Cache cache, ThreadHeader header)
 {
     SaveValue(cache, header, "Option", "Position", header.Position);
 }
Exemple #22
0
 /// <summary>
 /// お気に入りにitemが含まれているかどうかを判断
 /// </summary>
 /// <param name="header"></param>
 /// <returns></returns>
 public bool Contains(ThreadHeader header)
 {
     return(Search(header) != null);
 }
Exemple #23
0
 public static void SaveSirusi(Cache cache, ThreadHeader header)
 {
     SaveValue(cache, header, "Option", "Sirusi", header.Sirusi.ToArrayString());
 }
Exemple #24
0
 public static void SaveServerInfo(Cache cache, ThreadHeader header)
 {
     SaveValue(cache, header, "Board", "Server", header.BoardInfo.Server);
 }
Exemple #25
0
        /// <summary>
        /// インデックスを読み込む
        /// </summary>
        /// <param name="filePath">インデックスファイルへのファイルパス</param>
        /// <returns>読み込みに成功すればThreadHeaderのインスタンス、失敗すればnull</returns>
        public static ThreadHeader Read(string filePath)
        {
            if (filePath == null)
            {
                throw new ArgumentNullException("filePath");
            }

            ThreadHeader result = null;

            lock (typeof(ThreadIndexer))
            {
                // インデックスファイルへのパス

                if (File.Exists(filePath))
                {
                    try
                    {
                        CSPrivateProfile profile = new CSPrivateProfile();
                        profile.Read(filePath);

                        // 重要なセクションがなければエラー
                        if (!profile.Sections.ContainsSection("Board") ||
                            !profile.Sections.ContainsSection("Thread"))
                        {
                            return(null);
                        }

                        BbsType bbs = (BbsType)Enum.Parse(typeof(BbsType), profile.GetString("Board", "BBS", "X2ch"));

                        // 板情報
                        result = TypeCreator.CreateThreadHeader(bbs);
                        result.BoardInfo.Server = profile.GetString("Board", "Server", "Error");
                        result.BoardInfo.Path   = profile.GetString("Board", "Path", "Error");
                        result.BoardInfo.Name   = profile.GetString("Board", "Name", "Error");
                        result.BoardInfo.Bbs    = bbs;

                        // スレッド情報
                        result.ETag         = profile.GetString("Thread", "ETag", String.Empty);
                        result.LastWritten  = profile.GetDateTime("Thread", "LastWritten");
                        result.LastModified = profile.GetDateTime("Thread", "LastModified");
                        result.Subject      = profile.GetString("Thread", "Subject", "Error");
                        result.ResCount     = profile.GetInt("Thread", "ResCount", 0);
                        result.GotResCount  = profile.GetInt("Thread", "GotResCount", 0);
                        result.GotByteCount = profile.GetInt("Thread", "GotByteCount", 0);
                        result.NewResCount  = profile.GetInt("Thread", "NewResCount", 0);
                        result.Key          = profile.GetString("Thread", "Key", "Error");

                        // そのほかの情報
                        result.Position = profile.GetFloat("Option", "Position", 0);
                        result.Pastlog  = profile.GetBool("Option", "Pastlog", false);
                        result.UseGzip  = profile.GetBool("Option", "UseGzip", false);
                        result.Shiori   = profile.GetInt("Option", "Shiori", 0);
                        result.RefCount = profile.GetInt("Option", "RefCount", 0);
                        result.Sirusi.FromArrayString(profile.GetString("Option", "Sirusi", ""));
                    }
                    catch (Exception ex)
                    {
                        TwinDll.Output(ex);
                    }
                }
            }

            return(result);
        }
Exemple #26
0
 public static string GetForceValue(ThreadHeader h, ForceValueOf valueType)
 {
     return(new ThreadHeaderInfo(h).GetForceValue(valueType));
 }
Exemple #27
0
 /// <summary>
 /// フッタースキンを取得
 /// </summary>
 /// <param name="header"></param>
 /// <returns></returns>
 public override string GetFooter(ThreadHeader header)
 {
     return(ReplaceHeaderFooter(footerSkin, header));
 }
Exemple #28
0
 public static void SaveBookmark(Cache cache, ThreadHeader header)
 {
     SaveValue(cache, header, "Option", "Shiori", header.Shiori);
 }
Exemple #29
0
 public static void SavePastlog(Cache cache, ThreadHeader header, bool newValue)
 {
     SaveValue(cache, header, "Option", "Pastlog", newValue);
 }
Exemple #30
0
 /// <summary>
 /// 再起検索で指定したお気に入りを検索
 /// </summary>
 /// <param name="header"></param>
 /// <returns></returns>
 public BookmarkThread Search(ThreadHeader header)
 {
     return(Search(this, header));
 }