#!/usr/bin/perl #┌───────────────────────────────── #│ YY-BOARD v4.8 (2003/01/10) #│ Copyright(C) Kent Web 2003 #│ webmaster@kent-web.com #│ http://www.kent-web.com/ #└───────────────────────────────── $ver = 'YYBBS v4.8'; #┌───────────────────────────────── #│ [注意事項] #│ 1. このスクリプトはフリーソフトです。このスクリプトを使用した #│ いかなる損害に対して作者は一切の責任を負いません。 #│ 2. 設置に関する質問はサポート掲示板にお願いいたします。 #│ 直接メールによる質問は一切お受けいたしておりません。 #│ 3. 添付の home.gif は L.O.V.E の mayuRin さんによる画像です。 #└───────────────────────────────── # # 【ファイル構成】 # # public_html (ホームディレクトリ) # | # +-- yybbs / yybbs.cgi [701] # | bbslog.txt [600] # | dic.txt [600] # | history.txt [600] # | pastidx.dat [600] # | # +---- $lockdir [701] / $lockname [600] # $spt_ver = 'YY_BOARD/4.8 Poison_des_Yeux/1.35'; # ==== 改造者によるドキュメント ===================================== # このスクリプトは、KENTさん(webmaster@kent-web.com)が著作権を持つ # 「YY-BOARD v4.8」をもとに、もりば(rinrin@funifuni.net)が改造を行っ # たものです。 # 「YY-BOARD v4.8」に添付の home.gif は使用していません。 # ちなみにタブ幅は 4 です。 # =================================================================== # # ==== ver.1.14.2 以降に関する特記事項 ============================== # 特定文字列置換処理スクリプトは、Bee-X さん # (http://www2s.biglobe.ne.jp/~bee-x/)によって作られました。 # このバージョンでは、その一部を修正して使用しています。 # =================================================================== # # ==== ver.1.32 以降に関する特記事項 ================================ # rename関数による排他処理スクリプトは、大崎博基さんによるPerlメモ # (http://www.din.or.jp/~ohzaki/perl.htm)に記載の「排他制御(ファイル # ロック)をする」を参考にしました。 # =================================================================== # ログフォーマット # 一行目 # 最新レス番<>最新レスの投稿者host<>最新レス投稿時刻<>親記事数<> # 二行目以降 # レス番 ($no)<>親記事レス番 ($reno)<>ユーザ削除フラグ ($udel)<>削除キー ($pw)<>投稿時刻 ($times)<>投稿者 ($name)<>本文 ($com)<>タイトル ($sub)<>E-mail ($mail)<>URL ($url)<>最終更新時刻 ($mod_times)<>User-Agent ($env)<>投稿者host ($host)<>オプション ($opt)<>アイコン ($icon)<> # オプション ($opt) 書式 # 1 (hoge) タグ有効フラグ ($tag) preモードフラグ ($pre) URLtoAnchorフラグ ($anc) #============# # 設定項目 # #============# #------------# # 基本設定 # #------------# # タイトル名を指定 $title = 'よろづ書込処v4'; # 管理者用マスタパスワード (英数字で8文字以内) $pass = 'hogehoge'; # 文字コード $doccode = 'UTF-8'; # charset, accept-charset # ファイルロック形式 (0=no,1=symlink関数,2=mkdir関数,3=rename関数,4=flock関数) $lockkey = 3; # ロックファイル名 # → rename関数を使う場合はあらかじめファイルを作成しなければならない # → flock関数を使う場合は必要ない。 $lockfile = 'lock/yybbs.lock'; # スクリプトのファイル名 $script = 'yybbs.cgi'; # ログファイル名 $logfile = 'bbslog.txt'; # 改造履歴ファイル名 $hisfile = 'history.txt'; # ユーザ削除記事のタイトルとコメント $del_sub = '兄チャマ!'; $del_com = 'この記事はよつ……じゃなかった、怪盗クローバーが頂いたデス!'; # ページトップに表示するスレッド数 $top_log = 3; # 記事タイトルの最大バイト数 $sub_len = 78; # クッキーの賞味期限(日) $ck_exp = 90; # メールアドレスの入力確認 (0=no 1=yes) $in_mail = 0; #--------------------------# # アクセス・投稿制限設定 # #--------------------------# # 緊急避難用全投稿停止 $AllStop = 0; # 偽フォーム排除用基準URL # →空文字列の場合はチェックしない。 $base_url = ''; # 重複投稿をチェックする (0=no 1=yes) $dbl_post = 0; # 同一ホストからの連続投稿制限時間(秒) $wait = 0; # アクセス制限を行なう (0=no 1=yes) $denykey = 0; if ($denykey) { # 規制対象(ホスト名、IPアドレスを記述) @deny = ( '', '', ); } #----------------# # 過去ログ設定 # #----------------# # 過去ログ生成 (0=no 1=yes) $pastkey = 0; # 過去ログ情報ファイル名 $idxfile = 'pastidx.dat'; if ($pastkey) { # 過去ログディレクトリパス $pastdir = '../bbs/'; # 最大保持スレッド数 $max = 50; # 一回で過去ログに送るスレッド数 $pastctn = 20; } #----------------------# # 特定文字列置換機能 # #----------------------# # 置換機能を使用する (0=no 1=yes) $substkey = 1; if ($substkey) { # 置換辞書ファイル名 $dicfile = 'dic.txt'; # 置換許可文字(記号)の指定 # 指定しない場合は空文字列 # 記号(!"#$%&'()=~|@`[{;+:*]},<.>/?\_)を # 指定する場合は、「\」を追加する事。 # 例:「!」を指定する場合は「\!」と記述 # thx! Bee-X さん (http://www2s.biglobe.ne.jp/~bee-x/) $sst_sign = '!'; } #--------------------# # アイコン表示機能 # #--------------------# # アイコンを使用する (0=no 1=yes) $iconkey = 1; if ($iconkey) { # アイコン画像ディレクトリパス $icodir = 'image/'; # アイコン全体定義 # valueは「アイコングループ」配列のリファレンス %icons = ( 'ukagaka' => \@ukagaka, 'snow' => \@snow, 'wind' => \@wind, 'hajimete' => \@hajimete, 'one2' => \@one2, 'hani' => \@hani, 'mizuiro' => \@mizuiro, # 'mizuiro2' => \@mizuiro2, 'kiminozo' => \@kiminozo, 'muvluv' => \@muvluv, 'tukihime' => \@tukihime, 'ga' => \@ga, 'mahoraba' => \@mahoraba, 'pani' => \@pani, 'maria' => \@maria, 'maria2' => \@maria2, 'yumeria' => \@yumeria, ); # アイコングループ定義(各要素は無名配列) # 0:アイコングループ定義[サブディレクトリ名,ラベル(,拡張子,width,height)] # 1-:アイコン定義[ファイル名,ラベル(,拡張子,width,height)] # アイコン定義で拡張子等を省略した場合は、アイコングループ定義の値を適用。 # アイコングループ定義で省略した場合は、png,100,100 # 別記の他は(C)Expensive Noise(http://mint.cutegirl.jp/)256色アイコン @ukagaka = ( ['ukagaka','伺か。'], ['ic_niseharuna','さくら'],['ic_unyu1','うにゅう'],['ic_unyu2','うにゅう(刮目)'], ['ic_nekoko','ねここ'], ); @snow = ( ['snow','SNOW'], ['ic_sn_sumino','澄乃'],['ic_sn_shigure','しぐれ'],['ic_sn_asahi','旭'], ['ic_sn_ohka','桜花'],['ic_sn_meiko','芽依子様'],['ic_sn_hohsen','鳳仙'], ); @wind = ( ['wind','Wind'], ['ic_minamo','みなも'],['ic_hinata','ひなた'],['ic_wakaba','わかば'], ['ic_nozomi','望'],['ic_hikari','彩'],['ic_kasumi','紫光院様'], ); @hajimete = ( ['hajimete','はじめての'], ['ic_shiori','しおり'],['ic_saori','さおり'],['ic_h_yuuna','ゆうな'],['ic_h_maina','まいな'], ); @one2 = ( ['one2','ONE2 ~永遠の約束~','gif'], # (C)NEXTON(http://www.tactics.ne.jp/)TacticsNET/BaseSon/雛太屋特設コーナー顔チップアイコン ['k_nao','奈穂'],['k_nao2','奈穂(ミニ)'], ['k_ayame','綾芽'],['k_ayame2','綾芽(ミニ)'], ['k_kuon','久遠'],['k_kuon2','久遠(ミニ)'], ['k_haruka','遥先生'],['k_noa','乃逢'],['k_kokone','心音'], ); @hani = ( ['hani','月は東に日は西に','gif'], # (C)オーガスト(http://august-soft.com/)『月は東に日は西に ~Operation Sanctuary~』画像素材 ['hani_c0101','美琴さん', '','94','126'], ['hani_c0102','お喜びな美琴さん', '','94','126'], ['hani_c0103','てれてれな美琴さん', '','94','125'], ['hani_c0104','しょんぼりな美琴さん', '','80','118'], ['hani_c0201','保奈美さん', '','73','119'], ['hani_c0202','お喜びな保奈美さん', '','72','119'], ['hani_c0203','てれてれな保奈美さん', '','73','119'], ['hani_c0204','ご機嫌斜めな保奈美さん','','90','119'], ['hani_c0301','ちひろさん', '','58','119'], ['hani_c0302','お喜びなちひろさん', '','71','128'], ['hani_c0303','てれてれなちひろさん', '','58','119'], ['hani_c0304','落ちこみのちひろさん', '','105','127'], ['hani_c0401','茉理さん', '','100','119'], ['hani_c0402','お喜びな茉理さん', '','103','125'], ['hani_c0403','てれてれな茉理さん', '','124','120'], ['hani_c0404','お怒りの茉理さん', '','124','131'], ['hani_c0501','結先生', '','59','106'], ['hani_c0502','お喜びな結先生', '','72','110'], ['hani_c0503','てれてれな結先生', '','59','106'], ['hani_c0504','お困りな結先生', '','79','118'], ['hani_c0601','恭子先生', '','77','133'], ['hani_c0602','お喜びな恭子先生', '','83','133'], ['hani_c0603','てれてれな恭子先生', '','78','133'], ['hani_c0604','ご機嫌斜めな恭子先生', '','70','133'], ['hani_c0701','委員長', '','61','118'], ['hani_c0702','お喜びな委員長', '','61','118'], ['hani_c0703','てれてれな委員長', '','60','118'], ['hani_c0704','お怒りの委員長', '','61','118'], ['hani_c0801','弘司', '','76','130'], ['hani_c0802','お喜びな弘司', '','89','132'], ['hani_c0803','呆れてる弘司', '','76','130'], ['hani_c0901','理事長', '','77','126'], ['hani_c0902','眼鏡キラーンな理事長', '','64','126'], ['hani_c1001','英理さん', '','81','120'], ['hani_c1002','お喜びな英理さん', '','81','120'], ['hani_c1101','親父殿', '','72','119'], ['hani_c1102','お喜びな親父殿', '','73','119'], ['hani_c1201','フカセン', '','66','127'], ); @mizuiro = ( ['mizuiro','みずいろ','gif'], # (C)ねこねこソフト(http://www.din.or.jp/~nekoneko/)フリー素材 ['mizu_yuki','雪希'],['mizu_hiyori','日和'],['mizu_shinpon','新ぽん'], ['mizu_kiyoka','清香'],['mizu_yshindo','やかまさん'],['mizu_oshindoh','おとなさん'], ['mizu_asami','先輩'],['mizu_fuyuka','冬佳'], ); @mizuiro2 = ( ['mizuiro2','みずいろ2'], ['ic_yukimaru6sai','雪希'],['ic_hiyori','日和'],['ic_kiyoka','清香'], ['ic_oshindoh','おとなさん'],['ic_yshindoh','やかまさん'],['ic_asami','麻美'], ['ic_hiyori2','νひよりん'],['ic_hiyori3','まじかる☆ひよりん'], ['ic_kiyokamama','清香ママ'], ); @kiminozo = ( ['kiminozo','君が望む永遠'], ['ic_haruka','遙'],['ic_mitsuki','水月'],['ic_akane','茜'], ['ic_daikuji','あゆ'],['ic_mayumayu','まゆ'], ); @muvluv = ( ['muvluv','マブラヴ'], ['ic_sumika','純夏'],['ic_meiya','冥夜'],['ic_kei','慧'],['ic_chizuru','千鶴'], ['ic_miki','壬姫'],['ic_akane','茜'],['ic_mikoto','尊人'],['ic_mikoto2','美琴'], ['ic_kasumi','霞'],['ic_tsukuyomi','月詠'],['ic_takeru','武'], ); @tukihime = ( ['tukihime','月姫'], ['ic_arc','アルクェイド'],['ic_ciel','シエル'],['ic_akiha','秋葉'], ['ic_hisui','翡翠'],['ic_kohaku','琥珀'],['ic_sacchin','さっちん'], ['ic_ren','レン'],['ic_akira','晶'],['ic_hanepin','羽ピン'], ['ic_souka','蒼香'],['ic_nanako','ななこ'],['ic_sion','シオン'], ); @ga = ( ['ga','ギャラクシーエンジェル'], ['ic_mille','ミルフィーユ'],['ic_ranfa','蘭花'],['ic_mint','ミント'], ['ic_vanilla','ヴァニラ'],['ic_forte','フォルテ'],['ic_nomad','ノーマッド'], ); @mahoraba = ( ['mahoraba','まほらば'], ['ic_kozue','梢ちゃん'],['ic_saki','早紀ちゃん'],['ic_nanako','魚子ちゃん'], ['ic_natsume','棗ちゃん……かも'],['ic_tamami','珠実ちゃん'],['ic_megumi','桃乃さん'], ['ic_asami','朝美ちゃん'],['ic_sayoko','沙夜子さん'],['ic_sore','それ'], ); @pani = ( ['pani','ぱにぽに'], ['ic_mesousa','メソウサ'],['ic_kami','神'],['ic_panda','パンダ村長'],['ic_roboko','ロボ子'], ); @maria = ( ['maria','マリア様がみてる'], ['ic_mm_yumi2','祐巳さん'],['ic_mm_sachiko2','祥子さま'],['ic_mm_yohko2','蓉子さま'], ['ic_mm_yoshino2','由乃さん'],['ic_mm_rei2','令さま'],['ic_mm_eriko2','江利子さま'], ['ic_mm_noriko2','乃梨子ちゃん'],['ic_mm_shimako2','志摩子さん'],['ic_mm_sei2','聖さま'], ['ic_mm_shizuka2','静さま'],['ic_mm_tsutako2','蔦子さん'],['ic_mm_tohko2','瞳子ちゃん'], ['ic_mm_minako2','三奈子さま'],['ic_mm_mami2','真美さん'],['ic_mm_syohko2','笙子ちゃん'], ); @maria2 = ( ['maria2','マリア様がみてる2'], ['ic2_mm_yumi','祐巳さん'],['ic2_mm_sachiko','祥子さま'],['ic2_mm_yohko','蓉子さま'], ['ic2_mm_yoshino','由乃さん'],['ic2_mm_rei','令さま'],['ic2_mm_eriko','江利子さま'], ['ic2_mm_noriko','乃梨子ちゃん'],['ic2_mm_shimako','志摩子さん'],['ic2_mm_sei','聖さま'], ['ic2_mm_tsutako','蔦子さん'],['ic2_mm_tohko','瞳子ちゃん'],['ic2_mm_kanako','可南子ちゃん'], ); @yumeria = ( ['yumeria','ゆめりあ'], ['ic_yr_mone','もね'],['ic_yr_miduki','みづき'],['ic_yr_neneko','ねねこ'], ['ic_yr_kuyoh','九葉'],['ic_yr_nanase','七瀬さん'], ); } #---(ここまで「アイコン表示機能」設定)---# #-------------# # XHTML要素 # #-------------# # 許可する要素の候補 # ===== Modularization of XHTML? ===== http://www.w3.org/TR/xhtml-modularization/ # 5. XHTML Abstract Modules # 5.2. Core Modules # 5.2.2. Text Module ## Inline Structural @inlstruct = ('br','span',); ## Inline Phrasal @inlphras = ('abbr','acronym','cite','code','dfn','em','kbd','q','samp','strong','var',); # 5.2.3. Hypertext Module @hypertext = ('a',); # 5.4. Text Extension Modules # 5.4.1. Presentation Module ## Inline Presentational @inlpres = ('b','i','tt',); @inlpresdepre = ('big','small','sub','sup',); # 5.4.2. Edit Module @edit = ('ins','del',); # 5.4.3. Bi-directional Text Module @bdo = ('bdo',); # 5.7. Image Module @image = ('img',); # ===== Ruby Annotation Module ===== http://www.w3.org/TR/ruby @ruby = ('ruby','rbc','rtc','rb','rt','rp',); # 許可する要素 %eles = ( 'inlstruct' => '0', 'inlphras' => '1', 'hypertext' => '1', 'inlpres' => '1', 'edit' => '1', 'bdo' => '0', 'image' => '0', 'ruby' => '0', ); #---(ここまで「XHTML要素」設定)---# #----------------# # 文字実体参照 # #----------------# @entity = ( # Basic Latin 'quot','amp','apos','lt','gt', # Latin-1 Supplement 'nbsp','iexcl','cent','pound','curren','yen','brvbar','sect','uml','copy', 'ordf','laquo','not','shy','reg','macr','deg','plusmn','sup2','sup3', 'acute','micro','para','middot','cedil','sup1','ordm','raquo','frac14','frac12', 'frac34','iquest','Agrave','Aacute','Acirc','Atilde','Auml','Aring','AElig','Ccedil', 'Egrave','Eacute','Ecirc','Euml','Igrave','Iacute','Icirc','Iuml','ETH','Ntilde', 'Ograve','Oacute','Ocirc','Otilde','Ouml','times','Oslash','Ugrave','Uacute','Ucirc', 'Uuml','Yacute','THORN','szlig','agrave','aacute','acirc','atilde','auml','aring', 'aelig','ccedil','egrave','eacute','ecirc','euml','igrave','iacute','icirc','iuml', 'eth','ntilde','ograve','oacute','ocirc','otilde','ouml','divide','oslash','ugrave', 'uacute','ucirc','uuml','yacute','thorn','yuml', # Latin Extended-A 'OElig','oelig','Scaron','scaron','Yuml', # Latin Extended-B 'fnof', # Spacing Modifier Letters 'circ','tilde', # Greek 'Alpha','Beta','Gamma','Delta','Epsilon','Zeta','Eta','Theta','Iota','Kappa', 'Lambda','Mu','Nu','Xi','Omicron','Pi','Rho','Sigma','Tau','Upsilon', 'Phi','Chi','Psi','Omega', 'alpha','beta','gamma','delta','epsilon','zeta','eta','theta','iota','kappa', 'lambda','mu','nu','xi','omicron','pi','rho','sigmaf','sigma','tau','upsilon', 'phi','chi','psi','omega','thetasym','upsih','piv', # General Punctuation 'ensp','emsp','thinsp','zwnj','zwj','lrm','rlm','ndash','mdash','lsquo', 'rsquo','sbquo','ldquo','rdquo','bdquo','dagger','Dagger','bull','hellip','permil', 'prime','Prime','lsaquo','rsaquo','oline','frasl', # Currency Symbols 'euro', # Letterlike Symbols 'image','weierp','real','trade','alefsym', # Arrows 'larr','uarr','rarr','darr','harr','crarr','lArr','uArr','rArr','dArr', 'hArr', # Mathematical Operators 'forall','part','exist','empty','nabla','isin','notin','ni','prod','sum', 'minus','lowast','radic','prop','infin','ang','and','or','cap','cup', 'int','there4','sim','cong','asymp','ne','equiv','le','ge','sub', 'sup','nsub','sube','supe','oplus','otimes','perp','sdot', # Miscellaneous Technical 'lceil','rceil','lfloor','rfloor','lang','rang', # Geometric Shapes 'loz', # Miscellaneous Symbols 'spades','clubs','hearts','diams', ); #------------------------------# # 汎用メッセージ出力用定型文 # #------------------------------# # ステータスコード %respcode = ( # コード メッセージ付,日本語,詳細文 '200' => ['200 OK','200 了承', '要求は成功しました。',], '400' => ['400 Bad Request','400 悪い要求', '要求は正しくない形をした文法のために奉仕者によって理解されることができませんでした。依頼人は修正することなく要求を繰り返すべきではありません。',], '403' => ['403 Forbidden','403 御禁制', '奉仕者は要求を理解しました。しかしそれを完了することを拒絶しています。認証は役に立たないでしょう。また、要求は繰り返されるべきではありません。',], '404' => ['404 Not Found','404 無提供', '奉仕者は要求の統一的資源識別名と調和する何かを提供しませんでした。',], '405' => ['405 Method Not Allowed','405 許されない方法', '要求行に指定された方法は、要求の統一的資源識別名によって結びつけられた資源のためには許されません。',], '413' => ['413 Request Entity Too Large','413 大き過ぎる要求実体', '奉仕者が意図している、あるいは処理する事ができるより要求実体が大きい為に、奉仕者は要求を処理する事を拒絶しています。',], '500' => ['500 Internal Server Error','500 内部の奉仕者の誤り', '奉仕者は予期しない状態に遭遇し、それは奉仕者が要求を完了するのを妨げました。',], '503' => ['503 Service Unavailable','503 奉仕は利用できない', '奉仕者は現在、奉仕者の一時的過負荷あるいは保守のために要求を扱うことができません。',], ); # 応答メッセージ %respmsg = ( # メッセージ名 ステータスコード,見出し,内容 # 正常終了 'endofnew' => ['200','投稿完了', '新規投稿は正常に完了しました。',], 'endofres' => ['200','返信投稿完了', '指定されたスレッドへの返信は正常に完了しました。',], 'endofedt' => ['200','修正投稿完了', '指定された記事の修正は正常に完了しました。',], 'endofdel' => ['200','削除完了', '指定された記事の削除は正常に完了しました。',], # 管理都合系 'allstop' => ['503','投稿等機能停止中', '現在「新規投稿」「返信投稿」「記事修正」「記事削除」各機能を一時的に停止しています。再開をお待ちください。',], 'testok' => ['200','セクション通過', 'ここまでは来ている模様です。',], # 不正アクセス系 'notpost' => ['405','不正なアクセス', 'ログ書き込みを伴なうアクセスでの Method は POST 限定です。',], 'badmode' => ['400','謎のパラメータ (mode)', '未知の mode パラメータが設定されているような気がします。',], 'badclass' => ['400','謎のパラメータ (class)', '未知の class パラメータが設定されているような気がします。',], 'badnum' => ['400','謎のパラメータ (sub)', '未知のサブパラメータが設定されているような気がします。',], 'badoutput' => ['400','謎のパラメータ (output)', '未知の output パラメータが設定されているような気がします。',], 'badref' => ['403','不正なフォーム', '不正なフォームからの投稿のような気がします。',], 'refshost' => ['403','アクセス拒否', 'このホストからのアクセスは規制されています。',], 'rejpost' => ['403','投稿拒否', 'あなたからの投稿を拒絶します。心当たりがない場合はご連絡ください。',], # 不正入力系・非存在 'noresnum' => ['404','記事非存在', '指定された記事は存在しません。',], 'nothrnum' => ['404','スレッド非存在', '指定された記事を含むスレッドは存在しません。',], # 不正入力系・不能 'cannotres' => ['403','返信不能', '指定された記事はユーザによって削除されました。',], 'cannotedt' => ['403','修正不能', '指定された記事にはパスワードが設定されていません。',], 'cannotdel' => ['403','削除不能', '指定された記事にはパスワードが設定されていません。',], 'bigpost' => ['413','大きすぎ‥‥', '貴方のモノはとても大きいので、私には受け入れる事ができません。',], # 不正入力系・管理 'badadmin' => ['403','管理パスワード不一致', '入力されたパスワードは管理パスワードと一致しません。あなたは誰ですか?',], # 処理エラー系 'lockbusy' => ['500','排他処理中', '只今混雑しています。しばらくお待ちください。',], 'fileopen' => ['500','ファイルオープンエラー(入力)', 'ファイルを入力用として開く事ができませんでした。',], 'filewrite' => ['500','ファイルオープンエラー(出力)', 'ファイルを出力用として開く事ができませんでした。',], 'fileseek' => ['500','ファイルシークエラー', 'ファイルポインタを設定できませんでした。',], 'fileprint' => ['500','ファイル書き込みエラー', 'ファイルにデータを書き込めませんでした。',], 'filetc' => ['500','ファイルサイズ更新エラー', 'ファイルファイルサイズを設定できませんでした。',], 'logopen' => ['500','ログファイルオープンエラー(入力)', 'ログファイルを入力用として開く事ができませんでした。',], 'logwrite' => ['500','ログファイルオープンエラー(出力)', 'ログファイルを出力用として開く事ができませんでした。',], 'hisopen' => ['500','更新履歴ファイルオープンエラー(入力)', '更新履歴ファイルを入力用として開く事ができませんでした。',], 'hiswrite' => ['500','更新履歴ファイルオープンエラー(出力)', '更新履歴ファイルを出力用として開く事ができませんでした。',], 'dicopen' => ['500','置換辞書ファイルオープンエラー(入力)', '置換辞書ファイルを入力用として開く事ができませんでした。',], 'dicwrite' => ['500','置換辞書ファイルオープンエラー(出力)', '置換辞書ファイルを出力用として開く事ができませんでした。',], 'pstopen' => ['500','過去ログファイルオープンエラー(入力)', '過去ログファイルを入力用として開く事ができませんでした。',], 'pstwrite' => ['500','過去ログファイルオープンエラー(出力)', '過去ログファイルを出力用として開く事ができませんでした。',], 'psxopen' => ['500','過去ログ情報ファイルオープンエラー(入力)', '過去ログ情報ファイルを入力用として開く事ができませんでした。',], 'psxwrite' => ['500','過去ログ情報ファイルオープンエラー(出力)', '過去ログ情報ファイルを出力用として開く事ができませんでした。',], ); #---(ここまで「定型文」設定)---# #================# # 設定ここまで # #================# #==============# # メイン処理 # #==============# ($host,$addr) = &get_host; $media = &decode; $media and $horx = &media_param($media); #$denykey and &axs_check; $denykey and &deny_check; DO_MAIN: { undef %ep; if ($mode eq 'regist') { ®ist; } local ($no,$reno,$udel,$pw,$times,$name,$com, $sub,$mail,$url,$mod_times,$env,$host,$opt,$icon); if ($mode eq 'view') { if ($class eq 'all') { $class = 'last'; $num = 'all'; } if ($class eq 'list') { &subj_list; } if ($class eq 'last') { &threads_view; } if ($class eq 'no') { &res_view; } if ($class eq 'howto') { &howto; } if ($class eq 'history') { &history; } if ($class eq 'find') { &find; } if ($class eq 'dic' and $substkey) { &subst_dic; } if ($class eq 'image' and $iconkey) { &ico_image; } if ($class eq 'past') { &past; } &resp('name' => 'badclass','info' => "mode=$mode, class=$class"); } if ($mode eq 'form') { local ($form_title,$sub_default,$pwdnote,$com,$row,$class_value,$resto_value); local ($com_default_clear) = 0; # 全投稿停止 $AllStop and &resp('name' => 'allstop'); if ($class eq 'new') { &new_form; } # 対象記事を確認 local ($r,$d,$p,$c) = &cnctd_res($num); $d or &resp('name' => 'noresnum','info' => "No.$num"); if ($class eq 'res') { &res_form; } if ($class eq 'edt') { &edt_form; } if ($class eq 'del') { &del_form; } &resp('name' => 'badclass','info' => "mode=$mode, class=$class"); } if ($mode eq 'admin') { if ($in{'pass'} eq '') { &admin_gate; } if (!$post_flag) { &resp('name' => 'notpost'); } if ($in{'pass'} ne $pass) { &resp('name' => 'badadmin'); } if ($class eq 'admin_delete') { &admin_delete; } &admin; } if ($mode eq 'check') { ✓ } &resp('name' => 'badmode','info' => "mode=$mode, class=$class"); } &footer_menu; &footer; exit; #======================# # メイン処理ここまで # #======================# #----------------# # 記事一覧表示 # #----------------# # 引数 0:なし # 戻り値:なし sub subj_list { my ($top,@lines) = (); my ($bloc_obj,$net_ttl,$now_no) = (); $bloc_obj .= "

全ての記事のタイトルを一覧表示しています。各記事タイトルのリンクから、その記事の全文を表示させることができます。親記事の左にある [ALL] のリンクから、子記事も含めたスレッド全体を表示させる事ができます。

\n"; # ログを読み込み if ($lockkey == 4) { # flock ($top,@lines) = &file_read($logfile); } else { if ($lockkey) { $lockflag = &lock() or &resp('name' => 'lockbusy'); } open(IN,"$logfile") or &resp('name' => 'fileopen','info' => "$logfile"); ($top,@lines) = ; close(IN); &unlock($lockflag) if ($lockflag); } # スレッド繰り返し回数 my $i = (split(/<>/,$top))[3]; # 記事繰り返しカウント my $n = 0; my $flag = 0; $bloc_obj .= "", $flag = 0 if ($flag); $bloc_obj .= "\n" if ($n); # 親記事 $bloc_obj .= qq^
  • [ALL] $net_ttl

    ^; } else { # スレッド開始 $bloc_obj .= "\n\t
  • \n" if ($flag); $bloc_obj .= "\n"; # ヘッダを出力 &header('title' => "$title - 記事一覧",'lm' => 1); print $bloc_obj; last DO_MAIN; } #-----------------------# # 最新n件・全記事展開 # #-----------------------# # 引数 0:なし # 戻り値:なし sub threads_view { local ($top,@lines) = (); # サブルーチンでも使用するので local my $lm = ''; # Last-Modified 応答ヘッダを出力するか if (!$num) { $num = $top_log; $lm = 1; } if ($num =~ /^[0-9]+$/o) { &header('title' => "$title - 最近のスレッド $num 件",'lm' => $lm); print qq^

    最近のスレッド $num 件を表示しています。全ての記事は「記事一覧」から読むことができます。

    \n^; } elsif ($num eq 'all') { &header('title' => "$title - 全ての記事"); print "

    全ての記事を表示しています。

    \n"; } else { &resp('name' => 'badnum','info' => "mode=$mode, class=$class:$num"); } # ログを読み込み if ($lockkey == 4) { # flock ($top,@lines) = &file_read($logfile); } else { if ($lockkey) { $lockflag = &lock() or &resp('name' => 'lockbusy'); } open(IN,"$logfile") or &resp('name' => 'fileopen','info' => "$logfile"); ($top,@lines) = ; close(IN); &unlock($lockflag) if ($lockflag); } # スレッド繰り返し回数 my $i = ($num ne 'all') ? $num : (split(/<>/,$top))[3]; # 記事繰り返しカウント my $n = 0; # スレッドループ for (1..$i) { ($no,$reno,$udel,$pw,$times,$name,$com, $sub,$mail,$url,$mod_times,$env,$host,$opt,$icon) = split(/<>/,$lines[$n++]); # メニュー &footer_menu; print "
    \n"; # 親記事開始 print "
    \n"; # 親記事レス番を定義 $d = $no; # 記事の書式 print ${\res_fmt()}; # 子記事ループ do { ($no,$reno,$udel,$pw,$times,$name,$com, $sub,$mail,$url,$mod_times,$env,$host,$opt,$icon) = split(/<>/,$lines[$n++]); if ($reno) { # 子記事 print "
    \n"; # 親記事レス番を定義 $d = $reno; # 記事の書式 print ${\res_fmt()}; print "
    \n"; } else { $n--; } } while ($reno); # 親記事終了 print "
    \n"; } if ($num ne 'all') { # 次ページは無い print qq(
    \n); print qq(

    これ以前の記事は「記事一覧」からご覧ください。

    \n); } last DO_MAIN; } #------------------# # レス表示モード # #------------------# # 引数 0:なし # 戻り値:なし sub res_view { ($r,$d,$p,$c) = &cnctd_res($num); if ($thread) { $d or &resp('name' => 'nothrnum','info' => "No.$num"); &header('title' => "$title - スレッド No.$d"); print "

    スレッド No.$d を表示しています。

    各記事の(右)上部にある「返信」のリンクからその記事に返信することができます。また、「修正」「削除」のリンクからその記事を修正、削除することができます(要パスワード)。

    \n"; if ($thread == 2) { print "

    class=no:$d,thread という書式は非推奨となりました。将来のバージョンではサポートされません。スレッド No.$d を表示するためには、class=no:${d}t としてください。

    \n"; } &cnctd_view($p,$c); } else { $d or &resp('name' => 'noresnum','info' => "No.$num"); &header('title' => "$title - 記事 No.$num"); print "

    記事 No.$num を表示しています。

    記事の(右)上部にある「スレッド表示」のリンクからスレッド全体を表示させることができます。また、「返信」のリンクからこの記事に返信することが、「修正」「削除」のリンクからこの記事を修正、削除(要パスワード)することができます。

    \n"; &cnctd_view($r); } last DO_MAIN; } #--------------------------# # 指定記事・スレッド出力 # #--------------------------# # 引数 0:開始記事出現位置 # 引数 1:出力記事数(0オリジン) # 戻り値:なし sub cnctd_view { my ($a,$b) = @_; print "
    \n"; # 記事表示 $flag = 0; for ($a..$a+$b) { ($no,$reno,$udel,$pw,$times,$name,$com, $sub,$mail,$url,$mod_times,$env,$host,$opt,$icon) = split(/<>/,$lines[$_]); # 親記事 if (!$reno) { print "
    \n"; $flag = 1; } # 子記事 else { print "
    \n"; } # 記事の書式 print ${\res_fmt()}; print "
    \n" if ($reno); } print "
    \n" if ($flag); } #--------------------# # 記事フォーマット # #--------------------# # 引数 0:記事操作メニュー制御(0:表示, 1:非表示) # 戻り値:整形された記事 sub res_fmt { my $no_edit_menu = $_[0]; my ($date,$mod_date,$img,$bloc_obj) = (); # 記事見出しレベル my $hn = $reno ? '3' : '2'; if ($udel) { $bloc_obj .= "No.$no: $del_sub\n"; # 記事操作メニュー $bloc_obj .= qq^

    スレッド表示

    \n^ if (!$thread); $bloc_obj .= "

    $del_com

    \n"; } else { # オプション処理 ($tag,$pre,$anc) = &read_opt($opt); if ($tag) { # マークアップ処理 $com = &do_tag($com,$pre); # 文字実体参照処理 ($name,$sub,$com) = &do_entref($name,$sub,$com); # 数値文字参照処理 $com = &do_numref($com); } # URL自動リンク $com = &do_anchor($com) if ($anc); # @処理 ($name,$sub,$com,$url,$env) = &do_atmark($name,$sub,$com,$url,$env); # 題名の長さ if (length($sub) > $sub_len) { $sub = substr($sub,0,$sub_len); $sub .= "..."; } $name = "
  • Name: $name
  • \n"; $date = "
  • Date: ${\time_fmt($times,1)}
  • \n"; $mod_date = "
  • Last-Modified: ${\time_fmt($mod_times,1)}
  • \n" if ($mod_times); if ($com) { $com =~ s|
    |
    |g; } if ($mail) { $mail = qq^
  • E-mail: ${\do_mail($mail)}
  • \n^; } if ($url) { $url = qq^
  • URL: ${\do_anchor($url)}
  • \n^; } if ($env) { $env = qq^
  • User-Agent: $env
  • \n^; } # アイコン処理 if ($iconkey and $icon and $icon !~ /[\n]/) { my ($icogrp,$icoid) = split(' ',$icon); # アイコンへのパス my $imgsrc = "$icodir$icogrp/$icons{$icogrp}[$icoid][0]"; # # アイコンの代替文字列 # my $imgalt = "【$icons{$icogrp}[0][1]】$icons{$icogrp}[$icoid][1]"; # アイコンの説明 my $imgtitle = "【$icons{$icogrp}[0][1]】$icons{$icogrp}[$icoid][1]"; # アイコンの拡張子 my $imgpstx = $icons{$icogrp}[$icoid][2] || $icons{$icogrp}[0][2] || 'png'; # アイコンのwidth my $imgw = $icons{$icogrp}[$icoid][3] || $icons{$icogrp}[0][3] || '100'; # アイコンのheight my $imgh = $icons{$icogrp}[$icoid][4] || $icons{$icogrp}[0][4] || '100'; # アイコン定義 アイコングループ定義 デフォルト $img = qq^$imgalt\n^; } # 記事削除フォームではメニューなし if ($no_edit_menu) { # 記事タイトル $bloc_obj .= "No.$no: $sub\n"; } # 通常記事 else { # 記事タイトル $bloc_obj .= qq^No.$no: $sub\n^; # 記事操作メニュー $bloc_obj .= qq^

    ^; $bloc_obj .= qq^スレッド表示//^ if (!$thread); $bloc_obj .= qq^返信^; if ($pw) { $bloc_obj .= "/"; $bloc_obj .= qq^/修正^; $bloc_obj .= qq^/削除^; } $bloc_obj .= "

    \n"; } $bloc_obj .= qq^\n^; if ($pre) { $bloc_obj .= "
    $com
    \n"; } else { $bloc_obj .= "

    \n$img$com\n

    \n"; } if ($mail or $url or $env) { $bloc_obj .= qq^\n^;} } return $bloc_obj; } #------------------------# # 関連記事ピックアップ # #------------------------# # 引数 0:レス番号 # 戻り値:(該当記事出現位置 $r,関連親記事のレス番号 $d,関連親記事出現位置 $p,関連子記事数 $c) sub cnctd_res { my $n = $_[0]; my ($r,$d,$p,$c) = (0,0,0,0); my ($no,$reno) = (); # ログを読み込み if ($lockkey == 4) { # flock ($top,@lines) = &file_read($logfile); } else { if ($lockkey) { $lockflag = &lock() or &resp('name' => 'lockbusy'); } open(IN,"$logfile") or &resp('name' => 'fileopen','info' => "$logfile"); ($top,@lines) = ; close(IN); &unlock($lockflag) if ($lockflag); } # 親記事ピックアップ foreach (@lines) { ($no,$reno) = split(/<>/); if ($n == $no) { $d = $reno || $no; last; } $r++; } # 関連記事ピックアップ $flag = 0; foreach (@lines) { ($no,$reno) = split(/<>/); if ($flag) { if ($reno == $d) { $c++; next; } last; } if ($no == $d) { $flag = 1; next; } $p++; } return ($r,$d,$p,$c); } #--------------------# # 新規投稿フォーム # #--------------------# # 引数 0:なし # 戻り値:なし sub new_form { my $stat = ''; # フォーム個別化 # エラー回復 if (%ep) { ($name,$sub,$com,$mail,$url,$icon,$opt,$pwd) = ($ep{'name'},$ep{'sub'},$ep{'com'},$ep{'mail'},$ep{'url'},$ep{'icon'},$ep{'opt'},$ep{'pwd'},); $sub_default = $sub; $stat = '400 Bad Request'; } else { $com_default_clear = 1; # フォーカスを得た時に「コメント」入力欄をクリア $sub_default = ''; $com = '(お気楽に。てきとーに。)'; # クッキーを取得 ($name,$mail,$url,$pwd,$icon) = &get_cookie; ($name,$mail,$url) = &do_atmark($name,$mail,$url); } $form_title = '新規投稿'; $pwdnote = '(記事の修正・削除時に使用。英数字で8文字以内)'; $row = 18; $class_value = "$class"; $resto_value = ''; &header('title' => "$title - $form_title",'status' => $stat); print $ep{'msg'}; print "

    雑記への突っ込み、ぽあぞんでずゅーに対する御意見御感想御提言など、年中無休でお待ちしています。

    \n"; print ${\form_fmt()}; last DO_MAIN; } #--------------------# # 返信投稿フォーム # #--------------------# # 引数 0:なし # 戻り値:なし sub res_form { my $stat = ''; # 返信可能を確認 &confirm_flag($r,$class) or &resp('name' => 'cannotres','info' => "No.$num"); # エラー回復 if (%ep) { ($name,$sub,$com,$mail,$url,$icon,$opt,$pwd) = ($ep{'name'},$ep{'sub'},$ep{'com'},$ep{'mail'},$ep{'url'},$ep{'icon'},$ep{'opt'},$ep{'pwd'},); $stat = '400 Bad Request'; } else { # レス対象記事呼び出し ($no,$reno,$udel,$pw,$times,$name,$com, $sub,$mail,$url,$mod_times,$env,$host,$opt,$icon) = split(/<>/,$lines[$r]); # textarea の中身は #PCDATA ($sub,$com) = &do_atmark($sub,$com); # 引用符をつける $row = $com =~ s/
    /\n> /g; $com = "> $com"; # タイトル名を定義 if ($sub and $sub !~ /^Re\:/) { $sub = "Re\: $sub"; } # クッキーを取得 ($name,$mail,$url,$pwd,$icon) = &get_cookie; ($name,$mail,$url) = &do_atmark($name,$mail,$url); } # フォーム個別化 $form_title = '返信投稿'; $sub_default = $sub; $pwdnote = '(記事の修正・削除時に使用。英数字で8文字以内)'; $row += 18; $class_value = "$class:$d"; $resto_value = $num; &header('title' => "$title - No.$num に返信",'status' => $stat); print $ep{'msg'}; print qq(

    記事 No.$num(スレッド No.$d)への返信投稿フォームです(関連スレッド)。

    \n); print ${\form_fmt()}; # 関連スレ出力 print qq(

    関連スレッド

    \n); &cnctd_view($p,$c); last DO_MAIN; } #--------------------# # 記事修正フォーム # #--------------------# # 引数 0:なし # 戻り値:なし sub edt_form { my $stat = ''; # 修正可能を確認 &confirm_flag($r,$class) or &resp('name' => 'cannotedt','info' => "No.$num"); # エラー回復 if (%ep) { ($name,$sub,$com,$mail,$url,$icon,$opt,$pwd) = ($ep{'name'},$ep{'sub'},$ep{'com'},$ep{'mail'},$ep{'url'},$ep{'icon'},$ep{'opt'},$ep{'pwd'},); $stat = '400 Bad Request'; } else { # 該当記事呼び出し ($no,$reno,$udel,$pw,$times,$name,$com, $sub,$mail,$url,$mod_times,$env,$host,$opt,$icon) = split(/<>/,$lines[$r]); # textarea の中身は #PCDATA ($tag,$pre,$anc) = &read_opt($opt); ($name,$sub,$com,$mail,$url) = &do_atmark($name,$sub,$com,$mail,$url); $row = $com =~ s/
    /\n/g; } # フォーム個別化 $form_title = '記事修正'; $sub_default = $sub; $pwdnote = '(設定したパスワードを入力してください)'; $row += 5; $class_value = "$class:$num"; $resto_value = ''; &header('title' => "$title - No.$num を修正",'status' => $stat); print $ep{'msg'}; print qq(

    記事 No.$num の修正フォームです(関連スレッド)。

    \n); print ${\form_fmt()}; # 関連スレ出力 print qq(

    関連スレッド

    \n); &cnctd_view($p,$c); last DO_MAIN; } #--------------------# # 記事削除フォーム # #--------------------# # 引数 0:なし # 戻り値:なし sub del_form { my $stat = ''; # 削除可能を確認 &confirm_flag($r,$class) or &resp('name' => 'cannotdel','info' => "No.$num"); # エラー回復 $stat = '400 Bad Request' if (%ep); # 該当記事呼び出し ($no,$reno,$udel,$pw,$times,$name,$com, $sub,$mail,$url,$mod_times,$env,$host,$opt,$icon) = split(/<>/,$lines[$r]); &header('title' => "$title - No.$num を削除",'status' => $stat); print <<"EOM"; $ep{'msg'}

    記事 No.$num の削除フォームです(関連スレッド)。

    \n記事削除フォーム
    \n削除対象記事 ${\res_fmt(1)}
    \n記事削除
    \n
    \n

    関連スレッド

    EOM # 関連スレ出力 &cnctd_view($p,$c); last DO_MAIN; } #--------------# # フラグ確認 # #--------------# # 引数 0:対象記事出現位置 # 引数 1:確認内容(res|edt|del) # 戻り値:真偽値 sub confirm_flag { my ($m,$e) = @_; # 該当記事読み込み my ($no,$reno,$udel,$pw) = split(/<>/,$lines[$m]); # 返信可能確認 if ($e eq 'res') { if ($mode eq 'form') { $udel or return 1; # 削除済みでなければ返信フォーム表示可能 return 0; } if ($mode eq 'regist') { $reno or return 1; # 子記事でなければ返信投稿可能 return 0; } return undef; } # 修正・削除可能確認 if ($e eq 'edt' or $e eq 'del') { $pw and return 1; # パスワードが設定されている記事は修正・削除可能 return 0; } return 0; } #------------------------# # フォームフォーマット # #------------------------# # 引数 0:なし # 戻り値:整形されたフォーム sub form_fmt { my $agent = $ENV{'HTTP_USER_AGENT'}; my $form_obj = ''; # フォーム幅調整 if ($agent =~ /Opera|Gecko/i) { $nam_wid = 25; $sub_wid = 60; $com_wid = 70; $url_wid = 55; } elsif ($agent =~ /MSIE 3/i) { $nam_wid = 30; $sub_wid = 40; $com_wid = 65; $url_wid = 48; } elsif ($agent =~ /MSIE/i) { $nam_wid = 25; $sub_wid = 50; $com_wid = 55; $url_wid = 45; } elsif ($agent =~ /Mozilla\/4/i) { $nam_wid = 15; $sub_wid = 25; $com_wid = 40; $url_wid = 30; } else { $nam_wid = 15; $sub_wid = 50; $com_wid = 50; $url_wid = 35; } $form_obj .= qq(

    「ハンドル」と「コメント」は必須項目です。「コメント」では一部のタグ等が解釈されます。入力したままを表示させるにはオプションの「タグ無効」をチェックしてください。); $form_obj .= qq(また、「コメント」では $sst_sign対象文字列と書くと自動的に置換されます。) if ($substkey); $form_obj .= "

    \n"; $form_obj .= qq(
    \n$form_titleフォーム

    ); $form_obj .= qq(\n); $form_obj .= qq^
    \n^; $form_obj .= qq(