package Devscripts::Uscan::ftp;
use strict;
use Cwd qw/abs_path/;
use Devscripts::Uscan::Output;
use Devscripts::Uscan::Utils;
use Devscripts::Uscan::_xtp;
use Moo::Role;
#######################################################################
# search $newfile $newversion (ftp mode)
#######################################################################
sub ftp_search {
my ($self) = @_;
# FTP site
uscan_verbose "Requesting URL:\n $self->{parse_result}->{base}";
my $request = HTTP::Request->new('GET', $self->parse_result->{base});
my $response = $self->downloader->user_agent->request($request);
if (!$response->is_success) {
uscan_warn
"In watch file $self->{watchfile}, reading FTP directory\n $self->{parse_result}->{base} failed: "
. $response->status_line . "";
return undef;
}
my $content = $response->content;
uscan_extra_debug
"received content:\n$content\n[End of received content] by FTP";
# FTP directory listings either look like:
# info info ... info filename [ -> linkname]
# or they're HTMLised (if they've been through an HTTP proxy)
# so we may have to look for type patterns
uscan_verbose "matching pattern $self->{parse_result}->{pattern}";
my (@files);
# We separate out HTMLised listings from standard listings, so
# that we can target our search correctly
if ($content =~ /<\s*a\s+[^>]*href/i) {
uscan_verbose "HTMLized FTP listing by the HTTP proxy";
while ($content
=~ m/(?:<\s*a\s+[^>]*href\s*=\s*\")((?-i)$self->{parse_result}->{pattern})\"/gi
) {
my $file = fix_href($1);
my $mangled_version
= join(".", $file =~ m/^$self->{parse_result}->{pattern}$/);
if (
mangle(
$self->watchfile, \$self->line,
'uversionmangle:', \@{ $self->uversionmangle },
\$mangled_version
)
) {
return undef;
}
my $match = '';
if (defined $self->shared->{download_version}
and not $self->versionmode eq 'ignore') {
if ($mangled_version eq $self->shared->{download_version}) {
$match = "matched with the download version";
}
}
my $priority = $mangled_version . '-' . get_priority($file);
push @files, [$priority, $mangled_version, $file, $match];
}
} else {
uscan_verbose "Standard FTP listing.";
# they all look like:
# info info ... info filename [ -> linkname]
for my $ln (split(/\n/, $content)) {
$ln =~ s/^d.*$//; # FTP listing of directory, '' skipped
$ln =~ s/\s+->\s+\S+$//; # FTP listing for link destination
$ln =~ s/^.*\s(\S+)$/$1/; # filename only
if ($ln and $ln =~ m/^($self->{parse_result}->{filepattern})$/) {
my $file = $1;
my $mangled_version = join(".",
$file =~ m/^$self->{parse_result}->{filepattern}$/);
if (
mangle(
$self->watchfile, \$self->line,
'uversionmangle:', \@{ $self->uversionmangle },
\$mangled_version
)
) {
return undef;
}
my $match = '';
if (defined $self->shared->{download_version}) {
if ($mangled_version eq $self->shared->{download_version})
{
$match = "matched with the download version";
}
}
my $priority = $mangled_version . '-' . get_priority($file);
push @files, [$priority, $mangled_version, $file, $match];
}
}
}
if (@files) {
@files = Devscripts::Versort::versort(@files);
my $msg
= "Found the following matching files on the web page (newest first):\n";
foreach my $file (@files) {
$msg .= " $$file[2] ($$file[1]) index=$$file[0] $$file[3]\n";
}
uscan_verbose $msg;
}
my ($newversion, $newfile);
if (defined $self->shared->{download_version}) {
# extract ones which has $match in the above loop defined
my @vfiles = grep { $$_[3] } @files;
if (@vfiles) {
(undef, $newversion, $newfile, undef) = @{ $vfiles[0] };
} else {
uscan_warn
"In $self->{watchfile} no matching files for version $self->{shared}->{download_version}"
. " in watch line\n $self->{line}";
return undef;
}
} else {
if (@files) {
(undef, $newversion, $newfile, undef) = @{ $files[0] };
} else {
uscan_warn
"In $self->{watchfile} no matching files for watch line\n $self->{line}";
return undef;
}
}
return ($newversion, $newfile);
}
sub ftp_upstream_url {
my ($self) = @_;
return $self->parse_result->{base} . $self->search_result->{newfile};
}
*ftp_newfile_base = \&Devscripts::Uscan::_xtp::_xtp_newfile_base;
sub ftp_newdir {
my ($line, $site, $dir, $pattern, $dirversionmangle, $watchfile,
$lineptr, $download_version)
= @_;
my $downloader = $line->downloader;
my ($request, $response, $newdir);
my ($download_version_short1, $download_version_short2,
$download_version_short3)
= partial_version($download_version);
my $base = $site . $dir;
$request = HTTP::Request->new('GET', $base);
$response = $downloader->user_agent->request($request);
if (!$response->is_success) {
uscan_warn
"In watch file $watchfile, reading webpage\n $base failed: "
. $response->status_line;
return '';
}
my $content = $response->content;
uscan_extra_debug
"received content:\n$content\n[End of received content] by FTP";
# FTP directory listings either look like:
# info info ... info filename [ -> linkname]
# or they're HTMLised (if they've been through an HTTP proxy)
# so we may have to look for type patterns
uscan_verbose "matching pattern $pattern";
my (@dirs);
my $match = '';
# We separate out HTMLised listings from standard listings, so
# that we can target our search correctly
if ($content =~ /<\s*a\s+[^>]*href/i) {
uscan_verbose "HTMLized FTP listing by the HTTP proxy";
while (
$content =~ m/(?:<\s*a\s+[^>]*href\s*=\s*\")((?-i)$pattern)\"/gi) {
my $dir = $1;
uscan_verbose "Matching target for dirversionmangle: $dir";
my $mangled_version = join(".", $dir =~ m/^$pattern$/);
if (
mangle(
$watchfile, $lineptr,
'dirversionmangle:', \@{$dirversionmangle},
\$mangled_version
)
) {
return 1;
}
$match = '';
if (defined $download_version
and $mangled_version eq $download_version) {
$match = "matched with the download version";
}
if (defined $download_version_short3
and $mangled_version eq $download_version_short3) {
$match = "matched with the download version (partial 3)";
}
if (defined $download_version_short2
and $mangled_version eq $download_version_short2) {
$match = "matched with the download version (partial 2)";
}
if (defined $download_version_short1
and $mangled_version eq $download_version_short1) {
$match = "matched with the download version (partial 1)";
}
push @dirs, [$mangled_version, $dir, $match];
}
} else {
# they all look like:
# info info ... info filename [ -> linkname]
uscan_verbose "Standard FTP listing.";
foreach my $ln (split(/\n/, $content)) {
$ln =~ s/^-.*$//; # FTP listing of file, '' skipped
$ln =~ s/\s+->\s+\S+$//; # FTP listing for link destination
$ln =~ s/^.*\s(\S+)$/$1/; # filename only
if ($ln =~ m/^($pattern)(\s+->\s+\S+)?$/) {
my $dir = $1;
uscan_verbose "Matching target for dirversionmangle: $dir";
my $mangled_version = join(".", $dir =~ m/^$pattern$/);
if (
mangle(
$watchfile, $lineptr,
'dirversionmangle:', \@{$dirversionmangle},
\$mangled_version
)
) {
return 1;
}
$match = '';
if (defined $download_version
and $mangled_version eq $download_version) {
$match = "matched with the download version";
}
if (defined $download_version_short3
and $mangled_version eq $download_version_short3) {
$match = "matched with the download version (partial 3)";
}
if (defined $download_version_short2
and $mangled_version eq $download_version_short2) {
$match = "matched with the download version (partial 2)";
}
if (defined $download_version_short1
and $mangled_version eq $download_version_short1) {
$match = "matched with the download version (partial 1)";
}
push @dirs, [$mangled_version, $dir, $match];
}
}
}
# extract ones which has $match in the above loop defined
my @vdirs = grep { $$_[2] } @dirs;
if (@vdirs) {
@vdirs = Devscripts::Versort::upstream_versort(@vdirs);
$newdir = $vdirs[0][1];
}
if (@dirs) {
@dirs = Devscripts::Versort::upstream_versort(@dirs);
my $msg
= "Found the following matching FTP directories (newest first):\n";
foreach my $dir (@dirs) {
$msg .= " $$dir[1] ($$dir[0]) $$dir[2]\n";
}
uscan_verbose $msg;
$newdir //= $dirs[0][1];
} else {
uscan_warn
"In $watchfile no matching dirs for pattern\n $base$pattern";
$newdir = '';
}
return $newdir;
}
# Nothing to clean here
sub ftp_clean { 0 }
1;