summaryrefslogtreecommitdiff
path: root/cgi-bin
diff options
context:
space:
mode:
authorJules Laplace <carbon@melanarchy.org>2013-08-02 17:14:41 -0500
committerJules Laplace <carbon@melanarchy.org>2013-08-02 17:14:41 -0500
commite9192b3d42660a5781101df4357d276318151e8a (patch)
tree059eb6ace6147cf9559af74ed1ab5e221c80e280 /cgi-bin
parent79670053c7247d3a49b607960efd284e93f057e5 (diff)
cgi-bin & lib
Diffstat (limited to 'cgi-bin')
l---------cgi-bin/21
-rwxr-xr-xcgi-bin/adminz207
-rwxr-xr-xcgi-bin/bless23
-rwxr-xr-xcgi-bin/category290
-rwxr-xr-xcgi-bin/comment186
-rwxr-xr-xcgi-bin/details275
-rwxr-xr-xcgi-bin/import286
-rwxr-xr-xcgi-bin/inbox125
-rwxr-xr-xcgi-bin/index293
-rwxr-xr-xcgi-bin/invite123
-rw-r--r--cgi-bin/localbucky.pm70
-rw-r--r--cgi-bin/localbucky.pm.tmpl54
-rwxr-xr-xcgi-bin/login86
-rwxr-xr-xcgi-bin/logout12
-rwxr-xr-xcgi-bin/maintain289
-rwxr-xr-xcgi-bin/message149
-rwxr-xr-xcgi-bin/murder23
-rwxr-xr-xcgi-bin/playlist81
-rwxr-xr-xcgi-bin/post267
-rwxr-xr-xcgi-bin/profile167
-rwxr-xr-xcgi-bin/recipe148
-rwxr-xr-xcgi-bin/services_f83
-rwxr-xr-xcgi-bin/services_k62
-rwxr-xr-xcgi-bin/services_th54
-rw-r--r--cgi-bin/settings24
-rwxr-xr-xcgi-bin/tag290
-rwxr-xr-xcgi-bin/users228
27 files changed, 3896 insertions, 0 deletions
diff --git a/cgi-bin/2 b/cgi-bin/2
new file mode 120000
index 0000000..1c9ed49
--- /dev/null
+++ b/cgi-bin/2
@@ -0,0 +1 @@
+/var/www/vhosts/carbonpictures.com/bucky2/cgi-bin/ \ No newline at end of file
diff --git a/cgi-bin/adminz b/cgi-bin/adminz
new file mode 100755
index 0000000..4a71e38
--- /dev/null
+++ b/cgi-bin/adminz
@@ -0,0 +1,207 @@
+#!/usr/bin/perl
+#########################################
+# administration of threads, keywords,
+# privacy, etc.
+
+use localbucky;
+
+our $id;
+our $files;
+
+$dbh = DBI->connect ($dsn);
+
+our ($USER, $lastlog) = checkin();
+logout() unless ($USER != -1);
+
+if ($USER->{ulevel} != 3)
+ { redirect("/"); }
+else
+ {
+ header( { title => "bucky administrauma", color => "red" } );
+ menu();
+ if (exists($input->{c}))
+ {
+ if ($input->{c} eq "s")
+ {
+ update_thread_title($id, $input->{title});
+ $t->{title} = $input->{title};
+ print "Changed thread $id title to: <b>$t->{title}</b><br>\n";
+ }
+ elsif ($input->{c} eq "pass")
+ {
+ do_password_reset();
+ }
+ elsif ($input->{c} eq "p")
+ {
+ if ($input->{private} == 1)
+ {
+ print "Thread is now <b>private</b>.<br>";
+ switch_thread_privacy($id, 1);
+ $t->{allowed} = update_whitelist();
+ $t->{private} = 1;
+ }
+ else
+ {
+ print "Thread is now <b>public</b>.<br>";
+ switch_thread_privacy($id, 0);
+ $t->{private} = 0;
+ }
+ }
+ elsif ($input->{c} eq "f")
+ {
+ my @flagged = corral($input, "file");
+ if ($DEBUG)
+ {
+ print "<br>\nfiles flagged: ";
+ foreach (@flagged)
+ { print; print " "; }
+ print "<br>\n";
+ }
+ if ($input->{verb} eq "flag")
+ {
+ print "Flagged file $flagged[0]<br>";
+ update_flagged($id, $flagged[0]);
+ $t->{flagged} = $flagged[0];
+ admin_form($id, $t, $files, $k);
+ }
+ elsif ($input->{verb} eq "move")
+ {
+ print "When this works it will be like this:!<br>\n";
+ print "Where do you want to move these files here<br>\n";
+ print "Moving files...<br>\n";
+ # system("mv", $data_path/$oldpid/$filenamea ..., "$data_path/$newpid/");
+ print "Moving ids...<br>\n";
+ print "Recalculating thread sizes...<br>\n";
+ }
+ elsif ($input->{verb} eq "rm")
+ {
+ if (!$input->{ok})
+ {
+ print qq!<center><p><div class="bluebox" style="width: 320px; padding: 10px;"><big><b>Are you sure you want to delete these files?</b></big><hr noshade color="$BUCKY_COLOR_HR"><p>\n!;
+ print qq!<form action="$BUCKY/maintain" method="post" enctype="multipart/form-data">!;
+ print qq{<input type=hidden name="c" value="f">\n};
+ print qq{<input type=hidden name="id" value="$id">\n};
+ print qq{<input type=hidden name="debug" value="1">\n} if ($DEBUG);
+ print qq{<input type=hidden name="verb" value="rm">\n};
+ print qq{<input type=hidden name="ok" value="1">\n};
+
+ my $i = 0;
+ my $fid = shift(@flagged);
+ foreach my $fh (sort_by_id(@$files))
+ {
+ next if ($fid != $$fh{id});
+ $i++;
+ print qq{<input type=hidden name="file$i" value="$fid">\n};
+ print $$fh{filename}."<br>\n";
+ $fid = shift(@flagged);
+ }
+
+ print qq{<br><input type="submit" value="YES YES DELETE THE FILES" class="clicky"></form></div></center>};
+ }
+ else
+ {
+ my $i = 0;
+ my $fid = shift(@flagged);
+ foreach my $fh (sort_by_id(@$files))
+ {
+ next if ($fid != $$fh{id});
+ $i++;
+ delete_file_record($fid);
+ system("rm", "-f", qq!$data_path/$id/$$fh{filename}!);
+ print qq!deleted $$fh{filename}<br>\n!;
+ $fid = shift(@flagged);
+ }
+
+ print "Recalculating thread size...<br>\n";
+ update_thread_size($id);
+ $files = get_files($id);
+ }
+ }
+ }
+ adminster_form();
+ }
+ else
+ {
+ adminster_form();
+ }
+ footer();
+ }
+
+sub sort_by_username { sort { lc($a->{username}) cmp lc($b->{username}) } @_; }
+sub sort_by_id { sort { $a->{id} <=> $b->{id} } @_; }
+
+sub adminster_form
+ {
+ print qq{<table width="100%" cellpadding=0 cellspacing=0 border=0><tr><td align=left valign=top>\n\n};
+
+# my $reqs = get_user_requests();
+# if ($reqs != -1)
+# {
+# my $s = (@$reqs != 1) ? "s" : "";
+# alert_box("$BUCKY/approve", @$reqs." account request$s pending!");
+# }
+
+ print <<end;
+<div class="message" style="float: right;">
+<b>password reset form</b>
+<hr color="$BUCKY_COLOR_HR">
+end
+ password_reset_form();
+ print "</div>";
+
+# "flush" zips button
+# recalculcate thread sizes
+# links to approval etc (alert!)
+ print qq{</td></tr></table>\n\n};
+ }
+
+sub password_reset_form
+ {
+ my $users = get_all_users();
+
+ print qq!<form action="$BUCKY/adminz" method="post" enctype="multipart/form-data">!;
+ print qq{<input type=hidden name="c" value="pass">\n};
+ print qq{<input type=hidden name="debug" value="1">\n} if ($DEBUG);
+ print qq!<table cellpadding=2 cellspacing=0 border=0>!;
+ print qq!<tr><td align="right">user:</td><td align="left">!;
+ print qq!<select name="user">!;
+ foreach $c (sort_by_username(@$users))
+ {
+ print qq!<option value="$c->{username}"!;
+ print qq!>$c->{username}</option>!;
+ }
+ print qq!</select>\n!;
+ print <<pws;
+</td></tr>
+<tr><td align="right">
+password?<br>
+</td><td align="left">
+<input type="password" name="pw1" value="" size=13 maxlength=20><br>
+</td></tr>
+<tr><td align="right" valign="top">
+<small>again!</small>
+</td><td align="left">
+<input type="password" name="pw2" value="" size=13 maxlength=20><br>
+<input type="submit" value="RESET PASSWORD" class="clicky">
+</td></tr>
+</table>
+pws
+ print qq!</form>\n!;
+ }
+
+sub do_password_reset
+ {
+ if (exists($input->{pw1}) && exists($input->{pw2}) && $input->{pw1} && $input->{pw2})
+ {
+ if ($input->{pw1} eq $input->{pw2})
+ {
+ update_password($input->{user}, crypt($input->{pw1},lc($input->{user})));
+ print qq(password changed for $input->{user}<br>\n);
+ }
+ else
+ {
+ print "passwords don't match!<br>\n";
+ }
+ }
+ }
+
diff --git a/cgi-bin/bless b/cgi-bin/bless
new file mode 100755
index 0000000..0773fe7
--- /dev/null
+++ b/cgi-bin/bless
@@ -0,0 +1,23 @@
+#!/usr/bin/perl
+#########################################
+# bless
+#########################################
+
+use localbucky;
+
+$dbh = DBI->connect ($dsn);
+
+our ($USER, $lastlog) = checkin();
+logout() unless ($USER != -1);
+
+our $blessy = $input->{username};
+if (get_uid($blessy) == -1)
+ { error("no such user $blessy"); }
+elsif ($blessy eq $USER->{username})
+ { error("you fucking egomaniac"); }
+commit_blessing($blessy);
+new_message("$blessy.inbox", {sender => "$USER->{username}", recipient => "$blessy", unread => 1, subject => "You look radiant.", body => "You feel a slight prickling along your nape."});
+redirect("$BUCKY/index");
+
+$dbh->disconnect ();
+
diff --git a/cgi-bin/category b/cgi-bin/category
new file mode 100755
index 0000000..94ee934
--- /dev/null
+++ b/cgi-bin/category
@@ -0,0 +1,290 @@
+#!/usr/bin/perl
+#########################################
+# index
+# - do all index stuff, also deal with keyword admin
+#########################################
+
+use localbucky;
+
+$dbh = DBI->connect ($dsn);
+
+our ($USER, $lastlog) = checkin();
+
+my $k;
+my $tag;
+
+# check name of the calling script: index, tag, keyword
+$input->{script} ||= $input->{script_from_uri} if defined($input->{script_from_uri});
+
+# load the tag or keyword into the input params, if they don't exit already
+if ( $input->{script} eq $BUCKY_LEXICON_TAG )
+ {
+ $input->{tag} ||= $input->{object_from_uri} if defined($input->{object_from_uri});
+ }
+elsif ( $input->{script} eq $BUCKY_LEXICON_KEYWORD )
+ {
+ $input->{keyword} ||= $input->{object_from_uri} if defined($input->{object_from_uri});
+ }
+
+# Get keyword
+if (exists($input->{keyword}) && $input->{keyword} ne "new" && $input->{keyword} ne "unsorted")
+ {
+ $k = get_keyword($input->{keyword});
+ }
+
+
+# Create New Keyword? FORM
+if (exists($input->{keyword}) && $input->{keyword} eq "new")
+ {
+ my $t;
+ header("add new category");
+ if (exists($input->{thread}))
+ {
+ $t = get_thread($input->{thread});
+ }
+ menu();
+ print "<br><br>";
+ my %faek =
+ (
+ keyword => $input->{keyword},
+ thread => $input->{thread}
+ );
+ keyword_form($input->{keyword}, \%faek, $t);
+ footer();
+ }
+
+# Edit settings for keyword
+elsif ($input->{c} eq "edit" && (check_op($k) || $USER->{ulevel} == 3))
+ {
+ header(
+ {
+ title => "settings for category '$input->{keyword}'",
+ sticky => $input->{keyword}
+ } );
+ # 20070903 - marc - new menu args calling style
+ my $menu_args;
+ $menu_args->{keywords} = $k if $k;
+ menu( $menu_args );
+# menu($k);
+ print "<br><br>";
+
+ keyword_form($k->{keyword}, $k);
+
+ print qq!<center><table border=0 cellpadding=0 cellspacing=0 class="threadmain" width="580">!;
+ my $threads = get_threads_by_keyword($k->{keyword});
+ thread_box({ threads => $threads, kw => $k });
+
+ print qq!</table>!;
+ footer();
+ }
+
+# Create new keyword? Process form results
+elsif ($input->{c} eq "create")
+ {
+ if (!defined($input->{keyword}))
+ { error("no keyword specified!"); }
+ if (get_keyword($input->{keyword}) != -1)
+ { error("keyword already exists!"); }
+ my %nk =
+ (
+ keyword => $input->{keyword},
+ threads => " $input->{thread} ",
+ owner => $USER->{username},
+ public => $input->{public},
+ agglutinate => $input->{agglutinate},
+ color => $input->{color},
+ ops => (make_whitelist())
+ );
+ if ($DEBUG)
+ {
+ header("Creating keyword $input->{keyword}");
+ menu();
+ foreach my $ky (keys %nk)
+ { print "$ky => $nk{$ky}<br>\n"; }
+ }
+ add_keyword(\%nk);
+ update_thread_keyword($input->{thread}, $input->{keyword});
+ redirect("$BUCKY/$BUCKY_LEXICON_KEYWORD/$input->{keyword}");
+ }
+
+# Edit settings for keyword? Process form results
+elsif ($input->{c} eq "update")
+ {
+ if (!defined($input->{keyword}))
+ { error("no keyword specified!"); }
+ my %nk =
+ (
+ threads => " $input->{thread} ",
+ public => (exists($input->{public}) ? 1 : 0),
+ agglutinate => (exists($input->{agglutinate})) ? $input->{agglutinate} : 0,
+ color => $input->{color}
+ );
+ if (!exists($input->{public}))
+ {
+ $nk{ops} = make_whitelist();
+ }
+ if ($DEBUG)
+ {
+ header("Updating keyword $input->{keyword}");
+ menu();
+ foreach my $ky (keys %nk)
+ { print "$ky => $nk{$ky}<br>\n"; }
+ }
+ update_keyword($input->{keyword}, \%nk);
+ redirect("$BUCKY/$BUCKY_LEXICON_KEYWORD/$input->{keyword}");
+ }
+
+# Assign keyword processing form action
+elsif ($input->{c} eq "assign")
+ {
+ keyword_assign_mechanism($input->{keyword}, $input->{thread}, $k);
+ redirect("$BUCKY/maintain/$input->{thread}");
+ # redirect("$BUCKY/index?keyword=$input->{keyword}");
+ }
+
+# Detach keyword action
+elsif ($input->{c} eq "detach")
+ {
+ my $t;
+
+ if (!defined($input->{thread}))
+ { error("no post specified!"); }
+ $t = get_thread($input->{thread});
+ $k = get_keyword($t->{keyword});
+
+ my %nk = ( threads => delete_key($k->{threads}, $input->{thread}) );
+
+ if ($DEBUG)
+ {
+ header("Detaching post from $t->{keyword}");
+ menu();
+ foreach my $ky (keys %nk)
+ { print "$ky => $nk{$ky}<br>\n"; }
+ print "keyword ==> $t->{keyword}<br>\n";
+ print "detaching <b>$t->{title}</b> from <b>$t->{keyword}</b><br>\n";
+ }
+ update_keyword($t->{keyword}, \%nk);
+ update_thread_keyword($t->{id}, "NULL");
+ redirect("$BUCKY/maintain/$t->{id}");
+ }
+
+# Display main index page
+else
+ {
+ my $tag = exists($input->{tag}) ? $input->{tag} : undef;
+ my $keyword = exists($input->{keyword}) ? $input->{keyword} : "all";
+ my $limit = exists($input->{limit}) ? int($input->{limit}) : 40;
+ my $date = exists($input->{start}) ? int($input->{start}) : "now";
+
+ header({ title => get_random_line("titles"), sticky => $input->{keyword} });
+ my $keywords = get_keywords();
+ my $tags = get_tags();
+
+ my $menu_args;
+ $menu_args->{keywords} = $keywords->{$keyword} if $keywords->{$keyword};
+ menu( $menu_args );
+
+ print qq(<table width="100%" cellpadding=0 cellspacing=0 border=0>);
+ print qq(<tr>);
+#############################
+# KEYWORD LIST
+ print qq(<td align=center valign=top width="100">\n);
+ print qq(<div class="bluebox"><span style="line-height: 1.5em;"><nobr>);
+ my $p = ''; my $l = '';
+ my $with_letter = 0;
+ my $s = '';
+my $pre = '';
+ my $start = '';
+ foreach my $k (sort { lc($a) cmp lc($b) } keys %$keywords)
+ {
+ my $style;
+ $l = substr($k,0,1);
+ $start ||= $l;
+ if ($p && lc($l) ne lc($p))
+ {
+ if ($with_letter > 3)
+ {
+ print qq(<big><big><b>$start - $pre</b></big></big><br> );
+ print $s;
+ print qq(</nobr></span></div>);
+ print qq(<div class="bluebox"><span style="line-height: 1.5em;"><nobr>);
+ $s = '';
+ $with_letter = 1;
+ $p='';
+ $start = $l;
+ }
+ }
+ $with_letter += 1;
+ $p||=$l;
+ $pre=$l;
+ $s .= qq(<a style="$css" href="$BUCKY/category/$k">$k</a><br>);
+ }
+if ($s)
+ {
+ print qq(<big><big><b>$start - $pre</b></big></big><br> );
+ print $s;
+ print qq(</div>);
+ print qq(<div class="bluebox"><small><span style="line-height: 1.5em;"><nobr>);
+ }
+ print qq(</div>);
+ print qq(<div class="bluebox"><small><span style="line-height: 1.5em;"><nobr>);
+ print qq(.: <a href="$BUCKY/category/unsorted"><i>unsorted</i></a> :.<br>);
+ print qq(</nobr></span></small></div></td>\n);
+
+ print qq(<td width="300" align=right valign=top>\n);
+
+ alerts();
+ if ($USER == -1)
+ {
+ bPod_box();
+ }
+ else
+ {
+ welcome_box(); # if (check_key($USER->{boxes}, "welcome"));
+ search_box();
+ bPod_box() if (check_key($USER->{boxes}, "bPod"));
+ radio_box() if (check_key($USER->{boxes}, "radio"));
+ upload_form($keyword) if (check_key($USER->{boxes}, "postform"));
+ hoot_box() if (check_key($USER->{boxes}, "hootbox"));
+ }
+ print qq(</td>\n);
+ print qq(<td align=left valign=top>\n);
+
+ if (check_key($USER->{boxes}, "photostream") || ($USER == -1) )
+ {
+ if ( $keyword ne "all" )
+ { photostream({ keyword => $keyword, vertical => 0, count => 4 }); }
+ elsif ( $tag )
+ { photostream({ tag => $tag, vertical => 0, count => 4 }); }
+ else
+ { photostream({ user => 1, vertical => 0, count => 4 }); }
+ }
+
+ print qq(<center><table border=0 cellpadding=0 cellspacing=0 class="threadmain" width="580">);
+
+ if ($keyword ne "all")
+ {
+ my $threads = throttle_threads({ keyword => $keyword, newest => $date });
+ thread_box({ threads => $threads, kw => $keywords->{$keyword} });
+ }
+ elsif ($tag)
+ {
+ my $threads = throttle_threads({ tag => $tag, newest => $date });
+ thread_box({ threads => $threads, tag => $tags->{$tag}, sort_by => "name" });
+ }
+ else
+ {
+ alpha_index($keywords, $limit, $date);
+ }
+
+ print qq(</table>);
+ print qq(</td></tr>);
+
+ print qq(</table>\n\n);
+
+ footer();
+ }
+
+$dbh->disconnect ();
+
+print "Index: " . &report_time() . "\n" if $timer;
diff --git a/cgi-bin/comment b/cgi-bin/comment
new file mode 100755
index 0000000..01a763b
--- /dev/null
+++ b/cgi-bin/comment
@@ -0,0 +1,186 @@
+#!/usr/bin/perl
+#########################################
+# comment
+# redundant w/ post: add a comment/files to a thread
+#########################################
+
+use localbucky;
+
+my $pid;
+
+$dbh = DBI->connect ($dsn);
+
+our ($USER, $lastlog) = checkin();
+logout() unless ($USER != -1);
+
+$input->{id} ||= $input->{object_from_uri} if defined($input->{object_from_uri});
+$input->{id} =~ s/\D*//g;
+if ($input->{c} eq "edit")
+ {
+ my $header_args;
+ my $comment = get_comment($input->{id});
+ error("No such comment!") if ($comment == -1);
+ my $thread = get_thread($comment->{thread});
+ my $keyword = get_keyword($thread->{keyword});
+ error("Cannot edit comment!") unless ($USER->{username} eq $BUCKY_ADMINISTRATOR || $USER->{username} eq $comment->{username} || (check_key($thread->{display}, "editable") && check_privacy($thread, $keyword)));
+
+ $header_args->{title} = qq(editing comment . . .);
+ $header_args->{subtitle} = qq(<span class="lite"><a href="$BUCKY/).details_link($thread).qq(/$comment->{thread}">back to post</a> &middot; $thread->{title}</span>),
+ $header_args->{color} = "ivory";
+
+ header ($header_args);
+ menu();
+ print <<duh;
+<table width=100% border=0 cellpadding=0 cellspacing=5>
+<tr><td align=center valign=top width=100%><div style="width: 399px;">
+duh
+ curt_post_form($comment);
+ print qq!</td></tr></table>\n!;
+ footer();
+ }
+elsif ($input->{c} eq "delete")
+ {
+ my $header_args;
+ my $comment = get_comment($input->{id});
+ error("No such comment!") if ($comment == -1);
+ my $thread = get_thread($comment->{thread});
+ my $keyword = get_keyword($thread->{keyword});
+ error("Cannot delete comment!") unless ($USER->{username} eq $BUCKY_ADMINISTRATOR || $USER->{username} eq $comment->{username} || (check_key($thread->{display}, "editable") && check_privacy($thread, $keyword)));
+
+ if ($input->{ok} eq "yes")
+ {
+ delete_comment($comment->{id});
+ redirect("$BUCKY/".details_link($thread)."/$comment->{thread}".get_revision($thread));
+ }
+ else
+ {
+ $header_args->{title} = qq(delete comment?);
+ $header_args->{subtitle} = qq(<span class="lite"><a href="$BUCKY/).details_link($thread).qq(/$comment->{thread}">back to post</a> ($thread->{title})</span>);
+ $header_args->{color} = "ivory";
+
+ header ($header_args);
+ menu();
+ print qq!<center><p><div class="bluebox" style="width: 320px; padding: 10px;"><big><b>Are you sure you want to !;
+ print qq!delete this comment?</b></big><hr noshade color="$BUCKY_COLOR_HR"><p>\n!;
+ my $subcomment = substr($comment->{comment}, 0, 64);
+ $subcomment =~ s/</&lt;/g;
+ $subcomment =~ s/>/&gt;/g;
+ $subcomment =~ s/"/&quot;/g;
+ print "<p>".$subcomment."</p>";
+ print qq!<form action="$BUCKY/comment" method="post" enctype="multipart/form-data">!;
+ print qq(<input type=hidden name="c" value="delete">\n);
+ print qq(<input type=hidden name="id" value="$comment->{id}">\n);
+ print qq(<input type=hidden name="debug" value="1">\n) if ($DEBUG);
+ print qq(<input type=hidden name="ok" value="yes">\n);
+
+ print qq(<br><input type="submit" value="DELETE" class="clicky"></form></div></center>);
+ print qq(</td></tr></table>\n);
+ footer();
+ }
+ }
+elsif ($input->{c} eq "reply")
+ {
+ my $header_args;
+ my $comment = -1;
+ my $thread = -1;
+ my $keyword = -1;
+ if (exists($input->{id}))
+ {
+ $comment = get_comment($input->{id});
+ error("No such comment!") if ($comment == -1);
+ $thread = get_thread($comment->{thread});
+ }
+ elsif (exists($input->{thread}))
+ {
+ $thread = get_thread($input->{thread});
+ }
+ my $keyword = get_keyword($thread->{keyword});
+ error("Cannot see comment!") unless (check_privacy($thread) || check_op($keyword));
+
+ $header_args->{title} = qq(reply to comment . . .);
+ $header_args->{subtitle} = qq(<span class="lite"><a href="$BUCKY/).details_link($thread).qq(/$comment->{thread}">back to post</a> &middot; $thread->{title}</span>);
+ $header_args->{color} = "ivory";
+
+ header ($header_args);
+ menu();
+ print <<duh;
+<table width=100% border=0 cellpadding=0 cellspacing=5>
+<tr><td align=center valign=top width=100%><div style="width: 399px;">
+duh
+ curt_reply_form($comment, $thread, $keyword);
+ print qq!</td></tr></table>\n!;
+ footer();
+ }
+elsif ($input->{c} eq "update")
+ {
+ my $comment = get_comment($input->{id});
+ error("No such comment!") if ($comment == -1);
+ my $thread = get_thread($comment->{thread});
+ my $keyword = get_keyword($thread->{keyword});
+ error("Cannot edit comment!") unless ($USER->{username} eq $BUCKY_ADMINISTRATOR || $USER->{username} eq $comment->{username} || (check_key($thread->{display}, "editable") && check_privacy($thread, $keyword)));
+ update_comment($input->{id}, $input->{comment}) if ($input->{comment});
+ touch_thread($thread);
+
+ if ($comment->{thread} == 1)
+ {
+ redirect("$BUCKY/index");
+ }
+ else
+ {
+ redirect("$BUCKY/".details_link($thread)."/$comment->{thread}".get_revision($thread));
+ }
+ }
+elsif ($input->{id} == 1)
+ {
+ add_comment($input->{id}, -1, $USER->{username}, $input->{comment}) if ($input->{comment});
+ redirect("$BUCKY/index");
+ }
+else
+ {
+ my $pid;
+ my $t;
+ my $keyword;
+ if ($DEBUG)
+ {
+ header ("adding message to $input->{id}");
+ print "adding message to $input->{id}:<p><tt>";
+ }
+
+ $t = get_thread($input->{id});
+ if ($t == -1)
+ {
+ flush_files();
+ redirect("$BUCKY/".details_link($t)."/$comment->{thread}".get_revision($t));
+ }
+ $keyword = get_keyword($thread->{keyword});
+# error("No such thread!") unless ($t != -1 && check_privacy($t, $keyword));
+
+ if (exists($input->{parent_id}))
+ {
+ my $headc = get_comment($input->{parent_id});
+ error("No such comment!") if ($headc == -1);
+ if ($headc->{parent_id} != -1)
+ { $pid = $headc->{parent_id}; }
+ else
+ { $pid = $headc->{id}; }
+ }
+ else
+ {
+ $pid = -1;
+ }
+
+ add_comment($t->{id}, $pid, $USER->{username}, $input->{comment}) if ($input->{comment});
+ situate_files($t->{id}, $USER->{username});
+ touch_thread($t);
+ redirect("$BUCKY/".details_link($t)."/$t->{id}".get_revision($t));
+ switch_file_privacy($t->{id}, $t->{private});
+ }
+
+if ($DEBUG)
+ {
+ footer ();
+ }
+
+$dbh->disconnect ();
+
+print "Comment: " . &report_time() . "\n" if $timer;
diff --git a/cgi-bin/details b/cgi-bin/details
new file mode 100755
index 0000000..35b34c7
--- /dev/null
+++ b/cgi-bin/details
@@ -0,0 +1,275 @@
+#!/usr/bin/perl
+########################################
+# details
+#########################################
+
+use localbucky;
+
+$dbh = DBI->connect ($dsn);
+
+our ($USER, $lastlog) = checkin();
+our $loggedin = ($USER != -1);
+
+our ($t, $kw, $files, $comments) = details_init();
+details_run($t, $kw, $files, $comments);
+
+sub details_init
+ {
+ $input->{id} ||= $input->{object_from_uri} if defined($input->{object_from_uri});
+ my $id = exists($input->{id}) ? $input->{id} : error("No such thread!");
+
+ my $t = get_thread($id);
+ error("No such post.") if ($t == -1);
+ my $kw = get_keyword($t->{keyword});
+
+ my $files = get_files($t->{id});
+ my $comments = get_comments ($t->{id});
+
+ if ( ! check_privacy($t, $kw) ) # || check_participation($files, $comments) )
+ #unless ( check_privacy($t, $kw) || check_participation($files, $comments) )
+ { error("No such post!"); }
+
+ # Reset NULL viewed
+ if ( ! $t->{viewed} )
+ { $t->{viewed} = 0; }
+
+ # Increment viewed for this thread
+ $t->{viewed}++;
+ # Update thread viewed count
+ update_thread_viewed( $t->{id}, $t->{viewed} );
+
+ return ($t, $kw, $files, $comments);
+ }
+
+sub details_run
+ {
+ my ($t, $kw, $files, $comments) = @_;
+ my $header_args =
+ {
+ title => $t->{title},
+ sticky => $t->{keyword},
+ color => get_color($t, $kw, $comments)
+# participation => check_participation($files, $comments)
+ };
+
+ my $age = get_age($t->{lastmodified});
+ $age .= " ago" unless $age eq "now";
+
+ $header_args->{subtitle} =
+ qq!posted by <a href="$BUCKY/profile/$t->{username}">$t->{username}</a> on ! .
+ verbosedate($t->{createdate}) . " &middot; active " . $age .
+ qq! &middot; $t->{viewed} view! . courtesy_s($t->{viewed});
+
+ if ($t->{username} eq $USER->{username} || check_op($kw) || $header_args->{participation} == 2 || $USER->{ulevel} == 3)
+ {
+ $header_args->{subtitle} .= qq! &middot; !;
+ $header_args->{subtitle} .= qq!<a href="$BUCKY/maintain/$t->{id}">options</a>!;
+ }
+# else
+# {
+# $header_args->{subtitle} .=
+# qq! &middot; <a href="$BUCKY/index">go to <b>index</b></a>!;
+# }
+
+ $header_args->{subtitle} .= qq! &middot; !;
+ $header_args->{subtitle} .= qq!<span class="lite"><a href="scp://$BUCKY_FTP_USER\@$BUCKY_FTP_HOST/var/bucky/$t->{id}">download\!</a></span>!;
+
+ my @participants = get_participants($t, $files, $comments);
+
+ $header_args->{sidetitle} = details_participation(@participants)
+ if (@participants > 0);
+ $header_args->{sidesubtitle} = "<small><i>see also:</i> ".details_tags_box($t, $kw)."</small>"
+ if (@{$t->{tags}});
+
+ header($header_args);
+
+ # 20070903 - marc - new menu args calling style
+ my $menu_args;
+ $menu_args->{keywords} = $kw if $kw;
+ $menu_args->{ftp} = 1 if ($t->{files}+$t->{comments} + 1);
+ menu( $menu_args );
+
+ details_view($t, $kw, $comments, $files);
+ footer();
+ }
+
+
+##############################
+
+sub details_view
+ {
+ my ($t, $kw, $comments, $files) = @_;
+ my ($many_jpgs, $flagged) = find_jpeg_v2($files, $t->{flagged});
+ if ($many_jpgs > 6)
+ {
+ print qq(<center><table border=0 cellpadding=0 cellspacing=0 width="100%">);
+ }
+ else
+ {
+ print qq(<center><table border=0 cellpadding=0 cellspacing=0>);
+ }
+
+ print qq(<tr><td align=right valign=top width=440>);
+ print qq(<table class="commentbox" cellpadding=0 cellspacing=0 border=0 width=440>);
+
+ if ($flagged != -1 && $many_jpgs > 1)
+ {
+ print qq(<td align=center valign=middle colspan=2>);
+ print_flagged_jpeg($flagged);
+ print qq(</td></tr>);
+ }
+
+ sideshow_comments({ thread => $t, keyword => $kw, comments => $comments });
+ print qq(<tr><td align=center valign=top colspan=2>);
+ reply_form($t->{id}, $t);
+ print qq(</td></tr>);
+ print qq(</table>);
+
+ if ($flagged != -1 && $many_jpgs == 1)
+ {
+ print qq(<td align=left valign=top colspan=2 style="padding: 10px;">);
+ print_flagged_jpeg($flagged);
+ }
+ elsif ($many_jpgs > 1 || @$files > $many_jpgs)
+ {
+ print qq(<td align=left valign=top style="padding-left: 5px;">);
+ }
+ else
+ {
+ print qq(<td align=left valign=top style="padding-left: 5px;">);
+ }
+ if ($many_jpgs > 1)
+ {
+ if ($many_jpgs < 6) # && @$files == $many_jpgs)
+ { image_column($files, $flagged, $many_jpgs); }
+ else
+ { image_gallery($files, $flagged, $many_jpgs); }
+ }
+ if (@$files > $many_jpgs)
+ {
+ if (find_mp3($files))
+ {
+ my $z_playlist = "/cgi-bin/bucky/playlist/$t->{id}";
+ my $z_autoplay = "false";
+ if (check_key($USER->{boxes}, "autoplay"))
+ { $z_autoplay = "true"; }
+ print <<__PLAYLIST__;
+ <div id='mp3player'>LOADING MP3 PLAYER ...</div>
+
+<script type="text/javascript" src="/js/swfobject1.js"></script>
+<script type="text/javascript">
+ var s2 = new SWFObject("/mediaplayer.swf", "playlist", "392", "200", "7");
+ s2.addVariable("file","$z_playlist");
+ s2.addVariable("shuffle","false");
+ s2.addVariable("backcolor","0xEEEEEE");
+ s2.addVariable("frontcolor","0x111111");
+ s2.addVariable("lightcolor","0x444444");
+ s2.addVariable("displayheight","0");
+ s2.addVariable("width","392");
+ s2.addVariable("height","200");
+ s2.addVariable("volume","50");
+ s2.addVariable("autostart","$z_autoplay");
+ s2.write("mp3player");
+</script>
+__PLAYLIST__
+ }
+ if (check_key($t->{display}, "nfl")) # no file list
+ { ; }
+ elsif (check_key($t->{display}, "ffl")) # full file list
+ {
+ file_list($files, 0, 1, 0);
+ }
+ else # "terse" file list
+ {
+ file_list($files, 0, 1, $many_jpgs);
+ }
+ }
+ if ($ZIP_BUTTON_ENABLED && @$files > 4)
+ {
+ zip_this_button($t);
+ }
+
+ details_keywords_box($t, $kw);
+ print "</td>";
+
+ print qq(</tr></table></center>);
+ }
+
+sub find_mp3
+ {
+ my ($q) = @_;
+ foreach my $f (@$q)
+ { return 1 if $f->{filename} =~ /mp3$/i; }
+ return 0;
+ }
+
+sub details_tags_box
+ {
+ my ($t, $kw) = @_;
+# my $tags = $t->{tags};
+ return tags_stringify_links ( $t );
+# return join(", ", @$tags);
+ }
+
+sub details_participation
+ {
+ my (@participants) = @_;
+ my $pcount = 0;
+ my $out;
+
+ foreach my $p (@participants)
+ {
+ $pcount++;
+ next if ($pcount > 6);
+ my $image = get_profile_image($p, $AVATAR_MED_PREFIX);
+ if ($image != -1)
+ {
+ $out .= qq(&nbsp;);
+ $out .= qq(<a href="$BUCKY/profile/$p">);
+ $out .= qq(<img src="$image" width="$AVATAR_MED_WIDTH" height="$AVATAR_MED_WIDTH" border=1">);
+ $out .= qq(</a>);
+ }
+ }
+ if ($pcount > 6)
+ {
+ $out .= "<small>&nbsp;+&nbsp;".($pcount - 4);
+ $out .= "&nbsp;$BUCKY_DUDER_NOUN";
+ $out .= courtesy_s($pcount - 4);
+ $out .= "</small>";
+ }
+ return $out;
+ }
+
+# get list of unique users posting in thread
+sub get_participants
+ {
+ my ($t, $files, $comments) = @_;
+ my %participant;
+ $participant{$t->{username}} = 1000;
+
+ foreach my $f (@$files)
+ { $participant{$f->{username}}++; }
+ foreach my $c (keys %$comments)
+ { $participant{$comments->{$c}->{username}}++; }
+
+ return (sort { $participant{$b} <=> $participant{$a} } (keys(%participant)));
+ }
+
+sub details_keywords_box
+ {
+ my ($t, $kw) = @_;
+ if (defined($t->{keyword}) && !check_key($t->{display}, "kws"))
+ {
+ my $t = get_threads_by_keyword($t->{keyword});
+ if ($t != -1)
+ {
+ print qq(<table border=0 cellpadding=0 cellspacing=0 class="threadmain" width="$width">);
+ thread_box({ threads => $t, kw => $kw });
+ print qq(</table>);
+ }
+ }
+ }
+
+##############################
+
+print "Details: " . &report_time() . "\n" if $timer;
diff --git a/cgi-bin/import b/cgi-bin/import
new file mode 100755
index 0000000..fc7add5
--- /dev/null
+++ b/cgi-bin/import
@@ -0,0 +1,286 @@
+#!/usr/bin/perl
+#########################################
+# import
+# escorts ftp'd files into the database
+#########################################
+
+use localbucky;
+
+my $pid;
+
+$dbh = DBI->connect ($dsn);
+
+our ($USER, $lastlog) = checkin();
+logout() unless ($USER != -1);
+
+if ($input->{c} eq "n")
+ {
+ my $valid = 0;
+ my $thread_id = 0;
+ if ($DEBUG)
+ {
+ header("importing files...");
+ foreach $k (sort keys %$input) { print "$k => ".$input->{$k}."<br>"; }
+ }
+ foreach my $k (keys %$input)
+ {
+ if ($k =~ /^import/)
+ { $valid = 1; last; }
+ }
+ if ($valid)
+ {
+ if ($input->{id} && $input->{id} ne "new")
+ {
+ $thread = get_thread($input->{id});
+ $keyword = get_keyword($thread->{keyword});
+ if ($thread != -1 && check_privacy($thread, $keyword))
+ {
+ $thread_id = $thread->{id};
+ touch_thread($thread);
+ }
+ else
+ {
+ error("cannot import into specified thread");
+ }
+ }
+ else
+ {
+ if ($input->{title} eq undef || $input->{title} =~ /^\s+$/)
+ {
+ error ("No thread title!");
+ }
+ else
+ {
+ $thread_id = add_thread($input->{title}, $USER->{username}, 0);
+ }
+ }
+ print "thread_id => $thread_id<br>" if ($DEBUG);
+ add_comment($thread_id,-1,$USER->{username},$input->{comment}) if ($input->{comment} ne undef);
+ situate_imports($thread_id, $USER->{username});
+ if (exists($input->{keyword}))
+ {
+ my $k = get_keyword($input->{keyword});
+ if ($k->{public} || check_op($k))
+ {
+ keyword_assign_mechanism($input->{keyword}, $thread_id, $k);
+ }
+ }
+ }
+ else
+ { error("No imports specified!"); }
+ if ($DEBUG)
+ {
+ print qq{this way to your new thread: <a href="$BUCKY/details/$thread_id">link!</a>};
+ footer();
+ }
+ redirect("$BUCKY/details/$thread_id");
+ }
+
+else
+ {
+ my ($title, $size, $inc);
+
+ my $thread = -1;
+ my $keyword = -1;
+ if ($input->{id})
+ {
+ # id title username createdate lastmodified size private allowed flagged
+ $thread = get_thread($input->{id});
+ $keyword = get_keyword($thread->{keyword});
+ }
+ if ($input->{keyword})
+ {
+ $keyword = get_keyword($input->{keyword});
+ }
+ elsif ($thread->{keyword})
+ {
+ $keyword = get_keyword($thread->{keyword});
+ }
+
+ header("ftp import");
+ menu();
+ if ($USER->{'username'} eq "asdfasdfadsfadsf")
+ {
+ print <<__SORRY__;
+<center>
+<br>
+<div style="text-align: left; width: 300px; padding: 10px;" class="bluebox">
+<center><b><big>SORRY!</big></b>
+<hr noshade color="$BUCKY_COLOR_HR">
+You have maxed out your upload quota!<p>
+Delete some things you've uploaded, then try again.
+</center></div><br></center>
+__SORRY__
+ exit;
+ }
+ print <<impHEAD;
+<center>
+<br>
+<div style="float: right; text-align: left; width: 200px; padding: 10px; font-size: 11px; background-color: #f8f8f8;" class="bluebox"><center>
+
+<big><b>UPLOAD FILES TO BUCKY WITH CONVENIENCE USING SFTP</b></big>
+<hr noshade color="$BUCKY_COLOR_HR">
+
+You must generate a cryptographic key to use this service. Don't worry it's easy!<br/>
+<br/>
+<hr noshade color="#ddd">
+<br/>
+
+ON A MAC / UNIX<br/>
+<br/>
+recc'd sftp client: <a href="http://cyberduck.ch/" target="_blank">Cyberd*ck</a><br/>
+<b>to generate the key</b>, from Terminal run:<br/>
+<big><tt><b>ssh-keygen -t rsa</b></b></tt></big><br/>
+<a href="/cgi-bin/bucky/message/jules">send me the public key</a>
+<br/>
+(private key is handled automatically)
+<br/>
+<br/>
+<hr noshade color="#ddd">
+<br/>
+
+ON WINDOWS ...<br/>
+<br/>
+recc'd sftp client: <a href="http://winscp.net/" target="_blank">WINSCP (PC)</a><br/>
+<b>generate the key</b> with the program <a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html" target="_blank">puttygen</a>
+<br/>
+<a href="/cgi-bin/bucky/message/jules">send me the public key</a>
+<br/>
+(the private key goes in the program when you set up the session.)
+
+<br/>
+<br/>
+<hr noshade color="#ddd">
+<br/>
+
+log in here:
+<br/>
+<br/>
+<tt><big>
+$BUCKY_FTP_HOST<br>
+username: $BUCKY_FTP_USER</big></tt>
+
+<br/>
+<br/>
+<hr noshade color="#ddd">
+<br/>
+
+Once you're in, upload your files and they should show up below. <b>Check off</b> only the files that are yours,
+or click the toggle button to select them all.
+impHEAD
+
+ if ($thread == -1)
+ {
+ print qq(To attach FTP'd files to a pre-existing thread, go to the thread and click <b>ftp here</b>.);
+ }
+ print qq!</center></div>\n\n!;
+
+ print qq!<form name="checkz" action="$BUCKY/import" method="post" enctype="multipart/form-data">\n!;
+ print qq!<div width=500>\n!;
+ ($title, $inc, $size) = list_imports();
+
+ print <<widget;
+<script type="text/javascript">
+<!--
+function toggle()
+ {
+ var e = document.checkz.elements.length;
+ for (var i = 0; i < e; i++)
+ {
+ var y = "document.checkz[i].type";
+ type = eval(y);
+
+ var n = "document.checkz[i]";
+ box = eval(n);
+
+ if (type == "checkbox")
+ {
+ if (box.checked == false)
+ { box.checked = true; }
+ else
+ { box.checked = false; }
+ }
+ }
+ }
+-->
+</script>
+<table cellpadding=0 cellspacing=0 width="580">
+<tr>
+<td align="left" valign="top"><input type=button value="toggle checked" onClick="JavaScript:toggle()"></td>
+<td align="center" valign="middle">
+widget
+
+ if ($inc)
+ {
+ print "<center><small><i><b>INCOMPLETE</b> FILES ARE SHOWN IN ITALICS -- PLEASE WAIT FOR YOUR UPLOAD TO FINISH</i></small></center><p>\n\n";
+ }
+
+ if ($DEBUG) { print qq!<input type="hidden" name="debug" value="$DEBUG">\n!; }
+ print qq!<input type="hidden" name="c" value="n">\n!;
+
+ print qq!<center>!;
+ print qq!<table cellpadding=2 cellspacing=0>!;
+ if ($thread != -1 && check_privacy($thread, $keyword))
+ {
+ print qq!<tr><td align="right" valign="baseline">!;
+ print qq!&nbsp;!;
+ print qq!<td><td align="left" valign="baseline">!;
+ print qq!These files will be added to:<p><big><b>$thread->{title}</b></big><br>\n!;
+ print qq!posted by $thread->{username} on !.verbosedate($thread->{createdate}).qq!<p>\n\n!;
+ print qq!<input type="hidden" name="id" value="$thread->{id}">\n!;
+ print qq!</td></tr>!;
+ }
+ else
+ {
+ print qq!<input type="hidden" name="id" value="new">\n\n!;
+ print qq!<tr><td align="right" valign="baseline">!;
+ print qq!title:&nbsp;!;
+ print qq!<td><td align="left" valign="baseline">!;
+ print qq!<input type="text" name="title" value="$title" size=40 maxlength=48><br>\n!;
+ print qq!</td></tr>!;
+ print qq!<tr><td align="right" valign="baseline">!;
+ print "keyword:&nbsp;";
+ print qq!<td><td align="left" valign="baseline">!;
+ if (exists($input->{keyword}))
+ {
+ my $k = get_keyword($input->{keyword});
+ if ($k->{public} || check_op($k))
+ {
+ keyword_pulldown($k->{keyword});
+ $checked = $k->{public} ? "" : " checked";
+ }
+ else
+ { keyword_pulldown("NONE"); }
+ }
+ else
+ { keyword_pulldown("NONE"); }
+ print qq!</td></tr>!;
+ }
+ print qq!<tr><td>!;
+ print "&nbsp;";
+ print qq!</td></tr>!;
+
+ print qq!<tr><td align="right" valign="top">!;
+ print qq!comment:&nbsp;!;
+ print qq!<td><td align="left" valign="top">!;
+ print <<impFOOT;
+<p>
+<textarea name="comment" cols="40" rows="10"></textarea>
+<p>
+<input type="submit" value="IMPORT" class="clicky">
+</td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</center>
+</form>
+</div>
+
+impFOOT
+ footer();
+ }
+
+$dbh->disconnect ();
+
diff --git a/cgi-bin/inbox b/cgi-bin/inbox
new file mode 100755
index 0000000..9760a54
--- /dev/null
+++ b/cgi-bin/inbox
@@ -0,0 +1,125 @@
+#!/usr/bin/perl
+#########################################
+# inbox
+# deal with inboxing, message display
+#########################################
+
+use localbucky;
+
+$dbh = DBI->connect ($dsn);
+
+our ($USER, $lastlog) = checkin();
+logout() unless ($USER != -1);
+
+if ( defined($input->{object_from_uri}) )
+ {
+ if ( $input->{object_from_uri} =~ /^[0-9]+$/ )
+ {
+ $input->{id} ||= $input->{object_from_uri};
+ }
+ else
+ {
+ $input->{box} ||= $input->{object_from_uri};
+ }
+
+ }
+#$input->{id} ||= $input->{object_from_uri} if defined($input->{object_from_uri}) && ($input->{object_from_uri} =~ /^[0-9]+$/);
+#$input->{box} ||= $input->{object_from_uri} if defined($input->{object_from_uri}) && (
+if (exists($input->{id}))
+ {
+ # display message
+
+ my $message = get_message($input->{id});
+ my $bn = $b->{mbox};
+ $bn =~ s/^$USER->{username}\.//;
+ if ($message == -1)
+ { error("No such message!"); }
+ if ($USER->{username} ne $message->{recipient} && $USER->{username} ne $message->{sender})
+ { error("You are not the recipient of this message."); }
+ unflag_message($input->{id});
+ my $header_args= {};
+ $header_args->{'title'} = $message->{'subject'};
+ if ($message->{'body'} =~ /body bgcolor="?([#0-9a-fA-F]+)/)
+ {
+ $header_args->{'color'} = $1;
+ }
+
+ header($header_args);
+ menu();
+ print "<br><br>";
+ display_message($message);
+ footer();
+ }
+
+elsif ($input->{c} eq "f")
+ {
+ # folder_management_form();
+ }
+
+else
+ {
+ my $box = exists($input->{box}) ? $input->{box} : "inbox";
+ my $limit = exists($input->{limit}) ? int($input->{limit}) : 50;
+ my $date = exists($input->{start}) ? int($input->{start}) : "now";
+
+ header("your $box");
+ menu();
+
+ my $messages = get_messages("$USER->{username}.$box", $limit, $date);
+ my $boxes = get_boxes($USER->{username});
+
+ print qq!<center>!;
+
+ print <<userbox;
+<div class="bluebox" style="float: right;">
+<b>message center</b>
+<hr noshade color="$BUCKY_COLOR_HR">
+<center>
+<table border=0 cellspacing=2 width=100>
+<tr><td align=left><small><b>Folders</b></small></td><td align=center><small>msgs</small></td></tr>
+userbox
+
+ foreach my $b (@$boxes)
+ {
+ my $count = $b->{mcount} || 0;
+ my $bn = $b->{mbox};
+ $bn =~ s/^$USER->{username}\.//;
+ print qq!<tr><td align=left><small><a href="$BUCKY/inbox/$bn"><b>$bn</b></a></small></td>! .
+ qq!<td align=center>!.hushnull($count, undef, 1).qq!</td></tr>!;
+ }
+
+ print <<userbox;
+</table>
+</center>
+<hr noshade color="$BUCKY_COLOR_HR">
+<small>
+<a href="$BUCKY/message"><b>Compose New Mail</b></a>
+</small>
+<hr noshade color="$BUCKY_COLOR_HR">
+<small>
+need to find someone?<br>
+<a href="$BUCKY/users"><u>check the userlist</u></a>
+</small>
+</div>
+userbox
+
+ print qq!<table width="100%" cellpadding=0 cellspacing=0 border=0><tr><td align=left valign=top>!;
+
+ message_list($messages, $box);
+
+ if (@$messages == $limit)
+ {
+ print qq!<div align="right"><big><br>!;
+ $oldest = $messages->[-1]->{date};
+ print qq(<a href="$BUCKY/inbox/$box&limit=$limit&start=$oldest">next <b>$limit</b> messages &gt;&gt;</a>);
+ print qq!</big></div>\n!;
+ }
+
+ print qq!</td></tr></table>!;
+
+ footer();
+ }
+
+$dbh->disconnect ();
+
+print "Inbox: " . &report_time() . "\n" if $timer;
diff --git a/cgi-bin/index b/cgi-bin/index
new file mode 100755
index 0000000..8ddacb4
--- /dev/null
+++ b/cgi-bin/index
@@ -0,0 +1,293 @@
+#!/usr/bin/perl
+#########################################
+# index
+# - do all index stuff, also deal with keyword admin
+#########################################
+
+use localbucky;
+
+$dbh = DBI->connect ($dsn);
+
+our ($USER, $lastlog) = checkin();
+
+my $k;
+my $tag;
+
+# check name of the calling script: index, tag, keyword
+$input->{script} ||= $input->{script_from_uri} if defined($input->{script_from_uri});
+
+# load the tag or keyword into the input params, if they don't exit already
+if ( $input->{script} eq $BUCKY_LEXICON_TAG )
+ {
+ $input->{tag} ||= $input->{object_from_uri} if defined($input->{object_from_uri});
+ }
+elsif ( $input->{script} eq $BUCKY_LEXICON_KEYWORD )
+ {
+ $input->{keyword} ||= $input->{object_from_uri} if defined($input->{object_from_uri});
+ }
+
+# Get keyword
+if (exists($input->{keyword}) && $input->{keyword} ne "new" && $input->{keyword} ne "unsorted")
+ {
+ $k = get_keyword($input->{keyword});
+ }
+
+
+# Create New Keyword? FORM
+if (exists($input->{keyword}) && $input->{keyword} eq "new")
+ {
+ my $t;
+ header("add new category");
+ if (exists($input->{thread}))
+ {
+ $t = get_thread($input->{thread});
+ }
+ menu();
+ print "<br><br>";
+ my %faek =
+ (
+ keyword => $input->{keyword},
+ thread => $input->{thread}
+ );
+ keyword_form($input->{keyword}, \%faek, $t);
+ footer();
+ }
+
+# Edit settings for keyword
+elsif ($input->{c} eq "edit" && (check_op($k) || $USER->{ulevel} == 3))
+ {
+ header(
+ {
+ title => "settings for category '$input->{keyword}'",
+ sticky => $input->{keyword}
+ } );
+ # 20070903 - marc - new menu args calling style
+ my $menu_args;
+ $menu_args->{keywords} = $k if $k;
+ menu( $menu_args );
+# menu($k);
+ print "<br><br>";
+
+ keyword_form($k->{keyword}, $k);
+
+ print qq!<center><table border=0 cellpadding=0 cellspacing=0 class="threadmain" width="580">!;
+ my $threads = get_threads_by_keyword($k->{keyword});
+ thread_box({ threads => $threads, kw => $k });
+
+ print qq!</table>!;
+ footer();
+ }
+
+# Create new keyword? Process form results
+elsif ($input->{c} eq "create")
+ {
+ if (!defined($input->{keyword}))
+ { error("no keyword specified!"); }
+ if (get_keyword($input->{keyword}) != -1)
+ { error("keyword already exists!"); }
+ my %nk =
+ (
+ keyword => $input->{keyword},
+ threads => " $input->{thread} ",
+ owner => $USER->{username},
+ public => $input->{public},
+ agglutinate => $input->{agglutinate},
+ color => $input->{color},
+ ops => (make_whitelist())
+ );
+ if ($DEBUG)
+ {
+ header("Creating keyword $input->{keyword}");
+ menu();
+ foreach my $ky (keys %nk)
+ { print "$ky => $nk{$ky}<br>\n"; }
+ }
+ add_keyword(\%nk);
+ update_thread_keyword($input->{thread}, $input->{keyword});
+ redirect("$BUCKY/$BUCKY_LEXICON_KEYWORD/$input->{keyword}");
+ }
+
+# Edit settings for keyword? Process form results
+elsif ($input->{c} eq "update")
+ {
+ if (!defined($input->{keyword}))
+ { error("no keyword specified!"); }
+ my %nk =
+ (
+ threads => " $input->{thread} ",
+ public => (exists($input->{public}) ? 1 : 0),
+ agglutinate => (exists($input->{agglutinate})) ? $input->{agglutinate} : 0,
+ color => $input->{color}
+ );
+ if (!exists($input->{public}))
+ {
+ $nk{ops} = make_whitelist();
+ }
+ if ($DEBUG)
+ {
+ header("Updating keyword $input->{keyword}");
+ menu();
+ foreach my $ky (keys %nk)
+ { print "$ky => $nk{$ky}<br>\n"; }
+ }
+ update_keyword($input->{keyword}, \%nk);
+ redirect("$BUCKY/$BUCKY_LEXICON_KEYWORD/$input->{keyword}");
+ }
+
+# Assign keyword processing form action
+elsif ($input->{c} eq "assign")
+ {
+ keyword_assign_mechanism($input->{keyword}, $input->{thread}, $k);
+ redirect("$BUCKY/maintain/$input->{thread}");
+ # redirect("$BUCKY/index?keyword=$input->{keyword}");
+ }
+
+# Detach keyword action
+elsif ($input->{c} eq "detach")
+ {
+ my $t;
+
+ if (!defined($input->{thread}))
+ { error("no post specified!"); }
+ $t = get_thread($input->{thread});
+ $k = get_keyword($t->{keyword});
+
+ my %nk = ( threads => delete_key($k->{threads}, $input->{thread}) );
+
+ if ($DEBUG)
+ {
+ header("Detaching post from $t->{keyword}");
+ menu();
+ foreach my $ky (keys %nk)
+ { print "$ky => $nk{$ky}<br>\n"; }
+ print "keyword ==> $t->{keyword}<br>\n";
+ print "detaching <b>$t->{title}</b> from <b>$t->{keyword}</b><br>\n";
+ }
+ update_keyword($t->{keyword}, \%nk);
+ update_thread_keyword($t->{id}, "NULL");
+ redirect("$BUCKY/maintain/$t->{id}");
+ }
+
+# Display main index page
+else
+ {
+ my $tag = exists($input->{tag}) ? $input->{tag} : undef;
+ my $keyword = exists($input->{keyword}) ? $input->{keyword} : "all";
+ my $limit = exists($input->{limit}) ? int($input->{limit}) : $BUCKY_INDEX_LIMIT;
+ my $date = exists($input->{start}) ? int($input->{start}) : "now";
+
+ header({ title => get_random_line("titles"), sticky => $input->{keyword}, color => get_color_from_time() });
+ my $keywords = get_keywords();
+ my $tags = get_tags();
+
+ my $menu_args;
+ $menu_args->{keywords} = $keywords->{$keyword} if $keywords->{$keyword};
+ menu( $menu_args );
+
+ print qq(<table width="100%" cellpadding=0 cellspacing=0 border=0>);
+ print qq(<tr>);
+
+#############################
+# KEYWORD LIST
+ print qq(<td align=center valign=top style="width: 100px">\n);
+ print qq(<div class="bluebox" width="100"><span style="line-height: 1.5em;"><nobr>);
+ my $p = ''; my $l = '';
+ my $with_letter = 0;
+ my $s = '';
+my $pre = '';
+ my $start = '';
+ foreach my $k (sort { lc($a) cmp lc($b) } keys %$keywords)
+ {
+ my $style;
+ $l = substr($k,0,1);
+ $start ||= $l;
+ if ($p && lc($l) ne lc($p))
+ {
+ if ($with_letter > 3)
+ {
+ print qq(<big><big><b>$start - $pre</b></big></big><br> );
+ print $s;
+ print qq(</nobr></span></div>);
+ print qq(<div class="bluebox" width="100"><span style="line-height: 1.5em;"><nobr>);
+ $s = '';
+ $with_letter = 1;
+ $p='';
+ $start = $l;
+ }
+ }
+ $with_letter += 1;
+ $p||=$l;
+ $pre=$l;
+ $s .= qq(<a style="$css" href="$BUCKY/category/$k">$k</a><br>);
+ }
+if ($s)
+ {
+ print qq(<big><big><b>$start - $pre</b></big></big><br> );
+ print $s;
+ print qq(</div>);
+ print qq(<div class="bluebox" width="100"><small><span style="line-height: 1.5em;"><nobr>);
+ }
+ print qq(</div>);
+ print qq(<div class="bluebox"><small><span style="line-height: 1.5em;"><nobr>);
+ print qq(.: <a href="$BUCKY/category/unsorted"><i>unsorted</i></a> :.<br>);
+ print qq(</nobr></span></small></div></td>\n);
+
+#############################
+# PRINT MAIN PANE
+ print qq(<td align=left valign=top>\n);
+
+# index_photostream($keyword,$tag);
+
+# print qq(<table border=0 cellpadding=0 cellspacing=0 class="threadmain" width="580">);
+# print qq(<table border=0 cellpadding=0 cellspacing=0 class="threadmain">);
+ print qq(<table border=0 cellpadding=0 cellspacing=0 class="threadmain" width="100%">);
+
+ if ($keyword ne "all")
+ {
+ my $threads = throttle_threads({ keyword => $keyword, newest => $date });
+ thread_box({ threads => $threads, kw => $keywords->{$keyword} });
+ }
+ elsif ($tag)
+ {
+ my $threads = throttle_threads({ tag => $tag, newest => $date });
+ thread_box({ threads => $threads, tag => $tags->{$tag} });
+ }
+ else
+ {
+ alpha_index($keywords, $limit, $date);
+ }
+
+ print qq(</table>);
+ print qq(</td>\n);
+
+#############################
+# PRINT SIDEBAR
+ print qq(<td width="300" align=left valign=top>\n);
+ alerts();
+ if ($USER == -1)
+ {
+ bPod_box();
+ }
+ else
+ {
+ welcome_box(); # if (check_key($USER->{boxes}, "welcome"));
+ search_box();
+# radio_box() ; # if (check_key($USER->{boxes}, "radio"));
+# bPod_box() if (check_key($USER->{boxes}, "bPod"));
+ hoot_box() if (check_key($USER->{boxes}, "hootbox"));
+# svn_box();# if $USER->{'ulevel'} == 3;
+# upload_form($keyword) if (check_key($USER->{boxes}, "postform"));
+ }
+ print qq(</td>);
+
+###############################
+
+ print qq(</tr>);
+ print qq(</table>\n\n);
+
+ footer();
+ }
+
+$dbh->disconnect ();
+
+print "Index: " . &report_time() . "\n" if $timer;
diff --git a/cgi-bin/invite b/cgi-bin/invite
new file mode 100755
index 0000000..cf29b1b
--- /dev/null
+++ b/cgi-bin/invite
@@ -0,0 +1,123 @@
+#!/usr/bin/perl
+#########################################
+# invite
+#########################################
+# id hash state attest created expired username password realname email grass keywords
+
+use localbucky;
+
+use invite;
+use Digest::MD5 qw (md5_hex);
+
+$dbh = DBI->connect ($dsn);
+
+our ($USER, $lastlog) = checkin();
+our $loggedin = ($USER != -1);
+
+our ($command, $hash, $id) = invite_init();
+invite_run($command, $hash, $id);
+
+sub invite_init
+ {
+ my $command = exists($input->{c}) ? scrub($input->{c}) : -1;
+ my $hash = -1;
+ if (defined($input->{object_from_uri}))
+ { $hash = scrub($input->{object_from_uri}); }
+ elsif (exists($input->{hash}))
+ { $hash = scrub($input->{hash}); }
+ elsif (exists($input->{invite}))
+ { $hash = scrub($input->{invite}); }
+ elsif (exists($input->{i}))
+ { $hash = scrub($input->{i}); }
+ my $id = exists($input->{id}) ? scrub($input->{id}) : -1;
+ return ($command, $hash, $id);
+ }
+
+sub invite_run
+ {
+ my ($command, $hash, $id) = @_;
+
+ if ($loggedin)
+ { invite_process_user($command, $hash, $id); }
+ else
+ { invite_process_outsider($command, $hash); }
+ }
+
+sub invite_process_outsider
+ {
+ my ($command, $hash) = @_;
+
+ # validate invite
+ if ($command eq "validate")
+ {
+ validate_invite($hash);
+ }
+ # add request
+ elsif ($command eq "request")
+ {
+ request_invite();
+ }
+ # redeem invite
+ elsif ($hash != -1)
+ {
+ my $invite = get_invite_from_hash($hash);
+ unless (invite_is_active($invite))
+ { error("Bad invite key!"); }
+ registration_form($invite);
+ }
+ # registration form
+ else
+ {
+ registration_form();
+ }
+ }
+
+sub invite_process_user
+ {
+ my ($command, $hash, $id) = @_;
+ my $result = -1;
+ my $invite = -1;
+ if ($hash != -1)
+ { $invite = get_invite_from_hash($hash); }
+ elsif ($id)
+ { $invite = get_invite_from_id($id); }
+
+ # new invite
+ if ($command eq "new")
+ {
+ $hash = generate_invite();
+ $result = ($hash != -1) ? 1 : 0;
+ }
+ # approve/delete/extend invites
+ elsif ($command eq "approve" && $USER->{ulevel} == 3)
+ { $result = validate_approve($invite); }
+ elsif ($command eq "reject" && $USER->{ulevel} == 3)
+ { $result = set_invite_state($invite, $BUCKY_INVITE_REJECTED); }
+ elsif ($command eq "cancel" && $invite->{attest} eq $USER->{username})
+ { $result = set_invite_state($invite, $BUCKY_INVITE_EXPIRED); }
+ elsif ($command eq "renew" && $invite->{attest} eq $USER->{username})
+ { $result = set_invite_expired($invite, ($invite->{expired} + 86400*7)); }
+
+ header("invite manager");
+ menu();
+
+ print qq(<table width="100%" cellpadding=0 cellspacing=0 border=0>);
+ print qq(<tr><td align=center valign=top>\n);
+
+ display_personal_invites($user_invites);
+ print "<p>";
+ display_approve_list() if ($USER->{ulevel} == 3);
+
+ print qq(</td>\n<td width="200" align=right valign=top>\n);
+
+ invite_result_box($command, $hash, $result) if ($command != -1);
+ invite_create_box();
+
+ print qq(</td></tr></table>\n\n);
+
+ footer();
+ }
+
+$dbh->disconnect ();
+
+
diff --git a/cgi-bin/localbucky.pm b/cgi-bin/localbucky.pm
new file mode 100644
index 0000000..32d6e33
--- /dev/null
+++ b/cgi-bin/localbucky.pm
@@ -0,0 +1,70 @@
+#!/usr/bin/perl
+
+# Change this to point to Bucky library directory, where packages are installed
+use lib "/var/www/vhosts/carbonpictures.com/bucky/lib";
+
+# Change this to point to the directory of random texts
+our $BUCKY_FORTUNES = "/var/www/vhosts/carbonpictures.com/bucky/fortune";
+
+# Change this to point to the URL preamble for Bucky's script directory, where cgi-bin scripts are installed
+BEGIN
+ {
+ our $BUCKY = "/cgi-bin/bucky";
+ our $BUCKY_DB = "bucky";
+ our $BUCKY_DB_CNF = "/var/www/vhosts/carbonpictures.com/.bucky.cnf";
+ }
+
+#our $BUCKY = "";
+
+our $BUCKY_NAME = 'bucky';
+our $BUCKY_SHORT_NAME = 'bucky';
+our $BUCKY_COOKIE_DOMAIN = 'carbonpictures.com';
+our $BUCKY_HOST = 'www.carbonpictures.com'; # url domain
+
+our $BUCKY_ADMINISTRATOR = 'jules';
+our $BUCKY_DEFAULT_BOXES = " welcome bPod radio postform hootbox photostream ";
+our $BUCKY_DEFAULT_KEYWORD = 'NONE'; # default should be 'NONE'
+our $BUCKY_TIMEZONE_OFFSET = 5; # correct your server's offset from GMT
+our $BUCKY_DUDER_NOUN = 'duder'; # singular noun accepting courtesy 's'
+
+our $BUCKY_LOGIN_WELCOME = "welcome to bucky"; # welcome on login screen
+
+# bucky non-css colors
+our $BUCKY_COLOR_HR = "#201010";
+
+# /index
+# presumed max number of threads to show
+our $BUCKY_INDEX_LIMIT = 50;
+# how many days to display under "the latest"
+our $BUCKY_INDEX_LATEST = 1.78;
+
+our $LASTLOG_ONLY_FIRST_DAY = 0;
+
+our $INDEX_GALLERY_IMAGE_COUNT = 4;
+
+# bPod: URLs, colors
+our $BPOD_URL_SERVICES_KEYWORDS = $BUCKY_HOST . "$BUCKY/services_k";
+our $BPOD_URL_SERVICES_THREADS = $BUCKY_HOST . "$BUCKY/services_th?k=";
+our $BPOD_URL_SERVICES_FILES = $BUCKY_HOST . "$BUCKY/services_f?pid=";
+our $BPOD_URL_PREAMBLE_FILES = $BUCKY_HOST . "/bucky/data/";
+our $BPOD_URL_DETAILS = $BUCKY_HOST . "$BUCKY/details/";
+our $BPOD_COLOR_UI_GRADIENT_1 = "0xE6F0F0";
+our $BPOD_COLOR_UI_GRADIENT_2 = "0xD8E0EC";
+our $BPOD_COLOR_UI_STROKE = "0x201010";
+
+# thread url format: /details (== 0) or individually by /keyword (== 1)
+our $BUCKY_KEYWORD_IN_DETAILS_URL = 0;
+
+our $ZIP_BUTTON_ENABLED = 1;
+
+# (shoutcast) radio status
+our $RADIO_STATUS_ENABLED = 1;
+our $RADIO_STATUS_URL = "http://radiofreehanoi.com/status";
+our $RADIO_INFO_URL = "http://radiofreehanoi.com/info";
+
+
+# Load bucky packages
+use Bucky1;
+
+1;
+
diff --git a/cgi-bin/localbucky.pm.tmpl b/cgi-bin/localbucky.pm.tmpl
new file mode 100644
index 0000000..143c192
--- /dev/null
+++ b/cgi-bin/localbucky.pm.tmpl
@@ -0,0 +1,54 @@
+#!/usr/bin/perl
+
+use Time::Stopwatch;
+
+# Comment out this timer to suppress page loadtime messages
+tie our $timer, 'Time::Stopwatch';
+
+our $BUCKY_NAME = 'king of sf';
+our $BUCKY_SHORT_NAME = 'kingofsf';
+our $BUCKY_COOKIE_DOMAIN = 'kingofsf.com';
+
+our $BUCKY_ADMINISTRATOR = 'marc';
+our $BUCKY_DEFAULT_BOXES = " welcome bPod radio postform hootbox photostream ";
+our $BUCKY_DEFAULT_KEYWORD = 'NONE'; # default should be 'NONE'
+our $BUCKY_TIMEZONE_OFFSET = 8; # correct your server's offset from GMT
+
+# Change this to point to Bucky library directory, where packages are installed
+use lib "/bucky/lib";
+
+# Change this to point to the URL preamble for Bucky's script directory, where cgi-bin scripts are installed
+our $BUCKY = "/cgi-bin/bucky";
+
+# Change this to be a welcome messasge for your login screen
+our $BUCKY_LOGIN_WELCOME = "welcome to kitchen hacklab, pricks";
+
+# Change this to your bucky host!
+our $BUCKY_HOST = "www.carbonpictures.com";
+
+# bucky non-css colors
+our $BUCKY_COLOR_HR = "#201010";
+
+# bPod: URLs, colors
+our $BPOD_URL_SERVICES_KEYWORDS = $BUCKY_HOST . "$BUCKY/services_k";
+our $BPOD_URL_SERVICES_THREADS = $BUCKY_HOST . "$BUCKY/services_th?k=";
+our $BPOD_URL_SERVICES_FILES = $BUCKY_HOST . "$BUCKY/services_f?pid=";
+our $BPOD_URL_PREAMBLE_FILES = $BUCKY_HOST . "/bucky/data/";
+our $BPOD_URL_DETAILS = $BUCKY_HOST . "$BUCKY/details?id=";
+our $BPOD_COLOR_UI_GRADIENT_1 = "0xF8F8D7";
+our $BPOD_COLOR_UI_GRADIENT_2 = "0xF0F0E6";
+our $BPOD_COLOR_UI_STROKE = "0x201010";
+
+# thread url format: /details (== 0) or individually by /keyword/ (== 1)
+our $BUCKY_KEYWORD_IN_DETAILS_URL = 0;
+
+# Load bucky packages
+use Bucky;
+
+# Report nicely formatted time
+sub report_time
+ {
+ return sprintf("%2.2f", $timer * 1000) . "ms";
+ }
+1;
+
diff --git a/cgi-bin/login b/cgi-bin/login
new file mode 100755
index 0000000..0335549
--- /dev/null
+++ b/cgi-bin/login
@@ -0,0 +1,86 @@
+#!/usr/bin/perl
+#########################################
+# login
+# no input: print form
+# input: set cookie, send along to index
+#########################################
+
+if (-e "/var/www/vhosts/carbonpictures.com/bucky/lock")
+ {
+ print "Content-type: text/html\nPragma: no-cache\n\n";
+ print "<center><big><b><br>" . $BUCKY_CONFIG->{BUCKY_NAME} . " is down for maintenance!<p>please check back in a bit.</b></big></center>";
+ exit(0);
+ }
+
+if (! exists $ENV{'HTTPS'} || $ENV{'HTTPS'} ne "on")
+ {
+ print "Location: https://www.carbonpictures.com/cgi-bin/bucky/index\n\n";
+ exit;
+ }
+use localbucky;
+
+$dbh = DBI->connect ($dsn);
+
+# Check to see if user has supplied a username for login
+if (exists($input->{username}))
+ {
+ if ($DEBUG)
+ { header("login"); }
+
+ # Look up user, based on username and password
+ my ($USER) = auth( $input->{username}, crypt($input->{password}, lc($input->{username}) ) );
+
+ # No such user, or password failed, so redirect to logout
+ if ($USER == -1)
+ { print "password failed<br>\n" if $DEBUG; logout(); }
+
+ # User successfully logged in! Update the last login time
+ update_lastsession( $USER->{username} );
+ $USER->{lastsession} = $USER->{lastseen};
+
+ if ($DEBUG)
+ {
+ print "<div class=\"message\">\n";
+ print "uid: $USER->{id}\n<p>username: $USER->{username}\n<p>\n";
+ print "</div>\n";
+ footer();
+ }
+
+ nice_redirect();
+ }
+
+# Else, if there's an i=1 query string, redirect to adduser program
+elsif (exists($input->{i}) && $input->{i} == 1)
+ { redirect("$BUCKY/adduser?i=1"); }
+
+# Else, no username, so just display the login page
+else
+ {
+ header("login");
+ print qq{<hr color="$BUCKY_COLOR_HR" style="padding: 0px; margin: 2px;"><br><br><br><center><div class=message>};
+
+ # Display any login errors
+ if ($input->{error} == 1)
+ { print "bad username/password!<br>"; }
+ elsif ($input->{error} == 2)
+ { print "illegal traversal!<br>"; }
+
+ print "<b>$BUCKY_LOGIN_WELCOME</b>";
+ print qq{</b><br>\n<hr color="$BUCKY_COLOR_HR">\n\n};
+
+ login_form();
+
+ print qq(<p>\n<small>\n);
+# print qq(<a href="$BUCKY/index"><b>tour</b> the hacklab</a>);
+# print qq(<p>want an account?<br><a href="$BUCKY/invite">request one</a><br>);
+ print qq(</small></div></center>\n\n);
+
+ footer();
+ }
+
+$dbh->disconnect ();
+print "Login: " . &report_time() . "\n" if $timer;
+
+
+#########################################
+
diff --git a/cgi-bin/logout b/cgi-bin/logout
new file mode 100755
index 0000000..ac3888a
--- /dev/null
+++ b/cgi-bin/logout
@@ -0,0 +1,12 @@
+#!/usr/bin/perl
+
+#########################################
+# logout
+# i love logging out
+#########################################
+
+use localbucky;
+
+logout();
+print "Logout: " . &report_time() . "\n" if $timer;
+
diff --git a/cgi-bin/maintain b/cgi-bin/maintain
new file mode 100755
index 0000000..007e1e3
--- /dev/null
+++ b/cgi-bin/maintain
@@ -0,0 +1,289 @@
+#!/usr/bin/perl
+#########################################
+# maintain
+# - thread administration
+#########################################
+
+use localbucky;
+
+our $id;
+our $files;
+
+$dbh = DBI->connect ($dsn);
+
+our ($USER, $lastlog) = checkin();
+logout() unless ($USER != -1);
+
+$input->{id} ||= $input->{object_from_uri} if defined($input->{object_from_uri});
+if (exists($input->{id}) && $input->{id} > 0)
+ { $id = $input->{id}; }
+elsif (exists($input->{keyword}) )
+ { $keyword = $input->{keyword}; }
+else
+ { error("No post specified."); }
+
+my $t = get_thread($id);
+my $k = get_keyword($t->{keyword});
+
+if ($t == -1)
+ { error("No such post."); }
+
+$files = get_files($t->{id});
+$comments = get_comments($t->{id});
+
+#my ($participation) = check_participation($files, $comments);
+my ($participation) = 0;
+
+if (exists($input->{c}) && $input->{c} eq "zip")
+ {
+ if ($t->{zipped} == 0)
+ {
+ my $cleantitle = generate_zip_filename($t);
+ update_thread_zipped($t->{id}, -1);
+ $t->{zipped} = -1;
+ system(qq!$NOHUP_PATH $ZIP_PATH -jr "$data_path/$t->{id}/$cleantitle" $data_path/$t->{id}/* >$temp_path/.zip.out -x "$cleantitle" 2>&1 &!);
+ redirect("$BUCKY/".details_link($t)."/$t->{id}");
+ }
+ elsif ($t->{zipped} == 1)
+ {
+ my $cleantitle = generate_zip_filename($t);
+ update_thread_zipped($t->{id}, -1);
+ $t->{zipped} = -1;
+ system(qq!$NOHUP_PATH $ZIP_PATH -jr "$data_path/$t->{id}/$cleantitle" $data_path/$t->{id}/* >$temp_path/.zip.out -x "$cleantitle" 2>&1 &!);
+ redirect("$BUCKY/".details_link($t)."/$t->{id}");
+ }
+ }
+elsif ($t->{username} eq $USER->{username} || check_op($k) || $participation == 2 || (check_key($t->{display}, "opset") && check_privacy($t, $k)) || $USER->{ulevel} == 3)
+ {
+ header( {
+ title => "settings for \"$t->{title}\"",
+ subtitle => qq!posted by <a href="$BUCKY/profile/$t->{username}">$t->{username}</a> on ! .
+ (verbosedate($t->{createdate})) .
+ qq! &middot; <span class="lite"><a href="$BUCKY/!.details_link($t).qq!/$t->{id}">view post</a></span>!,
+ color => get_color($t, $k)
+ } );
+ menu();
+ if (exists($input->{c}))
+ {
+ if ($input->{c} eq "display")
+ {
+ if ($t->{title} ne $input->{title})
+ {
+ update_thread_title($t->{id}, $input->{title});
+ $t->{title} = $input->{title};
+ print "Changed title to: <b>$t->{title}</b><br>\n";
+ }
+
+ if (($t->{color} ne $input->{color}) && is_color($input->{color}))
+ {
+ update_thread_color($t->{id}, $input->{color});
+ $t->{color} = $input->{color};
+ print "Set color to: <b>$t->{color}</b><br>\n";
+ print qq(<link rel="stylesheet" href="/css/bogart/$t->{color}.css">);
+ }
+
+ my (@display) = qw[hoot ren "no-upload" shorturl editable opset "no-zip-button" hidekws];
+ my $newdisplay = ' ';
+ foreach my $key (@display)
+ {
+ if (exists($input->{$key}) && $input->{$key} == 1)
+ { $newdisplay = add_key($newdisplay, $key); }
+ }
+ if ($input->{filelist} == 2)
+ { $newdisplay = add_key($newdisplay, "ffl"); }
+ if ($input->{filelist} == 0)
+ { $newdisplay = add_key($newdisplay, "nfl"); }
+
+ if ($t->{display} ne $newdisplay)
+ {
+ update_thread_display($t->{id}, $newdisplay);
+ $t->{display} = $newdisplay;
+ print "New display settings: <b>$t->{display}</b><br>\n";
+ }
+
+ # touch_thread($t);
+ admin_form($t->{id}, $t, $files, $k);
+ }
+ elsif ($input->{c} eq "p")
+ {
+ if ($input->{private} == 2)
+ {
+ print "Thread is now <b>" . $BUCKY_CONFIG->{PRIVACY_OWNER} . "</b>.<br>";
+ switch_thread_privacy($t->{id}, 2);
+ $t->{allowed} = update_whitelist();
+ $t->{private} = 2;
+ }
+ elsif ($input->{private} == 1)
+ {
+ print "Thread is now viewable by <b>" . $BUCKY_CONFIG->{PRIVACY_BBS} || "other users" . "</b>.<br>";
+ switch_thread_privacy($t->{id}, 1);
+ $t->{allowed} = update_whitelist();
+ $t->{private} = 1;
+ }
+ else
+ {
+ print "Thread is now viewable by <b>" . $BUCKY_CONFIG->{PRIVACY_WORLD} . "</b>.<br>";
+ switch_thread_privacy($t->{id}, 0);
+ $t->{private} = 0;
+ }
+ admin_form($t->{id}, $t, $files, $k);
+ }
+ # change tags
+ elsif ($input->{c} eq "t")
+ {
+ my $new_tags = 0;
+ if ($input->{tags} ne $input->{tags_saved})
+ {
+ print "Changed Tag to " . $input->{tags} . "<br>" if ($DEBUG);
+ # First: add new tags
+ my $tags = get_tags_from_string( $input->{tags} );
+ foreach my $tag (@$tags)
+ {
+ print "Assigning tag $tag<br>\n" if ($DEBUG);
+ print tag_assign_mechanism( $tag, $t ) || "";
+ $new_tags++;
+ }
+
+ # Second: remove deleted tags
+ my $old_tags = get_tags_from_string( $input->{tags_saved} );
+ foreach my $old_tag (@$old_tags)
+ {
+ # If the new tags list does not contain this old tag, remove it
+ if ( ! grep ( /^$old_tag$/, @$tags ) )
+ {
+ print tag_remove_mechanism( $old_tag, $t ) || "";
+ $new_tags++;
+ }
+ }
+ }
+ # touch_thread($t);
+ $t = get_thread( $t->{id} ) if $new_tags;
+ admin_form($t->{id}, $t, $files, $k);
+ }
+ elsif ($input->{c} eq "f")
+ {
+ my @flagged = corral($input, "file");
+ if ($DEBUG)
+ {
+ print "<br>\nfiles flagged: ";
+ foreach (@flagged)
+ { print; print " "; }
+ print "<br>\n";
+ }
+ if ($input->{verb} eq "flag")
+ {
+ print "Flagged file $flagged[0]<br>";
+ update_flagged($t->{id}, $flagged[0]);
+ $t->{flagged} = $flagged[0];
+ touch_thread($t);
+ admin_form($t->{id}, $t, $files, $k);
+ }
+ elsif ($input->{verb} eq "move")
+ {
+ print "When this works it will be like this:!<br>\n";
+ print "Where do you want to move these files here<br>\n";
+ print "Moving files...<br>\n";
+ # system("mv", $data_path/$oldpid/$filenamea ..., "$data_path/$newpid/");
+ print "Moving ids...<br>\n";
+ print "Recalculating post sizes...<br>\n";
+ }
+ elsif ($input->{verb} eq "rm")
+ {
+ if (!$input->{ok})
+ {
+ print qq(<center><p><div class="bluebox" style="width: 320px; padding: 10px;"><big><b>Are you sure you want to delete these files?</b></big><hr noshade color="$BUCKY_COLOR_HR"><p>\n);
+ print qq(<form action="$BUCKY/maintain" method="post" enctype="multipart/form-data">);
+ print qq(<input type=hidden name="c" value="f">\n);
+ print qq(<input type=hidden name="id" value="$t->{id}">\n);
+ print qq(<input type=hidden name="debug" value="1">\n) if ($DEBUG);
+ print qq(<input type=hidden name="verb" value="rm">\n);
+ print qq(<input type=hidden name="ok" value="1">\n);
+
+ my $i = 0;
+ my $fid = shift(@flagged);
+ foreach my $fh (sort_by_id(@$files))
+ {
+ next if ($fid != $fh->{id});
+ $i++;
+
+ print qq{<input type=hidden name="file$fid" value="$fid">\n};
+ print $fh->{id}.": " if ($DEBUG);
+ print $fh->{filename}."<br>\n";
+
+ $fid = shift(@flagged);
+ }
+
+ print qq{<br><input type="submit" value="YES YES DELETE THE FILES" class="clicky"></form></div></center>};
+ }
+ else
+ {
+ my $i = 0;
+ my $fid = shift(@flagged);
+ foreach my $fh (sort_by_id(@$files))
+ {
+ next if ($fid != $fh->{id});
+ $i++;
+
+ next if -d qq!$data_path/$t->{id}/$$fh{filename}!;
+ delete_file_record($fid);
+ system($RM_PATH, "-f", qq!$data_path/$t->{id}/$$fh{filename}!);
+ system($RM_PATH, "-f", qq!$data_path/$t->{id}/.thumb/s.$$fh{filename}!);
+ system($RM_PATH, "-f", qq!$data_path/$t->{id}/.thumb/t.$$fh{filename}!);
+ system($RM_PATH, "-f", qq!$data_path/$t->{id}/.thumb/b.$$fh{filename}!);
+ print qq!deleted $$fh{filename}<br>\n!;
+
+ $fid = shift(@flagged);
+ }
+
+ print "Recalculating post size...<br>\n";
+ update_thread_size($t->{id});
+ $files = get_files($t->{id});
+ touch_thread($t);
+ admin_form($t->{id}, $t, $files, $k);
+ }
+ }
+ }
+ elsif ($input->{c} eq "clobber")
+ {
+ if ($input->{okay})
+ {
+ delete_thread($t->{id});
+ print qq!<br><br><center><table width=400 border=0 cellpadding=0 cellspacing=0><tr><td class="bluebox" style="padding: 20px;"><big><b>POST DELETED\!</b></big></td></tr></table></center>\n!;
+ }
+ else
+ {
+ my $fs = $t->{files} != 1 ? "s" : "";
+ my $cs = $t->{comments} != 1 ? "s" : "";
+ my $par = get_participation($t->{id});
+ my $ps = $par != 1 ? "s" : "";
+ print qq(<br><br><center><table width=350 border=0 cellpadding=0 cellspacing=0><tr><td class="bluebox" style="padding: 10px;">);
+ print qq(<big>Are you <b>sure</b> you want to delete:<br>$t->{title}</big><br><br>);
+ print qq(Doing so will delete <b>$t->{files} file$fs</b> and <b>$t->{comments} comment$cs</b>,<br>);
+ print qq(<b>destroying</b> the hard work of $par duder$ps\!<br>);
+ print qq(<br>);
+ print qq(<form action="$BUCKY/maintain" method="post" enctype="multipart/form-data">\n);
+ print qq(<input type=hidden name="debug" value="1">\n) if ($DEBUG);
+ print qq(<input type=hidden name="id" value="$t->{id}">\n);
+ print qq(<input type=hidden name="c" value="clobber">\n);
+ print qq(<input type=hidden name="okay" value="1">\n);
+ print qq(<center><table cellpadding=0 cellspacing=10 border=0><tr><td><input type="submit" value="OKAY" class="clicky"></form></td><td><input type="button" value="ABORT" class="clicky" onclick=")."javascript: history.go(-1)".qq("></td></tr></table></center>);
+
+ print qq!</td></tr></table></center>!;
+ }
+ }
+ }
+ else
+ {
+ admin_form($t->{id}, $t, $files, $k);
+ }
+ footer();
+ }
+else
+ {
+ error("Unable to access $id!");
+ }
+
+sub sort_by_username { sort { lc($a->{username}) cmp lc($b->{username}) } @_; }
+sub sort_by_id { sort { $a->{id} <=> $b->{id} } @_; }
+
+print "Maintain: " . &report_time() . "\n" if $timer;
diff --git a/cgi-bin/message b/cgi-bin/message
new file mode 100755
index 0000000..08c0968
--- /dev/null
+++ b/cgi-bin/message
@@ -0,0 +1,149 @@
+#!/usr/bin/perl
+#########################################
+# message
+# - deal with message reading/sending
+#########################################
+
+use localbucky;
+
+$dbh = DBI->connect ($dsn);
+
+our ($USER, $lastlog) = checkin();
+logout() unless ($USER != -1);
+
+$input->{username} ||= $input->{object_from_uri} if defined($input->{object_from_uri});
+if ($$input{c} eq "s")
+ {
+ my $subject;
+ my $recip = lc($$input{recipient});
+ my $box;
+ my $out;
+
+ # send message: take input, check on it, add to db
+ if (!exists($$input{recipient}) || !exists($$input{body}))
+ { error("Missing one or more fields!"); }
+ if ($recip eq "system")
+ { $recip = "marc"; }
+ if (get_uid($recip) == -1)
+ { error("No such user $recip!"); }
+ if (length($input->{subject}) == 0)
+ {
+ # no subject so obviously we have to supply something retarded
+ @subjects = ("sup duder", "WHAUT UP DWIZLINKA", "HAPPY BIG CHAVYO WILVERFAO?", "NO DUM bB SUXCER Ylo TWIENF", "fararyY*F**YFARRRRADAYY+++", "i doINT BELIEVE YOYU!&U#*&!", "fuckN TEHAS D", "YO WHAT UP DOGGIE", "SENdiN BUcKY MeZSaGeZ", "SALWE");
+ $subject = $subjects[(int rand @subjects)]
+ }
+ else
+ { $subject = $$input{subject}; }
+
+ my %newmsg = (sender => $USER->{username}, recipient => $recip, unread => 1, subject => $subject, body => $$input{body});
+
+ if (exists($input->{later}))
+ {
+ header("saving draft");
+ menu();
+ $box = "drafts";
+ $newmsg{unread} = 0;
+ if (exists($input->{oldid}))
+ {
+ update_message($input->{oldid}, \%newmsg);
+ }
+ else
+ {
+ new_message("$USER->{username}.$box", \%newmsg);
+ }
+
+ $out = "SAVED AS DRAFT";
+ }
+ else
+ {
+ header("sending message");
+ menu();
+ new_message("$recip.inbox", \%newmsg);
+
+ $box = "outbox";
+ $newmsg{unread} = 0;
+ new_message("$USER->{username}.$box", \%newmsg);
+ $out = "MESSAGE SENT";
+
+ if (exists($$input{oldid}))
+ {
+ delete_message($$input{oldid});
+ recount_mailbox("$USER->{username}.drafts");
+ }
+ }
+
+ print qq!<p><center><div class=message><big><br><b>$out</b><br><br><a href="$BUCKY/inbox/$box">return to $box</a><br><br></big></div></center>!;
+ footer();
+ }
+
+elsif ($$input{c} eq "r") # reply to message
+ {
+ $message = get_message($$input{id});
+ if ($message == -1)
+ { error("No such message."); }
+ elsif ($$message{recipient} ne $USER->{username} && $$message{sender} ne $USER->{username})
+ { error("You do not own this message."); }
+ if ($$message{mbox} =~ /drafts/)
+ {
+ header("edit message");
+ menu();
+ message_form($$message{recipient}, $message);
+ }
+ else
+ {
+ header("reply to message");
+ menu();
+ message_form($$message{sender}, $message);
+ }
+ footer();
+ }
+
+elsif ($$input{c} eq "d") # delete message
+ {
+ if ($DEBUG)
+ {
+ header("deleting message");
+ menu();
+ print "Deleting message $$input{id}";
+ }
+ my $box = process_delete($$input{id});
+ if ($DEBUG)
+ { footer(); }
+ else
+ {
+ $box =~ s/^$USER->{username}.//;
+ redirect("$BUCKY/inbox/$box");
+ }
+ }
+
+else # new message: display form
+ {
+ my $recipient;
+ if (exists($$input{username}))
+ { $recipient = $$input{username}; }
+ else
+ { $recipient = ""; }
+ header("new message");
+ menu();
+ message_form($recipient, -1);
+ footer();
+ }
+
+$dbh->disconnect ();
+
+sub process_delete
+ {
+ my ($mid) = (@_);
+ my $message;
+ if (!defined($mid))
+ { error("No id specified!"); }
+ $message = get_message($mid);
+ if ($message == -1)
+ { error("No such message."); }
+ elsif ($$message{recipient} ne $USER->{username})
+ { error("You do not own this message."); }
+ delete_message($mid);
+ recount_mailbox($$message{mbox});
+ return $$message{mbox};
+ }
+print "Message: " . &report_time() . "\n" if $timer;
diff --git a/cgi-bin/murder b/cgi-bin/murder
new file mode 100755
index 0000000..356cf5d
--- /dev/null
+++ b/cgi-bin/murder
@@ -0,0 +1,23 @@
+#!/usr/bin/perl
+#########################################
+# not bless
+#########################################
+
+use localbucky;
+
+$dbh = DBI->connect ($dsn);
+
+our ($USER, $lastlog) = checkin();
+logout() unless ($USER != -1);
+
+my $blessy = $input->{username};
+if (get_uid($blessy) == -1)
+ { error("no such user"); }
+elsif ($blessy eq $USER->{username})
+ { error("THE GUN JAMS"); }
+commit_murder($blessy);
+add_comment(1,-1,"system","BUT WHAT WILL WE DO WITH THE BODY");
+redirect("$BUCKY/index");
+
+$dbh->disconnect ();
+
diff --git a/cgi-bin/playlist b/cgi-bin/playlist
new file mode 100755
index 0000000..9b87d6a
--- /dev/null
+++ b/cgi-bin/playlist
@@ -0,0 +1,81 @@
+#!/usr/bin/perl
+
+use localbucky;
+use URI::Escape;
+
+$dbh = DBI->connect ($dsn);
+
+our ($USER, $lastlog) = checkin();
+our $loggedin = ($USER != -1);
+
+our ($t, $kw, $files) = playlist_init();
+playlist_run($t, $kw, $files);
+
+sub playlist_run
+ {
+ my ($t, $kw, $files) = @_;
+ my $sorty = sub { sort {lc($a->{filename}) cmp lc($b->{filename})} @_ };
+
+ my $z_title = $t->{title};
+ my $z_link = qq($BUCKY/).details_link().qq(/$t->{id});
+ $z_link .= get_revision($t) if ($USER != -1);
+
+ my $rss = <<__RSS__;
+<rss version="2.0" xmlns:media="http://">
+<channel>
+<title>$z_title</title>
+<link>$z_link</link>
+__RSS__
+
+ foreach my $file ($sorty->(@$files))
+ {
+ next if (($file->{username} ne $USER->{username}) && $file->{private} && !$whitelist && $USER->{ulevel} != 3);
+ next unless ($file->{filename} =~ /mp3$/i);
+ my $z_file = $file->{filename};
+ my $z_filepath = uri_escape($file->{filename});
+ my $z_content = "https://$BUCKY_HOST$live_path/$file->{thread}/$z_filepath";
+ $rss .= <<__RSS__;
+<item>
+<title>$z_file</title>
+<link>$z_content</link>
+<description></description>
+<media:content url="$z_content" type="audio/mpeg" />
+</item>
+__RSS__
+ }
+
+ $rss .= "</channel>\n</rss>\n";
+
+ print "Content-type: text/xml\n\n";
+ $rss =~ s/&/&amp;/g;
+ print $rss;
+ }
+
+sub playlist_init
+ {
+ $input->{id} ||= $input->{object_from_uri} if defined($input->{object_from_uri});
+ my $id = exists($input->{id}) ? $input->{id} : error("No such thread!");
+
+ my $t = get_thread($id);
+ error("No such post.") if ($t == -1);
+ my $kw = get_keyword($t->{keyword});
+
+ my $files = get_files($t->{id});
+# my $comments = get_comments ($t->{id});
+
+ if ( ! check_privacy($t, $kw) ) # || check_participation($files, $comments) )
+ #unless ( check_privacy($t, $kw) || check_participation($files, $comments) )
+ { error("No such post!"); }
+
+ # Reset NULL viewed
+ if ( ! $t->{viewed} )
+ { $t->{viewed} = 0; }
+
+ # Increment viewed for this thread
+# $t->{viewed}++;
+ # Update thread viewed count
+# update_thread_viewed( $t->{id}, $t->{viewed} );
+
+ return ($t, $kw, $files); # $comments);
+ }
+
diff --git a/cgi-bin/post b/cgi-bin/post
new file mode 100755
index 0000000..fd2de78
--- /dev/null
+++ b/cgi-bin/post
@@ -0,0 +1,267 @@
+#!/usr/bin/perl
+#########################################
+# post
+# - create a new thread/post from an initial file
+# - form: append multiple files
+#########################################
+
+use localbucky;
+
+my $pid;
+
+$dbh = DBI->connect ($dsn);
+
+our ($USER, $lastlog) = checkin();
+logout() unless ($USER != -1);
+
+if ($input->{c} eq 'new')
+ { new_post_action(); }
+elsif ($input->{c} eq 'reply')
+ { reply_post_action(); }
+else
+ { long_post_form(); }
+
+#################################
+
+sub long_post_form
+ {
+ my $t = -1;
+ my $k = -1;
+ if ( exists($input->{thread}) )
+ {
+ my $header_args;
+
+ $t = get_thread( $input->{thread} );
+ $k = get_keyword( $t->{keyword} );
+
+ error("No such post!") unless ($t != -1);
+ error("No such keyword!") unless ($k == -1 || ($k->{public} || check_op($k)));
+
+ $header_args->{title} = qq(reply to $t->{title});
+ $header_args->{subtitle} = qq(<span class="lite"><a href="$BUCKY/).details_link($t).qq($t->{id}">return to post</a></span>);
+
+ header ($header_args);
+ }
+ elsif ( exists($input->{keyword}) )
+ {
+ my $header_args;
+
+ $k = get_keyword( $input->{keyword} );
+
+ if ($k != -1 && (($k->{public} || check_op($k))))
+ {
+ $header_args->{title} = qq(new $k->{keyword});
+ $header_args->{subtitle} = qq(<span class="lite"><a href=").keyword_link($k).qq(">return to $BUCKY_LEXICON_KEYWORD</a></span>);
+ header ($header_args);
+ }
+ else
+ {
+ header("Creating a new post...");
+ }
+ }
+ else
+ {
+ header("Creating a new post...");
+ }
+
+ menu();
+ print "<p>\n\n";
+ my $checked = '';
+
+ print qq(<form action="$BUCKY/post" method="post" enctype="multipart/form-data">\n);
+ print qq!<input type="hidden" name="debug" value="$DEBUG">\n\n! if ($DEBUG);
+
+ print <<FORMmid;
+<center>
+<table cellpadding=0 cellspacing=0 border=0>
+<tr><td class="bluebox" style="padding: 20px 40px 20px 40px;">
+FORMmid
+
+ if ($t != -1)
+ {
+ print qq!<input type="hidden" name="c" value="reply">!;
+ print qq!<input type="hidden" name="thread" value="$t->{id}">!;
+ print qq!<table border=0 width=100%><tr><td style="text-align: right; vertical-align: center;">replying to:</td><td align="center"><b><big><a href="$BUCKY/!.details_link($t).qq!/$t->{id}">$t->{title}</a></big></b><br>posted !.verbosedate($t->{createdate}).qq! by <a href="$BUCKY/profile/$t->{username}">$t->{username}</a></td></tr></table>!;
+ }
+ else
+ {
+ print qq!<table cellpadding=2 border=0>!;
+ print qq!<tr><td align="right" valign="baseline">!;
+ print qq!title:&nbsp;!;
+ print qq!</td><td align="left" valign="baseline">!;
+ print qq!<input name="title" value="" size=48 maxlength=48><br>\n!;
+ print qq!</tr>!;
+ print qq!<tr><td align="right" valign="baseline">!;
+ print "category: ";
+ print qq!</td><td align="left" valign="baseline">!;
+ if ($k->{public} || check_op($k))
+ {
+ keyword_pulldown($k->{keyword});
+ $checked = $k->{public} ? "" : " checked";
+ }
+ else
+ { keyword_pulldown(); }
+ print qq!</tr>!;
+ print qq!<tr><td align="right" valign="baseline">!;
+ print qq!tags:&nbsp;!;
+ print qq!</td><td align="left" valign="baseline">!;
+ print qq!<input name="tags" value="" size=30 maxlength=48><br>\n!;
+ print qq!</tr>!;
+ print qq!<tr><td align="right" valign="middle">!;
+ print qq!publicity:!;
+ print qq!</td><td align="left" valign="middle">!;
+ # don't need this
+ # print qq!<input type=checkbox name="private" value="1"$checked>!
+ privacy_select("private", $checked);
+ print qq!</td></tr>!;
+ print qq!<tr><td></td><td align="left" valign="top">!;
+ print qq!<small>(can be changed at any time via post settings)</small>\n!;
+ print qq!</td></tr>!;
+ print qq!<tr><td align="right" valign="baseline">!;
+ print qq!</table>!;
+ print qq!<input type="hidden" name="c" value="new">!;
+ }
+
+ print qq!<hr color="$BUCKY_COLOR_HR" size=1>!;
+ print qq!<p><textarea name="comment" cols="52" rows="16"></textarea><p>\n!;
+
+ if (! check_key($t->{display}, "no-upload"))
+ {
+ print <<FORMEND;
+<input type="file" name="file1" size="12" maxlength="192" style="font-size: 10px; font-family: Trebuchet MS, Helvetica, Arial, sans-serif;" /> <input type="file" name="file2" size="12" maxlength="192" style="font-size: 10px; font-family: Trebuchet MS, Helvetica, Arial, sans-serif;" /> <input type="file" name="file3" size="12" maxlength="192" style="font-size: 10px; font-family: Trebuchet MS, Helvetica, Arial, sans-serif;" /><br>
+<input type="file" name="file4" size="12" maxlength="192" style="font-size: 10px; font-family: Trebuchet MS, Helvetica, Arial, sans-serif;" /> <input type="file" name="file5" size="12" maxlength="192" style="font-size: 10px; font-family: Trebuchet MS, Helvetica, Arial, sans-serif;" /> <input type="file" name="file6" size="12" maxlength="192" style="font-size: 10px; font-family: Trebuchet MS, Helvetica, Arial, sans-serif;" /><br>
+<input type="file" name="file7" size="12" maxlength="192" style="font-size: 10px; font-family: Trebuchet MS, Helvetica, Arial, sans-serif;" /> <input type="file" name="file8" size="12" maxlength="192" style="font-size: 10px; font-family: Trebuchet MS, Helvetica, Arial, sans-serif;" /> <input type="file" name="file9" size="12" maxlength="192" style="font-size: 10px; font-family: Trebuchet MS, Helvetica, Arial, sans-serif;" /><p>
+FORMEND
+ }
+ print qq(<table cellpadding=0 cellspacing=0 border=0 width=100%><tr><td width=90% align="center"><small>);
+# if ($t != -1)
+# { print qq(remember! you can always use <a href="$BUCKY/import?id=$t->{id}"><u><b>ftp</b></u></a> to upload files . . .); }
+# else
+# { print qq(remember! you can always use <a href="$BUCKY/import"><u><b>ftp</b></u></a> to upload files . . .); }
+ print "&nbsp;";
+ print <<FORMEND;
+</small></td>
+<td align="left"><input type="submit" value="POST" class="clicky"></td></tr></table>
+</form>
+</td></tr></table>
+</center>
+FORMEND
+ footer();
+ }
+
+sub new_post_action
+ {
+ my $files;
+ my $title = '';
+ my $private = 0;
+ my $k;
+
+ $k = get_keyword($input->{keyword}) if (exists($input->{keyword}) && ($input->{keyword} ne "NONE"));
+
+ if ($input->{title})
+ {
+ $title = $input->{title};
+ $title =~ s/^\s+//;
+ $title =~ s/\s+/ /g;
+ $title =~ s/_/ /g;
+ }
+ else
+ {
+ for (my $i = 1; $i < 10; $i++)
+ {
+ if ($input->{"file".$i} ne "temp_")
+ {
+ $title = $input->{"file".$i};
+ $i = 11;
+ }
+ }
+ if ($title)
+ {
+ $title =~ s/^temp_//i;
+ $title =~ s/\.....?$//;
+ $title =~ s/^\s+//;
+ $title =~ s/\s+/ /g;
+ $title =~ s/_/ /g;
+ }
+ elsif ($$input{"comment"})
+ {
+ $title = "dER buCKYiSt ***cHaTTEN**** AUF ZZem *AwL**";
+ }
+ else
+ {
+ error ("No title specified!");
+ }
+ }
+
+ if ($DEBUG)
+ {
+ header("new post");
+ print "attempting to make a new post: $title<p>";
+ }
+
+ $private = $input->{private} if ($input->{private});
+
+ $thread_id = add_thread($title, $USER->{username}, $private);
+ print "id: $thread_id<p>" if ($DEBUG);
+ add_comment($thread_id,-1,$USER->{username},$$input{comment});
+ situate_files($thread_id, $USER->{username});
+ switch_thread_privacy($thread_id, $private);
+ if ($k->{public} || check_op($k))
+ {
+ keyword_assign_mechanism($k->{keyword}, $thread_id, $k);
+ }
+
+ # Check for any supplied tags
+ if (exists($input->{tags}) && (length(trim($input->{tags}) ) > 0) )
+ {
+ # Unpack tags from the form text field (remove delimiters, retrieve already existing tags,
+ # create new tags
+ my $tags = get_tags_from_string( $input->{tags} );
+
+ # Loop through each tag
+ foreach my $tag (@$tags)
+ {
+ # should we even get this??
+# next unless ($tag->{public} || check_op($tag));
+
+ # Associate this tag with this thread
+ tag_assign_mechanism( $tag, $thread_id );
+ }
+ }
+
+ if ($DEBUG)
+ {
+ print qq{this way to your new post: <a href="$BUCKY/details/$thread_id">link!</a>};
+ footer();
+ }
+
+ if ($k != -1)
+ {
+ redirect("$BUCKY/".details_link($k)."/$thread_id");
+ }
+ else
+ {
+ redirect("$BUCKY/$BUCKY_LEXICON_DETAILS/$thread_id");
+ }
+ }
+
+sub reply_post_action
+ {
+ if ($DEBUG)
+ {
+ header("posting to $input->{thread}");
+ }
+ my $thread = (exists($input->{thread})) ? get_thread($input->{thread}) : error("No such thread!");
+ my $keyword = ($thread->{keyword}) ? get_keyword($thread->{keyword}) : -1;
+ error("Cannot see comment!") unless (check_privacy($thread) || check_op($keyword));
+
+ print "id: $thread->{id}<p>" if ($DEBUG);
+ add_comment($thread->{id}, -1, $USER->{username}, $input->{comment}) if ($input->{comment} ne undef);
+ situate_files($thread->{id}, $USER->{username});
+ switch_thread_privacy($thread->{id}, $thread->{private});
+ redirect("$BUCKY/".details_link($thread)."/$thread->{id}");
+ }
+
+$dbh->disconnect ();
+
+print "Post: " . &report_time() . "\n" if $timer;
diff --git a/cgi-bin/profile b/cgi-bin/profile
new file mode 100755
index 0000000..93dc089
--- /dev/null
+++ b/cgi-bin/profile
@@ -0,0 +1,167 @@
+#!/usr/bin/perl
+#########################################
+# profile
+# maintain a user's profile
+# or print a form
+#########################################
+
+use localbucky;
+
+my $pid;
+
+$dbh = DBI->connect ($dsn);
+
+our ($USER, $lastlog) = checkin();
+our $loggedin = ($USER != -1);
+
+sub main
+ {
+ $input->{username} ||= $input->{object_from_uri} if defined($input->{object_from_uri});
+ my ($keywords) = get_keywords();
+
+ if (exists($input->{c}) && $input->{c} eq "sticky" && defined($input->{keyword}))
+ {
+ logout() unless ($loggedin);
+ my $keyword = $input->{keyword};
+ print "Switching keyword $keyword for $USER->{username} ..." if ($DEBUG);
+ my $stkcy = check_key($keyword, $USER->{stickies});
+ my $newk;
+ if (exists($input->{chexor}))
+ { $newk = add_key($USER->{stickies}, $keyword); }
+ else
+ { $newk = delete_key($USER->{stickies}, $keyword); }
+ update_user_sticky($USER->{username}, $newk);
+ redirect("$BUCKY/index");
+ }
+ elsif (exists($input->{username}))
+ {
+ if ($USER->{username} eq $input->{username})
+ {
+ header( {
+ title => "profile for $input->{username}",
+ subtitle => qq!<a href="$BUCKY/profile?c=form">edit your profile</a>!
+ } );
+ }
+ elsif ($input->{username} eq "system")
+ {
+ $input->{username} = "marc";
+ header("profile for $input->{username}");
+ }
+ elsif (get_uid($input->{username}) == -1)
+ { nice_redirect(); }
+ else
+ { header("profile for $input->{username}"); }
+ menu();
+ show_profile($input->{username});
+ }
+ elsif ($input->{c} eq 'form')
+ {
+ logout() unless ($loggedin);
+ header( {
+ title => "editing $USER->{username}'s profile",
+ subtitle => qq!<a href="$BUCKY/profile">view your profile</a>!
+ } );
+
+ menu();
+ profile_form($USER->{username});
+ }
+ elsif ($input->{c} eq 'update')
+ {
+ logout() unless ($loggedin);
+ my $messages = '';
+ if (exists($input->{rmpic}) && $input->{rmpic} == 1)
+ {
+ system("rm", "-f", "$data_path/profile/$USER->{username}.jpg");
+ system("rm", "-f", "$data_path/profile/.thumb/$AVATAR_PROFILE_PREFIX$USER->{username}.jpg");
+ system("rm", "-f", "$data_path/profile/.thumb/$AVATAR_BIG_PREFIX$USER->{username}.jpg");
+ system("rm", "-f", "$data_path/profile/.thumb/$AVATAR_MED_PREFIX$USER->{username}.jpg");
+ $messages .= "old profile image deleted<br>\n";
+ }
+ if (exists($input->{pw1}) && exists($input->{pw2}) && $input->{pw1} && $input->{pw2})
+ {
+ if ($input->{pw1} eq $input->{pw2})
+ {
+ update_password($USER->{username}, crypt($input->{pw1},lc($USER->{username})));
+ $messages .= qq(password changed -- please <a href="/bucky/">log back in</a><br>\n);
+ }
+ else
+ {
+ $messages .= "passwords don't match!<br>\n";
+ }
+ }
+ if (exists($input->{stickies}))
+ {
+ my $s;
+ $input->{stickies} =~ s/[^A-Za-z0-9 ]//;
+ foreach my $k (split / /, $input->{stickies})
+ {
+ next unless ($keywords->{$k});
+ $s = add_key($s, lc($k));
+ }
+ $input->{stickies} = $s;
+ }
+ if (exists($input->{sink}))
+ {
+ my $s;
+ $input->{sink} =~ s/[^A-Za-z0-9 ]//g;
+ foreach my $k (split / /, $input->{sink})
+ {
+ next unless ($keywords->{$k});
+ $s = add_key($s, lc($k));
+ }
+ $input->{sink} = $s;
+ }
+
+ my (@boxes) = qw[welcome bPod radio postform hootbox photostream autoplay showhidden nologout];
+ my $newboxes = ' ';
+ foreach my $key (@boxes)
+ {
+ if (exists($input->{$key}) && $input->{$key} == 1)
+ { $newboxes = add_key($newboxes, $key); }
+ }
+ if ($USER->{boxes} ne $newboxes)
+ {
+ update_user_boxes($USER->{username}, $newboxes);
+ $USER->{boxes} = $newboxes;
+ $messages .= "New box settings: <b>$USER->{boxes}</b><br>\n" if ($DEBUG);
+ }
+
+ if ($loggedin && update_profile($USER->{username}, $input))
+ {
+ $USER->{timezone} = $input->{timezone};
+ $dateoffset = -1;
+ $messages .= "profile updated<br>"
+ }
+ if ($loggedin && update_profile_image($USER->{username}))
+ {
+ $messages .= "profile image updated<br>";
+ }
+
+ header( {
+ title => "updating profile...",
+ subtitle => qq!<a href="$BUCKY/profile?c=form">edit your profile</a>!
+ } );
+ menu();
+ print qq(<div style="padding: 30px;"><div class="bluebox">$messages);
+ print qq(</div></div><hr color="$BUCKY_COLOR_HR" style="padding: 0px; margin: 2px;">);
+ show_profile($USER->{username});
+ }
+ else
+ {
+ logout() unless ($loggedin);
+ header( {
+ title => "profile for $USER->{username}",
+ subtitle => qq!<a href="$BUCKY/profile?c=form">edit your profile</a>!
+ } );
+ menu();
+ show_profile($USER->{username});
+ }
+
+ footer();
+ }
+
+main();
+
+$dbh->disconnect ();
+
+print "Profile: " . &report_time() . "\n" if $timer;
diff --git a/cgi-bin/recipe b/cgi-bin/recipe
new file mode 100755
index 0000000..4f134c0
--- /dev/null
+++ b/cgi-bin/recipe
@@ -0,0 +1,148 @@
+#!/usr/bin/perl
+
+use localbucky;
+use JSON;
+
+$dbh = DBI->connect ($dsn);
+
+# our ($USER, $lastlog) = checkin();
+# our $loggedin = ($USER != -1);
+
+recipe_run();
+
+my $VALID_RECIPE_FIELDS = {};
+foreach my $field (qw[ title tags time cost skill servings calories equipment source ]);
+ { $VALID_RECIPE_FIELDS->{$field} = 1; }
+
+sub recipe_run
+ {
+ our ($t, $kw, $files, $comments) = recipe_init();
+
+ my $recipe;
+ my $title = $t->{'title'};
+
+ FIND_RECIPE:
+ {
+ foreach my $comment (@$comments)
+ {
+ $recipe = parse_comment_into_recipe($comment, $title);
+ if (is_valid_recipe_object($recipe)
+ {
+ last FIND_RECIPE;
+ }
+ }
+ print "Content-type: text/plain\n\n";
+ print "No recipe found!"
+ exit;
+ }
+
+ my ($many_jpgs, $flagged) = find_jpeg_v2($files, $t->{flagged});
+ if ($flagged != -1)
+ {
+ my $uri = "$live_path/";
+ $uri .= $flagged->{thread};
+ $uri .= "/.thumb/s.";
+ $uri .= lc($flagged->{filename})
+ $recipe->{'img'} = "https://www.carbonpictures.com$uri";
+ }
+
+ my $json = new JSON;
+ print "Content-type: application/json\n\n";
+ print $json->pretty->encode($recipe);
+ }
+
+sub recipe_init
+ {
+ $input->{id} ||= $input->{object_from_uri} if defined($input->{object_from_uri});
+ my $id = exists($input->{id}) ? $input->{id} : error("No such thread!");
+
+ my $t = get_thread($id);
+ error("No such post.") if ($t == -1);
+ my $kw = get_keyword($t->{keyword});
+
+ my $files = get_files($t->{id});
+ my $comments = get_comments ($t->{id});
+
+ if ( ! check_privacy($t, $kw) ) # || check_participation($files, $comments) )
+ #unless ( check_privacy($t, $kw) || check_participation($files, $comments) )
+ { error("No such post!"); }
+
+ return ($t, $kw, $files, $comments);
+ }
+
+sub is_valid_recipe_object
+ {
+ my ($recipe) = @_;
+ if ( exists($recipe->{'ingredients'}) && exists($recipe->{'directions'}) )
+ { return 1; }
+ else
+ { return 0; }
+ }
+sub parse_comment_into_recipe
+ {
+ my ($comment, $title) = @_;
+ my $recipe = {};
+ $recipe->{'chef'} = { name => $comment->{'username'} };
+ my @lines = split "\n", $comment->{'comment'};
+ my $last_line_was_ingredient = 0;
+ my $last_line_was_direction = 0;
+ foreach my $line (@lines)
+ {
+ chomp $line;
+ # key/value instruction
+ if (! length($line) )
+ {
+ $last_line_was_ingredient = 0;
+ $last_line_was_direction = 0;
+ next;
+ }
+ elsif ($line =~ /: /)
+ {
+ my ($key, $value) = split ": ", $line;
+ if (exists( $VALID_RECIPE_FIELDS->{$key} )
+ { $recipe->{$key} = $value; }
+ }
+ # direction
+ elsif ($line =~ /^(\d+\.|\-+|\*+)\s?/ || $last_line_was_direction)
+ {
+ my $bullet = $1;
+ $line =~ s/^$bullet//;
+ $last_line_was_direction = 1;
+ $recipe->{'directions'} ||= [];
+ push @{ $recipe->{'directions'} }, { display => $line };
+ }
+ # ingredient
+ elsif ($line =~ /^\d/ || $last_line_was_ingredient)
+ {
+ $recipe->{'ingredients'} ||= [];
+ push @{ $recipe->{'ingredients'} }, { display => $line };
+ $last_line_was_ingredient = 1;
+ }
+ else
+ {
+ if (! exists($recipe->{'name'}) && $line !~ /[^A-Z0-9 -]/)
+ {
+ $recipe->{'name'} = capitalize($line);
+ }
+ elsif (!exists( $recipe->{'ingredients'} ))
+ {
+ $recipe->{'notes'} ||= {};
+ $recipe->{'notes'}->{'intro'} .= $line;
+ }
+ else
+ {
+ $recipe->{'directions'} ||= [];
+ push @{ $recipe->{'directions'} }, { display => $line };
+ }
+ }
+ }
+ $recipe->{'name'} ||= $title;
+ return $recipe;
+ }
+sub capitalize
+ {
+ my ($self, $match) = @_;
+ $match =~ s/([\w']+)/\u\L$1/g;
+ return $match;
+ }
+
diff --git a/cgi-bin/services_f b/cgi-bin/services_f
new file mode 100755
index 0000000..ba51e4d
--- /dev/null
+++ b/cgi-bin/services_f
@@ -0,0 +1,83 @@
+#!/usr/bin/perl
+#########################################
+# services_f
+# feeds bPod the file list for a valid thread
+#########################################
+
+use localbucky;
+
+$dbh = DBI->connect ($dsn);
+
+our $KWAREZ = $BUCKY_CONFIG->{BPOD_SERVICES_WAREZ_DIR};
+
+our ($USER, $lastlog) = checkin();
+
+our $logged_in = ($USER != -1);
+
+# this start/end shit is all broken anyway
+#my $start = $input->{s};
+#my $end = $input->{e};
+my $pid = $input->{pid};
+
+print "Content-type: text/html\r\n\r\n";
+
+my $thread = get_thread( $pid );
+my $keyword = get_keyword( $thread->{keyword} );
+exit unless check_privacy( $thread, $keyword );
+
+my $files = get_files( $pid );
+
+my $numItems = @$files;
+
+my $returnString = " &numItems=" . ($numItems );
+
+@$files = sort{ lc($a->{filename}) cmp lc($b->{filename}) } @$files;
+
+my $fileCount = 0;
+foreach my $file_row (@$files)
+ {
+ $returnString .= "&filetype$fileCount=" . fileEXT($file_row->{filename});
+ $returnString .= "&filename$fileCount=" . lc($file_row->{filename});
+ $returnString .= "&username$fileCount=" . $file_row->{username};
+ $returnString .= "&date$fileCount=" . $file_row->{date};
+ $returnString .= "&url$fileCount=" . $KWAREZ . $file_row->{thread} ."/". spaceReplace($file_row->{filename});
+ $returnString .= "&size$fileCount=" . sizeinK($file_row->{size});
+ $fileCount++;
+ }
+print $returnString ;
+
+exit;
+
+sub fileEXT
+ {
+ my $filename = shift;
+ $filename =~ s/.+\.//;
+ return uc($filename);
+ }
+sub spaceReplace
+ {
+ my $filename = shift;
+ $filename =~ s/\ /\%20/g;
+ return $filename;
+ }
+sub sizeinK
+ {
+ my $bytes = shift;
+ my $size = $bytes / 1024;
+ if ( $size < 1024 )
+ {
+ $size = sprintf "%2.2f", $size;
+ $size .= "k";
+ }
+ elsif ( $size / 1024 < 1024 )
+ {
+ $size = sprintf "%2.2f", $size / 1024;
+ $size .= "mb";
+ }
+ elsif ( $size / 1024 / 1024 < 1024 )
+ {
+ $size = sprintf "%2.2f", $size / 1024 / 1024;
+ $size .= " GB";
+ }
+ return $size;
+ }
diff --git a/cgi-bin/services_k b/cgi-bin/services_k
new file mode 100755
index 0000000..3ce9940
--- /dev/null
+++ b/cgi-bin/services_k
@@ -0,0 +1,62 @@
+#!/usr/bin/perl
+#########################################
+# services_k
+# feeds bPod the keyword list for logged in user
+#########################################
+
+use localbucky;
+
+$dbh = DBI->connect ($dsn);
+
+our ($USER, $lastlog) = checkin();
+
+our $logged_in = ($USER != -1);
+
+our $TAGS = [ 'Docks', 'Dings', 'Mexico', 'France', 'Breakfast', 'Baked', 'Sandwich' ];
+
+# this start/end shit is all broken anyway
+#my $start = $input->{s};
+#my $end = $input->{e};
+
+my $keywords_hashref = get_keywords();
+my $keywords_arrayref = [];
+
+print "Content-type: text/html\r\n\r\n";
+foreach my $keyword (keys(%$keywords_hashref))
+ {
+ my $k = $keywords_hashref->{$keyword};
+ push ( @$keywords_arrayref, $keyword ) if (check_keyword($k));
+ }
+
+my $numItems = @$keywords_arrayref;
+
+my $returnString = " &numItems=" . ($numItems );
+#$returnString = "duhhh";
+
+@$keywords_arrayref = sort{ lc($a) cmp lc($b) } @$keywords_arrayref;
+
+my $keywordCount = 0;
+foreach my $keyword (@$keywords_arrayref)
+ {
+ $returnString .= "&keyword$keywordCount=$keyword";
+ my $color = $keywords_hashref->{$keyword}->{color} || "plain";
+ $returnString .= "&color$keywordCount=$color";
+ $keywordCount++;
+ }
+
+#@$tags_arrayref = sort{ $a cmp $b } @$TAGS;
+my $tags_arrayref = get_tag_names();
+@$tags_arrayref = sort{ lc($a) cmp lc($b) } @$tags_arrayref;
+my $numTags = @$tags_arrayref;
+
+$returnString .= "&numTags=" . $numTags;
+
+my $tagCount = 0;
+foreach my $tag (@$tags_arrayref)
+ {
+ $returnString .= "&tag$tagCount=$tag";
+ $tagCount++;
+ }
+
+print $returnString ;
+exit(0);
diff --git a/cgi-bin/services_th b/cgi-bin/services_th
new file mode 100755
index 0000000..6e2bb67
--- /dev/null
+++ b/cgi-bin/services_th
@@ -0,0 +1,54 @@
+#!/usr/bin/perl
+#########################################
+# services_th
+# feeds bPod the keyword list for logged in user
+#########################################
+
+use localbucky;
+
+$dbh = DBI->connect ($dsn);
+
+our ($USER, $lastlog) = checkin();
+
+our $logged_in = ($USER != -1);
+
+print "Content-type: text/html\r\n\r\n";
+
+my $threads;
+
+my $kws = {};
+my $keyword = $input->{k};
+if ($keyword =~ /^tag_/)
+ {
+ $keyword =~ s/^tag_//;
+ $threads = get_threads_by_tag( $keyword );
+ $kws = get_keywords();
+ }
+else
+ {
+ $kws->{$keyword} = get_keyword($keyword);
+ $threads = get_threads_by_keyword( $keyword );
+ }
+
+my $threads_allowed = [];
+foreach my $thread (@$threads)
+ {
+ push ( @$threads_allowed, $thread ) if (check_privacy( $thread, $kws->{$thread->{keyword}} ) > 0);
+ }
+
+my $numItems = @$threads_allowed;
+
+my $returnString = " &numItems=" . ($numItems );
+
+@$threads_allowed = sort{ lc($b->{title}) cmp lc($a->{title}) } @$threads_allowed;
+
+my $threadCount = $numItems - 1;
+foreach my $thread (@$threads_allowed)
+ {
+ $returnString .= "&title$threadCount=" . $thread->{title};
+ $returnString .= "&user$threadCount=" . $thread->{username};
+ $returnString .= "&id$threadCount=" . $thread->{id};
+ $threadCount--;
+ }
+print $returnString ;
+exit;
diff --git a/cgi-bin/settings b/cgi-bin/settings
new file mode 100644
index 0000000..e2b3b1f
--- /dev/null
+++ b/cgi-bin/settings
@@ -0,0 +1,24 @@
+#!/usr/bin/perl
+
+use localbucky;
+
+$dbh = DBI->connect ($dsn);
+
+our ($USER, $lastlog) = checkin();
+our $loggedin = ($USER != -1);
+
+#nice_redirect() if ($USER->{ulevel} != 3);
+
+header("bucky spritz tester", qq(<a href="$BUCKY/adminzz">roll back adminzz</a>) );
+menu();
+my $id = exists($input->{id}) ? $input->{id} : 165;
+my $thread = get_thread($id);
+my $keyword = get_keyword($thread->{keyword});
+my $files = get_files($id);
+print qq(<center><table border=0 cellpadding=0 cellspacing=0><tr><td>);
+find_jpeg($files, $thread->{flagged});
+sideshow_comments($thread, $keyword);
+reply_form($thread->{id}, $thread);
+print qq(</td></tr></table></center>);
+footer();
+
diff --git a/cgi-bin/tag b/cgi-bin/tag
new file mode 100755
index 0000000..6af4520
--- /dev/null
+++ b/cgi-bin/tag
@@ -0,0 +1,290 @@
+#!/usr/bin/perl
+#########################################
+# index
+# - do all index stuff, also deal with keyword admin
+#########################################
+
+use localbucky;
+
+$dbh = DBI->connect ($dsn);
+
+our ($USER, $lastlog) = checkin();
+
+my $k;
+my $tag;
+
+# check name of the calling script: index, tag, keyword
+$input->{script} ||= $input->{script_from_uri} if defined($input->{script_from_uri});
+
+# load the tag or keyword into the input params, if they don't exit already
+if ( $input->{script} eq $BUCKY_LEXICON_TAG )
+ {
+ $input->{tag} ||= $input->{object_from_uri} if defined($input->{object_from_uri});
+ }
+elsif ( $input->{script} eq $BUCKY_LEXICON_KEYWORD )
+ {
+ $input->{keyword} ||= $input->{object_from_uri} if defined($input->{object_from_uri});
+ }
+
+# Get keyword
+if (exists($input->{keyword}) && $input->{keyword} ne "new" && $input->{keyword} ne "unsorted")
+ {
+ $k = get_keyword($input->{keyword});
+ }
+
+
+# Create New Keyword? FORM
+if (exists($input->{keyword}) && $input->{keyword} eq "new")
+ {
+ my $t;
+ header("add new category");
+ if (exists($input->{thread}))
+ {
+ $t = get_thread($input->{thread});
+ }
+ menu();
+ print "<br><br>";
+ my %faek =
+ (
+ keyword => $input->{keyword},
+ thread => $input->{thread}
+ );
+ keyword_form($input->{keyword}, \%faek, $t);
+ footer();
+ }
+
+# Edit settings for keyword
+elsif ($input->{c} eq "edit" && (check_op($k) || $USER->{ulevel} == 3))
+ {
+ header(
+ {
+ title => "settings for category '$input->{keyword}'",
+ sticky => $input->{keyword}
+ } );
+ # 20070903 - marc - new menu args calling style
+ my $menu_args;
+ $menu_args->{keywords} = $k if $k;
+ menu( $menu_args );
+# menu($k);
+ print "<br><br>";
+
+ keyword_form($k->{keyword}, $k);
+
+ print qq!<center><table border=0 cellpadding=0 cellspacing=0 class="threadmain" width="580">!;
+ my $threads = get_threads_by_keyword($k->{keyword});
+ thread_box({ threads => $threads, kw => $k });
+
+ print qq!</table>!;
+ footer();
+ }
+
+# Create new keyword? Process form results
+elsif ($input->{c} eq "create")
+ {
+ if (!defined($input->{keyword}))
+ { error("no keyword specified!"); }
+ if (get_keyword($input->{keyword}) != -1)
+ { error("keyword already exists!"); }
+ my %nk =
+ (
+ keyword => $input->{keyword},
+ threads => " $input->{thread} ",
+ owner => $USER->{username},
+ public => $input->{public},
+ agglutinate => $input->{agglutinate},
+ color => $input->{color},
+ ops => (make_whitelist())
+ );
+ if ($DEBUG)
+ {
+ header("Creating keyword $input->{keyword}");
+ menu();
+ foreach my $ky (keys %nk)
+ { print "$ky => $nk{$ky}<br>\n"; }
+ }
+ add_keyword(\%nk);
+ update_thread_keyword($input->{thread}, $input->{keyword});
+ redirect("$BUCKY/$BUCKY_LEXICON_KEYWORD/$input->{keyword}");
+ }
+
+# Edit settings for keyword? Process form results
+elsif ($input->{c} eq "update")
+ {
+ if (!defined($input->{keyword}))
+ { error("no keyword specified!"); }
+ my %nk =
+ (
+ threads => " $input->{thread} ",
+ public => (exists($input->{public}) ? 1 : 0),
+ agglutinate => (exists($input->{agglutinate})) ? $input->{agglutinate} : 0,
+ color => $input->{color}
+ );
+ if (!exists($input->{public}))
+ {
+ $nk{ops} = make_whitelist();
+ }
+ if ($DEBUG)
+ {
+ header("Updating keyword $input->{keyword}");
+ menu();
+ foreach my $ky (keys %nk)
+ { print "$ky => $nk{$ky}<br>\n"; }
+ }
+ update_keyword($input->{keyword}, \%nk);
+ redirect("$BUCKY/$BUCKY_LEXICON_KEYWORD/$input->{keyword}");
+ }
+
+# Assign keyword processing form action
+elsif ($input->{c} eq "assign")
+ {
+ keyword_assign_mechanism($input->{keyword}, $input->{thread}, $k);
+ redirect("$BUCKY/maintain/$input->{thread}");
+ # redirect("$BUCKY/index?keyword=$input->{keyword}");
+ }
+
+# Detach keyword action
+elsif ($input->{c} eq "detach")
+ {
+ my $t;
+
+ if (!defined($input->{thread}))
+ { error("no post specified!"); }
+ $t = get_thread($input->{thread});
+ $k = get_keyword($t->{keyword});
+
+ my %nk = ( threads => delete_key($k->{threads}, $input->{thread}) );
+
+ if ($DEBUG)
+ {
+ header("Detaching post from $t->{keyword}");
+ menu();
+ foreach my $ky (keys %nk)
+ { print "$ky => $nk{$ky}<br>\n"; }
+ print "keyword ==> $t->{keyword}<br>\n";
+ print "detaching <b>$t->{title}</b> from <b>$t->{keyword}</b><br>\n";
+ }
+ update_keyword($t->{keyword}, \%nk);
+ update_thread_keyword($t->{id}, "NULL");
+ redirect("$BUCKY/maintain/$t->{id}");
+ }
+
+# Display main index page
+else
+ {
+ my $tag = exists($input->{tag}) ? $input->{tag} : undef;
+ my $keyword = exists($input->{keyword}) ? $input->{keyword} : "all";
+ my $limit = exists($input->{limit}) ? int($input->{limit}) : 40;
+ my $date = exists($input->{start}) ? int($input->{start}) : "now";
+
+ header({ title => get_random_line("titles"), sticky => $input->{keyword} });
+ my $keywords = get_keywords();
+ my $tags = get_tags();
+
+ my $menu_args;
+ $menu_args->{keywords} = $keywords->{$keyword} if $keywords->{$keyword};
+ menu( $menu_args );
+
+ print qq(<table width="100%" cellpadding=0 cellspacing=0 border=0>);
+ print qq(<tr>);
+#############################
+# KEYWORD LIST
+ print qq(<td align=center valign=top width="100">\n);
+ print qq(<div class="bluebox"><span style="line-height: 1.5em;"><nobr>);
+ my $p = ''; my $l = '';
+ my $with_letter = 0;
+ my $s = '';
+my $pre = '';
+ my $start = '';
+ foreach my $k (sort { lc($a) cmp lc($b) } keys %$keywords)
+ {
+ my $style;
+ $l = substr($k,0,1);
+ $start ||= $l;
+ if ($p && lc($l) ne lc($p))
+ {
+ if ($with_letter > 3)
+ {
+ print qq(<big><big><b>$start - $pre</b></big></big><br> );
+ print $s;
+ print qq(</nobr></span></div>);
+ print qq(<div class="bluebox"><span style="line-height: 1.5em;"><nobr>);
+ $s = '';
+ $with_letter = 1;
+ $p='';
+ $start = $l;
+ }
+ }
+ $with_letter += 1;
+ $p||=$l;
+ $pre=$l;
+ $s .= qq(<a style="$css" href="$BUCKY/category/$k">$k</a><br>);
+ }
+if ($s)
+ {
+ print qq(<big><big><b>$start - $pre</b></big></big><br> );
+ print $s;
+ print qq(</div>);
+ print qq(<div class="bluebox"><small><span style="line-height: 1.5em;"><nobr>);
+ }
+ print qq(</div>);
+ print qq(<div class="bluebox"><small><span style="line-height: 1.5em;"><nobr>);
+ print qq(.: <a href="$BUCKY/category/unsorted"><i>unsorted</i></a> :.<br>);
+ print qq(</nobr></span></small></div></td>\n);
+
+ print qq(<td width="300" align=right valign=top>\n);
+
+ alerts();
+ if ($USER == -1)
+ {
+ bPod_box();
+ print qq(</td></tr>);
+ }
+ else
+ {
+ welcome_box() if (check_key($USER->{boxes}, "welcome"));
+ bPod_box() if (check_key($USER->{boxes}, "bPod"));
+ radio_box() if (check_key($USER->{boxes}, "radio"));
+ upload_form($keyword) if (check_key($USER->{boxes}, "postform"));
+ hoot_box() if (check_key($USER->{boxes}, "hootbox"));
+ }
+
+ print qq(</td><td align=left valign=top>\n);
+
+ if (check_key($USER->{boxes}, "photostream") || ($USER == -1) )
+ {
+ if ( $keyword ne "all" )
+ { photostream({ keyword => $keyword, vertical => 0, count => 4 }); }
+ elsif ( $tag )
+ { photostream({ tag => $tag, vertical => 0, count => 4 }); }
+ else
+ { photostream({ user => 1, vertical => 0, count => 4 }); }
+ }
+
+ print qq(<center><table border=0 cellpadding=0 cellspacing=0 class="threadmain" width="580">);
+
+ if ($keyword ne "all")
+ {
+ my $threads = throttle_threads({ keyword => $keyword, newest => $date });
+ thread_box({ threads => $threads, kw => $keywords->{$keyword} });
+ }
+ elsif ($tag)
+ {
+ my $threads = throttle_threads({ tag => $tag, newest => $date });
+ thread_box({ threads => $threads, tag => $tags->{$tag} });
+ }
+ else
+ {
+ alpha_index($keywords, $limit, $date);
+ }
+
+ print qq(</table>);
+ print qq(</td>\n);
+ print qq(</tr>);
+ print qq(</table>\n\n);
+
+ footer();
+ }
+
+$dbh->disconnect ();
+
+print "Index: " . &report_time() . "\n" if $timer;
diff --git a/cgi-bin/users b/cgi-bin/users
new file mode 100755
index 0000000..b82a823
--- /dev/null
+++ b/cgi-bin/users
@@ -0,0 +1,228 @@
+#!/usr/bin/perl
+#########################################
+# display userlist
+#########################################
+
+use localbucky;
+use invite;
+
+$dbh = DBI->connect ($dsn);
+
+($USER, $lastlog) = checkin();
+logout() if ($USER == -1);
+
+ my $users = get_all_users();
+ my $keywords = get_keywords();
+
+ header( $BUCKY_CONFIG->{USERLIST_TITLE} );
+ menu();
+
+ our $command = -1;
+
+ print qq(<table width="100%" cellpadding=0 cellspacing=0 border=0>);
+ print qq(<tr><td align=center valign=top>\n);
+
+ display_user_list($users);
+
+ print qq(</td>\n<td width="200" align=right valign=top>\n);
+
+ invite_result_box($command, $hash, $result) if ($command != -1);
+ invite_create_box() if ($USER->{'ulevel'} > 1);
+ grass_box($users);
+
+ print qq(</td></tr></table>\n\n);
+
+ footer();
+
+sub grass_box
+ {
+ my ($users) = @_;
+ print qq(<div class="message">);
+ print qq(<b>newest users</b>\n);
+ my $i = 0;
+ print "<table border=0 cellpadding=0 cellspacing=3>";
+ foreach my $duder (sort_by_firstseen(@$users))
+ {
+ next if ($duder->{ulevel} < 1);
+ next if ($duder->{firstseen} == 0);
+ my $z_date = verbosedate($duder->{firstseen});
+ my $z_user = $duder->{username};
+ my $z_grass = $duder->{grass};
+ print qq(<tr><td colspan=2><hr noshade color="$BUCKY_COLOR_HR">\n</td></tr>);
+ print qq(<tr>);
+ print qq(<td align="left"><b><a href="$BUCKY/profile/$z_user">$z_user</a></b></td>);
+ print qq(<td align="right"><small>$z_date</small></td>);
+ print qq(</tr>);
+ if (length($z_grass))
+ {
+ print qq(<tr>);
+ print qq(<td align="left" colspan=2>);
+ print "$z_grass";
+ print qq(</td>);
+ print qq(</tr>);
+ }
+ last if (++$i == 20);
+ }
+ print qq(</table>\n);
+ print qq(</div>\n);
+ }
+
+sub display_user_list
+ {
+ my ($users) = @_;
+ print qq[<table border=0 cellpadding=2 cellspacing=0>];
+ print qq[<tr>\n];
+ print qq(<td>&nbsp;</td>\n);
+print <<userrows;
+<td class="head">&nbsp;</td>
+<td class="head" style="padding-left: 4px; padding-right: 8px;"><b>username</b></td>
+<td class="head" style="padding-left: 4px; padding-right: 8px;"><b>realname</b></td>
+<td class="head" style="padding-left: 4px; padding-right: 2px; text-align: right;"><b>idle</b></td>
+<td class="head" style="padding-left: 4px; padding-right: 8px;" colspan=3><b>&nbsp;</b></td>
+userrows
+ # print qq(<td class="head" style="padding-left: 4px; padding-right: 8px;">&nbsp;</td>\n) if ($USER->{ulevel} == 3);
+ print "</tr>\n";
+
+ my $r = 0;
+ my $i = 0;
+ my $today = 0;
+ my $neg = 0;
+ my $show_all = (exists($input->{showall})) ? 1 : 0;
+
+ foreach my $duder (sort_by_username(@$users))
+ {
+ next if ($duder->{ulevel} < 1);
+ my $vanished =
+ (
+ $duder->{ccount} < 1
+ && $duder->{fcount} < 1
+ && (time - $duder->{lastseen}) > 14*24*3600
+ );
+ if ($vanished && !$show_all)
+ {
+ $neg++;
+ next;
+ }
+ print qq[<tr class="row$r">];
+ print_blank_cell(qq(<small><a href="$BUCKY/profile/$$duder{username}">profile</a>&nbsp;&middot;&nbsp;<a href="$BUCKY/message/$$duder{username}">send&nbsp;message</a>&nbsp;&middot;</small>), "right", "blank");
+
+ my $image = get_profile_image($duder->{username}, $AVATAR_MED_PREFIX);
+ if ($image != -1)
+ {
+ my $av .=
+ qq(<a href="$BUCKY/profile/$duder->{username}">).
+ qq(<img src="$image" width="$AVATAR_MED_WIDTH" border=1">).
+ qq(</a>);
+ print_user_cell($av);
+ }
+ else
+ {
+ print_user_cell(qq(<img src="/blank.gif" width="$AVATAR_MED_WIDTH" height="$AVATAR_MED_WIDTH">));
+ }
+
+ if ($duder->{ulevel} > 1 && $USER->{ulevel} == 3 && $show_all)
+ {
+ print_user_cell("&middot;&nbsp;".$duder->{username});
+ }
+ elsif ($vanished)
+ {
+ print_user_cell("<small>".$duder->{username}."</small>");
+ }
+ else
+ {
+ $duder->{username} =~ s/\n/<br>/g;
+ print_user_cell($duder->{username});
+ }
+
+ $duder->{realname} =~ s/\s/&nbsp;/g;
+ if ($vanished)
+ { print_user_cell("<small>".$duder->{realname}."</small>"); }
+ else
+ { print_user_cell($duder->{realname}); }
+
+ my $col = carbondate($duder->{lastseen}, 0);
+ $today++ if ($col eq "new");
+ if ($vanished)
+ {
+ print_user_cell(qq!<span class="$col"><small>!.(get_age($duder->{lastseen})).qq!&nbsp;ago</small></span>!, "right");
+ }
+ else
+ {
+ print_user_cell(qq!<small><span class="$col">!.(get_age($duder->{lastseen})).qq!</span></small>!, "right");
+ }
+
+ if ($USER->{ulevel} == 3)
+ {
+ if ($duder->{ccount} == 0)
+ { print_user_cell("&nbsp;"); }
+ else
+ { print_user_cell("&nbsp;<small>".hushnull($duder->{ccount}, "c", 1)."</small>", "right"); }
+
+ if ($duder->{fcount} == 0)
+ { print_user_cell("&nbsp;"); }
+ else
+ { print_user_cell("&nbsp;<small>".hushnull($duder->{fcount}, "f", 1)."</small>&nbsp;", "right"); }
+ }
+
+ my $cell = '';
+ foreach my $sticky (split_keys($duder->{stickies}))
+ {
+ my $key = $keywords->{$sticky};
+ if ($key->{owner} eq $USER->{username} || check_op($key) || $USER->{ulevel} == 3)
+ {
+ $cell .= qq(<a href="$BUCKY/$BUCKY_LEXICON_KEYWORD/$sticky">$sticky</a>, );
+ }
+ }
+ $cell =~ s/, $//;
+ print_user_cell($cell);
+
+ print qq[</tr>];
+ $r = $r ? 0 : 1;
+ $i++;
+ }
+
+ print qq(<tr><td colspan=9 align=right><small>) .
+ qq(total: <b>$i</b> users \(<b>$today</b> seen today);
+ print qq(, $neg <a href="$BUCKY/users?showall=1">vanished</a>) if (!$show_all && $USER->{ulevel} > 2);
+ print qq(\)</small>&nbsp;</td></tr>\n);
+ print <<approvefoot;
+</table></center>
+approvefoot
+ }
+
+sub print_user_cell
+ {
+ my ($v, $align) = @_;
+ my ($lpx, $rpx) = ("4px", "2px");
+ ($lpx, $rpx) = ("2px", "4px") if ($align eq "right");
+ $align = "left" unless ($align);
+ print qq[<td nobreak style="padding: 3px; vertical-align: middle; text-align: $align;">$v</td>];
+ }
+
+sub print_blank_cell
+ {
+ my ($v) = @_;
+ print qq[<td nobreak style="padding: 3px; background-color: #e6f0e6; vertical-align: middle; text-align: $align;">$v</td>];
+ }
+
+sub print_sinks
+ {
+ $cell = '&nbsp;';
+ foreach my $sticky (split_keys($duder->{sink}))
+ {
+ my $key = $keywords->{$sticky};
+ if ($key->{owner} eq $USER->{username} || check_op($key) || $USER->{ulevel} == 3)
+ {
+ $cell .= qq(<a href="$BUCKY/$BUCKY_LEXICON_KEYWORD/$sticky">$sticky</a>, );
+ }
+ }
+ $cell =~ s/, $//;
+ print_user_cell($cell);
+ }
+
+sub sort_by_username { sort { uc($a->{username}) cmp uc($b->{username}) } @_; }
+sub sort_by_firstseen { sort { uc($b->{firstseen}) <=> uc($a->{firstseen}) } @_; }
+
+$dbh->disconnect ();
+print "Users: " . &report_time() . "\n" if $timer;
+