SHARE
TWEET

gethtmldat

nanashi_kana Mar 26th, 2015 (edited) 35,392 Never
  1. /********************************************************************/
  2. /*  gethtmldat.js :   ver.0.45   2015/12/11                         */
  3. /********************************************************************/
  4. //
  5. //  Jane2ch.exeでhtmlから過去ログを取得しdat形式に変換してLogsフォルダに格納する
  6. //  htmltodat-convert2.wsf+htmltodat.exeと同じような機能を果たす
  7. //  htmltodat-convert2.wsfとGetLog.wsfからコードを盗用してます(許して)
  8. //
  9. //==============================================================
  10. //  ※ 重要 ※
  11. //  なお、このスクリプトはpastbinのサイトから DOWNLOAD するのではなく、RAW( http://pastebin.com/raw.php?i=3EZzrsxY )
  12. //  で表示したものか 又は 下の方にある RAW Paste Data から、コピー&ペースト(CTRL+A,CTRL+C 及び CTRL+V)で、
  13. //  テキストエディタに貼り付け、gethtmldat.js という名前でShift-JISコード(メモ帳ではANSI)で保存し、
  14. //  Jane2ch.exe のあるフォルダに格納してください
  15. //  ※注意※ DOWNLOADすると、文字コードがUTF-8となり実行できません
  16. //           また、行番号付きでコピー&ペーストしても実行できません
  17. //==============================================================
  18. //
  19. //  Jane Styleでのコマンド登録方法は、メニュー - ツール - 設定 - 機能 - コマンド で
  20. //    コマンド名   - 過去ログ取得(gethtmldat)  ※ここには任意の名称をつけられます
  21. //    コマンド内容 - wscript "$BASEPATHgethtmldat.js" $LINK$URL
  22. //  を入力して、追加、OKします
  23. //       ※ なお、Jane直下フォルダでは無い場合はパスをフルパスで指定してください
  24. //          jane styleの下のscriptフォルダに入れた場合は、wscript "$BASEPATHscript\gethtmldat.js" $LINK$URL
  25. //
  26. //  コマンド登録時のパラメタに /w 又は /w:999(待ち時間) を追加するとキー送信(CTL+W)により、スレを閉じて再度開く動作をします
  27. //          wscript "$BASEPATHgethtmldat.js" $LINK$URL /w
  28. //    ※注意※ 当該スレが開く前にキー送信がなされると現在開いている別スレが閉じてしまいます
  29. //
  30. //  起動オプション: 順不同
  31. //    [+]http://~   url指定 (先頭に+を付けるとdatにURL末尾の指定範囲のレス部分だけ上書きする /aは無効となる)
  32. //    [/n:]999       レス番指定(そのレス番に飛ぶ)
  33. //    /f             urlを強制的に問い合わせる
  34. //    /w[:999]       スレを指定時間待って閉じ、開き直す(数値省略時 1200ms)
  35. //    /a[ppend]      差分のみ取得(管理人削除などで既存のログとサーバー上のデータに違いがあっても関知しない)
  36. //    /b[ak][1]      バックアップを取る(Logs\bak\の下に既存のdatファイルをコピーする) /b1 は1回限りで上書きしない
  37. //    /redraw[:999]  再描画 スレを開いた後、指定時間待ってからキーコード('ALT','T','G','0')を送る (数値省略時 1200ms)
  38. //    /z             Jane2ch.exeを終了し、情報(db,idx)設定後、再起動する(この場合 /w は不要)
  39. //                   ※ 高速Merge有効時には、SQLite3 ODBC Driver 又は sqlite3.exe のどちらかが必要
  40. //                       SQLite3 ODBC Driver : http://www.ch-werner.de/sqliteodbc/sqliteodbc.exe をインストール
  41. //                                           (インストールは上記exeを実行し、Next,I Agree,Next,Install,Finishボタンで進める)
  42. //                       sqlite3.exe         : http://www.sqlite.org/download.html から、sqlite-shell-win32-x86-3080900.zip
  43. //                                             をダウンロード・解凍し、本スクリプトと同じフォルダに格納する
  44. //    "/log[:file]"  トレースログを指定のファイルに追加書き込みします(ファイルパス名省略時は %temp%\gethtmldat.log)
  45. //    /keep_kako    渡された過去ログURLをそのまま処理する(したらば、next2ch、machi以外で有効)
  46. //
  47. //  使い方:
  48. //    以下のa)~c)のいずれかで右クリックして上記登録したコマンドを選択する
  49. //      a) Jane Styleで、過去ログを開いたレス表示欄
  50. //      b) 別スレに書かれているリンク
  51. //      c) 書き込みウィンドウ、メモ欄にURLを書き込みプレビューで現れるリンク
  52. //
  53. //  TIPS :
  54. //    ●★「過去ログ」と表示されている場合は、メニュー(スレッド)から「強制過去ログ化」のチェックを外すか
  55. //       又は、一旦ログを削除後にリンクから再取得してください
  56. //    ●レスが表示されない場合は、スレッドツールバーの「表示レス数/スレの再描画」アイコンを右クリックしてください
  57. //    ●未読状態が既読状態にならない場合やレス番リンクのポップアップが表示されなかったりID抽出回数が0回になる場合は
  58. //      1)ステータスが過去ログ以外の時、所属する板を開いてスレ一覧更新をして、スレを閉じ、
  59. //        リンク(又はスレ一覧から)クリックで開き直し、最新レス末尾までスクロールする
  60. //      2)過去ログの場合、上記「強制過去ログ化」のチェックを外した後、>>999 などの未読状態のレスを指すリンクをクリックする
  61. //        又は、名前欄1001をクリックする、又はアドレスバーに「スレURL/999」のようなレス番付きで入力する
  62. //    ●2ch.netでftp://問題により520エラー又はデータが途切れてしまう場合の部分的な救済方法
  63. //        webブラウザで問題となるレス番をtrial and errorで目星をつけて、それを避けるように範囲指定してデータを取得する
  64. //        例えば、レス番50が引っ掛かっている場合は、-49 と 51- の2回に分けて取得する
  65. //        コマンド登録時には、+$LINK$URLとし、URL末尾に範囲指定付きのリンクから使うか
  66. //        /f も追加して、実行時にURL末尾にレス番範囲を追加で入力する
  67. //
  68. //  修正履歴:
  69. //    http://pastebin.com/my14uCkr を参照
  70. //==============================================================
  71.  
  72. /*@cc_on
  73.         @set @DEBUG = false;
  74.         @set @EnabledTest2chJSON = false; // =true で2chで最初にJSONでの取得を試みる(お遊び機能:仕様等一切不明、過去ログは無理)
  75.         //漢字コード変換にbasp21.dllを試みる http://www.hi-ho.ne.jp/babaq/basp21.htmlのBASP21-2003-0211.exeのインストールが必要
  76.         @set @EnabledBASP21 = true;
  77. @*/
  78.  
  79. var HTTP_HEADERS = {
  80. //  "If-Modified-Since" : "Thu, 01 Jun 1970 00:00:00 GMT"
  81. //  ,"Content-Type" : "application/x-www-form-urlencoded"
  82. //  ,"User-Agent" : "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1;)"
  83. };
  84. var HTTP_TIMEOUT = 30 * 1000;
  85. var IDX_STATE = { "2ch":3 , "jbbs":3 }; //=0:現役 =3:dat落ち =10:過去ログ
  86. var ABN_MSG = "あぼーん<>あぼーん<>あぼーん<>あぼーん<>";
  87. var NOT_GET_MSG = "未取得<>未取得<>未取得<>未取得<>";
  88.  
  89. var fso   = new ActiveXObject("Scripting.FileSystemObject");
  90. var shell = new ActiveXObject("WScript.Shell");
  91. var sha   = new ActiveXObject("Shell.Application");
  92. var strm  = new ActiveXObject("ADODB.Stream");
  93. var http; try { http = new ActiveXObject("Msxml2.ServerXMLHTTP.6.0"); } catch(e){}
  94.                   if (!http) try { http = new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch(e){}
  95.                   if (!http) { http  = new ActiveXObject("Msxml2.XMLHTTP.3.0"); }
  96. var basp; /*@if (@EnabledBASP21) try { basp = new ActiveXObject("basp21"); } catch(e){} @end @*/
  97.  
  98. var JANE_PATH = shell.CurrentDirectory.replace(/[^\\]$/,"$&\\");
  99. var SCRIPT_PATH = fso.GetParentFolderName( WScript.ScriptFullName ).replace(/[^\\]$/,"$&\\");
  100. shell.CurrentDirectory = JANE_PATH;
  101. var JANE_EXE  = "Jane2ch.exe";
  102. var JANE_INI  = "Jane2ch.ini";
  103. var JANE_BRD  = "Jane2ch.brd";
  104. var JANE_LOGS = "Logs\\2ch\\";
  105. var JANE_BAK  = "Logs\\bak\\";
  106. var JANE_BRDCUSTOMIZE_INI = "brdcustomize.ini";
  107. var MY_NAME   = WScript.ScriptName.split(/\.(?=[^.]+$)/)[0];
  108. var TRACE_LOG = replaceEnv("%temp%\\"+MY_NAME+".log").replace(/\\\\/g,"\\");
  109.  
  110. //==============================================================
  111.  
  112. function o(s) { /*@if (@DEBUG) WScript.Echo(s); @end @*/ }
  113. function q() {WScript.Quit();}
  114. String.prototype.expand = function(v) { return this.replace(/\$(\d)/g, function(m, n) { return v[n]; }); }
  115. String.prototype.convDontUseStr = function() {
  116.         var tbl0 = { "CON":"$CON", "AUX":"$AUX", "NUL":"$NUL" /*, "PRN":"$PRN", "COM([0-2])":"$COM$1", "LPT([0-2])":"$LPT$1" */ }
  117.         var tbl1 = { "\\":"$Backslash", "/":"$Slash", ":":"$Colon", "*":"$Asterisk", "?":"$Question" }
  118.         var s = this;
  119.         for(var i in tbl0) { s=s.replace( new RegExp("^"+i+"$","i") , tbl0[i]); }
  120.         return s.replace(/[\\/:*?]/g, function (w){return tbl1[w];});
  121. }
  122. var trace = function(){};
  123. function Err(s,t) { s=ErrMsg(s,t); trace("---- "+s+" ----",2); throw new Error(s); }
  124. function ErrMsg(s,t) { return (ERROR_MSG[s]?ERROR_MSG[s]:"Unknown error") + (t?t:"");}
  125.  
  126. var ERROR_MSG = {
  127.          "E_already_there" : "このスレは既に取得しています"
  128.         ,"E_illegal_url" : "このURLでは処理できません"
  129.         ,"E_remained_garbage" : "レスデータのみの抽出に失敗しました"
  130.         ,"E_block_not_found" : "htmlからスレブロックが見つかりません"
  131.         ,"E_title_not_found" : "スレタイトルが見つかりません"
  132.         ,"E_require_sqlite" : "sqlite3.exe 又は SQLite3 ODBC Driver が必要です"
  133.         ,"E_require_sqlODBC" : "SQLite3 ODBC Driver が必要です"
  134.         ,"E_stop" : "処理を中止しました"
  135.         ,"E_no_data" : "取得データはありません"
  136.         ,"E_http_timeout" : "受信タイムアウト"
  137.         ,"E_http_recieve" : "http受信エラー"
  138.         ,"E_bbs_not_found" : "掲示板番号が不正です"
  139.         ,"E_key_not_found" :"スレッド番号が不正です"
  140.         ,"E_thread_not_found" : "スレッドがありません"
  141.         ,"E_brditem_not_found" : "dat格納場所が見つかりません"
  142.         ,"E_loadfile" : "ファイル読み込みエラー"
  143.         ,"E_savefile" : "ファイル書き込みエラー"
  144. }
  145.  
  146. function object(o) {
  147.         var f = object.f, i, len, n, prop;
  148.         f.prototype = o;
  149.         n = new f;
  150.         for (i=1, len=arguments.length; i<len; ++i) for (prop in arguments[i]) n[prop] = arguments[i][prop];
  151.         return n;
  152. }
  153. object.f = function(){};
  154. //--- http://with-love-from-siberia.blogspot.jp/2009/12/msgbox-inputbox-in-jscript.html -----------
  155. var vb = {};
  156. vb.Function = function(func) { return function() { return vb.Function.eval.call(this, func, arguments); }; };
  157. vb.Function.eval = function(func) {
  158.         var args = Array.prototype.slice.call(arguments[1]);
  159.         for (var i = 0; i < args.length; i++) {
  160.                 if ( typeof args[i] != 'string' ) { continue; }
  161.                 args[i] = '"' + args[i].replace(/"/g, '" + Chr(34) + "') + '"';
  162.         }
  163.         var vbe;
  164.         vbe = new ActiveXObject('ScriptControl');
  165.         vbe.Language = 'VBScript';
  166.         return vbe.eval(func + '(' + args.join(', ') + ')');
  167. };
  168. var InputBox = vb.Function('InputBox');
  169. var MsgBox = vb.Function('MsgBox');
  170.  
  171. //==============================================================
  172.  
  173. var args = parmParse(WScript.Arguments);
  174.  
  175. var URL_2ch = {
  176.   RE_HOST : new RegExp("^http://\\w+\\.(?:2ch\\.net|bbspink\\.com)/")   //この定義はdat取得できないサイトの判別に使う
  177.  ,RE_URL  : new RegExp("^http://((\\w+(?=\\.\\w+\\.))?(\\.?(\\w+).+?))/(?:(?:test|bbs)/.+?/)?(\\w+)/(?:kako/.+?/)?(((\\d+)\\d)\\d{5})(/|\\.html|\\.dat(?:\\.gz)?)?")
  178.  ,range   : ""
  179.  ,set_prm : function(url) { this._set_prm(url, 1, null, 5, 6); this.kako = /\/kako\//.test(url) && delete args.append; }
  180.  ,_set_prm: function(url,p1,p2,p3,p4) {
  181.                                 this.prm  = url.match(this.RE_URL) || Err("E_illegal_url");
  182.                                 if(/\d$/.test(this.prm[0])) this.prm[0] += "/";
  183.                                 this.url  = this.prm[0];
  184.                                 this.url2 = this.prm[0];
  185.                                 if (this.prm[0].slice(-1)=="/") {
  186.                                         var range = url.match(/\/n?((\d*)n?(-?)[^\/]*)$/)||[];
  187.                                         this.url2 += (args.opt_n || range[2] ||"");
  188.                                         if(range[3]) this.range = (range[1]||"").replace(/n/ig,"");
  189.                                         else if(range[2]) this.range = range[2] + "-" + range[2];
  190.                                 }
  191.                                 this.site     = this.prm[p1];
  192.                                 this.category = (p2) ? this.prm[p2] : "";
  193.                                 this.brdID    = this.prm[p3];
  194.                                 this.thrID    = this.prm[p4];
  195.                         }
  196.  ,appendRange : function(top) {
  197.                                         if (args.overwrite) this.url += this.range;
  198.                                         else                this.url += ((args.append && top) ? top+"-n" : "");
  199.                                 }
  200.  ,getUrl2 : function() { return this.url2; }
  201. }
  202. var URL_jbbs = object(URL_2ch,{
  203.   RE_HOST : new RegExp("^http://jbbs\\.(?:shitaraba|livedoor)\\.(?:net|jp|com)/")
  204.  ,RE_URL  : new RegExp("^http://(jbbs\\.shitaraba\\.net)/bbs/\\w+\\.cgi/(\\w+)/(\\d+)/(\\d+)/?")
  205.  ,set_prm : function(url) { this._set_prm(url,1,2,3,4); }
  206. });
  207. var URL_machi = object(URL_2ch,{
  208.   RE_HOST : new RegExp("^http://(?:\\w+\\.)?machi\\.to/")
  209.  ,RE_URL  : new RegExp("^http://((?:\\w+\\.)?machi\\.to)/bbs/\\w+\\.cgi/2/(\\w+)/(\\d+)/?")
  210.  ,set_prm : function(url) { this._set_prm(url,1,null,2,3); }
  211.  ,getUrl2 : function() { return this.url2.replace(/\/offlaw\.cgi\/2\//,"/read.cgi/"); }
  212. });
  213. var URL = URL_2ch;
  214.  
  215. var Jane_2ch = {
  216.  ini          : loadFile2(JANE_INI)
  217.  ,brd         : ""
  218.  ,LogBasePath : ""
  219.  ,init        : function() { this._setLogBasePath(); this._loadBRD(); }
  220.  ,getINI      : function(p) { var m=this._search(this.ini, this._re_ini, p); return m && RegExp.$1 || p[3]; }
  221.  ,getBRD      : function(p) {
  222.                                         var m = this._search(this.brd, this._re_brd, p);
  223.                                         return (m) ? RegExp.$1.convDontUseStr()+"\\"+RegExp.$2.convDontUseStr()+"\\" : null;
  224.                                 }
  225.  ,_re_ini     : "^\\[$1\\]\\r\\n(?:.*\\r\\n)*?(?:$2=(.*)|\\[.*\\])\\r\\n"
  226.  ,_re_brd     : "^([ \\S]+).*\\r\\n(?:\\t.*\\r\\n)*\\t\\w*$3\\t$5\\t([^\\t\\r\\n]+)\\r\\n"
  227.  ,_search     : function(f,s,p) { return f.match(new RegExp(this._expand(s,p),"img")); }
  228.  ,_expand     : function(s,p) { return s.replace(/\$(\d)/g, function(m, n) { return (""+p[n]).replace(/\./g,"\\."); }); }
  229.  ,_setLogBasePath : function() { this.LogBasePath = this.getINI([,"PATH","LogBasePath",""]).replace(/[^\\]$/,"$&\\");}
  230.  ,_loadBRD     : function() { this.brd = loadFile2(this.LogBasePath + JANE_BRD); }
  231. }
  232. var Jane_jbbs = object(Jane_2ch,{
  233.   _re_brd : "^([ \\S]+).*\\r\\n(?:\\t.*\\r\\n)*?\\t$1/$2\\t$3\\t([^\\t\\r\\n]+)\\r\\n"
  234. });
  235. var Jane_machi = object(Jane_2ch,{
  236.   _re_brd : "^([ \\S]+).*\\r\\n(?:\\t.*\\r\\n)*?\\t$1\\t$2\\t([^\\t\\r\\n]+)\\r\\n"
  237. });
  238.  
  239. var Jane = Jane_2ch;
  240. Jane.init();
  241.  
  242. if (args.trace !== void 0) { trace = new Trace(); }
  243. trace("--- start ---   "+args.url,1);trace("",1)
  244.  
  245. //----------------------
  246.  
  247. var DatInfo = {
  248.   cnt      : 0
  249.  ,title    : ""
  250.  ,msg      : ""
  251.  ,setInfo  : function(dat,bak,brd) {
  252.                                 this.dat = dat;
  253.                                 this.bak = bak;
  254.                                 this.brd = brd;
  255.                                 if (fso.FileExists(dat)) {
  256.                                         var msg = loadFile2(dat);
  257.                                         this.cnt  = msg.replace(/^.*$/mg,"").length;
  258.                                         this.title = (msg.match(/<>((?:(?!<>).)*)$/m)||[])[1];
  259.                                         if (args.overwrite) { this.msg = msg.slice(0,-1).split("\n"); }
  260.                                 }
  261.                          }
  262.  ,copyDat  : function() {
  263.                                 if (fso.FileExists(this.dat)) {
  264.                                         path(this.bak);
  265.                                         if (args.bak<0 || !fso.FileExists(this.bak) )
  266.                                                 try{ trace(); fso.CopyFile(this.dat, this.bak, true); trace("copy file:"+this.bak);} catch(e) {}
  267.                                 }
  268.                          }
  269.  ,setNewDatInfo : function(title, lines) {
  270.                                         this.title = title;
  271.                                         this.lines = parseInt(lines,10);
  272.                                   }
  273. }
  274.  
  275. //================================================================================
  276.  
  277.  
  278. var Thread = {
  279.   re_sel      : 0
  280.  ,REG_PATTERN : [ {} ]
  281.  ,msg         : ""
  282.  ,resNo       : []
  283.  ,requireFillAbn  : false
  284.  ,prepare     : function() {}
  285.  ,urlReplace  : function(u) { return u; }
  286.  ,preReplace  : function() {}
  287.                                        
  288.  ,mainReplace : function() { this.msg = this.msg.replace(this.REG_PATTERN[this.re_sel].msg, this.REG_PATTERN[this.re_sel].rep); }
  289.  ,postReplace : function() {}
  290.  ,createBrdFolder : function() { return null;}
  291.  ,matchTBlock :
  292.         function(s) {
  293.                 var i,ss;
  294.                 for(i=0; i<this.REG_PATTERN.length; i++) {
  295.                         this.re_sel =i;
  296.                         if(ss=s.match(this.REG_PATTERN[i].thr)) break;
  297.                 }
  298.                 return ss;
  299.         }
  300.  ,getTBlock   : function() { this.msg = (this.matchTBlock(this.msg)||[])[1]||""; }
  301.  ,getTitle    : function(s) { this.title = (s.match(/<title>(.*?)\n*<\/title>/i)||[])[1]; }
  302.  ,readHTTP    : function(url) {
  303.         trace("try URL="+url,9);
  304.         this.msg = readHTTP(url);
  305.         this.preReplace();
  306.         this.getTitle(this.msg);
  307.         this.getTBlock();
  308.         return true;
  309.   }
  310.  ,getFirst    : function() { return (args.overwrite) ? parseInt(URL.range,10) : (args.append) ? DatInfo.cnt + 1 : 1; }
  311.  ,getLast     : function() { return parseInt((this.msg.match(/(\d+).*\n$/i)||[])[1],10); }
  312.  ,delContents : function(s) { return s.replace(/^(?:(?:(?!<>).)*<>){4}.*$/mg, ""); }
  313.  ,checkData   : function(s) {
  314.                                         var ln = this.checkData0(s);
  315.                                         if(args.overwrite) return;
  316.                                         if (this.last-this.first+1 != ln.length)
  317.                                                 if (MsgBox("抽出したレス数が合いませんが続行しますか?(先頭="+this.first
  318.                                                             +" 末尾="+this.last+" レス数="+ln.length+")",4+48,MY_NAME)!=6)
  319.                                                         Err("E_stop");
  320.                                 }
  321.  ,checkData0  : function(s) {
  322.                                         var ln = this.delContents(s);
  323.                                         if (ln.replace(/\n/g,"").length > 0) Err("E_remained_garbage");
  324.                                         return ln;
  325.                                 }
  326.  ,addTitle    : function() { this.msg = this.msg.replace(/^.*?$/m, "$&"+this.title); }
  327.  ,delDupData  : function() { //わざと重複して要求した先頭レス番データ削除
  328.                                         if ((this.msg.match(/^(\d+)/i)||[])[1] == DatInfo.cnt) { this.msg = this.msg.replace(/^.*\n/m, ""); }
  329.                                 }
  330.  ,fillAbn     : function() {
  331.                                         // 透明あぼーんレスを挿入する
  332.                                         var d = [], n = this.first;
  333.                                         var s = this.msg.split("\n");
  334.                                         for (var i=0; i<s.length; i++) {
  335.                                                 for (var j=n; j<parseInt(s[i].replace(/^(\d+).+$/, "$1"),10); j++) { d.push(j+"<>"+ABN_MSG); n++; }
  336.                                                 d.push(s[i]); n++;
  337.                                         }
  338.                                         this.msg = d.join("\n");
  339.                                 }
  340.  ,delResNo    : function() { this.msg = this.msg.replace(/^\d+<>/mg, ""); }
  341.  ,overwriteMsg : function() {
  342.                                         var data = this.msg.split("\n");
  343.                                         var msg = DatInfo.msg;
  344.                                         var i;
  345.                                         for (i=0; i<data.length; i++) msg[parseInt(data[i],10)-1] = data[i].replace(/^\d+<>/,"");
  346.                                         for (i=0; i<msg.length; i++) if(!msg[i]) msg[i] = NOT_GET_MSG;
  347.                                         this.msg = msg.join("\n");
  348.                                         if(this.msg.slice(-1)!="\n") this.msg += "\n";
  349.                                  }
  350.  ,proc        : function() {
  351.                                         this.prepare();
  352.                                         URL.set_prm(this.urlReplace(args.url));
  353.                                         var brd = Jane.getBRD(URL.prm);
  354.                                         if (!brd) brd = this.createBrdFolder();
  355.                                         if (!brd) Err("E_brditem_not_found");
  356.                                         var dat = Jane.LogBasePath + JANE_LOGS + brd + URL.thrID + ".dat";
  357.                                         var bak = Jane.LogBasePath + JANE_BAK + brd + URL.thrID + ".dat";
  358.                                         DatInfo.setInfo(dat, bak, brd);
  359.                                         URL.appendRange(DatInfo.cnt);
  360.                                         if (trace()|this.readHTTP(URL.url)|trace("HTTP total read time")) {
  361.                                                 if (!this.msg) Err("E_block_not_found");
  362.                                                 if (!this.noChkTitle && !this.title) Err("E_title_not_found");
  363.                                                 trace(); this.mainReplace(); trace("html->dat main replace");
  364.                                                 if (args.append) {
  365.                                                         trace(); this.delDupData(); trace("del dupdata time");
  366.                                                         if(this.msg=="") Err("E_already_there");
  367.                                                 }
  368.                                                 this.first = this.getFirst();
  369.                                                 this.last  = this.getLast();
  370.                                                 this.checkData(this.msg);
  371.                                                 if (this.first==1) { this.addTitle(); }
  372.                                                 if(this.requireFillAbn) { trace(); this.fillAbn(); trace("透明abnレス挿入"); }
  373.                                                 this.postReplace();
  374.                                                 if(args.overwrite) this.overwriteMsg();
  375.                                                 else               this.delResNo();
  376.                                         }
  377.                                         trace("スレタイトル:"+this.title+"\tレス数:"+this.last,9);
  378.                                         saveDat(dat, this.msg);
  379.                                         DatInfo.setNewDatInfo(this.title, this.last);
  380.                                         saveIdx("http://"+URL.site+((URL.category)?"/"+URL.category:"")+"/"+URL.brdID);
  381.                                         invokeJaneStyle(URL.getUrl2());
  382.                                         trace("---- end ----",1);
  383.                                 }
  384. }
  385.  
  386. var Thread_2ch = object(Thread,{
  387.   read_cgi_ver : ""
  388.  ,REG_PATTERN : [
  389.     { "thr" : /^[\s\S]*?<dl[^>]*>\s*(?:<font[^>]*>.*<\/font>.*\s*)?((?:\s*<dt[^>]*>.+?<dd>.+\r?\n?)+)(\s*<\/dl>)?/i
  390.      ,"msg" : /[ \t]*<dt.*?>([0-9]+).+?(?:"mailto:(.+?)">)?<b[^>]*>(.*?)<\/b>(?:<\/font>|<\/a>)?(?: ?投稿日)? ?:(.*?)<dd>(.*?)(?:<br>)*(?=<dt.*?>|$)/img
  391.      ,"rep" : "$1<>$3<>$2<>$4<>$5<>"
  392.     }
  393.    ,{ "thr" : /^[\s\S]*?<div class="thread"[^>]*>((?:<div class="post"[^>]*>(?:<div[^>]*>.*?<\/div>)+<\/div>)*)(<\/div>)/i
  394.      ,"msg" : /.*?<div class="number">(\d+).+?<\/div><div class="name"><b>(?:<a href="mailto:(.+?)">)?(.*?)(?:<\/a>)?<\/b><\/div><div class="date">(.*?)<\/div><div class="message">(.*?)<\/div><\/div>(?=<div class="post"|$)/img
  395.      ,"rep" : "$1<>$3<>$2<>$4<>$5<>\n"
  396.     }
  397.   ]
  398. ,urlReplace  :
  399.         function(url) {
  400.                 url = url.replace(/^(http:\/\/next2ch\.net\/)(\w+\/)(?:kako\/\d{3,4}\/(?:\d{5}\/)?)?(\d+)(?:\/|\.html)?$/,"$1test/read.cgi/$2$3/");
  401.                 if(!args.keep_kako)
  402.                         url=url.replace(/^(.*?\/)(\w+\/)kako\/\d{3,4}\/(?:\d{5}\/)?(\d+)\.html$/,"$1test/read.cgi/$2$3/");
  403.                 return url;
  404.         }
  405.  ,preReplace  : function() {
  406.         this.msg = this.msg
  407.                                 .replace(/<div (?:class|id)="banner"[^>]*>[\s\S]*?(?=<dt|<div class="post"|<\/div><div class="cLength"|<\/dl>)/ig,"")
  408.                                 .replace(/(<a href=)"\/cdn-cgi\/l\/(email-protection\#.*?">)/ig,'$1"mailto:$2');
  409.   }
  410.  ,postReplace : function() {
  411.                                         this.msg = this.msg
  412.                                                                 .replace(/<\/div><div class="be[^>]*><a href="[^"]+\/(\d+)"[^>]*>\?(.*?)<\/a>/ig," BE:$1-$2")
  413.                                                                 .replace(/<a href="http.*?>(.*?)<\/a>/ig, "$1")
  414.                                                                 .replace(/<a href="javascript:be\(([^\)]+?)\)[^>]*>\?(.*?)<\/a>/ig, "BE:$1-$2")
  415.                                                                 .replace(/<img src="http:\/\/(img\.2ch\.net\/.+?)">/ig, "sssp://$1")
  416.                                                                 .replace(/<img src="(.*?)">/ig, "$1");
  417.                                 }
  418.  ,_getKakoUrl :
  419.         function() {
  420.                 var p = URL.prm;
  421.                 if(URL.thrID<1000000000)
  422.                         { url="http://$1/$2/kako/$3/$4.dat.gz".expand([,p[1],p[5],p[6].substr(0,3),p[6]]);}
  423.                 else
  424.                         {url="http://$1/$2/kako/$3/$4/$5.dat.gz".expand([,p[1],p[5],p[6].substr(0,4),p[6].substr(0,5),p[6]]);}
  425.                 return url;
  426.         }
  427.  ,readHTTP  :
  428.         function(url) {
  429.                 var s,ss,u,msgLength;
  430.                 if(!URL.kako && !URL.RE_HOST.test(url)) { if(!this.readHTTP0(url)) return false; } //dat取得
  431.                 /*@if (@EnabledTest2chJSON)
  432.                         o("1st try json");
  433.                         this.msg = get2chJSON();
  434.                         if(this.msg=="") Err("E_already_there");
  435.                         if(this.msg) return false;
  436.                         o("2nd try html");
  437.                 @end @*/
  438.                 this.kakoUrl = this._getKakoUrl();
  439.                 if(URL.kako) if(!this.readHTTP2(this.kakoUrl)) return false;
  440.                 trace("try URL="+url,9);
  441.                 this.msg = readHTTP(url);
  442.                 this.read_cgi_ver = (this.msg.match(/>read\.cgi ver ([\d.]+)/)||[])[1];
  443.                 this.preReplace();
  444.                 this.getTitle(this.msg);
  445.                 msgLength = this.msg.length;
  446.                 ss = this.matchTBlock(this.msg);
  447.                 if (!ss) {
  448.                         u = this.kakoUrl.replace(/\.dat\.gz$/,".html");
  449.                         if (u!=url) {
  450.                                 switch(this.readHTTP3(u)) {
  451.                                         case 0: return false;
  452.                                         case 1: url=u;  ss=this._matchTBlock(this.msg); break;
  453.                                         default: break // case -1
  454.                                 }
  455.                         }
  456.                 }
  457.                 if(!ss) {
  458.                         ss = "<URL>="+url+"\n<TITLE>="+this.title+"\n<メッセージ長>="+msgLength+"\n\n";
  459.                         ss += ((this.msg.match(/^((?=.*LoadAverage|人大杉).*$)/im)||[])[1])
  460.                                         || ((this.msg.match(/<h1[^>]*>([\s\S]*?)<\/h1>/m)||[])[1])
  461.                                         || ((this.msg.match(/<p[^>]*>\n*(.*\s+.*\s*)$/m)||[])[1])
  462.                                         || "不明";
  463.                         Err("E_block_not_found", "\nもしかしたら以下のはメッセージかも\n\n"+ss+"\n");
  464.                 }
  465.                 if (!ss[2]) {
  466.                         if (MsgBox("途中でデータが途切れているようですが続行しますか?",4+48,MY_NAME)!=6) Err("E_stop");
  467.                 }
  468.                 s = ss[1] || "";
  469.                 if(this.re_sel==0 && s && s.slice(-1)!='\n') s += '\n';
  470.                 this.msg = s;
  471.                 return true;
  472.         }
  473.  ,readHTTP2 :
  474.         function(url) {
  475.                 var re = /^(?:(?!<>).)*<>(?:(?!<>).)*<>(?:(?!<>).)*<>(?:(?!<>).)*<>((?:(?!<>).)*).*\s*$/m;
  476.                 trace("try URL="+url,9);
  477.                 var s="";
  478.                 try {s = readHTTP(url);}catch(e){} //9999999999.dat.gz
  479.                 var r = s.match(re);
  480.                 if(!r) {url=url.replace(/\.gz$/,""); trace("try URL="+url,9); try{s=readHTTP(url); r=s.match(re);}catch(e){} }
  481.                 if(r) {
  482.                         this.msg = s;
  483.                         this.last = this.checkData0(s).replace(/^.*$/m,"").length;
  484.                         this.title = r[1];
  485.                         URL.kako = true;
  486.                         delete args.append;
  487.                         return false;
  488.                 }
  489.                 return true;
  490.         }
  491.  ,readHTTP3 :
  492.         function(url) {
  493.                 var title=((this.msg.match(/<title>(.*)<\/title>/im)||[])[1]||"");
  494.                 trace("HTTP title="+title,9);
  495.                 if (/error/i.test(title)) {
  496.                         if(!this.readHTTP2(this.kakoUrl)) return 0; //最初に/kako/.../9999999999.dat.gzを試す
  497.                         trace("try URL="+url,9);
  498.                         var s = readHTTP(url);  //9999999999.html
  499.                         if(/<dl.*>/.test(s)) { // hit
  500.                                 this.msg = s;
  501.                                 this.preReplace();
  502.                                 URL.kako = true;
  503.                                 delete args.append;
  504.                                 return 1;
  505.                         }
  506.                         trace("HTTP title="+((s.match(/<title>(.*)<\/title>/im)||[])[1]||""),9);
  507.                 }
  508.                 return -1;
  509.         }
  510.  ,readHTTP0 :
  511.         function(url) {
  512.                 var re = /^(?:(?!<>).)*<>(?:(?!<>).)*<>(?:(?!<>).)*<>(?:(?!<>).)*<>((?:(?!<>).)*).*\s*$/m;
  513.                 var s;
  514.                 url = "http://"+URL.site+"/"+URL.brdID+"/dat/"+URL.thrID+".dat";
  515.                 trace("try URL="+url,9);
  516.                 try { s=readHTTP(url); } catch(e) {}
  517.                 if(s) {
  518.                         this.msg = s;
  519.                         this.title = (s.match(re)||[])[1];
  520.                         this.last = this.checkData0(s).replace(/^.*$/m,"").length;
  521.                         delete args.append;
  522.                         return false;
  523.                 }
  524.                 return true;
  525.         }
  526. });
  527.  
  528. var Thread_jbbs = object(Thread,{
  529.   prepare     : function() { Jane=Jane_jbbs; URL=URL_jbbs; }
  530.  ,REG_PATTERN : [
  531.     { "thr" : /^[\s\S]*?<dl\s+(?:class|id)="thread[^>]*?>\s*(<dt>(?:(?!<\/dl>)[\s\S])*?\s*)<\/dl>[\s\S]*$/i
  532.      ,"msg" : /<DT><A.*?>([0-9]+).+?(?:<A HREF="mailto:(.+?)">)?<B> ?(?:<font color.*?>)?(.*?)(?:<\/font>)? ?<\/B>(?:<\/A>|<\/FONT>)(?: 投稿日)?: ?(.*?)(?:<BR>)?<DD>(.*) ?<BR><BR>/img
  533.      ,"rep" : "$1<>$3<>$2<>$4<>$5<>"
  534.     }
  535.    ,{ "thr" : /^[\s\S]*?<dl[^>]*?>(?:(?!<dt>)[\s\S])*(<dt>(?:(?!<\/dl>)[\s\S])*)<\/dl>[\s\S]*$/i
  536.      ,"msg" : /<DT><A.*?>([0-9]+).+?(?:<A HREF="mailto:(.+?)">)?<B> ?(?:<font color.*?>)?(.*?)(?:<\/font>)? ?<\/B>(?:<\/A>|<\/FONT>)(?: 投稿日)?: ?(.*?)(?:<BR>)?<DD>(.*) ?<BR><BR>/img
  537.      ,"rep" : "$1<>$3<>$2<>$4<>$5<>"
  538.     }
  539.   ]
  540.  ,urlReplace  : function(u) {
  541.                                         //したらばの事前URL変換:旧site名、/storage/ URLを現在のURLに置換
  542.                                         return  u.replace(URL.RE_HOST,"http://jbbs.shitaraba.net/")
  543.                                                          .replace( /\/\w+\.cgi\//, "/read.cgi/")
  544.                                                          .replace(/^(http:\/\/[^\/]+\/)([^\/]+\/)([^\/]+\/)storage\/(\d+).*$/,"$1bbs/read.cgi/$2$3$4/");
  545.                                 }
  546. // ,preReplace : function() {
  547. //                                      s = s.replace(/^\s*$/mg,"");
  548. //                                      s = s.replace(/\n\n/g,"\n");
  549. //                                      s = s.replace(/\s*<div[^>]+>(?:(?!<\/div>)[\s\S])*<\/div>\s*/ig,"\n"); //100レス毎に入る公告を除去
  550. //                               }
  551.  ,mainReplace :
  552.         function() {
  553.                 this.msg = this.msg.replace(/^(\d+<>.*?<>.*?<>.*?)(<>.*<>)((?:(?!<>).)*)$/mg, function($0,$1,$2,$3) {return ($3)?$1+" ID:"+$3+$2:$0;});
  554.         }
  555.  ,createBrdFolder :
  556.         function() {
  557.                 var s = readHTTP( URL.url.replace( /\/\w+\.cgi(\/\w+\/\w+\/).*$/, "/api/setting.cgi$1") );
  558.                 var bbs_title = (s.match(/^BBS_TITLE=(.*)$/m)||[])[1];
  559.                 var category = (s.match(/^CATEGORY=(.*)$/m)||[])[1];
  560.                 bbs_title || category || Err("E_brditem_not_found");
  561.                 brd = [ "【したらば】" + category.convDontUseStr() , bbs_title.convDontUseStr() , ""].join("\\");
  562.                 path(Jane.LogBasePath + JANE_LOGS + brd + URL.thrID + ".dat");
  563.                 return brd;
  564.         }
  565.  ,checkData   :
  566.         function(s) {
  567.                 if (this.last-this.first+1 != s.replace(/^.*$/mg,"").length) {
  568.                         this.requireFillAbn = true;
  569.                 }
  570.                 // 末尾のIDを削除
  571.                 this.msg = s.replace(/^(.*?)<>((?!<>).)*$/mg, "$1");
  572.         }
  573.  ,getTitle    : function(s) {
  574.                                         this.title = (s.match(/<>((?:(?!<>).)*)<>(?:(?!<>).)*$/m)||[])[1];
  575.                                         if(!this.title) this.title=DatInfo.title;
  576.                                 }
  577.  ,addTitle    : function() {}
  578.  ,readHTTP  :
  579.         function(url) {
  580.                 //-- 1st try : rawmode read ----
  581.                 var raw_url = url.replace(/\/\w+\.cgi\//, "/rawmode.cgi/");
  582.                 trace("try URL="+raw_url,9);
  583.                 var s = readHTTP( raw_url, true);
  584.                 switch( errmsg = (s[1].match(/^ERROR: *(?! )(.*?)$/m)||[])[1]||"" ) {
  585.                         case "BBS NOT FOUND": Err("E_bbs_not_found");
  586.                         case "KEY NOT FOUND": Err("E_key_not_found");
  587.                         case "THREAD NOT FOUND": Err("E_thread_not_found");
  588.                         case "STORAGE IN":
  589.                                 this.getTitle = this.getTitle2;
  590.                                 this.delDupData = this.delDupData2
  591.                                 this.checkData = this.checkData2;
  592.                                 Thread.readHTTP.call(this, URL.prm[0]);
  593.                                 delete this.mainReplace;
  594.                                 delete this.addTitle;
  595.                                 break;
  596.                         case "": //正常取得
  597.                                 s = s[0];
  598.                                 this.getTitle(s);
  599.                                 IDX_STATE["jbbs"] = 0;
  600.                                 this.msg = s;
  601.                                 break;
  602.                         default: Err("E_http_recieve", "(rawmode) : " + errmsg);
  603.                 }
  604.                 return true;
  605.         }
  606.  ,getTitle2   :
  607.         function(s) { this.title = (s.match(/<h1 class="thread-title">(.*?)<\/h1>/i)||[])[1]
  608.                                   || (s.match(/<title>(.*?)<\/title>/i)||[])[1] || "";
  609.                                 }
  610.  ,delDupData2 : //append時、既存のレス数分データを読み飛ばす
  611.         function() { while( (this.msg.match(/^(\d+)/i)||[])[1] < DatInfo.cnt+1)
  612.                                         { this.msg = this.msg.replace(/^.*\n/m,""); }
  613.                            }
  614.  ,checkData2   :
  615.         function(s) { var ln = this.checkData0(s);
  616.                                   if (this.last-this.first+1 != ln.length) { this.requireFillAbn = true; }
  617.                                 }
  618. });
  619.  
  620. var Thread_machi = object(Thread,{
  621.   prepare     : function() { Jane=Jane_machi; URL=URL_machi; }
  622.  ,noChkTitle  : true
  623.  ,REG_PATTERN : [
  624.     { "thr" : /^(?:(?!<>).)*<>(?:(?!<>).)*<>(?:(?!<>).)*<>(?:(?!<>).)*<>(?:(?!<>).)*<>((?:(?!<>).)*)<>((?:(?!<>).)*).*\s*$/m
  625.      ,"msg" : /^((?:(?!<>).)*<>(?:(?!<>).)*<>(?:(?!<>).)*<>(?:(?!<>).)*)(<>(?:(?!<>).)*<>(?:(?!<>).)*)<>((?:(?!<>).)*)(?:<>)?(.*\s*)$/mg
  626.      ,"rep" : "$1 [ $3 ]$2$4"
  627.     }
  628.   ]
  629.  ,urlReplace  : function(u) { u=u.replace(/\/test\/(?=read)/,"/bbs/").replace(/\/read\.cgi\//,"/offlaw.cgi/2/"); trace("replace url="+u,9); return u; }
  630.  ,getTitle    : function(s) { this.title = (s.match(this.REG_PATTERN[this.re_sel].thr)||[])[1] || DatInfo.title; }
  631.  ,checkData   : function(s) {
  632.                                         if(!/^\d+<>.*?<>.+?<>.*?<>.*$/m.test(s)) Err("E_remained_garbage");
  633.                                         if (this.last-this.first+1 != s.replace(/^.*$/mg,"").length) { this.requireFillAbn = true; }
  634.                                 }
  635.  ,delDupData  : function() {}
  636.  ,addTitle    : function() {}
  637.  ,getTBlock   : function() {}
  638. });
  639.  
  640. //==============================================================
  641. function loadFile(f) {
  642.         var s;
  643.         try {
  644.                 strm.Type = 2;
  645.                 strm.Charset = 'shift_jis';
  646.                 strm.Open();
  647.                 strm.loadFromFile(f);
  648.                 s = strm.ReadText(-1);
  649.                 strm.Close();
  650.         } catch(e) { strm.Close(); Err("E_loadfile", "\n"+e.message+"\ncurrent="+shell.CurrentDirectory+"\nfile="+f); }
  651.         return s;
  652. }
  653. function loadFile2(f) {
  654.         var s;
  655.         try {
  656.                 var file = fso.OpenTextFile( f, 1, false, 0);
  657.                 s = file.ReadAll();
  658.                 file.close();
  659.         } catch(e) {
  660.                 if(file) file.close();
  661.                 s = loadFile(f);
  662.         }
  663.         return s;
  664. }
  665.  
  666. function saveFile(f,s) {
  667.         strm.Type = 2;
  668.         strm.Charset = 'shift_jis';
  669.         strm.Open();
  670.         if (args.append) { try {strm.loadFromFile(f); strm.Position = strm.Size;} catch(e){} }
  671.         strm.WriteText(s);
  672.         try { strm.Savetofile(f, 2); }
  673.         catch(e) { strm.Close(); Err("E_savefile", "\n"+e.message+"\ncurrent="+shell.CurrentDirectory+"\nfile="+f); }
  674.         strm.Close();
  675. }
  676. function saveFile2(f,s) {
  677.         try{
  678.                 var file = fso.OpenTextFile( f, (args.append)?8:2 , true, 0);
  679.                 file.Write(s);
  680.                 file.Close();
  681.         } catch(e) {
  682.                 if(file) file.Close();
  683.                 saveFile(f,s);
  684.         }
  685. }
  686.  
  687. function readHTTP(u, withHeaders) {
  688.         var s="", r="";
  689.         http.open("GET", u, true);
  690.         for(var i in HTTP_HEADERS) { http.setRequestHeader(i, HTTP_HEADERS[i]); }
  691.         http.send();
  692.         for (var t0=new Date(); http.readyState<4; ) {
  693.                 if (new Date() - t0 > HTTP_TIMEOUT) { http.abort(); Err("E_http_timeout"); }
  694.                 WScript.Sleep(50);
  695.         }
  696.         if (http.status != 200 && !http.status==0) Err("E_http_recieve", " status="+http.status);
  697.         var header = http.getResponseHeader("Content-Type");
  698.         if (withHeaders) r = http.getAllResponseHeaders();
  699.         try {s = http.responseText;} catch(e) {s="";}
  700.         if (!/charset=/i.test(header)) {
  701.                 if(http.responseBody !== void 0) {
  702.                         if(basp) {
  703.                                 trace("HTTP文字コード変換開始 using basp21",9);
  704.                                 s = basp.Kconv(http.responseBody,4);
  705.                         } else {
  706.                                 trace("HTTP文字コード変換開始",9);
  707.                                 var cs = (s.match(/<meta[^>]*charset=([^>;"'\s]+)/i)||[])[1] || '_autodetect';
  708.                                 strm.Type = 1;
  709.                                 strm.Open();
  710.                                 strm.Write(http.responseBody);
  711.                                 strm.Position = 0;
  712.                                 strm.Type = 2;
  713.                                 strm.Charset = cs;
  714.                                 s = strm.ReadText(-1);
  715.                                 strm.Close();
  716.                         }
  717.                 }
  718.         }
  719.         http.abort();
  720.         if(!s) s="";
  721.         return withHeaders ? [s,r] : s;
  722. }
  723.  
  724. function saveDat(dat,s) {
  725.         if (args.append) {
  726.                 if(s=="") Err("E_already_there");
  727.         } else {
  728.                 if(s.match(/\n/g)==null) Err("E_no_data");
  729.                 if(!args.overwrite && DatInfo.cnt>=s.match(/\n/g).length) {
  730.                         if (MsgBox("既存のスレデータの方が同じか又は大きいですが、置換を続行しますか?",4+32+256,MY_NAME) != 6){
  731.                                 Err("E_stop");
  732.                         }
  733.                 }
  734.         }
  735.         if(args.bak) DatInfo.copyDat();
  736.         trace(); saveFile2(path(dat), s); trace("save file:"+dat);
  737. }
  738.  
  739. function invokeJaneStyle(url) {
  740.         shell.Exec(JANE_EXE + " " + url);
  741.         if(args.sendkey && args.sendkey > 0) {
  742.                 WScript.Sleep(args.sendkey);
  743.                 shell.SendKeys('^(w)');
  744.                 WScript.Sleep(200);
  745.                 shell.Exec(JANE_EXE + " " + url);
  746.         }
  747.         if(args.redraw) {
  748.                 WScript.Sleep(args.redraw);
  749.                 shell.SendKeys('%');
  750.                 WScript.Sleep(20);
  751.                 shell.SendKeys('T');
  752.                 WScript.Sleep(10);
  753.                 shell.SendKeys('G');
  754.                 WScript.Sleep(10);
  755.                 shell.SendKeys('0');
  756.         }
  757. }
  758.  
  759. function terminateJaneExe() {
  760.         var wmi; try { wmi = new WMI(); } catch(e) { wmi=null; }
  761.         shell.Exec(JANE_EXE);
  762.         WScript.Sleep(200);
  763.         shell.SendKeys("%({F4})");
  764.         if(!wmi) { WScript.Sleep(4000);}
  765.         else {
  766.                 do {
  767.                         var cnt=40;
  768.                         while(cnt && wmi.isAliveProcess(JANE_EXE, JANE_PATH+JANE_EXE)) { WScript.Sleep(100); cnt--;}
  769.                         if(!cnt) { WScript.Echo(JANE_EXE+"を終了させてください"); }
  770.                 } while(!cnt);
  771.         }
  772. }
  773.  
  774. function saveIdx(boardUrl) {
  775.         var i,s,r;
  776.         var use_db = parseInt(Jane.getINI([,"OPTIONS","QuickMerge",""]),10);
  777.         if(chkJaneProg().indexOf('Xeno')>=0) { use_db = parseInt(Jane.getINI([,"OJVIEW","QuickMerge",""]),10); }
  778.         var basedir = shell.CurrentDirectory;
  779.         var dir = fso.GetParentFolderName(fso.GetFile(DatInfo.dat).Path);
  780.         var datName = DatInfo.dat.replace(/^.*\\([^\\]+)\.dat$/,"$1");
  781.        
  782.         var maxRes = getBrdCustomizeIni(boardUrl) || 1000;
  783.         var state = (DatInfo.lines>=maxRes) ? 0 : IDX_STATE[ (URL===URL_jbbs) ? "jbbs" : "2ch" ];
  784.         if (URL.kako) state = 10;
  785.        
  786.         var last_got = Number(new Date(fso.GetFile(DatInfo.dat).DateLastModified)/1000+9*60*60);
  787.         var idx = [ datName,DatInfo.title,'',DatInfo.lines,'0','',boardUrl,state,DatInfo.lines,'','','0',last_got,'0','0' ];
  788.         var idxText = [];
  789.         for(i=0; i<idx.length; i++) { idxText[i] = "'" + idx[i] + "'"; }
  790.         var SQL_CMD_1 = "CREATE TABLE IF NOT EXISTS tableversion (tablename PRIMARY KEY, version);"
  791.                                         + 'INSERT OR IGNORE INTO "tableversion" VALUES(' + "'board_db','00000001');"
  792.                                         + 'INSERT OR IGNORE INTO "tableversion" VALUES(' + "'idxlist','00000002');"
  793.                                         + "CREATE TABLE IF NOT EXISTS idxlist ("
  794.                                         + "datname TEXT PRIMARY KEY, title TEXT, last_modified TEXT, lines TEXT, view_pos TEXT, idx_mark TEXT,"
  795.                                         + " uri TEXT, state TEXT,new_lines TEXT, write_name TEXT, write_mail TEXT,"
  796.                                         + " last_wrote TEXT, last_got TEXT, read_pos TEXT, record_be TEXT,"
  797.                                         + " etc1 TEXT, etc2 TEXT);";
  798.         var SQL_CMD_2 = 'INSERT OR IGNORE INTO idxlist VALUES(' + idxText.join(",") + ",NULL,NULL);";
  799.         var SQL_CMD_3 = "update idxlist set new_lines=new_lines+$2-lines where datname='$1';".expand([,datName,DatInfo.lines]);
  800.         var SQL_CMD_4 = "update idxlist set lines=" + idxText[3] + ",uri=" + idxText[6] + ",title=" + idxText[1]
  801.                                          + ",state=" + idxText[7] + ",last_got=" + idxText[12] + " where datname=" + idxText[0] + ";";
  802.  
  803.         if (use_db && args.restart) {
  804.                 var sql = new Sql();
  805.                 if(chkJaneProg().substr(0,4)=='Xeno' && !sql.isSqlite_ODBC) Err("E_require_sqlODBC");
  806.                 sql.isSqlite_ODBC || sql.isSqlite_exe || Err("E_require_sqlite");
  807.         }
  808.         if(args.restart) terminateJaneExe();
  809.        
  810.         if (use_db && args.restart) {
  811.         switch(chkJaneProg()) {
  812.                 case 'Style' :
  813.                 case 'Style?':
  814.                         shell.CurrentDirectory = dir;
  815.                         r=sql.exec("BoardDB.db",SQL_CMD_1+SQL_CMD_2+SQL_CMD_3+SQL_CMD_4);
  816.                         break;
  817.                 case 'Xeno':
  818.                 case 'Xeno?':
  819.                         var qmerge3 = Jane.LogBasePath+JANE_LOGS+"qmerge3.db";
  820.                         if(!fso.FileExists(qmerge3)) break;
  821.                         idx.splice(14,1,last_got);
  822.                         idxText = [];
  823.                         for(i=0; i<idx.length; i++) { idxText[i] = "'" + idx[i] + "'"; }
  824.                         var brd=DatInfo.brd.slice(0,-1);
  825.                         var SQL_CMD_XENO1 = "select board_id,max(board_id) from board where board_name='"+brd+"';";
  826.                         var SQL_CMD_XENO2 = 'insert into board VALUES((select max(board_id)+1 from board),'+"'"+brd+"'"+');';
  827.                         var SQL_CMD_XENO3 = "select board_id from thread where board_id=$1 and datname='"+datName+"';";
  828.                         var SQL_CMD_XENO4 = "insert into thread values($1,"+idxText.join(",")+");";
  829.                         var SQL_CMD_XENO5 = "update thread set new_lines=new_lines+$2-lines where datname='$1';".expand([,datName,DatInfo.lines]);
  830.                         var SQL_CMD_XENO6 = "update thread set lines=" + idxText[3] + ",uri=" + idxText[6] + ",title=" + idxText[1]
  831.                                                                 + ",state=" + idxText[7] + ",last_got=" + idxText[12] + " where datname=" + idxText[0] + ";";
  832.                         var board_id = sql.select(qmerge3,SQL_CMD_XENO1);
  833.                         board_id = (board_id[0].match(/^(\d+)/)||[])[1];
  834.                         if (!board_id) { sql.exec(qmerge3, SQL_CMD_XENO2); board_id=((sql.select(qmerge3,SQL_CMD_XENO1))[0].match(/^(\d+)/)||[])[1]; }
  835.                         if(!((sql.select(qmerge3,SQL_CMD_XENO3.expand([,board_id])))[0].match(/^\d+/))) {
  836.                                 sql.exec(qmerge3, SQL_CMD_XENO4.expand([,board_id]));
  837.                         } else {
  838.                                 sql.exec(qmerge3, SQL_CMD_XENO5);
  839.                                 sql.exec(qmerge3, SQL_CMD_XENO6);
  840.                         }
  841.                         default: break;
  842.                 }
  843.                 sql.finalize();
  844.         }
  845.        
  846.         // idxファイルの更新
  847.         shell.CurrentDirectory = dir;
  848.         var isExistIdx = false;
  849.         if(fso.FileExists(datName+".idx")) {
  850.                 s = loadFile(datName+".idx").replace(/\r/g,"").split("\n");
  851.                 if(s.length>=12) {
  852.                         isExistIdx = true;
  853.                         s[7]  = "" + (parseInt(s[7],10) + DatInfo.lines - parseInt(s[2],10));
  854.                         s[2]  = "" + idx[3];
  855.                         s[5]  = idx[6];
  856.                         s[6]  = "" + idx[7];
  857.                         s[11] = "" + last_got;
  858.                         s[0]  = idx[1];
  859.                 }
  860.         }
  861.         if(!isExistIdx) {
  862.                 s = idx;
  863.                 s.splice(0,1);
  864.                 s.push("");
  865.         }
  866.         s = s.join("\r\n");
  867.         try { saveFile(datName+".idx", s); } catch(e) {}
  868.        
  869.         // subject.txtの更新
  870.         if(fso.FileExists("subject.txt")) {
  871.                 var re = new RegExp("^"+datName+"\\..*\\((\\d+)\\)(\\s*)$", "m");
  872.                 s = loadFile("subject.txt");
  873.                 r = s.match(re);
  874.                 if(r) {
  875.                         s = s.replace(re, r[0].replace(/\((\d+)\)(\s*)$/,"("+DatInfo.lines+")$2"));
  876.                         try { saveFile("subject.txt",s); } catch(e) {}
  877.                 }
  878.         }
  879.         shell.CurrentDirectory = basedir;
  880. }
  881.  
  882. function Sql(){
  883.         var DRIVER = "DRIVER=SQLite3 ODBC Driver;";
  884.         var db = new ActiveXObject("ADODB.Connection");
  885.         this.isSqlite_exe  = fso.FileExists(SCRIPT_PATH + "sqlite3.exe");
  886.         this.isSqlite_ODBC = (function(){var s=true; try {db.Open(DRIVER);db.Close();} catch(e){s=false;}; return s;})();
  887.         this.finalize = function() { db = null; }
  888.         var funcTables  = [ "exec", "select" ];
  889.         var types = (this.isSqlite_ODBC) ? "ODBC" : "exe";
  890.         for(var i=0; i<funcTables.length; i++) { eval( "this."+ funcTables[i] + "=" + funcTables[i] + "_" + types + ";"); }
  891.         function exec_ODBC(dbFile,sql) {
  892.                 try {
  893.                         var s="";
  894.                         db.Open(DRIVER+"Database="+dbFile);
  895.                         db.Execute(sql);
  896.                 } catch(e) { s = e.message; }
  897.                 try { db.Close(); } catch(e) { s += " | Connection Close:"+e.message; }
  898.                 return [,s];
  899.         }
  900.         function select_ODBC(dbFile,sql) {
  901.                 var r="",s="";
  902.                 var rs = new ActiveXObject("ADODB.Recordset");
  903.                 try {
  904.                         db.Open(DRIVER+"Database="+dbFile);
  905.                         rs.Open(sql,db);
  906.                         while(!rs.Eof) {
  907.                                 var rr=[];
  908.                                 for(var i=0; i<rs.Fields.count; i++) { rr.push(rs(i).Value); }
  909.                                 r += rr.join("|")+"\n";
  910.                                 rs.MoveNext();
  911.                         }
  912.                 } catch(e) { s = e.message; }
  913.                 try { rs.Close(); } catch(e) { s += " | Recordset Close:"+e.message; }
  914.                 try { db.Close(); } catch(e) { s += " | Connection Close:"+e.message; }
  915.                 rs = null;
  916.                 return [r, s];
  917.         }
  918.         function exec_exe(dbFile,sql) { return select_exe(dbFile, sql); }
  919.         function select_exe(dbFile, sql) {
  920.                 var sqlite = shell.Exec(SCRIPT_PATH + "sqlite3.exe");
  921.                 sqlite.StdIn.WriteLine(".open '"+ dbFile+ "'");
  922.                 sqlite.StdIn.WriteLine(sql);
  923.                 sqlite.StdIn.WriteLine(".quit");
  924.                 return [ sqlite.StdOut.ReadAll(), sqlite.StdErr.ReadAll() ];
  925.         }
  926. }
  927.  
  928. function getBrdCustomizeIni(brdurl) {
  929.         if(!fso.FileExists(JANE_BRDCUSTOMIZE_INI)) return null;
  930.         var s=loadFile(JANE_BRDCUSTOMIZE_INI),r,u;
  931.         brdurl=brdurl.replace(/^http:\/\//,"").replace(/\./g,"\\.");
  932.         do {
  933.                 if (r = s.match(new RegExp("^\\[$1/?\\]\\s+MaxResNum=(\\d+)".expand([,"http://"+brdurl]),"im"))) break;
  934.                 u = brdurl.split(/\/(?=[^\/]+$)/);
  935.                 brdurl =u[0];
  936.         } while(u[1])
  937.         return r&&r[1];
  938. }
  939.  
  940. function chkJaneProg() {
  941.         var i,n1=0,n2=0, description,productname;
  942.         var folder=sha.Namespace(JANE_PATH);
  943.         var items=folder.Items();
  944.         for(i=0; i<items.Count-1;i++) {
  945.                 if(folder.GetDetailsOf(items, i) == '説明') { n1=i; }
  946.                 if(folder.GetDetailsOf(items, i) == '製品名') { n2=i; }
  947.         }
  948.         if(n1>0) description = folder.GetDetailsOf(folder.ParseName("Jane2ch.exe"),n1);
  949.         if(n2>0) productname = folder.GetDetailsOf(folder.ParseName("Jane2ch.exe"),n2);
  950.         if (description=="JaneXeno") return "Xeno";
  951.         if (description=="JaneView") return "View";
  952.         if (productname=="Jane Style") return "Style";
  953.         var fileversion = parseFloat(fso.GetFileVersion(JANE_PATH+JANE_EXE));
  954.         if (fileversion>3.0) return "Style?";
  955.         if (fileversion<1.0) return "Xeno?";
  956.         return "Unknown";
  957. }
  958. //==============================================================
  959. function path(p) {
  960.         var d = p.match(/[^\\]+\\/g), e = "";
  961.         for (var i = 0; d[i]; i++) fso.FolderExists(e += d[i]) || fso.CreateFolder(e);
  962.         return p;
  963. }
  964.  
  965. function parmParse(args) {
  966.         var ptn = [ "^(?:/n:)?(\\d+)", "^/f", "^\\+?http://", "^/w:?(-?\\d+)?$", "^/-w", "^/a(?:ppend)?"
  967.                                 , "^/b(?:ak)?(1)?", "^/z", "^/redraw:?(\\d+)?$", "^/log:?(.*)$", "^/keep_kako$" ];
  968.         var p = {};
  969.         var require_input_url = false;
  970.         for (var i=0; i<args.length; i++) {
  971.         for (var j=0,n=-1; j<ptn.length;j++) {if ((new RegExp(ptn[j],"i")).test(args(i))) { n=j; break;} }
  972.         switch (n) {
  973.                 case 0: p["opt_n"] = ((args(i).match(new RegExp(ptn[n],"i"))||[])[1]||"");
  974.                                 break;
  975.                 case 1: require_input_url = true;
  976.                                 break;
  977.                 case 2: p["url"] = args(i);
  978.                                 break;
  979.                 case 3: p["sendkey"] = ((args(i).match(new RegExp(ptn[n],"i"))||[])[1]||1200);
  980.                                 break;
  981.                 case 4: p["sendkey"] = -1;
  982.                                 break;
  983.                 case 5: p["append"] = true;
  984.                                 break;
  985.                 case 6: p["bak"] = -1;
  986.                                 if ((args(i).match(new RegExp(ptn[n],"i"))||[])[1]) { p["bak"] = 1; }
  987.                                 break;
  988.                 case 7: p["restart"] = true;
  989.                                 break;
  990.                 case 8: p["redraw"] = ((args(i).match(new RegExp(ptn[n],"i"))||[])[1]||1200);
  991.                                 break;
  992.                 case 9: p["trace"] = ((args(i).match(new RegExp(ptn[n],"i"))||[])[1]||"");
  993.                                 break;
  994.                 case 10: p["keep_kako"] = true;
  995.                                 break;
  996.                 default: break;
  997.         }
  998.         }
  999.         p.url = (p.url||"").replace(/^(\+?http:\/\/.*?)http:\/\/.*$/, "$1")
  1000.         if (require_input_url || !p.url) p.url = InputBox("URLを指定してください",MY_NAME, p.url) || "";
  1001.         if(p.url.charAt(0)=='+') { p.url = p.url.substr(1); p["overwrite"] =true; }
  1002.         if(p.overwrite) p.append = false;
  1003.         return p;
  1004. }
  1005.  
  1006. //==============================================================
  1007.  
  1008. function WMI() {
  1009.         var locator = new ActiveXObject("WbemScripting.SWbemLocator");
  1010.         var services = locator.ConnectServer(null, "root\\CIMV2");
  1011.         return {
  1012.                 isAliveProcess :
  1013.                         function (pName, pPath) {
  1014.                                 var query = "SELECT * FROM Win32_Process WHERE name='"+pName+"'";
  1015.                                 var props = this.wmiProps(query);
  1016.                                 for (var i=0, status=false; i<props.length; i++) { if(props[i].ExecutablePath == pPath) {status = true;} }
  1017.                                 return status;
  1018.                         }
  1019.                 ,wmiProps :
  1020.                         function (query) {
  1021.                                 var result = [];
  1022.                                 try {
  1023.                                         var set = services.ExecQuery(query);
  1024.                                         var e = new Enumerator(set);
  1025.                                         while (!e.atEnd()) { result.push(e.item()); e.moveNext(); }
  1026.                                 } catch (e) { throw e; }
  1027.                                 return result;
  1028.                         }
  1029.                  ,getProcessID :
  1030.                         function (pName, pPath) {
  1031.                                 var query = "SELECT * FROM Win32_Process WHERE name='"+pName+"'";
  1032.                                 do {
  1033.                                         var props = this.wmiProps(query);
  1034.                                         for (var i=0,c=0,pid; i<props.length; i++) {
  1035.                                                 if (props[i].ExecutablePath == pPath) { c++; pid=props[i].ProcessID; }
  1036.                                         }
  1037.                                 } while (c>1);
  1038.                                 return pid;
  1039.                         }
  1040.         }
  1041. }
  1042. function Trace() {
  1043.         var logfile = TRACE_LOG;
  1044.         var flag    = true;
  1045.         var first   = true;
  1046.         var t       = [];
  1047.         if(args.trace) logfile = replaceEnv(args.trace);
  1048.         if(!fso.FileExists(logfile)) {
  1049.                 var env = new ENV();
  1050.                 try{
  1051.                         var f = fso.CreateTextFile(logfile);
  1052.                         f.WriteLine("["+MY_NAME+"]");
  1053.                         f.WriteLine("Jane Type = "+chkJaneProg()+"\t"+fso.GetFileVersion(JANE_PATH+JANE_EXE));
  1054.                         f.WriteLine("current path = "+JANE_PATH);
  1055.                         f.WriteLine("Logs path = "+Jane.LogBasePath+JANE_LOGS);
  1056.                         f.WriteLine("script path = "+SCRIPT_PATH);
  1057.                         f.WriteLine("UAC = "+env.UAC);
  1058.                         f.WriteLine("64bit? = "+env.PROCESSOR_ARCHITECTURE+"\t"+env.PROCESSOR_ARCHITEW6432);
  1059.                         f.WriteLine("----------------------------------------------------------------------");
  1060.                         f.Close();
  1061.                 } catch(e) {flag=false; if(f) f.Close();}
  1062.                 env = null;
  1063.         }
  1064.         return function(s,n) {
  1065.                 if(flag) try{
  1066.                         if(!n) n=0;
  1067.                         var f = fso.OpenTextFile(logfile,8,true,0);
  1068.                         if(first) {first=false; f.WriteLine("");}
  1069.                         var tt=new Date();
  1070.                         if(!s) { t[n] = new Date();}
  1071.                         else   { f.WriteLine(formatDate(tt,3)+"\t"+((n in t)?formatNum(tt-t[n],7)+"ms":"         ")+"\t"+s); }
  1072.                         f.Close();
  1073.                 } catch(e) {if(f) f.Close();}
  1074.         }
  1075. }
  1076. function getEnv(s) { var wse = shell.Environment("Process"); return wse(s); }
  1077. function replaceEnv(s) { return s.replace(/\%([^%]+)\%/ig, function(w0,w1) {return getEnv(w1);}); }
  1078. function formatDate(d,n) {
  1079.         return [d.getFullYear()
  1080.                         , "/"  , ("0"+(d.getMonth()+1)).slice(-2)
  1081.                         , "/"  , ("0"+d.getDate()).slice(-2)
  1082.                         , "("  , "日月火水木金土".substr(d.getDay(),1)
  1083.                         , ") " , ("0"+d.getHours()).slice(-2)
  1084.                         , ":"  , ("0"+d.getMinutes()).slice(-2)
  1085.                         , ":"  , ("0"+d.getSeconds()).slice(-2)
  1086.                         , "."  , ("00"+parseInt(d.getMilliseconds(),10)+" ").slice(-4,n-4)
  1087.                   ].join("");
  1088. }
  1089. function formatNum(d,n) {
  1090.         return ("        "+d).slice(-n);
  1091. }
  1092. function ENV() {
  1093.          this.UAC = sha.IsRestricted("system", "EnableLUA");
  1094.          this.PROCESSOR_ARCHITECTURE = getEnv("PROCESSOR_ARCHITECTURE");
  1095.          this.PROCESSOR_ARCHITEW6432 = getEnv("PROCESSOR_ARCHITEW6432")
  1096.          return this;
  1097. }
  1098. //==============================================================
  1099.  
  1100. function main() {
  1101.         if (URL_jbbs.RE_HOST.test(args.url)) Thread_jbbs.proc();
  1102.         else if (URL_machi.RE_HOST.test(args.url)) Thread_machi.proc();
  1103.         else Thread_2ch.proc();
  1104. }
  1105.  
  1106. /*@if (@DEBUG)
  1107.         main();
  1108.         @else @*/
  1109.         try {main();} catch (e) {WScript.Echo(e.message);}
  1110. /*@end @*/
  1111.  
  1112. //==============================================================
  1113. /*@if (@EnabledTest2chJSON)
  1114. function get2chJSON() {
  1115.         var urlJSON = "http://itest.2ch.net/public/newapi/client.php?subdomain=$2&board=$5&dat=$6".expand(URL.prm);
  1116.         trace("try URL=" + urlJSON,9);
  1117.         var s = readHTTP(urlJSON);
  1118.         if(!s) return null;
  1119.         var total_count = (s.match(/"total_count":(\d+)/)||[])[1];
  1120.         var thread      = s.match(/"thread":\[(\d+),(\d+),("[^"]*"),("[^"]*"),("[^"]*"),("[^"]*")\]/);
  1121.         var comments    = (s.match(/"comments":\[((?:\[(\d+),("[^"]*"),("[^"]*"),(\d+),("[^"]*"),("[^"]*"),("[^"]*")\],?)+)\]/)||[])[1];
  1122.         if (!thread || !comments) return null;
  1123.         eval("var title ="+thread[6]+";");
  1124.         comments = comments.replace(/(\[(?:\d+),(?:"[^"]*"),(?:"[^"]*"),(?:\d+),(?:"[^"]*"),(?:"[^"]*"),(?:"[^"]*")\]),/g,"$1\n").split("\n");
  1125.         Thread_2ch.title = title;
  1126.         Thread_2ch.last = comments.length;
  1127.         if(args.append && DatInfo.cnt>0) { comments.splice(0,DatInfo.cnt); }
  1128.         for(var i=0; i<comments.length; i++) {
  1129.                 var res,d,id="",be="";
  1130.                 var res = comments[i].substring(1,comments[i].length-1);
  1131.                 res = res.match(/^(\d+),("[^"]*"),("[^"]*"),(\d+),("[^"]*"),("[^"]*"),("[^"]*")$/);
  1132.                 var name = eval(res[2]).replace(/(◆.+)$/,"</b>$1<b>").replace(/(転載ダメ&copy;2ch\.net)/,"<small>$1</small>");
  1133.                
  1134.                 d = new Date( (res[4]<365*24*60*60*1000) ? res[4]*1000 : res[4] );
  1135.                 d = formatDate(d,2);
  1136.                 if (res[5]!='""')  id = " ID:" + eval(res[5]);
  1137.                 if (res[6]!='""')  be = " BE:" + eval(res[6]);
  1138.                 comments[i] = [ name, eval(res[3]), d + id + be, eval(res[7]), ].join("<>");
  1139.         }
  1140.         s = "";
  1141.         if(comments.length>0) {
  1142.                 if(!args.append || !DatInfo.cnt) { comments[0] += title; }
  1143.                 s = comments.join("\n") + "\n";
  1144.         }
  1145.         return s;
  1146. }
  1147. @end @*/
RAW Paste Data
Top