6 use File
::Temp qw
/ tempfile tempdir /;
19 if ($ARGV[0] =~ /^-/) {
20 if ($ARGV[0] eq '-o') {
28 my ($host, $port, $selector) = ng_parse_uri
($ARGV[$argo]);
31 my $shortname = fileparse
($selector);
32 download_aux
($host, $port, $selector, $shortname);
33 print "Saved (?) file $shortname\n";
37 my $cui = create_ui
();
44 sub ngo_next_selector
()
46 my $last_id = length(@history) - 1;
47 my $last = $history[ $last_id ];
49 ng_advance
($item{'host'}, $item{'port'}, $item{'selector'}, $item{'data'});
51 sub ngo_queue_selector
53 my ($host, $port, $selector, $post) = @_;
55 'uri' => 'gopher://'.$host.':'.$port.'/'.$selector,
56 'selector' => $selector,
65 my $cui = new Curses
::UI
( -color_support
=> 1 );
70 { -label
=> 'Go To... g', -value
=> \
&goto_dialog
},
71 { -label
=> 'Exit ^C', -value
=> \
&exit_dialog
},
76 { -label
=> 'Download... d', -value
=> \
&download_dialog
},
77 { -label
=> 'Follow f', -value
=> \
&follow_cb
},
78 #{ -label => 'Go Back b', -value => 0 },
89 $cui->set_binding(sub {$menu->focus}, "\cX");
90 $cui->set_binding(sub {$cui->layout}, "\cR");
91 $cui->set_binding( \
&exit_dialog
, "\cC");
92 $cui->set_binding( \
&exit_dialog
, "q");
93 $cui->set_binding( \
&goto_dialog
, "g");
94 $cui->set_binding( \
&follow_cb
, "f");
95 $cui->set_binding( \
&download_dialog
, "d");
105 my $win2 = $cui->add(
113 my $statusbar = $win2->add(
117 -text
=> 'Ready. Use ^X to access Menu.',
129 my $win = $cui->getobj('win1');
131 #my $curlen = $label->width - length($_[0]) - 2;
132 #if ($curlen < 0) { $curlen = 0; }
133 #$label->text($_[0].''.sprintf('%'.$curlen.'s', ''));
139 my $win = $cui->getobj('win2');
140 my $label = $win->getobj('label');
141 my $curlen = $label->width - length($_[0]) - 2;
142 if ($curlen < 0) { $curlen = 0; }
143 $label->text($_[0].''.sprintf('%'.$curlen.'s', ''));
145 #$label->intellidraw;
150 my $return = $cui->dialog(
151 -message
=> "Do you really want to quit?",
153 -buttons
=> ['yes', 'no'],
160 my $return = $cui->question(
161 -question
=> "'New Gopher' URI:",
162 -answer
=> $host.':'.$port.'/'.$selector,
163 #-title => "Are you sure???",
165 my ($host, $port, $selector) = ng_parse_uri
($return);
167 ng_advance
($host, $port, $selector);
168 #ngo_queue_selector($host, $port, $selector);
169 #$cui->schedule_event( \&ngo_next_selector );
175 my ($host, $port, $selector, $post) = @_;
177 statusbar
("Getting $host:$port/$selector");
179 my $resp = gopher_grab
($host, $port, $selector, $post);
181 if (!$resp) { return; }
183 my ($size, $mimetype, $data) = ng_parse_response
($resp);
186 statusbar
("$selector [$mimetype] $size b");
188 if ($mimetype eq 'text/x-menu')
191 gophmenu_dialog
($size, $mimetype, $data);
193 elsif ($mimetype eq 'application/x-interactive')
195 handle_interactive
($host, $port, $selector, $data);
197 elsif ($mimetype =~ /^text\//)
199 if (!$data) { $data = '<no data>'; }
200 my $title = $selector;
201 $title =~ s/\t.*//; # hide metadata
202 $cui->dialog(-message
=> $data, -title
=> $title, -bfg
=> "red");
206 $cui->dialog('File type ['.$mimetype.'] size '.$size.' should be downloaded'."\n".substr($data, 0, 1024));
209 statusbar
("$selector [$mimetype] $size b");
213 sub gophmenu_dialog
{
214 my ($size, $type, $data) = @_;
216 my @menu = ng_parse_menu
($data, $host, $port);
219 my (@values, %labels, $i);
224 $labels{$i} = gophmenu_pretty
($item{'type'}, $item{'name'}, $item{'selector'});
228 my $win = $cui->getobj("win1");
229 my $lb = $win->getobj("mylistbox");
231 $lb->values( \
@values );
232 $lb->labels( \
%labels );
233 $lb->userdata( \
@menu );
237 my $listbox = $win->add(
238 'mylistbox', 'Listbox',
242 -onchange
=> \
&gophmenu_select
,
243 -onselchange
=> \
&gophmenu_hover
,
251 my @udata = @
{$listbox->userdata()};
252 my %item = %{$udata[ $listbox->get_active_id() ]};
258 my %item = gophmenu_getitem
@_;
260 statusbar
($item{'host'}.':'.$item{'port'}.'/'.$item{'selector'});
266 my %item = gophmenu_getitem
$listbox;
268 $listbox->clear_selection();
270 ng_advance
($item{'host'}, $item{'port'}, $item{'selector'});
271 #ngo_queue_selector($item{'host'}, $item{'port'}, $item{'selector'});
272 #$cui->schedule_event( \&ngo_next_selector );
276 my $list = $cui->getobj("win1")->getobj("mylistbox");
277 gophmenu_select
($list);
280 sub download_dialog
() {
281 my $list = $cui->getobj("win1")->getobj("mylistbox");
282 my %item = gophmenu_getitem
$list;
284 if ($item{'type'} ne 'b') {
285 statusbar
("Can't download non-binary selector ".$item{'selector'});
289 my $shortname = fileparse
($item{'selector'});
290 my $file = $cui->savefilebrowser(-file
=> $shortname);
292 download_aux
($item{'host'}, $item{'port'}, $item{'selector'}, $file);
294 statusbar
("Saved file ".$file);
299 my ($type, $name, $selector) = @_;
301 return sprintf(" -- %s", $name);
303 return sprintf("[%-4s] %s", $type, $name);
307 my ($host, $port, $selector, $post) = @_;
309 my $sock = new IO
::Socket
::INET
(PeerAddr
=> $host, PeerPort
=> $port, Proto
=> 'tcp', );
310 if (!$sock) { $cui->dialog(-message
=>"Can't connect to $host : $port", -title
=> "Error", -fg
=> "blue"); return ""; }
311 #return "Could not create socket: $!\n" unless $sock;
312 print $sock $selector."\r\n";
314 print $sock length($post) . "\t\r\n";
319 #my ($size, $mimetype) = split /\t/, $header;
325 # $cui->dialog("GOT:\n".$data);
329 sub handle_interactive
() {
331 my ($host, $port, $selector, $data) = @_;
332 my ($long_target, $rest) = split /\n/, $data, 2;
333 my $target = substr $long_target, 1;
336 my ($fh, $filename) = tempfile
();
340 my $sb = stat($filename);
341 my $mtime = $sb->mtime;
344 system('$EDITOR '.$filename);
347 my $sb = stat($filename);
348 if ($mtime != $sb->mtime) {
349 my $fh; open $fh, $filename;
352 while (<$fh>) { $buf .= $_; }
355 ng_advance
($host, $port, $target, $buf);
356 #ngo_queue_selector($host, $port, $target, $buf);
357 #$cui->schedule_event( \&ngo_next_selector );
359 statusbar
("Interactive input aborted");
368 print " ./ngo [OPTIONS] HOST[:PORT][/SELECTOR] \n";
369 print " Options: \n";
370 print " -o Download file in non-interactive mode.\n";
371 #print " -p Post a Form file FILE.\n";
375 my ($host, $port, $selector, $filename) = @_;
377 my $resp = gopher_grab
($host, $port, $selector);
378 if (!$resp) { return; }
380 my ($size, $mimetype, $data) = ng_parse_response
($resp);
382 open my $fh, '>'.$filename;