#!/usr/bin/env perl use 5.016; use strict; use warnings; use File::Spec; use POSIX 'mkfifo'; my $password_command = "rbw get mail.tozt.net doy\@tozt.net"; my $mbsync_config = "$ENV{HOME}/.mbsyncloop"; my $goimapnotify_config = "$ENV{HOME}/.config/imapnotify/tozt.conf"; my ($pw_pipe, $pw_pid, $goimapnotify_pid); sub cleanup { unlink($pw_pipe) if $pw_pipe; kill KILL => -$pw_pid if $pw_pid; kill KILL => -$goimapnotify_pid if $goimapnotify_pid; } $SIG{INT} = $SIG{TERM} = sub { cleanup; exit }; END { cleanup } my $pw = `$password_command`; if ($?) { die "failed to fetch password: command returned $?"; } pipe(my $goimapnotify_r, my $goimapnotify_w) or die "failed to create unnamed pipe: $!"; $goimapnotify_pid = fork; die "fork failed: $!" unless defined $goimapnotify_pid; if (!$goimapnotify_pid) { setpgrp(0, 0); close $goimapnotify_r; while (1) { open my $fh, '-|', 'goimapnotify', '--conf', $goimapnotify_config or die "couldn't run goimapnotify: $!"; while (<$fh>) { $goimapnotify_w->print("N\n"); $goimapnotify_w->flush; } } } close $goimapnotify_w; $pw_pipe = make_pw_pipe(); $pw_pid = fork; die "fork failed: $!" unless defined $pw_pid; if (!$pw_pid) { $SIG{PIPE} = 'IGNORE'; setpgrp(0, 0); while (1) { open my $fh, '>', $pw_pipe or die "couldn't open $pw_pipe"; $fh->print("$pw\n"); close $fh; } } my $last_all = 0; $SIG{HUP} = sub { $last_all = 0 }; while (1) { my $now = time; if (($now - $last_all) >= 14 * 60) { sync("all"); $last_all = $now; } if (idle(15 * 60 - (time - $now))) { sync("priority"); } } sub sync { my ($channel) = @_; while (1) { my $status = system("mbsync -c '$mbsync_config' $channel"); if (!$status) { system("notmuch new | grep -v '^No new mail\.\$'"); last; } sleep 5; } } sub idle { my ($max_delay) = @_; my $rin = ''; vec($rin, fileno($goimapnotify_r), 1) = 1; my $ready = select(my $rout = $rin, undef, undef, $max_delay); return 0 if $ready == -1 && $! == POSIX::EINTR; die "failed to read goimapnotify output: $!" if $ready == -1; if ($ready) { while (1) { my $ready = select(my $rout = $rin, undef, undef, 0.01); return 0 if $ready == -1 && $! == POSIX::EINTR; die "failed to read goimapnotify output: $!" if $ready == -1; last unless $ready; sysread $goimapnotify_r, my $data, 4096; } return 1; } return 0; } sub make_pw_pipe { my $dir = "/run/user/$>"; if (!-d $dir) { $dir = File::Spec->tmpdir(); } my $file = File::Spec->catfile($dir, "mbsyncloop"); unlink($file); mkfifo($file, 0700) or die "couldn't create $file: $!"; $file }