/********************************************************************* 簡単な掲示板プログラム webbbs.cc 奥村晴彦 コンパイルにはこのディレクトリにある util.cc と util.h が必要です。 私は gcc-3.x で g++ -Wall webbbs.cc util.cc -o webbbs.cgi としていますが,gcc-2.95.2 + libstdc++-2.90.8 でも g++ -Wall -fhonor-std webbbs.cc util.cc -o webbbs.cgi でできると思います。いずれにしても, chmod 4511 webbbs.cgi しておきます。 index.html にはたとえば次のように書いておきます。 例:
お名前:
タイトル:
メッセージ:

書き込み一覧

書き換えを要するかもしれないところは最終番号を入れるファイル名 "count" だけだと思います。 書き込み前に確認画面を出すには,webbbsx.cc をコンパイルしたものを webbbs.cgi とし,webbbs.cc をコンパイルしたものを webbbs2.cgi と します。 *********************************************************************/ #include #include #include #include #include /* rename() */ #include /* unlink(), getpid() */ #include "util.h" using namespace std; /** テンポラリファイル名を生成 */ string tmpname() { return to_str(getpid()) + ".tmp"; } /** 行挿入,カウントを返す */ int insline(const string& subject, const string& name, const string& now) { LockFile lck("count"); int count = lck.getcount(); if (count < 0) throw "カウントファイルが開きません"; ++count; lck.setcount(count); ifstream in("index.html"); if (!in) throw "index.html が開きません"; string tmp = tmpname(); ofstream out(tmp.c_str()); if (!out) throw "テンポラリファイルが作れません"; string s; while (getline(in, s)) { out << s << '\n'; if (s == "") break; } out << count << ": " << now << " " << subject << " " << name << "
\n"; if (in) while (getline(in, s)) out << s << '\n'; in.close(); out.close(); if (rename(tmp.c_str(), "index.html") < 0) { // rename が失敗したなら unlink("index.html.bak"); // index.html.bak があれば消してから if (rename("index.html", "index.html.bak") < 0) { error_html(tmp + "書き込みが失敗しました(1)"); } else if (rename(tmp.c_str(), "index.html") < 0) { rename("index.html.bak", "index.html"); error_html(tmp + "書き込みが失敗しました(2)"); } } return count; // ここでロックが解除される } char* ipaddr() { static char ip[18]; char* p = getenv("REMOTE_ADDR"); if (p == 0) return ""; strncpy(ip, p, 15); #ifndef FULLIP if ((p = strrchr(ip, '.')) != 0) { *(p + 1) = '*'; *(p + 2) = 0; } #endif return ip; } #ifdef REPLY string deRe(string& s) // 頭の Re: を外す { string t; if (s.length() >= 3 && std::toupper(s[0]) == 'R' && std::toupper(s[1]) == 'E' && s[2] == ':') { size_t i = 3; while (i < s.length() && s[i] == ' ') i++; t = s.substr(i); } else { t = s; } if (t.empty()) t = "(無題)"; return t; } #endif void safarihack(string& s) { for (string::iterator p = s.begin(); p != s.end(); ++p) { if (*p == '?') *p = '\\'; } } /** メイン */ int main() { map post; parse_post(post); // POST されたキー・値のペアを取得 if (check_euc(post["message"]) < 10) error_html("本文の全角文字が少なすぎるか,不正な文字が入っています(スパム?)"); if (post["message"].empty()) error_html("本文がありません"); (void) check_euc(post["subject"]); if (post["subject"].empty()) error_html("題名がありません"); (void) check_euc(post["name"]); if (post["name"].empty()) error_html("名前がありません"); string message = to_html_a(post["message"]); string subject = to_html(post["subject"]); string name = to_html_a(post["name"]); if (!(post["safarihack"].empty())) { safarihack(subject); safarihack(message); } string now = timestr(); int count = 0; try { count = insline(subject, name, now); } catch (const char* e) { error_html(e); } string countstr = to_str(count); string filename = countstr + ".html"; ofstream outfile(filename.c_str()); if (!outfile) error_html("メッセージファイルがオープンできません"); outfile << "\n" #ifdef TEXQA "[qa:" << countstr << "] " << subject << "\n" #else "" << countstr << "\n" #endif #ifdef STYLESHEET "\n" #endif "\n"; outfile << "

" << subject << "

\n"; outfile << "
\n";
    outfile << "名前: " << name << '\n';
    outfile << "日時: " << now << '\n';
    outfile << "IPアドレス: " << ipaddr() << '\n';
    outfile << "
\n"; outfile << message << '\n'; outfile << "
\n"; #ifdef REPLY outfile << "
\n"; outfile << "

この書き込みへの返事:\n"; outfile << "

\n"; outfile << "お名前
\n"; outfile << "題名 
\n"; outfile << "メッセージ(タグは <a href=\"...\">...</a> だけ使えます。適宜改行を入れてください)
\n"; outfile << "\n"; outfile << "
\n"; outfile << "\n"; outfile << "\n"; outfile << "
\n"; #endif outfile.close(); cout << "Content-type: text/html\n\n" "\n" "\n" "\n" "Thank you\n" #ifdef STYLESHEET "\n" #endif "\n" "\n" "

書き込みました

\n" "

次のメッセージを書き込みました。
\n" "[書き込み一覧に戻る]\n" "

" << subject << "

\n" "
\n"
        "名前: " << name << "\n"
        "日時: " << now << "\n"
        "IPアドレス: " << ipaddr() << "\n"
        "
\n" << message << "\n" "
\n
\n

[書き込み一覧に戻る]\n" "\n"; #ifdef OKUMURA FILE *pipe = popen("/usr/sbin/sendmail -oi -t -f webbbs@oku.edu.mie-u.ac.jp", "w"); if (pipe) { char buf[128]; getcwd(buf, sizeof buf); string s; s = "Content-Type: text/plain; charset=iso-2022-jp\n"; s += "From: webbbs \n"; s += "Bcc: okumura@oku.edu.mie-u.ac.jp\n"; s += "Subject: [" + string(buf) + ":" + countstr + "]\n " + enmime(euc2jis(post["subject"])) + "\n\n"; s += "Subject: " + euc2jis(post["subject"]) + "\n"; s += "Name: " + euc2jis(post["name"]) + "\n"; s += "Date: " + now + "\n\n"; s += euc2jis(post["message"]) + "\n"; fputs(s.c_str(), pipe); pclose(pipe); } #endif #ifdef TEXQA FILE *pipe = popen("/usr/sbin/sendmail -oi -t -f tex-qa-admin@oku.edu.mie-u.ac.jp", "w"); if (pipe) { string s; s = "Content-Type: text/plain; charset=iso-2022-jp\n"; s += "From: TeX Q & A \n"; s += "Bcc: tex-qa@oku.edu.mie-u.ac.jp\n"; s += "Subject: [tex-qa:" + countstr + "] " + enmime(euc2jis(post["subject"])) + "\n\n"; s += "Subject: " + euc2jis(subject) + "\n"; s += "Name: " + euc2jis(name) + "\n"; s += "Date: " + now + "\n\n"; s += euc2jis(message) + "\n"; fputs(s.c_str(), pipe); pclose(pipe); } #endif }