#!perl -T # reputer analyzes and displays node reputation and xp data from perlmonks.org # homenode = http://perlmonks.org/index.pl?node=reputer # # List user nodes sorted by rep, title or date in HTML tables. # Three ways to graph number of nodes by reputation. # Display changed, deleted and new node info and rep change. # Cookies save info used for lwp transfers, and display options. # Can write up to 8 data files in temp dir, so give it write permission. # # Export/import enabled if Compress::Zlib is installed # Requires XML::Simple use strict; use CGI qw(header param url); eval("use XML::Simple 'XMLin'"); # required xml parser if($@){&install_xml_simple(); exit} use CGI::Cookie; use HTTP::Cookies; use HTTP::Request::Common; use HTML::Entities 'encode_entities'; use LWP::Simple 'get'; use LWP::UserAgent qw(agent cookie_jar request content); use Data::Dumper; #use CGI::Carp 'fatalsToBrowser'; # only use for debugging with -w my$trade = 0; eval("use Compress::Zlib"); unless($@){$trade = 1} # if installed enable export/import # config variables my$temp = './'; # where data files are saved my$public_access = ''; # 'yes' disables config, downloads, and external program functions my$bodytag = ''; my$form_method = 'get'; # get or post, 'get' shows params in url my%programs = ( # full path to optional external programs, links will appear in sort mode. # key = the display name, value = a system call which dumps output to the browser. # 'xrepwalker' => 'perl xlukerep.pl', # 'xstatswhore' => 'perl xstatswhore.pl', # 'tracert perlmonks' => 'tracert perlmonks.org', # 'ping perlmonks' => 'ping perlmonks.org', ); # proxy my$use_proxy = ''; # 'yes' enables use thru the following proxy my$proxy = 'http://proxy.dom:port'; # must define this to use proxy my$proxyid = ''; my$proxypass = ''; # end config variables my$bb = 0; # table border on node list if($ENV{'HTTP_USER_AGENT'}){ # ie cant do cellspacing as border in nested colored tables if(($ENV{'HTTP_USER_AGENT'}=~/MSIE/) || ($ENV{'HTTP_USER_AGENT'}!~/Mozilla/)){ $bb = 1 }} my$perlmonks = ''; # default for links if no cookie set my$ddi = 0; # data dumper intent level, 0 = smallest files # paths and data files my$df = $temp.'reputer.dat'; # main data file my$repthen = $temp.'reputer.then'; # 'previous' rep file my$repnow = $temp.'reputer.now'; # 'present' rep file my$uri = url(); # html elements my$nb = ' '; my$bq = '
'; my$eh = ''; my$metac = ""; my$metad = ""; # general vars my$handle = select(); my$today = localtime(time); my%cookies = CGI::Cookie->fetch(); my%i = map{$_ => param($_)} param; my%info = ( version => '1.0', date => '20010404' ); my($fix_title,$strip_re) = ''; # sort mode descriptions my%modescs = ( ta => 'Title', td => 'Title Reverse', ra => 'Lowest Reputation First', rd => 'Highest Reputation First', ca => 'Oldest First', cd => 'Newest First' ); if(($i{'exec'}) && ($public_access ne 'yes')){ # external programs if(($ENV{PATH}) && ($ENV{PATH}=~/(.*)/s)){$ENV{PATH}=$1} # get taint to accept our path if(exists $programs{$i{'exec'}}){ for(keys %programs){ if($_ eq $i{'exec'}){ my$status = system("$programs{$_}"); die "$programs{$_} failed: $?" unless $status == 0; } } } else{ print header; print "Can't find $i{'exec'} in program list."} exit } if(($i{'erase'}) && ($public_access ne 'yes')){ # delete data files if($i{'erase'} eq 'current'){&erase($repnow,$repthen); exit} if($i{'erase'} eq 'backup'){&erase("$repnow.bak","$repthen.bak"); exit} if($i{'erase'} eq 'safe'){&erase("$repnow.safe","$repthen.safe"); exit} } # var names for 3 required files below use vars qw($xpdat1 $dat1 $then1 $thenxp1 $thent $now1 $nowxp1 $nowt); # read from main data file if it exists, otherwise read from the network. my$nodat = 0; my($xpdata,$data,$md); # vars for next block if(eval "require '$df'"){ # offline mode $md = (stat($df))[9]; $md = sprintf "Data file updated: %s
", scalar localtime($md); $xpdata = $xpdat1; # hash containing parsed xp xml $data = $dat1; # hash containing parsed usernodes xml } else{$nodat = 1} # online mode # previous rep file my($then,$thenxp,$thentime,$then_is); if(($i{'n'}) && ($i{'n'} eq 'changes')){ if(eval "require '$repthen'"){ # old rep file $then_is = 1; $then = $then1; $thenxp = $thenxp1; $thentime = $thent; } } # present rep file my($now,$nowxp,$nowtime,$now_is); if(($i{'n'}) && ($i{'n'} eq 'changes')){ if(eval "require '$repnow'"){ # new rep file $now_is = 1; $now = $now1; $nowxp = $nowxp1; $nowtime = $nowt; } } my$ins = 0; if(($i{'n'}) && ($public_access ne 'yes')){ if($i{'n'} eq 'dumphash'){&dump_hash(); exit} # display raw data structure if($i{'n'} eq 'login'){ if($i{'user'}){$ins++} if($i{'pass'}){$ins++} if($i{'pm'}){$ins++} if($i{'show'}){$ins++} } } if( ($i{'n'}) && ($public_access ne 'yes') ){ # set cookies if logout or login if( ( ($i{'n'} eq 'login') && ($ins > 0) ) || ($i{'n'} eq 'logout') ){ my($c1,$c2,$c3,$c4,$s) = ''; if($i{'n'} eq 'login'){ if($i{'pm'}=~m|^(http://)|i){$i{'pm'}=~s/$1//o} $c1 = CGI::Cookie->new(-name=>'user',-value=>"$i{'user'}",-expires=>'+10y'); $c2 = CGI::Cookie->new(-name=>'pass',-value=>"$i{'pass'}",-expires=>'+10y'); $c3 = CGI::Cookie->new(-name=>'pm',-value=>"$i{'pm'}",-expires=>'+10y'); $c4 = CGI::Cookie->new(-name=>'show',-value=>"$i{'show'}",-expires=>'+10y'); } if($i{'n'} eq 'logout'){ $c1 = CGI::Cookie->new(-name=>'user',-value=>'',-expires=>'now'); $c2 = CGI::Cookie->new(-name=>'pass',-value=>'',-expires=>'now'); $c3 = CGI::Cookie->new(-name=>'pm',-value=>'',-expires=>'now'); $c4 = CGI::Cookie->new(-name=>'show',-value=>'',-expires=>'now'); } print header(-cookie=>[$c1,$c2,$c3,$c4]); unless($i{'n'} eq 'logout'){ if($ins > 1){$s='s'} &begin_html('fu'); print qq~$bq $bq $bq

Cookie$s set

username: $i{'user'}
password: $i{'pass'}
perlmonks: $i{'pm'}
nodes per page: $i{'show'}
~; my$err = 0; if( (!$i{'user'}) or (!$i{'pass'}) or (!$i{'pm'}) ){ print qq~

Warning: Required data missing!

    ~; if(!$i{'user'}){ print '
  1. username required to access perlmonks.
    '} if(!$i{'pass'}){ print '
  2. password required to access perlmonks.
    '} if(!$i{'pm'}){ print '
  3. perlmonks domain required to access perlmonks.
    '} print '
'; $err++ } unless(($i{'pm'}) && ($i{'pm'}=~/\..*?\./)){ print qq~

Error: perlmonks domain must have two dots!.~; $err++ } if( (!$i{'show'}) || (($i{'show'}) && ($i{'show'}!~/\d+/)) ){ print qq~

Caution: setting nodes per page to < 1 or blank shows all nodes.~; $err++ } if($nodat == 1){ print qq~

Data file not detected. Build a data file?~; $err++ } if($err > 0){ print qq~

~; } print qq~

Note: Setting a cookie with incorrect username, password or perlmonks domain is fatal to authenticated downloads (online mode functions: refresh and file creation) and will prompt to retry or login again. Bad login cookies do not interfere with offline operations.~; if($cookies{'ft'}){$fix_title = $cookies{'ft'}->value} if($cookies{'sr'}){$strip_re = $cookies{'sr'}->value} &print_form('z'); # print nav buttons, any arg just kicks it into another mode print $eh; # end_html exit } } } my($username,$password,$show) = ''; if($public_access ne 'yes'){ if(($i{'n'}) && ($i{'n'} eq 'logout')){&login_form(); exit} } if(%cookies){ # get cookies if($cookies{'user'}){$username = $cookies{'user'}->value} if($cookies{'pass'}){$password = $cookies{'pass'}->value} if($cookies{'pm'}){$perlmonks = $cookies{'pm'}->value} if($cookies{'show'}){$show = $cookies{'show'}->value} if($cookies{'ft'}){$fix_title = $cookies{'ft'}->value} if($cookies{'sr'}){$strip_re = $cookies{'sr'}->value} } my$start = 1; if(($i{'start'}) && ($i{'start'}=~/\d+/)){$start = $i{'start'}} if(($i{'show'}) && ($i{'show'}=~/\d+/)){$show = $i{'show'}} if(defined($i{'ft'})){$fix_title = $i{'ft'}} if(defined($i{'sr'})){$strip_re = $i{'sr'}} # urls my$pmurl = "http://$perlmonks/index.pl"; my$repurl = "$pmurl?node_id=32704"; my$xpurl = "$pmurl?node_id=16046"; if($i{'n'}){ if($i{'n'} eq ' ? '){&help(); exit} if($public_access ne 'yes'){ if($i{'n'} eq 'update'){&check_update(); exit} if(($i{'n'} eq 'login') && ($ins < 1)){&begin_html(); &login_form(); exit} if(($i{'n'} eq 'config') && ($nodat == 1)){&begin_html(); &config(); exit} } } my($xml,$repxml,$xpxml,$avgrep,$modesc); # if data file doesn't exist or is being created or refreshed read xml from network if( ($public_access ne 'yes') && ( ($nodat == 1) || ( ($i{'n'}) && ($i{'n'}=~/make data/) ) ) ){ unless(($username=~/\S/) && ($password=~/\S/)){ &begin_html(); &login_form(); exit } &login(); # returns $repxml and $xpxml &fixxml($xpxml); # returns $xml $xpdata = XMLin($xml, keyattr => 'XP', forcearray => 1); &fixxml($repxml); # returns $xml $data = XMLin($xml, keyattr => 'NODE', forcearray => 1); } # extract xp info and username my($xp,$level,$xp2next,$xusername); if(defined @{$xpdata->{'XP'}}){ for my $xpinfo(@{$xpdata->{'XP'}}){ $xp2next = $xpinfo->{'xp2nextlevel'}; $level = $xpinfo->{'level'}; $xp = $xpinfo->{'xp'}; } } if(defined @{$xpdata->{'INFO'}}){ for my $xpinfo(@{$xpdata->{'INFO'}}){ $xusername = $xpinfo->{'foruser'}; } } my$begin_html = 0; # init header check my($mode,$td,$ta,$rd,$ra,$ca,$cd) = ''; if($i{'n'}){ # sub calls unless($public_access eq 'yes'){ if($i{'filename'}){ if($i{'n'} eq 'import data'){&import(); exit} } if($i{'n'} eq 'import'){&import_data(); exit} if($i{'n'} eq 'export'){&export_data(); exit} } if($i{'n'} eq 'gif'){&gif(); exit} # sort modes if($i{'n'} eq 'td'){$mode=$i{'n'}; $td='selected'} # title reverse if($i{'n'} eq 'ta'){$mode=$i{'n'}; $ta='selected'} # title if($i{'n'} eq 'rd'){$mode=$i{'n'}; $rd='selected'} # highest rep first if($i{'n'} eq 'ra'){$mode=$i{'n'}; $ra='selected'} # lowest rep first if($i{'n'} eq 'ca'){$mode=$i{'n'}; $ca='selected'} # oldest first if($i{'n'} eq 'cd'){$mode=$i{'n'}; $cd='selected'} # newest first if($i{'n'} eq 'graph'){$mode='rd'; $rd='selected'} # graph - highest rep first } else{$mode='cd'; $cd='selected'} # default to newest first if no input my(%node_reps,%node_rep,%node_con,%node_cre,%rep_freq,%node_home); my(@reps,@reps_nodes,$total_nodes,$total_rep,$homenode); if(defined @{$data->{'NODE'}}){ my(@negs,@titles,@dates,$usersince); for my $node(@{$data->{'NODE'}}){ # find homenode $node_home{$node->{'id'}}=1 } my@hn = sort {$a <=> $b} keys %node_home; $homenode = $hn[0]; # by lowest node id for my $node(@{$data->{'NODE'}}){ if($node->{'id'} == $homenode){ $usersince = $node->{'createtime'} } unless($node->{'id'} == $homenode){ $rep_freq{$node->{'reputation'}}++; # frequency hash if($fix_title eq 'yes'){ $node->{'content'} =~ s/\($username\)//g; # strip username from node title } $node_con{$node->{'id'}} = $node->{'content'}; $node_cre{$node->{'id'}} = $node->{'createtime'}; $node_rep{$node->{'id'}} = $node->{'reputation'}; $node_reps{$node->{'id'}} = $node->{'reputation'}; $total_rep += $node->{'reputation'}; # total rep $total_nodes++; } } for(sort {$node_rep{$b} <=> $node_rep{$a}} keys %node_rep){ push @reps, $node_rep{$_}; # build a sorted array of node reps push @reps_nodes, $_; # and a parallel array of corresponding node_ids } my$rephi = $reps[0]; my$replo = $reps[-1]; if(($i{'n'}) && ($public_access ne 'yes')){ # bailout before html header if(($i{'n'} eq 'detect change') or ($i{'n'} eq 'detect')){&detect_changed_nodes(); exit} if(($i{'n'} eq 'restore') or ($i{'n'} eq 'restore previous')){&restore(); exit} if ($i{'n'} eq 'safe backup'){&safety('backup'); exit} if ($i{'n'} eq 'safe restore'){&safety('restore'); exit} } if(($show < 1) || ($show eq '')){$show = $total_nodes} if(($start < 1) || ($start eq '')){$start = 1} unless(($i{'re'}) && ($i{'re'}==1)){ &begin_html(); # html header, html start tags &the_bridge($total_rep,$xp,$rephi,$replo,$usersince); # display the summary and menu } if($i{'n'}){ # bailout after html header unless($public_access eq 'yes'){ if(($i{'n'} eq 'make data') || ($nodat == 1)){&makedat(); exit} if($i{'n'} eq 'config'){&config(); exit} } if($i{'n'} eq 'changes'){&nowthen(); exit} if($i{'n'} eq 'graph'){&graph(); &the_bridge($total_rep,$xp,$rephi,$replo,$usersince); print $eh; exit} } for(keys %modescs){ # find description of current sort mode if($_ eq $mode){ $modesc = $modescs{$mode} } } my($c,$d); if($mode=~/rd|ra/){ # by rep &listitle(); # print title corresponding to sort mode, opens table print qq~ numtitlerepdate~; if($mode=~/ra/){ # ascend @reps = reverse(@reps); @reps_nodes = reverse(@reps_nodes); } my$r = '-1'; for(@reps){ $r++; $c++; if($c >= $start){ $d++; unless($d > $show){ if($strip_re eq 'yes'){$node_con{$reps_nodes[$r]}=~s/Re: //g} print qq~$c $node_con{$reps_nodes[$r]} $_ $node_cre{$reps_nodes[$r]}~; } } } &nodes_per_page($start,$show,$c); } if($mode=~/td|ta/){ # by title &listitle(); print qq~ numtitlerepdate~; for(keys %node_con){ if($strip_re eq 'yes'){$node_con{$_}=~s/Re: //g} push @titles, $node_con{$_}."\t".$_ } if($mode=~/td/){@titles = sort { lc($b) cmp lc($a) } (@titles)} # descend if($mode=~/ta/){@titles = sort { lc($a) cmp lc($b) } (@titles)} # ascend for(@titles){ $c++; if($c >= $start){ $d++; unless($d > $show){ my($k,$v)=split(/\t/,$_); print qq~$c $k $node_reps{$v} $node_cre{$v}~; } } } &nodes_per_page($start,$show,$c); } if($mode=~/cd|ca/){ # by date &listitle(); print qq~ numtitlerepdate~; for(keys %node_cre){ push @dates, $node_cre{$_}."\t".$_} if($mode=~/cd/){@dates = sort { lc($b) cmp lc($a) } (@dates)} # descend if($mode=~/ca/){@dates = sort { lc($a) cmp lc($b) } (@dates)} # ascend for(@dates){ $c++; if($c >= $start){ $d++; unless($d > $show){ my($k,$v)=split(/\t/,$_); if($strip_re eq 'yes'){$node_con{$v}=~s/Re: //g} print qq~$c $node_con{$v} $node_reps{$v} $node_cre{$v}~; } } } &nodes_per_page($start,$show,$c); } &the_bridge($total_rep,$xp,$rephi,$replo,$usersince); print $eh; exit } sub nodes_per_page { # construct the 'previous' and 'next' paging links my($start,$show,$c) = @_; my$previous = ($start-$show); print '

'; unless($previous < 1){ # previous n print qq~<< Prev $show ~; } my$Next = ($start+$show); # start and show form print qq~
~; unless($Next > $c){ # next n print qq~ Next $show >>~; } print qq~
start show

~; } sub login_form { my$state = shift; &begin_html('fu'); print qq~

$bq

Login

~; if($state eq 'config'){ print qq~reputer creates 4 browser cookies

1. username, 2. password, and 3. perlmonks are required to read rep and xp data from the network, but aren't used when working with saved files. 4. nodes per page sets the page limit for the sorted node list. If blank or set to 0 or less than 1 it shows all nodes. Set a reasonable limit if you have a large number of nodes.~; } unless($state eq 'config'){ print qq~Enter your username, password and perlmonks domain here and select login. This saves browser cookies and prompts you to reload reputer, which then uses the cookie info for further interaction with perlmonks. The 'nodes per page' cookie defines the length of the node list. Logout deletes these browser cookies.

Note: username, password and perlmonks domain are required to acquire data.~; } if(($username!~/\S/) || ($password!~/\S/)){ unless(($i{'n'}) && ($i{'n'} eq 'logout')){ print '

Warning:

    '; unless($username=~/\S/){ print "
  1. username required"} unless($password=~/\S/){ print "
  2. password required"} unless($perlmonks=~/^.*?\..*?\..*?$/){ print "
  3. perlmonks domain required (with two dots)"} } } print qq~

    username
    password

    Set to your usual login domain.
    perlmonks
    Must have at least two dots.

    nodes per page
    ~; if(($i{'n'}) && ($i{'n'} ne 'config')){ print ' '} print "

$eh"; } sub login { # login and download rep and xp xml files my$state = shift; my$ua = LWP::UserAgent->new; # create a web browser object (useragent) $ua->agent("reputer/$info{'version'}"); # call it reputer $ua->cookie_jar(HTTP::Cookies->new()); # enable cookies $ua->proxy(http=>"$proxy") if ($use_proxy eq 'yes'); # proxy # build a request object, returns cookies my$req = POST ($pmurl, [op=>'login',user=>$username,passwd=>$password,expires=>'+10y',node_id=>'16046']); if($use_proxy eq 'yes'){$req->proxy_authorization_basic("$proxyid", "$proxypass")} # proxy my$res = $ua->request($req); # make request $req = GET ($repurl); # build new request (user rep data) if($use_proxy eq 'yes'){$req->proxy_authorization_basic("$proxyid", "$proxypass")} # proxy $res = $ua->request($req); # make request $repxml = $res->content; # extract content of response unless($repxml=~/\S/){ if($state eq 'detect'){ # restore if download fails &restore(); select($handle); &begin_html($metac); print qq~Download failed. Previous view restored, reloading...~; exit } else{ unless($begin_html == 1){&begin_html()} print qq~$bq Rep download failed, try again or login.~; exit } } $req = GET ($xpurl); # make new request (user rep data) if($use_proxy eq 'yes'){$req->proxy_authorization_basic("$proxyid", "$proxypass")} # proxy $res = $ua->request($req); $xpxml = $res->content; unless($xpxml=~/\S/){ unless($begin_html == 1){&begin_html()} print qq~$bq XP download failed, try again or login.~; exit } return } sub detect_changed_nodes { ©($repthen,"$repthen.bak"); ©($repnow,"$repnow.bak"); open(OLD,"< $repnow") or die "$!"; open(TMP,"> $repthen") or die "$!"; select(TMP); while(){ # repnow -> (fix variables) -> repthen $_=~s/\$nowxp1 = \{/\$thenxp1 = \{/o; $_=~s/\$now1 = \{/\$then1 = \{/o; $_=~s/\$nowt = '/\$thent = '/o; print TMP $_; } close(OLD) or die "$!"; close(TMP) or die "$!"; select($handle); &getsave($repnow,'nowxp','now','nowt','detect'); &getsave($df,'xpdat','dat','makedat'); # also update node list data file &begin_html($metac); print qq~Download complete, analyzing...~; } sub program_list { # list external programs if(($public_access ne 'yes') && (defined %programs)){ print qq~~; for(sort {$b cmp $a} keys %programs){ my$g = $_; $g =~ tr/ /+/; print qq~~; } print qq~
$_
~; } } sub install_xml_simple { print header; print qq~Install XML::Simple~; } sub fixxml { # replace ascii chrs that are not legal xml with underscore # nodes with title like this would break links back to the node $xml = shift; $xml =~ s/[\r\n\t]//g; # jcwren $xml =~ tr/\x80-\xff/_/; # $xml =~ tr/\x00-\x1f/_/; # return $xml; } sub getsave { # save data files according to passed parameters my$state = $_[4]; unless(($i{'n'} eq 'make data') || ($nodat == 1)){ &login($state); # returns $repxml and $xpxml &fixxml($xpxml); # returns $xml $xpdata = XMLin($xml, keyattr => 'XP', forcearray => 1); &fixxml($repxml); # returns $xml $data = XMLin($xml, keyattr => 'NODE', forcearray => 1); } open(DAT,"> $_[0]") or die "$!"; $Data::Dumper::Indent = $ddi; $Data::Dumper::Varname = "$_[1]"; print DAT Dumper($xpdata); $Data::Dumper::Indent = $ddi; $Data::Dumper::Varname = "$_[2]"; print DAT Dumper($data); print DAT '$'.$_[3]." = '$today';"; close(DAT) or die "$!"; } sub filedata { # find and print file size and createtime my$size = (-s $_[0]); my$when = (stat($_[0]))[9]; $when = sprintf "%s", scalar localtime($when); print ' - '.$size.' bytes, created '.$when.'
'; } sub copy { # simple file copy if(-e $_[0]){ open(OLD,"< $_[0]") or die "$!"; } else{ &begin_html($metad); print "$_[0] doesn't exist"; exit } open(NEW,"> $_[1]") or die "$!"; select(NEW); while(){ print NEW $_ } close(OLD) or die "$!"; close(NEW) or die "$!"; select($handle); } sub erase { # erase passed files and print results &begin_html($metad,'
    '); for(@_){ if(-e $_){ unlink $_; print "
  1. $_ deleted"; } else { print "
  2. $_ doesn't exist"; } } print "

Reloading..."; } sub restore { # restore previous view ©("$repthen.bak",$repthen); ©("$repnow.bak",$repnow); if($i{'n'}=~/restore/){ select($handle); &begin_html($metac); print qq~Previous restored, reloading...~; exit } } sub safety { # make or restore from safe backup my$state = shift; if($state eq 'backup'){ ©($repthen,"$repthen.safe"); ©($repnow,"$repnow.safe"); &begin_html($metac); print qq~Saved to the safe backup, reloading...~; } if($state eq 'restore'){ ©("$repthen.safe",$repthen); ©("$repnow.safe",$repnow); &begin_html($metac); print qq~Safe backup restored, reloading...~; } } sub makedat { # make the main data file &getsave($df,'xpdat','dat','makedat'); unless($i{'re'}==1){ print qq~

$bq Data file $df created.

Further access will use this data file until it's refreshed or overwritten.~; } if($i{'re'}==1){ print "Location: $uri?n=$i{'mode'}\n\n"} } sub import { # function open(DAT,"< $i{'filename'}") or die "$!"; local $/ = undef; my$imports = ; close(DAT) or die "$!"; &begin_html(); unless($imports=~/^M/){ print qq~

$bq Invalid data in $i{'filename'}.
Must be uuencoded data...~; exit } $imports = unpack ("u", $imports); # uudecode $imports = uncompress($imports); # uncompress unless(defined($imports)){ print qq~

$bq Invalid data in $i{'filename'}.
Must be zlib compressed data...~; exit } open(DAT,"> $df") or die "$!"; print DAT $imports; close(DAT) or die "$!"; print qq~

$bq $i{'filename'} imported and saved as $df

Sorted node list will read from this file until it's overwritten by 'refresh', 'detect change' or 'import'.

Return to
$eh~; } sub import_data { # menu my@dir; opendir THIS, "$temp" or die "$!"; while(defined ($_ = readdir(THIS))){ next unless $_ =~ m|reputer-(.*?)\.export|; push @dir, $_; } closedir THIS or die "$!"; @dir = sort { lc($a) cmp lc($b) } @dir; &begin_html(); print qq~

Import

Showing files named

reputer-username.export

in the temp dir ($temp).

Importing a file overwrites the
current data file ($df), and allows
viewing and sorting the imported nodes.


$eh~; exit } sub export_data { my($size1,$size2); open(DAT,"< $df") or die "$!"; local $/ = undef; my$exports = ; close(DAT) or die "$!"; $size1 = (-s($df)); $exports = compress($exports); # compress unless(defined($exports)){ print qq~

$bq zlib compression failed...~; exit } $exports = pack ("u", $exports); # uuencode $xusername =~ tr/ /+/; if($xusername=~/^([-\@\w.]+)$/){$xusername=$1} # untaint filename else{ die "Error! Can't use $xusername as part of the filename."} my$ef = $temp."reputer-$xusername.export"; unless($i{'e'} eq 'screen'){ open(DAT,"> $ef") or die "$!"; print DAT $exports; close(DAT) or die "$!"; $size2 = (-s($ef)); } if($i{'e'} eq 'screen'){ $size2 = length($exports); } my$fu = sprintf("%d",(($size2/$size1)*100)); $exports = encode_entities($exports); my$lines = $exports =~ tr/\n/\n/; $lines = ($lines/2); # testarea rows &begin_html(); print '

\n \n

Data exported~; unless($i{'e'} eq 'screen'){ print qq~ to $ef~; } print qq~
original $size1 bytes, exported $size2 bytes ($fu%)