[Affelio-cvs 947] CVS update: affelio/apps/bb

Back to archive index

Yoshihisa Fukuhara higef****@users*****
2005年 12月 19日 (月) 15:46:28 JST


Index: affelio/apps/bb/AF_app.cfg
diff -u /dev/null affelio/apps/bb/AF_app.cfg:1.1
--- /dev/null	Mon Dec 19 15:46:28 2005
+++ affelio/apps/bb/AF_app.cfg	Mon Dec 19 15:46:27 2005
@@ -0,0 +1,13 @@
+[this_installation]
+title=AffelioBB
+
+[application]
+app_URI = http://affelio.jp/NS/apps/bb
+app_name=AffelioBB
+app_version=1.0.1
+app_desc=AffelioBB
+app_author=Affelio project
+guest_index=index.cgi
+owner_index=owner.cgi
+action_types=super, user
+action_types_desc=特権ユーザ,一般ユーザ
Index: affelio/apps/bb/README
diff -u /dev/null affelio/apps/bb/README:1.1
--- /dev/null	Mon Dec 19 15:46:28 2005
+++ affelio/apps/bb/README	Mon Dec 19 15:46:27 2005
@@ -0,0 +1,83 @@
+##################################################
+#	Žg‚¢•û
+##################################################
+
+‚PjƒCƒ“ƒXƒg[ƒ‹
+	appsƒtƒHƒ‹ƒ_ˆÈ‰º‚É“K“–‚È–¼‘O‚Őݒu‚µ‚Ä‚­‚¾‚³‚¢B
+	iAffelio1.1.0RCˆÈ~‚ł͖{‘̂̊Ǘ‰æ–Ê‚©‚çAƒAƒvƒŠƒP[ƒVƒ‡ƒ““o˜^‚ðs‚¤•K—v‚ª‚ ‚è‚Ü‚·Bj
+	
+	™ŠçƒAƒCƒRƒ“‚ɂ‚¢‚Ä
+	”z•z”łɂ͊çƒAƒCƒRƒ“‚͊܂܂ê‚Ä‚¢‚Ü‚¹‚ñBŽg—p‚·‚éê‡‚́A‚²Ž©•ª‚Å—pˆÓ‚µ‚½ƒAƒCƒRƒ“‚ð
+	resource/face/@ƒtƒHƒ‹ƒ_ˆÈ‰º‚ɕۑ¶‚µ‚Ä‚­‚¾‚³‚¢B
+	‚È‚¨Aowner.gif‚Æ‚¢‚¤–¼‘O‚̉摜‚ðÝ’u‚·‚邯AŽ©“®“I‚ÉŠÇ—ŽÒê—p‚̃AƒCƒRƒ“‚ɂȂè‚Ü‚·B
+	ŠÇ—ŽÒ‚Æ‚µ‚ăRƒƒ“ƒg‚ð“o˜^‚·‚éÛA‘¼‚ÌŠçƒAƒCƒRƒ“‚ð‘I‘ð‚µ‚È‚¢‚ÆŽ©“®“I‚ÉŠÇ—ŽÒƒAƒCƒRƒ“‚ªÌ—p‚³‚ê‚Ü‚·B
+	
+‚QjŽg‚¢•û
+	3.1 Å‰‚É
+		E‚Ü‚¸Å‰‚ÉŠÇ—‰æ–ʂ́uƒJƒeƒSƒŠ‚̒ljÁ^•ҏWv‚©‚ç‚Ȃɂ©ƒJƒeƒSƒŠ‚ð’ljÁ‚µ‚Ä‚­‚¾‚³‚¢B
+		Å’áˆê‚ˆȏã‚̃JƒeƒSƒŠ‚ª‚È‚¢‚ÆŒfަ”‚͎g‚¦‚Ü‚¹‚ñB
+		EŽŸ‚ɁAuƒAƒNƒZƒXƒRƒ“ƒgƒ[ƒ‹v‚©‚çAƒAƒNƒZƒXŒ ‚̐ݒè‚ð‚µ‚Ä‚­‚¾‚³‚¢B
+		Œfަ”‚ðŠÜ‚ÞƒRƒ~ƒ…ƒjƒeƒB‚̉^‰c‚ÉŽQ‰Á‚·‚éƒRƒAƒƒ“ƒo[‚́u“ÁŒ ƒ†[ƒUv‚ÉŽw’è‚·‚邯‚æ‚¢‚Å‚µ‚傤B
+		Œfަ”‚ł̋c˜_‚ÉŽQ‰Á‚³‚¹‚郆[ƒU‚ɂ́uˆê”ʃ†[ƒUv‚ÌŽw’è‚ð‚µ‚Ä‚­‚¾‚³‚¢B‚±‚ê‚ð‚µ‚È‚¢‚Ə‘ž‚߂܂¹‚ñB
+		ˆê”ʃQƒXƒg‚É‚àŒfަ”‚ðŒöŠJ‚·‚éê‡‚ɂ́uˆê”ʃ†[ƒUv‚Æ‚µ‚Ä“o˜^‚µ‚Ä‚­‚¾‚³‚¢Bˆê”ʃQƒXƒg‚É“ÁŒ ƒ†[ƒUŒ ŒÀ‚ð—^‚¦‚邱‚Ƃ͐„§‚µ‚Ü‚¹‚ñB
+		EŽŸ‚Ƀgƒbƒvƒy[ƒW‚©‚çƒJƒeƒSƒŠ“à‚É‚¢‚­‚‚©ƒtƒH[ƒ‰ƒ€‚ðì‚Á‚Ă݂܂µ‚傤B
+		ˆê”ʃ†[ƒU‚Í‚±‚̃tƒH[ƒ‰ƒ€‚̉º‚ɃgƒsƒbƒN‚𗧂Ă邱‚Æ‚ª‚Å‚«‚邿‚¤‚ɂȂè‚Ü‚·B
+		
+	3.2 ‹LŽ–‚Ì“Še‚â•ҏW^íœ
+		—˜—pŽÒ‚̓gƒsƒbƒN‚ð—§‚Ä‚½‚èA‚»‚ê‚ɃRƒƒ“ƒg‚ð‚‚¯‚½‚è‚Å‚«‚Ü‚·B
+		“ŠeŽÒ‚ÍŽ©•ª‚̍쐬‚µ‚½ƒgƒsƒbƒN‚̕ҏW‚ª‚Å‚«‚Ü‚·B
+		“ŠeŽÒ‚ÍŽ©•ª‚Ì“Še‚µ‚½ƒRƒƒ“ƒg‚̍폜‚ª‚Å‚«‚Ü‚·B
+
+	3.3 ˆê”ʃQƒXƒg‚Ì“Še‚ɂ‚¢‚Ä
+		AffelioƒŠƒ“ƒN‚³‚ê‚Ä‚¢‚él‚ªŒfަ”‚𗘗p‚·‚éê‡AƒjƒbƒNƒl[ƒ€‚âƒpƒXƒ[ƒh‚ð“ü—Í‚·‚é•K—v‚Í‚ ‚è‚Ü‚¹‚ñB
+		‚»‚êˆÈŠO‚Ì•û‚ª—˜—p‚·‚éê‡‚̓jƒbƒNƒl[ƒ€‚â•ҏW^íœ—pƒpƒXƒ[ƒh‚Ì“ü—Í‚ð‹‚ß‚ç‚ê‚Ü‚·B
+
+‚RjƒAƒNƒZƒXŒ ‚̐ݒè
+	ƒAƒNƒZƒXŒ ‚̓AƒvƒŠŠÇ—‰æ–ʂ̃AƒNƒZƒXƒRƒ“ƒgƒ[ƒ‹‚©‚çÝ’è‚Å‚«‚Ü‚·B
+	ƒ†[ƒU[‚ɑ΂·‚éƒAƒNƒZƒXŒ ‚́uˆê”ʃ†[ƒUv‚Ɓu“ÁŒ ƒ†[ƒUv‚Ì“ñŽí—Þ‚ªÝ’è‚Å‚«‚Ü‚·B
+	ˆÈ‰º‚É‚»‚ꂼ‚ê‚̃†[ƒU[‚ɂ‚¢‚ďq‚ׂ܂·B
+
+	Eˆê”ʃ†[ƒU
+		ƒgƒsƒbƒN‚̍쐬‚âƒRƒƒ“ƒg‚̏‘‚«ž‚Ý‚ª‚Å‚«‚Ü‚·B
+	E“ÁŒ ƒ†[ƒU
+		ã‹L‚ɉÁ‚¦‚ătƒH[ƒ‰ƒ€‚̍쐬‚ª‚Å‚«‚Ü‚·B
+		ƒgƒsƒbƒN‚̃ƒbƒN^ƒAƒ“ƒƒbƒN‚ª‚Å‚«‚Ü‚·iƒƒbƒN‚³‚ꂽƒgƒsƒbƒN‚̓Rƒƒ“ƒg‘ž‚Ý‚ª‚Å‚«‚È‚­‚È‚è‚Ü‚·jB
+		ƒgƒsƒbƒN‚ɏd—v“x‚ªÝ’è‚Å‚«‚Ü‚·B
+		‚½‚¾‚µAŽ©•ª‚̏‘‚¢‚½ƒgƒsƒbƒN‚âƒtƒH[ƒ‰ƒ€ˆÈŠO‚͕ҏW^íœ‚Å‚«‚Ü‚¹‚ñB
+	EƒTƒCƒgƒI[ƒi[
+		ã‹L‚Ì‹@”\‚ª‚·‚ׂĎg‚¦‚Ü‚·B
+		‚Ü‚½‚·‚ׂĂ̏‘‚«ž‚݂ɑ΂µ‚āA•ҏW^íœŒ ŒÀ‚ðŽ‚¿‚Ü‚·B
+		ƒJƒeƒSƒŠ[‚̍쐬‚ª‚Å‚«‚Ü‚·B
+		‚»‚Ì‘¼ŠÇ—‰æ–Ê‚æ‚èŠeŽí‹@”\BBB	
+
+
+
+##################################################
+#	—š—ð
+##################################################
+
+2005.12.17	Ver1.0RC
+		First experimental release.
+
+2005.12.21	Ver1.0.1
+		Fixed some minor bugs.
+
+##################################################
+#	ƒ‰ƒCƒZƒ“ƒX
+##################################################
+
+# Copyright (C) 2005 FishGrove Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
\ No newline at end of file
Index: affelio/apps/bb/bb.pm
diff -u /dev/null affelio/apps/bb/bb.pm:1.1
--- /dev/null	Mon Dec 19 15:46:28 2005
+++ affelio/apps/bb/bb.pm	Mon Dec 19 15:46:27 2005
@@ -0,0 +1,896 @@
+# Copyright (C) 2005 FishGrove Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+package bb;
+
+use strict;
+use DBI;
+use Jcode;
+use HTML::Template;
+use Config::Tiny;
+use bb::L10N;
+use Affelio::NetLib::Email qw(send_email);
+
+##############################################
+# Constructor 
+##############################################
+sub new {
+    my ($class, $afap) = @_;
+    unless ($afap) { die("bb::new: Error: missing username\n"); }
+    
+    my $self = {};
+    $self->{afap}  = $afap;
+    $self->{tmpfile}= $afap->get_userdata_dir()."/.sqltmp";
+    $self->{category_tb}= "$afap->{install_name}_category";
+    $self->{forum_tb}= "$afap->{install_name}_forum";
+    $self->{topic_tb}= "$afap->{install_name}_topic";
+    $self->{pref_tb}= "$afap->{install_name}_pref";
+    $self->{spam_tb}= "$afap->{install_name}_spam";
+
+    $self->{dbh} = undef;
+    #initialize
+    
+    ###########################
+    #Locale init
+    ###########################
+    $self->{lh} = bb::L10N->get_handle(($afap->get_site_info("locale"),
+					$afap->get_site_info("locale")));
+    ###########################
+    my $sth;
+    my $query;
+    $self->{dbh} = $afap->get_userdata_dbh();
+    unless(-f $self->{tmpfile}) {
+	open(TMP,"> $self->{tmpfile}");
+	close(TMP); 	    
+
+	#Category table
+	$query="category_id INTEGER".get_query_primarykey($self)."
+			title		TEXT,
+			timestamp	INTEGER,
+			update_time	INTEGER,
+			user		TEXT,
+			afid		TEXT,
+			last_user	TEXT,
+			last_afid	TEXT,
+			lock INTEGER,
+			ord		INTEGER";
+	    
+	$self->{dbh}->do("CREATE TABLE $self->{category_tb} ($query)");
+	
+	#Forum table
+	$query="forum_id INTEGER".get_query_primarykey($self)."
+			category_id		INTEGER,
+			title		TEXT,
+			description TEXT,
+			timestamp	INTEGER,
+			update_time	INTEGER,
+			user		TEXT,
+			afid		TEXT,
+			pwd TEXT,
+			last_user	TEXT,
+			last_afid	TEXT,
+			topics		INTEGER,
+			posts INTEGER,
+			status INTEGER,
+			lock INTEGER,
+			ord		INTEGER";
+	
+	$self->{dbh}->do("CREATE TABLE $self->{forum_tb} ($query)");
+	
+	
+	#Topic table
+	$query="topic_id INTEGER".get_query_primarykey($self)."
+			forum_id		INTEGER,
+			title	TEXT,
+			description	TEXT,
+			icon	TEXT,
+			user		TEXT,
+			afid		TEXT,
+			pwd TEXT,
+			last_user	TEXT,
+			last_afid	TEXT,
+			view		INTEGER,
+			posts INTEGER,
+			status INTEGER,
+			lock INTEGER,
+			timestamp	INTEGER,
+			update_time INTEGER";
+		
+	$self->{dbh}->do("CREATE TABLE $self->{topic_tb} ($query)");
+	
+
+	    #general setting table
+	$query="key	TEXT,value TEXT";
+	$self->{dbh}->do("CREATE TABLE $self->{pref_tb} ($query)");
+	$self->{dbh}->do("INSERT INTO $self->{pref_tb} (key, value) VALUES ('title', 'Affelio BB')");
+	$self->{dbh}->do("INSERT INTO $self->{pref_tb} (key, value) VALUES ('email', '$self->{afap}->{af}->{user__email1}')");
+	$self->{dbh}->do("INSERT INTO $self->{pref_tb} (key, value) VALUES ('max_topics', '300')");
+	$self->{dbh}->do("INSERT INTO $self->{pref_tb} (key, value) VALUES ('max_comments', '1000')");
+	$self->{dbh}->do("INSERT INTO $self->{pref_tb} (key, value) VALUES ('num_topics', '50')");
+	$self->{dbh}->do("INSERT INTO $self->{pref_tb} (key, value) VALUES ('num_comments', '50')");
+	$self->{dbh}->do("INSERT INTO $self->{pref_tb} (key, value) VALUES ('max_sbjlen', '256')");
+	$self->{dbh}->do("INSERT INTO $self->{pref_tb} (key, value) VALUES ('max_textlen', '2000')");
+	
+	
+	#SPAM keywords table
+	$query="spam_id INTEGER".get_query_primarykey($self)."
+			keyword	TEXT";
+	$self->{dbh}->do("CREATE TABLE $self->{spam_tb} ($query)");
+    }
+    
+    bless $self, $class;
+    return $self;
+}
+
+##############################################
+# destructor
+##############################################
+
+sub DESTROY {
+    my $self = shift;
+    $self->{dbh}->disconnect;
+}
+
+
+##############################################
+# createReplyTable
+##############################################
+
+sub createReplyTable {
+    my ($self, $topic_id) = @_;
+    my $reply_tb = "reply_".$self->escape($topic_id, 'int');
+    
+    my $query="reply_id INTEGER".get_query_primarykey($self)."
+			title TEXT,
+			user		TEXT,
+			afid		TEXT,
+			pwd  TEXT,
+			comment		TEXT,
+			icon		TEXT,
+			timestamp	INTEGER,
+			update_time INTEGER";
+		
+    $self->{dbh}->do("CREATE TABLE $reply_tb ($query)");
+}
+
+##############################################
+# addCategory
+##############################################
+
+sub addCategory {
+    my ($self, $title, $user, $afid) = @_;
+    my $time = time;
+    
+#  	my $id = $self->getColumn("SELECT MAX(category_id) FROM $self->{category_tb}");
+    $title = $self->escape_all($title);
+    $user = $self->escape_all($user);
+    $afid = $self->escape_all($afid);
+    $self->checkContent($title, $user, $afid, "","","");
+    
+    my @same = $self->getall("SELECT category_id FROM $self->{category_tb} WHERE title='$title'");
+    $self->errorExit('<AF_M text="A category of the proposed name already exists.">') if($#same >= 0);
+
+    $self->{dbh}->do("INSERT INTO $self->{category_tb} (title, timestamp, update_time, user, afid, last_user, last_afid, lock, ord) VALUES ('$title', $time, $time, '$user', '$afid', '$user', '$afid', 0, 0)");
+#  	$id = $self->getColumn("SELECT MAX(category_id) FROM $self->{category_tb}");
+}
+
+
+##############################################
+# addForum
+##############################################
+
+sub addForum {
+    my ($self, $category_id,$title, $description, $user, $afid, $pwd) = @_;
+    my $time = time;
+    my $crypt="";
+    $category_id = $self->escape($category_id, 'int');
+    $title = $self->escape_all($title);
+    $user = $self->escape_all($user);
+    $afid = $self->escape_all($afid);
+    $description = $self->escape($description);
+    $pwd = $self->escape_all($pwd);
+    $crypt = $self->cryptPwd($pwd)	if ($pwd ne "");
+    $self->checkContent($title, $user, $afid, $description, "", $pwd);
+    
+    my @same = $self->getall("SELECT forum_id FROM $self->{forum_tb} WHERE title='$title'");
+    $self->errorExit('<AF_M text="A forum of the proposed name already exists.">') if($#same >= 0);
+    
+    $self->{dbh}->do("INSERT INTO $self->{forum_tb} (category_id, title, description, timestamp, update_time, user, afid, pwd, last_user, last_afid, topics, posts, status, lock, ord) VALUES ($category_id, '$title', '$description', $time, $time, '$user', '$afid', '$crypt', '$user', '$afid', 0, 0,0,0,0)");
+    my $forum_id=$self->getColumn("SELECT MAX(forum_id) FROM $self->{forum_tb} WHERE category_id = $category_id");
+
+    $self->sendBbMail("New Forum $title was created by $user.\n");
+
+    return $forum_id;
+}
+
+##############################################
+# addTopic
+##############################################
+
+sub addTopic {
+    my ($self, $forum_id,$title, $description, $icon,$user, $afid, $pwd,$status) = @_;
+    my $time = time;
+    my $crypt="";
+    my $num_topics = 0;
+    my $num_posts = 0;
+    $forum_id = $self->escape($forum_id, 'int');
+    $title = $self->escape_all($title);
+    $description = $self->escape($description);
+    $icon = $self->escape_all($icon);
+    $user = $self->escape_all($user);
+    $afid = $self->escape_all($afid);
+    $pwd = $self->escape_all($pwd);
+    $status = $self->escape($status, 'int');
+    $crypt = $self->cryptPwd($pwd)	if ($pwd ne "");
+    $self->checkContent($title, $user, $afid, $description, $icon, $pwd);
+    
+    my @same = $self->getall("SELECT topic_id FROM $self->{topic_tb} WHERE title='$title'");
+    $self->errorExit('<AF_M text="A topic of the proposed name already exists.">') if($#same >= 0);
+    
+    $self->{dbh}->do("INSERT INTO $self->{topic_tb} (forum_id, title, description, icon, user, afid, pwd, last_user, last_afid, view, posts, status, lock,timestamp, update_time) VALUES ($forum_id, '$title', '$description', '$icon', '$user', '$afid', '$crypt', '$user', '$afid', 0, 0, $status, 0, $time, $time)");
+    
+    my $topic_id=$self->getColumn("SELECT MAX(topic_id) FROM $self->{topic_tb} WHERE forum_id = $forum_id");
+
+    $num_topics = $self->getColumn("SELECT count(forum_id) FROM $self->{topic_tb} WHERE forum_id=$forum_id");
+    $num_posts = $self->getColumn("SELECT sum(posts) FROM $self->{topic_tb} WHERE forum_id=$forum_id");
+    $num_posts = $num_posts+$num_topics;
+    $self->{dbh}->do("UPDATE $self->{forum_tb} SET topics = $num_topics, posts = $num_posts, last_user = '$user', last_afid = '$afid', update_time = $time WHERE forum_id = $forum_id");
+
+    $self->sendBbMail("New Topic $title was created by $user.\n\n-----\n$description\n");
+    
+    return $topic_id;
+}
+
+
+##############################################
+# updateTopic
+##############################################
+
+sub updateTopic {
+    my ($self, $topic_id,$title, $description, $icon,$user, $afid, $status,$lock) = @_;
+    my $time = time;
+    $topic_id = $self->escape($topic_id, 'int');
+    $title = $self->escape_all($title);
+    $description = $self->escape($description);
+    $icon = $self->escape_all($icon);
+    $user = $self->escape_all($user);
+    $afid = $self->escape_all($afid);
+    $status = $self->escape($status, 'int');
+    $lock = $self->escape($lock, 'int');
+    $self->checkContent($title, $user, $afid, $description, $icon, "");
+    
+    my @same = $self->getall("SELECT topic_id FROM $self->{topic_tb} WHERE title='$title'");
+    $self->errorExit('<AF_M text="A topic of the proposed name already exists.">') if($#same >= 1);
+    
+    $self->{dbh}->do("UPDATE $self->{topic_tb} SET title='$title', description='$description', icon='$icon', status=$status, lock=$lock, user = '$user', afid = '$afid', timestamp = $time WHERE topic_id = $topic_id");
+
+    $self->sendBbMail("Topic $title was updated by $user.\n\n-----\n$description\n");
+
+    return $topic_id;
+}
+
+
+##############################################
+# updateForum
+##############################################
+
+sub updateForum {
+    my ($self, $forum_id,$title, $description, $user, $afid) = @_;
+    my $time = time;
+    $forum_id = $self->escape($forum_id, 'int');
+    $title = $self->escape_all($title);
+    $description = $self->escape($description);
+    $user = $self->escape_all($user);
+    $afid = $self->escape_all($afid);
+    $self->checkContent($title, $user, $afid, $description, "", "");
+    
+    my @same = $self->getall("SELECT forum_id FROM $self->{forum_tb} WHERE title='$title'");
+    $self->errorExit('<AF_M text="A forum of the proposed name already exists.">') if($#same >= 1);
+    
+    $self->{dbh}->do("UPDATE $self->{forum_tb} SET title='$title', description='$description', user = '$user', afid = '$afid', timestamp = $time WHERE forum_id = $forum_id");
+
+    $self->sendBbMail("Forum $title was updated by $user.\n\n-----\n$description\n");
+
+    return $forum_id;
+}
+
+
+##############################################
+# addSpamkey
+##############################################
+
+sub addSpamkey {
+    my ($self, $keyword) = @_;
+    $keyword = $self->escape_all($keyword);
+    my @same = $self->getall("SELECT keyword FROM $self->{spam_tb} WHERE keyword = '$keyword'");
+    if($#same >= 0) { return; }
+    $self->{dbh}->do("INSERT INTO $self->{spam_tb} (keyword) VALUES ('$keyword')");
+}
+
+##############################################
+# removeSpamkey
+##############################################
+
+sub removeSpamkey {
+    my ($self, $spam_id) = @_;
+    $spam_id = $self->escape($spam_id, 'int');
+    $self->{dbh}->do("DELETE FROM $self->{spam_tb} WHERE spam_id = $spam_id");
+}
+
+##############################################
+# deleteReply
+##############################################
+
+sub deleteReply {
+    my ($self, $topic_id, $reply_id) = @_;
+    $reply_id = $self->escape($reply_id, 'int');
+    my $reply_tb = "reply_".$self->escape($topic_id, 'int');
+    $self->{dbh}->do("UPDATE $reply_tb SET user = NULL, afid = NULL, title = NULL, icon = NULL, comment = '\<AF_M text=\"Deleted\"\>' WHERE reply_id = $reply_id");
+}
+
+##############################################
+# updateCategoryInfo
+##############################################
+
+sub updateCategoryInfo {
+    my ($self, $category_id, $user, $afid) = @_;
+    my $time = time;
+    $category_id = $self->escape($category_id, 'int');
+    $user = $self->escape_all($user);
+    $afid = $self->escape_all($afid);
+    
+    $self->{dbh}->do("UPDATE $self->{category_tb} SET last_user = '$user', last_afid = '$afid', update_time = $time WHERE category_id = $category_id");
+}
+
+
+##############################################
+# updateForumInfo
+##############################################
+#sub updateForumInfo {
+#    my ($self, $forum_id, $user, $afid) = @_;
+#    my $time = time;
+#    $forum_id = $self->escape($forum_id, 'int');
+#    $user = $self->escape_all($user);
+#    $afid = $self->escape_all($afid);
+#    $self->{dbh}->do("UPDATE $self->{forum_tb} SET last_user = '$user', last_afid = '$afid', update_time = $time WHERE forum_id = $forum_id");
+#}
+
+
+##############################################
+# addViewCountTopic
+##############################################
+
+sub addViewCountTopic {
+    my ($self, $topic_id) = @_;
+    $topic_id = $self->escape($topic_id, 'int');
+    $self->{dbh}->do("UPDATE $self->{topic_tb} SET view = view+1 WHERE topic_id = $topic_id");
+}
+
+##############################################
+# getCategory
+##############################################
+
+sub getCategory {
+    my ($self, $category_id) = @_;
+    $category_id = $self->escape($category_id, 'int');
+    my @ret = $self->getall("SELECT * FROM $self->{category_tb} WHERE category_id = $category_id");
+    return $ret[0];
+}
+
+##############################################
+# getForum
+##############################################
+
+sub getForum {
+    my ($self, $forum_id) = @_;
+    $forum_id = $self->escape($forum_id, 'int');
+    my @ret = $self->getall("SELECT * FROM $self->{forum_tb} WHERE forum_id = $forum_id");
+    return $ret[0];
+}
+
+##############################################
+# getTopic
+##############################################
+
+sub getTopic {
+    my ($self, $topic_id) = @_;
+    $topic_id = $self->escape($topic_id, 'int');
+    my @ret = $self->getall("SELECT * FROM $self->{topic_tb} WHERE topic_id = $topic_id");
+    return $ret[0];
+}
+
+##############################################
+# deleteTopic
+##############################################
+
+sub deleteTopic {
+    my ($self, $topic_id, $forum_id) = @_;
+    my $reply_tb = "reply_".$self->escape($topic_id, 'int');
+    $forum_id = $self->escape($forum_id, 'int');
+    $self->{dbh}->do("DELETE FROM $self->{topic_tb} WHERE topic_id = $topic_id");
+    $self->{dbh}->do("DROP TABLE $reply_tb");
+    my $num_topics = $self->getColumn("SELECT count(topic_id) FROM $self->{topic_tb} WHERE forum_id=$forum_id");
+
+    my $num_posts = $self->getColumn("SELECT sum(posts) FROM $self->{topic_tb} WHERE forum_id=$forum_id");
+
+    $num_posts += $num_topics;
+    $self->{dbh}->do("UPDATE $self->{forum_tb} SET topics = $num_topics, posts = $num_posts WHERE forum_id = $forum_id");
+}
+
+##############################################
+# getAllReplies
+##############################################
+
+sub getAllReplies {
+    my ($self, $topic_id) = @_;
+    my $reply_tb = "reply_".$self->escape($topic_id, 'int');
+    return $self->getall("SELECT * FROM $reply_tb ORDER BY timestamp");
+}
+
+##############################################
+# getReplies
+##############################################
+
+sub getReplies {
+    my ($self, $topic_id, $end, $start) = @_;
+    my $reply_tb = "reply_".$self->escape($topic_id, 'int');
+#    print "$start:$end";
+
+    return $self->getall("SELECT * FROM $reply_tb WHERE reply_id BETWEEN $start AND $end");
+}
+
+##############################################
+# getReply
+##############################################
+
+sub getReply {
+    my ($self, $topic_id, $reply_id) = @_;
+    $reply_id = $self->escape($reply_id, 'int');
+    my $reply_tb = "reply_".$self->escape($topic_id, 'int');
+    my @ret = $self->getall("SELECT * FROM $reply_tb WHERE reply_id = $reply_id");
+    return $ret[0];
+}
+
+##############################################
+# getPreference
+##############################################
+sub getPreference {
+    my $self = shift;
+    my $sth = $self->{dbh}->prepare("SELECT * FROM $self->{pref_tb}");
+    $sth->execute;
+    
+    my @pref;
+    while(my @row = $sth->fetchrow_array) {
+	push (@pref, @row);
+    }
+    $sth->finish;
+
+    return @pref;
+}
+
+##############################################
+# updatePreference
+##############################################
+
+sub updatePreference {
+    my ($self,$title,$email,$max_topics,$max_comments,$num_topics,$num_comments,$max_sbjlen,$max_textlen) = @_;
+    $self->errorExit('<AF_M text="Please input data correctly.">') if ($max_topics =~ /\D/ || $max_comments =~ /\D/ || $num_topics =~ /\D/ || $num_comments =~ /\D/ || $max_sbjlen =~ /\D/ || $max_textlen =~ /\D/);
+    $title = $self->escape_all($title);
+    
+    $self->{dbh}->do("UPDATE $self->{pref_tb} SET value = '$title' WHERE key = 'title'");
+    $self->{dbh}->do("UPDATE $self->{pref_tb} SET value = '$email' WHERE key = 'email'");
+    $self->{dbh}->do("UPDATE $self->{pref_tb} SET value = '$max_topics' WHERE key = 'max_topics'");
+    $self->{dbh}->do("UPDATE $self->{pref_tb} SET value = '$max_comments' WHERE key = 'max_comments'");
+    $self->{dbh}->do("UPDATE $self->{pref_tb} SET value = '$num_topics' WHERE key = 'num_topics'");
+    $self->{dbh}->do("UPDATE $self->{pref_tb} SET value = '$num_comments' WHERE key = 'num_comments'");
+    $self->{dbh}->do("UPDATE $self->{pref_tb} SET value = '$max_sbjlen' WHERE key = 'max_sbjlen'");
+    $self->{dbh}->do("UPDATE $self->{pref_tb} SET value = '$max_textlen' WHERE key = 'max_textlen'");
+}
+
+
+##############################################
+# getAllComments
+##############################################
+
+sub getAllComments {
+    my ($self, $topic_id) = @_;
+    $topic_id = $self->escape($topic_id, 'int');
+    return $self->getall("SELECT * FROM $self->{reply_tb} WHERE topic_id = $topic_id ORDER BY timestamp");
+}
+
+
+
+##############################################
+# getNewestEntries
+##############################################
+
+#sub getNewestEntries {
+#	my ($self, $num) = @_;
+#	unless ($num) { $num = 5; }
+#	return $self->getall("SELECT * FROM $self->{category_tb} ORDER BY update_time DESC LIMIT $num");
+#}
+
+##############################################
+# getNewestCategoryId
+##############################################
+
+sub getNewestCategoryId {
+  	my ($self) = @_;
+  	my @ret = $self->getall("SELECT MAX(category_id) as category_id FROM $self->{category_tb}");
+  	return $ret[0];
+}
+
+##############################################
+# getNewestProjectId
+##############################################
+
+sub getNewestProjectId {
+  	my ($self) = @_;
+  	my @ret = $self->getall("SELECT MAX(forum_id) as forum_id FROM $self->{forum_tb}");
+  	return $ret[0];
+}
+
+##############################################
+# getAllCategories
+##############################################
+
+sub getAllCategories {
+	my ($self) = @_;
+	return $self->getall("SELECT * FROM $self->{category_tb} ORDER BY timestamp");
+}
+
+##############################################
+# getAllForums
+##############################################
+
+sub getAllForums {
+    my ($self,$category_id) = @_;
+    $category_id = $self->escape($category_id, 'int');
+    return $self->getall("SELECT * FROM $self->{forum_tb} WHERE category_id = $category_id ORDER BY update_time DESC");
+}
+
+##############################################
+# getAllTopics
+##############################################
+
+sub getAllTopics {
+    my ($self,$forum_id) = @_;
+    $forum_id = $self->escape($forum_id, 'int');
+    return $self->getall("SELECT * FROM $self->{topic_tb} WHERE forum_id = $forum_id ORDER BY status DESC, update_time DESC");
+}
+
+##############################################
+# getAllSpamkeys
+##############################################
+
+sub getAllSpamkeys {
+    my ($self) = @_;
+    return $self->getall("SELECT * FROM $self->{spam_tb}");
+}
+
+
+##############################################
+# getSumOfFiles
+##############################################
+sub getSumOfFiles {
+    my ($self, $category_id) = @_;
+    $category_id = $self->escape($category_id, 'int');
+    return $self->getColumn("SELECT COUNT(*) FROM $self->{topic_tb} WHERE category_id = $category_id");
+}
+
+##############################################
+# getNumOfComments
+##############################################
+#sub getNumOfComments {
+#	my ($self, $topic_id) = @_;
+##	my $reply_tb = "reply_".$topic_id;
+##	return $self->getColumn("SELECT COUNT(*) FROM $reply_tb");
+#	return $self->getColumn("SELECT posts FROM $topic_tb WHERE topic_id=$topic_id");
+#}
+
+##############################################
+# addComment
+##############################################
+
+sub addComment {
+    my ($self, $topic_id, $title, $user, $afid, $comment, $pwd, $icon) = @_;
+    my $time = time;
+    my $crypt = "";
+    $topic_id = $self->escape($topic_id, 'int');
+    $title = $self->escape_all($title);
+    $user = $self->escape_all($user);
+    $afid = $self->escape_all($afid);
+    $comment = $self->escape($comment);
+    $pwd = $self->escape_all($pwd);
+    $icon = $self->escape_all($icon);
+    $crypt = $self->cryptPwd($pwd)	if ($pwd ne "");
+    $self->checkContent($title, $user, $afid, $comment, $icon, $pwd);
+    
+    my @same = $self->getall("SELECT reply_id FROM reply_$topic_id WHERE title = '$title' AND user = '$user' AND comment = '$comment'");
+    $self->errorExit('<AF_M text="A same comment already exists.">') if($#same >= 0);
+    
+    $self->{dbh}->do("INSERT INTO reply_$topic_id (title, user, afid, comment, icon, pwd, timestamp) VALUES ('$title', '$user', '$afid', '$comment', '$icon', '$crypt', $time)");
+    
+    $self->{dbh}->do("UPDATE $self->{topic_tb} SET posts = posts+1 WHERE topic_id = $topic_id");
+    my $forum_id = $self->getColumn("SELECT forum_id FROM $self->{topic_tb} WHERE topic_id = $topic_id");
+#    $self->{dbh}->do("UPDATE $self->{forum_tb} SET posts = posts+1 WHERE forum_id = $forum_id");
+    $self->{dbh}->do("UPDATE $self->{forum_tb} SET posts = posts+1, last_user = '$user', last_afid = '$afid', update_time = $time WHERE forum_id = $forum_id");
+
+    $self->{dbh}->do("UPDATE $self->{topic_tb} SET last_user = '$user', last_afid = '$afid', update_time = $time WHERE topic_id = $topic_id");
+    
+    $self->sendBbMail("New Comment $title was written by $user.\n\n-----\n$comment\n");
+}
+
+##############################################
+# sendBbMail
+##############################################
+sub sendBbMail {
+    my ($self,$msg) = @_;
+    my $mailto = $self->getColumn("SELECT value FROM $self->{pref_tb} WHERE key = 'email'");
+    my $bb_title = $self->getColumn("SELECT value FROM $self->{pref_tb} WHERE key = 'title'");
+    Affelio::NetLib::Email::send_email($self->{afap}->{af}->{cmd__sendmail}, "$self->{afap}->{af}->{user__email1}", "Affelio BB", $mailto, "Message from $bb_title", "$msg");
+}
+
+##############################################
+# getComments
+##############################################
+sub getComments {
+    my ($self, $id) = @_;
+    $id = $self->escape($id, 'int');
+    return $self->getall("SELECT * FROM $self->{reply_tb} WHERE id = $id ORDER BY timestamp");
+}
+
+##############################################
+# getCommentsNo
+##############################################
+sub getCommentsNo {
+    my ($self, $id) = @_;
+    $id = $self->escape($id, 'int');
+    return $self->getColumn("SELECT COUNT(*) FROM $self->{reply_tb} WHERE id = $id");
+}
+
+##############################################
+# getColumn
+##############################################
+sub getColumn {
+    my ($self, $query) = @_;
+    my $sth = $self->{dbh}->prepare($query);
+    $sth->execute;
+    my $num;
+    $sth->bind_columns(undef, \$num);
+    $sth->fetch;
+    $sth->finish;
+    if($num) {
+	return $num;
+    }
+    else {
+	return 0;
+    }
+}
+
+##############################################
+# get all columns
+##############################################
+sub getall {
+    my ($self, $query) = @_;
+    my $sth = $self->{dbh}->prepare($query);
+    $sth->execute;
+    
+    my @ret;
+    while(my $row = $sth->fetchrow_hashref) {
+	push @ret, $row;
+    }
+    $sth->finish;
+    
+    return @ret;
+}
+
+##############################################
+# escape
+##############################################
+sub escape {
+    my ($self, $str, $type) = @_;
+    
+    if ($type eq 'int') {
+	return int($str);
+    }
+    else {
+	$str =~ s/[\t\a]//g;
+	$str =~ s/&/&amp;/g;
+	$str =~ s/["']/&quot;/g;
+	$str =~ s/</&lt;/g;
+	$str =~ s/>/&gt;/g;
+	$str =~ s/&lt;(\/?)(a|p|i|b|big|strong|small|em|u|blockquote)&gt;/<$1$2>/ig;
+	$str =~ s/&lt;a +href=(&quot;)?(s?https?:\/\/[-_.!~*'()a-zA-Z0-9;\/?:\@&=+\$,%#]+) *(&quo\
+t;)? *&gt;/<a href="$2">/ig;
+	$str =~ s/&quot;"/"/g;
+	$str =~ s/(\r\n|\r|\n)/<br \/>/g;
+	
+	while ($str =~ /(<(a|p|i|b|big|strong|small|em|u|blockquote)\b(?:(?!<\/\2>).)*(?:<\2>|$))\
+/sigx) {
+	    $self->errorExit("Error: You may mistype a tag or forget to close it.");
+	}
+    }
+    
+    return $str;
+}
+
+sub escape_all {
+    my ($self, $str) = @_;
+    
+    $str =~ s/[\t\a]//g;
+    $str =~ s/&/&amp;/g;
+    $str =~ s/['"]/&quot;/g;
+    $str =~ s/</&lt;/g;
+    $str =~ s/>/&gt;/g;
+    $str =~ s/(\r\n|\r|\n)/<br \/>/g;
+    
+    return $str;
+}
+
+############################################################################
+# get user URI
+############################################################################
+sub getUserURI {
+    my ($self, $uri) = @_;
+    $uri=$self->{afap}->get_site_info("web_root").'/outgoing.cgi?dest_url='.$uri;
+    return $uri;
+}
+
+############################################################################
+# get primary key for DBs
+############################################################################
+sub get_query_primarykey {
+    my ($self) = @_;
+    my $DBConfig = Config::Tiny->new();
+    $DBConfig = Config::Tiny->read("$self->{afap}->{af}->{site__user_dir}/db.cfg");
+    my $db_type = $DBConfig->{db}->{type};
+    my $query;
+
+    if ($db_type eq "sqlite"){
+	$query = " PRIMARY KEY,";
+    }elsif ($db_type eq "mysql"){
+	$query = " AUTO_INCREMENT PRIMARY KEY,";
+    }
+    return $query;
+}
+
+##############################################
+# cryptPwd
+##############################################
+sub cryptPwd {
+    my ($self, $pwd) = @_;
+    if ( $pwd !~ /[a-zA-Z0-9]/){
+	$self->errorExit('<AF_M text="Please use alphameric characters.">');
+    }
+    if (length($pwd)<4){
+	$self->errorExit('<AF_M text="Please input more than 4 characters.">');
+    }
+    my @salts = ( "A".."Z", "a".."z", "0".."9", ".", "/" );
+    my $salt = $salts[int(rand(64))] . $salts[int(rand(64))];
+    my $crypt = crypt($pwd, $salt);
+    return $crypt;
+}
+
+##############################################
+# checkPwd
+##############################################
+sub checkPwd {
+    my ($self, $pwd) = @_;
+    $self->errorExit('<AF_M text="Please input a password.">') if($pwd eq "");
+    if ( $pwd !~ /[a-zA-Z0-9]/){
+	$self->errorExit('<AF_M text="Please use alphameric characters as your password.">');
+    }
+    if (length($pwd)<4){
+	$self->errorExit('<AF_M text="Please input more than 4 characters as your password.">');
+    }
+}
+
+##############################################
+# cryptID
+##############################################
+sub cryptID {
+    my ($self, $pwd) = @_;
+    if ( $pwd !~ /[a-zA-Z0-9]/){
+	$self->errorExit('<AF_M text="Please use alphameric characters.">');
+    }
+    if (length($pwd)<4){
+	$self->errorExit('<AF_M text="Please input more than 4 characters.">');
+    }
+    my $salt = substr($pwd ,0,2);
+    
+    my $crypt = crypt($pwd, $salt);
+    return $crypt;
+}
+
+
+############################################################################
+#L10N added by slash
+############################################################################
+sub translate_templateL10N{
+    my $af=shift;
+    my $mesg = shift;
+    
+    my $tag_body ="";
+    my $text_value="";
+    my $param_value="";
+    
+    while( $mesg =~ /<AF_M ([^>]+)>/ ){
+	$tag_body = $1;
+	
+	$tag_body =~ /text(\s*)=(\s*)["']([^"']*)["'](\s*)param(\s*)=(\s*)["']([^"']*)["']/;
+	$text_value=$3;
+	$param_value=$7;
+	if($text_value eq ""){
+	    $tag_body =~ /text(\s*)=(\s*)["']([^"']*)["']/;
+	    $text_value=$3;
+	}
+	
+	my $sbst = $af->{lh}->maketext($text_value, $param_value);
+	$mesg =~ s/\Q<AF_M $tag_body>\E/$sbst/g;
+    }
+    return($mesg);
+}
+
+############################################################################
+#check Content
+############################################################################
+sub checkContent {
+    my ($self, $title, $user, $afid, $description, $icon, $pwd) = @_;
+    my $max_sbjlen = $self->getColumn("SELECT value FROM $self->{pref_tb} WHERE key = 'max_sbjlen'");
+    my $max_textlen = $self->getColumn("SELECT value FROM $self->{pref_tb} WHERE key = 'max_textlen'");
+    $self->errorExit('<AF_M text="Too long title.">') if (length($title)>int($max_sbjlen));
+    $self->errorExit('<AF_M text="Too long content.">') if (length($description)>int($max_textlen));
+    $self->errorExit('<AF_M text="Too long nickname.">') if (length($user)>256);
+    $self->errorExit('<AF_M text="Too long URI.">') if (length($afid)>256);
+    $self->errorExit('<AF_M text="Too long filename of icon.">') if (length($icon)>64);
+    $self->errorExit('<AF_M text="Too long password.">') if (length($pwd)>32);
+
+    my @spam_key = $self->getall("SELECT keyword FROM $self->{spam_tb}");
+    foreach(@spam_key){
+	if ($description =~ /$_->{keyword}/ ||
+	    $title =~ /$_->{keyword}/){
+	    $self->errorExit('<AF_M text="Your message was quarantined as suspected spam.">');
+	}
+    }
+}
+
+
+############################################################################
+#Show Error
+############################################################################
+sub errorExit {
+    my ($self,$msg) = @_;
+    my $affelio_id = $self->{afap}->get_visitor_info("afid");
+    my $visitor_type=$self->{afap}->get_visitor_info("type");
+    
+    if($visitor_type eq ""){
+	$visitor_type="pb";
+    }
+    my $tmpl = HTML::Template->new(filename => "./templates/error.tmpl");
+    $tmpl->param(V_TYPE => $visitor_type);
+    $tmpl->param(AF_ID => $affelio_id);
+    $tmpl->param(MSG => $msg);
+
+    print $self->translate_templateL10N( $tmpl->output );
+    print $self->{afap}->get_HTML_footer();
+    exit;
+}
+
+1;
+
+
+
Index: affelio/apps/bb/comment.cgi
diff -u /dev/null affelio/apps/bb/comment.cgi:1.1
--- /dev/null	Mon Dec 19 15:46:28 2005
+++ affelio/apps/bb/comment.cgi	Mon Dec 19 15:46:27 2005
@@ -0,0 +1,185 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2005 FishGrove Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+use strict;
+use lib("../../extlib");
+use lib("../../lib");
+use HTML::Template;
+use CGI;
+use Cwd;
+use AffelioApp;
+use bb;
+
+
+#Initialize AFAP
+our $cgi = new CGI();
+our $afap = new AffelioApp(ConfigDir => Cwd::getcwd(), cgi => $cgi);
+our $bb = new bb($afap);
+my $tmpl;
+
+# put Content-type
+print "Content-type: text/html; charset=UTF-8\n";
+print "Pragma: no-cache", "\n\n"; 
+# put HTML Header
+print $afap->get_HTML_header("Affelio BB");
+# check access
+unless ($afap->check_access("super")||$afap->check_access("user")) {
+	$bb->errorExit('<AF_M text="Access denied">');
+}
+
+########### Init BB ####################################################
+my $mode = $afap->{cgi}->param("mode");
+my $action = $afap->{cgi}->param("action");
+my $t_id = $afap->{cgi}->param("t_id");
+$bb->errorExit('<AF_M text="Please specify the Topic.">') if ($t_id =~ /\D/ || $t_id eq "");
+my $reply_title = $afap->{cgi}->param("reply_title");
+my $comment = $afap->{cgi}->param("comment");
+my $pb_user = ($afap->get_visitor_info("type") eq "pb") ? "1" : "0";
+my $pwd = $afap->{cgi}->param("pwd");
+my $user_name = $afap->{cgi}->param("user_name");
+my $afid = $afap->{cgi}->param("afid");
+my $icon = $afap->{cgi}->param("icon");
+if ($pb_user eq "0"){
+	$user_name = $afap->get_visitor_info("nickname");
+	$afid = $afap->get_visitor_info("afid");
+}
+$bb->errorExit('<AF_M text="This topic is locked.">') if ($bb->getColumn("SELECT lock FROM $bb->{topic_tb} WHERE topic_id=$t_id"));
+
+########### Add new comment  ####################################################
+if ($mode eq "new_comment"){
+	$bb->errorExit('<AF_M text="Please input a subject.">') if($reply_title eq "");
+	$bb->errorExit('<AF_M text="Please input your comment.">') if($comment eq "");
+	if ($pb_user){
+		$bb->errorExit('<AF_M text="Please input your nickname.">') if($user_name eq "");
+		$bb->errorExit('<AF_M text="Please input a password.">') if($pwd eq "");
+	}
+	$tmpl = HTML::Template->new(filename => "./templates/comment.tmpl");
+	$tmpl->param(
+		NEW => "1",
+		T_ID => $t_id,
+		TITLE => $reply_title,
+		COMMENT => $comment,
+		USER => $user_name,
+		AFID => $afid,
+	);
+
+########### Confirm comment  ####################################################
+}elsif ($mode eq "confirm_comment"){
+	$bb->errorExit('<AF_M text="Please input a subject.">') if($reply_title eq "");
+	$bb->errorExit('<AF_M text="Please input your comment.">') if($comment eq "");
+	if ($pb_user){
+		$bb->errorExit('<AF_M text="Please input your nickname.">') if($user_name eq "");
+		$bb->checkPwd($pwd);
+	}
+	$icon = "owner.gif" if ($afap->get_visitor_info("type") eq "self" && $icon eq "");
+
+	$tmpl = HTML::Template->new(filename => "./templates/comment.tmpl");
+	$tmpl->param(
+		CONFIRM => "1",
+		T_ID => $t_id,
+		PB_USER => $pb_user,
+		TITLE => $reply_title,
+		COMMENT_SHOW => $bb->escape($comment),
+		COMMENT => $comment,
+		USER => $user_name,
+		AFID => $afid,
+		PWD => $pwd,
+		ICON => $icon,
+	);
+
+########### Submit comment  ####################################################
+}elsif ($mode eq "submit_comment"){
+	$bb->errorExit('<AF_M text="Please input a subject.">') if($reply_title eq "");
+	$bb->errorExit('<AF_M text="Please input your comment.">') if($comment eq "");
+	if ($pb_user){
+		$bb->errorExit('<AF_M text="Please input your nickname.">') if($user_name eq "");
+		$bb->errorExit('<AF_M text="Please input a password.">') if($pwd eq "");
+	}
+	$bb->addComment($t_id, $reply_title, $user_name, $afid, $comment, $pwd, $icon);
+
+	$tmpl = HTML::Template->new(filename => "./templates/comment.tmpl");
+	$tmpl->param(
+		SUBMIT => "1",
+		T_ID => $t_id,
+	);
+########### delete comment  ####################################################
+}elsif ($mode eq "delete_comment"){
+	my $r_id = $afap->{cgi}->param("r_id");
+	$bb->errorExit('<AF_M text="Please specify the comment.">') if ($r_id =~ /\D/ || $r_id eq "");
+	$tmpl = HTML::Template->new(filename => "./templates/comment.tmpl");
+	#Do delete
+	if ($action eq "do_delete"){
+		my $reply = $bb->getReply($t_id, $r_id);
+		if ($afap->get_visitor_info("type") eq "self"){
+			$bb->deleteReply($t_id, $r_id);
+		}else{
+			if($pb_user eq "0") {
+				if ($reply->{pwd} eq "" && $reply->{afid} eq $afid){
+					$bb->deleteReply($t_id, $r_id);
+				}else{
+					$bb->errorExit('<AF_M text="Authentication error.">');
+				}
+			} elsif($reply->{pwd} ne ""){
+				if ($pb_user){
+					$bb->errorExit('<AF_M text="Please input your nickname.">') if($user_name eq "");
+					$bb->checkPwd($pwd);	  
+				}
+				if (crypt($pwd,$reply->{pwd}) eq $reply->{pwd}){
+					$bb->deleteReply($t_id, $r_id);		
+				}else{
+					$bb->errorExit('<AF_M text="Authentication error.">');
+				}
+			}
+		}
+
+		$tmpl->param(
+			DONE_DELETE => "1",
+			T_ID => $t_id,
+		);
+	# Delete mode (no action)
+	}else{
+		my $reply = $bb->getReply($t_id, $r_id);
+		if ($afap->get_visitor_info("type") eq "self"){
+			$tmpl->param(PWD => "0");
+		}else{
+			if ($pb_user eq "0"){
+				if ($reply->{pwd} eq "" && $reply->{afid} eq $afid){
+					$tmpl->param(PWD => "0");
+				} else{
+					$bb->errorExit('<AF_M text="Authentication error.">');
+				}
+			}elsif($reply->{pwd} ne ""){
+				$tmpl->param(PWD => "1");
+			}
+		}
+
+		$tmpl->param(
+			CONFIRM_DELETE => "1",
+			T_ID => $t_id,
+			R_ID => $r_id,
+			USER => $reply->{user},
+			TITLE => $reply->{title},
+			COMMENT => $reply->{comment},
+			AFID => $reply->{afid},
+		);
+	}
+} else {
+	$bb->errorExit('<AF_M text="Error: Unknown access.">');
+}
+
+print $bb->translate_templateL10N( $tmpl->output );
+print $afap->get_HTML_footer();
Index: affelio/apps/bb/forum.cgi
diff -u /dev/null affelio/apps/bb/forum.cgi:1.1
--- /dev/null	Mon Dec 19 15:46:28 2005
+++ affelio/apps/bb/forum.cgi	Mon Dec 19 15:46:27 2005
@@ -0,0 +1,177 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2005 FishGrove Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+use strict;
+use lib("../../extlib");
+use lib("../../lib");
+use HTML::Template;
+use CGI;
+use Cwd;
+use AffelioApp;
+use bb;
+
+
+#Initialize AFAP
+our $cgi = new CGI();
+our $afap = new AffelioApp(ConfigDir => Cwd::getcwd(), cgi => $cgi);
+our $bb = new bb($afap);
+my $tmpl;
+
+# put Content-type
+print "Content-type: text/html; charset=UTF-8\n";
+print "Pragma: no-cache", "\n\n"; 
+# put HTML Header
+print $afap->get_HTML_header("Affelio BB");
+# check access
+unless ($afap->check_access("super")) {
+    $bb->errorExit('<AF_M text="Access denied">');
+}
+
+########### Init BB ####################################################
+my $mode = $afap->{cgi}->param("mode");
+my $action = $afap->{cgi}->param("action");
+my $c_id = $afap->{cgi}->param("c_id");
+$bb->errorExit('<AF_M text="Please specify the category.">') if ($c_id =~ /\D/);
+my $title = $afap->{cgi}->param("title");
+my $description = $afap->{cgi}->param("description");
+my $status = $afap->{cgi}->param("status");
+my $user = $afap->{cgi}->param("user");
+my $afid = $afap->{cgi}->param("afid");
+my $pwd = $afap->{cgi}->param("pwd");
+my $pb_user = ($afap->get_visitor_info("type") eq "pb") ? "1" : "0";
+if ($pb_user eq "0"){
+	$user = $afap->get_visitor_info("nickname");
+	$afid = $afap->get_visitor_info("afid");
+}
+my $status_edit = $afap->check_access("super") ? "1" : "0";
+
+########### Add new forum  ####################################################
+if ($mode eq "add_forum"){
+	$tmpl = HTML::Template->new(filename => "./templates/forum.tmpl");
+	$tmpl->param(
+		NEW			=> "1",
+		C_ID		=> $c_id,
+		TITLE		=> $title,
+		DESCRIPTION	=> $description,
+		PB_USER		=> $pb_user,
+		AFID		=> $afid,
+		USER		=> $user
+	);
+########### Confirm forum info ####################################################
+}elsif ($mode eq "confirm_forum"){
+	$bb->errorExit('<AF_M text="Please input a title.">') if ($title eq "");
+	$bb->errorExit('<AF_M text="Please input a description.">') if ($description eq "");
+	$bb->errorExit('<AF_M text="Please input your nickname.">') if ($user eq "");
+	$bb->checkPwd($pwd) if ($pb_user eq "1");
+	$tmpl = HTML::Template->new(filename => "./templates/forum.tmpl");
+	$tmpl->param(
+		CONFIRM		=> "1",
+		C_ID		=> $c_id,
+		TITLE		=> $title,
+		DESCRIPTION_SHOW=> $bb->escape($description),
+		DESCRIPTION	=> $description,
+		PB_USER		=> $pb_user,
+		AFID		=> $afid,
+		PWD			=> $pwd,
+		USER		=> $user
+	);
+########### Submit forum  ####################################################
+}elsif ($mode eq "submit_forum"){
+	$bb->errorExit('<AF_M text="Please input a title.">') if ($title eq "");
+	$bb->errorExit('<AF_M text="Please input a description.">') if ($description eq "");
+	$bb->errorExit('<AF_M text="Please input your nickname.">') if ($user eq "");
+	$bb->errorExit('<AF_M text="Please input a password.">') if ($pwd eq "" && $pb_user);
+
+	my $forum_id = $bb->addForum($c_id, $title, $description, $user, $afid, $pwd);
+	$bb->updateCategoryInfo($c_id, $user, $afid);
+	$tmpl = HTML::Template->new(filename => "./templates/forum.tmpl");
+	$tmpl->param(
+		DONE	=> "1",
+		F_ID	=> $forum_id,
+		MSG	=> "New forum was created.",
+    );
+########### edit forum  ####################################################
+}elsif ($mode eq "edit_forum"){
+	my $f_id = $afap->{cgi}->param("f_id");
+	$bb->errorExit('<AF_M text="Please specify the forum.">') if ($f_id =~ /\D/ || $f_id eq "");
+	$tmpl = HTML::Template->new(filename => "./templates/forum.tmpl");
+	my $forum = $bb->getForum($f_id);
+	my $auth=0;
+	if ($action ne ""){
+		if ($afap->get_visitor_info("type") eq "self"){
+			$auth=1;
+		}else{
+			if($pb_user eq "0") {
+				if ($forum->{pwd} eq "" && $forum->{afid} eq $afid){
+					$auth=1;
+				}else{
+					$bb->errorExit('<AF_M text="Authentication error.">');
+				}
+			} elsif($forum->{pwd} ne ""){
+				if ($pb_user){
+					$bb->errorExit('<AF_M text="Please input your nickname.">') if($user eq "");
+					$bb->checkPwd($pwd);	  
+				}
+				if (crypt($pwd,$forum->{pwd}) eq $forum->{pwd}){
+					$auth=1;
+				}else{
+					$bb->errorExit('<AF_M text="Authentication error.">');
+				}
+			}
+		}
+		# Do update
+		if($action eq "do_update"){
+			$bb->updateForum($f_id, $title, $description, $user, $afid) if ($auth);
+			$tmpl->param(
+				DONE => "1",
+				F_ID => $f_id,
+				MSG => "The forum was updated.",
+			);
+		}
+	# Edit mode (no action)
+	}else{
+		my $can_delete="";
+		if ($afap->get_visitor_info("type") eq "self"){
+			$tmpl->param(PWD => "0");
+			$can_delete = 1;
+		}else{
+			if ($pb_user eq "0"){
+				if ($forum->{pwd} eq "" && $forum->{afid} eq $afid){
+					$tmpl->param(PWD => "0");
+				} else {
+					$bb->errorExit('<AF_M text="Authentication error.">');
+				}
+			}elsif($forum->{pwd} ne ""){
+				$tmpl->param(PWD => "1");
+			}
+		}
+		$forum->{description} =~ s/<br[^>]*>/\n/g;
+		$tmpl->param(
+			EDIT => "1",
+			F_ID => $f_id,
+			USER => $forum->{user},
+			TITLE => $forum->{title},
+			DESCRIPTION => $forum->{description},
+			AFID => $forum->{afid},
+		);
+	}
+}else {
+	$bb->errorExit('<AF_M text="Error: Unknown access.">');
+}
+
+print $bb->translate_templateL10N( $tmpl->output );
+print $afap->get_HTML_footer();
Index: affelio/apps/bb/index.cgi
diff -u /dev/null affelio/apps/bb/index.cgi:1.1
--- /dev/null	Mon Dec 19 15:46:28 2005
+++ affelio/apps/bb/index.cgi	Mon Dec 19 15:46:27 2005
@@ -0,0 +1,109 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2005 FishGrove Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+use strict;
+use lib("../../extlib");
+use lib("../../lib");
+use HTML::Template;
+use CGI;
+use Cwd;
+use AffelioApp;
+use bb;
+
+#Initialize AFAP
+our $cgi = new CGI();
+our $afap = new AffelioApp(ConfigDir => Cwd::getcwd(), cgi => $cgi);
+our $bb = new bb($afap);
+my $tmpl;
+
+# put Content-type
+print "Content-type: text/html; charset=UTF-8\n";
+print "Pragma: no-cache", "\n\n"; 
+# put HTML Header
+print $afap->get_HTML_header("Affelio BB");
+# check access
+unless ($afap->check_access("DF_access")) {
+    $bb->errorExit('<AF_M text="Access denied">');
+}
+
+########### Show Category,Forum List ####################################################
+my %pref = $bb->getPreference;
+my @categories_param;
+my @categories;
+my @forums_param;
+my @forums;
+my $i=0;
+my $j=0;
+$tmpl = HTML::Template->new(filename => "./templates/index.tmpl");
+
+ @ categories = $bb->getAllCategories;
+$tmpl->param(
+	PAGE_TITLE => $pref{'title'},
+	EDITABLE => $afap->check_access("super"), 
+	HAS_CATEGORY=>$#categories+1
+);
+
+foreach(@categories) {
+	@forums = $bb->getAllForums($_->{category_id});
+	
+	foreach(@forums) {
+		my ($sec, $min, $hour, $mday, $mon, $year) = localtime($_->{update_time});
+		$mon+=1;
+		$year+=1900;
+		push @forums_param,
+		{
+			F_ID	=>	$_->{forum_id},
+			TITLE	=>	$_->{title},
+			DESCRIPTION =>  $_->{description},
+			USER	=>	$_->{user},
+			AFID	=>	$bb->getUserURI($_->{afid}),
+			TOPICS  =>  $_->{topics},
+			POSTS  =>  $_->{posts},
+			YEAR	=>	$year,
+			MONTH	=>	$mon,
+			DAY	=>	$mday,
+			TIME	=>	sprintf("%02d:%02d", $hour, $min),
+			LAST_USER =>$_->{last_user},
+			LAST_AFID =>$bb->getUserURI($_->{last_afid}),
+		};
+		$j++;
+	}
+
+	push @categories_param,
+	{
+		FORUM => [@forums_param[$i..($j-1)]],
+		TITLE	=>	$_->{title},   
+		HAS_FORUM => $#forums+1,
+	};
+	$i=$j;
+}
+$tmpl->param(CATEGORIES =>\@categories_param);
+
+########### Show 'add forum' button ####################################################
+my @select_list;
+foreach(@categories) {
+	push @select_list,
+	{
+		C_ID	=>	$_->{category_id},
+		TITLE	=>	$_->{title},
+	};
+}
+$tmpl->param(SELECT_LIST =>\@select_list);
+
+########### Output html ####################################################
+print $bb->translate_templateL10N( $tmpl->output );
+print $afap->get_HTML_footer();
Index: affelio/apps/bb/owner.cgi
diff -u /dev/null affelio/apps/bb/owner.cgi:1.1
--- /dev/null	Mon Dec 19 15:46:28 2005
+++ affelio/apps/bb/owner.cgi	Mon Dec 19 15:46:27 2005
@@ -0,0 +1,172 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2005 FishGrove Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+use strict;
+use lib("../../extlib");
+use lib("../../lib");
+use HTML::Template;
+use CGI;
+use Cwd;
+use AffelioApp;
+use bb;
+
+##############################################
+#Initialize AFAP & put header
+##############################################
+our $cgi = new CGI();
+our $afap = new AffelioApp(ConfigDir => Cwd::getcwd(), cgi => $cgi);
+our $bb = new bb($afap);
+my $tmpl;
+
+# put Content-type
+print "Content-type: text/html; charset=UTF-8\n";
+print "Pragma: no-cache", "\n\n"; 
+# put HTML Header
+print $afap->get_HTML_header("Affelio BB");
+# check access
+unless ($afap->get_visitor_info("type") eq "self"){
+    $bb->errorExit('<AF_M text="Access denied">');
+}
+my $mode = $afap->{cgi}->param("mode");
+my $action = $afap->{cgi}->param("action");
+
+########### Add Category  ####################################################
+if ($mode eq "add_category"){
+    if ($afap->get_visitor_info("type") eq "self"){
+	my $title=$afap->{cgi}->param("title");
+	$tmpl = HTML::Template->new(filename => "./templates/owner/add_category.tmpl");
+	$tmpl->param(
+	    EDIT => "1",
+	    TITLE => $title,
+	    USER => $afap->get_visitor_info("nickname"),
+	);
+    }else{
+	$bb->errorExit('<AF_M text="Access denied">');
+    }
+########### Confirm Category  ####################################################
+}elsif ($mode eq "confirm_category"){
+    if ($afap->get_visitor_info("type") eq "self"){
+	my $title = $afap->{cgi}->param("title");
+	$tmpl = HTML::Template->new(filename => "./templates/owner/add_category.tmpl");
+	$tmpl->param(
+	    CONFIRM => "1",
+	    TITLE => $title,
+	    USER => $afap->get_visitor_info("nickname"),
+	);
+    }else{
+	$bb->errorExit('<AF_M text="Access denied">');
+    }
+
+########### Submit Category  ####################################################
+}elsif ($mode eq "submit_category"){
+    if ($afap->get_visitor_info("type") eq "self"){
+	my $title = $afap->{cgi}->param("title");
+	my $user = $afap->get_visitor_info("nickname");
+	my $afid = $afap->get_visitor_info("afid");
+	#insert entry to DB
+
+	$bb->addCategory($title, $user, $afid);
+#	my $ret = $bb->getNewestCategoryId;
+
+	$tmpl = HTML::Template->new(filename => "./templates/owner/add_category.tmpl");
+	$tmpl->param(
+	    SUBMIT => "1",
+#	    ID => $ret->{e_id},
+	);
+    }else{
+	$bb->errorExit('<AF_M text="Access denied">');
+    }
+
+########### Category List ####################################################
+}elsif ($mode eq "list_category"){
+    $tmpl = HTML::Template->new(filename => "./templates/owner/list_category.tmpl");
+    $tmpl->param(access_control_URL => $afap->get_URL("access_control"));
+    my @entries_param;
+    my @entries;
+    @entries = $bb->getAllCategories;
+    $tmpl->param(has_category => '0');
+    if (@entries > 0 ){
+	$tmpl->param(has_category=>'1');
+	foreach(@entries) {
+	    push @entries_param,
+	    {
+		TITLE	=>	$_->{title},
+		ID	=>	$_->{category_id},
+	    };
+	}
+	$tmpl->param(ENTRIES => \@entries_param);
+    }
+}elsif ($mode eq "spam"){
+########### Prevent a SPAM comment ####################################################
+    $tmpl = HTML::Template->new(filename => "./templates/owner/spam.tmpl");
+    $tmpl->param(access_control_URL => $afap->get_URL("access_control"));
+
+    if ($action eq "add_spam_key"){
+	my $spam_key = $afap->{cgi}->param("spam_key");
+	$bb->addSpamkey($spam_key) if ($spam_key ne "");
+    }elsif ($action eq "remove_spam_key"){
+	my $spam_id = $afap->{cgi}->param("spam_keys");
+	$bb->removeSpamkey($spam_id);
+    }
+    my @key_list;
+    my @spam_keys;
+    @spam_keys = $bb->getAllSpamkeys;
+    $tmpl->param(HAS_KEY => '0');
+    if (@spam_keys > 0 ){
+	$tmpl->param(HAS_KEY=>'1');
+	foreach(@spam_keys) {
+	    push @key_list,
+	    {
+		S_ID => $_->{spam_id},
+		KEYWORD	=>	$_->{keyword},
+	    };
+	}
+	$tmpl->param(KEY_LIST => \@key_list);
+    }
+
+##############################################
+# Default (Owner mode)
+##############################################
+}else{
+    $tmpl = HTML::Template->new(filename => "./templates/owner/admin_general.tmpl");
+    $tmpl->param(access_control_URL => $afap->get_URL("access_control"));
+    if ($action eq "update"){
+	my $title = $afap->{cgi}->param("title");
+	my $email = $afap->{cgi}->param("email");
+	my $max_topics = $afap->{cgi}->param("max_topics");
+	my $max_comments = $afap->{cgi}->param("max_comments");
+	my $num_topics = $afap->{cgi}->param("num_topics");
+	my $num_comments = $afap->{cgi}->param("num_comments");
+	my $max_sbjlen = $afap->{cgi}->param("max_sbjlen");
+	my $max_textlen = $afap->{cgi}->param("max_textlen");
+
+	$bb->updatePreference($title,$email,$max_topics,$max_comments,$num_topics,$num_comments,$max_sbjlen,$max_textlen);
+    }
+    my %pref = $bb->getPreference;
+
+    $tmpl->param(TITLE => $pref{"title"},
+		 EMAIL => $pref{"email"},
+		 MAX_TOPICS => $pref{"max_topics"},
+		 MAX_COMMENTS => $pref{"max_comments"},
+		 NUM_TOPICS => $pref{"num_topics"},
+		 NUM_COMMENTS => $pref{"num_comments"},
+		 MAX_SBJLEN => $pref{"max_sbjlen"},
+		 MAX_TEXTLEN => $pref{"max_textlen"},
+		);
+}
+print $bb->translate_templateL10N( $tmpl->output );
+print $afap->get_HTML_footer();
Index: affelio/apps/bb/style.css
diff -u /dev/null affelio/apps/bb/style.css:1.1
--- /dev/null	Mon Dec 19 15:46:28 2005
+++ affelio/apps/bb/style.css	Mon Dec 19 15:46:27 2005
@@ -0,0 +1,105 @@
+.afAppBbTable table {
+        border: none;
+        border-collapse: collapse;
+}
+
+
+.afAppBbTable td {
+        color: black;
+        padding: 10px 15px 10px 15px;
+        margin: 0px 0px 0px 0px;
+        background-color: #fff;
+        font-size: midium;
+        border: 1px solid #aaa;
+        text-align: left;
+        line-height: 140%;
+}
+
+.afAppBbTable th {
+        color: #66F;
+        padding: 5px 5px 5px 5px;
+        margin: 0px 0px 0px 0px;
+        font-size: x-small;
+        border: 1px solid #aaa;
+        text-align: left;
+        background-color: #fff;
+}
+
+.afAppBbTable thead {
+        color: black;
+        background-color: #bbb;
+}
+
+td.afAppBbCategory { 
+font-size: large;
+font-weight: bold;
+        background-color: #ddf;
+}
+
+td.afAppBbForum { 
+font-size: large;
+font-weight: bold;
+        background-color: #ddf;
+}
+
+td.afAppBbPageIndex { 
+        color: black;
+        padding: 5px 15px 5px 15px;
+        margin: 0px 0px 0px 0px;
+        background-color: #fff;
+        font-size: x-small;
+        border: 1px dotted #aaa;
+        text-align: left;
+}
+
+td.afAppBbTopicTitle { 
+font-size: midium;
+font-weight: bold;
+        background-color: #ddf;
+}
+
+td.afAppBbTopicHeader { 
+font-size: midium;
+border-top: none;
+border-bottom: none;
+        padding: 5px 15px 5px 15px;
+        background-color: #fff;
+}
+
+td.afAppBbTopicContent { 
+font-size: midium;
+border-top: none;
+border-bottom: 1px dashed #aaa;
+}
+
+td.afAppBbRes { 
+font-size: midium;
+border-top: none;
+border-bottom: 1px dashed #aaa;
+        padding: 10px 15px 10px 40px;
+}
+
+td.afAppBbResTitle { 
+font-size: midium;
+border-top: none;
+border-bottom: none;
+        padding: 5px 15px 5px 40px;
+        background-color: #fff090;
+}
+
+div.afAppBbEditBtn { 
+font-size: x-small;
+text-align: right;
+        padding: 0px;
+}
+
+
+td.afAppBbColor1 { 
+background-color: #ddeeff;
+ }
+
+td.afAppBbColor2 { 
+background-color: #eafaff;
+ }
+
+
Index: affelio/apps/bb/topic.cgi
diff -u /dev/null affelio/apps/bb/topic.cgi:1.1
--- /dev/null	Mon Dec 19 15:46:28 2005
+++ affelio/apps/bb/topic.cgi	Mon Dec 19 15:46:27 2005
@@ -0,0 +1,232 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2005 FishGrove Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+use strict;
+use lib("../../extlib");
+use lib("../../lib");
+use HTML::Template;
+use CGI;
+use Cwd;
+use AffelioApp;
+use bb;
+
+
+#Initialize AFAP
+our $cgi = new CGI();
+our $afap = new AffelioApp(ConfigDir => Cwd::getcwd(), cgi => $cgi);
+our $bb = new bb($afap);
+my $tmpl;
+
+# put Content-type
+print "Content-type: text/html; charset=UTF-8\n";
+print "Pragma: no-cache", "\n\n"; 
+# put HTML Header
+print $afap->get_HTML_header("Affelio BB");
+# check access
+
+unless ($afap->check_access("super")||$afap->check_access("user")) {
+    $bb->errorExit('<AF_M text="Access denied">');
+}
+
+########### Init BB  ####################################################
+my $mode = $afap->{cgi}->param("mode");
+my $action = $afap->{cgi}->param("action");
+my $f_id = $afap->{cgi}->param("f_id");
+$bb->errorExit('<AF_M text="Please specify the forum.">') if ($f_id =~ /\D/);
+my $title = $afap->{cgi}->param("title");
+my $description = $afap->{cgi}->param("description");
+my $status = $afap->{cgi}->param("status");
+my $user = $afap->{cgi}->param("user");
+my $afid = $afap->{cgi}->param("afid");
+my $pwd = $afap->{cgi}->param("pwd");
+my $pb_user = ($afap->get_visitor_info("type") eq "pb") ? "1" : "0";
+if ($pb_user eq "0"){
+	$user = $afap->get_visitor_info("nickname");
+	$afid = $afap->get_visitor_info("afid");
+}
+my $status_edit = $afap->check_access("super") ? "1" : "0";
+
+########### Add new topic  ####################################################
+if ($mode eq "add_topic"){
+	$tmpl = HTML::Template->new(filename => "./templates/topic.tmpl");
+	$tmpl->param(
+		NEW			=>	"1",
+		F_ID		=>	$f_id,
+		TITLE		=>	$title,
+		DESCRIPTION	=>	$description,
+		STATUS_EDIT	=>	$status_edit,
+		PB_USER		=>	$pb_user,
+		AFID		=>	$afid,
+		USER		=>	$user
+    );
+########### Confirm topic  ####################################################
+}elsif ($mode eq "confirm_topic"){
+	$bb->errorExit('<AF_M text="Please input a title.">') if ($title eq "");
+	$bb->errorExit('<AF_M text="Please input a description.">') if ($description eq "");
+	$bb->errorExit('<AF_M text="Please input your nickname.">') if ($user eq "");
+	$bb->checkPwd($pwd) if ($pb_user eq "1");
+	my $status_str;
+	if ($status eq "0"){
+		$status_str = '<AF_M text="Default">';
+	}elsif ($status eq "1"){
+		$status_str = '<AF_M text="Sticky">';
+	}elsif ($status eq "2"){
+		$status_str = '<AF_M text="Announcement">';
+	}    
+
+	$tmpl = HTML::Template->new(filename => "./templates/topic.tmpl");
+	$tmpl->param(
+		CONFIRM		=>	"1",
+		F_ID		=>	$f_id,
+		TITLE		=>	$title,
+		DESCRIPTION_SHOW=>	$bb->escape($description),
+		DESCRIPTION	=>	$description,
+		STATUS		=>	$status,
+		STATUS_STR	=>	$status_str,
+		STATUS_EDIT	=>	$status_edit,
+		PB_USER		=>	$pb_user,
+		AFID		=>	$afid,
+		PWD			=>	$pwd,
+		USER		=>	$user
+	);
+########### Submit topic  ####################################################
+}elsif ($mode eq "submit_topic"){
+	$bb->errorExit('<AF_M text="Please input a title.">') if ($title eq "");
+	$bb->errorExit('<AF_M text="Please input a description.">') if ($description eq "");
+	$bb->errorExit('<AF_M text="Please input your nickname.">') if ($user eq "");
+	$bb->errorExit('<AF_M text="Please input a password.">') if ($pwd eq "" && $pb_user);
+
+	my $icon="";
+	$status=0 if (!$afap->check_access("super"));
+	my $topic_id=$bb->addTopic($f_id, $title, $description, $icon,$user, $afid, $pwd, $status);
+
+	my $current_forum = $bb->getForum($f_id);
+	$bb->updateCategoryInfo($current_forum->{category_id}, $user, $afid);
+	$bb->createReplyTable($topic_id);
+
+	$tmpl = HTML::Template->new(filename => "./templates/topic.tmpl");
+	$tmpl->param(
+		DONE	=>	"1",
+		T_ID	=>	$topic_id,
+		MSG		=>	"New Topic was created.",
+	);
+
+########### Edit topic mode ####################################################
+}elsif ($mode eq "edit_topic"){
+	my $t_id = $afap->{cgi}->param("t_id");
+	$bb->errorExit('<AF_M text="Please specify the topic.">') if ($t_id =~ /\D/ || $t_id eq "");
+	$tmpl = HTML::Template->new(filename => "./templates/topic.tmpl");
+	my $topic = $bb->getTopic($t_id);
+	my $auth=0;
+	if ($action ne ""){
+		if ($afap->get_visitor_info("type") eq "self"){
+			$auth=1;
+		}else{
+			if($pb_user eq "0") {
+				if ($topic->{pwd} eq "" && $topic->{afid} eq $afid){
+					$auth=1;
+				}else{
+					$bb->errorExit('<AF_M text="Authentication error.">');
+				}
+			} elsif($topic->{pwd} ne ""){
+				if ($pb_user){
+					$bb->errorExit('<AF_M text="Please input your nickname.">') if($user eq "");
+					$bb->checkPwd($pwd);	  
+				}
+				if (crypt($pwd,$topic->{pwd}) eq $topic->{pwd}){
+					$auth=1;
+				}else{
+					$bb->errorExit('<AF_M text="Authentication error.">');
+				}
+			}
+		}
+		# Do update
+		if($action eq "do_update"){
+			$bb->updateTopic($t_id, $title, $description, $topic->{icon}, $user, $afid,  $status, $topic->{lock}) if ($auth);
+			$tmpl->param(
+				DONE => "1",
+				T_ID => $t_id,
+				MSG => "The topic was updated.",
+			);
+		# Lock/unlock topic
+		}elsif($action eq "lock"){
+			$bb->updateTopic($t_id, $topic->{title}, $topic->{description}, $topic->{icon}, $user, $afid,  $topic->{status}, abs($topic->{lock}-1)) if ($auth);
+			if ($topic->{lock}){
+				$tmpl->param(MSG=>"The topic was unlocked.");
+			}else{
+				$tmpl->param(MSG=>"The topic was locked.");
+			}
+			$tmpl->param(
+				DONE => "1",
+				T_ID => $t_id,
+			);
+		# Confirm delete topic
+		}elsif($action eq "confirm_delete"){
+			$bb->errorExit('<AF_M text="Authentication error.">') if ($afap->get_visitor_info("type") ne "self");
+			$tmpl->param(
+				CONFIRM_DELETE => "1",
+				T_ID => $t_id,
+				F_ID => $f_id,
+				MSG => "Realy?",
+			);
+		# Do delete
+		}elsif($action eq "do_delete"){
+			$bb->errorExit('<AF_M text="Authentication error.">') if ($afap->get_visitor_info("type") ne "self");
+			$bb->deleteTopic($t_id,$f_id);
+			$tmpl->param(
+				DONE => "1",
+				T_ID => $t_id,
+				MSG => "The topic was removed.",
+			);
+		}
+	# Edit topic (no action)
+	}else{
+		my $can_delete = "";
+		if ($afap->get_visitor_info("type") eq "self"){
+			$tmpl->param(PWD => "0");
+			$can_delete = 1;
+		}else{
+			if ($pb_user eq "0"){
+				if ($topic->{pwd} eq "" && $topic->{afid} eq $afid){
+					$tmpl->param(PWD => "0");
+				} else {
+					$bb->errorExit('<AF_M text="Authentication error.">');
+				}
+			}elsif($topic->{pwd} ne ""){
+				$tmpl->param(PWD => "1");
+			}
+		}
+		$topic->{description} =~ s/<br[^>]*>/\n/g;
+		$tmpl->param(
+			EDIT => "1",
+			T_ID => $t_id,
+			F_ID => $f_id,
+			USER => $topic->{user},
+			TITLE => $topic->{title},
+			DESCRIPTION => $topic->{description},
+			AFID => $topic->{afid},
+			SUPER => $afap->check_access("super"),
+			STATUS => $topic->{status},
+			CAN_DELETE => $can_delete,
+		);
+	}
+}else {
+	$bb->errorExit('<AF_M text="Error: Unknown access.">');
+}
+
+print $bb->translate_templateL10N( $tmpl->output );
+print $afap->get_HTML_footer();
Index: affelio/apps/bb/view_forum.cgi
diff -u /dev/null affelio/apps/bb/view_forum.cgi:1.1
--- /dev/null	Mon Dec 19 15:46:28 2005
+++ affelio/apps/bb/view_forum.cgi	Mon Dec 19 15:46:27 2005
@@ -0,0 +1,153 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2005 FishGrove Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+use strict;
+use lib("../../extlib");
+use lib("../../lib");
+use HTML::Template;
+use CGI;
+use Cwd;
+use AffelioApp;
+use bb;
+
+
+#Initialize AFAP
+our $cgi = new CGI();
+our $afap = new AffelioApp(ConfigDir => Cwd::getcwd(), cgi => $cgi);
+our $bb = new bb($afap);
+my $tmpl;
+
+# put Content-type
+print "Content-type: text/html; charset=UTF-8\n";
+print "Pragma: no-cache", "\n\n"; 
+# put HTML Header
+print $afap->get_HTML_header("Affelio BB");
+# check access
+unless ($afap->check_access("DF_access")) {
+	$bb->errorExit('<AF_M text="Access denied">');
+}
+
+########### Init BB ####################################################
+
+my $f_id = $afap->{cgi}->param("f_id");
+$bb->errorExit('<AF_M text="Please specify the forum.">') if ($f_id =~ /\D/);
+my $pb_user = ($afap->get_visitor_info("type") eq "pb") ? "1" : "0";
+my $afid;
+$afid = $afap->get_visitor_info("afid") if ($pb_user eq "0");
+my %pref = $bb->getPreference;
+$tmpl = HTML::Template->new(filename => "./templates/view_forum.tmpl");
+my @topic_list;
+my @topics;
+my $icon;
+my $last_user;
+my $last_afid;
+my $current_forum = $bb->getForum($f_id);
+my $category = $bb->getColumn("SELECT title FROM $bb->{category_tb} WHERE category_id=$current_forum->{category_id}");
+my $can_add="";
+my $can_edit="";
+my $opt_msg="";
+$can_add=1 if ($afap->check_access("super") || $afap->check_access("user"));  
+
+if ($pb_user eq "0"){
+	if ($current_forum->{pwd} eq "" && $current_forum->{afid} eq $afid){
+		$can_edit = 1;
+	} 
+}elsif($current_forum->{pwd} ne ""){
+	$can_edit = 1;
+}
+$can_edit=1 if ($afap->get_visitor_info("type") eq "self");
+
+########### Get Topic List ####################################################
+ @ topics = $bb->getAllTopics($f_id);
+if ($#topics+1 >= int($bb->getColumn("SELECT value FROM $bb->{pref_tb} WHERE key = 'max_topics'"))){
+	$can_add = "";
+	$opt_msg = '<AF_M text="This forum was cloesd. Please make a new forum.">';
+}
+
+########### Get current time ####################################################
+my ($sec, $min, $hour, $mday, $mon, $year) = localtime($current_forum->{timestamp});
+$mon+=1;
+$year+=1900;
+
+########### Set forum info ####################################################
+$tmpl->param(
+	PAGE_TITLE	=>	$pref{"title"},
+	F_ID		=>	$f_id,
+	CATEGORY	=>	$category,
+	FORUM_NAME	=>	$current_forum->{title},
+	FORUM_DESCRIPTION => $current_forum->{description},
+	AFID		=>	$bb->getUserURI($current_forum->{afid}),
+	MODERATOR	=>	$current_forum->{user},
+	YEAR		=>	$year,
+	MONTH		=>	$mon,
+	DAY			=>	$mday,
+	TIME		=>	sprintf("%02d:%02d", $hour, $min),
+	CAN_ADD		=>	$can_add, 
+	CAN_EDIT	=>	$can_edit,
+	OPT_MSG		=>	$opt_msg,
+	HAS_TOPIC	=>	$#topics+1
+);
+
+########### Set Topic List ####################################################
+foreach(@topics) {
+	my $abst=$_->{description};
+	my ($sec, $min, $hour, $mday, $mon, $year) = localtime($_->{update_time});
+	$mon+=1;
+	$year+=1900;
+	if($_->{status} == 1){
+		$icon="sticky";
+	}elsif($_->{status} == 2){
+		$icon="announce";
+	}else{
+		$icon="normal";
+	}
+	if ($_->{lock} == 1){
+		$icon.="_lock";
+	}
+	$icon.=".gif";
+	if ($_->{posts}<1) {
+		$last_user=$_->{user};
+		$last_afid=$_->{afid};
+	}
+	if (length($_->{description})>50){
+		$abst = substr($_->{description},0,49)."...";
+	}
+
+	push @topic_list,
+	{
+		T_ID		=>	$_->{topic_id},
+		TITLE		=>	$_->{title},
+		ABST		=>	$abst,
+		POSTS		=>	$_->{posts},
+		USER		=>	$_->{user},
+		AFID		=>	$bb->getUserURI($_->{afid}),
+		VIEWS		=>	$_->{view},
+		YEAR		=>	$year,
+		MONTH		=>	$mon,
+		DAY			=>	$mday,
+		TIME		=>	sprintf("%02d:%02d", $hour, $min),
+		LAST_USER	=>	$_->{last_user},
+		LAST_AFID	=>	$bb->getUserURI($_->{last_afid}),
+		ICON		=>	$icon,
+	};
+}
+
+$tmpl->param(TOPIC_LIST => \@topic_list);
+
+########### Output html ####################################################
+print $bb->translate_templateL10N( $tmpl->output );
+print $afap->get_HTML_footer();
Index: affelio/apps/bb/view_topic.cgi
diff -u /dev/null affelio/apps/bb/view_topic.cgi:1.1
--- /dev/null	Mon Dec 19 15:46:28 2005
+++ affelio/apps/bb/view_topic.cgi	Mon Dec 19 15:46:27 2005
@@ -0,0 +1,199 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2005 FishGrove Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+use strict;
+use lib("../../extlib");
+use lib("../../lib");
+use HTML::Template;
+use CGI;
+use Cwd;
+use AffelioApp;
+use bb;
+
+
+#Initialize AFAP
+our $cgi = new CGI();
+our $afap = new AffelioApp(ConfigDir => Cwd::getcwd(), cgi => $cgi);
+our $bb = new bb($afap);
+my $tmpl;
+
+# put Content-type
+print "Content-type: text/html; charset=UTF-8\n";
+print "Pragma: no-cache", "\n\n"; 
+# put HTML Header
+print $afap->get_HTML_header("Affelio BB");
+# check access
+unless ($afap->check_access("DF_access")) {
+    $bb->errorExit('<AF_M text="Access denied">');
+}
+
+########### Init BB ####################################################
+my $t_id = $afap->{cgi}->param("t_id");
+$bb->errorExit('<AF_M text="Please specify the topic.">') if ($t_id =~ /\D/ || $t_id=="");
+my $page = $afap->{cgi}->param("page");
+$bb->errorExit('<AF_M text="Please specify the page correctly.">') if ($page =~ /\D/);
+$page=0 if ($page eq "");
+my $comment = $afap->{cgi}->param("comment");
+my $pb_user = ($afap->get_visitor_info("type") eq "pb") ? "1" : "0";
+my $user_name = $afap->{cgi}->param("user_name");
+my $afid = $afap->{cgi}->param("afid");
+if ($pb_user eq "0"){
+    $user_name = $afap->get_visitor_info("nickname");
+    $afid = $afap->get_visitor_info("afid");
+}
+my %pref = $bb->getPreference;
+my @reply_list;
+my @replies;
+$bb->errorExit('<AF_M text="The topic was not found.">') if (!(my $current_topic = $bb->getTopic($t_id)));
+my $current_forum = $bb->getForum($current_topic->{forum_id});
+my $current_category = $bb->getCategory($current_forum->{category_id});
+my $can_reply="";
+my $opt_msg="";
+$bb->addViewCountTopic($t_id);
+$tmpl = HTML::Template->new(filename => "./templates/view_topic.tmpl");
+
+########### Can you reply to this topic?  ####################################################
+$can_reply="1" if ($afap->check_access("super") || $afap->check_access("user"));  
+if ($current_topic->{lock}) {
+	$can_reply = "";
+	$opt_msg = '<AF_M text="This topic is locked.">';
+}
+
+########### Can you edit this topic?  ####################################################
+my $can_edit="";
+if ($pb_user eq "0"){
+	if ($current_topic->{pwd} eq "" && $current_topic->{afid} eq $afid){
+	$can_edit = 1;
+	} 
+}elsif($current_topic->{pwd} ne ""){
+    $can_edit = 1;
+}
+$can_edit=1 if ($afap->get_visitor_info("type") eq "self");
+
+########### Get current time  ####################################################
+my ($sec, $min, $hour, $mday, $mon, $year) = localtime($current_topic->{timestamp});
+$mon+=1;
+$year+=1900;
+
+my $rep_count = $bb->getColumn("SELECT count(reply_id) FROM reply_$t_id");
+if ($rep_count >= int($bb->getColumn("SELECT value FROM $bb->{pref_tb} WHERE key = 'max_comments'"))){
+	$can_reply = "";
+	$opt_msg = '<AF_M text="This topic was cloesd. Please make a new topic.">';
+}
+
+########### Set page index  ####################################################
+use integer;
+my @page_index;
+my $num_comments = $bb->getColumn("SELECT value FROM $bb->{pref_tb} WHERE key = 'num_comments'");
+my $i = ($rep_count)/$num_comments;
+while ($i>0){
+	unshift @page_index,
+	{
+		page => $i,
+		p_id => $i-1,
+		F_ID => $current_topic->{forum_id},
+		T_ID => $t_id,
+	};
+	$i--;
+}
+no integer;
+ @ replies = $bb->getReplies($t_id, $rep_count - $page*$num_comments, $rep_count - ($page*$num_comments+$num_comments)+1);
+
+########### Set topic info  ####################################################
+$tmpl->param(
+	PAGE_TITLE	=>	$pref{"title"},
+	CATEGORY	=>	$current_category->{title},
+	FORUM		=>	$current_forum->{title},
+	F_ID		=>	$current_topic->{forum_id},
+	T_ID		=>	$t_id,
+	TOPIC_NAME	=>	$current_topic->{title},
+	TOPIC_USER	=>	$current_topic->{user},
+	TOPIC_AFID	=>	$bb->getUserURI($current_topic->{afid}),
+	CAN_EDIT	=>	$can_edit,
+	CAN_REPLY	=>	$can_reply, 
+	PB_USER		=>	$pb_user,
+	REPLY_TITLE	=>	"RE:$current_topic->{title}",
+	USER_NAME	=>	$user_name,
+	AFID		=>	$afid,
+	COMMENT		=>	$comment,
+	OPT_MSG		=>	$opt_msg,
+	PAGE_INDEX	=>	\@page_index,
+	YEAR		=>	$year,
+	MONTH		=>	$mon,
+	DAY			=>	$mday,
+	TIME		=>	sprintf("%02d:%02d", $hour, $min),
+	HAS_REPLY	=>	$#replies+1,
+	TOPIC_DESCRIPTION => $current_topic->{description},
+);
+
+########### Set comments ####################################################
+foreach(@replies) {
+	my $can_edit="";
+	my ($sec, $min, $hour, $mday, $mon, $year) = localtime($_->{timestamp});
+	$mon+=1;
+	$year+=1900;
+	if ($pb_user eq "0"){
+		if ($_->{pwd} eq "" && $_->{afid} eq $afid){
+			$can_edit = 1;
+		} 
+	}elsif($_->{pwd} ne ""){
+		$can_edit = 1;
+	}
+	$can_edit=1 if ($afap->get_visitor_info("type") eq "self");
+	$can_edit="" if ($_->{title} eq "" && $_->{user} eq "" && $_->{afid} eq "");
+	my $uri = $bb->getUserURI($_->{afid}) unless ($_->{afid} eq "");
+
+	push @reply_list,
+	{
+		T_ID	=>	$t_id,
+		R_ID	=>	$_->{reply_id},
+		TITLE	=>	$_->{title},
+		USER	=>	$_->{user},
+		AFID	=>	$uri,
+		COMMENT	=>	$_->{comment},
+		YEAR	=>	$year,
+		MONTH	=>	$mon,
+		DAY		=>	$mday,
+		TIME	=>	sprintf("%02d:%02d", $hour, $min),
+		CAN_EDIT=>	$can_edit,
+		ICON	=>	$_->{icon},
+	};
+}
+$tmpl->param(REPLY_LIST => \@reply_list);
+
+########### Set face icons ####################################################
+if ($can_reply){
+	my @face_list;
+	my $face_dir = './resource/face';
+	opendir DIR, "$face_dir";
+	my @faces  = grep(!/^\.+/, readdir DIR);
+	close DIR;
+    
+	foreach (@faces){
+		unless ($_ eq "owner.gif"){
+			push @face_list,
+			{
+				FACE => $_
+			};
+		}
+	}
+	$tmpl->param(FACE_LIST => \@face_list);
+}
+
+########### Output html ####################################################
+print $bb->translate_templateL10N( $tmpl->output );
+print $afap->get_HTML_footer();


Affelio-cvs メーリングリストの案内
Back to archive index