#! /usr/bin/perl -T -I/var/www/perl-bin
# RealizationEngine
my $version = "2.5.0c";
# Copyright Realization Systems, Inc., 2002, 2003, 2004, 2005
# http://www.RealizationSystems.com/
# P.O. Box 1, Plains, Texas 79355, U.S.A.
# RealizationEngine is the trademark of Realization Systems, Inc.
# This program is not free software; you can modify it under the
# terms of the License but you may not redistribute without a
# license to do so from Realization Systems, Inc.
#
# This program is distributed WITHOUT ANY WARRANTY; without even
# the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
#
# You should have received a copy of the License
# along with this program; if not, write to Realization Systems,
# Inc., 407 N. York Ave., Hagerman, NM 88232.
#srand (time ^ $$ ^ unpack "%32L", 'ps axww | gzip');
# open URANDOM, "/dev/urandom";
# my $rand_seed = unpack "%32L", ;
# close URANDOM;
# srand ($rand_seed);
$|=1;
# what kind of mail transfer agent (MTA) are we gonna use? sendmail or Blat (Windows)
# my $MTA = "sendmail"; # uncomment this line for *nix systems
# $MTA = "blat"; # uncomment this line for Windows with Blat installed
use warnings;
use CGI qw(:cgi :form :html);
use DBI;
use POSIX;
use Digest::MD5 qw(md5_hex);
use Mail::Mailer;
use Fcntl qw/O_WRONLY O_CREAT O_EXCL/;
# use CGI::Carp qw(fatalsToBrowser warningsToBrowser carpout);
# use Benchmark;
# use vars qw/$t0 $t1 $td $tf/;
use strict;
# detaint ENV{'PATH'}
$ENV{'PATH'} = '/bin:/usr/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
use vars qw/$icon $text/; # theme and localization hashrefs
# database vars
use vars qw/$sth $dbh /;
# user data
use vars qw/$name %users_groups $folder_session_age $session_age $session /;
# system stuff
use vars qw/$op $cookie $expand $userid $groupid $our_userid $our_userid $open
$foldergroupid $group $folderid $ownerid $groupmember $groupw
$parentfolderid $foldername $groupname $contents @group @other $error
%allowed_table $in_table $in_block $expandmessage @folder $parentid
$groupr $otherr $otherw $folderURI $username $timestamp $session_timeout
$delta_time $cookie_domain $linkfolder $page $pages $limit @folder_array
%value $current_system_time $url_folder $message_userid $message_userid
$stylesheet
/;
use vars qw/$total $todays $weeks $sessions/; # declarations for sub countthread
use vars qw/$leader $leaders/; # declarations for sub quick_jump_menu
# $hooks is the API hooks hashref for plugins
use vars qw/$hooks @plugins $plugin_op_array $plugin_op_hash/;
$hooks = { 'message_body' => [], # plugins that affect message bodies
'message_compose_bottom' => [], # stuff that appears at the bottom of the message composition pages
'message_data' => [], # applies to none-contents data of a message
'folder_navigation_area' => [], # inside the folder navigation table, to the right of the folder nav links
};
$plugin_op_array = [];
$plugin_op_hash = {};
my $plugin_registry = "plugins/registry"; # location of plugin registry
eval { require "plugins/registry"; };
foreach my $plugin (@plugins) { # parse the plugin registry
eval { require $plugin; } || warn ("plugin loading failed, $plugin: $!");
}
$name = qq{};
my $home_dir = my $doc_root = $ENV{"DOCUMENT_ROOT"};
if ($home_dir =~ m#^(/home/[\w/.-]+/html)#) {
$home_dir = $1;
}
else {
warn ("doc_root failed test. --> $home_dir \n");
}
$home_dir =~ s/\/html//;
require "$home_dir/data/settings.re";
my ($dsn, $db_user, $dbpassword, $cgi_url) = &setup();
$cgi_url = script_name(); # path and name of RealizationEngine script
##########################
# icon theming
#
# later, we'll do things to allow the administrator to pick a theme from available themes
#
#########################
# eval { require "icon_themes/etiquette"; };
eval { require "$home_dir/icon_themes/icon-crystal"; };
##########################
# localization
#
# later, we'll do things to allow the administrator to pick a locale from available resources
#
#########################
eval { require "$home_dir/locale/default"; };
#########################
# set stylesheet
#########################
$stylesheet = "/re_default.css";
# $stylesheet = "/stylesheets/blah_blue.css";
# $stylesheet = "/stylesheets/purple_haze.css";
# connect to database
my $dbh = DBI->connect ($dsn, $db_user, $dbpassword);
# once connceted, get rid of the login information
undef $dsn; undef $db_user; undef $dbpassword;
unless (defined ($dbh) )
{
print header();
print $text->{failure_to_connect};
exit(0);
}
my $first_level_thread_order = "DESC";
my $nth_level_thread_order = "ASC";
# After connection, grab the site-specific settings
my $settings = {}; # settings hashref
my $query = qq{SELECT value FROM settings WHERE name="user_table"};
$sth = $dbh->prepare ($query);
$sth->execute ();
($settings->{'user_table'}) = my @ary = $sth->fetchrow_array ();
$query = qq{SELECT value FROM settings WHERE name="cookie_name"};
$sth = $dbh->prepare ($query);
$sth->execute ();
($settings->{'cookie_name'}) = $sth->fetchrow_array ();
$query = qq{SELECT value FROM settings WHERE name="domain_name"};
$sth = $dbh->prepare ($query);
$sth->execute ();
($settings->{'domain_name'}) = $sth->fetchrow_array ();
$query = qq{SELECT value FROM settings WHERE name="notification_address"};
$sth = $dbh->prepare ($query);
$sth->execute ();
($settings->{'notification_address'}) = $sth->fetchrow_array ();
$query = qq{SELECT value FROM settings WHERE name="notification_message"};
$sth = $dbh->prepare ($query);
$sth->execute ();
($settings->{'notification_message'}) = $sth->fetchrow_array ();
$query = qq{SELECT value FROM settings WHERE name="recent_interval"};
$sth = $dbh->prepare ($query);
$sth->execute ();
($settings->{'recent_interval'}) = $sth->fetchrow_array ();
$query = qq{SELECT value FROM settings WHERE name="edit_interval"};
$sth = $dbh->prepare ($query);
$sth->execute ();
($settings->{'edit_interval'}) = $sth->fetchrow_array ();
$settings->{'edit_interval'} = $settings->{'edit_interval'} * 3600; # convert hours to seconds
$query = qq{SELECT value FROM settings WHERE name="thread_limit"};
$sth = $dbh->prepare ($query);
$sth->execute ();
($settings->{'thread_limit'}) = $sth->fetchrow_array ();
$query = qq{SELECT value FROM settings WHERE name="thread_style"};
$sth = $dbh->prepare ($query);
$sth->execute ();
my ($thread_style) = $sth->fetchrow_array ();
$query = qq{SELECT value FROM settings WHERE name="fresh_message_time"};
$sth = $dbh->prepare ($query);
$sth->execute ();
($settings->{'fresh_message_time'}) = $sth->fetchrow_array ();
$settings->{'fresh_message_time'} = $settings->{'fresh_message_time'}*24*3600;
$query = qq{SELECT value FROM settings WHERE name="warm_message_time"};
$sth = $dbh->prepare ($query);
$sth->execute ();
($settings->{'warm_message_time'}) = $sth->fetchrow_array ();
$settings->{'warm_message_time'} = $settings->{'warm_message_time'}*24*3600;
$query = qq{SELECT value FROM settings WHERE name="allow_search"};
$sth = $dbh->prepare ($query);
$sth->execute ();
($settings->{'allow_search'}) = $sth->fetchrow_array ();
$query = qq{SELECT value FROM settings WHERE name="title_tag"};
$sth = $dbh->prepare ($query);
$sth->execute ();
($settings->{'title_tag'}) = $sth->fetchrow_array ();
$allowed_table{"title_tag"} = $settings->{'title_tag'};
$query = qq{SELECT value FROM settings WHERE name="title"};
$sth = $dbh->prepare ($query);
$sth->execute ();
($settings->{'title'}) = $sth->fetchrow_array ();
# $settings->{'title'} =~ s/\$(\w+)/$allowed_table{$1}/g;
$query = qq{SELECT value FROM settings WHERE name="page_footer"};
$sth = $dbh->prepare ($query);
$sth->execute ();
($settings->{'page_footer'}) = $sth->fetchrow_array ();
$settings->{'page_footer'} =~ s/\$(\w+)/${$1}/g;
$query = qq{SELECT value FROM settings WHERE name="upload_limit_MB"};
$sth = $dbh->prepare ($query);
$sth->execute ();
($settings->{'upload_limit_MB'} ) = $sth->fetchrow_array () || .10; # default to 100 KB
$CGI::POST_MAX=1024 * 1024 * $settings->{'upload_limit_MB'}; # limit uploads to $settings->{'upload_limit_MB'} MBs
$query = qq{SELECT value FROM settings WHERE name="P_privacy_statement"};
$sth = $dbh->prepare ($query);
$sth->execute ();
($settings->{'privacy_statement'}) = $sth->fetchrow_array () || $text->{privacy_statement};
$settings->{'page_footer'} =~ s/\$(\w+)/${$1}/g;
# Find name of 'root' folder
$query = qq{SELECT name FROM message WHERE id=1};
$sth = $dbh->prepare ($query);
$sth->execute ();
my ($root_folder_name) = $sth->fetchrow_array ();
$sth->finish ();
$root_folder_name = 'root' unless $root_folder_name;
$sth->finish ();
# list of html tags deamed safe for enclussion in messages
my @approved_tags = qw /b i font a blockquote li ol ul table td tr th span embed object param
u sup sub p em strong strike tt div img q pre center dd dt/;
# list of folder name safe chars
my $legal_folder_chars = qr/^['\w \.\-_\?:~()]+$/;
my $legal_folder_chars_enum = "[word characters] as well as 0-9,.-_?:~'()";
$in_table=0; # decalre $in_table for use in space translation supression
$in_block=0; # decalre $in_block for use in space translation supression
# Check for 'op' or NULL
$op = param('op') || NULL;
# Get search result if search result
my $searchresult = param('searchresult') || 0;
# get search query if search query
my $searchquery = param("searchquery") || '';
# get download id if download is requested
my $download = param('download') || NULL;
$download = int($download) if $download;
# set $user_thread_style to 0 for default
my $user_thread_style = 0;
# grab "marked" terms if asked for
my $mark = param('mark') || '';
my @marks;
if ($mark)
{
@marks = split(/,/, $mark);
}
# general declarations to avoid uneccessary waringings
my $op_status = '';
my $expand = param('expand') || 1;
my $folder = param("folder") || $root_folder_name;
$folder =~ s/^\///; $folder =~ s/\/$//; # clean off any hanging /'s on the front or end
# of the folder "path"
# if $op eq 'expand', find the folder the message lives in first and set that as our folder
# This will fix things in the case that folder the message resides in has been moved or renamed.
if ( $op eq 'expand' || $op eq 'isolate' )
{
$expandmessage = int( param('message') ) || 0;
my $query = qq{SELECT folderid
FROM message
WHERE id=$expandmessage};
my $sth = $dbh->prepare ($query);
$sth->execute ();
($folderid) = $sth->fetchrow_array ();
$sth->finish ();
$folder = $root_folder_name."/".regress_folders($folderid);
chop($folder);
}
@folder = split(/\//, $folder);
my $bread = $folder; # we'll need a copy of $folder to chop into breadcrumbs
my @breadcrumbs; # for bread crumb-style top-navigation
my $breadcrumb_link = ''; # declare the "bread crumb folder" link holder
# parse the folder params to find correct child folder
# we'll do this by itterating through the array created
# above and then feeding the info into a SELECT
my $where = qq{level$#folder.name = "$folder[$#folder]" AND };
my $i = 0; # set $i to 0 just in case
my $query_folderid = "level$#folder.id";
my ($from); # declare $from
my $level;
foreach (reverse(@folder) )
{
$level = $#folder - $i;
my $next_level = $level - 1;
$from .= "message level$level, ";
$where .= qq{level$level.parentid = level$next_level.id AND }.
qq{level$next_level.name = "$folder[$next_level]" AND }.
qq{level$level.folder = 'Y' AND }
if $level > 0;
$breadcrumbs[$level] = $bread; # assign the currect "bread" to $breadcrumbs[$level]
$breadcrumb_link = qq{/$folder[$level]}.$breadcrumb_link;
$bread =~ s/\/$folder[$level]$//; # trim a folder off the end of the $bread
$i++;
}
# prepend root folder
# my $expandtest = param('expand'); # this is only used to test for the parameter, no where else.
$breadcrumb_link = qq{$root_folder_name}.$breadcrumb_link
unless ( $breadcrumb_link =~ /folder=$root_folder_name"/ );
$breadcrumb_link =~ s/^\///; # trim off the leading "/" when it happens for the root folder
$from =~ s/,\s$//; # trim last ", " from $from
$where =~ s/AND\s$//; # trim last "AND " from $where
$query = qq{SELECT
$query_folderid
FROM $from
WHERE $where AND level$level.folder='Y'};
# explain_query($query);
# print header(),$query,br; # for diagnosing folder query
# $folder_query = $query; # store folder query for later use in debugging
$sth = $dbh->prepare ($query);
$sth->execute ();
($folderid) = $sth->fetchrow_array ();
$sth->finish ();
my ($parentfolder); #declare
if ( defined($folderid) )
{
# here's the new method by using the "folder" param passed to the script...
for ($i=0; $i<$#folder; $i++)
{
$parentfolder .= "/$folder[$i]";
}
$parentfolder =~ s/\ /\%20/g if $parentfolder;
$parentfolder = '' unless $parentfolder;
if ($folder ne '' && $folder ne $root_folder_name && $parentfolder eq '')
{
$parentfolder = $root_folder_name;
}
}
if (!defined($folderid) )
{
$folderid = 1;
$folder = $root_folder_name;
}
$query = qq{SELECT name, parentid, userid, groupid, groupr, groupw, otherr,
otherw, URI, contents, open
FROM message
WHERE id=$folderid};
$sth = $dbh->prepare ($query);
$sth->execute ();
($foldername, $parentid, $ownerid, $groupid, $groupr, $groupw, $otherr, $otherw,
$folderURI, $contents, $open) = $sth->fetchrow_array ();
$sth->finish ();
# after we know where we're going, we'll grab the user info or log the user in/out in
# the module below. This module cannot be moved higher in the code becuase we have to
# know the folder we're going to, and the owner and group that fold belongs to.
my $currently_online = '';
$name = user();
# if the there is no user logged in, we'll assign them as "guest"
$username = 'guest' unless $username;
####################################################
# begin operations
#
# this is where things actually get started....
####################################################
# Process any plugin defined operations
if ($op eq "new folder" && ($our_userid == $ownerid || $name eq "root"
|| ($groupmember eq "Y" && $groupw eq "Y")) && $open eq "Y" && $our_userid>0 ) {
print header(-cookie=>[$cookie]);
print start_html(-title=>"$settings->{'title_tag'} - $folder",
-head=>[Link({-rel=>"SHORTCUT ICON", -href=>'/favicon.ico'})],
-meta=>{'MSSmartTagsPreventParsing'=>'True'},
-meta=>{'viewport'=>'width=device-width'},
-style=>{-src=>"$stylesheet"});
print start_form(-action=>$cgi_url, -method=>"post");
print_title();
print_folder();
print qq{
$text->{create_folder_head}
},br;
print qq{$text->{folder_name_label}: },textfield(-name=>"foldername"),
qq{ $text->{folder_name_note}},br;
$query = qq{SELECT groups.name, groups.id FROM groups, members
WHERE members.userid=$our_userid AND groups.id = members.groupid
GROUP BY groups.name
ORDER BY groups.name};
$sth = $dbh->prepare ($query);
$sth->execute ();
print qq{
};
print qq{};
print qq{$text->{dialog_warning_username_required}},br,br
unless my $user_name_app = param('user_name_app');
print qq{$text->{dialog_warning_username_bang_disallowed}},br,br if $user_name_app =~ /^!/;
print qq{$text->{dialog_warning_email_required}},br,br unless my $email_app = param('email_app');
print qq{$text->{dialog_warning_email_confirm_required}},br,br
unless my $email_app1 = param('email_app1');
print qq{$text->{dialog_warning_email_not_match}},br unless $email_app eq $email_app1;
print qq{$text->{dialog_warning_password_required}},br,br
unless my $password_app = param('password_app');
print qq{$text->{dialog_warning_password_confirm_required}},br,br
unless my $password_app1 = param('password_app1');
print qq{$text->{dialog_warning_password_not_match}},br unless $password_app eq $password_app1;
# Error out if username or email are undefined or either password OR emails or passwords don't match
if ($user_name_app eq '' or $user_name_app =~ /^\!/
or $email_app eq '' or $email_app1 eq ''
or $password_app eq '' or $password_app1 eq ''
or $email_app ne $email_app1
or $password_app ne $password_app1 )
{
exit(0);
}
# Check for existing user name
my $user_name_app_banged = $dbh->quote("\!$user_name_app");
my $user_name_app_quoted = $dbh->quote($user_name_app);
$query = qq{SELECT id FROM $settings->{'user_table'} WHERE name=$user_name_app_quoted or name=$user_name_app_banged};
$sth = $dbh->prepare ($query);
my $rv = int ( $sth->execute() );
print qq{$text->{dialog_warning_username_taken}},br if $rv > 0;
my $stop_flag = 1 if $rv>0;
# Check for existing e-mail address
my $email_app_test = $dbh->quote($email_app);
$query = qq{SELECT id FROM $settings->{'user_table'} WHERE email=$email_app_test};
$sth = $dbh->prepare ($query);
$rv = int ( $sth->execute() );
print qq{$text->{dialog_warning_email_taken}},br if $rv > 0;
$stop_flag = 1 if $rv>0;
print qq{};
unless ( $stop_flag ) # unless $stop_flag is defined, proceed with user creation
{
# calculate md5 hash of new password
my $pass_md5 = md5_hex($password_app);
# get a passkey for the user....
my $passkey = passkey();
# insert new user into user table
my $query = qq{INSERT into $settings->{'user_table'} set name=$user_name_app_banged, email=$email_app_test,
password="$pass_md5", passkey="$passkey"};
my $sth = $dbh->prepare ($query);
$sth->execute ();
send_confirm_message("$user_name_app");
# Print confirmation
print qq{$text->{dialog_account_created_successfully}};
print qq{[ $text->{dialog_return_to} $settings->{'title_tag'} ]};
}
$sth->finish ();
}
elsif ( $op eq 'resend confirmation' && $name eq 'root') # resend the confimration link (root only)
{
my ($user_name_app) = param('user_name_app');
send_confirm_message($user_name_app);
print redirect(-cookie=>[$cookie], -location=>"$cgi_url?op=user%20administration");
}
elsif ( $op eq 'confirm')
{
my $secret = param('secret');
my $user_name= param('user');
print header();
print start_html(-title=>"$settings->{'title_tag'} - $text->{page_title_account_confirmation}",
-head=>[Link({-rel=>"SHORTCUT ICON", -href=>'/favicon.ico'})],
-meta=>{'MSSmartTagsPreventParsing'=>'True'},
-meta=>{'viewport'=>'width=device-width'},
-style=>{-src=>"$stylesheet"});
print_title();
print qq{
$text->{page_title_account_confirmation}
};
my $user_name_banged = $dbh->quote("!$user_name");
my $query = qq{SELECT passkey, id FROM $settings->{'user_table'} WHERE name=$user_name_banged};
my $sth = $dbh->prepare ($query);
$sth->execute ();
my ($passkey, $id) = $sth->fetchrow_array ();
if ( $passkey eq $secret )
{ # the secret matches the passkey, change user to confirmed
$user_name = $dbh->quote($user_name);
$query = qq{UPDATE $settings->{'user_table'} SET name=$user_name, timestamp=timestamp WHERE id=$id};
$sth = $dbh->prepare ($query);
$sth->execute ();
$query = qq{SELECT email FROM $settings->{'user_table'} WHERE id=$id};
$sth = $dbh->prepare ($query);
$sth->execute ();
my ($email_app) = $sth->fetchrow_array ();
print qq{$text->{dialog_account_confirmed} $text->{dialog_login}};
# Send new account notification to site owner if requested
if ($settings->{'notification_address'})
{
my $temp_domain_name = $settings->{'domain_name'};
$temp_domain_name =~ s/^\.//; # strip leading '.' from beginning of domain name
# if present.
my $message = <{'title_tag'} $text->{notification_dialog_new_user}: $user_name ($email_app).
$settings->{'notification_message'}
http://$temp_domain_name$cgi_url?op=manage%20this%20user&manage_userid=$id
$text->{notification_dialog_do_not_reply}
END_OF_MESSAGE
my $mailer = Mail::Mailer->new();
$mailer->open({'From' => "$settings->{'notification_address'}",
'To' => "$settings->{'notification_address'}",
'Subject' => "$settings->{'title_tag'} -- $text->{notification_new_user}"} );
print $mailer "$message";
close($mailer);
}
}
else
{
print qq{$text->{dialog_error_confirmation_somethingA}},
qq{$settings->{'notification_address'}},
qq{$text->{dialog_error_confirmation_somethingB}},br,br;
}
$sth->finish ();
}
elsif ( $op eq 'mail password') {
my $email = param('email');
my $query_email = $dbh->quote($email);
print header(-cookie=>[$cookie]);
print start_html(-title=>"$settings->{'title_tag'} - $text->{page_title_sending_password}",
-head=>[Link({-rel=>"SHORTCUT ICON", -href=>'/favicon.ico'})],
-meta=>{'MSSmartTagsPreventParsing'=>'True'},
-meta=>{'viewport'=>'width=device-width'},
-style=>{-src=>"$stylesheet"});
print_title();
print qq{
$text->{page_title_sending_password}
};
# grab username and password from user table
$query = qq{SELECT name, password FROM $settings->{'user_table'} WHERE email=$query_email AND id>1};
$sth = $dbh->prepare ($query);
$sth->execute ();
my ($name, $password) = $sth->fetchrow_array ();
if ($password eq 'deactivate') {
print qq{$text->{dialog_warning_account_deactivated}\n};
$sth->finish ();
$dbh->disconnect ();
exit(0);
}
elsif ( $name eq '' ) {
# do nothing if no user was found....
}
else {
# generate password
my @chars = ( "A" .. "Z", "a" .. "z", 0 .. 9, "+", "-", "=", "*", "#", "&", ".", ";", ",", "_" );
$password = join("", @chars[ map { rand @chars } (1 .. 6) ]);
# insert md5 hash of new password into user table
my $pass_md5 = md5_hex($password);
my $query_name = $dbh->quote($name);
$query = qq{UPDATE $settings->{'user_table'} SET password='$pass_md5', timestamp=timestamp WHERE name=$query_name};
$sth = $dbh->prepare ($query);
$sth->execute ();
}
if ($password) {
my $temp_domain_name = $settings->{'domain_name'};
$temp_domain_name =~ s/^\.//; # strip leading '.' from beginning of domain name if present.
# do some text substitutions
$text->{email_new_password_text} =~ s/%PASSWORD/$password/g;
$text->{email_new_password_text} =~ s/%NAME/$name/g;
$text->{email_new_password_text} =~ s/%TITLE/$settings->{'title_tag'}/g;
$text->{email_new_password_text} =~ s/%NOTICE/$text->{notification_dialog_do_not_reply}/g;
$text->{email_new_password_text} =~ s#%URL#http://$temp_domain_name#g;
my $mailer = Mail::Mailer->new();
$mailer->open({'From' => "$settings->{'notification_address'}",
'To' => "$email",
'Subject' => "Your $settings->{'title_tag'} login"} );
print $mailer "$text->{email_new_password_text}";
close($mailer);
# do some text substitutions
$text->{dialog_new_password_sent} =~ s/%CGI_URL/$cgi_url/;
print $text->{dialog_new_password_sent};
}
else
{
print qq{$text->{dialog_warning_no_account_for_email}},br;
}
}
elsif ( $op eq 'account maintenance' && $name ) {
$expand = param('expand') || $thread_style;
print header(-cookie=>[$cookie]);
print start_html(-title=>"$settings->{'title_tag'} - $text->{page_title_account_maintenance}",
-head=>[Link({-rel=>"SHORTCUT ICON", -href=>'/favicon.ico'})],
-meta=>{'MSSmartTagsPreventParsing'=>'True'},
-meta=>{'viewport'=>'width=device-width'},
-style=>{-src=>"$stylesheet"});
print_title();
print qq{
};
if ( $confirm ne 'Y' ) {
print qq{$text->{dialog_link_dont_delete}},br,br;
# Grab the message info for the message to be displayed
$query = qq{ SELECT message.name, contents, URI, linkname, $settings->{'user_table'}.name
FROM message, user
WHERE message.id=$messageid AND message.userid=user.id
};
$sth = $dbh->prepare ($query);
$sth->execute ();
@ary = $sth->fetchrow_array ();
my ($message_name, $message_contents, $URI, $linkname, $message_user) = @ary;
$sth->finish ();
$message_user = "Guest" unless $message_user;
print qq{
};
my $alternate_line_color = 'off'; # turn off "green bar" for first line
while ( @ary = $sth->fetchrow_array () )
{
my ($manage_userid, $manage_username, $manage_email, $last_access_time,
$last_message_time, $message_count, $user_pass) = @ary;
$last_message_time = "
};
}
my $query = qq{SELECT count(members.groupid)
FROM members
WHERE members.userid = $manage_userid
GROUP BY userid
};
my $sth = $dbh->prepare ($query);
$sth->execute ();
my ($group_count) = $sth->fetchrow_array () || 0;
print qq{
$group_count
};
print qq{
}; # end table row
}
print qq{
}; # end table
$sth->finish ();
print br,qq{[ $text->{dialog_link_jump_to_group_admin}},
qq{ ]},br.qq{ [ $text->{dialog_return_to} $settings->{'title_tag'} ]};
print end_form(), end_html();
}
elsif ( $op eq 'manage this user' && $name eq 'root') {
my $manage_userid = param('manage_userid');
print header(-cookie=>[$cookie]);
print start_html(-title=>"$settings->{'title_tag'} - $text->{page_title_user_administration}",
-head=>[Link({-rel=>"SHORTCUT ICON", -href=>'/favicon.ico'})],
-meta=>{'MSSmartTagsPreventParsing'=>'True'},
-meta=>{'viewport'=>'width=device-width'},
-style=>{-src=>"$stylesheet"});
print_title();
# Snag the user's name
$query = qq{SELECT name, email
FROM $settings->{'user_table'}
WHERE id=$manage_userid};
$sth = $dbh->prepare ($query);
$sth->execute ();
my ($manage_username, $manage_email) = $sth->fetchrow_array ();
print qq{
};
print start_form(-action=>$cgi_url, -method=>"post");
print qq{$text->{dialog_label_user_name}: $manage_username }
if $manage_userid != 1; # root's name can't change
print submit(-name=>'op', -value=>"$text->{button_label_change_username}"),br,br
if $manage_userid != 1; # root's name can't change
print qq{e-mail address: };
print textfield(-name=>'email', -size=>30, -value=>"$manage_email"),br,br;
print qq{
};
print qq{
$text->{dialog_label_new_password}:
},
password_field(-name=>"pass1", -value=>''),qq{
};
print qq{
$text->{dialog_label_retype_password}:
},
password_field(-name=>"pass2", -value=>''),qq{
};
print qq{
},br;
# Get a list of group names and ids
$query = qq{SELECT id, name FROM groups ORDER BY name ASC};
$sth = $dbh->prepare ($query);
$sth->execute ();
my (@group_id, %group_names);
while ( @ary = $sth->fetchrow_array () ) {
my ($group_id, $group_name) = @ary;
push (@group_id, $group_id);
$group_names{$group_id} = $group_name;
}
# Get a count of messages posted by this user
$query = qq{SELECT count(*) FROM message WHERE userid=$manage_userid};
$sth = $dbh->prepare ($query);
$sth->execute ();
my ($message_count) = @ary = $sth->fetchrow_array ();
$sth->finish ();
print qq{$text->{dialog_messages_posted}: $message_count},br;
# Get date/time of last message posted by user
$query = qq{SELECT date_format(MAX(message.time), '%e.%b.%Y %h:%i %p') }.
qq{FROM message WHERE userid=$manage_userid};
$sth = $dbh->prepare ($query);
$sth->execute ();
my ($last_message_time) = @ary = $sth->fetchrow_array () || '-';
$sth->finish ();
print qq{$text->{dialog_last_message_posted}: $last_message_time},br;
# Get date/time of last page access by user
$query = qq{SELECT date_format(timestamp, '%e.%b.%Y %h:%i %p') }.
qq{FROM $settings->{'user_table'} WHERE id=$manage_userid};
$sth = $dbh->prepare ($query);
$sth->execute ();
my ($last_access_time) = $sth->fetchrow_array ();
$sth->finish ();
print qq{$text->{dialog_last_access_time}: $last_access_time},br,br;
# Get a list of groups this user is a member of
$query = qq{SELECT groupid FROM members WHERE userid=$manage_userid};
$sth = $dbh->prepare ($query);
$sth->execute ();
my ($member_groupid, @member_groups);
while ( @ary = $sth->fetchrow_array () ) {
($member_groupid) = @ary;
push (@member_groups, $member_groupid);
}
$sth->finish ();
print qq{};
print qq{};
print qq{$text->{dialog_select_user_groups}},br;
print checkbox_group(-name=>'groupid',
-values=>[@group_id],
-labels=>\%group_names,
-linebreak=>'true',
-default=>[@member_groups],
-columns=>3),br;
print submit(-name=>'op', -value=>'update user', -label=>$text->{button_label_update_user}),br;
# if user has not created any messages, they can safely be deleted
if ($message_count == 0) {
print qq{$text->{dialog_notice_okay_to_delete_user}},br;
print submit(-name=>"op", -value=>"delete user", -label=>$text->{button_label_delete_user})," ";
print checkbox(-name=>"confirm delete", -value=>"confirm delete",
-label=>$text->{checkbox_label_confirm_delete}),br;
}
print br,qq{[ $text->{dialog_link_back_to_user_admin} ]},br;
print qq{[ $text->{dialog_link_jump_to_group_admin} ]},br;
print qq{ [ $text->{dialog_return_to} $settings->{'title_tag'} ]};
print end_form(), end_html();
$sth->finish ();
}
elsif ( $op eq 'change user name' && $name eq 'root') {
my $manage_userid = param('manage_userid');
my $manage_username = param('manage_username');
my $manage_email = param('email');
print header(-cookie=>[$cookie]);
print start_html(-title=>"$settings->{'title_tag'} - $text->{page_title_change_username}",
-head=>[Link({-rel=>"SHORTCUT ICON", -href=>'/favicon.ico'})],
-meta=>{'MSSmartTagsPreventParsing'=>'True'},
-meta=>{'viewport'=>'width=device-width'},
-style=>{-src=>"$stylesheet"});
print_title();
if ( $manage_userid != 1 ) { # root's name can't change
print qq{
},br,br;
print qq{$text->{dialog_notice_username_changed}},br,br;
print qq{$text->{dialog_notice_name_change_notification_sent} ($manage_email).},br,br;
$sth->finish ();
# send a note to the user notifying them that the change has been made by root.
my $temp_domain_name = $settings->{'domain_name'};
$temp_domain_name =~ s/^\.//; # strip leading '.' from beginning of domain name if present.
$text->{email_notice_username_change} =~ s/%TITLE/$settings->{'title_tag'}/g;
$text->{email_notice_username_change} =~ s/%NEW_NAME/$change_username/g;
$text->{email_notice_username_change} =~ s#%URL#http://$temp_domain_name#g;
$text->{email_notice_username_change_subject} =~ s/%TITLE/$settings->{'title_tag'}/g;
my $mailer = Mail::Mailer->new();
$mailer->open({'From' => "$settings->{'notification_address'}",
'To' => "$manage_email",
'Subject' => $text->{email_notice_username_change_subject}} );
print $mailer "$text->{email_notice_username_change}";
close($mailer);
}
print qq{[ $text->{dialog_link_back_to_user_admin} ]},br;
print qq{ [ $text->{dialog_return_to} $settings->{'title_tag'} ]};
}
elsif ( $op eq 'delete user' && $name eq 'root') {
my $manage_userid = param('manage_userid');
my $manage_username = param('manage_username');
my $confirm_delete = param('confirm delete');
# Get a count of how many messages this user owns
$query = qq{SELECT count(id) FROM message WHERE userid=$manage_userid};
$sth = $dbh->prepare ($query);
$sth->execute ();
my ($message_count) = $sth->fetchrow_array ();
$sth->finish ();
if ($message_count == 0 && $confirm_delete eq 'confirm delete') {
# delete all instances of user from groups
$query = qq{DELETE FROM members WHERE userid=$manage_userid};
$sth = $dbh->prepare ($query);
$sth->execute ();
$sth->finish ();
# delete user from user table
$query = qq{DELETE FROM $settings->{'user_table'} WHERE id=$manage_userid};
$sth = $dbh->prepare ($query);
$sth->execute ();
$sth->finish ();
print redirect(-cookie=>[$cookie], -location=>"$cgi_url?op=user%20administration");
}
else {
print header(-cookie=>[$cookie]);
print start_html(-title=>"$settings->{'title_tag'} - $text->{page_title_user_delete_failed}",
-head=>[Link({-rel=>"SHORTCUT ICON", -href=>'/favicon.ico'})],
-meta=>{'MSSmartTagsPreventParsing'=>'True'},
-meta=>{'viewport'=>'width=device-width'},
-style=>{-src=>"$stylesheet"});
print_title();
print qq{
};
if ($new_group_name eq 'NULL') { # if no name given, give error and link back.
print qq{
$text->{dialog_error_no_group_name}
};
print qq{[ $text->{dialog_link_back_to_user_admin} ]},br;
}
else { # check sent name for uniqueness against existing groups
# collect a list of groupnames and ids
$query = qq{SELECT id
FROM groups
WHERE name = '$new_group_name'};
$sth = $dbh->prepare ($query);
my $rv = int ( $sth->execute() );
if ($rv > 0) { # if name exists in groups table, kick out message and return link.
print qq{$new_group_name $text->{dialog_error_group_name_used}},br;
print qq{[ $text->{dialog_link_back_to_group_admin}},
qq{ ]},br;
}
else { # otherwise, create the new group and present link to edit group
$new_group_name = $dbh->quote($new_group_name);
$query = qq{INSERT INTO groups
SET name=$new_group_name};
$sth = $dbh->prepare ($query);
$sth->execute ();
$query = qq{SELECT LAST_INSERT_ID() FROM groups};
$sth = $dbh->prepare ($query);
$sth->execute ();
my ($new_group_id) = $sth->fetchrow_array ();
print start_form(-action=>"$cgi_url", -method=>"post");
print qq{$text->{dialog_label_new_group}: $new_group_name $text->{dialog_notice_group_created}},br;
print submit(-name=>"op", -value=>"manage this group", -label=>$text->{button_label_manage_group});
print hidden(-name=>"manage_groupid", value=>"$new_group_id"),br;
print qq{ [ $text->{dialog_link_back_to_group_admin}},
qq{ ]},br;
print qq{ [ $text->{page_title_user_administration} ]},br;
print qq{[ $text->{dialog_return_to} $settings->{'title_tag'} ]},br;
print end_form();
}
$sth->finish ();
}
print end_html();
}
elsif ( $op eq 'manage this group' && $name eq 'root') {
my $manage_groupid = param('manage_groupid');
print header(-cookie=>[$cookie]);
print start_html(-title=>"$settings->{'title_tag'} - $text->{page_title_group_admin} -- managing group",
-head=>[Link({-rel=>"SHORTCUT ICON", -href=>'/favicon.ico'})],
-meta=>{'MSSmartTagsPreventParsing'=>'True'},
-meta=>{'viewport'=>'width=device-width'},
-style=>{-src=>"$stylesheet"});
print_title();
# Snag the group's name
$query = qq{SELECT name FROM groups WHERE id=$manage_groupid};
$sth = $dbh->prepare ($query);
$sth->execute ();
my ($manage_groupname) = $sth->fetchrow_array ();
print qq{
\n};
# gather attachment information
$query = qq{SELECT attachment.id,
$settings->{'user_table'}.name,
attachment.filename,
date_format(attachment.date, '%Y-%b-%d %H:%i:%s'),
date_format(attachment.access, '%Y-%b-%d %H:%i:%s'),
folder.name,
attachment.access as last_access
FROM attachment, user, message as parent, message as folder
WHERE parent.id=attachment.message_id
AND $settings->{'user_table'}.id = parent.userid
AND folder.id=parent.folderid
ORDER BY $order};
$sth = $dbh->prepare ($query);
my $db_files = int ($sth->execute () );
my $alternate_line_color = 'off'; # turn off "green bar" for first line
my ($attachment, $posters_name, $filename, $date, $access, $in_folder_name);
while ( @ary = $sth->fetchrow_array () )
{
($attachment, $posters_name, $filename, $date, $access, $in_folder_name) = @ary;
my $local_file_name = sprintf("0%010d", $attachment);
my $file_size = -s "$home_dir/re_files/$local_file_name" || 0;
my $units = "b"; # set the units to default
my $deleted = 'no'; # set the deleted flag to default
unless ( -e "$home_dir/re_files/$local_file_name") { # if the file does not exist....
next if ( $hide eq 'yes' ); # AND "hide" is set to "yes", skip this row....
}
$access = '
\n};
# gather attachment information
$query = qq{SELECT attachment.id,
$settings->{'user_table'}.name,
attachment.filename,
date_format(attachment.date, '%Y-%b-%d %H:%i:%s'),
date_format(attachment.access, '%Y-%b-%d %H:%i:%s'),
folder.name,
attachment.access as last_access
FROM attachment, user, message as parent, message as folder
WHERE parent.id=attachment.message_id
AND $settings->{'user_table'}.id = parent.userid
AND folder.id=parent.folderid
AND $attachment_where
ORDER BY attachment.id};
$sth = $dbh->prepare ($query);
my $db_files = int ($sth->execute () );
my ($attachment, $posters_name, $filename, $date, $access, $in_folder_name, $hide,
$alternate_line_color, $md5sum);
while ( @ary = $sth->fetchrow_array () )
{
($attachment, $posters_name, $filename, $date, $access, $in_folder_name) = @ary;
$local_file_name = sprintf("0%010d", $attachment);
$file_size = -s "$home_dir/re_files/$local_file_name" || 0;
$units = "b";
unless ( -e "$home_dir/re_files/$local_file_name") # if the file does not exist....
{
next if ( $hide eq 'yes' ); # AND "hide" is set to "yes", skip this row....
}
$access = '
}; # number of times accessed
# grab the md5sum for this file
$md5sum = `md5sum $home_dir/re_files/$local_file_name`;
($md5sum, $filename) = split(/\ /, $md5sum);
print qq{
};
# $t0 = new Benchmark;
# Print folders
$parentfolder =~ s/^\/// if $parentfolder;
my @parentfolder = split ("/", $parentfolder) if $parentfolder;
my $parentindex = @folder - 2;
my ($parentname);
if (@folder > 1)
{
$parentname = $folder[$parentindex];
}
else
{
$parentname = $root_folder_name;
}
$parentfolder =~ s/\ /\%20/g if $parentfolder;
my $last_post_time = 0;
if ( $folderid != 1 )
{
# get the info on the parent folder
$query = qq{SELECT parent.id, parent.groupr, parent.otherr, parent.groupid, parent.userid
FROM message message, message parent
WHERE message.id=$folderid AND parent.id=message.parentid};
$sth = $dbh->prepare ($query);
$sth->execute ();
my ($parent_folderid, $parent_groupr, $parent_otherr, $parent_groupid, $parent_userid)
= $sth->fetchrow_array ();
$sth->finish ();
# check to see if user has permission to see messages in parent folder
my $parent_group_member;
if ( defined($users_groups{$parent_groupid}) )
{
$parent_group_member = 'Y' ;
}
$parent_group_member = 'Y' if $name eq 'root'; # root overrides parent membership
$parent_group_member = 'N' unless $name; # root overrides parent membership
# Print (open) folder navigation
$folder_array[$folder_count] = qq{}.
qq{{up}->[0] }.
qq{height=$icon->{up}->[0] border=0 />$parentname}; #"
if ( $parent_group_member eq 'Y' || $parent_otherr eq 'Y' || $name eq 'root' )
{
my $children = countchildren($parent_folderid);
if ($children->{last_posted})
{
$folder_array[$folder_count] .= qq{ ($children->{count}/}.
qq{$children->{today}/};
$folder_array[$folder_count] .= qq{} if $children->{session} > 0;
$folder_array[$folder_count] .= qq{$children->{session}};
$folder_array[$folder_count] .= qq{} if $children->{session} > 0;
$folder_array[$folder_count] .= qq{)};
}
}
$folder_array[$folder_count] .= br if $parentfolder;
$folder_count ++ if $parentfolder;
}
if ($otherr eq 'Y' || $our_userid == $ownerid || $name eq 'root'
|| $folder eq $root_folder_name # if we're in the root folder, we have to print
# the sub folders, for everyone.
|| ( $groupmember eq 'Y' && $groupr eq 'Y'))
{
# display the active folders in the current folder
$query = qq{SELECT name, id, groupr, otherr, groupid, userid
FROM message
WHERE folder='Y' AND folderid=$folderid AND open='Y' AND folderid!=id
ORDER BY name};
$sth = $dbh->prepare ($query);
$sth->execute ();
$folder = '' if $folder eq $root_folder_name;
while ( @ary = $sth->fetchrow_array () )
{
my ($childfolder,$childfolderid,$folder_groupr,$folder_otherr,$folder_groupid,$folder_userid)=@ary;
my $folder_group_member = 'N'; # set default membership to N
if ( defined($users_groups{$folder_groupid}) )
{
$folder_group_member = 'Y' ;
}
$folder_group_member = 'Y' if $name eq 'root'; # root overrides folder membership
my $path = "$folder/$childfolder";
$path =~ s/^\///;
my $linkpath = $path;
$linkpath =~ s/\ /%20/g;
my $printed_flag = 'N'; # set printed_flag to 'N'
if ( $folder_group_member eq 'Y' || $folder_otherr eq 'Y' || $name eq 'root' )
{
unless ( ($childfolder =~ /^\./ || $childfolder =~ /^~\./)
&& $folder_group_member eq 'N'
|| ( $our_userid != $folder_userid
&& $folder_groupr eq 'N'
&& $name ne 'root' ) )
{
$folder_array[$folder_count] = a({-href=>"$cgi_url?folder=$linkpath&expand=$expand",
-title=>"$text->{dialog_link_title_open_folder}, '$childfolder'"},
qq{{nav_folder}->[1]},
qq{height=$icon->{nav_folder}->[2] border=0 alt="[$childfolder]"/>$childfolder});
$printed_flag = 'Y'; # yes, we printed the folder
}
}
else
{
unless ($childfolder =~ /^\./ || $childfolder =~ /^~\./)
{
$folder_array[$folder_count] .= qq{{nav_folder}->[1] height=$icon->{nav_folder}->[2]}.
qq{ border=0 alt="$childfolder" />$childfolder};
$printed_flag = 'Y'; # yes, we printed the folder
}
}
my $folder_session_message_count = 0;
if ( $folder_group_member eq 'Y' || $folder_otherr eq 'Y' || $name eq 'root' )
{
unless ( ($childfolder =~ /^\./ || $childfolder =~ /^~\./)
&& $folder_group_member eq 'N'
|| ( $our_userid != $folder_userid
&& $folder_groupr eq 'N'
&& $name ne 'root' ) )
{
$last_post_time = 0;
my $children = countchildren($childfolderid);
my $foldercount = countfolders($childfolderid);
$folder_session_message_count = quick_folder_count($childfolderid) || 0;
if ($children->{last_posted})
{
$folder_array[$folder_count] .=
qq{ ($children->{count}/$children->{today}/};
$folder_array[$folder_count] .= qq{} if $children->{session} > 0;
$folder_array[$folder_count] .= qq{$children->{session}};
$folder_array[$folder_count] .= qq{} if $children->{session} > 0;
$folder_array[$folder_count] .= qq{)};
}
if ( $foldercount )
{
$folder_array[$folder_count] .= qq{ ($foldercount $text->{dialog_label_folders}};
$folder_array[$folder_count] .= " / $folder_session_message_count".
"" if $folder_session_message_count > 0;
$folder_array[$folder_count] .= ")";
}
}
}
# only print if we've printed a folder name
$folder_array[$folder_count] .= br if $printed_flag eq 'Y';
$folder_count ++ if $printed_flag eq 'Y'; # only print if we've printed a folder name
}
$sth->finish ();
# display the CLOSED folders in the current folder
$query = qq{SELECT name, id, groupr, otherr, groupid, userid
FROM message
WHERE folder='Y' AND folderid=$folderid AND open='N' AND folderid!=id
ORDER BY name};
$sth = $dbh->prepare ($query);
$sth->execute ();
$folder = '' if $folder eq $root_folder_name;
while ( @ary = $sth->fetchrow_array () )
{
my ($childfolder, $childfolderid, $folder_groupr, $folder_otherr, $folder_groupid,
$folder_userid) = @ary;
my $folder_group_member = 'N'; # set default membership to N
if ( defined($users_groups{$folder_groupid}) )
{
$folder_group_member = 'Y' ;
}
$folder_group_member = 'Y' if $name eq 'root'; # root overrides folder membership
my $path = "$folder/$childfolder";
$path =~ s/^\///;
my $linkpath = $path;
$linkpath =~ s/\ /%20/g;
my $printed_flag = 'N'; # set printed_flag to 'N'
my $foldercount;
if ( $folder_group_member eq 'Y' || $folder_otherr eq 'Y' || $name eq 'root' )
{
unless ( ($childfolder =~ /^\./ || $childfolder =~ /^~\./)
&& $folder_group_member eq 'N'
|| ( $our_userid != $folder_userid
&& $folder_groupr eq 'N'
&& $name ne 'root' ) )
{
$folder_array[$folder_count] .= a({-href=>"$cgi_url?folder=$linkpath&expand=$expand"},
qq{{nav_folder_locked}->[1] },
qq{height=$icon->{nav_folder_locked}->[2] border=0 alt="$childfolder" />$childfolder}); #"
$printed_flag = 'Y'; # yes, we printed the folder
}
}
else
{
if ($childfolder =~ /^\w/)
{
$folder_array[$folder_count]
.= qq{{nav_folder_locked}->[1] }.
qq{height=$icon->{nav_folder_locked}->[2] border=0 alt="$childfolder" />$childfolder}; # "
$printed_flag = 'Y'; # yes, we printed the folder
}
}
if ( $folder_group_member eq 'Y' || $folder_otherr eq 'Y' || $name eq 'root' )
{
unless ( ($childfolder =~ /^\./ || $childfolder =~ /^~\./)
&& $folder_group_member eq 'N'
|| ( $our_userid != $folder_userid && $folder_groupr eq 'N' ) )
{
$last_post_time = 0;
my $children = countchildren($childfolderid);
$foldercount = countfolders($childfolderid);
if ($last_post_time)
{
$folder_array[$folder_count] .= qq{ ($children->{count}/}.
qq{$children->{today}/};
$folder_array[$folder_count] .= qq{} if $children->{session} > 0;
$folder_array[$folder_count] .= qq{$children->{session}};
$folder_array[$folder_count] .= qq{} if $children->{session} > 0;
$folder_array[$folder_count] .= qq{)};
}
if ( $foldercount )
{
$folder_array[$folder_count] .= qq{ ($foldercount folder};
$folder_array[$folder_count] .= qq{s} if $foldercount>1;
$folder_array[$folder_count] .= qq{)};
}
}
}
# only print if we've printed a folder name
$folder_array[$folder_count] .= " $text->{dialog_folder_closed} " if $printed_flag eq 'Y';
$folder_count ++ if $printed_flag eq 'Y'; # only print if we've printed a folder name
}
$sth->finish ();
}
# $t1 = new Benchmark;
# $td = timediff($t1, $t0);
# $tf = timestr($td);
# print br,"benchmarks: tf = $tf",br;
my $col1;
if ($folder_count < 13)
{
$col1 = 6;
}
else
{
$col1 = ( ( $folder_count % 2) + $folder_count ) / 2;
}
my $recount = 0; # counter for recounting folders as we print them
foreach my $folder_line (@folder_array)
{
last if $recount >= $folder_count;
print $folder_line;
$recount ++;
print qq{
} if $recount == $col1;
}
$recount = 0; # force $recount back to 0
$folder_count = 0; # force $folder_count to 0
print qq{};
print end_form();
print qq{
};
# set up a temporary container for stuff passed to plugins to keep a plugin from
# making potentially dangerous changes
my $local_userid = $our_userid;
my $local_username = $username;
my $local_groupmember = $groupmember;
my $local_open = $open;
my $local_ownerid = $ownerid;
my $local_groupid = $groupid;
# One hashref for everything we're going to be passing to plugins
my $folder_navigation_data = { 'dbh' => \$dbh,
'folderid' => \$folderid,
'foldername' => \$foldername,
'username' => \$local_username,
'userid' => \$local_userid,
'ownerid' => \$local_ownerid,
'groupid' => \$local_groupid,
'groupmember' => \$local_groupmember,
'open' => \$local_open,
};
# apply plugins to folder navigation area
for (my $plugin=0; $plugin<@{$hooks->{'folder_navigation_area'}}; $plugin++) {
&{$hooks->{'folder_navigation_area'}->[$plugin]}($folder_navigation_data);
}
print qq{
};
print qq{
};
quick_jump_menu(1);
print qq{
};
print qq{
};
# Quick stats for root user (only display in root folder
if ( $folderid == 1 && $name eq 'root' )
{
# set up table to put tables in
print qq{
};
# set up user summary table
print qq{
$text->{summary_table_head_messages}
$text->{summary_table_head_users}
};
# last 24 hours
print qq{
$text->{summary_table_24_hours}
};
# messages in last 24 hours
$query = qq{SELECT count(*) FROM message
WHERE folder='N'
AND open='Y'
AND time > date_format(date_sub(now(), INTERVAL 1 day), "%Y%m%d%H%i%s")};
$sth = $dbh->prepare ($query);
$sth->execute ();
my ($last_24) = $sth->fetchrow_array () || 0;
$sth->finish ();
print qq{
$last_24
};
# users in last 24 hours
$query = qq{SELECT count(*) FROM user
WHERE timestamp > date_format(date_sub(now(), INTERVAL 1 day), "%Y%m%d%H%i%s")};
$sth = $dbh->prepare ($query);
$sth->execute ();
($last_24) = $sth->fetchrow_array () || 0;
print qq{
$last_24
};
print qq{
};
# last 7 days
print qq{
$text->{summary_table_7_days}
};
# Messages in last 7 days
$query = qq{SELECT count(*) FROM message
WHERE folder='N'
AND open='Y'
AND time > date_format(date_sub(now(), INTERVAL 7 day), "%Y%m%d%H%i%s")};
$sth = $dbh->prepare ($query);
$sth->execute ();
my ($last_7) = $sth->fetchrow_array () || 0;
$sth->finish ();
print qq{
$last_7
};
# users in last 7 days
$query = qq{SELECT count(*) FROM user
WHERE timestamp > date_format(date_sub(now(), INTERVAL 7 day), "%Y%m%d%H%i%s")};
$sth = $dbh->prepare ($query);
$sth->execute ();
($last_7) = $sth->fetchrow_array () || 0;
print qq{
$last_7
};
# totals
print qq{
$text->{summary_table_total}
};
# Total Messages
$query = qq{SELECT count(*) FROM message
WHERE folder='N' AND open='Y'};
$sth = $dbh->prepare ($query);
$sth->execute ();
my ($total) = $sth->fetchrow_array () || 0;
$sth->finish ();
print qq{
};
# close user summary cell, open file summary cell
print qq{
};
# set up file summary table
print qq{
$text->{summary_table_files}
$text->{summary_table_size}
};
# gather attachment information
$query = qq{SELECT id FROM attachment};
$sth = $dbh->prepare ($query);
my $db_files = int ($sth->execute () );
my $total_file_size = 0; # set initial value to 0
my ($attachment, $local_file_name, $file_size);
my $in_place_files = 0;
while ( @ary = $sth->fetchrow_array () )
{
($attachment) = @ary;
$local_file_name = sprintf("0%010d", $attachment);
$file_size = 0; # set initial value to 0 for each file
$file_size = -s "$home_dir/re_files/$local_file_name" || 0;
$total_file_size += $file_size;
$in_place_files ++ if ( -e "$home_dir/re_files/$local_file_name" );
}
$sth->finish ();
print qq{
};
}
print br,$settings->{'page_footer'} if $settings->{'page_footer'};
print qq{};
print qq{
v $version
};
print qq{
\n\n};
print qq{
\n},
qq{\n},
qq{\n},
qq{\n},
qq{\n},
qq{\n},
qq{\n\n};
print end_html();
$sth->finish ();
}
$sth->finish ();
$dbh->disconnect ();
foreach my $key (keys %users_groups)
{
$users_groups{$key} = undef();
}
while (@folder_array) # flush folders as last step (mod_perl will keep these)
{
pop(@folder_array);
}
$name = ''; # make sure name is cleared on exit.
# $t1 = new Benchmark;
# $td = timediff($t1, $t0);
# $tf = timestr($td);
# print br,"benchmarks: tf = $tf",br;
# warn qq{complete folder render ($foldername): $tf\n};
}
$sth->finish ();
$dbh->disconnect ();
sub threadchildren {
my($parent, $order, $root_message_id, $thread_style, $parent_title) = @_;
my ($messagename, $datetime, $URI, $message_username, $messageid, $attachment);
# thread_style -- how to display the message thread
# 1 = "normal" threading - calapse everything older than "fresh"
# 2 = "user enhanced" threading - calapse everyting older than users last session
# 3 = "expanded" threading - expand the whole thread, but only the thread starting
# at $root_message_id
# 4 = "compressed" - show thread, thread "owner" and thread summary only with aging
# 5 = "this week" - calapse messages older than 7 days (thread styel 1 enhanced for week)
$thread_style = 1 unless defined($thread_style);
# if $root_message_id is not passed to us, we'll set a "folder" flag
# if the "folder" flag is set, we'll assign a $root_message_id on the first level messages
my $folder_flag = 1 unless $root_message_id>0;
my $offset_threads = $settings->{'thread_limit'}*($page-1);
unless ( defined($limit) || $page == -1 )
{
$limit = qq{LIMIT $offset_threads,$settings->{'thread_limit'}} # if $limit is defined, create LIMIT query string
}
else
{
$limit = '';
}
my $sql_query;
if ( $parent == $folderid )
{
$sql_query = qq{
SELECT message.name, date_format(message.time, '%e.%b.%Y %h:%i %p'), URI, $settings->{'user_table'}.name, message.id,
( UNIX_TIMESTAMP() - UNIX_TIMESTAMP(message.time) ) as age, attachment.id
FROM ( message, user, threads )
LEFT JOIN attachment ON attachment.message_id=message.id
WHERE parentid=$parent
AND folderid=$folderid
AND threads.id = message.id
AND userid=user.id
AND folder='N'
AND open='Y'
GROUP BY message.id
ORDER BY threads.time DESC
$limit
};
}
elsif ($op_status eq 'isolate top') # if this is a request for an isolated thread, start at the top of the thread
{
$sql_query = qq{
SELECT message.name, date_format(message.time, '%e.%b.%Y %h:%i %p'), URI, $settings->{'user_table'}.name, message.id,
( UNIX_TIMESTAMP() - UNIX_TIMESTAMP(time) ) as age, attachment.id
FROM ( message, $settings->{'user_table'} AS user )
LEFT JOIN attachment ON attachment.message_id=message.id
WHERE message.id=$parent
AND folderid=$folderid
AND userid=user.id
AND folder='N'
AND open='Y'
GROUP BY message.id
ORDER BY message.id $order
$limit
};
$op_status = 'inside'; #set $op_status to arbitary, non-"isolate top" value
}
else
{
$sql_query = qq{
SELECT message.name, date_format(message.time, '%e.%b.%Y %h:%i %p'), URI, $settings->{'user_table'}.name, message.id,
( UNIX_TIMESTAMP() - UNIX_TIMESTAMP(time) ) as age, attachment.id
FROM ($settings->{'user_table'} AS user, message)
LEFT JOIN attachment ON (message.id=attachment.message_id)
WHERE message.parentid=$parent
# AND folderid=$folderid
AND message.userid=user.id
AND message.folder='N'
AND message.open='Y'
GROUP BY message.id
ORDER BY message.id $order
$limit
};
}
my $sth = $dbh -> prepare ($sql_query) || die $dbh->errstr;
my $rv = int ( $sth->execute() );
if ($rv > 0)
{
while ( my @ary = $sth->fetchrow_array () )
{
my ($messagename, $datetime, $URI, $message_username, $messageid, $age, $attachment) = @ary;
# One hashref for everything we're going to be passing to plugins
my $hooks_message_data = { 'dbh' => \$dbh,
'messagename' => \$messagename,
'datetime' => \$datetime,
'URI' => \$URI,
'message_username' => \$message_username,
'messageid' => \$messageid,
'age' => \$age,
'attachment' => \$attachment,
};
# apply plugins to everything except the message body text
for (my $plugin=0; $plugin<@{$hooks->{'message_data'}}; $plugin++) {
&{$hooks->{'message_data'}->[$plugin]}($hooks_message_data);
}
#slap empty message names
$messagename = "[no subject]" unless $messagename;
$messagename =~ s#http://">##g;
# HTML tag filter based on @approved_tags list at top
$_ = $messagename;
my @tags = m#<(?>"[^"]*"|'[^']*'|[^'">])*>#g;
my ($test_tag, $approved_tag);
EACH_TAG: foreach my $tag (@tags)
{
$test_tag = $tag;
$test_tag =~ tr/A-Z/a-z/;
$test_tag =~ s#*\s*(\S*)(?>"[^"]*"|'[^']*'|[^'">])*>#$1#;
TAG_TEST: foreach $approved_tag (@approved_tags)
{
next EACH_TAG if $approved_tag eq $test_tag; # tag good, next
}
$messagename =~ s#$tag##g; # remove the tag if not in approved list
}
my $trimmed_messagename = $messagename; # we'll use the "trimmed messagename"
$trimmed_messagename =~ s/^RE: //; # for dropping interstitial message title
# blocks.
$root_message_id = $messageid if $folder_flag; # > 0;
# if $folder_flag is set, grab a $root_message_id which will be
# passed on to our children.
print qq{\n
\n} unless ($thread_style == 4 && $expandmessage!=$messageid);
# expand for level 4 expansion
if ($thread_style == 4 && $messageid != $expandmessage )
{
my ($children) = countthread($messageid);
$children->{session}=0 unless $children->{session};
my $border;
if ($children->{session} > 0 || $age < $folder_session_age)
{
print qq{\n
\n};
print qq{\n}; # name tag for intra-page linking
if ( $messageid == $searchresult ) { $border = 1; } # set border visible on
# search result
else { $border = 0; } # otherwise, we'll have an invisable table border
# print qq{
\n}; # start message table
# print qq{
\n} # start message row for fresh or session messages (thread 1-3)
# if ( $age < $folder_session_age );
if ( $age < $folder_session_age )
{
# print qq{
\n} # print session flag if new since last
# if ($age < $folder_session_age); # session
# highlight search terms in message name to make them easy finding
my $display_messagename = $messagename;
foreach $mark (@marks)
{
$display_messagename =~ s/\b($mark)\b(?![^<]*?>)/$1<\/font>/gi;
}
$messagename =~ s# #\ #g;
print qq{$display_messagename};
# print qq{
\n} if ($age < $folder_session_age); # session flag
print qq{[$text->{dialog_by} };
print qq{$message_username};
$datetime =~ s/\ /\ /g;
print qq{] - $text->{dialog_posted}: $datetime};
print qq{};
my $message_expanded = 'N'; # reset expanded message flag to 'N'
# this is used to determine if we need to print the
# "expand thread" link
my ($linkname, $contents, $attachment_name, $message_userid);
if ( $age < $folder_session_age )
{
# mangle message title to keep it from screwing things up
my $mangled_messagename = $messagename;
$mangled_messagename =~ s/"/"/g;
$mangled_messagename =~ s/'/\\'/g;
$mangled_messagename =~ s/<[^>]*?>//g;
$mangled_messagename =~ s/>/>/g;
$mangled_messagename =~ s/</g;
print qq{};
# print qq{dura-link} for durable links
print qq{ [{dialog_link_title_duralink}'$mangled_messagename'">$text->{dialog_link_name_duralink}]}; #"
# print qq{isolate-link} for isolation links
print qq{ [{dialog_link_title_isolate}},
qq{'$mangled_messagename'">$text->{dialog_link_isolate}]} unless $op eq 'isolate';
print qq{\n},br,"\n";
my $sql_query = qq{
SELECT linkname, contents, attachment.filename, userid
FROM ( message, $settings->{'user_table'} AS user )
LEFT JOIN attachment ON attachment.message_id=message.id
WHERE message.id=$messageid
};
my $sth = $dbh -> prepare ($sql_query) || die $dbh->errstr;
$sth->execute();
($linkname, $contents, $attachment_name, $message_userid) = $sth->fetchrow_array ();
print_contents(\$contents);
if ($URI)
{
$URI = escapeHTML("$URI");
print qq{};
print qq{{link_flag}->[2]" align="middle" title="$text->{dialog_link_title_follow_link} };
$linkname ? print qq{$linkname} : print qq{$URI};
print qq{" border="0" /> };
$linkname ? print qq{$linkname} : print qq{$URI};
print qq{},br,qq{\n};
}
my ($local_file_name, @file_info, $attachment_size, $internal_attachment_name);
if ($attachment)
{
$local_file_name = sprintf("0%010d", $attachment);
@file_info = (stat "$home_dir/re_files/$local_file_name");
$attachment_size = $file_info[7];
$attachment_size = human_readable($attachment_size);
$internal_attachment_name = escapeHTML("$attachment_name");
$internal_attachment_name =~ s/\?/%3F/g; # escape any embeded ?'s in filename
$internal_attachment_name =~ s/\#/%23/g;
}
print qq{{dialog_link_title_download} '$attachment_name'">},
qq{{attachment_flag}->[1] },
qq{height=$icon->{attachment_flag}->[2] border=0 /> $attachment_name },
qq{($attachment_size)},br if $attachment;
$message_expanded = 'Y'; # set this flag is message was expanded
# this is used to determine if we need to print the
# "expand thread" link
}
if ( $message_expanded eq 'N' )
{
print qq{{attachment_flag}->[1] },
qq{height=$icon->{attachment_flag}->[2] border=0 },
qq{title='$text->{dialog_link_title_attachment} "$attachment_name"' />} if $attachment;
if ($URI)
{
$URI = escapeHTML("$URI");
print qq{{link_flag}->[2]" align="middle" title="$text->{dialog_link_title_link} };
$linkname ? print qq{$linkname} : print qq{$URI};
print qq{" />};
}
}
else
{
print qq{[ {dialog_link_title_reply}">$text->{dialog_link_reply} ] } #"
if ( ($otherw eq 'Y'
|| ($groupmember eq 'Y' && $groupw eq 'Y')
|| $our_userid == $ownerid)
&& $open eq 'Y'
&& $our_userid>0 );
print qq{[ $text->{dialog_link_edit} ] }
if ( ($our_userid == $message_userid
&& ( $groupmember eq 'Y' && $groupw eq 'Y' || $our_userid == $ownerid ) )
&& $open eq 'Y'
&& $our_userid >= 1 # to keep 'Guest' from editing messages
&& $age < ($settings->{'edit_interval'}) );
print qq{[ {dialog_link_title_disapear}">$text->{dialog_link_disapear} ] } if $name eq 'root';
}
# print qq{
\n};
print qq{\n};
# set $limit to "" so that there is no limit on children from this point on.
$limit = qq{};
$folder_session_age = folder_session_age($folderid);
threadchildren($messageid, $nth_level_thread_order, $root_message_id, 2, $messagename);
print qq{
{'warm_message_time'})
{
print qq{warm_body"};
}
elsif ($age > $settings->{'warm_message_time'})
{
print qq{day_old_body"};
}
print qq{>};
}
print qq{$text->{dialog_by} };
print qq{$message_username};
$datetime =~ s/\ /\ /g;
print qq{ [ $text->{dialog_posted}: $datetime ]};
print qq{};
my $message_expanded = 'N'; # reset expanded message flag to 'N'
# this is used to determine if we need to print the
# "expand thread" link
my ($linkname, $attachment_name, $local_file_name, @file_info, $attachment_size);
if ( ( ( ($age < $settings->{'fresh_message_time'} && $thread_style == 1) || ($age < 7*86400 && $thread_style == 5) )
|| $age < $folder_session_age)
|| $thread_style == 3
|| $messageid == $expandmessage)
{
# mangle message title to keep it from screwing things up
my $mangled_messagename = $messagename;
$mangled_messagename =~ s/"/"/g;
$mangled_messagename =~ s/'/\\'/g;
$mangled_messagename =~ s/<[^>]*?>//g;
$mangled_messagename =~ s/>/>/g;
$mangled_messagename =~ s/</g;
# print qq{dura-link} for durable links
print qq{};
print qq{ [{dialog_link_title_duralink}'$mangled_messagename'">dura-link]};
print qq{};
# print qq{isolate-link} for isolation links
print qq{};
print qq{[{dialog_link_title_isolate}},
qq{'$mangled_messagename'">$text->{dialog_link_isolate}]} unless $op eq 'isolate';
print qq{};
print br,"\n";
my $sql_query = qq{
SELECT linkname, contents, attachment.filename, userid
FROM ( message, $settings->{'user_table'} AS user )
LEFT JOIN attachment ON attachment.message_id=message.id
WHERE message.id=$messageid
};
my $sth = $dbh -> prepare ($sql_query) || die $dbh->errstr;
$sth->execute();
($linkname, $contents, $attachment_name, $message_userid) = $sth->fetchrow_array ();
print_contents(\$contents);
if ($URI)
{
$URI = escapeHTML("$URI");
print qq{};
print qq{{link_flag}->[2]" align="middle" title="$text->{dialog_link_title_follow_link}: };
$linkname ? print qq{$linkname} : print qq{$URI};
print qq{" border="0" /> };
$URI =~ s#(http\S{40})\S{4,}(\S{7})#$1....$2#ig; # trim long URLs to make them pretty
$linkname ? print qq{$linkname} : print qq{$URI};
print qq{},br;
}
my ($internal_attachment_name);
if ($attachment)
{
$local_file_name = sprintf("0%010d", $attachment);
@file_info = (stat "$home_dir/re_files/$local_file_name");
$attachment_size = $file_info[7];
$attachment_size = human_readable($attachment_size);
$internal_attachment_name = escapeHTML("$attachment_name");
$internal_attachment_name =~ s/\?/%3F/g; # escape any embeded ?'s in filename
$internal_attachment_name =~ s/\#/%23/g;
}
print qq{{dialog_link_title_download} '$attachment_name'">{attachment_flag}->[1] height=$icon->{attachment_flag}->[2] },
qq{border=0 /> $attachment_name ($attachment_size)},br if $attachment;
$message_expanded = 'Y'; # set this flag is message was expanded
# this is used to determine if we need to print the
# "expand thread" link
}
if ( $message_expanded eq 'N' )
{
if ($attachment)
{
print qq{{attachment_flag}->[1] },
qq{height=$icon->{attachment_flag}->[2] border=0 title='$text->{dialog_link_title_attachment}' />};
}
if ($URI)
{
$URI = escapeHTML("$URI");
print qq{{link_flag}->[2]" align="middle" title="$text->{dialog_link_title_link} };
$linkname ? print qq{$linkname} : print qq{$URI};
print qq{" />};
}
}
else
{
print qq{[ {dialog_link_title_reply}">$text->{dialog_link_reply} ] } #"
if ( ($otherw eq 'Y'
|| ($groupmember eq 'Y'
&& $groupw eq 'Y')
|| $our_userid == $ownerid)
&& $open eq 'Y'
&& $our_userid>0 );
print qq{[ $text->{dialog_link_edit} ] }
if ( ($our_userid == $message_userid
&& ( $groupmember eq 'Y' && $groupw eq 'Y' || $our_userid == $ownerid ) )
&& $open eq 'Y'
&& $our_userid >= 1 # to keep 'Guest' from editing messages
&& $age < ($settings->{'edit_interval'}) );
print qq{[ {dialog_link_title_disapear}"},
qq{>$text->{dialog_link_disapear} ] }
if $name eq 'root';
}
print qq{
\n};
print qq{
};
# print qq{
\n};
# set $limit to "" so that there is no limit on children from this point on.
$limit = qq{};
$folder_session_age = folder_session_age($folderid);
if ( $op eq 'expand' && $messageid == $expandmessage)
{
threadchildren($messageid, "$nth_level_thread_order", $root_message_id, 3, $messagename);
}
else
{
threadchildren($messageid, "$nth_level_thread_order", $root_message_id, $thread_style, $messagename);
}
print qq{} if $parent == $folderid;
} # end thread_style 1 # 3 progression
print qq{} unless ($thread_style == $expand && $expandmessage!=$messageid && $expand==4);
}
$sth->finish ();
}
$sth->finish ();
}
sub countchildren
{
my ($parent) = @_;
my $children = { today => 0, week => 0, session => 0};
my $sql_query = qq{ # get total messages in folder
SELECT count(*)
FROM message
WHERE folderid=$parent AND folder="N" AND open="Y"
};
my $sth = $dbh -> prepare ($sql_query) || die $dbh->errstr;
$sth->execute();
($children->{count}) = $sth->fetchrow_array ();
$sth->finish ();
$sql_query = qq{ # get all messages in last 24 hours
SELECT count(*)
FROM message
WHERE date_format(date_sub(now(), interval 1 day), '%Y%m%d%H%i%s') < time
AND folderid=$parent AND folder="N" AND open="Y"
};
$sth = $dbh -> prepare ($sql_query) || die $dbh->errstr;
$sth->execute();
($children->{today}) = $sth->fetchrow_array ();
$sth->finish ();
$sql_query = qq{ # children for last week (7 days)
SELECT count(*)
FROM message
WHERE time > date_format(date_sub(now(), interval 7 day), '%Y%m%d%H%i%s')
AND folderid=$parent AND folder="N" AND open="Y"
};
$sth = $dbh -> prepare ($sql_query) || die $dbh->errstr;
$sth->execute();
($children->{week}) = $sth->fetchrow_array ();
$sth->finish ();
$folder_session_age = 0 if $our_userid == 0; # this is a hack.
$folder_session_age = folder_session_age($parent);
($children->{session}) = countsessionchildren($parent);
$sql_query = qq{
SELECT date_format(time, "%H:%i %p")
FROM message
WHERE folderid=$parent AND folder="N" AND open="Y"
ORDER BY time DESC
LIMIT 1
};
$sth = $dbh -> prepare ($sql_query) || die $dbh->errstr;
$sth->execute();
($children->{last_posted}) = $sth->fetchrow_array ();
$sth->finish ();
return ($children);
}
sub countsessionchildren
{
my ($parent) = @_;
my ($sessions_children) = 0;
$folder_session_age = 0 if $our_userid == 0; # this is a hack.
# I can't figure out why $session_age is not being set to 0 when our user
# is 'Guest' ($our_userid == 0)
my $sql_query = qq{ # get the session age time
SELECT date_format(date_sub(now(), INTERVAL $folder_session_age second), '%Y%m%d%H%i%s')
};
my $sth = $dbh -> prepare ($sql_query) || die $dbh->errstr;
$sth->execute();
my ($session_time) = $sth->fetchrow_array ();
$sth->finish ();
$sql_query = qq{ # new messages since last session
SELECT count(*)
FROM message
WHERE folderid=$parent
AND folder="N" AND open="Y"
AND time > $session_time
};
$sth = $dbh -> prepare ($sql_query) || die $dbh->errstr;
$sth->execute();
($sessions_children) = $sth->fetchrow_array () || 0;
return ($sessions_children);
}
sub countthread
{
my ($parent) = shift @_;
my $count = { total => 0, today => 0, week => 0, session => 0, };
my $sql_query = qq{
SELECT id,
( UNIX_TIMESTAMP() - UNIX_TIMESTAMP(time) ) as age
FROM message
WHERE folder='N' and parentid=$parent AND open="Y" AND folderid=$folderid
};
my $sth = $dbh -> prepare ($sql_query) || die $dbh->errstr;
my $rv = int ( $sth->execute() );
my $childcount = $rv;
if ($rv > 0)
{
my ($messageid, $age);
while ( my @ary = $sth->fetchrow_array () )
{
($messageid, $age) = @ary;
$count->{today} ++ if $age < 1*24*3600;
$count->{week} ++ if ($age < 7*24*3600);
$count->{session} ++ if $age < $folder_session_age;
$count->{total} ++;
my $next_level = countthread($messageid);
$count->{total} += $next_level->{total} || 0;
$count->{today} += $next_level->{today} || 0;
$count->{session} += $next_level->{session} || 0;
$count->{week} += $next_level->{week} || 0;
}
}
return ($count); # ->{total}, $count->{today}, $count->{week}, $count->{session});
}
sub countfolders
{
my($parent) = @_;
my $foldercount;
my $sql_query = qq{
SELECT message.id
FROM message, members
WHERE folder='Y' AND folderid=$parent
AND (
( message.name NOT LIKE ".%" AND message.name NOT LIKE "~.%" ) # not hidden
OR ( # hidden
(message.name LIKE ".%" OR message.name LIKE "~.%")
AND ( message.userid=$our_userid # user is the owner of the folder
OR ( ( message.groupid=members.groupid AND members.userid=$our_userid ) # user is in group
AND message.groupr='Y' ) # and folder is group readable
)
)
)
GROUP BY message.id
};
if ( $name eq 'root' ) # override folder count for $name eq 'root'
{
$sql_query = qq{
SELECT message.id
FROM message
WHERE folder='Y' AND folderid=$parent
GROUP BY message.id
};
}
my $sth = $dbh -> prepare ($sql_query) || die $dbh->errstr;
my $rv = int ( $sth->execute() );
$sth->finish ();
return($rv)
}
sub print_folder
{
my $query = qq{SELECT name from $settings->{'user_table'} where id=$ownerid};
$sth = $dbh->prepare ($query);
$sth->execute ();
my ($folder_ownername) = $sth->fetchrow_array ();
$sth->finish ();
$query = qq{SELECT name from groups where id=$groupid};
$sth = $dbh->prepare ($query);
$sth->execute ();
my ($folder_groupname) = $sth->fetchrow_array ();
$sth->finish ();
print qq{};
if ($open eq 'Y')
{
if ($folderid == 1)
{
print qq{{in_root}->[1] height=$icon->{in_root}->[2] alt="" border=0}; #"
print qq{ align="top">};
}
else
{
print qq{{in_open_folder}->[1] height=$icon->{in_open_folder}->[2] alt="" border=0}; # "
print qq{ align="top">};
}
}
print qq{{'in_locked_folder'}->[1] height=$icon->{'in_locked_folder'}->[2] alt="" border=0\
align="top">}
if $open eq 'N'; # "
print qq{};
# print qq{ $folder};
print qq{ $breadcrumb_link};
print qq{ $text->{dialog_folder_closed}} if $open eq 'N';
$linkfolder = $folder;
$linkfolder =~ s/\ /%20/g;
# print attributes icon
print qq{ {dialog_link_title_attributes}">},
qq{{folder_attributes}->[1] },
qq{height=$icon->{folder_attributes}->[2] border=0 align="middle" />}
if ( $our_userid == $ownerid || $name eq 'root' ); # "
# print owner and group info
print qq{};
print qq{ [};
#print qq{$folder_ownername};
# print qq{ | };
print qq{};
print qq{$folder_groupname]};
print qq{};
print br;
}
sub find_thread_root
{
my($id) = @_;
my $rootid;
my $query = qq{SELECT parentid, folderid FROM message WHERE id=$id};
my $sth = $dbh -> prepare ($query) || die $dbh->errstr;
$sth->execute();
my ($parentid, $folderid) = $sth->fetchrow_array ();
$sth->finish ();
if ($parentid == $folderid)
{
$rootid = $id;
}
else
{
$rootid = find_thread_root($parentid);
}
return ($rootid);
}
sub regress_folders
{
my($parent_folderid) = @_;
my ($path) = '';
if ($parent_folderid > 0)
{
until ($parent_folderid == 1)
{
my $query = qq{SELECT name, parentid
FROM message
WHERE id=$parent_folderid};
my $sth = $dbh -> prepare ($query) || die $dbh->errstr;
$sth->execute();
my $folder_name;
($folder_name, $parent_folderid) = $sth->fetchrow_array ();
$path = $folder_name."/".$path;
}
$sth->finish ();
}
return ($path);
}
sub print_title
{
print $settings->{'title'};
}
sub passkey
{
my @chars = ( "A" .. "Z", "a" .. "z", 0 .. 9 );
my $passkey0 = join("", @chars[ map { rand @chars } (1 .. 20) ]);
# create a passkey with the username as an MD5 seed
my $passkey = md5_hex($name.$passkey0);
if ($name) # only do this update if a user is logged (don't want the warning for new users
{
# issue UPDATE to store new passkey
my $query = qq{UPDATE $settings->{'user_table'} SET passkey = "$passkey", counter=0 WHERE name="$name"};
$sth = $dbh->prepare ($query);
$sth->execute ();
$sth->finish ();
}
return("$passkey");
}
sub session_age
{
my ($session) = @_;
# get time in secs, then convert back to days
if ($session)
{
my $query = qq{SELECT ( UNIX_TIMESTAMP() - UNIX_TIMESTAMP('$session') )};
my $sth = $dbh->prepare ($query);
$sth->execute ();
my ($session_age) = $sth->fetchrow_array ();
$sth->finish ();
return($session_age);
}
else
{
return(0);
}
}
sub folder_session_age
{
my ($session_folderid) = @_;
my ($folder_dtime, $folder_timestamp, $folder_session, $folder_session_age);
if ($our_userid > 0 ) # we don't want to mess around if user not logged in.
{
my $query = qq{SELECT
( UNIX_TIMESTAMP() - UNIX_TIMESTAMP(timestamp) ),
timestamp, session
FROM sessions
WHERE user=$our_userid AND folder=$session_folderid
};
my $sth = $dbh->prepare ($query);
my $rv = int ( $sth->execute () );
if ($rv > 0 )
{
($folder_dtime, $folder_timestamp, $folder_session) = $sth->fetchrow_array ();
$sth->finish ();
}
else # if session info does not exist for this user in this folder, we'll just create
{ # it from the general user session data that we already have in memory
$sth->finish ();
$query = qq{INSERT INTO sessions
SET folder=$session_folderid,
user=$our_userid,
timestamp=$session,
session=$session};
$sth = $dbh->prepare ($query);
$sth->execute ();
$folder_dtime = $delta_time; # just use general delta time
$folder_timestamp = $timestamp;
$folder_session = $session;
$sth->finish ();
}
if ( ( $op eq 'add entry' # do not update session on entries
|| $op eq 'preview' # ... or previews of entries
|| $op eq ' entry' # ... or the start of creating new entries
|| $op eq 'expand' # ... or when a folder expansion is changed
|| $op eq 'isolate' # ... or when a thread is isolated for printing
|| $op eq 'edit' # ... or when a user edits one of his own messages
|| $op eq 'save changes' # ... or when a user saves changes after editing a message
|| defined(param('page')) ) # ... or the user requests a specific page in folder
&& $folderid == $session_folderid )
{ # if we're in the folder, and we've added a new entry, we'll preimptively update the
# update the folder timestamp but hold the session
update_folder_session($session_folderid);
}
elsif ( $folder_dtime > $session_timeout && $folderid == $session_folderid)
{
$folder_session = $folder_timestamp;
$query = qq{UPDATE sessions
SET session=date_format('$folder_timestamp', '%Y%m%d%H%i%s'), timestamp=now(), counter=0
WHERE user=$our_userid AND folder=$session_folderid};
$sth = $dbh->prepare ($query);
$sth->execute ();
$sth->finish ();
}
elsif ( $folderid == $session_folderid )
{ # if we're in the folder, but folderd_time not sessioned out
# update folder timestamp
update_folder_session($session_folderid);
}
else
{
$folder_session = $folder_timestamp;
}
$folder_session_age = session_age($folder_session);
$sth->finish ();
}
else
{
$folder_session_age = 0;
}
return($folder_session_age); # folder_session_age in secs
}
sub user
{
# Check for passkey in cookie or NULL
my ($passkey) = cookie(-name=>"$settings->{'cookie_name'}") || 'NULL';
($passkey, $name) = split('\-', $passkey, 2); # split the cookie, limited to 2 parts
chomp($passkey);
# If not $session_timeout defined, define it as 2 minutes
$session_timeout = 120; # 120 secs = 2 min for session time outs.
if ($passkey ne 'NULL')
{
my $query = qq{SELECT id, name, date_format(now(), '%e.%b.%Y %h:%i %p'),
( UNIX_TIMESTAMP() - UNIX_TIMESTAMP(timestamp) ),
timestamp, session, thread
FROM $settings->{'user_table'}
WHERE passkey='$passkey'};
my $sth = $dbh->prepare ($query);
$sth->execute ();
my @ary = $sth->fetchrow_array ();
($our_userid, $name, $current_system_time, $delta_time, $timestamp, $session, $user_thread_style) = @ary;
$username = $name;
$user_thread_style = 0 unless defined($user_thread_style); # make sure $user_thread_style is defined
if ($username)
{
$query = qq{SELECT groupid
FROM members
WHERE userid=$our_userid};
$sth = $dbh->prepare ($query);
$sth->execute ();
while (@ary = $sth->fetchrow_array ())
{
my ($this_group) = @ary;
# push (@users_groups, $this_group);
$users_groups{$this_group} = 'Y';
}
$sth->finish ();
}
$sth->finish ();
}
# set delta_time to 0 if no user
$delta_time = 0 unless $delta_time;
################################# this may cause trouble, so keep an eye out for bugs.
# if the time since last page acess (delta_time) is > the defined session timeout
# ($session_timeout), reset the session to the last timestamp
if ($delta_time > $session_timeout)
{
$session = $timestamp; # set $session to the last timestamp
# Put the last timestamp into the session column
$query = qq{UPDATE $settings->{'user_table'} SET session='$timestamp' WHERE id='$our_userid'};
$sth = $dbh->prepare ($query);
$sth->execute ();
$sth->finish ();
}
$session = 'NULL' unless $session; # set a default value if $session not defined
$name = '' if !$name; # just to get rid of the warnings....
if ($name ne '')
{
# see if user is a member of the group that owns the folder
my $query = qq{SELECT userid
FROM members
WHERE userid=$our_userid
AND groupid=$groupid};
my $sth = $dbh->prepare ($query);
$sth->execute ();
my ($answer) = $sth->fetchrow_array ();
$sth->finish ();
$groupmember = 'Y' if $answer;
unless ( $op eq 'norefresh' || $op eq 'clean output' || $op eq 'dlarchive' || $op eq 'publish' )
{
my $passkey = passkey();
$cookie_domain = $settings->{'domain_name'};
$cookie_domain =~ s/^\.//; # clear off any leading "."
$cookie_domain =~ s/^www\.//; # clear off any leading "www."
$cookie_domain = ".".$cookie_domain; # stick a "." on the front of the domain name
$cookie = cookie(-name=>"$settings->{'cookie_name'}", # this is the cookie name
-value=>"$passkey", # this is the fresh passkey
-path=>'/', # we want the cookie available from any path
-domain=>"$cookie_domain", # our modified cookie_domain
-expires=>'+15d'); # expire cookie in 15 days.
}
else
{
$query = qq{UPDATE $settings->{'user_table'} SET timestamp=now() WHERE id=$our_userid};
$query = qq{UPDATE $settings->{'user_table'} SET timestamp=now(), counter=0 WHERE id=$our_userid} if $op eq 'norefresh';
$sth = $dbh->prepare ($query);
$sth->execute ();
$sth->finish ();
}
# see who's been online "recently"
# I'm going to attempt to restrict user visability to group members.....
$query = qq{SELECT name
FROM user, members as ours, members as thiers
WHERE date_sub(now(), interval $settings->{'recent_interval'} minute) < timestamp
AND ours.userid = $our_userid
AND thiers.groupid = ours.groupid
AND $settings->{'user_table'}.id = thiers.userid
GROUP BY $settings->{'user_table'}.id
};
$query = qq{SELECT name
FROM $settings->{'user_table'}
WHERE date_sub(now(), interval $settings->{'recent_interval'} minute) < timestamp
} if $our_userid == 1;
$sth = $dbh->prepare ($query);
$sth->execute ();
while ( my @ary = $sth->fetchrow_array () )
{
my ($online_name) = @ary;
$currently_online .= "$online_name, "; # if $online_name ne $name;
}
$sth->finish ();
$currently_online =~ s/,\ $//;
}
elsif ($name eq '') { $our_userid = 0; $groupmember=0; $session_age=0;}
if ($op eq 'login')
{
$username = param('username') if param('username');
my $password = param('password') if param('password');
if ($username && $password)
{
# issue SELECT to verify user and password
$query = qq{SELECT name, password, timestamp FROM $settings->{'user_table'} WHERE name='$username'};
$sth = $dbh->prepare ($query);
$sth->execute ();
my @ary = $sth->fetchrow_array ();
my $pass_md5;
($name, $pass_md5, $session) = @ary;
if ($name =~ /^!/ ) # check for unconfirmed username
{
print header();
print $text->{dialog_warning_unconfirmed_account};
$sth->finish ();
$dbh->disconnect ();
exit(0);
}
if ($pass_md5 eq md5_hex('deactivate') )
{
print header();
print $text->{dialog_warning_account_deactivated};
$sth->finish ();
$dbh->disconnect ();
exit(0);
}
if ($pass_md5 ne md5_hex($password) )
{
print header();
print $text->{dialog_warning_loggin_failed},"\n",br,br;
print $text->{dialog_warning_check_username},br;
print $text->{dialog_warning_check_password},br;
print $text->{dialog_warning_check_capslock},br;
print qq{$text->{dialog_login}};
$sth->finish ();
$dbh->disconnect ();
exit(0);
}
# update session to our last timestamp (reguardless of delta_t)
$query = qq{UPDATE $settings->{'user_table'} SET session='$session' WHERE name='$username'};
$sth = $dbh->prepare ($query);
$sth->execute ();
$sth->finish ();
my $passkey = passkey();
$cookie_domain = $settings->{'domain_name'};
$cookie_domain =~ s/^\.//; # clear off any leading "."
$cookie_domain =~ s/^www\.//; # clear off any leading "www."
$cookie_domain = ".".$cookie_domain; # stick a "." on the front of the domain name
my $cookie = cookie(-name=>"$settings->{'cookie_name'}",
-value=>"$passkey-$name",
-path=>'/',
-domain=>"$cookie_domain",
-expires=>'+15d');
print redirect(-cookie=>[$cookie],
-url=>"$cgi_url?folder=$folder");
}
else
{
print header();
print start_html(-title=>"$settings->{'title_tag'} - login",
-head=>[Link({-rel=>"SHORTCUT ICON", -href=>'/favicon.ico'})],
-meta=>{'MSSmartTagsPreventParsing'=>'True'},
-meta=>{'viewport'=>'width=device-width'},
-style=>{-src=>"$stylesheet"});
print qq{
};
end_html();
exit(0);
}
}
elsif ($op eq 'logout' && $name)
{
$cookie_domain = $settings->{'domain_name'};
$cookie_domain =~ s/^\.//; # clear off any leading "."
$cookie_domain =~ s/^www\.//; # clear off any leading "www."
$cookie_domain = ".".$cookie_domain if $cookie_domain; # stick a "." on the front of the domain name
my $cookie = cookie(-name=>"$settings->{'cookie_name'}",
-value=>"",
-path=>'/',
-domain=>"$cookie_domain",
-expires=>'-1m');
print redirect(-cookie=>[$cookie],
-url=>"$cgi_url?folder=$folder");
print start_html();
passkey(); # set new passkey so that an eves dropper can't reenter
# the site using the old passkey. This is just added security
# for the extreemly paranoid
}
$sth->finish ();
return($name);
$session_age = session_age($session);
}
sub quick_jump_menu
{
my ($parent_id,$parentage) = @_;
my $new_messages;
$leader = " ";
$leaders += 1;
# if we're at the first level, we'll start the form and set things up.
if ($parent_id == 1)
{
print qq{
};
}
}
sub quick_folder_count
{
my ($parent_id) = @_;
my ($folder_session_count) = 0;
my $query = qq{SELECT folder.id
FROM message folder, members, sessions, user
WHERE folder.folder='Y' AND folder.open='Y'
AND sessions.folder=folder.id AND $settings->{'user_table'}.id=$our_userid
AND folder.folderid=$parent_id
AND members.userid=user.id
AND sessions.user=user.id
AND ( (folder.groupr='Y' AND members.groupid=folder.groupid)
OR ( folder.otherr='Y'
# AND ( folder.name NOT LIKE '.%'
# AND folder.name NOT LIKE '~.%' ))
AND (
( folder.name NOT LIKE ".%" AND folder.name NOT LIKE "~.%" ) # not hidden
OR ( # hidden
(folder.name LIKE ".%" OR folder.name LIKE "~.%")
AND ( folder.userid=user.id # user is the owner of the folder
OR ( ( folder.groupid=members.groupid AND members.userid=user.id ) # user is in group
AND folder.groupr='Y' ) # and folder is group readable
)
)
)
)
OR folder.userid=$our_userid
OR '$name'='root')
GROUP BY folder.id};
my $sth = $dbh->prepare ($query);
$sth->execute ();
while ( my @ary = $sth->fetchrow_array () )
{
my ($sub_folderid) = @ary;
$folder_session_count += quick_folder_count($sub_folderid);
}
# count the number of session messages in sub folders
$query = qq{SELECT message.id
FROM message message, message folder, sessions
WHERE folder.folder='Y' AND message.folder='N' AND folder.open='Y'
AND message.open='Y' AND sessions.folder=folder.id
AND message.folderid=folder.id AND folder.folderid=$parent_id
AND message.time > sessions.timestamp
AND sessions.user=$our_userid
GROUP BY message.id};
$sth = $dbh->prepare ($query);
# $sth->execute ();
$folder_session_count += int ( $sth->execute() );
$folder = '' if $folder eq $root_folder_name;
$sth->finish ();
return($folder_session_count);
}
sub move_folder
{
my ($parent_id,$parentage) = @_;
$leader = " ";
$leaders += 1;
return() if $folderid == 1; # don't show a "Move to:" menu for the root folder
# if we're at the first level, we'll start the form and set things up.
if ($parent_id == 1)
{
print qq{$text->{dialog_move_to}: };
}
}
sub update_folder_session
{
my ($session_folderid) = @_;
my $query = qq{UPDATE sessions
SET timestamp=now()
WHERE user=$our_userid
AND folder=$session_folderid};
my $sth = $dbh->prepare ($query);
$sth->execute ();
$sth->finish ();
}
sub print_contents
{
# A reference to the message contents is passed rather than the verbose contents
my ($contents) = shift;
$$contents =~ s#http://">##sg; # get rid of dangerous HTML
# apply plugins to message body text
for (my $plugin=0; $plugin<@{$hooks->{'message_body'}}; $plugin++) {
&{$hooks->{'message_body'}->[$plugin]}($contents);
}
# HTML tag filter based on @approved_tags list at top
$_ = $$contents;
my @tags = m#<(?>"[^"]*"|'[^']*'|[^'">])*>#g;
my ($test_tag, $approved_tag);
EACH_TAG: foreach my $tag (@tags)
{
# warn ("tag: $tag\n");
$test_tag = $tag;
$test_tag =~ tr/A-Z/a-z/s;
$test_tag =~ s/([\[\]])/\\$1/g;
$test_tag =~ s#?\s*(\w+)(?>\s|"[^"]*"|'[^']*'|[^'">])*>#$1#s;
TAG_TEST: foreach $approved_tag (@approved_tags)
{
next EACH_TAG if $approved_tag eq $test_tag; # tag good, next
}
# $line =~ s#$tag##g; # remove the tag if not in approved list
# if tag is not approved, convert <,> to <, > and replace
# my $failed_tag = $tag;
# $failed_tag =~ s/\</sg;
# $failed_tag =~ s/>/\>/sg;
$$contents =~ s#<(/?)$test_tag#\<$1$test_tag#sg;
$$contents =~ s#($test_tag(?>"[^"]*"|'[^']*'|[^'">])*)>#$1\>#sg;
}
# convert apparent URLs to linked URLs
# but not if they are already HTML coded as links
$$contents =~ s#(?)( ?)(https?:\/\/[^() \[\]\t"<>\\\^'{}\|\n]+(\w|\/))#$1$2<\/a>#ig;
# trim excessively long URLs for length
$$contents =~ s#>(http\S{40})\S{4,}(\S{7})#>$1....$2#ig;
# convert apparent email addressed to linked email addresses
# but not already linked emails
$$contents =~ s#(?$1#g;
# convert potential character problems to HTML escape sequences
$$contents =~ s#\x91#\‘#g; # left-single quote
$$contents =~ s#\x92#\’#g; # right-single quote
$$contents =~ s#\x93#\“#g; # left-double quote
$$contents =~ s#\x94#\”#g; # right-double quote
$$contents =~ s#\x96#\–#g; # n-dash
$$contents =~ s#\x97#\—#g; # m-dash
# highlight search terms in message to make them easy finding
foreach $mark(@marks)
{
$$contents =~ s/\b($mark)\b(?![^<]*?>)/$1<\/font>/gi;
}
my @contents = split (/\r?\n/, $$contents);
if ($#contents <= 1)
{
@contents = split (/\r/, $$contents);
}
my $tag_count;
foreach my $line (@contents)
{
# test for start of table, list, or blockquote
# if start of table increment "in_table" flag to supress space translation
if ($line =~ /
0 || $in_block > 0 )
{
# convert double spaces to '  ';
$line =~ s# #\ #g;
# odd-man catcher
$line =~ s# #\ #g;
# convert leading spaces to
$line =~ s#^ #\ #;
}
# test for end of table, list, or blockquote
# if end of table, decrement "in_table" flag to reactivate space translation
if ($line =~ /<\/table/i)
{
$_ = $line;
my @tag_count = m#
tags, incriment the counter
while ( $in_table < 0 )
{
$line =~ s#]*?>##i;
$in_table++;
}
# test for end of list, or blockquote
# if end of list or blockquote, decrement "in_block" flag to reactivate space translation
if ($line =~ /<\/(ol|ul|blockquote)/i)
{ $in_block--; }
print $line;
print br unless ( $line =~ m#?(ol|ul|li|blockquote|table|th|tr|td|br|/p|dt|dd)>#i );
print qq{\n};
}
# if $in_table > 0, we have a problem... inser enough tags,
# to close all tables and incriment the counter
while ( $in_table > 0 )
{
print qq{\n};
$in_table--;
}
print qq{\n\n
\n
\n} if $in_block > 0;
$in_table=0; #reset $in_table to 0 just in case.
$in_block=0; #reset $in_block to 0 just in case.
}
sub send_confirm_message # subroutine to send a confirmation link to user
{
my ($user_name) = @_;
# $user_name = '!'.$user_name;
my $banged_user_name = $dbh->quote('!'.$user_name);
$query = qq{ SELECT $settings->{'user_table'}.passkey, $settings->{'user_table'}.email
FROM user
WHERE $settings->{'user_table'}.name=$banged_user_name
};
$sth = $dbh->prepare ($query);
$sth->execute ();
@ary = $sth->fetchrow_array ();
my ($passkey, $email) = @ary;
my $temp_domain_name = $settings->{'domain_name'};
$temp_domain_name =~ s/^\.//; # strip leading '.' from beginning of domain name
# if present.
# $temp_user_name will hold the HTML escaped username for confirmation
my $temp_user_name = escapeHTML($user_name);
$temp_user_name =~ s/\ /\%20/g;
# warn "$temp_user_name\n";
my $message = <{notification_dialog_do_not_reply}
END_OF_MESSAGE
my $mailer = Mail::Mailer->new();
$mailer->open({'From' => "$settings->{'notification_address'}",
'To' => "$email",
'Subject' => "Your $settings->{'title_tag'} login"} );
print $mailer "$message";
close($mailer);
}
sub human_readable
{
my ($size) = @_;
$size = 0 unless $size;
my $units = "b ";
if ($size > 1000)
{
$size = $size/1024;
$units = "kb";
}
if ($size > 1000)
{
$size = $size/1024;
$units = "mb";
}
if ($size > 1000)
{
$size = $size/1024;
$units = "gb";
}
if ($size > 1000)
{
$size = $size/1024;
$units = "tb";
}
$size = sprintf("%.1f $units", $size) unless ( $units eq "b ");
$size = "$size $units " if ( $units eq "b ");
$size =~ s/ / /g;
return($size);
}
# various tools for testing
sub explain_query # subroutine to help with query optimization
{
my ($test_query) = @_;
$test_query =~ s/\n//g;
$test_query =~ s/\t/ /g;
warn (qq{EXPLAIN $test_query;\n});
}
# for testing queries
# $query =~ s/\n//g;
# $query =~ s/\t/ /g;
# $query =~ s/\ \ */ /g;
# $query =~ s/\ \ */ /g;
# warn ("QUERY: $query\n");