many changes from Alpha #1

Merged
peteyboy merged 7 commits from uris into develop 2024-06-24 20:21:34 -04:00
Showing only changes of commit e957438be6 - Show all commits

343
connex.pl
View File

@ -1,32 +1,40 @@
#!/usr/bin/perl -w #!/usr/bin/perl -w
#connex.pl Nightfall Express (nex://) browser
#TODO: Some branding (status popup on load?, Connex menu item?), About dialog
#TODO: Help dialog
use strict; use strict;
use warnings; use warnings;
use strict; use strict;
use Curses::UI; use Curses::UI;
use Net::Telnet; use Net::Telnet;
use URI::Split; use URI::Split qw(uri_split uri_join);
use URI ();
my $HOST_DEFAULT = "nightfall.city"; my $HOST_DEFAULT = "nightfall.city";
my $PATHSPEC_DEFAULT = ''; my $PATHSPEC_DEFAULT = '';
my $PORT_DEFAULT = 1900; my $PORT_DEFAULT = 1900;
my $PROT_NEX = "nex://"; my $SCHEME_NEX = "nex";
my $home_default= $PROT_NEX . $HOST_DEFAULT; my $home_default= $SCHEME_NEX . $HOST_DEFAULT;
my $host = "nightfall.city"; my $host = "nightfall.city";
my $port = "1900"; my $port = "1900";
my $pathspec = ""; my $pathspec = "";
my $docname = ""; my $docname; # = "";
my $doctype = "txt"; my $doctype = "txt";
my $dot_ext = "."; my $dot_ext = ".";
my @history;
my $HOME_URL = uri_join($SCHEME_NEX,$HOST_DEFAULT);
my $full_url = $HOME_URL;
my @history;
my @page_links;
my $statusbar; my $statusbar;
my $navwindow;
my $win1; my $win1;
my $cui = new Curses::UI( -color_support => 1 ); my $cui = new Curses::UI( -color_support => 1 );
my $connect = new Net::Telnet (Timeout => 10, my $connect = new Net::Telnet (Timeout => 10,
@ -34,10 +42,11 @@ my $connect = new Net::Telnet (Timeout => 10,
my @menu = ( my @menu = (
{ -label => 'File', { -label => 'File',
-submenu => [ -submenu => [
{ -label => 'Go to Link ^G', -value => \&goto_link_dialog }, { -label => 'Go to Link ^G', -value => \&navigate_link_dialog },
{ -label => 'Change Site ^C', -value => \&goto_site_dialog }, { -label => 'Choose Link >', -value => \&goto_link_dialog },
{ -label => 'Back ^B', -value => \&goto_back }, { -label => 'Back ^B', -value => \&goto_back },
{ -label => 'History ^H', -value => "\&history_status_dialog" }, { -label => 'History ^H', -value => \&history_status_dialog },
{ -label => 'Page Links ^P', -value => \&page_links_dialog },
{ -label => 'Exit ^Q', -value => \&exit_dialog } { -label => 'Exit ^Q', -value => \&exit_dialog }
] ]
}, },
@ -47,8 +56,8 @@ my @menu = (
sub exit_dialog() sub exit_dialog()
{ {
my $return = $cui->dialog( my $return = $cui->dialog(
-message => "Really quit?", -title => "Quit Connex?",
-title => "Are you sure?", -message => "Are you sure?",
-buttons => ['yes', 'no'], -buttons => ['yes', 'no'],
); );
@ -56,60 +65,102 @@ sub exit_dialog()
exit(0) if $return; exit(0) if $return;
} }
sub goto_link_dialog()
sub links_dialog()
{ {
my $return = $cui->question(-question => "This is [$host/ $pathspec]. Enter destination link:", my $return = $cui->dialog(
-answer => $pathspec, -message => page_links_list(),
); -title => "Page Links",
navigate($return); -buttons => ['ok'],
);
} }
sub unsupported_dialog
sub goto_site_dialog()
{ {
my $scheme = shift;
my $return = $cui->dialog(
-message => "$scheme protocol not supported.",
-title => "Bad Navigation",
-buttons => ['ok'],
);
my $return = $cui->question(-question => "This is [$host/ $pathspec]. Visit site:", }
-answer => $host,
); sub navigate_link_dialog()
if ($return){ {
my $site = $return; my $return = $cui->question(-question => "This is [$full_url]. Enter destination link:",
if($site ne ''){ -answer => $full_url,
$host = $site; );
add_history($host); #if not user canceled then navigate
load($pathspec); if($return){
update_status_bar(); navigate($return);
} update_status_bar();
history_status_dialog();
} }
} }
sub goto_link_dialog()
{
my $return = $cui->question(-question => "Enter link #:",
);
#if not canceled, or too big or too small, goto link
if($return){
my $linkcount = scalar @page_links;
if($return <= $linkcount && $return >0){
goto_link($return);
update_status_bar();
}else{
#$browser->focus();
my $return1 = $cui->status("there is no link # " . $return);
}
#do nothing on cancel
}
}
sub goto_back() sub goto_back()
{ {
my $fetched = fetch_history(); my $fetched = fetch_history();
#if($fetched) { #if($fetched) {
$pathspec =$fetched; $full_url =$fetched;
load($pathspec); load($full_url,0); #don't move back to top
update_status_bar(); update_status_bar();
history_status_dialog(); history_status_dialog();
#} #}
} }
sub goto_link{
my $linknum = shift;
my $linkcount = scalar @page_links;
#my $element=$linknum -1; #offset for array element
#if ($element <= $#page_links){ #such a perlism, this is highest INDEX of array
if ($linknum <= $linkcount){ #such a perlism, this is highest INDEX of array
navigate($page_links[$linknum-1]); #offset from count to index
}else{
#my $browser = $win1->getobj("browser");
#$browser->focus();
my $return = $cui->status("no link # " . $linknum);
}
}
sub navigate{ sub navigate{
my $link = shift; my $link = shift;
#if ($link){ add_history($full_url); #add last link to history before going forward!
# if($link ne ''){ $full_url = $link;
add_history($pathspec); #add last link to history before going forward! load($full_url, 1); #new URL go to top of page
$pathspec = $link;
load($pathspec);
# }else {
# $pathspec = '';
# }
update_status_bar();
#}
} }
@ -118,7 +169,8 @@ sub update_status_bar
{ {
my $browser = $win1->getobj("browser"); my $browser = $win1->getobj("browser");
my $statusbar = $win1->getobj("status"); my $statusbar = $win1->getobj("status");
$statusbar->text("Current site: $host, current link: [$pathspec]"); #$full_url = construct_valid_url($SCHEME_NEX, $host, $pathspec, $docname);
$statusbar->text("$full_url" . " | Press '>' key to enter link #. ctl-g to enter nex URL. '<' to go back.");
$statusbar->draw(); $statusbar->draw();
$browser->focus(); $browser->focus();
@ -129,7 +181,6 @@ sub update_status_bar
sub add_history sub add_history
{ {
my $link = shift; my $link = shift;
print ("link $link");
push(@history, $link); push(@history, $link);
history_status_dialog(); history_status_dialog();
return; return;
@ -142,7 +193,7 @@ sub fetch_history
$latest = pop(@history); $latest = pop(@history);
return $latest; return $latest;
}else{ }else{
return($PATHSPEC_DEFAULT); return($HOME_URL);
} }
} }
@ -152,12 +203,43 @@ sub history_status_dialog
if(@history){ if(@history){
my $browser = $win1->getobj("browser"); my $browser = $win1->getobj("browser");
$browser->focus(); $browser->focus();
my $history_list = join(", ", @history); my $history_list = join("\n", @history);
my $return = $cui->status("$history_list"); my $return = $cui->status("history:\n$history_list");
} }
} }
sub page_links_dialog
{
if(@page_links){
my $browser = $win1->getobj("browser");
$browser->focus();
#my $link_list = join("\n", @page_links);
my $link_list = page_links_list();
my $return = $cui->status("links on this page:\n$link_list");
}
}
sub page_links_list
{
if(@page_links){
my $browser = $win1->getobj("browser");
$browser->focus();
#my $link_list = join("\n", @page_links);
my $link_list="";
my $link;
my $count=0;
foreach $link (@page_links){
$count+=1;
$link_list = $link_list . "[$count] $link\n";
}
return $link_list;
}
}
my $menu = $cui->add( my $menu = $cui->add(
'menu','Menubar', 'menu','Menubar',
-menu => \@menu, -menu => \@menu,
@ -173,6 +255,9 @@ $win1 = $cui->add(
-vscrollbar => 'right', -vscrollbar => 'right',
); );
my $texteditor = $win1->add("browser", "TextViewer", my $texteditor = $win1->add("browser", "TextViewer",
-text => "Start Page", -text => "Start Page",
-border => 1, -border => 1,
@ -195,7 +280,7 @@ $statusbar = $win1->add("status", "TextViewer",
-width => -1, -width => -1,
-reverse => 1, -reverse => 1,
-paddingspaces => 1, -paddingspaces => 1,
-text => "Current site: $HOST_DEFAULT, current link: [/]", -text => "$HOME_URL | Press '>' key to enter link #. ctl-g to enter nex URL. '<' to go back.",
); );
@ -204,78 +289,120 @@ $statusbar = $win1->add("status", "TextViewer",
#key bindings, should match menu items #key bindings, should match menu items
$cui->set_binding(sub {$menu->focus()}, "\cX"); $cui->set_binding(sub {$menu->focus()}, "\cX");
$cui->set_binding( \&exit_dialog , "\cQ"); $cui->set_binding( \&exit_dialog , "\cQ");
$cui->set_binding( \&goto_link_dialog , "\cG"); $cui->set_binding( \&navigate_link_dialog , "\cG");
$cui->set_binding( \&goto_back , "\cB"); $cui->set_binding( \&goto_back , "\cB");
$cui->set_binding( \&goto_site_dialog , "\cC"); $cui->set_binding( \&goto_back , "<");
$cui->set_binding( \&goto_link_dialog , ">");
$cui->set_binding(sub {
my $cui = shift;
$cui->layout;
$cui->draw;
}, "\cL");
# There is no need for the editor widget to loose focus, so
# the "loose-focus" binding is disabled here. This also enables the
# use of the "TAB" key in the editor, which is nice to have.
$texteditor->clear_binding('loose-focus');
#start up #start up
$texteditor->focus(); #$texteditor->focus();
navigate(''); navigate($HOME_URL);
$cui->mainloop(); $cui->mainloop();
#pick apart nex:// urls, which we should be using
#sub parse_url #need to pass in url; and host, pathspec, file variables to be filled
#{
# my $url = @_[0];
# my $host = url;
# host =~ s/^nex://([a-z0-9]*)\/[a-z0-9\/\.]*$/$1/;
# my $pathspec = url;
# pathspec =~ s/^nex://[a-z0-9]*(\/[a-z0-9\/]*)[[a-z0-9\.]*$)/$1/;
# my $file = $url
#
#}
#make nex:// urls from parts, relative urls #make nex:// urls from parts, relative urls
#sub construct_valid_url #protocol, host, pathspec sub construct_valid_url #scheme, host, pathspec, docname
#{ {
# my $protocol = shift; my $scheme = shift;
# my $host = shift; my $host = shift;
# my $pathspec = shift; my $pathspec = shift;
# my $file = shift; my $docname = shift;
# my $url = $protocol; if (defined($docname)){
#need error handling $pathspec= $pathspec . '/' . $docname; #this is just local pathspec
#what about the end slash and files vs index? }
# $url = $protocol . $host; my $url = uri_join($scheme, $host, $pathspec);
# if ($pathspec){ return $url;
# $url = $url . '/' . $pathspec; }
# if ($file){
# $url = $url . '.' $file;
# }
# }
# return $url;
#}
sub is_path_index{
my $path = shift;
my $result = 1;
if ($path !~ /\/$/ && $path =~ /\.[a-zA-Z]*$/){
$result =0;
}
return($result);
}
sub add_page_link{
my $linkline = shift;
my $base_url = shift;
my $uri_object;
#my $link= $linkline=~ s/^=>[ ]*(.*$)/$1/r;
local $URI::ABS_ALLOW_RELATIVE_SCHEME = 1;
local $URI::ABS_REMOTE_LEADING_DOTS = 1;
$uri_object=URI->new_abs($linkline=~ /^=>[ ]+([^ ]*)/,$base_url);
push(@page_links, $uri_object->as_string);
my $count = scalar @page_links; #scalar is size/count of links, but $#page_links is highest INDEX
return $linkline =~ s/(^=>.*$)/$1 [\>$count\]/r;
}
sub load sub load
{ {
my $pathspec = shift;
my @lines; my @lines;
my $ok; my $ok;
$connect->host($host); my $url = shift;
$connect->port($port); my $top = shift;
$ok= $connect->open($host); #my $scheme, $host, $path, $query, $frag;
$ok= $connect->print($pathspec); my ($scheme, $host, $path, $query, $frag) = uri_split($url);
@lines =$connect->getlines(ErrMode=> 'return'); #what happens with different scheme?
print $connect->eof(); if ($scheme eq $SCHEME_NEX){
#handle non-existant request? $connect->host($host);
die unless $connect->eof(); $connect->port($port);
$connect->close(); $ok= $connect->open($host);
my $widget= $texteditor; $ok= $connect->print($path);
my $loaded_text =""; @lines =$connect->getlines(ErrMode=> 'return');
my $currentline; print $connect->eof();
my $count=0; #handle non-existant request?
foreach $currentline (@lines){ die unless $connect->eof();
if ($currentline =~ m/^=>/){ $connect->close();
$count+=1; my $widget= $texteditor;
$currentline =~ s/(^=>.*$)/$1 [\>$count\]/;
} #loop through nex response and load into text editor. Identify, mark and store link lines for index pages
$loaded_text= $loaded_text . $currentline; #TODO: store link lines for index pages
} my $page_contents =""; #this is the page contents
$widget->text($loaded_text); my $currentline;
my $count=0;
my $is_index= is_path_index($path);
undef @page_links; #clear list
foreach $currentline (@lines){
if ($currentline =~ m/^=>/){
if ($is_index){
$currentline = add_page_link($currentline, $url);
}
}
$page_contents= $page_contents . $currentline;
}
$widget->text($page_contents);
$widget->draw();
if ($top){
$widget->pos(0);
}
}else{
#can't load non-nex as of now
my $browser = $win1->getobj("browser");
$browser->focus();
my $return = unsupported_dialog($scheme);
#pop and trash history
my $fetched = fetch_history();
}
} }