#!perl

use strict;
use warnings;

use FindBin;
use lib
    "$FindBin::Bin/../lib",
    ;
use Mojolicious::Commands;

# Start command line interface for application
Mojolicious::Commands->start_app( 'Whim', @ARGV );

=head1 NAME

whim - A L<Webmention|https://jmac.org/webmention/> multitool

=head1 SYNOPSIS

Listen for webmentions at port 3000, and store any that arrive.

 $ whim listen start # Also launches a webserver for displaying webmentions!

Verify recently arrived webmentions

 $ whim verify

See summaries of received, valid webmentions

 $ whim query --after=2020-01-01
 $ whim query --target=my-site.example.com/some/article

Block a domain from further consideration

 $ whim query --block=trollface.example

Send one webmention

 $ whim send https://my-site.example.com/some/article \
             https://another-site.example/target/article

Send webmentions to all valid targets found in a page's content

 $ whim send https://my-site.example.com/some/article

=head1 DESCRIPTION

Whim is a "webmention multitool" that lets you receive, send, view, and
display webmentions for your website.

Its main interface is the C<whim> command-line program, which has
various sub-commands. You can run C<whim help> (or just C<whim>, with no
arguments) at any time to see a summary of available commands.


=head1 Concepts

Concepts to understand to get the most out of Whim:


=head2 Whim's home directory

Whim keeps its data, logs, and other important information in a home
directory. By default, this is C<.whim/> within your own home directory.
Whim will try to create it if it doesn't already exist, and will
complain if it can't.

You can set this location to something other than the default via the
C<WHIM_HOME> environment variable.

=head2 Webmention

Webmention is L<a W3C
standard|https://www.w3.org/TR/2017/REC-webmention-20170112/> that --
especially when combined with semantic markup through microformats --
allows for surprisingly rich interactions among the authors of otherwise
unconnected websites, running at different domains.

For introductory information and resources about Webmention, see
L<https://jmac.org/webmention/>.


=head2 Blocklist

Whim lets you maintain a B<blocklist> against which it filters every
webmention's source prior to displaying it, or returning it as part of
any other query. An entry in Whim's blocklist is a simple string, and
Whim will block any webmention whose source contains that
string.

For example, if the blocklist contains "https://foobar.example.com/blah"
as an element, Whim will block a webmention with the source
`https://foobar.example.com/blah/bazzle.html`, but not
`https://foobar.example.com/baz`.

Blocklist elements needn't be full URLs like this; you could block every
webmention whose source URL contained the substring `foo` at all, if you
wished.

Whim will continue to store, verify, and perform other actions as needed
with blocked webmentions. It just won't display them to you, until and
unless you remove the relevant blocks from its blocklist.


=head1 Commands


=head2 listen

    whim listen start whim listen -l http://*:8080 start
    whim listen -l 'https://*:3000?cert=./server.crt&key=./server.key' \
         start
    whim listen stop

Runs a daemon that listens for webmentions, and also displays stored
webmentions on request.

By default, the daemon listens on port 3000, but you can adjust this
with command-line options. See C<whim help listen> for a more complete
list of options available.

Its required final argument is a typical daemon-control directive:
start, stop, restart, or status. Whim's listener daemon will log to
C<log/listen.log> within Whim's home directory.

=head3 Storing webmentions

The listener will automatically store all received well-formed
webmentions in its database, but will not process them. You must call
C<whim verify> as a separate step to do that. (This all happens in
accordance with W3C's Webmention spec, which recommends that receipt and
processing take place asynchronously.)

The listener will respond to GET requests at the path C</> with a simple
message that it's up and running. (Actual webmentions arrive via POST at
C</>.)

=head3 Displaying webmentions

Furthermore, the listener sets up GET endpoints at C</display_wms> and
C</summarize_wms> that will return HTML representations of webmentions
whose source matches the value of a given C<url> query-string argument.
These two endpoints return a detailed list of webmentions akin to a
comments section, and a very small numeric summary of reactions
received, respectively.

For example:

    https://my-site.example:3000/display_wms?url=http://source.example

Whim has its own default templates for displaying webmentions like this.
You can override them in whole or in part with custom template files, as
described in L<"Templates">, below.

=head2 query

 # See summaries of received, valid webmentions
 whim query --after=2020-01-01
 whim query --target=my-site.example.com/some/article

 # Block a domain from further consideration
 whim query --block=trollface.example

Display, as human-readable summaries printed to standard output,
verified webmentions that match the given criteria. (If no criteria are
given, then Whim prints every verified webmention it knows about.)

For a full list of options, type `whim help query`.

The `query` command also gives you controls to view and update Whim's
blocklist.

=head2 send

    # Try to send one webmention
    whim send http://source.example/path/to/page \
    http://target.example/path/to/another/page

    # Try to send many webmentions
    whim send http://source.example/path/to/page

Try to send webmentions, based on the one or two URLs given as
arguments. It prints a short description of what it did to standard
output.

(Note that attempts to send webmentions often end in failure, simply
because the target URL does not advertise a webmention endpoint, leaving
Whim with no place to actually send it. This is not unusual, and thus
all the rather passive-sounding "try to send" language used here.)

If you call C<whim send> with two arguments, it will try to send a
single webmention, using the two URLs as the webmention's source and
target, respectively.

If called with one argument, it will attempt to load the document at
that URL, and then try to determine which part of that document
represents the content (as opposed to comments, headers and sidebars,
and the like). If it gets this far, then it will attempt to send a
webmention for every webmention-valid hyperlink found within.

Whim tries to determine content by locating an C<h-entry> microformat
with an C<e-content> property within the document's HTML. If it can't
find anything like that, then it will send no webmentions.

=head2 verify

    whim verify

Attempt to verify all unprocessed webmentions in Whim's database --
those with no validation attempts made on them. This is the initial
state of every webmention that Whim receives and stores; you can think
of the collection of unprocessed webmentions as Whim's "inbox".

Whim will try to load the content from every unprocessed webmention's
source, and confirm that it really does link to the target URL. If it
does, it will mark it as verified. Otherwise, it will mark it as
unverified. In either case, Whim will consider the webmention
"processed", and not subject to future verification attempts.

This command is suitable for calling as a cron task, or through some
other method asynchronous from the initial receipt and storage of
webmentions, as recommended in the Webmention standard. Note that it
might take a while to run, depending upon the size of the
unprocessed-webmention queue.



=head1 Templates

Whim will check for templates in C<templates/> within its home directory
before falling back to its built-in default templates. At this time,
Whim expects templates to be L<Mojo "embedded Perl" template
files|https://metacpan.org/pod/Mojo::Template#SYNTAX>.

Whim directly calls only one template, which it expects to find at
C<webmentions.html.ep>. It passes this template the following Perl
variables:

=over

=item *

B<webmention_count>, the total number of verified webmentions the given
URL has received.


=item *

B<webmentions>, a hash reference containing object representations of
all the webmentions the given URL has received, sorted under hash-keys
named after webmention types.

Possible keys include:


=over

=item *

mention


=item *

like


=item *

repost


=item *

rsvp


=item *

quotation


=item *

reply


=back

The webmentions are L<Web::Mention> objects, as described at that manual
page.



=back

My best advice for starting custom templates, at this time, involves
looking at the default templates in Whim's source code, found in
C<lib/Whim/templates>, and seeing how it works there. Yes, this is not
very good advice. I really do want to make this easier! But, it's all we
have for now.


=head1 Notes


=head2 Project status

At the time of this writing (summer 2020), this project is very young,
and under active development as its author and other contributors work
to find its desired shape.

While Whim works right now, it is still rough around the edges, and
probably full of both bugs and fundamental design flaws. Details about
the commands below are subject to change dramatically in future
releases.


=head2 Support

=over

=item *

L<Email the author|mailto:jmac@jmac.org>


=item *

L<Whim on GitHub|https://github.com/jmacdotorg/whim/>


=item *

The C<#whim> channel on L<Libera Chat|https://libera.chat>


=back

The author very much welcomes questions, bug reports, and other
communication about Whim via any of these channels.

=head1 AUTHOR

Jason McIntosh E<lt>jmac@jmac.orgE<gt>
