From ee8eec119f224725ab5022240ebd21407a86aa21 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Tue, 21 Jul 2020 21:25:04 -0700 Subject: mailscripts.el: drop hard dep on Projectile, add project.el support Signed-off-by: Sean Whitton --- debian/changelog | 11 +++++++++++ mailscripts.el | 59 +++++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 59 insertions(+), 11 deletions(-) diff --git a/debian/changelog b/debian/changelog index c467894..294857a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,14 @@ +mailscripts (0.22-1) UNRELEASED; urgency=medium + + * mailscripts.el: + - drop hard dependency on Projectile + - add new defcustom, mailscripts-project-library + - replace *-projectile commands with new *-to-project commands, which + support both Projectile and project.el for choosing from known + projects. + + -- Sean Whitton Tue, 21 Jul 2020 21:22:39 -0700 + mailscripts (0.21-1) unstable; urgency=medium * mailscripts.el: diff --git a/mailscripts.el b/mailscripts.el index 50e3b89..d31223a 100644 --- a/mailscripts.el +++ b/mailscripts.el @@ -2,7 +2,7 @@ ;; Author: Sean Whitton ;; Version: 0.21 -;; Package-Requires: (notmuch projectile) +;; Package-Requires: (notmuch) ;; Copyright (C) 2018, 2019, 2020 Sean Whitton @@ -22,7 +22,6 @@ ;;; Code: (require 'notmuch) -(require 'projectile) (require 'thingatpt) (defgroup mailscripts nil @@ -46,6 +45,23 @@ Note that this does not prevent the creation of new branches." :type 'boolean :group 'mailscripts) +(defcustom mailscripts-project-library 'projectile + "Which project management library to use to choose from known projects. + +Some mailscripts functions allow selecting the repository to +which patches will be applied from the list of projects already +known to Emacs. There is more than one popular library for +maintaining a list of known projects, however, so this variable +must be set to the one you use. + +Once there is a more fully-featured version of project.el +included in the latest stable release of GNU Emacs, the default +value of this variable may change, so if you wish to continue +using Projectile, you should explicitly customize this." + :type '(choice (const :tag "project.el" project) + (const :tag "Projectile" projectile)) + :group 'mailscripts) + ;;;###autoload (defun notmuch-slurp-debbug (bug &optional no-open) "Slurp Debian bug with bug number BUG and open the thread in notmuch. @@ -123,10 +139,16 @@ threads to the notmuch-extract-patch(1) command." "*notmuch-apply-thread-series*"))) ;;;###autoload -(defun notmuch-extract-thread-patches-projectile () - "Like `notmuch-extract-thread-patches', but use projectile to choose the repo." +(define-obsolete-function-alias + 'notmuch-extract-thread-patches-projectile + 'notmuch-extract-thread-patches-to-project + "mailscripts 0.22") + +;;;###autoload +(defun notmuch-extract-thread-patches-to-project () + "Like `notmuch-extract-thread-patches', but choose repo from known projects." (interactive) - (mailscripts--projectile-repo-and-branch + (mailscripts--project-repo-and-branch 'notmuch-extract-thread-patches (when current-prefix-arg (prefix-numeric-value current-prefix-arg)))) @@ -157,10 +179,16 @@ git-format-patch(1)." mm-handle)))) ;;;###autoload -(defun notmuch-extract-message-patches-projectile () - "Like `notmuch-extract-message-patches', but use projectile to choose the repo." +(define-obsolete-function-alias + 'notmuch-extract-message-patches-projectile + 'notmuch-extract-message-patches-to-project + "mailscripts 0.22") + +;;;###autoload +(defun notmuch-extract-message-patches-to-project () + "Like `notmuch-extract-message-patches', but choose repo from known projects." (interactive) - (mailscripts--projectile-repo-and-branch 'notmuch-extract-message-patches)) + (mailscripts--project-repo-and-branch 'notmuch-extract-message-patches)) (defun mailscripts--check-out-branch (branch) (if (string= branch "") @@ -173,9 +201,18 @@ git-format-patch(1)." (concat mailscripts-extract-patches-branch-prefix branch) branch)))))) -(defun mailscripts--projectile-repo-and-branch (f &rest args) - (let ((repo (projectile-completing-read - "Select projectile project: " projectile-known-projects)) +(defun mailscripts--project-repo-and-branch (f &rest args) + (let ((repo (case mailscripts-project-library + ('project + (require 'project) + (project-prompt-project-dir)) + ('projectile + (require 'projectile) + (projectile-completing-read + "Select Projectile project: " projectile-known-projects)) + (nil + (user-error + "Please customize variable `mailscripts-project-library'.")))) (branch (completing-read "Branch name (or leave blank to apply to current HEAD): " nil))) -- cgit v1.2.3 From bcae92b442ab909e633a838d5f83bcf8185b2784 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Wed, 22 Jul 2020 07:17:09 -0700 Subject: don't call completing-read when there are no completions Signed-off-by: Sean Whitton --- mailscripts.el | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mailscripts.el b/mailscripts.el index d31223a..703f86e 100644 --- a/mailscripts.el +++ b/mailscripts.el @@ -213,9 +213,8 @@ git-format-patch(1)." (nil (user-error "Please customize variable `mailscripts-project-library'.")))) - (branch (completing-read - "Branch name (or leave blank to apply to current HEAD): " - nil))) + (branch (read-from-minibuffer + "Branch name (or leave blank to apply to current HEAD): "))) (apply f repo branch args))) (provide 'mailscripts) -- cgit v1.2.3 From d402aaa1e1a507e6145ef9c1a7c1957496e3cdc3 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Tue, 19 Jan 2021 16:13:00 -0700 Subject: Use 'cl-case' not 'case' and require cl-lib Signed-off-by: Sean Whitton --- debian/changelog | 3 ++- mailscripts.el | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 294857a..050458b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -5,7 +5,8 @@ mailscripts (0.22-1) UNRELEASED; urgency=medium - add new defcustom, mailscripts-project-library - replace *-projectile commands with new *-to-project commands, which support both Projectile and project.el for choosing from known - projects. + projects + - Use 'cl-case' not 'case' and require cl-lib. -- Sean Whitton Tue, 21 Jul 2020 21:22:39 -0700 diff --git a/mailscripts.el b/mailscripts.el index 703f86e..aafcf15 100644 --- a/mailscripts.el +++ b/mailscripts.el @@ -21,6 +21,7 @@ ;;; Code: +(require 'cl-lib) (require 'notmuch) (require 'thingatpt) @@ -202,7 +203,7 @@ git-format-patch(1)." branch)))))) (defun mailscripts--project-repo-and-branch (f &rest args) - (let ((repo (case mailscripts-project-library + (let ((repo (cl-case mailscripts-project-library ('project (require 'project) (project-prompt-project-dir)) -- cgit v1.2.3 From 5793c537ec8897ae84b9c9e9c733a47042388225 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Tue, 19 Jan 2021 16:14:51 -0700 Subject: release mailscripts 0.22 (-1 to Debian unstable) Signed-off-by: Sean Whitton --- debian/changelog | 4 ++-- mailscripts.el | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 050458b..5767aa8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -mailscripts (0.22-1) UNRELEASED; urgency=medium +mailscripts (0.22-1) unstable; urgency=medium * mailscripts.el: - drop hard dependency on Projectile @@ -8,7 +8,7 @@ mailscripts (0.22-1) UNRELEASED; urgency=medium projects - Use 'cl-case' not 'case' and require cl-lib. - -- Sean Whitton Tue, 21 Jul 2020 21:22:39 -0700 + -- Sean Whitton Tue, 19 Jan 2021 16:14:45 -0700 mailscripts (0.21-1) unstable; urgency=medium diff --git a/mailscripts.el b/mailscripts.el index aafcf15..08947b5 100644 --- a/mailscripts.el +++ b/mailscripts.el @@ -1,7 +1,7 @@ ;;; mailscripts.el --- functions to access tools in the mailscripts package ;; Author: Sean Whitton -;; Version: 0.21 +;; Version: 0.22 ;; Package-Requires: (notmuch) ;; Copyright (C) 2018, 2019, 2020 Sean Whitton -- cgit v1.2.3 From bd274a20b46202f3a7d53a51a117cfd4110c3a67 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sat, 23 Jan 2021 17:18:10 -0700 Subject: new script: gmi2email Signed-off-by: Sean Whitton --- Makefile | 3 +- debian/changelog | 9 ++ debian/control | 8 ++ debian/copyright | 2 +- debian/mailscripts.install | 1 + debian/mailscripts.manpages | 1 + gmi2email | 272 ++++++++++++++++++++++++++++++++++++++++++++ gmi2email.1.pod | 81 +++++++++++++ mailscripts.el | 2 +- 9 files changed, 376 insertions(+), 3 deletions(-) create mode 100755 gmi2email create mode 100644 gmi2email.1.pod diff --git a/Makefile b/Makefile index e2ae233..6f52483 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,8 @@ MANPAGES=mdmv.1 mbox2maildir.1 \ imap-dl.1 \ email-extract-openpgp-certs.1 \ email-print-mime-structure.1 \ - notmuch-import-patch.1 + notmuch-import-patch.1 \ + gmi2email.1 COMPLETIONS=completions/bash/email-print-mime-structure completions/bash/imap-dl all: $(MANPAGES) $(COMPLETIONS) diff --git a/debian/changelog b/debian/changelog index 5767aa8..bbb3bf5 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +mailscripts (0.23-1) UNRELEASED; urgency=medium + + * New script: gmi2email + - add libdbd-sqlite3-perl, libio-socket-ssl-perl, libmime-lite-perl, + libemail-date-format-perl, libtry-tiny-perl and libmailtools-perl to + Recommends. + + -- Sean Whitton Sat, 23 Jan 2021 16:36:25 -0700 + mailscripts (0.22-1) unstable; urgency=medium * mailscripts.el: diff --git a/debian/control b/debian/control index 3a549a3..a47be4c 100644 --- a/debian/control +++ b/debian/control @@ -51,6 +51,12 @@ Recommends: devscripts, git, libgit-wrapper-perl, + libdbd-sqlite3-perl, + libio-socket-ssl-perl, + libmime-lite-perl, + libemail-date-format-perl, + libtry-tiny-perl, + libmailtools-perl, notmuch, python3-argcomplete, python3-gssapi, @@ -85,3 +91,5 @@ Description: collection of scripts for manipulating e-mail on Debian email-extract-openpgp-certs -- extract OpenPGP certificates from a message . imap-dl -- download messages from an IMAP mailbox to a maildir + . + gmi2email -- subscribe to gemlogs and read individual Gemini pages by e-mail diff --git a/debian/copyright b/debian/copyright index db97f3d..1d246a9 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,7 +1,7 @@ mailscripts Collection of scripts for manipulating e-mail on Debian -Copyright (C)2017-2020 Sean Whitton +Copyright (C)2017-2021 Sean Whitton Copyright (C)2019-2020 Daniel Kahn Gillmor Copyright (C)2020 Red Hat, Inc. diff --git a/debian/mailscripts.install b/debian/mailscripts.install index df220b3..53665b3 100644 --- a/debian/mailscripts.install +++ b/debian/mailscripts.install @@ -8,3 +8,4 @@ mbox-extract-patch /usr/bin notmuch-extract-patch /usr/bin notmuch-import-patch /usr/bin notmuch-slurp-debbug /usr/bin +gmi2email /usr/bin diff --git a/debian/mailscripts.manpages b/debian/mailscripts.manpages index 345053a..d704a87 100644 --- a/debian/mailscripts.manpages +++ b/debian/mailscripts.manpages @@ -8,3 +8,4 @@ mbox-extract-patch.1 notmuch-extract-patch.1 notmuch-import-patch.1 notmuch-slurp-debbug.1 +gmi2email.1 diff --git a/gmi2email b/gmi2email new file mode 100755 index 0000000..c85728b --- /dev/null +++ b/gmi2email @@ -0,0 +1,272 @@ +#!/usr/bin/perl + +# gmi2email -- subscribe to gemlogs and read individual Gemini pages by e-mail + +# Copyright (C) 2021 Sean Whitton +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or (at +# your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +use 5.028; +use strict; +use warnings; + +use DBI; +use File::Spec::Functions "catfile"; +use IO::Socket::SSL; +use MIME::Lite; +use Config::Tiny; +use Text::Wrap; +use Try::Tiny; +use Getopt::Long; +use Email::Date::Format "email_date"; +use Time::Local; +use Mail::Field::AddrList; + +my ($from, $to, $do_subs, $inline_images); +GetOptions + "from=s" => \$from, + "to=s" => \$to, + "subscriptions!" => \$do_subs, + "inline-images!" => \$inline_images; + +my $conf_r = $ENV{XDG_CONFIG_HOME} || catfile $ENV{HOME}, ".config"; +my $conf_f = catfile $conf_r, "mailscripts", "gmi2email.config"; +-e $conf_f + or (defined $to and defined $from) + or die + "no config file or sufficient command line options: don't know who to mail"; +my $conf = Config::Tiny->new->read($conf_f); + +my %to_mail_opts = ( + from => ( + $from + or $conf->{_}->{from} + or die "no From: address set in config or on command line" + ), + to => ( + $to + or $conf->{_}->{to} + or die "no To: address set in config or on command line" + ), + inline_images => $inline_images // $conf->{_}->{inline_images} // 0 +); + +@ARGV or $do_subs or die "nothing to do\n"; + +for (@ARGV) { + my $data; + if (-f) { + open my $fh, "<", $_; + $data = [<$fh>]; + } else { + my $type; + ($type, $data) = gemini_fetch($_, abs_links => 1); + $type =~ m{^text/gemini} or die "$_ is not gemtext"; + } + gemtext_to_mail($data, %to_mail_opts)->send; +} + +exit unless $do_subs; + +my $subs_f = catfile $conf_r, "mailscripts", "gmi2email.subscriptions"; +-e $subs_f or die "no list of subscriptions"; +open my $subs_fh, "<", $subs_f; + +my $db_r = $ENV{XDG_CACHE_HOME} || catfile $ENV{HOME}, ".cache"; +my $db_d = catfile $db_r, "mailscripts"; +-d $db_d or mkdir $db_d; +my $db_f = catfile $db_d, "gmi2email.db"; +my $dbh = DBI->connect("dbi:SQLite:dbname=$db_f", "", ""); +$dbh->do("CREATE TABLE IF NOT EXISTS seen (uri TEXT PRIMARY KEY)") + or die "failed to initialise database"; + +foreach my $sub (<$subs_fh>) { + chomp $sub; + my ($gemlog, $type, $data); + #<<< + try { + ($type, $data) = gemini_fetch($sub, abs_links => 1); + } catch { + my ($code) = /"gemini error: ([1-6])/; + if ($code == 4) { + warn "temporary failure retrieving $sub"; + next; # try again next run + } else { + die "while retrieving $sub $_"; + } + }; + #>>> + $type =~ m{^text/gemini} or die "$sub is not gemtext"; + for (@$data) { + if (/^#\s*/ and not $gemlog) { + chomp($gemlog = $'); + } elsif (my ($uri, $y, $m, $d, $title) + = /^=>\s*(\S+)\s+([0-9]{4})-([0-9]{2})-([0-9]{2})[\s-]*(.*)/) { + my ($rows) + = $dbh->selectrow_array( + "SELECT COUNT(*) FROM seen WHERE uri = \"$uri\""); + if ($rows == 0) { + my $mail = 1; + my ($type, $data); + #<<< + try { + ($type, $data) = gemini_fetch($uri, abs_links => 1); + } catch { + warn "when fetching $uri, $_"; + my ($code) = /"gemini error: ([1-6])/; + if ($code == 4) { + next; # try again next run + } else { + $mail = 0; # don't try this one again + } + }; + #>>> + $dbh->do("INSERT INTO seen VALUES (\"$uri\")"); + $mail or next; + if ($type =~ m{^text/gemini}) { + gemtext_to_mail( + $data, %to_mail_opts, + gemlog => $gemlog // "unknown gemlog", + link_title => $title, + date => email_date timelocal 0, + 0, 12, $d, $m - 1, $y + )->send; + } else { + warn "$uri is not gemtext"; + } + } + } + } +} + +sub gemini_fetch { + my ($uri, %opts) = @_; + + # regexp from Alex Schroeder's moku-pona program + my ($scheme, $authority, $path, $query, $fragment) + = $uri + =~ m|(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?|; + $scheme and $scheme eq "gemini" + or die "'$uri' does not use the gemini scheme"; + $authority or die "'$uri' lacks an authority"; + my ($host, $port) = split ":", $authority; + my $cl = IO::Socket::SSL->new( + PeerHost => $host, + PeerPort => $port // 1965, + SSL_verify_mode => SSL_VERIFY_NONE + ); + print $cl "$uri\r\n"; + + my ($status, $meta) = <$cl> =~ /^([0-9]+) (.+)/; + 20 <= $status and $status < 30 or die "gemini error: $status $meta"; + + if ($meta =~ "^text/gemini") { + my @lines; + if ($opts{abs_links}) { + $authority =~ m{/$} or $authority .= "/"; + $path =~ m{/$} or $path .= "/"; + for (<$cl>) { + s/\r?\n\z//; + if (m{^=> (?!/)} and not m{^=> [a-z]+://}) { + push @lines, "=> gemini://$authority$path$'"; + } elsif (m{^=> /}) { + push @lines, "=> gemini://$authority$'"; + } else { + push @lines, $_; + } + } + } else { + @lines = <$cl>; + } + push @lines, "" unless $lines[$#lines] eq ""; + push @lines, "Retrieved from $uri\n at " . localtime; + return $meta, \@lines; + } else { + return $meta, do { local $/; <$cl> }; + } +} + +sub gemtext_to_mail { + my ($gemtext, %opts) = @_; + $opts{from} or die "no From: address specified"; + $opts{to} or die "no To: address specified"; + + my $subject = $opts{link_title} // ""; + if ($gemtext->[0] =~ m{^#(?!#)\s*}) { + $subject = $'; + shift @$gemtext; + shift @$gemtext while $gemtext->[0] =~ /^$/; + } + + if ($opts{gemlog}) { + $opts{from} + = Mail::Field->new("From")->create($opts{from}, $opts{gemlog}) + ->stringify; + $subject = "$opts{gemlog}: $subject" if $subject; + } + + my $msg = MIME::Lite->new( + From => $opts{from}, + To => $opts{to}, + Subject => $subject, + Type => "multipart/mixed" + ); + $msg->add(Date => $opts{date}) if $opts{date}; + + my ($pre, @buffer); + my $flush = sub { + return unless @buffer; + $msg->attach(Type => "TEXT", Data => join "\r\n", @buffer); + undef @buffer; + }; + my $pad + = sub { push @buffer, "" unless !@buffer or $buffer[$#buffer] eq "" }; + for (@$gemtext) { + if ($pre) { + if (/^```/) { + $pre = 0; + } else { + push @buffer, " $_"; + } + } elsif (/^```/) { + &$pad; + $pre = 1; + } elsif (/^>\s*/) { + &$pad; + push @buffer, split "\n", wrap "> ", "> ", $'; + } elsif (/^\*\s*/) { + &$pad; + push @buffer, split "\n", wrap "• ", " ", $'; + } elsif ($opts{inline_images} + and my ($uri) = /^=>\s(\S+\.(?:jpg|jpeg|png|gif))\s/) { + &$flush; + my ($type, $data) = gemini_fetch($uri); + $msg->attach( + Type => $type, + Data => $data, + Filename => (split "/", $uri)[-1], + Disposition => "inline" + ); + } elsif (/^(?:=>|#+)/) { + &$pad; + push @buffer, $_; + } else { + &$pad; + push @buffer, split "\n", wrap "", "", $_; + } + } + + &$flush; + return $msg; +} diff --git a/gmi2email.1.pod b/gmi2email.1.pod new file mode 100644 index 0000000..5fa6d20 --- /dev/null +++ b/gmi2email.1.pod @@ -0,0 +1,81 @@ +=head1 NAME + +gmi2email - subscribe to gemlogs and read individual Gemini pages by e-mail + +=head1 SYNOPSIS + +B [I] [I] ... + +=head1 DESCRIPTION + +B fetches pages served using the Gemini protocol, converts them to +e-mail messages, and then sends those messages. It is mainly useful for +subscribing to Gemini logs ("gemlogs") by e-mail, like rss2email(1). +B fetches, converts and sends all URIs and files containing +text/gemini content specified on the command line. + +=head1 OPTIONS + +=over 4 + +=item B<--subscriptions> + +In addition to mailing any URIs/files specified on the command line, check +subscribed gemlogs for new posts and send those too. Useful in a crontab. + +Currently we only support the subscription mechanism described at +. + +B looks for a file with a list of gemini:// URIs to check for new +posts, one per line, in +B<$XDG_CONFIG_HOME/mailscripts/gmi2email.subscriptions>, or if XDG_CONFIG_HOME +is not set, it falls back to trying to read +B<~/.config/mailscripts/gmi2email.subscriptions>. + +=item B<--inline-images> + +Download and inline any images included in the post. + +=item B<--from=>I
+ +Set the From: address, overriding the configuration file. + +=item B<--to=>I
+ +Set the To: address, overriding the configuration file. + +=back + +=head1 CONFIGURATION + +B tries to read configuration from the file +B<$XDG_CONFIG_HOME/mailscripts/gmi2email.config>, or if XDG_CONFIG_HOME is not +set, it falls back to trying to read +B<~/.config/mailscripts/gmi2email.config>. + +The format is I, one per line. The following +configuration keys are supported: + +=over 4 + +=item B + +Set the From: address. + +=item B + +Set the To: address. + +=item inline_images + +Set to 1 to implicitly pass B<--inline-images>. + +=back + +=head1 SEE ALSO + + + +=head1 AUTHOR + +B was written by Sean Whitton . diff --git a/mailscripts.el b/mailscripts.el index 08947b5..8dc5875 100644 --- a/mailscripts.el +++ b/mailscripts.el @@ -1,7 +1,7 @@ ;;; mailscripts.el --- functions to access tools in the mailscripts package ;; Author: Sean Whitton -;; Version: 0.22 +;; Version: 0.23 ;; Package-Requires: (notmuch) ;; Copyright (C) 2018, 2019, 2020 Sean Whitton -- cgit v1.2.3 From b23033238d8ae711cdb9bddcf6a1b21b2066fb6d Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sat, 23 Jan 2021 18:11:51 -0700 Subject: gmi2email: refactor to avoid a level of nesting No functional change. Signed-off-by: Sean Whitton --- gmi2email | 53 ++++++++++++++++++++++++++--------------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/gmi2email b/gmi2email index c85728b..0d7615b 100755 --- a/gmi2email +++ b/gmi2email @@ -116,35 +116,34 @@ foreach my $sub (<$subs_fh>) { my ($rows) = $dbh->selectrow_array( "SELECT COUNT(*) FROM seen WHERE uri = \"$uri\""); - if ($rows == 0) { - my $mail = 1; - my ($type, $data); - #<<< - try { - ($type, $data) = gemini_fetch($uri, abs_links => 1); - } catch { - warn "when fetching $uri, $_"; - my ($code) = /"gemini error: ([1-6])/; - if ($code == 4) { - next; # try again next run - } else { - $mail = 0; # don't try this one again - } - }; - #>>> - $dbh->do("INSERT INTO seen VALUES (\"$uri\")"); - $mail or next; - if ($type =~ m{^text/gemini}) { - gemtext_to_mail( - $data, %to_mail_opts, - gemlog => $gemlog // "unknown gemlog", - link_title => $title, - date => email_date timelocal 0, - 0, 12, $d, $m - 1, $y - )->send; + next unless $rows == 0; + my $mail = 1; + my ($type, $data); + #<<< + try { + ($type, $data) = gemini_fetch($uri, abs_links => 1); + } catch { + warn "when fetching $uri, $_"; + my ($code) = /"gemini error: ([1-6])/; + if ($code == 4) { + next; # try again next run } else { - warn "$uri is not gemtext"; + $mail = 0; # don't try this one again } + }; + #>>> + $dbh->do("INSERT INTO seen VALUES (\"$uri\")"); + $mail or next; + if ($type =~ m{^text/gemini}) { + gemtext_to_mail( + $data, %to_mail_opts, + gemlog => $gemlog // "unknown gemlog", + link_title => $title, + date => email_date timelocal 0, + 0, 12, $d, $m - 1, $y + )->send; + } else { + warn "$uri is not gemtext"; } } } -- cgit v1.2.3 From c3b79c295706791b809024f5247fc366a7c78c53 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sat, 23 Jan 2021 18:15:24 -0700 Subject: gmi2email: avoid blank lines within lists of links Signed-off-by: Sean Whitton --- gmi2email | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/gmi2email b/gmi2email index 0d7615b..75816e6 100755 --- a/gmi2email +++ b/gmi2email @@ -257,9 +257,12 @@ sub gemtext_to_mail { Filename => (split "/", $uri)[-1], Disposition => "inline" ); - } elsif (/^(?:=>|#+)/) { - &$pad; + } elsif (/^=>/) { + &$pad unless @buffer and $buffer[$#buffer] =~ /^=>/; push @buffer, $_; + } elsif (/^#+/) { + &$pad; + push @buffer, $_; } else { &$pad; push @buffer, split "\n", wrap "", "", $_; -- cgit v1.2.3 From b8694107731a779b2e2ebd307577c8f1f6dc7c91 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sat, 23 Jan 2021 18:29:14 -0700 Subject: gmi2email: add --no-send Signed-off-by: Sean Whitton --- gmi2email | 9 +++++---- gmi2email.1.pod | 6 ++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/gmi2email b/gmi2email index 75816e6..67f9562 100755 --- a/gmi2email +++ b/gmi2email @@ -33,12 +33,13 @@ use Email::Date::Format "email_date"; use Time::Local; use Mail::Field::AddrList; -my ($from, $to, $do_subs, $inline_images); +my ($from, $to, $do_subs, $inline_images, $no_mail); GetOptions "from=s" => \$from, "to=s" => \$to, "subscriptions!" => \$do_subs, - "inline-images!" => \$inline_images; + "inline-images!" => \$inline_images, + "no-send!" => \$no_mail; my $conf_r = $ENV{XDG_CONFIG_HOME} || catfile $ENV{HOME}, ".config"; my $conf_f = catfile $conf_r, "mailscripts", "gmi2email.config"; @@ -74,7 +75,7 @@ for (@ARGV) { ($type, $data) = gemini_fetch($_, abs_links => 1); $type =~ m{^text/gemini} or die "$_ is not gemtext"; } - gemtext_to_mail($data, %to_mail_opts)->send; + $no_mail or gemtext_to_mail($data, %to_mail_opts)->send; } exit unless $do_subs; @@ -133,7 +134,7 @@ foreach my $sub (<$subs_fh>) { }; #>>> $dbh->do("INSERT INTO seen VALUES (\"$uri\")"); - $mail or next; + $mail and !$no_mail or next; if ($type =~ m{^text/gemini}) { gemtext_to_mail( $data, %to_mail_opts, diff --git a/gmi2email.1.pod b/gmi2email.1.pod index 5fa6d20..d4e656c 100644 --- a/gmi2email.1.pod +++ b/gmi2email.1.pod @@ -36,6 +36,12 @@ B<~/.config/mailscripts/gmi2email.subscriptions>. Download and inline any images included in the post. +=item B<--no-send> + +Don't actually send any mail. Intended when you just added some new +subscriptions and want to avoid receiving all the old posts you've already +read. + =item B<--from=>I
Set the From: address, overriding the configuration file. -- cgit v1.2.3 From 57384462f932628c66793f9ea5b13f98fd75035b Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sat, 23 Jan 2021 18:29:29 -0700 Subject: gmi2email: don't attempt to inline images from outside of gemini:// Signed-off-by: Sean Whitton --- gmi2email | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gmi2email b/gmi2email index 67f9562..1b04883 100755 --- a/gmi2email +++ b/gmi2email @@ -249,7 +249,7 @@ sub gemtext_to_mail { &$pad; push @buffer, split "\n", wrap "• ", " ", $'; } elsif ($opts{inline_images} - and my ($uri) = /^=>\s(\S+\.(?:jpg|jpeg|png|gif))\s/) { + and my ($uri) = m{^=>\s(gemini://\S+\.(?:jpg|jpeg|png|gif))\s}) { &$flush; my ($type, $data) = gemini_fetch($uri); $msg->attach( -- cgit v1.2.3 From e004630d1e55006a4d8bce8dfea0658274f69d1b Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sun, 24 Jan 2021 11:25:03 -0700 Subject: gmi2email: factor out send_subscribed_gemtext Signed-off-by: Sean Whitton --- gmi2email | 69 ++++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/gmi2email b/gmi2email index 1b04883..714e58a 100755 --- a/gmi2email +++ b/gmi2email @@ -114,42 +114,47 @@ foreach my $sub (<$subs_fh>) { chomp($gemlog = $'); } elsif (my ($uri, $y, $m, $d, $title) = /^=>\s*(\S+)\s+([0-9]{4})-([0-9]{2})-([0-9]{2})[\s-]*(.*)/) { - my ($rows) - = $dbh->selectrow_array( - "SELECT COUNT(*) FROM seen WHERE uri = \"$uri\""); - next unless $rows == 0; - my $mail = 1; - my ($type, $data); - #<<< - try { - ($type, $data) = gemini_fetch($uri, abs_links => 1); - } catch { - warn "when fetching $uri, $_"; - my ($code) = /"gemini error: ([1-6])/; - if ($code == 4) { - next; # try again next run - } else { - $mail = 0; # don't try this one again - } - }; - #>>> - $dbh->do("INSERT INTO seen VALUES (\"$uri\")"); - $mail and !$no_mail or next; - if ($type =~ m{^text/gemini}) { - gemtext_to_mail( - $data, %to_mail_opts, - gemlog => $gemlog // "unknown gemlog", - link_title => $title, - date => email_date timelocal 0, - 0, 12, $d, $m - 1, $y - )->send; - } else { - warn "$uri is not gemtext"; - } + send_subscribed_gemtext($uri, $gemlog // "unknown gemlog", + $title, timelocal 0, 0, 12, $d, $m - 1, $y); } } } +sub send_subscribed_gemtext { + my ($uri, $gemlog, $link_title, $feed_date) = @_; + my ($rows) + = $dbh->selectrow_array( + "SELECT COUNT(*) FROM seen WHERE uri = \"$uri\""); + next unless $rows == 0; + my $mail = 1; + my ($type, $data); + #<<< + try { + ($type, $data) = gemini_fetch($uri, abs_links => 1); + } catch { + warn "when fetching $uri, $_"; + my ($code) = /"gemini error: ([1-6])/; + if ($code == 4) { + return; # try again next run + } else { + $mail = 0; # don't try this one again + } + }; + #>>> + $dbh->do("INSERT INTO seen VALUES (\"$uri\")"); + $mail and !$no_mail or return; + if ($type =~ m{^text/gemini}) { + gemtext_to_mail( + $data, %to_mail_opts, + gemlog => $gemlog // "unknown gemlog", + link_title => $link_title, + date => email_date $feed_date + )->send; + } else { + warn "$uri is not gemtext"; + } +} + sub gemini_fetch { my ($uri, %opts) = @_; -- cgit v1.2.3 From d41a20368ed7c7458495cfbe2a13eab50f9c5c28 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sun, 24 Jan 2021 11:36:27 -0700 Subject: gmi2email: support for Atom feeds Signed-off-by: Sean Whitton --- debian/changelog | 4 ++-- debian/control | 1 + gmi2email | 25 +++++++++++++++++-------- gmi2email.1.pod | 5 +++-- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/debian/changelog b/debian/changelog index bbb3bf5..5373cf1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,8 +2,8 @@ mailscripts (0.23-1) UNRELEASED; urgency=medium * New script: gmi2email - add libdbd-sqlite3-perl, libio-socket-ssl-perl, libmime-lite-perl, - libemail-date-format-perl, libtry-tiny-perl and libmailtools-perl to - Recommends. + libemail-date-format-perl, libtry-tiny-perl, libmailtools-perl and + libxml-feed-perl to Recommends. -- Sean Whitton Sat, 23 Jan 2021 16:36:25 -0700 diff --git a/debian/control b/debian/control index a47be4c..552da66 100644 --- a/debian/control +++ b/debian/control @@ -57,6 +57,7 @@ Recommends: libemail-date-format-perl, libtry-tiny-perl, libmailtools-perl, + libxml-feed-perl, notmuch, python3-argcomplete, python3-gssapi, diff --git a/gmi2email b/gmi2email index 714e58a..dd9edba 100755 --- a/gmi2email +++ b/gmi2email @@ -32,6 +32,7 @@ use Getopt::Long; use Email::Date::Format "email_date"; use Time::Local; use Mail::Field::AddrList; +use XML::Feed; my ($from, $to, $do_subs, $inline_images, $no_mail); GetOptions @@ -108,15 +109,23 @@ foreach my $sub (<$subs_fh>) { } }; #>>> - $type =~ m{^text/gemini} or die "$sub is not gemtext"; - for (@$data) { - if (/^#\s*/ and not $gemlog) { - chomp($gemlog = $'); - } elsif (my ($uri, $y, $m, $d, $title) - = /^=>\s*(\S+)\s+([0-9]{4})-([0-9]{2})-([0-9]{2})[\s-]*(.*)/) { - send_subscribed_gemtext($uri, $gemlog // "unknown gemlog", - $title, timelocal 0, 0, 12, $d, $m - 1, $y); + if ($type =~ m{^text/gemini}) { + for (@$data) { + if (/^#\s*/ and not $gemlog) { + chomp($gemlog = $'); + } elsif (my ($uri, $y, $m, $d, $title) + = /^=>\s*(\S+)\s+([0-9]{4})-([0-9]{2})-([0-9]{2})[\s-]*(.*)/) { + send_subscribed_gemtext($uri, $gemlog // "unknown gemlog", + $title, timelocal 0, 0, 12, $d, $m - 1, $y); + } } + } elsif ($type =~ m{^text/xml}) { + my $feed = XML::Feed->parse(\$data); + send_subscribed_gemtext($_->link, $feed->title, $_->title, + ($_->issued // $_->modified)->epoch) + for $feed->entries; + } else { + die "$sub is not gemtext"; } } diff --git a/gmi2email.1.pod b/gmi2email.1.pod index d4e656c..d5004d5 100644 --- a/gmi2email.1.pod +++ b/gmi2email.1.pod @@ -23,8 +23,9 @@ text/gemini content specified on the command line. In addition to mailing any URIs/files specified on the command line, check subscribed gemlogs for new posts and send those too. Useful in a crontab. -Currently we only support the subscription mechanism described at -. +We support the subscription mechanism described at + as well as +Atom feeds. B looks for a file with a list of gemini:// URIs to check for new posts, one per line, in -- cgit v1.2.3 From 9de11b455fbbda71bf2476f46babb1d4770b124c Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sun, 24 Jan 2021 11:37:13 -0700 Subject: demote gmi2email-only deps to Suggests Signed-off-by: Sean Whitton --- debian/changelog | 2 +- debian/control | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/debian/changelog b/debian/changelog index 5373cf1..6b943e0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,7 +3,7 @@ mailscripts (0.23-1) UNRELEASED; urgency=medium * New script: gmi2email - add libdbd-sqlite3-perl, libio-socket-ssl-perl, libmime-lite-perl, libemail-date-format-perl, libtry-tiny-perl, libmailtools-perl and - libxml-feed-perl to Recommends. + libxml-feed-perl to Suggests. -- Sean Whitton Sat, 23 Jan 2021 16:36:25 -0700 diff --git a/debian/control b/debian/control index 552da66..763e8e9 100644 --- a/debian/control +++ b/debian/control @@ -51,13 +51,6 @@ Recommends: devscripts, git, libgit-wrapper-perl, - libdbd-sqlite3-perl, - libio-socket-ssl-perl, - libmime-lite-perl, - libemail-date-format-perl, - libtry-tiny-perl, - libmailtools-perl, - libxml-feed-perl, notmuch, python3-argcomplete, python3-gssapi, @@ -68,6 +61,13 @@ Suggests: gpg-agent, gpgsm, openssl, + libdbd-sqlite3-perl, + libio-socket-ssl-perl, + libmime-lite-perl, + libemail-date-format-perl, + libtry-tiny-perl, + libmailtools-perl, + libxml-feed-perl, Architecture: all Description: collection of scripts for manipulating e-mail on Debian This package provides a collection of scripts for manipulating e-mail -- cgit v1.2.3 From 558d2566377ad7f6946129eab1f679e244b8999d Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sun, 24 Jan 2021 11:51:29 -0700 Subject: gmi2email: improve image link regexp Signed-off-by: Sean Whitton --- gmi2email | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gmi2email b/gmi2email index dd9edba..e58532c 100755 --- a/gmi2email +++ b/gmi2email @@ -263,7 +263,7 @@ sub gemtext_to_mail { &$pad; push @buffer, split "\n", wrap "• ", " ", $'; } elsif ($opts{inline_images} - and my ($uri) = m{^=>\s(gemini://\S+\.(?:jpg|jpeg|png|gif))\s}) { + and my ($uri) = m{^=>\s*(gemini://\S+\.(?:jpg|jpeg|png|gif))}) { &$flush; my ($type, $data) = gemini_fetch($uri); $msg->attach( -- cgit v1.2.3 From e29e329b58b8e4a92c0d535a5e67f147e8a3d026 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sun, 24 Jan 2021 11:51:43 -0700 Subject: gmi2email(1): add "TYPICAL USAGE" Signed-off-by: Sean Whitton --- gmi2email.1.pod | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/gmi2email.1.pod b/gmi2email.1.pod index d5004d5..6f12b84 100644 --- a/gmi2email.1.pod +++ b/gmi2email.1.pod @@ -14,6 +14,47 @@ subscribing to Gemini logs ("gemlogs") by e-mail, like rss2email(1). B fetches, converts and sends all URIs and files containing text/gemini content specified on the command line. +=head2 TYPICAL USAGE + +1. Ensure you have a working MTA: B will use the sendmail(1) +command to send mail. + +2. Create B<~/.config/mailscripts/gmi2email.config> with content like this: + +=over 4 + + from = rss@example.com + to = your_email@example.com + inline_images = 1 + +=back + +3. Create B<~/.config/mailscripts/gmi2email.subscriptions> with some feed +URIs, e.g. + +=over 4 + + gemini://example.com/my_cool_gemlog/ + gemini://example.com/other_cool_gemlog/feed.xml + +=back + +4. Just once, execute + +=over 4 + + % gmi2email --subscriptions --no-send + +=back + +5. Periodically, execute + +=over 4 + + % gmi2email --subscriptions + +=back + =head1 OPTIONS =over 4 -- cgit v1.2.3 From eee09b348af9d8ca553687ede1525137a8ef734e Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sun, 24 Jan 2021 12:04:14 -0700 Subject: gmi2email: don't exit subroutine via next Signed-off-by: Sean Whitton --- gmi2email | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gmi2email b/gmi2email index e58532c..4d9c2d3 100755 --- a/gmi2email +++ b/gmi2email @@ -134,7 +134,7 @@ sub send_subscribed_gemtext { my ($rows) = $dbh->selectrow_array( "SELECT COUNT(*) FROM seen WHERE uri = \"$uri\""); - next unless $rows == 0; + return unless $rows == 0; my $mail = 1; my ($type, $data); #<<< -- cgit v1.2.3 From cf42a5ec60a17f75fafbf8a91b17c794e48f5d02 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sun, 24 Jan 2021 12:06:00 -0700 Subject: gmi2email: accept application/xml MIME type Signed-off-by: Sean Whitton --- gmi2email | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gmi2email b/gmi2email index 4d9c2d3..063703a 100755 --- a/gmi2email +++ b/gmi2email @@ -119,7 +119,7 @@ foreach my $sub (<$subs_fh>) { $title, timelocal 0, 0, 12, $d, $m - 1, $y); } } - } elsif ($type =~ m{^text/xml}) { + } elsif ($type =~ m{^(?:text|application)/xml}) { my $feed = XML::Feed->parse(\$data); send_subscribed_gemtext($_->link, $feed->title, $_->title, ($_->issued // $_->modified)->epoch) -- cgit v1.2.3 From a18924ea980affccdac63b9b56daa594a97d1b64 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sun, 24 Jan 2021 12:10:37 -0700 Subject: gmi2email: accept application/atom+xml MIME type Signed-off-by: Sean Whitton --- gmi2email | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gmi2email b/gmi2email index 063703a..e0f4fa1 100755 --- a/gmi2email +++ b/gmi2email @@ -119,7 +119,7 @@ foreach my $sub (<$subs_fh>) { $title, timelocal 0, 0, 12, $d, $m - 1, $y); } } - } elsif ($type =~ m{^(?:text|application)/xml}) { + } elsif ($type =~ m{^(?:text|application)/(?:atom\+)?xml}) { my $feed = XML::Feed->parse(\$data); send_subscribed_gemtext($_->link, $feed->title, $_->title, ($_->issued // $_->modified)->epoch) -- cgit v1.2.3 From 7c523ab1153bb8cc4b31378ebe0563ef9813bdab Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sun, 24 Jan 2021 12:10:51 -0700 Subject: gmi2email: improve error message Signed-off-by: Sean Whitton --- gmi2email | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gmi2email b/gmi2email index e0f4fa1..d0b2fa9 100755 --- a/gmi2email +++ b/gmi2email @@ -125,7 +125,7 @@ foreach my $sub (<$subs_fh>) { ($_->issued // $_->modified)->epoch) for $feed->entries; } else { - die "$sub is not gemtext"; + die "$sub is not gemtext or an Atom feed, so far as I can tell"; } } -- cgit v1.2.3 From 5b02197c3b928beb7b2de297df05a299ff188765 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sun, 24 Jan 2021 12:30:27 -0700 Subject: gmi2email: handle redirects Signed-off-by: Sean Whitton --- gmi2email | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/gmi2email b/gmi2email index d0b2fa9..8510643 100755 --- a/gmi2email +++ b/gmi2email @@ -182,8 +182,16 @@ sub gemini_fetch { ); print $cl "$uri\r\n"; - my ($status, $meta) = <$cl> =~ /^([0-9]+) (.+)/; - 20 <= $status and $status < 30 or die "gemini error: $status $meta"; + my ($status, $meta) = <$cl> =~ /^([0-9]+) (\V+)/; + if (30 <= $status and $status < 40) { + $opts{orig_uri} = $uri unless $opts{redirects}; + die "too many redirects while fetching $opts{orig_uri}" + if $opts{redirects} and $opts{redirects} > 5; + $opts{redirects}++; + return gemini_fetch($meta, %opts); + } elsif ($status < 20 or $status >= 40) { + die "gemini error: $status $meta"; + } if ($meta =~ "^text/gemini") { my @lines; -- cgit v1.2.3 From a9f38097bd9bf8af9bed3b4512618543a4330668 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sun, 24 Jan 2021 12:30:42 -0700 Subject: gmi2email: comment with shell snippet Signed-off-by: Sean Whitton --- gmi2email | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gmi2email b/gmi2email index 8510643..9cff323 100755 --- a/gmi2email +++ b/gmi2email @@ -17,6 +17,14 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +# TESTING/DEVEL +# +# To forget about seen entries of a feed: +# +# % perl -MDBI +# -we'DBI->connect("dbi:SQLite:dbname=$ENV{HOME}/.cache/mailscripts/gmi2email.db", +# "", "")->do("DELETE FROM seen WHERE uri LIKE \"gemini://example.com/%\"")' + use 5.028; use strict; use warnings; -- cgit v1.2.3 From 0245e5f9c57b40be31228dddc1efabea3f9c7b3a Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sun, 24 Jan 2021 12:54:04 -0700 Subject: gmi2email: tweak error message Signed-off-by: Sean Whitton --- gmi2email | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gmi2email b/gmi2email index 9cff323..4fccb38 100755 --- a/gmi2email +++ b/gmi2email @@ -133,7 +133,7 @@ foreach my $sub (<$subs_fh>) { ($_->issued // $_->modified)->epoch) for $feed->entries; } else { - die "$sub is not gemtext or an Atom feed, so far as I can tell"; + die "$sub is not gemtext nor an Atom feed, so far as I can tell"; } } -- cgit v1.2.3 From 0552ba0301456c5137081665315e93d1eca7198c Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sun, 24 Jan 2021 18:54:03 -0700 Subject: gmi2email: tweak error message Signed-off-by: Sean Whitton --- gmi2email | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gmi2email b/gmi2email index 4fccb38..a124099 100755 --- a/gmi2email +++ b/gmi2email @@ -55,7 +55,7 @@ my $conf_f = catfile $conf_r, "mailscripts", "gmi2email.config"; -e $conf_f or (defined $to and defined $from) or die - "no config file or sufficient command line options: don't know who to mail"; + "no config file nor sufficient command line options: don't know who to mail"; my $conf = Config::Tiny->new->read($conf_f); my %to_mail_opts = ( -- cgit v1.2.3 From 77740f4625825f605258fa706069efff52b511d9 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Mon, 25 Jan 2021 10:52:19 -0700 Subject: gmi2email: tweak error message Signed-off-by: Sean Whitton --- gmi2email | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gmi2email b/gmi2email index a124099..f03c930 100755 --- a/gmi2email +++ b/gmi2email @@ -198,7 +198,7 @@ sub gemini_fetch { $opts{redirects}++; return gemini_fetch($meta, %opts); } elsif ($status < 20 or $status >= 40) { - die "gemini error: $status $meta"; + die "while fetching $uri: gemini error: $status $meta"; } if ($meta =~ "^text/gemini") { -- cgit v1.2.3 From 3872d4850ca9ade0eccc8c7054b6459a1d00b25f Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Mon, 25 Jan 2021 19:39:58 -0700 Subject: gmi2email: don't record as seen if sending mail threw an exception Signed-off-by: Sean Whitton --- gmi2email | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gmi2email b/gmi2email index f03c930..cae0767 100755 --- a/gmi2email +++ b/gmi2email @@ -158,18 +158,17 @@ sub send_subscribed_gemtext { } }; #>>> - $dbh->do("INSERT INTO seen VALUES (\"$uri\")"); - $mail and !$no_mail or return; if ($type =~ m{^text/gemini}) { gemtext_to_mail( $data, %to_mail_opts, gemlog => $gemlog // "unknown gemlog", link_title => $link_title, date => email_date $feed_date - )->send; + )->send if $mail and !$no_mail; } else { warn "$uri is not gemtext"; } + $dbh->do("INSERT INTO seen VALUES (\"$uri\")"); } sub gemini_fetch { -- cgit v1.2.3 From f43a42a8c5687057ff28e884863d7a5a877837f3 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Mon, 25 Jan 2021 19:40:42 -0700 Subject: gmi2email: drop superfluous chomp Signed-off-by: Sean Whitton --- gmi2email | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gmi2email b/gmi2email index cae0767..5b8ba4a 100755 --- a/gmi2email +++ b/gmi2email @@ -120,7 +120,7 @@ foreach my $sub (<$subs_fh>) { if ($type =~ m{^text/gemini}) { for (@$data) { if (/^#\s*/ and not $gemlog) { - chomp($gemlog = $'); + $gemlog = $'; } elsif (my ($uri, $y, $m, $d, $title) = /^=>\s*(\S+)\s+([0-9]{4})-([0-9]{2})-([0-9]{2})[\s-]*(.*)/) { send_subscribed_gemtext($uri, $gemlog // "unknown gemlog", -- cgit v1.2.3 From 16b42aa5983e022e4662bad333765d284e52b61b Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Wed, 27 Jan 2021 16:25:26 -0700 Subject: gmi2email: perltidy Signed-off-by: Sean Whitton --- gmi2email | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/gmi2email b/gmi2email index 5b8ba4a..4c567e9 100755 --- a/gmi2email +++ b/gmi2email @@ -164,7 +164,8 @@ sub send_subscribed_gemtext { gemlog => $gemlog // "unknown gemlog", link_title => $link_title, date => email_date $feed_date - )->send if $mail and !$no_mail; + )->send + if $mail and !$no_mail; } else { warn "$uri is not gemtext"; } @@ -191,13 +192,13 @@ sub gemini_fetch { my ($status, $meta) = <$cl> =~ /^([0-9]+) (\V+)/; if (30 <= $status and $status < 40) { - $opts{orig_uri} = $uri unless $opts{redirects}; + $opts{orig_uri} = $uri unless $opts{redirects}; die "too many redirects while fetching $opts{orig_uri}" if $opts{redirects} and $opts{redirects} > 5; - $opts{redirects}++; - return gemini_fetch($meta, %opts); + $opts{redirects}++; + return gemini_fetch($meta, %opts); } elsif ($status < 20 or $status >= 40) { - die "while fetching $uri: gemini error: $status $meta"; + die "while fetching $uri: gemini error: $status $meta"; } if ($meta =~ "^text/gemini") { @@ -290,9 +291,9 @@ sub gemtext_to_mail { } elsif (/^=>/) { &$pad unless @buffer and $buffer[$#buffer] =~ /^=>/; push @buffer, $_; - } elsif (/^#+/) { - &$pad; - push @buffer, $_; + } elsif (/^#+/) { + &$pad; + push @buffer, $_; } else { &$pad; push @buffer, split "\n", wrap "", "", $_; -- cgit v1.2.3 From 1f07bf968d154664cfec5d2414b8a960f82e38ec Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Wed, 27 Jan 2021 16:27:14 -0700 Subject: gmi2email: enable specifying a list of subscriptions Signed-off-by: Sean Whitton --- gmi2email | 24 ++++++++++++------------ gmi2email.1.pod | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/gmi2email b/gmi2email index 4c567e9..54a3459 100755 --- a/gmi2email +++ b/gmi2email @@ -42,13 +42,13 @@ use Time::Local; use Mail::Field::AddrList; use XML::Feed; -my ($from, $to, $do_subs, $inline_images, $no_mail); +my ($from, $to, $subs, $inline_images, $no_mail); GetOptions - "from=s" => \$from, - "to=s" => \$to, - "subscriptions!" => \$do_subs, - "inline-images!" => \$inline_images, - "no-send!" => \$no_mail; + "from=s" => \$from, + "to=s" => \$to, + "subscriptions:s" => \$subs, + "inline-images!" => \$inline_images, + "no-send!" => \$no_mail; my $conf_r = $ENV{XDG_CONFIG_HOME} || catfile $ENV{HOME}, ".config"; my $conf_f = catfile $conf_r, "mailscripts", "gmi2email.config"; @@ -57,6 +57,8 @@ my $conf_f = catfile $conf_r, "mailscripts", "gmi2email.config"; or die "no config file nor sufficient command line options: don't know who to mail"; my $conf = Config::Tiny->new->read($conf_f); +$subs ||= catfile $conf_r, "mailscripts", "gmi2email.subscriptions" + if defined $subs; my %to_mail_opts = ( from => ( @@ -72,7 +74,7 @@ my %to_mail_opts = ( inline_images => $inline_images // $conf->{_}->{inline_images} // 0 ); -@ARGV or $do_subs or die "nothing to do\n"; +@ARGV or $subs or die "nothing to do\n"; for (@ARGV) { my $data; @@ -87,11 +89,9 @@ for (@ARGV) { $no_mail or gemtext_to_mail($data, %to_mail_opts)->send; } -exit unless $do_subs; - -my $subs_f = catfile $conf_r, "mailscripts", "gmi2email.subscriptions"; --e $subs_f or die "no list of subscriptions"; -open my $subs_fh, "<", $subs_f; +exit unless $subs; +-r $subs or die "file $subs not readable"; +open my $subs_fh, "<", $subs; my $db_r = $ENV{XDG_CACHE_HOME} || catfile $ENV{HOME}, ".cache"; my $db_d = catfile $db_r, "mailscripts"; diff --git a/gmi2email.1.pod b/gmi2email.1.pod index 6f12b84..b7e9108 100644 --- a/gmi2email.1.pod +++ b/gmi2email.1.pod @@ -59,7 +59,7 @@ URIs, e.g. =over 4 -=item B<--subscriptions> +=item B<--subscriptions>[=I] In addition to mailing any URIs/files specified on the command line, check subscribed gemlogs for new posts and send those too. Useful in a crontab. @@ -69,7 +69,7 @@ We support the subscription mechanism described at Atom feeds. B looks for a file with a list of gemini:// URIs to check for new -posts, one per line, in +posts, one per line, in I, or if that is not set, in B<$XDG_CONFIG_HOME/mailscripts/gmi2email.subscriptions>, or if XDG_CONFIG_HOME is not set, it falls back to trying to read B<~/.config/mailscripts/gmi2email.subscriptions>. -- cgit v1.2.3 From 2226a0b70fa795771f1eff94063d37e0477a3e4e Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Wed, 27 Jan 2021 17:07:39 -0700 Subject: gmi2email: don't exit subroutine via 'next' Signed-off-by: Sean Whitton --- gmi2email | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gmi2email b/gmi2email index 54a3459..bb880a5 100755 --- a/gmi2email +++ b/gmi2email @@ -103,7 +103,7 @@ $dbh->do("CREATE TABLE IF NOT EXISTS seen (uri TEXT PRIMARY KEY)") foreach my $sub (<$subs_fh>) { chomp $sub; - my ($gemlog, $type, $data); + my ($gemlog, $type, $data, $next); #<<< try { ($type, $data) = gemini_fetch($sub, abs_links => 1); @@ -111,12 +111,13 @@ foreach my $sub (<$subs_fh>) { my ($code) = /"gemini error: ([1-6])/; if ($code == 4) { warn "temporary failure retrieving $sub"; - next; # try again next run + $next = 1, return; # try again next run } else { die "while retrieving $sub $_"; } }; #>>> + next if $next; if ($type =~ m{^text/gemini}) { for (@$data) { if (/^#\s*/ and not $gemlog) { -- cgit v1.2.3 From e56b457674c0b2ef5743998611c68d364eeba6de Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Wed, 27 Jan 2021 17:07:49 -0700 Subject: gmi2email: die if did not get gemini response Signed-off-by: Sean Whitton --- gmi2email | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gmi2email b/gmi2email index bb880a5..d2477ac 100755 --- a/gmi2email +++ b/gmi2email @@ -192,6 +192,8 @@ sub gemini_fetch { print $cl "$uri\r\n"; my ($status, $meta) = <$cl> =~ /^([0-9]+) (\V+)/; + defined $status and defined $meta + or die "while fetching $uri: missing or invalid gemini response\n"; if (30 <= $status and $status < 40) { $opts{orig_uri} = $uri unless $opts{redirects}; die "too many redirects while fetching $opts{orig_uri}" -- cgit v1.2.3 From cd604d24886a22b4b7eb1a40b2b9d5be8701aca9 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Wed, 27 Jan 2021 17:08:19 -0700 Subject: gmi2email: treat missing gemini response as a temporary failure Signed-off-by: Sean Whitton --- gmi2email | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gmi2email b/gmi2email index d2477ac..c3e26e5 100755 --- a/gmi2email +++ b/gmi2email @@ -109,7 +109,7 @@ foreach my $sub (<$subs_fh>) { ($type, $data) = gemini_fetch($sub, abs_links => 1); } catch { my ($code) = /"gemini error: ([1-6])/; - if ($code == 4) { + if (defined $code and $code == 4 or /missing or invalid gemini response/) { warn "temporary failure retrieving $sub"; $next = 1, return; # try again next run } else { -- cgit v1.2.3 From 293af10a9bd6acfee58b15c8f5a709f888aead58 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Wed, 27 Jan 2021 17:38:32 -0700 Subject: gmi2email: die if fail to establish SSL connection Signed-off-by: Sean Whitton --- gmi2email | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gmi2email b/gmi2email index c3e26e5..02e3d66 100755 --- a/gmi2email +++ b/gmi2email @@ -188,7 +188,7 @@ sub gemini_fetch { PeerHost => $host, PeerPort => $port // 1965, SSL_verify_mode => SSL_VERIFY_NONE - ); + ) or die "while fetching $uri: failed to establish SSL connection\n"; print $cl "$uri\r\n"; my ($status, $meta) = <$cl> =~ /^([0-9]+) (\V+)/; -- cgit v1.2.3 From 344694d50aa941e90c09108e453a17b273130c14 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Wed, 27 Jan 2021 17:39:01 -0700 Subject: gmi2email: cope with feed entries which don't have dates Signed-off-by: Sean Whitton --- gmi2email | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/gmi2email b/gmi2email index 02e3d66..716a866 100755 --- a/gmi2email +++ b/gmi2email @@ -130,9 +130,11 @@ foreach my $sub (<$subs_fh>) { } } elsif ($type =~ m{^(?:text|application)/(?:atom\+)?xml}) { my $feed = XML::Feed->parse(\$data); - send_subscribed_gemtext($_->link, $feed->title, $_->title, - ($_->issued // $_->modified)->epoch) - for $feed->entries; + for ($feed->entries) { + my $date = $_->issued // $_->modified; + $date = $date->epoch if $date; + send_subscribed_gemtext($_->link, $feed->title, $_->title, $date); + } } else { die "$sub is not gemtext nor an Atom feed, so far as I can tell"; } @@ -164,7 +166,7 @@ sub send_subscribed_gemtext { $data, %to_mail_opts, gemlog => $gemlog // "unknown gemlog", link_title => $link_title, - date => email_date $feed_date + date => email_date $feed_date // time )->send if $mail and !$no_mail; } else { -- cgit v1.2.3 From f95a05571afe962dc9aa1ffe6995444c06026910 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Wed, 27 Jan 2021 17:39:44 -0700 Subject: gmi2email: treat SSL connection failure as a temporary failure Signed-off-by: Sean Whitton --- gmi2email | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gmi2email b/gmi2email index 716a866..6b8bd6c 100755 --- a/gmi2email +++ b/gmi2email @@ -109,7 +109,9 @@ foreach my $sub (<$subs_fh>) { ($type, $data) = gemini_fetch($sub, abs_links => 1); } catch { my ($code) = /"gemini error: ([1-6])/; - if (defined $code and $code == 4 or /missing or invalid gemini response/) { + if ( defined $code and $code == 4 + or /missing or invalid gemini response/ + or /failed to establish SSL connection/) { warn "temporary failure retrieving $sub"; $next = 1, return; # try again next run } else { -- cgit v1.2.3 From b8c5591bf83da92138369e2c135be95115bec009 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Wed, 27 Jan 2021 17:41:09 -0700 Subject: gmi2email: tweak error message Signed-off-by: Sean Whitton --- gmi2email | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gmi2email b/gmi2email index 6b8bd6c..89c9f13 100755 --- a/gmi2email +++ b/gmi2email @@ -112,7 +112,7 @@ foreach my $sub (<$subs_fh>) { if ( defined $code and $code == 4 or /missing or invalid gemini response/ or /failed to establish SSL connection/) { - warn "temporary failure retrieving $sub"; + warn "temporary failure retrieving $sub; will try again later:\n $_"; $next = 1, return; # try again next run } else { die "while retrieving $sub $_"; -- cgit v1.2.3 From f9370aec2aa8702bb7826535a2f9409ff0f44040 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Wed, 27 Jan 2021 17:43:42 -0700 Subject: gmi2email: perltidy Signed-off-by: Sean Whitton --- gmi2email | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gmi2email b/gmi2email index 89c9f13..ed0fb28 100755 --- a/gmi2email +++ b/gmi2email @@ -132,11 +132,11 @@ foreach my $sub (<$subs_fh>) { } } elsif ($type =~ m{^(?:text|application)/(?:atom\+)?xml}) { my $feed = XML::Feed->parse(\$data); - for ($feed->entries) { - my $date = $_->issued // $_->modified; - $date = $date->epoch if $date; - send_subscribed_gemtext($_->link, $feed->title, $_->title, $date); - } + for ($feed->entries) { + my $date = $_->issued // $_->modified; + $date = $date->epoch if $date; + send_subscribed_gemtext($_->link, $feed->title, $_->title, $date); + } } else { die "$sub is not gemtext nor an Atom feed, so far as I can tell"; } -- cgit v1.2.3 From f83c52007dde3fa3b243a0fe3ac6bb052b963b71 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Wed, 27 Jan 2021 18:10:17 -0700 Subject: gmi2email: avoid double slashes Seems some servers don't eliminate these themselves and can return "Not found". Signed-off-by: Sean Whitton --- gmi2email | 1 + 1 file changed, 1 insertion(+) diff --git a/gmi2email b/gmi2email index ed0fb28..1015328 100755 --- a/gmi2email +++ b/gmi2email @@ -211,6 +211,7 @@ sub gemini_fetch { if ($meta =~ "^text/gemini") { my @lines; if ($opts{abs_links}) { + $path =~ s{^/}{}; $authority =~ m{/$} or $authority .= "/"; $path =~ m{/$} or $path .= "/"; for (<$cl>) { -- cgit v1.2.3 From 891877f7b1bbb1dea0f82ec6e577dc0cb3ce51e0 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Wed, 27 Jan 2021 18:10:46 -0700 Subject: gmi2email: handle ./ links Signed-off-by: Sean Whitton --- gmi2email | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gmi2email b/gmi2email index 1015328..9fa4c23 100755 --- a/gmi2email +++ b/gmi2email @@ -212,11 +212,14 @@ sub gemini_fetch { my @lines; if ($opts{abs_links}) { $path =~ s{^/}{}; + (my $dir = $path) =~ s{[^/]*$}{}; $authority =~ m{/$} or $authority .= "/"; $path =~ m{/$} or $path .= "/"; for (<$cl>) { s/\r?\n\z//; - if (m{^=> (?!/)} and not m{^=> [a-z]+://}) { + if (m{^=>\s*\./}) { + push @lines, "=> gemini://$authority$dir$'"; + } elsif (m{^=> (?!/)} and not m{^=> [a-z]+://}) { push @lines, "=> gemini://$authority$path$'"; } elsif (m{^=> /}) { push @lines, "=> gemini://$authority$'"; -- cgit v1.2.3 From c97c00d799bbfbab958d3b03d403c5431a1cb7e2 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Thu, 28 Jan 2021 00:16:18 -0700 Subject: gmi2email: avoid loading whole gemtext into memory Signed-off-by: Sean Whitton --- gmi2email | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gmi2email b/gmi2email index 9fa4c23..d3e0ed5 100755 --- a/gmi2email +++ b/gmi2email @@ -215,7 +215,7 @@ sub gemini_fetch { (my $dir = $path) =~ s{[^/]*$}{}; $authority =~ m{/$} or $authority .= "/"; $path =~ m{/$} or $path .= "/"; - for (<$cl>) { + while (local $_ = <$cl>) { s/\r?\n\z//; if (m{^=>\s*\./}) { push @lines, "=> gemini://$authority$dir$'"; -- cgit v1.2.3 From f42d49b2939ab6983271a7ecdcf16a996f6ebeac Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Thu, 28 Jan 2021 00:16:49 -0700 Subject: gmi2email: handle failures to fetch images Signed-off-by: Sean Whitton --- gmi2email | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/gmi2email b/gmi2email index d3e0ed5..ef38426 100755 --- a/gmi2email +++ b/gmi2email @@ -292,13 +292,21 @@ sub gemtext_to_mail { } elsif ($opts{inline_images} and my ($uri) = m{^=>\s*(gemini://\S+\.(?:jpg|jpeg|png|gif))}) { &$flush; - my ($type, $data) = gemini_fetch($uri); + my ($type, $data, $failed); + #<<< + try { + ($type, $data) = gemini_fetch($uri); + } catch { + push @buffer, "when fetching $uri, $_"; + $failed = 1; + }; + #>>> $msg->attach( Type => $type, Data => $data, Filename => (split "/", $uri)[-1], Disposition => "inline" - ); + ) unless $failed; } elsif (/^=>/) { &$pad unless @buffer and $buffer[$#buffer] =~ /^=>/; push @buffer, $_; -- cgit v1.2.3 From 9cb043b4cf9b273a170430b566135fde72d9ef55 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Thu, 28 Jan 2021 00:17:01 -0700 Subject: gmi2email: fix handling relative links Signed-off-by: Sean Whitton --- gmi2email | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/gmi2email b/gmi2email index ef38426..f4a13a6 100755 --- a/gmi2email +++ b/gmi2email @@ -211,17 +211,13 @@ sub gemini_fetch { if ($meta =~ "^text/gemini") { my @lines; if ($opts{abs_links}) { - $path =~ s{^/}{}; - (my $dir = $path) =~ s{[^/]*$}{}; + my $dir = $path =~ s{[^/]*$}{}r =~ s{^/}{}r; $authority =~ m{/$} or $authority .= "/"; - $path =~ m{/$} or $path .= "/"; while (local $_ = <$cl>) { s/\r?\n\z//; - if (m{^=>\s*\./}) { + if (m{^=>\s*\./} || m{^=>\s*(?!/)} and not m{^=> [a-z]+://}) { push @lines, "=> gemini://$authority$dir$'"; - } elsif (m{^=> (?!/)} and not m{^=> [a-z]+://}) { - push @lines, "=> gemini://$authority$path$'"; - } elsif (m{^=> /}) { + } elsif (m{^=>\s*/}) { push @lines, "=> gemini://$authority$'"; } else { push @lines, $_; -- cgit v1.2.3 From f86afc9f4f372d0322d693e9b767d924e08a7682 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Thu, 28 Jan 2021 16:02:39 -0700 Subject: gmi2email: cope with links in feeds missing the protocol Signed-off-by: Sean Whitton --- gmi2email | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/gmi2email b/gmi2email index f4a13a6..0d9861b 100755 --- a/gmi2email +++ b/gmi2email @@ -135,7 +135,17 @@ foreach my $sub (<$subs_fh>) { for ($feed->entries) { my $date = $_->issued // $_->modified; $date = $date->epoch if $date; - send_subscribed_gemtext($_->link, $feed->title, $_->title, $date); + + my $link; + if ($_->link =~ m{^//}) { + $link = "gemini:" . $_->link; + } elsif ($_->link !~ m{^[a-z]+://}) { + $link = "gemini://" . $_->link; + } else { + $link = $_->link; + } + + send_subscribed_gemtext($link, $feed->title, $_->title, $date); } } else { die "$sub is not gemtext nor an Atom feed, so far as I can tell"; -- cgit v1.2.3 From 182d28e47858c183d3be2e172c400e3b0521167f Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Thu, 28 Jan 2021 16:03:03 -0700 Subject: gmi2email: avoid some uninitialised variables Signed-off-by: Sean Whitton --- gmi2email | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gmi2email b/gmi2email index 0d9861b..fcf0f0e 100755 --- a/gmi2email +++ b/gmi2email @@ -166,14 +166,14 @@ sub send_subscribed_gemtext { } catch { warn "when fetching $uri, $_"; my ($code) = /"gemini error: ([1-6])/; - if ($code == 4) { + if ($code and $code == 4) { return; # try again next run } else { $mail = 0; # don't try this one again } }; #>>> - if ($type =~ m{^text/gemini}) { + if ($type and $type =~ m{^text/gemini}) { gemtext_to_mail( $data, %to_mail_opts, gemlog => $gemlog // "unknown gemlog", @@ -236,7 +236,7 @@ sub gemini_fetch { } else { @lines = <$cl>; } - push @lines, "" unless $lines[$#lines] eq ""; + push @lines, "" unless !@lines or $lines[$#lines] eq ""; push @lines, "Retrieved from $uri\n at " . localtime; return $meta, \@lines; } else { -- cgit v1.2.3 From 30fda961a6662eff16e06fc2f1b6fd023ba3d8b4 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Thu, 28 Jan 2021 16:03:15 -0700 Subject: gmi2email: accept more MIME types Signed-off-by: Sean Whitton --- gmi2email | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gmi2email b/gmi2email index fcf0f0e..27249fa 100755 --- a/gmi2email +++ b/gmi2email @@ -130,7 +130,7 @@ foreach my $sub (<$subs_fh>) { $title, timelocal 0, 0, 12, $d, $m - 1, $y); } } - } elsif ($type =~ m{^(?:text|application)/(?:atom\+)?xml}) { + } elsif ($type =~ m{^(?:text|application)/(?:(?:atom|rss)\+)?xml}) { my $feed = XML::Feed->parse(\$data); for ($feed->entries) { my $date = $_->issued // $_->modified; -- cgit v1.2.3 From 8a0d58491ce203fe33fc3071acf6866c0986aa26 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Thu, 28 Jan 2021 16:03:25 -0700 Subject: gmi2email: cope with .. in links Signed-off-by: Sean Whitton --- gmi2email | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gmi2email b/gmi2email index 27249fa..cbbded4 100755 --- a/gmi2email +++ b/gmi2email @@ -226,7 +226,10 @@ sub gemini_fetch { while (local $_ = <$cl>) { s/\r?\n\z//; if (m{^=>\s*\./} || m{^=>\s*(?!/)} and not m{^=> [a-z]+://}) { - push @lines, "=> gemini://$authority$dir$'"; + my $link = "$dir$'"; + # attempt to resolve any use of '..' notation + 1 while $link =~ s{/[^/]+/../}{/}; + push @lines, "=> gemini://$authority$link"; } elsif (m{^=>\s*/}) { push @lines, "=> gemini://$authority$'"; } else { -- cgit v1.2.3 From 7b3d79afdaca217183b9715cfb40979a16cafd89 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Thu, 28 Jan 2021 16:34:55 -0700 Subject: release mailscripts 0.23 (-1 to Debian unstable) Signed-off-by: Sean Whitton --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 6b943e0..947cbcb 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,11 +1,11 @@ -mailscripts (0.23-1) UNRELEASED; urgency=medium +mailscripts (0.23-1) unstable; urgency=medium * New script: gmi2email - add libdbd-sqlite3-perl, libio-socket-ssl-perl, libmime-lite-perl, libemail-date-format-perl, libtry-tiny-perl, libmailtools-perl and libxml-feed-perl to Suggests. - -- Sean Whitton Sat, 23 Jan 2021 16:36:25 -0700 + -- Sean Whitton Thu, 28 Jan 2021 16:34:40 -0700 mailscripts (0.22-1) unstable; urgency=medium -- cgit v1.2.3