Gossamer Forum
Home : Products : Links 2.0 : Customization :

If I don't accept modifications I want the link to remain...

Quote Reply
If I don't accept modifications I want the link to remain...
Hi,
I've done a lot of modifications to links and I don't know if it's the same for all the other users.

My problem:
When someone wants to modify his link a receive the email and then I log in and decide wheter or not accepting the modification.

- If I accept, no problem... the program rebuilds the links with the modification
- If I don't, the program erase the link!

Well I'd like the program not to erase the link but to let it in as it was before the owner tried to modify.

Is this possible? Is there a way to prevent it?
I would just like to send an email where I say that I've not accepted the modification and that the user still can try to post a new modification....

Please, Help and best wishes to all Links fans!!!

Andrea
Quote Reply
Re: [Andreaf] If I don't accept modifications I want the link to remain... In reply to
Could you upload modify.cgi, db.pl and db_utils.pl here, so we can see what mods etc you have done?

Cheers

Andy (mod)
andy@ultranerds.co.uk
Want to give me something back for my help? Please see my Amazon Wish List
GLinks ULTRA Package | GLinks ULTRA Package PRO
Links SQL Plugins | Website Design and SEO | UltraNerds | ULTRAGLobals Plugin | Pre-Made Template Sets | FREE GLinks Plugins!
Quote Reply
Re: [Andy] If I don't accept modifications I want the link to remain... In reply to
Hey Andy, you're better than a live help customer care!
It just took you few seconds to reply my post...

Well heare are the codes:

MODIFY.CGI
Code:
# Required Librariers
# --------------------------------------------------------
eval {
($0 =~ m,(.*)/[^/]+,) && unshift (@INC, "$1"); # Get the script location: UNIX /
($0 =~ m,(.*)\\[^\\]+,) && unshift (@INC, "$1"); # Get the script location: Windows \

require "admin/links.cfg"; # Change this to full path to links.cfg if you have problems.
require "$db_lib_path/db_utils.pl";
require "$db_lib_path/links.def";
$build_use_templates ?
require "$db_lib_path/site_html_templates.pl" :
require "$db_lib_path/site_html.pl";
};
if ($@) {
print "Content-type: text/plain\n\n";
print "Error including libraries: $@\n";
print "Make sure they exist, permissions are set properly, and paths are set correctly.";
exit;
}

# ========================================================

eval { &main; }; # Trap any fatal errors so the program hopefully
if ($@) { &cgierr("fatal error: $@"); } # never produces that nasty 500 server error page.
exit; # There are only two exit calls in the script, here and in in &cgierr.

sub main {
# --------------------------------------------------------
local (%in) = &parse_form;

# We are processing the form.
if ($in{'Submit'}) {
&process_form;
}
# Otherwise we are displaying the form (in site_html.pl), displaying
# the entrance (Asks for Link ID and Password)
else {
if ($in{'ID'} =~ /^\d+$/) {
my (%rec) = &get_record ($in{'ID'});

if ($rec{$db_key} eq $in{'ID'}) {
if ($rec{'Password'} eq $in{'password'}) {
&site_html_modify_form (%rec);
}
else {
&site_html_modify_failure ("Password Invalid: $in{'password'}");
}
}
else {
&site_html_modify_failure ("Unkown Link ID: $in{'ID'}");
}
}
else {
&site_html_modify_first;
}
}
}

sub process_form {
# --------------------------------------------------------
my ($key, $status, @values, $found);
local (%original);

# Make sure we have a link to modify.
# !$in{'Current URL'} and &site_html_modify_failure ("non hai specificato il link da modificare") and return;

# Let's check to make sure the link we want to update is actually
# in the database.
open (DB, "<$db_file_name") or &cgierr("errore nel validate_records. impossibile aprire il db file: $db_file_name. Motivo: $!");
$found = 0;
LINE: while (<DB>) {
(/^#/) and next LINE;
(/^\s*$/) and next LINE;
chomp;
@data = &split_decode($_);
if ($data[$db_key] eq $in{'ID'}) {
$in{$db_key} = $data[0];
$found = 1;
%original = &array_to_hash (0, @data);
last LINE;
}
}
close DB;
!$found and &site_html_modify_failure ("il link non è stato trovato nel database") and return;

# Since we have a valid link, let's make sure the system fields are set to their
# proper values. We will simply copy over the original field values. This is to stop
# people from trying to modify system fields like number of hits, etc.
foreach $key (keys %add_system_fields) {
$in{$key} = $original{$key};
}

# Set date variable to today's date.
$in{$db_cols[$db_modified]} = &get_date;

# Validate the form input..
$status = &validate_record(%in);
if ($status eq "ok") {
# First make sure the link isn't already in there.
open (MOD, "<$db_modified_name") or &cgierr ("impossibile aprire modified database: $db_modified_name. Motivo: $!");
while (<MOD>) {
chomp;
@values = split /\|/;
if ($values[0] eq $in{$db_key}) {
close MOD;
&site_html_modify_failure("Una richiesta per apportare delle modifiche a questo link è già stata ricevuta. Si prega di riprovare più tardi.");
return;
}
}
close MOD;

# Print out the modified record to a "modified database" where it is stored until
# the admin decides to add it into the real database.
open (MOD, ">>$db_modified_name") or &cgierr("errore nel modify.cgi. impossibile aprire modification database: $db_modified_name. Motivo: $!");
flock(MOD, $LOCK_EX) unless (!$db_use_flock);
print MOD &join_encode(%in);
close MOD; # automatically removes file lock

# Send the admin an email message notifying of new addition.
&send_email;
# Send the visitor to the success page.
&site_html_modify_success;
}
else {
# Let's change that error message from a comma delimted list to an html
# bulleted list.
&site_html_modify_failure($status);
}
}

sub send_email {
# --------------------------------------------------------
# Sends an email to the admin, letting him know that there is
# a new link waiting to be validated.

# Check to make sure that there is an admin email address defined.
$db_admin_email or &cgierr("Indirizzo Email Amministratore Database Non E' Definito Nel Config File!");
my $to = $db_admin_email;
my $from = $in{$db_cols[$db_contact_email]};
my $subject = "Modifica al Dominio: $in{'Title'}";
my $msg = qq|
E' stata ricevuta una richiesta di modifica al databse del dominio $in{'Title'}

DATI ORIGINALI:
===============================================
Titolo $original{'Title'}
URL: $original{'URL'}
Descrizione: $original{'Description'}
Country: $original{'Country'}
Type: $original{'Type'}
Nome: $original{'Contact Name'}
Email: $original{'Contact Email'}
Categoria: $original{'Category'}

NUOVI DATI:
===============================================
Titolo: $in{'Title'}
URL: $in{'URL'}
Descrizione: $in{'Description'}
Country: $in{'Country'}
Type: $in{'Type'}
Nome: $in{'Contact Name'}
Email: $in{'Contact Email'}
Categoria: $in{'Category'}

Remote Host: $ENV{'REMOTE_HOST'}
Referer: $ENV{'HTTP_REFERER'}

Per accettare oppure rifiutare le modifiche collegati a:
$db_script_url

Gestione
|;

# Then mail it away!
require "$db_lib_path/Mailer.pm";
my $mailer = new Mailer ( { smtp => $db_smtp_server,
sendmail => $db_mail_path,
from => $from,
subject => $subject,
to => $to,
msg => $msg,
log => $db_mailer_log
} ) or return undef;
$mailer->send or return undef;


DB.PL


Code:
sub add_record {
# --------------------------------------------------------
# Adds a record to the database. First, validate_record is called
# to make sure the record is ok to add. If it is, then the record is
# encoded and added to the database and the user is sent to
# html_add_success, otherwise the user is sent to html_add_failure with
# an error message explaining why. The counter file is also updated to the
# next number.

my ($output, $status, $counter);

# First we validate the record to make sure the addition is ok.
$status = &validate_record (%in);

# We keep checking for the next available key, or until we've tried 50 times
# after which we give up.
while ($status eq "duplicate key error" and $db_key_track) {
return "duplicate key error" if ($counter++ > 50);
$in{$db_key}++;
$status = &validate_record (%in);
}
if ($status eq "ok") {
open (DB, ">>$db_file_name") or &cgierr("error in add_record. unable to open database: $db_file_name.\nReason: $!");
if ($db_use_flock) {
flock(DB, 2) or &cgierr("unable to get exclusive lock on $db_file_name.\nReason: $!");
}
print DB &join_encode(%in);
close DB; # automatically removes file lock
if ($db_key_track) {
open (ID, ">$db_id_file_name") or &cgierr("error in get_defaults. unable to open id file: $db_id_file_name.\nReason: $!");
if ($db_use_flock) {
flock(ID, 2) or &cgierr("unable to get exclusive lock on $db_id_file_name.\nReason: $!");
}
print ID $in{$db_key}; # update counter.
close ID; # automatically removes file lock
}
&html_add_success;
}
else {
&html_add_failure($status);
}
}

sub delete_records {
# --------------------------------------------------------
# Deletes a single or multiple records. First the routine goes thrrough
# the form input and makes sure there are some records to delete. It then goes
# through the database deleting each entry and marking it deleted. If there
# are any keys not deleted, an error message will be returned saying which keys
# were not found and not deleted, otherwise the user will go to the success page.

my ($key, %delete_list, $rec_to_delete, @data, $errstr, $succstr, $output);
$rec_to_delete = 0;
foreach $key (keys %in) { # Build a hash of keys to delete.
if ($in{$key} eq "delete") {
$delete_list{$key} = 1;
$rec_to_delete = 1;
}
}
$rec_to_delete or (&html_generic("Error: $html_object(s) Not Deleted", "no records specified.") and return);

# Search the database for a record to delete.
open (DB, "<$db_file_name") or &cgierr("error in delete_records. unable to open db file: $db_file_name.\nReason: $!");
if ($db_use_flock) { flock(DB, 1); }
LINE: while (<DB>) {
(/^#/) and ($output .= $_ and next LINE);
(/^\s*$/) and next LINE;
chomp;
@data = &split_decode($_);

$delete_list{$data[$db_key_pos]} ? # if this id is one we want to delete
($delete_list{$data[$db_key_pos]} = 0) : # then mark it deleted and don't print it to the new database.
($output .= "$_\n"); # otherwise print it.
}
close DB;

# Reprint out the database.
open (DB, ">$db_file_name") or &cgierr("error in delete_records. unable to open db file: $db_file_name.\nReason: $!");
if ($db_use_flock) {
flock(DB, 2) or &cgierr("unable to get exclusive lock on $db_file_name.\nReason: $!");
}
print DB $output;
close DB; # automatically removes file lock

# Build success/error messages.
foreach $key (keys %delete_list) {
$delete_list{$key} ? # Check to see if any items weren't deleted
($errstr .= "$key,") : # that should have been.
($succstr .= "$key,"); # For logging, we'll remember the one's we deleted.
}
chop($succstr); # Remove trailing delimeter
chop($errstr); # Remove trailing delimeter

$errstr ? # Do we have an error?
&html_generic("Error: $html_object(s) Not Deleted", qq|The records with the following keys were not found in the database: <FONT COLOR="red">'$errstr'</FONT>.|) : # If so, then let's report go to the failure page
&html_generic("$html_object(s) Deleted", "The following records were deleted from the database: '$succstr'"); # else, everything went fine.
}

sub modify_record {
# --------------------------------------------------------
# This routine does the actual modification of a record. It expects
# to find in %in a record that is already in the database, and will
# rewrite the database with the new entry. First it checks to make
# sure that the modified record is ok with validate record.
# It then goes through the database looking for the right record to
# modify, if found, it prints out the modified record, and returns
# the user to a success page. Otherwise the user is returned to an error
# page with a reason why.

my ($status, @data, $output, $found);

$status = &validate_record (%in); # Check to make sure the modifications are ok!

if ($status eq "ok") {
$found = 0; # Make sure the record is in here!
open (DB, "<$db_file_name") or &cgierr("error in modify_records. unable to open db file: $db_file_name.\nReason: $!");
if ($db_use_flock) { flock(DB, 1); }
LINE: while (<DB>) {
(/^#/) and ($output .= $_ and next LINE);
(/^\s*$/) and next LINE;
chomp;
@data = &split_decode($_);

if ($data[$db_key_pos] eq $in{$db_key}) {
$output .= &join_encode(%in);
$found = 1;
}
else {
$output .= "$_\n"; # else print regular line.
}
}
close DB;

if ($found) {
open (DB, ">$db_file_name") or &cgierr("error in modify_records. unable to open db file: $db_file_name.\nReason: $!");
if ($db_use_flock) {
flock(DB, 2) or &cgierr("unable to get exclusive lock on $db_file_name.\nReason: $!");
}
print DB $output;
close DB; # automatically removes file lock
&html_modify_success;
}
else {
&html_modify_failure("$in{$db_key} (can't find requested record)");
}
}
else {
&html_modify_failure($status); # Validation Error
}
}

sub modify_mult_record {
# --------------------------------------------------------
# This routine will update multiple records at once. It expects
# to find in %in a series of records to update. They will be of the
# form field_name-key.
#
my ($key, %modify_list, %modify_rec, $rec_to_modify, @data, $key,
$errstr, $succstr, $output, %errors);

# First let's pick which records to modify and then separate them and store
# them in their own hashes.
$rec_to_modify = 0;
foreach $key (keys %in) { # Build a hash of keys to modify.
if ($in{$key} eq "modify") {
$modify_list{$key} = 1;
$rec_to_modify = 1;
}
($key =~ /^(.*)-(.+)$/) and (${$modify_rec{$2}}{$1} = $in{$key});
}
# Choke if we don't have anything to do.
$rec_to_modify or (&html_modify_failure("no records specified.") and return);

open (DB, "<$db_file_name") or &cgierr("error in modify_records. unable to open db file: $db_file_name.\nReason: $!");
if ($db_use_flock) { flock(DB, 1); }
LINE: while (<DB>) {
(/^#/) and ($output .= $_ and next LINE);
(/^\s*$/) and next LINE;
chomp;
@data = &split_decode($_);
$key = $data[$db_key_pos];

# Now we check if this record is something we want to modify. If so, then
# we make sure the new record is ok, if so we replace it.
if ($modify_list{$key}) {
$status = &validate_record(%{$modify_rec{$key}});
if ($status eq "ok") {
$output .= &join_encode(%{$modify_rec{$key}});
$modify_list{$key} = 0;
}
else {
$errors{$key} = $status;
$output .= "$_\n";
}
}
else {
$output .= "$_\n";
}
}
close DB;

# Reprint out the database.
open (DB, ">$db_file_name") or &cgierr("error in modify_records. unable to open db file: $db_file_name.\nReason: $!");
if ($db_use_flock) {
flock(DB, 2) or &cgierr("unable to get exclusive lock on $db_file_name.\nReason: $!");
}
print DB $output;
close DB; # automatically removes file lock

# Let's display an error message if we were unable to modify a record
# for some reason.
foreach $key (keys %modify_list) {
if ($modify_list{$key}) {
($errors{$key}) ?
($errstr .= "$key: $errors{$key}") :
($errstr .= "$key: not found");
}
else {
$succstr .= qq~<a href="$db_script_link_url&view_records=1&$db_key=$key&ww=1">$key</a>,~;
}
}
chop($succstr); # Remove trailing delimeter

&html_modify_mult_results($succstr, $errstr);
}

sub view_records {
# --------------------------------------------------------
# This is called when a user is searching the database for
# viewing. All the work is done in query() and the routines just
# checks to see if the search was successful or not and returns
# the user to the appropriate page.

my ($status, @hits) = &query("view");
if ($status eq "ok") {
&html_view_success(@hits);
}
else {
&html_view_failure($status);
}
}

sub query {
# --------------------------------------------------------
# First let's get a list of database fields we want to search on and
# store it in @search_fields

my ($i, $column, @search_fields, @search_gt_fields, @search_lt_fields, $maxhits, $numhits, $nh,
$field, @regexp, @values, $key_match, @hits, @sortedhits, $next_url, $next_hit, $prev_hit,
$first, $last, $upper, $lower, $left, $right);
my ($mode) = shift;
local (%sortby);

# First thing we do is find out what we are searching for. We build a list of fields
# we want to search on in @search_fields.
if ($in{'keyword'}) { # If this is a keyword search, we are searching the same
$i = 0; # thing in all fields. Make sure "match any" option is
$in{'ma'} = "on"; # on, otherwise this will almost always fail.
foreach $column (@db_cols) {
if (($db_sort{$column} eq 'date') and !&date_to_unix($in{'keyword'})) { $i++; next; }
push (@search_fields, $i); # Search every column
$in{$column} = $in{'keyword'}; # Fill %in with keyword we are looking for.
$i++;
}
}
else { # Otherwise this is a regular search, and we only want records
$i = 0; # that match everything the user specified for.
foreach $column (@db_cols) {
if ($in{$column} =~ /^\>(.+)$/) { ($db_sort{$column} eq 'date') and (&date_to_unix($1) or return "Invalid date format: '$1'");
push (@search_gt_fields, $i); $in{"$column-gt"} = $1; $i++; next; }
if ($in{$column} =~ /^\<(.+)$/) { ($db_sort{$column} eq 'date') and (&date_to_unix($1) or return "Invalid date format: '$1'");
push (@search_lt_fields, $i); $in{"$column-lt"} = $1; $i++; next; }
if ($in{$column} !~ /^\s*$/) { ($db_sort{$column} eq 'date') and (&date_to_unix($in{$column}) or return "Invalid date format: '$in{$column}'");
push(@search_fields, $i); $i++; next; }
if ($in{"$column-gt"} !~ /^\s*$/) { ($db_sort{$column} eq 'date') and (&date_to_unix($in{$column}) or return "Invalid date format: '$in{$column}'");
push(@search_gt_fields, $i); }
if ($in{"$column-lt"} !~ /^\s*$/) { ($db_sort{$column} eq 'date') and (&date_to_unix($in{$column}) or return "Invalid date format: '$in{$column}'");
push(@search_lt_fields, $i); }
$i++;
}
}
# If we don't have anything to search on, let's complain.
if (!@search_fields and !@search_gt_fields and !@search_lt_fields) {
return "no search terms specified";
}

# Define the maximum number of hits we will allow, and the next hit counter.
$in{'mh'} ? ($maxhits = $in{'mh'}) : ($maxhits = $db_max_hits);
$in{'nh'} ? ($nh = $in{'nh'}) : ($nh = 1);
$numhits = 0;

# Now let's build up all the regexpressions we will use. This saves the program
# from having to recompile the same regular expression every time.
foreach $field (@search_fields) {
my $tmpreg = "$in{$db_cols[$field]}";
(!$in{'re'}) and ($tmpreg = "\Q$tmpreg\E");
($in{'ww'}) and ($tmpreg = "\\b$tmpreg\\b");
(!$in{'cs'}) and ($tmpreg = "(?i)$tmpreg");
($in{$db_cols[$field]} eq "*") and ($tmpreg = ".*"); # A "*" matches anything.

$regexp_func[$field] = eval "sub { m/$tmpreg/o }";
$regexp_bold[$field] = $tmpreg;
}

# Now we go through the database and do the actual searching.
# First figure out which records we want:
$first = ($maxhits * ($nh - 1));
$last = $first + $maxhits - 1;

open (DB, "<$db_file_name") or &cgierr("error in search. unable to open database: $db_file_name.\nReason: $!");
if ($db_use_flock) { flock(DB, 1); }
LINE: while (<DB>) {
/^#/ and next LINE; # Skip comment Lines.
/^\s*$/ and next LINE; # Skip blank lines.
chomp; # Remove trailing new line.
@values = &split_decode($_);

# Normal searches.
$key_match = 0;
foreach $field (@search_fields) {
$_ = $values[$field]; # Reg function works on $_.
$in{'ma'} ?
($key_match = ($key_match or &{$regexp_func[$field]})) :
(&{$regexp_func[$field]} or next LINE);
}
# Greater then searches.
foreach $field (@search_gt_fields) {
$term = $in{"$db_cols[$field]-gt"};
if ($db_sort{$db_cols[$field]} eq "date") {
$in{'ma'} ?
($key_match = ($key_match or (&date_to_unix($values[$field])) > &date_to_unix($term))) :
(&date_to_unix($values[$field]) > (&date_to_unix($term)) or next LINE);
}
elsif ($db_sort{$db_cols[$field]} eq 'alpha') {
$in{'ma'} ?
($key_match = ($key_match or ($values[$field] > $term))) :
((lc($values[$field]) gt lc($term)) or next LINE);
}
else {;
$in{'ma'} ?
($key_match = ($key_match or ($values[$field] > $term))) :
(($values[$field] > $term) or next LINE);
}
}
# Less then searches.
foreach $field (@search_lt_fields) {
$term = $in{"$db_cols[$field]-lt"};
if ($db_sort{$db_cols[$field]} eq "date") {
$in{'ma'} ?
($key_match = ($key_match or (&date_to_unix($values[$field]) < &date_to_unix($term)))) :
(&date_to_unix($values[$field]) < (&date_to_unix($term)) or next LINE);
}
elsif ($db_sort{$db_cols[$field]} eq 'alpha') {
$in{'ma'} ?
($key_match = ($key_match or ($values[$field] < $term))) :
((lc($values[$field]) lt lc($term)) or next LINE);
}
else {
$in{'ma'} ?
($key_match = ($key_match or ($values[$field] < $term))) :
(($values[$field] < $term) or next LINE);
}
}
# Did we find a match? We only add the hit to the @hits array if we need it. We can
# skip it if we are not sorting and it's not in our first < > last range.
if ($key_match || (!($in{'keyword'}) && !($in{'ma'}))) {
if (exists $in{'sb'}) {
$sortby{(($#hits+1) / ($#db_cols+1))} = $values[$in{'sb'}];
push (@hits, @values);
}
else {
(($numhits >= $first) and ($numhits <= $last)) and push (@hits, @values);
}
$numhits++; # But we always count it!
}
}
close DB;

# Now we've stored all our hits in @hits, and we've got a sorting values stored
# in %sortby indexed by their position in @hits.
$numhits ? ($db_total_hits = $numhits) : ($db_total_hits = 0);
($db_total_hits == 0) and return ("no matching records.");

# Sort the array @hits in order if we are meant to sort.
if (exists $in{'sb'}) { # Sort hits on $in{'sb'} field.
my ($sort_order, $sort_func);
$in{'so'} ? ($sort_order = $in{'so'}) : ($sort_order = "ascend");
$sort_func = "$db_sort{$db_cols[$in{'sb'}]}_$sort_order";

foreach $hit (sort $sort_func (keys %sortby)) {
$first = ($hit * $#db_cols) + $hit; $last = ($hit * $#db_cols) + $#db_cols + $hit;
push (@sortedhits, @hits[$first .. $last]);
}
@hits = @sortedhits;
}

# If we have to many hits, let's build the next toolbar, and return only the hits we want.
if ($numhits > $maxhits) {
# Remove the nh= from the query string.
$next_url = $ENV{'QUERY_STRING'};
$next_url =~ s/\&nh=\d+//;
$next_hit = $nh + 1; $prev_hit = $nh - 1;

# Build the next hits toolbar. It seems really complicated as we have to do
# some number crunching to keep track of where we are on the toolbar, and so
# that the toolbar stays centred.

# First, set how many pages we have on the left and the right.
$left = $nh; $right = int($numhits/$maxhits) - $nh;
# Then work out what page number we can go above and below.
($left > 7) ? ($lower = $left - 7) : ($lower = 1);
($right > 7) ? ($upper = $nh + 7) : ($upper = int($numhits/$maxhits) + 1);
# Finally, adjust those page numbers if we are near an endpoint.
(7 - $nh >= 0) and ($upper = $upper + (8 - $nh));
($nh > ($numhits/$maxhits - 7)) and ($lower = $lower - ($nh - int($numhits/$maxhits - 7) - 1));
$db_next_hits = "";

# Then let's go through the pages and build the HTML.
($nh > 1) and ($db_next_hits .= qq~<a href="$db_script_url?$next_url&nh=$prev_hit">[<<]</a> ~);
for ($i = 1; $i <= int($numhits/$maxhits) + 1; $i++) {
if ($i < $lower) { $db_next_hits .= " ... "; $i = ($lower-1); next; }
if ($i > $upper) { $db_next_hits .= " ... "; last; }
($i == $nh) ?
($db_next_hits .= qq~$i ~) :
($db_next_hits .= qq~<a href="$db_script_url?$next_url&nh=$i">$i</a> ~);
(($i * $maxhits) >= $numhits) and last; # Special case if we hit exact.
}
$db_next_hits .= qq~<a href="$db_script_url?$next_url&nh=$next_hit">[>>]</a> ~ unless ($nh == $i);

# Slice the @hits to only return the ones we want, only have to do this if the results are sorted.
if (exists $in{'sb'}) {
$first = ($maxhits * ($nh - 1)) * ($#db_cols+1);
$last = $first + (($#db_cols+1) * $maxhits) - 1;
$last = $#hits if ($last > $#hits);
@hits = @hits[$first .. $last];
}
}

# Bold the results
if ($db_bold and $in{'view_records'}) {
for $i (0 .. (($#hits+1) / ($#db_cols+1)) - 1) {
$offset = $i * ($#db_cols+1);
foreach $field (@search_fields) {
$hits[$field + $offset] =~ s,(<[^>]+>)|($regexp_bold[$field]),defined($1) ? $1 : "<B>$2</B>",ge;
}
}
}
return ("ok", @hits);
}

sub validate_records {
# --------------------------------------------------------
# This routine takes a list of records to either delete, validate
# or modify and does the appropriate action.

my ($rec_to_delete, $rec_to_validate, $rec_to_modify,
%delete_list, %validate_list, %modify_list, %links,
@lines, @data, $id, $first, $last, $errstr, $output);

# First let's go through %in and see what we have to delete, modify
# and/or validate. We also store all the links in easy to get at hashes.
# We know what fields go with what records as they should all be of the form
# ID-Field_Name. For instance: 12-URL is the URL field for record number 12.

$rec_to_delete = $rec_to_validate = $rec_to_modify = 0;
foreach $key (keys %in) { # Build a hash of keys to delete, validate and modify.
($in{$key} eq "delete") and $delete_list{$key} = 1 and $rec_to_delete = 1;
($in{$key} eq "validate") and $validate_list{$key} = 1 and $rec_to_validate = 1;
($in{$key} eq "modify") and $modify_list{$key} = 1 and $rec_to_modify = 1;
($key =~ /^(.*)-(\d+)$/) and $links{$2}{$1} = $in{$key};
}

# If there isn't anything to do, let's complain.
if (!$rec_to_validate and !$rec_to_delete and !$rec_to_modify) {
&html_generic ("Problems Validating $html_objects", "<font color=red><b>Error: No records specified.</b></font>"); return;
}

# Let's go through the validation file and remove all the ones
# we want to validate as well as all the ones we want to delete.
if ($rec_to_validate or $rec_to_delete) {
open (VAL, "<$db_valid_name") or &cgierr("error in validate_records. unable to open validate file: $db_valid_name. Reason: $!");
if ($db_use_flock) { flock (VAL, 1); }
LINE: while (<VAL>) {
(/^#/) and ($output .= $_ and next LINE);
(/^\s*$/) and next LINE;
chomp;
@data = &split_decode($_);
$id = $data[$db_key_pos];

if ($delete_list{$id}) { $delete_list{$id} = 0; }
elsif ($validate_list{$id}) { $validate_list{$id} = 2; }
else { $output .= "$_\n"; }
}
close VAL;
open (VAL, ">$db_valid_name") or &cgierr("error in validate_records. unable to open validate file: $db_valid_name. Reason: $!");
flock(VAL, 2) unless (!$db_use_flock);
print VAL $output;
close VAL; # automatically removes file lock
undef $output;
}

# Now if we have something to delete from the modify list, let's get rid of it.
if ($rec_to_modify or $rec_to_delete) {
open (MOD, "<$db_modified_name") or &cgierr("error in validate_records. unable to open modified database: $db_modified_name. Reason: $!");
if ($db_use_flock) { flock (MOD, 1); }
LINE: while (<MOD>) {
(/^#/) and ($output .= $_ and next LINE);
(/^\s*$/) and next LINE;
chomp;
@data = &split_decode($_);
$id = $data[$db_key_pos];

if ($delete_list{$id}) { $delete_list{$id} = 0; }
elsif ($modify_list{$id}) { $modify_list{$id} = 2; }
else { $output .= "$_\n"; }
}
close MOD;

open (MOD, ">$db_modified_name") or &cgierr("error in validate_records. unable to open modified database: $db_modified_name. Reason: $!");
flock(MOD, 2) unless (!$db_use_flock);
print MOD $output;
close MOD; # automatically removes file lock
undef $output;
}

# Now we update any modifications to the database.
if ($rec_to_modify) {
$found = 0; # Make sure the record is in here!
open (DB, "<$db_file_name") or &cgierr("error in validate_records. unable to open db file: $db_file_name. Reason: $!");
if ($db_use_flock) { flock (DB, 1); }
LINE: while (<DB>) {
(/^#/) and ($output .= $_ and next LINE);
(/^\s*$/) and next LINE;
chomp;
@data = &split_decode($_);
$id = $data[$db_key_pos];

if ($modify_list{$id} == 2) { # If this is the one we are looking for
$output .= &join_encode(%{$links{$id}});
$modify_list{$id} = 0; $found = 1;
}
else {
$output .= "$_\n"; # else print regular line.
}
}
close DB;
if ($found) {
open (DB, ">$db_file_name") or &cgierr("error in validate_records. unable to open db file: $db_file_name. Reason: $!");
flock(DB, 2) unless (!$db_use_flock);
print DB $output;
close DB; # automatically removes file lock
}
undef $output;
}

# Now let's see if we have something to add to the real database, then
# let's do it.
if ($rec_to_validate) {
open (DB, ">>$db_file_name") or &cgierr("error in validate_records, unable to open db file: $db_file_name. Reason: $!");
flock(DB, 2) if ($db_use_flock);

foreach $id (keys %validate_list) {
if ($validate_list{$id} == 2) {
print DB &join_encode(%{$links{$id}});
$validate_list{$id} = 0;
}
}
close DB;
}

# Now let's check to make sure everything that was asked to be val/del/mod
# actually happend. If not, let's complain.
foreach $key (keys %validate_list) {
if ($validate_list{$key}) { $errstr .= "<li>Validate Error: <strong>$key</strong>. Couldn't find record in validation database."; }
else { $valsuc .= "$key,"; }
}
foreach $key (keys %delete_list) {
if ($delete_list{$key}) { $errstr .= "<li>Delete Error: <strong>$key</strong>. Couldn't find record in validation/modified database."; }
else { $delsuc .= "$key,"; }
}
foreach $key (keys %modify_list) {
if ($modify_list{$key}) { $errstr .= "<li>Modify Error: <strong>$key</strong>. Couldn't find record in modified/links database."; }
else { $modsuc .= "$key,"; }
}
chop($errstr); chop($valsuc); chop ($delsuc); chop ($modsuc);

# Before we display the HTML, let's fire off some validate/modify/delete emails
# lettings visitors know we've added their link. We only send the mail
# if $modify_list{$id} = 0 (if it's still 1, that means there was an error).

# NOTE: You can modify the text of the email in the email templates.
&html_print_headers; # Just in case sendmail coughs up an error.

if ($db_email_modify) {
ID: foreach $id (keys %modify_list) {
if ($modify_list{$id}) { next ID; }
elsif (${$links{$id}}{'Contact Email'} =~ /(@.*@)|(\.\.)|(@\.)|(\.@)|(^\.)/ ||
${$links{$id}}{'Contact Email'} !~ /^.+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,3}|[0-9]{1,3})(\]?)$/) {
$errstr .= ($errstr, "<li>Email Error: <strong>$id</strong>. Record validated, but couldn't send auto email. Reason: Bad Email addres: '${$links{$id}}{'Contact Email'}'.");
}
else { &html_modify_email (%{$links{$id}}); }
}
}
if ($db_email_add) {
ID: foreach $id (keys %validate_list) {
if ($validate_list{$id}) { next ID; }
elsif (${$links{$id}}{'Contact Email'} =~ /(@.*@)|(\.\.)|(@\.)|(\.@)|(^\.)/ ||
${$links{$id}}{'Contact Email'} !~ /^.+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,3}|[0-9]{1,3})(\]?)$/) {
$errstr .= ($errstr, "<li>Email Error: <strong>$id</strong>. Record validated, but couldn't send auto email. Reason: Bad Email addres: '${$links{$id}}{'Contact Email'}'.");
}
else { &html_validate_email (%{$links{$id}}); }
}
}
ID: foreach $id (keys %delete_list) {
if ($delete_list{$id}) { next ID; }
elsif (!$in{"reason-$id"}) { next ID; }
elsif (${$links{$id}}{'Contact Email'} =~ /(@.*@)|(\.\.)|(@\.)|(\.@)|(^\.)/ ||
${$links{$id}}{'Contact Email'} !~ /^.+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,3}|[0-9]{1,3})(\]?)$/) {
$errstr .= ($errstr, "<li>Email Error: <strong>$id</strong>. Record deleted, but couldn't send rejection letter. Reason: Bad Email addres: '${$links{$id}}{'Contact Email'}'.");
}
else { &html_reject_email (%{$links{$id}}); }
}

# Now let's go to the error page or the success page depending on
# what $errstr is.
$errstr ?
&html_generic ("Validate Links", "Error validating links: <ul>$errstr</ul>") :
&html_validate_success($valsuc, $modsuc, $delsuc);
}

sub check_links {
# --------------------------------------------------------
# This routine makes sure that there is an entry in the category
# database for every category in the links database.
#
my %category_hash = map { $_ => 1 } &category_list;
my (@values, %missing_categories, $category_out, $category, $count);

open (DB, "<$db_links_name") or &cgierr("error in check_links. unable to open db file: $db_links_name. Reason: $!");
LINE: while (<DB>) {
(/^#/) and next LINE;
(/^\s*$/) and next LINE;
chomp;
@values = &split_decode($_);

# Check to see if this link is in a valid category.
$category_hash{$values[$db_category]} and next LINE;

# Otherwise, mark it missed, and add the link as a bad link.
$missing_categories{$values[$db_category]}++;
}
close DB;

# Create the HTML Output.
if (%missing_categories) {
$category_out = qq~<table border=1><tr><td><$font><b>Add</b></font></td>
<td><$font><b>Delete</b></font></td>
<td><$font><b>Category</b></font></td>
<td colspan=2><$font><b>Move links to this existing Category</b></font></td></tr>~;
foreach $category (keys %missing_categories) {
$category_out .= qq|
<tr><td><input type=radio name="$category" value="add"></td>
<td><input type=radio name="$category" value="delete"></td>
<td><$font>$category</font></td>
<td><input type=radio name="$category" value="move"></td><td>| . &build_select_field ("Category", "", "Move-$category") . qq|</tr>|;
last if $count++ > 10;
}
$category_out .= qq| </table>|;
}
&html_check_links ($category_out);
}

sub fix_links {
# --------------------------------------------------------
# This routine fixes up category structure problems identified in
# &check_links.
#
my (@add_cats, %del_links, %mov_links, %move_to, @values, $category, $count);

# First figure out what to do.
foreach (keys %in) {
($in{$_} eq 'add') and push @add_cats, $_;
($in{$_} eq 'delete') and $del_links{$_}++;
($in{$_} eq 'move') and $mov_links{$_}++;
(/^Move-(.+)/) and $move_to{$1} = $in{$_};
}
if (!@add_cats and !%del_links and !%mov_links) {
&html_check_links (undef, "No categories were selected!");
return;
}
# If we have to move or delete links, then update the database.
if (keys %mov_links or keys %del_links) {
open (DB, "$db_file_name") or &cgierr ("Unable to open $db_file_name. Reason: $!");
open (DBTMP, ">$db_file_name.bak") or &cgierr ("Unable to open $db_file_name.bak. Reason: $!");
LINE: while (<DB>) {
/^#/ and next LINE; # Skip comment Lines.
/^\s*$/ and next LINE; # Skip blank lines.
chomp; # Remove trailing new line.
@values = &split_decode($_);
$category = $values[$db_category];
exists $del_links{$category} and next LINE;
exists $mov_links{$category} and ($values[$db_category] = $move_to{$category});
print DBTMP &join_encode (&array_to_hash (0, @values));
}
close DB;
close DBTMP;
if (-s "$db_file_name.bak" > 0) {
if (! rename ("$db_file_name.bak", $db_file_name)) {
print "\tCouldn't rename! Had to copy. Strange: $!\n";
open (DBTMP, ">$db_file_name") or &cgierr ("unable to open links database: $db_file_name. Reason: $!");
open (DB, "$db_file_name.bak") or &cgierr ("unable to open temp links database: $db_file_name.bak. Reason: $!");
while (<DB>) { print DBTMP; }
close DB;
close DBTMP;
}
}
else {
&cgierr ("Error building! Links database is 0 bytes!");
}
}

# If we are adding categories, load the category.def and update the database.
if ($#add_cats >= 0) {
require "$db_lib_path/category.def";
$in{'db'} = 'category';

open (CATID, "<$db_category_id_file_name") or &cgierr ("Unable to open category id file: $db_category_id_file_name. Reason: $!");
$count = int <CATID>;
close CATID;

open (CAT, ">>$db_category_name") or &cgierr ("Unable to open category file: $db_category_name. Reason: $!");
foreach $category (@add_cats) {
%tmp = ( $db_key => $count++, Name => $category );
print CAT &join_encode (%tmp);
}
close CAT;

open (CATID, ">$db_category_id_file_name") or &cgierr ("Unable to open category id file: $db_category_id_file_name. Reason: $!");
print CATID $count;
close CATID;
}
&html_check_links (undef, "The database was successfully updated!");
}

sub check_duplicates {
# --------------------------------------------------------
# This routine searches through the database and pulls up sets
# of links that have the same domain.
#
my (@values, %seen, %doubles, $url, $count);

open (DB, "<$db_links_name") or &cgierr("error in check_duplicates. unable to open db file: $db_links_name. Reason: $!");
LINE: while (<DB>) {
(/^#/) and next LINE;
(/^\s*$/) and next LINE;
chomp;
@values = &split_decode($_);
$values[$db_url] =~ s,/$,,;
$seen{$values[$db_url]}++;
push (@{$doubles{$values[$db_url]}}, $values[$db_key_pos], $values[$db_title], $values[$db_category]);
}
close DB;
while (($url, $count) = each %seen) {
($count < 2) and delete $doubles{$url};
}
&html_check_duplicates (%doubles);
}

sub save_template {
# --------------------------------------------------------
# This routine will save a modified template.
#
my $tpl_name = $in{'save_tpl'};
my $tpl = $in{'tpl'};
$tpl =~ s,</text-area>,</textarea>,ig;
$tpl_name =~ /^[\w\d_\-]+\.[\w\d_\-]+$/ or &cgierr ("Invalid template name: $tpl_name. Can only contain letters, numbers, underscore and dash.");
open (TPL, ">$db_template_path/$tpl_name") or &cgierr ("Can't open template: $db_template_path/$tpl_name for writing. Reason: $!");
print TPL $tpl;
close TPL;

$in{'edit_tpl'} = $in{'save_tpl'};
&html_edit_template ("The template $tpl_name has been updated.");
}

sub get_template_list {
# --------------------------------------------------------
# Returns a list of all the templates (select list).
#
my $default = shift;

opendir (TPL, "$db_template_path") or &cgierr ("Invalid template directory: $db_template_path. Reason: $!");
my @tpls = grep $_ !~ /^\.\.?$/, readdir(TPL);
closedir (TPL);

my $output = '<select name="edit_tpl">';
foreach (sort @tpls) {
($default eq $_) ? ($output .= qq~<option value="$_" SELECTED>$_~) :
($output .= qq~<option value="$_">$_~);
}
$output .= '</select>';
return $output;
}

# These are the sorting functions used in &query.
# --------------------------------------------------------
sub alpha_ascend { lc($sortby{$a}) cmp lc ($sortby{$b}) }
sub alpha_descend { lc($sortby{$b}) cmp lc ($sortby{$a}) }
sub numer_ascend { $sortby{$a} <=> $sortby{$b} }
sub numer_descend { $sortby{$b} <=> $sortby{$a} }
sub date_ascend { &date_to_unix($sortby{$a}) <=> &date_to_unix($sortby{$b}) }
sub date_descend { &date_to_unix($sortby{$b}) <=> &date_to_unix($sortby{$a}) }

1;



DB_UTILS.PL




Code:
sub get_record {
# --------------------------------------------------------
# Given an ID as input, get_record returns a hash of the
# requested record or undefined if not found.

my ($key, $found, @data, $field);
$key = shift; $found = 0;

open (DB, "<$db_file_name") or &cgierr("error in get_records. unable to open db file: $db_file_name.\nReason: $!");
if ($db_use_flock) { flock(DB, 1); }
LINE: while (<DB>) {
(/^#/) and next LINE;
(/^\s*$/) and next LINE;
chomp;
@data = &split_decode($_);
if ($data[$db_key_pos] eq $key) {
$found = 1;
%rec = &array_to_hash (0, @data);
last LINE;
}
}
close DB;
$found ? (return %rec) : (return undef);
}

sub get_defaults {
# --------------------------------------------------------
# Returns a hash of the defaults used for a new record.

my %default;

foreach $field (keys %db_defaults) {
$db_defaults{$field} =~ /^\s*$/ and ($default{$field} = $in{$field}) and next;
(ref $db_defaults{$field} eq 'CODE') ?
($default{$field} = &{$db_defaults{$field}}) : ($default{$field} = $db_defaults{$field});
}
if ($db_key_track) {
open (ID, "<$db_id_file_name") or &cgierr("error in get_defaults. unable to open id file: $db_id_file_name.\nReason: $!");
if ($db_use_flock) { flock(ID, 1); }
$default{$db_key} = <ID> + 1; # Get next ID number
close ID;
}
return %default;
}

sub validate_record {
# --------------------------------------------------------
# Verifies that the information passed through the form and stored
# in %in matches a valid record. It checks first to see that if
# we are adding, that a duplicate ID key does not exist. It then
# checks to see that fields specified as not null are indeed not null,
# finally it checks against the reg expression given in the database
# definition.
#
my ($col, @input_err, $errstr, $err, $line, @lines, @data);
my (%rec) = @_;

if ($rec{'add_record'}) { # don't need to worry about duplicate key if modifying
open (DB, "<$db_file_name") or &cgierr("error in validate_records. unable to open db file: $db_file_name.\nReason: $!");
if ($db_use_flock) { flock(DB, 1); }
LINE: while (<DB>) {
(/^#/) and next LINE;
(/^\s*$/) and next LINE;
chomp;
@data = &split_decode($_);
($data[$db_key_pos] eq $rec{$db_key}) and return "duplicate key error";
}
close DB;
}
foreach $col (@db_cols) {
if ($rec{$col} =~ /^\s*$/) { # entry is null or only whitespace
($db_not_null{$col}) and # entry is not allowed to be null.
push(@input_err, "$col (Non può essere lasciato bianco)"); # so let's add it as an error
}
else { # else entry is not null.
($db_valid_types{$col} && !($rec{$col} =~ /$db_valid_types{$col}/)) and
push(@input_err, "$col (Formato non valido)"); # but has failed validation.
(length($rec{$col}) > $db_lengths{$col}) and
push (@input_err, "$col (Troppo lungo. Lunghezza Max: $db_lengths{$col})");
if ($db_sort{$col} eq "date") {
push (@input_err, "$col (Invalid date format)") unless &date_to_unix($rec{$col});
}
}
}
if ($#input_err+1 > 0) { # since there are errors, let's build
foreach $err (@input_err) { # a string listing the errors
$errstr .= "<li>$err"; # and return it.
}
return "<ul>$errstr</ul>";
}
else {
return "ok"; # no errors, return ok.
}
}

sub build_email_list {
# --------------------------------------------------------
# Build a list of all subscribers to mail to.
#
my ($name, $email, $output);
$output = qq~<select name="mailto" multiple size=5>~;

open (DB, "<$db_email_name ") or &cgierr("unable to open db file: $db_email_name .\nReason: $!");
if ($db_use_flock) { flock(DB, 1); }
LINE: while (<DB>) {
(/^#/) and next LINE;
(/^\s*$/) and next LINE;
chomp;
($email, $name) = split /\Q$db_delim\E/;
$output .= "<option selected>$email</option>\n";
}
$output .= "</select>";
close DB;
return $output;
}

sub build_new_links {
# --------------------------------------------------------
# Returns a text string used in the email newsletter of all
# new links.
#
my $output = '';
my (@data, %rec);

open (DB, "<$db_file_name") or &cgierr("unable to open db file: $db_file_name.\nReason: $!");
if ($db_use_flock) { flock(DB, 1); }
LINE: while (<DB>) {
(/^#/) and next LINE;
(/^\s*$/) and next LINE;
chomp;
@data = &split_decode($_);
if ($data[$db_isnew] eq 'Yes') {
%rec = &array_to_hash(0, @data);
my $des_q = &linewrap ($rec{'Description'});
$output .= qq~
-------------------------------------------------------------------
$rec{'Title'} (inserito il: $rec{'Date'})
$rec{'URL'}
$des_q
~;
}
}
close DB;
return $output;
}

sub build_select_field {
# --------------------------------------------------------
# Builds a SELECT field based on information found
# in the database definition.
#
my ($column, $value, $name, $mult) = @_;
my ($size, %values);

$name || ($name = $column);
$size || ($size = 1);

if (! exists $db_select_fields{$column}) {
$db_select_fields{$db_cols[$db_category]} = $db_select_fields{'Mult-Related'} = join (",", &category_list);
}
if ($mult) {
@fields = split (/\,/, $db_select_fields{"Mult-$column"});
%values = map { $_ => 1 } split (/\Q$db_delim\E/, $value);
}
else {
@fields = split (/\,/, $db_select_fields{$column});
$values{$value}++;
}
($#fields >= 0) or return "error building select field: no select fields specified in config for field '$column'!";

$output = qq|<SELECT NAME="$name" $mult SIZE=$size><OPTION>---|;
foreach $field (@fields) {
$values{$field} ?
($output .= "<OPTION SELECTED>$field\n") :
($output .= "<OPTION>$field");
}
$output .= "</SELECT>";
return $output;
}

sub build_select_field_from_db {
# --------------------------------------------------------
# Builds a SELECT field from the database.
#
my ($column, $value, $name) = @_;
my (@fields, $field, %selectfields, $ouptut, $fieldnum, $found);

# Make sure this is a valid field.
(grep $_ eq $column, @db_cols) or return "error building select field: no fields specified!";

$fieldnum = $db_def{$column}[0];
$name ||= $column;

# Go through the database and get each unique name in that column.
open (DB, "<$db_file_name") or &cgierr("unable to open $db_file_name. Reason: $!");
if ($db_use_flock) { flock(DB, 1); }
LINE: while (<DB>) {
/^\s*$/ and next LINE; # Skip blank lines
/^#/ and next LINE; # Comment Line
@fields = &split_decode ($_);
$selectfields{$fields[$fieldnum]}++;
}
close DB;

# Make a select list out of those names.
$output = qq|<SELECT NAME="$name"><OPTION>---|;
foreach $field (sort keys %selectfields) {
($field eq $value) ?
($output .= "<OPTION SELECTED>$field\n") :
($output .= "<OPTION>$field\n");
}
$output .= "</SELECT>\n";
return $output;
}

sub build_checkbox_field {
# --------------------------------------------------------
# Builds a CHECKBOX field based on information found
# in the database definition. Parameters are the column to build
# whether it should be checked or not and a default value (optional).

my ($column, $values, $name) = @_;

$db_checkbox_fields{$column} or return "error building checkboxes: no checkboxes specified in config for field '$column'";
$name ||= $column;

my @values = split (/\Q$db_delim\E/, $values);
my @boxes = split (/,/, $db_checkbox_fields{$column});
my ($output, $box);

foreach $box (@boxes) {
(grep $_ eq $box, @values) ?
($output .= qq!<INPUT TYPE="CHECKBOX" NAME="$name" VALUE="$box" CHECKED> $box\n!) :
($output .= qq!<INPUT TYPE="CHECKBOX" NAME="$name" VALUE="$box"> $box\n!);
}
return $output;
}

sub build_radio_field {
# --------------------------------------------------------
# Builds a RADIO Button field based on information found
# in the database definition. Parameters are the column to build
# and a default value (optional).
#
my ($column, $value, $name) = @_;
my (@buttons, $button, $output);

$db_radio_fields{$column} or return "error building radio buttons: no radio fields specified in config for field '$column'!";
$name ||= $column;

@buttons = split (/,/, $db_radio_fields{$column});

foreach $button (@buttons) {
($value eq $button) ?
($output .= qq|<INPUT TYPE="RADIO" NAME="$name" VALUE="$button" CHECKED> $button \n|) :
($output .= qq|<INPUT TYPE="RADIO" NAME="$name" VALUE="$button"> $button \n|);
}
return $output;
}

sub build_html_record {
# --------------------------------------------------------
# Builds a record based on the config information.
#
my (%rec) = @_;
my ($output, $field);

$output = "<p><table border=1 width=450>\n";
foreach $field (@db_cols) {
next if ($db_form_len{$field} == -1);
$output .= qq~
<tr><td align=right valign=top width=20%><$font>$field:</font></td>
<td width=80%><$font>$rec{$field}</font></td></tr>
~;
}
$output .= "</table></p>\n";
return $output;
}

sub build_html_record_form {
# --------------------------------------------------------
# Builds a record form based on the config information.
#
my ($output, $field, $multiple, $name);
($_[0] eq "multiple") and ($multiple = 1) and shift;
my (%rec) = @_;

$output = "<p><table border=1>";

# Go through a little hoops to only load category list when absolutely neccessary.
if ($in{'db'} eq 'links') {
exists $db_select_fields{$db_cols[$db_category]}
or ($db_select_fields{$db_cols[$db_category]} = join (",", &category_list));
}
else {
$db_select_fields{'Related'} or
($db_select_fields{'Related'} = $db_select_fields{'Mult-Related'} = join ",", &category_list);
}

foreach $field (@db_cols) {
# Set the field name to field-key if we are doing multiple forms.
$multiple ? ($name = "$field-$rec{$db_key}") : ($name = $field);
if ($db_select_fields{"Mult-$field"}) { $output .= "<tr><td align=right valign=top width=20%><$font>$field:</font></td><td width=80%>" . &build_select_field($field, $rec{$field}, $name, "MULTIPLE SIZE=3") . "</td></tr>\n"; }
elsif ($db_select_fields{$field}) { $output .= "<tr><td align=right valign=top width=20%><$font>$field:</font></td><td width=80%>" . &build_select_field($field, $rec{$field}, $name) . "</td></tr>\n"; }
elsif ($db_radio_fields{$field}) { $output .= "<tr><td align=right valign=top width=20%><$font>$field:</font></td><td width=80%>" . &build_radio_field($field, $rec{$field}, $name) . "</td></tr>\n"; }
elsif ($db_checkbox_fields{$field}) { $output .= "<tr><td align=right valign=top width=20%><$font>$field:</font></td><td width=80%>" . &build_checkbox_field ($field, $rec{$field}, $name) . "</td></tr>\n"; }
elsif ($db_form_len{$field} =~
/(\d+)x(\d+)/) { $output .= qq~<tr><td align=right valign=top width=20%><$font>$field:</font></td><td width=80%><textarea wrap="virtual" name="$name" cols="$1" rows="$2">$rec{$field}</textarea></td></tr>\n~; }
elsif ($db_form_len{$field} == -1) { $output = qq~<input type=hidden name="$field" value="$rec{$field}">\n$output~; }
else { $output .= qq~<tr><td align=right valign=top width=20%><$font>$field:</font></td><td width=80%><input type=text name="$name" value="$rec{$field}" size="$db_form_len{$field}" maxlength="$db_lengths{$field}"></td></tr>\n~; }
}
$output .= "</table></p>\n";
return $output;
}

sub category_list {
# --------------------------------------------------------
# Returns a list of all categories in the database.
#
my (%categories, @fields);

# If we've already loaded this, return it.
defined @db_category_list and return @db_category_list;

# Otherwise pull the list from the database.
open (DB, "<$db_category_name") or &cgierr("unable to open $db_file_name. Reason: $!");
if ($db_use_flock) { flock(DB, 1); }
LINE: while (<DB>) {
(/^#/) and next LINE;
(/^\s*$/) and next LINE;
@fields = &split_decode ($_);
$categories{$fields[$db_main_category]}++;
}
close DB;

# Cache the output in case we use this again.
@db_category_list = sort keys %categories;

return @db_category_list;
}

sub build_clean {
# --------------------------------------------------------
# Formats a category name for displaying.
#
my ($input) = shift;
$input =~ s/_/ /g; # Change '_' to spaces.
$input =~ s,/, : ,g; # Change '/' to ' : '.
return $input;
}

sub build_sorthit {
# --------------------------------------------------------
# This function sorts a list of links. It has been modified to sort
# new links first, then cool links, then the rest alphabetically. By modifying
# the sort function below, you can sort the links however you like (by date,
# or random, etc.).
#
my (@unsorted) = @_;
my ($num) = ($#unsorted+1) / ($#db_cols+1);
my (%sortby, %isnew, %iscool, $hit, $i, @sorted);

for ($i = 0; $i < $num; $i++) {
$sortby{$i} = $unsorted[$db_sort_links + ($i * ($#db_cols+1))];
($unsorted[$db_isnew + ($i * ($#db_cols+1))] eq "Yes") and ($isnew{$i} = 1);
($unsorted[$db_ispop + ($i * ($#db_cols+1))] eq "Yes") and ($iscool{$i} = 1);
}
foreach $hit (sort {
($isnew{$b} and !$isnew{$a}) and return 1;
($isnew{$a} and !$isnew{$b}) and return -1;
($iscool{$b} and !$iscool{$a}) and return 1;
($iscool{$a} and !$iscool{$b}) and return -1;
($isnew{$a} and $isnew{$b}) and return lc($sortby{$a}) cmp lc($sortby{$b});
($iscool{$a} and $iscool{$b}) and return lc($sortby{$a}) cmp lc($sortby{$b});
return lc($sortby{$a}) cmp lc($sortby{$b});
} (keys %sortby)) {
$first = ($hit * $#db_cols) + $hit;
$last = ($hit * $#db_cols) + $#db_cols + $hit;
push (@sorted, @unsorted[$first .. $last]);
}
return @sorted;
}

sub urlencode {
# --------------------------------------------------------
# Escapes a string to make it suitable for printing as a URL.
#
my($toencode) = shift;
$toencode =~ s/([^a-zA-Z0-9_\-.])/uc sprintf("%%%02x",ord($1))/eg;
$toencode =~ s/\%2F/\//g;
return $toencode;
}

sub get_date {
# --------------------------------------------------------
# Returns the current date.
#
my ($time) = shift;
$time ||= time();

exists $DATE_CACHE{$time} or ($DATE_CACHE{$time} = &unix_to_date($time));
return $DATE_CACHE{$time};
}

sub get_time {
# --------------------------------------------------------
# Returns the time in the format "hh-mm-ss".
#
my $time = shift;
$time ||= time();
my ($sec, $min, $hour, @junk) = localtime ($time);
($sec < 10) and ($sec = "0$sec");
($min < 10) and ($min = "0$min");
($hour < 10) and ($hour = "0$hour");

return "$hour:$min:$sec";
}

sub days_old {
# --------------------------------------------------------
# Returns the number of days from a given day to today (number of days
# old.
#
exists $DATE_CACHE{$_[0]} or ($DATE_CACHE{$_[0]} = &date_to_unix($_[0]));
return int ((time() - $DATE_CACHE{$_[0]}) / 86400);
}

sub compare_dates {
# --------------------------------------------------------
# Returns 1 if date a is greater then date b, otherwise returns 0.
#
exists $DATE_CACHE{$_[0]} or ($DATE_CACHE{$_[0]} = &date_to_unix($_[0]));
exists $DATE_CACHE{$_[1]} or ($DATE_CACHE{$_[1]} = &date_to_unix($_[1]));
return $DATE_CACHE{$_[0]} > $DATE_CACHE{$_[1]};
}

sub array_to_hash {
# --------------------------------------------------------
# Converts an array to a hash using db_cols as the field names.
#
my ($hit, @array) = @_;
my ($i);
return map { $db_cols[$i] => $array[$hit * ($#db_cols+1) + $i++] } @_;
}

sub linewrap {
# --------------------------------------------------------
# Wraps a line into 60 char chunks. Modified from code by
# Tim Gim Yee <tgy@chocobo.org>.
#
my $line = shift; defined $line or return '';
my @data = split /\t/, $line;
my $columns = 60;
my $tabstop = 1;
my $frag = '';
my $col = $columns - 1;

for (@data) {
$_ = "$frag$_";
$frag = '';
s/(.{1,$columns}$)|(.{1,$col}(?:\S\s+|-(?=\w)))|(.{$col})/
$3 ? "$3-\n" :
$2 ? "$2\n" :
(($frag = $1), '')
/ge;
$frag .= (' ' x ($tabstop - length($frag) % $tabstop));
}

local $_ = join '', @data, $frag;
s/\s+$//gm;
return $_;
}

sub load_template {
# --------------------------------------------------------
# Loads and parses a template. Expects to find as input a
# template file name, and a hash ref and optionally template text.
# If text is defined, then no file is loaded, but rather the template
# is taken from $text.
#
my ($tpl, $vars, $string) = @_;
(ref $vars eq 'HASH') or &cgierr ("Not a hash ref: $vars in load_template!");

if (!defined $db_template) {
require "$db_lib_path/Template.pm";
$db_template = new Template ( { ROOT => $db_template_path, CHECK => 0 } );
}
$db_template->clear_vars;
$db_template->load_template ($tpl, $string) or &cgierr ("Can't load template. Reason: $Template::error");
$db_template->load_vars ($vars) or &cgierr ("Can't load variables. Reason: $Template::error");
return $db_template->parse ($tpl) or &cgierr ("Can't parse template. Reason: $Template::error");
}

sub join_encode {
# --------------------------------------------------------
# Takes a hash (ususally from the form input) and builds one
# line to output into the database. It changes all occurrences
# of the database delimeter to '~~' and all newline chars to '``'.

my %hash = @_;
my ($tmp, $col, $output);

foreach $col (@db_cols) {
$tmp = $hash{$col};
$tmp =~ s/^\s+//g; # Trim leading blanks...
$tmp =~ s/\s+$//g; # Trim trailing blanks...
$tmp =~ s/\Q$db_delim\E/~~/og; # Change delimeter to ~~ symbol.
$tmp =~ s/\n/``/g; # Change newline to `` symbol.
$tmp =~ s/\r//g; # Remove Windows linefeed character.
$output .= $tmp . $db_delim; # Build Output.
}
chop $output; # remove extra delimeter.
$output .= "\n"; # add linefeed char.
return $output;
}

sub split_decode {
# --------------------------------------------------------
# Takes one line of the database as input and returns an
# array of all the values. It replaces special mark up that
# join_encode makes such as replacing the '``' symbol with a
# newline and the '~~' symbol with a database delimeter.

my ($input) = shift;
my (@array) = split (/\Q$db_delim\E/o, $input, $#db_cols+1);
foreach (@array) {
s/~~/$db_delim/g; # Retrieve Delimiter..
s/``/\n/g; # Change '' back to newlines..
}
return @array;
}

sub html_print_headers {
# --------------------------------------------------------
# Print out the headers if they haven't already been printed.
#
if (!$html_headers_printed) {
print "HTTP/1.0 200 OK\n" if ($db_iis or $nph);
print "Pragma: no-cache\n" if ($db_nocache);
print "Content-type: text/html\n\n";
$html_headers_printed = 1;
}
}

sub parse_form {
# --------------------------------------------------------
# Parses the form input and returns a hash with all the name
# value pairs. Removes any field with "---" as a value
# (as this denotes an empty SELECT field.
#
my (@pairs, %in);
my ($buffer, $pair, $name, $value);

if ($ENV{'REQUEST_METHOD'} eq 'GET') {
@pairs = split(/&/, $ENV{'QUERY_STRING'});
}
elsif ($ENV{'REQUEST_METHOD'} eq 'POST') {
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
@pairs = split(/&/, $buffer);
}
else {
&cgierr('You cant run this script from telnet/shell.');
}

PAIR: foreach $pair (@pairs) {
($name, $value) = split(/=/, $pair);

$name =~ tr/+/ /;
$name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

($value eq "---") and next PAIR;
exists $in{$name} ? ($in{$name} .= "~~$value") : ($in{$name} = $value);
}
return %in;
}

sub cgierr {
# --------------------------------------------------------
# Displays any errors and prints out FORM and ENVIRONMENT
# information. Useful for debugging.
#
if (!$html_headers_printed) {
print "Content-type: text/html\n\n";
$html_headers_printed = 1;
}
print "<PRE>\n\nCGI ERROR\n==========================================\n";
$_[0] and print "Error Message : $_[0]\n";
$0 and print "Script Location : $0\n";
$] and print "Perl Version : $]\n";

print "\nForm Variables\n-------------------------------------------\n";
foreach $key (sort keys %in) {
my $space = " " x (20 - length($key));
print "$key$space: $in{$key}\n";
}
print "\nEnvironment Variables\n-------------------------------------------\n";
foreach $env (sort keys %ENV) {
my $space = " " x (20 - length($env));
print "$env$space: $ENV{$env}\n";
}
print "\n</PRE>";
exit -1;
}

1;


That's it!

I also have problems with the modify page too but I won't take much of your time.

Thanks

Andrea
Quote Reply
Re: [Andreaf] If I don't accept modifications I want the link to remain... In reply to
Mmmm...I'm a little stumped there. I'm going out to do some last minute christmas shooping now, but I'll have another look for you later on today. If I find anything, I'll let you know Smile

Cheers

Andy (mod)
andy@ultranerds.co.uk
Want to give me something back for my help? Please see my Amazon Wish List
GLinks ULTRA Package | GLinks ULTRA Package PRO
Links SQL Plugins | Website Design and SEO | UltraNerds | ULTRAGLobals Plugin | Pre-Made Template Sets | FREE GLinks Plugins!
Quote Reply
Re: [Andreaf] If I don't accept modifications I want the link to remain... In reply to
Please attach the files to your post rather than pasting them - it makes them much easier to view.
Quote Reply
Re: [Paul] If I don't accept modifications I want the link to remain... In reply to
correct me if I'm wrong, but Links only deletes the record pending approval from the validation database, not links.db.

Philip
------------------
Limecat is not pleased.

Last edited by:

fuzzy thoughts: Dec 24, 2002, 10:59 AM
Quote Reply
Re: [fuzzy thoughts] If I don't accept modifications I want the link to remain... In reply to
Andrew,
when I receive a request of modification and I log in to accept it or not, if I don't accept I select the Delete. Email Reason:...

It's what I'm looking for... a way to keep the record even if I don't accept the modification.

I guess it's the same for every Links owner, or am I wrong?

Andrea