From 83f7b1dc2f27acced24cb99963b985c0b05d3f09 Mon Sep 17 00:00:00 2001 From: jake Date: Thu, 13 Jan 2022 01:32:55 -0500 Subject: Less basic client --- gmi.pl | 327 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 311 insertions(+), 16 deletions(-) diff --git a/gmi.pl b/gmi.pl index b16a178..3012dda 100755 --- a/gmi.pl +++ b/gmi.pl @@ -6,28 +6,323 @@ use strict; use warnings; use utf8; use bytes; +use feature qw(refaliasing); +no warnings qw(experimental::refaliasing); -our $VERSION = '0.0.1'; +our $VERSION = 'v0.0.9'; + +#TODO: back() only works once; should fix this # Modules -use IO::Socket::SSL; # CPAN +use IO::Socket::SSL; # CPAN use URL::XS qw(parse_url split_url_path parse_url_query); # CPAN +use Term::TUI qw(:all); # CPAN +use IO::Pager; # CPAN +require Text::Wrapper; # CPAN +use Term::ReadKey; # CPAN +use Term::ANSIColor; # Core +use Smart::Comments; # CPAN + +#my ($wchar) = GetTerminalSize(); +my $wrapper = Text::Wrapper->new(columns=>70, body_start=>''); +$ENV{pager} = 'less'; +my $use_pager = 1; +my $pager_text_wrap_auto = 1; +my $doc_out = 1; # display doc for human consumption? +my $doc; +my @links; +my $current_url = ""; +my @history; + +# The way Term::TUI handles the data makes it impossible +# to just give it a variable, but it does support stdin +my %modes = +(".HELP" => "Super basic gemini glient.\nVersion: $VERSION\n" . + "Type 'go' to enter 'go' mode. You can also: 'go url capsule.com' without being in 'go' mode.", + + "go" => {".HELP" => "going to browse", + + "url" => [ "Make a request to a URL\nThis will set the current working URL" . + "\nExample: [gemini://]capsule.com/", \&url ], + + "cwu" => ["Returns current working URL", \&cwu ], + + "links" => ["Current working URL's links", \&links ], + + "nav" => ["Follow a link.\n" . + "Sets current working URL.", \&nav, 0 ], + + "navh" => ["Follow a link from history.\n", \&nav, 1 ], + + "root" => ["Go to current working URL root\n" . + "E.G. gemini://capsule.com/blog/20220112.gmi -> gemini://capsule.com/", \&root ], + + "hist" => ["Returns history.", \&hist ], + + "back" => ["Go back to the previous URL (uses history)", \&back, 0 ], + "b" => ["Alias of `back'", \&back, 0 ], + + "backnodisplay" => ["Go back to the previous URL (uses history), ". + "but do not display the page.", \&back, 1 ], + "bd" => ["Alias of `backnodisplay'.", \&back, 1 ], + + "display" => ["Display the current working URL.", \&display] , + "d" => ["Alias of `display'", \&display ], + + }, + "cert" => {".HELP" => "Manage certs", + "aaa" => [ "This command returns `aaa'.", \&aaa ], + }, + "config" => {".HELP" => "Config settings to your liking.", + "usepager" => ["This toggles pager use.\n" . + "1 = use pager, 0 = stdout\n", \&toggle, 'pager'], + + "textwrap" => ["Input must be an interger or 'auto'. No\n". + "input returns the current text-wrap.", \&textwrap], + + "pager" => ["Set which pager to use.", \&pager], + + "save" => ["Save your settings (not implimented yet)", \&asdf], + } +); + +my $flag; +$flag=TUI_Run("gc",\%modes); +#print "*** ABORT ***\n" if ($flag); + +#TUI_Script(\%modes,"/config pager;"); + +sub url { + # gemini://website.com/request-path.gmi + my ($url) = @_; + if (!$url) { TUI_Out("Example: [gemini://]capsule.com/\n"); return 0;} + if ( $url !~ m|^.*://.*|) { + $url = "gemini://$url"; + } + ### $url + $url = parse_url($url); + + my $cl = IO::Socket::SSL->new( + PeerHost => "$url->{host}", + PeerPort => '1965', + + SSL_verify_mode => SSL_VERIFY_NONE, + # will update version when support is better or + # when gemini removes TLSv1_2 as a supported version + SSL_version => 'TLSv1_2', + + ); #or die "error=$!, ssl_error=$SSL_ERROR"; + + if ($cl) { + my $path; + if (! $url->{path}) { + $path = '' + } + else { + $path = "$url->{path}"; + } + + $current_url = "$url->{scheme}://$url->{host}/$path"; + + # ["absolute_url", "description"] + update_history( ["$url->{scheme}://$url->{host}/$path", "$url->{host}/$path"] ); + + # gemini spec: + # is an absolute path + print $cl "$url->{scheme}://$url->{host}/$path\r\n"; + + undef($doc); + + while (<$cl>) { + $doc .= $_; + } + + get_links($doc); + + if ($doc_out) { + display($doc); + } + } + else { + TUI_Out("error=$!, ssl_error=$SSL_ERROR\n"); + } +} + +sub get_links { + undef(@links); + my ($doc) = @_; + #map(push(@links, $_), $doc =~ m/^=>[\s]*([\w\-\\\/\.\:\~\?\=]+)[\s]*(.+)?$/gm); + for my $line (split('\n', $doc)) { + if ($line =~ m/^=>[\s]*([\w\d\-\\\/\.\:\~\?\=\#]+)[\s]*(.+)?$/gm) { + if ($2) { + push(@links, ["$1", "$2"]); + } + else { + push(@links, ["$1", "$1"]); + } + } + } + ## @links +} + +sub hist { + my $hist; + my $counter = 1; + for my $item (@history) { + $hist .= "[$counter] $$item[0] $$item[1]\n"; + #$hist .= "$$item[1][0]\n"; + $counter++; + } + if ($hist) { + TUI_Out($hist); + } + else { + TUI_Out("\n"); + } +} + +sub update_history { + my ($history) = @_; + push(@history, $history); +} + +sub links { + my $d; + my $counter = 1; + for my $item (@links) { + $d .= "[$counter] ". colored($$item[0], 'underline') . " $$item[1]\n"; + $counter++; + } + if ($d) { + TUI_Out($d); + } + else { + TUI_Out("No links.\n"); + } + 0; +} + +sub cwu { + TUI_Out("$current_url\n"); + 0; +} + +sub nav { + # Setting 0: from links + # Setting 1: from history + my ($setting,$n) = @_; + $n -= 1; + + ### $n + ### $setting + ### @_ + my $link; + + if ($setting == 0) { + $link = $links[$n][0]; + } elsif ($setting == 1) { + $link = $history[$n][0]; + } + + if (has_scheme($link)) { + url("$link"); + 0; + } + else { + url("$current_url$link"); + 0; + } +} + +sub has_scheme { + print ($_[0]); + return ($_[0] =~ m|^.*(://)|); +} + +sub root { + TUI_Out("Not implimented yet."); +} + +sub back { + my ($display) = @_; + + ### @_ + ### $display + # + my $dok_out = $doc_out; + + $doc_out = 0 if ($display == 1); + + url("$history[-2][0]"); + ### @history + + $doc_out = $dok_out if ($display == 1); +} + +sub aaa { + TUI_Out("aaa\n"); +} -# Global variables -# ARGV[0]: gemini://website.com/request-path.gmi -my $url = $ARGV[0]; -$url = parse_url($url); +sub display { + if ($pager_text_wrap_auto) { + my ($wc) = GetTerminalSize(); + $wrapper->columns($wc); + } + if ($use_pager) { + IO::Pager::open(my $FH) or warn($!); + print $FH $wrapper->wrap($doc); + } + else { + TUI_Out($wrapper->wrap($doc)); + } +} -my $cl = IO::Socket::SSL->new( - PeerHost => "$url->{host}", - PeerPort => '1965', +sub toggle { + my ($t) = @_; + if ($t eq 'pager') { + set_toggle($use_pager); + print "$use_pager\n"; + } +} - SSL_verify_mode => SSL_VERIFY_NONE, - # will update version when support is better or - # when gemini removes TLSv1_2 as a supported version - SSL_version => 'TLSv1_2', +sub set_toggle { + # refaliasing + \my $t = \$_[0]; + if ($t == 1) { + $t = 0; + } + else { + $t = 1; + } +} -) or die "error=$!, ssl_error=$SSL_ERROR"; +sub textwrap { + my ($c) = @_; + if ($c and $c =~ m/^\d+$/) { + $wrapper->columns($c); + #$wchar = $c; + $pager_text_wrap_auto = 0; + } elsif ($c and $c eq 'auto') { + $pager_text_wrap_auto = 1; + } + else { + if ($pager_text_wrap_auto) { + my ($c) = GetTerminalSize(); + TUI_Out("[AUTO] $c\n"); + } + else { + TUI_Out("$wrapper->{columns}\n"); + } + } +} -print $cl "$url->{scheme}://$url->{host}/$url->{path}\r\n"; -print <$cl>; +sub pager { + my ($p) = @_; + if ($p) { + $ENV{pager} = $p; + 0; + } + else { + TUI_Out("$ENV{pager}\n"); + } +} -- cgit v1.2.3