/// <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(); } }
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); } } }
/// <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); }
/// <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)); }
/// <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); } }
/// <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); } }
/// <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)); }
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); } } }
/// <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(); } }
/// <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); } } }
/// <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); }
/// <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); }
/// <summary> /// フッターを取得 /// </summary> /// <param name="header"></param> /// <returns></returns> public abstract string GetFooter(ThreadHeader header);
/// <summary> /// NumberClickEventArgsクラスのインスタンスを初期化 /// </summary> /// <param name="header"></param> /// <param name="res"></param> public NumberClickEventArgs(ThreadHeader header, ResSet res) { this.header = header; this.resSet = res; }
/// <summary> /// BookmarkThreadクラスのインスタンスを初期化 /// </summary> /// <param name="header"></param> public BookmarkThread(ThreadHeader header) : this(header, -1) { }
public static void SaveLastWritten(Cache cache, ThreadHeader header) { SaveValue(cache, header, "Thread", "LastWritten", header.LastWritten); }
public static void SavePosition(Cache cache, ThreadHeader header) { SaveValue(cache, header, "Option", "Position", header.Position); }
/// <summary> /// お気に入りにitemが含まれているかどうかを判断 /// </summary> /// <param name="header"></param> /// <returns></returns> public bool Contains(ThreadHeader header) { return(Search(header) != null); }
public static void SaveSirusi(Cache cache, ThreadHeader header) { SaveValue(cache, header, "Option", "Sirusi", header.Sirusi.ToArrayString()); }
public static void SaveServerInfo(Cache cache, ThreadHeader header) { SaveValue(cache, header, "Board", "Server", header.BoardInfo.Server); }
/// <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); }
public static string GetForceValue(ThreadHeader h, ForceValueOf valueType) { return(new ThreadHeaderInfo(h).GetForceValue(valueType)); }
/// <summary> /// フッタースキンを取得 /// </summary> /// <param name="header"></param> /// <returns></returns> public override string GetFooter(ThreadHeader header) { return(ReplaceHeaderFooter(footerSkin, header)); }
public static void SaveBookmark(Cache cache, ThreadHeader header) { SaveValue(cache, header, "Option", "Shiori", header.Shiori); }
public static void SavePastlog(Cache cache, ThreadHeader header, bool newValue) { SaveValue(cache, header, "Option", "Pastlog", newValue); }
/// <summary> /// 再起検索で指定したお気に入りを検索 /// </summary> /// <param name="header"></param> /// <returns></returns> public BookmarkThread Search(ThreadHeader header) { return(Search(this, header)); }