#!/usr/bin/perl
# vim:ft=perl:et:
use vars qw($VERSION);
my $APP  = 'rmshit';
$VERSION = '0.6.4';

my $DEBUG = $ENV{DEBUG};

use strict;
use Carp;
use Linux::Inotify2;
use File::Path qw(remove_tree make_path);
use Getopt::Long;
use Pod::Usage;
#use Data::Dumper;

my $inotify = Linux::Inotify2->new;

my $logdir = $ENV{XDG_DATA_HOME};

$logdir = "$ENV{HOME}/.local" if $logdir eq "";
my $log = "$logdir/rmshit/rmshit.log";

my $pidfile = '/tmp/rmshit.pid';

if(!-d "$logdir/rmshit") {
  make_path("$logdir/rmshit", 1, 0777)
    or croak "Cant make_path $logdir/rmshit: $!";
}


_config_init();

our ($watchdir,%shittyfiles); # imported from the config file

GetOptions(
  'k|kill'    => \&killkid,
  'c|clean'   => sub { clean_first(); exit(0); },
  'l|log:i'   => sub { shift; recent_events(shift); },
  'h|help'    => sub { pod2usage(-verbose => 1) and exit(0); },
  'v|version' => sub { print "$APP v$VERSION\n" and exit(0); },
  'm|man'     => sub { pod2usage(-verbose => 3) and exit(0); },
);

$inotify->watch($watchdir, IN_CREATE) or carp($!);

sub recent_events {
  my $num = shift;
  $num = 25 if( ($num !~ m/^[0-9]+$/) or ($num < 1) );

  open(my $fh, '<', $log) or croak($!);;
  my @events = <$fh>;
  close($fh);

  if(scalar(@events) < $num) {
    $num = scalar(@events);
  }

  for(@events[scalar(@events)-$num .. scalar(@events)]) {
    print;
  }
  return;
}

sub daemonize {
  use POSIX 'setsid';
  my $PID = fork();
  exit(0) if($PID); # p
  exit(1) if(!defined($PID));

  setsid();
  $PID = fork();
  exit(1) if(!defined($PID));

  if($PID) {
    waitpid($PID,0);
    unlink($pidfile);
    exit(0);
  }
  elsif($PID == 0) { #c
    open(my $fh, '>', $pidfile) or die($!);
    print $fh $$;
    close($fh);

    do {
      open(STDOUT, '>', '/dev/null');
      open(STDERR, '>', '/dev/null');
      open(STDIN,  '<', '/dev/null');
    } unless($DEBUG);
  }
}

sub killkid {
  open(my $fh, '<', $pidfile) or print "rmshit is not running\n" and exit(1);
  my $target= <$fh>;
  close($fh);

  if(kill(9, $target)) {
    open(my $fh, '>>', $log) or print "Could not open $log: $!\n" and exit(1);

    print $fh '--- rmshit ' . $VERSION
      . ' terminated at ' . localtime() . " ---\n";

    close($fh);
    print "rmshit($target) vanished\n";
  }
  exit(0);
}

sub clean_first {
  open(my $fh, '>>', $log) or die("Can not open $log: $!");
  print $fh '--- rmshit ' . $VERSION . '    started at ' . localtime() . " ---\n";
  for my $dir(keys(%shittyfiles)) {
    for my $file(@{$shittyfiles{$dir}}) {

      if(-d "$dir/$file") {
        if(remove_tree("$dir/$file")) {
          print $fh "[*  DIR] ", nicetime(), "$dir/$file\n";
          close($fh);
        }
      }
      if(-f "$dir/$file") {
        if(unlink("$dir/$file")) {
          open(my $fh, '>>', $log);
          print $fh "[* FILE] ", nicetime(), "$dir/$file\n";
          close($fh);
        }
      }
    }
  }
  return 0;
}

sub nicetime {
  my @date = localtime(time);
  my $nicetime = sprintf("%04d-%02d-%02d %02d:%02d:%02d",
    $date[5]+1900, $date[4]+1, $date[3], $date[2], $date[1], $date[0]
  );
  return $nicetime;
}


print "rmshit is running\n" and exit(1) if(-e $pidfile);

clean_first();
daemonize();

while (1) {
  my @events = $inotify->read;
  unless (@events > 0) {
    print "read error: $!";
    last;
  }
  for my $event(@events) {
    for my $file( @{$shittyfiles{$watchdir}} ) {
      if($file eq $event->name) {
        open(my $fh, '>>', $log) or die("Can NOT open $log: $!");


        if(-d $event->fullname) {
          if(remove_tree($event->fullname)) {
            print $fh "[   DIR] ", nicetime(), $event->fullname,"\n";
          }
        }
        else {
          if(unlink($event->fullname)) {
            print $fh "[  FILE] ", nicetime(), $event->fullname,"\n";
          }
        }
        close $fh;
      }
    }
  }
}

sub _config_init {
  my $config;
  if(-e "$ENV{XDG_CONFIG_HOME}/rmshit/rmshit.conf") {
    $config = "$ENV{XDG_CONFIG_HOME}/rmshit/rmshit.conf";
  }
  elsif(-e "$ENV{HOME}/.config/rmshit/rmshit.conf") {
    $config = "$ENV{HOME}/.config/rmshit/rmshit.conf";
  }
  elsif(-e "$ENV{HOME}/.rmshit.conf") {
    $config = "$ENV{HOME}/.rmshit.conf";
  }
  elsif(-e "$ENV{HOME}/rmshit.conf") {
    $config = "$ENV{HOME}/rmshit.conf";
  }
  elsif(-e './rmshit.conf') {
    $config = './rmshit.conf';
  }
  elsif(-e '/etc/rmshit.conf') {
    $config = '/etc/rmshit.conf';
  }
  else {
    warn "No configuration file found.\n";
    warn "See docs/rmshit.conf.example for an example configuration file.\n";
    exit 1;
  }

  require $config;
  carp($@) if $@;
}




=pod

=head1 NAME

rmshit - keep a directory structure clean at all times

=head1 SYNOPSIS

rmshit [OPTIONS]

=head1 DESCRIPTION

B<rmshit> was born out of plain rage and frustation, seeing that nobody seems to
care about the XDG specifications, and dumping configuration files, temporary
data and logs straight into $HOME.

Even if you manually delete these files, they will be recreated when the
Application of Sin wants to (when it's executed, seeing default data is missing,
for example).

The most well known application that does this, as of this writing, is Mozilla
Firefox, creating $HOME/Desktop, over and over again.

rmshit uses inotify to keep an eye on a directory structure, instantly removing
data upon it's creation.

=head1 OPTIONS

  -c, --clean   clean dir(s) of unwanted files and exit
  -l, --lastlog show the last n number of removed files (default: 25)
  -k, --kill    kill a running rmshit process
  -h, --help    this help
  -m, --man     manpage

=head1 ENVIRONMENT

rmshit watches the directories you specify in the configuration file. It should
be placed in $XDG_CONFIG_HOME/rmshit/rmshit.conf or
$HOME/.config/rmshit/rmshit.conf.

The log file will be placed in $XDG_DATA_HOME/rmshit/rmshit.log. Entries will
look like this:

[* FILE] 2010-07-18 07:19:26: /home/scp1/.fehrc

[*  DIR] 2010-07-18 07:20:02: /home/scp1/Desktop

[  FILE] 2010-07-18 07:20:02: /home/scp1/.craprc

The '*' indicates the file was already present when rmshit was started.

=head1 REPORTING BUGS

Report bugs to m@japh.se

rmshit homepage: http://github.com/trapd00r/rmshit

=head1 AUTHOR

  Magnus Woldrich
  CPAN ID: WOLDRICH
  m@japh.se
  http://japh.se

=head1 COPYRIGHT

Copyright 2010, 2019- Magnus Woldrich <m@japh.se>. This program is free
software; you may redistribute it and/or modify it under the same terms as
Perl itself.

=cut
