/// <summary>
        /// 別スレッドとして受信処理を行うメソッドです。
        /// </summary>
        private void OpenInternal()
        {
            // 完了状態を表す
            CompleteStatus status = CompleteStatus.Success;

            List <ThreadHeader> items = null;

            try {
                OnLoading(new EventArgs());

                if (OpenReader(boardInfo))
                {
                    items = Reading();

                    if (canceled)
                    {
                        return;
                    }

                    headerList.AddRange(items);
                    Invoke(new WriteListMethodInvoker(WriteInternal), new object[] { items });
                }
            }
            catch (Exception ex)
            {
                status = CompleteStatus.Error;
                OnStatusTextChanged(ex.Message);
                TwinDll.Output(ex);
            }
            finally {
                if (canceled)
                {
                    status = CompleteStatus.Error;
                }

                if (baseReader != null)
                {
                    baseReader.Close();
                }

                canceled = false;

                if (thread != null)
                {
                    lock (thread)
                        thread = null;
                }

                OnComplete(new CompleteEventArgs(status));

                if (status == CompleteStatus.Success)
                {
                    OnStatusTextChanged(
                        String.Format("{0}板の読み込みを完了 (総数: {1})",
                                      boardInfo.Name, headerList.Count));
                }
            }
        }
예제 #2
0
        /// <summary>
        /// 指定した板の既得インデックスを読み込む
        /// </summary>
        /// <param name="cache"></param>
        /// <param name="board"></param>
        /// <returns></returns>
        public static List <ThreadHeader> Read(Cache cache, BoardInfo board)
        {
            if (cache == null)
            {
                throw new ArgumentNullException("cache");
            }
            if (board == null)
            {
                throw new ArgumentNullException("board");
            }

            List <ThreadHeader> items = new List <ThreadHeader>();
            string indicesPath        = GetIndicesPath(cache, board);

            if (File.Exists(indicesPath))
            {
                XmlDocument document = new XmlDocument();

                lock (typeof(GotThreadListIndexer))
                {
                    document.Load(indicesPath);
                }

                XmlElement  root     = document.DocumentElement;
                XmlNodeList children = root.ChildNodes;

                foreach (XmlNode node in children)
                {
                    try
                    {
                        ThreadHeader header = TypeCreator.CreateThreadHeader(board.Bbs);
                        header.BoardInfo = board;
                        header.Key       = node.Attributes.GetNamedItem("key").Value;
                        header.Subject   = node.SelectSingleNode("subject").InnerText;

                        int resCount;
                        if (Int32.TryParse(node.SelectSingleNode("resCount").InnerText, out resCount))
                        {
                            header.ResCount = resCount;
                        }

                        items.Add(header);
                    }
                    catch (Exception ex)
                    {
                        TwinDll.Output(ex);
                    }
                }
            }

            return(items);
        }
예제 #3
0
 /// <summary>
 /// 指定した板のログと書込履歴を削除
 /// </summary>
 /// <param name="board"></param>
 /// <returns></returns>
 public virtual void Remove(BoardInfo board)
 {
     if (board != null)
     {
         try {
             string folder = GetFolderPath(board);
             Directory.Delete(folder, true);
         }
         catch (Exception ex) {
             TwinDll.Output(ex);
         }
     }
 }
예제 #4
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);
                }
            }
        }
예제 #5
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);
        }
예제 #6
0
        /// <summary>
        /// オンラインで板一覧を更新 ([BBS MENU for 2ch]に対応)
        /// </summary>
        /// <param name="url">更新先URL</param>
        /// <param name="callback">板が移転していた場合に呼ばれるコールバック</param>
        public void OnlineUpdate(string url, BoardUpdateEventHandler callback)
        {
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);

            req.Headers.Add("Pragma", "no-cache");
            req.Headers.Add("Cache-Control", "no-cache");

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

            try
            {
                IBoardTable newTable = new KatjuBoardTable();
                string      htmlData;

                using (StreamReader sr = new StreamReader(res.GetResponseStream(), Encoding.GetEncoding("Shift_Jis")))
                    htmlData = sr.ReadToEnd();

                res.Close();
                res = null;

                // 2012/12/05 Mizutama実装
                // 板情報を抽出
                // <BR><BR><B>カテゴリ名</B><BR>
                // <A HREF=http://[サーバー]/[板名]/>名前</A>
                MatchCollection cats = Regex.Matches
                                       (
                    htmlData,
                    @"<BR><BR><B>(?<cat>.+?)</B><BR>(?<brds>.+?)(?=\<BR\>\<BR\>\<B\>)",
                    RegexOptions.Singleline | RegexOptions.IgnoreCase
                                       );
                foreach (Match m in cats)
                {
                    Category category = new Category(m.Groups["cat"].Value);

                    MatchCollection brds = Regex.Matches
                                           (
                        m.Groups["brds"].Value,
                        @"<A HREF=(?<url>[^\s>]+).*?>(?<subj>.+?)</A>",
                        RegexOptions.Singleline | RegexOptions.IgnoreCase
                                           );
                    foreach (Match matchBrd in brds)
                    {
                        // ボード情報を作成
                        BoardInfo newBoard = URLParser.ParseBoard(matchBrd.Groups["url"].Value);
                        if (newBoard != null)
                        {
                            newBoard.Name = matchBrd.Groups["subj"].Value;
                            category.Children.Add(newBoard);

                            if (callback != null)
                            {
                                // 新板&移転チェック
                                BoardInfo            old  = FromName(newBoard.Name, newBoard.DomainPath);
                                BoardUpdateEventArgs args = null;

                                // 見つからなければ新板と判断
                                if (old == null)
                                {
                                    args = new BoardUpdateEventArgs(BoardUpdateEvent.New, null, newBoard);
                                }
                                // 見つかったが板のURLが違う場合は移転と判断
                                else if (old.Server != newBoard.Server)
                                {
                                    args = new BoardUpdateEventArgs(BoardUpdateEvent.Change, old, newBoard);
                                }

                                if (args != null)
                                {
                                    callback(this, args);
                                }
                            }
                        }
                    }

                    if (category.Children.Count > 0)
                    {
                        newTable.Items.Add(category);
                    }
                }

                if (newTable.Items.Count > 0)
                {
                    // 新しい板一覧を設定
                    Items.Clear();
                    Items.AddRange(newTable.Items);
                }
                else
                {
                    throw new ApplicationException("板一覧の更新に失敗しました");
                }
            }
            catch (ThreadAbortException)
            {
                if (callback != null)
                {
                    callback(this, new BoardUpdateEventArgs(BoardUpdateEvent.Cancelled, null, null));
                }
            }
            catch (Exception ex)
            {
                TwinDll.ShowOutput(ex);
            }
            finally
            {
                if (res != null)
                {
                    res.Close();
                }
            }
        }
        /// <summary>
        /// textを解析
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        protected virtual string Parse(string text)
        {
            if (text == null)
            {
                throw new ArgumentNullException("text");
            }

            try
            {
                // 2ch_Xを検索する正規表現
                Regex regex2chx = new Regex(@"<!--\s*?(2ch_X:\w+)\s*?-->",
                                            RegexOptions.IgnoreCase | RegexOptions.Singleline);

                // タイトルを検索する正規表現
                Regex regext = new Regex(@"<title>(?<t>.+?)</title>",
                                         RegexOptions.IgnoreCase | RegexOptions.Singleline);

                // 本文を検索する正規表現
                Regex regexb = new Regex(@"(<body.*?>(?<b>.+)</body>)|(</head>(?<b>.+)</body>)",
                                         RegexOptions.IgnoreCase | RegexOptions.Singleline);

                // タイトルを取得
                Match match0 = regext.Match(text);
                if (match0.Success)
                {
                    title    = match0.Groups["t"].Value;
                    response = TitleToStatus(title);
                }

                // 2ch_Xを取得
                Match match1 = regex2chx.Match(text);
                if (match1.Success)
                {
                    response = x2chXToStatus(match1.Value);
                }

                // 本文を取得(タグを取り除く)
                Match match2 = regexb.Match(text);
                if (match2.Success)
                {
                    string result = match2.Groups["b"].Value;

                    if (result.IndexOf("書き込み確認") != -1)
                    {
                        response = PostResponse.Cookie;
                    }

                    else if (result.IndexOf("クッキーをオンにしてちょ") != -1)
                    {
                        response = PostResponse.Cookie;
                    }

                    else if (result.IndexOf("ERROR - 593") != -1)
                    {
                        response = PostResponse.Samba;

                        Match m = Regex.Match(result, "593 (?<cnt>\\d+) sec");
                        if (m.Success)
                        {
                            Int32.TryParse(m.Groups["cnt"].Value, out sambaCount);
                        }
                    }

                    result    = Regex.Replace(result, "<br>", "\r\n", RegexOptions.IgnoreCase);
                    result    = Regex.Replace(result, "<hr>", "\r\n", RegexOptions.IgnoreCase);
                    result    = Regex.Replace(result, "</?[^>]+>", "");
                    result    = Regex.Replace(result, "\t", "");
                    result    = Regex.Replace(result, "(\r\n|\r|\n){2,}", "\r\n", RegexOptions.Singleline);
                    plainText = result;


                    if (response == PostResponse.Cookie)
                    {
                        MatchCollection matches = Regex.Matches(text, "<input type=hidden name=\"?(\\w+?)\"? value=\"?(\\w+?)\"?>", RegexOptions.IgnoreCase);

                        foreach (Match m in matches)
                        {
                            string name  = m.Groups[1].Value;
                            string value = m.Groups[2].Value;

                            hiddenParamsDic.Add(name, value);
#if DEBUG
                            Console.WriteLine("{0}={1}", name, value);
#endif
                        }
                    }
                }

                if (plainText == String.Empty)
                {
                    plainText = htmlText;
                }
            }
            catch (Exception ex)
            {
                TwinDll.Output(ex.ToString());
            }

            return(plainText);
        }
예제 #8
0
        private void OpenInternal()
        {
            CompleteStatus status = CompleteStatus.Success;

            try
            {
                try
                {
                    isWaiting = true;
                    OnLoading(new EventArgs());
                }
                finally
                {
                    isWaiting = false;
                }
                if (canceled)
                {
                    return;
                }

                // 開く処理を行う
                if (modeOpen)
                {
                    Invoke(new MethodInvoker(Opening));
                }

                // キャッシュを読み込み表示
                ReadCache(resCollection);

                if (canceled)
                {
                    return;
                }

                Invoke(new MethodInvoker(WriteBegin));

                if (canceled)
                {
                    return;
                }

                if (modeOpen)
                {
                    Invoke(new WriteResMethodInvoker(Write), new object[] { resCollection });

                    // スクロール位置を復元 (値が0の場合は復元しない)
                    if (modeOpen && headerInfo.Position != 0.0f)
                    {
                        Invoke(new PositionMethodInvoker(SetScrollPosition),
                               new object[] { headerInfo.Position });
                    }
                }

Retry:
                try
                {
                    // サーバーに接続
                    if (OpenReader())
                    {
                        if (canceled)
                        {
                            return;
                        }

                        Reading();

                        // あぼーんを検知した場合
                        if (aboneDetected)
                        {
                        }
                    }
                    else
                    {
                        headerInfo.NewResCount = 0;
                        ThreadIndexer.Write(Cache, headerInfo);
                    }
                }
                finally
                {
                    if (reader != null)
                    {
                        reader.Close();
                    }
                }

                // 再試行が要求された場合、最初から
                if (retried)
                {
                    goto Retry;
                }

                if (canceled)
                {
                    return;
                }


                Invoke(new MethodInvoker(WriteEnd));
            }
            catch (Exception ex)
            {
                status = CompleteStatus.Error;
                //			isOpen = false; #10/15
                TwinDll.Output(ex);
                OnStatusTextChanged(ex.Message);
            }
            finally
            {
                // 中止された場合はETagをリセット
                if (canceled)
                {
                    headerInfo.ETag = String.Empty;
                }

                indicesValues.Clear();

                canceled = false;

                lock (syncObject)
                    thread = null;

                if (status == CompleteStatus.Success)
                {
                    OnStatusTextChanged(
                        String.Format("{0}の読み込みを完了 (新着: {1}件)",
                                      headerInfo.Subject, headerInfo.NewResCount));
                }
                /** 9/26 追加 **/
                else if (reader is X2chAuthenticateThreadReader)
                {
                    X2chRokkaResponseState rokkaState = ((X2chAuthenticateThreadReader)reader).RokkaResponseState;
                    if (rokkaState != X2chRokkaResponseState.Success)
                    {
                        TwinDll.Output("RokkaResponseState: {0}, URL: {1}, ", rokkaState, headerInfo.Url);
                    }
                    OnStatusTextChanged(String.Format("RokkaResponseState: {0}", rokkaState));
                }
                /****/

                IsReading             = false;
                lastCompletedDateTime = DateTime.Now;

                OnComplete(new CompleteEventArgs(status));
            }
        }
예제 #9
0
        /// <summary>
        /// データを読み込む&書き込む
        /// </summary>
        private void Reading()
        {
            ResSetCollection items = new ResSetCollection(),
                             buffer = new ResSetCollection();
            int read = -1, byteParsed, totalByteCount = 0;

            while (read != 0)
            {
                if (canceled)
                {
                    return;
                }

                read = reader.Read(buffer, out byteParsed);

                // あぼーんを検知した場合、処理を中止。
                if (read == -1)
                {
                    aboneDetected = true;
                    return;
                }

                totalByteCount += byteParsed;

                items.AddRange(buffer);

                // 逐次受信の場合はビューアに書き込む
                if (!isPackageReception)
                {
                    if (canceled)
                    {
                        return;
                    }

                    Invoke(new WriteResMethodInvoker(WriteInternal), new object[] { buffer });
                }
                buffer.Clear();

                OnReceive(new ReceiveEventArgs(
                              reader.Length, reader.Position, read));

                OnStatusTextChanged(
                    String.Format("{0} 受信中 ({1}/{2})",
                                  headerInfo.Subject, reader.Position, reader.Length));
            }

            // 一括受信の場合はここで一気にフラッシュ
            if (isPackageReception)
            {
                if (canceled)
                {
                    return;
                }

                Invoke(new WriteResMethodInvoker(WriteInternal), new object[] { items });
            }

            try
            {
                // スレッドのインデックス情報を保存
                storage            = new LocalThreadStorage(Cache, headerInfo, StorageMode.Write);
                storage.BufferSize = bufferSize;
                storage.Write(items);

                headerInfo.GotByteCount += totalByteCount;
                headerInfo.GotResCount  += items.Count;
                headerInfo.NewResCount   = items.Count;
                ThreadIndexer.Write(Cache, headerInfo);
            }
            catch (Exception ex)
            {
                TwinDll.Output(ex);
            }
            finally
            {
                storage.Close();
            }

            SaveThreadListIndices();
        }