/// <summary> /// スレッドをdat形式で保存 /// </summary> /// <param name="cache">キャッシュ情報</param> /// <param name="header">保存するスレッド</param> /// <param name="filePath">保存先ファイルパス</param> public static void SaveDat(Cache cache, ThreadHeader header, string filePath) { if (cache == null) { throw new ArgumentNullException("cache"); } if (header == null) { throw new ArgumentNullException("header"); } if (filePath == null) { throw new ArgumentNullException("filePath"); } // datの存在するパスを取得 string fromPath = cache.GetDatPath(header); ThreadStorage reader = null; StreamWriter writer = null; ResSetCollection items = new ResSetCollection(); X2chThreadFormatter formatter = new X2chThreadFormatter(); try { // 読み込みストリームを開く reader = new LocalThreadStorage(cache, header, StorageMode.Read); // 書き込みストリームを開く writer = new StreamWriter(filePath, false, Encoding.GetEncoding("Shift_Jis")); // すべて読み込む while (reader.Read(items) != 0) { ; } writer.Write(formatter.Format(items)); } finally { if (reader != null) { reader.Close(); } if (writer != null) { writer.Close(); } } }
/// <summary> /// メッセージを投稿 /// </summary> /// <param name="header">投稿先のスレッド</param> /// <param name="res">投稿する内容</param> public override void Post(ThreadHeader header, PostRes res) { if (header == null) { throw new ArgumentNullException("header"); } try { // 投稿時刻を作成 int time = GetTime(header.LastModified); // 送信データを作成 bool retried = false; Retry: if (retried) { Thread.Sleep(100); } string uri = String.Format("http://{0}/{1}", header.BoardInfo.Server, postCGIPath); StringBuilder sb = new StringBuilder(); // sb.Append("submit=" + (retried ? UrlEncode("全責任を負うことを承諾して書き込む") : UrlEncode("書き込む"))); sb.Append("submit=" + UrlEncode("書き込む")); sb.Append("&FROM=" + UrlEncode(res.From)); sb.Append("&mail=" + UrlEncode(res.Email)); sb.Append("&MESSAGE=" + UrlEncode(res.Body)); sb.Append("&bbs=" + header.BoardInfo.Path); sb.Append("&key=" + header.Key); sb.Append("&time=" + time); // sb.Append("&hana=mogera"); sb.Append(TwinDll.AditionalAgreementField); sb.Append(TwinDll.AddWriteSection); AddSessionId(sb); byte[] bytes = Encoding.GetBytes(sb.ToString()); Posting(header.BoardInfo, bytes, uri, ref retried); if (retried) { goto Retry; } } catch (Exception ex) { TwinDll.Output(ex); throw ex; } }
/// <summary> /// 指定した板の書き込み履歴に追加 /// </summary> /// <param name="board"></param> /// <param name="res"></param> public void Append(ThreadHeader header, WroteRes res) { try { string filePath = GetKomiPath(header.BoardInfo); StringBuilder sb = new StringBuilder(); sb.AppendFormat("Date: {0}\r\nSubject: {1}\r\nURL: {2}\r\nFrom: {3}\r\nEmail: {4}\r\n\r\n{5}\r\n------------------------\r\n", res.Date.ToString(), header.Subject, header.Url, res.From, res.Email, res.Message); FileUtility.Write(filePath, sb.ToString(), true); } catch (Exception ex) { TwinDll.Output(ex); } }
/// <summary> /// 最新のスレッド一覧を取得し、item の次スレと思われるスレッドを検索します。 /// </summary> /// <param name="item">次スレをチェックするスレッド。</param> public void Check(ThreadHeader item) { if (item == null) { throw new ArgumentNullException("item"); } if (IsChecking) { throw new InvalidOperationException("チェック中です"); } header = item; matchItems.Clear(); Checking(); }
private static ThreadHeader GetThreadHeader(IDomObject titleNode, IDomObject authorNode, MillRequest request, int i) { var titleAnchor = titleNode.Cq().Find("a:first").FirstOrDefault(); if (titleAnchor == null) { throw new ProcessFaultException(request, string.Format("第{0}个title元素里面没有a元素。", i)); } var url = titleAnchor["href"]; var titleText = titleAnchor.Cq().Text().Trim(); var threadId = url.GetThreadId(); if (0 == threadId) { throw new ProcessFaultException(request, string.Format("无法从第{0}个thread url中获取thread id。", i)); } var header = new ThreadHeader { Id = threadId, Url = url, Title = titleText, ReplyCount = -1 }; var authorText = authorNode.Cq().Text(); if (string.IsNullOrWhiteSpace(authorText)) { return(header); } var values = authorText.Replace("[", "").Replace("]", "").Split('/'); if (values.Length != 4) { return(header); } header.UserName = values[0]; int replyCount; if (int.TryParse(values[1], out replyCount)) { header.ReplyCount = replyCount; } return(header); }
/// <summary> /// スレッドを開く /// </summary> /// <param name="th"></param> public override bool Open(ThreadHeader header) { if (header == null) { throw new ArgumentNullException("header"); } retry: // ヘッダが存在する場合はキャッシュストリームを開く if (ThreadIndexer.Exists(cache, header)) { int resCount = header.ResCount; ThreadIndexer.Read(cache, header); header.ResCount = resCount; if (readCache) { storage.Open(header, StorageMode.Read); storage.BufferSize = BufferSize; length = storage.Length; isOpen = storage.IsOpen; } } if (!storage.IsOpen) { try { isOpen = OpenBaseStream(header); } catch (X2chRetryKakologException ex) { header.BoardInfo = ex.RetryBoard; goto retry; } } headerInfo = header; headerInfo.NewResCount = 0; position = 0; return(isOpen); }
/// <summary> /// 指定したスレッドに設定されているコテハンを取得 /// </summary> /// <param name="header">スレッド情報</param> /// <returns>存在すればKotehanクラスのインスタンスを返す。存在しなければデフォルト値</returns> public Kotehan Get(ThreadHeader header) { if (header == null) { throw new ArgumentNullException("header"); } string key = GetSection(header); Kotehan kote = GetInternal(key); if (kote == null) { kote = Get(header.BoardInfo); } return(kote); }
public int Compare(object a, object b) { ThreadHeader itemA = (ThreadHeader)a; ThreadHeader itemB = (ThreadHeader)b; int levela = (int)itemA.Tag; int levelb = (int)itemB.Tag; // itemA が itemB より上に表示させるならマイナスの値、itemB の方が上に表示させるならプラスの値を返す…? int ret = (levelb - levela); if (ret == 0) { // レベルが同一の場合、レス数とスレの勢いで判定する int a_resCount = itemA.ResCount, b_resCount = itemB.ResCount, a_no = itemA.No, b_no = itemB.No; float a_force = new ThreadHeaderInfo(itemA).ForceValueDay, b_force = new ThreadHeaderInfo(itemB).ForceValueDay; // レス数は多いほうが優先 int compareValue = 0; if (a_resCount != b_resCount) { compareValue += (a_resCount - b_resCount) < 0 ? 1 : -1; } // 勢いは多いほうが優先 if (a_force != b_force) { compareValue += (a_force - b_force) < 0 ? 1 : -1; } // スレNOは小さいほうが優先 if (a_no != b_no) { compareValue += (a_no - b_no) < 0 ? -1 : 1; } compareValue += String.Compare(itemA.Subject, itemB.Subject); return(compareValue); } else { return(ret); } }
/// <summary> /// 指定した板に存在する草稿を取得 /// </summary> /// <param name="filePath"></param> public Draft[] Load(BoardInfo board) { if (board == null) { throw new ArgumentNullException("board"); } XmlDocument doc = new XmlDocument(); ArrayList arrayList = new ArrayList(); string filePath = cache.GetFolderPath(board); filePath = Path.Combine(filePath, DraftFileName); try { doc.Load(filePath); // 草稿要素をすべて取得 XmlNodeList nodeList = doc.SelectNodes("draft/thread"); foreach (XmlNode node in nodeList) { ThreadHeader header = TypeCreator.CreateThreadHeader(board.Bbs); header.BoardInfo = board; header.Key = node.Attributes.GetNamedItem("key").Value; if (ThreadIndexer.Read(cache, header) != null) { string name = node.SelectSingleNode("from").InnerText; string email = node.SelectSingleNode("email").InnerText; string body = node.SelectSingleNode("message").InnerText; // 草稿情報を作成 PostRes res = new PostRes(name, email, body); Draft draft = new Draft(header, res); arrayList.Add(draft); } } } catch (FileNotFoundException) {} return((Draft[])arrayList.ToArray(typeof(Draft))); }
/// <summary> /// 子ノードを作成 /// </summary> /// <param name="header"></param> /// <returns></returns> public void AppendChild(XmlDocument doc, XmlElement root, ThreadHeader header) { XmlAttribute attr = doc.CreateAttribute("key"); attr.Value = header.Key; XmlElement child = doc.CreateElement("item"); child.Attributes.Append(attr); XmlElement subj = doc.CreateElement("subject"); subj.AppendChild(doc.CreateCDataSection(header.Subject)); XmlElement resc = doc.CreateElement("resCount"); resc.InnerText = header.ResCount.ToString(); child.AppendChild(subj); child.AppendChild(resc); root.AppendChild(child); }
/// <summary> /// monalog形式のスレッドをキャッシュとして保存 /// </summary> /// <param name="cache"></param> /// <param name="filePath"></param> /// <returns></returns> public static ThreadHeader OpenMonalog(Cache cache, string filePath) { ResSetCollection resItems = null; ThreadHeader header = null; MonalogConverter conv = new MonalogConverter(); conv.Read(filePath, out header, out resItems); using (LocalThreadStorage storage = new LocalThreadStorage(cache, header, StorageMode.Write)) { storage.Write(resItems); } ThreadIndexer.Write(cache, header); return(header); }
/// <summary> /// お気に入り以外の既得スレッドを削除します。 /// </summary> /// <param name="bookmarkRoot"></param> public void RemoveWithoutBookmarks(IBoardTable table, BookmarkRoot bookmarkRoot) { if (bookmarkRoot == null) { throw new ArgumentNullException("bookmarkRoot"); } // すべての板の既得インデックスを読み込む List <ThreadHeader> targets = Twin.IO.GotThreadListReader.GetAllThreads(cache, table); int count1 = targets.Count; // 読み込まれたインデックスで、お気に入りに登録されている物は除外 for (int i = 0; i < targets.Count;) { ThreadHeader h = targets[i]; BookmarkThread match = bookmarkRoot.Search(h); if (match != null) { targets.RemoveAt(i); } else { i++; } } int count2 = count1 - targets.Count; foreach (ThreadHeader h in targets) { cache.Remove(h); } cache.ClearEmptyFolders(); #if DEBUG int count3 = Twin.IO.GotThreadListReader.GetAllThreads(cache, table).Count; MessageBox.Show(String.Format("削除前={0}, お気に入りの数={1}, 削除後のログ数={2}", count1, count2, count3)); #endif }
/// <summary> /// 非同期でチェックを始める /// </summary> /// <param name="item"></param> public void CheckBegin(ThreadHeader item) { if (item == null) { throw new ArgumentNullException("item"); } if (IsChecking) { throw new InvalidOperationException("チェック中です"); } header = item; header.BoardInfo.Bbs = EnsureCurrentBbs(header.BoardInfo.Bbs); matchItems.Clear(); thread = new Thread(Checking); thread.Name = "NST_" + item.Key; thread.IsBackground = true; thread.Start(); }
public void Read(string filePath, out ThreadHeader header, out ResSetCollection resCollection) { // .idxファイルへのパスを求める string indexPath = GetIndexPath(filePath); if (!File.Exists(indexPath)) { throw new FileNotFoundException("インデックスファイルが存在しません"); } // インデックス情報を読み込む header = ThreadIndexer.Read(indexPath); if (header == null) { throw new ConvertException("インデックスファイルの読み込みに失敗しました"); } resCollection = ReadFile(filePath, header.UseGzip); }
/// <summary> /// 指定したヘッダーを書式化して文字列に変換 /// </summary> public override string Format(ThreadHeader header) { if (header == null) { throw new ArgumentNullException("header"); } StringBuilder sb = new StringBuilder(128); // 書式: key.dat<>subject (rescount) sb.Append(header.Key); sb.Append(".dat"); sb.Append("<>"); sb.Append(header.Subject); sb.Append(" ("); sb.Append(header.ResCount); sb.Append(")"); return(sb.ToString()); }
protected override ThreadHeader[] ParseData(string dataText) { List <ThreadHeader> list = new List <ThreadHeader>(100); const string token = ".cgi,"; int begin = 0, index; try { // 123456.cgi,スレッド名(123) while (begin < dataText.Length && (index = newline.Search(dataText, begin)) != -1) { string data = dataText.Substring(begin, index - begin); int idxDot = data.IndexOf(token); int idxSep1 = data.LastIndexOf('('); int idxSep2 = data.LastIndexOf(')'); int idxSubj = idxDot + token.Length; if (idxDot >= 0 && idxSep1 >= 0 && idxSep2 >= 0) { ThreadHeader header = TypeCreator.CreateThreadHeader(bbsType); header.Key = data.Substring(0, idxDot); header.Subject = data.Substring(idxSubj, idxSep1 - idxSubj); int resCnt; if (Int32.TryParse(data.Substring(idxSep1 + 1, idxSep2 - (idxSep1 + 1)), out resCnt)) { header.ResCount = resCnt; } list.Add(header); } begin = (index + newline.Pattern.Length); } } catch (Exception ex) { TwinDll.Output(ex); } return(list.ToArray()); }
/// <summary> /// メッセージを投稿 /// </summary> /// <param name="header">投稿先のスレッド</param> /// <param name="res">投稿する内容</param> public override void Post(ThreadHeader header, PostRes res) { if (header == null) { throw new ArgumentNullException("header"); } try { BoardInfo board = header.BoardInfo; // 投稿時刻を作成 int time = GetTime(header.LastModified); // BoardInfo.PathをBBSとDIRに分割 string[] dirbbs = board.Path.Split('/'); Trace.Assert(dirbbs.Length == 2); // 送信データを作成 string uri = String.Format("http://{0}/bbs/write.cgi/{1}/{2}/", board.Server, board.Path, header.Key); StringBuilder sb = new StringBuilder(); sb.Append("submit=" + UrlEncode("書き込む")); sb.Append("&NAME=" + UrlEncode(res.From)); sb.Append("&MAIL=" + UrlEncode(res.Email)); sb.Append("&MESSAGE=" + UrlEncode(res.Body)); sb.Append("&DIR=" + dirbbs[0]); sb.Append("&BBS=" + dirbbs[1]); sb.Append("&KEY=" + header.Key); sb.Append("&TIME=" + time); bool retried = false; byte[] bytes = Encoding.GetBytes(sb.ToString()); Posting(header.BoardInfo, bytes, uri, ref retried); } catch (Exception ex) { TwinDll.Output(ex); throw ex; } }
/// <summary> /// 基本ストリームを開く /// </summary> protected bool OpenBaseStream(ThreadHeader headerInfo) { if (baseReader.IsOpen) { return(false); } // 過去ログ落ちしていない場合のみ開く //0324 if (!headerInfo.Pastlog) { baseReader.Open(headerInfo); // スレッドを開くのに成功した場合、ストレージも開く if (baseReader.IsOpen) { length = baseReader.Length; position = 0; return(storage.Open(headerInfo, StorageMode.Write)); } } return(false); }
/// <summary> /// スレッドをmonalog形式で保存 /// </summary> /// <param name="cache">キャッシュ情報</param> /// <param name="header">保存するスレッド</param> /// <param name="filePath">保存先ファイルパス</param> public static void SaveMonalog(Cache cache, ThreadHeader header, string filePath) { if (filePath == null) { throw new ArgumentNullException("filePath"); } if (cache == null) { throw new ArgumentNullException("cache"); } if (header == null) { throw new ArgumentNullException("header"); } // datの存在するパスを取得 string fromPath = cache.GetDatPath(header); MonalogConverter conv = new MonalogConverter(); ThreadStorage reader = null; ResSetCollection items = new ResSetCollection(); try { reader = new LocalThreadStorage(cache, header, StorageMode.Read); while (reader.Read(items) != 0) { ; } conv.Write(filePath, header, items); } finally { if (reader != null) { reader.Close(); } } }
/// <summary> /// 指定したスレッドの草稿を取得 /// </summary> /// <param name="header"></param> /// <returns></returns> public Draft Load(ThreadHeader header) { if (header == null) { throw new ArgumentNullException("header"); } Draft draft = null; string filePath = cache.GetFolderPath(header.BoardInfo); filePath = Path.Combine(filePath, DraftFileName); if (File.Exists(filePath)) { XmlDocument doc = new XmlDocument(); doc.Load(filePath); // 同じスレッド番号を持つ草稿要素を検索するためのXPath string xpath = String.Format("draft/thread[@key=\"{0}\"]", header.Key); XmlNode node = doc.SelectSingleNode(xpath); if (node != null && ThreadIndexer.Read(cache, header) != null) { string name = node.SelectSingleNode("from").InnerText; string email = node.SelectSingleNode("email").InnerText; string body = node.SelectSingleNode("message").InnerText; // 草稿情報を作成 PostRes res = new PostRes(name, email, body); draft = new Draft(header, res); } } return(draft); }
public void Write(string filePath, ThreadHeader header, ResSetCollection resCollection) { XmlDocument doc = new XmlDocument(); // バージョン属性を作成 XmlAttribute version = doc.CreateAttribute("version"); version.Value = "1.0"; // ルートを作成 XmlNode root = doc.CreateElement("monalog", "http://www.monazilla.org/Monalog/1.0"); root.Attributes.Append(version); // スレッド要素を作成 XmlNode thread = CreateThreadElement(doc, header, resCollection); root.AppendChild(thread); doc.AppendChild(root); // エンコーダをShift_Jisで保存 XmlTextWriter writer = null; try { writer = new XmlTextWriter(filePath, Encoding.GetEncoding("Shift_Jis")); writer.Formatting = Formatting.Indented; doc.Save(writer); } finally { if (writer != null) { writer.Close(); } } }
/// <summary> /// スレッドを開く /// </summary> /// <param name="th"></param> public override bool Open(ThreadHeader header) { if (header == null) { throw new ArgumentNullException("header"); } if (IsOpen) { throw new InvalidOperationException("既にストリームが開かれています"); } // 差分取得かどうか aboneCheck = (header.GotByteCount > 0) ? true : false; // Retry: _res = null; try { HttpWebRequest req = (HttpWebRequest)WebRequest.Create(header.DatUrl); req.Timeout = 60000; req.AllowAutoRedirect = false; req.UserAgent = UserAgent; //req.Headers.Add("Pragma", "no-cache"); //req.Headers.Add("Cache-Control", "no-cache"); if (!String.IsNullOrEmpty(header.ETag)) { req.Headers.Add("If-None-Match", header.ETag); } if (header.GotByteCount > 0) { req.AddRange(header.GotByteCount - 1); } //if (!aboneCheck && getGzip) // req.Headers.Add("Accept-Encoding", "gzip"); _res = (HttpWebResponse)req.GetResponse(); baseStream = _res.GetResponseStream(); headerInfo = header; bool encGzip = _res.ContentEncoding.EndsWith("gzip"); if (encGzip) { using (GZipStream gzipInp = new GZipStream(baseStream, CompressionMode.Decompress)) baseStream = FileUtility.CreateMemoryStream(gzipInp); length = (int)baseStream.Length; } else { length = aboneCheck ? (int)_res.ContentLength - 1 : (int)_res.ContentLength; } // OK if (_res.StatusCode == HttpStatusCode.OK || _res.StatusCode == HttpStatusCode.PartialContent) { headerInfo.LastModified = _res.LastModified; headerInfo.ETag = _res.Headers["ETag"]; index = header.GotResCount + 1; position = 0; isOpen = true; } // dat落ちした予感 else { _res.Close(); if (_res.StatusCode == HttpStatusCode.Found) { // 10/05 移転追尾をすると過去ログ倉庫が読めなくなってしまう事がわかったので、一時的に外してみる //if (IsServerChanged(headerInfo)) //{ // // サーバーが移転したら新しい板情報でリトライ。 // goto Retry; //} //else { // そうでなければ dat落ちとして判断 //0324 headerInfo.Pastlog = true; PastlogEventArgs argument = new PastlogEventArgs(headerInfo); OnPastlog(argument); } } _res = null; } } catch (WebException ex) { HttpWebResponse res = (HttpWebResponse)ex.Response; // あぼーんの予感 if (res != null && res.StatusCode == HttpStatusCode.RequestedRangeNotSatisfiable) { OnABone(); } else { throw ex; } } return(isOpen); }
protected virtual bool IsMatch(List <__WordSet> wordList, ThreadHeader checkItem, ref int level) { if (checkItem.IsLimitOverThread) { return(false); } float matchCount = 0; string input = checkItem.Subject; string backWord = String.Empty; foreach (__WordSet ws in wordList) { WordType type = ws.Key; string key = ws.Value; // ひらがな1文字は無視 if (key.Length == 1 && type == WordType.Hira) { continue; } if (Regex.IsMatch(input, Regex.Escape(key), RegexOptions.IgnoreCase)) { if (type == WordType.Kanji || type == WordType.Kata || type == WordType.Hankaku || type == WordType.Alpha) { matchCount += key.Length * 2.0f; } else { matchCount += 1; } } // key を直前の単語 backWord と結合し、ひとつのワードとして検索。 // "BS11 3691" と "BSフジ 1125" が両方とも "BS" と "11" が一致し、同じ一致レベルとされてしまう問題があったたため if (backWord != "" && Regex.IsMatch(input, Regex.Escape(backWord + key), RegexOptions.IgnoreCase)) { string longKey = backWord + key; matchCount += longKey.Length * 1.5f; } // スレのカウント+1 の数字が存在したら有力候補…? if (type == WordType.Decimal) { int dec; if (Int32.TryParse(key, out dec)) { dec += 1; if (Regex.IsMatch(input, dec + "|" + HtmlTextUtility.HanToZen(dec.ToString()))) { matchCount += 3; } } } backWord = key; } // スレの勢いがあればあるほど matchCount += new ThreadHeaderInfo(checkItem).ForceValueDay / 10000; if (level - matchCount <= 0) { level = (int)Math.Round(matchCount, MidpointRounding.AwayFromZero); Console.WriteLine("{0} level of {1}", level, input); return(true); } return(false); }
/// <summary> /// 次スレかどうかを判断 /// </summary> /// <param name="sourceItem">前スレ情報</param> /// <param name="checkItem">判断するスレッドアイテム</param> /// <param name="level">一致判断単語数(一致した場合は一致レベルが代入される)</param> /// <returns>一致したならtrue</returns> protected virtual bool IsMatch(ThreadHeader sourceItem, ThreadHeader checkItem, ref int level) { return(IsMatch(GetWords(sourceItem.Subject), checkItem, ref level)); }
/// <summary> /// スレッドを開く /// </summary> /// <param name="th"></param> public override bool Open(ThreadHeader header) { if (header == null) { throw new ArgumentNullException("header"); } if (IsOpen) { throw new InvalidOperationException("既にストリームが開かれています"); } X2chKakoThreadHeader kakoheader = header as X2chKakoThreadHeader; bool retried = false; if (kakoheader != null) { kakoheader.GzipCompress = true; } Retry: // ネットワークストリームを初期化 HttpWebRequest req = (HttpWebRequest)WebRequest.Create(header.DatUrl); req.Timeout = 30000; req.AllowAutoRedirect = false; req.Referer = header.Url; req.UserAgent = UserAgent; req.Headers.Add("Accept-Encoding", "gzip"); req.Headers.Add("Pragma", "no-cache"); req.Headers.Add("Cache-Control", "no-cache"); if (header.GotByteCount > 0) { req.AddRange(header.GotByteCount - 1); } if (header.ETag != String.Empty) { req.Headers.Add("If-None-Match", header.ETag); } _res = (HttpWebResponse)req.GetResponse(); baseStream = _res.GetResponseStream(); headerInfo = header; // OK if (_res.StatusCode == HttpStatusCode.OK || _res.StatusCode == HttpStatusCode.PartialContent) { bool encGzip = _res.ContentEncoding.EndsWith("gzip"); // Gzipを使用する場合はすべて読み込む if (encGzip) { using (GZipStream gzipInp = new GZipStream(_res.GetResponseStream(), CompressionMode.Decompress)) baseStream = FileUtility.CreateMemoryStream(gzipInp); baseStream.Position = 0; length = (int)baseStream.Length; } else { length = aboneCheck ? (int)_res.ContentLength - 1 : (int)_res.ContentLength; } headerInfo.LastModified = _res.LastModified; headerInfo.ETag = _res.Headers["ETag"]; index = header.GotResCount + 1; position = 0; isOpen = true; } else if (!retried) { _res.Close(); _res = null; if (kakoheader != null) { kakoheader.GzipCompress = !kakoheader.GzipCompress; } retried = true; goto Retry; } else if (_res.StatusCode == HttpStatusCode.Found) { if (retryServers != null && retryCount < retryServers.Length) { BoardInfo retryBoard = retryServers[retryCount++]; _res.Close(); _res = null; if (retryBoard != null) { throw new X2chRetryKakologException(retryBoard); } } } // 過去ログなのでdat落ちに設定 //0324 headerInfo.Pastlog = true; retryCount = 0; return(isOpen); }
/// <summary> /// 指定したスレッドのセクション名を取得 /// </summary> /// <param name="header"></param> /// <returns></returns> private string GetSection(ThreadHeader header) { return(header.BoardInfo.DomainPath + "#" + header.Key); }
/// <summary> /// スレッドを開く /// </summary> /// <param name="header"></param> public abstract bool Open(ThreadHeader header);
/// <summary> /// 指定したヘッダーを書式化して文字列に変換 /// </summary> public abstract string Format(ThreadHeader header);
public void Read(string filePath, out ThreadHeader header, out ResSetCollection resCollection) { XmlDocument doc = new XmlDocument(); doc.Load(filePath); header = TypeCreator.CreateThreadHeader(BbsType.X2ch); resCollection = new ResSetCollection(); // ルート要素を取得 XmlNode root = doc.DocumentElement; // <thread>要素の処理 XmlNode thread = root.SelectSingleNode("thread"); if (thread == null) { throw new ConvertException("<thread>要素が存在しません"); } XmlNode serv = thread.Attributes.GetNamedItem("server"); if (serv == null) { throw new ConvertException("server属性が存在しません"); } XmlNode board = thread.Attributes.GetNamedItem("board"); if (board == null) { throw new ConvertException("board属性が存在しません"); } XmlNode key = thread.Attributes.GetNamedItem("key"); if (key == null) { throw new ConvertException("key属性が存在しません"); } // スレッドタイトルを取得 XmlNode title = thread.SelectSingleNode("title"); if (title == null) { throw new ConvertException("<title>要素が存在しません"); } // <info>要素の処理 XmlNode info = thread.SelectSingleNode("info"); if (info == null) { throw new ConvertException("<info>要素が存在しません"); } XmlNode lastmod = info.Attributes.GetNamedItem("last-modified"); if (lastmod == null) { throw new ConvertException("last-modified属性が存在しません"); } XmlNode size = info.Attributes.GetNamedItem("size"); if (size == null) { throw new ConvertException("size属性が存在しません"); } // スレッドの情報を設定 header.Key = key.Value; header.BoardInfo.Server = serv.Value; header.BoardInfo.Path = board.Value; header.Subject = title.InnerText; header.LastModified = DateTime.Parse(lastmod.Value); int gotByteCount; if (Int32.TryParse(size.Value, out gotByteCount)) { header.GotByteCount = gotByteCount; } // <res-set>要素の処理 XmlNode children = thread.SelectSingleNode("res-set"); if (children == null) { throw new ConvertException("<res-set>要素が存在しません"); } resCollection = GetResCollection(doc, children); header.GotResCount = resCollection.Count; }
/// <summary> /// スレッドを開く /// </summary> /// <param name="th"></param> public override bool Open(ThreadHeader header) { if (header == null) { throw new ArgumentNullException("header"); } if (IsOpen) { throw new InvalidOperationException("既にストリームが開かれています"); } string url = header.DatUrl; if (header.GotByteCount > 0) { // 差分取得用にURLに修正を加える url += String.Format("{0}-n", header.GotResCount + 1); } // ネットワークストリームを初期化 HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url); req.Timeout = 15000; req.IfModifiedSince = header.LastModified; req.Referer = url; req.UserAgent = UserAgent; req.Headers.Add("Pragma", "no-cache"); req.Headers.Add("Cache-Control", "no-cache"); _res = (HttpWebResponse)req.GetResponse(); baseStream = _res.GetResponseStream(); headerInfo = header; this._errorStatus = ParseErrorStatus(_res.Headers["ERROR"]); // OK if (_res.StatusCode == HttpStatusCode.OK) { position = 0; length = (int)_res.ContentLength; index = header.GotResCount + 1; headerInfo.LastModified = _res.LastModified; isOpen = true; } else { if (_errorStatus == JbbsErrorStatus.StorageIn) { // dat落ちした予感 headerInfo.Pastlog = true; } _res.Close(); _res = null; } return(isOpen); }