BBS-Universal
view release on metacpan or search on metacpan
lib/BBS/Universal.pm view on Meta::CPAN
'TOGGLE SHOW EMAIL' => sub {
my $self = shift;
$self->users_toggle_permission('show_email');
return ($self->load_menu('files/main/account'));
},
'TOGGLE PREFER NICKNAME' => sub {
my $self = shift;
$self->users_toggle_permission('prefer_nickname');
return ($self->load_menu('files/main/account'));
},
'TOGGLE PLAY FORTUNES' => sub {
my $self = shift;
$self->users_toggle_permission('play_fortunes');
return ($self->load_menu('files/main/account'));
},
'BBS LIST ADD' => sub {
my $self = shift;
$self->bbs_list_add();
return ($self->load_menu('files/main/bbs_listing'));
},
'BBS LISTING' => sub {
my $self = shift;
return ($self->load_menu('files/main/bbs_listing'));
},
'LIST USERS' => sub {
my $self = shift;
return ($self->load_menu('files/main/list_users'));
},
'ACCOUNT MANAGER' => sub {
my $self = shift;
return ($self->load_menu('files/main/account'));
},
'BACK' => sub {
my $self = shift;
return ($self->load_menu('files/main/menu'));
},
'DISCONNECT' => sub {
my $self = shift;
$self->output("\nDisconnect, are you sure (y|N)? ");
unless ($self->decision()) {
return ($self->load_menu('files/main/menu'));
}
$self->output("\n");
},
'FILE CATEGORY' => sub {
my $self = shift;
$self->choose_file_category();
return ($self->load_menu('files/main/files_menu'));
},
'FILES' => sub {
my $self = shift;
return ($self->load_menu('files/main/files_menu'));
},
'LIST FILES SUMMARY' => sub {
my $self = shift;
$self->files_list_summary(FALSE);
return ($self->load_menu('files/main/files_menu'));
},
'UPLOAD FILE' => sub {
my $self = shift;
$self->files_upload_choices();
return ($self->load_menu('files/main/files_menu'));
},
'LIST FILES DETAILED' => sub {
my $self = shift;
$self->files_list_detailed(FALSE);
return ($self->load_menu('files/main/files_menu'));
},
'SEARCH FILES SUMMARY' => sub {
my $self = shift;
$self->files_list_summary(TRUE);
return ($self->load_menu('files/main/files_menu'));
},
'SEARCH FILES DETAILED' => sub {
my $self = shift;
$self->files_list_detailed(TRUE);
return ($self->load_menu('files/main/files_menu'));
},
'NEWS' => sub {
my $self = shift;
return ($self->load_menu('files/main/news'));
},
'NEWS SUMMARY' => sub {
my $self = shift;
$self->news_summary();
return ($self->load_menu('files/main/news'));
},
'NEWS DISPLAY' => sub {
my $self = shift;
$self->news_display();
return ($self->load_menu('files/main/news'));
},
'FORUMS' => sub {
my $self = shift;
return ($self->load_menu('files/main/forums'));
},
'ABOUT' => sub {
my $self = shift;
return ($self->load_menu('files/main/about'));
},
};
$self->{'debug'}->DEBUG(['End Commands initialize']);
}
# package BBS::Universal::DB;
sub db_initialize {
my $self = shift;
$self->{'debug'}->DEBUG(['Start DB Initialize']);
$self->{'debug'}->DEBUG(['End DB Initialize']);
return ($self);
} ## end sub db_initialize
sub db_connect {
my $self = shift;
$self->{'debug'}->DEBUG(['Start DB Connect']);
my @dbhosts = split(/\s*,\s*/, $self->{'CONF'}->{'STATIC'}->{'DATABASE HOSTNAME'});
my $errors = '';
lib/BBS/Universal.pm view on Meta::CPAN
sub db_disconnect {
my $self = shift;
$self->{'debug'}->DEBUG(['Start DB Disconnect']);
$self->{'dbh'}->disconnect() if (defined($self->{'dbh'}));
$self->{'debug'}->DEBUG(['End DB Disconnect']);
return (TRUE);
} ## end sub db_disconnect
# package BBS::Universal::FileTransfer;
sub filetransfer_initialize {
my ($self) = @_;
$self->{'debug'}->DEBUG(['Start FileTransfer Initialize']);
$self->{'debug'}->DEBUG(['End FileTransfer Initialize']);
return ($self);
} ## end sub filetransfer_initialize
sub files_type {
my ($self, $file) = @_;
$self->{'debug'}->DEBUG(['Start File Type']);
my @tmp = split(/\./, $file);
my $ext = uc(pop(@tmp));
my $sth = $self->{'dbh'}->prepare('SELECT type FROM file_types WHERE extension=?');
$sth->execute($ext);
my $name;
if ($sth->rows > 0) {
$name = $sth->fetchrow_array();
}
$sth->finish();
$self->{'debug'}->DEBUG(['End File Type']);
return ($ext, $name);
} ## end sub files_type
sub files_load_file {
my ($self, $file) = @_;
$self->{'debug'}->DEBUG(['Start Files Load File']);
my $filename = sprintf('%s.%s', $file, $self->{'USER'}->{'text_mode'});
$self->{'CACHE'}->set(sprintf('SERVER %02d %s', $self->{'thread_number'}, 'CURRENT MENU FILE'), $filename);
open(my $FILE, '<', $filename);
my @text = <$FILE>;
close($FILE);
chomp(@text);
$self->{'debug'}->DEBUG(['End Files Load File']);
return (join("\n", @text));
} ## end sub files_load_file
sub files_list_summary {
my ($self, $search) = @_;
$self->{'debug'}->DEBUG(['Start Files List Summary']);
my $sth;
my $filter;
if ($search) {
$self->prompt('Search for (blank for all)');
$filter = $self->get_line({ 'type' => STRING, 'max' => 255, 'default' => '' });
$sth = $self->{'dbh'}->prepare('SELECT * FROM files_view WHERE (filename LIKE ? OR title LIKE ?) AND category_id=? ORDER BY uploaded DESC');
$sth->execute('%' . $filter . '%', '%' . $filter . '%', $self->{'USER'}->{'file_category'});
} else {
$sth = $self->{'dbh'}->prepare('SELECT * FROM files_view WHERE category_id=? ORDER BY uploaded DESC');
$sth->execute($self->{'USER'}->{'file_category'});
}
my @files;
my $max_filename = 10;
my $max_title = 20;
if ($sth->rows > 0) {
while (my $row = $sth->fetchrow_hashref()) {
push(@files, $row);
$max_filename = max(length($row->{'filename'}), $max_filename);
$max_title = max(length($row->{'title'}), $max_title);
}
my $table = Text::SimpleTable->new($max_filename, $max_title);
$table->row('FILENAME', 'TITLE');
$table->hr();
foreach my $record (@files) {
$table->row($record->{'filename'}, $record->{'title'});
}
my $mode = $self->{'USER'}->{'text_mode'};
if ($mode eq 'ANSI') {
my $text = $table->boxes2('MAGENTA')->draw();
while ($text =~ / (FILENAME|TITLE) /s) {
my $ch = $1;
my $new = '[% BRIGHT YELLOW %]' . $ch . '[% RESET %]';
$text =~ s/ $ch / $new /gs;
}
$self->output("\n$text");
} elsif ($mode eq 'ATASCII') {
$self->output("\n" . $self->color_border($table->boxes->draw(), 'MAGENTA'));
} elsif ($mode eq 'PETSCII') {
my $text = $table->boxes->draw();
while ($text =~ / (FILENAME|TITLE) /s) {
my $ch = $1;
my $new = '[% YELLOW %]' . $ch . '[% RESET %]';
$text =~ s/ $ch / $new /gs;
}
$self->output("\n" . $self->color_border($text, 'PURPLE'));
} else {
$self->output("\n" . $table->draw());
}
} elsif ($search) {
$self->output("\nSorry '$filter' not found");
} else {
$self->output("\nSorry, this file category is empty\n");
}
$self->output("\nPress a key to continue ...");
$self->get_key(ECHO, BLOCKING);
$self->{'debug'}->DEBUG(['End Files List Summary']);
return (TRUE);
} ## end sub files_list_summary
sub files_choices {
my ($self, $record) = @_;
while ($self->is_connected()) {
my $view = FALSE;
my $mapping = {
'TEXT' => '',
'Z' => { 'command' => 'BACK', 'color' => 'WHITE', 'access_level' => 'USER', 'text' => 'Return to File Menu' },
'N' => { 'command' => 'NEXT', 'color' => 'BLUE', 'access_level' => 'USER', 'text' => 'Next file' },
'D' => { 'command' => 'DOWNLOAD', 'color' => 'CYAN', 'access_level' => 'VETERAN', 'text' => 'Download file' },
'R' => { 'command' => 'REMOVE FILE', 'color' => 'RED', 'access_level' => 'JUNIOR SYSOP', 'text' => 'Remove file' },
};
if ($record->{'extension'} =~ /^(TXT|ASC|ATA|PET|VT|ANS|MD|INF|CDF|PL|PM|PY|C|CPP|H|SH|CSS|HTM|HTML|SHTML|JS|JAVA|XML|BAT)$/ && $self->check_access_level('VETERAN')) {
$view = TRUE;
$mapping->{'V'} = { 'command' => 'VIEW FILE', 'color' => 'CYAN', 'access_level' => 'VETERAN', 'text' => 'View file' };
} ## end if ($record->{'extension'...})
$self->show_choices($mapping);
$self->prompt('Choose');
my $key;
do {
$key = uc($self->get_key());
} until ($key =~ /D|N|Z/ || ($key eq 'V' && $view) || ($key eq 'R' && $self->check_access_level('JUNION SYSOP')));
$self->output($mapping->{$key}->{'command'} . "\n");
if ($mapping->{$key}->{'command'} eq 'DOWNLOAD') {
my $file = $self->{'CONF'}->{'BBS ROOT'} . '/' . $self->{'CONF'}->{'FILES PATH'} . '/' . $self->{'USER'}->{'file_category_path'} . '/' . $record->{'filename'};
$mapping = {
'B' => { 'command' => 'BACK', 'color' => 'WHITE', 'access_level' => 'USER', 'text' => 'Return to File Menu' },
'Y' => { 'command' => 'YMODEM', 'color' => 'YELLOW', 'access_level' => 'VETERAN', 'text' => 'Download with the Ymodem protocol' },
'X' => { 'command' => 'XMODEM', 'color' => 'BRIGHT BLUE', 'access_level' => 'VETERAN', 'text' => 'Download with the Xmodem protocol' },
'Z' => { 'command' => 'ZMODEM', 'color' => 'GREEN', 'access_level' => 'VETERAN', 'text' => 'Download with the Zmodem protocol' },
};
$self->show_choices($mapping);
$self->prompt('Choose');
do {
$key = uc($self->get_key());
} until ($key =~ /B|X|Y|Z/);
$self->output($mapping->{$key}->{'command'});
if ($mapping->{$key}->{'command'} eq 'XMODEM') {
system('sz', '--xmodem', '--quiet', '--binary', $file);
} elsif ($mapping->{$key}->{'command'} eq 'YMODEM') {
system('sz', '--ymodem', '--quiet', '--binary', $file);
} elsif ($mapping->{$key}->{'command'} eq 'ZMODEM') {
system('sz', '--zmodem', '--quiet', '--binary', '--resume', $file);
} else {
return (FALSE);
}
return (TRUE);
} elsif ($mapping->{$key}->{'command'} eq 'VIEW FILE' && $self->check_access_level($mapping->{$key}->{'access_level'})) {
my $file = $self->{'CONF'}->{'BBS ROOT'} . '/' . $self->{'CONF'}->{'FILES PATH'} . '/' . $self->{'USER'}->{'file_category_path'} . '/' . $record->{'filename'};
open(my $VIEW, '<', $file);
binmode($VIEW, ":encoding(UTF-8)");
my $data;
read($VIEW, $data, $record->{'file_size'}, 0);
close($VIEW);
$self->output('[% CLS %]' . $data . '[% RESET %]');
} elsif ($mapping->{$key}->{'command'} eq 'REMOVE FILE' && $self->check_access_level($mapping->{$key}->{'access_level'})) {
return (TRUE);
} elsif ($mapping->{$key}->{'command'} eq 'NEXT') {
return (TRUE);
} elsif ($mapping->{$key}->{'command'} eq 'BACK') {
return (FALSE);
}
} ## end while ($self->is_connected...)
} ## end sub files_choices
sub files_upload_choices {
my ($self) = @_;
my $ckey;
$self->prompt('File Name? ');
my $file = $self->get_line({ 'type' => FILENAME, 'max' => 255, 'default' => '' });
my $ext = uc($file =~ /\.(.*?)$/);
$self->prompt('Title (Fiendly name)? ');
my $title = $self->get_line({ 'type' => STRING, 'max' => 255, 'default' => '' });
$self->prompt('Description? ');
my $description = $self->get_line({ 'type' => STRING, 'max' => 255, 'default' => '' });
my $file_category = $self->{'USER'}->{'file_category'};
my $mapping = {
'B' => { 'command' => 'BACK', 'color' => 'WHITE', 'access_level' => 'USER', 'text' => 'Return to File Menu' },
'Y' => { 'command' => 'YMODEM', 'color' => 'YELLOW', 'access_level' => 'VETERAN', 'text' => 'Upload with the Ymodem protocol' },
'X' => { 'command' => 'XMODEM', 'color' => 'BRIGHT BLUE', 'access_level' => 'VETERAN', 'text' => 'Upload with the Xmodem protocol' },
'Z' => { 'command' => 'ZMODEM', 'color' => 'GREEN', 'access_level' => 'VETERAN', 'text' => 'Upload with the Zmodem protocol' },
};
$self->show_choices($mapping);
$self->prompt('Choose');
do {
$ckey = uc($self->get_key());
} until ($ckey =~ /B|X|Y|Z/);
$self->output($mapping->{$ckey}->{'command'});
if ($mapping->{$ckey}->{'command'} eq 'XMODEM') {
if ($self->files_receive_file($file, XMODEM)) {
my $filename = $self->{'CONF'}->{'BBS ROOT'} . '/' . $self->{'CONF'}->{'FILES PATH'} . '/' . $self->{'USER'}->{'file_category_path'} . '/' . $file;
my $size = (-s $filename);
my $sth = $self->{'dbh'}->prepare('INSERT INTO files (category,filename,title,file_type,description,file_size) VALUES (?,?,?,(SELECT id FROM file_types WHERE extension=?),?,?');
$sth->execute($file_category, $file, $title, $ext, $description, $size);
$sth->finish();
} ## end if ($self->files_receive_file...)
} elsif ($mapping->{$ckey}->{'command'} eq 'YMODEM') {
if ($self->files_receive_file($file, YMODEM)) {
my $filename = $self->{'CONF'}->{'BBS ROOT'} . '/' . $self->{'CONF'}->{'FILES PATH'} . '/' . $self->{'USER'}->{'file_category_path'} . '/' . $file;
my $size = (-s $filename);
my $sth = $self->{'dbh'}->prepare('INSERT INTO files (category,filename,title,file_type,description,file_size) VALUES (?,?,?,(SELECT id FROM file_types WHERE extension=?),?,?');
$sth->execute($file_category, $file, $title, $ext, $description, $size);
$sth->finish();
} ## end if ($self->files_receive_file...)
} elsif ($mapping->{$ckey}->{'command'} eq 'ZMODEM') {
if ($self->files_receive_file($file, ZMODEM)) {
my $filename = $self->{'CONF'}->{'BBS ROOT'} . '/' . $self->{'CONF'}->{'FILES PATH'} . '/' . $self->{'USER'}->{'file_category_path'} . '/' . $file;
my $size = (-s $filename);
my $sth = $self->{'dbh'}->prepare('INSERT INTO files (category,filename,title,file_type,description,file_size) VALUES (?,?,?,(SELECT id FROM file_types WHERE extension=?),?,?');
$sth->execute($file_category, $file, $title, $ext, $description, $size);
$sth->finish();
} ## end if ($self->files_receive_file...)
} else {
return (FALSE);
}
if ($? == -1) {
$self->{'debug'}->ERROR(["Could not execute rz: $!"]);
} elsif ($? & 127) {
$self->{'debug'}->ERROR(["File Transfer Aborted: $!"]);
} else {
$self->{'debug'}->DEBUG(['File Transfer Successful']);
}
return (TRUE);
} ## end sub files_upload_choices
sub files_list_detailed {
my ($self, $search) = @_;
$self->{'debug'}->DEBUG(['Start Files List Detailed']);
my $sth;
my $filter;
my $columns = $self->{'USER'}->{'max_columns'};
if ($search) {
$self->prompt('Search for');
$filter = $self->get_line({ 'type' => STRING, 'max' => 255, 'default' => '' });
$sth = $self->{'dbh'}->prepare('SELECT * FROM files_view WHERE (filename LIKE ? OR title LIKE ?) AND category_id=? ORDER BY uploaded DESC');
$sth->execute('%' . $filter . '%', '%' . $filter . '%', $self->{'USER'}->{'file_category'});
} else {
$sth = $self->{'dbh'}->prepare('SELECT * FROM files_view WHERE category_id=? ORDER BY uploaded DESC');
$sth->execute($self->{'USER'}->{'file_category'});
}
my @files;
if ($sth->rows > 0) {
$self->{'debug'}->DEBUGMAX(\@files);
my $table;
my $mode = $self->{'USER'}->{'text_mode'};
while (my $row = $sth->fetchrow_hashref()) {
push(@files, $row);
}
$sth->finish();
foreach my $record (@files) {
if ($mode eq 'ANSI') {
$self->output("\n" . '[% HORIZONTAL RULE GREEN %]' . "\n");
$self->output('[% B_BLUE %][% BRIGHT WHITE %] TITLE [% RESET %] ' . $record->{'title'} . "\n");
$self->output('[% B_BLUE %][% BRIGHT WHITE %] FILENAME [% RESET %] ' . $record->{'filename'} . "\n");
$self->output('[% B_BLUE %][% BRIGHT WHITE %] FILE SIZE [% RESET %] ' . format_number($record->{'file_size'}) . "\n");
if ($record->{'prefer_nickname'}) {
$self->output('[% B_BLUE %][% BRIGHT WHITE %] UPLOADER [% RESET %] ' . $record->{'nickname'} . "\n");
} else {
$self->output('[% B_BLUE %][% BRIGHT WHITE %] UPLOADER [% RESET %] ' . $record->{'fullname'} . "\n");
}
$self->output('[% B_BLUE %][% BRIGHT WHITE %] FILE TYPE [% RESET %] ' . $record->{'type'} . "\n");
$self->output('[% B_BLUE %][% BRIGHT WHITE %] UPLOADED [% RESET %] ' . $record->{'uploaded'} . "\n");
$self->output('[% B_BLUE %][% BRIGHT WHITE %] THUMBS [% RESET %] [% THUMBS UP SIGN %] ' . (0 + $record->{'thumbs_up'}) . ' [% THUMBS DOWN SIGN %] ' . (0 + $record->{'tumbs_down'}) . "\n");
$self->output('[% HORIZONTAL RULE GREEN %]' . "\n");
} else {
$self->output("\n TITLE: " . $record->{'title'} . "\n");
$self->output(' FILENAME: ' . $record->{'filename'} . "\n");
$self->output(' FILE SIZE: ' . format_number($record->{'file_size'}) . "\n");
if ($record->{'prefer_nickname'}) {
$self->output(' UPLOADER: ' . $record->{'nickname'} . "\n");
} else {
$self->output(' UPLOADER: ' . $record->{'fullname'} . "\n");
}
$self->output(' FILE TYPE: ' . $record->{'type'} . "\n");
$self->output(' UPLOADED: ' . $record->{'uploaded'} . "\n");
$self->output(' THUMBS UP: ' . (0 + $record->{'thumbs_up'}) . "\n");
$self->output('THUMBS DOWN: ' . (0 + $record->{'thumbs_down'}) . "\n");
} ## end else [ if ($mode eq 'ANSI') ]
last unless ($self->files_choices($record));
} ## end foreach my $record (@files)
} elsif ($search) {
$self->output("\nSorry '$filter' not found");
} else {
$self->output("\nSorry, this file category is empty\n");
}
$self->output("\nPress a key to continue ...");
$self->get_key(ECHO, BLOCKING);
$self->{'debug'}->DEBUG(['End Files List Detailed']);
return (TRUE);
} ## end sub files_list_detailed
sub files_save_file {
my ($self) = @_;
$self->{'debug'}->DEBUG(['Start Save File']);
$self->{'debug'}->DEBUG(['End Save File']);
return (TRUE);
} ## end sub files_save_file
sub files_receive_file {
my ($self, $file, $protocol) = @_;
my $success = TRUE;
$self->{'debug'}->DEBUG(['Start Receive File']);
unless ($self->{'local_mode'}) {
if ($protocol == YMODEM) {
$self->{'debug'}->DEBUG(["Send file $file with Ymodem"]);
$success = $self->files_receive_file_ymodem($self->{'CONF'}->{'BBS ROOT'} . '/' . $self->{'CONF'}->{'FILES PATH'} . '/' . $self->{'USER'}->{'file_category_path'} . '/' . $file);
} elsif ($protocol == ZMODEM) {
$self->{'debug'}->DEBUG(["Send file $file with Zmodem"]);
$success = $self->files_receive_file_zmodem($self->{'CONF'}->{'BBS ROOT'} . '/' . $self->{'CONF'}->{'FILES PATH'} . '/' . $self->{'USER'}->{'file_category_path'} . '/' . $file);
} else { # Xmodem
$success = $self->files_receive_file_xmodem($self->{'CONF'}->{'BBS ROOT'} . '/' . $self->{'CONF'}->{'FILES PATH'} . '/' . $self->{'USER'}->{'file_category_path'} . '/' . $file);
$self->{'debug'}->DEBUG(["Send file $file with Xmodem"]);
}
} else {
$self->output("Upload not allowed in local mode\n");
}
$self->{'debug'}->DEBUG(['End Receive File']);
return ($success);
} ## end sub files_receive_file
sub files_receive_file_xmodem {
my ($self, $file) = @_;
$self->{'debug'}->DEBUG(['Start files_receive_file_xmodem']);
my $sock = $self->{'cl_socket'};
unless ($sock) {
$self->{'debug'}->ERROR(["No client socket for XMODEM receive"]);
return 0;
}
$self->output("\nStart sending your file via Xmodem\n");
my $path = $file;
my $FH;
lib/BBS/Universal.pm view on Meta::CPAN
# if exec fails
POSIX::_exit(1);
} ## end if ($pid == 0)
# parent: wait for child, return success based on exit status
waitpid($pid, 0);
my $status = $?; # full status
if ($status == -1) {
$self->{'debug'}->ERROR(["Failed to waitpid for $cmd: $!"]);
return 0;
}
my $exitcode = ($status >> 8) & 0xFF;
if ($exitcode != 0) {
$self->{'debug'}->DEBUG(["$cmd exited with code $exitcode"]);
}
return $exitcode == 0 ? 1 : 0;
} ## end sub _run_on_socket
sub files_send_zmodem {
my ($self, $file) = @_;
$self->{'debug'}->DEBUG(['Start files_send_zmodem (using lrzsz)']);
# Require lrzsz (sz) to be installed on the system.
# sz will write to the socket (which we've dup'd to STDOUT in child).
my $sock = $self->{'cl_socket'};
unless ($sock) {
$self->{'debug'}->ERROR(["No client socket for ZMODEM send"]);
return 0;
}
$self->output("\nStart Zmodem file download\n");
# full path to file on server
my $path = $file;
unless (-e $path) {
$self->{'debug'}->ERROR(["File not found for ZMODEM send: $path"]);
return 0;
}
# Use sz --zmodem --binary --quiet --resume <file>
# note: --resume is helpful if client requests resume. Adjust flags per your lrzsz version.
my @args = ('--zmodem', '--binary', '--quiet', '--resume', $path);
my $ok = $self->_run_on_socket('sz', \@args);
$self->output("\nFile download complete\n");
$self->{'debug'}->DEBUG(['End files_send_zmodem (using lrzsz)']);
return $ok;
} ## end sub files_send_zmodem
sub files_receive_file_zmodem {
my ($self, $file) = @_;
$self->{'debug'}->DEBUG(['Start files_receive_file_zmodem (using lrzsz)']);
my $sock = $self->{'cl_socket'};
unless ($sock) {
$self->{'debug'}->ERROR(["No client socket for ZMODEM receive"]);
return 0;
}
$self->output("\nStart Zmodem file upload\n");
# When rz receives files it writes them into the current working directory.
# Use the destination directory from config (same place other uploads are stored).
my $dest_dir = $self->{'CONF'}->{'BBS ROOT'} . '/' . $self->{'CONF'}->{'FILES PATH'} . '/' . $self->{'USER'}->{'file_category_path'};
# ensure directory exists
unless (-d $dest_dir) {
File::Path::mkpath($dest_dir);
if ($@) {
$self->{'debug'}->ERROR(["Failed to create dest dir $dest_dir: $@"]);
return 0;
}
} ## end unless (-d $dest_dir)
# We will chdir in the child before exec so the received file lands in $dest_dir.
# Use rz --binary --quiet. Depending on lrzsz version you may want --overwrite or --keep
my @args = ('--binary', '--overwrite', '--quiet');
my $ok = $self->_run_on_socket('rz', \@args, $dest_dir);
$self->output("\nFile upload complete\n");
$self->{'debug'}->DEBUG(['End files_receive_file_zmodem (using lrzsz)']);
return $ok;
} ## end sub files_receive_file_zmodem
# package BBS::Universal::Messages;
sub messages_initialize {
my $self = shift;
$self->{'debug'}->DEBUG(['Start Messages Initialize']);
$self->{'debug'}->DEBUG(['End Messages Initialize']);
return ($self);
} ## end sub messages_initialize
sub messages_forum_categories {
my $self = shift;
$self->{'debug'}->DEBUG(['Start Messages Forum Categories']);
my $command = '';
my $id;
my $sth = $self->{'dbh'}->prepare('SELECT * FROM message_categories ORDER BY description');
my $category = $self->{'USER'}->{'forum_category'};
$sth->execute(); # $self->{'USER'}->{'forum_category'});
my $mapping = {
'TEXT' => '',
'Z' => { 'command' => 'BACK', 'color' => 'WHITE', 'access_level' => 'USER', 'text' => 'Return to Forum Menu' },
};
my @menu_choices = @{ $self->{'MENU CHOICES'} };
while (my $result = $sth->fetchrow_hashref()) {
if ($self->check_access_level($result->{'access_level'})) {
$mapping->{ shift(@menu_choices) } = {
'command' => $result->{'name'},
'id' => $result->{'id'},
'color' => ($category == $result->{'id'}) ? 'GREEN' : 'WHITE',
'access_level' => $result->{'access_level'},
'text' => $result->{'description'},
};
} ## end if ($self->check_access_level...)
} ## end while (my $result = $sth->...)
$sth->finish();
$self->show_choices($mapping);
$self->prompt('Choose Forum Category');
my $key;
do {
$key = uc($self->get_key(SILENT, BLOCKING));
} until (exists($mapping->{$key}) || $key eq chr(3) || !$self->is_connected());
if ($key eq chr(3)) {
$command = 'DISCONNECT';
} else {
$id = $mapping->{$key}->{'id'};
$command = $mapping->{$key}->{'command'};
}
return ($command) if ($key eq 'Z');
if ($self->is_connected() && $command ne 'DISCONNECT') {
$self->output($command);
$sth = $self->{'dbh'}->prepare('UPDATE users SET forum_category=? WHERE id=?');
$sth->execute($id, $self->{'USER'}->{'id'});
$sth->finish();
lib/BBS/Universal.pm view on Meta::CPAN
while ($text =~ /\[\%\s+HORIZONTAL RULE (.*?)\s+\%\]/) {
my $rule = "[% $1 %]" . '[% TOP HORIZONTAL BAR %]' x $self->{'USER'}->{'max_columns'} . '[% RESET %]';
$text =~ s/\[\%\s+HORIZONTAL RULE (.*?)\s+\%\]/$rule/gs;
}
foreach my $string (keys %{ $self->{'petscii_meta'} }) { # Decode macros
if ($string =~ /CLEAR|CLS/i && ($self->{'sysop'} || $self->{'local_mode'})) {
my $ch = locate(($self->{'CACHE'}->get('START_ROW') + $self->{'CACHE'}->get('ROW_ADJUST')), 1) . cldown;
$text =~ s/\[\%\s+$string\s+\%\]/$ch/gi;
} else {
$text =~ s/\[\%\s+$string\s+\%\]/$self->{'petscii_meta'}->{$string}->{'out'}/gi;
}
} ## end foreach my $string (keys %{...})
} ## end if (length($text) > 1)
my $s_len = length($text);
my $nl = $self->{'petscii_meta'}->{'NEWLINE'}->{'out'};
foreach my $count (0 .. $s_len) {
my $char = substr($text, $count, 1);
if ($char eq "\n") {
if ($text !~ /$nl/ && !$self->{'local_mode'}) { # translate only if the file doesn't have ASCII newlines
$char = $nl;
}
$lines--;
if ($lines <= 0) {
$lines = $mlines;
last unless ($self->scroll($nl));
}
} ## end if ($char eq "\n")
$self->send_char($char);
} ## end foreach my $count (0 .. $s_len)
$self->{'debug'}->DEBUG(['End PETSCII Output']);
return (TRUE);
} ## end sub petscii_output
# package BBS::Universal::SysOp;
sub sysop_initialize {
my $self = shift;
$self->{'debug'}->DEBUG(['Start SysOp Initialize']);
# Screen size and derived sections for layout
my ($wsize, $hsize, $wpixels, $hpixels) = GetTerminalSize();
$self->{'wsize'} = $wsize;
$self->{'hsize'} = $hsize;
$self->{'debug'}->DEBUG(["Screen Size is $wsize x $hsize"]);
my $sections = _sections_for_width($wsize);
my $versions = $self->sysop_versions_format($sections, FALSE);
my $bbs_versions = $self->sysop_versions_format($sections, TRUE);
# Visual config
$self->{'sysop_menu_colors'} = [91, 93, 92, 95, 94, 96];
$self->{'sysop_menu_files'} = ['', '', '', '', ''];
# Default user capability flags
$self->{'flags_default'} = {
'prefer_nickname' => 'ON',
'view_files' => 'ON',
'upload_files' => 'OFF',
'download_files' => 'ON',
'remove_files' => 'OFF',
'read_message' => 'ON',
'post_message' => 'ON',
'remove_message' => 'OFF',
'sysop' => 'OFF',
'show_email' => 'OFF',
};
# Tokens (static + dynamic)
my $static = _build_static_tokens($self, $versions, $bbs_versions);
my $dynamic = _build_dynamic_tokens($self);
$self->{'sysop_tokens'} = { %{$static}, %{$dynamic} };
# Field orderings
$self->{'SYSOP ORDER DETAILED'} = [
qw(
id
fullname
username
given
family
nickname
email
birthday
location
access_level
date_format
baud_rate
text_mode
max_columns
max_rows
timeout
retro_systems
accomplishments
prefer_nickname
view_files
upload_files
download_files
remove_files
play_fortunes
read_message
post_message
remove_message
sysop
banned
login_time
logout_time
)
];
$self->{'SYSOP ORDER ABBREVIATED'} = [
qw(
id
fullname
username
given
family
nickname
text_mode
)
];
# Field type definitions
$self->{'SYSOP FIELD TYPES'} = {
'id' => { 'type' => NUMERIC, 'max' => 2, 'min' => 2 },
'username' => { 'type' => HOST, 'max' => 32, 'min' => 16 },
'fullname' => { 'type' => STRING, 'max' => 20, 'min' => 15 },
'given' => { 'type' => STRING, 'max' => 120, 'min' => 32 },
'family' => { 'type' => STRING, 'max' => 120, 'min' => 32 },
'nickname' => { 'type' => STRING, 'max' => 120, 'min' => 32 },
'email' => { 'type' => STRING, 'max' => 120, 'min' => 32 },
'birthday' => { 'type' => STRING, 'max' => 10, 'min' => 10 },
'location' => { 'type' => STRING, 'max' => 120, 'min' => 40 },
'date_format' => { 'type' => RADIO, 'max' => 14, 'min' => 14, 'choices' => ['MONTH/DAY/YEAR', 'DAY/MONTH/YEAR', 'YEAR/MONTH/DAY'], 'default' => 'DAY/MONTH/YEAR', },
'access_level' => { 'type' => RADIO, 'max' => 12, 'min' => 12, 'choices' => ['USER', 'VETERAN', 'JUNIOR SYSOP', 'SYSOP'], 'default' => 'USER', },
'baud_rate' => { 'type' => RADIO, 'max' => 5, 'min' => 5, 'choices' => ['FULL', '115200', '57600', '38400', '19200', '9600', '4800', '2400', '1200', '600', '300'], 'default' => 'FULL', },
'login_time' => { 'type' => STRING, 'max' => 10, 'min' => 10 },
'logout_time' => { 'type' => STRING, 'max' => 10, 'min' => 10 },
'text_mode' => { 'type' => RADIO, 'max' => 7, 'min' => 9, 'choices' => ['ANSI', 'ASCII', 'ATASCII', 'PETSCII'], 'default' => 'ASCII', },
'max_rows' => { 'type' => NUMERIC, 'max' => 3, 'min' => 3, 'default' => 25 },
'max_columns' => { 'type' => NUMERIC, 'max' => 3, 'min' => 3, 'default' => 80 },
'timeout' => { 'type' => NUMERIC, 'max' => 5, 'min' => 5, 'default' => 10 },
'retro_systems' => { 'type' => STRING, 'max' => 120, 'min' => 40 },
'accomplishments' => { 'type' => STRING, 'max' => 120, 'min' => 40 },
'prefer_nickname' => { 'type' => BOOLEAN, 'max' => 5, 'min' => 5, 'choices' => ['ON', 'OFF'], 'default' => 'OFF' },
'view_files' => { 'type' => BOOLEAN, 'max' => 5, 'min' => 5, 'choices' => ['ON', 'OFF'], 'default' => 'ON' },
'banned' => { 'type' => BOOLEAN, 'max' => 5, 'min' => 5, 'choices' => ['ON', 'OFF'], 'default' => 'OFF' },
'upload_files' => { 'type' => BOOLEAN, 'max' => 5, 'min' => 5, 'choices' => ['ON', 'OFF'], 'default' => 'OFF' },
'download_files' => { 'type' => BOOLEAN, 'max' => 5, 'min' => 5, 'choices' => ['ON', 'OFF'], 'default' => 'OFF' },
'remove_files' => { 'type' => BOOLEAN, 'max' => 5, 'min' => 5, 'choices' => ['ON', 'OFF'], 'default' => 'OFF' },
'read_message' => { 'type' => BOOLEAN, 'max' => 5, 'min' => 5, 'choices' => ['ON', 'OFF'], 'default' => 'ON' },
'post_message' => { 'type' => BOOLEAN, 'max' => 5, 'min' => 5, 'choices' => ['ON', 'OFF'], 'default' => 'OFF' },
'remove_message' => { 'type' => BOOLEAN, 'max' => 5, 'min' => 5, 'choices' => ['ON', 'OFF'], 'default' => 'OFF' },
'play_fortunes' => { 'type' => BOOLEAN, 'max' => 5, 'min' => 5, 'choices' => ['ON', 'OFF'], 'default' => 'ON' },
'sysop' => { 'type' => BOOLEAN, 'max' => 5, 'min' => 5, 'choices' => ['ON', 'OFF'], 'default' => 'OFF' },
'password' => { 'type' => STRING, 'max' => 64, 'min' => 32 },
};
$self->{'debug'}->DEBUG(['End SysOp Initialize']);
return $self;
} ## end sub sysop_initialize
# Helper: map terminal width to section count
sub _sections_for_width {
my ($wsize) = @_;
return 1 if $wsize <= 80;
return 2 if $wsize <= 120;
return 3 if $wsize <= 160;
return 4 if $wsize <= 200;
return 5 if $wsize <= 240;
return 6;
} ## end sub _sections_for_width
# Helper: build static token fields from $self
sub _build_static_tokens {
my ($self, $versions, $bbs_versions) = @_;
return {
'HOSTNAME' => $self->sysop_hostname,
'IP ADDRESS' => $self->sysop_ip_address(),
'CPU BITS' => $self->{'CPU'}->{'CPU BITS'},
'CPU CORES' => $self->{'CPU'}->{'CPU CORES'},
'CPU SPEED' => $self->{'CPU'}->{'CPU SPEED'},
'CPU IDENTITY' => $self->{'CPU'}->{'CPU IDENTITY'},
'CPU THREADS' => $self->{'CPU'}->{'CPU THREADS'},
'HARDWARE' => $self->{'CPU'}->{'HARDWARE'},
'VERSIONS' => $versions,
'BBS VERSIONS' => $bbs_versions,
'BBS NAME' => colored(['green'], $self->{'CONF'}->{'BBS NAME'}),
};
} ## end sub _build_static_tokens
# Helper: build dynamic token closures (uniform style)
sub _build_dynamic_tokens {
my ($self) = @_;
return {
'THREADS COUNT' => sub { my $self = shift; return $self->{'CACHE'}->get('THREADS_RUNNING'); },
'USERS COUNT' => sub { my $self = shift; return $self->db_count_users(); },
'UPTIME' => sub { my $self = shift; my $uptime = `uptime -p`; chomp($uptime); return $uptime; },
'DISK FREE SPACE' => sub { my $self = shift; return $self->sysop_disk_free(); },
'MEMORY' => sub { my $self = shift; return $self->sysop_memory(); },
'ONLINE' => sub { my $self = shift; return $self->sysop_online_count(); },
'CPU LOAD' => sub { my $self = shift; return $self->cpu_info->{'CPU LOAD'}; },
'ENVIRONMENT' => sub { my $self = shift; return $self->sysop_showenv(); },
'FILE CATEGORY' => sub {
my $self = shift;
my $sth = $self->{'dbh'}->prepare('SELECT description FROM file_categories WHERE id=?');
$sth->execute($self->{'USER'}->{'file_category'});
my ($result) = $sth->fetchrow_array();
lib/BBS/Universal.pm view on Meta::CPAN
foreach my $name (@order) {
push(@hw, $self->{'SYSOP FIELD TYPES'}->{$name}->{'min'});
}
$table = Text::SimpleTable->new(@hw);
if ($list_mode =~ /ABBREVIATED/) {
$table->row(@order);
} else {
my @title = ();
foreach my $heading (@order) {
push(@title, $self->sysop_vertical_heading($heading));
}
$table->row(@title);
} ## end else [ if ($list_mode =~ /ABBREVIATED/)]
$table->hr();
while (my $row = $sth->fetchrow_hashref()) {
my @vals = ();
foreach my $name (@order) {
push(@vals, $row->{$name} . '');
$self->{'debug'}->DEBUGMAX([$name, $row->{$name}]);
}
$table->row(@vals);
} ## end while (my $row = $sth->fetchrow_hashref...)
$sth->finish();
my $string = $table->thick('CYAN')->draw();
$self->sysop_pager("$string\n");
} ## end else [ if ($list_mode =~ /VERTICAL/)]
print 'Press a key to continue ... ';
$self->{'debug'}->DEBUG(['End SysOp List Users']);
return ($self->sysop_keypress());
} ## end sub sysop_list_users
sub sysop_delete_files { # Placeholder
my $self = shift;
$self->{'debug'}->DEBUG(['Start SysOp Delete Files']);
$self->{'debug'}->DEBUG(['End SysOp Delete Files']);
return (TRUE);
} ## end sub sysop_delete_files
sub sysop_list_files {
my $self = shift;
$self->{'debug'}->DEBUG(['Start SysOp List Files']);
my ($wsize, $hsize, $wpixels, $hpixels) = GetTerminalSize();
my $sth = $self->{'dbh'}->prepare('SELECT * FROM files_view WHERE category_id=?');
$sth->execute($self->{'USER'}->{'file_category'});
my $sizes = {};
while (my $row = $sth->fetchrow_hashref()) {
foreach my $name (keys %{$row}) {
if ($name eq 'file_size') {
my $size = format_number($row->{$name});
$sizes->{$name} = max(length($size), $sizes->{$name});
} else {
$sizes->{$name} = max(length($row->{$name}), $sizes->{$name});
}
} ## end foreach my $name (keys %{$row...})
} ## end while (my $row = $sth->fetchrow_hashref...)
$sth->finish();
my $table;
if ($wsize > 150) {
$table = Text::SimpleTable->new(max(5, $sizes->{'title'}), max(8, $sizes->{'filename'}), max(4, $sizes->{'type'}), max(11, $sizes->{'description'}), max(8, $sizes->{'username'}), max(4, $sizes->{'file_size'}), max(8, $sizes->{'uploaded'}), ma...
$table->row('TITLE', 'FILENAME', 'TYPE', 'DESCRIPTION', 'UPLOADER', 'SIZE', 'UPLOADED', 'THUMBS UP', 'THUMBS DOWN');
} else {
$table = Text::SimpleTable->new(max(5, $sizes->{'filename'}), max(8, $sizes->{'title'}), max(4, $sizes->{'extension'}), max(11, $sizes->{'description'}), max(8, $sizes->{'username'}), max(4, $sizes->{'file_size'}), max(9, $sizes->{'thumbs_up'...
$table->row('TITLE', 'FILENAME', 'TYPE', 'DESCRIPTION', 'UPLOADER', 'SIZE', 'THUMBS UP', 'THUMBS DOWN');
}
$table->hr();
$sth = $self->{'dbh'}->prepare('SELECT * FROM files_view WHERE category_id=?');
$sth->execute($self->{'USER'}->{'file_category'});
my $category;
while (my $row = $sth->fetchrow_hashref()) {
if ($wsize > 150) {
$table->row($row->{'title'}, $row->{'filename'}, $row->{'type'}, $row->{'description'}, $row->{'username'}, format_number($row->{'file_size'}), $row->{'uploaded'}, sprintf('%-06u', $row->{'thumbs_up'}), sprintf('%-06u', $row->{'thumbs_dow...
} else {
$table->row($row->{'title'}, $row->{'filename'}, $row->{'extension'}, $row->{'description'}, $row->{'username'}, format_number($row->{'file_size'}), sprintf('%-06u', $row->{'thumbs_up'}), sprintf('%-06u', $row->{'thumbs_down'}));
}
$category = $row->{'category'};
} ## end while (my $row = $sth->fetchrow_hashref...)
$sth->finish();
$self->sysop_output("\n" . '[% B_ORANGE %][% BLACK %] Current Category [% RESET %] [% BRIGHT YELLOW %][% BLACK RIGHT-POINTING TRIANGLE %][% RESET %] [% BRIGHT WHITE %][% FILE CATEGORY %][% RESET %]');
my $tbl = $table->twin('YELLOW')->draw();
while ($tbl =~ / (TITLE|FILENAME|TYPE|DESCRIPTION|UPLOADER|SIZE|UPLOADED|THUMBS UP|THUMBS DOWN) /) {
my $ch = $1;
my $new = '[% BRIGHT GREEN %]' . $ch . '[% RESET %]';
$tbl =~ s/ $ch / $new /gs;
}
$self->sysop_output("\n$tbl\nPress a Key To Continue ...");
$self->sysop_keypress();
print " BACK\n";
$self->{'debug'}->DEBUG(['End SysOp List Files']);
return (TRUE);
} ## end sub sysop_list_files
sub sysop_color_border {
my ($self, $tbl, $color, $type) = @_;
$self->{'debug'}->DEBUG(['Start SysOp Color Border']);
$color = '[% ' . $color . ' %]';
my $new;
if ($tbl =~ /(â)/) {
my $ch = $1;
$new = $ch;
if ($type eq 'DOUBLE') {
$new =~ s/â/\[\% BOX DRAWINGS DOUBLE HORIZONTAL \%\]/gs;
} elsif ($type eq 'HEAVY') {
$new =~ s/â/\[\% BOX DRAWINGS HEAVY HORIZONTAL \%\]/gs;
}
$new = $color . $new . '[% RESET %]';
$tbl =~ s/$ch/$new/gs;
} ## end if ($tbl =~ /(â)/)
if ($tbl =~ /(â)/) {
my $ch = $1;
$new = $ch;
if ($type eq 'DOUBLE') {
$new =~ s/â/\[\% BOX DRAWINGS DOUBLE VERTICAL \%\]/gs;
} elsif ($type eq 'HEAVY') {
$new =~ s/â/\[\% BOX DRAWINGS HEAVY VERTICAL \%\]/gs;
}
$new = '[% RESET %]' . $color . $new . '[% RESET %]';
$tbl =~ s/$ch/$new/gs;
} ## end if ($tbl =~ /(â)/)
if ($tbl =~ /(â)/) {
my $ch = $1;
$new = $ch;
if ($type eq 'ROUNDED') {
$new =~ s/â/\[\% BOX DRAWINGS LIGHT ARC DOWN AND RIGHT \%\]/gs;
} elsif ($type eq 'DOUBLE') {
$new =~ s/â/\[\% BOX DRAWINGS DOUBLE DOWN AND RIGHT \%\]/gs;
} elsif ($type eq 'HEAVY') {
$new =~ s/â/\[\% BOX DRAWINGS HEAVY DOWN AND RIGHT \%\]/gs;
}
$new = $color . $new . '[% RESET %]';
$tbl =~ s/$ch/$new/gs;
lib/BBS/Universal.pm view on Meta::CPAN
if (defined($user_row)) {
my ($wsize, $hsize, $wpixels, $hpixels) = GetTerminalSize();
do {
my $valsize = 1;
foreach my $fld (keys %{$user_row}) {
$valsize = max($valsize, length($user_row->{$fld}));
}
$valsize = min($valsize, $wsize - 29);
my $table = Text::SimpleTable->new(6, 16, $valsize);
$table->row('CHOICE', 'FIELD', 'VALUE');
$table->hr();
my $count = 0;
my %choice;
foreach my $field (@{ $self->{'SYSOP ORDER DETAILED'} }) {
if ($field =~ /_time|fullname|_category|id/) {
$table->row(' ', uc($field), $user_row->{$field} . '');
} else {
if ($user_row->{$field} =~ /^(0|1)$/) {
$table->row($choices[$count], uc($field), $self->sysop_true_false($user_row->{$field}, 'YN'));
} elsif ($field eq 'access_level') {
$table->row($choices[$count], uc($field), $user_row->{$field} . ' - USER, VETERAN, JUNIOR SYSOP, SYSOP');
} elsif ($field eq 'date_format') {
$table->row($choices[$count], uc($field), $user_row->{$field} . ' - YEAR/MONTH/DAY, MONTH/DAY/YEAR, DAY/MONTH/YEAR');
} elsif ($field eq 'baud_rate') {
$table->row($choices[$count], uc($field), $user_row->{$field} . ' - 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, FULL');
} elsif ($field eq 'text_mode') {
$table->row($choices[$count], uc($field), $user_row->{$field} . ' - ASCII, ANSI, ATASCII, PETSCII');
} elsif ($field eq 'timeout') {
$table->row($choices[$count], uc($field), $user_row->{$field} . ' - Minutes');
} else {
$table->row($choices[$count], uc($field), $user_row->{$field} . '');
}
$count++ if ($key_exit eq $choices[$count]);
$choice{ $choices[$count] } = $field;
$count++;
} ## end else [ if ($field =~ /_time|fullname|_category|id/)]
} ## end foreach my $field (@{ $self...})
my $tbl = $table->round('BRIGHT CYAN')->draw();
while ($tbl =~ / (CHOICE|FIELD|VALUE|No|Yes|USER. VETERAN. JUNIOR SYSOP. SYSOP|YEAR.MONTH.DAY, MONTH.DAY.YEAR, DAY.MONTH.YEAR|300. 600. 1200. 2400. 4800. 9600. 19200. FULL|ASCII. ANSI. ATASCII. PETSCII|Minutes) /) {
my $ch = $1;
my $new;
if ($ch =~ /Yes/) {
$new = '[% GREEN %]' . $ch . '[% RESET %]';
} elsif ($ch =~ /No/) {
$new = '[% RED %]' . $ch . '[% RESET %]';
} elsif ($ch =~ /CHOICE|FIELD|VALUE/) {
$new = '[% BRIGHT YELLOW %]' . $ch . '[% RESET %]';
} else {
$new = '[% RGB 50,50,150 %]' . $ch . '[% RESET %]';
}
$tbl =~ s/$ch/$new/g;
} ## end while ($tbl =~ / (CHOICE|FIELD|VALUE|No|Yes|USER. VETERAN. JUNIOR SYSOP. SYSOP|YEAR.MONTH.DAY, MONTH.DAY.YEAR, DAY.MONTH.YEAR|300. 600. 1200. 2400. 4800. 9600. 19200. FULL|ASCII. ANSI. ATASCII. PETSCII|Minutes) /)
$self->sysop_output('[% CLS %]' . $tbl . "\n");
$self->sysop_show_choices($mapping);
$self->sysop_prompt('Choose');
do {
$key = uc($self->sysop_keypress());
} until ('1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ' =~ /$key/i);
if ($key !~ /$key_exit/i) {
print 'Edit > (', $choice{$key}, ' = ', $user_row->{ $choice{$key} }, ') > ';
if ($choice{$key} =~ /^(play_fortunes|prefer_nickname|view_files|upload_files|download_files|remove_files|read_message|post_message|remove_message|sysop)$/) {
$user_row->{ $choice{$key} } = ($user_row->{ $choice{$key} } == 1) ? 0 : 1;
my $sth = $self->{'dbh'}->prepare('UPDATE permissions SET ' . $choice{$key} . '= !' . $choice{$key} . ' WHERE id=?');
$sth->execute($user_row->{'id'});
$sth->finish();
} elsif($choice{$key} =~ /text_mode/) {
my $new = $self->sysop_get_line($self->{'SYSOP FIELD TYPES'}->{ $choice{$key} }, $user_row->{ $choice{$key} });
$user_row->{ $choice{$key} } = $new;
my $sth = $self->{'dbh'}->prepare('UPDATE users SET ' . $choice{$key} . '=? WHERE id=?');
$sth->execute($new, $self->{'text_modes'}->{$user_row->{'id'}});
$sth->finish();
} else {
my $new = $self->sysop_get_line($self->{'SYSOP FIELD TYPES'}->{ $choice{$key} }, $user_row->{ $choice{$key} });
$user_row->{ $choice{$key} } = $new;
my $sth = $self->{'dbh'}->prepare('UPDATE users SET ' . $choice{$key} . '=? WHERE id=?');
$sth->execute($new, $user_row->{'id'});
$sth->finish();
} ## end else [ if ($choice{$key} =~ /^(prefer_nickname|view_files|upload_files|download_files|remove_files|read_message|post_message|remove_message|sysop)$/)]
} else {
print "BACK\n";
}
} until ($key =~ /$key_exit/i);
} elsif ($search ne '') {
print "User not found!\n\n";
}
$self->{'debug'}->DEBUG(['End SysOp User Edit']);
return (TRUE);
} ## end sub sysop_user_edit
sub sysop_new_user_edit {
my $self = shift;
my $row = shift;
my $file = shift;
$self->{'debug'}->DEBUG(['Start SysOp User Edit']);
my $mapping = $self->sysop_load_menu($row, $file);
print locate($row, 1), cldown, $mapping->{'TEXT'};
delete($mapping->{'TEXT'});
my ($key_exit) = (keys %{$mapping});
my @choices = qw( 0 1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M N O P Q R S T U V W X Y );
my $key;
my @responses;
my $sth = $self->{'dbh'}->prepare('SELECT * FROM users_view WHERE access_level=?');
$sth->execute('USER');
my $user_row;
while ($user_row = $sth->fetchrow_hashref()) {
push(@responses, $user_row);
}
$sth->finish();
$self->{'debug'}->DEBUGMAX(\@responses);
my ($wsize, $hsize, $wpixels, $hpixels) = GetTerminalSize();
while ($user_row = pop(@responses)) {
do {
my $valsize = 1;
foreach my $fld (keys %{$user_row}) {
$valsize = max($valsize, length($user_row->{$fld}));
}
$valsize = min($valsize, $wsize - 29);
my $table = Text::SimpleTable->new(6, 16, $valsize);
$table->row('CHOICE', 'FIELD', 'VALUE');
$table->hr();
my $count = 0;
my %choice;
foreach my $field (@{ $self->{'SYSOP ORDER DETAILED'} }) {
if ($field =~ /_time|fullname|_category|id/) {
$table->row(' ', $field, $user_row->{$field} . '');
} else {
if ($user_row->{$field} =~ /^(0|1)$/) {
$table->row($choices[$count], $field, $self->sysop_true_false($user_row->{$field}, 'YN'));
} elsif ($field eq 'access_level') {
$table->row($choices[$count], $field, $user_row->{$field} . ' - USER, VETERAN, JUNIOR SYSOP, SYSOP');
} elsif ($field eq 'date_format') {
$table->row($choices[$count], $field, $user_row->{$field} . ' - YEAR/MONTH/DAY, MONTH/DAY/YEAR, DAY/MONTH/YEAR');
} elsif ($field eq 'baud_rate') {
$table->row($choices[$count], $field, $user_row->{$field} . ' - 300, 600, 1200, 2400, 4800, 9600, 19200, FULL');
} elsif ($field eq 'text_mode') {
$table->row($choices[$count], $field, $user_row->{$field} . ' - ASCII, ANSI, ATASCII, PETSCII');
} elsif ($field eq 'timeout') {
$table->row($choices[$count], $field, $user_row->{$field} . ' - Minutes');
} else {
$table->row($choices[$count], $field, $user_row->{$field} . '');
}
$count++ if ($key_exit eq $choices[$count]);
$choice{ $choices[$count] } = $field;
$count++;
} ## end else [ if ($field =~ /_time|fullname|_category|id/)]
} ## end foreach my $field (@{ $self...})
my $tbl = $table->round('BRIGHT CYAN')->draw();
while ($tbl =~ / (CHOICE|FIELD|VALUE|No|Yes|USER. VETERAN. JUNIOR SYSOP. SYSOP|YEAR.MONTH.DAY, MONTH.DAY.YEAR, DAY.MONTH.YEAR|300. 600. 1200. 2400. 4800. 9600. 19200. FULL|ASCII. ANSI. ATASCII. PETSCII|Minutes) /) {
my $ch = $1;
my $new;
if ($ch =~ /Yes/) {
$new = '[% GREEN %]' . $ch . '[% RESET %]';
} elsif ($ch =~ /No/) {
$new = '[% RED %]' . $ch . '[% RESET %]';
} elsif ($ch =~ /CHOICE|FIELD|VALUE/) {
$new = '[% BRIGHT YELLOW %]' . $ch . '[% RESET %]';
} else {
$new = '[% RGB 50,50,150 %]' . $ch . '[% RESET %]';
}
$tbl =~ s/$ch/$new/g;
} ## end while ($tbl =~ / (CHOICE|FIELD|VALUE|No|Yes|USER. VETERAN. JUNIOR SYSOP. SYSOP|YEAR.MONTH.DAY, MONTH.DAY.YEAR, DAY.MONTH.YEAR|300. 600. 1200. 2400. 4800. 9600. 19200. FULL|ASCII. ANSI. ATASCII. PETSCII|Minutes) /)
$self->sysop_output('[% CLS %]' . $tbl . "\n");
$self->sysop_show_choices($mapping);
$self->sysop_prompt('Choose');
do {
$key = uc($self->sysop_keypress());
} until ('1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ' =~ /$key/i);
if ($key !~ /$key_exit/i) {
print 'Edit > (', $choice{$key}, ' = ', $user_row->{ $choice{$key} }, ') > ';
my $new = $self->sysop_get_line(ECHO, 1 + $self->{'SYSOP FIELD TYPES'}->{ $choice{$key} }->{'max'}, $user_row->{ $choice{$key} });
unless ($new eq '') {
$new =~ s/^(Yes|On)$/1/i;
$new =~ s/^(No|Off)$/0/i;
}
$user_row->{ $choice{$key} } = $new;
if ($key =~ /prefer_nickname|view_files|upload_files|download_files|remove_files|read_message|post_message|remove_message|sysop/) {
my $sth = $self->{'dbh'}->prepare('UPDATE permissions SET ' . choice { $key } . '=? WHERE id=?');
$sth->execute($new, $user_row->{'id'});
$sth->finish();
} else {
my $sth = $self->{'dbh'}->prepare('UPDATE users SET ' . $choice{$key} . '=? WHERE id=?');
$sth->execute($new, $user_row->{'id'});
$sth->finish();
}
} else {
print "BACK\n";
}
} until ($key =~ /$key_exit/i);
} ## end while ($user_row = pop(@responses...))
$self->{'debug'}->DEBUG(['End SysOp User Edit']);
return (TRUE);
} ## end sub sysop_new_user_edit
sub sysop_user_add {
my $self = shift;
my $row = shift;
my $file = shift;
$self->{'debug'}->DEBUG(['Start SysOp User Add']);
my $flags_default = $self->{'flags_default'};
my $mapping = $self->sysop_load_menu($row, $file);
print locate($row, 1), cldown, $mapping->{'TEXT'};
my $table = Text::SimpleTable->new(15, 150);
my $user_template;
my @tmp = grep(!/id|banned|fullname|_time|max_|_category/, @{ $self->{'SYSOP ORDER DETAILED'} });
push(@tmp, 'password');
foreach my $name (@tmp) {
my $size = max(3, $self->{'SYSOP FIELD TYPES'}->{$name}->{'max'});
if ($name eq 'timeout') {
$table->row($name, '_' x $size . ' - Minutes');
} elsif ($name eq 'baud_rate') {
$table->row($name, '_' x $size . ' - 300 or 600 or 1200 or 2400 or 4800 or 9600 or 19200 or FULL');
} elsif ($name =~ /username|given|family|password/) {
if ($name eq 'given') {
$table->row("$name (first)", '_' x $size . ' - Cannot be empty');
} elsif ($name eq 'family') {
$table->row("$name (last)", '_' x $size . ' - Cannot be empty');
} else {
$table->row($name, '_' x $size . ' - Cannot be empty');
}
} elsif ($name eq 'date_format') {
$table->row($name, '_' x $size . ' - YEAR/MONTH/DAY or MONTH/DAY/YEAR or DAY/MONTH/YEAR');
} elsif ($name eq 'access_level') {
$table->row($name, '_' x $size . ' - USER or VETERAN or JUNIOR SYSOP or SYSOP');
} elsif ($name eq 'text_mode') {
$table->row($name, '_' x $size . ' - ANSI or ASCII or ATASCII or PETSCII');
} elsif ($name eq 'birthday') {
$table->row($name, '_' x $size . ' - YEAR-MM-DD');
} elsif ($name =~ /(prefer_nickname|_files|_message|sysop|fortunes)/) {
$table->row($name, '_' x $size . ' - Yes/No or True/False or On/Off or 1/0');
} elsif ($name =~ /location|retro_systems|accomplishments/) {
$table->row($name, '_' x ($self->{'SYSOP FIELD TYPES'}->{$name}->{'max'}));
} else {
$table->row($name, '_' x $size);
}
lib/BBS/Universal.pm view on Meta::CPAN
'color' => 'WHITE',
'access_level' => 'USER',
'text' => $result->{'text_mode'},
};
$count++;
} ## end while (my $result = $sth->...)
$sth->finish();
$self->show_choices($mapping);
my $mode = $self->{'USER'}->{'text_mode'};
if ($mode eq 'ANSI') {
$self->prompt('([% BRIGHT YELLOW %]' . $self->{'USER'}->{'username'} . '[% RESET %]) ' . 'Choose');
} elsif ($mode eq 'ATASCII') {
$self->prompt('(' . $self->{'USER'}->{'username'} . ') ' . 'Choose');
} elsif ($mode eq 'PETSCII') {
$self->prompt('([% YELLOW %]' . $self->{'USER'}->{'username'} . '[% RESET %]) ' . 'Choose');
} else {
$self->prompt('(' . $self->{'USER'}->{'username'} . ') ' . 'Choose');
}
my $key;
do {
$key = uc($self->get_key(SILENT, FALSE));
} until (exists($mapping->{$key}) || $key eq chr(3) || !$self->is_connected());
$self->output($mapping->{$key}->{'command'} . "\n");
unless ($key eq 'Z' || $key eq chr(3)) {
my $command = $mapping->{$key}->{'command'};
my $sth = $self->{'dbh'}->prepare('UPDATE users SET text_mode=(SELECT id FROM text_modes WHERE text_mode=?) WHERE id=?');
$sth->execute($command, $self->{'USER'}->{'id'});
$sth->finish;
$self->{'USER'}->{'text_mode'} = $command;
$self->{'debug'}->DEBUG([" Text Mode: $command"]);
} ## end unless ($key eq 'Z' || $key...)
$self->{'debug'}->DEBUG(['Start Users Update Text Mode']);
return (TRUE);
} ## end sub users_update_text_mode
sub users_load {
my $self = shift;
my $username = shift;
my $password = shift;
$self->{'debug'}->DEBUG(['Start Users Load']);
my $sth;
if ($self->{'sysop'}) {
$sth = $self->{'dbh'}->prepare('SELECT * FROM users_view WHERE username=?');
$sth->execute($username);
} else {
$sth = $self->{'dbh'}->prepare('SELECT * FROM users_view WHERE username=? AND password=SHA2(?,512)');
$sth->execute($username, $password);
}
my $results = $sth->fetchrow_hashref();
my $response = FALSE;
if (defined($results)) {
$self->{'USER'} = $results;
delete($self->{'USER'}->{'password'});
foreach my $field ( # For numeric values
qw(
show_email
prefer_nickname
view_files
upload_files
download_files
remove_files
read_message
post_message
remove_message
play_fortunes
banned
sysop
)
) {
$self->{'USER'}->{$field} = 0 + $self->{'USER'}->{$field};
} ## end foreach my $field ( qw( show_email...))
$response = TRUE;
} ## end if (defined($results))
$self->{'debug'}->DEBUG(['End Users Load']);
return ($response);
} ## end sub users_load
sub users_get_date {
my $self = shift;
my $old_date = shift;
$self->{'debug'}->DEBUG(['Start User Get Date']);
my $response;
if ($old_date =~ / /) {
my $time;
($old_date, $time) = split(/ /, $old_date);
my ($year, $month, $day) = split(/-/, $old_date);
my $date = $self->{'USER'}->{'date_format'};
$date =~ s/YEAR/$year/;
$date =~ s/MONTH/$month/;
$date =~ s/DAY/$day/;
$response = "$date $time";
} else {
my ($year, $month, $day) = split(/-/, $old_date);
my $date = $self->{'USER'}->{'date_format'};
$date =~ s/YEAR/$year/;
$date =~ s/MONTH/$month/;
$date =~ s/DAY/$day/;
$response = $date;
} ## end else [ if ($old_date =~ / /) ]
$self->{'debug'}->DEBUG(['End User Get Date']);
return ($response);
} ## end sub users_get_date
sub users_list {
my $self = shift;
$self->{'debug'}->DEBUG(['Start Users List']);
my $sth = $self->{'dbh'}->prepare(
q{
SELECT username,
fullname,
nickname,
accomplishments,
retro_systems,
birthday,
prefer_nickname,
location
FROM users_view
lib/BBS/Universal.pm view on Meta::CPAN
}
} ## end while (my $results = $sth...)
$sth->finish;
my $text;
my $mode = $self->{'USER'}->{'text_mode'};
if ($mode eq 'ANSI') {
$text = $table->boxes2('GREEN')->draw();
foreach my $orig ('USERNAME', 'NICKNAME', 'FULLNAME', 'LOCATION', 'RETRO SYSTEMS', 'BDAY', 'ACCOMPLISHMENTS') {
my $ch = '[% BRIGHT YELLOW %]' . $orig . '[% RESET %]';
$text =~ s/$orig/$ch/gs;
}
} elsif ($mode eq 'ATASCII') {
$text = $self->color_border($table->boxes->draw(), '');
} elsif ($mode eq 'PETSCII') {
$text = $table->boxes->draw();
foreach my $orig ('USERNAME', 'NICKNAME', 'FULLNAME', 'LOCATION', 'RETRO SYSTEMS', 'BDAY', 'ACCOMPLISHMENTS') {
my $ch = '[% YELLOW %]' . $orig . '[% RESET %]';
$text =~ s/$orig/$ch/gs;
}
$text = $self->color_border($text, 'GREEN');
} else {
$text = $table->draw();
}
$self->{'debug'}->DEBUG(['End Users List']);
return ($text);
} ## end sub users_list
sub users_add {
my $self = shift;
my $user_template = shift;
$self->{'debug'}->DEBUG(['Start Users Add']);
$self->{'debug'}->DEBUGMAX([$user_template]);
$self->{'dbh'}->begin_work;
my $sth = $self->{'dbh'}->prepare(
q{
INSERT INTO users (
username,
given,
family,
nickname,
email,
accomplishments,
retro_systems,
birthday,
location,
baud_rate,
text_mode,
password)
VALUES (?,?,?,?,?,?,?,DATE(?),?,?,(SELECT text_modes.id FROM text_modes WHERE text_modes.text_mode=?),SHA2(?,512))
}
);
$sth->execute($user_template->{'username'}, $user_template->{'given'}, $user_template->{'family'}, $user_template->{'nickname'}, $user_template->{'email'}, $user_template->{'accomplishments'}, $user_template->{'retro_systems'}, $user_template->{'...
$sth->finish;
$sth = $self->{'dbh'}->prepare(
q{
INSERT INTO permissions (
id,
prefer_nickname,
view_files,
upload_files,
download_files,
remove_files,
read_message,
show_email,
post_message,
remove_message,
sysop,
play_fortunes,
timeout)
VALUES (LAST_INSERT_ID(),?,?,?,?,?,?,?,?,?,?,?,?,?);
}
);
$sth->execute($user_template->{'prefer_nickname'}, $user_template->{'view_files'}, $user_template->{'upload_files'}, $user_template->{'download_files'}, $user_template->{'remove_files'}, $user_template->{'read_message'}, $user_template->{'show_em...
my $response;
if ($self->{'dbh'}->err) {
$self->{'dbh'}->rollback;
$sth->finish();
$response = FALSE;
} else {
$self->{'dbh'}->commit;
$sth->finish();
$response = TRUE;
}
$self->{'debug'}->DEBUG(['End Users Add']);
return ($response);
} ## end sub users_add
sub users_delete {
my $self = shift;
my $id = shift;
$self->{'debug'}->DEBUG(['Start Users Delete']);
if ($id == 1) {
$self->{'debug'}->ERROR([' Attempt to delete SysOp user']);
return (FALSE);
}
$self->{'debug'}->WARNING([" Delete user $id"]);
$self->{'dbh'}->begin_work();
my $sth = $self->{'dbh'}->prepare('DELETE FROM permissions WHERE id=?');
$sth->execute($id);
if ($self->{'dbh'}->err) {
$self->{'debug'}->ERROR([$self->{'dbh'}->errstr]);
$self->{'dbh'}->rollback();
$sth->finish();
$self->{'debug'}->DEBUG([' End Users Delete']);
return (FALSE);
} else {
$sth->finish();
$sth = $self->{'dbh'}->prepare('DELETE FROM users WHERE id=?');
$sth->execute($id);
if ($self->{'dbh'}->err) {
$self->{'debug'}->ERROR([$self->{'dbh'}->errstr]);
$self->{'dbh'}->rollback();
$sth->finish();
$self->{'debug'}->DEBUG([' End Users Delete']);
return (FALSE);
} else {
$self->{'dbh'}->commit();
$sth->finish();
$self->{'debug'}->DEBUG([' End Users Delete']);
return (TRUE);
} ## end else [ if ($self->{'dbh'}->err)]
} ## end else [ if ($self->{'dbh'}->err)]
$self->{'debug'}->DEBUG(['End Users Delete']);
} ## end sub users_delete
sub users_file_category {
my $self = shift;
$self->{'debug'}->DEBUG(['Start Users File Category']);
my $sth = $self->{'dbh'}->prepare('SELECT description FROM file_categories WHERE id=?');
$sth->execute($self->{'USER'}->{'file_category'});
lib/BBS/Universal.pm view on Meta::CPAN
$sth->execute($self->{'USER'}->{'rss_category'});
my ($category) = ($sth->fetchrow_array());
$sth->finish();
$self->{'debug'}->DEBUG(['End Users RSS Category']);
return ($category);
} ## end sub users_rss_category
sub users_find {
my $self = shift;
$self->{'debug'}->DEBUG(['Start Users Find']);
$self->{'debug'}->DEBUG(['End Users Find']);
return (TRUE);
} ## end sub users_find
sub users_count {
my $self = shift;
$self->{'debug'}->DEBUG(['Start Users Count']);
my $sth = $self->{'dbh'}->prepare('SELECT COUNT(*) FROM users');
$sth->execute();
my ($count) = ($sth->fetchrow_array());
$sth->finish();
$self->{'debug'}->DEBUG(['End Users Count']);
return ($count);
} ## end sub users_count
sub users_info {
my $self = shift;
$self->{'debug'}->DEBUG(['Start Users Info']);
my $table;
my $text = '';
my $width = 1;
foreach my $field (keys %{ $self->{'USER'} }) {
$width = max($width, length($self->{'USER'}->{$field}));
}
my $columns = $self->{'USER'}->{'max_columns'};
$self->{'debug'}->DEBUG([" $columns Columns"]);
if ($columns <= 40) {
$table = sprintf('%-15s=%-25s', 'FIELD', 'VALUE') . "\n";
$table .= '-' x $self->{'USER'}->{'max_columns'} . "\n";
$table .= sprintf('%-15s=%-25s', 'ACCOUNT NUMBER', $self->{'USER'}->{'id'}) . "\n";
$table .= sprintf('%-15s=%-25s', 'USERNAME', $self->{'USER'}->{'username'}) . "\n";
$table .= sprintf('%-15s=%-25s', 'FULL NAME', $self->{'USER'}->{'fullname'}) . "\n";
$table .= sprintf('%-15s=%-25s', 'NICKNAME', $self->{'USER'}->{'nickname'}) . "\n";
$table .= sprintf('%-15s=%-25s', 'EMAIL', $self->{'USER'}->{'email'}) . "\n";
$table .= sprintf('%-15s=%-25s', 'DATE FORMAT', $self->{'USER'}->{'date_format'}) . "\n";
$table .= sprintf('%-15s=%-25s', 'SCREEN', $self->{'USER'}->{'max_columns'} . 'x' . $self->{'USER'}->{'max_rows'}) . "\n";
$table .= sprintf('%-15s=%-25s', 'BIRTHDAY', $self->users_get_date($self->{'USER'}->{'birthday'})) . "\n";
$table .= sprintf('%-15s=%-25s', 'LOCATION', $self->{'USER'}->{'location'}) . "\n";
$table .= sprintf('%-15s=%-25s', 'BAUD RATE', $self->{'USER'}->{'baud_rate'}) . "\n";
$table .= sprintf('%-15s=%-25s', 'LAST LOGIN', $self->{'USER'}->{'login_time'}) . "\n";
$table .= sprintf('%-15s=%-25s', 'LAST LOGOUT', $self->{'USER'}->{'logout_time'}) . "\n";
$table .= sprintf('%-15s=%-25s', 'TEXT MODE', $self->{'USER'}->{'text_mode'}) . "\n";
$table .= sprintf('%-15s=%-25s', 'IDLE TIMEOUT', $self->{'USER'}->{'timeout'}) . "\n";
$table .= sprintf('%-15s=%-25s', 'SHOW EMAIL', $self->yes_no($self->{'USER'}->{'show_email'}, FALSE)) . "\n";
$table .= sprintf('%-15s=%-25s', 'PREFER NICKNAME', $self->yes_no($self->{'USER'}->{'prefer_nickname'}, FALSE)) . "\n";
$table .= sprintf('%-15s=%-25s', 'VIEW FILES', $self->yes_no($self->{'USER'}->{'view_files'}, FALSE)) . "\n";
$table .= sprintf('%-15s=%-25s', 'UPLOAD FILES', $self->yes_no($self->{'USER'}->{'upload_files'}, FALSE)) . "\n";
$table .= sprintf('%-15s=%-25s', 'DOWNLOAD FILES', $self->yes_no($self->{'USER'}->{'download_files'}, FALSE)) . "\n";
$table .= sprintf('%-15s=%-25s', 'REMOVE FILES', $self->yes_no($self->{'USER'}->{'remove_files'}, FALSE)) . "\n";
$table .= sprintf('%-15s=%-25s', 'READ MESSAGES', $self->yes_no($self->{'USER'}->{'read_message'}, FALSE)) . "\n";
$table .= sprintf('%-15s=%-25s', 'POST MESSAGES', $self->yes_no($self->{'USER'}->{'post_message'}, FALSE)) . "\n";
$table .= sprintf('%-15s=%-25s', 'REMOVE MESSAGES', $self->yes_no($self->{'USER'}->{'remove_message'}, FALSE)) . "\n";
$table .= sprintf('%-15s=%-25s', 'PLAY FORTUNES', $self->yes_no($self->{'USER'}->{'play_fortunes'}, FALSE)) . "\n";
$table .= sprintf('%-15s=%-25s', 'ACCESS LEVEL', $self->{'USER'}->{'access_level'}) . "\n";
$table .= sprintf('%-15s=%-25s', 'RETRO SYSTEMS', $self->{'USER'}->{'retro_systems'}) . "\n";
$table .= sprintf('%-15s=%-25s', 'ACCOMPLISHMENTS', $self->{'USER'}->{'accomplishments'}) . "\n";
} elsif ((($width + 22) * 2) <= $columns) {
$table = Text::SimpleTable->new(15, $width, 15, $width);
$table->row('FIELD', 'VALUE', 'FIELD', 'VALUE');
$table->hr();
$table->row('ACCOUNT NUMBER', $self->{'USER'}->{'id'}, 'USERNAME', $self->{'USER'}->{'username'});
$table->row('FULLNAME', $self->{'USER'}->{'fullname'}, 'NICKNAME', $self->{'USER'}->{'nickname'});
$table->row('EMAIL', $self->{'USER'}->{'email'}, 'SCREEN', $self->{'USER'}->{'max_columns'} . 'x' . $self->{'USER'}->{'max_rows'});
$table->row('BIRTHDAY', $self->users_get_date($self->{'USER'}->{'birthday'}), 'LOCATION', $self->{'USER'}->{'location'});
$table->row('BAUD RATE', $self->{'USER'}->{'baud_rate'}, 'LAST LOGIN', $self->users_get_date($self->{'USER'}->{'login_time'}));
$table->row('DATE FORMAT', $self->{'USER'}->{'date_format'}, 'LAST LOGOUT', $self->users_get_date($self->{'USER'}->{'logout_time'}));
$table->row('IDLE TIMEOUT', $self->{'USER'}->{'timeout'}, 'TEXT MODE', $self->{'USER'}->{'text_mode'});
$table->row('PREFER NICKNAME', $self->yes_no($self->{'USER'}->{'prefer_nickname'}, FALSE), 'VIEW FILES', $self->yes_no($self->{'USER'}->{'view_files'}, FALSE));
$table->row('UPLOAD FILES', $self->yes_no($self->{'USER'}->{'upload_files'}, FALSE), 'DOWNLOAD FILES', $self->yes_no($self->{'USER'}->{'download_files'}, FALSE));
$table->row('REMOVE FILES', $self->yes_no($self->{'USER'}->{'remove_files'}, FALSE), 'READ MESSAGES', $self->yes_no($self->{'USER'}->{'read_message'}, FALSE));
$table->row('POST MESSAGES', $self->yes_no($self->{'USER'}->{'post_message'}, FALSE), 'REMOVE MESSAGES', $self->yes_no($self->{'USER'}->{'remove_message'}, FALSE));
$table->row('SHOW EMAIL', $self->yes_no($self->{'USER'}->{'show_email'}, FALSE), 'ACCESS LEVEL', $self->{'USER'}->{'access_level'});
$table->row('PLAY FORTUNES', $self->yes_no($self->{'USER'}->{'play_fortunes'}, FALSE), 'ACCOMPLISHMENTS', $self->{'USER'}->{'accomplishments'});
$table->row('RETRO SYSTEMS', $self->{'USER'}->{'retro_systems'},'','');
} else {
$width = min($width + 7, $self->{'USER'}->{'max_columns'} - 7);
$table = Text::SimpleTable->new(15, $width);
$table->row('FIELD', 'VALUE');
$table->hr();
$table->row('ACCOUNT NUMBER', $self->{'USER'}->{'id'});
$table->row('USERNAME', $self->{'USER'}->{'username'});
$table->row('FULLNAME', $self->{'USER'}->{'fullname'});
$table->row('NICKNAME', $self->{'USER'}->{'nickname'});
$table->row('EMAIL', $self->{'USER'}->{'email'});
$table->row('DATE FORMAT', $self->{'USER'}->{'date_format'});
$table->row('SCREEN', $self->{'USER'}->{'max_columns'} . 'x' . $self->{'USER'}->{'max_rows'});
$table->row('BIRTHDAY', $self->users_get_date($self->{'USER'}->{'birthday'}));
$table->row('LOCATION', $self->{'USER'}->{'location'});
$table->row('BAUD RATE', $self->{'USER'}->{'baud_rate'});
$table->row('LAST LOGIN', $self->{'USER'}->{'login_time'});
$table->row('LAST LOGOUT', $self->{'USER'}->{'logout_time'});
$table->row('TEXT MODE', $self->{'USER'}->{'text_mode'});
$table->row('IDLE TIMEOUT', $self->{'USER'}->{'timeout'});
$table->row('SHOW EMAIL', $self->yes_no($self->{'USER'}->{'show_email'}, FALSE));
$table->row('PREFER NICKNAME', $self->yes_no($self->{'USER'}->{'prefer_nickname'}, FALSE));
$table->row('VIEW FILES', $self->yes_no($self->{'USER'}->{'view_files'}, FALSE));
$table->row('UPLOAD FILES', $self->yes_no($self->{'USER'}->{'upload_files'}, FALSE));
$table->row('DOWNLOAD FILES', $self->yes_no($self->{'USER'}->{'download_files'}, FALSE));
$table->row('REMOVE FILES', $self->yes_no($self->{'USER'}->{'remove_files'}, FALSE));
$table->row('READ MESSAGES', $self->yes_no($self->{'USER'}->{'read_message'}, FALSE));
$table->row('POST MESSAGES', $self->yes_no($self->{'USER'}->{'post_message'}, FALSE));
$table->row('REMOVE MESSAGES', $self->yes_no($self->{'USER'}->{'remove_message'}, FALSE));
$table->row('PLAY FORTUNES', $self->yes_no($self->{'USER'}->{'play_fortunes'}, FALSE));
$table->row('ACCESS LEVEL', $self->{'USER'}->{'access_level'});
$table->row('RETRO SYSTEMS', $self->{'USER'}->{'retro_systems'});
$table->row('ACCOMPLISHMENTS', $self->{'USER'}->{'accomplishments'});
} ## end else [ if ($columns <= 40) ]
my $mode = $self->{'USER'}->{'text_mode'};
if ($mode eq 'ATASCII') {
$text = $self->color_border($table->boxes->draw(), 'WHITE');
} elsif ($mode eq 'ANSI') {
$text = $table->boxes2('RGB 0,90,190')->draw();
my $no = colored(['red'], 'NO');
my $yes = colored(['green'], 'YES');
my $field = colored(['bright_yellow'], 'FIELD');
my $va = colored(['bright_yellow'], 'VALUE');
$text =~ s/ FIELD / $field /gs;
$text =~ s/ VALUE / $va /gs;
$text =~ s/ NO / $no /gs;
$text =~ s/ YES / $yes /gs;
foreach $field ('PLAY FORTUNES', 'ACCESS LEVEL', 'SUFFIX', 'ACCOUNT NUMBER', 'USERNAME', 'FULLNAME', 'SCREEN', 'BIRTHDAY', 'LOCATION', 'BAUD RATE', 'LAST LOGIN', 'LAST LOGOUT', 'TEXT MODE', 'IDLE TIMEOUT', 'RETRO SYSTEMS', 'ACCOMPLISHMENTS', ...
my $ch = colored(['yellow'], $field);
$text =~ s/$field/$ch/gs;
}
} elsif ($mode eq 'PETSCII') {
$text = $table->boxes->draw();
my $no = '[% RED %]NO[% RESET %]';
my $yes = '[% GREEN %]YES[% RESET %]';
my $field = '[% YELLOW %]FIELD[% RESET %]';
my $va = '[% YELLOW %]VALUE[% RESET %]';
$text =~ s/ FIELD / $field /gs;
$text =~ s/ VALUE / $va /gs;
$text =~ s/ NO / $no /gs;
$text =~ s/ YES / $yes /gs;
foreach $field ('PLAY FORTUNES', 'ACCESS LEVEL', 'SUFFIX', 'ACCOUNT NUMBER', 'USERNAME', 'FULLNAME', 'SCREEN', 'BIRTHDAY', 'LOCATION', 'BAUD RATE', 'LAST LOGIN', 'LAST LOGOUT', 'TEXT MODE', 'IDLE TIMEOUT', 'RETRO SYSTEMS', 'ACCOMPLISHMENTS', ...
my $ch = '[% BROWN %]' . $field . '[% RESET %]';
$text =~ s/$field/$ch/gs;
}
$text = $self->color_border($text, 'BLUE');
} else {
$text = $table->draw();
}
$self->{'debug'}->DEBUG(['End Users Info']);
return ($text);
} ## end sub users_info
# MANUAL IMPORT HERE #
1;
( run in 0.759 second using v1.01-cache-2.11-cpan-b16cb0d3907 )